Home | History | Annotate | Download | only in Compress
      1 // PpmdEncoder.cpp
      2 // 2009-03-11 : Igor Pavlov : Public domain
      3 
      4 #include "StdAfx.h"
      5 
      6 #include "../../../C/Alloc.h"
      7 #include "../../../C/CpuArch.h"
      8 
      9 #include "../Common/StreamUtils.h"
     10 
     11 #include "PpmdEncoder.h"
     12 
     13 namespace NCompress {
     14 namespace NPpmd {
     15 
     16 static const UInt32 kBufSize = (1 << 20);
     17 
     18 static void *SzBigAlloc(void *, size_t size) { return BigAlloc(size); }
     19 static void SzBigFree(void *, void *address) { BigFree(address); }
     20 static ISzAlloc g_BigAlloc = { SzBigAlloc, SzBigFree };
     21 
     22 CEncoder::CEncoder():
     23   _inBuf(NULL),
     24   _usedMemSize(1 << 24),
     25   _order(6)
     26 {
     27   _rangeEnc.Stream = &_outStream.p;
     28   Ppmd7_Construct(&_ppmd);
     29 }
     30 
     31 CEncoder::~CEncoder()
     32 {
     33   ::MidFree(_inBuf);
     34   Ppmd7_Free(&_ppmd, &g_BigAlloc);
     35 }
     36 
     37 STDMETHODIMP CEncoder::SetCoderProperties(const PROPID *propIDs, const PROPVARIANT *props, UInt32 numProps)
     38 {
     39   for (UInt32 i = 0; i < numProps; i++)
     40   {
     41     const PROPVARIANT &prop = props[i];
     42     if (prop.vt != VT_UI4)
     43       return E_INVALIDARG;
     44     UInt32 v = (UInt32)prop.ulVal;
     45     switch(propIDs[i])
     46     {
     47       case NCoderPropID::kUsedMemorySize:
     48         if (v < (1 << 16) || v > PPMD7_MAX_MEM_SIZE || (v & 3) != 0)
     49           return E_INVALIDARG;
     50         _usedMemSize = v;
     51         break;
     52       case NCoderPropID::kOrder:
     53         if (v < 2 || v > 32)
     54           return E_INVALIDARG;
     55         _order = (Byte)v;
     56         break;
     57       default:
     58         return E_INVALIDARG;
     59     }
     60   }
     61   return S_OK;
     62 }
     63 
     64 STDMETHODIMP CEncoder::WriteCoderProperties(ISequentialOutStream *outStream)
     65 {
     66   const UInt32 kPropSize = 5;
     67   Byte props[kPropSize];
     68   props[0] = _order;
     69   SetUi32(props + 1, _usedMemSize);
     70   return WriteStream(outStream, props, kPropSize);
     71 }
     72 
     73 HRESULT CEncoder::Code(ISequentialInStream *inStream, ISequentialOutStream *outStream,
     74     const UInt64 * /* inSize */, const UInt64 * /* outSize */, ICompressProgressInfo *progress)
     75 {
     76   if (!_inBuf)
     77   {
     78     _inBuf = (Byte *)::MidAlloc(kBufSize);
     79     if (!_inBuf)
     80       return E_OUTOFMEMORY;
     81   }
     82   if (!_outStream.Alloc(1 << 20))
     83     return E_OUTOFMEMORY;
     84   if (!Ppmd7_Alloc(&_ppmd, _usedMemSize, &g_BigAlloc))
     85     return E_OUTOFMEMORY;
     86 
     87   _outStream.Stream = outStream;
     88   _outStream.Init();
     89 
     90   Ppmd7z_RangeEnc_Init(&_rangeEnc);
     91   Ppmd7_Init(&_ppmd, _order);
     92 
     93   UInt64 processed = 0;
     94   for (;;)
     95   {
     96     UInt32 size;
     97     RINOK(inStream->Read(_inBuf, kBufSize, &size));
     98     if (size == 0)
     99     {
    100       // We don't write EndMark in PPMD-7z.
    101       // Ppmd7_EncodeSymbol(&_ppmd, &_rangeEnc, -1);
    102       Ppmd7z_RangeEnc_FlushData(&_rangeEnc);
    103       return _outStream.Flush();
    104     }
    105     for (UInt32 i = 0; i < size; i++)
    106     {
    107       Ppmd7_EncodeSymbol(&_ppmd, &_rangeEnc, _inBuf[i]);
    108       RINOK(_outStream.Res);
    109     }
    110     processed += size;
    111     if (progress)
    112     {
    113       UInt64 outSize = _outStream.GetProcessed();
    114       RINOK(progress->SetRatioInfo(&processed, &outSize));
    115     }
    116   }
    117 }
    118 
    119 }}
    120