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