Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/kornelski/7z.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'CPP/7zip/Archive/Zip/ZipUpdate.cpp')
-rw-r--r--CPP/7zip/Archive/Zip/ZipUpdate.cpp303
1 files changed, 201 insertions, 102 deletions
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<ISequentialOutStream> 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<ISequentialInStream> 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<ISequentialInStream> 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<ISequentialInStream> packStream;
+
+ RINOK(inArchive->GetItemStream(itemEx, ui.NewProps, packStream));
+ if (!packStream)
+ return E_NOTIMPL;
+
+ complexity += rangeSize;
+
+ CMyComPtr<ISequentialOutStream> 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<IInStream> 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<IOutStream> 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<IArchiveUpdateCallbackFile> 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<IOutStream> 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<ISequentialOutStream> 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<IOutStream> 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
{