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