view src/win32/7zip/7z/CPP/7zip/Compress/LzhDecoder.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 // LzhDecoder.cpp
3 #include "StdAfx.h"
5 #include "LzhDecoder.h"
7 #include "Windows/Defs.h"
9 namespace NCompress{
10 namespace NLzh {
11 namespace NDecoder {
13 static const UInt32 kHistorySize = (1 << 16);
15 static const int kBlockSizeBits = 16;
16 static const int kNumCBits = 9;
17 static const int kNumLevelBits = 5; // smallest integer such that (1 << kNumLevelBits) > kNumLevelSymbols/
19 UInt32 CCoder::ReadBits(int numBits) { return m_InBitStream.ReadBits(numBits); }
21 HRESULT CCoder::ReadLevelTable()
22 {
23 int n = ReadBits(kNumLevelBits);
24 if (n == 0)
25 {
26 m_LevelHuffman.Symbol = ReadBits(kNumLevelBits);
27 if (m_LevelHuffman.Symbol >= kNumLevelSymbols)
28 return S_FALSE;
29 }
30 else
31 {
32 if (n > kNumLevelSymbols)
33 return S_FALSE;
34 m_LevelHuffman.Symbol = -1;
35 Byte lens[kNumLevelSymbols];
36 int i = 0;
37 while (i < n)
38 {
39 int c = m_InBitStream.ReadBits(3);
40 if (c == 7)
41 while (ReadBits(1))
42 if (c++ > kMaxHuffmanLen)
43 return S_FALSE;
44 lens[i++] = (Byte)c;
45 if (i == kNumSpecLevelSymbols)
46 {
47 c = ReadBits(2);
48 while (--c >= 0)
49 lens[i++] = 0;
50 }
51 }
52 while (i < kNumLevelSymbols)
53 lens[i++] = 0;
54 m_LevelHuffman.SetCodeLengths(lens);
55 }
56 return S_OK;
57 }
59 HRESULT CCoder::ReadPTable(int numBits)
60 {
61 int n = ReadBits(numBits);
62 if (n == 0)
63 {
64 m_PHuffmanDecoder.Symbol = ReadBits(numBits);
65 if (m_PHuffmanDecoder.Symbol >= kNumDistanceSymbols)
66 return S_FALSE;
67 }
68 else
69 {
70 if (n > kNumDistanceSymbols)
71 return S_FALSE;
72 m_PHuffmanDecoder.Symbol = -1;
73 Byte lens[kNumDistanceSymbols];
74 int i = 0;
75 while (i < n)
76 {
77 int c = m_InBitStream.ReadBits(3);
78 if (c == 7)
79 while (ReadBits(1))
80 {
81 if (c > kMaxHuffmanLen)
82 return S_FALSE;
83 c++;
84 }
85 lens[i++] = (Byte)c;
86 }
87 while (i < kNumDistanceSymbols)
88 lens[i++] = 0;
89 m_PHuffmanDecoder.SetCodeLengths(lens);
90 }
91 return S_OK;
92 }
94 HRESULT CCoder::ReadCTable()
95 {
96 int n = ReadBits(kNumCBits);
97 if (n == 0)
98 {
99 m_CHuffmanDecoder.Symbol = ReadBits(kNumCBits);
100 if (m_CHuffmanDecoder.Symbol >= kNumCSymbols)
101 return S_FALSE;
102 }
103 else
104 {
105 if (n > kNumCSymbols)
106 return S_FALSE;
107 m_CHuffmanDecoder.Symbol = -1;
108 Byte lens[kNumCSymbols];
109 int i = 0;
110 while (i < n)
111 {
112 int c = m_LevelHuffman.Decode(&m_InBitStream);
113 if (c < kNumSpecLevelSymbols)
114 {
115 if (c == 0)
116 c = 1;
117 else if (c == 1)
118 c = ReadBits(4) + 3;
119 else
120 c = ReadBits(kNumCBits) + 20;
121 while (--c >= 0)
122 {
123 if (i > kNumCSymbols)
124 return S_FALSE;
125 lens[i++] = 0;
126 }
127 }
128 else
129 lens[i++] = (Byte)(c - 2);
130 }
131 while (i < kNumCSymbols)
132 lens[i++] = 0;
133 m_CHuffmanDecoder.SetCodeLengths(lens);
134 }
135 return S_OK;
136 }
138 STDMETHODIMP CCoder::CodeReal(ISequentialInStream *inStream,
139 ISequentialOutStream *outStream, const UInt64 * /* inSize */, const UInt64 *outSize,
140 ICompressProgressInfo *progress)
141 {
142 if (outSize == NULL)
143 return E_INVALIDARG;
145 if (!m_OutWindowStream.Create(kHistorySize))
146 return E_OUTOFMEMORY;
147 if (!m_InBitStream.Create(1 << 20))
148 return E_OUTOFMEMORY;
150 UInt64 pos = 0;
151 m_OutWindowStream.SetStream(outStream);
152 m_OutWindowStream.Init(false);
153 m_InBitStream.SetStream(inStream);
154 m_InBitStream.Init();
156 CCoderReleaser coderReleaser(this);
158 int pbit;
159 if (m_NumDictBits <= 13)
160 pbit = 4;
161 else
162 pbit = 5;
164 UInt32 blockSize = 0;
166 while(pos < *outSize)
167 {
168 // for (i = 0; i < dictSize; i++) dtext[i] = 0x20;
170 if (blockSize == 0)
171 {
172 if (progress != NULL)
173 {
174 UInt64 packSize = m_InBitStream.GetProcessedSize();
175 RINOK(progress->SetRatioInfo(&packSize, &pos));
176 }
177 blockSize = ReadBits(kBlockSizeBits);
178 ReadLevelTable();
179 ReadCTable();
180 RINOK(ReadPTable(pbit));
181 }
182 blockSize--;
183 UInt32 c = m_CHuffmanDecoder.Decode(&m_InBitStream);
184 if (c < 256)
185 {
186 m_OutWindowStream.PutByte((Byte)c);
187 pos++;
188 }
189 else if (c >= kNumCSymbols)
190 return S_FALSE;
191 else
192 {
193 // offset = (interface->method == LARC_METHOD_NUM) ? 0x100 - 2 : 0x100 - 3;
194 UInt32 len = c - 256 + kMinMatch;
195 UInt32 distance = m_PHuffmanDecoder.Decode(&m_InBitStream);
196 if (distance != 0)
197 distance = (1 << (distance - 1)) + ReadBits(distance - 1);
198 if (distance >= pos)
199 return S_FALSE;
200 if (pos + len > *outSize)
201 len = (UInt32)(*outSize - pos);
202 pos += len;
203 m_OutWindowStream.CopyBlock(distance, len);
204 }
205 }
206 coderReleaser.NeedFlush = false;
207 return m_OutWindowStream.Flush();
208 }
210 STDMETHODIMP CCoder::Code(ISequentialInStream *inStream,
211 ISequentialOutStream *outStream, const UInt64 *inSize, const UInt64 *outSize,
212 ICompressProgressInfo *progress)
213 {
214 try { return CodeReal(inStream, outStream, inSize, outSize, progress);}
215 catch(const CInBufferException &e) { return e.ErrorCode; }
216 catch(const CLzOutWindowException &e) { return e.ErrorCode; }
217 catch(...) { return S_FALSE; }
218 }
220 }}}