other-licenses/7zstub/src/7zip/Compress/Branch/x86_2.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 // x86_2.cpp
     3 #include "StdAfx.h"
     4 #include "x86_2.h"
     6 #include "../../../Common/Alloc.h"
     8 static const int kBufferSize = 1 << 17;
    10 inline bool IsJcc(Byte b0, Byte b1)
    11 {
    12   return (b0 == 0x0F && (b1 & 0xF0) == 0x80);
    13 }
    15 #ifndef EXTRACT_ONLY
    17 static bool inline Test86MSByte(Byte b)
    18 {
    19   return (b == 0 || b == 0xFF);
    20 }
    22 bool CBCJ2_x86_Encoder::Create()
    23 {
    24   if (!_mainStream.Create(1 << 16))
    25     return false;
    26   if (!_callStream.Create(1 << 20))
    27     return false;
    28   if (!_jumpStream.Create(1 << 20))
    29     return false;
    30   if (!_rangeEncoder.Create(1 << 20))
    31     return false;
    32   if (_buffer == 0)
    33   {
    34     _buffer = (Byte *)MidAlloc(kBufferSize);
    35     if (_buffer == 0)
    36       return false;
    37   }
    38   return true;
    39 }
    41 CBCJ2_x86_Encoder::~CBCJ2_x86_Encoder()
    42 {
    43   ::MidFree(_buffer);
    44 }
    46 HRESULT CBCJ2_x86_Encoder::Flush()
    47 {
    48   RINOK(_mainStream.Flush());
    49   RINOK(_callStream.Flush());
    50   RINOK(_jumpStream.Flush());
    51   _rangeEncoder.FlushData();
    52   return _rangeEncoder.FlushStream();
    53 }
    55 const UInt32 kDefaultLimit = (1 << 24);
    57 HRESULT CBCJ2_x86_Encoder::CodeReal(ISequentialInStream **inStreams,
    58       const UInt64 **inSizes,
    59       UInt32 numInStreams,
    60       ISequentialOutStream **outStreams,
    61       const UInt64 **outSizes,
    62       UInt32 numOutStreams,
    63       ICompressProgressInfo *progress)
    64 {
    65   if (numInStreams != 1 || numOutStreams != 4)
    66     return E_INVALIDARG;
    68   if (!Create())
    69     return E_OUTOFMEMORY;
    71   bool sizeIsDefined = false;
    72   UInt64 inSize;
    73   if (inSizes != NULL)
    74     if (inSizes[0] != NULL)
    75     {
    76       inSize = *inSizes[0];
    77       if (inSize <= kDefaultLimit)
    78         sizeIsDefined = true;
    79     }
    81   ISequentialInStream *inStream = inStreams[0];
    83   _mainStream.SetStream(outStreams[0]);
    84   _mainStream.Init();
    85   _callStream.SetStream(outStreams[1]);
    86   _callStream.Init();
    87   _jumpStream.SetStream(outStreams[2]);
    88   _jumpStream.Init();
    89   _rangeEncoder.SetStream(outStreams[3]);
    90   _rangeEncoder.Init();
    91   for (int i = 0; i < 256; i++)
    92     _statusE8Encoder[i].Init();
    93   _statusE9Encoder.Init();
    94   _statusJccEncoder.Init();
    95   CCoderReleaser releaser(this);
    97   CMyComPtr<ICompressGetSubStreamSize> getSubStreamSize;
    98   {
    99     inStream->QueryInterface(IID_ICompressGetSubStreamSize, (void **)&getSubStreamSize);
   100   }
   102   UInt32 nowPos = 0;
   103   UInt64 nowPos64 = 0;
   104   UInt32 bufferPos = 0;
   106   Byte prevByte = 0;
   108   UInt64 subStreamIndex = 0;
   109   UInt64 subStreamStartPos  = 0;
   110   UInt64 subStreamEndPos = 0;
   112   while(true)
   113   {
   114     UInt32 processedSize = 0;
   115     while(true)
   116     {
   117       UInt32 size = kBufferSize - (bufferPos + processedSize);
   118       UInt32 processedSizeLoc;
   119       if (size == 0)
   120         break;
   121       RINOK(inStream->Read(_buffer + bufferPos + processedSize, size, &processedSizeLoc));
   122       if (processedSizeLoc == 0)
   123         break;
   124       processedSize += processedSizeLoc;
   125     }
   126     UInt32 endPos = bufferPos + processedSize;
   128     if (endPos < 5)
   129     {
   130       // change it 
   131       for (bufferPos = 0; bufferPos < endPos; bufferPos++)
   132       {
   133         Byte b = _buffer[bufferPos];
   134         _mainStream.WriteByte(b);
   135         if (b == 0xE8)
   136           _statusE8Encoder[prevByte].Encode(&_rangeEncoder, 0);
   137         else if (b == 0xE9)
   138           _statusE9Encoder.Encode(&_rangeEncoder, 0);
   139         else if (IsJcc(prevByte, b))
   140           _statusJccEncoder.Encode(&_rangeEncoder, 0);
   141         prevByte = b;
   142       }
   143       return Flush();
   144     }
   146     bufferPos = 0;
   148     UInt32 limit = endPos - 5;
   149     while(bufferPos <= limit)
   150     {
   151       Byte b = _buffer[bufferPos];
   152       _mainStream.WriteByte(b);
   153       if (b != 0xE8 && b != 0xE9 && !IsJcc(prevByte, b))
   154       {
   155         bufferPos++;
   156         prevByte = b;
   157         continue;
   158       }
   159       Byte nextByte = _buffer[bufferPos + 4];
   160       UInt32 src = 
   161         (UInt32(nextByte) << 24) |
   162         (UInt32(_buffer[bufferPos + 3]) << 16) |
   163         (UInt32(_buffer[bufferPos + 2]) << 8) |
   164         (_buffer[bufferPos + 1]);
   165       UInt32 dest = (nowPos + bufferPos + 5) + src;
   166       // if (Test86MSByte(nextByte))
   167       bool convert;
   168       if (getSubStreamSize != NULL)
   169       {
   170         UInt64 currentPos = (nowPos64 + bufferPos);
   171         while (subStreamEndPos < currentPos)
   172         {
   173           UInt64 subStreamSize;
   174           HRESULT result = getSubStreamSize->GetSubStreamSize(subStreamIndex, &subStreamSize);
   175           if (result == S_OK)
   176           {
   177             subStreamStartPos = subStreamEndPos;
   178             subStreamEndPos += subStreamSize;          
   179             subStreamIndex++;
   180           }
   181           else if (result == S_FALSE || result == E_NOTIMPL)
   182           {
   183             getSubStreamSize.Release();
   184             subStreamStartPos = 0;
   185             subStreamEndPos = subStreamStartPos - 1;          
   186           }
   187           else
   188             return result;
   189         }
   190         if (getSubStreamSize == NULL)
   191         {
   192           if (sizeIsDefined)
   193             convert = (dest < inSize);
   194           else
   195             convert = Test86MSByte(nextByte);
   196         }
   197         else if (subStreamEndPos - subStreamStartPos > kDefaultLimit)
   198           convert = Test86MSByte(nextByte);
   199         else
   200         {
   201           UInt64 dest64 = (currentPos + 5) + Int64(Int32(src));
   202           convert = (dest64 >= subStreamStartPos && dest64 < subStreamEndPos);
   203         }
   204       }
   205       else if (sizeIsDefined)
   206         convert = (dest < inSize);
   207       else
   208         convert = Test86MSByte(nextByte);
   209       if (convert)
   210       {
   211         if (b == 0xE8)
   212           _statusE8Encoder[prevByte].Encode(&_rangeEncoder, 1);
   213         else if (b == 0xE9)
   214           _statusE9Encoder.Encode(&_rangeEncoder, 1);
   215         else 
   216           _statusJccEncoder.Encode(&_rangeEncoder, 1);
   218         bufferPos += 5;
   219         if (b == 0xE8)
   220         {
   221           _callStream.WriteByte((Byte)(dest >> 24));
   222           _callStream.WriteByte((Byte)(dest >> 16));
   223           _callStream.WriteByte((Byte)(dest >> 8));
   224           _callStream.WriteByte((Byte)(dest));
   225         }
   226         else 
   227         {
   228           _jumpStream.WriteByte((Byte)(dest >> 24));
   229           _jumpStream.WriteByte((Byte)(dest >> 16));
   230           _jumpStream.WriteByte((Byte)(dest >> 8));
   231           _jumpStream.WriteByte((Byte)(dest));
   232         }
   233         prevByte = nextByte;
   234       }
   235       else
   236       {
   237         if (b == 0xE8)
   238           _statusE8Encoder[prevByte].Encode(&_rangeEncoder, 0);
   239         else if (b == 0xE9)
   240           _statusE9Encoder.Encode(&_rangeEncoder, 0);
   241         else
   242           _statusJccEncoder.Encode(&_rangeEncoder, 0);
   243         bufferPos++;
   244         prevByte = b;
   245       }
   246     }
   247     nowPos += bufferPos;
   248     nowPos64 += bufferPos;
   250     if (progress != NULL)
   251     {
   252       RINOK(progress->SetRatioInfo(&nowPos64, NULL));
   253     }
   255     UInt32 i = 0;
   256     while(bufferPos < endPos)
   257       _buffer[i++] = _buffer[bufferPos++];
   258     bufferPos = i;
   259   }
   260 }
   262 STDMETHODIMP CBCJ2_x86_Encoder::Code(ISequentialInStream **inStreams,
   263       const UInt64 **inSizes,
   264       UInt32 numInStreams,
   265       ISequentialOutStream **outStreams,
   266       const UInt64 **outSizes,
   267       UInt32 numOutStreams,
   268       ICompressProgressInfo *progress)
   269 {
   270   try
   271   {
   272     return CodeReal(inStreams, inSizes, numInStreams,
   273       outStreams, outSizes,numOutStreams, progress);
   274   }
   275   catch(const COutBufferException &e) { return e.ErrorCode; }
   276   catch(...) { return S_FALSE; }
   277 }
   279 #endif
   281 HRESULT CBCJ2_x86_Decoder::CodeReal(ISequentialInStream **inStreams,
   282       const UInt64 **inSizes,
   283       UInt32 numInStreams,
   284       ISequentialOutStream **outStreams,
   285       const UInt64 **outSizes,
   286       UInt32 numOutStreams,
   287       ICompressProgressInfo *progress)
   288 {
   289   if (numInStreams != 4 || numOutStreams != 1)
   290     return E_INVALIDARG;
   292   if (!_mainInStream.Create(1 << 16))
   293     return E_OUTOFMEMORY;
   294   if (!_callStream.Create(1 << 20))
   295     return E_OUTOFMEMORY;
   296   if (!_jumpStream.Create(1 << 16))
   297     return E_OUTOFMEMORY;
   298   if (!_rangeDecoder.Create(1 << 20))
   299     return E_OUTOFMEMORY;
   300   if (!_outStream.Create(1 << 16))
   301     return E_OUTOFMEMORY;
   303   _mainInStream.SetStream(inStreams[0]);
   304   _callStream.SetStream(inStreams[1]);
   305   _jumpStream.SetStream(inStreams[2]);
   306   _rangeDecoder.SetStream(inStreams[3]);
   307   _outStream.SetStream(outStreams[0]);
   309   _mainInStream.Init();
   310   _callStream.Init();
   311   _jumpStream.Init();
   312   _rangeDecoder.Init();
   313   _outStream.Init();
   315   for (int i = 0; i < 256; i++)
   316     _statusE8Decoder[i].Init();
   317   _statusE9Decoder.Init();
   318   _statusJccDecoder.Init();
   320   CCoderReleaser releaser(this);
   322   Byte prevByte = 0;
   323   UInt32 processedBytes = 0;
   324   while(true)
   325   {
   326     if (processedBytes > (1 << 20) && progress != NULL)
   327     {
   328       UInt64 nowPos64 = _outStream.GetProcessedSize();
   329       RINOK(progress->SetRatioInfo(NULL, &nowPos64));
   330       processedBytes = 0;
   331     }
   332     processedBytes++;
   333     Byte b;
   334     if (!_mainInStream.ReadByte(b))
   335       return Flush();
   336     _outStream.WriteByte(b);
   337     if (b != 0xE8 && b != 0xE9 && !IsJcc(prevByte, b))
   338     {
   339       prevByte = b;
   340       continue;
   341     }
   342     bool status;
   343     if (b == 0xE8)
   344       status = (_statusE8Decoder[prevByte].Decode(&_rangeDecoder) == 1);
   345     else if (b == 0xE9)
   346       status = (_statusE9Decoder.Decode(&_rangeDecoder) == 1);
   347     else
   348       status = (_statusJccDecoder.Decode(&_rangeDecoder) == 1);
   349     if (status)
   350     {
   351       UInt32 src;
   352       if (b == 0xE8)
   353       {
   354         Byte b0;
   355         if(!_callStream.ReadByte(b0))
   356           return S_FALSE;
   357         src = ((UInt32)b0) << 24;
   358         if(!_callStream.ReadByte(b0))
   359           return S_FALSE;
   360         src |= ((UInt32)b0) << 16;
   361         if(!_callStream.ReadByte(b0))
   362           return S_FALSE;
   363         src |= ((UInt32)b0) << 8;
   364         if(!_callStream.ReadByte(b0))
   365           return S_FALSE;
   366         src |= ((UInt32)b0);
   367       }
   368       else
   369       {
   370         Byte b0;
   371         if(!_jumpStream.ReadByte(b0))
   372           return S_FALSE;
   373         src = ((UInt32)b0) << 24;
   374         if(!_jumpStream.ReadByte(b0))
   375           return S_FALSE;
   376         src |= ((UInt32)b0) << 16;
   377         if(!_jumpStream.ReadByte(b0))
   378           return S_FALSE;
   379         src |= ((UInt32)b0) << 8;
   380         if(!_jumpStream.ReadByte(b0))
   381           return S_FALSE;
   382         src |= ((UInt32)b0);
   383       }
   384       UInt32 dest = src - (UInt32(_outStream.GetProcessedSize()) + 4) ;
   385       _outStream.WriteByte((Byte)(dest));
   386       _outStream.WriteByte((Byte)(dest >> 8));
   387       _outStream.WriteByte((Byte)(dest >> 16));
   388       _outStream.WriteByte((Byte)(dest >> 24));
   389       prevByte = (dest >> 24);
   390       processedBytes += 4;
   391     }
   392     else
   393       prevByte = b;
   394   }
   395 }
   397 STDMETHODIMP CBCJ2_x86_Decoder::Code(ISequentialInStream **inStreams,
   398       const UInt64 **inSizes,
   399       UInt32 numInStreams,
   400       ISequentialOutStream **outStreams,
   401       const UInt64 **outSizes,
   402       UInt32 numOutStreams,
   403       ICompressProgressInfo *progress)
   404 {
   405   try
   406   {
   407     return CodeReal(inStreams, inSizes, numInStreams,
   408         outStreams, outSizes,numOutStreams, progress);
   409   }
   410   catch(const COutBufferException &e) { return e.ErrorCode; }
   411   catch(...) { return S_FALSE; }
   412 }

mercurial