other-licenses/7zstub/src/7zip/Archive/7z/7zDecode.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 // 7zDecode.cpp
     3 #include "StdAfx.h"
     5 #include "7zDecode.h"
     7 #include "../../IPassword.h"
     8 #include "../../Common/LockedStream.h"
     9 #include "../../Common/StreamObjects.h"
    10 #include "../../Common/ProgressUtils.h"
    11 #include "../../Common/LimitedStreams.h"
    12 #include "../Common/FilterCoder.h"
    14 #include "7zMethods.h"
    16 #ifdef COMPRESS_LZMA
    17 #include "../../Compress/LZMA/LZMADecoder.h"
    18 static NArchive::N7z::CMethodID k_LZMA = { { 0x3, 0x1, 0x1 }, 3 };
    19 #endif
    21 #ifdef COMPRESS_PPMD
    22 #include "../../Compress/PPMD/PPMDDecoder.h"
    23 static NArchive::N7z::CMethodID k_PPMD = { { 0x3, 0x4, 0x1 }, 3 };
    24 #endif
    26 #ifdef COMPRESS_BCJ_X86
    27 #include "../../Compress/Branch/x86.h"
    28 static NArchive::N7z::CMethodID k_BCJ_X86 = { { 0x3, 0x3, 0x1, 0x3 }, 4 };
    29 #endif
    31 #ifdef COMPRESS_BCJ2
    32 #include "../../Compress/Branch/x86_2.h"
    33 static NArchive::N7z::CMethodID k_BCJ2 = { { 0x3, 0x3, 0x1, 0x1B }, 4 };
    34 #endif
    36 #ifdef COMPRESS_DEFLATE
    37 #ifndef COMPRESS_DEFLATE_DECODER
    38 #define COMPRESS_DEFLATE_DECODER
    39 #endif
    40 #endif
    42 #ifdef COMPRESS_DEFLATE_DECODER
    43 #include "../../Compress/Deflate/DeflateDecoder.h"
    44 static NArchive::N7z::CMethodID k_Deflate = { { 0x4, 0x1, 0x8 }, 3 };
    45 #endif
    47 #ifdef COMPRESS_BZIP2
    48 #ifndef COMPRESS_BZIP2_DECODER
    49 #define COMPRESS_BZIP2_DECODER
    50 #endif
    51 #endif
    53 #ifdef COMPRESS_BZIP2_DECODER
    54 #include "../../Compress/BZip2/BZip2Decoder.h"
    55 static NArchive::N7z::CMethodID k_BZip2 = { { 0x4, 0x2, 0x2 }, 3 };
    56 #endif
    58 #ifdef COMPRESS_COPY
    59 #include "../../Compress/Copy/CopyCoder.h"
    60 static NArchive::N7z::CMethodID k_Copy = { { 0x0 }, 1 };
    61 #endif
    63 #ifdef CRYPTO_7ZAES
    64 #include "../../Crypto/7zAES/7zAES.h"
    65 static NArchive::N7z::CMethodID k_7zAES = { { 0x6, 0xF1, 0x07, 0x01 }, 4 };
    66 #endif
    68 namespace NArchive {
    69 namespace N7z {
    71 static void ConvertFolderItemInfoToBindInfo(const CFolder &folder,
    72     CBindInfoEx &bindInfo)
    73 {
    74   bindInfo.Clear();
    75   int i;
    76   for (i = 0; i < folder.BindPairs.Size(); i++)
    77   {
    78     NCoderMixer2::CBindPair bindPair;
    79     bindPair.InIndex = (UInt32)folder.BindPairs[i].InIndex;
    80     bindPair.OutIndex = (UInt32)folder.BindPairs[i].OutIndex;
    81     bindInfo.BindPairs.Add(bindPair);
    82   }
    83   UInt32 outStreamIndex = 0;
    84   for (i = 0; i < folder.Coders.Size(); i++)
    85   {
    86     NCoderMixer2::CCoderStreamsInfo coderStreamsInfo;
    87     const CCoderInfo &coderInfo = folder.Coders[i];
    88     coderStreamsInfo.NumInStreams = (UInt32)coderInfo.NumInStreams;
    89     coderStreamsInfo.NumOutStreams = (UInt32)coderInfo.NumOutStreams;
    90     bindInfo.Coders.Add(coderStreamsInfo);
    91     const CAltCoderInfo &altCoderInfo = coderInfo.AltCoders.Front();
    92     bindInfo.CoderMethodIDs.Add(altCoderInfo.MethodID);
    93     for (UInt32 j = 0; j < coderStreamsInfo.NumOutStreams; j++, outStreamIndex++)
    94       if (folder.FindBindPairForOutStream(outStreamIndex) < 0)
    95         bindInfo.OutStreams.Add(outStreamIndex);
    96   }
    97   for (i = 0; i < folder.PackStreams.Size(); i++)
    98     bindInfo.InStreams.Add((UInt32)folder.PackStreams[i]);
    99 }
   101 static bool AreCodersEqual(const NCoderMixer2::CCoderStreamsInfo &a1, 
   102     const NCoderMixer2::CCoderStreamsInfo &a2)
   103 {
   104   return (a1.NumInStreams == a2.NumInStreams) &&
   105     (a1.NumOutStreams == a2.NumOutStreams);
   106 }
   108 static bool AreBindPairsEqual(const NCoderMixer2::CBindPair &a1, const NCoderMixer2::CBindPair &a2)
   109 {
   110   return (a1.InIndex == a2.InIndex) &&
   111     (a1.OutIndex == a2.OutIndex);
   112 }
   114 static bool AreBindInfoExEqual(const CBindInfoEx &a1, const CBindInfoEx &a2)
   115 {
   116   if (a1.Coders.Size() != a2.Coders.Size())
   117     return false;
   118   int i;
   119   for (i = 0; i < a1.Coders.Size(); i++)
   120     if (!AreCodersEqual(a1.Coders[i], a2.Coders[i]))
   121       return false;
   122   if (a1.BindPairs.Size() != a2.BindPairs.Size())
   123     return false;
   124   for (i = 0; i < a1.BindPairs.Size(); i++)
   125     if (!AreBindPairsEqual(a1.BindPairs[i], a2.BindPairs[i]))
   126       return false;
   127   for (i = 0; i < a1.CoderMethodIDs.Size(); i++)
   128     if (a1.CoderMethodIDs[i] != a2.CoderMethodIDs[i])
   129       return false;
   130   if (a1.InStreams.Size() != a2.InStreams.Size())
   131     return false;
   132   if (a1.OutStreams.Size() != a2.OutStreams.Size())
   133     return false;
   134   return true;
   135 }
   137 CDecoder::CDecoder(bool multiThread)
   138 {
   139   #ifndef _ST_MODE
   140   multiThread = true;
   141   #endif
   142   _multiThread = multiThread;
   143   _bindInfoExPrevIsDefinded = false;
   144   #ifndef EXCLUDE_COM
   145   LoadMethodMap();
   146   #endif
   147 }
   149 HRESULT CDecoder::Decode(IInStream *inStream,
   150     UInt64 startPos,
   151     const UInt64 *packSizes,
   152     const CFolder &folderInfo, 
   153     ISequentialOutStream *outStream,
   154     ICompressProgressInfo *compressProgress
   155     #ifndef _NO_CRYPTO
   156     , ICryptoGetTextPassword *getTextPassword
   157     #endif
   158     #ifdef COMPRESS_MT
   159     , bool mtMode, UInt32 numThreads
   160     #endif
   161     )
   162 {
   163   CObjectVector< CMyComPtr<ISequentialInStream> > inStreams;
   165   CLockedInStream lockedInStream;
   166   lockedInStream.Init(inStream);
   168   for (int j = 0; j < folderInfo.PackStreams.Size(); j++)
   169   {
   170     CLockedSequentialInStreamImp *lockedStreamImpSpec = new 
   171         CLockedSequentialInStreamImp;
   172     CMyComPtr<ISequentialInStream> lockedStreamImp = lockedStreamImpSpec;
   173     lockedStreamImpSpec->Init(&lockedInStream, startPos);
   174     startPos += packSizes[j];
   176     CLimitedSequentialInStream *streamSpec = new 
   177         CLimitedSequentialInStream;
   178     CMyComPtr<ISequentialInStream> inStream = streamSpec;
   179     streamSpec->Init(lockedStreamImp, packSizes[j]);
   180     inStreams.Add(inStream);
   181   }
   183   int numCoders = folderInfo.Coders.Size();
   185   CBindInfoEx bindInfo;
   186   ConvertFolderItemInfoToBindInfo(folderInfo, bindInfo);
   187   bool createNewCoders;
   188   if (!_bindInfoExPrevIsDefinded)
   189     createNewCoders = true;
   190   else
   191     createNewCoders = !AreBindInfoExEqual(bindInfo, _bindInfoExPrev);
   192   if (createNewCoders)
   193   {
   194     int i;
   195     _decoders.Clear();
   196     // _decoders2.Clear();
   198     _mixerCoder.Release();
   200     if (_multiThread)
   201     {
   202       _mixerCoderMTSpec = new NCoderMixer2::CCoderMixer2MT;
   203       _mixerCoder = _mixerCoderMTSpec;
   204       _mixerCoderCommon = _mixerCoderMTSpec;
   205     }
   206     else
   207     {
   208       #ifdef _ST_MODE
   209       _mixerCoderSTSpec = new NCoderMixer2::CCoderMixer2ST;
   210       _mixerCoder = _mixerCoderSTSpec;
   211       _mixerCoderCommon = _mixerCoderSTSpec;
   212       #endif
   213     }
   214     _mixerCoderCommon->SetBindInfo(bindInfo);
   216     for (i = 0; i < numCoders; i++)
   217     {
   218       const CCoderInfo &coderInfo = folderInfo.Coders[i];
   219       const CAltCoderInfo &altCoderInfo = coderInfo.AltCoders.Front();
   220       #ifndef EXCLUDE_COM
   221       CMethodInfo methodInfo;
   222       if (!GetMethodInfo(altCoderInfo.MethodID, methodInfo)) 
   223         return E_NOTIMPL;
   224       #endif
   226       if (coderInfo.IsSimpleCoder())
   227       {
   228         CMyComPtr<ICompressCoder> decoder;
   229         CMyComPtr<ICompressFilter> filter;
   231         #ifdef COMPRESS_LZMA
   232         if (altCoderInfo.MethodID == k_LZMA)
   233           decoder = new NCompress::NLZMA::CDecoder;
   234         #endif
   236         #ifdef COMPRESS_PPMD
   237         if (altCoderInfo.MethodID == k_PPMD)
   238           decoder = new NCompress::NPPMD::CDecoder;
   239         #endif
   241         #ifdef COMPRESS_BCJ_X86
   242         if (altCoderInfo.MethodID == k_BCJ_X86)
   243           filter = new CBCJ_x86_Decoder;
   244         #endif
   246         #ifdef COMPRESS_DEFLATE_DECODER
   247         if (altCoderInfo.MethodID == k_Deflate)
   248           decoder = new NCompress::NDeflate::NDecoder::CCOMCoder;
   249         #endif
   251         #ifdef COMPRESS_BZIP2_DECODER
   252         if (altCoderInfo.MethodID == k_BZip2)
   253           decoder = new NCompress::NBZip2::CDecoder;
   254         #endif
   256         #ifdef COMPRESS_COPY
   257         if (altCoderInfo.MethodID == k_Copy)
   258           decoder = new NCompress::CCopyCoder;
   259         #endif
   261         #ifdef CRYPTO_7ZAES
   262         if (altCoderInfo.MethodID == k_7zAES)
   263           filter = new NCrypto::NSevenZ::CDecoder;
   264         #endif
   266         if (filter)
   267         {
   268           CFilterCoder *coderSpec = new CFilterCoder;
   269           decoder = coderSpec;
   270           coderSpec->Filter = filter;
   271         }
   272         #ifndef EXCLUDE_COM
   273         if (decoder == 0)
   274         {
   275           RINOK(_libraries.CreateCoderSpec(methodInfo.FilePath, 
   276               methodInfo.Decoder, &decoder));
   277         }
   278         #endif
   280         if (decoder == 0)
   281           return E_NOTIMPL;
   283         _decoders.Add((IUnknown *)decoder);
   285         if (_multiThread)
   286           _mixerCoderMTSpec->AddCoder(decoder);
   287         #ifdef _ST_MODE
   288         else
   289           _mixerCoderSTSpec->AddCoder(decoder, false);
   290         #endif
   291       }
   292       else
   293       {
   294         CMyComPtr<ICompressCoder2> decoder;
   296         #ifdef COMPRESS_BCJ2
   297         if (altCoderInfo.MethodID == k_BCJ2)
   298           decoder = new CBCJ2_x86_Decoder;
   299         #endif
   301         #ifndef EXCLUDE_COM
   302         if (decoder == 0)
   303         {
   304           RINOK(_libraries.CreateCoder2(methodInfo.FilePath, 
   305               methodInfo.Decoder, &decoder));
   306         }
   307         #endif
   309         if (decoder == 0)
   310           return E_NOTIMPL;
   312         _decoders.Add((IUnknown *)decoder);
   313         if (_multiThread)
   314           _mixerCoderMTSpec->AddCoder2(decoder);
   315         #ifdef _ST_MODE
   316         else
   317           _mixerCoderSTSpec->AddCoder2(decoder, false);
   318         #endif
   319       }
   320     }
   321     _bindInfoExPrev = bindInfo;
   322     _bindInfoExPrevIsDefinded = true;
   323   }
   324   int i;
   325   _mixerCoderCommon->ReInit();
   327   UInt32 packStreamIndex = 0, unPackStreamIndex = 0;
   328   UInt32 coderIndex = 0;
   329   // UInt32 coder2Index = 0;
   331   for (i = 0; i < numCoders; i++)
   332   {
   333     const CCoderInfo &coderInfo = folderInfo.Coders[i];
   334     const CAltCoderInfo &altCoderInfo = coderInfo.AltCoders.Front();
   335     CMyComPtr<IUnknown> &decoder = _decoders[coderIndex];
   337     {
   338       CMyComPtr<ICompressSetDecoderProperties2> setDecoderProperties;
   339       HRESULT result = decoder.QueryInterface(IID_ICompressSetDecoderProperties2, &setDecoderProperties);
   340       if (setDecoderProperties)
   341       {
   342         const CByteBuffer &properties = altCoderInfo.Properties;
   343         size_t size = properties.GetCapacity();
   344         if (size > 0xFFFFFFFF)
   345           return E_NOTIMPL;
   346         if (size > 0)
   347         {
   348           RINOK(setDecoderProperties->SetDecoderProperties2((const Byte *)properties, (UInt32)size));
   349         }
   350       }
   351     }
   353     #ifdef COMPRESS_MT
   354     if (mtMode)
   355     {
   356       CMyComPtr<ICompressSetCoderMt> setCoderMt;
   357       decoder.QueryInterface(IID_ICompressSetCoderMt, &setCoderMt);
   358       if (setCoderMt)
   359       {
   360         RINOK(setCoderMt->SetNumberOfThreads(numThreads));
   361       }
   362     }
   363     #endif
   365     #ifndef _NO_CRYPTO
   366     {
   367       CMyComPtr<ICryptoSetPassword> cryptoSetPassword;
   368       HRESULT result = decoder.QueryInterface(IID_ICryptoSetPassword, &cryptoSetPassword);
   369       if (cryptoSetPassword)
   370       {
   371         if (getTextPassword == 0)
   372           return E_FAIL;
   373         CMyComBSTR password;
   374         RINOK(getTextPassword->CryptoGetTextPassword(&password));
   375         CByteBuffer buffer;
   376         UString unicodePassword(password);
   377         const UInt32 sizeInBytes = unicodePassword.Length() * 2;
   378         buffer.SetCapacity(sizeInBytes);
   379         for (int i = 0; i < unicodePassword.Length(); i++)
   380         {
   381           wchar_t c = unicodePassword[i];
   382           ((Byte *)buffer)[i * 2] = (Byte)c;
   383           ((Byte *)buffer)[i * 2 + 1] = (Byte)(c >> 8);
   384         }
   385         RINOK(cryptoSetPassword->CryptoSetPassword(
   386           (const Byte *)buffer, sizeInBytes));
   387       }
   388     }
   389     #endif
   391     coderIndex++;
   393     UInt32 numInStreams = (UInt32)coderInfo.NumInStreams;
   394     UInt32 numOutStreams = (UInt32)coderInfo.NumOutStreams;
   395     CRecordVector<const UInt64 *> packSizesPointers;
   396     CRecordVector<const UInt64 *> unPackSizesPointers;
   397     packSizesPointers.Reserve(numInStreams);
   398     unPackSizesPointers.Reserve(numOutStreams);
   399     UInt32 j;
   400     for (j = 0; j < numOutStreams; j++, unPackStreamIndex++)
   401       unPackSizesPointers.Add(&folderInfo.UnPackSizes[unPackStreamIndex]);
   403     for (j = 0; j < numInStreams; j++, packStreamIndex++)
   404     {
   405       int bindPairIndex = folderInfo.FindBindPairForInStream(packStreamIndex);
   406       if (bindPairIndex >= 0)
   407         packSizesPointers.Add(
   408         &folderInfo.UnPackSizes[(UInt32)folderInfo.BindPairs[bindPairIndex].OutIndex]);
   409       else
   410       {
   411         int index = folderInfo.FindPackStreamArrayIndex(packStreamIndex);
   412         if (index < 0)
   413           return E_FAIL;
   414         packSizesPointers.Add(&packSizes[index]);
   415       }
   416     }
   418     _mixerCoderCommon->SetCoderInfo(i, 
   419         &packSizesPointers.Front(), 
   420         &unPackSizesPointers.Front());
   421   }
   422   UInt32 mainCoder, temp;
   423   bindInfo.FindOutStream(bindInfo.OutStreams[0], mainCoder, temp);
   425   if (_multiThread)
   426     _mixerCoderMTSpec->SetProgressCoderIndex(mainCoder);
   427   /*
   428   else
   429     _mixerCoderSTSpec->SetProgressCoderIndex(mainCoder);;
   430   */
   432   if (numCoders == 0)
   433     return 0;
   434   CRecordVector<ISequentialInStream *> inStreamPointers;
   435   inStreamPointers.Reserve(inStreams.Size());
   436   for (i = 0; i < inStreams.Size(); i++)
   437     inStreamPointers.Add(inStreams[i]);
   438   ISequentialOutStream *outStreamPointer = outStream;
   439   return _mixerCoder->Code(&inStreamPointers.Front(), NULL, 
   440     inStreams.Size(), &outStreamPointer, NULL, 1, compressProgress);
   441 }
   443 }}

mercurial