1 // PpmdEncoder.cpp
2
3 #include "StdAfx.h"
4
5 #include "../../../C/Alloc.h"
6 #include "../../../C/CpuArch.h"
7
8 #include "../Common/StreamUtils.h"
9
10 #include "PpmdEncoder.h"
11
12 namespace NCompress {
13 namespace NPpmd {
14
15 static const UInt32 kBufSize = (1 << 20);
16
SzBigAlloc(void *,size_t size)17 static void *SzBigAlloc(void *, size_t size) { return BigAlloc(size); }
SzBigFree(void *,void * address)18 static void SzBigFree(void *, void *address) { BigFree(address); }
19 static ISzAlloc g_BigAlloc = { SzBigAlloc, SzBigFree };
20
21 static const Byte kOrders[10] = { 3, 4, 4, 5, 5, 6, 8, 16, 24, 32 };
22
Normalize(int level)23 void CEncProps::Normalize(int level)
24 {
25 if (level < 0) level = 5;
26 if (level > 9) level = 9;
27 if (MemSize == (UInt32)(Int32)-1)
28 MemSize = level >= 9 ? ((UInt32)192 << 20) : ((UInt32)1 << (level + 19));
29 const unsigned kMult = 16;
30 if (MemSize / kMult > ReduceSize)
31 {
32 for (unsigned i = 16; i <= 31; i++)
33 {
34 UInt32 m = (UInt32)1 << i;
35 if (ReduceSize <= m / kMult)
36 {
37 if (MemSize > m)
38 MemSize = m;
39 break;
40 }
41 }
42 }
43 if (Order == -1) Order = kOrders[level];
44 }
45
CEncoder()46 CEncoder::CEncoder():
47 _inBuf(NULL)
48 {
49 _props.Normalize(-1);
50 _rangeEnc.Stream = &_outStream.p;
51 Ppmd7_Construct(&_ppmd);
52 }
53
~CEncoder()54 CEncoder::~CEncoder()
55 {
56 ::MidFree(_inBuf);
57 Ppmd7_Free(&_ppmd, &g_BigAlloc);
58 }
59
SetCoderProperties(const PROPID * propIDs,const PROPVARIANT * coderProps,UInt32 numProps)60 STDMETHODIMP CEncoder::SetCoderProperties(const PROPID *propIDs, const PROPVARIANT *coderProps, UInt32 numProps)
61 {
62 int level = -1;
63 CEncProps props;
64 for (UInt32 i = 0; i < numProps; i++)
65 {
66 const PROPVARIANT &prop = coderProps[i];
67 PROPID propID = propIDs[i];
68 if (propID > NCoderPropID::kReduceSize)
69 continue;
70 if (propID == NCoderPropID::kReduceSize)
71 {
72 if (prop.vt == VT_UI8 && prop.uhVal.QuadPart < (UInt32)(Int32)-1)
73 props.ReduceSize = (UInt32)prop.uhVal.QuadPart;
74 continue;
75 }
76 if (prop.vt != VT_UI4)
77 return E_INVALIDARG;
78 UInt32 v = (UInt32)prop.ulVal;
79 switch (propID)
80 {
81 case NCoderPropID::kUsedMemorySize:
82 if (v < (1 << 16) || v > PPMD7_MAX_MEM_SIZE || (v & 3) != 0)
83 return E_INVALIDARG;
84 props.MemSize = v;
85 break;
86 case NCoderPropID::kOrder:
87 if (v < 2 || v > 32)
88 return E_INVALIDARG;
89 props.Order = (Byte)v;
90 break;
91 case NCoderPropID::kNumThreads: break;
92 case NCoderPropID::kLevel: level = (int)v; break;
93 default: return E_INVALIDARG;
94 }
95 }
96 props.Normalize(level);
97 _props = props;
98 return S_OK;
99 }
100
WriteCoderProperties(ISequentialOutStream * outStream)101 STDMETHODIMP CEncoder::WriteCoderProperties(ISequentialOutStream *outStream)
102 {
103 const UInt32 kPropSize = 5;
104 Byte props[kPropSize];
105 props[0] = (Byte)_props.Order;
106 SetUi32(props + 1, _props.MemSize);
107 return WriteStream(outStream, props, kPropSize);
108 }
109
Code(ISequentialInStream * inStream,ISequentialOutStream * outStream,const UInt64 *,const UInt64 *,ICompressProgressInfo * progress)110 HRESULT CEncoder::Code(ISequentialInStream *inStream, ISequentialOutStream *outStream,
111 const UInt64 * /* inSize */, const UInt64 * /* outSize */, ICompressProgressInfo *progress)
112 {
113 if (!_inBuf)
114 {
115 _inBuf = (Byte *)::MidAlloc(kBufSize);
116 if (!_inBuf)
117 return E_OUTOFMEMORY;
118 }
119 if (!_outStream.Alloc(1 << 20))
120 return E_OUTOFMEMORY;
121 if (!Ppmd7_Alloc(&_ppmd, _props.MemSize, &g_BigAlloc))
122 return E_OUTOFMEMORY;
123
124 _outStream.Stream = outStream;
125 _outStream.Init();
126
127 Ppmd7z_RangeEnc_Init(&_rangeEnc);
128 Ppmd7_Init(&_ppmd, _props.Order);
129
130 UInt64 processed = 0;
131 for (;;)
132 {
133 UInt32 size;
134 RINOK(inStream->Read(_inBuf, kBufSize, &size));
135 if (size == 0)
136 {
137 // We don't write EndMark in PPMD-7z.
138 // Ppmd7_EncodeSymbol(&_ppmd, &_rangeEnc, -1);
139 Ppmd7z_RangeEnc_FlushData(&_rangeEnc);
140 return _outStream.Flush();
141 }
142 for (UInt32 i = 0; i < size; i++)
143 {
144 Ppmd7_EncodeSymbol(&_ppmd, &_rangeEnc, _inBuf[i]);
145 RINOK(_outStream.Res);
146 }
147 processed += size;
148 if (progress)
149 {
150 UInt64 outSize = _outStream.GetProcessed();
151 RINOK(progress->SetRatioInfo(&processed, &outSize));
152 }
153 }
154 }
155
156 }}
157