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