123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325 |
- #include "rar.hpp"
- ComprDataIO::ComprDataIO()
- {
- #ifndef RAR_NOCRYPT
- Crypt=new CryptData;
- Decrypt=new CryptData;
- #endif
- Init();
- }
- void ComprDataIO::Init()
- {
- UnpackFromMemory=false;
- UnpackToMemory=false;
- UnpPackedSize=0;
- UnpPackedLeft=0;
- ShowProgress=true;
- TestMode=false;
- SkipUnpCRC=false;
- NoFileHeader=false;
- PackVolume=false;
- UnpVolume=false;
- NextVolumeMissing=false;
- SrcFile=NULL;
- DestFile=NULL;
- UnpWrAddr=NULL;
- UnpWrSize=0;
- Command=NULL;
- Encryption=false;
- Decryption=false;
- CurPackRead=CurPackWrite=CurUnpRead=CurUnpWrite=0;
- LastPercent=-1;
- SubHead=NULL;
- SubHeadPos=NULL;
- CurrentCommand=0;
- ProcessedArcSize=0;
- LastArcSize=0;
- TotalArcSize=0;
- }
- ComprDataIO::~ComprDataIO()
- {
- #ifndef RAR_NOCRYPT
- delete Crypt;
- delete Decrypt;
- #endif
- }
- int ComprDataIO::UnpRead(byte *Addr,size_t Count)
- {
- #ifndef RAR_NOCRYPT
- // In case of encryption we need to align read size to encryption
- // block size. We can do it by simple masking, because unpack read code
- // always reads more than CRYPT_BLOCK_SIZE, so we do not risk to make it 0.
- if (Decryption)
- Count &= ~CRYPT_BLOCK_MASK;
- #endif
-
- int ReadSize=0,TotalRead=0;
- byte *ReadAddr;
- ReadAddr=Addr;
- while (Count > 0)
- {
- Archive *SrcArc=(Archive *)SrcFile;
- if (UnpackFromMemory)
- {
- memcpy(Addr,UnpackFromMemoryAddr,UnpackFromMemorySize);
- ReadSize=(int)UnpackFromMemorySize;
- UnpackFromMemorySize=0;
- }
- else
- {
- size_t SizeToRead=((int64)Count>UnpPackedLeft) ? (size_t)UnpPackedLeft:Count;
- if (SizeToRead > 0)
- {
- if (UnpVolume && Decryption && (int64)Count>UnpPackedLeft)
- {
- // We need aligned blocks for decryption and we want "Keep broken
- // files" to work efficiently with missing encrypted volumes.
- // So for last data block in volume we adjust the size to read to
- // next equal or smaller block producing aligned total block size.
- // So we'll ask for next volume only when processing few unaligned
- // bytes left in the end, when most of data is already extracted.
- size_t NewTotalRead = TotalRead + SizeToRead;
- size_t Adjust = NewTotalRead - (NewTotalRead & ~CRYPT_BLOCK_MASK);
- size_t NewSizeToRead = SizeToRead - Adjust;
- if ((int)NewSizeToRead > 0)
- SizeToRead = NewSizeToRead;
- }
- if (!SrcFile->IsOpened())
- return -1;
- ReadSize=SrcFile->Read(ReadAddr,SizeToRead);
- FileHeader *hd=SubHead!=NULL ? SubHead:&SrcArc->FileHead;
- if (!NoFileHeader && hd->SplitAfter)
- PackedDataHash.Update(ReadAddr,ReadSize);
- }
- }
- CurUnpRead+=ReadSize;
- TotalRead+=ReadSize;
- #ifndef NOVOLUME
- // These variable are not used in NOVOLUME mode, so it is better
- // to exclude commands below to avoid compiler warnings.
- ReadAddr+=ReadSize;
- Count-=ReadSize;
- #endif
- UnpPackedLeft-=ReadSize;
- // Do not ask for next volume if we read something from current volume.
- // If next volume is missing, we need to process all data from current
- // volume before aborting. It helps to recover all possible data
- // in "Keep broken files" mode. But if we process encrypted data,
- // we ask for next volume also if we have non-aligned encryption block.
- // Since we adjust data size for decryption earlier above,
- // it does not hurt "Keep broken files" mode efficiency.
- if (UnpVolume && UnpPackedLeft == 0 &&
- (ReadSize==0 || Decryption && (TotalRead & CRYPT_BLOCK_MASK) != 0) )
- {
- #ifndef NOVOLUME
- if (!MergeArchive(*SrcArc,this,true,CurrentCommand))
- #endif
- {
- NextVolumeMissing=true;
- return -1;
- }
- }
- else
- break;
- }
- Archive *SrcArc=(Archive *)SrcFile;
- if (SrcArc!=NULL)
- ShowUnpRead(SrcArc->NextBlockPos-UnpPackedSize+CurUnpRead,TotalArcSize);
- if (ReadSize!=-1)
- {
- ReadSize=TotalRead;
- #ifndef RAR_NOCRYPT
- if (Decryption)
- Decrypt->DecryptBlock(Addr,ReadSize);
- #endif
- }
- Wait();
- return ReadSize;
- }
- void ComprDataIO::UnpWrite(byte *Addr,size_t Count)
- {
- #ifdef RARDLL
- RAROptions *Cmd=((Archive *)SrcFile)->GetRAROptions();
- if (Cmd->DllOpMode!=RAR_SKIP)
- {
- if (Cmd->Callback!=NULL &&
- Cmd->Callback(UCM_PROCESSDATA,Cmd->UserData,(LPARAM)Addr,Count)==-1)
- ErrHandler.Exit(RARX_USERBREAK);
- /* // OPENMPT ADDITION
- if (Cmd->ProcessDataProc!=NULL)
- {
- int RetCode=Cmd->ProcessDataProc(Addr,(int)Count);
- if (RetCode==0)
- ErrHandler.Exit(RARX_USERBREAK);
- }
- */ // OPENMPT ADDITION
- }
- #endif // RARDLL
- UnpWrAddr=Addr;
- UnpWrSize=Count;
- if (UnpackToMemory)
- {
- if (Count <= UnpackToMemorySize)
- {
- memcpy(UnpackToMemoryAddr,Addr,Count);
- UnpackToMemoryAddr+=Count;
- UnpackToMemorySize-=Count;
- }
- }
- else
- if (!TestMode)
- DestFile->Write(Addr,Count);
- CurUnpWrite+=Count;
- if (!SkipUnpCRC)
- UnpHash.Update(Addr,Count);
- ShowUnpWrite();
- Wait();
- }
- void ComprDataIO::ShowUnpRead(int64 ArcPos,int64 ArcSize)
- {
- return; // OPENMPT ADDITION
- if (ShowProgress && SrcFile!=NULL)
- {
- // Important when processing several archives or multivolume archive.
- ArcPos+=ProcessedArcSize;
- Archive *SrcArc=(Archive *)SrcFile;
- RAROptions *Cmd=SrcArc->GetRAROptions();
- int CurPercent=ToPercent(ArcPos,ArcSize);
- if (!Cmd->DisablePercentage && CurPercent!=LastPercent)
- {
- uiExtractProgress(CurUnpWrite,SrcArc->FileHead.UnpSize,ArcPos,ArcSize);
- LastPercent=CurPercent;
- }
- }
- }
- void ComprDataIO::ShowUnpWrite()
- {
- }
- void ComprDataIO::SetFiles(File *SrcFile,File *DestFile)
- {
- if (SrcFile!=NULL)
- ComprDataIO::SrcFile=SrcFile;
- if (DestFile!=NULL)
- ComprDataIO::DestFile=DestFile;
- LastPercent=-1;
- }
- void ComprDataIO::GetUnpackedData(byte **Data,size_t *Size)
- {
- *Data=UnpWrAddr;
- *Size=UnpWrSize;
- }
- void ComprDataIO::SetEncryption(bool Encrypt,CRYPT_METHOD Method,
- SecPassword *Password,const byte *Salt,const byte *InitV,
- uint Lg2Cnt,byte *HashKey,byte *PswCheck)
- {
- #ifndef RAR_NOCRYPT
- if (Encrypt)
- Encryption=Crypt->SetCryptKeys(true,Method,Password,Salt,InitV,Lg2Cnt,HashKey,PswCheck);
- else
- Decryption=Decrypt->SetCryptKeys(false,Method,Password,Salt,InitV,Lg2Cnt,HashKey,PswCheck);
- #endif
- }
- #if !defined(SFX_MODULE) && !defined(RAR_NOCRYPT)
- void ComprDataIO::SetAV15Encryption()
- {
- Decryption=true;
- Decrypt->SetAV15Encryption();
- }
- #endif
- #if !defined(SFX_MODULE) && !defined(RAR_NOCRYPT)
- void ComprDataIO::SetCmt13Encryption()
- {
- Decryption=true;
- Decrypt->SetCmt13Encryption();
- }
- #endif
- void ComprDataIO::SetUnpackToMemory(byte *Addr,uint Size)
- {
- UnpackToMemory=true;
- UnpackToMemoryAddr=Addr;
- UnpackToMemorySize=Size;
- }
- // Extraction progress is based on the position in archive and we adjust
- // the total archives size here, so trailing blocks do not prevent progress
- // reaching 100% at the end of extraction. Alternatively we could print "100%"
- // after completing the entire archive extraction, but then we would need
- // to take into account possible messages like the checksum error after
- // last file percent progress.
- void ComprDataIO::AdjustTotalArcSize(Archive *Arc)
- {
- // If we know a position of QO or RR blocks, use them to adjust the total
- // packed size to beginning of these blocks. Earlier we already calculated
- // the total size based on entire archive sizes. We also set LastArcSize
- // to start of first trailing block, to add it later to ProcessedArcSize.
- int64 ArcLength=Arc->IsSeekable() ? Arc->FileLength() : 0;
- if (Arc->MainHead.QOpenOffset!=0) // QO is always preceding RR record.
- LastArcSize=Arc->MainHead.QOpenOffset;
- else
- if (Arc->MainHead.RROffset!=0)
- LastArcSize=Arc->MainHead.RROffset;
- else
- {
- // If neither QO nor RR are found, exclude the approximate size of
- // end of archive block.
- // We select EndBlock to be larger than typical 8 bytes HEAD_ENDARC,
- // but to not exceed the smallest 22 bytes HEAD_FILE with 1 byte file
- // name, so we do not have two files with 100% at the end of archive.
- const uint EndBlock=23;
- if (ArcLength>EndBlock)
- LastArcSize=ArcLength-EndBlock;
- }
- TotalArcSize-=ArcLength-LastArcSize;
- }
|