1 // 7zEncode.cpp
2 
3 #include "StdAfx.h"
4 
5 #include "../../Common/CreateCoder.h"
6 #include "../../Common/FilterCoder.h"
7 #include "../../Common/LimitedStreams.h"
8 #include "../../Common/InOutTempBuffer.h"
9 #include "../../Common/ProgressUtils.h"
10 #include "../../Common/StreamObjects.h"
11 
12 #include "7zEncode.h"
13 #include "7zSpecStream.h"
14 
15 namespace NArchive {
16 namespace N7z {
17 
InitBindConv()18 void CEncoder::InitBindConv()
19 {
20   unsigned numIn = _bindInfo.Coders.Size();
21 
22   _SrcIn_to_DestOut.ClearAndSetSize(numIn);
23   _DestOut_to_SrcIn.ClearAndSetSize(numIn);
24 
25   unsigned numOut = _bindInfo.GetNum_Bonds_and_PackStreams();
26   _SrcOut_to_DestIn.ClearAndSetSize(numOut);
27   // _DestIn_to_SrcOut.ClearAndSetSize(numOut);
28 
29   UInt32 destIn = 0;
30   UInt32 destOut = 0;
31 
32   for (unsigned i = _bindInfo.Coders.Size(); i != 0;)
33   {
34     i--;
35 
36     const NCoderMixer2::CCoderStreamsInfo &coder = _bindInfo.Coders[i];
37 
38     numIn--;
39     numOut -= coder.NumStreams;
40 
41     _SrcIn_to_DestOut[numIn] = destOut;
42     _DestOut_to_SrcIn[destOut] = numIn;
43 
44     destOut++;
45 
46     for (UInt32 j = 0; j < coder.NumStreams; j++, destIn++)
47     {
48       UInt32 index = numOut + j;
49       _SrcOut_to_DestIn[index] = destIn;
50       // _DestIn_to_SrcOut[destIn] = index;
51     }
52   }
53 }
54 
SetFolder(CFolder & folder)55 void CEncoder::SetFolder(CFolder &folder)
56 {
57   folder.Bonds.SetSize(_bindInfo.Bonds.Size());
58 
59   unsigned i;
60 
61   for (i = 0; i < _bindInfo.Bonds.Size(); i++)
62   {
63     CBond &fb = folder.Bonds[i];
64     const NCoderMixer2::CBond &mixerBond = _bindInfo.Bonds[_bindInfo.Bonds.Size() - 1 - i];
65     fb.PackIndex = _SrcOut_to_DestIn[mixerBond.PackIndex];
66     fb.UnpackIndex = _SrcIn_to_DestOut[mixerBond.UnpackIndex];
67   }
68 
69   folder.Coders.SetSize(_bindInfo.Coders.Size());
70 
71   for (i = 0; i < _bindInfo.Coders.Size(); i++)
72   {
73     CCoderInfo &coderInfo = folder.Coders[i];
74     const NCoderMixer2::CCoderStreamsInfo &coderStreamsInfo = _bindInfo.Coders[_bindInfo.Coders.Size() - 1 - i];
75 
76     coderInfo.NumStreams = coderStreamsInfo.NumStreams;
77     coderInfo.MethodID = _decompressionMethods[i];
78     // we don't free coderInfo.Props here. So coderInfo.Props can be non-empty.
79   }
80 
81   folder.PackStreams.SetSize(_bindInfo.PackStreams.Size());
82 
83   for (i = 0; i < _bindInfo.PackStreams.Size(); i++)
84     folder.PackStreams[i] = _SrcOut_to_DestIn[_bindInfo.PackStreams[i]];
85 }
86 
87 
88 
SetCoderProps2(const CProps & props,const UInt64 * dataSizeReduce,IUnknown * coder)89 static HRESULT SetCoderProps2(const CProps &props, const UInt64 *dataSizeReduce, IUnknown *coder)
90 {
91   CMyComPtr<ICompressSetCoderProperties> setCoderProperties;
92   coder->QueryInterface(IID_ICompressSetCoderProperties, (void **)&setCoderProperties);
93   if (setCoderProperties)
94     return props.SetCoderProps(setCoderProperties, dataSizeReduce);
95   return props.AreThereNonOptionalProps() ? E_INVALIDARG : S_OK;
96 }
97 
98 
99 
Init(ICompressProgressInfo * progress)100 void CMtEncMultiProgress::Init(ICompressProgressInfo *progress)
101 {
102   _progress = progress;
103   OutSize = 0;
104 }
105 
SetRatioInfo(const UInt64 * inSize,const UInt64 *)106 STDMETHODIMP CMtEncMultiProgress::SetRatioInfo(const UInt64 *inSize, const UInt64 * /* outSize */)
107 {
108   UInt64 outSize2;
109   {
110     #ifndef _7ZIP_ST
111     NWindows::NSynchronization::CCriticalSectionLock lock(CriticalSection);
112     #endif
113     outSize2 = OutSize;
114   }
115 
116   if (_progress)
117     return _progress->SetRatioInfo(inSize, &outSize2);
118 
119   return S_OK;
120 }
121 
122 
123 
CreateMixerCoder(DECL_EXTERNAL_CODECS_LOC_VARS const UInt64 * inSizeForReduce)124 HRESULT CEncoder::CreateMixerCoder(
125     DECL_EXTERNAL_CODECS_LOC_VARS
126     const UInt64 *inSizeForReduce)
127 {
128   #ifdef USE_MIXER_MT
129   #ifdef USE_MIXER_ST
130   if (_options.MultiThreadMixer)
131   #endif
132   {
133     _mixerMT = new NCoderMixer2::CMixerMT(true);
134     _mixerRef = _mixerMT;
135     _mixer = _mixerMT;
136   }
137   #ifdef USE_MIXER_ST
138   else
139   #endif
140   #endif
141   {
142     #ifdef USE_MIXER_ST
143     _mixerST = new NCoderMixer2::CMixerST(true);
144     _mixerRef = _mixerST;
145     _mixer = _mixerST;
146     #endif
147   }
148 
149   RINOK(_mixer->SetBindInfo(_bindInfo));
150 
151   FOR_VECTOR (m, _options.Methods)
152   {
153     const CMethodFull &methodFull = _options.Methods[m];
154 
155     CCreatedCoder cod;
156 
157     if (methodFull.CodecIndex >= 0)
158     {
159       RINOK(CreateCoder_Index(
160         EXTERNAL_CODECS_LOC_VARS
161         (unsigned)methodFull.CodecIndex, true, cod));
162     }
163     else
164     {
165       RINOK(CreateCoder_Id(
166         EXTERNAL_CODECS_LOC_VARS
167         methodFull.Id, true, cod));
168     }
169 
170     if (cod.NumStreams != methodFull.NumStreams)
171       return E_FAIL;
172     if (!cod.Coder && !cod.Coder2)
173       return E_FAIL;
174 
175     CMyComPtr<IUnknown> encoderCommon = cod.Coder ? (IUnknown *)cod.Coder : (IUnknown *)cod.Coder2;
176 
177     #ifndef _7ZIP_ST
178     if (methodFull.Set_NumThreads)
179     {
180       CMyComPtr<ICompressSetCoderMt> setCoderMt;
181       encoderCommon.QueryInterface(IID_ICompressSetCoderMt, &setCoderMt);
182       if (setCoderMt)
183       {
184         RINOK(setCoderMt->SetNumberOfThreads(
185             /* _options.NumThreads */
186             methodFull.NumThreads
187             ));
188       }
189     }
190     #endif
191 
192     RINOK(SetCoderProps2(methodFull, inSizeForReduce, encoderCommon));
193 
194     /*
195     CMyComPtr<ICryptoResetSalt> resetSalt;
196     encoderCommon.QueryInterface(IID_ICryptoResetSalt, (void **)&resetSalt);
197     if (resetSalt)
198     {
199       resetSalt->ResetSalt();
200     }
201     */
202 
203     // now there is no codec that uses another external codec
204     /*
205     #ifdef EXTERNAL_CODECS
206     CMyComPtr<ISetCompressCodecsInfo> setCompressCodecsInfo;
207     encoderCommon.QueryInterface(IID_ISetCompressCodecsInfo, (void **)&setCompressCodecsInfo);
208     if (setCompressCodecsInfo)
209     {
210       // we must use g_ExternalCodecs also
211       RINOK(setCompressCodecsInfo->SetCompressCodecsInfo(__externalCodecs->GetCodecs));
212     }
213     #endif
214     */
215 
216     CMyComPtr<ICryptoSetPassword> cryptoSetPassword;
217     encoderCommon.QueryInterface(IID_ICryptoSetPassword, &cryptoSetPassword);
218 
219     if (cryptoSetPassword)
220     {
221       const unsigned sizeInBytes = _options.Password.Len() * 2;
222       CByteBuffer_Wipe buffer(sizeInBytes);
223       for (unsigned i = 0; i < _options.Password.Len(); i++)
224       {
225         wchar_t c = _options.Password[i];
226         ((Byte *)buffer)[i * 2] = (Byte)c;
227         ((Byte *)buffer)[i * 2 + 1] = (Byte)(c >> 8);
228       }
229       RINOK(cryptoSetPassword->CryptoSetPassword((const Byte *)buffer, (UInt32)sizeInBytes));
230     }
231 
232     _mixer->AddCoder(cod);
233   }
234   return S_OK;
235 }
236 
237 
238 
239 class CSequentialOutTempBufferImp2:
240   public ISequentialOutStream,
241   public CMyUnknownImp
242 {
243   CInOutTempBuffer *_buf;
244 public:
245   CMtEncMultiProgress *_mtProgresSpec;
246 
CSequentialOutTempBufferImp2()247   CSequentialOutTempBufferImp2(): _buf(0), _mtProgresSpec(NULL) {}
Init(CInOutTempBuffer * buffer)248   void Init(CInOutTempBuffer *buffer) { _buf = buffer; }
249   MY_UNKNOWN_IMP1(ISequentialOutStream)
250 
251   STDMETHOD(Write)(const void *data, UInt32 size, UInt32 *processedSize);
252 };
253 
Write(const void * data,UInt32 size,UInt32 * processed)254 STDMETHODIMP CSequentialOutTempBufferImp2::Write(const void *data, UInt32 size, UInt32 *processed)
255 {
256   HRESULT res  = _buf->Write_HRESULT(data, size);
257   if (res != S_OK)
258   {
259     if (processed)
260       *processed = 0;
261     return res;
262   }
263   if (processed)
264     *processed = size;
265   if (_mtProgresSpec)
266     _mtProgresSpec->AddOutSize(size);
267   return S_OK;
268 }
269 
270 
271 class CSequentialOutMtNotify:
272   public ISequentialOutStream,
273   public CMyUnknownImp
274 {
275 public:
276   CMyComPtr<ISequentialOutStream> _stream;
277   CMtEncMultiProgress *_mtProgresSpec;
278 
CSequentialOutMtNotify()279   CSequentialOutMtNotify(): _mtProgresSpec(NULL) {}
280   MY_UNKNOWN_IMP1(ISequentialOutStream)
281 
282   STDMETHOD(Write)(const void *data, UInt32 size, UInt32 *processedSize);
283 };
284 
Write(const void * data,UInt32 size,UInt32 * processed)285 STDMETHODIMP CSequentialOutMtNotify::Write(const void *data, UInt32 size, UInt32 *processed)
286 {
287   UInt32 realProcessed = 0;
288   HRESULT res = _stream->Write(data, size, &realProcessed);
289   if (processed)
290     *processed = realProcessed;
291   if (_mtProgresSpec)
292     _mtProgresSpec->AddOutSize(size);
293   return res;
294 }
295 
296 
297 
Encode(DECL_EXTERNAL_CODECS_LOC_VARS ISequentialInStream * inStream,const UInt64 * inSizeForReduce,CFolder & folderItem,CRecordVector<UInt64> & coderUnpackSizes,UInt64 & unpackSize,ISequentialOutStream * outStream,CRecordVector<UInt64> & packSizes,ICompressProgressInfo * compressProgress)298 HRESULT CEncoder::Encode(
299     DECL_EXTERNAL_CODECS_LOC_VARS
300     ISequentialInStream *inStream,
301     // const UInt64 *inStreamSize,
302     const UInt64 *inSizeForReduce,
303     CFolder &folderItem,
304     CRecordVector<UInt64> &coderUnpackSizes,
305     UInt64 &unpackSize,
306     ISequentialOutStream *outStream,
307     CRecordVector<UInt64> &packSizes,
308     ICompressProgressInfo *compressProgress)
309 {
310   RINOK(EncoderConstr());
311 
312   if (!_mixerRef)
313   {
314     RINOK(CreateMixerCoder(EXTERNAL_CODECS_LOC_VARS inSizeForReduce));
315   }
316 
317   RINOK(_mixer->ReInit2());
318 
319   CMtEncMultiProgress *mtProgressSpec = NULL;
320   CMyComPtr<ICompressProgressInfo> mtProgress;
321 
322   CSequentialOutMtNotify *mtOutStreamNotifySpec = NULL;
323   CMyComPtr<ISequentialOutStream> mtOutStreamNotify;
324 
325   CObjectVector<CInOutTempBuffer> inOutTempBuffers;
326   CObjectVector<CSequentialOutTempBufferImp2 *> tempBufferSpecs;
327   CObjectVector<CMyComPtr<ISequentialOutStream> > tempBuffers;
328 
329   unsigned numMethods = _bindInfo.Coders.Size();
330 
331   unsigned i;
332 
333   for (i = 1; i < _bindInfo.PackStreams.Size(); i++)
334   {
335     CInOutTempBuffer &iotb = inOutTempBuffers.AddNew();
336     iotb.Create();
337     iotb.InitWriting();
338   }
339 
340   for (i = 1; i < _bindInfo.PackStreams.Size(); i++)
341   {
342     CSequentialOutTempBufferImp2 *tempBufferSpec = new CSequentialOutTempBufferImp2;
343     CMyComPtr<ISequentialOutStream> tempBuffer = tempBufferSpec;
344     tempBufferSpec->Init(&inOutTempBuffers[i - 1]);
345     tempBuffers.Add(tempBuffer);
346     tempBufferSpecs.Add(tempBufferSpec);
347   }
348 
349   for (i = 0; i < numMethods; i++)
350     _mixer->SetCoderInfo(i, NULL, NULL, false);
351 
352 
353   /* inStreamSize can be used by BCJ2 to set optimal range of conversion.
354      But current BCJ2 encoder uses also another way to check exact size of current file.
355      So inStreamSize is not required. */
356 
357   /*
358   if (inStreamSize)
359     _mixer->SetCoderInfo(_bindInfo.UnpackCoder, inStreamSize, NULL);
360   */
361 
362 
363   CSequentialInStreamSizeCount2 *inStreamSizeCountSpec = new CSequentialInStreamSizeCount2;
364   CMyComPtr<ISequentialInStream> inStreamSizeCount = inStreamSizeCountSpec;
365 
366   CSequentialOutStreamSizeCount *outStreamSizeCountSpec = NULL;
367   CMyComPtr<ISequentialOutStream> outStreamSizeCount;
368 
369   inStreamSizeCountSpec->Init(inStream);
370 
371   ISequentialInStream *inStreamPointer = inStreamSizeCount;
372   CRecordVector<ISequentialOutStream *> outStreamPointers;
373 
374   SetFolder(folderItem);
375 
376   for (i = 0; i < numMethods; i++)
377   {
378     IUnknown *coder = _mixer->GetCoder(i).GetUnknown();
379 
380     CMyComPtr<ICryptoResetInitVector> resetInitVector;
381     coder->QueryInterface(IID_ICryptoResetInitVector, (void **)&resetInitVector);
382     if (resetInitVector)
383     {
384       resetInitVector->ResetInitVector();
385     }
386 
387     {
388       CMyComPtr<ICompressSetCoderPropertiesOpt> optProps;
389       coder->QueryInterface(IID_ICompressSetCoderPropertiesOpt, (void **)&optProps);
390       if (optProps)
391       {
392         PROPID propID = NCoderPropID::kExpectedDataSize;
393         NWindows::NCOM::CPropVariant prop = (UInt64)unpackSize;
394         RINOK(optProps->SetCoderPropertiesOpt(&propID, &prop, 1));
395       }
396     }
397 
398     CMyComPtr<ICompressWriteCoderProperties> writeCoderProperties;
399     coder->QueryInterface(IID_ICompressWriteCoderProperties, (void **)&writeCoderProperties);
400 
401     CByteBuffer &props = folderItem.Coders[numMethods - 1 - i].Props;
402 
403     if (writeCoderProperties)
404     {
405       CDynBufSeqOutStream *outStreamSpec = new CDynBufSeqOutStream;
406       CMyComPtr<ISequentialOutStream> dynOutStream(outStreamSpec);
407       outStreamSpec->Init();
408       RINOK(writeCoderProperties->WriteCoderProperties(dynOutStream));
409       outStreamSpec->CopyToBuffer(props);
410     }
411     else
412       props.Free();
413   }
414 
415   _mixer->SelectMainCoder(false);
416   UInt32 mainCoder = _mixer->MainCoderIndex;
417 
418   bool useMtProgress = false;
419   if (!_mixer->Is_PackSize_Correct_for_Coder(mainCoder))
420   {
421     #ifdef _7ZIP_ST
422     if (!_mixer->IsThere_ExternalCoder_in_PackTree(mainCoder))
423     #endif
424       useMtProgress = true;
425   }
426 
427   if (useMtProgress)
428   {
429     mtProgressSpec = new CMtEncMultiProgress;
430     mtProgress = mtProgressSpec;
431     mtProgressSpec->Init(compressProgress);
432 
433     mtOutStreamNotifySpec = new CSequentialOutMtNotify;
434     mtOutStreamNotify = mtOutStreamNotifySpec;
435     mtOutStreamNotifySpec->_stream = outStream;
436     mtOutStreamNotifySpec->_mtProgresSpec = mtProgressSpec;
437 
438     FOR_VECTOR(t, tempBufferSpecs)
439     {
440       tempBufferSpecs[t]->_mtProgresSpec = mtProgressSpec;
441     }
442   }
443 
444 
445   if (_bindInfo.PackStreams.Size() != 0)
446   {
447     outStreamSizeCountSpec = new CSequentialOutStreamSizeCount;
448     outStreamSizeCount = outStreamSizeCountSpec;
449     outStreamSizeCountSpec->SetStream(mtOutStreamNotify ? (ISequentialOutStream *)mtOutStreamNotify : outStream);
450     outStreamSizeCountSpec->Init();
451     outStreamPointers.Add(outStreamSizeCount);
452   }
453 
454   for (i = 1; i < _bindInfo.PackStreams.Size(); i++)
455     outStreamPointers.Add(tempBuffers[i - 1]);
456 
457   bool dataAfterEnd_Error;
458 
459   RINOK(_mixer->Code(
460       &inStreamPointer,
461       &outStreamPointers.Front(),
462       mtProgress ? (ICompressProgressInfo *)mtProgress : compressProgress, dataAfterEnd_Error));
463 
464   if (_bindInfo.PackStreams.Size() != 0)
465     packSizes.Add(outStreamSizeCountSpec->GetSize());
466 
467   for (i = 1; i < _bindInfo.PackStreams.Size(); i++)
468   {
469     CInOutTempBuffer &inOutTempBuffer = inOutTempBuffers[i - 1];
470     RINOK(inOutTempBuffer.WriteToStream(outStream));
471     packSizes.Add(inOutTempBuffer.GetDataSize());
472   }
473 
474   unpackSize = 0;
475 
476   for (i = 0; i < _bindInfo.Coders.Size(); i++)
477   {
478     int bond = _bindInfo.FindBond_for_UnpackStream(_DestOut_to_SrcIn[i]);
479     UInt64 streamSize;
480     if (bond < 0)
481     {
482       streamSize = inStreamSizeCountSpec->GetSize();
483       unpackSize = streamSize;
484     }
485     else
486       streamSize = _mixer->GetBondStreamSize((unsigned)bond);
487     coderUnpackSizes.Add(streamSize);
488   }
489 
490   return S_OK;
491 }
492 
493 
CEncoder(const CCompressionMethodMode & options)494 CEncoder::CEncoder(const CCompressionMethodMode &options):
495     _constructed(false)
496 {
497   if (options.IsEmpty())
498     throw 1;
499 
500   _options = options;
501 
502   #ifdef USE_MIXER_ST
503     _mixerST = NULL;
504   #endif
505 
506   #ifdef USE_MIXER_MT
507     _mixerMT = NULL;
508   #endif
509 
510   _mixer = NULL;
511 }
512 
513 
EncoderConstr()514 HRESULT CEncoder::EncoderConstr()
515 {
516   if (_constructed)
517     return S_OK;
518   if (_options.Methods.IsEmpty())
519   {
520     // it has only password method;
521     if (!_options.PasswordIsDefined)
522       throw 1;
523     if (!_options.Bonds.IsEmpty())
524       throw 1;
525 
526     CMethodFull method;
527     method.Id = k_AES;
528     method.NumStreams = 1;
529     _options.Methods.Add(method);
530 
531     NCoderMixer2::CCoderStreamsInfo coderStreamsInfo;
532     coderStreamsInfo.NumStreams = 1;
533     _bindInfo.Coders.Add(coderStreamsInfo);
534 
535     _bindInfo.PackStreams.Add(0);
536     _bindInfo.UnpackCoder = 0;
537   }
538   else
539   {
540 
541   UInt32 numOutStreams = 0;
542   unsigned i;
543 
544   for (i = 0; i < _options.Methods.Size(); i++)
545   {
546     const CMethodFull &methodFull = _options.Methods[i];
547     NCoderMixer2::CCoderStreamsInfo cod;
548 
549     cod.NumStreams = methodFull.NumStreams;
550 
551     if (_options.Bonds.IsEmpty())
552     {
553       // if there are no bonds in options, we create bonds via first streams of coders
554       if (i != _options.Methods.Size() - 1)
555       {
556         NCoderMixer2::CBond bond;
557         bond.PackIndex = numOutStreams;
558         bond.UnpackIndex = i + 1; // it's next coder
559         _bindInfo.Bonds.Add(bond);
560       }
561       else if (cod.NumStreams != 0)
562         _bindInfo.PackStreams.Insert(0, numOutStreams);
563 
564       for (UInt32 j = 1; j < cod.NumStreams; j++)
565         _bindInfo.PackStreams.Add(numOutStreams + j);
566     }
567 
568     numOutStreams += cod.NumStreams;
569 
570     _bindInfo.Coders.Add(cod);
571   }
572 
573   if (!_options.Bonds.IsEmpty())
574   {
575     for (i = 0; i < _options.Bonds.Size(); i++)
576     {
577       NCoderMixer2::CBond mixerBond;
578       const CBond2 &bond = _options.Bonds[i];
579       if (bond.InCoder >= _bindInfo.Coders.Size()
580           || bond.OutCoder >= _bindInfo.Coders.Size()
581           || bond.OutStream >= _bindInfo.Coders[bond.OutCoder].NumStreams)
582         return E_INVALIDARG;
583       mixerBond.PackIndex = _bindInfo.GetStream_for_Coder(bond.OutCoder) + bond.OutStream;
584       mixerBond.UnpackIndex = bond.InCoder;
585       _bindInfo.Bonds.Add(mixerBond);
586     }
587 
588     for (i = 0; i < numOutStreams; i++)
589       if (_bindInfo.FindBond_for_PackStream(i) == -1)
590         _bindInfo.PackStreams.Add(i);
591   }
592 
593   if (!_bindInfo.SetUnpackCoder())
594     return E_INVALIDARG;
595 
596   if (!_bindInfo.CalcMapsAndCheck())
597     return E_INVALIDARG;
598 
599   if (_bindInfo.PackStreams.Size() != 1)
600   {
601     /* main_PackStream is pack stream of main path of coders tree.
602        We find main_PackStream, and place to start of list of out streams.
603        It allows to use more optimal memory usage for temp buffers,
604        if main_PackStream is largest stream. */
605 
606     UInt32 ci = _bindInfo.UnpackCoder;
607 
608     for (;;)
609     {
610       if (_bindInfo.Coders[ci].NumStreams == 0)
611         break;
612 
613       UInt32 outIndex = _bindInfo.Coder_to_Stream[ci];
614       int bond = _bindInfo.FindBond_for_PackStream(outIndex);
615       if (bond >= 0)
616       {
617         ci = _bindInfo.Bonds[(unsigned)bond].UnpackIndex;
618         continue;
619       }
620 
621       int si = _bindInfo.FindStream_in_PackStreams(outIndex);
622       if (si >= 0)
623         _bindInfo.PackStreams.MoveToFront((unsigned)si);
624       break;
625     }
626   }
627 
628   if (_options.PasswordIsDefined)
629   {
630     unsigned numCryptoStreams = _bindInfo.PackStreams.Size();
631 
632     unsigned numInStreams = _bindInfo.Coders.Size();
633 
634     for (i = 0; i < numCryptoStreams; i++)
635     {
636       NCoderMixer2::CBond bond;
637       bond.UnpackIndex = numInStreams + i;
638       bond.PackIndex = _bindInfo.PackStreams[i];
639       _bindInfo.Bonds.Add(bond);
640     }
641     _bindInfo.PackStreams.Clear();
642 
643     /*
644     if (numCryptoStreams == 0)
645       numCryptoStreams = 1;
646     */
647 
648     for (i = 0; i < numCryptoStreams; i++)
649     {
650       CMethodFull method;
651       method.NumStreams = 1;
652       method.Id = k_AES;
653       _options.Methods.Add(method);
654 
655       NCoderMixer2::CCoderStreamsInfo cod;
656       cod.NumStreams = 1;
657       _bindInfo.Coders.Add(cod);
658 
659       _bindInfo.PackStreams.Add(numOutStreams++);
660     }
661   }
662 
663   }
664 
665   for (unsigned i = _options.Methods.Size(); i != 0;)
666     _decompressionMethods.Add(_options.Methods[--i].Id);
667 
668   if (_bindInfo.Coders.Size() > 16)
669     return E_INVALIDARG;
670   if (_bindInfo.GetNum_Bonds_and_PackStreams() > 16)
671     return E_INVALIDARG;
672 
673   if (!_bindInfo.CalcMapsAndCheck())
674     return E_INVALIDARG;
675 
676   InitBindConv();
677   _constructed = true;
678   return S_OK;
679 }
680 
~CEncoder()681 CEncoder::~CEncoder() {}
682 
683 }}
684