1370b324cSopenharmony_ci// PpmdEncoder.cpp 2370b324cSopenharmony_ci 3370b324cSopenharmony_ci#include "StdAfx.h" 4370b324cSopenharmony_ci 5370b324cSopenharmony_ci#include "../../../C/Alloc.h" 6370b324cSopenharmony_ci 7370b324cSopenharmony_ci#include "../Common/StreamUtils.h" 8370b324cSopenharmony_ci 9370b324cSopenharmony_ci#include "PpmdEncoder.h" 10370b324cSopenharmony_ci 11370b324cSopenharmony_cinamespace NCompress { 12370b324cSopenharmony_cinamespace NPpmd { 13370b324cSopenharmony_ci 14370b324cSopenharmony_cistatic const UInt32 kBufSize = (1 << 20); 15370b324cSopenharmony_ci 16370b324cSopenharmony_cistatic const Byte kOrders[10] = { 3, 4, 4, 5, 5, 6, 8, 16, 24, 32 }; 17370b324cSopenharmony_ci 18370b324cSopenharmony_civoid CEncProps::Normalize(int level) 19370b324cSopenharmony_ci{ 20370b324cSopenharmony_ci if (level < 0) level = 5; 21370b324cSopenharmony_ci if (level > 9) level = 9; 22370b324cSopenharmony_ci if (MemSize == (UInt32)(Int32)-1) 23370b324cSopenharmony_ci MemSize = (UInt32)1 << (level + 19); 24370b324cSopenharmony_ci const unsigned kMult = 16; 25370b324cSopenharmony_ci if (MemSize / kMult > ReduceSize) 26370b324cSopenharmony_ci { 27370b324cSopenharmony_ci for (unsigned i = 16; i < 32; i++) 28370b324cSopenharmony_ci { 29370b324cSopenharmony_ci UInt32 m = (UInt32)1 << i; 30370b324cSopenharmony_ci if (ReduceSize <= m / kMult) 31370b324cSopenharmony_ci { 32370b324cSopenharmony_ci if (MemSize > m) 33370b324cSopenharmony_ci MemSize = m; 34370b324cSopenharmony_ci break; 35370b324cSopenharmony_ci } 36370b324cSopenharmony_ci } 37370b324cSopenharmony_ci } 38370b324cSopenharmony_ci if (Order == -1) Order = kOrders[(unsigned)level]; 39370b324cSopenharmony_ci} 40370b324cSopenharmony_ci 41370b324cSopenharmony_ciCEncoder::CEncoder(): 42370b324cSopenharmony_ci _inBuf(NULL) 43370b324cSopenharmony_ci{ 44370b324cSopenharmony_ci _props.Normalize(-1); 45370b324cSopenharmony_ci Ppmd7_Construct(&_ppmd); 46370b324cSopenharmony_ci _ppmd.rc.enc.Stream = &_outStream.vt; 47370b324cSopenharmony_ci} 48370b324cSopenharmony_ci 49370b324cSopenharmony_ciCEncoder::~CEncoder() 50370b324cSopenharmony_ci{ 51370b324cSopenharmony_ci ::MidFree(_inBuf); 52370b324cSopenharmony_ci Ppmd7_Free(&_ppmd, &g_BigAlloc); 53370b324cSopenharmony_ci} 54370b324cSopenharmony_ci 55370b324cSopenharmony_ciZ7_COM7F_IMF(CEncoder::SetCoderProperties(const PROPID *propIDs, const PROPVARIANT *coderProps, UInt32 numProps)) 56370b324cSopenharmony_ci{ 57370b324cSopenharmony_ci int level = -1; 58370b324cSopenharmony_ci CEncProps props; 59370b324cSopenharmony_ci for (UInt32 i = 0; i < numProps; i++) 60370b324cSopenharmony_ci { 61370b324cSopenharmony_ci const PROPVARIANT &prop = coderProps[i]; 62370b324cSopenharmony_ci const PROPID propID = propIDs[i]; 63370b324cSopenharmony_ci if (propID > NCoderPropID::kReduceSize) 64370b324cSopenharmony_ci continue; 65370b324cSopenharmony_ci if (propID == NCoderPropID::kReduceSize) 66370b324cSopenharmony_ci { 67370b324cSopenharmony_ci if (prop.vt == VT_UI8 && prop.uhVal.QuadPart < (UInt32)(Int32)-1) 68370b324cSopenharmony_ci props.ReduceSize = (UInt32)prop.uhVal.QuadPart; 69370b324cSopenharmony_ci continue; 70370b324cSopenharmony_ci } 71370b324cSopenharmony_ci 72370b324cSopenharmony_ci if (propID == NCoderPropID::kUsedMemorySize) 73370b324cSopenharmony_ci { 74370b324cSopenharmony_ci // here we have selected (4 GiB - 1 KiB) as replacement for (4 GiB) MEM_SIZE. 75370b324cSopenharmony_ci const UInt32 kPpmd_Default_4g = (UInt32)0 - ((UInt32)1 << 10); 76370b324cSopenharmony_ci UInt32 v; 77370b324cSopenharmony_ci if (prop.vt == VT_UI8) 78370b324cSopenharmony_ci { 79370b324cSopenharmony_ci // 21.03 : we support 64-bit values (for 4 GiB value) 80370b324cSopenharmony_ci const UInt64 v64 = prop.uhVal.QuadPart; 81370b324cSopenharmony_ci if (v64 > ((UInt64)1 << 32)) 82370b324cSopenharmony_ci return E_INVALIDARG; 83370b324cSopenharmony_ci if (v64 == ((UInt64)1 << 32)) 84370b324cSopenharmony_ci v = kPpmd_Default_4g; 85370b324cSopenharmony_ci else 86370b324cSopenharmony_ci v = (UInt32)v64; 87370b324cSopenharmony_ci } 88370b324cSopenharmony_ci else if (prop.vt == VT_UI4) 89370b324cSopenharmony_ci v = (UInt32)prop.ulVal; 90370b324cSopenharmony_ci else 91370b324cSopenharmony_ci return E_INVALIDARG; 92370b324cSopenharmony_ci if (v > PPMD7_MAX_MEM_SIZE) 93370b324cSopenharmony_ci v = kPpmd_Default_4g; 94370b324cSopenharmony_ci 95370b324cSopenharmony_ci /* here we restrict MEM_SIZE for Encoder. 96370b324cSopenharmony_ci It's for better performance of encoding and decoding. 97370b324cSopenharmony_ci The Decoder still supports more MEM_SIZE values. */ 98370b324cSopenharmony_ci if (v < ((UInt32)1 << 16) || (v & 3) != 0) 99370b324cSopenharmony_ci return E_INVALIDARG; 100370b324cSopenharmony_ci // if (v < PPMD7_MIN_MEM_SIZE) return E_INVALIDARG; // (1 << 11) 101370b324cSopenharmony_ci /* 102370b324cSopenharmony_ci Supported MEM_SIZE range : 103370b324cSopenharmony_ci [ (1 << 11) , 0xFFFFFFFF - 12 * 3 ] - current 7-Zip's Ppmd7 constants 104370b324cSopenharmony_ci [ 1824 , 0xFFFFFFFF ] - real limits of Ppmd7 code 105370b324cSopenharmony_ci */ 106370b324cSopenharmony_ci props.MemSize = v; 107370b324cSopenharmony_ci continue; 108370b324cSopenharmony_ci } 109370b324cSopenharmony_ci 110370b324cSopenharmony_ci if (prop.vt != VT_UI4) 111370b324cSopenharmony_ci return E_INVALIDARG; 112370b324cSopenharmony_ci const UInt32 v = (UInt32)prop.ulVal; 113370b324cSopenharmony_ci switch (propID) 114370b324cSopenharmony_ci { 115370b324cSopenharmony_ci case NCoderPropID::kOrder: 116370b324cSopenharmony_ci if (v < 2 || v > 32) 117370b324cSopenharmony_ci return E_INVALIDARG; 118370b324cSopenharmony_ci props.Order = (Byte)v; 119370b324cSopenharmony_ci break; 120370b324cSopenharmony_ci case NCoderPropID::kNumThreads: break; 121370b324cSopenharmony_ci case NCoderPropID::kLevel: level = (int)v; break; 122370b324cSopenharmony_ci default: return E_INVALIDARG; 123370b324cSopenharmony_ci } 124370b324cSopenharmony_ci } 125370b324cSopenharmony_ci props.Normalize(level); 126370b324cSopenharmony_ci _props = props; 127370b324cSopenharmony_ci return S_OK; 128370b324cSopenharmony_ci} 129370b324cSopenharmony_ci 130370b324cSopenharmony_ciZ7_COM7F_IMF(CEncoder::WriteCoderProperties(ISequentialOutStream *outStream)) 131370b324cSopenharmony_ci{ 132370b324cSopenharmony_ci const UInt32 kPropSize = 5; 133370b324cSopenharmony_ci Byte props[kPropSize]; 134370b324cSopenharmony_ci props[0] = (Byte)_props.Order; 135370b324cSopenharmony_ci SetUi32(props + 1, _props.MemSize) 136370b324cSopenharmony_ci return WriteStream(outStream, props, kPropSize); 137370b324cSopenharmony_ci} 138370b324cSopenharmony_ci 139370b324cSopenharmony_ciZ7_COM7F_IMF(CEncoder::Code(ISequentialInStream *inStream, ISequentialOutStream *outStream, 140370b324cSopenharmony_ci const UInt64 * /* inSize */, const UInt64 * /* outSize */, ICompressProgressInfo *progress)) 141370b324cSopenharmony_ci{ 142370b324cSopenharmony_ci if (!_inBuf) 143370b324cSopenharmony_ci { 144370b324cSopenharmony_ci _inBuf = (Byte *)::MidAlloc(kBufSize); 145370b324cSopenharmony_ci if (!_inBuf) 146370b324cSopenharmony_ci return E_OUTOFMEMORY; 147370b324cSopenharmony_ci } 148370b324cSopenharmony_ci if (!_outStream.Alloc(1 << 20)) 149370b324cSopenharmony_ci return E_OUTOFMEMORY; 150370b324cSopenharmony_ci if (!Ppmd7_Alloc(&_ppmd, _props.MemSize, &g_BigAlloc)) 151370b324cSopenharmony_ci return E_OUTOFMEMORY; 152370b324cSopenharmony_ci 153370b324cSopenharmony_ci _outStream.Stream = outStream; 154370b324cSopenharmony_ci _outStream.Init(); 155370b324cSopenharmony_ci 156370b324cSopenharmony_ci Ppmd7z_Init_RangeEnc(&_ppmd); 157370b324cSopenharmony_ci Ppmd7_Init(&_ppmd, (unsigned)_props.Order); 158370b324cSopenharmony_ci 159370b324cSopenharmony_ci UInt64 processed = 0; 160370b324cSopenharmony_ci for (;;) 161370b324cSopenharmony_ci { 162370b324cSopenharmony_ci UInt32 size; 163370b324cSopenharmony_ci RINOK(inStream->Read(_inBuf, kBufSize, &size)) 164370b324cSopenharmony_ci if (size == 0) 165370b324cSopenharmony_ci { 166370b324cSopenharmony_ci // We don't write EndMark in PPMD-7z. 167370b324cSopenharmony_ci // Ppmd7z_EncodeSymbol(&_ppmd, -1); 168370b324cSopenharmony_ci Ppmd7z_Flush_RangeEnc(&_ppmd); 169370b324cSopenharmony_ci return _outStream.Flush(); 170370b324cSopenharmony_ci } 171370b324cSopenharmony_ci const Byte *buf = _inBuf; 172370b324cSopenharmony_ci const Byte *lim = buf + size; 173370b324cSopenharmony_ci /* 174370b324cSopenharmony_ci for (; buf < lim; buf++) 175370b324cSopenharmony_ci { 176370b324cSopenharmony_ci Ppmd7z_EncodeSymbol(&_ppmd, *buf); 177370b324cSopenharmony_ci RINOK(_outStream.Res); 178370b324cSopenharmony_ci } 179370b324cSopenharmony_ci */ 180370b324cSopenharmony_ci 181370b324cSopenharmony_ci Ppmd7z_EncodeSymbols(&_ppmd, buf, lim); 182370b324cSopenharmony_ci RINOK(_outStream.Res) 183370b324cSopenharmony_ci 184370b324cSopenharmony_ci processed += size; 185370b324cSopenharmony_ci if (progress) 186370b324cSopenharmony_ci { 187370b324cSopenharmony_ci const UInt64 outSize = _outStream.GetProcessed(); 188370b324cSopenharmony_ci RINOK(progress->SetRatioInfo(&processed, &outSize)) 189370b324cSopenharmony_ci } 190370b324cSopenharmony_ci } 191370b324cSopenharmony_ci} 192370b324cSopenharmony_ci 193370b324cSopenharmony_ci}} 194