1cd66d540cead3f8200b0c73bad9c276d67896c3dDavid Srbecky// PpmdDecoder.cpp 2cd66d540cead3f8200b0c73bad9c276d67896c3dDavid Srbecky// 2009-03-11 : Igor Pavlov : Public domain 3cd66d540cead3f8200b0c73bad9c276d67896c3dDavid Srbecky 4cd66d540cead3f8200b0c73bad9c276d67896c3dDavid Srbecky#include "StdAfx.h" 5cd66d540cead3f8200b0c73bad9c276d67896c3dDavid Srbecky 6cd66d540cead3f8200b0c73bad9c276d67896c3dDavid Srbecky#include "../../../C/Alloc.h" 7cd66d540cead3f8200b0c73bad9c276d67896c3dDavid Srbecky#include "../../../C/CpuArch.h" 8cd66d540cead3f8200b0c73bad9c276d67896c3dDavid Srbecky 9cd66d540cead3f8200b0c73bad9c276d67896c3dDavid Srbecky#include "../Common/StreamUtils.h" 10cd66d540cead3f8200b0c73bad9c276d67896c3dDavid Srbecky 11cd66d540cead3f8200b0c73bad9c276d67896c3dDavid Srbecky#include "PpmdDecoder.h" 12cd66d540cead3f8200b0c73bad9c276d67896c3dDavid Srbecky 13cd66d540cead3f8200b0c73bad9c276d67896c3dDavid Srbeckynamespace NCompress { 14cd66d540cead3f8200b0c73bad9c276d67896c3dDavid Srbeckynamespace NPpmd { 15cd66d540cead3f8200b0c73bad9c276d67896c3dDavid Srbecky 16cd66d540cead3f8200b0c73bad9c276d67896c3dDavid Srbeckystatic const UInt32 kBufSize = (1 << 20); 17cd66d540cead3f8200b0c73bad9c276d67896c3dDavid Srbecky 18cd66d540cead3f8200b0c73bad9c276d67896c3dDavid Srbeckyenum 19cd66d540cead3f8200b0c73bad9c276d67896c3dDavid Srbecky{ 20cd66d540cead3f8200b0c73bad9c276d67896c3dDavid Srbecky kStatus_NeedInit, 21cd66d540cead3f8200b0c73bad9c276d67896c3dDavid Srbecky kStatus_Normal, 22cd66d540cead3f8200b0c73bad9c276d67896c3dDavid Srbecky kStatus_Finished, 23cd66d540cead3f8200b0c73bad9c276d67896c3dDavid Srbecky kStatus_Error 24cd66d540cead3f8200b0c73bad9c276d67896c3dDavid Srbecky}; 25cd66d540cead3f8200b0c73bad9c276d67896c3dDavid Srbecky 26cd66d540cead3f8200b0c73bad9c276d67896c3dDavid Srbeckystatic void *SzBigAlloc(void *, size_t size) { return BigAlloc(size); } 27cd66d540cead3f8200b0c73bad9c276d67896c3dDavid Srbeckystatic void SzBigFree(void *, void *address) { BigFree(address); } 28cd66d540cead3f8200b0c73bad9c276d67896c3dDavid Srbeckystatic ISzAlloc g_BigAlloc = { SzBigAlloc, SzBigFree }; 29cd66d540cead3f8200b0c73bad9c276d67896c3dDavid Srbecky 30cd66d540cead3f8200b0c73bad9c276d67896c3dDavid SrbeckyCDecoder::~CDecoder() 31cd66d540cead3f8200b0c73bad9c276d67896c3dDavid Srbecky{ 32cd66d540cead3f8200b0c73bad9c276d67896c3dDavid Srbecky ::MidFree(_outBuf); 33cd66d540cead3f8200b0c73bad9c276d67896c3dDavid Srbecky Ppmd7_Free(&_ppmd, &g_BigAlloc); 34cd66d540cead3f8200b0c73bad9c276d67896c3dDavid Srbecky} 35cd66d540cead3f8200b0c73bad9c276d67896c3dDavid Srbecky 36cd66d540cead3f8200b0c73bad9c276d67896c3dDavid SrbeckySTDMETHODIMP CDecoder::SetDecoderProperties2(const Byte *props, UInt32 size) 37cd66d540cead3f8200b0c73bad9c276d67896c3dDavid Srbecky{ 38cd66d540cead3f8200b0c73bad9c276d67896c3dDavid Srbecky if (size < 5) 39cd66d540cead3f8200b0c73bad9c276d67896c3dDavid Srbecky return E_INVALIDARG; 40cd66d540cead3f8200b0c73bad9c276d67896c3dDavid Srbecky _order = props[0]; 41cd66d540cead3f8200b0c73bad9c276d67896c3dDavid Srbecky UInt32 memSize = GetUi32(props + 1); 42cd66d540cead3f8200b0c73bad9c276d67896c3dDavid Srbecky if (_order < PPMD7_MIN_ORDER || 43cd66d540cead3f8200b0c73bad9c276d67896c3dDavid Srbecky _order > PPMD7_MAX_ORDER || 44cd66d540cead3f8200b0c73bad9c276d67896c3dDavid Srbecky memSize < PPMD7_MIN_MEM_SIZE || 45cd66d540cead3f8200b0c73bad9c276d67896c3dDavid Srbecky memSize > PPMD7_MAX_MEM_SIZE) 46cd66d540cead3f8200b0c73bad9c276d67896c3dDavid Srbecky return E_NOTIMPL; 47cd66d540cead3f8200b0c73bad9c276d67896c3dDavid Srbecky if (!_inStream.Alloc(1 << 20)) 48cd66d540cead3f8200b0c73bad9c276d67896c3dDavid Srbecky return E_OUTOFMEMORY; 49cd66d540cead3f8200b0c73bad9c276d67896c3dDavid Srbecky if (!Ppmd7_Alloc(&_ppmd, memSize, &g_BigAlloc)) 50cd66d540cead3f8200b0c73bad9c276d67896c3dDavid Srbecky return E_OUTOFMEMORY; 51cd66d540cead3f8200b0c73bad9c276d67896c3dDavid Srbecky return S_OK; 52cd66d540cead3f8200b0c73bad9c276d67896c3dDavid Srbecky} 53cd66d540cead3f8200b0c73bad9c276d67896c3dDavid Srbecky 54cd66d540cead3f8200b0c73bad9c276d67896c3dDavid SrbeckyHRESULT CDecoder::CodeSpec(Byte *memStream, UInt32 size) 55cd66d540cead3f8200b0c73bad9c276d67896c3dDavid Srbecky{ 56cd66d540cead3f8200b0c73bad9c276d67896c3dDavid Srbecky switch(_status) 57cd66d540cead3f8200b0c73bad9c276d67896c3dDavid Srbecky { 58cd66d540cead3f8200b0c73bad9c276d67896c3dDavid Srbecky case kStatus_Finished: return S_OK; 59cd66d540cead3f8200b0c73bad9c276d67896c3dDavid Srbecky case kStatus_Error: return S_FALSE; 60cd66d540cead3f8200b0c73bad9c276d67896c3dDavid Srbecky case kStatus_NeedInit: 61cd66d540cead3f8200b0c73bad9c276d67896c3dDavid Srbecky _inStream.Init(); 62cd66d540cead3f8200b0c73bad9c276d67896c3dDavid Srbecky if (!Ppmd7z_RangeDec_Init(&_rangeDec)) 63cd66d540cead3f8200b0c73bad9c276d67896c3dDavid Srbecky { 64cd66d540cead3f8200b0c73bad9c276d67896c3dDavid Srbecky _status = kStatus_Error; 65cd66d540cead3f8200b0c73bad9c276d67896c3dDavid Srbecky return S_FALSE; 66cd66d540cead3f8200b0c73bad9c276d67896c3dDavid Srbecky } 67cd66d540cead3f8200b0c73bad9c276d67896c3dDavid Srbecky _status = kStatus_Normal; 68cd66d540cead3f8200b0c73bad9c276d67896c3dDavid Srbecky Ppmd7_Init(&_ppmd, _order); 69cd66d540cead3f8200b0c73bad9c276d67896c3dDavid Srbecky break; 70cd66d540cead3f8200b0c73bad9c276d67896c3dDavid Srbecky } 71cd66d540cead3f8200b0c73bad9c276d67896c3dDavid Srbecky if (_outSizeDefined) 72cd66d540cead3f8200b0c73bad9c276d67896c3dDavid Srbecky { 73cd66d540cead3f8200b0c73bad9c276d67896c3dDavid Srbecky const UInt64 rem = _outSize - _processedSize; 74cd66d540cead3f8200b0c73bad9c276d67896c3dDavid Srbecky if (size > rem) 75cd66d540cead3f8200b0c73bad9c276d67896c3dDavid Srbecky size = (UInt32)rem; 76cd66d540cead3f8200b0c73bad9c276d67896c3dDavid Srbecky } 77cd66d540cead3f8200b0c73bad9c276d67896c3dDavid Srbecky 78cd66d540cead3f8200b0c73bad9c276d67896c3dDavid Srbecky UInt32 i; 79cd66d540cead3f8200b0c73bad9c276d67896c3dDavid Srbecky int sym = 0; 80cd66d540cead3f8200b0c73bad9c276d67896c3dDavid Srbecky for (i = 0; i != size; i++) 81cd66d540cead3f8200b0c73bad9c276d67896c3dDavid Srbecky { 82cd66d540cead3f8200b0c73bad9c276d67896c3dDavid Srbecky sym = Ppmd7_DecodeSymbol(&_ppmd, &_rangeDec.p); 83cd66d540cead3f8200b0c73bad9c276d67896c3dDavid Srbecky if (_inStream.Extra || sym < 0) 84cd66d540cead3f8200b0c73bad9c276d67896c3dDavid Srbecky break; 85cd66d540cead3f8200b0c73bad9c276d67896c3dDavid Srbecky memStream[i] = (Byte)sym; 86cd66d540cead3f8200b0c73bad9c276d67896c3dDavid Srbecky } 87cd66d540cead3f8200b0c73bad9c276d67896c3dDavid Srbecky 88cd66d540cead3f8200b0c73bad9c276d67896c3dDavid Srbecky _processedSize += i; 89cd66d540cead3f8200b0c73bad9c276d67896c3dDavid Srbecky if (_inStream.Extra) 90cd66d540cead3f8200b0c73bad9c276d67896c3dDavid Srbecky { 91cd66d540cead3f8200b0c73bad9c276d67896c3dDavid Srbecky _status = kStatus_Error; 92cd66d540cead3f8200b0c73bad9c276d67896c3dDavid Srbecky return _inStream.Res; 93cd66d540cead3f8200b0c73bad9c276d67896c3dDavid Srbecky } 94cd66d540cead3f8200b0c73bad9c276d67896c3dDavid Srbecky if (sym < 0) 95cd66d540cead3f8200b0c73bad9c276d67896c3dDavid Srbecky _status = (sym < -1) ? kStatus_Error : kStatus_Finished; 96cd66d540cead3f8200b0c73bad9c276d67896c3dDavid Srbecky return S_OK; 97cd66d540cead3f8200b0c73bad9c276d67896c3dDavid Srbecky} 98cd66d540cead3f8200b0c73bad9c276d67896c3dDavid Srbecky 99cd66d540cead3f8200b0c73bad9c276d67896c3dDavid SrbeckySTDMETHODIMP CDecoder::Code(ISequentialInStream *inStream, ISequentialOutStream *outStream, 100cd66d540cead3f8200b0c73bad9c276d67896c3dDavid Srbecky const UInt64 * /* inSize */, const UInt64 *outSize, ICompressProgressInfo *progress) 101cd66d540cead3f8200b0c73bad9c276d67896c3dDavid Srbecky{ 102cd66d540cead3f8200b0c73bad9c276d67896c3dDavid Srbecky if (!_outBuf) 103cd66d540cead3f8200b0c73bad9c276d67896c3dDavid Srbecky { 104cd66d540cead3f8200b0c73bad9c276d67896c3dDavid Srbecky _outBuf = (Byte *)::MidAlloc(kBufSize); 105cd66d540cead3f8200b0c73bad9c276d67896c3dDavid Srbecky if (!_outBuf) 106cd66d540cead3f8200b0c73bad9c276d67896c3dDavid Srbecky return E_OUTOFMEMORY; 107cd66d540cead3f8200b0c73bad9c276d67896c3dDavid Srbecky } 108cd66d540cead3f8200b0c73bad9c276d67896c3dDavid Srbecky 109cd66d540cead3f8200b0c73bad9c276d67896c3dDavid Srbecky _inStream.Stream = inStream; 110cd66d540cead3f8200b0c73bad9c276d67896c3dDavid Srbecky SetOutStreamSize(outSize); 111cd66d540cead3f8200b0c73bad9c276d67896c3dDavid Srbecky 112cd66d540cead3f8200b0c73bad9c276d67896c3dDavid Srbecky do 113cd66d540cead3f8200b0c73bad9c276d67896c3dDavid Srbecky { 114cd66d540cead3f8200b0c73bad9c276d67896c3dDavid Srbecky const UInt64 startPos = _processedSize; 115cd66d540cead3f8200b0c73bad9c276d67896c3dDavid Srbecky HRESULT res = CodeSpec(_outBuf, kBufSize); 116cd66d540cead3f8200b0c73bad9c276d67896c3dDavid Srbecky size_t processed = (size_t)(_processedSize - startPos); 117cd66d540cead3f8200b0c73bad9c276d67896c3dDavid Srbecky RINOK(WriteStream(outStream, _outBuf, processed)); 118cd66d540cead3f8200b0c73bad9c276d67896c3dDavid Srbecky RINOK(res); 119cd66d540cead3f8200b0c73bad9c276d67896c3dDavid Srbecky if (_status == kStatus_Finished) 120cd66d540cead3f8200b0c73bad9c276d67896c3dDavid Srbecky break; 121cd66d540cead3f8200b0c73bad9c276d67896c3dDavid Srbecky if (progress) 122cd66d540cead3f8200b0c73bad9c276d67896c3dDavid Srbecky { 123cd66d540cead3f8200b0c73bad9c276d67896c3dDavid Srbecky UInt64 inSize = _inStream.GetProcessed(); 124cd66d540cead3f8200b0c73bad9c276d67896c3dDavid Srbecky RINOK(progress->SetRatioInfo(&inSize, &_processedSize)); 125cd66d540cead3f8200b0c73bad9c276d67896c3dDavid Srbecky } 126cd66d540cead3f8200b0c73bad9c276d67896c3dDavid Srbecky } 127cd66d540cead3f8200b0c73bad9c276d67896c3dDavid Srbecky while (!_outSizeDefined || _processedSize < _outSize); 128cd66d540cead3f8200b0c73bad9c276d67896c3dDavid Srbecky return S_OK; 129cd66d540cead3f8200b0c73bad9c276d67896c3dDavid Srbecky} 130cd66d540cead3f8200b0c73bad9c276d67896c3dDavid Srbecky 131cd66d540cead3f8200b0c73bad9c276d67896c3dDavid SrbeckySTDMETHODIMP CDecoder::SetOutStreamSize(const UInt64 *outSize) 132cd66d540cead3f8200b0c73bad9c276d67896c3dDavid Srbecky{ 133cd66d540cead3f8200b0c73bad9c276d67896c3dDavid Srbecky _outSizeDefined = (outSize != NULL); 134cd66d540cead3f8200b0c73bad9c276d67896c3dDavid Srbecky if (_outSizeDefined) 135cd66d540cead3f8200b0c73bad9c276d67896c3dDavid Srbecky _outSize = *outSize; 136cd66d540cead3f8200b0c73bad9c276d67896c3dDavid Srbecky _processedSize = 0; 137cd66d540cead3f8200b0c73bad9c276d67896c3dDavid Srbecky _status = kStatus_NeedInit; 138cd66d540cead3f8200b0c73bad9c276d67896c3dDavid Srbecky return S_OK; 139cd66d540cead3f8200b0c73bad9c276d67896c3dDavid Srbecky} 140cd66d540cead3f8200b0c73bad9c276d67896c3dDavid Srbecky 141cd66d540cead3f8200b0c73bad9c276d67896c3dDavid Srbecky#ifndef NO_READ_FROM_CODER 142cd66d540cead3f8200b0c73bad9c276d67896c3dDavid Srbecky 143cd66d540cead3f8200b0c73bad9c276d67896c3dDavid SrbeckySTDMETHODIMP CDecoder::SetInStream(ISequentialInStream *inStream) 144cd66d540cead3f8200b0c73bad9c276d67896c3dDavid Srbecky{ 145cd66d540cead3f8200b0c73bad9c276d67896c3dDavid Srbecky InSeqStream = inStream; 146cd66d540cead3f8200b0c73bad9c276d67896c3dDavid Srbecky _inStream.Stream = inStream; 147cd66d540cead3f8200b0c73bad9c276d67896c3dDavid Srbecky return S_OK; 148cd66d540cead3f8200b0c73bad9c276d67896c3dDavid Srbecky} 149cd66d540cead3f8200b0c73bad9c276d67896c3dDavid Srbecky 150cd66d540cead3f8200b0c73bad9c276d67896c3dDavid SrbeckySTDMETHODIMP CDecoder::ReleaseInStream() 151cd66d540cead3f8200b0c73bad9c276d67896c3dDavid Srbecky{ 152cd66d540cead3f8200b0c73bad9c276d67896c3dDavid Srbecky InSeqStream.Release(); 153cd66d540cead3f8200b0c73bad9c276d67896c3dDavid Srbecky return S_OK; 154cd66d540cead3f8200b0c73bad9c276d67896c3dDavid Srbecky} 155cd66d540cead3f8200b0c73bad9c276d67896c3dDavid Srbecky 156cd66d540cead3f8200b0c73bad9c276d67896c3dDavid SrbeckySTDMETHODIMP CDecoder::Read(void *data, UInt32 size, UInt32 *processedSize) 157cd66d540cead3f8200b0c73bad9c276d67896c3dDavid Srbecky{ 158cd66d540cead3f8200b0c73bad9c276d67896c3dDavid Srbecky const UInt64 startPos = _processedSize; 159cd66d540cead3f8200b0c73bad9c276d67896c3dDavid Srbecky HRESULT res = CodeSpec((Byte *)data, size); 160cd66d540cead3f8200b0c73bad9c276d67896c3dDavid Srbecky if (processedSize) 161cd66d540cead3f8200b0c73bad9c276d67896c3dDavid Srbecky *processedSize = (UInt32)(_processedSize - startPos); 162cd66d540cead3f8200b0c73bad9c276d67896c3dDavid Srbecky return res; 163cd66d540cead3f8200b0c73bad9c276d67896c3dDavid Srbecky} 164cd66d540cead3f8200b0c73bad9c276d67896c3dDavid Srbecky 165cd66d540cead3f8200b0c73bad9c276d67896c3dDavid Srbecky#endif 166cd66d540cead3f8200b0c73bad9c276d67896c3dDavid Srbecky 167cd66d540cead3f8200b0c73bad9c276d67896c3dDavid Srbecky}} 168