1 // Implode/Decoder.cpp
2 
3 #include "StdAfx.h"
4 
5 #include "ImplodeDecoder.h"
6 #include "Common/Defs.h"
7 
8 namespace NCompress {
9 namespace NImplode {
10 namespace NDecoder {
11 
12 class CException
13 {
14 public:
15   enum ECauseType
16   {
17     kData
18   } m_Cause;
CException(ECauseType cause)19   CException(ECauseType cause): m_Cause(cause) {}
20 };
21 
22 static const int kNumDistanceLowDirectBitsForBigDict = 7;
23 static const int kNumDistanceLowDirectBitsForSmallDict = 6;
24 
25 static const int kNumBitsInByte = 8;
26 
27 // static const int kLevelStructuresNumberFieldSize = kNumBitsInByte;
28 static const int kLevelStructuresNumberAdditionalValue = 1;
29 
30 static const int kNumLevelStructureLevelBits = 4;
31 static const int kLevelStructureLevelAdditionalValue = 1;
32 
33 static const int kNumLevelStructureRepNumberBits = 4;
34 static const int kLevelStructureRepNumberAdditionalValue = 1;
35 
36 
37 static const int kLiteralTableSize = (1 << kNumBitsInByte);
38 static const int kDistanceTableSize = 64;
39 static const int kLengthTableSize = 64;
40 
41 static const UInt32 kHistorySize =
42     (1 << MyMax(kNumDistanceLowDirectBitsForBigDict,
43                 kNumDistanceLowDirectBitsForSmallDict)) *
44     kDistanceTableSize; // = 8 KB;
45 
46 static const int kNumAdditionalLengthBits = 8;
47 
48 static const UInt32 kMatchMinLenWhenLiteralsOn = 3;
49 static const UInt32 kMatchMinLenWhenLiteralsOff = 2;
50 
51 static const UInt32 kMatchMinLenMax = MyMax(kMatchMinLenWhenLiteralsOn,
52     kMatchMinLenWhenLiteralsOff);  // 3
53 
54 // static const UInt32 kMatchMaxLenMax = kMatchMinLenMax + (kLengthTableSize - 1) + (1 << kNumAdditionalLengthBits) - 1;  // or 2
55 
56 enum
57 {
58   kMatchId = 0,
59   kLiteralId = 1
60 };
61 
62 
CCoder()63 CCoder::CCoder():
64   m_LiteralDecoder(kLiteralTableSize),
65   m_LengthDecoder(kLengthTableSize),
66   m_DistanceDecoder(kDistanceTableSize)
67 {
68 }
69 
ReleaseStreams()70 void CCoder::ReleaseStreams()
71 {
72   m_OutWindowStream.ReleaseStream();
73   m_InBitStream.ReleaseStream();
74 }
75 
ReadLevelItems(NImplode::NHuffman::CDecoder & decoder,Byte * levels,int numLevelItems)76 bool CCoder::ReadLevelItems(NImplode::NHuffman::CDecoder &decoder,
77     Byte *levels, int numLevelItems)
78 {
79   int numCodedStructures = m_InBitStream.ReadBits(kNumBitsInByte) +
80       kLevelStructuresNumberAdditionalValue;
81   int currentIndex = 0;
82   for(int i = 0; i < numCodedStructures; i++)
83   {
84     int level = m_InBitStream.ReadBits(kNumLevelStructureLevelBits) +
85       kLevelStructureLevelAdditionalValue;
86     int rep = m_InBitStream.ReadBits(kNumLevelStructureRepNumberBits) +
87       kLevelStructureRepNumberAdditionalValue;
88     if (currentIndex + rep > numLevelItems)
89       throw CException(CException::kData);
90     for(int j = 0; j < rep; j++)
91       levels[currentIndex++] = (Byte)level;
92   }
93   if (currentIndex != numLevelItems)
94     return false;
95   return decoder.SetCodeLengths(levels);
96 }
97 
98 
ReadTables(void)99 bool CCoder::ReadTables(void)
100 {
101   if (m_LiteralsOn)
102   {
103     Byte literalLevels[kLiteralTableSize];
104     if (!ReadLevelItems(m_LiteralDecoder, literalLevels, kLiteralTableSize))
105       return false;
106   }
107 
108   Byte lengthLevels[kLengthTableSize];
109   if (!ReadLevelItems(m_LengthDecoder, lengthLevels, kLengthTableSize))
110     return false;
111 
112   Byte distanceLevels[kDistanceTableSize];
113   return ReadLevelItems(m_DistanceDecoder, distanceLevels, kDistanceTableSize);
114 }
115 
116 class CCoderReleaser
117 {
118   CCoder *m_Coder;
119 public:
CCoderReleaser(CCoder * coder)120   CCoderReleaser(CCoder *coder): m_Coder(coder) {}
~CCoderReleaser()121   ~CCoderReleaser() { m_Coder->ReleaseStreams(); }
122 };
123 
CodeReal(ISequentialInStream * inStream,ISequentialOutStream * outStream,const UInt64 *,const UInt64 * outSize,ICompressProgressInfo * progress)124 HRESULT CCoder::CodeReal(ISequentialInStream *inStream, ISequentialOutStream *outStream,
125     const UInt64 * /* inSize */, const UInt64 *outSize, ICompressProgressInfo *progress)
126 {
127   if (!m_InBitStream.Create(1 << 20))
128     return E_OUTOFMEMORY;
129   if (!m_OutWindowStream.Create(kHistorySize))
130     return E_OUTOFMEMORY;
131   if (outSize == NULL)
132     return E_INVALIDARG;
133   UInt64 pos = 0, unPackSize = *outSize;
134 
135   m_OutWindowStream.SetStream(outStream);
136   m_OutWindowStream.Init(false);
137   m_InBitStream.SetStream(inStream);
138   m_InBitStream.Init();
139   CCoderReleaser coderReleaser(this);
140 
141   if (!ReadTables())
142     return S_FALSE;
143 
144   while(pos < unPackSize)
145   {
146     if (progress != NULL && pos % (1 << 16) == 0)
147     {
148       UInt64 packSize = m_InBitStream.GetProcessedSize();
149       RINOK(progress->SetRatioInfo(&packSize, &pos));
150     }
151     if(m_InBitStream.ReadBits(1) == kMatchId) // match
152     {
153       UInt32 lowDistBits = m_InBitStream.ReadBits(m_NumDistanceLowDirectBits);
154       UInt32 distance = m_DistanceDecoder.DecodeSymbol(&m_InBitStream);
155       if (distance >= kDistanceTableSize)
156         return S_FALSE;
157       distance = (distance << m_NumDistanceLowDirectBits) + lowDistBits;
158       UInt32 lengthSymbol = m_LengthDecoder.DecodeSymbol(&m_InBitStream);
159       if (lengthSymbol >= kLengthTableSize)
160         return S_FALSE;
161       UInt32 length = lengthSymbol + m_MinMatchLength;
162       if (lengthSymbol == kLengthTableSize - 1) // special symbol  = 63
163         length += m_InBitStream.ReadBits(kNumAdditionalLengthBits);
164       while(distance >= pos && length > 0)
165       {
166         m_OutWindowStream.PutByte(0);
167         pos++;
168         length--;
169       }
170       if (length > 0)
171         m_OutWindowStream.CopyBlock(distance, length);
172       pos += length;
173     }
174     else
175     {
176       Byte b;
177       if (m_LiteralsOn)
178       {
179         UInt32 temp = m_LiteralDecoder.DecodeSymbol(&m_InBitStream);
180         if (temp >= kLiteralTableSize)
181           return S_FALSE;
182         b = (Byte)temp;
183       }
184       else
185         b = (Byte)m_InBitStream.ReadBits(kNumBitsInByte);
186       m_OutWindowStream.PutByte(b);
187       pos++;
188     }
189   }
190   if (pos > unPackSize)
191     return S_FALSE;
192   return m_OutWindowStream.Flush();
193 }
194 
Code(ISequentialInStream * inStream,ISequentialOutStream * outStream,const UInt64 * inSize,const UInt64 * outSize,ICompressProgressInfo * progress)195 STDMETHODIMP CCoder::Code(ISequentialInStream *inStream, ISequentialOutStream *outStream,
196     const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress)
197 {
198   try { return CodeReal(inStream, outStream, inSize, outSize, progress);  }
199   catch(const CLzOutWindowException &e) { return e.ErrorCode; }
200   catch(...) { return S_FALSE; }
201 }
202 
SetDecoderProperties2(const Byte * data,UInt32 size)203 STDMETHODIMP CCoder::SetDecoderProperties2(const Byte *data, UInt32 size)
204 {
205   if (size < 1)
206     return E_INVALIDARG;
207   Byte flag = data[0];
208   m_BigDictionaryOn = ((flag & 2) != 0);
209   m_NumDistanceLowDirectBits = m_BigDictionaryOn ?
210       kNumDistanceLowDirectBitsForBigDict:
211       kNumDistanceLowDirectBitsForSmallDict;
212   m_LiteralsOn = ((flag & 4) != 0);
213   m_MinMatchLength = m_LiteralsOn ?
214       kMatchMinLenWhenLiteralsOn :
215       kMatchMinLenWhenLiteralsOff;
216   return S_OK;
217 }
218 
219 }}}
220