rlm@1
|
1 // PpmdDecoder.cpp
|
rlm@1
|
2
|
rlm@1
|
3 #include "StdAfx.h"
|
rlm@1
|
4
|
rlm@1
|
5 #include "Common/Defs.h"
|
rlm@1
|
6 #include "Windows/Defs.h"
|
rlm@1
|
7
|
rlm@1
|
8 #include "PpmdDecoder.h"
|
rlm@1
|
9
|
rlm@1
|
10 namespace NCompress {
|
rlm@1
|
11 namespace NPpmd {
|
rlm@1
|
12
|
rlm@1
|
13 const int kLenIdFinished = -1;
|
rlm@1
|
14 const int kLenIdNeedInit = -2;
|
rlm@1
|
15
|
rlm@1
|
16 STDMETHODIMP CDecoder::SetDecoderProperties2(const Byte *properties, UInt32 size)
|
rlm@1
|
17 {
|
rlm@1
|
18 if (size < 5)
|
rlm@1
|
19 return E_INVALIDARG;
|
rlm@1
|
20 _order = properties[0];
|
rlm@1
|
21 _usedMemorySize = 0;
|
rlm@1
|
22 for (int i = 0; i < 4; i++)
|
rlm@1
|
23 _usedMemorySize += ((UInt32)(properties[1 + i])) << (i * 8);
|
rlm@1
|
24
|
rlm@1
|
25 if (_usedMemorySize > kMaxMemBlockSize)
|
rlm@1
|
26 return E_NOTIMPL;
|
rlm@1
|
27
|
rlm@1
|
28 if (!_rangeDecoder.Create(1 << 20))
|
rlm@1
|
29 return E_OUTOFMEMORY;
|
rlm@1
|
30 if (!_info.SubAllocator.StartSubAllocator(_usedMemorySize))
|
rlm@1
|
31 return E_OUTOFMEMORY;
|
rlm@1
|
32
|
rlm@1
|
33 return S_OK;
|
rlm@1
|
34 }
|
rlm@1
|
35
|
rlm@1
|
36 class CDecoderFlusher
|
rlm@1
|
37 {
|
rlm@1
|
38 CDecoder *_coder;
|
rlm@1
|
39 public:
|
rlm@1
|
40 bool NeedFlush;
|
rlm@1
|
41 CDecoderFlusher(CDecoder *coder): _coder(coder), NeedFlush(true) {}
|
rlm@1
|
42 ~CDecoderFlusher()
|
rlm@1
|
43 {
|
rlm@1
|
44 if (NeedFlush)
|
rlm@1
|
45 _coder->Flush();
|
rlm@1
|
46 _coder->ReleaseStreams();
|
rlm@1
|
47 }
|
rlm@1
|
48 };
|
rlm@1
|
49
|
rlm@1
|
50 HRESULT CDecoder::CodeSpec(UInt32 size, Byte *memStream)
|
rlm@1
|
51 {
|
rlm@1
|
52 if (_outSizeDefined)
|
rlm@1
|
53 {
|
rlm@1
|
54 const UInt64 rem = _outSize - _processedSize;
|
rlm@1
|
55 if (size > rem)
|
rlm@1
|
56 size = (UInt32)rem;
|
rlm@1
|
57 }
|
rlm@1
|
58 const UInt32 startSize = size;
|
rlm@1
|
59
|
rlm@1
|
60 if (_remainLen == kLenIdFinished)
|
rlm@1
|
61 return S_OK;
|
rlm@1
|
62 if (_remainLen == kLenIdNeedInit)
|
rlm@1
|
63 {
|
rlm@1
|
64 _rangeDecoder.Init();
|
rlm@1
|
65 _remainLen = 0;
|
rlm@1
|
66 _info.MaxOrder = 0;
|
rlm@1
|
67 _info.StartModelRare(_order);
|
rlm@1
|
68 }
|
rlm@1
|
69 while (size != 0)
|
rlm@1
|
70 {
|
rlm@1
|
71 int symbol = _info.DecodeSymbol(&_rangeDecoder);
|
rlm@1
|
72 if (symbol < 0)
|
rlm@1
|
73 {
|
rlm@1
|
74 _remainLen = kLenIdFinished;
|
rlm@1
|
75 break;
|
rlm@1
|
76 }
|
rlm@1
|
77 if (memStream != 0)
|
rlm@1
|
78 *memStream++ = (Byte)symbol;
|
rlm@1
|
79 else
|
rlm@1
|
80 _outStream.WriteByte((Byte)symbol);
|
rlm@1
|
81 size--;
|
rlm@1
|
82 }
|
rlm@1
|
83 _processedSize += startSize - size;
|
rlm@1
|
84 return S_OK;
|
rlm@1
|
85 }
|
rlm@1
|
86
|
rlm@1
|
87 STDMETHODIMP CDecoder::CodeReal(ISequentialInStream *inStream, ISequentialOutStream *outStream,
|
rlm@1
|
88 const UInt64 * /* inSize */, const UInt64 *outSize, ICompressProgressInfo *progress)
|
rlm@1
|
89 {
|
rlm@1
|
90 if (!_outStream.Create(1 << 20))
|
rlm@1
|
91 return E_OUTOFMEMORY;
|
rlm@1
|
92
|
rlm@1
|
93 SetInStream(inStream);
|
rlm@1
|
94 _outStream.SetStream(outStream);
|
rlm@1
|
95 SetOutStreamSize(outSize);
|
rlm@1
|
96 CDecoderFlusher flusher(this);
|
rlm@1
|
97
|
rlm@1
|
98 for (;;)
|
rlm@1
|
99 {
|
rlm@1
|
100 _processedSize = _outStream.GetProcessedSize();
|
rlm@1
|
101 UInt32 curSize = (1 << 18);
|
rlm@1
|
102 RINOK(CodeSpec(curSize, NULL));
|
rlm@1
|
103 if (_remainLen == kLenIdFinished)
|
rlm@1
|
104 break;
|
rlm@1
|
105 if (progress != NULL)
|
rlm@1
|
106 {
|
rlm@1
|
107 UInt64 inSize = _rangeDecoder.GetProcessedSize();
|
rlm@1
|
108 RINOK(progress->SetRatioInfo(&inSize, &_processedSize));
|
rlm@1
|
109 }
|
rlm@1
|
110 if (_outSizeDefined)
|
rlm@1
|
111 if (_outStream.GetProcessedSize() >= _outSize)
|
rlm@1
|
112 break;
|
rlm@1
|
113 }
|
rlm@1
|
114 flusher.NeedFlush = false;
|
rlm@1
|
115 return Flush();
|
rlm@1
|
116 }
|
rlm@1
|
117
|
rlm@1
|
118 #ifdef _NO_EXCEPTIONS
|
rlm@1
|
119
|
rlm@1
|
120 #define PPMD_TRY_BEGIN
|
rlm@1
|
121 #define PPMD_TRY_END
|
rlm@1
|
122
|
rlm@1
|
123 #else
|
rlm@1
|
124
|
rlm@1
|
125 #define PPMD_TRY_BEGIN try {
|
rlm@1
|
126 #define PPMD_TRY_END } \
|
rlm@1
|
127 catch(const CInBufferException &e) { return e.ErrorCode; } \
|
rlm@1
|
128 catch(const COutBufferException &e) { return e.ErrorCode; } \
|
rlm@1
|
129 catch(...) { return S_FALSE; }
|
rlm@1
|
130
|
rlm@1
|
131 #endif
|
rlm@1
|
132
|
rlm@1
|
133
|
rlm@1
|
134 STDMETHODIMP CDecoder::Code(ISequentialInStream *inStream, ISequentialOutStream *outStream,
|
rlm@1
|
135 const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress)
|
rlm@1
|
136 {
|
rlm@1
|
137 PPMD_TRY_BEGIN
|
rlm@1
|
138 return CodeReal(inStream, outStream, inSize, outSize, progress);
|
rlm@1
|
139 PPMD_TRY_END
|
rlm@1
|
140 }
|
rlm@1
|
141
|
rlm@1
|
142 STDMETHODIMP CDecoder::SetInStream(ISequentialInStream *inStream)
|
rlm@1
|
143 {
|
rlm@1
|
144 _rangeDecoder.SetStream(inStream);
|
rlm@1
|
145 return S_OK;
|
rlm@1
|
146 }
|
rlm@1
|
147
|
rlm@1
|
148 STDMETHODIMP CDecoder::ReleaseInStream()
|
rlm@1
|
149 {
|
rlm@1
|
150 _rangeDecoder.ReleaseStream();
|
rlm@1
|
151 return S_OK;
|
rlm@1
|
152 }
|
rlm@1
|
153
|
rlm@1
|
154 STDMETHODIMP CDecoder::SetOutStreamSize(const UInt64 *outSize)
|
rlm@1
|
155 {
|
rlm@1
|
156 _outSizeDefined = (outSize != NULL);
|
rlm@1
|
157 if (_outSizeDefined)
|
rlm@1
|
158 _outSize = *outSize;
|
rlm@1
|
159 _processedSize = 0;
|
rlm@1
|
160 _remainLen = kLenIdNeedInit;
|
rlm@1
|
161 _outStream.Init();
|
rlm@1
|
162 return S_OK;
|
rlm@1
|
163 }
|
rlm@1
|
164
|
rlm@1
|
165 #ifndef NO_READ_FROM_CODER
|
rlm@1
|
166
|
rlm@1
|
167 STDMETHODIMP CDecoder::Read(void *data, UInt32 size, UInt32 *processedSize)
|
rlm@1
|
168 {
|
rlm@1
|
169 PPMD_TRY_BEGIN
|
rlm@1
|
170 if (processedSize)
|
rlm@1
|
171 *processedSize = 0;
|
rlm@1
|
172 const UInt64 startPos = _processedSize;
|
rlm@1
|
173 RINOK(CodeSpec(size, (Byte *)data));
|
rlm@1
|
174 if (processedSize)
|
rlm@1
|
175 *processedSize = (UInt32)(_processedSize - startPos);
|
rlm@1
|
176 return Flush();
|
rlm@1
|
177 PPMD_TRY_END
|
rlm@1
|
178 }
|
rlm@1
|
179
|
rlm@1
|
180 #endif
|
rlm@1
|
181
|
rlm@1
|
182 }}
|