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