annotate 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
rev   line source
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 }}