• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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