xref: /aosp_15_r20/external/lzma/CPP/7zip/Compress/PpmdEncoder.cpp (revision f6dc9357d832569d4d1f5d24eacdb3935a1ae8e6)
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