view src/win32/7zip/7z/CPP/7zip/Compress/PpmdDecoder.cpp @ 1:f9f4f1b99eed

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