HRESULT CDecoder::CodeSpec(UInt32 curSize) { if (_remainLen == kLenIdNeedInit) { _remainLen = 0; m_InBitStream.Init(); if (!_keepHistory || !m_IsUncompressedBlock) m_InBitStream.Normalize(); if (!_keepHistory) { _skipByte = false; m_UnCompressedBlockSize = 0; ClearPrevLevels(); UInt32 i86TranslationSize = 12000000; bool translationMode = true; if (!_wimMode) { translationMode = (ReadBits(1) != 0); if (translationMode) { i86TranslationSize = ReadBits(16) << 16; i86TranslationSize |= ReadBits(16); } } m_x86ConvertOutStreamSpec->Init(translationMode, i86TranslationSize); for (unsigned i = 0 ; i < kNumRepDistances; i++) m_RepDistances[i] = 0; } } while (_remainLen > 0 && curSize > 0) { m_OutWindowStream.PutByte(m_OutWindowStream.GetByte(m_RepDistances[0])); _remainLen--; curSize--; } while (curSize > 0) { if (m_UnCompressedBlockSize == 0) if (!ReadTables()) return S_FALSE; UInt32 next = (Int32)MyMin(m_UnCompressedBlockSize, curSize); curSize -= next; m_UnCompressedBlockSize -= next; if (m_IsUncompressedBlock) { while (next > 0) { m_OutWindowStream.PutByte(m_InBitStream.DirectReadByte()); next--; } } else while (next > 0) { UInt32 number = m_MainDecoder.DecodeSymbol(&m_InBitStream); if (number < 256) { m_OutWindowStream.PutByte((Byte)number); next--; } else { UInt32 posLenSlot = number - 256; if (posLenSlot >= m_NumPosLenSlots) return S_FALSE; UInt32 posSlot = posLenSlot / kNumLenSlots; UInt32 lenSlot = posLenSlot % kNumLenSlots; UInt32 len = kMatchMinLen + lenSlot; if (lenSlot == kNumLenSlots - 1) { UInt32 lenTemp = m_LenDecoder.DecodeSymbol(&m_InBitStream); if (lenTemp >= kNumLenSymbols) return S_FALSE; len += lenTemp; } if (posSlot < kNumRepDistances) { UInt32 distance = m_RepDistances[posSlot]; m_RepDistances[posSlot] = m_RepDistances[0]; m_RepDistances[0] = distance; } else { UInt32 distance; unsigned numDirectBits; if (posSlot < kNumPowerPosSlots) { numDirectBits = (unsigned)(posSlot >> 1) - 1; distance = ((2 | (posSlot & 1)) << numDirectBits); } else { numDirectBits = kNumLinearPosSlotBits; distance = ((posSlot - 0x22) << kNumLinearPosSlotBits); } if (m_AlignIsUsed && numDirectBits >= kNumAlignBits) { distance += (m_InBitStream.ReadBits(numDirectBits - kNumAlignBits) << kNumAlignBits); UInt32 alignTemp = m_AlignDecoder.DecodeSymbol(&m_InBitStream); if (alignTemp >= kAlignTableSize) return S_FALSE; distance += alignTemp; } else distance += m_InBitStream.ReadBits(numDirectBits); m_RepDistances[2] = m_RepDistances[1]; m_RepDistances[1] = m_RepDistances[0]; m_RepDistances[0] = distance - kNumRepDistances; } UInt32 locLen = len; if (locLen > next) locLen = next; if (!m_OutWindowStream.CopyBlock(m_RepDistances[0], locLen)) return S_FALSE; len -= locLen; next -= locLen; if (len != 0) { _remainLen = (int)len; return S_OK; } } }
HRESULT CCoder::CodeReal(ISequentialInStream *inStream, ISequentialOutStream *outStream, const UInt64 * /* inSize */, const UInt64 *outSize, ICompressProgressInfo *progress) { if (!m_InBitStream.Create(1 << 20)) return E_OUTOFMEMORY; if (!m_OutWindowStream.Create(kHistorySize)) return E_OUTOFMEMORY; if (outSize == NULL) return E_INVALIDARG; UInt64 pos = 0, unPackSize = *outSize; m_OutWindowStream.SetStream(outStream); m_OutWindowStream.Init(false); m_InBitStream.SetStream(inStream); m_InBitStream.Init(); // CCoderReleaser coderReleaser(this); if (!ReadTables()) return S_FALSE; while (pos < unPackSize) { if (progress != NULL && pos % (1 << 16) == 0) { UInt64 packSize = m_InBitStream.GetProcessedSize(); RINOK(progress->SetRatioInfo(&packSize, &pos)); } if (m_InBitStream.ReadBits(1) == kMatchId) // match { UInt32 lowDistBits = m_InBitStream.ReadBits(m_NumDistanceLowDirectBits); UInt32 distance = m_DistanceDecoder.DecodeSymbol(&m_InBitStream); if (distance >= kDistanceTableSize) return S_FALSE; distance = (distance << m_NumDistanceLowDirectBits) + lowDistBits; UInt32 lengthSymbol = m_LengthDecoder.DecodeSymbol(&m_InBitStream); if (lengthSymbol >= kLengthTableSize) return S_FALSE; UInt32 length = lengthSymbol + m_MinMatchLength; if (lengthSymbol == kLengthTableSize - 1) // special symbol = 63 length += m_InBitStream.ReadBits(kNumAdditionalLengthBits); while (distance >= pos && length > 0) { m_OutWindowStream.PutByte(0); pos++; length--; } if (length > 0) m_OutWindowStream.CopyBlock(distance, length); pos += length; } else { Byte b; if (m_LiteralsOn) { UInt32 temp = m_LiteralDecoder.DecodeSymbol(&m_InBitStream); if (temp >= kLiteralTableSize) return S_FALSE; b = (Byte)temp; } else b = (Byte)m_InBitStream.ReadBits(kNumBitsInByte); m_OutWindowStream.PutByte(b); pos++; } } if (pos > unPackSize) return S_FALSE; return m_OutWindowStream.Flush(); }
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::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 {
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; } if (PPMError) 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) { 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; 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::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 {
// Decode Huffman block and save decoded data to memory. void Unpack::UnpackDecode(UnpackThreadData &D) { if (!D.TableRead) { D.TableRead=true; if (!ReadTables(D.Inp,D.BlockHeader,D.BlockTables)) { D.DamagedData=true; return; } } if (D.Inp.InAddr>D.BlockHeader.HeaderSize+D.BlockHeader.BlockSize) { D.DamagedData=true; return; } D.DecodedSize=0; int BlockBorder=D.BlockHeader.BlockStart+D.BlockHeader.BlockSize-1; // Reserve enough space even for filter entry. int DataBorder=D.DataSize-16; int ReadBorder=Min(BlockBorder,DataBorder); while (true) { if (D.Inp.InAddr>=ReadBorder) { if (D.Inp.InAddr>BlockBorder || D.Inp.InAddr==BlockBorder && D.Inp.InBit>=D.BlockHeader.BlockBitSize) break; // If we do not have any more data in file to read, we must process // what we have until last byte. Otherwise we can return and append // more data to unprocessed few bytes. if ((D.Inp.InAddr>=DataBorder) && !D.NoDataLeft || D.Inp.InAddr>=D.DataSize) { D.Incomplete=true; break; } } if (D.DecodedSize>D.DecodedAllocated-8) // Filter can use several slots. { D.DecodedAllocated=D.DecodedAllocated*2; D.Decoded=(UnpackDecodedItem *)realloc(D.Decoded,D.DecodedAllocated*sizeof(UnpackDecodedItem)); if (D.Decoded==NULL) ErrHandler.MemoryError(); } UnpackDecodedItem *CurItem=D.Decoded+D.DecodedSize++; uint MainSlot=DecodeNumber(D.Inp,&D.BlockTables.LD); if (MainSlot<256) { if (D.DecodedSize>1) { UnpackDecodedItem *PrevItem=CurItem-1; if (PrevItem->Type==UNPDT_LITERAL && PrevItem->Length<3) { PrevItem->Length++; PrevItem->Literal[PrevItem->Length]=(byte)MainSlot; D.DecodedSize--; continue; } } CurItem->Type=UNPDT_LITERAL; CurItem->Literal[0]=(byte)MainSlot; CurItem->Length=0; continue; } if (MainSlot>=262) { uint Length=SlotToLength(D.Inp,MainSlot-262); uint DBits,Distance=1,DistSlot=DecodeNumber(D.Inp,&D.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+=((D.Inp.getbits32()>>(36-DBits))<<4); D.Inp.addbits(DBits-4); } uint LowDist=DecodeNumber(D.Inp,&D.BlockTables.LDD); Distance+=LowDist; } else { Distance+=D.Inp.getbits32()>>(32-DBits); D.Inp.addbits(DBits); } }