| #include "rar.hpp" |
| |
| namespace third_party_unrar { |
| |
| 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. |
| } |
| |
| } // namespace third_party_unrar |