Imported Upstream version 9.20
[platform/upstream/7zip.git] / CPP / 7zip / Compress / ZDecoder.cpp
1 // ZDecoder.cpp\r
2 \r
3 #include "StdAfx.h"\r
4 \r
5 #include "../../../C/Alloc.h"\r
6 \r
7 #include "../Common/InBuffer.h"\r
8 #include "../Common/OutBuffer.h"\r
9 \r
10 #include "ZDecoder.h"\r
11 \r
12 namespace NCompress {\r
13 namespace NZ {\r
14 \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
20 \r
21 void CDecoder::Free()\r
22 {\r
23   MyFree(_parents); _parents = 0;\r
24   MyFree(_suffixes); _suffixes = 0;\r
25   MyFree(_stack); _stack = 0;\r
26 }\r
27 \r
28 CDecoder::~CDecoder() { Free(); }\r
29 \r
30 HRESULT CDecoder::CodeReal(ISequentialInStream *inStream, ISequentialOutStream *outStream,\r
31     const UInt64 * /* inSize */, const UInt64 * /* outSize */, ICompressProgressInfo *progress)\r
32 {\r
33   CInBuffer inBuffer;\r
34   COutBuffer outBuffer;\r
35 \r
36   if (!inBuffer.Create(kBufferSize))\r
37     return E_OUTOFMEMORY;\r
38   inBuffer.SetStream(inStream);\r
39   inBuffer.Init();\r
40 \r
41   if (!outBuffer.Create(kBufferSize))\r
42     return E_OUTOFMEMORY;\r
43   outBuffer.SetStream(outStream);\r
44   outBuffer.Init();\r
45 \r
46   int maxbits = _properties & kNumBitsMask;\r
47   if (maxbits < kNumMinBits || maxbits > kNumMaxBits)\r
48     return S_FALSE;\r
49   UInt32 numItems = 1 << maxbits;\r
50   bool blockMode = ((_properties & kBlockModeMask) != 0);\r
51 \r
52   if (maxbits != _numMaxBits || _parents == 0 || _suffixes == 0 || _stack == 0)\r
53   {\r
54     Free();\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
59   }\r
60 \r
61   UInt64 prevPos = 0;\r
62   int numBits = kNumMinBits;\r
63   UInt32 head = blockMode ? 257 : 256;\r
64 \r
65   bool needPrev = false;\r
66 \r
67   unsigned bitPos = 0;\r
68   unsigned numBufBits = 0;\r
69 \r
70   Byte buf[kNumMaxBits + 4];\r
71 \r
72   _parents[256] = 0; // virus protection\r
73   _suffixes[256] = 0;\r
74 \r
75   for (;;)\r
76   {\r
77     if (numBufBits == bitPos)\r
78     {\r
79       numBufBits = (unsigned)inBuffer.ReadBytes(buf, numBits) * 8;\r
80       bitPos = 0;\r
81       UInt64 nowPos = outBuffer.GetProcessedSize();\r
82       if (progress != NULL && nowPos - prevPos >= (1 << 18))\r
83       {\r
84         prevPos = nowPos;\r
85         UInt64 packSize = inBuffer.GetProcessedSize();\r
86         RINOK(progress->SetRatioInfo(&packSize, &nowPos));\r
87       }\r
88     }\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
93     bitPos += numBits;\r
94     if (bitPos > numBufBits)\r
95       break;\r
96     if (symbol >= head)\r
97       return S_FALSE;\r
98     if (blockMode && symbol == 256)\r
99     {\r
100       numBufBits = bitPos = 0;\r
101       numBits = kNumMinBits;\r
102       head = 257;\r
103       needPrev = false;\r
104       continue;\r
105     }\r
106     UInt32 cur = symbol;\r
107     int i = 0;\r
108     while (cur >= 256)\r
109     {\r
110       _stack[i++] = _suffixes[cur];\r
111       cur = _parents[cur];\r
112     }\r
113     _stack[i++] = (Byte)cur;\r
114     if (needPrev)\r
115     {\r
116       _suffixes[head - 1] = (Byte)cur;\r
117       if (symbol == head - 1)\r
118         _stack[0] = (Byte)cur;\r
119     }\r
120     do\r
121       outBuffer.WriteByte((_stack[--i]));\r
122     while (i > 0);\r
123     if (head < numItems)\r
124     {\r
125       needPrev = true;\r
126       _parents[head++] = (UInt16)symbol;\r
127       if (head > ((UInt32)1 << numBits))\r
128       {\r
129         if (numBits < maxbits)\r
130         {\r
131           numBufBits = bitPos = 0;\r
132           numBits++;\r
133         }\r
134       }\r
135     }\r
136     else\r
137       needPrev = false;\r
138   }\r
139   return outBuffer.Flush();\r
140 }\r
141 \r
142 STDMETHODIMP CDecoder::Code(ISequentialInStream *inStream, ISequentialOutStream *outStream,\r
143     const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress)\r
144 {\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
149 }\r
150 \r
151 STDMETHODIMP CDecoder::SetDecoderProperties2(const Byte *data, UInt32 size)\r
152 {\r
153   if (size < 1)\r
154     return E_INVALIDARG;\r
155   _properties = data[0];\r
156   return S_OK;\r
157 }\r
158 \r
159 }}\r