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