tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

7zEncode.cpp (18455B)


      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 }}