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 14namespace NCompress { 15namespace NLzma2 { 16 17CDecoder::CDecoder(): 18 _dec(NULL) 19 , _inProcessed(0) 20 , _prop(0xFF) 21 , _finishMode(false) 22 , _inBufSize(1 << 20) 23 , _outStep(1 << 20) 24 #ifndef Z7_ST 25 , _tryMt(1) 26 , _numThreads(1) 27 , _memUsage((UInt64)(sizeof(size_t)) << 28) 28 #endif 29{} 30 31CDecoder::~CDecoder() 32{ 33 if (_dec) 34 Lzma2DecMt_Destroy(_dec); 35} 36 37Z7_COM7F_IMF(CDecoder::SetInBufSize(UInt32 , UInt32 size)) { _inBufSize = size; return S_OK; } 38Z7_COM7F_IMF(CDecoder::SetOutBufSize(UInt32 , UInt32 size)) { _outStep = size; return S_OK; } 39 40Z7_COM7F_IMF(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 51Z7_COM7F_IMF(CDecoder::SetFinishMode(UInt32 finishMode)) 52{ 53 _finishMode = (finishMode != 0); 54 return S_OK; 55} 56 57 58 59#ifndef Z7_ST 60 61static 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 84Z7_COM7F_IMF(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 Z7_ST 106 { 107 props.numThreads = 1; 108 UInt32 numThreads = _numThreads; 109 110 if (_tryMt && numThreads >= 1) 111 { 112 const UInt64 useLimit = _memUsage; 113 const UInt32 dictSize = LZMA2_DIC_SIZE_FROM_PROP_FULL(_prop); 114 const UInt64 expectedBlockSize64 = Get_ExpectedBlockSize_From_Dict(dictSize); 115 const size_t expectedBlockSize = (size_t)expectedBlockSize64; 116 const 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 const 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 Z7_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 Z7_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 189Z7_COM7F_IMF(CDecoder::GetInStreamProcessedSize(UInt64 *value)) 190{ 191 *value = _inProcessed; 192 return S_OK; 193} 194 195 196#ifndef Z7_ST 197 198Z7_COM7F_IMF(CDecoder::SetNumberOfThreads(UInt32 numThreads)) 199{ 200 _numThreads = numThreads; 201 return S_OK; 202} 203 204Z7_COM7F_IMF(CDecoder::SetMemLimit(UInt64 memUsage)) 205{ 206 _memUsage = memUsage; 207 return S_OK; 208} 209 210#endif 211 212 213#ifndef Z7_NO_READ_FROM_CODER 214 215Z7_COM7F_IMF(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 const 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 241Z7_COM7F_IMF(CDecoder::SetInStream(ISequentialInStream *inStream)) 242 { _inStream = inStream; return S_OK; } 243Z7_COM7F_IMF(CDecoder::ReleaseInStream()) 244 { _inStream.Release(); return S_OK; } 245 246 247Z7_COM7F_IMF(CDecoder::Read(void *data, UInt32 size, UInt32 *processedSize)) 248{ 249 if (processedSize) 250 *processedSize = 0; 251 252 size_t size2 = size; 253 UInt64 inProcessed = 0; 254 255 const SRes res = Lzma2DecMt_Read(_dec, (Byte *)data, &size2, &inProcessed); 256 257 _inProcessed += inProcessed; 258 if (processedSize) 259 *processedSize = (UInt32)size2; 260 if (res != SZ_OK) 261 return SResToHRESULT(res); 262 return S_OK; 263} 264 265#endif 266 267}} 268