From 2efa10565ac395d2ce9a679ead46e70fb2f963eb Mon Sep 17 00:00:00 2001 From: Igor Pavlov Date: Sun, 30 Apr 2017 00:00:00 +0000 Subject: 17.00 --- CPP/7zip/Archive/Zip/ZipUpdate.cpp | 303 ++++++++++++++++++++++++------------- 1 file changed, 201 insertions(+), 102 deletions(-) (limited to 'CPP/7zip/Archive/Zip/ZipUpdate.cpp') diff --git a/CPP/7zip/Archive/Zip/ZipUpdate.cpp b/CPP/7zip/Archive/Zip/ZipUpdate.cpp index bc50c1d7..81f48a2a 100644 --- a/CPP/7zip/Archive/Zip/ZipUpdate.cpp +++ b/CPP/7zip/Archive/Zip/ZipUpdate.cpp @@ -42,32 +42,38 @@ static const Byte kHostOS = static const Byte kMadeByHostOS = kHostOS; static const Byte kExtractHostOS = kHostOS; -static const Byte kMethodForDirectory = NFileHeader::NCompressionMethod::kStored; +static const Byte kMethodForDirectory = NFileHeader::NCompressionMethod::kStore; -static HRESULT CopyBlockToArchive(ISequentialInStream *inStream, UInt64 size, - COutArchive &outArchive, ICompressProgressInfo *progress) + +static void AddAesExtra(CItem &item, Byte aesKeyMode, UInt16 method) { - CMyComPtr outStream; - outArchive.CreateStreamForCopying(&outStream); - return NCompress::CopyStream_ExactSize(inStream, outStream, size, progress); + CWzAesExtra wzAesField; + wzAesField.Strength = aesKeyMode; + wzAesField.Method = method; + item.Method = NFileHeader::NCompressionMethod::kWzAES; + item.Crc = 0; + CExtraSubBlock sb; + wzAesField.SetSubBlock(sb); + item.LocalExtra.SubBlocks.Add(sb); + item.CentralExtra.SubBlocks.Add(sb); } + static void SetFileHeader( - COutArchive &archive, const CCompressionMethodMode &options, const CUpdateItem &ui, // bool isSeqMode, CItemOut &item) { item.Size = ui.Size; - bool isDir; + bool isDir = ui.IsDir; item.ClearFlags(); if (ui.NewProps) { - isDir = ui.IsDir; item.Name = ui.Name; + item.Comment = ui.Comment; item.SetUtf8(ui.IsUtf8); item.ExternalAttrib = ui.Attrib; item.Time = ui.Time; @@ -76,10 +82,11 @@ static void SetFileHeader( item.Ntfs_CTime = ui.Ntfs_CTime; item.NtfsTimeIsDefined = ui.NtfsTimeIsDefined; } + /* else isDir = item.IsDir(); + */ - item.LocalHeaderPos = archive.GetCurPos(); item.MadeByVersion.HostOS = kMadeByHostOS; item.MadeByVersion.Version = NFileHeader::NCompressionMethod::kMadeByProgramVersion; @@ -97,14 +104,32 @@ static void SetFileHeader( item.Size = 0; item.Crc = 0; } + + item.LocalExtra.Clear(); + item.CentralExtra.Clear(); + + if (isDir) + { + item.ExtractVersion.Version = NFileHeader::NCompressionMethod::kExtractVersion_Dir; + item.Method = kMethodForDirectory; + item.PackSize = 0; + item.Size = 0; + item.Crc = 0; + } + else if (options.IsRealAesMode()) + AddAesExtra(item, options.AesKeyMode, (Byte)(options.MethodSequence.IsEmpty() ? 8 : options.MethodSequence[0])); } +// we call SetItemInfoFromCompressingResult() after SetFileHeader() + static void SetItemInfoFromCompressingResult(const CCompressingResult &compressingResult, bool isAesMode, Byte aesKeyMode, CItem &item) { item.ExtractVersion.Version = compressingResult.ExtractVersion; item.Method = compressingResult.Method; + if (compressingResult.Method == NFileHeader::NCompressionMethod::kLZMA && compressingResult.LzmaEos) + item.Flags |= NFileHeader::NFlags::kLzmaEOS; item.Crc = compressingResult.CRC; item.Size = compressingResult.UnpackSize; item.PackSize = compressingResult.PackSize; @@ -113,17 +138,7 @@ static void SetItemInfoFromCompressingResult(const CCompressingResult &compressi item.CentralExtra.Clear(); if (isAesMode) - { - CWzAesExtra wzAesField; - wzAesField.Strength = aesKeyMode; - wzAesField.Method = compressingResult.Method; - item.Method = NFileHeader::NCompressionMethod::kWzAES; - item.Crc = 0; - CExtraSubBlock sb; - wzAesField.SetSubBlock(sb); - item.LocalExtra.SubBlocks.Add(sb); - item.CentralExtra.SubBlocks.Add(sb); - } + AddAesExtra(item, aesKeyMode, compressingResult.Method); } @@ -151,6 +166,7 @@ struct CThreadInfo HRESULT Result; CCompressingResult CompressingResult; + bool SeqMode; bool IsFree; UInt32 UpdateIndex; UInt32 FileTime; @@ -160,6 +176,7 @@ struct CThreadInfo ProgressSpec(0), OutStreamSpec(0), Coder(options), + SeqMode(false), FileTime(0) {} @@ -193,7 +210,7 @@ void CThreadInfo::WaitAndCode() Result = Coder.Compress( EXTERNAL_CODECS_LOC_VARS - InStream, OutStream, FileTime, Progress, CompressingResult); + InStream, OutStream, SeqMode, FileTime, Progress, CompressingResult); if (Result == S_OK && Progress) Result = Progress->SetRatioInfo(&CompressingResult.UnpackSize, &CompressingResult.PackSize); @@ -342,6 +359,8 @@ static HRESULT UpdateItemOldData( NUpdateNotifyOp::kReplicate)) } + UInt64 rangeSize; + if (ui.NewProps) { if (item.HasDescriptor()) @@ -349,14 +368,11 @@ static HRESULT UpdateItemOldData( // use old name size. - CMyComPtr packStream; - RINOK(inArchive->GetItemStream(itemEx, true, packStream)); - if (!packStream) - return E_NOTIMPL; - // we keep ExternalAttrib and some another properties from old archive // item.ExternalAttrib = ui.Attrib; + // if we don't change Comment, we keep Comment from OldProperties + item.Comment = ui.Comment; item.Name = ui.Name; item.SetUtf8(ui.IsUtf8); item.Time = ui.Time; @@ -367,46 +383,37 @@ static HRESULT UpdateItemOldData( item.CentralExtra.RemoveUnknownSubBlocks(); item.LocalExtra.RemoveUnknownSubBlocks(); - item.LocalHeaderPos = archive.GetCurPos(); - archive.PrepareWriteCompressedData2(item.Name.Len(), item.Size, item.PackSize, item.LocalExtra.HasWzAes()); archive.WriteLocalHeader(item); - - RINOK(CopyBlockToArchive(packStream, itemEx.PackSize, archive, progress)); - - complexity += itemEx.PackSize; + rangeSize = item.GetPackSizeWithDescriptor(); } else { - CMyComPtr packStream; - RINOK(inArchive->GetItemStream(itemEx, false, packStream)); - if (!packStream) - return E_NOTIMPL; - - // set new header position item.LocalHeaderPos = archive.GetCurPos(); - - const UInt64 rangeSize = itemEx.GetLocalFullSize(); - - RINOK(CopyBlockToArchive(packStream, rangeSize, archive, progress)); - - complexity += rangeSize; - archive.MoveCurPos(rangeSize); + rangeSize = itemEx.GetLocalFullSize(); } - return S_OK; + CMyComPtr packStream; + + RINOK(inArchive->GetItemStream(itemEx, ui.NewProps, packStream)); + if (!packStream) + return E_NOTIMPL; + + complexity += rangeSize; + + CMyComPtr outStream; + archive.CreateStreamForCopying(outStream); + HRESULT res = NCompress::CopyStream_ExactSize(packStream, outStream, rangeSize, progress); + archive.MoveCurPos(rangeSize); + return res; } static void WriteDirHeader(COutArchive &archive, const CCompressionMethodMode *options, const CUpdateItem &ui, CItemOut &item) { - SetFileHeader(archive, *options, ui, item); - archive.PrepareWriteCompressedData(item.Name.Len(), ui.Size, - // options->IsRealAesMode() - false // fixed 9.31 - ); - archive.WriteLocalHeader_And_SeekToNextFile(item); + SetFileHeader(*options, ui, item); + archive.WriteLocalHeader(item); } @@ -490,6 +497,8 @@ static HRESULT Update2St( if (!ui.NewProps || !ui.NewData) { + // Note: for (ui.NewProps && !ui.NewData) it copies Props from old archive, + // But we will rewrite all important properties later. But we can keep some properties like Comment itemEx = inputItems[ui.IndexInArc]; if (inArchive->ReadLocalItemAfterCdItemFull(itemEx) != S_OK) return E_NOTIMPL; @@ -498,7 +507,8 @@ static HRESULT Update2St( if (ui.NewData) { - bool isDir = ((ui.NewProps) ? ui.IsDir : item.IsDir()); + // bool isDir = ((ui.NewProps) ? ui.IsDir : item.IsDir()); + bool isDir = ui.IsDir; if (isDir) { WriteDirHeader(archive, options, ui, item); @@ -517,28 +527,39 @@ static HRESULT Update2St( if (!fileInStream) return E_INVALIDARG; - // bool isSeqMode = false; - /* + bool seqMode; { CMyComPtr inStream2; fileInStream->QueryInterface(IID_IInStream, (void **)&inStream2); - isSeqMode = (inStream2 == NULL); + seqMode = (inStream2 == NULL); } - */ + // seqMode = true; // to test seqMode UpdatePropsFromStream(ui, fileInStream, updateCallback, totalComplexity); - SetFileHeader(archive, *options, ui, item); + SetFileHeader(*options, ui, item); + + item.SetDescriptorMode(seqMode); // file Size can be 64-bit !!! - archive.PrepareWriteCompressedData(item.Name.Len(), ui.Size, options->IsRealAesMode()); + CCompressingResult compressingResult; + + RINOK(compressor.Set_Pre_CompressionResult( + seqMode, + ui.Size, + compressingResult)); + + SetItemInfoFromCompressingResult(compressingResult, options->IsRealAesMode(), options->AesKeyMode, item); + + archive.WriteLocalHeader(item); + CMyComPtr outStream; - archive.CreateStreamForCompressing(&outStream); + archive.CreateStreamForCompressing(outStream); RINOK(compressor.Compress( EXTERNAL_CODECS_LOC_VARS fileInStream, outStream, - ui.Time, + seqMode, ui.Time, progress, compressingResult)); if (compressingResult.FileTimeWasUsed) @@ -551,7 +572,9 @@ static HRESULT Update2St( } SetItemInfoFromCompressingResult(compressingResult, options->IsRealAesMode(), options->AesKeyMode, item); - archive.WriteLocalHeader_And_SeekToNextFile(item); + + archive.WriteLocalHeader_Replace(item); + RINOK(updateCallback->SetOperationResult(NArchive::NUpdate::NOperationResult::kOK)); unpackSizeTotal += item.Size; packSizeTotal += item.PackSize; @@ -561,7 +584,9 @@ static HRESULT Update2St( { UInt64 complexity = 0; lps->SendRatio = false; + RINOK(UpdateItemOldData(archive, inArchive, itemEx, ui, item, progress, opCallback, complexity)); + lps->SendRatio = true; lps->ProgressOffset += complexity; } @@ -591,6 +616,7 @@ static HRESULT Update2( CMyComPtr opCallback; updateCallback->QueryInterface(IID_IArchiveUpdateCallbackFile, (void **)&opCallback); + bool unknownComplexity = false; UInt64 complexity = 0; UInt64 numFilesToCompress = 0; UInt64 numBytesToCompress = 0; @@ -602,7 +628,10 @@ static HRESULT Update2( const CUpdateItem &ui = updateItems[i]; if (ui.NewData) { - complexity += ui.Size; + if (ui.Size == (UInt64)(Int64)-1) + unknownComplexity = true; + else + complexity += ui.Size; numBytesToCompress += ui.Size; numFilesToCompress++; /* @@ -625,19 +654,49 @@ static HRESULT Update2( if (comment) complexity += comment->Size(); complexity++; // end of central - updateCallback->SetTotal(complexity); + + if (!unknownComplexity) + updateCallback->SetTotal(complexity); UInt64 totalComplexity = complexity; - CAddCommon compressor(options); + CCompressionMethodMode options2 = options; + + if (options2._methods.IsEmpty()) + { + // we need method item, if default method was used + options2._methods.AddNew(); + } + + CAddCommon compressor(options2); complexity = 0; - CCompressionMethodMode options2 = options; + const Byte method = options.MethodSequence.Front(); + + COneMethodInfo *oneMethodMain = NULL; + if (!options2._methods.IsEmpty()) + oneMethodMain = &options2._methods[0]; + + { + FOR_VECTOR (mi, options2._methods) + { + options2.SetGlobalLevelTo(options2._methods[mi]); + } + } + + if (oneMethodMain) + { + // appnote recommends to use EOS marker for LZMA. + if (method == NFileHeader::NCompressionMethod::kLZMA) + oneMethodMain->AddProp_EndMarker_if_NotFound(true); + } + #ifndef _7ZIP_ST - UInt32 numThreads = options.NumThreads; + UInt32 numThreads = options._numThreads; + const UInt32 kNumMaxThreads = 64; if (numThreads > kNumMaxThreads) numThreads = kNumMaxThreads; @@ -646,7 +705,6 @@ static HRESULT Update2( if (numThreads < 1) numThreads = 1; - const size_t kMemPerThread = (1 << 25); const size_t kBlockSize = 1 << 16; @@ -655,44 +713,69 @@ static HRESULT Update2( if (numFilesToCompress <= 1) mtMode = false; - Byte method = options.MethodSequence.Front(); - if (!mtMode) { - if (options2.MethodInfo.FindProp(NCoderPropID::kNumThreads) < 0) + FOR_VECTOR (mi, options2._methods) { - // fixed for 9.31. bzip2 default is just one thread. - if (options2.NumThreadsWasChanged || method == NFileHeader::NCompressionMethod::kBZip2) - options2.MethodInfo.AddProp_NumThreads(numThreads); + COneMethodInfo &onem = options2._methods[mi]; + + if (onem.FindProp(NCoderPropID::kNumThreads) < 0) + { + // fixed for 9.31. bzip2 default is just one thread. + onem.AddProp_NumThreads(numThreads); + } } } else { - if (method == NFileHeader::NCompressionMethod::kStored && !options.PasswordIsDefined) + if (method == NFileHeader::NCompressionMethod::kStore && !options.PasswordIsDefined) numThreads = 1; + + if (oneMethodMain) + { + if (method == NFileHeader::NCompressionMethod::kBZip2) { bool fixedNumber; - UInt32 numBZip2Threads = options2.MethodInfo.Get_BZip2_NumThreads(fixedNumber); + UInt32 numBZip2Threads = oneMethodMain->Get_BZip2_NumThreads(fixedNumber); if (!fixedNumber) { - UInt64 averageSize = numBytesToCompress / numFilesToCompress; - UInt32 blockSize = options2.MethodInfo.Get_BZip2_BlockSize(); - UInt64 averageNumberOfBlocks = averageSize / blockSize + 1; + const UInt64 averageSize = numBytesToCompress / numFilesToCompress; + const UInt32 blockSize = oneMethodMain->Get_BZip2_BlockSize(); + const UInt64 averageNumberOfBlocks = averageSize / blockSize + 1; numBZip2Threads = 32; - if (averageNumberOfBlocks < numBZip2Threads) + if (numBZip2Threads > averageNumberOfBlocks) numBZip2Threads = (UInt32)averageNumberOfBlocks; - options2.MethodInfo.AddProp_NumThreads(numBZip2Threads); + oneMethodMain->AddProp_NumThreads(numBZip2Threads); } numThreads /= numBZip2Threads; } - if (method == NFileHeader::NCompressionMethod::kLZMA) + + if (method == NFileHeader::NCompressionMethod::kXz) { bool fixedNumber; + UInt32 numLzma2Threads = oneMethodMain->Get_Lzma2_NumThreads(fixedNumber); + if (!fixedNumber) + { + const UInt64 averageSize = numBytesToCompress / numFilesToCompress; + const UInt64 blockSize = oneMethodMain->Get_Lzma2_BlockSize(); + const UInt64 averageNumberOfBlocks = averageSize / blockSize + 1; + numLzma2Threads = 2; + if (numLzma2Threads > averageNumberOfBlocks) + numLzma2Threads = (UInt32)averageNumberOfBlocks; + oneMethodMain->AddProp_NumThreads(numLzma2Threads); + } + numThreads /= numLzma2Threads; + } + + if (method == NFileHeader::NCompressionMethod::kLZMA) + { // we suppose that default LZMA is 2 thread. So we don't change it - UInt32 numLZMAThreads = options2.MethodInfo.Get_Lzma_NumThreads(fixedNumber); + UInt32 numLZMAThreads = oneMethodMain->Get_Lzma_NumThreads(); numThreads /= numLZMAThreads; } + } + if (numThreads > numFilesToCompress) numThreads = (UInt32)numFilesToCompress; if (numThreads <= 1) @@ -747,6 +830,7 @@ static HRESULT Update2( threadInfo.ProgressSpec = new CMtCompressProgress(); threadInfo.Progress = threadInfo.ProgressSpec; threadInfo.ProgressSpec->Init(&mtCompressProgressMixer, (int)i); + threadInfo.SeqMode = false; // fix it ! threadInfo.FileTime = 0; // fix it ! RINOK(threadInfo.CreateThread()); } @@ -777,7 +861,9 @@ static HRESULT Update2( if (inArchive->ReadLocalItemAfterCdItemFull(itemEx) != S_OK) return E_NOTIMPL; (CItem &)item = itemEx; - if (item.IsDir()) + if (item.IsDir() != ui.IsDir) + return E_NOTIMPL; + if (ui.IsDir) continue; } @@ -849,7 +935,8 @@ static HRESULT Update2( if (ui.NewData) { - bool isDir = ((ui.NewProps) ? ui.IsDir : item.IsDir()); + // bool isDir = ((ui.NewProps) ? ui.IsDir : item.IsDir()); + bool isDir = ui.IsDir; if (isDir) { @@ -857,39 +944,51 @@ static HRESULT Update2( } else { - if (lastRealStreamItemIndex < (int)itemIndex) - { - lastRealStreamItemIndex = itemIndex; - SetFileHeader(archive, options, ui, item); - // file Size can be 64-bit !!! - archive.PrepareWriteCompressedData(item.Name.Len(), ui.Size, options.IsRealAesMode()); - } - CMemBlocks2 &memRef = refs.Refs[itemIndex]; if (memRef.Defined) { - CMyComPtr outStream; - archive.CreateStreamForCompressing(&outStream); - memRef.WriteToStream(memManager.GetBlockSize(), outStream); - SetFileHeader(archive, options, ui, item); + if (lastRealStreamItemIndex < (int)itemIndex) + lastRealStreamItemIndex = itemIndex; + + SetFileHeader(options, ui, item); // the BUG was fixed in 9.26: // SetItemInfoFromCompressingResult must be after SetFileHeader // to write correct Size. SetItemInfoFromCompressingResult(memRef.CompressingResult, options.IsRealAesMode(), options.AesKeyMode, item); - archive.WriteLocalHeader_And_SeekToNextFile(item); + archive.WriteLocalHeader(item); // RINOK(updateCallback->SetOperationResult(NArchive::NUpdate::NOperationResult::kOK)); + CMyComPtr outStream; + archive.CreateStreamForCopying(outStream); + memRef.WriteToStream(memManager.GetBlockSize(), outStream); + archive.MoveCurPos(item.PackSize); memRef.FreeOpt(&memManager); } else { + if (lastRealStreamItemIndex < (int)itemIndex) + { + lastRealStreamItemIndex = itemIndex; + SetFileHeader(options, ui, item); + + CCompressingResult compressingResult; + RINOK(compressor.Set_Pre_CompressionResult( + false, // seqMode + ui.Size, + compressingResult)); + SetItemInfoFromCompressingResult(compressingResult, options.IsRealAesMode(), options.AesKeyMode, item); + + // file Size can be 64-bit !!! + archive.WriteLocalHeader(item); + } + { CThreadInfo &thread = threads.Threads[threadIndices.Front()]; if (!thread.OutStreamSpec->WasUnlockEventSent()) { CMyComPtr outStream; - archive.CreateStreamForCompressing(&outStream); + archive.CreateStreamForCompressing(outStream); thread.OutStreamSpec->SetOutStream(outStream); thread.OutStreamSpec->SetRealStreamMode(); } @@ -918,10 +1017,10 @@ static HRESULT Update2( { RINOK(threadInfo.OutStreamSpec->WriteToRealStream()); threadInfo.OutStreamSpec->ReleaseOutStream(); - SetFileHeader(archive, options, ui, item); + SetFileHeader(options, ui, item); SetItemInfoFromCompressingResult(threadInfo.CompressingResult, options.IsRealAesMode(), options.AesKeyMode, item); - archive.WriteLocalHeader_And_SeekToNextFile(item); + archive.WriteLocalHeader_Replace(item); } else { -- cgit v1.2.3