Initial community commit
This commit is contained in:
parent
537bcbc862
commit
fc06254474
16440 changed files with 4239995 additions and 2 deletions
300
Src/external_dependencies/openmpt-trunk/include/unrar/qopen.cpp
vendored
Normal file
300
Src/external_dependencies/openmpt-trunk/include/unrar/qopen.cpp
vendored
Normal file
|
@ -0,0 +1,300 @@
|
|||
#include "rar.hpp"
|
||||
|
||||
QuickOpen::QuickOpen()
|
||||
{
|
||||
Buf=NULL;
|
||||
Init(NULL,false);
|
||||
}
|
||||
|
||||
|
||||
QuickOpen::~QuickOpen()
|
||||
{
|
||||
Close();
|
||||
delete[] Buf;
|
||||
}
|
||||
|
||||
|
||||
void QuickOpen::Init(Archive *Arc,bool WriteMode)
|
||||
{
|
||||
if (Arc!=NULL) // Unless called from constructor.
|
||||
Close();
|
||||
|
||||
QuickOpen::Arc=Arc;
|
||||
QuickOpen::WriteMode=WriteMode;
|
||||
|
||||
ListStart=NULL;
|
||||
ListEnd=NULL;
|
||||
|
||||
if (Buf==NULL)
|
||||
Buf=new byte[MaxBufSize];
|
||||
|
||||
CurBufSize=0; // Current size of buffered data in write mode.
|
||||
|
||||
Loaded=false;
|
||||
}
|
||||
|
||||
|
||||
void QuickOpen::Close()
|
||||
{
|
||||
QuickOpenItem *Item=ListStart;
|
||||
while (Item!=NULL)
|
||||
{
|
||||
QuickOpenItem *Next=Item->Next;
|
||||
delete[] Item->Header;
|
||||
delete Item;
|
||||
Item=Next;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void QuickOpen::Load(uint64 BlockPos)
|
||||
{
|
||||
if (!Loaded)
|
||||
{
|
||||
// If loading for the first time, perform additional intialization.
|
||||
SeekPos=Arc->Tell();
|
||||
UnsyncSeekPos=false;
|
||||
|
||||
int64 SavePos=SeekPos;
|
||||
Arc->Seek(BlockPos,SEEK_SET);
|
||||
|
||||
// If BlockPos points to original main header, we'll have the infinite
|
||||
// recursion, because ReadHeader() for main header will attempt to load
|
||||
// QOpen and call QuickOpen::Load again. If BlockPos points to long chain
|
||||
// of other main headers, we'll have multiple recursive calls of this
|
||||
// function wasting resources. So we prohibit QOpen temporarily to
|
||||
// prevent this. ReadHeader() calls QOpen.Init and sets MainHead Locator
|
||||
// and QOpenOffset fields, so we cannot use them to prohibit QOpen.
|
||||
Arc->SetProhibitQOpen(true);
|
||||
size_t ReadSize=Arc->ReadHeader();
|
||||
Arc->SetProhibitQOpen(false);
|
||||
|
||||
if (ReadSize==0 || Arc->GetHeaderType()!=HEAD_SERVICE ||
|
||||
!Arc->SubHead.CmpName(SUBHEAD_TYPE_QOPEN))
|
||||
{
|
||||
Arc->Seek(SavePos,SEEK_SET);
|
||||
return;
|
||||
}
|
||||
QOHeaderPos=Arc->CurBlockPos;
|
||||
RawDataStart=Arc->Tell();
|
||||
RawDataSize=Arc->SubHead.UnpSize;
|
||||
Arc->Seek(SavePos,SEEK_SET);
|
||||
|
||||
Loaded=true; // Set only after all file processing calls like Tell, Seek, ReadHeader.
|
||||
}
|
||||
|
||||
if (Arc->SubHead.Encrypted)
|
||||
{
|
||||
RAROptions *Cmd=Arc->GetRAROptions();
|
||||
#ifndef RAR_NOCRYPT
|
||||
if (Cmd->Password.IsSet())
|
||||
Crypt.SetCryptKeys(false,CRYPT_RAR50,&Cmd->Password,Arc->SubHead.Salt,
|
||||
Arc->SubHead.InitV,Arc->SubHead.Lg2Count,
|
||||
Arc->SubHead.HashKey,Arc->SubHead.PswCheck);
|
||||
else
|
||||
#endif
|
||||
{
|
||||
Loaded=false;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
RawDataPos=0;
|
||||
ReadBufSize=0;
|
||||
ReadBufPos=0;
|
||||
LastReadHeader.Reset();
|
||||
LastReadHeaderPos=0;
|
||||
|
||||
ReadBuffer();
|
||||
}
|
||||
|
||||
|
||||
bool QuickOpen::Read(void *Data,size_t Size,size_t &Result)
|
||||
{
|
||||
if (!Loaded)
|
||||
return false;
|
||||
// Find next suitable cached block.
|
||||
while (LastReadHeaderPos+LastReadHeader.Size()<=SeekPos)
|
||||
if (!ReadNext())
|
||||
break;
|
||||
if (!Loaded)
|
||||
{
|
||||
// If something wrong happened, let's set the correct file pointer
|
||||
// and stop further quick open processing.
|
||||
if (UnsyncSeekPos)
|
||||
Arc->File::Seek(SeekPos,SEEK_SET);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (SeekPos>=LastReadHeaderPos && SeekPos+Size<=LastReadHeaderPos+LastReadHeader.Size())
|
||||
{
|
||||
memcpy(Data,LastReadHeader+size_t(SeekPos-LastReadHeaderPos),Size);
|
||||
Result=Size;
|
||||
SeekPos+=Size;
|
||||
UnsyncSeekPos=true;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (UnsyncSeekPos)
|
||||
{
|
||||
Arc->File::Seek(SeekPos,SEEK_SET);
|
||||
UnsyncSeekPos=false;
|
||||
}
|
||||
int ReadSize=Arc->File::Read(Data,Size);
|
||||
if (ReadSize<0)
|
||||
{
|
||||
Loaded=false;
|
||||
return false;
|
||||
}
|
||||
Result=ReadSize;
|
||||
SeekPos+=ReadSize;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool QuickOpen::Seek(int64 Offset,int Method)
|
||||
{
|
||||
if (!Loaded)
|
||||
return false;
|
||||
|
||||
// Normally we process an archive sequentially from beginning to end,
|
||||
// so we read quick open data sequentially. But some operations like
|
||||
// archive updating involve several passes. So if we detect that file
|
||||
// pointer is moved back, we reload quick open data from beginning.
|
||||
if (Method==SEEK_SET && (uint64)Offset<SeekPos && (uint64)Offset<LastReadHeaderPos)
|
||||
Load(QOHeaderPos);
|
||||
|
||||
if (Method==SEEK_SET)
|
||||
SeekPos=Offset;
|
||||
if (Method==SEEK_CUR)
|
||||
SeekPos+=Offset;
|
||||
UnsyncSeekPos=true;
|
||||
|
||||
if (Method==SEEK_END)
|
||||
{
|
||||
Arc->File::Seek(Offset,SEEK_END);
|
||||
SeekPos=Arc->File::Tell();
|
||||
UnsyncSeekPos=false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool QuickOpen::Tell(int64 *Pos)
|
||||
{
|
||||
if (!Loaded)
|
||||
return false;
|
||||
*Pos=SeekPos;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
uint QuickOpen::ReadBuffer()
|
||||
{
|
||||
int64 SavePos=Arc->Tell();
|
||||
Arc->File::Seek(RawDataStart+RawDataPos,SEEK_SET);
|
||||
size_t SizeToRead=(size_t)Min(RawDataSize-RawDataPos,MaxBufSize-ReadBufSize);
|
||||
if (Arc->SubHead.Encrypted)
|
||||
SizeToRead &= ~CRYPT_BLOCK_MASK;
|
||||
int ReadSize=0;
|
||||
if (SizeToRead!=0)
|
||||
{
|
||||
ReadSize=Arc->File::Read(Buf+ReadBufSize,SizeToRead);
|
||||
if (ReadSize<=0)
|
||||
ReadSize=0;
|
||||
else
|
||||
{
|
||||
#ifndef RAR_NOCRYPT
|
||||
if (Arc->SubHead.Encrypted)
|
||||
Crypt.DecryptBlock(Buf+ReadBufSize,ReadSize & ~CRYPT_BLOCK_MASK);
|
||||
#endif
|
||||
RawDataPos+=ReadSize;
|
||||
ReadBufSize+=ReadSize;
|
||||
}
|
||||
}
|
||||
Arc->Seek(SavePos,SEEK_SET);
|
||||
return ReadSize;
|
||||
}
|
||||
|
||||
|
||||
// Fill RawRead object from buffer.
|
||||
bool QuickOpen::ReadRaw(RawRead &Raw)
|
||||
{
|
||||
if (MaxBufSize-ReadBufPos<0x100) // We are close to end of buffer.
|
||||
{
|
||||
// Ensure that we have enough data to read CRC and header size.
|
||||
size_t DataLeft=ReadBufSize-ReadBufPos;
|
||||
memcpy(Buf,Buf+ReadBufPos,DataLeft);
|
||||
ReadBufPos=0;
|
||||
ReadBufSize=DataLeft;
|
||||
ReadBuffer();
|
||||
}
|
||||
const size_t FirstReadSize=7;
|
||||
if (ReadBufPos+FirstReadSize>ReadBufSize)
|
||||
return false;
|
||||
Raw.Read(Buf+ReadBufPos,FirstReadSize);
|
||||
ReadBufPos+=FirstReadSize;
|
||||
|
||||
uint SavedCRC=Raw.Get4();
|
||||
uint SizeBytes=Raw.GetVSize(4);
|
||||
uint64 BlockSize=Raw.GetV();
|
||||
int SizeToRead=int(BlockSize);
|
||||
SizeToRead-=FirstReadSize-SizeBytes-4; // Adjust overread size bytes if any.
|
||||
if (SizeToRead<0 || SizeBytes==0 || BlockSize==0)
|
||||
{
|
||||
Loaded=false; // Invalid data.
|
||||
return false;
|
||||
}
|
||||
|
||||
// If rest of block data crosses Buf boundary, read it in loop.
|
||||
while (SizeToRead>0)
|
||||
{
|
||||
size_t DataLeft=ReadBufSize-ReadBufPos;
|
||||
size_t CurSizeToRead=Min(DataLeft,(size_t)SizeToRead);
|
||||
Raw.Read(Buf+ReadBufPos,CurSizeToRead);
|
||||
ReadBufPos+=CurSizeToRead;
|
||||
SizeToRead-=int(CurSizeToRead);
|
||||
if (SizeToRead>0) // We read the entire buffer and still need more data.
|
||||
{
|
||||
ReadBufPos=0;
|
||||
ReadBufSize=0;
|
||||
if (ReadBuffer()==0)
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return SavedCRC==Raw.GetCRC50();
|
||||
}
|
||||
|
||||
|
||||
// Read next cached header.
|
||||
bool QuickOpen::ReadNext()
|
||||
{
|
||||
RawRead Raw(NULL);
|
||||
if (!ReadRaw(Raw)) // Read internal quick open header preceding stored block.
|
||||
return false;
|
||||
uint Flags=(uint)Raw.GetV();
|
||||
uint64 Offset=Raw.GetV();
|
||||
size_t HeaderSize=(size_t)Raw.GetV();
|
||||
if (HeaderSize>MAX_HEADER_SIZE_RAR5)
|
||||
return false;
|
||||
LastReadHeader.Alloc(HeaderSize);
|
||||
Raw.GetB(&LastReadHeader[0],HeaderSize);
|
||||
// Calculate the absolute position as offset from quick open service header.
|
||||
LastReadHeaderPos=QOHeaderPos-Offset;
|
||||
return true;
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue