other-licenses/7zstub/src/7zip/Compress/LZMA/LZMADecoder.cpp

Tue, 06 Jan 2015 21:39:09 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Tue, 06 Jan 2015 21:39:09 +0100
branch
TOR_BUG_9701
changeset 8
97036ab72558
permissions
-rw-r--r--

Conditionally force memory storage according to privacy.thirdparty.isolate;
This solves Tor bug #9701, complying with disk avoidance documented in
https://www.torproject.org/projects/torbrowser/design/#disk-avoidance.

     1 // LZMADecoder.cpp
     3 #include "StdAfx.h"
     5 #include "LZMADecoder.h"
     6 #include "../../../Common/Defs.h"
     8 namespace NCompress {
     9 namespace NLZMA {
    11 const int kLenIdFinished = -1;
    12 const int kLenIdNeedInit = -2;
    14 void CDecoder::Init()
    15 {
    16   { 
    17     for(int i = 0; i < kNumStates; i++)
    18     {
    19       for (UInt32 j = 0; j <= _posStateMask; j++)
    20       {
    21         _isMatch[i][j].Init();
    22         _isRep0Long[i][j].Init();
    23       }
    24       _isRep[i].Init();
    25       _isRepG0[i].Init();
    26       _isRepG1[i].Init();
    27       _isRepG2[i].Init();
    28     }
    29   }
    30   { 
    31     for (UInt32 i = 0; i < kNumLenToPosStates; i++)
    32     _posSlotDecoder[i].Init();
    33   }
    34   { 
    35     for(UInt32 i = 0; i < kNumFullDistances - kEndPosModelIndex; i++)
    36       _posDecoders[i].Init();
    37   }
    38   _posAlignDecoder.Init();
    39   _lenDecoder.Init(_posStateMask + 1);
    40   _repMatchLenDecoder.Init(_posStateMask + 1);
    41   _literalDecoder.Init();
    43   _state.Init();
    44   _reps[0] = _reps[1] = _reps[2] = _reps[3] = 0;
    45 }
    47 HRESULT CDecoder::CodeSpec(UInt32 curSize)
    48 {
    49   if (_outSizeDefined)
    50   {
    51     const UInt64 rem = _outSize - _outWindowStream.GetProcessedSize();
    52     if (curSize > rem)
    53       curSize = (UInt32)rem;
    54   }
    56   if (_remainLen == kLenIdFinished)
    57     return S_OK;
    58   if (_remainLen == kLenIdNeedInit)
    59   {
    60     _rangeDecoder.Init();
    61     Init();
    62     _remainLen = 0;
    63   }
    64   if (curSize == 0)
    65     return S_OK;
    67   UInt32 rep0 = _reps[0];
    68   UInt32 rep1 = _reps[1];
    69   UInt32 rep2 = _reps[2];
    70   UInt32 rep3 = _reps[3];
    71   CState state = _state;
    72   Byte previousByte;
    74   while(_remainLen > 0 && curSize > 0)
    75   {
    76     previousByte = _outWindowStream.GetByte(rep0);
    77     _outWindowStream.PutByte(previousByte);
    78     _remainLen--;
    79     curSize--;
    80   }
    81   UInt64 nowPos64 = _outWindowStream.GetProcessedSize();
    82   if (nowPos64 == 0)
    83     previousByte = 0;
    84   else
    85     previousByte = _outWindowStream.GetByte(0);
    87   while(curSize > 0)
    88   {
    89     {
    90       #ifdef _NO_EXCEPTIONS
    91       if (_rangeDecoder.Stream.ErrorCode != S_OK)
    92         return _rangeDecoder.Stream.ErrorCode;
    93       #endif
    94       if (_rangeDecoder.Stream.WasFinished())
    95         return S_FALSE;
    96       UInt32 posState = UInt32(nowPos64) & _posStateMask;
    97       if (_isMatch[state.Index][posState].Decode(&_rangeDecoder) == 0)
    98       {
    99         if(!state.IsCharState())
   100           previousByte = _literalDecoder.DecodeWithMatchByte(&_rangeDecoder, 
   101               (UInt32)nowPos64, previousByte, _outWindowStream.GetByte(rep0));
   102         else
   103           previousByte = _literalDecoder.DecodeNormal(&_rangeDecoder, 
   104               (UInt32)nowPos64, previousByte);
   105         _outWindowStream.PutByte(previousByte);
   106         state.UpdateChar();
   107         curSize--;
   108         nowPos64++;
   109       }
   110       else             
   111       {
   112         UInt32 len;
   113         if(_isRep[state.Index].Decode(&_rangeDecoder) == 1)
   114         {
   115           len = 0;
   116           if(_isRepG0[state.Index].Decode(&_rangeDecoder) == 0)
   117           {
   118             if(_isRep0Long[state.Index][posState].Decode(&_rangeDecoder) == 0)
   119             {
   120               state.UpdateShortRep();
   121               len = 1;
   122             }
   123           }
   124           else
   125           {
   126             UInt32 distance;
   127             if(_isRepG1[state.Index].Decode(&_rangeDecoder) == 0)
   128               distance = rep1;
   129             else 
   130             {
   131               if (_isRepG2[state.Index].Decode(&_rangeDecoder) == 0)
   132                 distance = rep2;
   133               else
   134               {
   135                 distance = rep3;
   136                 rep3 = rep2;
   137               }
   138               rep2 = rep1;
   139             }
   140             rep1 = rep0;
   141             rep0 = distance;
   142           }
   143           if (len == 0)
   144           {
   145             len = _repMatchLenDecoder.Decode(&_rangeDecoder, posState) + kMatchMinLen;
   146             state.UpdateRep();
   147           }
   148         }
   149         else
   150         {
   151           rep3 = rep2;
   152           rep2 = rep1;
   153           rep1 = rep0;
   154           len = kMatchMinLen + _lenDecoder.Decode(&_rangeDecoder, posState);
   155           state.UpdateMatch();
   156           UInt32 posSlot = _posSlotDecoder[GetLenToPosState(len)].Decode(&_rangeDecoder);
   157           if (posSlot >= kStartPosModelIndex)
   158           {
   159             UInt32 numDirectBits = (posSlot >> 1) - 1;
   160             rep0 = ((2 | (posSlot & 1)) << numDirectBits);
   162             if (posSlot < kEndPosModelIndex)
   163               rep0 += NRangeCoder::ReverseBitTreeDecode(_posDecoders + 
   164                   rep0 - posSlot - 1, &_rangeDecoder, numDirectBits);
   165             else
   166             {
   167               rep0 += (_rangeDecoder.DecodeDirectBits(
   168                   numDirectBits - kNumAlignBits) << kNumAlignBits);
   169               rep0 += _posAlignDecoder.ReverseDecode(&_rangeDecoder);
   170               if (rep0 == 0xFFFFFFFF)
   171               {
   172                 _remainLen = kLenIdFinished;
   173                 return S_OK;
   174               }
   175             }
   176           }
   177           else
   178             rep0 = posSlot;
   179         }
   180         UInt32 locLen = len;
   181         if (len > curSize)
   182           locLen = (UInt32)curSize;
   183         if (!_outWindowStream.CopyBlock(rep0, locLen))
   184           return S_FALSE;
   185         previousByte = _outWindowStream.GetByte(0);
   186         curSize -= locLen;
   187         nowPos64 += locLen;
   188         len -= locLen;
   189         if (len != 0)
   190         {
   191           _remainLen = (Int32)len;
   192           break;
   193         }
   195         #ifdef _NO_EXCEPTIONS
   196         if (_outWindowStream.ErrorCode != S_OK)
   197           return _outWindowStream.ErrorCode;
   198         #endif
   199       }
   200     }
   201   }
   202   if (_rangeDecoder.Stream.WasFinished())
   203     return S_FALSE;
   204   _reps[0] = rep0;
   205   _reps[1] = rep1;
   206   _reps[2] = rep2;
   207   _reps[3] = rep3;
   208   _state = state;
   210   return S_OK;
   211 }
   213 STDMETHODIMP CDecoder::CodeReal(ISequentialInStream *inStream,
   214     ISequentialOutStream *outStream, 
   215     const UInt64 *, const UInt64 *outSize,
   216     ICompressProgressInfo *progress)
   217 {
   218   SetInStream(inStream);
   219   _outWindowStream.SetStream(outStream);
   220   SetOutStreamSize(outSize);
   221   CDecoderFlusher flusher(this);
   223   while (true)
   224   {
   225     UInt32 curSize = 1 << 18;
   226     RINOK(CodeSpec(curSize));
   227     if (_remainLen == kLenIdFinished)
   228       break;
   229     if (progress != NULL)
   230     {
   231       UInt64 inSize = _rangeDecoder.GetProcessedSize();
   232       UInt64 nowPos64 = _outWindowStream.GetProcessedSize();
   233       RINOK(progress->SetRatioInfo(&inSize, &nowPos64));
   234     }
   235     if (_outSizeDefined)
   236       if (_outWindowStream.GetProcessedSize() >= _outSize)
   237         break;
   238   } 
   239   flusher.NeedFlush = false;
   240   return Flush();
   241 }
   244 #ifdef _NO_EXCEPTIONS
   246 #define LZMA_TRY_BEGIN
   247 #define LZMA_TRY_END
   249 #else
   251 #define LZMA_TRY_BEGIN try { 
   252 #define LZMA_TRY_END } \
   253   catch(const CInBufferException &e)  { return e.ErrorCode; } \
   254   catch(const CLZOutWindowException &e)  { return e.ErrorCode; } \
   255   catch(...) { return S_FALSE; }
   257 #endif
   260 STDMETHODIMP CDecoder::Code(ISequentialInStream *inStream,
   261       ISequentialOutStream *outStream, const UInt64 *inSize, const UInt64 *outSize,
   262       ICompressProgressInfo *progress)
   263 {
   264   LZMA_TRY_BEGIN
   265   return CodeReal(inStream, outStream, inSize, outSize, progress); 
   266   LZMA_TRY_END
   267 }
   269 STDMETHODIMP CDecoder::SetDecoderProperties2(const Byte *properties, UInt32 size)
   270 {
   271   if (size < 5)
   272     return E_INVALIDARG;
   273   int lc = properties[0] % 9;
   274   Byte remainder = (Byte)(properties[0] / 9);
   275   int lp = remainder % 5;
   276   int pb = remainder / 5;
   277   if (pb > NLength::kNumPosStatesBitsMax)
   278     return E_INVALIDARG;
   279   _posStateMask = (1 << pb) - 1;
   280   UInt32 dictionarySize = 0;
   281   for (int i = 0; i < 4; i++)
   282     dictionarySize += ((UInt32)(properties[1 + i])) << (i * 8);
   283   if (!_outWindowStream.Create(dictionarySize))
   284     return E_OUTOFMEMORY;
   285   if (!_literalDecoder.Create(lp, lc))
   286     return E_OUTOFMEMORY;
   287   if (!_rangeDecoder.Create(1 << 20))
   288     return E_OUTOFMEMORY;
   289   return S_OK;
   290 }
   292 STDMETHODIMP CDecoder::GetInStreamProcessedSize(UInt64 *value)
   293 {
   294   *value = _rangeDecoder.GetProcessedSize();
   295   return S_OK;
   296 }
   298 STDMETHODIMP CDecoder::SetInStream(ISequentialInStream *inStream)
   299 {
   300   _rangeDecoder.SetStream(inStream);
   301   return S_OK;
   302 }
   304 STDMETHODIMP CDecoder::ReleaseInStream()
   305 {
   306   _rangeDecoder.ReleaseStream();
   307   return S_OK;
   308 }
   310 STDMETHODIMP CDecoder::SetOutStreamSize(const UInt64 *outSize)
   311 {
   312   if (_outSizeDefined = (outSize != NULL))
   313     _outSize = *outSize;
   314   _remainLen = kLenIdNeedInit;
   315   _outWindowStream.Init();
   316   return S_OK;
   317 }
   319 #ifdef _ST_MODE
   321 STDMETHODIMP CDecoder::Read(void *data, UInt32 size, UInt32 *processedSize)
   322 {
   323   LZMA_TRY_BEGIN
   324   if (processedSize)
   325     *processedSize = 0;
   326   const UInt64 startPos = _outWindowStream.GetProcessedSize();
   327   _outWindowStream.SetMemStream((Byte *)data);
   328   RINOK(CodeSpec(size));
   329   if (processedSize)
   330     *processedSize = (UInt32)(_outWindowStream.GetProcessedSize() - startPos);
   331   return Flush();
   332   LZMA_TRY_END
   333 }
   335 #endif
   337 }}

mercurial