tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

PpmdEncoder.cpp (3852B)


      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.vt;
     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 }}