5 #include "../../../C/Alloc.h"
\r
7 #include "../Common/InBuffer.h"
\r
8 #include "../Common/OutBuffer.h"
\r
10 #include "ZDecoder.h"
\r
12 namespace NCompress {
\r
15 static const UInt32 kBufferSize = (1 << 20);
\r
16 static const Byte kNumBitsMask = 0x1F;
\r
17 static const Byte kBlockModeMask = 0x80;
\r
18 static const int kNumMinBits = 9;
\r
19 static const int kNumMaxBits = 16;
\r
21 void CDecoder::Free()
\r
23 MyFree(_parents); _parents = 0;
\r
24 MyFree(_suffixes); _suffixes = 0;
\r
25 MyFree(_stack); _stack = 0;
\r
28 CDecoder::~CDecoder() { Free(); }
\r
30 HRESULT CDecoder::CodeReal(ISequentialInStream *inStream, ISequentialOutStream *outStream,
\r
31 const UInt64 * /* inSize */, const UInt64 * /* outSize */, ICompressProgressInfo *progress)
\r
34 COutBuffer outBuffer;
\r
36 if (!inBuffer.Create(kBufferSize))
\r
37 return E_OUTOFMEMORY;
\r
38 inBuffer.SetStream(inStream);
\r
41 if (!outBuffer.Create(kBufferSize))
\r
42 return E_OUTOFMEMORY;
\r
43 outBuffer.SetStream(outStream);
\r
46 int maxbits = _properties & kNumBitsMask;
\r
47 if (maxbits < kNumMinBits || maxbits > kNumMaxBits)
\r
49 UInt32 numItems = 1 << maxbits;
\r
50 bool blockMode = ((_properties & kBlockModeMask) != 0);
\r
52 if (maxbits != _numMaxBits || _parents == 0 || _suffixes == 0 || _stack == 0)
\r
55 _parents = (UInt16 *)MyAlloc(numItems * sizeof(UInt16)); if (_parents == 0) return E_OUTOFMEMORY;
\r
56 _suffixes = (Byte *)MyAlloc(numItems * sizeof(Byte)); if (_suffixes == 0) return E_OUTOFMEMORY;
\r
57 _stack = (Byte *)MyAlloc(numItems * sizeof(Byte)); if (_stack == 0) return E_OUTOFMEMORY;
\r
58 _numMaxBits = maxbits;
\r
62 int numBits = kNumMinBits;
\r
63 UInt32 head = blockMode ? 257 : 256;
\r
65 bool needPrev = false;
\r
67 unsigned bitPos = 0;
\r
68 unsigned numBufBits = 0;
\r
70 Byte buf[kNumMaxBits + 4];
\r
72 _parents[256] = 0; // virus protection
\r
77 if (numBufBits == bitPos)
\r
79 numBufBits = (unsigned)inBuffer.ReadBytes(buf, numBits) * 8;
\r
81 UInt64 nowPos = outBuffer.GetProcessedSize();
\r
82 if (progress != NULL && nowPos - prevPos >= (1 << 18))
\r
85 UInt64 packSize = inBuffer.GetProcessedSize();
\r
86 RINOK(progress->SetRatioInfo(&packSize, &nowPos));
\r
89 unsigned bytePos = bitPos >> 3;
\r
90 UInt32 symbol = buf[bytePos] | ((UInt32)buf[bytePos + 1] << 8) | ((UInt32)buf[bytePos + 2] << 16);
\r
91 symbol >>= (bitPos & 7);
\r
92 symbol &= (1 << numBits) - 1;
\r
94 if (bitPos > numBufBits)
\r
98 if (blockMode && symbol == 256)
\r
100 numBufBits = bitPos = 0;
\r
101 numBits = kNumMinBits;
\r
106 UInt32 cur = symbol;
\r
110 _stack[i++] = _suffixes[cur];
\r
111 cur = _parents[cur];
\r
113 _stack[i++] = (Byte)cur;
\r
116 _suffixes[head - 1] = (Byte)cur;
\r
117 if (symbol == head - 1)
\r
118 _stack[0] = (Byte)cur;
\r
121 outBuffer.WriteByte((_stack[--i]));
\r
123 if (head < numItems)
\r
126 _parents[head++] = (UInt16)symbol;
\r
127 if (head > ((UInt32)1 << numBits))
\r
129 if (numBits < maxbits)
\r
131 numBufBits = bitPos = 0;
\r
139 return outBuffer.Flush();
\r
142 STDMETHODIMP CDecoder::Code(ISequentialInStream *inStream, ISequentialOutStream *outStream,
\r
143 const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress)
\r
145 try { return CodeReal(inStream, outStream, inSize, outSize, progress); }
\r
146 catch(const CInBufferException &e) { return e.ErrorCode; }
\r
147 catch(const COutBufferException &e) { return e.ErrorCode; }
\r
148 catch(...) { return S_FALSE; }
\r
151 STDMETHODIMP CDecoder::SetDecoderProperties2(const Byte *data, UInt32 size)
\r
154 return E_INVALIDARG;
\r
155 _properties = data[0];
\r