Better wording for transaction fee notification messages
[novacoin.git] / cryptopp / secblock.h
1 // secblock.h - written and placed in the public domain by Wei Dai
2
3 #ifndef CRYPTOPP_SECBLOCK_H
4 #define CRYPTOPP_SECBLOCK_H
5
6 #include "config.h"
7 #include "misc.h"
8 #include <assert.h>
9
10 #if defined(CRYPTOPP_MEMALIGN_AVAILABLE) || defined(CRYPTOPP_MM_MALLOC_AVAILABLE) || defined(QNX)
11         #include <malloc.h>
12 #else
13         #include <stdlib.h>
14 #endif
15
16 NAMESPACE_BEGIN(CryptoPP)
17
18 // ************** secure memory allocation ***************
19
20 template<class T>
21 class AllocatorBase
22 {
23 public:
24         typedef T value_type;
25         typedef size_t size_type;
26 #ifdef CRYPTOPP_MSVCRT6
27         typedef ptrdiff_t difference_type;
28 #else
29         typedef std::ptrdiff_t difference_type;
30 #endif
31         typedef T * pointer;
32         typedef const T * const_pointer;
33         typedef T & reference;
34         typedef const T & const_reference;
35
36         pointer address(reference r) const {return (&r);}
37         const_pointer address(const_reference r) const {return (&r); }
38         void construct(pointer p, const T& val) {new (p) T(val);}
39         void destroy(pointer p) {p->~T();}
40         size_type max_size() const {return ~size_type(0)/sizeof(T);}    // switch to std::numeric_limits<T>::max later
41
42 protected:
43         static void CheckSize(size_t n)
44         {
45                 if (n > ~size_t(0) / sizeof(T))
46                         throw InvalidArgument("AllocatorBase: requested size would cause integer overflow");
47         }
48 };
49
50 #define CRYPTOPP_INHERIT_ALLOCATOR_TYPES        \
51 typedef typename AllocatorBase<T>::value_type value_type;\
52 typedef typename AllocatorBase<T>::size_type size_type;\
53 typedef typename AllocatorBase<T>::difference_type difference_type;\
54 typedef typename AllocatorBase<T>::pointer pointer;\
55 typedef typename AllocatorBase<T>::const_pointer const_pointer;\
56 typedef typename AllocatorBase<T>::reference reference;\
57 typedef typename AllocatorBase<T>::const_reference const_reference;
58
59 #if defined(_MSC_VER) && (_MSC_VER < 1300)
60 // this pragma causes an internal compiler error if placed immediately before std::swap(a, b)
61 #pragma warning(push)
62 #pragma warning(disable: 4700)  // VC60 workaround: don't know how to get rid of this warning
63 #endif
64
65 template <class T, class A>
66 typename A::pointer StandardReallocate(A& a, T *p, typename A::size_type oldSize, typename A::size_type newSize, bool preserve)
67 {
68         if (oldSize == newSize)
69                 return p;
70
71         if (preserve)
72         {
73                 typename A::pointer newPointer = a.allocate(newSize, NULL);
74                 memcpy_s(newPointer, sizeof(T)*newSize, p, sizeof(T)*STDMIN(oldSize, newSize));
75                 a.deallocate(p, oldSize);
76                 return newPointer;
77         }
78         else
79         {
80                 a.deallocate(p, oldSize);
81                 return a.allocate(newSize, NULL);
82         }
83 }
84
85 #if defined(_MSC_VER) && (_MSC_VER < 1300)
86 #pragma warning(pop)
87 #endif
88
89 template <class T, bool T_Align16 = false>
90 class AllocatorWithCleanup : public AllocatorBase<T>
91 {
92 public:
93         CRYPTOPP_INHERIT_ALLOCATOR_TYPES
94
95         pointer allocate(size_type n, const void * = NULL)
96         {
97                 CheckSize(n);
98                 if (n == 0)
99                         return NULL;
100
101                 if (CRYPTOPP_BOOL_ALIGN16_ENABLED && T_Align16 && n*sizeof(T) >= 16)
102                 {
103                         byte *p;
104                 #ifdef CRYPTOPP_MM_MALLOC_AVAILABLE
105                         while (!(p = (byte *)_mm_malloc(sizeof(T)*n, 16)))
106                 #elif defined(CRYPTOPP_MEMALIGN_AVAILABLE)
107                         while (!(p = (byte *)memalign(16, sizeof(T)*n)))
108                 #elif defined(CRYPTOPP_MALLOC_ALIGNMENT_IS_16)
109                         while (!(p = (byte *)malloc(sizeof(T)*n)))
110                 #else
111                         while (!(p = (byte *)malloc(sizeof(T)*n + 16)))
112                 #endif
113                                 CallNewHandler();
114
115                 #ifdef CRYPTOPP_NO_ALIGNED_ALLOC
116                         size_t adjustment = 16-((size_t)p%16);
117                         p += adjustment;
118                         p[-1] = (byte)adjustment;
119                 #endif
120
121                         assert(IsAlignedOn(p, 16));
122                         return (pointer)p;
123                 }
124
125                 pointer p;
126                 while (!(p = (pointer)malloc(sizeof(T)*n)))
127                         CallNewHandler();
128                 return p;
129         }
130
131         void deallocate(void *p, size_type n)
132         {
133                 memset_z(p, 0, n*sizeof(T));
134
135                 if (CRYPTOPP_BOOL_ALIGN16_ENABLED && T_Align16 && n*sizeof(T) >= 16)
136                 {
137                 #ifdef CRYPTOPP_MM_MALLOC_AVAILABLE
138                         _mm_free(p);
139                 #elif defined(CRYPTOPP_NO_ALIGNED_ALLOC)
140                         p = (byte *)p - ((byte *)p)[-1];
141                         free(p);
142                 #else
143                         free(p);
144                 #endif
145                         return;
146                 }
147
148                 free(p);
149         }
150
151         pointer reallocate(T *p, size_type oldSize, size_type newSize, bool preserve)
152         {
153                 return StandardReallocate(*this, p, oldSize, newSize, preserve);
154         }
155
156         // VS.NET STL enforces the policy of "All STL-compliant allocators have to provide a
157         // template class member called rebind".
158     template <class U> struct rebind { typedef AllocatorWithCleanup<U, T_Align16> other; };
159 #if _MSC_VER >= 1500
160         AllocatorWithCleanup() {}
161         template <class U, bool A> AllocatorWithCleanup(const AllocatorWithCleanup<U, A> &) {}
162 #endif
163 };
164
165 CRYPTOPP_DLL_TEMPLATE_CLASS AllocatorWithCleanup<byte>;
166 CRYPTOPP_DLL_TEMPLATE_CLASS AllocatorWithCleanup<word16>;
167 CRYPTOPP_DLL_TEMPLATE_CLASS AllocatorWithCleanup<word32>;
168 CRYPTOPP_DLL_TEMPLATE_CLASS AllocatorWithCleanup<word64>;
169 #if CRYPTOPP_BOOL_X86
170 CRYPTOPP_DLL_TEMPLATE_CLASS AllocatorWithCleanup<word, true>;   // for Integer
171 #endif
172
173 template <class T>
174 class NullAllocator : public AllocatorBase<T>
175 {
176 public:
177         CRYPTOPP_INHERIT_ALLOCATOR_TYPES
178
179         pointer allocate(size_type n, const void * = NULL)
180         {
181                 assert(false);
182                 return NULL;
183         }
184
185         void deallocate(void *p, size_type n)
186         {
187                 //// Bitcoin: don't know why this trips, probably a false alarm, depends on the compiler used. 
188                 //assert(false);
189         }
190
191         size_type max_size() const {return 0;}
192 };
193
194 // This allocator can't be used with standard collections because
195 // they require that all objects of the same allocator type are equivalent.
196 // So this is for use with SecBlock only.
197 template <class T, size_t S, class A = NullAllocator<T>, bool T_Align16 = false>
198 class FixedSizeAllocatorWithCleanup : public AllocatorBase<T>
199 {
200 public:
201         CRYPTOPP_INHERIT_ALLOCATOR_TYPES
202
203         FixedSizeAllocatorWithCleanup() : m_allocated(false) {}
204
205         pointer allocate(size_type n)
206         {
207                 assert(IsAlignedOn(m_array, 8));
208
209                 if (n <= S && !m_allocated)
210                 {
211                         m_allocated = true;
212                         return GetAlignedArray();
213                 }
214                 else
215                         return m_fallbackAllocator.allocate(n);
216         }
217
218         pointer allocate(size_type n, const void *hint)
219         {
220                 if (n <= S && !m_allocated)
221                 {
222                         m_allocated = true;
223                         return GetAlignedArray();
224                 }
225                 else
226                         return m_fallbackAllocator.allocate(n, hint);
227         }
228
229         void deallocate(void *p, size_type n)
230         {
231                 if (p == GetAlignedArray())
232                 {
233                         assert(n <= S);
234                         assert(m_allocated);
235                         m_allocated = false;
236                         memset(p, 0, n*sizeof(T));
237                 }
238                 else
239                         m_fallbackAllocator.deallocate(p, n);
240         }
241
242         pointer reallocate(pointer p, size_type oldSize, size_type newSize, bool preserve)
243         {
244                 if (p == GetAlignedArray() && newSize <= S)
245                 {
246                         assert(oldSize <= S);
247                         if (oldSize > newSize)
248                                 memset(p + newSize, 0, (oldSize-newSize)*sizeof(T));
249                         return p;
250                 }
251
252                 pointer newPointer = allocate(newSize, NULL);
253                 if (preserve)
254                         memcpy(newPointer, p, sizeof(T)*STDMIN(oldSize, newSize));
255                 deallocate(p, oldSize);
256                 return newPointer;
257         }
258
259         size_type max_size() const {return STDMAX(m_fallbackAllocator.max_size(), S);}
260
261 private:
262 #ifdef __BORLANDC__
263         T* GetAlignedArray() {return m_array;}
264         T m_array[S];
265 #else
266         T* GetAlignedArray() {return (CRYPTOPP_BOOL_ALIGN16_ENABLED && T_Align16) ? (T*)(((byte *)m_array) + (0-(size_t)m_array)%16) : m_array;}
267         CRYPTOPP_ALIGN_DATA(8) T m_array[(CRYPTOPP_BOOL_ALIGN16_ENABLED && T_Align16) ? S+8/sizeof(T) : S];
268 #endif
269         A m_fallbackAllocator;
270         bool m_allocated;
271 };
272
273 //! a block of memory allocated using A
274 template <class T, class A = AllocatorWithCleanup<T> >
275 class SecBlock
276 {
277 public:
278         typedef typename A::value_type value_type;
279         typedef typename A::pointer iterator;
280         typedef typename A::const_pointer const_iterator;
281         typedef typename A::size_type size_type;
282
283         explicit SecBlock(size_type size=0)
284                 : m_size(size) {m_ptr = m_alloc.allocate(size, NULL);}
285         SecBlock(const SecBlock<T, A> &t)
286                 : m_size(t.m_size) {m_ptr = m_alloc.allocate(m_size, NULL); memcpy_s(m_ptr, m_size*sizeof(T), t.m_ptr, m_size*sizeof(T));}
287         SecBlock(const T *t, size_type len)
288                 : m_size(len)
289         {
290                 m_ptr = m_alloc.allocate(len, NULL);
291                 if (t == NULL)
292                         memset_z(m_ptr, 0, len*sizeof(T));
293                 else
294                         memcpy(m_ptr, t, len*sizeof(T));
295         }
296
297         ~SecBlock()
298                 {m_alloc.deallocate(m_ptr, m_size);}
299
300 #ifdef __BORLANDC__
301         operator T *() const
302                 {return (T*)m_ptr;}
303 #else
304         operator const void *() const
305                 {return m_ptr;}
306         operator void *()
307                 {return m_ptr;}
308
309         operator const T *() const
310                 {return m_ptr;}
311         operator T *()
312                 {return m_ptr;}
313 #endif
314
315 //      T *operator +(size_type offset)
316 //              {return m_ptr+offset;}
317
318 //      const T *operator +(size_type offset) const
319 //              {return m_ptr+offset;}
320
321 //      T& operator[](size_type index)
322 //              {assert(index >= 0 && index < m_size); return m_ptr[index];}
323
324 //      const T& operator[](size_type index) const
325 //              {assert(index >= 0 && index < m_size); return m_ptr[index];}
326
327         iterator begin()
328                 {return m_ptr;}
329         const_iterator begin() const
330                 {return m_ptr;}
331         iterator end()
332                 {return m_ptr+m_size;}
333         const_iterator end() const
334                 {return m_ptr+m_size;}
335
336         typename A::pointer data() {return m_ptr;}
337         typename A::const_pointer data() const {return m_ptr;}
338
339         size_type size() const {return m_size;}
340         bool empty() const {return m_size == 0;}
341
342         byte * BytePtr() {return (byte *)m_ptr;}
343         const byte * BytePtr() const {return (const byte *)m_ptr;}
344         size_type SizeInBytes() const {return m_size*sizeof(T);}
345
346         //! set contents and size
347         void Assign(const T *t, size_type len)
348         {
349                 New(len);
350                 memcpy_s(m_ptr, m_size*sizeof(T), t, len*sizeof(T));
351         }
352
353         //! copy contents and size from another SecBlock
354         void Assign(const SecBlock<T, A> &t)
355         {
356                 New(t.m_size);
357                 memcpy_s(m_ptr, m_size*sizeof(T), t.m_ptr, m_size*sizeof(T));
358         }
359
360         SecBlock<T, A>& operator=(const SecBlock<T, A> &t)
361         {
362                 Assign(t);
363                 return *this;
364         }
365
366         // append to this object
367         SecBlock<T, A>& operator+=(const SecBlock<T, A> &t)
368         {
369                 size_type oldSize = m_size;
370                 Grow(m_size+t.m_size);
371                 memcpy_s(m_ptr+oldSize, m_size*sizeof(T), t.m_ptr, t.m_size*sizeof(T));
372                 return *this;
373         }
374
375         // append operator
376         SecBlock<T, A> operator+(const SecBlock<T, A> &t)
377         {
378                 SecBlock<T, A> result(m_size+t.m_size);
379                 memcpy_s(result.m_ptr, result.m_size*sizeof(T), m_ptr, m_size*sizeof(T));
380                 memcpy_s(result.m_ptr+m_size, t.m_size*sizeof(T), t.m_ptr, t.m_size*sizeof(T));
381                 return result;
382         }
383
384         bool operator==(const SecBlock<T, A> &t) const
385         {
386                 return m_size == t.m_size && VerifyBufsEqual(m_ptr, t.m_ptr, m_size*sizeof(T));
387         }
388
389         bool operator!=(const SecBlock<T, A> &t) const
390         {
391                 return !operator==(t);
392         }
393
394         //! change size, without preserving contents
395         void New(size_type newSize)
396         {
397                 m_ptr = m_alloc.reallocate(m_ptr, m_size, newSize, false);
398                 m_size = newSize;
399         }
400
401         //! change size and set contents to 0
402         void CleanNew(size_type newSize)
403         {
404                 New(newSize);
405                 memset_z(m_ptr, 0, m_size*sizeof(T));
406         }
407
408         //! change size only if newSize > current size. contents are preserved
409         void Grow(size_type newSize)
410         {
411                 if (newSize > m_size)
412                 {
413                         m_ptr = m_alloc.reallocate(m_ptr, m_size, newSize, true);
414                         m_size = newSize;
415                 }
416         }
417
418         //! change size only if newSize > current size. contents are preserved and additional area is set to 0
419         void CleanGrow(size_type newSize)
420         {
421                 if (newSize > m_size)
422                 {
423                         m_ptr = m_alloc.reallocate(m_ptr, m_size, newSize, true);
424                         memset(m_ptr+m_size, 0, (newSize-m_size)*sizeof(T));
425                         m_size = newSize;
426                 }
427         }
428
429         //! change size and preserve contents
430         void resize(size_type newSize)
431         {
432                 m_ptr = m_alloc.reallocate(m_ptr, m_size, newSize, true);
433                 m_size = newSize;
434         }
435
436         //! swap contents and size with another SecBlock
437         void swap(SecBlock<T, A> &b)
438         {
439                 std::swap(m_alloc, b.m_alloc);
440                 std::swap(m_size, b.m_size);
441                 std::swap(m_ptr, b.m_ptr);
442         }
443
444 //private:
445         A m_alloc;
446         size_type m_size;
447         T *m_ptr;
448 };
449
450 typedef SecBlock<byte> SecByteBlock;
451 typedef SecBlock<byte, AllocatorWithCleanup<byte, true> > AlignedSecByteBlock;
452 typedef SecBlock<word> SecWordBlock;
453
454 //! a SecBlock with fixed size, allocated statically
455 template <class T, unsigned int S, class A = FixedSizeAllocatorWithCleanup<T, S> >
456 class FixedSizeSecBlock : public SecBlock<T, A>
457 {
458 public:
459         explicit FixedSizeSecBlock() : SecBlock<T, A>(S) {}
460 };
461
462 template <class T, unsigned int S, bool T_Align16 = true>
463 class FixedSizeAlignedSecBlock : public FixedSizeSecBlock<T, S, FixedSizeAllocatorWithCleanup<T, S, NullAllocator<T>, T_Align16> >
464 {
465 };
466
467 //! a SecBlock that preallocates size S statically, and uses the heap when this size is exceeded
468 template <class T, unsigned int S, class A = FixedSizeAllocatorWithCleanup<T, S, AllocatorWithCleanup<T> > >
469 class SecBlockWithHint : public SecBlock<T, A>
470 {
471 public:
472         explicit SecBlockWithHint(size_t size) : SecBlock<T, A>(size) {}
473 };
474
475 template<class T, bool A, class U, bool B>
476 inline bool operator==(const CryptoPP::AllocatorWithCleanup<T, A>&, const CryptoPP::AllocatorWithCleanup<U, B>&) {return (true);}
477 template<class T, bool A, class U, bool B>
478 inline bool operator!=(const CryptoPP::AllocatorWithCleanup<T, A>&, const CryptoPP::AllocatorWithCleanup<U, B>&) {return (false);}
479
480 NAMESPACE_END
481
482 NAMESPACE_BEGIN(std)
483 template <class T, class A>
484 inline void swap(CryptoPP::SecBlock<T, A> &a, CryptoPP::SecBlock<T, A> &b)
485 {
486         a.swap(b);
487 }
488
489 #if defined(_STLP_DONT_SUPPORT_REBIND_MEMBER_TEMPLATE) || (defined(_STLPORT_VERSION) && !defined(_STLP_MEMBER_TEMPLATE_CLASSES))
490 // working for STLport 5.1.3 and MSVC 6 SP5
491 template <class _Tp1, class _Tp2>
492 inline CryptoPP::AllocatorWithCleanup<_Tp2>&
493 __stl_alloc_rebind(CryptoPP::AllocatorWithCleanup<_Tp1>& __a, const _Tp2*)
494 {
495         return (CryptoPP::AllocatorWithCleanup<_Tp2>&)(__a);
496 }
497 #endif
498
499 NAMESPACE_END
500
501 #endif