1*f6dc9357SAndroid Build Coastguard Worker // PpmdEncoder.cpp
2*f6dc9357SAndroid Build Coastguard Worker
3*f6dc9357SAndroid Build Coastguard Worker #include "StdAfx.h"
4*f6dc9357SAndroid Build Coastguard Worker
5*f6dc9357SAndroid Build Coastguard Worker #include "../../../C/Alloc.h"
6*f6dc9357SAndroid Build Coastguard Worker
7*f6dc9357SAndroid Build Coastguard Worker #include "../Common/StreamUtils.h"
8*f6dc9357SAndroid Build Coastguard Worker
9*f6dc9357SAndroid Build Coastguard Worker #include "PpmdEncoder.h"
10*f6dc9357SAndroid Build Coastguard Worker
11*f6dc9357SAndroid Build Coastguard Worker namespace NCompress {
12*f6dc9357SAndroid Build Coastguard Worker namespace NPpmd {
13*f6dc9357SAndroid Build Coastguard Worker
14*f6dc9357SAndroid Build Coastguard Worker static const UInt32 kBufSize = (1 << 20);
15*f6dc9357SAndroid Build Coastguard Worker
16*f6dc9357SAndroid Build Coastguard Worker static const Byte kOrders[10] = { 3, 4, 4, 5, 5, 6, 8, 16, 24, 32 };
17*f6dc9357SAndroid Build Coastguard Worker
Normalize(int level)18*f6dc9357SAndroid Build Coastguard Worker void CEncProps::Normalize(int level)
19*f6dc9357SAndroid Build Coastguard Worker {
20*f6dc9357SAndroid Build Coastguard Worker if (level < 0) level = 5;
21*f6dc9357SAndroid Build Coastguard Worker if (level > 9) level = 9;
22*f6dc9357SAndroid Build Coastguard Worker if (MemSize == (UInt32)(Int32)-1)
23*f6dc9357SAndroid Build Coastguard Worker MemSize = (UInt32)1 << (level + 19);
24*f6dc9357SAndroid Build Coastguard Worker const unsigned kMult = 16;
25*f6dc9357SAndroid Build Coastguard Worker if (MemSize / kMult > ReduceSize)
26*f6dc9357SAndroid Build Coastguard Worker {
27*f6dc9357SAndroid Build Coastguard Worker for (unsigned i = 16; i < 32; i++)
28*f6dc9357SAndroid Build Coastguard Worker {
29*f6dc9357SAndroid Build Coastguard Worker UInt32 m = (UInt32)1 << i;
30*f6dc9357SAndroid Build Coastguard Worker if (ReduceSize <= m / kMult)
31*f6dc9357SAndroid Build Coastguard Worker {
32*f6dc9357SAndroid Build Coastguard Worker if (MemSize > m)
33*f6dc9357SAndroid Build Coastguard Worker MemSize = m;
34*f6dc9357SAndroid Build Coastguard Worker break;
35*f6dc9357SAndroid Build Coastguard Worker }
36*f6dc9357SAndroid Build Coastguard Worker }
37*f6dc9357SAndroid Build Coastguard Worker }
38*f6dc9357SAndroid Build Coastguard Worker if (Order == -1) Order = kOrders[(unsigned)level];
39*f6dc9357SAndroid Build Coastguard Worker }
40*f6dc9357SAndroid Build Coastguard Worker
CEncoder()41*f6dc9357SAndroid Build Coastguard Worker CEncoder::CEncoder():
42*f6dc9357SAndroid Build Coastguard Worker _inBuf(NULL)
43*f6dc9357SAndroid Build Coastguard Worker {
44*f6dc9357SAndroid Build Coastguard Worker _props.Normalize(-1);
45*f6dc9357SAndroid Build Coastguard Worker Ppmd7_Construct(&_ppmd);
46*f6dc9357SAndroid Build Coastguard Worker _ppmd.rc.enc.Stream = &_outStream.vt;
47*f6dc9357SAndroid Build Coastguard Worker }
48*f6dc9357SAndroid Build Coastguard Worker
~CEncoder()49*f6dc9357SAndroid Build Coastguard Worker CEncoder::~CEncoder()
50*f6dc9357SAndroid Build Coastguard Worker {
51*f6dc9357SAndroid Build Coastguard Worker ::MidFree(_inBuf);
52*f6dc9357SAndroid Build Coastguard Worker Ppmd7_Free(&_ppmd, &g_BigAlloc);
53*f6dc9357SAndroid Build Coastguard Worker }
54*f6dc9357SAndroid Build Coastguard Worker
Z7_COM7F_IMF(CEncoder::SetCoderProperties (const PROPID * propIDs,const PROPVARIANT * coderProps,UInt32 numProps))55*f6dc9357SAndroid Build Coastguard Worker Z7_COM7F_IMF(CEncoder::SetCoderProperties(const PROPID *propIDs, const PROPVARIANT *coderProps, UInt32 numProps))
56*f6dc9357SAndroid Build Coastguard Worker {
57*f6dc9357SAndroid Build Coastguard Worker int level = -1;
58*f6dc9357SAndroid Build Coastguard Worker CEncProps props;
59*f6dc9357SAndroid Build Coastguard Worker for (UInt32 i = 0; i < numProps; i++)
60*f6dc9357SAndroid Build Coastguard Worker {
61*f6dc9357SAndroid Build Coastguard Worker const PROPVARIANT &prop = coderProps[i];
62*f6dc9357SAndroid Build Coastguard Worker const PROPID propID = propIDs[i];
63*f6dc9357SAndroid Build Coastguard Worker if (propID > NCoderPropID::kReduceSize)
64*f6dc9357SAndroid Build Coastguard Worker continue;
65*f6dc9357SAndroid Build Coastguard Worker if (propID == NCoderPropID::kReduceSize)
66*f6dc9357SAndroid Build Coastguard Worker {
67*f6dc9357SAndroid Build Coastguard Worker if (prop.vt == VT_UI8 && prop.uhVal.QuadPart < (UInt32)(Int32)-1)
68*f6dc9357SAndroid Build Coastguard Worker props.ReduceSize = (UInt32)prop.uhVal.QuadPart;
69*f6dc9357SAndroid Build Coastguard Worker continue;
70*f6dc9357SAndroid Build Coastguard Worker }
71*f6dc9357SAndroid Build Coastguard Worker
72*f6dc9357SAndroid Build Coastguard Worker if (propID == NCoderPropID::kUsedMemorySize)
73*f6dc9357SAndroid Build Coastguard Worker {
74*f6dc9357SAndroid Build Coastguard Worker // here we have selected (4 GiB - 1 KiB) as replacement for (4 GiB) MEM_SIZE.
75*f6dc9357SAndroid Build Coastguard Worker const UInt32 kPpmd_Default_4g = (UInt32)0 - ((UInt32)1 << 10);
76*f6dc9357SAndroid Build Coastguard Worker UInt32 v;
77*f6dc9357SAndroid Build Coastguard Worker if (prop.vt == VT_UI8)
78*f6dc9357SAndroid Build Coastguard Worker {
79*f6dc9357SAndroid Build Coastguard Worker // 21.03 : we support 64-bit values (for 4 GiB value)
80*f6dc9357SAndroid Build Coastguard Worker const UInt64 v64 = prop.uhVal.QuadPart;
81*f6dc9357SAndroid Build Coastguard Worker if (v64 > ((UInt64)1 << 32))
82*f6dc9357SAndroid Build Coastguard Worker return E_INVALIDARG;
83*f6dc9357SAndroid Build Coastguard Worker if (v64 == ((UInt64)1 << 32))
84*f6dc9357SAndroid Build Coastguard Worker v = kPpmd_Default_4g;
85*f6dc9357SAndroid Build Coastguard Worker else
86*f6dc9357SAndroid Build Coastguard Worker v = (UInt32)v64;
87*f6dc9357SAndroid Build Coastguard Worker }
88*f6dc9357SAndroid Build Coastguard Worker else if (prop.vt == VT_UI4)
89*f6dc9357SAndroid Build Coastguard Worker v = (UInt32)prop.ulVal;
90*f6dc9357SAndroid Build Coastguard Worker else
91*f6dc9357SAndroid Build Coastguard Worker return E_INVALIDARG;
92*f6dc9357SAndroid Build Coastguard Worker if (v > PPMD7_MAX_MEM_SIZE)
93*f6dc9357SAndroid Build Coastguard Worker v = kPpmd_Default_4g;
94*f6dc9357SAndroid Build Coastguard Worker
95*f6dc9357SAndroid Build Coastguard Worker /* here we restrict MEM_SIZE for Encoder.
96*f6dc9357SAndroid Build Coastguard Worker It's for better performance of encoding and decoding.
97*f6dc9357SAndroid Build Coastguard Worker The Decoder still supports more MEM_SIZE values. */
98*f6dc9357SAndroid Build Coastguard Worker if (v < ((UInt32)1 << 16) || (v & 3) != 0)
99*f6dc9357SAndroid Build Coastguard Worker return E_INVALIDARG;
100*f6dc9357SAndroid Build Coastguard Worker // if (v < PPMD7_MIN_MEM_SIZE) return E_INVALIDARG; // (1 << 11)
101*f6dc9357SAndroid Build Coastguard Worker /*
102*f6dc9357SAndroid Build Coastguard Worker Supported MEM_SIZE range :
103*f6dc9357SAndroid Build Coastguard Worker [ (1 << 11) , 0xFFFFFFFF - 12 * 3 ] - current 7-Zip's Ppmd7 constants
104*f6dc9357SAndroid Build Coastguard Worker [ 1824 , 0xFFFFFFFF ] - real limits of Ppmd7 code
105*f6dc9357SAndroid Build Coastguard Worker */
106*f6dc9357SAndroid Build Coastguard Worker props.MemSize = v;
107*f6dc9357SAndroid Build Coastguard Worker continue;
108*f6dc9357SAndroid Build Coastguard Worker }
109*f6dc9357SAndroid Build Coastguard Worker
110*f6dc9357SAndroid Build Coastguard Worker if (prop.vt != VT_UI4)
111*f6dc9357SAndroid Build Coastguard Worker return E_INVALIDARG;
112*f6dc9357SAndroid Build Coastguard Worker const UInt32 v = (UInt32)prop.ulVal;
113*f6dc9357SAndroid Build Coastguard Worker switch (propID)
114*f6dc9357SAndroid Build Coastguard Worker {
115*f6dc9357SAndroid Build Coastguard Worker case NCoderPropID::kOrder:
116*f6dc9357SAndroid Build Coastguard Worker if (v < 2 || v > 32)
117*f6dc9357SAndroid Build Coastguard Worker return E_INVALIDARG;
118*f6dc9357SAndroid Build Coastguard Worker props.Order = (Byte)v;
119*f6dc9357SAndroid Build Coastguard Worker break;
120*f6dc9357SAndroid Build Coastguard Worker case NCoderPropID::kNumThreads: break;
121*f6dc9357SAndroid Build Coastguard Worker case NCoderPropID::kLevel: level = (int)v; break;
122*f6dc9357SAndroid Build Coastguard Worker default: return E_INVALIDARG;
123*f6dc9357SAndroid Build Coastguard Worker }
124*f6dc9357SAndroid Build Coastguard Worker }
125*f6dc9357SAndroid Build Coastguard Worker props.Normalize(level);
126*f6dc9357SAndroid Build Coastguard Worker _props = props;
127*f6dc9357SAndroid Build Coastguard Worker return S_OK;
128*f6dc9357SAndroid Build Coastguard Worker }
129*f6dc9357SAndroid Build Coastguard Worker
Z7_COM7F_IMF(CEncoder::WriteCoderProperties (ISequentialOutStream * outStream))130*f6dc9357SAndroid Build Coastguard Worker Z7_COM7F_IMF(CEncoder::WriteCoderProperties(ISequentialOutStream *outStream))
131*f6dc9357SAndroid Build Coastguard Worker {
132*f6dc9357SAndroid Build Coastguard Worker const UInt32 kPropSize = 5;
133*f6dc9357SAndroid Build Coastguard Worker Byte props[kPropSize];
134*f6dc9357SAndroid Build Coastguard Worker props[0] = (Byte)_props.Order;
135*f6dc9357SAndroid Build Coastguard Worker SetUi32(props + 1, _props.MemSize)
136*f6dc9357SAndroid Build Coastguard Worker return WriteStream(outStream, props, kPropSize);
137*f6dc9357SAndroid Build Coastguard Worker }
138*f6dc9357SAndroid Build Coastguard Worker
Z7_COM7F_IMF(CEncoder::Code (ISequentialInStream * inStream,ISequentialOutStream * outStream,const UInt64 *,const UInt64 *,ICompressProgressInfo * progress))139*f6dc9357SAndroid Build Coastguard Worker Z7_COM7F_IMF(CEncoder::Code(ISequentialInStream *inStream, ISequentialOutStream *outStream,
140*f6dc9357SAndroid Build Coastguard Worker const UInt64 * /* inSize */, const UInt64 * /* outSize */, ICompressProgressInfo *progress))
141*f6dc9357SAndroid Build Coastguard Worker {
142*f6dc9357SAndroid Build Coastguard Worker if (!_inBuf)
143*f6dc9357SAndroid Build Coastguard Worker {
144*f6dc9357SAndroid Build Coastguard Worker _inBuf = (Byte *)::MidAlloc(kBufSize);
145*f6dc9357SAndroid Build Coastguard Worker if (!_inBuf)
146*f6dc9357SAndroid Build Coastguard Worker return E_OUTOFMEMORY;
147*f6dc9357SAndroid Build Coastguard Worker }
148*f6dc9357SAndroid Build Coastguard Worker if (!_outStream.Alloc(1 << 20))
149*f6dc9357SAndroid Build Coastguard Worker return E_OUTOFMEMORY;
150*f6dc9357SAndroid Build Coastguard Worker if (!Ppmd7_Alloc(&_ppmd, _props.MemSize, &g_BigAlloc))
151*f6dc9357SAndroid Build Coastguard Worker return E_OUTOFMEMORY;
152*f6dc9357SAndroid Build Coastguard Worker
153*f6dc9357SAndroid Build Coastguard Worker _outStream.Stream = outStream;
154*f6dc9357SAndroid Build Coastguard Worker _outStream.Init();
155*f6dc9357SAndroid Build Coastguard Worker
156*f6dc9357SAndroid Build Coastguard Worker Ppmd7z_Init_RangeEnc(&_ppmd);
157*f6dc9357SAndroid Build Coastguard Worker Ppmd7_Init(&_ppmd, (unsigned)_props.Order);
158*f6dc9357SAndroid Build Coastguard Worker
159*f6dc9357SAndroid Build Coastguard Worker UInt64 processed = 0;
160*f6dc9357SAndroid Build Coastguard Worker for (;;)
161*f6dc9357SAndroid Build Coastguard Worker {
162*f6dc9357SAndroid Build Coastguard Worker UInt32 size;
163*f6dc9357SAndroid Build Coastguard Worker RINOK(inStream->Read(_inBuf, kBufSize, &size))
164*f6dc9357SAndroid Build Coastguard Worker if (size == 0)
165*f6dc9357SAndroid Build Coastguard Worker {
166*f6dc9357SAndroid Build Coastguard Worker // We don't write EndMark in PPMD-7z.
167*f6dc9357SAndroid Build Coastguard Worker // Ppmd7z_EncodeSymbol(&_ppmd, -1);
168*f6dc9357SAndroid Build Coastguard Worker Ppmd7z_Flush_RangeEnc(&_ppmd);
169*f6dc9357SAndroid Build Coastguard Worker return _outStream.Flush();
170*f6dc9357SAndroid Build Coastguard Worker }
171*f6dc9357SAndroid Build Coastguard Worker const Byte *buf = _inBuf;
172*f6dc9357SAndroid Build Coastguard Worker const Byte *lim = buf + size;
173*f6dc9357SAndroid Build Coastguard Worker /*
174*f6dc9357SAndroid Build Coastguard Worker for (; buf < lim; buf++)
175*f6dc9357SAndroid Build Coastguard Worker {
176*f6dc9357SAndroid Build Coastguard Worker Ppmd7z_EncodeSymbol(&_ppmd, *buf);
177*f6dc9357SAndroid Build Coastguard Worker RINOK(_outStream.Res);
178*f6dc9357SAndroid Build Coastguard Worker }
179*f6dc9357SAndroid Build Coastguard Worker */
180*f6dc9357SAndroid Build Coastguard Worker
181*f6dc9357SAndroid Build Coastguard Worker Ppmd7z_EncodeSymbols(&_ppmd, buf, lim);
182*f6dc9357SAndroid Build Coastguard Worker RINOK(_outStream.Res)
183*f6dc9357SAndroid Build Coastguard Worker
184*f6dc9357SAndroid Build Coastguard Worker processed += size;
185*f6dc9357SAndroid Build Coastguard Worker if (progress)
186*f6dc9357SAndroid Build Coastguard Worker {
187*f6dc9357SAndroid Build Coastguard Worker const UInt64 outSize = _outStream.GetProcessed();
188*f6dc9357SAndroid Build Coastguard Worker RINOK(progress->SetRatioInfo(&processed, &outSize))
189*f6dc9357SAndroid Build Coastguard Worker }
190*f6dc9357SAndroid Build Coastguard Worker }
191*f6dc9357SAndroid Build Coastguard Worker }
192*f6dc9357SAndroid Build Coastguard Worker
193*f6dc9357SAndroid Build Coastguard Worker }}
194