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