void Unpack::Unpack29(bool Solid) { static unsigned char LDecode[]={0,1,2,3,4,5,6,7,8,10,12,14,16,20,24,28,32,40,48,56,64,80,96,112,128,160,192,224}; static unsigned char LBits[]= {0,0,0,0,0,0,0,0,1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5}; static int DDecode[DC]; static byte DBits[DC]; static unsigned int DBitLengthCounts[]= {4,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,14,0,12}; static unsigned char SDDecode[]={0,4,8,16,32,64,128,192}; static unsigned char SDBits[]= {2,2,3, 4, 5, 6, 6, 6}; unsigned int Bits; if (DDecode[1]==0) { int Dist=0,BitLength=0,Slot=0; for (unsigned int I=0;I<sizeof(DBitLengthCounts)/sizeof(DBitLengthCounts[0]);I++,BitLength++) for (unsigned int J=0;J<DBitLengthCounts[I];J++,Slot++,Dist+=(1<<BitLength)) { DDecode[Slot]=Dist; DBits[Slot]=BitLength; } } FileExtracted=true; if (!Suspended) { UnpInitData(Solid); if (!UnpReadBuf()) return; if (!TablesRead) if (!ReadTables()) return; // if (!TablesRead && Solid) // if (!ReadTables()) // return; //if ((!Solid || !TablesRead) && !ReadTables()) // return; } if (PPMError) return; while (true) { if (UnpIO->bQuit) { FileExtracted=false; return; } UnpPtr&=MAXWINMASK; if (InAddr>ReadBorder) { if (!UnpReadBuf()) break; } if (((WrPtr-UnpPtr) & MAXWINMASK)<260 && WrPtr!=UnpPtr) { UnpWriteBuf(); if (WrittenFileSize>DestUnpSize) return; if (Suspended) { FileExtracted=false; return; } } if (UnpBlockType==BLOCK_PPM) { int Ch=PPM.DecodeChar(); if (Ch==-1) { PPMError=true; break; } if (Ch==PPMEscChar) { int NextCh=PPM.DecodeChar(); if (NextCh==0) { if (!ReadTables()) break; continue; } if (NextCh==2 || NextCh==-1) break; if (NextCh==3) { if (!ReadVMCodePPM()) break; continue; } if (NextCh==4) { unsigned int Distance=0,Length=0; bool Failed=false; for (int I=0;I<4 && !Failed;I++) { int Ch=PPM.DecodeChar(); if (Ch==-1) Failed=true; else if (I==3) Length=(byte)Ch; else Distance=(Distance<<8)+(byte)Ch; } if (Failed) break; CopyString(Length+32,Distance+2); continue; } if (NextCh==5) { int Length=PPM.DecodeChar(); if (Length==-1) break; CopyString(Length+4,1); continue; } } Window[UnpPtr++]=Ch; continue; } int Number=DecodeNumber((struct Decode *)&LD); if (Number<256) { Window[UnpPtr++]=(byte)Number; continue; } if (Number>=271) { int Length=LDecode[Number-=271]+3; if ((Bits=LBits[Number])>0) { Length+=getbits()>>(16-Bits); addbits(Bits); } int DistNumber=DecodeNumber((struct Decode *)&DD); unsigned int Distance=DDecode[DistNumber]+1; if ((Bits=DBits[DistNumber])>0) { if (DistNumber>9) { if (Bits>4) { Distance+=((getbits()>>(20-Bits))<<4); addbits(Bits-4); } if (LowDistRepCount>0) { LowDistRepCount--; Distance+=PrevLowDist; } else { int LowDist=DecodeNumber((struct Decode *)&LDD); if (LowDist==16) { LowDistRepCount=LOW_DIST_REP_COUNT-1; Distance+=PrevLowDist; } else { Distance+=LowDist; PrevLowDist=LowDist; } } } else {
void Unpack::Unpack5(bool Solid) { FileExtracted=true; if (!Suspended) { UnpInitData(Solid); if (!UnpReadBuf()) return; if (!ReadBlockHeader(Inp,BlockHeader) || !ReadTables(Inp,BlockHeader,BlockTables)) return; } while (true) { UnpPtr&=MaxWinMask; if (Inp.InAddr>=ReadBorder) { bool FileDone=false; // We use 'while', because for empty block containing only Huffman table, // we'll be on the block border once again just after reading the table. while (Inp.InAddr>BlockHeader.BlockStart+BlockHeader.BlockSize-1 || Inp.InAddr==BlockHeader.BlockStart+BlockHeader.BlockSize-1 && Inp.InBit>=BlockHeader.BlockBitSize) { if (BlockHeader.LastBlockInFile) { FileDone=true; break; } if (!ReadBlockHeader(Inp,BlockHeader) || !ReadTables(Inp,BlockHeader,BlockTables)) return; } if (FileDone || !UnpReadBuf()) break; } if (((WriteBorder-UnpPtr) & MaxWinMask)<MAX_LZ_MATCH+3 && WriteBorder!=UnpPtr) { UnpWriteBuf(); if (WrittenFileSize>DestUnpSize) return; if (Suspended) { FileExtracted=false; return; } } uint MainSlot=DecodeNumber(Inp,&BlockTables.LD); if (MainSlot<256) { if (Fragmented) FragWindow[UnpPtr++]=(byte)MainSlot; else Window[UnpPtr++]=(byte)MainSlot; continue; } if (MainSlot>=262) { uint Length=SlotToLength(Inp,MainSlot-262); uint DBits,Distance=1,DistSlot=DecodeNumber(Inp,&BlockTables.DD); if (DistSlot<4) { DBits=0; Distance+=DistSlot; } else { DBits=DistSlot/2 - 1; Distance+=(2 | (DistSlot & 1)) << DBits; } if (DBits>0) { if (DBits>=4) { if (DBits>4) { Distance+=((Inp.getbits32()>>(36-DBits))<<4); Inp.addbits(DBits-4); } uint LowDist=DecodeNumber(Inp,&BlockTables.LDD); Distance+=LowDist; } else { Distance+=Inp.getbits32()>>(32-DBits); Inp.addbits(DBits); } }
void Unpack::Unpack5MT(bool Solid) { InitMT(); UnpInitData(Solid); for (uint I=0;I<MaxUserThreads*UNP_BLOCKS_PER_THREAD;I++) { UnpackThreadData *CurData=UnpThreadData+I; CurData->LargeBlock=false; CurData->Incomplete=false; } UnpThreadData[0].BlockHeader=BlockHeader; UnpThreadData[0].BlockTables=BlockTables; uint LastBlockNum=0; int DataSize=0; int BlockStart=0; // 'true' if we found a block too large for multithreaded extraction, // so we switched to single threaded mode until the end of file. // Large blocks could cause too high memory use in multithreaded mode. bool LargeBlock=false; bool Done=false; while (!Done) { int ReadSize=UnpIO->UnpRead(ReadBufMT+DataSize,(UNP_READ_SIZE_MT-DataSize)&~0xf); if (ReadSize<0) break; DataSize+=ReadSize; if (DataSize==0) break; bool BufferProcessed=false; while (BlockStart<DataSize && !Done) { // Data amount, which is guaranteed to fit block header and tables, // so we can safely read them without additional checks. const int TooSmallToProcess=1024; uint BlockNumber=0,BlockNumberMT=0; while (BlockNumber<MaxUserThreads*UNP_BLOCKS_PER_THREAD) { UnpackThreadData *CurData=UnpThreadData+BlockNumber; LastBlockNum=BlockNumber; CurData->UnpackPtr=this; // 'Incomplete' thread is present. This is a thread processing block // in the end of buffer, split between two read operations. if (CurData->Incomplete) CurData->DataSize=DataSize; else { CurData->Inp.SetExternalBuffer(ReadBufMT+BlockStart); CurData->Inp.InitBitInput(); CurData->DataSize=DataSize-BlockStart; if (CurData->DataSize==0) break; CurData->DamagedData=false; CurData->HeaderRead=false; CurData->TableRead=false; } // We should not use 'last block in file' block flag here unless // we'll check the block size, because even if block is last in file, // it can exceed the current buffer and require more reading. CurData->NoDataLeft=(ReadSize==0); CurData->Incomplete=false; CurData->ThreadNumber=BlockNumber; if (!CurData->HeaderRead) { CurData->HeaderRead=true; if (!ReadBlockHeader(CurData->Inp,CurData->BlockHeader)) { Done=true; break; } } // To prevent too high memory use we switch to single threaded mode // if block exceeds this size. Typically RAR blocks do not exceed // 64 KB, so this protection should not affect most of valid archives. const int LargeBlockSize=0x20000; if (LargeBlock || CurData->BlockHeader.BlockSize>LargeBlockSize) LargeBlock=CurData->LargeBlock=true; else BlockNumberMT++; // Number of normal blocks processed in MT mode. BlockStart+=CurData->BlockHeader.HeaderSize+CurData->BlockHeader.BlockSize; BlockNumber++; int DataLeft=DataSize-BlockStart; if (DataLeft>=0 && CurData->BlockHeader.LastBlockInFile) break; // For second and following threads we move smaller blocks to buffer // start to ensure that we have enough data to fit block header // and tables. if (DataLeft<TooSmallToProcess) break; } //#undef USE_THREADS UnpackThreadDataList UTDArray[MaxPoolThreads]; uint UTDArrayPos=0; uint MaxBlockPerThread=BlockNumberMT/MaxUserThreads; if (BlockNumberMT%MaxUserThreads!=0) MaxBlockPerThread++; // Decode all normal blocks until the first 'large' if any. for (uint CurBlock=0;CurBlock<BlockNumberMT;CurBlock+=MaxBlockPerThread) { UnpackThreadDataList *UTD=UTDArray+UTDArrayPos++; UTD->D=UnpThreadData+CurBlock; UTD->BlockCount=Min(MaxBlockPerThread,BlockNumberMT-CurBlock); #ifdef USE_THREADS if (BlockNumber==1) UnpackDecode(*UTD->D); else UnpThreadPool->AddTask(UnpackDecodeThread,(void*)UTD); #else for (uint I=0;I<UTD->BlockCount;I++) UnpackDecode(UTD->D[I]); #endif } if (BlockNumber==0) break; #ifdef USE_THREADS UnpThreadPool->WaitDone(); #endif bool IncompleteThread=false; for (uint Block=0;Block<BlockNumber;Block++) { UnpackThreadData *CurData=UnpThreadData+Block; if (!CurData->LargeBlock && !ProcessDecoded(*CurData) || CurData->LargeBlock && !UnpackLargeBlock(*CurData) || CurData->DamagedData) { Done=true; break; } if (CurData->Incomplete) { int BufPos=int(CurData->Inp.InBuf+CurData->Inp.InAddr-ReadBufMT); if (DataSize<=BufPos) // Thread exceeded input buffer boundary. { Done=true; break; } IncompleteThread=true; memmove(ReadBufMT,ReadBufMT+BufPos,DataSize-BufPos); CurData->BlockHeader.BlockSize-=CurData->Inp.InAddr-CurData->BlockHeader.BlockStart; CurData->BlockHeader.HeaderSize=0; CurData->BlockHeader.BlockStart=0; CurData->Inp.InBuf=ReadBufMT; CurData->Inp.InAddr=0; if (Block!=0) { // Move the incomplete thread entry to the first position, // so we'll start processing from it. Preserve the original // buffer for decoded data. UnpackDecodedItem *Decoded=UnpThreadData[0].Decoded; uint DecodedAllocated=UnpThreadData[0].DecodedAllocated; UnpThreadData[0]=*CurData; UnpThreadData[0].Decoded=Decoded; UnpThreadData[0].DecodedAllocated=DecodedAllocated; CurData->Incomplete=false; } BlockStart=0; DataSize-=BufPos; break; } else if (CurData->BlockHeader.LastBlockInFile) { Done=true; break; } } if (IncompleteThread || Done) break; // Current buffer is done, read more data or quit. else { int DataLeft=DataSize-BlockStart; if (DataLeft<TooSmallToProcess) { if (DataLeft<0) // Invalid data, must not happen in valid archive. { Done=true; break; } // If we do not have incomplete thread and have some data // in the end of buffer, too small for single thread, // let's move it to beginning of next buffer. if (DataLeft>0) memmove(ReadBufMT,ReadBufMT+BlockStart,DataLeft); DataSize=DataLeft; BlockStart=0; break; // Current buffer is done, try to read more data. } } } } UnpWriteBuf(); BlockHeader=UnpThreadData[LastBlockNum].BlockHeader; BlockTables=UnpThreadData[LastBlockNum].BlockTables; }
void Unpack::Unpack29(bool Solid) { // tables moved outside function unsigned int Bits; FileExtracted=true; if (!Suspended) { UnpInitData(Solid); if (!UnpReadBuf()) return; if ((!Solid || !TablesRead) && !ReadTables()) return; } while (true) { UnpPtr&=MAXWINMASK; if (InAddr>ReadBorder) { if (!UnpReadBuf()) break; } if (((WrPtr-UnpPtr) & MAXWINMASK)<260 && WrPtr!=UnpPtr) { UnpWriteBuf(); if (WrittenFileSize>DestUnpSize) return; if (Suspended) { FileExtracted=false; return; } } if (UnpBlockType==BLOCK_PPM) { int Ch=PPM.DecodeChar(); if (Ch==-1) { PPM.CleanUp(); // turn off PPM compression mode in case of error, so UnRAR will // call PPM.DecodeInit in case it needs to turn it on back later. UnpBlockType=BLOCK_LZ; break; } if (Ch==PPMEscChar) { int NextCh=PPM.DecodeChar(); if (NextCh==0) { if (!ReadTables()) break; continue; } if (NextCh==2 || NextCh==-1) break; if (NextCh==3) { if (!ReadVMCodePPM()) break; continue; } if (NextCh==4) { unsigned int Distance=0,Length; Length = 0; // avoids warning bool Failed=false; for (int I=0;I<4 && !Failed;I++) { int Ch=PPM.DecodeChar(); if (Ch==-1) Failed=true; else if (I==3) Length=(byte)Ch; else Distance=(Distance<<8)+(byte)Ch; } if (Failed) break; #ifdef _MSC_VER // avoid a warning about uninitialized 'Length' variable #pragma warning( disable : 4701 ) #endif CopyString(Length+32,Distance+2); continue; } if (NextCh==5) { int Length=PPM.DecodeChar(); if (Length==-1) break; CopyString(Length+4,1); continue; } } Window[UnpPtr++]=Ch; continue; } int Number=DecodeNumber((struct Decode *)&LD); if (Number<256) { Window[UnpPtr++]=(byte)Number; continue; } if (Number>=271) { int Length=LDecode[Number-=271]+3; if ((Bits=LBits[Number])>0) { Length+=getbits()>>(16-Bits); addbits(Bits); } int DistNumber=DecodeNumber((struct Decode *)&DD); unsigned int Distance=DDecode[DistNumber]+1; if ((Bits=DBits[DistNumber])>0) { if (DistNumber>9) { if (Bits>4) { Distance+=((getbits()>>(20-Bits))<<4); addbits(Bits-4); } if (LowDistRepCount>0) { LowDistRepCount--; Distance+=PrevLowDist; } else { int LowDist=DecodeNumber((struct Decode *)&LDD); if (LowDist==16) { LowDistRepCount=LOW_DIST_REP_COUNT-1; Distance+=PrevLowDist; } else { Distance+=LowDist; PrevLowDist=LowDist; } } } else {
void Unpack::Unpack29(bool Solid) { static unsigned char LDecode[]={0,1,2,3,4,5,6,7,8,10,12,14,16,20,24,28,32,40,48,56,64,80,96,112,128,160,192,224}; static unsigned char LBits[]= {0,0,0,0,0,0,0,0,1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5}; static int DDecode[DC]; static byte DBits[DC]; static int DBitLengthCounts[]= {4,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,14,0,12}; static unsigned char SDDecode[]={0,4,8,16,32,64,128,192}; static unsigned char SDBits[]= {2,2,3, 4, 5, 6, 6, 6}; unsigned int Bits; if (DDecode[1]==0) { int Dist=0,BitLength=0,Slot=0; for (int I=0;I<sizeof(DBitLengthCounts)/sizeof(DBitLengthCounts[0]);I++,BitLength++) for (int J=0;J<DBitLengthCounts[I];J++,Slot++,Dist+=(1<<BitLength)) { DDecode[Slot]=Dist; DBits[Slot]=BitLength; } } FileExtracted=true; if (!Suspended) { UnpInitData(Solid); if (!UnpReadBuf()) return; if ((!Solid || !TablesRead) && !ReadTables()) return; } while (true) { UnpPtr&=MAXWINMASK; if (InAddr>ReadBorder) { if (!UnpReadBuf()) break; } if (((WrPtr-UnpPtr) & MAXWINMASK)<260 && WrPtr!=UnpPtr) { UnpWriteBuf(); if (WrittenFileSize>DestUnpSize) return; if (Suspended) { FileExtracted=false; return; } } if (UnpBlockType==BLOCK_PPM) { // Here speed is critical, so we do not use SafePPMDecodeChar, // because sometimes even the inline function can introduce // some additional penalty. int Ch=PPM.DecodeChar(); if (Ch==-1) // Corrupt PPM data found. { PPM.CleanUp(); // Reset possibly corrupt PPM data structures. UnpBlockType=BLOCK_LZ; // Set faster and more fail proof LZ mode. break; } if (Ch==PPMEscChar) { int NextCh=SafePPMDecodeChar(); if (NextCh==0) // End of PPM encoding. { if (!ReadTables()) break; continue; } if (NextCh==-1) // Corrupt PPM data found. break; if (NextCh==2) // End of file in PPM mode.. break; if (NextCh==3) // Read VM code. { if (!ReadVMCodePPM()) break; continue; } if (NextCh==4) // LZ inside of PPM. { unsigned int Distance=0,Length; bool Failed=false; for (int I=0;I<4 && !Failed;I++) { int Ch=SafePPMDecodeChar(); if (Ch==-1) Failed=true; else if (I==3) Length=(byte)Ch; else Distance=(Distance<<8)+(byte)Ch; } if (Failed) break; CopyString(Length+32,Distance+2); continue; } if (NextCh==5) // One byte distance match (RLE) inside of PPM. { int Length=SafePPMDecodeChar(); if (Length==-1) break; CopyString(Length+4,1); continue; } // If we are here, NextCh must be 1, what means that current byte // is equal to our 'escape' byte, so we just store it to Window. } Window[UnpPtr++]=Ch; continue; } int Number=DecodeNumber((struct Decode *)&LD); if (Number<256) { Window[UnpPtr++]=(byte)Number; continue; } if (Number>=271) { int Length=LDecode[Number-=271]+3; if ((Bits=LBits[Number])>0) { Length+=getbits()>>(16-Bits); addbits(Bits); } int DistNumber=DecodeNumber((struct Decode *)&DD); unsigned int Distance=DDecode[DistNumber]+1; if ((Bits=DBits[DistNumber])>0) { if (DistNumber>9) { if (Bits>4) { Distance+=((getbits()>>(20-Bits))<<4); addbits(Bits-4); } if (LowDistRepCount>0) { LowDistRepCount--; Distance+=PrevLowDist; } else { int LowDist=DecodeNumber((struct Decode *)&LDD); if (LowDist==16) { LowDistRepCount=LOW_DIST_REP_COUNT-1; Distance+=PrevLowDist; } else { Distance+=LowDist; PrevLowDist=LowDist; } } } else {