1 // Lzma2Decoder.cpp 2 3 #include "StdAfx.h" 4 5 #include "../../../C/Alloc.h" 6 7 #include "../Common/StreamUtils.h" 8 9 #include "Lzma2Decoder.h" 10 11 static HRESULT SResToHRESULT(SRes res) 12 { 13 switch (res) 14 { 15 case SZ_OK: return S_OK; 16 case SZ_ERROR_MEM: return E_OUTOFMEMORY; 17 case SZ_ERROR_PARAM: return E_INVALIDARG; 18 // case SZ_ERROR_PROGRESS: return E_ABORT; 19 case SZ_ERROR_DATA: return S_FALSE; 20 } 21 return E_FAIL; 22 } 23 24 namespace NCompress { 25 namespace NLzma2 { 26 27 CDecoder::CDecoder(): 28 _inBuf(NULL), 29 _inBufSize(0), 30 _inBufSizeNew(1 << 20), 31 _outStepSize(1 << 22), 32 _outSizeDefined(false), 33 _finishMode(false) 34 { 35 Lzma2Dec_Construct(&_state); 36 } 37 38 STDMETHODIMP CDecoder::SetInBufSize(UInt32 , UInt32 size) { _inBufSizeNew = size; return S_OK; } 39 STDMETHODIMP CDecoder::SetOutBufSize(UInt32 , UInt32 size) { _outStepSize = size; return S_OK; } 40 41 CDecoder::~CDecoder() 42 { 43 Lzma2Dec_Free(&_state, &g_Alloc); 44 MidFree(_inBuf); 45 } 46 47 STDMETHODIMP CDecoder::SetDecoderProperties2(const Byte *prop, UInt32 size) 48 { 49 if (size != 1) 50 return E_NOTIMPL; 51 52 RINOK(SResToHRESULT(Lzma2Dec_Allocate(&_state, prop[0], &g_Alloc))); 53 if (!_inBuf || _inBufSize != _inBufSizeNew) 54 { 55 MidFree(_inBuf); 56 _inBufSize = 0; 57 _inBuf = (Byte *)MidAlloc(_inBufSizeNew); 58 if (!_inBuf) 59 return E_OUTOFMEMORY; 60 _inBufSize = _inBufSizeNew; 61 } 62 63 return S_OK; 64 } 65 66 STDMETHODIMP CDecoder::GetInStreamProcessedSize(UInt64 *value) { *value = _inSizeProcessed; return S_OK; } 67 STDMETHODIMP CDecoder::SetInStream(ISequentialInStream *inStream) { _inStream = inStream; return S_OK; } 68 STDMETHODIMP CDecoder::ReleaseInStream() { _inStream.Release(); return S_OK; } 69 70 STDMETHODIMP CDecoder::SetOutStreamSize(const UInt64 *outSize) 71 { 72 _outSizeDefined = (outSize != NULL); 73 _outSize = 0; 74 if (_outSizeDefined) 75 _outSize = *outSize; 76 77 Lzma2Dec_Init(&_state); 78 79 _inPos = _inSize = 0; 80 _inSizeProcessed = _outSizeProcessed = 0; 81 return S_OK; 82 } 83 84 STDMETHODIMP CDecoder::SetFinishMode(UInt32 finishMode) 85 { 86 _finishMode = (finishMode != 0); 87 return S_OK; 88 } 89 90 STDMETHODIMP CDecoder::Code(ISequentialInStream *inStream, 91 ISequentialOutStream *outStream, const UInt64 *inSize, 92 const UInt64 *outSize, ICompressProgressInfo *progress) 93 { 94 if (!_inBuf) 95 return S_FALSE; 96 SetOutStreamSize(outSize); 97 98 UInt32 step = _outStepSize; 99 const UInt32 kOutStepSize_Min = 1 << 12; 100 if (step < kOutStepSize_Min) 101 step = kOutStepSize_Min; 102 103 SizeT wrPos = _state.decoder.dicPos; 104 105 SizeT next = (_state.decoder.dicBufSize - _state.decoder.dicPos < step) ? 106 _state.decoder.dicBufSize : 107 _state.decoder.dicPos + step; 108 109 HRESULT hres = S_OK; 110 111 for (;;) 112 { 113 if (_inPos == _inSize) 114 { 115 _inPos = _inSize = 0; 116 hres = inStream->Read(_inBuf, _inBufSize, &_inSize); 117 if (hres != S_OK) 118 break; 119 } 120 121 SizeT dicPos = _state.decoder.dicPos; 122 SizeT curSize = next - dicPos; 123 124 ELzmaFinishMode finishMode = LZMA_FINISH_ANY; 125 if (_outSizeDefined) 126 { 127 const UInt64 rem = _outSize - _outSizeProcessed; 128 if (curSize >= rem) 129 { 130 curSize = (SizeT)rem; 131 if (_finishMode) 132 finishMode = LZMA_FINISH_END; 133 } 134 } 135 136 SizeT inSizeProcessed = _inSize - _inPos; 137 ELzmaStatus status; 138 SRes res = Lzma2Dec_DecodeToDic(&_state, dicPos + curSize, _inBuf + _inPos, &inSizeProcessed, finishMode, &status); 139 140 _inPos += (UInt32)inSizeProcessed; 141 _inSizeProcessed += inSizeProcessed; 142 SizeT outSizeProcessed = _state.decoder.dicPos - dicPos; 143 _outSizeProcessed += outSizeProcessed; 144 145 bool finished = (inSizeProcessed == 0 && outSizeProcessed == 0 146 || status == LZMA_STATUS_FINISHED_WITH_MARK); 147 bool outFinished = (_outSizeDefined && _outSizeProcessed >= _outSize); 148 149 if (res != 0 150 || _state.decoder.dicPos >= next 151 || finished 152 || outFinished) 153 { 154 HRESULT res2 = WriteStream(outStream, _state.decoder.dic + wrPos, _state.decoder.dicPos - wrPos); 155 156 if (_state.decoder.dicPos == _state.decoder.dicBufSize) 157 _state.decoder.dicPos = 0; 158 159 wrPos = _state.decoder.dicPos; 160 161 next = (_state.decoder.dicBufSize - _state.decoder.dicPos < step) ? 162 _state.decoder.dicBufSize : 163 _state.decoder.dicPos + step; 164 165 if (res != 0) 166 return S_FALSE; 167 RINOK(res2); 168 169 if (finished) 170 { 171 if (status == LZMA_STATUS_FINISHED_WITH_MARK) 172 { 173 if (_finishMode && inSize && *inSize != _inSizeProcessed) 174 return S_FALSE; 175 if (finishMode == LZMA_FINISH_END && !outFinished) 176 return S_FALSE; 177 return S_OK; 178 } 179 return (finishMode == LZMA_FINISH_END) ? S_FALSE : S_OK; 180 } 181 182 if (outFinished && finishMode == LZMA_FINISH_ANY) 183 return S_OK; 184 } 185 186 if (progress) 187 { 188 RINOK(progress->SetRatioInfo(&_inSizeProcessed, &_outSizeProcessed)); 189 } 190 } 191 192 HRESULT res2 = WriteStream(outStream, _state.decoder.dic + wrPos, _state.decoder.dicPos - wrPos); 193 if (hres != S_OK) 194 return hres; 195 return res2; 196 } 197 198 #ifndef NO_READ_FROM_CODER 199 200 STDMETHODIMP CDecoder::Read(void *data, UInt32 size, UInt32 *processedSize) 201 { 202 UInt32 totalProcessed = 0; 203 204 if (processedSize) 205 *processedSize = 0; 206 207 for (;;) 208 { 209 if (_inPos == _inSize) 210 { 211 _inPos = _inSize = 0; 212 RINOK(_inStream->Read(_inBuf, _inBufSize, &_inSize)); 213 } 214 { 215 ELzmaFinishMode finishMode = LZMA_FINISH_ANY; 216 if (_outSizeDefined) 217 { 218 const UInt64 rem = _outSize - _outSizeProcessed; 219 if (rem <= size) 220 { 221 size = (UInt32)rem; 222 if (_finishMode) 223 finishMode = LZMA_FINISH_END; 224 } 225 } 226 227 SizeT outProcessed = size; 228 SizeT inProcessed = _inSize - _inPos; 229 230 ELzmaStatus status; 231 SRes res = Lzma2Dec_DecodeToBuf(&_state, (Byte *)data, &outProcessed, 232 _inBuf + _inPos, &inProcessed, finishMode, &status); 233 234 _inPos += (UInt32)inProcessed; 235 _inSizeProcessed += inProcessed; 236 _outSizeProcessed += outProcessed; 237 size -= (UInt32)outProcessed; 238 data = (Byte *)data + outProcessed; 239 240 totalProcessed += (UInt32)outProcessed; 241 if (processedSize) 242 *processedSize = totalProcessed; 243 244 if (res != SZ_OK) 245 { 246 if (totalProcessed != 0) 247 return S_OK; 248 return SResToHRESULT(res); 249 } 250 251 if (inProcessed == 0 && outProcessed == 0) 252 return S_OK; 253 if (status == LZMA_STATUS_FINISHED_WITH_MARK) 254 return S_OK; 255 if (outProcessed != 0) 256 { 257 if (finishMode != LZMA_FINISH_END || _outSize != _outSizeProcessed) 258 return S_OK; 259 } 260 } 261 } 262 } 263 264 #endif 265 266 }} 267