Unpack5(bool Solid)1 void Unpack::Unpack5(bool Solid)
2 {
3   FileExtracted=true;
4 
5   if (!Suspended)
6   {
7     UnpInitData(Solid);
8     if (!UnpReadBuf())
9       return;
10 
11     // Check TablesRead5 to be sure that we read tables at least once
12     // regardless of current block header TablePresent flag.
13     // So we can safefly use these tables below.
14     if (!ReadBlockHeader(Inp,BlockHeader) ||
15         !ReadTables(Inp,BlockHeader,BlockTables) || !TablesRead5)
16       return;
17   }
18 
19   while (true)
20   {
21     UnpPtr&=MaxWinMask;
22 
23     if (Inp.InAddr>=ReadBorder)
24     {
25       bool FileDone=false;
26 
27       // We use 'while', because for empty block containing only Huffman table,
28       // we'll be on the block border once again just after reading the table.
29       while (Inp.InAddr>BlockHeader.BlockStart+BlockHeader.BlockSize-1 ||
30              Inp.InAddr==BlockHeader.BlockStart+BlockHeader.BlockSize-1 &&
31              Inp.InBit>=BlockHeader.BlockBitSize)
32       {
33         if (BlockHeader.LastBlockInFile)
34         {
35           FileDone=true;
36           break;
37         }
38         if (!ReadBlockHeader(Inp,BlockHeader) || !ReadTables(Inp,BlockHeader,BlockTables))
39           return;
40       }
41       if (FileDone || !UnpReadBuf())
42         break;
43     }
44 
45     if (((WriteBorder-UnpPtr) & MaxWinMask)<MAX_INC_LZ_MATCH && WriteBorder!=UnpPtr)
46     {
47       UnpWriteBuf();
48       if (WrittenFileSize>DestUnpSize)
49         return;
50       if (Suspended)
51       {
52         FileExtracted=false;
53         return;
54       }
55     }
56 
57     uint MainSlot=DecodeNumber(Inp,&BlockTables.LD);
58     if (MainSlot<256)
59     {
60       if (Fragmented)
61         FragWindow[UnpPtr++]=(byte)MainSlot;
62       else
63         Window[UnpPtr++]=(byte)MainSlot;
64       continue;
65     }
66     if (MainSlot>=262)
67     {
68       uint Length=SlotToLength(Inp,MainSlot-262);
69 
70       uint DBits,Distance=1,DistSlot=DecodeNumber(Inp,&BlockTables.DD);
71       if (DistSlot<4)
72       {
73         DBits=0;
74         Distance+=DistSlot;
75       }
76       else
77       {
78         DBits=DistSlot/2 - 1;
79         Distance+=(2 | (DistSlot & 1)) << DBits;
80       }
81 
82       if (DBits>0)
83       {
84         if (DBits>=4)
85         {
86           if (DBits>4)
87           {
88             Distance+=((Inp.getbits32()>>(36-DBits))<<4);
89             Inp.addbits(DBits-4);
90           }
91           uint LowDist=DecodeNumber(Inp,&BlockTables.LDD);
92           Distance+=LowDist;
93         }
94         else
95         {
96           Distance+=Inp.getbits32()>>(32-DBits);
97           Inp.addbits(DBits);
98         }
99       }
100 
101       if (Distance>0x100)
102       {
103         Length++;
104         if (Distance>0x2000)
105         {
106           Length++;
107           if (Distance>0x40000)
108             Length++;
109         }
110       }
111 
112       InsertOldDist(Distance);
113       LastLength=Length;
114       if (Fragmented)
115         FragWindow.CopyString(Length,Distance,UnpPtr,MaxWinMask);
116       else
117         CopyString(Length,Distance);
118       continue;
119     }
120     if (MainSlot==256)
121     {
122       UnpackFilter Filter;
123       if (!ReadFilter(Inp,Filter) || !AddFilter(Filter))
124         break;
125       continue;
126     }
127     if (MainSlot==257)
128     {
129       if (LastLength!=0)
130         if (Fragmented)
131           FragWindow.CopyString(LastLength,OldDist[0],UnpPtr,MaxWinMask);
132         else
133           CopyString(LastLength,OldDist[0]);
134       continue;
135     }
136     if (MainSlot<262)
137     {
138       uint DistNum=MainSlot-258;
139       uint Distance=OldDist[DistNum];
140       for (uint I=DistNum;I>0;I--)
141         OldDist[I]=OldDist[I-1];
142       OldDist[0]=Distance;
143 
144       uint LengthSlot=DecodeNumber(Inp,&BlockTables.RD);
145       uint Length=SlotToLength(Inp,LengthSlot);
146       LastLength=Length;
147       if (Fragmented)
148         FragWindow.CopyString(Length,Distance,UnpPtr,MaxWinMask);
149       else
150         CopyString(Length,Distance);
151       continue;
152     }
153   }
154   UnpWriteBuf();
155 }
156 
157 
ReadFilterData(BitInput & Inp)158 uint Unpack::ReadFilterData(BitInput &Inp)
159 {
160   uint ByteCount=(Inp.fgetbits()>>14)+1;
161   Inp.addbits(2);
162 
163   uint Data=0;
164   for (uint I=0;I<ByteCount;I++)
165   {
166     Data+=(Inp.fgetbits()>>8)<<(I*8);
167     Inp.addbits(8);
168   }
169   return Data;
170 }
171 
172 
ReadFilter(BitInput & Inp,UnpackFilter & Filter)173 bool Unpack::ReadFilter(BitInput &Inp,UnpackFilter &Filter)
174 {
175   if (!Inp.ExternalBuffer && Inp.InAddr>ReadTop-16)
176     if (!UnpReadBuf())
177       return false;
178 
179   Filter.BlockStart=ReadFilterData(Inp);
180   Filter.BlockLength=ReadFilterData(Inp);
181   if (Filter.BlockLength>MAX_FILTER_BLOCK_SIZE)
182     Filter.BlockLength=0;
183 
184   Filter.Type=Inp.fgetbits()>>13;
185   Inp.faddbits(3);
186 
187   if (Filter.Type==FILTER_DELTA)
188   {
189     Filter.Channels=(Inp.fgetbits()>>11)+1;
190     Inp.faddbits(5);
191   }
192 
193   return true;
194 }
195 
196 
AddFilter(UnpackFilter & Filter)197 bool Unpack::AddFilter(UnpackFilter &Filter)
198 {
199   if (Filters.Size()>=MAX_UNPACK_FILTERS)
200   {
201     UnpWriteBuf(); // Write data, apply and flush filters.
202     if (Filters.Size()>=MAX_UNPACK_FILTERS)
203       InitFilters(); // Still too many filters, prevent excessive memory use.
204   }
205 
206   // If distance to filter start is that large that due to circular dictionary
207   // mode now it points to old not written yet data, then we set 'NextWindow'
208   // flag and process this filter only after processing that older data.
209   Filter.NextWindow=WrPtr!=UnpPtr && ((WrPtr-UnpPtr)&MaxWinMask)<=Filter.BlockStart;
210 
211   Filter.BlockStart=uint((Filter.BlockStart+UnpPtr)&MaxWinMask);
212   Filters.Push(Filter);
213   return true;
214 }
215 
216 
UnpReadBuf()217 bool Unpack::UnpReadBuf()
218 {
219   int DataSize=ReadTop-Inp.InAddr; // Data left to process.
220   if (DataSize<0)
221     return false;
222   BlockHeader.BlockSize-=Inp.InAddr-BlockHeader.BlockStart;
223   if (Inp.InAddr>BitInput::MAX_SIZE/2)
224   {
225     // If we already processed more than half of buffer, let's move
226     // remaining data into beginning to free more space for new data
227     // and ensure that calling function does not cross the buffer border
228     // even if we did not read anything here. Also it ensures that read size
229     // is not less than CRYPT_BLOCK_SIZE, so we can align it without risk
230     // to make it zero.
231     if (DataSize>0)
232       memmove(Inp.InBuf,Inp.InBuf+Inp.InAddr,DataSize);
233     Inp.InAddr=0;
234     ReadTop=DataSize;
235   }
236   else
237     DataSize=ReadTop;
238   int ReadCode=0;
239   if (BitInput::MAX_SIZE!=DataSize)
240     ReadCode=UnpIO->UnpRead(Inp.InBuf+DataSize,BitInput::MAX_SIZE-DataSize);
241   if (ReadCode>0) // Can be also -1.
242     ReadTop+=ReadCode;
243   ReadBorder=ReadTop-30;
244   BlockHeader.BlockStart=Inp.InAddr;
245   if (BlockHeader.BlockSize!=-1) // '-1' means not defined yet.
246   {
247     // We may need to quit from main extraction loop and read new block header
248     // and trees earlier than data in input buffer ends.
249     ReadBorder=Min(ReadBorder,BlockHeader.BlockStart+BlockHeader.BlockSize-1);
250   }
251   return ReadCode!=-1;
252 }
253 
254 
UnpWriteBuf()255 void Unpack::UnpWriteBuf()
256 {
257   size_t WrittenBorder=WrPtr;
258   size_t FullWriteSize=(UnpPtr-WrittenBorder)&MaxWinMask;
259   size_t WriteSizeLeft=FullWriteSize;
260   bool NotAllFiltersProcessed=false;
261   for (size_t I=0;I<Filters.Size();I++)
262   {
263     // Here we apply filters to data which we need to write.
264     // We always copy data to another memory block before processing.
265     // We cannot process them just in place in Window buffer, because
266     // these data can be used for future string matches, so we must
267     // preserve them in original form.
268 
269     UnpackFilter *flt=&Filters[I];
270     if (flt->Type==FILTER_NONE)
271       continue;
272     if (flt->NextWindow)
273     {
274       // Here we skip filters which have block start in current data range
275       // due to address wrap around in circular dictionary, but actually
276       // belong to next dictionary block. If such filter start position
277       // is included to current write range, then we reset 'NextWindow' flag.
278       // In fact we can reset it even without such check, because current
279       // implementation seems to guarantee 'NextWindow' flag reset after
280       // buffer writing for all existing filters. But let's keep this check
281       // just in case. Compressor guarantees that distance between
282       // filter block start and filter storing position cannot exceed
283       // the dictionary size. So if we covered the filter block start with
284       // our write here, we can safely assume that filter is applicable
285       // to next block on no further wrap arounds is possible.
286       if (((flt->BlockStart-WrPtr)&MaxWinMask)<=FullWriteSize)
287         flt->NextWindow=false;
288       continue;
289     }
290     uint BlockStart=flt->BlockStart;
291     uint BlockLength=flt->BlockLength;
292     if (((BlockStart-WrittenBorder)&MaxWinMask)<WriteSizeLeft)
293     {
294       if (WrittenBorder!=BlockStart)
295       {
296         UnpWriteArea(WrittenBorder,BlockStart);
297         WrittenBorder=BlockStart;
298         WriteSizeLeft=(UnpPtr-WrittenBorder)&MaxWinMask;
299       }
300       if (BlockLength<=WriteSizeLeft)
301       {
302         if (BlockLength>0) // We set it to 0 also for invalid filters.
303         {
304           uint BlockEnd=(BlockStart+BlockLength)&MaxWinMask;
305 
306           FilterSrcMemory.Alloc(BlockLength);
307           byte *Mem=&FilterSrcMemory[0];
308           if (BlockStart<BlockEnd || BlockEnd==0)
309           {
310             if (Fragmented)
311               FragWindow.CopyData(Mem,BlockStart,BlockLength);
312             else
313               memcpy(Mem,Window+BlockStart,BlockLength);
314           }
315           else
316           {
317             size_t FirstPartLength=size_t(MaxWinSize-BlockStart);
318             if (Fragmented)
319             {
320               FragWindow.CopyData(Mem,BlockStart,FirstPartLength);
321               FragWindow.CopyData(Mem+FirstPartLength,0,BlockEnd);
322             }
323             else
324             {
325               memcpy(Mem,Window+BlockStart,FirstPartLength);
326               memcpy(Mem+FirstPartLength,Window,BlockEnd);
327             }
328           }
329 
330           byte *OutMem=ApplyFilter(Mem,BlockLength,flt);
331 
332           Filters[I].Type=FILTER_NONE;
333 
334           if (OutMem!=NULL)
335             UnpIO->UnpWrite(OutMem,BlockLength);
336 
337           UnpSomeRead=true;
338           WrittenFileSize+=BlockLength;
339           WrittenBorder=BlockEnd;
340           WriteSizeLeft=(UnpPtr-WrittenBorder)&MaxWinMask;
341         }
342       }
343       else
344       {
345         // Current filter intersects the window write border, so we adjust
346         // the window border to process this filter next time, not now.
347         WrPtr=WrittenBorder;
348 
349         // Since Filter start position can only increase, we quit processing
350         // all following filters for this data block and reset 'NextWindow'
351         // flag for them.
352         for (size_t J=I;J<Filters.Size();J++)
353         {
354           UnpackFilter *flt=&Filters[J];
355           if (flt->Type!=FILTER_NONE)
356             flt->NextWindow=false;
357         }
358 
359         // Do not write data left after current filter now.
360         NotAllFiltersProcessed=true;
361         break;
362       }
363     }
364   }
365 
366   // Remove processed filters from queue.
367   size_t EmptyCount=0;
368   for (size_t I=0;I<Filters.Size();I++)
369   {
370     if (EmptyCount>0)
371       Filters[I-EmptyCount]=Filters[I];
372     if (Filters[I].Type==FILTER_NONE)
373       EmptyCount++;
374   }
375   if (EmptyCount>0)
376     Filters.Alloc(Filters.Size()-EmptyCount);
377 
378   if (!NotAllFiltersProcessed) // Only if all filters are processed.
379   {
380     // Write data left after last filter.
381     UnpWriteArea(WrittenBorder,UnpPtr);
382     WrPtr=UnpPtr;
383   }
384 
385   // We prefer to write data in blocks not exceeding UNPACK_MAX_WRITE
386   // instead of potentially huge MaxWinSize blocks. It also allows us
387   // to keep the size of Filters array reasonable.
388   WriteBorder=(UnpPtr+Min(MaxWinSize,UNPACK_MAX_WRITE))&MaxWinMask;
389 
390   // Choose the nearest among WriteBorder and WrPtr actual written border.
391   // If border is equal to UnpPtr, it means that we have MaxWinSize data ahead.
392   if (WriteBorder==UnpPtr ||
393       WrPtr!=UnpPtr && ((WrPtr-UnpPtr)&MaxWinMask)<((WriteBorder-UnpPtr)&MaxWinMask))
394     WriteBorder=WrPtr;
395 }
396 
397 
ApplyFilter(byte * Data,uint DataSize,UnpackFilter * Flt)398 byte* Unpack::ApplyFilter(byte *Data,uint DataSize,UnpackFilter *Flt)
399 {
400   byte *SrcData=Data;
401   switch(Flt->Type)
402   {
403     case FILTER_E8:
404     case FILTER_E8E9:
405       {
406         uint FileOffset=(uint)WrittenFileSize;
407 
408         const uint FileSize=0x1000000;
409         byte CmpByte2=Flt->Type==FILTER_E8E9 ? 0xe9:0xe8;
410         // DataSize is unsigned, so we use "CurPos+4" and not "DataSize-4"
411         // to avoid overflow for DataSize<4.
412         for (uint CurPos=0;CurPos+4<DataSize;)
413         {
414           byte CurByte=*(Data++);
415           CurPos++;
416           if (CurByte==0xe8 || CurByte==CmpByte2)
417           {
418             uint Offset=(CurPos+FileOffset)%FileSize;
419             uint Addr=RawGet4(Data);
420 
421             // We check 0x80000000 bit instead of '< 0' comparison
422             // not assuming int32 presence or uint size and endianness.
423             if ((Addr & 0x80000000)!=0)              // Addr<0
424             {
425               if (((Addr+Offset) & 0x80000000)==0)   // Addr+Offset>=0
426                 RawPut4(Addr+FileSize,Data);
427             }
428             else
429               if (((Addr-FileSize) & 0x80000000)!=0) // Addr<FileSize
430                 RawPut4(Addr-Offset,Data);
431 
432             Data+=4;
433             CurPos+=4;
434           }
435         }
436       }
437       return SrcData;
438     case FILTER_ARM:
439       // 2019-11-15: we turned off ARM filter by default when compressing,
440       // mostly because it is inefficient for modern 64 bit ARM binaries.
441       // It was turned on by default in 5.0 - 5.80b3 , so we still need it
442       // here for compatibility with some of previously created archives.
443       {
444         uint FileOffset=(uint)WrittenFileSize;
445         // DataSize is unsigned, so we use "CurPos+3" and not "DataSize-3"
446         // to avoid overflow for DataSize<3.
447         for (uint CurPos=0;CurPos+3<DataSize;CurPos+=4)
448         {
449           byte *D=Data+CurPos;
450           if (D[3]==0xeb) // BL command with '1110' (Always) condition.
451           {
452             uint Offset=D[0]+uint(D[1])*0x100+uint(D[2])*0x10000;
453             Offset-=(FileOffset+CurPos)/4;
454             D[0]=(byte)Offset;
455             D[1]=(byte)(Offset>>8);
456             D[2]=(byte)(Offset>>16);
457           }
458         }
459       }
460       return SrcData;
461     case FILTER_DELTA:
462       {
463         // Unlike RAR3, we do not need to reject excessive channel
464         // values here, since RAR5 uses only 5 bits to store channel.
465         uint Channels=Flt->Channels,SrcPos=0;
466 
467         FilterDstMemory.Alloc(DataSize);
468         byte *DstData=&FilterDstMemory[0];
469 
470         // Bytes from same channels are grouped to continual data blocks,
471         // so we need to place them back to their interleaving positions.
472         for (uint CurChannel=0;CurChannel<Channels;CurChannel++)
473         {
474           byte PrevByte=0;
475           for (uint DestPos=CurChannel;DestPos<DataSize;DestPos+=Channels)
476             DstData[DestPos]=(PrevByte-=Data[SrcPos++]);
477         }
478         return DstData;
479       }
480 
481   }
482   return NULL;
483 }
484 
485 
UnpWriteArea(size_t StartPtr,size_t EndPtr)486 void Unpack::UnpWriteArea(size_t StartPtr,size_t EndPtr)
487 {
488   if (EndPtr!=StartPtr)
489     UnpSomeRead=true;
490   if (EndPtr<StartPtr)
491     UnpAllBuf=true;
492 
493   if (Fragmented)
494   {
495     size_t SizeToWrite=(EndPtr-StartPtr) & MaxWinMask;
496     while (SizeToWrite>0)
497     {
498       size_t BlockSize=FragWindow.GetBlockSize(StartPtr,SizeToWrite);
499       UnpWriteData(&FragWindow[StartPtr],BlockSize);
500       SizeToWrite-=BlockSize;
501       StartPtr=(StartPtr+BlockSize) & MaxWinMask;
502     }
503   }
504   else
505     if (EndPtr<StartPtr)
506     {
507       UnpWriteData(Window+StartPtr,MaxWinSize-StartPtr);
508       UnpWriteData(Window,EndPtr);
509     }
510     else
511       UnpWriteData(Window+StartPtr,EndPtr-StartPtr);
512 }
513 
514 
UnpWriteData(byte * Data,size_t Size)515 void Unpack::UnpWriteData(byte *Data,size_t Size)
516 {
517   if (WrittenFileSize>=DestUnpSize)
518     return;
519   size_t WriteSize=Size;
520   int64 LeftToWrite=DestUnpSize-WrittenFileSize;
521   if ((int64)WriteSize>LeftToWrite)
522     WriteSize=(size_t)LeftToWrite;
523   UnpIO->UnpWrite(Data,WriteSize);
524   WrittenFileSize+=Size;
525 }
526 
527 
UnpInitData50(bool Solid)528 void Unpack::UnpInitData50(bool Solid)
529 {
530   if (!Solid)
531     TablesRead5=false;
532 }
533 
534 
ReadBlockHeader(BitInput & Inp,UnpackBlockHeader & Header)535 bool Unpack::ReadBlockHeader(BitInput &Inp,UnpackBlockHeader &Header)
536 {
537   Header.HeaderSize=0;
538 
539   if (!Inp.ExternalBuffer && Inp.InAddr>ReadTop-7)
540     if (!UnpReadBuf())
541       return false;
542   Inp.faddbits((8-Inp.InBit)&7);
543 
544   byte BlockFlags=Inp.fgetbits()>>8;
545   Inp.faddbits(8);
546   uint ByteCount=((BlockFlags>>3)&3)+1; // Block size byte count.
547 
548   if (ByteCount==4)
549     return false;
550 
551   Header.HeaderSize=2+ByteCount;
552 
553   Header.BlockBitSize=(BlockFlags&7)+1;
554 
555   byte SavedCheckSum=Inp.fgetbits()>>8;
556   Inp.faddbits(8);
557 
558   int BlockSize=0;
559   for (uint I=0;I<ByteCount;I++)
560   {
561     BlockSize+=(Inp.fgetbits()>>8)<<(I*8);
562     Inp.addbits(8);
563   }
564 
565   Header.BlockSize=BlockSize;
566   byte CheckSum=byte(0x5a^BlockFlags^BlockSize^(BlockSize>>8)^(BlockSize>>16));
567   if (CheckSum!=SavedCheckSum)
568     return false;
569 
570   Header.BlockStart=Inp.InAddr;
571   ReadBorder=Min(ReadBorder,Header.BlockStart+Header.BlockSize-1);
572 
573   Header.LastBlockInFile=(BlockFlags & 0x40)!=0;
574   Header.TablePresent=(BlockFlags & 0x80)!=0;
575   return true;
576 }
577 
578 
ReadTables(BitInput & Inp,UnpackBlockHeader & Header,UnpackBlockTables & Tables)579 bool Unpack::ReadTables(BitInput &Inp,UnpackBlockHeader &Header,UnpackBlockTables &Tables)
580 {
581   if (!Header.TablePresent)
582     return true;
583 
584   if (!Inp.ExternalBuffer && Inp.InAddr>ReadTop-25)
585     if (!UnpReadBuf())
586       return false;
587 
588   byte BitLength[BC];
589   for (uint I=0;I<BC;I++)
590   {
591     uint Length=(byte)(Inp.fgetbits() >> 12);
592     Inp.faddbits(4);
593     if (Length==15)
594     {
595       uint ZeroCount=(byte)(Inp.fgetbits() >> 12);
596       Inp.faddbits(4);
597       if (ZeroCount==0)
598         BitLength[I]=15;
599       else
600       {
601         ZeroCount+=2;
602         while (ZeroCount-- > 0 && I<ASIZE(BitLength))
603           BitLength[I++]=0;
604         I--;
605       }
606     }
607     else
608       BitLength[I]=Length;
609   }
610 
611   MakeDecodeTables(BitLength,&Tables.BD,BC);
612 
613   byte Table[HUFF_TABLE_SIZE];
614   const uint TableSize=HUFF_TABLE_SIZE;
615   for (uint I=0;I<TableSize;)
616   {
617     if (!Inp.ExternalBuffer && Inp.InAddr>ReadTop-5)
618       if (!UnpReadBuf())
619         return false;
620     uint Number=DecodeNumber(Inp,&Tables.BD);
621     if (Number<16)
622     {
623       Table[I]=Number;
624       I++;
625     }
626     else
627       if (Number<18)
628       {
629         uint N;
630         if (Number==16)
631         {
632           N=(Inp.fgetbits() >> 13)+3;
633           Inp.faddbits(3);
634         }
635         else
636         {
637           N=(Inp.fgetbits() >> 9)+11;
638           Inp.faddbits(7);
639         }
640         if (I==0)
641         {
642           // We cannot have "repeat previous" code at the first position.
643           // Multiple such codes would shift Inp position without changing I,
644           // which can lead to reading beyond of Inp boundary in mutithreading
645           // mode, where Inp.ExternalBuffer disables bounds check and we just
646           // reserve a lot of buffer space to not need such check normally.
647           return false;
648         }
649         else
650           while (N-- > 0 && I<TableSize)
651           {
652             Table[I]=Table[I-1];
653             I++;
654           }
655       }
656       else
657       {
658         uint N;
659         if (Number==18)
660         {
661           N=(Inp.fgetbits() >> 13)+3;
662           Inp.faddbits(3);
663         }
664         else
665         {
666           N=(Inp.fgetbits() >> 9)+11;
667           Inp.faddbits(7);
668         }
669         while (N-- > 0 && I<TableSize)
670           Table[I++]=0;
671       }
672   }
673   TablesRead5=true;
674   if (!Inp.ExternalBuffer && Inp.InAddr>ReadTop)
675     return false;
676   MakeDecodeTables(&Table[0],&Tables.LD,NC);
677   MakeDecodeTables(&Table[NC],&Tables.DD,DC);
678   MakeDecodeTables(&Table[NC+DC],&Tables.LDD,LDC);
679   MakeDecodeTables(&Table[NC+DC+LDC],&Tables.RD,RC);
680   return true;
681 }
682 
683 
InitFilters()684 void Unpack::InitFilters()
685 {
686   Filters.SoftReset();
687 }
688