tor-browser

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

LzmaDecoder.cpp (8416B)


      1 // LzmaDecoder.cpp
      2 
      3 #include "StdAfx.h"
      4 
      5 #include "../../../C/Alloc.h"
      6 
      7 #include "../Common/StreamUtils.h"
      8 
      9 #include "LzmaDecoder.h"
     10 
     11 static HRESULT SResToHRESULT(SRes res)
     12 {
     13  switch (res)
     14  {
     15    case SZ_OK: return S_OK;
     16    case SZ_ERROR_MEM: return E_OUTOFMEMORY;
     17    case SZ_ERROR_PARAM: return E_INVALIDARG;
     18    case SZ_ERROR_UNSUPPORTED: return E_NOTIMPL;
     19    case SZ_ERROR_DATA: return S_FALSE;
     20  }
     21  return E_FAIL;
     22 }
     23 
     24 namespace NCompress {
     25 namespace NLzma {
     26 
     27 CDecoder::CDecoder():
     28    _inBuf(NULL),
     29    _lzmaStatus(LZMA_STATUS_NOT_SPECIFIED),
     30    FinishStream(false),
     31    _propsWereSet(false),
     32    _outSizeDefined(false),
     33    _outStep(1 << 20),
     34    _inBufSize(0),
     35    _inBufSizeNew(1 << 20)
     36 {
     37  _inProcessed = 0;
     38  _inPos = _inLim = 0;
     39 
     40  /*
     41  AlignOffsetAlloc_CreateVTable(&_alloc);
     42  _alloc.numAlignBits = 7;
     43  _alloc.offset = 0;
     44  */
     45  LzmaDec_Construct(&_state);
     46 }
     47 
     48 CDecoder::~CDecoder()
     49 {
     50  LzmaDec_Free(&_state, &g_AlignedAlloc); // &_alloc.vt
     51  MyFree(_inBuf);
     52 }
     53 
     54 STDMETHODIMP CDecoder::SetInBufSize(UInt32 , UInt32 size) { _inBufSizeNew = size; return S_OK; }
     55 STDMETHODIMP CDecoder::SetOutBufSize(UInt32 , UInt32 size) { _outStep = size; return S_OK; }
     56 
     57 HRESULT CDecoder::CreateInputBuffer()
     58 {
     59  if (!_inBuf || _inBufSizeNew != _inBufSize)
     60  {
     61    MyFree(_inBuf);
     62    _inBufSize = 0;
     63    _inBuf = (Byte *)MyAlloc(_inBufSizeNew);
     64    if (!_inBuf)
     65      return E_OUTOFMEMORY;
     66    _inBufSize = _inBufSizeNew;
     67  }
     68  return S_OK;
     69 }
     70 
     71 
     72 STDMETHODIMP CDecoder::SetDecoderProperties2(const Byte *prop, UInt32 size)
     73 {
     74  RINOK(SResToHRESULT(LzmaDec_Allocate(&_state, prop, size, &g_AlignedAlloc))) // &_alloc.vt
     75  _propsWereSet = true;
     76  return CreateInputBuffer();
     77 }
     78 
     79 
     80 void CDecoder::SetOutStreamSizeResume(const UInt64 *outSize)
     81 {
     82  _outSizeDefined = (outSize != NULL);
     83  _outSize = 0;
     84  if (_outSizeDefined)
     85    _outSize = *outSize;
     86  _outProcessed = 0;
     87  _lzmaStatus = LZMA_STATUS_NOT_SPECIFIED;
     88 
     89  LzmaDec_Init(&_state);
     90 }
     91 
     92 
     93 STDMETHODIMP CDecoder::SetOutStreamSize(const UInt64 *outSize)
     94 {
     95  _inProcessed = 0;
     96  _inPos = _inLim = 0;
     97  SetOutStreamSizeResume(outSize);
     98  return S_OK;
     99 }
    100 
    101 
    102 STDMETHODIMP CDecoder::SetFinishMode(UInt32 finishMode)
    103 {
    104  FinishStream = (finishMode != 0);
    105  return S_OK;
    106 }
    107 
    108 
    109 STDMETHODIMP CDecoder::GetInStreamProcessedSize(UInt64 *value)
    110 {
    111  *value = _inProcessed;
    112  return S_OK;
    113 }
    114 
    115 
    116 HRESULT CDecoder::CodeSpec(ISequentialInStream *inStream, ISequentialOutStream *outStream, ICompressProgressInfo *progress)
    117 {
    118  if (!_inBuf || !_propsWereSet)
    119    return S_FALSE;
    120  
    121  const UInt64 startInProgress = _inProcessed;
    122  SizeT wrPos = _state.dicPos;
    123  HRESULT readRes = S_OK;
    124 
    125  for (;;)
    126  {
    127    if (_inPos == _inLim && readRes == S_OK)
    128    {
    129      _inPos = _inLim = 0;
    130      readRes = inStream->Read(_inBuf, _inBufSize, &_inLim);
    131    }
    132 
    133    const SizeT dicPos = _state.dicPos;
    134    SizeT size;
    135    {
    136      SizeT next = _state.dicBufSize;
    137      if (next - wrPos > _outStep)
    138        next = wrPos + _outStep;
    139      size = next - dicPos;
    140    }
    141 
    142    ELzmaFinishMode finishMode = LZMA_FINISH_ANY;
    143    if (_outSizeDefined)
    144    {
    145      const UInt64 rem = _outSize - _outProcessed;
    146      if (size >= rem)
    147      {
    148        size = (SizeT)rem;
    149        if (FinishStream)
    150          finishMode = LZMA_FINISH_END;
    151      }
    152    }
    153 
    154    SizeT inProcessed = _inLim - _inPos;
    155    ELzmaStatus status;
    156    
    157    SRes res = LzmaDec_DecodeToDic(&_state, dicPos + size, _inBuf + _inPos, &inProcessed, finishMode, &status);
    158 
    159    _lzmaStatus = status;
    160    _inPos += (UInt32)inProcessed;
    161    _inProcessed += inProcessed;
    162    const SizeT outProcessed = _state.dicPos - dicPos;
    163    _outProcessed += outProcessed;
    164 
    165    // we check for LZMA_STATUS_NEEDS_MORE_INPUT to allow RangeCoder initialization, if (_outSizeDefined && _outSize == 0)
    166    bool outFinished = (_outSizeDefined && _outProcessed >= _outSize);
    167 
    168    bool needStop = (res != 0
    169        || (inProcessed == 0 && outProcessed == 0)
    170        || status == LZMA_STATUS_FINISHED_WITH_MARK
    171        || (outFinished && status != LZMA_STATUS_NEEDS_MORE_INPUT));
    172 
    173    if (needStop || outProcessed >= size)
    174    {
    175      HRESULT res2 = WriteStream(outStream, _state.dic + wrPos, _state.dicPos - wrPos);
    176 
    177      if (_state.dicPos == _state.dicBufSize)
    178        _state.dicPos = 0;
    179      wrPos = _state.dicPos;
    180      
    181      RINOK(res2);
    182 
    183      if (needStop)
    184      {
    185        if (res != 0)
    186          return S_FALSE;
    187 
    188        if (status == LZMA_STATUS_FINISHED_WITH_MARK)
    189        {
    190          if (FinishStream)
    191            if (_outSizeDefined && _outSize != _outProcessed)
    192              return S_FALSE;
    193          return readRes;
    194        }
    195        
    196        if (outFinished && status != LZMA_STATUS_NEEDS_MORE_INPUT)
    197          if (!FinishStream || status == LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK)
    198            return readRes;
    199          
    200        return S_FALSE;
    201      }
    202    }
    203    
    204    if (progress)
    205    {
    206      const UInt64 inSize = _inProcessed - startInProgress;
    207      RINOK(progress->SetRatioInfo(&inSize, &_outProcessed));
    208    }
    209  }
    210 }
    211 
    212 
    213 STDMETHODIMP CDecoder::Code(ISequentialInStream *inStream, ISequentialOutStream *outStream,
    214    const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress)
    215 {
    216  if (!_inBuf)
    217    return E_INVALIDARG;
    218  SetOutStreamSize(outSize);
    219  HRESULT res = CodeSpec(inStream, outStream, progress);
    220  if (res == S_OK)
    221    if (FinishStream && inSize && *inSize != _inProcessed)
    222      res = S_FALSE;
    223  return res;
    224 }
    225 
    226 
    227 #ifndef NO_READ_FROM_CODER
    228 
    229 STDMETHODIMP CDecoder::SetInStream(ISequentialInStream *inStream) { _inStream = inStream; return S_OK; }
    230 STDMETHODIMP CDecoder::ReleaseInStream() { _inStream.Release(); return S_OK; }
    231 
    232 
    233 STDMETHODIMP CDecoder::Read(void *data, UInt32 size, UInt32 *processedSize)
    234 {
    235  if (processedSize)
    236    *processedSize = 0;
    237 
    238  ELzmaFinishMode finishMode = LZMA_FINISH_ANY;
    239  if (_outSizeDefined)
    240  {
    241    const UInt64 rem = _outSize - _outProcessed;
    242    if (size >= rem)
    243    {
    244      size = (UInt32)rem;
    245      if (FinishStream)
    246        finishMode = LZMA_FINISH_END;
    247    }
    248  }
    249 
    250  HRESULT readRes = S_OK;
    251  
    252  for (;;)
    253  {
    254    if (_inPos == _inLim && readRes == S_OK)
    255    {
    256      _inPos = _inLim = 0;
    257      readRes = _inStream->Read(_inBuf, _inBufSize, &_inLim);
    258    }
    259 
    260    SizeT inProcessed = _inLim - _inPos;
    261    SizeT outProcessed = size;
    262    ELzmaStatus status;
    263    
    264    SRes res = LzmaDec_DecodeToBuf(&_state, (Byte *)data, &outProcessed,
    265        _inBuf + _inPos, &inProcessed, finishMode, &status);
    266    
    267    _lzmaStatus = status;
    268    _inPos += (UInt32)inProcessed;
    269    _inProcessed += inProcessed;
    270    _outProcessed += outProcessed;
    271    size -= (UInt32)outProcessed;
    272    data = (Byte *)data + outProcessed;
    273    if (processedSize)
    274      *processedSize += (UInt32)outProcessed;
    275 
    276    if (res != 0)
    277      return S_FALSE;
    278    
    279    /*
    280    if (status == LZMA_STATUS_FINISHED_WITH_MARK)
    281      return readRes;
    282 
    283    if (size == 0 && status != LZMA_STATUS_NEEDS_MORE_INPUT)
    284    {
    285      if (FinishStream
    286          && _outSizeDefined && _outProcessed >= _outSize
    287          && status != LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK)
    288        return S_FALSE;
    289      return readRes;
    290    }
    291    */
    292 
    293    if (inProcessed == 0 && outProcessed == 0)
    294      return readRes;
    295  }
    296 }
    297 
    298 
    299 HRESULT CDecoder::CodeResume(ISequentialOutStream *outStream, const UInt64 *outSize, ICompressProgressInfo *progress)
    300 {
    301  SetOutStreamSizeResume(outSize);
    302  return CodeSpec(_inStream, outStream, progress);
    303 }
    304 
    305 
    306 HRESULT CDecoder::ReadFromInputStream(void *data, UInt32 size, UInt32 *processedSize)
    307 {
    308  RINOK(CreateInputBuffer());
    309  
    310  if (processedSize)
    311    *processedSize = 0;
    312 
    313  HRESULT readRes = S_OK;
    314 
    315  while (size != 0)
    316  {
    317    if (_inPos == _inLim)
    318    {
    319      _inPos = _inLim = 0;
    320      if (readRes == S_OK)
    321        readRes = _inStream->Read(_inBuf, _inBufSize, &_inLim);
    322      if (_inLim == 0)
    323        break;
    324    }
    325 
    326    UInt32 cur = _inLim - _inPos;
    327    if (cur > size)
    328      cur = size;
    329    memcpy(data, _inBuf + _inPos, cur);
    330    _inPos += cur;
    331    _inProcessed += cur;
    332    size -= cur;
    333    data = (Byte *)data + cur;
    334    if (processedSize)
    335      *processedSize += cur;
    336  }
    337  
    338  return readRes;
    339 }
    340 
    341 #endif
    342 
    343 }}