Mercurial > vba-linux
comparison src/win32/7zip/7z/CPP/7zip/Compress/Rar2Decoder.cpp @ 1:f9f4f1b99eed
importing src directory
author | Robert McIntyre <rlm@mit.edu> |
---|---|
date | Sat, 03 Mar 2012 10:31:27 -0600 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
0:8ced16adf2e1 | 1:f9f4f1b99eed |
---|---|
1 // Rar2Decoder.cpp | |
2 // According to unRAR license, this code may not be used to develop | |
3 // a program that creates RAR archives | |
4 | |
5 #include "StdAfx.h" | |
6 | |
7 #include "Rar2Decoder.h" | |
8 | |
9 namespace NCompress { | |
10 namespace NRar2 { | |
11 | |
12 namespace NMultimedia { | |
13 | |
14 Byte CFilter::Decode(int &channelDelta, Byte deltaByte) | |
15 { | |
16 D4 = D3; | |
17 D3 = D2; | |
18 D2 = LastDelta - D1; | |
19 D1 = LastDelta; | |
20 int predictedValue = ((8 * LastChar + K1 * D1 + K2 * D2 + K3 * D3 + K4 * D4 + K5 * channelDelta) >> 3); | |
21 | |
22 Byte realValue = (Byte)(predictedValue - deltaByte); | |
23 int i = ((int)(signed char)deltaByte) << 3; | |
24 | |
25 Dif[0] += abs(i); | |
26 Dif[1] += abs(i - D1); | |
27 Dif[2] += abs(i + D1); | |
28 Dif[3] += abs(i - D2); | |
29 Dif[4] += abs(i + D2); | |
30 Dif[5] += abs(i - D3); | |
31 Dif[6] += abs(i + D3); | |
32 Dif[7] += abs(i - D4); | |
33 Dif[8] += abs(i + D4); | |
34 Dif[9] += abs(i - channelDelta); | |
35 Dif[10] += abs(i + channelDelta); | |
36 | |
37 channelDelta = LastDelta = (signed char)(realValue - LastChar); | |
38 LastChar = realValue; | |
39 | |
40 if (((++ByteCount) & 0x1F) == 0) | |
41 { | |
42 UInt32 minDif = Dif[0]; | |
43 UInt32 numMinDif = 0; | |
44 Dif[0] = 0; | |
45 for (i = 1; i < sizeof(Dif) / sizeof(Dif[0]); i++) | |
46 { | |
47 if (Dif[i] < minDif) | |
48 { | |
49 minDif = Dif[i]; | |
50 numMinDif = i; | |
51 } | |
52 Dif[i] = 0; | |
53 } | |
54 switch(numMinDif) | |
55 { | |
56 case 1: if (K1 >= -16) K1--; break; | |
57 case 2: if (K1 < 16) K1++; break; | |
58 case 3: if (K2 >= -16) K2--; break; | |
59 case 4: if (K2 < 16) K2++; break; | |
60 case 5: if (K3 >= -16) K3--; break; | |
61 case 6: if (K3 < 16) K3++; break; | |
62 case 7: if (K4 >= -16) K4--; break; | |
63 case 8: if (K4 < 16) K4++; break; | |
64 case 9: if (K5 >= -16) K5--; break; | |
65 case 10:if (K5 < 16) K5++; break; | |
66 } | |
67 } | |
68 return realValue; | |
69 } | |
70 } | |
71 | |
72 static const char *kNumberErrorMessage = "Number error"; | |
73 | |
74 static const UInt32 kHistorySize = 1 << 20; | |
75 | |
76 static const int kNumStats = 11; | |
77 | |
78 static const UInt32 kWindowReservSize = (1 << 22) + 256; | |
79 | |
80 CDecoder::CDecoder(): | |
81 m_IsSolid(false) | |
82 { | |
83 } | |
84 | |
85 void CDecoder::InitStructures() | |
86 { | |
87 m_MmFilter.Init(); | |
88 for(int i = 0; i < kNumRepDists; i++) | |
89 m_RepDists[i] = 0; | |
90 m_RepDistPtr = 0; | |
91 m_LastLength = 0; | |
92 memset(m_LastLevels, 0, kMaxTableSize); | |
93 } | |
94 | |
95 UInt32 CDecoder::ReadBits(int numBits) { return m_InBitStream.ReadBits(numBits); } | |
96 | |
97 #define RIF(x) { if (!(x)) return false; } | |
98 | |
99 bool CDecoder::ReadTables(void) | |
100 { | |
101 Byte levelLevels[kLevelTableSize]; | |
102 Byte newLevels[kMaxTableSize]; | |
103 m_AudioMode = (ReadBits(1) == 1); | |
104 | |
105 if (ReadBits(1) == 0) | |
106 memset(m_LastLevels, 0, kMaxTableSize); | |
107 int numLevels; | |
108 if (m_AudioMode) | |
109 { | |
110 m_NumChannels = ReadBits(2) + 1; | |
111 if (m_MmFilter.CurrentChannel >= m_NumChannels) | |
112 m_MmFilter.CurrentChannel = 0; | |
113 numLevels = m_NumChannels * kMMTableSize; | |
114 } | |
115 else | |
116 numLevels = kHeapTablesSizesSum; | |
117 | |
118 int i; | |
119 for (i = 0; i < kLevelTableSize; i++) | |
120 levelLevels[i] = (Byte)ReadBits(4); | |
121 RIF(m_LevelDecoder.SetCodeLengths(levelLevels)); | |
122 i = 0; | |
123 while (i < numLevels) | |
124 { | |
125 UInt32 number = m_LevelDecoder.DecodeSymbol(&m_InBitStream); | |
126 if (number < kTableDirectLevels) | |
127 { | |
128 newLevels[i] = (Byte)((number + m_LastLevels[i]) & kLevelMask); | |
129 i++; | |
130 } | |
131 else | |
132 { | |
133 if (number == kTableLevelRepNumber) | |
134 { | |
135 int t = ReadBits(2) + 3; | |
136 for (int reps = t; reps > 0 && i < numLevels ; reps--, i++) | |
137 newLevels[i] = newLevels[i - 1]; | |
138 } | |
139 else | |
140 { | |
141 int num; | |
142 if (number == kTableLevel0Number) | |
143 num = ReadBits(3) + 3; | |
144 else if (number == kTableLevel0Number2) | |
145 num = ReadBits(7) + 11; | |
146 else | |
147 return false; | |
148 for (;num > 0 && i < numLevels; num--) | |
149 newLevels[i++] = 0; | |
150 } | |
151 } | |
152 } | |
153 if (m_AudioMode) | |
154 for (i = 0; i < m_NumChannels; i++) | |
155 { | |
156 RIF(m_MMDecoders[i].SetCodeLengths(&newLevels[i * kMMTableSize])); | |
157 } | |
158 else | |
159 { | |
160 RIF(m_MainDecoder.SetCodeLengths(&newLevels[0])); | |
161 RIF(m_DistDecoder.SetCodeLengths(&newLevels[kMainTableSize])); | |
162 RIF(m_LenDecoder.SetCodeLengths(&newLevels[kMainTableSize + kDistTableSize])); | |
163 } | |
164 memcpy(m_LastLevels, newLevels, kMaxTableSize); | |
165 return true; | |
166 } | |
167 | |
168 bool CDecoder::ReadLastTables() | |
169 { | |
170 // it differs a little from pure RAR sources; | |
171 // UInt64 ttt = m_InBitStream.GetProcessedSize() + 2; | |
172 // + 2 works for: return 0xFF; in CInBuffer::ReadByte. | |
173 if (m_InBitStream.GetProcessedSize() + 7 <= m_PackSize) // test it: probably incorrect; | |
174 // if (m_InBitStream.GetProcessedSize() + 2 <= m_PackSize) // test it: probably incorrect; | |
175 if (m_AudioMode) | |
176 { | |
177 UInt32 symbol = m_MMDecoders[m_MmFilter.CurrentChannel].DecodeSymbol(&m_InBitStream); | |
178 if (symbol == 256) | |
179 return ReadTables(); | |
180 if (symbol >= kMMTableSize) | |
181 return false; | |
182 } | |
183 else | |
184 { | |
185 UInt32 number = m_MainDecoder.DecodeSymbol(&m_InBitStream); | |
186 if (number == kReadTableNumber) | |
187 return ReadTables(); | |
188 if (number >= kMainTableSize) | |
189 return false; | |
190 } | |
191 return true; | |
192 } | |
193 | |
194 class CCoderReleaser | |
195 { | |
196 CDecoder *m_Coder; | |
197 public: | |
198 CCoderReleaser(CDecoder *coder): m_Coder(coder) {} | |
199 ~CCoderReleaser() | |
200 { | |
201 m_Coder->ReleaseStreams(); | |
202 } | |
203 }; | |
204 | |
205 bool CDecoder::DecodeMm(UInt32 pos) | |
206 { | |
207 while (pos-- > 0) | |
208 { | |
209 UInt32 symbol = m_MMDecoders[m_MmFilter.CurrentChannel].DecodeSymbol(&m_InBitStream); | |
210 if (symbol == 256) | |
211 return true; | |
212 if (symbol >= kMMTableSize) | |
213 return false; | |
214 /* | |
215 Byte byPredict = m_Predictor.Predict(); | |
216 Byte byReal = (Byte)(byPredict - (Byte)symbol); | |
217 m_Predictor.Update(byReal, byPredict); | |
218 */ | |
219 Byte byReal = m_MmFilter.Decode((Byte)symbol); | |
220 m_OutWindowStream.PutByte(byReal); | |
221 if (++m_MmFilter.CurrentChannel == m_NumChannels) | |
222 m_MmFilter.CurrentChannel = 0; | |
223 } | |
224 return true; | |
225 } | |
226 | |
227 bool CDecoder::DecodeLz(Int32 pos) | |
228 { | |
229 while (pos > 0) | |
230 { | |
231 UInt32 number = m_MainDecoder.DecodeSymbol(&m_InBitStream); | |
232 UInt32 length, distance; | |
233 if (number < 256) | |
234 { | |
235 m_OutWindowStream.PutByte(Byte(number)); | |
236 pos--; | |
237 continue; | |
238 } | |
239 else if (number >= kMatchNumber) | |
240 { | |
241 number -= kMatchNumber; | |
242 length = kNormalMatchMinLen + UInt32(kLenStart[number]) + | |
243 m_InBitStream.ReadBits(kLenDirectBits[number]); | |
244 number = m_DistDecoder.DecodeSymbol(&m_InBitStream); | |
245 if (number >= kDistTableSize) | |
246 return false; | |
247 distance = kDistStart[number] + m_InBitStream.ReadBits(kDistDirectBits[number]); | |
248 if (distance >= kDistLimit3) | |
249 { | |
250 length += 2 - ((distance - kDistLimit4) >> 31); | |
251 // length++; | |
252 // if (distance >= kDistLimit4) | |
253 // length++; | |
254 } | |
255 } | |
256 else if (number == kRepBothNumber) | |
257 { | |
258 length = m_LastLength; | |
259 distance = m_RepDists[(m_RepDistPtr + 4 - 1) & 3]; | |
260 } | |
261 else if (number < kLen2Number) | |
262 { | |
263 distance = m_RepDists[(m_RepDistPtr - (number - kRepNumber + 1)) & 3]; | |
264 number = m_LenDecoder.DecodeSymbol(&m_InBitStream); | |
265 if (number >= kLenTableSize) | |
266 return false; | |
267 length = 2 + kLenStart[number] + m_InBitStream.ReadBits(kLenDirectBits[number]); | |
268 if (distance >= kDistLimit2) | |
269 { | |
270 length++; | |
271 if (distance >= kDistLimit3) | |
272 { | |
273 length += 2 - ((distance - kDistLimit4) >> 31); | |
274 // length++; | |
275 // if (distance >= kDistLimit4) | |
276 // length++; | |
277 } | |
278 } | |
279 } | |
280 else if (number < kReadTableNumber) | |
281 { | |
282 number -= kLen2Number; | |
283 distance = kLen2DistStarts[number] + | |
284 m_InBitStream.ReadBits(kLen2DistDirectBits[number]); | |
285 length = 2; | |
286 } | |
287 else if (number == kReadTableNumber) | |
288 return true; | |
289 else | |
290 return false; | |
291 m_RepDists[m_RepDistPtr++ & 3] = distance; | |
292 m_LastLength = length; | |
293 if (!m_OutWindowStream.CopyBlock(distance, length)) | |
294 return false; | |
295 pos -= length; | |
296 } | |
297 return true; | |
298 } | |
299 | |
300 HRESULT CDecoder::CodeReal(ISequentialInStream *inStream, ISequentialOutStream *outStream, | |
301 const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress) | |
302 { | |
303 if (inSize == NULL || outSize == NULL) | |
304 return E_INVALIDARG; | |
305 | |
306 if (!m_OutWindowStream.Create(kHistorySize)) | |
307 return E_OUTOFMEMORY; | |
308 if (!m_InBitStream.Create(1 << 20)) | |
309 return E_OUTOFMEMORY; | |
310 | |
311 m_PackSize = *inSize; | |
312 | |
313 UInt64 pos = 0, unPackSize = *outSize; | |
314 | |
315 m_OutWindowStream.SetStream(outStream); | |
316 m_OutWindowStream.Init(m_IsSolid); | |
317 m_InBitStream.SetStream(inStream); | |
318 m_InBitStream.Init(); | |
319 | |
320 CCoderReleaser coderReleaser(this); | |
321 if (!m_IsSolid) | |
322 { | |
323 InitStructures(); | |
324 if (unPackSize == 0) | |
325 { | |
326 if (m_InBitStream.GetProcessedSize() + 2 <= m_PackSize) // test it: probably incorrect; | |
327 if (!ReadTables()) | |
328 return S_FALSE; | |
329 return S_OK; | |
330 } | |
331 if (!ReadTables()) | |
332 return S_FALSE; | |
333 } | |
334 | |
335 UInt64 startPos = m_OutWindowStream.GetProcessedSize(); | |
336 while(pos < unPackSize) | |
337 { | |
338 UInt32 blockSize = 1 << 20; | |
339 if (blockSize > unPackSize - pos) | |
340 blockSize = (UInt32)(unPackSize - pos); | |
341 UInt64 blockStartPos = m_OutWindowStream.GetProcessedSize(); | |
342 if (m_AudioMode) | |
343 { | |
344 if (!DecodeMm(blockSize)) | |
345 return S_FALSE; | |
346 } | |
347 else | |
348 { | |
349 if (!DecodeLz((Int32)blockSize)) | |
350 return S_FALSE; | |
351 } | |
352 UInt64 globalPos = m_OutWindowStream.GetProcessedSize(); | |
353 pos = globalPos - blockStartPos; | |
354 if (pos < blockSize) | |
355 if (!ReadTables()) | |
356 return S_FALSE; | |
357 pos = globalPos - startPos; | |
358 if (progress != 0) | |
359 { | |
360 UInt64 packSize = m_InBitStream.GetProcessedSize(); | |
361 RINOK(progress->SetRatioInfo(&packSize, &pos)); | |
362 } | |
363 } | |
364 if (pos > unPackSize) | |
365 return S_FALSE; | |
366 | |
367 if (!ReadLastTables()) | |
368 return S_FALSE; | |
369 return m_OutWindowStream.Flush(); | |
370 } | |
371 | |
372 STDMETHODIMP CDecoder::Code(ISequentialInStream *inStream, ISequentialOutStream *outStream, | |
373 const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress) | |
374 { | |
375 try { return CodeReal(inStream, outStream, inSize, outSize, progress); } | |
376 catch(const CInBufferException &e) { return e.ErrorCode; } | |
377 catch(const CLzOutWindowException &e) { return e.ErrorCode; } | |
378 catch(...) { return S_FALSE; } | |
379 } | |
380 | |
381 STDMETHODIMP CDecoder::SetDecoderProperties2(const Byte *data, UInt32 size) | |
382 { | |
383 if (size < 1) | |
384 return E_INVALIDARG; | |
385 m_IsSolid = (data[0] != 0); | |
386 return S_OK; | |
387 } | |
388 | |
389 }} |