blob: 964a96ba8d78ddebbfd61981055e692297db3b0b [file] [log] [blame]
#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