1 // Lzma2Decoder.cpp
2
3 #include "StdAfx.h"
4
5 // #include <stdio.h>
6
7 #include "../../../C/Alloc.h"
8 // #include "../../../C/CpuTicks.h"
9
10 #include "../Common/StreamUtils.h"
11
12 #include "Lzma2Decoder.h"
13
14 namespace NCompress {
15 namespace NLzma2 {
16
CDecoder()17 CDecoder::CDecoder():
18 _dec(NULL)
19 , _inProcessed(0)
20 , _prop(0xFF)
21 , _finishMode(false)
22 , _inBufSize(1 << 20)
23 , _outStep(1 << 20)
24 #ifndef _7ZIP_ST
25 , _tryMt(1)
26 , _numThreads(1)
27 , _memUsage((UInt64)(sizeof(size_t)) << 28)
28 #endif
29 {}
30
~CDecoder()31 CDecoder::~CDecoder()
32 {
33 if (_dec)
34 Lzma2DecMt_Destroy(_dec);
35 }
36
SetInBufSize(UInt32,UInt32 size)37 STDMETHODIMP CDecoder::SetInBufSize(UInt32 , UInt32 size) { _inBufSize = size; return S_OK; }
SetOutBufSize(UInt32,UInt32 size)38 STDMETHODIMP CDecoder::SetOutBufSize(UInt32 , UInt32 size) { _outStep = size; return S_OK; }
39
SetDecoderProperties2(const Byte * prop,UInt32 size)40 STDMETHODIMP CDecoder::SetDecoderProperties2(const Byte *prop, UInt32 size)
41 {
42 if (size != 1)
43 return E_NOTIMPL;
44 if (prop[0] > 40)
45 return E_NOTIMPL;
46 _prop = prop[0];
47 return S_OK;
48 }
49
50
SetFinishMode(UInt32 finishMode)51 STDMETHODIMP CDecoder::SetFinishMode(UInt32 finishMode)
52 {
53 _finishMode = (finishMode != 0);
54 return S_OK;
55 }
56
57
58
59 #ifndef _7ZIP_ST
60
Get_ExpectedBlockSize_From_Dict(UInt32 dictSize)61 static UInt64 Get_ExpectedBlockSize_From_Dict(UInt32 dictSize)
62 {
63 const UInt32 kMinSize = (UInt32)1 << 20;
64 const UInt32 kMaxSize = (UInt32)1 << 28;
65 UInt64 blockSize = (UInt64)dictSize << 2;
66 if (blockSize < kMinSize) blockSize = kMinSize;
67 if (blockSize > kMaxSize) blockSize = kMaxSize;
68 if (blockSize < dictSize) blockSize = dictSize;
69 blockSize += (kMinSize - 1);
70 blockSize &= ~(UInt64)(kMinSize - 1);
71 return blockSize;
72 }
73
74 #define LZMA2_DIC_SIZE_FROM_PROP_FULL(p) ((p) == 40 ? 0xFFFFFFFF : (((UInt32)2 | ((p) & 1)) << ((p) / 2 + 11)))
75
76 #endif
77
78 #define RET_IF_WRAP_ERROR_CONFIRMED(wrapRes, sRes, sResErrorCode) \
79 if (wrapRes != S_OK && sRes == sResErrorCode) return wrapRes;
80
81 #define RET_IF_WRAP_ERROR(wrapRes, sRes, sResErrorCode) \
82 if (wrapRes != S_OK /* && (sRes == SZ_OK || sRes == sResErrorCode) */) return wrapRes;
83
Code(ISequentialInStream * inStream,ISequentialOutStream * outStream,const UInt64 * inSize,const UInt64 * outSize,ICompressProgressInfo * progress)84 STDMETHODIMP CDecoder::Code(ISequentialInStream *inStream, ISequentialOutStream *outStream,
85 const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress)
86 {
87 _inProcessed = 0;
88
89 if (!_dec)
90 {
91 _dec = Lzma2DecMt_Create(
92 // &g_AlignedAlloc,
93 &g_Alloc,
94 &g_MidAlloc);
95 if (!_dec)
96 return E_OUTOFMEMORY;
97 }
98
99 CLzma2DecMtProps props;
100 Lzma2DecMtProps_Init(&props);
101
102 props.inBufSize_ST = _inBufSize;
103 props.outStep_ST = _outStep;
104
105 #ifndef _7ZIP_ST
106 {
107 props.numThreads = 1;
108 UInt32 numThreads = _numThreads;
109
110 if (_tryMt && numThreads >= 1)
111 {
112 UInt64 useLimit = _memUsage;
113 UInt32 dictSize = LZMA2_DIC_SIZE_FROM_PROP_FULL(_prop);
114 UInt64 expectedBlockSize64 = Get_ExpectedBlockSize_From_Dict(dictSize);
115 size_t expectedBlockSize = (size_t)expectedBlockSize64;
116 size_t inBlockMax = expectedBlockSize + expectedBlockSize / 16;
117 if (expectedBlockSize == expectedBlockSize64 && inBlockMax >= expectedBlockSize)
118 {
119 props.outBlockMax = expectedBlockSize;
120 props.inBlockMax = inBlockMax;
121 const size_t kOverheadSize = props.inBufSize_MT + (1 << 16);
122 UInt64 okThreads = useLimit / (props.outBlockMax + props.inBlockMax + kOverheadSize);
123 if (numThreads > okThreads)
124 numThreads = (UInt32)okThreads;
125 if (numThreads == 0)
126 numThreads = 1;
127 props.numThreads = numThreads;
128 }
129 }
130 }
131 #endif
132
133 CSeqInStreamWrap inWrap;
134 CSeqOutStreamWrap outWrap;
135 CCompressProgressWrap progressWrap;
136
137 inWrap.Init(inStream);
138 outWrap.Init(outStream);
139 progressWrap.Init(progress);
140
141 SRes res;
142
143 UInt64 inProcessed = 0;
144 int isMT = False;
145
146 #ifndef _7ZIP_ST
147 isMT = _tryMt;
148 #endif
149
150 // UInt64 cpuTicks = GetCpuTicks();
151
152 res = Lzma2DecMt_Decode(_dec, _prop, &props,
153 &outWrap.vt, outSize, _finishMode,
154 &inWrap.vt,
155 &inProcessed,
156 &isMT,
157 progress ? &progressWrap.vt : NULL);
158
159 /*
160 cpuTicks = GetCpuTicks() - cpuTicks;
161 printf("\n ticks = %10I64u\n", cpuTicks / 1000000);
162 */
163
164
165 #ifndef _7ZIP_ST
166 /* we reset _tryMt, only if p->props.numThreads was changed */
167 if (props.numThreads > 1)
168 _tryMt = isMT;
169 #endif
170
171 _inProcessed = inProcessed;
172
173 RET_IF_WRAP_ERROR(progressWrap.Res, res, SZ_ERROR_PROGRESS)
174 RET_IF_WRAP_ERROR(outWrap.Res, res, SZ_ERROR_WRITE)
175 RET_IF_WRAP_ERROR_CONFIRMED(inWrap.Res, res, SZ_ERROR_READ)
176
177 if (res == SZ_OK && _finishMode)
178 {
179 if (inSize && *inSize != inProcessed)
180 res = SZ_ERROR_DATA;
181 if (outSize && *outSize != outWrap.Processed)
182 res = SZ_ERROR_DATA;
183 }
184
185 return SResToHRESULT(res);
186 }
187
188
GetInStreamProcessedSize(UInt64 * value)189 STDMETHODIMP CDecoder::GetInStreamProcessedSize(UInt64 *value)
190 {
191 *value = _inProcessed;
192 return S_OK;
193 }
194
195
196 #ifndef _7ZIP_ST
197
SetNumberOfThreads(UInt32 numThreads)198 STDMETHODIMP CDecoder::SetNumberOfThreads(UInt32 numThreads)
199 {
200 _numThreads = numThreads;
201 return S_OK;
202 }
203
SetMemLimit(UInt64 memUsage)204 STDMETHODIMP CDecoder::SetMemLimit(UInt64 memUsage)
205 {
206 _memUsage = memUsage;
207 return S_OK;
208 }
209
210 #endif
211
212
213 #ifndef NO_READ_FROM_CODER
214
SetOutStreamSize(const UInt64 * outSize)215 STDMETHODIMP CDecoder::SetOutStreamSize(const UInt64 *outSize)
216 {
217 CLzma2DecMtProps props;
218 Lzma2DecMtProps_Init(&props);
219 props.inBufSize_ST = _inBufSize;
220 props.outStep_ST = _outStep;
221
222 _inProcessed = 0;
223
224 if (!_dec)
225 {
226 _dec = Lzma2DecMt_Create(&g_AlignedAlloc, &g_MidAlloc);
227 if (!_dec)
228 return E_OUTOFMEMORY;
229 }
230
231 _inWrap.Init(_inStream);
232
233 SRes res = Lzma2DecMt_Init(_dec, _prop, &props, outSize, _finishMode, &_inWrap.vt);
234
235 if (res != SZ_OK)
236 return SResToHRESULT(res);
237 return S_OK;
238 }
239
240
SetInStream(ISequentialInStream * inStream)241 STDMETHODIMP CDecoder::SetInStream(ISequentialInStream *inStream) { _inStream = inStream; return S_OK; }
ReleaseInStream()242 STDMETHODIMP CDecoder::ReleaseInStream() { _inStream.Release(); return S_OK; }
243
244
Read(void * data,UInt32 size,UInt32 * processedSize)245 STDMETHODIMP CDecoder::Read(void *data, UInt32 size, UInt32 *processedSize)
246 {
247 if (processedSize)
248 *processedSize = 0;
249
250 size_t size2 = size;
251 UInt64 inProcessed = 0;
252
253 SRes res = Lzma2DecMt_Read(_dec, (Byte *)data, &size2, &inProcessed);
254
255 _inProcessed += inProcessed;
256 if (processedSize)
257 *processedSize = (UInt32)size2;
258 if (res != SZ_OK)
259 return SResToHRESULT(res);
260 return S_OK;
261 }
262
263 #endif
264
265 }}
266