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