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