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