1// PpmdDecoder.cpp 2 3#include "StdAfx.h" 4 5#include "../../../C/Alloc.h" 6#include "../../../C/CpuArch.h" 7 8#include "../Common/StreamUtils.h" 9 10#include "PpmdDecoder.h" 11 12namespace NCompress { 13namespace NPpmd { 14 15static const UInt32 kBufSize = (1 << 16); 16 17enum 18{ 19 kStatus_NeedInit, 20 kStatus_Normal, 21 kStatus_Finished_With_Mark, 22 kStatus_Error 23}; 24 25CDecoder::~CDecoder() 26{ 27 ::MidFree(_outBuf); 28 Ppmd7_Free(&_ppmd, &g_BigAlloc); 29} 30 31Z7_COM7F_IMF(CDecoder::SetDecoderProperties2(const Byte *props, UInt32 size)) 32{ 33 if (size < 5) 34 return E_INVALIDARG; 35 _order = props[0]; 36 const UInt32 memSize = GetUi32(props + 1); 37 if (_order < PPMD7_MIN_ORDER || 38 _order > PPMD7_MAX_ORDER || 39 memSize < PPMD7_MIN_MEM_SIZE || 40 memSize > PPMD7_MAX_MEM_SIZE) 41 return E_NOTIMPL; 42 if (!_inStream.Alloc(1 << 20)) 43 return E_OUTOFMEMORY; 44 if (!Ppmd7_Alloc(&_ppmd, memSize, &g_BigAlloc)) 45 return E_OUTOFMEMORY; 46 return S_OK; 47} 48 49#define MY_rangeDec _ppmd.rc.dec 50 51#define CHECK_EXTRA_ERROR \ 52 if (_inStream.Extra) { \ 53 _status = kStatus_Error; \ 54 return (_res = (_inStream.Res != SZ_OK ? _inStream.Res: S_FALSE)); } 55 56 57HRESULT CDecoder::CodeSpec(Byte *memStream, UInt32 size) 58{ 59 if (_res != S_OK) 60 return _res; 61 62 switch (_status) 63 { 64 case kStatus_Finished_With_Mark: return S_OK; 65 case kStatus_Error: return S_FALSE; 66 case kStatus_NeedInit: 67 _inStream.Init(); 68 if (!Ppmd7z_RangeDec_Init(&MY_rangeDec)) 69 { 70 _status = kStatus_Error; 71 return (_res = S_FALSE); 72 } 73 CHECK_EXTRA_ERROR 74 _status = kStatus_Normal; 75 Ppmd7_Init(&_ppmd, _order); 76 break; 77 } 78 79 if (_outSizeDefined) 80 { 81 const UInt64 rem = _outSize - _processedSize; 82 if (size > rem) 83 size = (UInt32)rem; 84 } 85 86 int sym = 0; 87 { 88 Byte *buf = memStream; 89 const Byte *lim = buf + size; 90 for (; buf != lim; buf++) 91 { 92 sym = Ppmd7z_DecodeSymbol(&_ppmd); 93 if (_inStream.Extra || sym < 0) 94 break; 95 *buf = (Byte)sym; 96 } 97 /* 98 buf = Ppmd7z_DecodeSymbols(&_ppmd, buf, lim); 99 sym = _ppmd.LastSymbol; 100 */ 101 _processedSize += (size_t)(buf - memStream); 102 } 103 104 CHECK_EXTRA_ERROR 105 106 if (sym >= 0) 107 { 108 if (!FinishStream 109 || !_outSizeDefined 110 || _outSize != _processedSize 111 || MY_rangeDec.Code == 0) 112 return S_OK; 113 /* 114 // We can decode additional End Marker here: 115 sym = Ppmd7z_DecodeSymbol(&_ppmd); 116 CHECK_EXTRA_ERROR 117 */ 118 } 119 120 if (sym != PPMD7_SYM_END || MY_rangeDec.Code != 0) 121 { 122 _status = kStatus_Error; 123 return (_res = S_FALSE); 124 } 125 126 _status = kStatus_Finished_With_Mark; 127 return S_OK; 128} 129 130 131 132Z7_COM7F_IMF(CDecoder::Code(ISequentialInStream *inStream, ISequentialOutStream *outStream, 133 const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress)) 134{ 135 if (!_outBuf) 136 { 137 _outBuf = (Byte *)::MidAlloc(kBufSize); 138 if (!_outBuf) 139 return E_OUTOFMEMORY; 140 } 141 142 _inStream.Stream = inStream; 143 SetOutStreamSize(outSize); 144 145 do 146 { 147 const UInt64 startPos = _processedSize; 148 const HRESULT res = CodeSpec(_outBuf, kBufSize); 149 const size_t processed = (size_t)(_processedSize - startPos); 150 RINOK(WriteStream(outStream, _outBuf, processed)) 151 RINOK(res) 152 if (_status == kStatus_Finished_With_Mark) 153 break; 154 if (progress) 155 { 156 const UInt64 inProcessed = _inStream.GetProcessed(); 157 RINOK(progress->SetRatioInfo(&inProcessed, &_processedSize)) 158 } 159 } 160 while (!_outSizeDefined || _processedSize < _outSize); 161 162 if (FinishStream && inSize && *inSize != _inStream.GetProcessed()) 163 return S_FALSE; 164 165 return S_OK; 166} 167 168 169Z7_COM7F_IMF(CDecoder::SetOutStreamSize(const UInt64 *outSize)) 170{ 171 _outSizeDefined = (outSize != NULL); 172 if (_outSizeDefined) 173 _outSize = *outSize; 174 _processedSize = 0; 175 _status = kStatus_NeedInit; 176 _res = SZ_OK; 177 return S_OK; 178} 179 180Z7_COM7F_IMF(CDecoder::SetFinishMode(UInt32 finishMode)) 181{ 182 FinishStream = (finishMode != 0); 183 return S_OK; 184} 185 186Z7_COM7F_IMF(CDecoder::GetInStreamProcessedSize(UInt64 *value)) 187{ 188 *value = _inStream.GetProcessed(); 189 return S_OK; 190} 191 192#ifndef Z7_NO_READ_FROM_CODER 193 194Z7_COM7F_IMF(CDecoder::SetInStream(ISequentialInStream *inStream)) 195{ 196 InSeqStream = inStream; 197 _inStream.Stream = inStream; 198 return S_OK; 199} 200 201Z7_COM7F_IMF(CDecoder::ReleaseInStream()) 202{ 203 InSeqStream.Release(); 204 return S_OK; 205} 206 207Z7_COM7F_IMF(CDecoder::Read(void *data, UInt32 size, UInt32 *processedSize)) 208{ 209 const UInt64 startPos = _processedSize; 210 const HRESULT res = CodeSpec((Byte *)data, size); 211 if (processedSize) 212 *processedSize = (UInt32)(_processedSize - startPos); 213 return res; 214} 215 216#endif 217 218}} 219