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