misc/libphysfs/lzma/CPP/7zip/Archive/7z/7zDecode.cpp
changeset 13904 99b265e0d1d0
parent 13903 5f819b90d479
child 13905 b172a5d40eee
equal deleted inserted replaced
13903:5f819b90d479 13904:99b265e0d1d0
     1 // 7zDecode.cpp
       
     2 
       
     3 #include "StdAfx.h"
       
     4 
       
     5 #include "7zDecode.h"
       
     6 
       
     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/CreateCoder.h"
       
    13 #include "../../Common/FilterCoder.h"
       
    14 
       
    15 namespace NArchive {
       
    16 namespace N7z {
       
    17 
       
    18 static void ConvertFolderItemInfoToBindInfo(const CFolder &folder,
       
    19     CBindInfoEx &bindInfo)
       
    20 {
       
    21   bindInfo.Clear();
       
    22   int i;
       
    23   for (i = 0; i < folder.BindPairs.Size(); i++)
       
    24   {
       
    25     NCoderMixer::CBindPair bindPair;
       
    26     bindPair.InIndex = (UInt32)folder.BindPairs[i].InIndex;
       
    27     bindPair.OutIndex = (UInt32)folder.BindPairs[i].OutIndex;
       
    28     bindInfo.BindPairs.Add(bindPair);
       
    29   }
       
    30   UInt32 outStreamIndex = 0;
       
    31   for (i = 0; i < folder.Coders.Size(); i++)
       
    32   {
       
    33     NCoderMixer::CCoderStreamsInfo coderStreamsInfo;
       
    34     const CCoderInfo &coderInfo = folder.Coders[i];
       
    35     coderStreamsInfo.NumInStreams = (UInt32)coderInfo.NumInStreams;
       
    36     coderStreamsInfo.NumOutStreams = (UInt32)coderInfo.NumOutStreams;
       
    37     bindInfo.Coders.Add(coderStreamsInfo);
       
    38     bindInfo.CoderMethodIDs.Add(coderInfo.MethodID);
       
    39     for (UInt32 j = 0; j < coderStreamsInfo.NumOutStreams; j++, outStreamIndex++)
       
    40       if (folder.FindBindPairForOutStream(outStreamIndex) < 0)
       
    41         bindInfo.OutStreams.Add(outStreamIndex);
       
    42   }
       
    43   for (i = 0; i < folder.PackStreams.Size(); i++)
       
    44     bindInfo.InStreams.Add((UInt32)folder.PackStreams[i]);
       
    45 }
       
    46 
       
    47 static bool AreCodersEqual(const NCoderMixer::CCoderStreamsInfo &a1, 
       
    48     const NCoderMixer::CCoderStreamsInfo &a2)
       
    49 {
       
    50   return (a1.NumInStreams == a2.NumInStreams) &&
       
    51     (a1.NumOutStreams == a2.NumOutStreams);
       
    52 }
       
    53 
       
    54 static bool AreBindPairsEqual(const NCoderMixer::CBindPair &a1, const NCoderMixer::CBindPair &a2)
       
    55 {
       
    56   return (a1.InIndex == a2.InIndex) &&
       
    57     (a1.OutIndex == a2.OutIndex);
       
    58 }
       
    59 
       
    60 static bool AreBindInfoExEqual(const CBindInfoEx &a1, const CBindInfoEx &a2)
       
    61 {
       
    62   if (a1.Coders.Size() != a2.Coders.Size())
       
    63     return false;
       
    64   int i;
       
    65   for (i = 0; i < a1.Coders.Size(); i++)
       
    66     if (!AreCodersEqual(a1.Coders[i], a2.Coders[i]))
       
    67       return false;
       
    68   if (a1.BindPairs.Size() != a2.BindPairs.Size())
       
    69     return false;
       
    70   for (i = 0; i < a1.BindPairs.Size(); i++)
       
    71     if (!AreBindPairsEqual(a1.BindPairs[i], a2.BindPairs[i]))
       
    72       return false;
       
    73   for (i = 0; i < a1.CoderMethodIDs.Size(); i++)
       
    74     if (a1.CoderMethodIDs[i] != a2.CoderMethodIDs[i])
       
    75       return false;
       
    76   if (a1.InStreams.Size() != a2.InStreams.Size())
       
    77     return false;
       
    78   if (a1.OutStreams.Size() != a2.OutStreams.Size())
       
    79     return false;
       
    80   return true;
       
    81 }
       
    82 
       
    83 CDecoder::CDecoder(bool multiThread)
       
    84 {
       
    85   #ifndef _ST_MODE
       
    86   multiThread = true;
       
    87   #endif
       
    88   _multiThread = multiThread;
       
    89   _bindInfoExPrevIsDefined = false;
       
    90 }
       
    91 
       
    92 HRESULT CDecoder::Decode(
       
    93     DECL_EXTERNAL_CODECS_LOC_VARS
       
    94     IInStream *inStream,
       
    95     UInt64 startPos,
       
    96     const UInt64 *packSizes,
       
    97     const CFolder &folderInfo, 
       
    98     ISequentialOutStream *outStream,
       
    99     ICompressProgressInfo *compressProgress
       
   100     #ifndef _NO_CRYPTO
       
   101     , ICryptoGetTextPassword *getTextPassword
       
   102     #endif
       
   103     #ifdef COMPRESS_MT
       
   104     , bool mtMode, UInt32 numThreads
       
   105     #endif
       
   106     )
       
   107 {
       
   108   CObjectVector< CMyComPtr<ISequentialInStream> > inStreams;
       
   109   
       
   110   CLockedInStream lockedInStream;
       
   111   lockedInStream.Init(inStream);
       
   112   
       
   113   for (int j = 0; j < folderInfo.PackStreams.Size(); j++)
       
   114   {
       
   115     CLockedSequentialInStreamImp *lockedStreamImpSpec = new 
       
   116         CLockedSequentialInStreamImp;
       
   117     CMyComPtr<ISequentialInStream> lockedStreamImp = lockedStreamImpSpec;
       
   118     lockedStreamImpSpec->Init(&lockedInStream, startPos);
       
   119     startPos += packSizes[j];
       
   120     
       
   121     CLimitedSequentialInStream *streamSpec = new 
       
   122         CLimitedSequentialInStream;
       
   123     CMyComPtr<ISequentialInStream> inStream = streamSpec;
       
   124     streamSpec->SetStream(lockedStreamImp);
       
   125     streamSpec->Init(packSizes[j]);
       
   126     inStreams.Add(inStream);
       
   127   }
       
   128   
       
   129   int numCoders = folderInfo.Coders.Size();
       
   130   
       
   131   CBindInfoEx bindInfo;
       
   132   ConvertFolderItemInfoToBindInfo(folderInfo, bindInfo);
       
   133   bool createNewCoders;
       
   134   if (!_bindInfoExPrevIsDefined)
       
   135     createNewCoders = true;
       
   136   else
       
   137     createNewCoders = !AreBindInfoExEqual(bindInfo, _bindInfoExPrev);
       
   138   if (createNewCoders)
       
   139   {
       
   140     int i;
       
   141     _decoders.Clear();
       
   142     // _decoders2.Clear();
       
   143     
       
   144     _mixerCoder.Release();
       
   145 
       
   146     if (_multiThread)
       
   147     {
       
   148       _mixerCoderMTSpec = new NCoderMixer::CCoderMixer2MT;
       
   149       _mixerCoder = _mixerCoderMTSpec;
       
   150       _mixerCoderCommon = _mixerCoderMTSpec;
       
   151     }
       
   152     else
       
   153     {
       
   154       #ifdef _ST_MODE
       
   155       _mixerCoderSTSpec = new NCoderMixer::CCoderMixer2ST;
       
   156       _mixerCoder = _mixerCoderSTSpec;
       
   157       _mixerCoderCommon = _mixerCoderSTSpec;
       
   158       #endif
       
   159     }
       
   160     RINOK(_mixerCoderCommon->SetBindInfo(bindInfo));
       
   161     
       
   162     for (i = 0; i < numCoders; i++)
       
   163     {
       
   164       const CCoderInfo &coderInfo = folderInfo.Coders[i];
       
   165 
       
   166   
       
   167       CMyComPtr<ICompressCoder> decoder;
       
   168       CMyComPtr<ICompressCoder2> decoder2;
       
   169       RINOK(CreateCoder(
       
   170           EXTERNAL_CODECS_LOC_VARS
       
   171           coderInfo.MethodID, decoder, decoder2, false));
       
   172       CMyComPtr<IUnknown> decoderUnknown;
       
   173       if (coderInfo.IsSimpleCoder())
       
   174       {
       
   175         if (decoder == 0)
       
   176           return E_NOTIMPL;
       
   177 
       
   178         decoderUnknown = (IUnknown *)decoder;
       
   179         
       
   180         if (_multiThread)
       
   181           _mixerCoderMTSpec->AddCoder(decoder);
       
   182         #ifdef _ST_MODE
       
   183         else
       
   184           _mixerCoderSTSpec->AddCoder(decoder, false);
       
   185         #endif
       
   186       }
       
   187       else
       
   188       {
       
   189         if (decoder2 == 0)
       
   190           return E_NOTIMPL;
       
   191         decoderUnknown = (IUnknown *)decoder2;
       
   192         if (_multiThread)
       
   193           _mixerCoderMTSpec->AddCoder2(decoder2);
       
   194         #ifdef _ST_MODE
       
   195         else
       
   196           _mixerCoderSTSpec->AddCoder2(decoder2, false);
       
   197         #endif
       
   198       }
       
   199       _decoders.Add(decoderUnknown);
       
   200       #ifdef EXTERNAL_CODECS
       
   201       CMyComPtr<ISetCompressCodecsInfo> setCompressCodecsInfo;
       
   202       decoderUnknown.QueryInterface(IID_ISetCompressCodecsInfo, (void **)&setCompressCodecsInfo);
       
   203       if (setCompressCodecsInfo)
       
   204       {
       
   205         RINOK(setCompressCodecsInfo->SetCompressCodecsInfo(codecsInfo));
       
   206       }
       
   207       #endif
       
   208     }
       
   209     _bindInfoExPrev = bindInfo;
       
   210     _bindInfoExPrevIsDefined = true;
       
   211   }
       
   212   int i;
       
   213   _mixerCoderCommon->ReInit();
       
   214   
       
   215   UInt32 packStreamIndex = 0, unPackStreamIndex = 0;
       
   216   UInt32 coderIndex = 0;
       
   217   // UInt32 coder2Index = 0;
       
   218   
       
   219   for (i = 0; i < numCoders; i++)
       
   220   {
       
   221     const CCoderInfo &coderInfo = folderInfo.Coders[i];
       
   222     CMyComPtr<IUnknown> &decoder = _decoders[coderIndex];
       
   223     
       
   224     {
       
   225       CMyComPtr<ICompressSetDecoderProperties2> setDecoderProperties;
       
   226       decoder.QueryInterface(IID_ICompressSetDecoderProperties2, &setDecoderProperties);
       
   227       if (setDecoderProperties)
       
   228       {
       
   229         const CByteBuffer &properties = coderInfo.Properties;
       
   230         size_t size = properties.GetCapacity();
       
   231         if (size > 0xFFFFFFFF)
       
   232           return E_NOTIMPL;
       
   233         if (size > 0)
       
   234         {
       
   235           RINOK(setDecoderProperties->SetDecoderProperties2((const Byte *)properties, (UInt32)size));
       
   236         }
       
   237       }
       
   238     }
       
   239 
       
   240     #ifdef COMPRESS_MT
       
   241     if (mtMode)
       
   242     {
       
   243       CMyComPtr<ICompressSetCoderMt> setCoderMt;
       
   244       decoder.QueryInterface(IID_ICompressSetCoderMt, &setCoderMt);
       
   245       if (setCoderMt)
       
   246       {
       
   247         RINOK(setCoderMt->SetNumberOfThreads(numThreads));
       
   248       }
       
   249     }
       
   250     #endif
       
   251 
       
   252     #ifndef _NO_CRYPTO
       
   253     {
       
   254       CMyComPtr<ICryptoSetPassword> cryptoSetPassword;
       
   255       decoder.QueryInterface(IID_ICryptoSetPassword, &cryptoSetPassword);
       
   256       if (cryptoSetPassword)
       
   257       {
       
   258         if (getTextPassword == 0)
       
   259           return E_FAIL;
       
   260         CMyComBSTR password;
       
   261         RINOK(getTextPassword->CryptoGetTextPassword(&password));
       
   262         CByteBuffer buffer;
       
   263         UString unicodePassword(password);
       
   264         const UInt32 sizeInBytes = unicodePassword.Length() * 2;
       
   265         buffer.SetCapacity(sizeInBytes);
       
   266         for (int i = 0; i < unicodePassword.Length(); i++)
       
   267         {
       
   268           wchar_t c = unicodePassword[i];
       
   269           ((Byte *)buffer)[i * 2] = (Byte)c;
       
   270           ((Byte *)buffer)[i * 2 + 1] = (Byte)(c >> 8);
       
   271         }
       
   272         RINOK(cryptoSetPassword->CryptoSetPassword(
       
   273           (const Byte *)buffer, sizeInBytes));
       
   274       }
       
   275     }
       
   276     #endif
       
   277 
       
   278     coderIndex++;
       
   279     
       
   280     UInt32 numInStreams = (UInt32)coderInfo.NumInStreams;
       
   281     UInt32 numOutStreams = (UInt32)coderInfo.NumOutStreams;
       
   282     CRecordVector<const UInt64 *> packSizesPointers;
       
   283     CRecordVector<const UInt64 *> unPackSizesPointers;
       
   284     packSizesPointers.Reserve(numInStreams);
       
   285     unPackSizesPointers.Reserve(numOutStreams);
       
   286     UInt32 j;
       
   287     for (j = 0; j < numOutStreams; j++, unPackStreamIndex++)
       
   288       unPackSizesPointers.Add(&folderInfo.UnPackSizes[unPackStreamIndex]);
       
   289     
       
   290     for (j = 0; j < numInStreams; j++, packStreamIndex++)
       
   291     {
       
   292       int bindPairIndex = folderInfo.FindBindPairForInStream(packStreamIndex);
       
   293       if (bindPairIndex >= 0)
       
   294         packSizesPointers.Add(
       
   295         &folderInfo.UnPackSizes[(UInt32)folderInfo.BindPairs[bindPairIndex].OutIndex]);
       
   296       else
       
   297       {
       
   298         int index = folderInfo.FindPackStreamArrayIndex(packStreamIndex);
       
   299         if (index < 0)
       
   300           return E_FAIL;
       
   301         packSizesPointers.Add(&packSizes[index]);
       
   302       }
       
   303     }
       
   304     
       
   305     _mixerCoderCommon->SetCoderInfo(i, 
       
   306         &packSizesPointers.Front(), 
       
   307         &unPackSizesPointers.Front());
       
   308   }
       
   309   UInt32 mainCoder, temp;
       
   310   bindInfo.FindOutStream(bindInfo.OutStreams[0], mainCoder, temp);
       
   311 
       
   312   if (_multiThread)
       
   313     _mixerCoderMTSpec->SetProgressCoderIndex(mainCoder);
       
   314   /*
       
   315   else
       
   316     _mixerCoderSTSpec->SetProgressCoderIndex(mainCoder);;
       
   317   */
       
   318   
       
   319   if (numCoders == 0)
       
   320     return 0;
       
   321   CRecordVector<ISequentialInStream *> inStreamPointers;
       
   322   inStreamPointers.Reserve(inStreams.Size());
       
   323   for (i = 0; i < inStreams.Size(); i++)
       
   324     inStreamPointers.Add(inStreams[i]);
       
   325   ISequentialOutStream *outStreamPointer = outStream;
       
   326   return _mixerCoder->Code(&inStreamPointers.Front(), NULL, 
       
   327     inStreams.Size(), &outStreamPointer, NULL, 1, compressProgress);
       
   328 }
       
   329 
       
   330 }}