Lzma2Decoder.cpp (6353B)
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 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 31 CDecoder::~CDecoder() 32 { 33 if (_dec) 34 Lzma2DecMt_Destroy(_dec); 35 } 36 37 STDMETHODIMP CDecoder::SetInBufSize(UInt32 , UInt32 size) { _inBufSize = size; return S_OK; } 38 STDMETHODIMP CDecoder::SetOutBufSize(UInt32 , UInt32 size) { _outStep = size; return S_OK; } 39 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 51 STDMETHODIMP CDecoder::SetFinishMode(UInt32 finishMode) 52 { 53 _finishMode = (finishMode != 0); 54 return S_OK; 55 } 56 57 58 59 #ifndef _7ZIP_ST 60 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 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 189 STDMETHODIMP CDecoder::GetInStreamProcessedSize(UInt64 *value) 190 { 191 *value = _inProcessed; 192 return S_OK; 193 } 194 195 196 #ifndef _7ZIP_ST 197 198 STDMETHODIMP CDecoder::SetNumberOfThreads(UInt32 numThreads) 199 { 200 _numThreads = numThreads; 201 return S_OK; 202 } 203 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 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 241 STDMETHODIMP CDecoder::SetInStream(ISequentialInStream *inStream) { _inStream = inStream; return S_OK; } 242 STDMETHODIMP CDecoder::ReleaseInStream() { _inStream.Release(); return S_OK; } 243 244 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 }}