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