libclamunrar/array.hpp
d39cb658
 #ifndef _RAR_ARRAY_
 #define _RAR_ARRAY_
 
 extern ErrorHandler ErrHandler;
 
 template <class T> class Array
 {
   private:
     T *Buffer;
     size_t BufSize;
     size_t AllocSize;
     size_t MaxSize;
     bool Secure; // Clean memory if true.
   public:
     Array();
     Array(size_t Size);
     Array(const Array &Src); // Copy constructor.
     ~Array();
     inline void CleanData();
     inline T& operator [](size_t Item) const;
     inline T* operator + (size_t Pos);
     inline size_t Size(); // Returns the size in items, not in bytes.
     void Add(size_t Items);
     void Alloc(size_t Items);
     void Reset();
     void SoftReset();
     void operator = (Array<T> &Src);
     void Push(T Item);
     void Append(T *Item,size_t Count);
     T* Addr(size_t Item) {return Buffer+Item;}
     void SetMaxSize(size_t Size) {MaxSize=Size;}
     T* Begin() {return Buffer;}
     T* End() {return Buffer==NULL ? NULL:Buffer+BufSize;}
     void SetSecure() {Secure=true;}
 };
 
 
 template <class T> void Array<T>::CleanData()
 {
   Buffer=NULL;
   BufSize=0;
   AllocSize=0;
   MaxSize=0;
   Secure=false;
 }
 
 
 template <class T> Array<T>::Array()
 {
   CleanData();
 }
 
 
 template <class T> Array<T>::Array(size_t Size)
 {
   CleanData();
   Add(Size);
 }
 
 
 // Copy constructor in case we need to pass an object as value.
 template <class T> Array<T>::Array(const Array &Src)
 {
   CleanData();
   Alloc(Src.BufSize);
   if (Src.BufSize!=0)
     memcpy((void *)Buffer,(void *)Src.Buffer,Src.BufSize*sizeof(T));
 }
 
 
 template <class T> Array<T>::~Array()
 {
   if (Buffer!=NULL)
   {
     if (Secure)
       cleandata(Buffer,AllocSize*sizeof(T));
     free(Buffer);
   }
 }
 
 
 template <class T> inline T& Array<T>::operator [](size_t Item) const
 {
   return Buffer[Item];
 }
 
 
 template <class T> inline T* Array<T>::operator +(size_t Pos)
 {
   return Buffer+Pos;
 }
 
 
 template <class T> inline size_t Array<T>::Size()
 {
   return BufSize;
 }
 
 
 template <class T> void Array<T>::Add(size_t Items)
 {
   BufSize+=Items;
   if (BufSize>AllocSize)
   {
     if (MaxSize!=0 && BufSize>MaxSize)
     {
       ErrHandler.GeneralErrMsg(L"Maximum allowed array size (%u) is exceeded",MaxSize);
       ErrHandler.MemoryError();
     }
 
     size_t Suggested=AllocSize+AllocSize/4+32;
     size_t NewSize=Max(BufSize,Suggested);
 
     T *NewBuffer;
     if (Secure)
     {
       NewBuffer=(T *)malloc(NewSize*sizeof(T));
       if (NewBuffer==NULL)
         ErrHandler.MemoryError();
       if (Buffer!=NULL)
       {
         memcpy(NewBuffer,Buffer,AllocSize*sizeof(T));
         cleandata(Buffer,AllocSize*sizeof(T));
         free(Buffer);
       }
     }
     else
     {
       NewBuffer=(T *)realloc(Buffer,NewSize*sizeof(T));
       if (NewBuffer==NULL)
         ErrHandler.MemoryError();
     }
     Buffer=NewBuffer;
     AllocSize=NewSize;
   }
 }
 
 
 template <class T> void Array<T>::Alloc(size_t Items)
 {
   if (Items>AllocSize)
     Add(Items-BufSize);
   else
     BufSize=Items;
 }
 
 
 template <class T> void Array<T>::Reset()
 {
   if (Buffer!=NULL)
   {
     free(Buffer);
     Buffer=NULL;
   }
   BufSize=0;
   AllocSize=0;
 }
 
 
 // Reset buffer size, but preserve already allocated memory if any,
 // so we can reuse it without wasting time to allocation.
 template <class T> void Array<T>::SoftReset()
 {
   BufSize=0;
 }
 
 
 template <class T> void Array<T>::operator =(Array<T> &Src)
 {
   Reset();
   Alloc(Src.BufSize);
   if (Src.BufSize!=0)
     memcpy((void *)Buffer,(void *)Src.Buffer,Src.BufSize*sizeof(T));
 }
 
 
 template <class T> void Array<T>::Push(T Item)
 {
   Add(1);
   (*this)[Size()-1]=Item;
 }
 
 
 template <class T> void Array<T>::Append(T *Items,size_t Count)
 {
   size_t CurSize=Size();
   Add(Count);
   memcpy(Buffer+CurSize,Items,Count*sizeof(T));
 }
 
 #endif