diff options
Diffstat (limited to 'src/libs/7zip/win/CPP/7zip/Compress/ZDecoder.cpp')
-rw-r--r-- | src/libs/7zip/win/CPP/7zip/Compress/ZDecoder.cpp | 159 |
1 files changed, 159 insertions, 0 deletions
diff --git a/src/libs/7zip/win/CPP/7zip/Compress/ZDecoder.cpp b/src/libs/7zip/win/CPP/7zip/Compress/ZDecoder.cpp new file mode 100644 index 000000000..e28c64518 --- /dev/null +++ b/src/libs/7zip/win/CPP/7zip/Compress/ZDecoder.cpp @@ -0,0 +1,159 @@ +// ZDecoder.cpp + +#include "StdAfx.h" + +#include "../../../C/Alloc.h" + +#include "../Common/InBuffer.h" +#include "../Common/OutBuffer.h" + +#include "ZDecoder.h" + +namespace NCompress { +namespace NZ { + +static const UInt32 kBufferSize = (1 << 20); +static const Byte kNumBitsMask = 0x1F; +static const Byte kBlockModeMask = 0x80; +static const int kNumMinBits = 9; +static const int kNumMaxBits = 16; + +void CDecoder::Free() +{ + MyFree(_parents); _parents = 0; + MyFree(_suffixes); _suffixes = 0; + MyFree(_stack); _stack = 0; +} + +CDecoder::~CDecoder() { Free(); } + +HRESULT CDecoder::CodeReal(ISequentialInStream *inStream, ISequentialOutStream *outStream, + const UInt64 * /* inSize */, const UInt64 * /* outSize */, ICompressProgressInfo *progress) +{ + CInBuffer inBuffer; + COutBuffer outBuffer; + + if (!inBuffer.Create(kBufferSize)) + return E_OUTOFMEMORY; + inBuffer.SetStream(inStream); + inBuffer.Init(); + + if (!outBuffer.Create(kBufferSize)) + return E_OUTOFMEMORY; + outBuffer.SetStream(outStream); + outBuffer.Init(); + + int maxbits = _properties & kNumBitsMask; + if (maxbits < kNumMinBits || maxbits > kNumMaxBits) + return S_FALSE; + UInt32 numItems = 1 << maxbits; + bool blockMode = ((_properties & kBlockModeMask) != 0); + + if (maxbits != _numMaxBits || _parents == 0 || _suffixes == 0 || _stack == 0) + { + Free(); + _parents = (UInt16 *)MyAlloc(numItems * sizeof(UInt16)); if (_parents == 0) return E_OUTOFMEMORY; + _suffixes = (Byte *)MyAlloc(numItems * sizeof(Byte)); if (_suffixes == 0) return E_OUTOFMEMORY; + _stack = (Byte *)MyAlloc(numItems * sizeof(Byte)); if (_stack == 0) return E_OUTOFMEMORY; + _numMaxBits = maxbits; + } + + UInt64 prevPos = 0; + int numBits = kNumMinBits; + UInt32 head = blockMode ? 257 : 256; + + bool needPrev = false; + + unsigned bitPos = 0; + unsigned numBufBits = 0; + + Byte buf[kNumMaxBits + 4]; + + _parents[256] = 0; // virus protection + _suffixes[256] = 0; + + for (;;) + { + if (numBufBits == bitPos) + { + numBufBits = (unsigned)inBuffer.ReadBytes(buf, numBits) * 8; + bitPos = 0; + UInt64 nowPos = outBuffer.GetProcessedSize(); + if (progress != NULL && nowPos - prevPos >= (1 << 18)) + { + prevPos = nowPos; + UInt64 packSize = inBuffer.GetProcessedSize(); + RINOK(progress->SetRatioInfo(&packSize, &nowPos)); + } + } + unsigned bytePos = bitPos >> 3; + UInt32 symbol = buf[bytePos] | ((UInt32)buf[bytePos + 1] << 8) | ((UInt32)buf[bytePos + 2] << 16); + symbol >>= (bitPos & 7); + symbol &= (1 << numBits) - 1; + bitPos += numBits; + if (bitPos > numBufBits) + break; + if (symbol >= head) + return S_FALSE; + if (blockMode && symbol == 256) + { + numBufBits = bitPos = 0; + numBits = kNumMinBits; + head = 257; + needPrev = false; + continue; + } + UInt32 cur = symbol; + int i = 0; + while (cur >= 256) + { + _stack[i++] = _suffixes[cur]; + cur = _parents[cur]; + } + _stack[i++] = (Byte)cur; + if (needPrev) + { + _suffixes[head - 1] = (Byte)cur; + if (symbol == head - 1) + _stack[0] = (Byte)cur; + } + do + outBuffer.WriteByte((_stack[--i])); + while (i > 0); + if (head < numItems) + { + needPrev = true; + _parents[head++] = (UInt16)symbol; + if (head > ((UInt32)1 << numBits)) + { + if (numBits < maxbits) + { + numBufBits = bitPos = 0; + numBits++; + } + } + } + else + needPrev = false; + } + return outBuffer.Flush(); +} + +STDMETHODIMP CDecoder::Code(ISequentialInStream *inStream, ISequentialOutStream *outStream, + const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress) +{ + try { return CodeReal(inStream, outStream, inSize, outSize, progress); } + catch(const CInBufferException &e) { return e.ErrorCode; } + catch(const COutBufferException &e) { return e.ErrorCode; } + catch(...) { return S_FALSE; } +} + +STDMETHODIMP CDecoder::SetDecoderProperties2(const Byte *data, UInt32 size) +{ + if (size < 1) + return E_INVALIDARG; + _properties = data[0]; + return S_OK; +} + +}} |