mirror of
https://github.com/Xevion/easy7zip.git
synced 2025-12-07 11:14:58 -06:00
Update to 7-Zip 17.01 Beta from Igor Pavlov
- Minor speed optimization for LZMA2 (xz and 7z) multi-threading compression.
7-Zip now uses additional memory buffers for multi-block LZMA2 compression.
CPU utilization was slightly improved.
- 7-zip now creates multi-block xz archives by default. Block size can be
specified with -ms[Size]{m|g} switch.
- xz decoder now can unpack random block from multi-block xz archives. 7-Zip
File Manager now can open nested multi-block xz archives (for example,
image.iso.xz) without full unpacking of xz archive.
- 7-Zip now can create zip archives from stdin to stdout.
- 7-Zip command line: @listfile now doesn't work after -- switch. Use
-i@listfile before -- switch instead.
fixed bugs:
- 7-Zip could add unrequired alternate file streams to WIM archives, for
commands that contain filename wildcards and -sns switch.
- 7-Zip 17.00 beta crashed for commands that write anti-item to 7z archive.
- 7-Zip 17.00 beta ignored "Use large memory pages" option.
This commit is contained in:
@@ -36,6 +36,7 @@ static const UInt32 kLzmaHeaderSize = 4 + kLzmaPropsSize;
|
||||
class CLzmaEncoder:
|
||||
public ICompressCoder,
|
||||
public ICompressSetCoderProperties,
|
||||
public ICompressSetCoderPropertiesOpt,
|
||||
public CMyUnknownImp
|
||||
{
|
||||
public:
|
||||
@@ -46,8 +47,11 @@ public:
|
||||
STDMETHOD(Code)(ISequentialInStream *inStream, ISequentialOutStream *outStream,
|
||||
const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress);
|
||||
STDMETHOD(SetCoderProperties)(const PROPID *propIDs, const PROPVARIANT *props, UInt32 numProps);
|
||||
STDMETHOD(SetCoderPropertiesOpt)(const PROPID *propIDs, const PROPVARIANT *props, UInt32 numProps);
|
||||
|
||||
MY_UNKNOWN_IMP1(ICompressSetCoderProperties)
|
||||
MY_UNKNOWN_IMP2(
|
||||
ICompressSetCoderProperties,
|
||||
ICompressSetCoderPropertiesOpt)
|
||||
};
|
||||
|
||||
STDMETHODIMP CLzmaEncoder::SetCoderProperties(const PROPID *propIDs, const PROPVARIANT *props, UInt32 numProps)
|
||||
@@ -71,6 +75,11 @@ STDMETHODIMP CLzmaEncoder::SetCoderProperties(const PROPID *propIDs, const PROPV
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
STDMETHODIMP CLzmaEncoder::SetCoderPropertiesOpt(const PROPID *propIDs, const PROPVARIANT *props, UInt32 numProps)
|
||||
{
|
||||
return EncoderSpec->SetCoderPropertiesOpt(propIDs, props, numProps);
|
||||
}
|
||||
|
||||
STDMETHODIMP CLzmaEncoder::Code(ISequentialInStream *inStream, ISequentialOutStream *outStream,
|
||||
const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress)
|
||||
{
|
||||
@@ -118,7 +127,8 @@ HRESULT CAddCommon::CalcStreamCRC(ISequentialInStream *inStream, UInt32 &resultC
|
||||
}
|
||||
|
||||
|
||||
HRESULT CAddCommon::Set_Pre_CompressionResult(bool seqMode, UInt64 unpackSize, CCompressingResult &opRes) const
|
||||
HRESULT CAddCommon::Set_Pre_CompressionResult(bool inSeqMode, bool outSeqMode, UInt64 unpackSize,
|
||||
CCompressingResult &opRes) const
|
||||
{
|
||||
// We use Zip64, if unPackSize size is larger than 0xF8000000 to support
|
||||
// cases when compressed size can be about 3% larger than uncompressed size
|
||||
@@ -144,7 +154,7 @@ HRESULT CAddCommon::Set_Pre_CompressionResult(bool seqMode, UInt64 unpackSize, C
|
||||
opRes.LzmaEos = false;
|
||||
|
||||
opRes.ExtractVersion = NCompressionMethod::kExtractVersion_Default;
|
||||
opRes.FileTimeWasUsed = false;
|
||||
opRes.DescriptorMode = outSeqMode;
|
||||
|
||||
if (_options.PasswordIsDefined)
|
||||
{
|
||||
@@ -153,8 +163,8 @@ HRESULT CAddCommon::Set_Pre_CompressionResult(bool seqMode, UInt64 unpackSize, C
|
||||
opRes.ExtractVersion = NCompressionMethod::kExtractVersion_Aes;
|
||||
else
|
||||
{
|
||||
if (seqMode)
|
||||
opRes.FileTimeWasUsed = true;
|
||||
if (inSeqMode)
|
||||
opRes.DescriptorMode = true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -187,7 +197,8 @@ HRESULT CAddCommon::Set_Pre_CompressionResult(bool seqMode, UInt64 unpackSize, C
|
||||
HRESULT CAddCommon::Compress(
|
||||
DECL_EXTERNAL_CODECS_LOC_VARS
|
||||
ISequentialInStream *inStream, IOutStream *outStream,
|
||||
bool seqMode, UInt32 fileTime,
|
||||
bool inSeqMode, bool outSeqMode,
|
||||
UInt32 fileTime, UInt64 expectedDataSize,
|
||||
ICompressProgressInfo *progress, CCompressingResult &opRes)
|
||||
{
|
||||
opRes.LzmaEos = false;
|
||||
@@ -202,16 +213,31 @@ HRESULT CAddCommon::Compress(
|
||||
CMyComPtr<ISequentialInStream> inCrcStream = inSecCrcStreamSpec;
|
||||
|
||||
CMyComPtr<IInStream> inStream2;
|
||||
if (!seqMode)
|
||||
if (!inSeqMode)
|
||||
{
|
||||
inStream->QueryInterface(IID_IInStream, (void **)&inStream2);
|
||||
if (!inStream2)
|
||||
{
|
||||
// inSeqMode = true;
|
||||
// inSeqMode must be correct before
|
||||
return E_FAIL;
|
||||
}
|
||||
}
|
||||
|
||||
inSecCrcStreamSpec->SetStream(inStream);
|
||||
inSecCrcStreamSpec->Init();
|
||||
|
||||
unsigned numTestMethods = _options.MethodSequence.Size();
|
||||
|
||||
if (seqMode || (numTestMethods > 1 && !inStream2))
|
||||
numTestMethods = 1;
|
||||
|
||||
bool descriptorMode = outSeqMode;
|
||||
if (!outSeqMode)
|
||||
if (inSeqMode && _options.PasswordIsDefined && !_options.IsAesMode)
|
||||
descriptorMode = true;
|
||||
opRes.DescriptorMode = descriptorMode;
|
||||
|
||||
if (numTestMethods > 1)
|
||||
if (inSeqMode || outSeqMode || !inStream2)
|
||||
numTestMethods = 1;
|
||||
|
||||
UInt32 crc = 0;
|
||||
bool crc_IsCalculated = false;
|
||||
@@ -219,19 +245,23 @@ HRESULT CAddCommon::Compress(
|
||||
Byte method = 0;
|
||||
CFilterCoder::C_OutStream_Releaser outStreamReleaser;
|
||||
opRes.ExtractVersion = NCompressionMethod::kExtractVersion_Default;
|
||||
opRes.FileTimeWasUsed = false;
|
||||
|
||||
for (unsigned i = 0; i < numTestMethods; i++)
|
||||
{
|
||||
opRes.LzmaEos = false;
|
||||
opRes.ExtractVersion = NCompressionMethod::kExtractVersion_Default;
|
||||
if (inStream2 && i != 0)
|
||||
|
||||
if (i != 0)
|
||||
{
|
||||
inSecCrcStreamSpec->Init();
|
||||
RINOK(inStream2->Seek(0, STREAM_SEEK_SET, NULL));
|
||||
if (inStream2)
|
||||
{
|
||||
inSecCrcStreamSpec->Init();
|
||||
RINOK(inStream2->Seek(0, STREAM_SEEK_SET, NULL));
|
||||
}
|
||||
|
||||
RINOK(outStream->SetSize(0));
|
||||
RINOK(outStream->Seek(0, STREAM_SEEK_SET, NULL));
|
||||
}
|
||||
RINOK(outStream->SetSize(0));
|
||||
RINOK(outStream->Seek(0, STREAM_SEEK_SET, NULL));
|
||||
|
||||
if (_options.PasswordIsDefined)
|
||||
{
|
||||
@@ -264,7 +294,12 @@ HRESULT CAddCommon::Compress(
|
||||
|
||||
UInt32 check;
|
||||
|
||||
if (inStream2)
|
||||
if (descriptorMode)
|
||||
{
|
||||
// it's Info-ZIP modification for stream_mode descriptor_mode (bit 3 of the general purpose bit flag is set)
|
||||
check = (fileTime & 0xFFFF);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!crc_IsCalculated)
|
||||
{
|
||||
@@ -275,11 +310,6 @@ HRESULT CAddCommon::Compress(
|
||||
}
|
||||
check = (crc >> 16);
|
||||
}
|
||||
else
|
||||
{
|
||||
opRes.FileTimeWasUsed = true;
|
||||
check = (fileTime & 0xFFFF);
|
||||
}
|
||||
|
||||
RINOK(_filterSpec->WriteHeader_Check16(outStream, (UInt16)check));
|
||||
}
|
||||
@@ -295,7 +325,13 @@ HRESULT CAddCommon::Compress(
|
||||
{
|
||||
case NCompressionMethod::kStore:
|
||||
{
|
||||
if (_copyCoderSpec == NULL)
|
||||
if (descriptorMode)
|
||||
{
|
||||
// we still can create descriptor_mode archives with "Store" method, but they are not good for 100%
|
||||
return E_NOTIMPL;
|
||||
}
|
||||
|
||||
if (!_copyCoderSpec)
|
||||
{
|
||||
_copyCoderSpec = new NCompress::CCopyCoder;
|
||||
_copyCoder = _copyCoderSpec;
|
||||
@@ -390,6 +426,18 @@ HRESULT CAddCommon::Compress(
|
||||
outStreamNew = outStream;
|
||||
if (_compressExtractVersion > opRes.ExtractVersion)
|
||||
opRes.ExtractVersion = _compressExtractVersion;
|
||||
|
||||
{
|
||||
CMyComPtr<ICompressSetCoderPropertiesOpt> optProps;
|
||||
_compressEncoder->QueryInterface(IID_ICompressSetCoderPropertiesOpt, (void **)&optProps);
|
||||
if (optProps)
|
||||
{
|
||||
PROPID propID = NCoderPropID::kExpectedDataSize;
|
||||
NWindows::NCOM::CPropVariant prop = (UInt64)expectedDataSize;
|
||||
RINOK(optProps->SetCoderPropertiesOpt(&propID, &prop, 1));
|
||||
}
|
||||
}
|
||||
|
||||
RINOK(_compressEncoder->Code(inCrcStream, outStreamNew, NULL, NULL, progress));
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -26,7 +26,7 @@ struct CCompressingResult
|
||||
UInt32 CRC;
|
||||
UInt16 Method;
|
||||
Byte ExtractVersion;
|
||||
bool FileTimeWasUsed;
|
||||
bool DescriptorMode;
|
||||
bool LzmaEos;
|
||||
};
|
||||
|
||||
@@ -53,12 +53,14 @@ public:
|
||||
CAddCommon(const CCompressionMethodMode &options);
|
||||
~CAddCommon();
|
||||
|
||||
HRESULT Set_Pre_CompressionResult(bool seqMode, UInt64 unpackSize, CCompressingResult &opRes) const;
|
||||
HRESULT Set_Pre_CompressionResult(bool inSeqMode, bool outSeqMode, UInt64 unpackSize,
|
||||
CCompressingResult &opRes) const;
|
||||
|
||||
HRESULT Compress(
|
||||
DECL_EXTERNAL_CODECS_LOC_VARS
|
||||
ISequentialInStream *inStream, IOutStream *outStream,
|
||||
bool seqMode, UInt32 fileTime,
|
||||
bool inSeqMode, bool outSeqMode,
|
||||
UInt32 fileTime, UInt64 expectedDataSize,
|
||||
ICompressProgressInfo *progress, CCompressingResult &opRes);
|
||||
};
|
||||
|
||||
|
||||
@@ -564,7 +564,8 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val
|
||||
AString s2 = FlagsToString(g_HeaderCharacts, ARRAY_SIZE(g_HeaderCharacts), flags);
|
||||
if (!s2.IsEmpty())
|
||||
{
|
||||
s.Add_OptSpaced(":");
|
||||
if (!s.IsEmpty())
|
||||
s.Add_OptSpaced(":");
|
||||
s.Add_OptSpaced(s2);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -459,7 +459,16 @@ API_FUNC_IsArc IsArc_Zip(const Byte *p, size_t size)
|
||||
extraSize -= 4;
|
||||
p += 4;
|
||||
if (dataSize > extraSize)
|
||||
return k_IsArc_Res_NO;
|
||||
{
|
||||
// It can be error on header.
|
||||
// We want to support such rare case bad archives.
|
||||
// We use additional checks to reduce false-positive probability.
|
||||
if (nameSize == 0
|
||||
|| nameSize > (1 << 9)
|
||||
|| extraSize > (1 << 9))
|
||||
return k_IsArc_Res_NO;
|
||||
return k_IsArc_Res_YES;
|
||||
}
|
||||
if (dataSize > size)
|
||||
return k_IsArc_Res_NEED_MORE;
|
||||
size -= dataSize;
|
||||
|
||||
@@ -269,7 +269,25 @@ UInt32 CItem::GetWinAttrib() const
|
||||
case NHostOS::kUnix:
|
||||
// do we need to clear 16 low bits in this case?
|
||||
if (FromCentral)
|
||||
{
|
||||
/*
|
||||
Some programs write posix attributes in high 16 bits of ExternalAttrib
|
||||
Also some programs can write additional marker flag:
|
||||
0x8000 - p7zip
|
||||
0x4000 - Zip in MacOS
|
||||
no marker - Info-Zip
|
||||
|
||||
Client code has two options to detect posix field:
|
||||
1) check 0x8000 marker. In that case we must add 0x8000 marker here.
|
||||
2) check that high 4 bits (file type bits in posix field) of attributes are not zero.
|
||||
*/
|
||||
|
||||
winAttrib = ExternalAttrib & 0xFFFF0000;
|
||||
|
||||
// #ifndef _WIN32
|
||||
winAttrib |= 0x8000; // add posix mode marker
|
||||
// #endif
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (IsDir()) // test it;
|
||||
|
||||
@@ -174,6 +174,9 @@ void COutArchive::WriteLocalHeader_Replace(CItemOut &item)
|
||||
{
|
||||
WriteDescriptor(item);
|
||||
m_OutBuffer.FlushWithCheck();
|
||||
return;
|
||||
// we don't replace local header, if we write Descriptor.
|
||||
// so local header with Descriptor flag must be written to local header before.
|
||||
}
|
||||
|
||||
const UInt64 nextPos = m_CurPos;
|
||||
|
||||
@@ -62,7 +62,7 @@ static void AddAesExtra(CItem &item, Byte aesKeyMode, UInt16 method)
|
||||
static void SetFileHeader(
|
||||
const CCompressionMethodMode &options,
|
||||
const CUpdateItem &ui,
|
||||
// bool isSeqMode,
|
||||
bool useDescriptor,
|
||||
CItemOut &item)
|
||||
{
|
||||
item.Size = ui.Size;
|
||||
@@ -94,7 +94,7 @@ static void SetFileHeader(
|
||||
|
||||
item.InternalAttrib = 0; // test it
|
||||
item.SetEncrypted(!isDir && options.PasswordIsDefined);
|
||||
// item.SetDescriptorMode(isSeqMode);
|
||||
item.SetDescriptorMode(useDescriptor);
|
||||
|
||||
if (isDir)
|
||||
{
|
||||
@@ -166,18 +166,22 @@ struct CThreadInfo
|
||||
HRESULT Result;
|
||||
CCompressingResult CompressingResult;
|
||||
|
||||
bool SeqMode;
|
||||
bool InSeqMode;
|
||||
bool OutSeqMode;
|
||||
bool IsFree;
|
||||
UInt32 UpdateIndex;
|
||||
UInt32 FileTime;
|
||||
UInt64 ExpectedDataSize;
|
||||
|
||||
CThreadInfo(const CCompressionMethodMode &options):
|
||||
ExitThread(false),
|
||||
ProgressSpec(0),
|
||||
OutStreamSpec(0),
|
||||
Coder(options),
|
||||
SeqMode(false),
|
||||
FileTime(0)
|
||||
InSeqMode(false),
|
||||
OutSeqMode(false),
|
||||
FileTime(0),
|
||||
ExpectedDataSize((UInt64)(Int64)-1)
|
||||
{}
|
||||
|
||||
HRESULT CreateEvents()
|
||||
@@ -210,7 +214,9 @@ void CThreadInfo::WaitAndCode()
|
||||
|
||||
Result = Coder.Compress(
|
||||
EXTERNAL_CODECS_LOC_VARS
|
||||
InStream, OutStream, SeqMode, FileTime, Progress, CompressingResult);
|
||||
InStream, OutStream,
|
||||
InSeqMode, OutSeqMode, FileTime, ExpectedDataSize,
|
||||
Progress, CompressingResult);
|
||||
|
||||
if (Result == S_OK && Progress)
|
||||
Result = Progress->SetRatioInfo(&CompressingResult.UnpackSize, &CompressingResult.PackSize);
|
||||
@@ -237,10 +243,13 @@ public:
|
||||
|
||||
struct CMemBlocks2: public CMemLockBlocks
|
||||
{
|
||||
CCompressingResult CompressingResult;
|
||||
bool Defined;
|
||||
bool Skip;
|
||||
CMemBlocks2(): Defined(false), Skip(false) {}
|
||||
bool InSeqMode;
|
||||
bool PreDescriptorMode;
|
||||
bool Finished;
|
||||
CCompressingResult CompressingResult;
|
||||
|
||||
CMemBlocks2(): Skip(false), InSeqMode(false), PreDescriptorMode(false), Finished(false) {}
|
||||
};
|
||||
|
||||
class CMemRefs
|
||||
@@ -412,7 +421,7 @@ static HRESULT UpdateItemOldData(
|
||||
static void WriteDirHeader(COutArchive &archive, const CCompressionMethodMode *options,
|
||||
const CUpdateItem &ui, CItemOut &item)
|
||||
{
|
||||
SetFileHeader(*options, ui, item);
|
||||
SetFileHeader(*options, ui, false, item);
|
||||
archive.WriteLocalHeader(item);
|
||||
}
|
||||
|
||||
@@ -471,7 +480,7 @@ static HRESULT Update2St(
|
||||
CInArchive *inArchive,
|
||||
const CObjectVector<CItemEx> &inputItems,
|
||||
CObjectVector<CUpdateItem> &updateItems,
|
||||
const CCompressionMethodMode *options,
|
||||
const CCompressionMethodMode *options, bool outSeqMode,
|
||||
const CByteBuffer *comment,
|
||||
IArchiveUpdateCallback *updateCallback,
|
||||
UInt64 &totalComplexity,
|
||||
@@ -527,28 +536,28 @@ static HRESULT Update2St(
|
||||
if (!fileInStream)
|
||||
return E_INVALIDARG;
|
||||
|
||||
bool seqMode;
|
||||
bool inSeqMode = false;
|
||||
if (!inSeqMode)
|
||||
{
|
||||
CMyComPtr<IInStream> inStream2;
|
||||
fileInStream->QueryInterface(IID_IInStream, (void **)&inStream2);
|
||||
seqMode = (inStream2 == NULL);
|
||||
inSeqMode = (inStream2 == NULL);
|
||||
}
|
||||
// seqMode = true; // to test seqMode
|
||||
|
||||
UpdatePropsFromStream(ui, fileInStream, updateCallback, totalComplexity);
|
||||
SetFileHeader(*options, ui, item);
|
||||
|
||||
item.SetDescriptorMode(seqMode);
|
||||
|
||||
// file Size can be 64-bit !!!
|
||||
|
||||
CCompressingResult compressingResult;
|
||||
|
||||
RINOK(compressor.Set_Pre_CompressionResult(
|
||||
seqMode,
|
||||
inSeqMode, outSeqMode,
|
||||
ui.Size,
|
||||
compressingResult));
|
||||
|
||||
SetFileHeader(*options, ui, compressingResult.DescriptorMode, item);
|
||||
|
||||
// file Size can be 64-bit !!!
|
||||
|
||||
SetItemInfoFromCompressingResult(compressingResult, options->IsRealAesMode(), options->AesKeyMode, item);
|
||||
|
||||
archive.WriteLocalHeader(item);
|
||||
@@ -559,17 +568,12 @@ static HRESULT Update2St(
|
||||
RINOK(compressor.Compress(
|
||||
EXTERNAL_CODECS_LOC_VARS
|
||||
fileInStream, outStream,
|
||||
seqMode, ui.Time,
|
||||
inSeqMode, outSeqMode,
|
||||
ui.Time, ui.Size,
|
||||
progress, compressingResult));
|
||||
|
||||
if (compressingResult.FileTimeWasUsed)
|
||||
{
|
||||
/*
|
||||
if (!item.HasDescriptor())
|
||||
return E_FAIL;
|
||||
*/
|
||||
item.SetDescriptorMode(true);
|
||||
}
|
||||
if (item.HasDescriptor() != compressingResult.DescriptorMode)
|
||||
return E_FAIL;
|
||||
|
||||
SetItemInfoFromCompressingResult(compressingResult, options->IsRealAesMode(), options->AesKeyMode, item);
|
||||
|
||||
@@ -609,7 +613,7 @@ static HRESULT Update2(
|
||||
CInArchive *inArchive,
|
||||
const CObjectVector<CItemEx> &inputItems,
|
||||
CObjectVector<CUpdateItem> &updateItems,
|
||||
const CCompressionMethodMode &options,
|
||||
const CCompressionMethodMode &options, bool outSeqMode,
|
||||
const CByteBuffer *comment,
|
||||
IArchiveUpdateCallback *updateCallback)
|
||||
{
|
||||
@@ -743,32 +747,38 @@ static HRESULT Update2(
|
||||
const UInt64 averageSize = numBytesToCompress / numFilesToCompress;
|
||||
const UInt32 blockSize = oneMethodMain->Get_BZip2_BlockSize();
|
||||
const UInt64 averageNumberOfBlocks = averageSize / blockSize + 1;
|
||||
numBZip2Threads = 32;
|
||||
numBZip2Threads = 64;
|
||||
if (numBZip2Threads > averageNumberOfBlocks)
|
||||
numBZip2Threads = (UInt32)averageNumberOfBlocks;
|
||||
if (numBZip2Threads > numThreads)
|
||||
numBZip2Threads = numThreads;
|
||||
oneMethodMain->AddProp_NumThreads(numBZip2Threads);
|
||||
}
|
||||
numThreads /= numBZip2Threads;
|
||||
}
|
||||
|
||||
if (method == NFileHeader::NCompressionMethod::kXz)
|
||||
else if (method == NFileHeader::NCompressionMethod::kXz)
|
||||
{
|
||||
bool fixedNumber;
|
||||
UInt32 numLzma2Threads = oneMethodMain->Get_Lzma2_NumThreads(fixedNumber);
|
||||
if (!fixedNumber)
|
||||
UInt32 numLzmaThreads = 1;
|
||||
int numXzThreads = oneMethodMain->Get_Xz_NumThreads(numLzmaThreads);
|
||||
if (numXzThreads < 0)
|
||||
{
|
||||
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);
|
||||
const UInt64 blockSize = oneMethodMain->Get_Xz_BlockSize();
|
||||
UInt64 averageNumberOfBlocks = 1;
|
||||
if (blockSize != (UInt64)(Int64)-1)
|
||||
averageNumberOfBlocks = averageSize / blockSize + 1;
|
||||
UInt32 t = 256;
|
||||
if (t > averageNumberOfBlocks)
|
||||
t = (UInt32)averageNumberOfBlocks;
|
||||
t *= numLzmaThreads;
|
||||
if (t > numThreads)
|
||||
t = numThreads;
|
||||
oneMethodMain->AddProp_NumThreads(t);
|
||||
numXzThreads = t;
|
||||
}
|
||||
numThreads /= numLzma2Threads;
|
||||
numThreads /= (unsigned)numXzThreads;
|
||||
}
|
||||
|
||||
if (method == NFileHeader::NCompressionMethod::kLZMA)
|
||||
else if (method == NFileHeader::NCompressionMethod::kLZMA)
|
||||
{
|
||||
// we suppose that default LZMA is 2 thread. So we don't change it
|
||||
UInt32 numLZMAThreads = oneMethodMain->Get_Lzma_NumThreads();
|
||||
@@ -782,12 +792,14 @@ static HRESULT Update2(
|
||||
mtMode = false;
|
||||
}
|
||||
|
||||
// mtMode = true; // to test mtMode for seqMode
|
||||
|
||||
if (!mtMode)
|
||||
#endif
|
||||
return Update2St(
|
||||
EXTERNAL_CODECS_LOC_VARS
|
||||
archive, inArchive,
|
||||
inputItems, updateItems, &options2, comment, updateCallback, totalComplexity, opCallback);
|
||||
inputItems, updateItems, &options2, outSeqMode, comment, updateCallback, totalComplexity, opCallback);
|
||||
|
||||
|
||||
#ifndef _7ZIP_ST
|
||||
@@ -830,8 +842,10 @@ 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 !
|
||||
threadInfo.InSeqMode = false;
|
||||
threadInfo.OutSeqMode = false;
|
||||
threadInfo.FileTime = 0;
|
||||
threadInfo.ExpectedDataSize = (UInt64)(Int64)-1;
|
||||
RINOK(threadInfo.CreateThread());
|
||||
}
|
||||
}
|
||||
@@ -840,10 +854,15 @@ static HRESULT Update2(
|
||||
unsigned itemIndex = 0;
|
||||
int lastRealStreamItemIndex = -1;
|
||||
|
||||
|
||||
while (itemIndex < updateItems.Size())
|
||||
{
|
||||
if (threadIndices.Size() < numThreads && mtItemIndex < updateItems.Size())
|
||||
{
|
||||
// we start ahead the threads for compressing
|
||||
// also we set refs.Refs[itemIndex].SeqMode that is used later
|
||||
// don't move that code block
|
||||
|
||||
CUpdateItem &ui = updateItems[mtItemIndex++];
|
||||
if (!ui.NewData)
|
||||
continue;
|
||||
@@ -869,6 +888,8 @@ static HRESULT Update2(
|
||||
|
||||
CMyComPtr<ISequentialInStream> fileInStream;
|
||||
|
||||
CMemBlocks2 &memRef2 = refs.Refs[mtItemIndex - 1];
|
||||
|
||||
{
|
||||
NWindows::NSynchronization::CCriticalSectionLock lock(mtProgressMixerSpec->Mixer2->CriticalSection);
|
||||
HRESULT res = updateCallback->GetStream(ui.IndexInClient, &fileInStream);
|
||||
@@ -878,7 +899,7 @@ static HRESULT Update2(
|
||||
complexity += kLocalHeaderSize;
|
||||
mtProgressMixerSpec->Mixer2->SetProgressOffset(complexity);
|
||||
RINOK(updateCallback->SetOperationResult(NArchive::NUpdate::NOperationResult::kOK));
|
||||
refs.Refs[mtItemIndex - 1].Skip = true;
|
||||
memRef2.Skip = true;
|
||||
continue;
|
||||
}
|
||||
RINOK(res);
|
||||
@@ -888,26 +909,46 @@ static HRESULT Update2(
|
||||
RINOK(updateCallback->SetOperationResult(NArchive::NUpdate::NOperationResult::kOK));
|
||||
}
|
||||
|
||||
for (UInt32 k = 0; k < numThreads; k++)
|
||||
UInt32 k;
|
||||
for (k = 0; k < numThreads; k++)
|
||||
if (threads.Threads[k].IsFree)
|
||||
break;
|
||||
|
||||
if (k == numThreads)
|
||||
return E_FAIL;
|
||||
{
|
||||
CThreadInfo &threadInfo = threads.Threads[k];
|
||||
if (threadInfo.IsFree)
|
||||
{
|
||||
CThreadInfo &threadInfo = threads.Threads[k];
|
||||
threadInfo.IsFree = false;
|
||||
threadInfo.InStream = fileInStream;
|
||||
|
||||
bool inSeqMode = false;
|
||||
|
||||
if (!inSeqMode)
|
||||
{
|
||||
CMyComPtr<IInStream> inStream2;
|
||||
fileInStream->QueryInterface(IID_IInStream, (void **)&inStream2);
|
||||
inSeqMode = (inStream2 == NULL);
|
||||
}
|
||||
memRef2.InSeqMode = inSeqMode;
|
||||
|
||||
// !!!!! we must release ref before sending event
|
||||
// BUG was here in v4.43 and v4.44. It could change ref counter in two threads in same time
|
||||
fileInStream.Release();
|
||||
|
||||
threadInfo.OutStreamSpec->Init();
|
||||
threadInfo.ProgressSpec->Reinit();
|
||||
threadInfo.CompressEvent.Set();
|
||||
|
||||
threadInfo.UpdateIndex = mtItemIndex - 1;
|
||||
|
||||
threadInfo.InSeqMode = inSeqMode;
|
||||
threadInfo.OutSeqMode = outSeqMode;
|
||||
threadInfo.FileTime = ui.Time; // FileTime is used for ZipCrypto only in seqMode
|
||||
threadInfo.ExpectedDataSize = ui.Size;
|
||||
|
||||
threadInfo.CompressEvent.Set();
|
||||
|
||||
compressingCompletedEvents.Add(threadInfo.CompressionCompletedEvent);
|
||||
threadIndices.Add(k);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -946,15 +987,17 @@ static HRESULT Update2(
|
||||
{
|
||||
CMemBlocks2 &memRef = refs.Refs[itemIndex];
|
||||
|
||||
if (memRef.Defined)
|
||||
if (memRef.Finished)
|
||||
{
|
||||
if (lastRealStreamItemIndex < (int)itemIndex)
|
||||
lastRealStreamItemIndex = itemIndex;
|
||||
|
||||
SetFileHeader(options, ui, item);
|
||||
SetFileHeader(options, ui, memRef.CompressingResult.DescriptorMode, 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(item);
|
||||
@@ -967,16 +1010,25 @@ static HRESULT Update2(
|
||||
}
|
||||
else
|
||||
{
|
||||
// current file was not finished
|
||||
|
||||
if (lastRealStreamItemIndex < (int)itemIndex)
|
||||
{
|
||||
// LocalHeader was not written for current itemIndex still
|
||||
|
||||
lastRealStreamItemIndex = itemIndex;
|
||||
SetFileHeader(options, ui, item);
|
||||
|
||||
// thread was started before for that item already, and memRef.SeqMode was set
|
||||
|
||||
CCompressingResult compressingResult;
|
||||
RINOK(compressor.Set_Pre_CompressionResult(
|
||||
false, // seqMode
|
||||
memRef.InSeqMode, outSeqMode,
|
||||
ui.Size,
|
||||
compressingResult));
|
||||
|
||||
memRef.PreDescriptorMode = compressingResult.DescriptorMode;
|
||||
SetFileHeader(options, ui, compressingResult.DescriptorMode, item);
|
||||
|
||||
SetItemInfoFromCompressingResult(compressingResult, options.IsRealAesMode(), options.AesKeyMode, item);
|
||||
|
||||
// file Size can be 64-bit !!!
|
||||
@@ -1015,19 +1067,29 @@ static HRESULT Update2(
|
||||
|
||||
if (t == 0)
|
||||
{
|
||||
// if thread for current file was finished.
|
||||
if (threadInfo.UpdateIndex != itemIndex)
|
||||
return E_FAIL;
|
||||
|
||||
if (memRef.PreDescriptorMode != threadInfo.CompressingResult.DescriptorMode)
|
||||
return E_FAIL;
|
||||
|
||||
RINOK(threadInfo.OutStreamSpec->WriteToRealStream());
|
||||
threadInfo.OutStreamSpec->ReleaseOutStream();
|
||||
SetFileHeader(options, ui, item);
|
||||
SetFileHeader(options, ui, threadInfo.CompressingResult.DescriptorMode, item);
|
||||
SetItemInfoFromCompressingResult(threadInfo.CompressingResult,
|
||||
options.IsRealAesMode(), options.AesKeyMode, item);
|
||||
|
||||
archive.WriteLocalHeader_Replace(item);
|
||||
}
|
||||
else
|
||||
{
|
||||
// it's not current file. So we must store information in array
|
||||
CMemBlocks2 &memRef2 = refs.Refs[threadInfo.UpdateIndex];
|
||||
threadInfo.OutStreamSpec->DetachData(memRef2);
|
||||
memRef2.CompressingResult = threadInfo.CompressingResult;
|
||||
memRef2.Defined = true;
|
||||
// memRef2.SeqMode = threadInfo.SeqMode; // it was set before
|
||||
memRef2.Finished = true;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
@@ -1060,6 +1122,7 @@ class CCacheOutStream:
|
||||
public CMyUnknownImp
|
||||
{
|
||||
CMyComPtr<IOutStream> _stream;
|
||||
CMyComPtr<ISequentialOutStream> _seqStream;
|
||||
Byte *_cache;
|
||||
UInt64 _virtPos;
|
||||
UInt64 _virtSize;
|
||||
@@ -1075,10 +1138,10 @@ class CCacheOutStream:
|
||||
}
|
||||
HRESULT FlushCache();
|
||||
public:
|
||||
CCacheOutStream(): _cache(0) {}
|
||||
CCacheOutStream(): _cache(NULL) {}
|
||||
~CCacheOutStream();
|
||||
bool Allocate();
|
||||
HRESULT Init(IOutStream *stream);
|
||||
HRESULT Init(ISequentialOutStream *seqStream, IOutStream *stream);
|
||||
|
||||
MY_UNKNOWN_IMP
|
||||
|
||||
@@ -1094,13 +1157,19 @@ bool CCacheOutStream::Allocate()
|
||||
return (_cache != NULL);
|
||||
}
|
||||
|
||||
HRESULT CCacheOutStream::Init(IOutStream *stream)
|
||||
HRESULT CCacheOutStream::Init(ISequentialOutStream *seqStream, IOutStream *stream)
|
||||
{
|
||||
_virtPos = _phyPos = 0;
|
||||
_virtPos = 0;
|
||||
_phyPos = 0;
|
||||
_virtSize = 0;
|
||||
_seqStream = seqStream;
|
||||
_stream = stream;
|
||||
RINOK(_stream->Seek(0, STREAM_SEEK_CUR, &_virtPos));
|
||||
RINOK(_stream->Seek(0, STREAM_SEEK_END, &_virtSize));
|
||||
RINOK(_stream->Seek(_virtPos, STREAM_SEEK_SET, &_virtPos));
|
||||
if (_stream)
|
||||
{
|
||||
RINOK(_stream->Seek(0, STREAM_SEEK_CUR, &_virtPos));
|
||||
RINOK(_stream->Seek(0, STREAM_SEEK_END, &_virtSize));
|
||||
RINOK(_stream->Seek(_virtPos, STREAM_SEEK_SET, &_virtPos));
|
||||
}
|
||||
_phyPos = _virtPos;
|
||||
_phySize = _virtSize;
|
||||
_cachedPos = 0;
|
||||
@@ -1114,12 +1183,14 @@ HRESULT CCacheOutStream::MyWrite(size_t size)
|
||||
{
|
||||
if (_phyPos != _cachedPos)
|
||||
{
|
||||
if (!_stream)
|
||||
return E_FAIL;
|
||||
RINOK(_stream->Seek(_cachedPos, STREAM_SEEK_SET, &_phyPos));
|
||||
}
|
||||
size_t pos = (size_t)_cachedPos & kCacheMask;
|
||||
size_t curSize = MyMin(kCacheSize - pos, _cachedSize);
|
||||
curSize = MyMin(curSize, size);
|
||||
RINOK(WriteStream(_stream, _cache + pos, curSize));
|
||||
RINOK(WriteStream(_seqStream, _cache + pos, curSize));
|
||||
_phyPos += curSize;
|
||||
if (_phySize < _phyPos)
|
||||
_phySize = _phyPos;
|
||||
@@ -1138,10 +1209,13 @@ HRESULT CCacheOutStream::FlushCache()
|
||||
CCacheOutStream::~CCacheOutStream()
|
||||
{
|
||||
FlushCache();
|
||||
if (_virtSize != _phySize)
|
||||
_stream->SetSize(_virtSize);
|
||||
if (_virtPos != _phyPos)
|
||||
_stream->Seek(_virtPos, STREAM_SEEK_SET, NULL);
|
||||
if (_stream)
|
||||
{
|
||||
if (_virtSize != _phySize)
|
||||
_stream->SetSize(_virtSize);
|
||||
if (_virtPos != _phyPos)
|
||||
_stream->Seek(_virtPos, STREAM_SEEK_SET, NULL);
|
||||
}
|
||||
::MidFree(_cache);
|
||||
}
|
||||
|
||||
@@ -1250,6 +1324,8 @@ STDMETHODIMP CCacheOutStream::SetSize(UInt64 newSize)
|
||||
_virtSize = newSize;
|
||||
if (newSize < _phySize)
|
||||
{
|
||||
if (!_stream)
|
||||
return E_NOTIMPL;
|
||||
RINOK(_stream->SetSize(newSize));
|
||||
_phySize = newSize;
|
||||
}
|
||||
@@ -1281,11 +1357,14 @@ HRESULT Update(
|
||||
|
||||
|
||||
CMyComPtr<IOutStream> outStream;
|
||||
bool outSeqMode;
|
||||
{
|
||||
CMyComPtr<IOutStream> outStreamReal;
|
||||
seqOutStream->QueryInterface(IID_IOutStream, (void **)&outStreamReal);
|
||||
if (!outStreamReal)
|
||||
return E_NOTIMPL;
|
||||
{
|
||||
// return E_NOTIMPL;
|
||||
}
|
||||
|
||||
if (inArchive)
|
||||
{
|
||||
@@ -1293,7 +1372,7 @@ HRESULT Update(
|
||||
{
|
||||
IInStream *baseStream = inArchive->GetBaseStream();
|
||||
RINOK(baseStream->Seek(0, STREAM_SEEK_SET, NULL));
|
||||
RINOK(NCompress::CopyStream_ExactSize(baseStream, outStreamReal, inArchive->ArcInfo.Base, NULL));
|
||||
RINOK(NCompress::CopyStream_ExactSize(baseStream, seqOutStream, inArchive->ArcInfo.Base, NULL));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1301,7 +1380,8 @@ HRESULT Update(
|
||||
outStream = cacheStream;
|
||||
if (!cacheStream->Allocate())
|
||||
return E_OUTOFMEMORY;
|
||||
RINOK(cacheStream->Init(outStreamReal));
|
||||
RINOK(cacheStream->Init(seqOutStream, outStreamReal));
|
||||
outSeqMode = (outStreamReal == NULL);
|
||||
}
|
||||
|
||||
COutArchive outArchive;
|
||||
@@ -1323,7 +1403,7 @@ HRESULT Update(
|
||||
EXTERNAL_CODECS_LOC_VARS
|
||||
outArchive, inArchive,
|
||||
inputItems, updateItems,
|
||||
compressionMethodMode,
|
||||
compressionMethodMode, outSeqMode,
|
||||
inArchive ? &inArchive->ArcInfo.Comment : NULL,
|
||||
updateCallback);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user