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         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     {
179       CMyComPtr<ICompressSetCoderMt> setCoderMt;
180       encoderCommon.QueryInterface(IID_ICompressSetCoderMt, &setCoderMt);
181       if (setCoderMt)
182       {
183         RINOK(setCoderMt->SetNumberOfThreads(_options.NumThreads));
184       }
185     }
186     #endif
187 
188     RINOK(SetCoderProps2(methodFull, inSizeForReduce, encoderCommon));
189 
190     /*
191     CMyComPtr<ICryptoResetSalt> resetSalt;
192     encoderCommon.QueryInterface(IID_ICryptoResetSalt, (void **)&resetSalt);
193     if (resetSalt)
194     {
195       resetSalt->ResetSalt();
196     }
197     */
198 
199     // now there is no codec that uses another external codec
200     /*
201     #ifdef EXTERNAL_CODECS
202     CMyComPtr<ISetCompressCodecsInfo> setCompressCodecsInfo;
203     encoderCommon.QueryInterface(IID_ISetCompressCodecsInfo, (void **)&setCompressCodecsInfo);
204     if (setCompressCodecsInfo)
205     {
206       // we must use g_ExternalCodecs also
207       RINOK(setCompressCodecsInfo->SetCompressCodecsInfo(__externalCodecs->GetCodecs));
208     }
209     #endif
210     */
211 
212     CMyComPtr<ICryptoSetPassword> cryptoSetPassword;
213     encoderCommon.QueryInterface(IID_ICryptoSetPassword, &cryptoSetPassword);
214 
215     if (cryptoSetPassword)
216     {
217       const unsigned sizeInBytes = _options.Password.Len() * 2;
218       CByteBuffer buffer(sizeInBytes);
219       for (unsigned i = 0; i < _options.Password.Len(); i++)
220       {
221         wchar_t c = _options.Password[i];
222         ((Byte *)buffer)[i * 2] = (Byte)c;
223         ((Byte *)buffer)[i * 2 + 1] = (Byte)(c >> 8);
224       }
225       RINOK(cryptoSetPassword->CryptoSetPassword((const Byte *)buffer, (UInt32)sizeInBytes));
226     }
227 
228     _mixer->AddCoder(cod);
229   }
230   return S_OK;
231 }
232 
233 
234 
235 class CSequentialOutTempBufferImp2:
236   public ISequentialOutStream,
237   public CMyUnknownImp
238 {
239   CInOutTempBuffer *_buf;
240 public:
241   CMtEncMultiProgress *_mtProgresSpec;
242 
CSequentialOutTempBufferImp2()243   CSequentialOutTempBufferImp2(): _buf(0), _mtProgresSpec(NULL) {}
Init(CInOutTempBuffer * buffer)244   void Init(CInOutTempBuffer *buffer) { _buf = buffer; }
245   MY_UNKNOWN_IMP1(ISequentialOutStream)
246 
247   STDMETHOD(Write)(const void *data, UInt32 size, UInt32 *processedSize);
248 };
249 
Write(const void * data,UInt32 size,UInt32 * processed)250 STDMETHODIMP CSequentialOutTempBufferImp2::Write(const void *data, UInt32 size, UInt32 *processed)
251 {
252   if (!_buf->Write(data, size))
253   {
254     if (processed)
255       *processed = 0;
256     return E_FAIL;
257   }
258   if (processed)
259     *processed = size;
260   if (_mtProgresSpec)
261     _mtProgresSpec->AddOutSize(size);
262   return S_OK;
263 }
264 
265 
266 class CSequentialOutMtNotify:
267   public ISequentialOutStream,
268   public CMyUnknownImp
269 {
270 public:
271   CMyComPtr<ISequentialOutStream> _stream;
272   CMtEncMultiProgress *_mtProgresSpec;
273 
CSequentialOutMtNotify()274   CSequentialOutMtNotify(): _mtProgresSpec(NULL) {}
275   MY_UNKNOWN_IMP1(ISequentialOutStream)
276 
277   STDMETHOD(Write)(const void *data, UInt32 size, UInt32 *processedSize);
278 };
279 
Write(const void * data,UInt32 size,UInt32 * processed)280 STDMETHODIMP CSequentialOutMtNotify::Write(const void *data, UInt32 size, UInt32 *processed)
281 {
282   UInt32 realProcessed = 0;
283   HRESULT res = _stream->Write(data, size, &realProcessed);
284   if (processed)
285     *processed = realProcessed;
286   if (_mtProgresSpec)
287     _mtProgresSpec->AddOutSize(size);
288   return res;
289 }
290 
291 
292 
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)293 HRESULT CEncoder::Encode(
294     DECL_EXTERNAL_CODECS_LOC_VARS
295     ISequentialInStream *inStream,
296     // const UInt64 *inStreamSize,
297     const UInt64 *inSizeForReduce,
298     CFolder &folderItem,
299     CRecordVector<UInt64> &coderUnpackSizes,
300     UInt64 &unpackSize,
301     ISequentialOutStream *outStream,
302     CRecordVector<UInt64> &packSizes,
303     ICompressProgressInfo *compressProgress)
304 {
305   RINOK(EncoderConstr());
306 
307   if (!_mixerRef)
308   {
309     RINOK(CreateMixerCoder(EXTERNAL_CODECS_LOC_VARS inSizeForReduce));
310   }
311 
312   _mixer->ReInit();
313 
314   CMtEncMultiProgress *mtProgressSpec = NULL;
315   CMyComPtr<ICompressProgressInfo> mtProgress;
316 
317   CSequentialOutMtNotify *mtOutStreamNotifySpec = NULL;
318   CMyComPtr<ISequentialOutStream> mtOutStreamNotify;
319 
320   CObjectVector<CInOutTempBuffer> inOutTempBuffers;
321   CObjectVector<CSequentialOutTempBufferImp2 *> tempBufferSpecs;
322   CObjectVector<CMyComPtr<ISequentialOutStream> > tempBuffers;
323 
324   unsigned numMethods = _bindInfo.Coders.Size();
325 
326   unsigned i;
327 
328   for (i = 1; i < _bindInfo.PackStreams.Size(); i++)
329   {
330     CInOutTempBuffer &iotb = inOutTempBuffers.AddNew();
331     iotb.Create();
332     iotb.InitWriting();
333   }
334 
335   for (i = 1; i < _bindInfo.PackStreams.Size(); i++)
336   {
337     CSequentialOutTempBufferImp2 *tempBufferSpec = new CSequentialOutTempBufferImp2;
338     CMyComPtr<ISequentialOutStream> tempBuffer = tempBufferSpec;
339     tempBufferSpec->Init(&inOutTempBuffers[i - 1]);
340     tempBuffers.Add(tempBuffer);
341     tempBufferSpecs.Add(tempBufferSpec);
342   }
343 
344   for (i = 0; i < numMethods; i++)
345     _mixer->SetCoderInfo(i, NULL, NULL, false);
346 
347 
348   /* inStreamSize can be used by BCJ2 to set optimal range of conversion.
349      But current BCJ2 encoder uses also another way to check exact size of current file.
350      So inStreamSize is not required. */
351 
352   /*
353   if (inStreamSize)
354     _mixer->SetCoderInfo(_bindInfo.UnpackCoder, inStreamSize, NULL);
355   */
356 
357 
358   CSequentialInStreamSizeCount2 *inStreamSizeCountSpec = new CSequentialInStreamSizeCount2;
359   CMyComPtr<ISequentialInStream> inStreamSizeCount = inStreamSizeCountSpec;
360 
361   CSequentialOutStreamSizeCount *outStreamSizeCountSpec = NULL;
362   CMyComPtr<ISequentialOutStream> outStreamSizeCount;
363 
364   inStreamSizeCountSpec->Init(inStream);
365 
366   ISequentialInStream *inStreamPointer = inStreamSizeCount;
367   CRecordVector<ISequentialOutStream *> outStreamPointers;
368 
369   SetFolder(folderItem);
370 
371   for (i = 0; i < numMethods; i++)
372   {
373     IUnknown *coder = _mixer->GetCoder(i).GetUnknown();
374 
375     CMyComPtr<ICryptoResetInitVector> resetInitVector;
376     coder->QueryInterface(IID_ICryptoResetInitVector, (void **)&resetInitVector);
377     if (resetInitVector)
378     {
379       resetInitVector->ResetInitVector();
380     }
381 
382     {
383       CMyComPtr<ICompressSetCoderPropertiesOpt> optProps;
384       coder->QueryInterface(IID_ICompressSetCoderPropertiesOpt, (void **)&optProps);
385       if (optProps)
386       {
387         PROPID propID = NCoderPropID::kExpectedDataSize;
388         NWindows::NCOM::CPropVariant prop = (UInt64)unpackSize;
389         RINOK(optProps->SetCoderPropertiesOpt(&propID, &prop, 1));
390       }
391     }
392 
393     CMyComPtr<ICompressWriteCoderProperties> writeCoderProperties;
394     coder->QueryInterface(IID_ICompressWriteCoderProperties, (void **)&writeCoderProperties);
395 
396     CByteBuffer &props = folderItem.Coders[numMethods - 1 - i].Props;
397 
398     if (writeCoderProperties)
399     {
400       CDynBufSeqOutStream *outStreamSpec = new CDynBufSeqOutStream;
401       CMyComPtr<ISequentialOutStream> dynOutStream(outStreamSpec);
402       outStreamSpec->Init();
403       RINOK(writeCoderProperties->WriteCoderProperties(dynOutStream));
404       outStreamSpec->CopyToBuffer(props);
405     }
406     else
407       props.Free();
408   }
409 
410   _mixer->SelectMainCoder(false);
411   UInt32 mainCoder = _mixer->MainCoderIndex;
412 
413   bool useMtProgress = false;
414   if (!_mixer->Is_PackSize_Correct_for_Coder(mainCoder))
415   {
416     #ifdef _7ZIP_ST
417     if (!_mixer->IsThere_ExternalCoder_in_PackTree(mainCoder))
418     #endif
419       useMtProgress = true;
420   }
421 
422   if (useMtProgress)
423   {
424     mtProgressSpec = new CMtEncMultiProgress;
425     mtProgress = mtProgressSpec;
426     mtProgressSpec->Init(compressProgress);
427 
428     mtOutStreamNotifySpec = new CSequentialOutMtNotify;
429     mtOutStreamNotify = mtOutStreamNotifySpec;
430     mtOutStreamNotifySpec->_stream = outStream;
431     mtOutStreamNotifySpec->_mtProgresSpec = mtProgressSpec;
432 
433     FOR_VECTOR(t, tempBufferSpecs)
434     {
435       tempBufferSpecs[t]->_mtProgresSpec = mtProgressSpec;
436     }
437   }
438 
439 
440   if (_bindInfo.PackStreams.Size() != 0)
441   {
442     outStreamSizeCountSpec = new CSequentialOutStreamSizeCount;
443     outStreamSizeCount = outStreamSizeCountSpec;
444     outStreamSizeCountSpec->SetStream(mtOutStreamNotify ? (ISequentialOutStream *)mtOutStreamNotify : outStream);
445     outStreamSizeCountSpec->Init();
446     outStreamPointers.Add(outStreamSizeCount);
447   }
448 
449   for (i = 1; i < _bindInfo.PackStreams.Size(); i++)
450     outStreamPointers.Add(tempBuffers[i - 1]);
451 
452   bool dataAfterEnd_Error;
453 
454   RINOK(_mixer->Code(
455       &inStreamPointer,
456       &outStreamPointers.Front(),
457       mtProgress ? (ICompressProgressInfo *)mtProgress : compressProgress, dataAfterEnd_Error));
458 
459   if (_bindInfo.PackStreams.Size() != 0)
460     packSizes.Add(outStreamSizeCountSpec->GetSize());
461 
462   for (i = 1; i < _bindInfo.PackStreams.Size(); i++)
463   {
464     CInOutTempBuffer &inOutTempBuffer = inOutTempBuffers[i - 1];
465     RINOK(inOutTempBuffer.WriteToStream(outStream));
466     packSizes.Add(inOutTempBuffer.GetDataSize());
467   }
468 
469   unpackSize = 0;
470 
471   for (i = 0; i < _bindInfo.Coders.Size(); i++)
472   {
473     int bond = _bindInfo.FindBond_for_UnpackStream(_DestOut_to_SrcIn[i]);
474     UInt64 streamSize;
475     if (bond < 0)
476     {
477       streamSize = inStreamSizeCountSpec->GetSize();
478       unpackSize = streamSize;
479     }
480     else
481       streamSize = _mixer->GetBondStreamSize(bond);
482     coderUnpackSizes.Add(streamSize);
483   }
484 
485   return S_OK;
486 }
487 
488 
CEncoder(const CCompressionMethodMode & options)489 CEncoder::CEncoder(const CCompressionMethodMode &options):
490     _constructed(false)
491 {
492   if (options.IsEmpty())
493     throw 1;
494 
495   _options = options;
496 
497   #ifdef USE_MIXER_ST
498     _mixerST = NULL;
499   #endif
500 
501   #ifdef USE_MIXER_MT
502     _mixerMT = NULL;
503   #endif
504 
505   _mixer = NULL;
506 }
507 
508 
EncoderConstr()509 HRESULT CEncoder::EncoderConstr()
510 {
511   if (_constructed)
512     return S_OK;
513   if (_options.Methods.IsEmpty())
514   {
515     // it has only password method;
516     if (!_options.PasswordIsDefined)
517       throw 1;
518     if (!_options.Bonds.IsEmpty())
519       throw 1;
520 
521     CMethodFull method;
522     method.Id = k_AES;
523     method.NumStreams = 1;
524     _options.Methods.Add(method);
525 
526     NCoderMixer2::CCoderStreamsInfo coderStreamsInfo;
527     coderStreamsInfo.NumStreams = 1;
528     _bindInfo.Coders.Add(coderStreamsInfo);
529 
530     _bindInfo.PackStreams.Add(0);
531     _bindInfo.UnpackCoder = 0;
532   }
533   else
534   {
535 
536   UInt32 numOutStreams = 0;
537   unsigned i;
538 
539   for (i = 0; i < _options.Methods.Size(); i++)
540   {
541     const CMethodFull &methodFull = _options.Methods[i];
542     NCoderMixer2::CCoderStreamsInfo cod;
543 
544     cod.NumStreams = methodFull.NumStreams;
545 
546     if (_options.Bonds.IsEmpty())
547     {
548       // if there are no bonds in options, we create bonds via first streams of coders
549       if (i != _options.Methods.Size() - 1)
550       {
551         NCoderMixer2::CBond bond;
552         bond.PackIndex = numOutStreams;
553         bond.UnpackIndex = i + 1; // it's next coder
554         _bindInfo.Bonds.Add(bond);
555       }
556       else if (cod.NumStreams != 0)
557         _bindInfo.PackStreams.Insert(0, numOutStreams);
558 
559       for (UInt32 j = 1; j < cod.NumStreams; j++)
560         _bindInfo.PackStreams.Add(numOutStreams + j);
561     }
562 
563     numOutStreams += cod.NumStreams;
564 
565     _bindInfo.Coders.Add(cod);
566   }
567 
568   if (!_options.Bonds.IsEmpty())
569   {
570     for (i = 0; i < _options.Bonds.Size(); i++)
571     {
572       NCoderMixer2::CBond mixerBond;
573       const CBond2 &bond = _options.Bonds[i];
574       if (bond.InCoder >= _bindInfo.Coders.Size()
575           || bond.OutCoder >= _bindInfo.Coders.Size()
576           || bond.OutStream >= _bindInfo.Coders[bond.OutCoder].NumStreams)
577         return E_INVALIDARG;
578       mixerBond.PackIndex = _bindInfo.GetStream_for_Coder(bond.OutCoder) + bond.OutStream;
579       mixerBond.UnpackIndex = bond.InCoder;
580       _bindInfo.Bonds.Add(mixerBond);
581     }
582 
583     for (i = 0; i < numOutStreams; i++)
584       if (_bindInfo.FindBond_for_PackStream(i) == -1)
585         _bindInfo.PackStreams.Add(i);
586   }
587 
588   if (!_bindInfo.SetUnpackCoder())
589     return E_INVALIDARG;
590 
591   if (!_bindInfo.CalcMapsAndCheck())
592     return E_INVALIDARG;
593 
594   if (_bindInfo.PackStreams.Size() != 1)
595   {
596     /* main_PackStream is pack stream of main path of coders tree.
597        We find main_PackStream, and place to start of list of out streams.
598        It allows to use more optimal memory usage for temp buffers,
599        if main_PackStream is largest stream. */
600 
601     UInt32 ci = _bindInfo.UnpackCoder;
602 
603     for (;;)
604     {
605       if (_bindInfo.Coders[ci].NumStreams == 0)
606         break;
607 
608       UInt32 outIndex = _bindInfo.Coder_to_Stream[ci];
609       int bond = _bindInfo.FindBond_for_PackStream(outIndex);
610       if (bond >= 0)
611       {
612         ci = _bindInfo.Bonds[bond].UnpackIndex;
613         continue;
614       }
615 
616       int si = _bindInfo.FindStream_in_PackStreams(outIndex);
617       if (si >= 0)
618         _bindInfo.PackStreams.MoveToFront(si);
619       break;
620     }
621   }
622 
623   if (_options.PasswordIsDefined)
624   {
625     unsigned numCryptoStreams = _bindInfo.PackStreams.Size();
626 
627     unsigned numInStreams = _bindInfo.Coders.Size();
628 
629     for (i = 0; i < numCryptoStreams; i++)
630     {
631       NCoderMixer2::CBond bond;
632       bond.UnpackIndex = numInStreams + i;
633       bond.PackIndex = _bindInfo.PackStreams[i];
634       _bindInfo.Bonds.Add(bond);
635     }
636     _bindInfo.PackStreams.Clear();
637 
638     /*
639     if (numCryptoStreams == 0)
640       numCryptoStreams = 1;
641     */
642 
643     for (i = 0; i < numCryptoStreams; i++)
644     {
645       CMethodFull method;
646       method.NumStreams = 1;
647       method.Id = k_AES;
648       _options.Methods.Add(method);
649 
650       NCoderMixer2::CCoderStreamsInfo cod;
651       cod.NumStreams = 1;
652       _bindInfo.Coders.Add(cod);
653 
654       _bindInfo.PackStreams.Add(numOutStreams++);
655     }
656   }
657 
658   }
659 
660   for (unsigned i = _options.Methods.Size(); i != 0;)
661     _decompressionMethods.Add(_options.Methods[--i].Id);
662 
663   if (_bindInfo.Coders.Size() > 16)
664     return E_INVALIDARG;
665   if (_bindInfo.GetNum_Bonds_and_PackStreams() > 16)
666     return E_INVALIDARG;
667 
668   if (!_bindInfo.CalcMapsAndCheck())
669     return E_INVALIDARG;
670 
671   InitBindConv();
672   _constructed = true;
673   return S_OK;
674 }
675 
~CEncoder()676 CEncoder::~CEncoder() {}
677 
678 }}
679