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