summaryrefslogtreecommitdiffstats
path: root/src/libs/7zip/win/CPP/7zip/Compress/PpmdZip.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/libs/7zip/win/CPP/7zip/Compress/PpmdZip.cpp')
-rw-r--r--src/libs/7zip/win/CPP/7zip/Compress/PpmdZip.cpp223
1 files changed, 223 insertions, 0 deletions
diff --git a/src/libs/7zip/win/CPP/7zip/Compress/PpmdZip.cpp b/src/libs/7zip/win/CPP/7zip/Compress/PpmdZip.cpp
new file mode 100644
index 000000000..e83d979c3
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Compress/PpmdZip.cpp
@@ -0,0 +1,223 @@
+// PpmdZip.cpp
+// 2010-03-24 : 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));
+ }
+ }
+}
+
+}}