Home | History | Annotate | Download | only in Compress
      1 // PpmdDecoder.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 "PpmdDecoder.h"
     12 
     13 namespace NCompress {
     14 namespace NPpmd {
     15 
     16 static const UInt32 kBufSize = (1 << 20);
     17 
     18 enum
     19 {
     20   kStatus_NeedInit,
     21   kStatus_Normal,
     22   kStatus_Finished,
     23   kStatus_Error
     24 };
     25 
     26 CDecoder::~CDecoder()
     27 {
     28   ::MidFree(_outBuf);
     29   Ppmd7_Free(&_ppmd, &g_BigAlloc);
     30 }
     31 
     32 STDMETHODIMP CDecoder::SetDecoderProperties2(const Byte *props, UInt32 size)
     33 {
     34   if (size < 5)
     35     return E_INVALIDARG;
     36   _order = props[0];
     37   UInt32 memSize = GetUi32(props + 1);
     38   if (_order < PPMD7_MIN_ORDER ||
     39       _order > PPMD7_MAX_ORDER ||
     40       memSize < PPMD7_MIN_MEM_SIZE ||
     41       memSize > PPMD7_MAX_MEM_SIZE)
     42     return E_NOTIMPL;
     43   if (!_inStream.Alloc(1 << 20))
     44     return E_OUTOFMEMORY;
     45   if (!Ppmd7_Alloc(&_ppmd, memSize, &g_BigAlloc))
     46     return E_OUTOFMEMORY;
     47   return S_OK;
     48 }
     49 
     50 HRESULT CDecoder::CodeSpec(Byte *memStream, UInt32 size)
     51 {
     52   switch (_status)
     53   {
     54     case kStatus_Finished: return S_OK;
     55     case kStatus_Error: return S_FALSE;
     56     case kStatus_NeedInit:
     57       _inStream.Init();
     58       if (!Ppmd7z_RangeDec_Init(&_rangeDec))
     59       {
     60         _status = kStatus_Error;
     61         return S_FALSE;
     62       }
     63       _status = kStatus_Normal;
     64       Ppmd7_Init(&_ppmd, _order);
     65       break;
     66   }
     67   if (_outSizeDefined)
     68   {
     69     const UInt64 rem = _outSize - _processedSize;
     70     if (size > rem)
     71       size = (UInt32)rem;
     72   }
     73 
     74   UInt32 i;
     75   int sym = 0;
     76   for (i = 0; i != size; i++)
     77   {
     78     sym = Ppmd7_DecodeSymbol(&_ppmd, &_rangeDec.p);
     79     if (_inStream.Extra || sym < 0)
     80       break;
     81     memStream[i] = (Byte)sym;
     82   }
     83 
     84   _processedSize += i;
     85   if (_inStream.Extra)
     86   {
     87     _status = kStatus_Error;
     88     return _inStream.Res;
     89   }
     90   if (sym < 0)
     91     _status = (sym < -1) ? kStatus_Error : kStatus_Finished;
     92   return S_OK;
     93 }
     94 
     95 STDMETHODIMP CDecoder::Code(ISequentialInStream *inStream, ISequentialOutStream *outStream,
     96     const UInt64 * /* inSize */, const UInt64 *outSize, ICompressProgressInfo *progress)
     97 {
     98   if (!_outBuf)
     99   {
    100     _outBuf = (Byte *)::MidAlloc(kBufSize);
    101     if (!_outBuf)
    102       return E_OUTOFMEMORY;
    103   }
    104 
    105   _inStream.Stream = inStream;
    106   SetOutStreamSize(outSize);
    107 
    108   do
    109   {
    110     const UInt64 startPos = _processedSize;
    111     HRESULT res = CodeSpec(_outBuf, kBufSize);
    112     size_t processed = (size_t)(_processedSize - startPos);
    113     RINOK(WriteStream(outStream, _outBuf, processed));
    114     RINOK(res);
    115     if (_status == kStatus_Finished)
    116       break;
    117     if (progress)
    118     {
    119       UInt64 inSize = _inStream.GetProcessed();
    120       RINOK(progress->SetRatioInfo(&inSize, &_processedSize));
    121     }
    122   }
    123   while (!_outSizeDefined || _processedSize < _outSize);
    124   return S_OK;
    125 }
    126 
    127 STDMETHODIMP CDecoder::SetOutStreamSize(const UInt64 *outSize)
    128 {
    129   _outSizeDefined = (outSize != NULL);
    130   if (_outSizeDefined)
    131     _outSize = *outSize;
    132   _processedSize = 0;
    133   _status = kStatus_NeedInit;
    134   return S_OK;
    135 }
    136 
    137 #ifndef NO_READ_FROM_CODER
    138 
    139 STDMETHODIMP CDecoder::SetInStream(ISequentialInStream *inStream)
    140 {
    141   InSeqStream = inStream;
    142   _inStream.Stream = inStream;
    143   return S_OK;
    144 }
    145 
    146 STDMETHODIMP CDecoder::ReleaseInStream()
    147 {
    148   InSeqStream.Release();
    149   return S_OK;
    150 }
    151 
    152 STDMETHODIMP CDecoder::Read(void *data, UInt32 size, UInt32 *processedSize)
    153 {
    154   const UInt64 startPos = _processedSize;
    155   HRESULT res = CodeSpec((Byte *)data, size);
    156   if (processedSize)
    157     *processedSize = (UInt32)(_processedSize - startPos);
    158   return res;
    159 }
    160 
    161 #endif
    162 
    163 }}
    164