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