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