HRESULT UpdateArchive(UInt64 unpackSize, ISequentialOutStream *outStream, int indexInClient, UInt32 dictionary, UInt32 numPasses, #ifdef COMPRESS_MT UInt32 numThreads, #endif IArchiveUpdateCallback *updateCallback) { RINOK(updateCallback->SetTotal(unpackSize)); UInt64 complexity = 0; RINOK(updateCallback->SetCompleted(&complexity)); CMyComPtr<ISequentialInStream> fileInStream; RINOK(updateCallback->GetStream(indexInClient, &fileInStream)); CLocalProgress *localProgressSpec = new CLocalProgress; CMyComPtr<ICompressProgressInfo> localProgress = localProgressSpec; localProgressSpec->Init(updateCallback, true); #ifndef COMPRESS_BZIP2 CCoderLibrary lib; #endif CMyComPtr<ICompressCoder> encoder; #ifdef COMPRESS_BZIP2 encoder = new NCompress::NBZip2::CEncoder; #else RINOK(lib.LoadAndCreateCoder(GetBZip2CodecPath(), CLSID_CCompressBZip2Encoder, &encoder)); #endif CMyComPtr<ICompressSetCoderProperties> setCoderProperties; encoder.QueryInterface(IID_ICompressSetCoderProperties, &setCoderProperties); if (setCoderProperties) { NWindows::NCOM::CPropVariant properties[] = { dictionary, numPasses #ifdef COMPRESS_MT , numThreads #endif }; PROPID propIDs[] = { NCoderPropID::kDictionarySize, NCoderPropID::kNumPasses #ifdef COMPRESS_MT , NCoderPropID::kNumThreads #endif }; RINOK(setCoderProperties->SetCoderProperties(propIDs, properties, sizeof(propIDs) / sizeof(propIDs[0]))); } RINOK(encoder->Code(fileInStream, outStream, NULL, NULL, localProgress)); return updateCallback->SetOperationResult(NArchive::NUpdate::NOperationResult::kOK); }
HRESULT SetMethodProperties(const CMethod &method, const UInt64 *inSizeForReduce, IUnknown *coder) { bool tryReduce = false; UInt32 reducedDictionarySize = 1 << 10; if (inSizeForReduce != 0 && (method.Id == k_LZMA || method.Id == k_LZMA2)) { for (;;) { const UInt32 step = (reducedDictionarySize >> 1); if (reducedDictionarySize >= *inSizeForReduce) { tryReduce = true; break; } reducedDictionarySize += step; if (reducedDictionarySize >= *inSizeForReduce) { tryReduce = true; break; } if (reducedDictionarySize >= ((UInt32)3 << 30)) break; reducedDictionarySize += step; } } { int numProps = method.Props.Size(); CMyComPtr<ICompressSetCoderProperties> setCoderProperties; coder->QueryInterface(IID_ICompressSetCoderProperties, (void **)&setCoderProperties); if (setCoderProperties == NULL) { if (numProps != 0) return E_INVALIDARG; } else { CRecordVector<PROPID> propIDs; NWindows::NCOM::CPropVariant *values = new NWindows::NCOM::CPropVariant[numProps]; HRESULT res = S_OK; try { for (int i = 0; i < numProps; i++) { const CProp &prop = method.Props[i]; propIDs.Add(prop.Id); NWindows::NCOM::CPropVariant &value = values[i]; value = prop.Value; // if (tryReduce && prop.Id == NCoderPropID::kDictionarySize && value.vt == VT_UI4 && reducedDictionarySize < value.ulVal) if (tryReduce) if (prop.Id == NCoderPropID::kDictionarySize) if (value.vt == VT_UI4) if (reducedDictionarySize < value.ulVal) value.ulVal = reducedDictionarySize; } CMyComPtr<ICompressSetCoderProperties> setCoderProperties; coder->QueryInterface(IID_ICompressSetCoderProperties, (void **)&setCoderProperties); res = setCoderProperties->SetCoderProperties(&propIDs.Front(), values, numProps); } catch(...) { delete []values; throw; } delete []values; RINOK(res); } } /* CMyComPtr<ICompressWriteCoderProperties> writeCoderProperties; coder->QueryInterface(IID_ICompressWriteCoderProperties, (void **)&writeCoderProperties); if (writeCoderProperties != NULL) { CSequentialOutStreamImp *outStreamSpec = new CSequentialOutStreamImp; CMyComPtr<ISequentialOutStream> outStream(outStreamSpec); outStreamSpec->Init(); RINOK(writeCoderProperties->WriteCoderProperties(outStream)); size_t size = outStreamSpec->GetSize(); filterProps.SetCapacity(size); memmove(filterProps, outStreamSpec->GetBuffer(), size); } */ return S_OK; }
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 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); }
HRESULT CAddCommon::Compress(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) { // RINOK(m_MatchFinder.CoCreateInstance(CLSID_CMatchFinderBT3)); #ifndef COMPRESS_DEFLATE UString methodName; N7z::LoadMethodMap(); #endif switch(method) { case NFileHeader::NCompressionMethod::kDeflated: { #ifdef COMPRESS_DEFLATE _compressEncoder = new NCompress::NDeflate::NEncoder::CCOMCoder; #else methodName = L"Deflate"; #endif break; } case NFileHeader::NCompressionMethod::kDeflated64: { #ifdef COMPRESS_DEFLATE64 _compressEncoder = new NCompress::NDeflate::NEncoder::CCOMCoder64; #else methodName = L"Deflate64"; #endif break; } case NFileHeader::NCompressionMethod::kBZip2: { #ifdef COMPRESS_BZIP2 _compressEncoder = new NCompress::NBZip2::CEncoder; #else methodName = L"BZip2"; #endif break; } } #ifndef COMPRESS_DEFLATE N7z::CMethodInfo2 methodInfo; if (!N7z::GetMethodInfo(methodName, methodInfo)) return E_NOTIMPL; RINOK(_compressLib.LoadAndCreateCoder( methodInfo.FilePath, methodInfo.Encoder, &_compressEncoder)); #endif if (method == NFileHeader::NCompressionMethod::kDeflated || method == NFileHeader::NCompressionMethod::kDeflated64) { NWindows::NCOM::CPropVariant properties[] = { _options.NumPasses, _options.NumFastBytes, _options.NumMatchFinderCycles }; PROPID propIDs[] = { 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, properties, numProps)); } } else if (method == NFileHeader::NCompressionMethod::kBZip2) { NWindows::NCOM::CPropVariant properties[] = { _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, properties, 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); }