view 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
line wrap: on
line source
1 // Rar2Decoder.cpp
2 // According to unRAR license, this code may not be used to develop
3 // a program that creates RAR archives
5 #include "StdAfx.h"
7 #include "Rar2Decoder.h"
9 namespace NCompress {
10 namespace NRar2 {
12 namespace NMultimedia {
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);
22 Byte realValue = (Byte)(predictedValue - deltaByte);
23 int i = ((int)(signed char)deltaByte) << 3;
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);
37 channelDelta = LastDelta = (signed char)(realValue - LastChar);
38 LastChar = realValue;
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 }
72 static const char *kNumberErrorMessage = "Number error";
74 static const UInt32 kHistorySize = 1 << 20;
76 static const int kNumStats = 11;
78 static const UInt32 kWindowReservSize = (1 << 22) + 256;
80 CDecoder::CDecoder():
81 m_IsSolid(false)
82 {
83 }
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 }
95 UInt32 CDecoder::ReadBits(int numBits) { return m_InBitStream.ReadBits(numBits); }
97 #define RIF(x) { if (!(x)) return false; }
99 bool CDecoder::ReadTables(void)
100 {
101 Byte levelLevels[kLevelTableSize];
102 Byte newLevels[kMaxTableSize];
103 m_AudioMode = (ReadBits(1) == 1);
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;
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 }
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 }
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 };
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 }
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 }
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;
306 if (!m_OutWindowStream.Create(kHistorySize))
307 return E_OUTOFMEMORY;
308 if (!m_InBitStream.Create(1 << 20))
309 return E_OUTOFMEMORY;
311 m_PackSize = *inSize;
313 UInt64 pos = 0, unPackSize = *outSize;
315 m_OutWindowStream.SetStream(outStream);
316 m_OutWindowStream.Init(m_IsSolid);
317 m_InBitStream.SetStream(inStream);
318 m_InBitStream.Init();
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 }
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;
367 if (!ReadLastTables())
368 return S_FALSE;
369 return m_OutWindowStream.Flush();
370 }
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 }
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 }
389 }}