| namespace third_party_unrar { |
| |
| // We use it instead of direct PPM.DecodeChar call to be sure that |
| // we reset PPM structures in case of corrupt data. It is important, |
| // because these structures can be invalid after PPM.DecodeChar returned -1. |
| inline int Unpack::SafePPMDecodeChar() |
| { |
| 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. |
| } |
| return(Ch); |
| } |
| |
| |
| 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<ASIZE(DBitLengthCounts);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 (!UnpReadBuf30()) |
| return; |
| if ((!Solid || !TablesRead3) && !ReadTables30()) |
| return; |
| } |
| |
| while (true) |
| { |
| UnpPtr&=MaxWinMask; |
| |
| if (Inp.InAddr>ReadBorder) |
| { |
| if (!UnpReadBuf30()) |
| break; |
| } |
| if (((WrPtr-UnpPtr) & MaxWinMask)<260 && WrPtr!=UnpPtr) |
| { |
| UnpWriteBuf30(); |
| 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 (!ReadTables30()) |
| 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; |
| } |
| |
| uint Number=DecodeNumber(Inp,&BlockTables.LD); |
| if (Number<256) |
| { |
| Window[UnpPtr++]=(byte)Number; |
| continue; |
| } |
| if (Number>=271) |
| { |
| uint Length=LDecode[Number-=271]+3; |
| if ((Bits=LBits[Number])>0) |
| { |
| Length+=Inp.getbits()>>(16-Bits); |
| Inp.addbits(Bits); |
| } |
| |
| uint DistNumber=DecodeNumber(Inp,&BlockTables.DD); |
| uint Distance=DDecode[DistNumber]+1; |
| if ((Bits=DBits[DistNumber])>0) |
| { |
| if (DistNumber>9) |
| { |
| if (Bits>4) |
| { |
| Distance+=((Inp.getbits()>>(20-Bits))<<4); |
| Inp.addbits(Bits-4); |
| } |
| if (LowDistRepCount>0) |
| { |
| LowDistRepCount--; |
| Distance+=PrevLowDist; |
| } |
| else |
| { |
| uint LowDist=DecodeNumber(Inp,&BlockTables.LDD); |
| if (LowDist==16) |
| { |
| LowDistRepCount=LOW_DIST_REP_COUNT-1; |
| Distance+=PrevLowDist; |
| } |
| else |
| { |
| Distance+=LowDist; |
| PrevLowDist=LowDist; |
| } |
| } |
| } |
| else |
| { |
| Distance+=Inp.getbits()>>(16-Bits); |
| Inp.addbits(Bits); |
| } |
| } |
| |
| if (Distance>=0x2000) |
| { |
| Length++; |
| if (Distance>=0x40000) |
| Length++; |
| } |
| |
| InsertOldDist(Distance); |
| LastLength=Length; |
| CopyString(Length,Distance); |
| continue; |
| } |
| if (Number==256) |
| { |
| if (!ReadEndOfBlock()) |
| break; |
| continue; |
| } |
| if (Number==257) |
| { |
| if (!ReadVMCode()) |
| break; |
| continue; |
| } |
| if (Number==258) |
| { |
| if (LastLength!=0) |
| CopyString(LastLength,OldDist[0]); |
| continue; |
| } |
| if (Number<263) |
| { |
| uint DistNum=Number-259; |
| uint Distance=OldDist[DistNum]; |
| for (uint I=DistNum;I>0;I--) |
| OldDist[I]=OldDist[I-1]; |
| OldDist[0]=Distance; |
| |
| uint LengthNumber=DecodeNumber(Inp,&BlockTables.RD); |
| int Length=LDecode[LengthNumber]+2; |
| if ((Bits=LBits[LengthNumber])>0) |
| { |
| Length+=Inp.getbits()>>(16-Bits); |
| Inp.addbits(Bits); |
| } |
| LastLength=Length; |
| CopyString(Length,Distance); |
| continue; |
| } |
| if (Number<272) |
| { |
| uint Distance=SDDecode[Number-=263]+1; |
| if ((Bits=SDBits[Number])>0) |
| { |
| Distance+=Inp.getbits()>>(16-Bits); |
| Inp.addbits(Bits); |
| } |
| InsertOldDist(Distance); |
| LastLength=2; |
| CopyString(2,Distance); |
| continue; |
| } |
| } |
| UnpWriteBuf30(); |
| } |
| |
| |
| // Return 'false' to quit unpacking the current file or 'true' to continue. |
| bool Unpack::ReadEndOfBlock() |
| { |
| uint BitField=Inp.getbits(); |
| bool NewTable,NewFile=false; |
| |
| // "1" - no new file, new table just here. |
| // "00" - new file, no new table. |
| // "01" - new file, new table (in beginning of next file). |
| |
| if ((BitField & 0x8000)!=0) |
| { |
| NewTable=true; |
| Inp.addbits(1); |
| } |
| else |
| { |
| NewFile=true; |
| NewTable=(BitField & 0x4000)!=0; |
| Inp.addbits(2); |
| } |
| TablesRead3=!NewTable; |
| |
| // Quit immediately if "new file" flag is set. If "new table" flag |
| // is present, we'll read the table in beginning of next file |
| // based on 'TablesRead3' 'false' value. |
| if (NewFile) |
| return false; |
| return ReadTables30(); // Quit only if we failed to read tables. |
| } |
| |
| |
| bool Unpack::ReadVMCode() |
| { |
| // Entire VM code is guaranteed to fully present in block defined |
| // by current Huffman table. Compressor checks that VM code does not cross |
| // Huffman block boundaries. |
| uint FirstByte=Inp.getbits()>>8; |
| Inp.addbits(8); |
| uint Length=(FirstByte & 7)+1; |
| if (Length==7) |
| { |
| Length=(Inp.getbits()>>8)+7; |
| Inp.addbits(8); |
| } |
| else |
| if (Length==8) |
| { |
| Length=Inp.getbits(); |
| Inp.addbits(16); |
| } |
| if (Length==0) |
| return false; |
| Array<byte> VMCode(Length); |
| for (uint I=0;I<Length;I++) |
| { |
| // Try to read the new buffer if only one byte is left. |
| // But if we read all bytes except the last, one byte is enough. |
| if (Inp.InAddr>=ReadTop-1 && !UnpReadBuf30() && I<Length-1) |
| return false; |
| VMCode[I]=Inp.getbits()>>8; |
| Inp.addbits(8); |
| } |
| return AddVMCode(FirstByte,&VMCode[0],Length); |
| } |
| |
| |
| bool Unpack::ReadVMCodePPM() |
| { |
| uint FirstByte=SafePPMDecodeChar(); |
| if ((int)FirstByte==-1) |
| return false; |
| uint Length=(FirstByte & 7)+1; |
| if (Length==7) |
| { |
| int B1=SafePPMDecodeChar(); |
| if (B1==-1) |
| return false; |
| Length=B1+7; |
| } |
| else |
| if (Length==8) |
| { |
| int B1=SafePPMDecodeChar(); |
| if (B1==-1) |
| return false; |
| int B2=SafePPMDecodeChar(); |
| if (B2==-1) |
| return false; |
| Length=B1*256+B2; |
| } |
| if (Length==0) |
| return false; |
| Array<byte> VMCode(Length); |
| for (uint I=0;I<Length;I++) |
| { |
| int Ch=SafePPMDecodeChar(); |
| if (Ch==-1) |
| return false; |
| VMCode[I]=Ch; |
| } |
| return AddVMCode(FirstByte,&VMCode[0],Length); |
| } |
| |
| |
| bool Unpack::AddVMCode(uint FirstByte,byte *Code,uint CodeSize) |
| { |
| VMCodeInp.InitBitInput(); |
| memcpy(VMCodeInp.InBuf,Code,Min(BitInput::MAX_SIZE,CodeSize)); |
| VM.Init(); |
| |
| uint FiltPos; |
| if ((FirstByte & 0x80)!=0) |
| { |
| FiltPos=RarVM::ReadData(VMCodeInp); |
| if (FiltPos==0) |
| InitFilters30(false); |
| else |
| FiltPos--; |
| } |
| else |
| FiltPos=LastFilter; // Use the same filter as last time. |
| |
| if (FiltPos>Filters30.Size() || FiltPos>OldFilterLengths.Size()) |
| return false; |
| LastFilter=FiltPos; |
| bool NewFilter=(FiltPos==Filters30.Size()); |
| |
| UnpackFilter30 *StackFilter=new UnpackFilter30; // New filter for PrgStack. |
| |
| UnpackFilter30 *Filter; |
| if (NewFilter) // New filter code, never used before since VM reset. |
| { |
| if (FiltPos>MAX3_UNPACK_FILTERS) |
| { |
| // Too many different filters, corrupt archive. |
| delete StackFilter; |
| return false; |
| } |
| |
| Filters30.Add(1); |
| Filters30[Filters30.Size()-1]=Filter=new UnpackFilter30; |
| StackFilter->ParentFilter=(uint)(Filters30.Size()-1); |
| |
| // Reserve one item to store the data block length of our new filter |
| // entry. We'll set it to real block length below, after reading it. |
| // But we need to initialize it now, because when processing corrupt |
| // data, we can access this item even before we set it to real value. |
| OldFilterLengths.Push(0); |
| } |
| else // Filter was used in the past. |
| { |
| Filter=Filters30[FiltPos]; |
| StackFilter->ParentFilter=FiltPos; |
| } |
| |
| uint EmptyCount=0; |
| for (uint I=0;I<PrgStack.Size();I++) |
| { |
| PrgStack[I-EmptyCount]=PrgStack[I]; |
| if (PrgStack[I]==NULL) |
| EmptyCount++; |
| if (EmptyCount>0) |
| PrgStack[I]=NULL; |
| } |
| if (EmptyCount==0) |
| { |
| if (PrgStack.Size()>MAX3_UNPACK_FILTERS) |
| { |
| delete StackFilter; |
| return false; |
| } |
| PrgStack.Add(1); |
| EmptyCount=1; |
| } |
| size_t StackPos=PrgStack.Size()-EmptyCount; |
| PrgStack[StackPos]=StackFilter; |
| |
| uint BlockStart=RarVM::ReadData(VMCodeInp); |
| if ((FirstByte & 0x40)!=0) |
| BlockStart+=258; |
| StackFilter->BlockStart=(uint)((BlockStart+UnpPtr)&MaxWinMask); |
| if ((FirstByte & 0x20)!=0) |
| { |
| StackFilter->BlockLength=RarVM::ReadData(VMCodeInp); |
| |
| // Store the last data block length for current filter. |
| OldFilterLengths[FiltPos]=StackFilter->BlockLength; |
| } |
| else |
| { |
| // Set the data block size to same value as the previous block size |
| // for same filter. It is possible for corrupt data to access a new |
| // and not filled yet item of OldFilterLengths array here. This is why |
| // we set new OldFilterLengths items to zero above. |
| StackFilter->BlockLength=FiltPos<OldFilterLengths.Size() ? OldFilterLengths[FiltPos]:0; |
| } |
| |
| StackFilter->NextWindow=WrPtr!=UnpPtr && ((WrPtr-UnpPtr)&MaxWinMask)<=BlockStart; |
| |
| // DebugLog("\nNextWindow: UnpPtr=%08x WrPtr=%08x BlockStart=%08x",UnpPtr,WrPtr,BlockStart); |
| |
| memset(StackFilter->Prg.InitR,0,sizeof(StackFilter->Prg.InitR)); |
| StackFilter->Prg.InitR[4]=StackFilter->BlockLength; |
| |
| if ((FirstByte & 0x10)!=0) // Set registers to optional parameters if any. |
| { |
| uint InitMask=VMCodeInp.fgetbits()>>9; |
| VMCodeInp.faddbits(7); |
| for (uint I=0;I<7;I++) |
| if (InitMask & (1<<I)) |
| StackFilter->Prg.InitR[I]=RarVM::ReadData(VMCodeInp); |
| } |
| |
| if (NewFilter) |
| { |
| uint VMCodeSize=RarVM::ReadData(VMCodeInp); |
| if (VMCodeSize>=0x10000 || VMCodeSize==0 || VMCodeInp.InAddr+VMCodeSize>CodeSize) |
| return false; |
| Array<byte> VMCode(VMCodeSize); |
| for (uint I=0;I<VMCodeSize;I++) |
| { |
| if (VMCodeInp.Overflow(3)) |
| return false; |
| VMCode[I]=VMCodeInp.fgetbits()>>8; |
| VMCodeInp.faddbits(8); |
| } |
| VM.Prepare(&VMCode[0],VMCodeSize,&Filter->Prg); |
| } |
| StackFilter->Prg.Type=Filter->Prg.Type; |
| |
| return true; |
| } |
| |
| |
| bool Unpack::UnpReadBuf30() |
| { |
| int DataSize=ReadTop-Inp.InAddr; // Data left to process. |
| if (DataSize<0) |
| return false; |
| if (Inp.InAddr>BitInput::MAX_SIZE/2) |
| { |
| // If we already processed more than half of buffer, let's move |
| // remaining data into beginning to free more space for new data |
| // and ensure that calling function does not cross the buffer border |
| // even if we did not read anything here. Also it ensures that read size |
| // is not less than CRYPT_BLOCK_SIZE, so we can align it without risk |
| // to make it zero. |
| if (DataSize>0) |
| memmove(Inp.InBuf,Inp.InBuf+Inp.InAddr,DataSize); |
| Inp.InAddr=0; |
| ReadTop=DataSize; |
| } |
| else |
| DataSize=ReadTop; |
| int ReadCode=UnpIO->UnpRead(Inp.InBuf+DataSize,BitInput::MAX_SIZE-DataSize); |
| if (ReadCode>0) |
| ReadTop+=ReadCode; |
| ReadBorder=ReadTop-30; |
| return ReadCode!=-1; |
| } |
| |
| |
| void Unpack::UnpWriteBuf30() |
| { |
| uint WrittenBorder=(uint)WrPtr; |
| uint WriteSize=(uint)((UnpPtr-WrittenBorder)&MaxWinMask); |
| for (size_t I=0;I<PrgStack.Size();I++) |
| { |
| // Here we apply filters to data which we need to write. |
| // We always copy data to virtual machine memory before processing. |
| // We cannot process them just in place in Window buffer, because |
| // these data can be used for future string matches, so we must |
| // preserve them in original form. |
| |
| UnpackFilter30 *flt=PrgStack[I]; |
| if (flt==NULL) |
| continue; |
| if (flt->NextWindow) |
| { |
| flt->NextWindow=false; |
| continue; |
| } |
| unsigned int BlockStart=flt->BlockStart; |
| unsigned int BlockLength=flt->BlockLength; |
| if (((BlockStart-WrittenBorder)&MaxWinMask)<WriteSize) |
| { |
| if (WrittenBorder!=BlockStart) |
| { |
| UnpWriteArea(WrittenBorder,BlockStart); |
| WrittenBorder=BlockStart; |
| WriteSize=(uint)((UnpPtr-WrittenBorder)&MaxWinMask); |
| } |
| if (BlockLength<=WriteSize) |
| { |
| uint BlockEnd=(BlockStart+BlockLength)&MaxWinMask; |
| if (BlockStart<BlockEnd || BlockEnd==0) |
| VM.SetMemory(0,Window+BlockStart,BlockLength); |
| else |
| { |
| uint FirstPartLength=uint(MaxWinSize-BlockStart); |
| VM.SetMemory(0,Window+BlockStart,FirstPartLength); |
| VM.SetMemory(FirstPartLength,Window,BlockEnd); |
| } |
| |
| VM_PreparedProgram *ParentPrg=&Filters30[flt->ParentFilter]->Prg; |
| VM_PreparedProgram *Prg=&flt->Prg; |
| |
| ExecuteCode(Prg); |
| |
| byte *FilteredData=Prg->FilteredData; |
| unsigned int FilteredDataSize=Prg->FilteredDataSize; |
| |
| delete PrgStack[I]; |
| PrgStack[I]=NULL; |
| while (I+1<PrgStack.Size()) |
| { |
| UnpackFilter30 *NextFilter=PrgStack[I+1]; |
| // It is required to check NextWindow here. |
| if (NextFilter==NULL || NextFilter->BlockStart!=BlockStart || |
| NextFilter->BlockLength!=FilteredDataSize || NextFilter->NextWindow) |
| break; |
| |
| // Apply several filters to same data block. |
| |
| VM.SetMemory(0,FilteredData,FilteredDataSize); |
| |
| VM_PreparedProgram *ParentPrg=&Filters30[NextFilter->ParentFilter]->Prg; |
| VM_PreparedProgram *NextPrg=&NextFilter->Prg; |
| |
| ExecuteCode(NextPrg); |
| |
| FilteredData=NextPrg->FilteredData; |
| FilteredDataSize=NextPrg->FilteredDataSize; |
| I++; |
| delete PrgStack[I]; |
| PrgStack[I]=NULL; |
| } |
| UnpIO->UnpWrite(FilteredData,FilteredDataSize); |
| UnpSomeRead=true; |
| WrittenFileSize+=FilteredDataSize; |
| WrittenBorder=BlockEnd; |
| WriteSize=uint((UnpPtr-WrittenBorder)&MaxWinMask); |
| } |
| else |
| { |
| // Current filter intersects the window write border, so we adjust |
| // the window border to process this filter next time, not now. |
| for (size_t J=I;J<PrgStack.Size();J++) |
| { |
| UnpackFilter30 *flt=PrgStack[J]; |
| if (flt!=NULL && flt->NextWindow) |
| flt->NextWindow=false; |
| } |
| WrPtr=WrittenBorder; |
| return; |
| } |
| } |
| } |
| |
| UnpWriteArea(WrittenBorder,UnpPtr); |
| WrPtr=UnpPtr; |
| } |
| |
| |
| void Unpack::ExecuteCode(VM_PreparedProgram *Prg) |
| { |
| Prg->InitR[6]=(uint)WrittenFileSize; |
| VM.Execute(Prg); |
| } |
| |
| |
| bool Unpack::ReadTables30() |
| { |
| byte BitLength[BC]; |
| byte Table[HUFF_TABLE_SIZE30]; |
| if (Inp.InAddr>ReadTop-25) |
| if (!UnpReadBuf30()) |
| return(false); |
| Inp.faddbits((8-Inp.InBit)&7); |
| uint BitField=Inp.fgetbits(); |
| if (BitField & 0x8000) |
| { |
| UnpBlockType=BLOCK_PPM; |
| return(PPM.DecodeInit(this,PPMEscChar)); |
| } |
| UnpBlockType=BLOCK_LZ; |
| |
| PrevLowDist=0; |
| LowDistRepCount=0; |
| |
| if (!(BitField & 0x4000)) |
| memset(UnpOldTable,0,sizeof(UnpOldTable)); |
| Inp.faddbits(2); |
| |
| for (uint I=0;I<BC;I++) |
| { |
| uint Length=(byte)(Inp.fgetbits() >> 12); |
| Inp.faddbits(4); |
| if (Length==15) |
| { |
| uint ZeroCount=(byte)(Inp.fgetbits() >> 12); |
| Inp.faddbits(4); |
| if (ZeroCount==0) |
| BitLength[I]=15; |
| else |
| { |
| ZeroCount+=2; |
| while (ZeroCount-- > 0 && I<ASIZE(BitLength)) |
| BitLength[I++]=0; |
| I--; |
| } |
| } |
| else |
| BitLength[I]=Length; |
| } |
| MakeDecodeTables(BitLength,&BlockTables.BD,BC30); |
| |
| const uint TableSize=HUFF_TABLE_SIZE30; |
| for (uint I=0;I<TableSize;) |
| { |
| if (Inp.InAddr>ReadTop-5) |
| if (!UnpReadBuf30()) |
| return(false); |
| uint Number=DecodeNumber(Inp,&BlockTables.BD); |
| if (Number<16) |
| { |
| Table[I]=(Number+UnpOldTable[I]) & 0xf; |
| I++; |
| } |
| else |
| if (Number<18) |
| { |
| uint N; |
| if (Number==16) |
| { |
| N=(Inp.fgetbits() >> 13)+3; |
| Inp.faddbits(3); |
| } |
| else |
| { |
| N=(Inp.fgetbits() >> 9)+11; |
| Inp.faddbits(7); |
| } |
| if (I==0) |
| return false; // We cannot have "repeat previous" code at the first position. |
| else |
| while (N-- > 0 && I<TableSize) |
| { |
| Table[I]=Table[I-1]; |
| I++; |
| } |
| } |
| else |
| { |
| uint N; |
| if (Number==18) |
| { |
| N=(Inp.fgetbits() >> 13)+3; |
| Inp.faddbits(3); |
| } |
| else |
| { |
| N=(Inp.fgetbits() >> 9)+11; |
| Inp.faddbits(7); |
| } |
| while (N-- > 0 && I<TableSize) |
| Table[I++]=0; |
| } |
| } |
| TablesRead3=true; |
| if (Inp.InAddr>ReadTop) |
| return false; |
| MakeDecodeTables(&Table[0],&BlockTables.LD,NC30); |
| MakeDecodeTables(&Table[NC30],&BlockTables.DD,DC30); |
| MakeDecodeTables(&Table[NC30+DC30],&BlockTables.LDD,LDC30); |
| MakeDecodeTables(&Table[NC30+DC30+LDC30],&BlockTables.RD,RC30); |
| memcpy(UnpOldTable,Table,sizeof(UnpOldTable)); |
| return true; |
| } |
| |
| |
| void Unpack::UnpInitData30(bool Solid) |
| { |
| if (!Solid) |
| { |
| TablesRead3=false; |
| memset(UnpOldTable,0,sizeof(UnpOldTable)); |
| PPMEscChar=2; |
| UnpBlockType=BLOCK_LZ; |
| } |
| InitFilters30(Solid); |
| } |
| |
| |
| void Unpack::InitFilters30(bool Solid) |
| { |
| if (!Solid) |
| { |
| OldFilterLengths.SoftReset(); |
| LastFilter=0; |
| |
| for (size_t I=0;I<Filters30.Size();I++) |
| delete Filters30[I]; |
| Filters30.SoftReset(); |
| } |
| for (size_t I=0;I<PrgStack.Size();I++) |
| delete PrgStack[I]; |
| PrgStack.SoftReset(); |
| } |
| |
| } // namespace third_party_unrar |