1// PpmdEncoder.cpp 2// 2009-03-11 : Igor Pavlov : Public domain 3 4#include "StdAfx.h" 5 6#include "../../../C/Alloc.h" 7#include "../../../C/CpuArch.h" 8 9#include "../Common/StreamUtils.h" 10 11#include "PpmdEncoder.h" 12 13namespace NCompress { 14namespace NPpmd { 15 16static const UInt32 kBufSize = (1 << 20); 17 18static void *SzBigAlloc(void *, size_t size) { return BigAlloc(size); } 19static void SzBigFree(void *, void *address) { BigFree(address); } 20static ISzAlloc g_BigAlloc = { SzBigAlloc, SzBigFree }; 21 22CEncoder::CEncoder(): 23 _inBuf(NULL), 24 _usedMemSize(1 << 24), 25 _order(6) 26{ 27 _rangeEnc.Stream = &_outStream.p; 28 Ppmd7_Construct(&_ppmd); 29} 30 31CEncoder::~CEncoder() 32{ 33 ::MidFree(_inBuf); 34 Ppmd7_Free(&_ppmd, &g_BigAlloc); 35} 36 37STDMETHODIMP CEncoder::SetCoderProperties(const PROPID *propIDs, const PROPVARIANT *props, UInt32 numProps) 38{ 39 for (UInt32 i = 0; i < numProps; i++) 40 { 41 const PROPVARIANT &prop = props[i]; 42 if (prop.vt != VT_UI4) 43 return E_INVALIDARG; 44 UInt32 v = (UInt32)prop.ulVal; 45 switch(propIDs[i]) 46 { 47 case NCoderPropID::kUsedMemorySize: 48 if (v < (1 << 16) || v > PPMD7_MAX_MEM_SIZE || (v & 3) != 0) 49 return E_INVALIDARG; 50 _usedMemSize = v; 51 break; 52 case NCoderPropID::kOrder: 53 if (v < 2 || v > 32) 54 return E_INVALIDARG; 55 _order = (Byte)v; 56 break; 57 default: 58 return E_INVALIDARG; 59 } 60 } 61 return S_OK; 62} 63 64STDMETHODIMP CEncoder::WriteCoderProperties(ISequentialOutStream *outStream) 65{ 66 const UInt32 kPropSize = 5; 67 Byte props[kPropSize]; 68 props[0] = _order; 69 SetUi32(props + 1, _usedMemSize); 70 return WriteStream(outStream, props, kPropSize); 71} 72 73HRESULT CEncoder::Code(ISequentialInStream *inStream, ISequentialOutStream *outStream, 74 const UInt64 * /* inSize */, const UInt64 * /* outSize */, ICompressProgressInfo *progress) 75{ 76 if (!_inBuf) 77 { 78 _inBuf = (Byte *)::MidAlloc(kBufSize); 79 if (!_inBuf) 80 return E_OUTOFMEMORY; 81 } 82 if (!_outStream.Alloc(1 << 20)) 83 return E_OUTOFMEMORY; 84 if (!Ppmd7_Alloc(&_ppmd, _usedMemSize, &g_BigAlloc)) 85 return E_OUTOFMEMORY; 86 87 _outStream.Stream = outStream; 88 _outStream.Init(); 89 90 Ppmd7z_RangeEnc_Init(&_rangeEnc); 91 Ppmd7_Init(&_ppmd, _order); 92 93 UInt64 processed = 0; 94 for (;;) 95 { 96 UInt32 size; 97 RINOK(inStream->Read(_inBuf, kBufSize, &size)); 98 if (size == 0) 99 { 100 // We don't write EndMark in PPMD-7z. 101 // Ppmd7_EncodeSymbol(&_ppmd, &_rangeEnc, -1); 102 Ppmd7z_RangeEnc_FlushData(&_rangeEnc); 103 return _outStream.Flush(); 104 } 105 for (UInt32 i = 0; i < size; i++) 106 { 107 Ppmd7_EncodeSymbol(&_ppmd, &_rangeEnc, _inBuf[i]); 108 RINOK(_outStream.Res); 109 } 110 processed += size; 111 if (progress) 112 { 113 UInt64 outSize = _outStream.GetProcessed(); 114 RINOK(progress->SetRatioInfo(&processed, &outSize)); 115 } 116 } 117} 118 119}} 120