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