2 // According to unRAR license, this code may not be used to develop
\r
3 // a program that creates RAR archives
\r
7 #include "Rar2Decoder.h"
\r
9 namespace NCompress {
\r
12 namespace NMultimedia {
\r
14 Byte CFilter::Decode(int &channelDelta, Byte deltaByte)
\r
18 D2 = LastDelta - D1;
\r
20 int predictedValue = ((8 * LastChar + K1 * D1 + K2 * D2 + K3 * D3 + K4 * D4 + K5 * channelDelta) >> 3);
\r
22 Byte realValue = (Byte)(predictedValue - deltaByte);
\r
23 int i = ((int)(signed char)deltaByte) << 3;
\r
26 Dif[1] += abs(i - D1);
\r
27 Dif[2] += abs(i + D1);
\r
28 Dif[3] += abs(i - D2);
\r
29 Dif[4] += abs(i + D2);
\r
30 Dif[5] += abs(i - D3);
\r
31 Dif[6] += abs(i + D3);
\r
32 Dif[7] += abs(i - D4);
\r
33 Dif[8] += abs(i + D4);
\r
34 Dif[9] += abs(i - channelDelta);
\r
35 Dif[10] += abs(i + channelDelta);
\r
37 channelDelta = LastDelta = (signed char)(realValue - LastChar);
\r
38 LastChar = realValue;
\r
40 if (((++ByteCount) & 0x1F) == 0)
\r
42 UInt32 minDif = Dif[0];
\r
43 UInt32 numMinDif = 0;
\r
45 for (i = 1; i < sizeof(Dif) / sizeof(Dif[0]); i++)
\r
47 if (Dif[i] < minDif)
\r
56 case 1: if (K1 >= -16) K1--; break;
\r
57 case 2: if (K1 < 16) K1++; break;
\r
58 case 3: if (K2 >= -16) K2--; break;
\r
59 case 4: if (K2 < 16) K2++; break;
\r
60 case 5: if (K3 >= -16) K3--; break;
\r
61 case 6: if (K3 < 16) K3++; break;
\r
62 case 7: if (K4 >= -16) K4--; break;
\r
63 case 8: if (K4 < 16) K4++; break;
\r
64 case 9: if (K5 >= -16) K5--; break;
\r
65 case 10:if (K5 < 16) K5++; break;
\r
72 static const char *kNumberErrorMessage = "Number error";
\r
74 static const UInt32 kHistorySize = 1 << 20;
\r
76 static const int kNumStats = 11;
\r
78 static const UInt32 kWindowReservSize = (1 << 22) + 256;
\r
80 CDecoder::CDecoder():
\r
85 void CDecoder::InitStructures()
\r
88 for(int i = 0; i < kNumRepDists; i++)
\r
92 memset(m_LastLevels, 0, kMaxTableSize);
\r
95 UInt32 CDecoder::ReadBits(int numBits) { return m_InBitStream.ReadBits(numBits); }
\r
97 #define RIF(x) { if (!(x)) return false; }
\r
99 bool CDecoder::ReadTables(void)
\r
101 Byte levelLevels[kLevelTableSize];
\r
102 Byte newLevels[kMaxTableSize];
\r
103 m_AudioMode = (ReadBits(1) == 1);
\r
105 if (ReadBits(1) == 0)
\r
106 memset(m_LastLevels, 0, kMaxTableSize);
\r
110 m_NumChannels = ReadBits(2) + 1;
\r
111 if (m_MmFilter.CurrentChannel >= m_NumChannels)
\r
112 m_MmFilter.CurrentChannel = 0;
\r
113 numLevels = m_NumChannels * kMMTableSize;
\r
116 numLevels = kHeapTablesSizesSum;
\r
119 for (i = 0; i < kLevelTableSize; i++)
\r
120 levelLevels[i] = (Byte)ReadBits(4);
\r
121 RIF(m_LevelDecoder.SetCodeLengths(levelLevels));
\r
123 while (i < numLevels)
\r
125 UInt32 number = m_LevelDecoder.DecodeSymbol(&m_InBitStream);
\r
126 if (number < kTableDirectLevels)
\r
128 newLevels[i] = (Byte)((number + m_LastLevels[i]) & kLevelMask);
\r
133 if (number == kTableLevelRepNumber)
\r
135 int t = ReadBits(2) + 3;
\r
136 for (int reps = t; reps > 0 && i < numLevels ; reps--, i++)
\r
137 newLevels[i] = newLevels[i - 1];
\r
142 if (number == kTableLevel0Number)
\r
143 num = ReadBits(3) + 3;
\r
144 else if (number == kTableLevel0Number2)
\r
145 num = ReadBits(7) + 11;
\r
148 for (;num > 0 && i < numLevels; num--)
\r
149 newLevels[i++] = 0;
\r
154 for (i = 0; i < m_NumChannels; i++)
\r
156 RIF(m_MMDecoders[i].SetCodeLengths(&newLevels[i * kMMTableSize]));
\r
160 RIF(m_MainDecoder.SetCodeLengths(&newLevels[0]));
\r
161 RIF(m_DistDecoder.SetCodeLengths(&newLevels[kMainTableSize]));
\r
162 RIF(m_LenDecoder.SetCodeLengths(&newLevels[kMainTableSize + kDistTableSize]));
\r
164 memcpy(m_LastLevels, newLevels, kMaxTableSize);
\r
168 bool CDecoder::ReadLastTables()
\r
170 // it differs a little from pure RAR sources;
\r
171 // UInt64 ttt = m_InBitStream.GetProcessedSize() + 2;
\r
172 // + 2 works for: return 0xFF; in CInBuffer::ReadByte.
\r
173 if (m_InBitStream.GetProcessedSize() + 7 <= m_PackSize) // test it: probably incorrect;
\r
174 // if (m_InBitStream.GetProcessedSize() + 2 <= m_PackSize) // test it: probably incorrect;
\r
177 UInt32 symbol = m_MMDecoders[m_MmFilter.CurrentChannel].DecodeSymbol(&m_InBitStream);
\r
179 return ReadTables();
\r
180 if (symbol >= kMMTableSize)
\r
185 UInt32 number = m_MainDecoder.DecodeSymbol(&m_InBitStream);
\r
186 if (number == kReadTableNumber)
\r
187 return ReadTables();
\r
188 if (number >= kMainTableSize)
\r
194 class CCoderReleaser
\r
198 CCoderReleaser(CDecoder *coder): m_Coder(coder) {}
\r
201 m_Coder->ReleaseStreams();
\r
205 bool CDecoder::DecodeMm(UInt32 pos)
\r
209 UInt32 symbol = m_MMDecoders[m_MmFilter.CurrentChannel].DecodeSymbol(&m_InBitStream);
\r
212 if (symbol >= kMMTableSize)
\r
215 Byte byPredict = m_Predictor.Predict();
\r
216 Byte byReal = (Byte)(byPredict - (Byte)symbol);
\r
217 m_Predictor.Update(byReal, byPredict);
\r
219 Byte byReal = m_MmFilter.Decode((Byte)symbol);
\r
220 m_OutWindowStream.PutByte(byReal);
\r
221 if (++m_MmFilter.CurrentChannel == m_NumChannels)
\r
222 m_MmFilter.CurrentChannel = 0;
\r
227 bool CDecoder::DecodeLz(Int32 pos)
\r
231 UInt32 number = m_MainDecoder.DecodeSymbol(&m_InBitStream);
\r
232 UInt32 length, distance;
\r
235 m_OutWindowStream.PutByte(Byte(number));
\r
239 else if (number >= kMatchNumber)
\r
241 number -= kMatchNumber;
\r
242 length = kNormalMatchMinLen + UInt32(kLenStart[number]) +
\r
243 m_InBitStream.ReadBits(kLenDirectBits[number]);
\r
244 number = m_DistDecoder.DecodeSymbol(&m_InBitStream);
\r
245 if (number >= kDistTableSize)
\r
247 distance = kDistStart[number] + m_InBitStream.ReadBits(kDistDirectBits[number]);
\r
248 if (distance >= kDistLimit3)
\r
250 length += 2 - ((distance - kDistLimit4) >> 31);
\r
252 // if (distance >= kDistLimit4)
\r
256 else if (number == kRepBothNumber)
\r
258 length = m_LastLength;
\r
261 distance = m_RepDists[(m_RepDistPtr + 4 - 1) & 3];
\r
263 else if (number < kLen2Number)
\r
265 distance = m_RepDists[(m_RepDistPtr - (number - kRepNumber + 1)) & 3];
\r
266 number = m_LenDecoder.DecodeSymbol(&m_InBitStream);
\r
267 if (number >= kLenTableSize)
\r
269 length = 2 + kLenStart[number] + m_InBitStream.ReadBits(kLenDirectBits[number]);
\r
270 if (distance >= kDistLimit2)
\r
273 if (distance >= kDistLimit3)
\r
275 length += 2 - ((distance - kDistLimit4) >> 31);
\r
277 // if (distance >= kDistLimit4)
\r
282 else if (number < kReadTableNumber)
\r
284 number -= kLen2Number;
\r
285 distance = kLen2DistStarts[number] +
\r
286 m_InBitStream.ReadBits(kLen2DistDirectBits[number]);
\r
289 else if (number == kReadTableNumber)
\r
293 m_RepDists[m_RepDistPtr++ & 3] = distance;
\r
294 m_LastLength = length;
\r
295 if (!m_OutWindowStream.CopyBlock(distance, length))
\r
302 HRESULT CDecoder::CodeReal(ISequentialInStream *inStream, ISequentialOutStream *outStream,
\r
303 const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress)
\r
305 if (inSize == NULL || outSize == NULL)
\r
306 return E_INVALIDARG;
\r
308 if (!m_OutWindowStream.Create(kHistorySize))
\r
309 return E_OUTOFMEMORY;
\r
310 if (!m_InBitStream.Create(1 << 20))
\r
311 return E_OUTOFMEMORY;
\r
313 m_PackSize = *inSize;
\r
315 UInt64 pos = 0, unPackSize = *outSize;
\r
317 m_OutWindowStream.SetStream(outStream);
\r
318 m_OutWindowStream.Init(m_IsSolid);
\r
319 m_InBitStream.SetStream(inStream);
\r
320 m_InBitStream.Init();
\r
322 CCoderReleaser coderReleaser(this);
\r
326 if (unPackSize == 0)
\r
328 if (m_InBitStream.GetProcessedSize() + 2 <= m_PackSize) // test it: probably incorrect;
\r
337 UInt64 startPos = m_OutWindowStream.GetProcessedSize();
\r
338 while(pos < unPackSize)
\r
340 UInt32 blockSize = 1 << 20;
\r
341 if (blockSize > unPackSize - pos)
\r
342 blockSize = (UInt32)(unPackSize - pos);
\r
343 UInt64 blockStartPos = m_OutWindowStream.GetProcessedSize();
\r
346 if (!DecodeMm(blockSize))
\r
351 if (!DecodeLz((Int32)blockSize))
\r
354 UInt64 globalPos = m_OutWindowStream.GetProcessedSize();
\r
355 pos = globalPos - blockStartPos;
\r
356 if (pos < blockSize)
\r
359 pos = globalPos - startPos;
\r
362 UInt64 packSize = m_InBitStream.GetProcessedSize();
\r
363 RINOK(progress->SetRatioInfo(&packSize, &pos));
\r
366 if (pos > unPackSize)
\r
369 if (!ReadLastTables())
\r
371 return m_OutWindowStream.Flush();
\r
374 STDMETHODIMP CDecoder::Code(ISequentialInStream *inStream, ISequentialOutStream *outStream,
\r
375 const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress)
\r
377 try { return CodeReal(inStream, outStream, inSize, outSize, progress); }
\r
378 catch(const CInBufferException &e) { return e.ErrorCode; }
\r
379 catch(const CLzOutWindowException &e) { return e.ErrorCode; }
\r
380 catch(...) { return S_FALSE; }
\r
383 STDMETHODIMP CDecoder::SetDecoderProperties2(const Byte *data, UInt32 size)
\r
386 return E_INVALIDARG;
\r
387 m_IsSolid = (data[0] != 0);
\r