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 
ConvertFolderItemInfoToBindInfo(const CFolder & folder,CBindInfoEx & bindInfo)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 
AreCodersEqual(const NCoderMixer::CCoderStreamsInfo & a1,const NCoderMixer::CCoderStreamsInfo & a2)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 
AreBindPairsEqual(const NCoderMixer::CBindPair & a1,const NCoderMixer::CBindPair & a2)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 
AreBindInfoExEqual(const CBindInfoEx & a1,const CBindInfoEx & a2)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 
CDecoder(bool multiThread)84 CDecoder::CDecoder(bool multiThread)
85 {
86   #ifndef _ST_MODE
87   multiThread = true;
88   #endif
89   _multiThread = multiThread;
90   _bindInfoExPrevIsDefined = false;
91 }
92 
Decode(DECL_EXTERNAL_CODECS_LOC_VARS IInStream * inStream,UInt64 startPos,const CFolders & folders,int folderIndex,ISequentialOutStream * outStream,ICompressProgressInfo * compressProgress _7Z_DECODER_CRYPRO_VARS_DECL,bool mtMode,UInt32 numThreads)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