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