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