view src/win32/7zip/7z/CPP/7zip/Compress/ImplodeDecoder.cpp @ 1:f9f4f1b99eed

importing src directory
author Robert McIntyre <rlm@mit.edu>
date Sat, 03 Mar 2012 10:31:27 -0600
parents
children
line wrap: on
line source
1 // Implode/Decoder.cpp
3 #include "StdAfx.h"
5 #include "ImplodeDecoder.h"
6 #include "Common/Defs.h"
8 namespace NCompress {
9 namespace NImplode {
10 namespace NDecoder {
12 class CException
13 {
14 public:
15 enum ECauseType
16 {
17 kData
18 } m_Cause;
19 CException(ECauseType cause): m_Cause(cause) {}
20 };
22 static const int kNumDistanceLowDirectBitsForBigDict = 7;
23 static const int kNumDistanceLowDirectBitsForSmallDict = 6;
25 static const int kNumBitsInByte = 8;
27 // static const int kLevelStructuresNumberFieldSize = kNumBitsInByte;
28 static const int kLevelStructuresNumberAdditionalValue = 1;
30 static const int kNumLevelStructureLevelBits = 4;
31 static const int kLevelStructureLevelAdditionalValue = 1;
33 static const int kNumLevelStructureRepNumberBits = 4;
34 static const int kLevelStructureRepNumberAdditionalValue = 1;
37 static const int kLiteralTableSize = (1 << kNumBitsInByte);
38 static const int kDistanceTableSize = 64;
39 static const int kLengthTableSize = 64;
41 static const UInt32 kHistorySize =
42 (1 << MyMax(kNumDistanceLowDirectBitsForBigDict,
43 kNumDistanceLowDirectBitsForSmallDict)) *
44 kDistanceTableSize; // = 8 KB;
46 static const int kNumAdditionalLengthBits = 8;
48 static const UInt32 kMatchMinLenWhenLiteralsOn = 3;
49 static const UInt32 kMatchMinLenWhenLiteralsOff = 2;
51 static const UInt32 kMatchMinLenMax = MyMax(kMatchMinLenWhenLiteralsOn,
52 kMatchMinLenWhenLiteralsOff); // 3
54 // static const UInt32 kMatchMaxLenMax = kMatchMinLenMax + (kLengthTableSize - 1) + (1 << kNumAdditionalLengthBits) - 1; // or 2
56 enum
57 {
58 kMatchId = 0,
59 kLiteralId = 1
60 };
63 CCoder::CCoder():
64 m_LiteralDecoder(kLiteralTableSize),
65 m_LengthDecoder(kLengthTableSize),
66 m_DistanceDecoder(kDistanceTableSize)
67 {
68 }
70 void CCoder::ReleaseStreams()
71 {
72 m_OutWindowStream.ReleaseStream();
73 m_InBitStream.ReleaseStream();
74 }
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 }
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 }
108 Byte lengthLevels[kLengthTableSize];
109 if (!ReadLevelItems(m_LengthDecoder, lengthLevels, kLengthTableSize))
110 return false;
112 Byte distanceLevels[kDistanceTableSize];
113 return ReadLevelItems(m_DistanceDecoder, distanceLevels, kDistanceTableSize);
114 }
116 class CCoderReleaser
117 {
118 CCoder *m_Coder;
119 public:
120 CCoderReleaser(CCoder *coder): m_Coder(coder) {}
121 ~CCoderReleaser() { m_Coder->ReleaseStreams(); }
122 };
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;
135 m_OutWindowStream.SetStream(outStream);
136 m_OutWindowStream.Init(false);
137 m_InBitStream.SetStream(inStream);
138 m_InBitStream.Init();
139 CCoderReleaser coderReleaser(this);
141 if (!ReadTables())
142 return S_FALSE;
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 }
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 }
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 }
219 }}}