annotate src/win32/7zip/7z/CPP/7zip/Compress/Rar3Decoder.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 // Rar3Decoder.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 "../Common/StreamUtils.h"
rlm@1 8
rlm@1 9 #include "Rar3Decoder.h"
rlm@1 10
rlm@1 11 namespace NCompress {
rlm@1 12 namespace NRar3 {
rlm@1 13
rlm@1 14 static const UInt32 kNumAlignReps = 15;
rlm@1 15
rlm@1 16 static const UInt32 kSymbolReadTable = 256;
rlm@1 17 static const UInt32 kSymbolRep = 259;
rlm@1 18 static const UInt32 kSymbolLen2 = kSymbolRep + kNumReps;
rlm@1 19
rlm@1 20 static const Byte kLenStart[kLenTableSize] = {0,1,2,3,4,5,6,7,8,10,12,14,16,20,24,28,32,40,48,56,64,80,96,112,128,160,192,224};
rlm@1 21 static const Byte kLenDirectBits[kLenTableSize] = {0,0,0,0,0,0,0,0,1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5};
rlm@1 22
rlm@1 23 static const Byte kDistDirectBits[kDistTableSize] =
rlm@1 24 {0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13,14,14,15,15,
rlm@1 25 16,16,16,16,16,16,16,16,16,16,16,16,16,16,
rlm@1 26 18,18,18,18,18,18,18,18,18,18,18,18};
rlm@1 27
rlm@1 28 static const Byte kLevelDirectBits[kLevelTableSize] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,7};
rlm@1 29
rlm@1 30 static const Byte kLen2DistStarts[kNumLen2Symbols]={0,4,8,16,32,64,128,192};
rlm@1 31 static const Byte kLen2DistDirectBits[kNumLen2Symbols]={2,2,3, 4, 5, 6, 6, 6};
rlm@1 32
rlm@1 33 static const UInt32 kDistLimit3 = 0x2000 - 2;
rlm@1 34 static const UInt32 kDistLimit4 = 0x40000 - 2;
rlm@1 35
rlm@1 36 static const UInt32 kNormalMatchMinLen = 3;
rlm@1 37
rlm@1 38 static const UInt32 kVmDataSizeMax = 1 << 16;
rlm@1 39 static const UInt32 kVmCodeSizeMax = 1 << 16;
rlm@1 40
rlm@1 41 CDecoder::CDecoder():
rlm@1 42 _window(0),
rlm@1 43 _winPos(0),
rlm@1 44 _wrPtr(0),
rlm@1 45 _lzSize(0),
rlm@1 46 _writtenFileSize(0),
rlm@1 47 _vmData(0),
rlm@1 48 _vmCode(0),
rlm@1 49 m_IsSolid(false)
rlm@1 50 {
rlm@1 51 }
rlm@1 52
rlm@1 53 CDecoder::~CDecoder()
rlm@1 54 {
rlm@1 55 InitFilters();
rlm@1 56 ::MidFree(_vmData);
rlm@1 57 ::MidFree(_window);
rlm@1 58 }
rlm@1 59
rlm@1 60 HRESULT CDecoder::WriteDataToStream(const Byte *data, UInt32 size)
rlm@1 61 {
rlm@1 62 return WriteStream(_outStream, data, size);
rlm@1 63 }
rlm@1 64
rlm@1 65 HRESULT CDecoder::WriteData(const Byte *data, UInt32 size)
rlm@1 66 {
rlm@1 67 HRESULT res = S_OK;
rlm@1 68 if (_writtenFileSize < _unpackSize)
rlm@1 69 {
rlm@1 70 UInt32 curSize = size;
rlm@1 71 UInt64 remain = _unpackSize - _writtenFileSize;
rlm@1 72 if (remain < curSize)
rlm@1 73 curSize = (UInt32)remain;
rlm@1 74 res = WriteDataToStream(data, curSize);
rlm@1 75 }
rlm@1 76 _writtenFileSize += size;
rlm@1 77 return res;
rlm@1 78 }
rlm@1 79
rlm@1 80 HRESULT CDecoder::WriteArea(UInt32 startPtr, UInt32 endPtr)
rlm@1 81 {
rlm@1 82 if (startPtr <= endPtr)
rlm@1 83 return WriteData(_window + startPtr, endPtr - startPtr);
rlm@1 84 RINOK(WriteData(_window + startPtr, kWindowSize - startPtr));
rlm@1 85 return WriteData(_window, endPtr);
rlm@1 86 }
rlm@1 87
rlm@1 88 void CDecoder::ExecuteFilter(int tempFilterIndex, NVm::CBlockRef &outBlockRef)
rlm@1 89 {
rlm@1 90 CTempFilter *tempFilter = _tempFilters[tempFilterIndex];
rlm@1 91 tempFilter->InitR[6] = (UInt32)_writtenFileSize;
rlm@1 92 NVm::SetValue32(&tempFilter->GlobalData[0x24], (UInt32)_writtenFileSize);
rlm@1 93 NVm::SetValue32(&tempFilter->GlobalData[0x28], (UInt32)(_writtenFileSize >> 32));
rlm@1 94 CFilter *filter = _filters[tempFilter->FilterIndex];
rlm@1 95 _vm.Execute(filter, tempFilter, outBlockRef, filter->GlobalData);
rlm@1 96 delete tempFilter;
rlm@1 97 _tempFilters[tempFilterIndex] = 0;
rlm@1 98 }
rlm@1 99
rlm@1 100 HRESULT CDecoder::WriteBuf()
rlm@1 101 {
rlm@1 102 UInt32 writtenBorder = _wrPtr;
rlm@1 103 UInt32 writeSize = (_winPos - writtenBorder) & kWindowMask;
rlm@1 104 for (int i = 0; i < _tempFilters.Size(); i++)
rlm@1 105 {
rlm@1 106 CTempFilter *filter = _tempFilters[i];
rlm@1 107 if (filter == NULL)
rlm@1 108 continue;
rlm@1 109 if (filter->NextWindow)
rlm@1 110 {
rlm@1 111 filter->NextWindow = false;
rlm@1 112 continue;
rlm@1 113 }
rlm@1 114 UInt32 blockStart = filter->BlockStart;
rlm@1 115 UInt32 blockSize = filter->BlockSize;
rlm@1 116 if (((blockStart - writtenBorder) & kWindowMask) < writeSize)
rlm@1 117 {
rlm@1 118 if (writtenBorder != blockStart)
rlm@1 119 {
rlm@1 120 RINOK(WriteArea(writtenBorder, blockStart));
rlm@1 121 writtenBorder = blockStart;
rlm@1 122 writeSize = (_winPos - writtenBorder) & kWindowMask;
rlm@1 123 }
rlm@1 124 if (blockSize <= writeSize)
rlm@1 125 {
rlm@1 126 UInt32 blockEnd = (blockStart + blockSize) & kWindowMask;
rlm@1 127 if (blockStart < blockEnd || blockEnd == 0)
rlm@1 128 _vm.SetMemory(0, _window + blockStart, blockSize);
rlm@1 129 else
rlm@1 130 {
rlm@1 131 UInt32 tailSize = kWindowSize - blockStart;
rlm@1 132 _vm.SetMemory(0, _window + blockStart, tailSize);
rlm@1 133 _vm.SetMemory(tailSize, _window, blockEnd);
rlm@1 134 }
rlm@1 135 NVm::CBlockRef outBlockRef;
rlm@1 136 ExecuteFilter(i, outBlockRef);
rlm@1 137 while (i + 1 < _tempFilters.Size())
rlm@1 138 {
rlm@1 139 CTempFilter *nextFilter = _tempFilters[i + 1];
rlm@1 140 if (nextFilter == NULL || nextFilter->BlockStart != blockStart ||
rlm@1 141 nextFilter->BlockSize != outBlockRef.Size || nextFilter->NextWindow)
rlm@1 142 break;
rlm@1 143 _vm.SetMemory(0, _vm.GetDataPointer(outBlockRef.Offset), outBlockRef.Size);
rlm@1 144 ExecuteFilter(++i, outBlockRef);
rlm@1 145 }
rlm@1 146 WriteDataToStream(_vm.GetDataPointer(outBlockRef.Offset), outBlockRef.Size);
rlm@1 147 _writtenFileSize += outBlockRef.Size;
rlm@1 148 writtenBorder = blockEnd;
rlm@1 149 writeSize = (_winPos - writtenBorder) & kWindowMask;
rlm@1 150 }
rlm@1 151 else
rlm@1 152 {
rlm@1 153 for (int j = i; j < _tempFilters.Size(); j++)
rlm@1 154 {
rlm@1 155 CTempFilter *filter = _tempFilters[j];
rlm@1 156 if (filter != NULL && filter->NextWindow)
rlm@1 157 filter->NextWindow = false;
rlm@1 158 }
rlm@1 159 _wrPtr = writtenBorder;
rlm@1 160 return S_OK; // check it
rlm@1 161 }
rlm@1 162 }
rlm@1 163 }
rlm@1 164
rlm@1 165 _wrPtr = _winPos;
rlm@1 166 return WriteArea(writtenBorder, _winPos);
rlm@1 167 }
rlm@1 168
rlm@1 169 void CDecoder::InitFilters()
rlm@1 170 {
rlm@1 171 _lastFilter = 0;
rlm@1 172 int i;
rlm@1 173 for (i = 0; i < _tempFilters.Size(); i++)
rlm@1 174 delete _tempFilters[i];
rlm@1 175 _tempFilters.Clear();
rlm@1 176 for (i = 0; i < _filters.Size(); i++)
rlm@1 177 delete _filters[i];
rlm@1 178 _filters.Clear();
rlm@1 179 }
rlm@1 180
rlm@1 181 bool CDecoder::AddVmCode(UInt32 firstByte, UInt32 codeSize)
rlm@1 182 {
rlm@1 183 CMemBitDecoder inp;
rlm@1 184 inp.Init(_vmData, codeSize);
rlm@1 185
rlm@1 186 UInt32 filterIndex;
rlm@1 187 if (firstByte & 0x80)
rlm@1 188 {
rlm@1 189 filterIndex = NVm::ReadEncodedUInt32(inp);
rlm@1 190 if (filterIndex == 0)
rlm@1 191 InitFilters();
rlm@1 192 else
rlm@1 193 filterIndex--;
rlm@1 194 }
rlm@1 195 else
rlm@1 196 filterIndex = _lastFilter;
rlm@1 197 if (filterIndex > (UInt32)_filters.Size())
rlm@1 198 return false;
rlm@1 199 _lastFilter = filterIndex;
rlm@1 200 bool newFilter = (filterIndex == (UInt32)_filters.Size());
rlm@1 201
rlm@1 202 CFilter *filter;
rlm@1 203 if (newFilter)
rlm@1 204 {
rlm@1 205 // check if too many filters
rlm@1 206 if (filterIndex > 1024)
rlm@1 207 return false;
rlm@1 208 filter = new CFilter;
rlm@1 209 _filters.Add(filter);
rlm@1 210 }
rlm@1 211 else
rlm@1 212 {
rlm@1 213 filter = _filters[filterIndex];
rlm@1 214 filter->ExecCount++;
rlm@1 215 }
rlm@1 216
rlm@1 217 int numEmptyItems = 0;
rlm@1 218 int i;
rlm@1 219 for (i = 0; i < _tempFilters.Size(); i++)
rlm@1 220 {
rlm@1 221 _tempFilters[i - numEmptyItems] = _tempFilters[i];
rlm@1 222 if (_tempFilters[i] == NULL)
rlm@1 223 numEmptyItems++;
rlm@1 224 if (numEmptyItems > 0)
rlm@1 225 _tempFilters[i] = NULL;
rlm@1 226 }
rlm@1 227 if (numEmptyItems == 0)
rlm@1 228 {
rlm@1 229 _tempFilters.Add(NULL);
rlm@1 230 numEmptyItems = 1;
rlm@1 231 }
rlm@1 232 CTempFilter *tempFilter = new CTempFilter;
rlm@1 233 _tempFilters[_tempFilters.Size() - numEmptyItems] = tempFilter;
rlm@1 234 tempFilter->FilterIndex = filterIndex;
rlm@1 235 tempFilter->ExecCount = filter->ExecCount;
rlm@1 236
rlm@1 237 UInt32 blockStart = NVm::ReadEncodedUInt32(inp);
rlm@1 238 if (firstByte & 0x40)
rlm@1 239 blockStart += 258;
rlm@1 240 tempFilter->BlockStart = (blockStart + _winPos) & kWindowMask;
rlm@1 241 if (firstByte & 0x20)
rlm@1 242 filter->BlockSize = NVm::ReadEncodedUInt32(inp);
rlm@1 243 tempFilter->BlockSize = filter->BlockSize;
rlm@1 244 tempFilter->NextWindow = _wrPtr != _winPos && ((_wrPtr - _winPos) & kWindowMask) <= blockStart;
rlm@1 245
rlm@1 246 memset(tempFilter->InitR, 0, sizeof(tempFilter->InitR));
rlm@1 247 tempFilter->InitR[3] = NVm::kGlobalOffset;
rlm@1 248 tempFilter->InitR[4] = tempFilter->BlockSize;
rlm@1 249 tempFilter->InitR[5] = tempFilter->ExecCount;
rlm@1 250 if (firstByte & 0x10)
rlm@1 251 {
rlm@1 252 UInt32 initMask = inp.ReadBits(NVm::kNumGpRegs);
rlm@1 253 for (int i = 0; i < NVm::kNumGpRegs; i++)
rlm@1 254 if (initMask & (1 << i))
rlm@1 255 tempFilter->InitR[i] = NVm::ReadEncodedUInt32(inp);
rlm@1 256 }
rlm@1 257 if (newFilter)
rlm@1 258 {
rlm@1 259 UInt32 vmCodeSize = NVm::ReadEncodedUInt32(inp);
rlm@1 260 if (vmCodeSize >= kVmCodeSizeMax || vmCodeSize == 0)
rlm@1 261 return false;
rlm@1 262 for (UInt32 i = 0; i < vmCodeSize; i++)
rlm@1 263 _vmCode[i] = (Byte)inp.ReadBits(8);
rlm@1 264 _vm.PrepareProgram(_vmCode, vmCodeSize, filter);
rlm@1 265 }
rlm@1 266
rlm@1 267 tempFilter->AllocateEmptyFixedGlobal();
rlm@1 268
rlm@1 269 Byte *globalData = &tempFilter->GlobalData[0];
rlm@1 270 for (i = 0; i < NVm::kNumGpRegs; i++)
rlm@1 271 NVm::SetValue32(&globalData[i * 4], tempFilter->InitR[i]);
rlm@1 272 NVm::SetValue32(&globalData[NVm::NGlobalOffset::kBlockSize], tempFilter->BlockSize);
rlm@1 273 NVm::SetValue32(&globalData[NVm::NGlobalOffset::kBlockPos], 0); // It was commented. why?
rlm@1 274 NVm::SetValue32(&globalData[NVm::NGlobalOffset::kExecCount], tempFilter->ExecCount);
rlm@1 275
rlm@1 276 if (firstByte & 8)
rlm@1 277 {
rlm@1 278 UInt32 dataSize = NVm::ReadEncodedUInt32(inp);
rlm@1 279 if (dataSize > NVm::kGlobalSize - NVm::kFixedGlobalSize)
rlm@1 280 return false;
rlm@1 281 CRecordVector<Byte> &globalData = tempFilter->GlobalData;
rlm@1 282 int requredSize = (int)(dataSize + NVm::kFixedGlobalSize);
rlm@1 283 if (globalData.Size() < requredSize)
rlm@1 284 {
rlm@1 285 globalData.Reserve(requredSize);
rlm@1 286 for (; globalData.Size() < requredSize; i++)
rlm@1 287 globalData.Add(0);
rlm@1 288 }
rlm@1 289 for (UInt32 i = 0; i < dataSize; i++)
rlm@1 290 globalData[NVm::kFixedGlobalSize + i] = (Byte)inp.ReadBits(8);
rlm@1 291 }
rlm@1 292 return true;
rlm@1 293 }
rlm@1 294
rlm@1 295 bool CDecoder::ReadVmCodeLZ()
rlm@1 296 {
rlm@1 297 UInt32 firstByte = m_InBitStream.ReadBits(8);
rlm@1 298 UInt32 length = (firstByte & 7) + 1;
rlm@1 299 if (length == 7)
rlm@1 300 length = m_InBitStream.ReadBits(8) + 7;
rlm@1 301 else if (length == 8)
rlm@1 302 length = m_InBitStream.ReadBits(16);
rlm@1 303 if (length > kVmDataSizeMax)
rlm@1 304 return false;
rlm@1 305 for (UInt32 i = 0; i < length; i++)
rlm@1 306 _vmData[i] = (Byte)m_InBitStream.ReadBits(8);
rlm@1 307 return AddVmCode(firstByte, length);
rlm@1 308 }
rlm@1 309
rlm@1 310 bool CDecoder::ReadVmCodePPM()
rlm@1 311 {
rlm@1 312 int firstByte = DecodePpmSymbol();
rlm@1 313 if (firstByte == -1)
rlm@1 314 return false;
rlm@1 315 UInt32 length = (firstByte & 7) + 1;
rlm@1 316 if (length == 7)
rlm@1 317 {
rlm@1 318 int b1 = DecodePpmSymbol();
rlm@1 319 if (b1 == -1)
rlm@1 320 return false;
rlm@1 321 length = b1 + 7;
rlm@1 322 }
rlm@1 323 else if (length == 8)
rlm@1 324 {
rlm@1 325 int b1 = DecodePpmSymbol();
rlm@1 326 if (b1 == -1)
rlm@1 327 return false;
rlm@1 328 int b2 = DecodePpmSymbol();
rlm@1 329 if (b2 == -1)
rlm@1 330 return false;
rlm@1 331 length = b1 * 256 + b2;
rlm@1 332 }
rlm@1 333 if (length > kVmDataSizeMax)
rlm@1 334 return false;
rlm@1 335 for (UInt32 i = 0; i < length; i++)
rlm@1 336 {
rlm@1 337 int b = DecodePpmSymbol();
rlm@1 338 if (b == -1)
rlm@1 339 return false;
rlm@1 340 _vmData[i] = (Byte)b;
rlm@1 341 }
rlm@1 342 return AddVmCode(firstByte, length);
rlm@1 343 }
rlm@1 344
rlm@1 345 #define RIF(x) { if (!(x)) return S_FALSE; }
rlm@1 346
rlm@1 347 UInt32 CDecoder::ReadBits(int numBits) { return m_InBitStream.ReadBits(numBits); }
rlm@1 348
rlm@1 349 /////////////////////////////////////////////////
rlm@1 350 // PPM
rlm@1 351
rlm@1 352 HRESULT CDecoder::InitPPM()
rlm@1 353 {
rlm@1 354 Byte maxOrder = (Byte)ReadBits(7);
rlm@1 355
rlm@1 356 bool reset = ((maxOrder & 0x20) != 0);
rlm@1 357 int maxMB = 0;
rlm@1 358 if (reset)
rlm@1 359 maxMB = (Byte)ReadBits(8);
rlm@1 360 else
rlm@1 361 {
rlm@1 362 if (_ppm.SubAllocator.GetSubAllocatorSize()== 0)
rlm@1 363 return S_FALSE;
rlm@1 364 }
rlm@1 365 if (maxOrder & 0x40)
rlm@1 366 PpmEscChar = (Byte)ReadBits(8);
rlm@1 367 m_InBitStream.InitRangeCoder();
rlm@1 368 /*
rlm@1 369 if (m_InBitStream.m_BitPos != 0)
rlm@1 370 return S_FALSE;
rlm@1 371 */
rlm@1 372 if (reset)
rlm@1 373 {
rlm@1 374 maxOrder = (maxOrder & 0x1F) + 1;
rlm@1 375 if (maxOrder > 16)
rlm@1 376 maxOrder = 16 + (maxOrder - 16) * 3;
rlm@1 377 if (maxOrder == 1)
rlm@1 378 {
rlm@1 379 // SubAlloc.StopSubAllocator();
rlm@1 380 _ppm.SubAllocator.StopSubAllocator();
rlm@1 381 return S_FALSE;
rlm@1 382 }
rlm@1 383 // SubAlloc.StartSubAllocator(MaxMB+1);
rlm@1 384 // StartModelRare(maxOrder);
rlm@1 385
rlm@1 386 if (!_ppm.SubAllocator.StartSubAllocator((maxMB + 1) << 20))
rlm@1 387 return E_OUTOFMEMORY;
rlm@1 388 _ppm.MaxOrder = 0;
rlm@1 389 _ppm.StartModelRare(maxOrder);
rlm@1 390
rlm@1 391 }
rlm@1 392 // return (minContext != NULL);
rlm@1 393
rlm@1 394 return S_OK;
rlm@1 395 }
rlm@1 396
rlm@1 397 int CDecoder::DecodePpmSymbol() { return _ppm.DecodeSymbol(&m_InBitStream); }
rlm@1 398
rlm@1 399 HRESULT CDecoder::DecodePPM(Int32 num, bool &keepDecompressing)
rlm@1 400 {
rlm@1 401 keepDecompressing = false;
rlm@1 402 do
rlm@1 403 {
rlm@1 404 if (((_wrPtr - _winPos) & kWindowMask) < 260 && _wrPtr != _winPos)
rlm@1 405 {
rlm@1 406 RINOK(WriteBuf());
rlm@1 407 if (_writtenFileSize > _unpackSize)
rlm@1 408 {
rlm@1 409 keepDecompressing = false;
rlm@1 410 return S_OK;
rlm@1 411 }
rlm@1 412 }
rlm@1 413 int c = DecodePpmSymbol();
rlm@1 414 if (c == -1)
rlm@1 415 {
rlm@1 416 // Original code sets PPMError=true here and then it returns S_OK. Why ???
rlm@1 417 // return S_OK;
rlm@1 418 return S_FALSE;
rlm@1 419 }
rlm@1 420 if (c == PpmEscChar)
rlm@1 421 {
rlm@1 422 int nextCh = DecodePpmSymbol();
rlm@1 423 if (nextCh == 0)
rlm@1 424 return ReadTables(keepDecompressing);
rlm@1 425 if (nextCh == 2 || nextCh == -1)
rlm@1 426 return S_OK;
rlm@1 427 if (nextCh == 3)
rlm@1 428 {
rlm@1 429 if (!ReadVmCodePPM())
rlm@1 430 return S_FALSE;
rlm@1 431 continue;
rlm@1 432 }
rlm@1 433 if (nextCh == 4 || nextCh == 5)
rlm@1 434 {
rlm@1 435 UInt32 distance = 0;
rlm@1 436 UInt32 length = 4;
rlm@1 437 if (nextCh == 4)
rlm@1 438 {
rlm@1 439 for (int i = 0; i < 3; i++)
rlm@1 440 {
rlm@1 441 int c = DecodePpmSymbol();
rlm@1 442 if (c == -1)
rlm@1 443 return S_OK;
rlm@1 444 distance = (distance << 8) + (Byte)c;
rlm@1 445 }
rlm@1 446 distance++;
rlm@1 447 length += 28;
rlm@1 448 }
rlm@1 449 int c = DecodePpmSymbol();
rlm@1 450 if (c == -1)
rlm@1 451 return S_OK;
rlm@1 452 length += c;
rlm@1 453 if (distance >= _lzSize)
rlm@1 454 return S_FALSE;
rlm@1 455 CopyBlock(distance, length);
rlm@1 456 num -= (Int32)length;
rlm@1 457 continue;
rlm@1 458 }
rlm@1 459 }
rlm@1 460 PutByte((Byte)c);
rlm@1 461 num--;
rlm@1 462 }
rlm@1 463 while (num >= 0);
rlm@1 464 keepDecompressing = true;
rlm@1 465 return S_OK;
rlm@1 466 }
rlm@1 467
rlm@1 468 /////////////////////////////////////////////////
rlm@1 469 // LZ
rlm@1 470
rlm@1 471 HRESULT CDecoder::ReadTables(bool &keepDecompressing)
rlm@1 472 {
rlm@1 473 keepDecompressing = true;
rlm@1 474 ReadBits((8 - m_InBitStream.GetBitPosition()) & 7);
rlm@1 475 if (ReadBits(1) != 0)
rlm@1 476 {
rlm@1 477 _lzMode = false;
rlm@1 478 return InitPPM();
rlm@1 479 }
rlm@1 480
rlm@1 481 _lzMode = true;
rlm@1 482 PrevAlignBits = 0;
rlm@1 483 PrevAlignCount = 0;
rlm@1 484
rlm@1 485 Byte levelLevels[kLevelTableSize];
rlm@1 486 Byte newLevels[kTablesSizesSum];
rlm@1 487
rlm@1 488 if (ReadBits(1) == 0)
rlm@1 489 memset(m_LastLevels, 0, kTablesSizesSum);
rlm@1 490
rlm@1 491 int i;
rlm@1 492 for (i = 0; i < kLevelTableSize; i++)
rlm@1 493 {
rlm@1 494 UInt32 length = ReadBits(4);
rlm@1 495 if (length == 15)
rlm@1 496 {
rlm@1 497 UInt32 zeroCount = ReadBits(4);
rlm@1 498 if (zeroCount != 0)
rlm@1 499 {
rlm@1 500 zeroCount += 2;
rlm@1 501 while (zeroCount-- > 0 && i < kLevelTableSize)
rlm@1 502 levelLevels[i++]=0;
rlm@1 503 i--;
rlm@1 504 continue;
rlm@1 505 }
rlm@1 506 }
rlm@1 507 levelLevels[i] = (Byte)length;
rlm@1 508 }
rlm@1 509 RIF(m_LevelDecoder.SetCodeLengths(levelLevels));
rlm@1 510 i = 0;
rlm@1 511 while (i < kTablesSizesSum)
rlm@1 512 {
rlm@1 513 UInt32 number = m_LevelDecoder.DecodeSymbol(&m_InBitStream);
rlm@1 514 if (number < 16)
rlm@1 515 {
rlm@1 516 newLevels[i] = Byte((number + m_LastLevels[i]) & 15);
rlm@1 517 i++;
rlm@1 518 }
rlm@1 519 else if (number > kLevelTableSize)
rlm@1 520 return S_FALSE;
rlm@1 521 else
rlm@1 522 {
rlm@1 523 int num;
rlm@1 524 if (((number - 16) & 1) == 0)
rlm@1 525 num = ReadBits(3) + 3;
rlm@1 526 else
rlm@1 527 num = ReadBits(7) + 11;
rlm@1 528 if (number < 18)
rlm@1 529 {
rlm@1 530 if (i == 0)
rlm@1 531 return S_FALSE;
rlm@1 532 for (; num > 0 && i < kTablesSizesSum; num--, i++)
rlm@1 533 newLevels[i] = newLevels[i - 1];
rlm@1 534 }
rlm@1 535 else
rlm@1 536 {
rlm@1 537 for (; num > 0 && i < kTablesSizesSum; num--)
rlm@1 538 newLevels[i++] = 0;
rlm@1 539 }
rlm@1 540 }
rlm@1 541 }
rlm@1 542 TablesRead = true;
rlm@1 543
rlm@1 544 // original code has check here:
rlm@1 545 /*
rlm@1 546 if (InAddr > ReadTop)
rlm@1 547 {
rlm@1 548 keepDecompressing = false;
rlm@1 549 return true;
rlm@1 550 }
rlm@1 551 */
rlm@1 552
rlm@1 553 RIF(m_MainDecoder.SetCodeLengths(&newLevels[0]));
rlm@1 554 RIF(m_DistDecoder.SetCodeLengths(&newLevels[kMainTableSize]));
rlm@1 555 RIF(m_AlignDecoder.SetCodeLengths(&newLevels[kMainTableSize + kDistTableSize]));
rlm@1 556 RIF(m_LenDecoder.SetCodeLengths(&newLevels[kMainTableSize + kDistTableSize + kAlignTableSize]));
rlm@1 557
rlm@1 558 memcpy(m_LastLevels, newLevels, kTablesSizesSum);
rlm@1 559 return S_OK;
rlm@1 560 }
rlm@1 561
rlm@1 562 class CCoderReleaser
rlm@1 563 {
rlm@1 564 CDecoder *m_Coder;
rlm@1 565 public:
rlm@1 566 CCoderReleaser(CDecoder *coder): m_Coder(coder) {}
rlm@1 567 ~CCoderReleaser()
rlm@1 568 {
rlm@1 569 // m_Coder->m_OutWindowStream.Flush();
rlm@1 570 m_Coder->ReleaseStreams();
rlm@1 571 }
rlm@1 572 };
rlm@1 573
rlm@1 574 HRESULT CDecoder::ReadEndOfBlock(bool &keepDecompressing)
rlm@1 575 {
rlm@1 576 if (ReadBits(1) != 0)
rlm@1 577 {
rlm@1 578 // old file
rlm@1 579 TablesRead = false;
rlm@1 580 return ReadTables(keepDecompressing);
rlm@1 581 }
rlm@1 582 // new file
rlm@1 583 keepDecompressing = false;
rlm@1 584 TablesRead = (ReadBits(1) == 0);
rlm@1 585 return S_OK;
rlm@1 586 }
rlm@1 587
rlm@1 588 UInt32 kDistStart[kDistTableSize];
rlm@1 589
rlm@1 590 class CDistInit
rlm@1 591 {
rlm@1 592 public:
rlm@1 593 CDistInit() { Init(); }
rlm@1 594 void Init()
rlm@1 595 {
rlm@1 596 UInt32 start = 0;
rlm@1 597 for (UInt32 i = 0; i < kDistTableSize; i++)
rlm@1 598 {
rlm@1 599 kDistStart[i] = start;
rlm@1 600 start += (1 << kDistDirectBits[i]);
rlm@1 601 }
rlm@1 602 }
rlm@1 603 } g_DistInit;
rlm@1 604
rlm@1 605 HRESULT CDecoder::DecodeLZ(bool &keepDecompressing)
rlm@1 606 {
rlm@1 607 UInt32 rep0 = _reps[0];
rlm@1 608 UInt32 rep1 = _reps[1];
rlm@1 609 UInt32 rep2 = _reps[2];
rlm@1 610 UInt32 rep3 = _reps[3];
rlm@1 611 UInt32 length = _lastLength;
rlm@1 612 for (;;)
rlm@1 613 {
rlm@1 614 if (((_wrPtr - _winPos) & kWindowMask) < 260 && _wrPtr != _winPos)
rlm@1 615 {
rlm@1 616 RINOK(WriteBuf());
rlm@1 617 if (_writtenFileSize > _unpackSize)
rlm@1 618 {
rlm@1 619 keepDecompressing = false;
rlm@1 620 return S_OK;
rlm@1 621 }
rlm@1 622 }
rlm@1 623 UInt32 number = m_MainDecoder.DecodeSymbol(&m_InBitStream);
rlm@1 624 if (number < 256)
rlm@1 625 {
rlm@1 626 PutByte(Byte(number));
rlm@1 627
rlm@1 628 continue;
rlm@1 629 }
rlm@1 630 else if (number == kSymbolReadTable)
rlm@1 631 {
rlm@1 632 RINOK(ReadEndOfBlock(keepDecompressing));
rlm@1 633 break;
rlm@1 634 }
rlm@1 635 else if (number == 257)
rlm@1 636 {
rlm@1 637 if (!ReadVmCodeLZ())
rlm@1 638 return S_FALSE;
rlm@1 639 continue;
rlm@1 640 }
rlm@1 641 else if (number == 258)
rlm@1 642 {
rlm@1 643 }
rlm@1 644 else if (number < kSymbolRep + 4)
rlm@1 645 {
rlm@1 646 if (number != kSymbolRep)
rlm@1 647 {
rlm@1 648 UInt32 distance;
rlm@1 649 if (number == kSymbolRep + 1)
rlm@1 650 distance = rep1;
rlm@1 651 else
rlm@1 652 {
rlm@1 653 if (number == kSymbolRep + 2)
rlm@1 654 distance = rep2;
rlm@1 655 else
rlm@1 656 {
rlm@1 657 distance = rep3;
rlm@1 658 rep3 = rep2;
rlm@1 659 }
rlm@1 660 rep2 = rep1;
rlm@1 661 }
rlm@1 662 rep1 = rep0;
rlm@1 663 rep0 = distance;
rlm@1 664 }
rlm@1 665
rlm@1 666 UInt32 number = m_LenDecoder.DecodeSymbol(&m_InBitStream);
rlm@1 667 if (number >= kLenTableSize)
rlm@1 668 return S_FALSE;
rlm@1 669 length = 2 + kLenStart[number] + m_InBitStream.ReadBits(kLenDirectBits[number]);
rlm@1 670 }
rlm@1 671 else
rlm@1 672 {
rlm@1 673 rep3 = rep2;
rlm@1 674 rep2 = rep1;
rlm@1 675 rep1 = rep0;
rlm@1 676 if (number < 271)
rlm@1 677 {
rlm@1 678 number -= 263;
rlm@1 679 rep0 = kLen2DistStarts[number] + m_InBitStream.ReadBits(kLen2DistDirectBits[number]);
rlm@1 680 length = 2;
rlm@1 681 }
rlm@1 682 else if (number < 299)
rlm@1 683 {
rlm@1 684 number -= 271;
rlm@1 685 length = kNormalMatchMinLen + (UInt32)kLenStart[number] + m_InBitStream.ReadBits(kLenDirectBits[number]);
rlm@1 686 UInt32 number = m_DistDecoder.DecodeSymbol(&m_InBitStream);
rlm@1 687 if (number >= kDistTableSize)
rlm@1 688 return S_FALSE;
rlm@1 689 rep0 = kDistStart[number];
rlm@1 690 int numBits = kDistDirectBits[number];
rlm@1 691 if (number >= (kNumAlignBits * 2) + 2)
rlm@1 692 {
rlm@1 693 if (numBits > kNumAlignBits)
rlm@1 694 rep0 += (m_InBitStream.ReadBits(numBits - kNumAlignBits) << kNumAlignBits);
rlm@1 695 if (PrevAlignCount > 0)
rlm@1 696 {
rlm@1 697 PrevAlignCount--;
rlm@1 698 rep0 += PrevAlignBits;
rlm@1 699 }
rlm@1 700 else
rlm@1 701 {
rlm@1 702 UInt32 number = m_AlignDecoder.DecodeSymbol(&m_InBitStream);
rlm@1 703 if (number < (1 << kNumAlignBits))
rlm@1 704 {
rlm@1 705 rep0 += number;
rlm@1 706 PrevAlignBits = number;
rlm@1 707 }
rlm@1 708 else if (number == (1 << kNumAlignBits))
rlm@1 709 {
rlm@1 710 PrevAlignCount = kNumAlignReps;
rlm@1 711 rep0 += PrevAlignBits;
rlm@1 712 }
rlm@1 713 else
rlm@1 714 return S_FALSE;
rlm@1 715 }
rlm@1 716 }
rlm@1 717 else
rlm@1 718 rep0 += m_InBitStream.ReadBits(numBits);
rlm@1 719 length += ((kDistLimit4 - rep0) >> 31) + ((kDistLimit3 - rep0) >> 31);
rlm@1 720 }
rlm@1 721 else
rlm@1 722 return S_FALSE;
rlm@1 723 }
rlm@1 724 if (rep0 >= _lzSize)
rlm@1 725 return S_FALSE;
rlm@1 726 CopyBlock(rep0, length);
rlm@1 727 }
rlm@1 728 _reps[0] = rep0;
rlm@1 729 _reps[1] = rep1;
rlm@1 730 _reps[2] = rep2;
rlm@1 731 _reps[3] = rep3;
rlm@1 732 _lastLength = length;
rlm@1 733
rlm@1 734 return S_OK;
rlm@1 735 }
rlm@1 736
rlm@1 737 HRESULT CDecoder::CodeReal(ICompressProgressInfo *progress)
rlm@1 738 {
rlm@1 739 _writtenFileSize = 0;
rlm@1 740 if (!m_IsSolid)
rlm@1 741 {
rlm@1 742 _lzSize = 0;
rlm@1 743 _winPos = 0;
rlm@1 744 _wrPtr = 0;
rlm@1 745 for (int i = 0; i < kNumReps; i++)
rlm@1 746 _reps[i] = 0;
rlm@1 747 _lastLength = 0;
rlm@1 748 memset(m_LastLevels, 0, kTablesSizesSum);
rlm@1 749 TablesRead = false;
rlm@1 750 PpmEscChar = 2;
rlm@1 751 InitFilters();
rlm@1 752 }
rlm@1 753 if (!m_IsSolid || !TablesRead)
rlm@1 754 {
rlm@1 755 bool keepDecompressing;
rlm@1 756 RINOK(ReadTables(keepDecompressing));
rlm@1 757 if (!keepDecompressing)
rlm@1 758 return S_OK;
rlm@1 759 }
rlm@1 760
rlm@1 761 for(;;)
rlm@1 762 {
rlm@1 763 bool keepDecompressing;
rlm@1 764 if (_lzMode)
rlm@1 765 {
rlm@1 766 RINOK(DecodeLZ(keepDecompressing))
rlm@1 767 }
rlm@1 768 else
rlm@1 769 {
rlm@1 770 RINOK(DecodePPM(1 << 18, keepDecompressing))
rlm@1 771 }
rlm@1 772 UInt64 packSize = m_InBitStream.GetProcessedSize();
rlm@1 773 RINOK(progress->SetRatioInfo(&packSize, &_writtenFileSize));
rlm@1 774 if (!keepDecompressing)
rlm@1 775 break;
rlm@1 776 }
rlm@1 777 RINOK(WriteBuf());
rlm@1 778 if (_writtenFileSize < _unpackSize)
rlm@1 779 return S_FALSE;
rlm@1 780 // return m_OutWindowStream.Flush();
rlm@1 781 return S_OK;
rlm@1 782 }
rlm@1 783
rlm@1 784 STDMETHODIMP CDecoder::Code(ISequentialInStream *inStream, ISequentialOutStream *outStream,
rlm@1 785 const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress)
rlm@1 786 {
rlm@1 787 try
rlm@1 788 {
rlm@1 789 if (inSize == NULL || outSize == NULL)
rlm@1 790 return E_INVALIDARG;
rlm@1 791
rlm@1 792 if (_vmData == 0)
rlm@1 793 {
rlm@1 794 _vmData = (Byte *)::MidAlloc(kVmDataSizeMax + kVmCodeSizeMax);
rlm@1 795 if (_vmData == 0)
rlm@1 796 return E_OUTOFMEMORY;
rlm@1 797 _vmCode = _vmData + kVmDataSizeMax;
rlm@1 798 }
rlm@1 799
rlm@1 800 if (_window == 0)
rlm@1 801 {
rlm@1 802 _window = (Byte *)::MidAlloc(kWindowSize);
rlm@1 803 if (_window == 0)
rlm@1 804 return E_OUTOFMEMORY;
rlm@1 805 }
rlm@1 806 if (!m_InBitStream.Create(1 << 20))
rlm@1 807 return E_OUTOFMEMORY;
rlm@1 808 if (!_vm.Create())
rlm@1 809 return E_OUTOFMEMORY;
rlm@1 810
rlm@1 811
rlm@1 812 m_InBitStream.SetStream(inStream);
rlm@1 813 m_InBitStream.Init();
rlm@1 814 _outStream = outStream;
rlm@1 815
rlm@1 816 CCoderReleaser coderReleaser(this);
rlm@1 817 _unpackSize = *outSize;
rlm@1 818 return CodeReal(progress);
rlm@1 819 }
rlm@1 820 catch(const CInBufferException &e) { return e.ErrorCode; }
rlm@1 821 catch(...) { return S_FALSE; }
rlm@1 822 // CNewException is possible here. But probably CNewException is caused
rlm@1 823 // by error in data stream.
rlm@1 824 }
rlm@1 825
rlm@1 826 STDMETHODIMP CDecoder::SetDecoderProperties2(const Byte *data, UInt32 size)
rlm@1 827 {
rlm@1 828 if (size < 1)
rlm@1 829 return E_INVALIDARG;
rlm@1 830 m_IsSolid = (data[0] != 0);
rlm@1 831 return S_OK;
rlm@1 832 }
rlm@1 833
rlm@1 834 }}