libclamunrar/rawread.cpp
01eebc13
 #include "rar.hpp"
 
 RawRead::RawRead()
 {
   RawRead::SrcFile=NULL;
   Reset();
 }
 
 
 RawRead::RawRead(File *SrcFile)
 {
   RawRead::SrcFile=SrcFile;
   Reset();
 }
 
 
 void RawRead::Reset()
 {
   Data.SoftReset();
   ReadPos=0;
   DataSize=0;
   Crypt=NULL;
 }
 
 
 size_t RawRead::Read(size_t Size)
 {
   size_t ReadSize=0;
 #if !defined(RAR_NOCRYPT)
   if (Crypt!=NULL)
   {
     // Full size of buffer with already read data including data read 
     // for encryption block alignment.
     size_t FullSize=Data.Size();
 
     // Data read for alignment and not processed yet.
     size_t DataLeft=FullSize-DataSize;
 
     if (Size>DataLeft) // Need to read more than we already have.
     {
       size_t SizeToRead=Size-DataLeft;
       size_t AlignedReadSize=SizeToRead+((~SizeToRead+1) & CRYPT_BLOCK_MASK);
       Data.Add(AlignedReadSize);
       ReadSize=SrcFile->Read(&Data[FullSize],AlignedReadSize);
       Crypt->DecryptBlock(&Data[FullSize],AlignedReadSize);
       DataSize+=ReadSize==0 ? 0:Size;
     }
     else // Use buffered data, no real read.
     {
       ReadSize=Size;
       DataSize+=Size;
     }
   }
   else
 #endif
     if (Size!=0)
     {
       Data.Add(Size);
       ReadSize=SrcFile->Read(&Data[DataSize],Size);
       DataSize+=ReadSize;
     }
   return ReadSize;
 }
 
 
 void RawRead::Read(byte *SrcData,size_t Size)
 {
   if (Size!=0)
   {
     Data.Add(Size);
     memcpy(&Data[DataSize],SrcData,Size);
     DataSize+=Size;
   }
 }
 
 
 byte RawRead::Get1()
 {
   return ReadPos<DataSize ? Data[ReadPos++]:0;
 }
 
 
 ushort RawRead::Get2()
 {
   if (ReadPos+1<DataSize)
   {
     ushort Result=Data[ReadPos]+(Data[ReadPos+1]<<8);
     ReadPos+=2;
     return Result;
   }
   return 0;
 }
 
 
 uint RawRead::Get4()
 {
   if (ReadPos+3<DataSize)
   {
     uint Result=Data[ReadPos]+(Data[ReadPos+1]<<8)+(Data[ReadPos+2]<<16)+
                 (Data[ReadPos+3]<<24);
     ReadPos+=4;
     return Result;
   }
   return 0;
 }
 
 
 uint64 RawRead::Get8()
 {
   uint Low=Get4(),High=Get4();
   return INT32TO64(High,Low);
 }
 
 
 uint64 RawRead::GetV()
 {
   uint64 Result=0;
   // Need to check Shift<64, because for shift greater than or equal to
   // the width of the promoted left operand, the behavior is undefined.
   for (uint Shift=0;ReadPos<DataSize && Shift<64;Shift+=7)
   {
     byte CurByte=Data[ReadPos++];
     Result+=uint64(CurByte & 0x7f)<<Shift;
     if ((CurByte & 0x80)==0)
       return Result; // Decoded successfully.
   }
   return 0; // Out of buffer border.
 }
 
 
 // Return a number of bytes in current variable length integer.
 uint RawRead::GetVSize(size_t Pos)
 {
   for (size_t CurPos=Pos;CurPos<DataSize;CurPos++)
     if ((Data[CurPos] & 0x80)==0)
       return int(CurPos-Pos+1);
   return 0; // Buffer overflow.
 }
 
 
 size_t RawRead::GetB(void *Field,size_t Size)
 {
   byte *F=(byte *)Field;
   size_t CopySize=Min(DataSize-ReadPos,Size);
   if (CopySize>0)
     memcpy(F,&Data[ReadPos],CopySize);
   if (Size>CopySize)
     memset(F+CopySize,0,Size-CopySize);
   ReadPos+=CopySize;
   return CopySize;
 }
 
 
 void RawRead::GetW(wchar *Field,size_t Size)
 {
   if (ReadPos+2*Size-1<DataSize)
   {
     RawToWide(&Data[ReadPos],Field,Size);
     ReadPos+=sizeof(wchar)*Size;
   }
   else
     memset(Field,0,sizeof(wchar)*Size);
 }
 
 
 uint RawRead::GetCRC15(bool ProcessedOnly) // RAR 1.5 block CRC.
 {
   if (DataSize<=2)
     return 0;
   uint HeaderCRC=CRC32(0xffffffff,&Data[2],(ProcessedOnly ? ReadPos:DataSize)-2);
   return ~HeaderCRC & 0xffff;
 }
 
 
 uint RawRead::GetCRC50() // RAR 5.0 block CRC.
 {
   if (DataSize<=4)
     return 0xffffffff;
   return CRC32(0xffffffff,&Data[4],DataSize-4) ^ 0xffffffff;
 }
 
 
 // Read vint from arbitrary byte array.
 uint64 RawGetV(const byte *Data,uint &ReadPos,uint DataSize,bool &Overflow)
 {
   Overflow=false;
   uint64 Result=0;
   for (uint Shift=0;ReadPos<DataSize;Shift+=7)
   {
     byte CurByte=Data[ReadPos++];
     Result+=uint64(CurByte & 0x7f)<<Shift;
     if ((CurByte & 0x80)==0)
       return Result; // Decoded successfully.
   }
   Overflow=true;
   return 0; // Out of buffer border.
 }