rlm@1
|
1 // LzmaDecoder.cpp
|
rlm@1
|
2
|
rlm@1
|
3 #include "StdAfx.h"
|
rlm@1
|
4
|
rlm@1
|
5 extern "C"
|
rlm@1
|
6 {
|
rlm@1
|
7 #include "../../../C/Alloc.h"
|
rlm@1
|
8 }
|
rlm@1
|
9
|
rlm@1
|
10 #include "../Common/StreamUtils.h"
|
rlm@1
|
11
|
rlm@1
|
12 #include "LzmaDecoder.h"
|
rlm@1
|
13
|
rlm@1
|
14 static HRESULT SResToHRESULT(SRes res)
|
rlm@1
|
15 {
|
rlm@1
|
16 switch(res)
|
rlm@1
|
17 {
|
rlm@1
|
18 case SZ_OK: return S_OK;
|
rlm@1
|
19 case SZ_ERROR_MEM: return E_OUTOFMEMORY;
|
rlm@1
|
20 case SZ_ERROR_PARAM: return E_INVALIDARG;
|
rlm@1
|
21 case SZ_ERROR_UNSUPPORTED: return E_NOTIMPL;
|
rlm@1
|
22 // case SZ_ERROR_PROGRESS: return E_ABORT;
|
rlm@1
|
23 case SZ_ERROR_DATA: return S_FALSE;
|
rlm@1
|
24 }
|
rlm@1
|
25 return E_FAIL;
|
rlm@1
|
26 }
|
rlm@1
|
27
|
rlm@1
|
28 namespace NCompress {
|
rlm@1
|
29 namespace NLzma {
|
rlm@1
|
30
|
rlm@1
|
31 static const UInt32 kInBufSize = 1 << 20;
|
rlm@1
|
32
|
rlm@1
|
33 CDecoder::CDecoder(): _inBuf(0), _outSizeDefined(false), FinishStream(false)
|
rlm@1
|
34 {
|
rlm@1
|
35 LzmaDec_Construct(&_state);
|
rlm@1
|
36 }
|
rlm@1
|
37
|
rlm@1
|
38 static void *SzAlloc(void *p, size_t size) { p = p; return MyAlloc(size); }
|
rlm@1
|
39 static void SzFree(void *p, void *address) { p = p; MyFree(address); }
|
rlm@1
|
40 static ISzAlloc g_Alloc = { SzAlloc, SzFree };
|
rlm@1
|
41
|
rlm@1
|
42 CDecoder::~CDecoder()
|
rlm@1
|
43 {
|
rlm@1
|
44 LzmaDec_Free(&_state, &g_Alloc);
|
rlm@1
|
45 MyFree(_inBuf);
|
rlm@1
|
46 }
|
rlm@1
|
47
|
rlm@1
|
48 STDMETHODIMP CDecoder::SetDecoderProperties2(const Byte *prop, UInt32 size)
|
rlm@1
|
49 {
|
rlm@1
|
50 RINOK(SResToHRESULT(LzmaDec_Allocate(&_state, prop, size, &g_Alloc)));
|
rlm@1
|
51
|
rlm@1
|
52 if (_inBuf == 0)
|
rlm@1
|
53 {
|
rlm@1
|
54 _inBuf = (Byte *)MyAlloc(kInBufSize);
|
rlm@1
|
55 if (_inBuf == 0)
|
rlm@1
|
56 return E_OUTOFMEMORY;
|
rlm@1
|
57 }
|
rlm@1
|
58
|
rlm@1
|
59 return S_OK;
|
rlm@1
|
60 }
|
rlm@1
|
61
|
rlm@1
|
62 STDMETHODIMP CDecoder::GetInStreamProcessedSize(UInt64 *value) { *value = _inSizeProcessed; return S_OK; }
|
rlm@1
|
63 STDMETHODIMP CDecoder::SetInStream(ISequentialInStream *inStream) { _inStream = inStream; return S_OK; }
|
rlm@1
|
64 STDMETHODIMP CDecoder::ReleaseInStream() { _inStream.Release(); return S_OK; }
|
rlm@1
|
65
|
rlm@1
|
66 STDMETHODIMP CDecoder::SetOutStreamSize(const UInt64 *outSize)
|
rlm@1
|
67 {
|
rlm@1
|
68 _outSizeDefined = (outSize != NULL);
|
rlm@1
|
69 if (_outSizeDefined)
|
rlm@1
|
70 _outSize = *outSize;
|
rlm@1
|
71
|
rlm@1
|
72 LzmaDec_Init(&_state);
|
rlm@1
|
73
|
rlm@1
|
74 _inPos = _inSize = 0;
|
rlm@1
|
75 _inSizeProcessed = _outSizeProcessed = 0;
|
rlm@1
|
76 return S_OK;
|
rlm@1
|
77 }
|
rlm@1
|
78
|
rlm@1
|
79 STDMETHODIMP CDecoder::Code(ISequentialInStream *inStream, ISequentialOutStream *outStream,
|
rlm@1
|
80 const UInt64 * /* inSize */, const UInt64 *outSize, ICompressProgressInfo *progress)
|
rlm@1
|
81 {
|
rlm@1
|
82 if (_inBuf == 0)
|
rlm@1
|
83 return S_FALSE;
|
rlm@1
|
84 SetOutStreamSize(outSize);
|
rlm@1
|
85
|
rlm@1
|
86 for (;;)
|
rlm@1
|
87 {
|
rlm@1
|
88 if (_inPos == _inSize)
|
rlm@1
|
89 {
|
rlm@1
|
90 _inPos = _inSize = 0;
|
rlm@1
|
91 RINOK(inStream->Read(_inBuf, kInBufSize, &_inSize));
|
rlm@1
|
92 }
|
rlm@1
|
93
|
rlm@1
|
94 SizeT dicPos = _state.dicPos;
|
rlm@1
|
95 SizeT curSize = _state.dicBufSize - dicPos;
|
rlm@1
|
96 const UInt32 kStepSize = ((UInt32)1 << 22);
|
rlm@1
|
97 if (curSize > kStepSize)
|
rlm@1
|
98 curSize = (SizeT)kStepSize;
|
rlm@1
|
99
|
rlm@1
|
100 ELzmaFinishMode finishMode = LZMA_FINISH_ANY;
|
rlm@1
|
101 if (_outSizeDefined)
|
rlm@1
|
102 {
|
rlm@1
|
103 const UInt64 rem = _outSize - _outSizeProcessed;
|
rlm@1
|
104 if (rem < curSize)
|
rlm@1
|
105 {
|
rlm@1
|
106 curSize = (SizeT)rem;
|
rlm@1
|
107 if (FinishStream)
|
rlm@1
|
108 finishMode = LZMA_FINISH_END;
|
rlm@1
|
109 }
|
rlm@1
|
110 }
|
rlm@1
|
111
|
rlm@1
|
112 SizeT inSizeProcessed = _inSize - _inPos;
|
rlm@1
|
113 ELzmaStatus status;
|
rlm@1
|
114 SRes res = LzmaDec_DecodeToDic(&_state, dicPos + curSize, _inBuf + _inPos, &inSizeProcessed, finishMode, &status);
|
rlm@1
|
115
|
rlm@1
|
116 _inPos += (UInt32)inSizeProcessed;
|
rlm@1
|
117 _inSizeProcessed += inSizeProcessed;
|
rlm@1
|
118 SizeT outSizeProcessed = _state.dicPos - dicPos;
|
rlm@1
|
119 _outSizeProcessed += outSizeProcessed;
|
rlm@1
|
120
|
rlm@1
|
121 bool finished = (inSizeProcessed == 0 && outSizeProcessed == 0);
|
rlm@1
|
122 bool stopDecoding = (_outSizeDefined && _outSizeProcessed >= _outSize);
|
rlm@1
|
123
|
rlm@1
|
124 if (res != 0 || _state.dicPos == _state.dicBufSize || finished || stopDecoding)
|
rlm@1
|
125 {
|
rlm@1
|
126 HRESULT res2 = WriteStream(outStream, _state.dic, _state.dicPos);
|
rlm@1
|
127 if (res != 0)
|
rlm@1
|
128 return S_FALSE;
|
rlm@1
|
129 RINOK(res2);
|
rlm@1
|
130 if (stopDecoding)
|
rlm@1
|
131 return S_OK;
|
rlm@1
|
132 if (finished)
|
rlm@1
|
133 return (status == LZMA_STATUS_FINISHED_WITH_MARK ? S_OK : S_FALSE);
|
rlm@1
|
134 }
|
rlm@1
|
135 if (_state.dicPos == _state.dicBufSize)
|
rlm@1
|
136 _state.dicPos = 0;
|
rlm@1
|
137
|
rlm@1
|
138 if (progress != NULL)
|
rlm@1
|
139 {
|
rlm@1
|
140 RINOK(progress->SetRatioInfo(&_inSizeProcessed, &_outSizeProcessed));
|
rlm@1
|
141 }
|
rlm@1
|
142 }
|
rlm@1
|
143 }
|
rlm@1
|
144
|
rlm@1
|
145 #ifndef NO_READ_FROM_CODER
|
rlm@1
|
146
|
rlm@1
|
147 STDMETHODIMP CDecoder::Read(void *data, UInt32 size, UInt32 *processedSize)
|
rlm@1
|
148 {
|
rlm@1
|
149 if (processedSize)
|
rlm@1
|
150 *processedSize = 0;
|
rlm@1
|
151 do
|
rlm@1
|
152 {
|
rlm@1
|
153 if (_inPos == _inSize)
|
rlm@1
|
154 {
|
rlm@1
|
155 _inPos = _inSize = 0;
|
rlm@1
|
156 RINOK(_inStream->Read(_inBuf, kInBufSize, &_inSize));
|
rlm@1
|
157 }
|
rlm@1
|
158 {
|
rlm@1
|
159 SizeT inProcessed = _inSize - _inPos;
|
rlm@1
|
160
|
rlm@1
|
161 if (_outSizeDefined)
|
rlm@1
|
162 {
|
rlm@1
|
163 const UInt64 rem = _outSize - _outSizeProcessed;
|
rlm@1
|
164 if (rem < size)
|
rlm@1
|
165 size = (UInt32)rem;
|
rlm@1
|
166 }
|
rlm@1
|
167
|
rlm@1
|
168 SizeT outProcessed = size;
|
rlm@1
|
169 ELzmaStatus status;
|
rlm@1
|
170 SRes res = LzmaDec_DecodeToBuf(&_state, (Byte *)data, &outProcessed,
|
rlm@1
|
171 _inBuf + _inPos, &inProcessed, LZMA_FINISH_ANY, &status);
|
rlm@1
|
172 _inPos += (UInt32)inProcessed;
|
rlm@1
|
173 _inSizeProcessed += inProcessed;
|
rlm@1
|
174 _outSizeProcessed += outProcessed;
|
rlm@1
|
175 size -= (UInt32)outProcessed;
|
rlm@1
|
176 data = (Byte *)data + outProcessed;
|
rlm@1
|
177 if (processedSize)
|
rlm@1
|
178 *processedSize += (UInt32)outProcessed;
|
rlm@1
|
179 RINOK(SResToHRESULT(res));
|
rlm@1
|
180 if (inProcessed == 0 && outProcessed == 0)
|
rlm@1
|
181 return S_OK;
|
rlm@1
|
182 }
|
rlm@1
|
183 }
|
rlm@1
|
184 while (size != 0);
|
rlm@1
|
185 return S_OK;
|
rlm@1
|
186 }
|
rlm@1
|
187
|
rlm@1
|
188 #endif
|
rlm@1
|
189
|
rlm@1
|
190 }}
|