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 13 namespace NCompress { 14 namespace NPpmd { 15 16 static const UInt32 kBufSize = (1 << 20); 17 18 static void *SzBigAlloc(void *, size_t size) { return BigAlloc(size); } 19 static void SzBigFree(void *, void *address) { BigFree(address); } 20 static ISzAlloc g_BigAlloc = { SzBigAlloc, SzBigFree }; 21 22 CEncoder::CEncoder(): 23 _inBuf(NULL), 24 _usedMemSize(1 << 24), 25 _order(6) 26 { 27 _rangeEnc.Stream = &_outStream.p; 28 Ppmd7_Construct(&_ppmd); 29 } 30 31 CEncoder::~CEncoder() 32 { 33 ::MidFree(_inBuf); 34 Ppmd7_Free(&_ppmd, &g_BigAlloc); 35 } 36 37 STDMETHODIMP 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 64 STDMETHODIMP 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 73 HRESULT 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