diff options
Diffstat (limited to 'CPP/7zip/Compress/PpmdZip.cpp')
-rwxr-xr-x | CPP/7zip/Compress/PpmdZip.cpp | 223 |
1 files changed, 223 insertions, 0 deletions
diff --git a/CPP/7zip/Compress/PpmdZip.cpp b/CPP/7zip/Compress/PpmdZip.cpp new file mode 100755 index 00000000..f576909f --- /dev/null +++ b/CPP/7zip/Compress/PpmdZip.cpp @@ -0,0 +1,223 @@ +// PpmdZip.cpp +// 2010-03-11 : Igor Pavlov : Public domain + +#include "StdAfx.h" + +#include "../../../C/CpuArch.h" + +#include "../Common/StreamUtils.h" + +#include "PpmdZip.h" + +namespace NCompress { +namespace NPpmdZip { + +static void *SzBigAlloc(void *, size_t size) { return BigAlloc(size); } +static void SzBigFree(void *, void *address) { BigFree(address); } +static ISzAlloc g_BigAlloc = { SzBigAlloc, SzBigFree }; + +CDecoder::CDecoder(bool fullFileMode): + _fullFileMode(fullFileMode) +{ + _ppmd.Stream.In = &_inStream.p; + Ppmd8_Construct(&_ppmd); +} + +CDecoder::~CDecoder() +{ + Ppmd8_Free(&_ppmd, &g_BigAlloc); +} + +STDMETHODIMP CDecoder::Code(ISequentialInStream *inStream, ISequentialOutStream *outStream, + const UInt64 * /* inSize */, const UInt64 *outSize, ICompressProgressInfo *progress) +{ + if (!_outStream.Alloc()) + return E_OUTOFMEMORY; + if (!_inStream.Alloc(1 << 20)) + return E_OUTOFMEMORY; + + _inStream.Stream = inStream; + _inStream.Init(); + + { + Byte buf[2]; + for (int i = 0; i < 2; i++) + buf[i] = _inStream.ReadByte(); + if (_inStream.Extra) + return S_FALSE; + + UInt32 val = GetUi16(buf); + UInt32 order = (val & 0xF) + 1; + UInt32 mem = ((val >> 4) & 0xFF) + 1; + UInt32 restor = (val >> 12); + if (order < 2 || restor > 2) + return S_FALSE; + + #ifndef PPMD8_FREEZE_SUPPORT + if (restor == 2) + return E_NOTIMPL; + #endif + + if (!Ppmd8_Alloc(&_ppmd, mem << 20, &g_BigAlloc)) + return E_OUTOFMEMORY; + + if (!Ppmd8_RangeDec_Init(&_ppmd)) + return S_FALSE; + Ppmd8_Init(&_ppmd, order, restor); + } + + bool wasFinished = false; + UInt64 processedSize = 0; + while (!outSize || processedSize < *outSize) + { + size_t size = kBufSize; + if (outSize != NULL) + { + const UInt64 rem = *outSize - processedSize; + if (size > rem) + size = (size_t)rem; + } + Byte *data = _outStream.Buf; + size_t i = 0; + int sym = 0; + do + { + sym = Ppmd8_DecodeSymbol(&_ppmd); + if (_inStream.Extra || sym < 0) + break; + data[i] = (Byte)sym; + } + while (++i != size); + processedSize += i; + + RINOK(WriteStream(outStream, _outStream.Buf, i)); + + RINOK(_inStream.Res); + if (_inStream.Extra) + return S_FALSE; + + if (sym < 0) + { + if (sym != -1) + return S_FALSE; + wasFinished = true; + break; + } + if (progress) + { + UInt64 inSize = _inStream.GetProcessed(); + RINOK(progress->SetRatioInfo(&inSize, &processedSize)); + } + } + RINOK(_inStream.Res); + if (_fullFileMode) + { + if (!wasFinished) + { + int res = Ppmd8_DecodeSymbol(&_ppmd); + RINOK(_inStream.Res); + if (_inStream.Extra || res != -1) + return S_FALSE; + } + if (!Ppmd8_RangeDec_IsFinishedOK(&_ppmd)) + return S_FALSE; + } + return S_OK; +} + + +// ---------- Encoder ---------- + +CEncoder::~CEncoder() +{ + Ppmd8_Free(&_ppmd, &g_BigAlloc); +} + +HRESULT CEncoder::SetCoderProperties(const PROPID *propIDs, const PROPVARIANT *props, UInt32 numProps) +{ + for (UInt32 i = 0; i < numProps; i++) + { + const PROPVARIANT &prop = props[i]; + if (prop.vt != VT_UI4) + return E_INVALIDARG; + UInt32 v = (UInt32)prop.ulVal; + switch(propIDs[i]) + { + case NCoderPropID::kAlgorithm: + if (v > 1) + return E_INVALIDARG; + _restor = v; + break; + case NCoderPropID::kUsedMemorySize: + if (v < (1 << 20) || v > (1 << 28)) + return E_INVALIDARG; + _usedMemInMB = v >> 20; + break; + case NCoderPropID::kOrder: + if (v < PPMD8_MIN_ORDER || v > PPMD8_MAX_ORDER) + return E_INVALIDARG; + _order = (Byte)v; + break; + default: + return E_INVALIDARG; + } + } + return S_OK; +} + +CEncoder::CEncoder(): + _usedMemInMB(16), + _order(6), + _restor(PPMD8_RESTORE_METHOD_RESTART) +{ + _ppmd.Stream.Out = &_outStream.p; + Ppmd8_Construct(&_ppmd); +} + +HRESULT CEncoder::Code(ISequentialInStream *inStream, ISequentialOutStream *outStream, + const UInt64 * /* inSize */, const UInt64 * /* outSize */, ICompressProgressInfo *progress) +{ + if (!_inStream.Alloc()) + return E_OUTOFMEMORY; + if (!_outStream.Alloc(1 << 20)) + return E_OUTOFMEMORY; + if (!Ppmd8_Alloc(&_ppmd, _usedMemInMB << 20, &g_BigAlloc)) + return E_OUTOFMEMORY; + + _outStream.Stream = outStream; + _outStream.Init(); + + Ppmd8_RangeEnc_Init(&_ppmd); + Ppmd8_Init(&_ppmd, _order, _restor); + + UInt32 val = (UInt32)((_order - 1) + ((_usedMemInMB - 1) << 4) + (_restor << 12)); + _outStream.WriteByte((Byte)(val & 0xFF)); + _outStream.WriteByte((Byte)(val >> 8)); + RINOK(_outStream.Res); + + UInt64 processed = 0; + for (;;) + { + UInt32 size; + RINOK(inStream->Read(_inStream.Buf, kBufSize, &size)); + if (size == 0) + { + Ppmd8_EncodeSymbol(&_ppmd, -1); + Ppmd8_RangeEnc_FlushData(&_ppmd); + return _outStream.Flush(); + } + for (UInt32 i = 0; i < size; i++) + { + Ppmd8_EncodeSymbol(&_ppmd, _inStream.Buf[i]); + RINOK(_outStream.Res); + } + processed += size; + if (progress != NULL) + { + UInt64 outSize = _outStream.GetProcessed(); + RINOK(progress->SetRatioInfo(&processed, &outSize)); + } + } +} + +}} |