| // 7zEncode.cpp | |
| #include "StdAfx.h" | |
| #include "../../Common/CreateCoder.h" | |
| #include "../../Common/FilterCoder.h" | |
| #include "../../Common/LimitedStreams.h" | |
| #include "../../Common/InOutTempBuffer.h" | |
| #include "../../Common/ProgressUtils.h" | |
| #include "../../Common/StreamObjects.h" | |
| #include "7zEncode.h" | |
| #include "7zSpecStream.h" | |
| static const UInt64 k_Delta = 0x03; | |
| static const UInt64 k_BCJ = 0x03030103; | |
| static const UInt64 k_BCJ2 = 0x0303011B; | |
| namespace NArchive { | |
| namespace N7z { | |
| static void ConvertBindInfoToFolderItemInfo(const NCoderMixer::CBindInfo &bindInfo, | |
| const CRecordVector<CMethodId> decompressionMethods, | |
| CFolder &folder) | |
| { | |
| // bindInfo.CoderMethodIDs.Clear(); | |
| // folder.OutStreams.Clear(); | |
| folder.BindPairs.SetSize(bindInfo.BindPairs.Size()); | |
| unsigned i; | |
| for (i = 0; i < bindInfo.BindPairs.Size(); i++) | |
| { | |
| CBindPair &bp = folder.BindPairs[i]; | |
| const NCoderMixer::CBindPair &mixerBp = bindInfo.BindPairs[i]; | |
| bp.InIndex = mixerBp.InIndex; | |
| bp.OutIndex = mixerBp.OutIndex; | |
| } | |
| folder.Coders.SetSize(bindInfo.Coders.Size()); | |
| for (i = 0; i < bindInfo.Coders.Size(); i++) | |
| { | |
| CCoderInfo &coderInfo = folder.Coders[i]; | |
| const NCoderMixer::CCoderStreamsInfo &coderStreamsInfo = bindInfo.Coders[i]; | |
| coderInfo.NumInStreams = coderStreamsInfo.NumInStreams; | |
| coderInfo.NumOutStreams = coderStreamsInfo.NumOutStreams; | |
| coderInfo.MethodID = decompressionMethods[i]; | |
| // coderInfo.Props can be nonFree; | |
| } | |
| folder.PackStreams.SetSize(bindInfo.InStreams.Size()); | |
| for (i = 0; i < bindInfo.InStreams.Size(); i++) | |
| folder.PackStreams[i] = bindInfo.InStreams[i]; | |
| } | |
| static HRESULT SetCoderProps2(const CProps &props, const UInt64 *dataSizeReduce, IUnknown *coder) | |
| { | |
| CMyComPtr<ICompressSetCoderProperties> setCoderProperties; | |
| coder->QueryInterface(IID_ICompressSetCoderProperties, (void **)&setCoderProperties); | |
| if (setCoderProperties) | |
| return props.SetCoderProps(setCoderProperties, dataSizeReduce); | |
| return props.AreThereNonOptionalProps() ? E_INVALIDARG : S_OK; | |
| } | |
| HRESULT CEncoder::CreateMixerCoder( | |
| DECL_EXTERNAL_CODECS_LOC_VARS | |
| const UInt64 *inSizeForReduce) | |
| { | |
| _mixerCoderSpec = new NCoderMixer::CCoderMixer2MT; | |
| _mixerCoder = _mixerCoderSpec; | |
| RINOK(_mixerCoderSpec->SetBindInfo(_bindInfo)); | |
| FOR_VECTOR (i, _options.Methods) | |
| { | |
| const CMethodFull &methodFull = _options.Methods[i]; | |
| CCoderInfo &encodingInfo = _codersInfo.AddNew(); | |
| encodingInfo.MethodID = methodFull.Id; | |
| CMyComPtr<ICompressCoder> encoder; | |
| CMyComPtr<ICompressCoder2> encoder2; | |
| RINOK(CreateCoder( | |
| EXTERNAL_CODECS_LOC_VARS | |
| methodFull.Id, encoder, encoder2, true)); | |
| if (!encoder && !encoder2) | |
| return E_FAIL; | |
| CMyComPtr<IUnknown> encoderCommon = encoder ? (IUnknown *)encoder : (IUnknown *)encoder2; | |
| #ifndef _7ZIP_ST | |
| { | |
| CMyComPtr<ICompressSetCoderMt> setCoderMt; | |
| encoderCommon.QueryInterface(IID_ICompressSetCoderMt, &setCoderMt); | |
| if (setCoderMt) | |
| { | |
| RINOK(setCoderMt->SetNumberOfThreads(_options.NumThreads)); | |
| } | |
| } | |
| #endif | |
| RINOK(SetCoderProps2(methodFull, inSizeForReduce, encoderCommon)); | |
| /* | |
| CMyComPtr<ICryptoResetSalt> resetSalt; | |
| encoderCommon.QueryInterface(IID_ICryptoResetSalt, (void **)&resetSalt); | |
| if (resetSalt) | |
| { | |
| resetSalt->ResetSalt(); | |
| } | |
| */ | |
| #ifdef EXTERNAL_CODECS | |
| CMyComPtr<ISetCompressCodecsInfo> setCompressCodecsInfo; | |
| encoderCommon.QueryInterface(IID_ISetCompressCodecsInfo, (void **)&setCompressCodecsInfo); | |
| if (setCompressCodecsInfo) | |
| { | |
| RINOK(setCompressCodecsInfo->SetCompressCodecsInfo(__externalCodecs->GetCodecs)); | |
| } | |
| #endif | |
| CMyComPtr<ICryptoSetPassword> cryptoSetPassword; | |
| encoderCommon.QueryInterface(IID_ICryptoSetPassword, &cryptoSetPassword); | |
| if (cryptoSetPassword) | |
| { | |
| const UInt32 sizeInBytes = _options.Password.Len() * 2; | |
| CByteBuffer buffer(sizeInBytes); | |
| for (unsigned i = 0; i < _options.Password.Len(); i++) | |
| { | |
| wchar_t c = _options.Password[i]; | |
| ((Byte *)buffer)[i * 2] = (Byte)c; | |
| ((Byte *)buffer)[i * 2 + 1] = (Byte)(c >> 8); | |
| } | |
| RINOK(cryptoSetPassword->CryptoSetPassword((const Byte *)buffer, sizeInBytes)); | |
| } | |
| if (encoder) | |
| _mixerCoderSpec->AddCoder(encoder); | |
| else | |
| _mixerCoderSpec->AddCoder2(encoder2); | |
| } | |
| return S_OK; | |
| } | |
| HRESULT CEncoder::Encode( | |
| DECL_EXTERNAL_CODECS_LOC_VARS | |
| ISequentialInStream *inStream, | |
| const UInt64 *inStreamSize, const UInt64 *inSizeForReduce, | |
| CFolder &folderItem, | |
| CRecordVector<UInt64> &coderUnpackSizes, | |
| UInt64 &unpackSize, | |
| ISequentialOutStream *outStream, | |
| CRecordVector<UInt64> &packSizes, | |
| ICompressProgressInfo *compressProgress) | |
| { | |
| RINOK(EncoderConstr()); | |
| if (!_mixerCoderSpec) | |
| { | |
| RINOK(CreateMixerCoder(EXTERNAL_CODECS_LOC_VARS inSizeForReduce)); | |
| } | |
| _mixerCoderSpec->ReInit(); | |
| // _mixerCoderSpec->SetCoderInfo(0, NULL, NULL, progress); | |
| CObjectVector<CInOutTempBuffer> inOutTempBuffers; | |
| CObjectVector<CSequentialOutTempBufferImp *> tempBufferSpecs; | |
| CObjectVector<CMyComPtr<ISequentialOutStream> > tempBuffers; | |
| unsigned numMethods = _bindInfo.Coders.Size(); | |
| unsigned i; | |
| for (i = 1; i < _bindInfo.OutStreams.Size(); i++) | |
| { | |
| CInOutTempBuffer &iotb = inOutTempBuffers.AddNew(); | |
| iotb.Create(); | |
| iotb.InitWriting(); | |
| } | |
| for (i = 1; i < _bindInfo.OutStreams.Size(); i++) | |
| { | |
| CSequentialOutTempBufferImp *tempBufferSpec = new CSequentialOutTempBufferImp; | |
| CMyComPtr<ISequentialOutStream> tempBuffer = tempBufferSpec; | |
| tempBufferSpec->Init(&inOutTempBuffers[i - 1]); | |
| tempBuffers.Add(tempBuffer); | |
| tempBufferSpecs.Add(tempBufferSpec); | |
| } | |
| for (i = 0; i < numMethods; i++) | |
| _mixerCoderSpec->SetCoderInfo(i, NULL, NULL); | |
| if (_bindInfo.InStreams.IsEmpty()) | |
| return E_FAIL; | |
| UInt32 mainCoderIndex, mainStreamIndex; | |
| _bindInfo.FindInStream(_bindInfo.InStreams[0], mainCoderIndex, mainStreamIndex); | |
| if (inStreamSize) | |
| { | |
| CRecordVector<const UInt64 *> sizePointers; | |
| for (UInt32 i = 0; i < _bindInfo.Coders[mainCoderIndex].NumInStreams; i++) | |
| if (i == mainStreamIndex) | |
| sizePointers.Add(inStreamSize); | |
| else | |
| sizePointers.Add(NULL); | |
| _mixerCoderSpec->SetCoderInfo(mainCoderIndex, &sizePointers.Front(), NULL); | |
| } | |
| // UInt64 outStreamStartPos; | |
| // RINOK(stream->Seek(0, STREAM_SEEK_CUR, &outStreamStartPos)); | |
| CSequentialInStreamSizeCount2 *inStreamSizeCountSpec = new CSequentialInStreamSizeCount2; | |
| CMyComPtr<ISequentialInStream> inStreamSizeCount = inStreamSizeCountSpec; | |
| CSequentialOutStreamSizeCount *outStreamSizeCountSpec = NULL; | |
| CMyComPtr<ISequentialOutStream> outStreamSizeCount; | |
| inStreamSizeCountSpec->Init(inStream); | |
| CRecordVector<ISequentialInStream *> inStreamPointers; | |
| CRecordVector<ISequentialOutStream *> outStreamPointers; | |
| inStreamPointers.Add(inStreamSizeCount); | |
| if (_bindInfo.OutStreams.Size() != 0) | |
| { | |
| outStreamSizeCountSpec = new CSequentialOutStreamSizeCount; | |
| outStreamSizeCount = outStreamSizeCountSpec; | |
| outStreamSizeCountSpec->SetStream(outStream); | |
| outStreamSizeCountSpec->Init(); | |
| outStreamPointers.Add(outStreamSizeCount); | |
| } | |
| for (i = 1; i < _bindInfo.OutStreams.Size(); i++) | |
| outStreamPointers.Add(tempBuffers[i - 1]); | |
| for (i = 0; i < _codersInfo.Size(); i++) | |
| { | |
| CCoderInfo &encodingInfo = _codersInfo[i]; | |
| CMyComPtr<ICryptoResetInitVector> resetInitVector; | |
| _mixerCoderSpec->_coders[i].QueryInterface(IID_ICryptoResetInitVector, (void **)&resetInitVector); | |
| if (resetInitVector) | |
| { | |
| resetInitVector->ResetInitVector(); | |
| } | |
| CMyComPtr<ICompressWriteCoderProperties> writeCoderProperties; | |
| _mixerCoderSpec->_coders[i].QueryInterface(IID_ICompressWriteCoderProperties, (void **)&writeCoderProperties); | |
| if (writeCoderProperties) | |
| { | |
| CDynBufSeqOutStream *outStreamSpec = new CDynBufSeqOutStream; | |
| CMyComPtr<ISequentialOutStream> outStream(outStreamSpec); | |
| outStreamSpec->Init(); | |
| writeCoderProperties->WriteCoderProperties(outStream); | |
| outStreamSpec->CopyToBuffer(encodingInfo.Props); | |
| } | |
| } | |
| UInt32 progressIndex = mainCoderIndex; | |
| for (i = 0; i + 1 < _codersInfo.Size(); i++) | |
| { | |
| UInt64 m = _codersInfo[i].MethodID; | |
| if (m == k_Delta || m == k_BCJ || m == k_BCJ2) | |
| progressIndex = i + 1; | |
| } | |
| _mixerCoderSpec->SetProgressCoderIndex(progressIndex); | |
| RINOK(_mixerCoder->Code(&inStreamPointers.Front(), NULL, 1, | |
| &outStreamPointers.Front(), NULL, outStreamPointers.Size(), compressProgress)); | |
| ConvertBindInfoToFolderItemInfo(_decompressBindInfo, _decompressionMethods, folderItem); | |
| if (_bindInfo.OutStreams.Size() != 0) | |
| packSizes.Add(outStreamSizeCountSpec->GetSize()); | |
| for (i = 1; i < _bindInfo.OutStreams.Size(); i++) | |
| { | |
| CInOutTempBuffer &inOutTempBuffer = inOutTempBuffers[i - 1]; | |
| RINOK(inOutTempBuffer.WriteToStream(outStream)); | |
| packSizes.Add(inOutTempBuffer.GetDataSize()); | |
| } | |
| unpackSize = 0; | |
| for (i = 0; i < (int)_bindReverseConverter->NumSrcInStreams; i++) | |
| { | |
| int binder = _bindInfo.FindBinderForInStream( | |
| _bindReverseConverter->DestOutToSrcInMap[i]); | |
| UInt64 streamSize; | |
| if (binder < 0) | |
| { | |
| streamSize = inStreamSizeCountSpec->GetSize(); | |
| unpackSize = streamSize; | |
| } | |
| else | |
| streamSize = _mixerCoderSpec->GetWriteProcessedSize(binder); | |
| coderUnpackSizes.Add(streamSize); | |
| } | |
| for (i = 0; i < numMethods; i++) | |
| folderItem.Coders[numMethods - 1 - i].Props = _codersInfo[i].Props; | |
| return S_OK; | |
| } | |
| CEncoder::CEncoder(const CCompressionMethodMode &options): | |
| _bindReverseConverter(0), | |
| _constructed(false) | |
| { | |
| if (options.IsEmpty()) | |
| throw 1; | |
| _options = options; | |
| _mixerCoderSpec = NULL; | |
| } | |
| HRESULT CEncoder::EncoderConstr() | |
| { | |
| if (_constructed) | |
| return S_OK; | |
| if (_options.Methods.IsEmpty()) | |
| { | |
| // it has only password method; | |
| if (!_options.PasswordIsDefined) | |
| throw 1; | |
| if (!_options.Binds.IsEmpty()) | |
| throw 1; | |
| NCoderMixer::CCoderStreamsInfo coderStreamsInfo; | |
| CMethodFull method; | |
| method.NumInStreams = 1; | |
| method.NumOutStreams = 1; | |
| coderStreamsInfo.NumInStreams = 1; | |
| coderStreamsInfo.NumOutStreams = 1; | |
| method.Id = k_AES; | |
| _options.Methods.Add(method); | |
| _bindInfo.Coders.Add(coderStreamsInfo); | |
| _bindInfo.InStreams.Add(0); | |
| _bindInfo.OutStreams.Add(0); | |
| } | |
| else | |
| { | |
| UInt32 numInStreams = 0, numOutStreams = 0; | |
| unsigned i; | |
| for (i = 0; i < _options.Methods.Size(); i++) | |
| { | |
| const CMethodFull &methodFull = _options.Methods[i]; | |
| NCoderMixer::CCoderStreamsInfo coderStreamsInfo; | |
| coderStreamsInfo.NumInStreams = methodFull.NumOutStreams; | |
| coderStreamsInfo.NumOutStreams = methodFull.NumInStreams; | |
| if (_options.Binds.IsEmpty()) | |
| { | |
| if (i < _options.Methods.Size() - 1) | |
| { | |
| NCoderMixer::CBindPair bindPair; | |
| bindPair.InIndex = numInStreams + coderStreamsInfo.NumInStreams; | |
| bindPair.OutIndex = numOutStreams; | |
| _bindInfo.BindPairs.Add(bindPair); | |
| } | |
| else if (coderStreamsInfo.NumOutStreams != 0) | |
| _bindInfo.OutStreams.Insert(0, numOutStreams); | |
| for (UInt32 j = 1; j < coderStreamsInfo.NumOutStreams; j++) | |
| _bindInfo.OutStreams.Add(numOutStreams + j); | |
| } | |
| numInStreams += coderStreamsInfo.NumInStreams; | |
| numOutStreams += coderStreamsInfo.NumOutStreams; | |
| _bindInfo.Coders.Add(coderStreamsInfo); | |
| } | |
| if (!_options.Binds.IsEmpty()) | |
| { | |
| for (i = 0; i < _options.Binds.Size(); i++) | |
| { | |
| NCoderMixer::CBindPair bindPair; | |
| const CBind &bind = _options.Binds[i]; | |
| bindPair.InIndex = _bindInfo.GetCoderInStreamIndex(bind.InCoder) + bind.InStream; | |
| bindPair.OutIndex = _bindInfo.GetCoderOutStreamIndex(bind.OutCoder) + bind.OutStream; | |
| _bindInfo.BindPairs.Add(bindPair); | |
| } | |
| for (i = 0; i < (int)numOutStreams; i++) | |
| if (_bindInfo.FindBinderForOutStream(i) == -1) | |
| _bindInfo.OutStreams.Add(i); | |
| } | |
| for (i = 0; i < (int)numInStreams; i++) | |
| if (_bindInfo.FindBinderForInStream(i) == -1) | |
| _bindInfo.InStreams.Add(i); | |
| if (_bindInfo.InStreams.IsEmpty()) | |
| throw 1; // this is error | |
| // Make main stream first in list | |
| int inIndex = _bindInfo.InStreams[0]; | |
| for (;;) | |
| { | |
| UInt32 coderIndex, coderStreamIndex; | |
| _bindInfo.FindInStream(inIndex, coderIndex, coderStreamIndex); | |
| UInt32 outIndex = _bindInfo.GetCoderOutStreamIndex(coderIndex); | |
| int binder = _bindInfo.FindBinderForOutStream(outIndex); | |
| if (binder >= 0) | |
| { | |
| inIndex = _bindInfo.BindPairs[binder].InIndex; | |
| continue; | |
| } | |
| for (i = 0; i < _bindInfo.OutStreams.Size(); i++) | |
| if (_bindInfo.OutStreams[i] == outIndex) | |
| { | |
| _bindInfo.OutStreams.Delete(i); | |
| _bindInfo.OutStreams.Insert(0, outIndex); | |
| break; | |
| } | |
| break; | |
| } | |
| if (_options.PasswordIsDefined) | |
| { | |
| unsigned numCryptoStreams = _bindInfo.OutStreams.Size(); | |
| for (i = 0; i < numCryptoStreams; i++) | |
| { | |
| NCoderMixer::CBindPair bindPair; | |
| bindPair.InIndex = numInStreams + i; | |
| bindPair.OutIndex = _bindInfo.OutStreams[i]; | |
| _bindInfo.BindPairs.Add(bindPair); | |
| } | |
| _bindInfo.OutStreams.Clear(); | |
| /* | |
| if (numCryptoStreams == 0) | |
| numCryptoStreams = 1; | |
| */ | |
| for (i = 0; i < numCryptoStreams; i++) | |
| { | |
| NCoderMixer::CCoderStreamsInfo coderStreamsInfo; | |
| CMethodFull method; | |
| method.NumInStreams = 1; | |
| method.NumOutStreams = 1; | |
| coderStreamsInfo.NumInStreams = method.NumOutStreams; | |
| coderStreamsInfo.NumOutStreams = method.NumInStreams; | |
| method.Id = k_AES; | |
| _options.Methods.Add(method); | |
| _bindInfo.Coders.Add(coderStreamsInfo); | |
| _bindInfo.OutStreams.Add(numOutStreams + i); | |
| } | |
| } | |
| } | |
| for (int i = _options.Methods.Size() - 1; i >= 0; i--) | |
| { | |
| const CMethodFull &methodFull = _options.Methods[i]; | |
| _decompressionMethods.Add(methodFull.Id); | |
| } | |
| _bindReverseConverter = new NCoderMixer::CBindReverseConverter(_bindInfo); | |
| _bindReverseConverter->CreateReverseBindInfo(_decompressBindInfo); | |
| _constructed = true; | |
| return S_OK; | |
| } | |
| CEncoder::~CEncoder() | |
| { | |
| delete _bindReverseConverter; | |
| } | |
| }} |