HRESULT CreateCoder( DECL_EXTERNAL_CODECS_LOC_VARS CMethodId methodId, CMyComPtr<ICompressCoder> &coder, bool encode) { CMyComPtr<ICompressFilter> filter; CMyComPtr<ICompressCoder2> coder2; return CreateCoder( EXTERNAL_CODECS_LOC_VARS methodId, coder, coder2, encode); }
STDAPI CreateObject(const GUID *clsid, const GUID *iid, void **outObject) { // COM_TRY_BEGIN *outObject = 0; if (*iid == IID_ICompressCoder || *iid == IID_ICompressCoder2 || *iid == IID_ICompressFilter) { return CreateCoder(clsid, iid, outObject); } else { return CreateArchiver(clsid, iid, outObject); } // COM_TRY_END }
HRESULT CAddCommon::Compress( DECL_EXTERNAL_CODECS_LOC_VARS ISequentialInStream *inStream, IOutStream *outStream, ICompressProgressInfo *progress, CCompressingResult &operationResult) { CSequentialInStreamWithCRC *inSecCrcStreamSpec = 0; CInStreamWithCRC *inCrcStreamSpec = 0; CMyComPtr<ISequentialInStream> inCrcStream; { CMyComPtr<IInStream> inStream2; // we don't support stdin, since stream from stdin can require 64-bit size header RINOK(inStream->QueryInterface(IID_IInStream, (void **)&inStream2)); if (inStream2) { inCrcStreamSpec = new CInStreamWithCRC; inCrcStream = inCrcStreamSpec; inCrcStreamSpec->SetStream(inStream2); inCrcStreamSpec->Init(); } else { inSecCrcStreamSpec = new CSequentialInStreamWithCRC; inCrcStream = inSecCrcStreamSpec; inSecCrcStreamSpec->SetStream(inStream); inSecCrcStreamSpec->Init(); } } int numTestMethods = _options.MethodSequence.Size(); if (numTestMethods > 1 || _options.PasswordIsDefined) { if (inCrcStreamSpec == 0) { if (_options.PasswordIsDefined) return E_NOTIMPL; numTestMethods = 1; } } Byte method = 0; COutStreamReleaser outStreamReleaser; for (int i = 0; i < numTestMethods; i++) { if (inCrcStreamSpec != 0) RINOK(inCrcStreamSpec->Seek(0, STREAM_SEEK_SET, NULL)); RINOK(outStream->Seek(0, STREAM_SEEK_SET, NULL)); if (_options.PasswordIsDefined) { if (!_cryptoStream) { _cryptoStreamSpec = new CFilterCoder; _cryptoStream = _cryptoStreamSpec; } if (_options.IsAesMode) { _cryptoStreamSpec->Filter = _aesFilter = _filterAesSpec = new NCrypto::NWzAes::CEncoder; _filterAesSpec->SetKeyMode(_options.AesKeyMode); RINOK(_filterAesSpec->CryptoSetPassword( (const Byte *)(const char *)_options.Password, _options.Password.Length())); RINOK(_filterAesSpec->WriteHeader(outStream)); } else { _cryptoStreamSpec->Filter = _zipCryptoFilter = _filterSpec = new NCrypto::NZip::CEncoder; RINOK(_filterSpec->CryptoSetPassword( (const Byte *)(const char *)_options.Password, _options.Password.Length())); UInt32 crc = 0; RINOK(GetStreamCRC(inStream, crc)); RINOK(inCrcStreamSpec->Seek(0, STREAM_SEEK_SET, NULL)); RINOK(_filterSpec->CryptoSetCRC(crc)); RINOK(_filterSpec->WriteHeader(outStream)); } RINOK(_cryptoStreamSpec->SetOutStream(outStream)); outStreamReleaser.FilterCoder = _cryptoStreamSpec; } method = _options.MethodSequence[i]; switch(method) { case NFileHeader::NCompressionMethod::kStored: { if (_copyCoderSpec == NULL) { _copyCoderSpec = new NCompress::CCopyCoder; _copyCoder = _copyCoderSpec; } CMyComPtr<ISequentialOutStream> outStreamNew; if (_options.PasswordIsDefined) outStreamNew = _cryptoStream; else outStreamNew = outStream; RINOK(_copyCoder->Code(inCrcStream, outStreamNew, NULL, NULL, progress)); operationResult.ExtractVersion = NFileHeader::NCompressionMethod::kStoreExtractVersion; break; } default: { if (!_compressEncoder) { if (method == NFileHeader::NCompressionMethod::kLZMA) { CLzmaEncoder *_lzmaEncoder = new CLzmaEncoder(); _compressEncoder = _lzmaEncoder; NWindows::NCOM::CPropVariant props[] = { #ifdef COMPRESS_MT _options.NumThreads, #endif _options.Algo, _options.DicSize, _options.NumFastBytes, (BSTR)(const wchar_t *)_options.MatchFinder, _options.NumMatchFinderCycles }; PROPID propIDs[] = { #ifdef COMPRESS_MT NCoderPropID::kNumThreads, #endif NCoderPropID::kAlgorithm, NCoderPropID::kDictionarySize, NCoderPropID::kNumFastBytes, NCoderPropID::kMatchFinder, NCoderPropID::kMatchFinderCycles }; int numProps = sizeof(propIDs) / sizeof(propIDs[0]); if (!_options.NumMatchFinderCyclesDefined) numProps--; RINOK(_lzmaEncoder->SetCoderProperties(propIDs, props, numProps)); } else { CMethodId methodId; switch(method) { case NFileHeader::NCompressionMethod::kBZip2: methodId = kMethodId_BZip2; break; default: methodId = kMethodId_ZipBase + method; break; } RINOK(CreateCoder( EXTERNAL_CODECS_LOC_VARS methodId, _compressEncoder, true)); if (!_compressEncoder) return E_NOTIMPL; if (method == NFileHeader::NCompressionMethod::kDeflated || method == NFileHeader::NCompressionMethod::kDeflated64) { NWindows::NCOM::CPropVariant props[] = { _options.Algo, _options.NumPasses, _options.NumFastBytes, _options.NumMatchFinderCycles }; PROPID propIDs[] = { NCoderPropID::kAlgorithm, NCoderPropID::kNumPasses, NCoderPropID::kNumFastBytes, NCoderPropID::kMatchFinderCycles }; int numProps = sizeof(propIDs) / sizeof(propIDs[0]); if (!_options.NumMatchFinderCyclesDefined) numProps--; CMyComPtr<ICompressSetCoderProperties> setCoderProperties; _compressEncoder.QueryInterface(IID_ICompressSetCoderProperties, &setCoderProperties); if (setCoderProperties) { RINOK(setCoderProperties->SetCoderProperties(propIDs, props, numProps)); } } else if (method == NFileHeader::NCompressionMethod::kBZip2) { NWindows::NCOM::CPropVariant props[] = { _options.DicSize, _options.NumPasses #ifdef COMPRESS_MT , _options.NumThreads #endif }; PROPID propIDs[] = { NCoderPropID::kDictionarySize, NCoderPropID::kNumPasses #ifdef COMPRESS_MT , NCoderPropID::kNumThreads #endif }; CMyComPtr<ICompressSetCoderProperties> setCoderProperties; _compressEncoder.QueryInterface(IID_ICompressSetCoderProperties, &setCoderProperties); if (setCoderProperties) { RINOK(setCoderProperties->SetCoderProperties(propIDs, props, sizeof(propIDs) / sizeof(propIDs[0]))); } } } } CMyComPtr<ISequentialOutStream> outStreamNew; if (_options.PasswordIsDefined) outStreamNew = _cryptoStream; else outStreamNew = outStream; RINOK(_compressEncoder->Code(inCrcStream, outStreamNew, NULL, NULL, progress)); operationResult.ExtractVersion = NFileHeader::NCompressionMethod::kDeflateExtractVersion; break; } } RINOK(outStream->Seek(0, STREAM_SEEK_CUR, &operationResult.PackSize)); if (inCrcStreamSpec != 0) { operationResult.CRC = inCrcStreamSpec->GetCRC(); operationResult.UnpackSize = inCrcStreamSpec->GetSize(); } else { operationResult.CRC = inSecCrcStreamSpec->GetCRC(); operationResult.UnpackSize = inSecCrcStreamSpec->GetSize(); } if (_options.PasswordIsDefined) { if (operationResult.PackSize < operationResult.UnpackSize + (_options.IsAesMode ? _filterAesSpec->GetHeaderSize() : NCrypto::NZip::kHeaderSize)) break; } else if (operationResult.PackSize < operationResult.UnpackSize) break; } if (_options.IsAesMode) { RINOK(_filterAesSpec->WriteFooter(outStream)); RINOK(outStream->Seek(0, STREAM_SEEK_CUR, &operationResult.PackSize)); } operationResult.Method = method; return outStream->SetSize(operationResult.PackSize); }
HRESULT CDecoder::Decode( DECL_EXTERNAL_CODECS_LOC_VARS IInStream *inStream, UInt64 startPos, const UInt64 *packSizes, const CFolder &folderInfo, ISequentialOutStream *outStream, ICompressProgressInfo *compressProgress #ifndef _NO_CRYPTO , ICryptoGetTextPassword *getTextPassword, bool &passwordIsDefined #endif #ifdef COMPRESS_MT , bool mtMode, UInt32 numThreads #endif ) { if (!folderInfo.CheckStructure()) return E_NOTIMPL; #ifndef _NO_CRYPTO passwordIsDefined = false; #endif CObjectVector< CMyComPtr<ISequentialInStream> > inStreams; CLockedInStream lockedInStream; lockedInStream.Init(inStream); for (int j = 0; j < folderInfo.PackStreams.Size(); j++) { CLockedSequentialInStreamImp *lockedStreamImpSpec = new CLockedSequentialInStreamImp; CMyComPtr<ISequentialInStream> lockedStreamImp = lockedStreamImpSpec; lockedStreamImpSpec->Init(&lockedInStream, startPos); startPos += packSizes[j]; CLimitedSequentialInStream *streamSpec = new CLimitedSequentialInStream; CMyComPtr<ISequentialInStream> inStream = streamSpec; streamSpec->SetStream(lockedStreamImp); streamSpec->Init(packSizes[j]); inStreams.Add(inStream); } int numCoders = folderInfo.Coders.Size(); CBindInfoEx bindInfo; ConvertFolderItemInfoToBindInfo(folderInfo, bindInfo); bool createNewCoders; if (!_bindInfoExPrevIsDefined) createNewCoders = true; else createNewCoders = !AreBindInfoExEqual(bindInfo, _bindInfoExPrev); if (createNewCoders) { int i; _decoders.Clear(); // _decoders2.Clear(); _mixerCoder.Release(); if (_multiThread) { _mixerCoderMTSpec = new NCoderMixer::CCoderMixer2MT; _mixerCoder = _mixerCoderMTSpec; _mixerCoderCommon = _mixerCoderMTSpec; } else { #ifdef _ST_MODE _mixerCoderSTSpec = new NCoderMixer::CCoderMixer2ST; _mixerCoder = _mixerCoderSTSpec; _mixerCoderCommon = _mixerCoderSTSpec; #endif } RINOK(_mixerCoderCommon->SetBindInfo(bindInfo)); for (i = 0; i < numCoders; i++) { const CCoderInfo &coderInfo = folderInfo.Coders[i]; CMyComPtr<ICompressCoder> decoder; CMyComPtr<ICompressCoder2> decoder2; RINOK(CreateCoder( EXTERNAL_CODECS_LOC_VARS coderInfo.MethodID, decoder, decoder2, false)); CMyComPtr<IUnknown> decoderUnknown; if (coderInfo.IsSimpleCoder()) { if (decoder == 0) return E_NOTIMPL; decoderUnknown = (IUnknown *)decoder; if (_multiThread) _mixerCoderMTSpec->AddCoder(decoder); #ifdef _ST_MODE else _mixerCoderSTSpec->AddCoder(decoder, false); #endif } else { if (decoder2 == 0) return E_NOTIMPL; decoderUnknown = (IUnknown *)decoder2; if (_multiThread) _mixerCoderMTSpec->AddCoder2(decoder2); #ifdef _ST_MODE else _mixerCoderSTSpec->AddCoder2(decoder2, false); #endif } _decoders.Add(decoderUnknown); #ifdef EXTERNAL_CODECS CMyComPtr<ISetCompressCodecsInfo> setCompressCodecsInfo; decoderUnknown.QueryInterface(IID_ISetCompressCodecsInfo, (void **)&setCompressCodecsInfo); if (setCompressCodecsInfo) { RINOK(setCompressCodecsInfo->SetCompressCodecsInfo(codecsInfo)); } #endif } _bindInfoExPrev = bindInfo; _bindInfoExPrevIsDefined = true; } int i; _mixerCoderCommon->ReInit(); UInt32 packStreamIndex = 0, unpackStreamIndex = 0; UInt32 coderIndex = 0; // UInt32 coder2Index = 0; for (i = 0; i < numCoders; i++) { const CCoderInfo &coderInfo = folderInfo.Coders[i]; CMyComPtr<IUnknown> &decoder = _decoders[coderIndex]; { CMyComPtr<ICompressSetDecoderProperties2> setDecoderProperties; decoder.QueryInterface(IID_ICompressSetDecoderProperties2, &setDecoderProperties); if (setDecoderProperties) { const CByteBuffer &props = coderInfo.Props; size_t size = props.GetCapacity(); if (size > 0xFFFFFFFF) return E_NOTIMPL; if (size > 0) { RINOK(setDecoderProperties->SetDecoderProperties2((const Byte *)props, (UInt32)size)); } } } #ifdef COMPRESS_MT if (mtMode) { CMyComPtr<ICompressSetCoderMt> setCoderMt; decoder.QueryInterface(IID_ICompressSetCoderMt, &setCoderMt); if (setCoderMt) { RINOK(setCoderMt->SetNumberOfThreads(numThreads)); } } #endif #ifndef _NO_CRYPTO { CMyComPtr<ICryptoSetPassword> cryptoSetPassword; decoder.QueryInterface(IID_ICryptoSetPassword, &cryptoSetPassword); if (cryptoSetPassword) { if (getTextPassword == 0) return E_FAIL; CMyComBSTR passwordBSTR; RINOK(getTextPassword->CryptoGetTextPassword(&passwordBSTR)); CByteBuffer buffer; passwordIsDefined = true; const UString password(passwordBSTR); const UInt32 sizeInBytes = password.Length() * 2; buffer.SetCapacity(sizeInBytes); for (int i = 0; i < password.Length(); i++) { wchar_t c = password[i]; ((Byte *)buffer)[i * 2] = (Byte)c; ((Byte *)buffer)[i * 2 + 1] = (Byte)(c >> 8); } RINOK(cryptoSetPassword->CryptoSetPassword((const Byte *)buffer, sizeInBytes)); } } #endif coderIndex++; UInt32 numInStreams = (UInt32)coderInfo.NumInStreams; UInt32 numOutStreams = (UInt32)coderInfo.NumOutStreams; CRecordVector<const UInt64 *> packSizesPointers; CRecordVector<const UInt64 *> unpackSizesPointers; packSizesPointers.Reserve(numInStreams); unpackSizesPointers.Reserve(numOutStreams); UInt32 j; for (j = 0; j < numOutStreams; j++, unpackStreamIndex++) unpackSizesPointers.Add(&folderInfo.UnpackSizes[unpackStreamIndex]); for (j = 0; j < numInStreams; j++, packStreamIndex++) { int bindPairIndex = folderInfo.FindBindPairForInStream(packStreamIndex); if (bindPairIndex >= 0) packSizesPointers.Add( &folderInfo.UnpackSizes[(UInt32)folderInfo.BindPairs[bindPairIndex].OutIndex]); else { int index = folderInfo.FindPackStreamArrayIndex(packStreamIndex); if (index < 0) return E_FAIL; packSizesPointers.Add(&packSizes[index]); } } _mixerCoderCommon->SetCoderInfo(i, &packSizesPointers.Front(), &unpackSizesPointers.Front()); } UInt32 mainCoder, temp; bindInfo.FindOutStream(bindInfo.OutStreams[0], mainCoder, temp); if (_multiThread) _mixerCoderMTSpec->SetProgressCoderIndex(mainCoder); /* else _mixerCoderSTSpec->SetProgressCoderIndex(mainCoder);; */ if (numCoders == 0) return 0; CRecordVector<ISequentialInStream *> inStreamPointers; inStreamPointers.Reserve(inStreams.Size()); for (i = 0; i < inStreams.Size(); i++) inStreamPointers.Add(inStreams[i]); ISequentialOutStream *outStreamPointer = outStream; return _mixerCoder->Code(&inStreamPointers.Front(), NULL, inStreams.Size(), &outStreamPointer, NULL, 1, compressProgress); }
HRESULT UpdateArchive( DECL_EXTERNAL_CODECS_LOC_VARS IInStream * /* inStream */, UInt64 unpackSize, ISequentialOutStream *outStream, const CItem &newItem, const CCompressionMethodMode &compressionMethod, int indexInClient, IArchiveUpdateCallback *updateCallback) { UInt64 complexity = unpackSize; RINOK(updateCallback->SetTotal(complexity)); CMyComPtr<ICompressCoder> deflateEncoder; complexity = 0; RINOK(updateCallback->SetCompleted(&complexity)); CMyComPtr<ISequentialInStream> fileInStream; RINOK(updateCallback->GetStream(indexInClient, &fileInStream)); CSequentialInStreamWithCRC *inStreamSpec = new CSequentialInStreamWithCRC; CMyComPtr<ISequentialInStream> crcStream(inStreamSpec); inStreamSpec->SetStream(fileInStream); inStreamSpec->Init(); CLocalProgress *lps = new CLocalProgress; CMyComPtr<ICompressProgressInfo> progress = lps; lps->Init(updateCallback, true); COutArchive outArchive; outArchive.Create(outStream); CItem item = newItem; item.CompressionMethod = NFileHeader::NCompressionMethod::kDeflate; item.ExtraFlags = 0; item.HostOS = kHostOS; RINOK(outArchive.WriteHeader(item)); { RINOK(CreateCoder( EXTERNAL_CODECS_LOC_VARS kMethodId_Deflate, deflateEncoder, true)); if (!deflateEncoder) return E_NOTIMPL; NWindows::NCOM::CPropVariant properties[] = { compressionMethod.Algo, compressionMethod.NumPasses, compressionMethod.NumFastBytes, compressionMethod.NumMatchFinderCycles }; PROPID propIDs[] = { NCoderPropID::kAlgorithm, NCoderPropID::kNumPasses, NCoderPropID::kNumFastBytes, NCoderPropID::kMatchFinderCycles }; int numProps = sizeof(propIDs) / sizeof(propIDs[0]); if (!compressionMethod.NumMatchFinderCyclesDefined) numProps--; CMyComPtr<ICompressSetCoderProperties> setCoderProperties; RINOK(deflateEncoder.QueryInterface(IID_ICompressSetCoderProperties, &setCoderProperties)); RINOK(setCoderProperties->SetCoderProperties(propIDs, properties, numProps)); } RINOK(deflateEncoder->Code(crcStream, outStream, NULL, NULL, progress)); item.FileCRC = inStreamSpec->GetCRC(); item.UnPackSize32 = (UInt32)inStreamSpec->GetSize(); RINOK(outArchive.WritePostHeader(item)); return updateCallback->SetOperationResult(NArchive::NUpdate::NOperationResult::kOK); }
STDAPI CreateObject(const GUID *clsid, const GUID *iid, void **outObject) { return CreateCoder(clsid, iid, outObject); }
HRESULT CEncoder::CreateMixerCoder( DECL_EXTERNAL_CODECS_LOC_VARS const UInt64 *inSizeForReduce) { _mixerCoderSpec = new NCoderMixer::CCoderMixer2MT; _mixerCoder = _mixerCoderSpec; RINOK(_mixerCoderSpec->SetBindInfo(_bindInfo)); for (int i = 0; i < _options.Methods.Size(); i++) { const CMethodFull &methodFull = _options.Methods[i]; _codersInfo.Add(CCoderInfo()); CCoderInfo &encodingInfo = _codersInfo.Back(); 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(SetMethodProperties(methodFull, inSizeForReduce, encoderCommon)); /* CMyComPtr<ICryptoResetSalt> resetSalt; encoderCommon.QueryInterface(IID_ICryptoResetSalt, (void **)&resetSalt); if (resetSalt != NULL) { resetSalt->ResetSalt(); } */ #ifdef EXTERNAL_CODECS CMyComPtr<ISetCompressCodecsInfo> setCompressCodecsInfo; encoderCommon.QueryInterface(IID_ISetCompressCodecsInfo, (void **)&setCompressCodecsInfo); if (setCompressCodecsInfo) { RINOK(setCompressCodecsInfo->SetCompressCodecsInfo(codecsInfo)); } #endif CMyComPtr<ICryptoSetPassword> cryptoSetPassword = new CCryptoSetPassword; encoderCommon.QueryInterface(IID_ICryptoSetPassword, &cryptoSetPassword); if (cryptoSetPassword) { UString & password = _options.Password; /* const UInt32 sizeInBytes = (_options.Password.Length()+1) * 2; CByteBuffer buffer; buffer.SetCapacity(sizeInBytes); parallel::_for( 0,password.Length(), [&buffer, &password]( int i, bool & breakFlag ) { if( breakFlag ) return; wchar_t c = password[i]; ((Byte *)buffer)[i * 2] = (Byte)c; ((Byte *)buffer)[i * 2 + 1] = (Byte)(c >> 8); } , 4 ); buffer[sizeInBytes-1] = 0; buffer[sizeInBytes-2] = 0; RINOK(cryptoSetPassword->CryptoSetPassword((const Byte *)buffer, sizeInBytes-2)); */ RINOK(cryptoSetPassword->CryptoSetPassword((const Byte *)(&_options.Password[0]), password.Length()*2)); } if (encoder) _mixerCoderSpec->AddCoder(encoder); else _mixerCoderSpec->AddCoder2(encoder2); } return S_OK; }