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