tor-browser

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

Bcj2Coder.cpp (17714B)


      1 // Bcj2Coder.cpp
      2 
      3 #include "StdAfx.h"
      4 
      5 #include "../../../C/Alloc.h"
      6 
      7 #include "../Common/StreamUtils.h"
      8 
      9 #include "Bcj2Coder.h"
     10 
     11 namespace NCompress {
     12 namespace NBcj2 {
     13 
     14 CBaseCoder::CBaseCoder()
     15 {
     16  for (int i = 0; i < BCJ2_NUM_STREAMS + 1; i++)
     17  {
     18    _bufs[i] = NULL;
     19    _bufsCurSizes[i] = 0;
     20    _bufsNewSizes[i] = (1 << 18);
     21  }
     22 }
     23 
     24 CBaseCoder::~CBaseCoder()
     25 {
     26  for (int i = 0; i < BCJ2_NUM_STREAMS + 1; i++)
     27    ::MidFree(_bufs[i]);
     28 }
     29 
     30 HRESULT CBaseCoder::Alloc(bool allocForOrig)
     31 {
     32  unsigned num = allocForOrig ? BCJ2_NUM_STREAMS + 1 : BCJ2_NUM_STREAMS;
     33  for (unsigned i = 0; i < num; i++)
     34  {
     35    UInt32 newSize = _bufsNewSizes[i];
     36    const UInt32 kMinBufSize = 1;
     37    if (newSize < kMinBufSize)
     38      newSize = kMinBufSize;
     39    if (!_bufs[i] || newSize != _bufsCurSizes[i])
     40    {
     41      if (_bufs[i])
     42      {
     43        ::MidFree(_bufs[i]);
     44        _bufs[i] = 0;
     45      }
     46      _bufsCurSizes[i] = 0;
     47      Byte *buf = (Byte *)::MidAlloc(newSize);
     48      _bufs[i] = buf;
     49      if (!buf)
     50        return E_OUTOFMEMORY;
     51      _bufsCurSizes[i] = newSize;
     52    }
     53  }
     54  return S_OK;
     55 }
     56 
     57 
     58 
     59 #ifndef EXTRACT_ONLY
     60 
     61 CEncoder::CEncoder(): _relatLim(BCJ2_RELAT_LIMIT) {}
     62 CEncoder::~CEncoder() {}
     63 
     64 STDMETHODIMP CEncoder::SetInBufSize(UInt32, UInt32 size) { _bufsNewSizes[BCJ2_NUM_STREAMS] = size; return S_OK; }
     65 STDMETHODIMP CEncoder::SetOutBufSize(UInt32 streamIndex, UInt32 size) { _bufsNewSizes[streamIndex] = size; return S_OK; }
     66 
     67 STDMETHODIMP CEncoder::SetCoderProperties(const PROPID *propIDs, const PROPVARIANT *props, UInt32 numProps)
     68 {
     69  UInt32 relatLim = BCJ2_RELAT_LIMIT;
     70  
     71  for (UInt32 i = 0; i < numProps; i++)
     72  {
     73    const PROPVARIANT &prop = props[i];
     74    PROPID propID = propIDs[i];
     75    if (propID >= NCoderPropID::kReduceSize)
     76      continue;
     77    switch (propID)
     78    {
     79      /*
     80      case NCoderPropID::kDefaultProp:
     81      {
     82        if (prop.vt != VT_UI4)
     83          return E_INVALIDARG;
     84        UInt32 v = prop.ulVal;
     85        if (v > 31)
     86          return E_INVALIDARG;
     87        relatLim = (UInt32)1 << v;
     88        break;
     89      }
     90      */
     91      case NCoderPropID::kDictionarySize:
     92      {
     93        if (prop.vt != VT_UI4)
     94          return E_INVALIDARG;
     95        relatLim = prop.ulVal;
     96        if (relatLim > ((UInt32)1 << 31))
     97          return E_INVALIDARG;
     98        break;
     99      }
    100 
    101      case NCoderPropID::kNumThreads:
    102        continue;
    103      case NCoderPropID::kLevel:
    104        continue;
    105     
    106      default: return E_INVALIDARG;
    107    }
    108  }
    109  
    110  _relatLim = relatLim;
    111  
    112  return S_OK;
    113 }
    114 
    115 
    116 HRESULT CEncoder::CodeReal(ISequentialInStream * const *inStreams, const UInt64 * const *inSizes, UInt32 numInStreams,
    117    ISequentialOutStream * const *outStreams, const UInt64 * const * /* outSizes */, UInt32 numOutStreams,
    118    ICompressProgressInfo *progress)
    119 {
    120  if (numInStreams != 1 || numOutStreams != BCJ2_NUM_STREAMS)
    121    return E_INVALIDARG;
    122 
    123  RINOK(Alloc());
    124 
    125  UInt32 fileSize_for_Conv = 0;
    126  if (inSizes && inSizes[0])
    127  {
    128    UInt64 inSize = *inSizes[0];
    129    if (inSize <= BCJ2_FileSize_MAX)
    130      fileSize_for_Conv = (UInt32)inSize;
    131  }
    132 
    133  CMyComPtr<ICompressGetSubStreamSize> getSubStreamSize;
    134  inStreams[0]->QueryInterface(IID_ICompressGetSubStreamSize, (void **)&getSubStreamSize);
    135 
    136  CBcj2Enc enc;
    137    
    138  enc.src = _bufs[BCJ2_NUM_STREAMS];
    139  enc.srcLim = enc.src;
    140    
    141  {
    142    for (int i = 0; i < BCJ2_NUM_STREAMS; i++)
    143    {
    144      enc.bufs[i] = _bufs[i];
    145      enc.lims[i] = _bufs[i] + _bufsCurSizes[i];
    146    }
    147  }
    148 
    149  size_t numBytes_in_ReadBuf = 0;
    150  UInt64 prevProgress = 0;
    151  UInt64 totalStreamRead = 0; // size read from InputStream
    152  UInt64 currentInPos = 0; // data that was processed, it doesn't include data in input buffer and data in enc.temp
    153  UInt64 outSizeRc = 0;
    154 
    155  Bcj2Enc_Init(&enc);
    156 
    157  enc.fileIp = 0;
    158  enc.fileSize = fileSize_for_Conv;
    159 
    160  enc.relatLimit = _relatLim;
    161 
    162  enc.finishMode = BCJ2_ENC_FINISH_MODE_CONTINUE;
    163 
    164  bool needSubSize = false;
    165  UInt64 subStreamIndex = 0;
    166  UInt64 subStreamStartPos = 0;
    167  bool readWasFinished = false;
    168 
    169  for (;;)
    170  {
    171    if (needSubSize && getSubStreamSize)
    172    {
    173      enc.fileIp = 0;
    174      enc.fileSize = fileSize_for_Conv;
    175      enc.finishMode = BCJ2_ENC_FINISH_MODE_CONTINUE;
    176      
    177      for (;;)
    178      {
    179        UInt64 subStreamSize = 0;
    180        HRESULT result = getSubStreamSize->GetSubStreamSize(subStreamIndex, &subStreamSize);
    181        needSubSize = false;
    182        
    183        if (result == S_OK)
    184        {
    185          UInt64 newEndPos = subStreamStartPos + subStreamSize;
    186          
    187          bool isAccurateEnd = (newEndPos < totalStreamRead ||
    188            (newEndPos <= totalStreamRead && readWasFinished));
    189          
    190          if (newEndPos <= currentInPos && isAccurateEnd)
    191          {
    192            subStreamStartPos = newEndPos;
    193            subStreamIndex++;
    194            continue;
    195          }
    196          
    197          enc.srcLim = _bufs[BCJ2_NUM_STREAMS] + numBytes_in_ReadBuf;
    198          
    199          if (isAccurateEnd)
    200          {
    201            // data in enc.temp is possible here
    202            size_t rem = (size_t)(totalStreamRead - newEndPos);
    203            
    204            /* Pos_of(enc.src) <= old newEndPos <= newEndPos
    205               in another case, it's fail in some code */
    206            if ((size_t)(enc.srcLim - enc.src) < rem)
    207              return E_FAIL;
    208            
    209            enc.srcLim -= rem;
    210            enc.finishMode = BCJ2_ENC_FINISH_MODE_END_BLOCK;
    211          }
    212          
    213          if (subStreamSize <= BCJ2_FileSize_MAX)
    214          {
    215            enc.fileIp = enc.ip + (UInt32)(subStreamStartPos - currentInPos);
    216            enc.fileSize = (UInt32)subStreamSize;
    217          }
    218          break;
    219        }
    220        
    221        if (result == S_FALSE)
    222          break;
    223        if (result == E_NOTIMPL)
    224        {
    225          getSubStreamSize.Release();
    226          break;
    227        }
    228        return result;
    229      }
    230    }
    231 
    232    if (readWasFinished && totalStreamRead - currentInPos == Bcj2Enc_Get_InputData_Size(&enc))
    233      enc.finishMode = BCJ2_ENC_FINISH_MODE_END_STREAM;
    234 
    235    Bcj2Enc_Encode(&enc);
    236 
    237    currentInPos = totalStreamRead - numBytes_in_ReadBuf + (enc.src - _bufs[BCJ2_NUM_STREAMS]) - enc.tempPos;
    238    
    239    if (Bcj2Enc_IsFinished(&enc))
    240      break;
    241 
    242    if (enc.state < BCJ2_NUM_STREAMS)
    243    {
    244      size_t curSize = enc.bufs[enc.state] - _bufs[enc.state];
    245      // printf("Write stream = %2d %6d\n", enc.state, curSize);
    246      RINOK(WriteStream(outStreams[enc.state], _bufs[enc.state], curSize));
    247      if (enc.state == BCJ2_STREAM_RC)
    248        outSizeRc += curSize;
    249 
    250      enc.bufs[enc.state] = _bufs[enc.state];
    251      enc.lims[enc.state] = _bufs[enc.state] + _bufsCurSizes[enc.state];
    252    }
    253    else if (enc.state != BCJ2_ENC_STATE_ORIG)
    254      return E_FAIL;
    255    else
    256    {
    257      needSubSize = true;
    258 
    259      if (numBytes_in_ReadBuf != (size_t)(enc.src - _bufs[BCJ2_NUM_STREAMS]))
    260      {
    261        enc.srcLim = _bufs[BCJ2_NUM_STREAMS] + numBytes_in_ReadBuf;
    262        continue;
    263      }
    264 
    265      if (readWasFinished)
    266        continue;
    267      
    268      numBytes_in_ReadBuf = 0;
    269      enc.src    = _bufs[BCJ2_NUM_STREAMS];
    270      enc.srcLim = _bufs[BCJ2_NUM_STREAMS];
    271 
    272      UInt32 curSize = _bufsCurSizes[BCJ2_NUM_STREAMS];
    273      RINOK(inStreams[0]->Read(_bufs[BCJ2_NUM_STREAMS], curSize, &curSize));
    274 
    275      // printf("Read %6d bytes\n", curSize);
    276      if (curSize == 0)
    277      {
    278        readWasFinished = true;
    279        continue;
    280      }
    281 
    282      numBytes_in_ReadBuf = curSize;
    283      totalStreamRead += numBytes_in_ReadBuf;
    284      enc.srcLim = _bufs[BCJ2_NUM_STREAMS] + numBytes_in_ReadBuf;
    285    }
    286 
    287    if (progress && currentInPos - prevProgress >= (1 << 20))
    288    {
    289      UInt64 outSize2 = currentInPos + outSizeRc + enc.bufs[BCJ2_STREAM_RC] - enc.bufs[BCJ2_STREAM_RC];
    290      prevProgress = currentInPos;
    291      // printf("progress %8d, %8d\n", (int)inSize2, (int)outSize2);
    292      RINOK(progress->SetRatioInfo(&currentInPos, &outSize2));
    293    }
    294  }
    295 
    296  for (int i = 0; i < BCJ2_NUM_STREAMS; i++)
    297  {
    298    RINOK(WriteStream(outStreams[i], _bufs[i], enc.bufs[i] - _bufs[i]));
    299  }
    300 
    301  // if (currentInPos != subStreamStartPos + subStreamSize) return E_FAIL;
    302 
    303  return S_OK;
    304 }
    305 
    306 STDMETHODIMP CEncoder::Code(ISequentialInStream * const *inStreams, const UInt64 * const *inSizes, UInt32 numInStreams,
    307    ISequentialOutStream * const *outStreams, const UInt64 * const *outSizes, UInt32 numOutStreams,
    308    ICompressProgressInfo *progress)
    309 {
    310  try
    311  {
    312    return CodeReal(inStreams, inSizes, numInStreams, outStreams, outSizes,numOutStreams, progress);
    313  }
    314  catch(...) { return E_FAIL; }
    315 }
    316 
    317 #endif
    318 
    319 
    320 
    321 
    322 
    323 
    324 STDMETHODIMP CDecoder::SetInBufSize(UInt32 streamIndex, UInt32 size) { _bufsNewSizes[streamIndex] = size; return S_OK; }
    325 STDMETHODIMP CDecoder::SetOutBufSize(UInt32 , UInt32 size) { _bufsNewSizes[BCJ2_NUM_STREAMS] = size; return S_OK; }
    326 
    327 CDecoder::CDecoder(): _finishMode(false), _outSizeDefined(false), _outSize(0)
    328 {}
    329 
    330 STDMETHODIMP CDecoder::SetFinishMode(UInt32 finishMode)
    331 {
    332  _finishMode = (finishMode != 0);
    333  return S_OK;
    334 }
    335 
    336 void CDecoder::InitCommon()
    337 {
    338  {
    339    for (int i = 0; i < BCJ2_NUM_STREAMS; i++)
    340      dec.lims[i] = dec.bufs[i] = _bufs[i];
    341  }
    342 
    343  {
    344    for (int i = 0; i < BCJ2_NUM_STREAMS; i++)
    345    {
    346      _extraReadSizes[i] = 0;
    347      _inStreamsProcessed[i] = 0;
    348      _readRes[i] = S_OK;
    349    }
    350  }
    351    
    352  Bcj2Dec_Init(&dec);
    353 }
    354 
    355 HRESULT CDecoder::Code(ISequentialInStream * const *inStreams, const UInt64 * const *inSizes, UInt32 numInStreams,
    356    ISequentialOutStream * const *outStreams, const UInt64 * const *outSizes, UInt32 numOutStreams,
    357    ICompressProgressInfo *progress)
    358 {
    359  if (numInStreams != BCJ2_NUM_STREAMS || numOutStreams != 1)
    360    return E_INVALIDARG;
    361 
    362  RINOK(Alloc());
    363    
    364  InitCommon();
    365 
    366  dec.destLim = dec.dest = _bufs[BCJ2_NUM_STREAMS];
    367  
    368  UInt64 outSizeProcessed = 0;
    369  UInt64 prevProgress = 0;
    370 
    371  HRESULT res = S_OK;
    372 
    373  for (;;)
    374  {
    375    if (Bcj2Dec_Decode(&dec) != SZ_OK)
    376      return S_FALSE;
    377    
    378    if (dec.state < BCJ2_NUM_STREAMS)
    379    {
    380      size_t totalRead = _extraReadSizes[dec.state];
    381      {
    382        Byte *buf = _bufs[dec.state];
    383        for (size_t i = 0; i < totalRead; i++)
    384          buf[i] = dec.bufs[dec.state][i];
    385        dec.lims[dec.state] =
    386        dec.bufs[dec.state] = buf;
    387      }
    388 
    389      if (_readRes[dec.state] != S_OK)
    390      {
    391        res = _readRes[dec.state];
    392        break;
    393      }
    394 
    395      do
    396      {
    397        UInt32 curSize = _bufsCurSizes[dec.state] - (UInt32)totalRead;
    398        /*
    399        we want to call Read even even if size is 0
    400        if (inSizes && inSizes[dec.state])
    401        {
    402          UInt64 rem = *inSizes[dec.state] - _inStreamsProcessed[dec.state];
    403          if (curSize > rem)
    404            curSize = (UInt32)rem;
    405        }
    406        */
    407 
    408        HRESULT res2 = inStreams[dec.state]->Read(_bufs[dec.state] + totalRead, curSize, &curSize);
    409        _readRes[dec.state] = res2;
    410        if (curSize == 0)
    411          break;
    412        _inStreamsProcessed[dec.state] += curSize;
    413        totalRead += curSize;
    414        if (res2 != S_OK)
    415          break;
    416      }
    417      while (totalRead < 4 && BCJ2_IS_32BIT_STREAM(dec.state));
    418 
    419      if (_readRes[dec.state] != S_OK)
    420        res = _readRes[dec.state];
    421 
    422      if (totalRead == 0)
    423        break;
    424 
    425      // res == S_OK;
    426 
    427      if (BCJ2_IS_32BIT_STREAM(dec.state))
    428      {
    429        unsigned extraSize = ((unsigned)totalRead & 3);
    430        _extraReadSizes[dec.state] = extraSize;
    431        if (totalRead < 4)
    432        {
    433          res = (_readRes[dec.state] != S_OK) ? _readRes[dec.state] : S_FALSE;
    434          break;
    435        }
    436        totalRead -= extraSize;
    437      }
    438 
    439      dec.lims[dec.state] = _bufs[dec.state] + totalRead;
    440    }
    441    else // if (dec.state <= BCJ2_STATE_ORIG)
    442    {
    443      size_t curSize = dec.dest - _bufs[BCJ2_NUM_STREAMS];
    444      if (curSize != 0)
    445      {
    446        outSizeProcessed += curSize;
    447        RINOK(WriteStream(outStreams[0], _bufs[BCJ2_NUM_STREAMS], curSize));
    448      }
    449      dec.dest = _bufs[BCJ2_NUM_STREAMS];
    450      {
    451        size_t rem = _bufsCurSizes[BCJ2_NUM_STREAMS];
    452        if (outSizes && outSizes[0])
    453        {
    454          UInt64 outSize = *outSizes[0] - outSizeProcessed;
    455          if (rem > outSize)
    456            rem = (size_t)outSize;
    457        }
    458        dec.destLim = dec.dest + rem;
    459        if (rem == 0)
    460          break;
    461      }
    462    }
    463 
    464    if (progress)
    465    {
    466      const UInt64 outSize2 = outSizeProcessed + (dec.dest - _bufs[BCJ2_NUM_STREAMS]);
    467      if (outSize2 - prevProgress >= (1 << 22))
    468      {
    469        const UInt64 inSize2 = outSize2 + _inStreamsProcessed[BCJ2_STREAM_RC] - (dec.lims[BCJ2_STREAM_RC] - dec.bufs[BCJ2_STREAM_RC]);
    470        RINOK(progress->SetRatioInfo(&inSize2, &outSize2));
    471        prevProgress = outSize2;
    472      }
    473    }
    474  }
    475 
    476  size_t curSize = dec.dest - _bufs[BCJ2_NUM_STREAMS];
    477  if (curSize != 0)
    478  {
    479    outSizeProcessed += curSize;
    480    RINOK(WriteStream(outStreams[0], _bufs[BCJ2_NUM_STREAMS], curSize));
    481  }
    482 
    483  if (res != S_OK)
    484    return res;
    485 
    486  if (_finishMode)
    487  {
    488    if (!Bcj2Dec_IsFinished(&dec))
    489      return S_FALSE;
    490 
    491    // we still allow the cases when input streams are larger than required for decoding.
    492    // so the case (dec.state == BCJ2_STATE_ORIG) is also allowed, if MAIN stream is larger than required.
    493    if (dec.state != BCJ2_STREAM_MAIN &&
    494        dec.state != BCJ2_DEC_STATE_ORIG)
    495      return S_FALSE;
    496 
    497    if (inSizes)
    498    {
    499      for (int i = 0; i < BCJ2_NUM_STREAMS; i++)
    500      {
    501        size_t rem = dec.lims[i] - dec.bufs[i] + _extraReadSizes[i];
    502        /*
    503        if (rem != 0)
    504          return S_FALSE;
    505        */
    506        if (inSizes[i] && *inSizes[i] != _inStreamsProcessed[i] - rem)
    507          return S_FALSE;
    508      }
    509    }
    510  }
    511 
    512  return S_OK;
    513 }
    514 
    515 STDMETHODIMP CDecoder::SetInStream2(UInt32 streamIndex, ISequentialInStream *inStream)
    516 {
    517  _inStreams[streamIndex] = inStream;
    518  return S_OK;
    519 }
    520 
    521 STDMETHODIMP CDecoder::ReleaseInStream2(UInt32 streamIndex)
    522 {
    523  _inStreams[streamIndex].Release();
    524  return S_OK;
    525 }
    526 
    527 STDMETHODIMP CDecoder::SetOutStreamSize(const UInt64 *outSize)
    528 {
    529  _outSizeDefined = (outSize != NULL);
    530  _outSize = 0;
    531  if (_outSizeDefined)
    532    _outSize = *outSize;
    533 
    534  _outSize_Processed = 0;
    535 
    536  HRESULT res = Alloc(false);
    537  
    538  InitCommon();
    539  dec.destLim = dec.dest = NULL;
    540 
    541  return res;
    542 }
    543 
    544 
    545 STDMETHODIMP CDecoder::Read(void *data, UInt32 size, UInt32 *processedSize)
    546 {
    547  if (processedSize)
    548    *processedSize = 0;
    549 
    550  if (size == 0)
    551    return S_OK;
    552 
    553  UInt32 totalProcessed = 0;
    554 
    555  if (_outSizeDefined)
    556  {
    557    UInt64 rem = _outSize - _outSize_Processed;
    558    if (size > rem)
    559      size = (UInt32)rem;
    560  }
    561  dec.dest = (Byte *)data;
    562  dec.destLim = (const Byte *)data + size;
    563 
    564  HRESULT res = S_OK;
    565 
    566  for (;;)
    567  {
    568    SRes sres = Bcj2Dec_Decode(&dec);
    569    if (sres != SZ_OK)
    570      return S_FALSE;
    571    
    572    {
    573      UInt32 curSize = (UInt32)(dec.dest - (Byte *)data);
    574      if (curSize != 0)
    575      {
    576        totalProcessed += curSize;
    577        if (processedSize)
    578          *processedSize = totalProcessed;
    579        data = (void *)((Byte *)data + curSize);
    580        size -= curSize;
    581        _outSize_Processed += curSize;
    582      }
    583    }
    584 
    585    if (dec.state >= BCJ2_NUM_STREAMS)
    586      break;
    587 
    588    {
    589      size_t totalRead = _extraReadSizes[dec.state];
    590      {
    591        Byte *buf = _bufs[dec.state];
    592        for (size_t i = 0; i < totalRead; i++)
    593          buf[i] = dec.bufs[dec.state][i];
    594        dec.lims[dec.state] =
    595        dec.bufs[dec.state] = buf;
    596      }
    597 
    598      if (_readRes[dec.state] != S_OK)
    599        return _readRes[dec.state];
    600 
    601      do
    602      {
    603        UInt32 curSize = _bufsCurSizes[dec.state] - (UInt32)totalRead;
    604        HRESULT res2 = _inStreams[dec.state]->Read(_bufs[dec.state] + totalRead, curSize, &curSize);
    605        _readRes[dec.state] = res2;
    606        if (curSize == 0)
    607          break;
    608        _inStreamsProcessed[dec.state] += curSize;
    609        totalRead += curSize;
    610        if (res2 != S_OK)
    611          break;
    612      }
    613      while (totalRead < 4 && BCJ2_IS_32BIT_STREAM(dec.state));
    614 
    615      if (totalRead == 0)
    616      {
    617        if (totalProcessed == 0)
    618          res = _readRes[dec.state];
    619        break;
    620      }
    621 
    622      if (BCJ2_IS_32BIT_STREAM(dec.state))
    623      {
    624        unsigned extraSize = ((unsigned)totalRead & 3);
    625        _extraReadSizes[dec.state] = extraSize;
    626        if (totalRead < 4)
    627        {
    628          if (totalProcessed != 0)
    629            return S_OK;
    630          return (_readRes[dec.state] != S_OK) ? _readRes[dec.state] : S_FALSE;
    631        }
    632        totalRead -= extraSize;
    633      }
    634 
    635      dec.lims[dec.state] = _bufs[dec.state] + totalRead;
    636    }
    637  }
    638 
    639  if (_finishMode && _outSizeDefined && _outSize == _outSize_Processed)
    640  {
    641    if (!Bcj2Dec_IsFinished(&dec))
    642      return S_FALSE;
    643 
    644    if (dec.state != BCJ2_STREAM_MAIN &&
    645        dec.state != BCJ2_DEC_STATE_ORIG)
    646      return S_FALSE;
    647  
    648    /*
    649    for (int i = 0; i < BCJ2_NUM_STREAMS; i++)
    650      if (dec.bufs[i] != dec.lims[i] || _extraReadSizes[i] != 0)
    651        return S_FALSE;
    652    */
    653  }
    654 
    655  return res;
    656 }
    657 
    658 
    659 STDMETHODIMP CDecoder::GetInStreamProcessedSize2(UInt32 streamIndex, UInt64 *value)
    660 {
    661  const size_t rem = dec.lims[streamIndex] - dec.bufs[streamIndex] + _extraReadSizes[streamIndex];
    662  *value = _inStreamsProcessed[streamIndex] - rem;
    663  return S_OK;
    664 }
    665 
    666 }}