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 
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 
CSequentialOutTempBufferImp2()254   CSequentialOutTempBufferImp2(): _mtProgressSpec(NULL) {}
255 };
256 
Write(const void *data, UInt32 size, UInt32 *processed)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 
CSequentialOutMtNotify()280   CSequentialOutMtNotify(): _mtProgressSpec(NULL) {}
281 };
282 
Write(const void *data, UInt32 size, UInt32 *processed)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 
FillProps_from_Coder(IUnknown *coder, CByteBuffer &props)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     CDynBufSeqOutStream *outStreamSpec = new CDynBufSeqOutStream;
303     CMyComPtr<ISequentialOutStream> dynOutStream(outStreamSpec);
304     outStreamSpec->Init();
305     RINOK(writeCoderProperties->WriteCoderProperties(dynOutStream))
306     outStreamSpec->CopyToBuffer(props);
307   }
308   else
309     props.Free();
310   return S_OK;
311 }
312 
Encode1( DECL_EXTERNAL_CODECS_LOC_VARS ISequentialInStream *inStream, const UInt64 *inSizeForReduce, UInt64 expectedDataSize, CFolder &folderItem, ISequentialOutStream *outStream, CRecordVector<UInt64> &packSizes, ICompressProgressInfo *compressProgress)313 HRESULT CEncoder::Encode1(
314     DECL_EXTERNAL_CODECS_LOC_VARS
315     ISequentialInStream *inStream,
316     // const UInt64 *inStreamSize,
317     const UInt64 *inSizeForReduce,
318     UInt64 expectedDataSize,
319     CFolder &folderItem,
320     // CRecordVector<UInt64> &coderUnpackSizes,
321     // UInt64 &unpackSize,
322     ISequentialOutStream *outStream,
323     CRecordVector<UInt64> &packSizes,
324     ICompressProgressInfo *compressProgress)
325 {
326   RINOK(EncoderConstr())
327 
328   if (!_mixerRef)
329   {
330     RINOK(CreateMixerCoder(EXTERNAL_CODECS_LOC_VARS inSizeForReduce))
331   }
332 
333   RINOK(_mixer->ReInit2())
334 
335   CMtEncMultiProgress *mtProgressSpec = NULL;
336   CMyComPtr<ICompressProgressInfo> mtProgress;
337 
338   CSequentialOutMtNotify *mtOutStreamNotifySpec = NULL;
339   CMyComPtr<ISequentialOutStream> mtOutStreamNotify;
340 
341   CRecordVector<CSequentialOutTempBufferImp2 *> tempBufferSpecs;
342   CObjectVector<CMyComPtr<ISequentialOutStream> > tempBuffers;
343 
344   unsigned i;
345 
346   for (i = 1; i < _bindInfo.PackStreams.Size(); i++)
347   {
348     CSequentialOutTempBufferImp2 *tempBufferSpec = new CSequentialOutTempBufferImp2();
349     CMyComPtr<ISequentialOutStream> tempBuffer = tempBufferSpec;
350     tempBufferSpecs.Add(tempBufferSpec);
351     tempBuffers.Add(tempBuffer);
352   }
353 
354   const unsigned numMethods = _bindInfo.Coders.Size();
355 
356   for (i = 0; i < numMethods; i++)
357     _mixer->SetCoderInfo(i, NULL, NULL, false);
358 
359 
360   /* inStreamSize can be used by BCJ2 to set optimal range of conversion.
361      But current BCJ2 encoder uses also another way to check exact size of current file.
362      So inStreamSize is not required. */
363 
364   /*
365   if (inStreamSize)
366     _mixer->SetCoderInfo(_bindInfo.UnpackCoder, inStreamSize, NULL);
367   */
368 
369 
370   /*
371   CSequentialInStreamSizeCount2 *inStreamSizeCountSpec = new CSequentialInStreamSizeCount2;
372   CMyComPtr<ISequentialInStream> inStreamSizeCount = inStreamSizeCountSpec;
373   */
374 
375   CSequentialOutStreamSizeCount *outStreamSizeCountSpec = NULL;
376   CMyComPtr<ISequentialOutStream> outStreamSizeCount;
377 
378   // inStreamSizeCountSpec->Init(inStream);
379 
380   // ISequentialInStream *inStreamPointer = inStreamSizeCount;
381   ISequentialInStream *inStreamPointer = inStream;
382 
383   CRecordVector<ISequentialOutStream *> outStreamPointers;
384 
385   SetFolder(folderItem);
386 
387   for (i = 0; i < numMethods; i++)
388   {
389     IUnknown *coder = _mixer->GetCoder(i).GetUnknown();
390     /*
391     {
392       CEncoder *sfEncoder = NULL;
393       Z7_DECL_CMyComPtr_QI_FROM(
394           IGetSfEncoderInternal,
395           sf, coder)
396       if (sf)
397       {
398         RINOK(sf->GetSfEncoder(&sfEncoder));
399         if (!sfEncoder)
400           return E_FAIL;
401 
402       }
403     }
404     */
405     /*
406     #ifdef Z7_EXTERNAL_CODECS
407     {
408       Z7_DECL_CMyComPtr_QI_FROM(
409           ISetCompressCodecsInfo,
410           setCompressCodecsInfo, coder)
411       if (setCompressCodecsInfo)
412       {
413         // we must use g_ExternalCodecs also
414         RINOK(setCompressCodecsInfo->SetCompressCodecsInfo(_externalCodecs->GetCodecs))
415       }
416     }
417     #endif
418     */
419     {
420       Z7_DECL_CMyComPtr_QI_FROM(
421           ICryptoResetInitVector,
422           resetInitVector, coder)
423       if (resetInitVector)
424       {
425         RINOK(resetInitVector->ResetInitVector())
426       }
427     }
428     {
429       Z7_DECL_CMyComPtr_QI_FROM(
430           ICompressSetCoderPropertiesOpt,
431           optProps, coder)
432       if (optProps)
433       {
434         const PROPID propID = NCoderPropID::kExpectedDataSize;
435         NWindows::NCOM::CPropVariant prop = (UInt64)expectedDataSize;
436         RINOK(optProps->SetCoderPropertiesOpt(&propID, &prop, 1))
437       }
438     }
439     // we must write properties from coder after ResetInitVector()
440     RINOK(FillProps_from_Coder(coder, folderItem.Coders[numMethods - 1 - i].Props))
441   }
442 
443   _mixer->SelectMainCoder(false);
444   const UInt32 mainCoder = _mixer->MainCoderIndex;
445 
446   bool useMtProgress = false;
447   if (!_mixer->Is_PackSize_Correct_for_Coder(mainCoder))
448   {
449     #ifdef Z7_ST
450     if (!_mixer->IsThere_ExternalCoder_in_PackTree(mainCoder))
451     #endif
452       useMtProgress = true;
453   }
454 
455   if (useMtProgress)
456   {
457     mtProgressSpec = new CMtEncMultiProgress;
458     mtProgress = mtProgressSpec;
459     mtProgressSpec->Init(compressProgress);
460 
461     mtOutStreamNotifySpec = new CSequentialOutMtNotify;
462     mtOutStreamNotify = mtOutStreamNotifySpec;
463     mtOutStreamNotifySpec->_stream = outStream;
464     mtOutStreamNotifySpec->_mtProgressSpec = mtProgressSpec;
465 
466     FOR_VECTOR (t, tempBufferSpecs)
467     {
468       tempBufferSpecs[t]->_mtProgressSpec = mtProgressSpec;
469     }
470   }
471 
472 
473   if (_bindInfo.PackStreams.Size() != 0)
474   {
475     outStreamSizeCountSpec = new CSequentialOutStreamSizeCount;
476     outStreamSizeCount = outStreamSizeCountSpec;
477     outStreamSizeCountSpec->SetStream(mtOutStreamNotify ? (ISequentialOutStream *)mtOutStreamNotify : outStream);
478     outStreamSizeCountSpec->Init();
479     outStreamPointers.Add(outStreamSizeCount);
480   }
481 
482   for (i = 1; i < _bindInfo.PackStreams.Size(); i++)
483     outStreamPointers.Add(tempBuffers[i - 1]);
484 
485   bool dataAfterEnd_Error;
486 
487   RINOK(_mixer->Code(
488       &inStreamPointer,
489       &outStreamPointers.Front(),
490       mtProgress ? (ICompressProgressInfo *)mtProgress : compressProgress, dataAfterEnd_Error))
491 
492   if (_bindInfo.PackStreams.Size() != 0)
493     packSizes.Add(outStreamSizeCountSpec->GetSize());
494 
495   for (i = 1; i < _bindInfo.PackStreams.Size(); i++)
496   {
497     CInOutTempBuffer &iotb = tempBufferSpecs[i - 1]->TempBuffer;
498     RINOK(iotb.WriteToStream(outStream))
499     packSizes.Add(iotb.GetDataSize());
500   }
501 
502   /* Code() in some future codec can change properties.
503      v23: so we fill properties again after Code() */
504   for (i = 0; i < numMethods; i++)
505   {
506     IUnknown *coder = _mixer->GetCoder(i).GetUnknown();
507     RINOK(FillProps_from_Coder(coder, folderItem.Coders[numMethods - 1 - i].Props))
508   }
509 
510   return S_OK;
511 }
512 
513 
Encode_Post( UInt64 unpackSize, CRecordVector<UInt64> &coderUnpackSizes)514 void CEncoder::Encode_Post(
515       UInt64 unpackSize,
516       CRecordVector<UInt64> &coderUnpackSizes)
517 {
518   // unpackSize = 0;
519   for (unsigned i = 0; i < _bindInfo.Coders.Size(); i++)
520   {
521     const int bond = _bindInfo.FindBond_for_UnpackStream(DestOut_to_SrcIn[i]);
522     UInt64 streamSize;
523     if (bond < 0)
524     {
525       // streamSize = inStreamSizeCountSpec->GetSize();
526       // unpackSize = streamSize;
527       streamSize = unpackSize;
528     }
529     else
530       streamSize = _mixer->GetBondStreamSize((unsigned)bond);
531     coderUnpackSizes.Add(streamSize);
532   }
533 }
534 
535 
CEncoder(const CCompressionMethodMode &options)536 CEncoder::CEncoder(const CCompressionMethodMode &options):
537     _constructed(false)
538 {
539   if (options.IsEmpty())
540     throw 1;
541 
542   _options = options;
543 
544   #ifdef USE_MIXER_ST
545     _mixerST = NULL;
546   #endif
547 
548   #ifdef USE_MIXER_MT
549     _mixerMT = NULL;
550   #endif
551 
552   _mixer = NULL;
553 }
554 
555 
EncoderConstr()556 HRESULT CEncoder::EncoderConstr()
557 {
558   if (_constructed)
559     return S_OK;
560   if (_options.Methods.IsEmpty())
561   {
562     // it has only password method;
563     if (!_options.PasswordIsDefined)
564       throw 1;
565     if (!_options.Bonds.IsEmpty())
566       throw 1;
567 
568     CMethodFull method;
569     method.Id = k_AES;
570     method.NumStreams = 1;
571     _options.Methods.Add(method);
572 
573     NCoderMixer2::CCoderStreamsInfo coderStreamsInfo;
574     coderStreamsInfo.NumStreams = 1;
575     _bindInfo.Coders.Add(coderStreamsInfo);
576 
577     _bindInfo.PackStreams.Add(0);
578     _bindInfo.UnpackCoder = 0;
579   }
580   else
581   {
582 
583   UInt32 numOutStreams = 0;
584   unsigned i;
585 
586   for (i = 0; i < _options.Methods.Size(); i++)
587   {
588     const CMethodFull &methodFull = _options.Methods[i];
589     NCoderMixer2::CCoderStreamsInfo cod;
590 
591     cod.NumStreams = methodFull.NumStreams;
592 
593     if (_options.Bonds.IsEmpty())
594     {
595       // if there are no bonds in options, we create bonds via first streams of coders
596       if (i != _options.Methods.Size() - 1)
597       {
598         NCoderMixer2::CBond bond;
599         bond.PackIndex = numOutStreams;
600         bond.UnpackIndex = i + 1; // it's next coder
601         _bindInfo.Bonds.Add(bond);
602       }
603       else if (cod.NumStreams != 0)
604         _bindInfo.PackStreams.Insert(0, numOutStreams);
605 
606       for (UInt32 j = 1; j < cod.NumStreams; j++)
607         _bindInfo.PackStreams.Add(numOutStreams + j);
608     }
609 
610     numOutStreams += cod.NumStreams;
611 
612     _bindInfo.Coders.Add(cod);
613   }
614 
615   if (!_options.Bonds.IsEmpty())
616   {
617     for (i = 0; i < _options.Bonds.Size(); i++)
618     {
619       NCoderMixer2::CBond mixerBond;
620       const CBond2 &bond = _options.Bonds[i];
621       if (bond.InCoder >= _bindInfo.Coders.Size()
622           || bond.OutCoder >= _bindInfo.Coders.Size()
623           || bond.OutStream >= _bindInfo.Coders[bond.OutCoder].NumStreams)
624         return E_INVALIDARG;
625       mixerBond.PackIndex = _bindInfo.GetStream_for_Coder(bond.OutCoder) + bond.OutStream;
626       mixerBond.UnpackIndex = bond.InCoder;
627       _bindInfo.Bonds.Add(mixerBond);
628     }
629 
630     for (i = 0; i < numOutStreams; i++)
631       if (_bindInfo.FindBond_for_PackStream(i) == -1)
632         _bindInfo.PackStreams.Add(i);
633   }
634 
635   if (!_bindInfo.SetUnpackCoder())
636     return E_INVALIDARG;
637 
638   if (!_bindInfo.CalcMapsAndCheck())
639     return E_INVALIDARG;
640 
641   if (_bindInfo.PackStreams.Size() != 1)
642   {
643     /* main_PackStream is pack stream of main path of coders tree.
644        We find main_PackStream, and place to start of list of out streams.
645        It allows to use more optimal memory usage for temp buffers,
646        if main_PackStream is largest stream. */
647 
648     UInt32 ci = _bindInfo.UnpackCoder;
649 
650     for (;;)
651     {
652       if (_bindInfo.Coders[ci].NumStreams == 0)
653         break;
654 
655       const UInt32 outIndex = _bindInfo.Coder_to_Stream[ci];
656       const int bond = _bindInfo.FindBond_for_PackStream(outIndex);
657       if (bond >= 0)
658       {
659         ci = _bindInfo.Bonds[(unsigned)bond].UnpackIndex;
660         continue;
661       }
662 
663       const int si = _bindInfo.FindStream_in_PackStreams(outIndex);
664       if (si >= 0)
665         _bindInfo.PackStreams.MoveToFront((unsigned)si);
666       break;
667     }
668   }
669 
670   if (_options.PasswordIsDefined)
671   {
672     unsigned numCryptoStreams = _bindInfo.PackStreams.Size();
673 
674     unsigned numInStreams = _bindInfo.Coders.Size();
675 
676     for (i = 0; i < numCryptoStreams; i++)
677     {
678       NCoderMixer2::CBond bond;
679       bond.UnpackIndex = numInStreams + i;
680       bond.PackIndex = _bindInfo.PackStreams[i];
681       _bindInfo.Bonds.Add(bond);
682     }
683     _bindInfo.PackStreams.Clear();
684 
685     /*
686     if (numCryptoStreams == 0)
687       numCryptoStreams = 1;
688     */
689 
690     for (i = 0; i < numCryptoStreams; i++)
691     {
692       CMethodFull method;
693       method.NumStreams = 1;
694       method.Id = k_AES;
695       _options.Methods.Add(method);
696 
697       NCoderMixer2::CCoderStreamsInfo cod;
698       cod.NumStreams = 1;
699       _bindInfo.Coders.Add(cod);
700 
701       _bindInfo.PackStreams.Add(numOutStreams++);
702     }
703   }
704 
705   }
706 
707   for (unsigned i = _options.Methods.Size(); i != 0;)
708     _decompressionMethods.Add(_options.Methods[--i].Id);
709 
710   if (_bindInfo.Coders.Size() > 16)
711     return E_INVALIDARG;
712   if (_bindInfo.GetNum_Bonds_and_PackStreams() > 16)
713     return E_INVALIDARG;
714 
715   if (!_bindInfo.CalcMapsAndCheck())
716     return E_INVALIDARG;
717 
718   InitBindConv();
719   _constructed = true;
720   return S_OK;
721 }
722 
~CEncoder()723 CEncoder::~CEncoder() {}
724 
725 }}
726