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