Home | History | Annotate | Download | only in 7z
      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 
     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 
     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 
     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 
    100 void CMtEncMultiProgress::Init(ICompressProgressInfo *progress)
    101 {
    102   _progress = progress;
    103   OutSize = 0;
    104 }
    105 
    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 
    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 
    243   CSequentialOutTempBufferImp2(): _buf(0), _mtProgresSpec(NULL) {}
    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 
    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 
    274   CSequentialOutMtNotify(): _mtProgresSpec(NULL) {}
    275   MY_UNKNOWN_IMP1(ISequentialOutStream)
    276 
    277   STDMETHOD(Write)(const void *data, UInt32 size, UInt32 *processedSize);
    278 };
    279 
    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 
    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 
    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 
    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 
    676 CEncoder::~CEncoder() {}
    677 
    678 }}
    679