Mercurial > vba-linux
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.cpp2 // According to unRAR license, this code may not be used to develop3 // a program that creates RAR archives5 #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 else116 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 else132 {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 else140 {141 int num;142 if (number == kTableLevel0Number)143 num = ReadBits(3) + 3;144 else if (number == kTableLevel0Number2)145 num = ReadBits(7) + 11;146 else147 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 else159 {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 else184 {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 CCoderReleaser195 {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 else290 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 else348 {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 }}