1 // PpmdEncoder.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 "PpmdEncoder.h" 11 12 namespace NCompress { 13 namespace NPpmd { 14 15 static const UInt32 kBufSize = (1 << 20); 16 17 static const Byte kOrders[10] = { 3, 4, 4, 5, 5, 6, 8, 16, 24, 32 }; 18 19 void CEncProps::Normalize(int level) 20 { 21 if (level < 0) level = 5; 22 if (level > 9) level = 9; 23 if (MemSize == (UInt32)(Int32)-1) 24 MemSize = level >= 9 ? ((UInt32)192 << 20) : ((UInt32)1 << (level + 19)); 25 const unsigned kMult = 16; 26 if (MemSize / kMult > ReduceSize) 27 { 28 for (unsigned i = 16; i <= 31; i++) 29 { 30 UInt32 m = (UInt32)1 << i; 31 if (ReduceSize <= m / kMult) 32 { 33 if (MemSize > m) 34 MemSize = m; 35 break; 36 } 37 } 38 } 39 if (Order == -1) Order = kOrders[(unsigned)level]; 40 } 41 42 CEncoder::CEncoder(): 43 _inBuf(NULL) 44 { 45 _props.Normalize(-1); 46 _rangeEnc.Stream = &_outStream.p; 47 Ppmd7_Construct(&_ppmd); 48 } 49 50 CEncoder::~CEncoder() 51 { 52 ::MidFree(_inBuf); 53 Ppmd7_Free(&_ppmd, &g_BigAlloc); 54 } 55 56 STDMETHODIMP CEncoder::SetCoderProperties(const PROPID *propIDs, const PROPVARIANT *coderProps, UInt32 numProps) 57 { 58 int level = -1; 59 CEncProps props; 60 for (UInt32 i = 0; i < numProps; i++) 61 { 62 const PROPVARIANT &prop = coderProps[i]; 63 PROPID propID = propIDs[i]; 64 if (propID > NCoderPropID::kReduceSize) 65 continue; 66 if (propID == NCoderPropID::kReduceSize) 67 { 68 if (prop.vt == VT_UI8 && prop.uhVal.QuadPart < (UInt32)(Int32)-1) 69 props.ReduceSize = (UInt32)prop.uhVal.QuadPart; 70 continue; 71 } 72 if (prop.vt != VT_UI4) 73 return E_INVALIDARG; 74 UInt32 v = (UInt32)prop.ulVal; 75 switch (propID) 76 { 77 case NCoderPropID::kUsedMemorySize: 78 if (v < (1 << 16) || v > PPMD7_MAX_MEM_SIZE || (v & 3) != 0) 79 return E_INVALIDARG; 80 props.MemSize = v; 81 break; 82 case NCoderPropID::kOrder: 83 if (v < 2 || v > 32) 84 return E_INVALIDARG; 85 props.Order = (Byte)v; 86 break; 87 case NCoderPropID::kNumThreads: break; 88 case NCoderPropID::kLevel: level = (int)v; break; 89 default: return E_INVALIDARG; 90 } 91 } 92 props.Normalize(level); 93 _props = props; 94 return S_OK; 95 } 96 97 STDMETHODIMP CEncoder::WriteCoderProperties(ISequentialOutStream *outStream) 98 { 99 const UInt32 kPropSize = 5; 100 Byte props[kPropSize]; 101 props[0] = (Byte)_props.Order; 102 SetUi32(props + 1, _props.MemSize); 103 return WriteStream(outStream, props, kPropSize); 104 } 105 106 HRESULT CEncoder::Code(ISequentialInStream *inStream, ISequentialOutStream *outStream, 107 const UInt64 * /* inSize */, const UInt64 * /* outSize */, ICompressProgressInfo *progress) 108 { 109 if (!_inBuf) 110 { 111 _inBuf = (Byte *)::MidAlloc(kBufSize); 112 if (!_inBuf) 113 return E_OUTOFMEMORY; 114 } 115 if (!_outStream.Alloc(1 << 20)) 116 return E_OUTOFMEMORY; 117 if (!Ppmd7_Alloc(&_ppmd, _props.MemSize, &g_BigAlloc)) 118 return E_OUTOFMEMORY; 119 120 _outStream.Stream = outStream; 121 _outStream.Init(); 122 123 Ppmd7z_RangeEnc_Init(&_rangeEnc); 124 Ppmd7_Init(&_ppmd, _props.Order); 125 126 UInt64 processed = 0; 127 for (;;) 128 { 129 UInt32 size; 130 RINOK(inStream->Read(_inBuf, kBufSize, &size)); 131 if (size == 0) 132 { 133 // We don't write EndMark in PPMD-7z. 134 // Ppmd7_EncodeSymbol(&_ppmd, &_rangeEnc, -1); 135 Ppmd7z_RangeEnc_FlushData(&_rangeEnc); 136 return _outStream.Flush(); 137 } 138 for (UInt32 i = 0; i < size; i++) 139 { 140 Ppmd7_EncodeSymbol(&_ppmd, &_rangeEnc, _inBuf[i]); 141 RINOK(_outStream.Res); 142 } 143 processed += size; 144 if (progress) 145 { 146 UInt64 outSize = _outStream.GetProcessed(); 147 RINOK(progress->SetRatioInfo(&processed, &outSize)); 148 } 149 } 150 } 151 152 }} 153