misc/libphysfs/lzma/CPP/7zip/Archive/7z/7zEncode.cpp
changeset 12213 bb5522e88ab2
equal deleted inserted replaced
12212:ea891871f481 12213:bb5522e88ab2
       
     1 // Encode.cpp
       
     2 
       
     3 #include "StdAfx.h"
       
     4 
       
     5 #include "7zEncode.h"
       
     6 #include "7zSpecStream.h"
       
     7 
       
     8 #include "../../IPassword.h"
       
     9 #include "../../Common/ProgressUtils.h"
       
    10 #include "../../Common/LimitedStreams.h"
       
    11 #include "../../Common/InOutTempBuffer.h"
       
    12 #include "../../Common/StreamObjects.h"
       
    13 #include "../../Common/CreateCoder.h"
       
    14 #include "../../Common/FilterCoder.h"
       
    15 
       
    16 static const UInt64 k_AES = 0x06F10701;
       
    17 static const UInt64 k_BCJ  = 0x03030103;
       
    18 static const UInt64 k_BCJ2 = 0x0303011B;
       
    19 
       
    20 namespace NArchive {
       
    21 namespace N7z {
       
    22 
       
    23 static void ConvertBindInfoToFolderItemInfo(const NCoderMixer::CBindInfo &bindInfo,
       
    24     const CRecordVector<CMethodId> decompressionMethods,
       
    25     CFolder &folder)
       
    26 {
       
    27   folder.Coders.Clear();
       
    28   // bindInfo.CoderMethodIDs.Clear();
       
    29   // folder.OutStreams.Clear();
       
    30   folder.PackStreams.Clear();
       
    31   folder.BindPairs.Clear();
       
    32   int i;
       
    33   for (i = 0; i < bindInfo.BindPairs.Size(); i++)
       
    34   {
       
    35     CBindPair bindPair;
       
    36     bindPair.InIndex = bindInfo.BindPairs[i].InIndex;
       
    37     bindPair.OutIndex = bindInfo.BindPairs[i].OutIndex;
       
    38     folder.BindPairs.Add(bindPair);
       
    39   }
       
    40   for (i = 0; i < bindInfo.Coders.Size(); i++)
       
    41   {
       
    42     CCoderInfo coderInfo;
       
    43     const NCoderMixer::CCoderStreamsInfo &coderStreamsInfo = bindInfo.Coders[i];
       
    44     coderInfo.NumInStreams = coderStreamsInfo.NumInStreams;
       
    45     coderInfo.NumOutStreams = coderStreamsInfo.NumOutStreams;
       
    46     coderInfo.MethodID = decompressionMethods[i];
       
    47     folder.Coders.Add(coderInfo);
       
    48   }
       
    49   for (i = 0; i < bindInfo.InStreams.Size(); i++)
       
    50     folder.PackStreams.Add(bindInfo.InStreams[i]);
       
    51 }
       
    52 
       
    53 HRESULT CEncoder::CreateMixerCoder(
       
    54     DECL_EXTERNAL_CODECS_LOC_VARS
       
    55     const UInt64 *inSizeForReduce)
       
    56 {
       
    57   _mixerCoderSpec = new NCoderMixer::CCoderMixer2MT;
       
    58   _mixerCoder = _mixerCoderSpec;
       
    59   RINOK(_mixerCoderSpec->SetBindInfo(_bindInfo));
       
    60   for (int i = 0; i < _options.Methods.Size(); i++)
       
    61   {
       
    62     const CMethodFull &methodFull = _options.Methods[i];
       
    63     _codersInfo.Add(CCoderInfo());
       
    64     CCoderInfo &encodingInfo = _codersInfo.Back();
       
    65     encodingInfo.MethodID = methodFull.Id;
       
    66     CMyComPtr<ICompressCoder> encoder;
       
    67     CMyComPtr<ICompressCoder2> encoder2;
       
    68     
       
    69 
       
    70     RINOK(CreateCoder(
       
    71         EXTERNAL_CODECS_LOC_VARS
       
    72         methodFull.Id, encoder, encoder2, true));
       
    73 
       
    74     if (!encoder && !encoder2)
       
    75       return E_FAIL;
       
    76 
       
    77     CMyComPtr<IUnknown> encoderCommon = encoder ? (IUnknown *)encoder : (IUnknown *)encoder2;
       
    78    
       
    79     #ifdef COMPRESS_MT
       
    80     {
       
    81       CMyComPtr<ICompressSetCoderMt> setCoderMt;
       
    82       encoderCommon.QueryInterface(IID_ICompressSetCoderMt, &setCoderMt);
       
    83       if (setCoderMt)
       
    84       {
       
    85         RINOK(setCoderMt->SetNumberOfThreads(_options.NumThreads));
       
    86       }
       
    87     }
       
    88     #endif
       
    89         
       
    90 
       
    91     RINOK(SetMethodProperties(methodFull, inSizeForReduce, encoderCommon));
       
    92 
       
    93     /*
       
    94     CMyComPtr<ICryptoResetSalt> resetSalt;
       
    95     encoderCommon.QueryInterface(IID_ICryptoResetSalt, (void **)&resetSalt);
       
    96     if (resetSalt != NULL)
       
    97     {
       
    98       resetSalt->ResetSalt();
       
    99     }
       
   100     */
       
   101 
       
   102     #ifdef EXTERNAL_CODECS
       
   103     CMyComPtr<ISetCompressCodecsInfo> setCompressCodecsInfo;
       
   104     encoderCommon.QueryInterface(IID_ISetCompressCodecsInfo, (void **)&setCompressCodecsInfo);
       
   105     if (setCompressCodecsInfo)
       
   106     {
       
   107       RINOK(setCompressCodecsInfo->SetCompressCodecsInfo(codecsInfo));
       
   108     }
       
   109     #endif
       
   110     
       
   111     CMyComPtr<ICryptoSetPassword> cryptoSetPassword;
       
   112     encoderCommon.QueryInterface(IID_ICryptoSetPassword, &cryptoSetPassword);
       
   113 
       
   114     if (cryptoSetPassword)
       
   115     {
       
   116       CByteBuffer buffer;
       
   117       const UInt32 sizeInBytes = _options.Password.Length() * 2;
       
   118       buffer.SetCapacity(sizeInBytes);
       
   119       for (int i = 0; i < _options.Password.Length(); i++)
       
   120       {
       
   121         wchar_t c = _options.Password[i];
       
   122         ((Byte *)buffer)[i * 2] = (Byte)c;
       
   123         ((Byte *)buffer)[i * 2 + 1] = (Byte)(c >> 8);
       
   124       }
       
   125       RINOK(cryptoSetPassword->CryptoSetPassword((const Byte *)buffer, sizeInBytes));
       
   126     }
       
   127 
       
   128     if (encoder)
       
   129       _mixerCoderSpec->AddCoder(encoder);
       
   130     else
       
   131       _mixerCoderSpec->AddCoder2(encoder2);
       
   132   }
       
   133   return S_OK;
       
   134 }
       
   135 
       
   136 HRESULT CEncoder::Encode(
       
   137     DECL_EXTERNAL_CODECS_LOC_VARS
       
   138     ISequentialInStream *inStream,
       
   139     const UInt64 *inStreamSize, const UInt64 *inSizeForReduce,
       
   140     CFolder &folderItem,
       
   141     ISequentialOutStream *outStream,
       
   142     CRecordVector<UInt64> &packSizes,
       
   143     ICompressProgressInfo *compressProgress)
       
   144 {
       
   145   RINOK(EncoderConstr());
       
   146 
       
   147   if (_mixerCoderSpec == NULL)
       
   148   {
       
   149     RINOK(CreateMixerCoder(EXTERNAL_CODECS_LOC_VARS inSizeForReduce));
       
   150   }
       
   151   _mixerCoderSpec->ReInit();
       
   152   // _mixerCoderSpec->SetCoderInfo(0, NULL, NULL, progress);
       
   153 
       
   154   CObjectVector<CInOutTempBuffer> inOutTempBuffers;
       
   155   CObjectVector<CSequentialOutTempBufferImp *> tempBufferSpecs;
       
   156   CObjectVector<CMyComPtr<ISequentialOutStream> > tempBuffers;
       
   157   int numMethods = _bindInfo.Coders.Size();
       
   158   int i;
       
   159   for (i = 1; i < _bindInfo.OutStreams.Size(); i++)
       
   160   {
       
   161     inOutTempBuffers.Add(CInOutTempBuffer());
       
   162     inOutTempBuffers.Back().Create();
       
   163     inOutTempBuffers.Back().InitWriting();
       
   164   }
       
   165   for (i = 1; i < _bindInfo.OutStreams.Size(); i++)
       
   166   {
       
   167     CSequentialOutTempBufferImp *tempBufferSpec = 
       
   168         new CSequentialOutTempBufferImp;
       
   169     CMyComPtr<ISequentialOutStream> tempBuffer = tempBufferSpec;
       
   170     tempBufferSpec->Init(&inOutTempBuffers[i - 1]);
       
   171     tempBuffers.Add(tempBuffer);
       
   172     tempBufferSpecs.Add(tempBufferSpec);
       
   173   }
       
   174 
       
   175   for (i = 0; i < numMethods; i++)
       
   176     _mixerCoderSpec->SetCoderInfo(i, NULL, NULL);
       
   177 
       
   178   if (_bindInfo.InStreams.IsEmpty())
       
   179     return E_FAIL;
       
   180   UInt32 mainCoderIndex, mainStreamIndex;
       
   181   _bindInfo.FindInStream(_bindInfo.InStreams[0], mainCoderIndex, mainStreamIndex);
       
   182   
       
   183   if (inStreamSize != NULL)
       
   184   {
       
   185     CRecordVector<const UInt64 *> sizePointers;
       
   186     for (UInt32 i = 0; i < _bindInfo.Coders[mainCoderIndex].NumInStreams; i++)
       
   187       if (i == mainStreamIndex)
       
   188         sizePointers.Add(inStreamSize);
       
   189       else
       
   190         sizePointers.Add(NULL);
       
   191     _mixerCoderSpec->SetCoderInfo(mainCoderIndex, &sizePointers.Front(), NULL);
       
   192   }
       
   193 
       
   194   
       
   195   // UInt64 outStreamStartPos;
       
   196   // RINOK(stream->Seek(0, STREAM_SEEK_CUR, &outStreamStartPos));
       
   197   
       
   198   CSequentialInStreamSizeCount2 *inStreamSizeCountSpec = 
       
   199       new CSequentialInStreamSizeCount2;
       
   200   CMyComPtr<ISequentialInStream> inStreamSizeCount = inStreamSizeCountSpec;
       
   201   CSequentialOutStreamSizeCount *outStreamSizeCountSpec = 
       
   202       new CSequentialOutStreamSizeCount;
       
   203   CMyComPtr<ISequentialOutStream> outStreamSizeCount = outStreamSizeCountSpec;
       
   204 
       
   205   inStreamSizeCountSpec->Init(inStream);
       
   206   outStreamSizeCountSpec->SetStream(outStream);
       
   207   outStreamSizeCountSpec->Init();
       
   208 
       
   209   CRecordVector<ISequentialInStream *> inStreamPointers;
       
   210   CRecordVector<ISequentialOutStream *> outStreamPointers;
       
   211   inStreamPointers.Add(inStreamSizeCount);
       
   212   outStreamPointers.Add(outStreamSizeCount);
       
   213   for (i = 1; i < _bindInfo.OutStreams.Size(); i++)
       
   214     outStreamPointers.Add(tempBuffers[i - 1]);
       
   215 
       
   216   for (i = 0; i < _codersInfo.Size(); i++)
       
   217   {
       
   218     CCoderInfo &encodingInfo = _codersInfo[i];
       
   219     
       
   220     CMyComPtr<ICryptoResetInitVector> resetInitVector;
       
   221     _mixerCoderSpec->_coders[i].QueryInterface(IID_ICryptoResetInitVector, (void **)&resetInitVector);
       
   222     if (resetInitVector != NULL)
       
   223     {
       
   224       resetInitVector->ResetInitVector();
       
   225     }
       
   226 
       
   227     CMyComPtr<ICompressWriteCoderProperties> writeCoderProperties;
       
   228     _mixerCoderSpec->_coders[i].QueryInterface(IID_ICompressWriteCoderProperties, (void **)&writeCoderProperties);
       
   229     if (writeCoderProperties != NULL)
       
   230     {
       
   231       CSequentialOutStreamImp *outStreamSpec = new CSequentialOutStreamImp;
       
   232       CMyComPtr<ISequentialOutStream> outStream(outStreamSpec);
       
   233       outStreamSpec->Init();
       
   234       writeCoderProperties->WriteCoderProperties(outStream);
       
   235       size_t size = outStreamSpec->GetSize();
       
   236       encodingInfo.Properties.SetCapacity(size);
       
   237       memmove(encodingInfo.Properties, outStreamSpec->GetBuffer(), size);
       
   238     }
       
   239   }
       
   240 
       
   241   UInt32 progressIndex = mainCoderIndex;
       
   242 
       
   243   for (i = 0; i < _codersInfo.Size(); i++)
       
   244   {
       
   245     const CCoderInfo &e = _codersInfo[i];
       
   246     if ((e.MethodID == k_BCJ || e.MethodID == k_BCJ2) && i + 1 < _codersInfo.Size())
       
   247       progressIndex = i + 1;
       
   248   }
       
   249 
       
   250   _mixerCoderSpec->SetProgressCoderIndex(progressIndex);
       
   251   
       
   252   RINOK(_mixerCoder->Code(&inStreamPointers.Front(), NULL, 1,
       
   253     &outStreamPointers.Front(), NULL, outStreamPointers.Size(), compressProgress));
       
   254   
       
   255   ConvertBindInfoToFolderItemInfo(_decompressBindInfo, _decompressionMethods,
       
   256       folderItem);
       
   257   
       
   258   packSizes.Add(outStreamSizeCountSpec->GetSize());
       
   259   
       
   260   for (i = 1; i < _bindInfo.OutStreams.Size(); i++)
       
   261   {
       
   262     CInOutTempBuffer &inOutTempBuffer = inOutTempBuffers[i - 1];
       
   263     inOutTempBuffer.FlushWrite();
       
   264     inOutTempBuffer.InitReading();
       
   265     inOutTempBuffer.WriteToStream(outStream);
       
   266     packSizes.Add(inOutTempBuffer.GetDataSize());
       
   267   }
       
   268   
       
   269   for (i = 0; i < (int)_bindReverseConverter->NumSrcInStreams; i++)
       
   270   {
       
   271     int binder = _bindInfo.FindBinderForInStream(
       
   272         _bindReverseConverter->DestOutToSrcInMap[i]);
       
   273     UInt64 streamSize;
       
   274     if (binder < 0)
       
   275       streamSize = inStreamSizeCountSpec->GetSize();
       
   276     else
       
   277       streamSize = _mixerCoderSpec->GetWriteProcessedSize(binder);
       
   278     folderItem.UnPackSizes.Add(streamSize);
       
   279   }
       
   280   for (i = numMethods - 1; i >= 0; i--)
       
   281     folderItem.Coders[numMethods - 1 - i].Properties = _codersInfo[i].Properties;
       
   282   return S_OK;
       
   283 }
       
   284 
       
   285 
       
   286 CEncoder::CEncoder(const CCompressionMethodMode &options):
       
   287   _bindReverseConverter(0),
       
   288   _constructed(false)
       
   289 {
       
   290   if (options.IsEmpty())
       
   291     throw 1;
       
   292 
       
   293   _options = options;
       
   294   _mixerCoderSpec = NULL;
       
   295 }
       
   296 
       
   297 HRESULT CEncoder::EncoderConstr()
       
   298 {
       
   299   if (_constructed)
       
   300     return S_OK;
       
   301   if (_options.Methods.IsEmpty())
       
   302   {
       
   303     // it has only password method;
       
   304     if (!_options.PasswordIsDefined)
       
   305       throw 1;
       
   306     if (!_options.Binds.IsEmpty())
       
   307       throw 1;
       
   308     NCoderMixer::CCoderStreamsInfo coderStreamsInfo;
       
   309     CMethodFull method;
       
   310     
       
   311     method.NumInStreams = 1;
       
   312     method.NumOutStreams = 1;
       
   313     coderStreamsInfo.NumInStreams = 1;
       
   314     coderStreamsInfo.NumOutStreams = 1;
       
   315     method.Id = k_AES;
       
   316     
       
   317     _options.Methods.Add(method);
       
   318     _bindInfo.Coders.Add(coderStreamsInfo);
       
   319   
       
   320     _bindInfo.InStreams.Add(0);
       
   321     _bindInfo.OutStreams.Add(0);
       
   322   }
       
   323   else
       
   324   {
       
   325 
       
   326   UInt32 numInStreams = 0, numOutStreams = 0;
       
   327   int i;
       
   328   for (i = 0; i < _options.Methods.Size(); i++)
       
   329   {
       
   330     const CMethodFull &methodFull = _options.Methods[i];
       
   331     NCoderMixer::CCoderStreamsInfo coderStreamsInfo;
       
   332     coderStreamsInfo.NumInStreams = methodFull.NumOutStreams;
       
   333     coderStreamsInfo.NumOutStreams = methodFull.NumInStreams;
       
   334     if (_options.Binds.IsEmpty())
       
   335     {
       
   336       if (i < _options.Methods.Size() - 1)
       
   337       {
       
   338         NCoderMixer::CBindPair bindPair;
       
   339         bindPair.InIndex = numInStreams + coderStreamsInfo.NumInStreams;
       
   340         bindPair.OutIndex = numOutStreams;
       
   341         _bindInfo.BindPairs.Add(bindPair);
       
   342       }
       
   343       else
       
   344         _bindInfo.OutStreams.Insert(0, numOutStreams);
       
   345       for (UInt32 j = 1; j < coderStreamsInfo.NumOutStreams; j++)
       
   346         _bindInfo.OutStreams.Add(numOutStreams + j);
       
   347     }
       
   348     
       
   349     numInStreams += coderStreamsInfo.NumInStreams;
       
   350     numOutStreams += coderStreamsInfo.NumOutStreams;
       
   351 
       
   352     _bindInfo.Coders.Add(coderStreamsInfo);
       
   353   }
       
   354 
       
   355   if (!_options.Binds.IsEmpty())
       
   356   {
       
   357     for (i = 0; i < _options.Binds.Size(); i++)
       
   358     {
       
   359       NCoderMixer::CBindPair bindPair;
       
   360       const CBind &bind = _options.Binds[i];
       
   361       bindPair.InIndex = _bindInfo.GetCoderInStreamIndex(bind.InCoder) + bind.InStream;
       
   362       bindPair.OutIndex = _bindInfo.GetCoderOutStreamIndex(bind.OutCoder) + bind.OutStream;
       
   363       _bindInfo.BindPairs.Add(bindPair);
       
   364     }
       
   365     for (i = 0; i < (int)numOutStreams; i++)
       
   366       if (_bindInfo.FindBinderForOutStream(i) == -1)
       
   367         _bindInfo.OutStreams.Add(i);
       
   368   }
       
   369 
       
   370   for (i = 0; i < (int)numInStreams; i++)
       
   371     if (_bindInfo.FindBinderForInStream(i) == -1)
       
   372       _bindInfo.InStreams.Add(i);
       
   373 
       
   374   if (_bindInfo.InStreams.IsEmpty())
       
   375     throw 1; // this is error
       
   376 
       
   377   // Make main stream first in list
       
   378   int inIndex = _bindInfo.InStreams[0];
       
   379   for (;;)
       
   380   {
       
   381     UInt32 coderIndex, coderStreamIndex;
       
   382     _bindInfo.FindInStream(inIndex, coderIndex, coderStreamIndex);
       
   383     UInt32 outIndex = _bindInfo.GetCoderOutStreamIndex(coderIndex);
       
   384     int binder = _bindInfo.FindBinderForOutStream(outIndex);
       
   385     if (binder >= 0)
       
   386     {
       
   387       inIndex = _bindInfo.BindPairs[binder].InIndex;
       
   388       continue;
       
   389     }
       
   390     for (i = 0; i < _bindInfo.OutStreams.Size(); i++)
       
   391       if (_bindInfo.OutStreams[i] == outIndex)
       
   392       {
       
   393         _bindInfo.OutStreams.Delete(i);
       
   394         _bindInfo.OutStreams.Insert(0, outIndex);
       
   395         break;
       
   396       }
       
   397     break;
       
   398   }
       
   399 
       
   400   if (_options.PasswordIsDefined)
       
   401   {
       
   402     int numCryptoStreams = _bindInfo.OutStreams.Size();
       
   403 
       
   404     for (i = 0; i < numCryptoStreams; i++)
       
   405     {
       
   406       NCoderMixer::CBindPair bindPair;
       
   407       bindPair.InIndex = numInStreams + i;
       
   408       bindPair.OutIndex = _bindInfo.OutStreams[i];
       
   409       _bindInfo.BindPairs.Add(bindPair);
       
   410     }
       
   411     _bindInfo.OutStreams.Clear();
       
   412 
       
   413     /*
       
   414     if (numCryptoStreams == 0)
       
   415       numCryptoStreams = 1;
       
   416     */
       
   417 
       
   418     for (i = 0; i < numCryptoStreams; i++)
       
   419     {
       
   420       NCoderMixer::CCoderStreamsInfo coderStreamsInfo;
       
   421       CMethodFull method;
       
   422       method.NumInStreams = 1;
       
   423       method.NumOutStreams = 1;
       
   424       coderStreamsInfo.NumInStreams = method.NumOutStreams;
       
   425       coderStreamsInfo.NumOutStreams = method.NumInStreams;
       
   426       method.Id = k_AES;
       
   427 
       
   428       _options.Methods.Add(method);
       
   429       _bindInfo.Coders.Add(coderStreamsInfo);
       
   430       _bindInfo.OutStreams.Add(numOutStreams + i);
       
   431     }
       
   432   }
       
   433 
       
   434   }
       
   435 
       
   436   for (int i = _options.Methods.Size() - 1; i >= 0; i--)
       
   437   {
       
   438     const CMethodFull &methodFull = _options.Methods[i];
       
   439     _decompressionMethods.Add(methodFull.Id);
       
   440   }
       
   441 
       
   442   _bindReverseConverter = new NCoderMixer::CBindReverseConverter(_bindInfo);
       
   443   _bindReverseConverter->CreateReverseBindInfo(_decompressBindInfo);
       
   444   _constructed = true;
       
   445   return S_OK;
       
   446 }
       
   447 
       
   448 CEncoder::~CEncoder()
       
   449 {
       
   450   delete _bindReverseConverter;
       
   451 }
       
   452 
       
   453 }}