Upload 2.0.2
[physicsfs] / lzma / CPP / 7zip / Archive / 7z / 7zEncode.cpp
1 // Encode.cpp
2
3 #include "StdAfx.h"
4
5 #include "7zEncode.h"
6 #include "7zSpecStream.h"
7
8 #include "../../IPassword.h"
9 #include "../../Common/ProgressUtils.h"
10 #include "../../Common/LimitedStreams.h"
11 #include "../../Common/InOutTempBuffer.h"
12 #include "../../Common/StreamObjects.h"
13 #include "../../Common/CreateCoder.h"
14 #include "../../Common/FilterCoder.h"
15
16 static const UInt64 k_AES = 0x06F10701;
17 static const UInt64 k_BCJ  = 0x03030103;
18 static const UInt64 k_BCJ2 = 0x0303011B;
19
20 namespace NArchive {
21 namespace N7z {
22
23 static void ConvertBindInfoToFolderItemInfo(const NCoderMixer::CBindInfo &bindInfo,
24     const CRecordVector<CMethodId> decompressionMethods,
25     CFolder &folder)
26 {
27   folder.Coders.Clear();
28   // bindInfo.CoderMethodIDs.Clear();
29   // folder.OutStreams.Clear();
30   folder.PackStreams.Clear();
31   folder.BindPairs.Clear();
32   int i;
33   for (i = 0; i < bindInfo.BindPairs.Size(); i++)
34   {
35     CBindPair bindPair;
36     bindPair.InIndex = bindInfo.BindPairs[i].InIndex;
37     bindPair.OutIndex = bindInfo.BindPairs[i].OutIndex;
38     folder.BindPairs.Add(bindPair);
39   }
40   for (i = 0; i < bindInfo.Coders.Size(); i++)
41   {
42     CCoderInfo coderInfo;
43     const NCoderMixer::CCoderStreamsInfo &coderStreamsInfo = bindInfo.Coders[i];
44     coderInfo.NumInStreams = coderStreamsInfo.NumInStreams;
45     coderInfo.NumOutStreams = coderStreamsInfo.NumOutStreams;
46     coderInfo.MethodID = decompressionMethods[i];
47     folder.Coders.Add(coderInfo);
48   }
49   for (i = 0; i < bindInfo.InStreams.Size(); i++)
50     folder.PackStreams.Add(bindInfo.InStreams[i]);
51 }
52
53 HRESULT CEncoder::CreateMixerCoder(
54     DECL_EXTERNAL_CODECS_LOC_VARS
55     const UInt64 *inSizeForReduce)
56 {
57   _mixerCoderSpec = new NCoderMixer::CCoderMixer2MT;
58   _mixerCoder = _mixerCoderSpec;
59   RINOK(_mixerCoderSpec->SetBindInfo(_bindInfo));
60   for (int i = 0; i < _options.Methods.Size(); i++)
61   {
62     const CMethodFull &methodFull = _options.Methods[i];
63     _codersInfo.Add(CCoderInfo());
64     CCoderInfo &encodingInfo = _codersInfo.Back();
65     encodingInfo.MethodID = methodFull.Id;
66     CMyComPtr<ICompressCoder> encoder;
67     CMyComPtr<ICompressCoder2> encoder2;
68     
69
70     RINOK(CreateCoder(
71         EXTERNAL_CODECS_LOC_VARS
72         methodFull.Id, encoder, encoder2, true));
73
74     if (!encoder && !encoder2)
75       return E_FAIL;
76
77     CMyComPtr<IUnknown> encoderCommon = encoder ? (IUnknown *)encoder : (IUnknown *)encoder2;
78    
79     #ifdef COMPRESS_MT
80     {
81       CMyComPtr<ICompressSetCoderMt> setCoderMt;
82       encoderCommon.QueryInterface(IID_ICompressSetCoderMt, &setCoderMt);
83       if (setCoderMt)
84       {
85         RINOK(setCoderMt->SetNumberOfThreads(_options.NumThreads));
86       }
87     }
88     #endif
89         
90
91     RINOK(SetMethodProperties(methodFull, inSizeForReduce, encoderCommon));
92
93     /*
94     CMyComPtr<ICryptoResetSalt> resetSalt;
95     encoderCommon.QueryInterface(IID_ICryptoResetSalt, (void **)&resetSalt);
96     if (resetSalt != NULL)
97     {
98       resetSalt->ResetSalt();
99     }
100     */
101
102     #ifdef EXTERNAL_CODECS
103     CMyComPtr<ISetCompressCodecsInfo> setCompressCodecsInfo;
104     encoderCommon.QueryInterface(IID_ISetCompressCodecsInfo, (void **)&setCompressCodecsInfo);
105     if (setCompressCodecsInfo)
106     {
107       RINOK(setCompressCodecsInfo->SetCompressCodecsInfo(codecsInfo));
108     }
109     #endif
110     
111     CMyComPtr<ICryptoSetPassword> cryptoSetPassword;
112     encoderCommon.QueryInterface(IID_ICryptoSetPassword, &cryptoSetPassword);
113
114     if (cryptoSetPassword)
115     {
116       CByteBuffer buffer;
117       const UInt32 sizeInBytes = _options.Password.Length() * 2;
118       buffer.SetCapacity(sizeInBytes);
119       for (int i = 0; i < _options.Password.Length(); i++)
120       {
121         wchar_t c = _options.Password[i];
122         ((Byte *)buffer)[i * 2] = (Byte)c;
123         ((Byte *)buffer)[i * 2 + 1] = (Byte)(c >> 8);
124       }
125       RINOK(cryptoSetPassword->CryptoSetPassword((const Byte *)buffer, sizeInBytes));
126     }
127
128     if (encoder)
129       _mixerCoderSpec->AddCoder(encoder);
130     else
131       _mixerCoderSpec->AddCoder2(encoder2);
132   }
133   return S_OK;
134 }
135
136 HRESULT CEncoder::Encode(
137     DECL_EXTERNAL_CODECS_LOC_VARS
138     ISequentialInStream *inStream,
139     const UInt64 *inStreamSize, const UInt64 *inSizeForReduce,
140     CFolder &folderItem,
141     ISequentialOutStream *outStream,
142     CRecordVector<UInt64> &packSizes,
143     ICompressProgressInfo *compressProgress)
144 {
145   RINOK(EncoderConstr());
146
147   if (_mixerCoderSpec == NULL)
148   {
149     RINOK(CreateMixerCoder(EXTERNAL_CODECS_LOC_VARS inSizeForReduce));
150   }
151   _mixerCoderSpec->ReInit();
152   // _mixerCoderSpec->SetCoderInfo(0, NULL, NULL, progress);
153
154   CObjectVector<CInOutTempBuffer> inOutTempBuffers;
155   CObjectVector<CSequentialOutTempBufferImp *> tempBufferSpecs;
156   CObjectVector<CMyComPtr<ISequentialOutStream> > tempBuffers;
157   int numMethods = _bindInfo.Coders.Size();
158   int i;
159   for (i = 1; i < _bindInfo.OutStreams.Size(); i++)
160   {
161     inOutTempBuffers.Add(CInOutTempBuffer());
162     inOutTempBuffers.Back().Create();
163     inOutTempBuffers.Back().InitWriting();
164   }
165   for (i = 1; i < _bindInfo.OutStreams.Size(); i++)
166   {
167     CSequentialOutTempBufferImp *tempBufferSpec = 
168         new CSequentialOutTempBufferImp;
169     CMyComPtr<ISequentialOutStream> tempBuffer = tempBufferSpec;
170     tempBufferSpec->Init(&inOutTempBuffers[i - 1]);
171     tempBuffers.Add(tempBuffer);
172     tempBufferSpecs.Add(tempBufferSpec);
173   }
174
175   for (i = 0; i < numMethods; i++)
176     _mixerCoderSpec->SetCoderInfo(i, NULL, NULL);
177
178   if (_bindInfo.InStreams.IsEmpty())
179     return E_FAIL;
180   UInt32 mainCoderIndex, mainStreamIndex;
181   _bindInfo.FindInStream(_bindInfo.InStreams[0], mainCoderIndex, mainStreamIndex);
182   
183   if (inStreamSize != NULL)
184   {
185     CRecordVector<const UInt64 *> sizePointers;
186     for (UInt32 i = 0; i < _bindInfo.Coders[mainCoderIndex].NumInStreams; i++)
187       if (i == mainStreamIndex)
188         sizePointers.Add(inStreamSize);
189       else
190         sizePointers.Add(NULL);
191     _mixerCoderSpec->SetCoderInfo(mainCoderIndex, &sizePointers.Front(), NULL);
192   }
193
194   
195   // UInt64 outStreamStartPos;
196   // RINOK(stream->Seek(0, STREAM_SEEK_CUR, &outStreamStartPos));
197   
198   CSequentialInStreamSizeCount2 *inStreamSizeCountSpec = 
199       new CSequentialInStreamSizeCount2;
200   CMyComPtr<ISequentialInStream> inStreamSizeCount = inStreamSizeCountSpec;
201   CSequentialOutStreamSizeCount *outStreamSizeCountSpec = 
202       new CSequentialOutStreamSizeCount;
203   CMyComPtr<ISequentialOutStream> outStreamSizeCount = outStreamSizeCountSpec;
204
205   inStreamSizeCountSpec->Init(inStream);
206   outStreamSizeCountSpec->SetStream(outStream);
207   outStreamSizeCountSpec->Init();
208
209   CRecordVector<ISequentialInStream *> inStreamPointers;
210   CRecordVector<ISequentialOutStream *> outStreamPointers;
211   inStreamPointers.Add(inStreamSizeCount);
212   outStreamPointers.Add(outStreamSizeCount);
213   for (i = 1; i < _bindInfo.OutStreams.Size(); i++)
214     outStreamPointers.Add(tempBuffers[i - 1]);
215
216   for (i = 0; i < _codersInfo.Size(); i++)
217   {
218     CCoderInfo &encodingInfo = _codersInfo[i];
219     
220     CMyComPtr<ICryptoResetInitVector> resetInitVector;
221     _mixerCoderSpec->_coders[i].QueryInterface(IID_ICryptoResetInitVector, (void **)&resetInitVector);
222     if (resetInitVector != NULL)
223     {
224       resetInitVector->ResetInitVector();
225     }
226
227     CMyComPtr<ICompressWriteCoderProperties> writeCoderProperties;
228     _mixerCoderSpec->_coders[i].QueryInterface(IID_ICompressWriteCoderProperties, (void **)&writeCoderProperties);
229     if (writeCoderProperties != NULL)
230     {
231       CSequentialOutStreamImp *outStreamSpec = new CSequentialOutStreamImp;
232       CMyComPtr<ISequentialOutStream> outStream(outStreamSpec);
233       outStreamSpec->Init();
234       writeCoderProperties->WriteCoderProperties(outStream);
235       size_t size = outStreamSpec->GetSize();
236       encodingInfo.Properties.SetCapacity(size);
237       memmove(encodingInfo.Properties, outStreamSpec->GetBuffer(), size);
238     }
239   }
240
241   UInt32 progressIndex = mainCoderIndex;
242
243   for (i = 0; i < _codersInfo.Size(); i++)
244   {
245     const CCoderInfo &e = _codersInfo[i];
246     if ((e.MethodID == k_BCJ || e.MethodID == k_BCJ2) && i + 1 < _codersInfo.Size())
247       progressIndex = i + 1;
248   }
249
250   _mixerCoderSpec->SetProgressCoderIndex(progressIndex);
251   
252   RINOK(_mixerCoder->Code(&inStreamPointers.Front(), NULL, 1,
253     &outStreamPointers.Front(), NULL, outStreamPointers.Size(), compressProgress));
254   
255   ConvertBindInfoToFolderItemInfo(_decompressBindInfo, _decompressionMethods,
256       folderItem);
257   
258   packSizes.Add(outStreamSizeCountSpec->GetSize());
259   
260   for (i = 1; i < _bindInfo.OutStreams.Size(); i++)
261   {
262     CInOutTempBuffer &inOutTempBuffer = inOutTempBuffers[i - 1];
263     inOutTempBuffer.FlushWrite();
264     inOutTempBuffer.InitReading();
265     inOutTempBuffer.WriteToStream(outStream);
266     packSizes.Add(inOutTempBuffer.GetDataSize());
267   }
268   
269   for (i = 0; i < (int)_bindReverseConverter->NumSrcInStreams; i++)
270   {
271     int binder = _bindInfo.FindBinderForInStream(
272         _bindReverseConverter->DestOutToSrcInMap[i]);
273     UInt64 streamSize;
274     if (binder < 0)
275       streamSize = inStreamSizeCountSpec->GetSize();
276     else
277       streamSize = _mixerCoderSpec->GetWriteProcessedSize(binder);
278     folderItem.UnPackSizes.Add(streamSize);
279   }
280   for (i = numMethods - 1; i >= 0; i--)
281     folderItem.Coders[numMethods - 1 - i].Properties = _codersInfo[i].Properties;
282   return S_OK;
283 }
284
285
286 CEncoder::CEncoder(const CCompressionMethodMode &options):
287   _bindReverseConverter(0),
288   _constructed(false)
289 {
290   if (options.IsEmpty())
291     throw 1;
292
293   _options = options;
294   _mixerCoderSpec = NULL;
295 }
296
297 HRESULT CEncoder::EncoderConstr()
298 {
299   if (_constructed)
300     return S_OK;
301   if (_options.Methods.IsEmpty())
302   {
303     // it has only password method;
304     if (!_options.PasswordIsDefined)
305       throw 1;
306     if (!_options.Binds.IsEmpty())
307       throw 1;
308     NCoderMixer::CCoderStreamsInfo coderStreamsInfo;
309     CMethodFull method;
310     
311     method.NumInStreams = 1;
312     method.NumOutStreams = 1;
313     coderStreamsInfo.NumInStreams = 1;
314     coderStreamsInfo.NumOutStreams = 1;
315     method.Id = k_AES;
316     
317     _options.Methods.Add(method);
318     _bindInfo.Coders.Add(coderStreamsInfo);
319   
320     _bindInfo.InStreams.Add(0);
321     _bindInfo.OutStreams.Add(0);
322   }
323   else
324   {
325
326   UInt32 numInStreams = 0, numOutStreams = 0;
327   int i;
328   for (i = 0; i < _options.Methods.Size(); i++)
329   {
330     const CMethodFull &methodFull = _options.Methods[i];
331     NCoderMixer::CCoderStreamsInfo coderStreamsInfo;
332     coderStreamsInfo.NumInStreams = methodFull.NumOutStreams;
333     coderStreamsInfo.NumOutStreams = methodFull.NumInStreams;
334     if (_options.Binds.IsEmpty())
335     {
336       if (i < _options.Methods.Size() - 1)
337       {
338         NCoderMixer::CBindPair bindPair;
339         bindPair.InIndex = numInStreams + coderStreamsInfo.NumInStreams;
340         bindPair.OutIndex = numOutStreams;
341         _bindInfo.BindPairs.Add(bindPair);
342       }
343       else
344         _bindInfo.OutStreams.Insert(0, numOutStreams);
345       for (UInt32 j = 1; j < coderStreamsInfo.NumOutStreams; j++)
346         _bindInfo.OutStreams.Add(numOutStreams + j);
347     }
348     
349     numInStreams += coderStreamsInfo.NumInStreams;
350     numOutStreams += coderStreamsInfo.NumOutStreams;
351
352     _bindInfo.Coders.Add(coderStreamsInfo);
353   }
354
355   if (!_options.Binds.IsEmpty())
356   {
357     for (i = 0; i < _options.Binds.Size(); i++)
358     {
359       NCoderMixer::CBindPair bindPair;
360       const CBind &bind = _options.Binds[i];
361       bindPair.InIndex = _bindInfo.GetCoderInStreamIndex(bind.InCoder) + bind.InStream;
362       bindPair.OutIndex = _bindInfo.GetCoderOutStreamIndex(bind.OutCoder) + bind.OutStream;
363       _bindInfo.BindPairs.Add(bindPair);
364     }
365     for (i = 0; i < (int)numOutStreams; i++)
366       if (_bindInfo.FindBinderForOutStream(i) == -1)
367         _bindInfo.OutStreams.Add(i);
368   }
369
370   for (i = 0; i < (int)numInStreams; i++)
371     if (_bindInfo.FindBinderForInStream(i) == -1)
372       _bindInfo.InStreams.Add(i);
373
374   if (_bindInfo.InStreams.IsEmpty())
375     throw 1; // this is error
376
377   // Make main stream first in list
378   int inIndex = _bindInfo.InStreams[0];
379   for (;;)
380   {
381     UInt32 coderIndex, coderStreamIndex;
382     _bindInfo.FindInStream(inIndex, coderIndex, coderStreamIndex);
383     UInt32 outIndex = _bindInfo.GetCoderOutStreamIndex(coderIndex);
384     int binder = _bindInfo.FindBinderForOutStream(outIndex);
385     if (binder >= 0)
386     {
387       inIndex = _bindInfo.BindPairs[binder].InIndex;
388       continue;
389     }
390     for (i = 0; i < _bindInfo.OutStreams.Size(); i++)
391       if (_bindInfo.OutStreams[i] == outIndex)
392       {
393         _bindInfo.OutStreams.Delete(i);
394         _bindInfo.OutStreams.Insert(0, outIndex);
395         break;
396       }
397     break;
398   }
399
400   if (_options.PasswordIsDefined)
401   {
402     int numCryptoStreams = _bindInfo.OutStreams.Size();
403
404     for (i = 0; i < numCryptoStreams; i++)
405     {
406       NCoderMixer::CBindPair bindPair;
407       bindPair.InIndex = numInStreams + i;
408       bindPair.OutIndex = _bindInfo.OutStreams[i];
409       _bindInfo.BindPairs.Add(bindPair);
410     }
411     _bindInfo.OutStreams.Clear();
412
413     /*
414     if (numCryptoStreams == 0)
415       numCryptoStreams = 1;
416     */
417
418     for (i = 0; i < numCryptoStreams; i++)
419     {
420       NCoderMixer::CCoderStreamsInfo coderStreamsInfo;
421       CMethodFull method;
422       method.NumInStreams = 1;
423       method.NumOutStreams = 1;
424       coderStreamsInfo.NumInStreams = method.NumOutStreams;
425       coderStreamsInfo.NumOutStreams = method.NumInStreams;
426       method.Id = k_AES;
427
428       _options.Methods.Add(method);
429       _bindInfo.Coders.Add(coderStreamsInfo);
430       _bindInfo.OutStreams.Add(numOutStreams + i);
431     }
432   }
433
434   }
435
436   for (int i = _options.Methods.Size() - 1; i >= 0; i--)
437   {
438     const CMethodFull &methodFull = _options.Methods[i];
439     _decompressionMethods.Add(methodFull.Id);
440   }
441
442   _bindReverseConverter = new NCoderMixer::CBindReverseConverter(_bindInfo);
443   _bindReverseConverter->CreateReverseBindInfo(_decompressBindInfo);
444   _constructed = true;
445   return S_OK;
446 }
447
448 CEncoder::~CEncoder()
449 {
450   delete _bindReverseConverter;
451 }
452
453 }}