• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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   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 
AreCodersEqual(const NCoderMixer::CCoderStreamsInfo & a1,const NCoderMixer::CCoderStreamsInfo & a2)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 
AreBindPairsEqual(const NCoderMixer::CBindPair & a1,const NCoderMixer::CBindPair & a2)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 
AreBindInfoExEqual(const CBindInfoEx & a1,const CBindInfoEx & a2)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 
CDecoder(bool multiThread)80 CDecoder::CDecoder(bool multiThread)
81 {
82   #ifndef _ST_MODE
83   multiThread = true;
84   #endif
85   _multiThread = multiThread;
86   _bindInfoExPrevIsDefined = false;
87 }
88 
Decode(DECL_EXTERNAL_CODECS_LOC_VARS IInStream * inStream,UInt64 startPos,const UInt64 * packSizes,const CFolder & folderInfo,ISequentialOutStream * outStream,ICompressProgressInfo * compressProgress,ICryptoGetTextPassword * getTextPassword,bool & passwordIsDefined,bool mtMode,UInt32 numThreads)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