Update to 7-Zip Version 21.02

This commit is contained in:
Tino Reichardt
2021-05-13 16:39:14 +02:00
parent 3724ecfedc
commit 48fa49f76c
620 changed files with 35032 additions and 10925 deletions

View File

@@ -89,14 +89,18 @@ STDMETHODIMP CLzmaEncoder::Code(ISequentialInStream *inStream, ISequentialOutStr
}
CAddCommon::CAddCommon(const CCompressionMethodMode &options):
_options(options),
CAddCommon::CAddCommon():
_copyCoderSpec(NULL),
_isLzmaEos(false),
_cryptoStreamSpec(NULL),
_buf(NULL),
_isLzmaEos(false)
_buf(NULL)
{}
void CAddCommon::SetOptions(const CCompressionMethodMode &options)
{
_options = options;
}
CAddCommon::~CAddCommon()
{
MidFree(_buf);
@@ -232,6 +236,11 @@ HRESULT CAddCommon::Compress(
unsigned numTestMethods = _options.MethodSequence.Size();
bool descriptorMode = outSeqMode;
// ZipCrypto without descriptor requires additional reading pass for
// inStream to calculate CRC for password check field.
// The descriptor allows to use ZipCrypto check field without CRC (InfoZip's modification).
if (!outSeqMode)
if (inSeqMode && _options.PasswordIsDefined && !_options.IsAesMode)
descriptorMode = true;
@@ -264,6 +273,15 @@ HRESULT CAddCommon::Compress(
RINOK(outStream->SetSize(0));
RINOK(outStream->Seek(0, STREAM_SEEK_SET, NULL));
}
method = _options.MethodSequence[i];
if (method == NCompressionMethod::kStore && descriptorMode)
{
// we still can create descriptor_mode archives with "Store" method, but they are not good for 100%
return E_NOTIMPL;
}
bool needCode = true;
if (_options.PasswordIsDefined)
{
@@ -316,23 +334,25 @@ HRESULT CAddCommon::Compress(
RINOK(_filterSpec->WriteHeader_Check16(outStream, (UInt16)check));
}
RINOK(_cryptoStreamSpec->SetOutStream(outStream));
RINOK(_cryptoStreamSpec->InitEncoder());
outStreamReleaser.FilterCoder = _cryptoStreamSpec;
if (method == NCompressionMethod::kStore)
{
needCode = false;
RINOK(_cryptoStreamSpec->Code(inCrcStream, outStream, NULL, NULL, progress));
}
else
{
RINOK(_cryptoStreamSpec->SetOutStream(outStream));
RINOK(_cryptoStreamSpec->InitEncoder());
outStreamReleaser.FilterCoder = _cryptoStreamSpec;
}
}
method = _options.MethodSequence[i];
switch (method)
if (needCode)
{
switch (method)
{
case NCompressionMethod::kStore:
{
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;
@@ -446,15 +466,21 @@ HRESULT CAddCommon::Compress(
}
}
try {
RINOK(_compressEncoder->Code(inCrcStream, outStreamNew, NULL, NULL, progress));
} catch (...) { return E_FAIL; }
break;
}
} // switch end
if (_options.PasswordIsDefined)
{
RINOK(_cryptoStreamSpec->OutStreamFinish());
}
}
if (_options.PasswordIsDefined)
{
RINOK(_cryptoStreamSpec->OutStreamFinish());
if (_options.IsAesMode)
{
RINOK(_filterAesSpec->WriteFooter(outStream));

View File

@@ -28,9 +28,15 @@ struct CCompressingResult
Byte ExtractVersion;
bool DescriptorMode;
bool LzmaEos;
CCompressingResult()
{
// for GCC:
UnpackSize = 0;
}
};
class CAddCommon
class CAddCommon MY_UNCOPYABLE
{
CCompressionMethodMode _options;
NCompress::CCopyCoder *_copyCoderSpec;
@@ -50,7 +56,9 @@ class CAddCommon
HRESULT CalcStreamCRC(ISequentialInStream *inStream, UInt32 &resultCRC);
public:
CAddCommon(const CCompressionMethodMode &options);
// CAddCommon(const CCompressionMethodMode &options);
CAddCommon();
void SetOptions(const CCompressionMethodMode &options);
~CAddCommon();
HRESULT Set_Pre_CompressionResult(bool inSeqMode, bool outSeqMode, UInt64 unpackSize,

View File

@@ -35,7 +35,7 @@ struct CCompressionMethodMode: public CBaseProps
{
CRecordVector<Byte> MethodSequence;
bool PasswordIsDefined;
AString Password;
AString Password; // _Wipe
UInt64 _dataSizeReduce;
bool _dataSizeReduceDefined;
@@ -47,6 +47,8 @@ struct CCompressionMethodMode: public CBaseProps
_dataSizeReduceDefined = false;
_dataSizeReduce = 0;
}
~CCompressionMethodMode() { Password.Wipe_and_Empty(); }
};
}}

View File

@@ -18,6 +18,17 @@
#include "../../Common/StreamUtils.h"
#include "../../Compress/CopyCoder.h"
#ifdef EXTERNAL_CODECS
#ifndef SUPPORT_LZFSE
#define SUPPORT_LZFSE
#endif
#endif
#ifdef SUPPORT_LZFSE
#include "../../Compress/LzfseDecoder.h"
#endif
#include "../../Compress/LzmaDecoder.h"
#include "../../Compress/ImplodeDecoder.h"
#include "../../Compress/PpmdZip.h"
@@ -82,18 +93,24 @@ const char * const kMethodNames1[kNumMethodNames1] =
, "BZip2"
, NULL
, "LZMA"
, NULL
, NULL
, NULL
, NULL
, NULL
, "zstd-pk"
};
const char * const kMethodNames2[kNumMethodNames2] =
{
"zstd"
, NULL
, "MP3"
, "xz"
, "Jpeg"
, "WavPack"
, "PPMd"
, "WzAES"
, "LZFSE" // , "WzAES"
};
#define kMethod_AES "AES"
@@ -243,6 +260,12 @@ STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)
if (m_Archive.IsZip64)
s.Add_OptSpaced("Zip64");
if (m_Archive.IsCdUnsorted)
s.Add_OptSpaced("Unsorted_CD");
if (m_Archive.IsApk)
s.Add_OptSpaced("apk");
if (m_Archive.ExtraMinorError)
s.Add_OptSpaced("Minor_Extra_ERROR");
@@ -315,9 +338,8 @@ STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)
// case kpidIsAltStream: prop = true; break;
}
prop.Detach(value);
return prop.Detach(value);
COM_TRY_END
return S_OK;
}
STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems)
@@ -339,7 +361,9 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val
{
UString res;
item.GetUnicodeString(res, item.Name, false, _forceCodePage, _specifiedCodePage);
NItemName::ReplaceToOsSlashes_Remove_TailSlash(res);
NItemName::ReplaceToOsSlashes_Remove_TailSlash(res,
item.Is_MadeBy_Unix() // useBackslashReplacement
);
/*
if (item.ParentOfAltStream >= 0)
{
@@ -362,7 +386,7 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val
case kpidIsDir: prop = item.IsDir(); break;
case kpidSize:
{
if (item.FromCentral || !item.FromLocal || !item.HasDescriptor() || item.DescriptorWasRead)
if (!item.IsBadDescriptor())
prop = item.Size;
break;
}
@@ -470,23 +494,27 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val
case kpidMethod:
{
unsigned id = item.Method;
AString m;
if (item.IsEncrypted())
bool isWzAes = false;
unsigned id = item.Method;
if (id == NFileHeader::NCompressionMethod::kWzAES)
{
if (id == NFileHeader::NCompressionMethod::kWzAES)
CWzAesExtra aesField;
if (extra.GetWzAes(aesField))
{
m += kMethod_AES;
CWzAesExtra aesField;
if (extra.GetWzAes(aesField))
{
m += '-';
m.Add_UInt32(((unsigned)aesField.Strength + 1) * 64);
id = aesField.Method;
}
m += '-';
m.Add_UInt32(((unsigned)aesField.Strength + 1) * 64);
id = aesField.Method;
isWzAes = true;
}
else if (item.IsStrongEncrypted())
}
if (item.IsEncrypted())
if (!isWzAes)
{
if (item.IsStrongEncrypted())
{
CStrongCryptoExtra f;
f.AlgId = 0;
@@ -509,8 +537,9 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val
}
else
m += kMethod_ZipCrypto;
m += ' ';
}
m.Add_Space_if_NotEmpty();
{
const char *s = NULL;
@@ -519,7 +548,7 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val
else
{
int id2 = (int)id - (int)kMethodNames2Start;
if (id2 >= 0 && id2 < kNumMethodNames2)
if (id2 >= 0 && (unsigned)id2 < kNumMethodNames2)
s = kMethodNames2[id2];
}
if (s)
@@ -535,7 +564,7 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val
{
if (level & 1)
m += ":eos";
level &= ~1;
level &= ~(unsigned)1;
}
else if (id == NFileHeader::NCompressionMethod::kDeflate)
{
@@ -579,7 +608,7 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val
}
UInt32 flags = item.Flags;
flags &= ~(6); // we don't need compression related bits here.
flags &= ~(unsigned)6; // we don't need compression related bits here.
if (flags != 0)
{
@@ -592,7 +621,7 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val
}
}
if (!item.FromCentral && item.FromLocal && item.HasDescriptor() && !item.DescriptorWasRead)
if (item.IsBadDescriptor())
s.Add_OptSpaced("Descriptor_ERROR");
if (!s.IsEmpty())
@@ -637,8 +666,7 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val
*/
}
prop.Detach(value);
return S_OK;
return prop.Detach(value);
COM_TRY_END
}
@@ -889,11 +917,14 @@ public:
};
static HRESULT SkipStreamData(ISequentialInStream *stream, bool &thereAreData)
static HRESULT SkipStreamData(ISequentialInStream *stream,
ICompressProgressInfo *progress, UInt64 packSize, UInt64 unpackSize,
bool &thereAreData)
{
thereAreData = false;
const size_t kBufSize = 1 << 12;
Byte buf[kBufSize];
UInt64 prev = packSize;
for (;;)
{
size_t size = kBufSize;
@@ -901,10 +932,80 @@ static HRESULT SkipStreamData(ISequentialInStream *stream, bool &thereAreData)
if (size == 0)
return S_OK;
thereAreData = true;
packSize += size;
if ((packSize - prev) >= (1 << 22))
{
prev = packSize;
RINOK(progress->SetRatioInfo(&packSize, &unpackSize));
}
}
}
class COutStreamWithPadPKCS7:
public ISequentialOutStream,
public CMyUnknownImp
{
CMyComPtr<ISequentialOutStream> _stream;
UInt64 _size;
UInt64 _padPos;
UInt32 _padSize;
bool _padFailure;
public:
MY_UNKNOWN_IMP
STDMETHOD(Write)(const void *data, UInt32 size, UInt32 *processedSize);
void SetStream(ISequentialOutStream *stream) { _stream = stream; }
void ReleaseStream() { _stream.Release(); }
// padSize == 0 means (no_pad Mode)
void Init(UInt64 padPos, UInt32 padSize)
{
_padPos = padPos;
_padSize = padSize;
_size = 0;
_padFailure = false;
}
UInt64 GetSize() const { return _size; }
bool WasPadFailure() const { return _padFailure; }
};
STDMETHODIMP COutStreamWithPadPKCS7::Write(const void *data, UInt32 size, UInt32 *processedSize)
{
UInt32 written = 0;
HRESULT result = S_OK;
if (_size < _padPos)
{
const UInt64 rem = _padPos - _size;
UInt32 num = size;
if (num > rem)
num = (UInt32)rem;
result = _stream->Write(data, num, &written);
_size += written;
if (processedSize)
*processedSize = written;
if (_size != _padPos || result != S_OK)
return result;
size -= written;
data = ((const Byte *)data) + written;
}
_size += size;
written += size;
if (processedSize)
*processedSize = written;
if (_padSize != 0)
for (; size != 0; size--)
{
if (*(const Byte *)data != _padSize)
_padFailure = true;
data = ((const Byte *)data) + 1;
}
return result;
}
HRESULT CZipDecoder::Decode(
DECL_EXTERNAL_CODECS_LOC_VARS
CInArchive &archive, const CItemEx &item,
@@ -924,9 +1025,32 @@ HRESULT CZipDecoder::Decode(
bool needCRC = true;
bool wzAesMode = false;
bool pkAesMode = false;
bool badDescriptor = item.IsBadDescriptor();
if (badDescriptor)
needCRC = false;
unsigned id = item.Method;
CWzAesExtra aesField;
// LZFSE and WinZip's AES use same id - kWzAES.
if (id == NFileHeader::NCompressionMethod::kWzAES)
{
if (item.GetMainExtra().GetWzAes(aesField))
{
if (!item.IsEncrypted())
{
res = NExtract::NOperationResult::kUnsupportedMethod;
return S_OK;
}
wzAesMode = true;
needCRC = aesField.NeedCrc();
}
}
if (!wzAesMode)
if (item.IsEncrypted())
{
if (item.IsStrongEncrypted())
@@ -939,14 +1063,6 @@ HRESULT CZipDecoder::Decode(
}
pkAesMode = true;
}
else if (id == NFileHeader::NCompressionMethod::kWzAES)
{
CWzAesExtra aesField;
if (!item.GetMainExtra().GetWzAes(aesField))
return S_OK;
wzAesMode = true;
needCRC = aesField.NeedCrc();
}
}
COutStreamWithCRC *outStreamSpec = new COutStreamWithCRC;
@@ -986,9 +1102,6 @@ HRESULT CZipDecoder::Decode(
{
if (wzAesMode)
{
CWzAesExtra aesField;
if (!item.GetMainExtra().GetWzAes(aesField))
return S_OK;
id = aesField.Method;
if (!_wzAesDecoder)
{
@@ -1031,12 +1144,12 @@ HRESULT CZipDecoder::Decode(
if (getTextPassword)
{
CMyComBSTR password;
CMyComBSTR_Wipe password;
RINOK(getTextPassword->CryptoGetTextPassword(&password));
AString charPassword;
AString_Wipe charPassword;
if (password)
{
UnicodeStringToMultiByte2(charPassword, (const wchar_t *)password, CP_ACP);
UnicodeStringToMultiByte2(charPassword, (LPCOLESTR)password, CP_ACP);
/*
if (wzAesMode || pkAesMode)
{
@@ -1090,10 +1203,16 @@ HRESULT CZipDecoder::Decode(
}
else if (id ==NFileHeader::NCompressionMethod::kZstd)
mi.Coder = new CZstdDecoder();
else if (id ==NFileHeader::NCompressionMethod::kZstdPk)
mi.Coder = new CZstdDecoder();
else if (id == NFileHeader::NCompressionMethod::kXz)
mi.Coder = new NCompress::NXz::CComDecoder;
else if (id == NFileHeader::NCompressionMethod::kPPMd)
mi.Coder = new NCompress::NPpmdZip::CDecoder(true);
#ifdef SUPPORT_LZFSE
else if (id == NFileHeader::NCompressionMethod::kWzAES)
mi.Coder = new NCompress::NLzfse::CDecoder;
#endif
else
{
CMethodId szMethodID;
@@ -1120,7 +1239,8 @@ HRESULT CZipDecoder::Decode(
m = methodItems.Add(mi);
}
ICompressCoder *coder = methodItems[m].Coder;
const CMethodItem &mi = methodItems[m];
ICompressCoder *coder = mi.Coder;
#ifndef _7ZIP_ST
@@ -1154,14 +1274,22 @@ HRESULT CZipDecoder::Decode(
}
CMyComPtr<ISequentialInStream> inStreamNew;
bool isFullStreamExpected = (!item.HasDescriptor() || item.PackSize != 0);
bool needReminderCheck = false;
bool dataAfterEnd = false;
bool truncatedError = false;
bool lzmaEosError = false;
bool headersError = false;
bool padError = false;
bool readFromFilter = false;
const bool useUnpackLimit = (id == NFileHeader::NCompressionMethod::kStore
|| !item.HasDescriptor()
|| item.Size >= ((UInt64)1 << 32)
|| item.LocalExtra.IsZip64
|| item.CentralExtra.IsZip64
);
{
HRESULT result = S_OK;
@@ -1229,23 +1357,7 @@ HRESULT CZipDecoder::Decode(
}
}
}
if (result == S_OK)
{
inStreamReleaser.FilterCoder = filterStreamSpec;
RINOK(filterStreamSpec->SetInStream(inStream));
/* IFilter::Init() does nothing in all zip crypto filters.
So we can call any Initialize function in CFilterCoder. */
RINOK(filterStreamSpec->Init_NoSubFilterInit());
// RINOK(filterStreamSpec->SetOutStreamSize(NULL));
inStreamNew = filterStream;
}
}
else
inStreamNew = inStream;
if (result == S_OK)
{
@@ -1253,26 +1365,84 @@ HRESULT CZipDecoder::Decode(
coder->QueryInterface(IID_ICompressSetFinishMode, (void **)&setFinishMode);
if (setFinishMode)
{
RINOK(setFinishMode->SetFinishMode(BoolToInt(true)));
RINOK(setFinishMode->SetFinishMode(BoolToUInt(true)));
}
const UInt64 coderPackSize = limitedStreamSpec->GetRem();
bool useUnpackLimit = (id == 0
|| !item.HasDescriptor()
|| item.Size >= ((UInt64)1 << 32)
|| item.LocalExtra.IsZip64
|| item.CentralExtra.IsZip64
);
result = coder->Code(inStreamNew, outStream,
isFullStreamExpected ? &coderPackSize : NULL,
// NULL,
useUnpackLimit ? &item.Size : NULL,
compressProgress);
if (result == S_OK)
if (id == NFileHeader::NCompressionMethod::kStore && item.IsEncrypted())
{
readFromFilter = false;
COutStreamWithPadPKCS7 *padStreamSpec = NULL;
CMyComPtr<ISequentialOutStream> padStream;
UInt32 padSize = 0;
if (pkAesMode)
{
padStreamSpec = new COutStreamWithPadPKCS7;
padStream = padStreamSpec;
padSize = _pkAesDecoderSpec->GetPadSize((UInt32)item.Size);
padStreamSpec->SetStream(outStream);
padStreamSpec->Init(item.Size, padSize);
}
// Here we decode minimal required size, including padding
const UInt64 expectedSize = item.Size + padSize;
UInt64 size = coderPackSize;
if (item.Size > coderPackSize)
headersError = true;
else if (expectedSize != coderPackSize)
{
headersError = true;
if (coderPackSize > expectedSize)
size = expectedSize;
}
result = filterStreamSpec->Code(inStream, padStream ?
(ISequentialOutStream *)padStream :
(ISequentialOutStream *)outStream,
NULL, &size, compressProgress);
if (outStreamSpec->GetSize() != item.Size)
truncatedError = true;
if (pkAesMode)
{
if (padStreamSpec->GetSize() != size)
truncatedError = true;
if (padStreamSpec->WasPadFailure())
padError = true;
}
}
else
{
if (item.IsEncrypted())
{
readFromFilter = true;
inStreamReleaser.FilterCoder = filterStreamSpec;
RINOK(filterStreamSpec->SetInStream(inStream));
/* IFilter::Init() does nothing in all zip crypto filters.
So we can call any Initialize function in CFilterCoder. */
RINOK(filterStreamSpec->Init_NoSubFilterInit());
// RINOK(filterStreamSpec->SetOutStreamSize(NULL));
}
try {
result = coder->Code(readFromFilter ?
(ISequentialInStream *)filterStream :
(ISequentialInStream *)inStream,
outStream,
isFullStreamExpected ? &coderPackSize : NULL,
// NULL,
useUnpackLimit ? &item.Size : NULL,
compressProgress);
} catch (...) { return E_FAIL; }
if (result == S_OK)
{
CMyComPtr<ICompressGetInStreamProcessedSize> getInStreamProcessedSize;
coder->QueryInterface(IID_ICompressGetInStreamProcessedSize, (void **)&getInStreamProcessedSize);
if (getInStreamProcessedSize && setFinishMode)
@@ -1290,7 +1460,32 @@ HRESULT CZipDecoder::Decode(
{
if (processed + padSize < coderPackSize)
dataAfterEnd = true;
// also here we can check PKCS7 padding data from reminder (it can be inside stream buffer in coder).
else
{
// here we can PKCS7 padding data from reminder (it can be inside stream buffer in coder).
CMyComPtr<ICompressReadUnusedFromInBuf> readInStream;
coder->QueryInterface(IID_ICompressReadUnusedFromInBuf, (void **)&readInStream);
if (readInStream)
{
// change pad size, it we support another block size in ZipStron
// here we request more to detect error with data after end.
const UInt32 kBufSize = NCrypto::NZipStrong::kAesPadAllign + 16;
Byte buf[kBufSize];
UInt32 processedSize;
RINOK(readInStream->ReadUnusedFromInBuf(buf, kBufSize, &processedSize));
if (processedSize > padSize)
dataAfterEnd = true;
else
{
if (ReadStream_FALSE(filterStream, buf + processedSize, padSize - processedSize) != S_OK)
padError = true;
else
for (unsigned i = 0; i < padSize; i++)
if (buf[i] != padSize)
padError = true;
}
}
}
}
}
else
@@ -1301,11 +1496,15 @@ HRESULT CZipDecoder::Decode(
dataAfterEnd = true;
}
else if (processed > coderPackSize)
{
// that case is additional check, that can show the bugs in code (coder)
truncatedError = true;
}
needReminderCheck = isFullStreamExpected;
}
}
}
}
}
if (result == S_OK && id == NFileHeader::NCompressionMethod::kLZMA)
@@ -1329,19 +1528,33 @@ HRESULT CZipDecoder::Decode(
bool authOk = true;
if (needCRC)
crcOK = (outStreamSpec->GetCRC() == item.Crc);
if (useUnpackLimit)
if (outStreamSpec->GetSize() != item.Size)
truncatedError = true;
if (wzAesMode)
{
const UInt64 unpackSize = outStreamSpec->GetSize();
const UInt64 packSize = limitedStreamSpec->GetSize();
bool thereAreData = false;
if (SkipStreamData(inStreamNew, thereAreData) != S_OK)
// read to the end from filter or from packed stream
if (SkipStreamData(readFromFilter ?
(ISequentialInStream *)filterStream :
(ISequentialInStream *)inStream,
compressProgress, packSize, unpackSize, thereAreData) != S_OK)
authOk = false;
if (needReminderCheck && thereAreData)
dataAfterEnd = true;
limitedStreamSpec->Init(NCrypto::NWzAes::kMacSize);
if (_wzAesDecoderSpec->CheckMac(inStream, authOk) != S_OK)
authOk = false;
if (limitedStreamSpec->GetRem() != 0)
truncatedError = true;
else
{
limitedStreamSpec->Init(NCrypto::NWzAes::kMacSize);
if (_wzAesDecoderSpec->CheckMac(inStream, authOk) != S_OK)
authOk = false;
}
}
res = NExtract::NOperationResult::kCRCError;
@@ -1352,10 +1565,16 @@ HRESULT CZipDecoder::Decode(
if (dataAfterEnd)
res = NExtract::NOperationResult::kDataAfterEnd;
else if (padError)
res = NExtract::NOperationResult::kCRCError;
else if (truncatedError)
res = NExtract::NOperationResult::kUnexpectedEnd;
else if (headersError)
res = NExtract::NOperationResult::kHeadersError;
else if (lzmaEosError)
res = NExtract::NOperationResult::kHeadersError;
else if (badDescriptor)
res = NExtract::NOperationResult::kUnexpectedEnd;
// CheckDescriptor() supports only data descriptor with signature and
// it doesn't support "old" pkzip's data descriptor without signature.

View File

@@ -15,7 +15,7 @@
namespace NArchive {
namespace NZip {
const unsigned kNumMethodNames1 = NFileHeader::NCompressionMethod::kLZMA + 1;
const unsigned kNumMethodNames1 = NFileHeader::NCompressionMethod::kZstdPk + 1;
const unsigned kMethodNames2Start = NFileHeader::NCompressionMethod::kZstd;
const unsigned kNumMethodNames2 = NFileHeader::NCompressionMethod::kWzAES + 1 - kMethodNames2Start;

View File

@@ -53,7 +53,7 @@ static int FindZipMethod(const char *s, const char * const *names, unsigned num)
{
const char *name = names[i];
if (name && StringsAreEqualNoCase_Ascii(s, name))
return i;
return (int)i;
}
return -1;
}
@@ -65,7 +65,7 @@ static int FindZipMethod(const char *s)
return k;
k = FindZipMethod(s, kMethodNames2, kNumMethodNames2);
if (k >= 0)
return kMethodNames2Start + k;
return (int)kMethodNames2Start + k;
return -1;
}
@@ -75,7 +75,7 @@ static int FindZipMethod(const char *s)
catch(const CSystemException &e) { return e.ErrorCode; } \
catch(...) { return E_OUTOFMEMORY; }
static HRESULT GetTime(IArchiveUpdateCallback *callback, int index, PROPID propID, FILETIME &filetime)
static HRESULT GetTime(IArchiveUpdateCallback *callback, unsigned index, PROPID propID, FILETIME &filetime)
{
filetime.dwHighDateTime = filetime.dwLowDateTime = 0;
NCOM::CPropVariant prop;
@@ -106,6 +106,10 @@ STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numIt
UInt64 largestSize = 0;
bool largestSizeDefined = false;
#ifdef _WIN32
const UINT oemCP = GetOEMCP();
#endif
UString name;
CUpdateItem ui;
@@ -125,7 +129,7 @@ STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numIt
ui.NewProps = IntToBool(newProps);
ui.NewData = IntToBool(newData);
ui.IndexInArc = indexInArc;
ui.IndexInArc = (int)indexInArc;
ui.IndexInClient = i;
bool existInArchive = (indexInArc != (UInt32)(Int32)-1);
@@ -240,10 +244,25 @@ STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numIt
if (needSlash)
name += kSlash;
UINT codePage = _forceCodePage ? _specifiedCodePage : CP_OEMCP;
const UINT codePage = _forceCodePage ? _specifiedCodePage : CP_OEMCP;
bool tryUtf8 = true;
if ((m_ForceLocal || !m_ForceUtf8) && codePage != CP_UTF8)
/*
Windows 10 allows users to set UTF-8 in Region Settings via option:
"Beta: Use Unicode UTF-8 for worldwide language support"
In that case Windows uses CP_UTF8 when we use CP_OEMCP.
21.02 fixed:
we set UTF-8 mark for non-latin files for such UTF-8 mode in Windows.
we write additional Info-Zip Utf-8 FileName Extra for non-latin names/
*/
if ((codePage != CP_UTF8) &&
#ifdef _WIN32
(m_ForceLocal || !m_ForceUtf8) && (oemCP != CP_UTF8)
#else
(m_ForceLocal && !m_ForceUtf8)
#endif
)
{
bool defaultCharWasUsed;
ui.Name = UnicodeStringToMultiByte(name, codePage, '_', defaultCharWasUsed);
@@ -251,13 +270,26 @@ STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numIt
MultiByteToUnicodeString(ui.Name, codePage) != name));
}
const bool isNonLatin = !name.IsAscii();
if (tryUtf8)
{
ui.IsUtf8 = !name.IsAscii();
ui.IsUtf8 = isNonLatin;
ConvertUnicodeToUTF8(name, ui.Name);
}
if (ui.Name.Len() >= (1 << 16))
#ifndef _WIN32
if (ui.IsUtf8 && !CheckUTF8_AString(ui.Name))
{
// if it's non-Windows and there are non-UTF8 characters we clear UTF8-flag
ui.IsUtf8 = false;
}
#endif
}
else if (isNonLatin)
Convert_Unicode_To_UTF8_Buf(name, ui.Name_Utf);
if (ui.Name.Len() >= (1 << 16)
|| ui.Name_Utf.Size() >= (1 << 16) - 128)
return E_INVALIDARG;
{
@@ -337,10 +369,10 @@ STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numIt
options._dataSizeReduceDefined = largestSizeDefined;
options.PasswordIsDefined = false;
options.Password.Empty();
options.Password.Wipe_and_Empty();
if (getTextPassword)
{
CMyComBSTR password;
CMyComBSTR_Wipe password;
Int32 passwordIsDefined;
RINOK(getTextPassword->CryptoGetTextPassword2(&passwordIsDefined, &password));
options.PasswordIsDefined = IntToBool(passwordIsDefined);
@@ -352,7 +384,7 @@ STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numIt
if (!IsSimpleAsciiString(password))
return E_INVALIDARG;
if (password)
options.Password = UnicodeStringToMultiByte((LPCOLESTR)password, CP_OEMCP);
UnicodeStringToMultiByte2(options.Password, (LPCOLESTR)password, CP_OEMCP);
if (options.IsAesMode)
{
if (options.Password.Len() > NCrypto::NWzAes::kPasswordSizeMax)
@@ -496,7 +528,7 @@ STDMETHODIMP CHandler::SetProperties(const wchar_t * const *names, const PROPVAR
UInt32 id = prop.ulVal;
if (id > 0xFF)
return E_INVALIDARG;
m_MainMethod = id;
m_MainMethod = (int)id;
}
else
{
@@ -518,7 +550,7 @@ STDMETHODIMP CHandler::SetProperties(const wchar_t * const *names, const PROPVAR
const char *end;
UInt32 id = ConvertStringToUInt32(methodName, &end);
if (*end == 0 && id <= 0xFF)
m_MainMethod = id;
m_MainMethod = (int)id;
else if (methodName.IsEqualTo_Ascii_NoCase("Copy")) // it's alias for "Store"
m_MainMethod = 0;
}

View File

@@ -49,24 +49,25 @@ namespace NFileHeader
kDeflate = 8,
kDeflate64 = 9,
kPKImploding = 10,
kBZip2 = 12,
kLZMA = 14,
kTerse = 18,
kLz77 = 19,
kZstd = 93,
kXz = 95,
kJpeg = 96,
kWavPack = 97,
kPPMd = 98,
kWzAES = 99
kBZip2 = 12, // File is compressed using BZIP2 algorithm
kLZMA = 14, // LZMA
kTerse = 18, // File is compressed using IBM TERSE (new)
kLz77 = 19, // IBM LZ77 z Architecture
kZstdPk = 20, // deprecated (use method 93 for zstd)
kZstd = 93, // Zstandard (zstd) Compression
kMP3 = 94, // MP3 Compression
kXz = 95, // XZ Compression
kJpeg = 96, // JPEG variant
kWavPack = 97, // WavPack compressed data
kPPMd = 98, // PPMd version I, Rev 1
kWzAES = 99 // AE-x encryption marker (see APPENDIX E)
};
const Byte kMadeByProgramVersion = 63;
const Byte kExtractVersion_Default = 10;
const Byte kExtractVersion_Dir = 20;
const Byte kExtractVersion_ZipCrypto = 20;
@@ -77,7 +78,7 @@ namespace NFileHeader
const Byte kExtractVersion_Aes = 51;
const Byte kExtractVersion_LZMA = 63;
const Byte kExtractVersion_PPMd = 63;
const Byte kExtractVersion_Xz = 20; // test it
const Byte kExtractVersion_Xz = 20; // test it
const Byte kExtractVersion_Zstd = 20; // WinZip mark it
}
@@ -92,7 +93,10 @@ namespace NFileHeader
kUnixExtra = 0x5855,
kIzUnicodeComment = 0x6375,
kIzUnicodeName = 0x7075,
kWzAES = 0x9901
kUnix2Extra = 0x7855,
kUnix3Extra = 0x7875,
kWzAES = 0x9901,
kApkAlign = 0xD935
};
}

View File

@@ -152,6 +152,9 @@ void CInArchive::Close()
IsArc = false;
IsZip64 = false;
IsApk = false;
IsCdUnsorted = false;
HeadersError = false;
HeadersWarning = false;
ExtraMinorError = false;
@@ -169,7 +172,7 @@ void CInArchive::Close()
IsMultiVol = false;
UseDisk_in_SingleVol = false;
EcdVolIndex = 0;
ArcInfo.Clear();
ClearRefs();
@@ -181,7 +184,7 @@ HRESULT CInArchive::Seek_SavePos(UInt64 offset)
{
// InitBuf();
// if (!Stream) return S_FALSE;
return Stream->Seek(offset, STREAM_SEEK_SET, &_streamPos);
return Stream->Seek((Int64)offset, STREAM_SEEK_SET, &_streamPos);
}
HRESULT CInArchive::SeekToVol(int volIndex, UInt64 offset)
@@ -193,9 +196,9 @@ HRESULT CInArchive::SeekToVol(int volIndex, UInt64 offset)
{
if ((unsigned)volIndex >= Vols.Streams.Size())
return S_FALSE;
if (!Vols.Streams[volIndex].Stream)
if (!Vols.Streams[(unsigned)volIndex].Stream)
return S_FALSE;
Stream = Vols.Streams[volIndex].Stream;
Stream = Vols.Streams[(unsigned)volIndex].Stream;
}
else if (volIndex == -2)
{
@@ -277,11 +280,11 @@ HRESULT CInArchive::ReadFromCache(Byte *data, unsigned size, unsigned &processed
}
else
{
UInt32 cur = 0;
result = Stream->Read(data, size, &cur);
size_t cur = size;
result = ReadStream(Stream, data, &cur);
data += cur;
size -= cur;
processed += cur;
size -= (unsigned)cur;
processed += (unsigned)cur;
_streamPos += cur;
_cnt += cur;
if (cur != 0)
@@ -299,7 +302,7 @@ HRESULT CInArchive::ReadFromCache(Byte *data, unsigned size, unsigned &processed
|| (unsigned)Vols.StreamIndex + 1 >= Vols.Streams.Size())
break;
const CVols::CSubStreamInfo &s = Vols.Streams[Vols.StreamIndex + 1];
const CVols::CSubStreamInfo &s = Vols.Streams[(unsigned)Vols.StreamIndex + 1];
if (!s.Stream)
break;
result = s.SeekToStart();
@@ -316,6 +319,16 @@ HRESULT CInArchive::ReadFromCache(Byte *data, unsigned size, unsigned &processed
}
HRESULT CInArchive::ReadFromCache_FALSE(Byte *data, unsigned size)
{
unsigned processed;
HRESULT res = ReadFromCache(data, size, processed);
if (res == S_OK && size != processed)
return S_FALSE;
return res;
}
static bool CheckDosTime(UInt32 dosTime)
{
if (dosTime == 0)
@@ -412,8 +425,12 @@ API_FUNC_IsArc IsArc_Zip(const Byte *p, size_t size)
const unsigned nameSize = Get16(p + 22);
unsigned extraSize = Get16(p + 24);
const UInt32 extraOffset = kLocalHeaderSize + (UInt32)nameSize;
/*
// 21.02: fixed. we don't use the following check
if (extraOffset + extraSize > (1 << 16))
return k_IsArc_Res_NO;
*/
p -= 4;
@@ -498,12 +515,9 @@ static const Byte *FindPK(const Byte *p, const Byte *limit)
{
for (;;)
{
Byte b0 = p[0];
if (p >= limit)
return p;
p++;
if (b0 == 0x50)
break;
Byte b0;
b0 = p[0]; if (p >= limit) return p; p++; if (b0 == 0x50) break;
b0 = p[0]; if (p >= limit) return p; p++; if (b0 == 0x50) break;
}
if (p[0] == 0x4B)
return p - 1;
@@ -540,10 +554,7 @@ HRESULT CInArchive::FindMarker(const UInt64 *searchLimit)
if (searchLimit && *searchLimit == 0)
{
Byte startBuf[kMarkerSize];
unsigned processed;
RINOK(ReadFromCache(startBuf, kMarkerSize, processed));
if (processed != kMarkerSize)
return S_FALSE;
RINOK(ReadFromCache_FALSE(startBuf, kMarkerSize));
UInt32 marker = Get32(startBuf);
_signature = marker;
@@ -551,9 +562,7 @@ HRESULT CInArchive::FindMarker(const UInt64 *searchLimit)
if ( marker == NSignature::kNoSpan
|| marker == NSignature::kSpan)
{
RINOK(ReadFromCache(startBuf, kMarkerSize, processed));
if (processed != kMarkerSize)
return S_FALSE;
RINOK(ReadFromCache_FALSE(startBuf, kMarkerSize));
_signature = Get32(startBuf);
}
@@ -605,7 +614,7 @@ HRESULT CInArchive::FindMarker(const UInt64 *searchLimit)
SkipLookahed(avail);
const CVols::CSubStreamInfo &s = Vols.Streams[Vols.StreamIndex + 1];
const CVols::CSubStreamInfo &s = Vols.Streams[(unsigned)Vols.StreamIndex + 1];
if (!s.Stream)
break;
@@ -645,14 +654,14 @@ HRESULT CInArchive::FindMarker(const UInt64 *searchLimit)
p = FindPK(p, limit);
if (p >= limit)
break;
const size_t rem = pStart + avail - p;
const size_t rem = (size_t)(pStart + avail - p);
UInt32 res = IsArc_Zip_2(p, rem, isFinished);
if (res != k_IsArc_Res_NO)
{
if (rem < kMarkerSize)
return S_FALSE;
_signature = Get32(p);
SkipLookahed(p - pStart);
SkipLookahed((size_t)(p - pStart));
ArcInfo.MarkerVolIndex = Vols.StreamIndex;
ArcInfo.MarkerPos = GetVirtStreamPos();
ArcInfo.MarkerPos2 = ArcInfo.MarkerPos;
@@ -674,7 +683,7 @@ HRESULT CInArchive::FindMarker(const UInt64 *searchLimit)
if (!IsMultiVol && isFinished)
break;
SkipLookahed(p - pStart);
SkipLookahed((size_t)(p - pStart));
if (Callback && (_cnt - progressPrev) >= ((UInt32)1 << 23))
{
@@ -728,7 +737,7 @@ HRESULT CInArchive::IncreaseRealPosition(UInt64 offset, bool &isFinished)
if (!IsMultiVol)
{
_cnt += offset;
return Stream->Seek(offset, STREAM_SEEK_CUR, &_streamPos);
return Stream->Seek((Int64)offset, STREAM_SEEK_CUR, &_streamPos);
}
for (;;)
@@ -744,7 +753,7 @@ HRESULT CInArchive::IncreaseRealPosition(UInt64 offset, bool &isFinished)
return S_OK;
}
{
const CVols::CSubStreamInfo &s = Vols.Streams[Vols.StreamIndex];
const CVols::CSubStreamInfo &s = Vols.Streams[(unsigned)Vols.StreamIndex];
if (!s.Stream)
{
isFinished = true;
@@ -756,7 +765,7 @@ HRESULT CInArchive::IncreaseRealPosition(UInt64 offset, bool &isFinished)
if ((UInt64)offset <= rem)
{
_cnt += offset;
return Stream->Seek(offset, STREAM_SEEK_CUR, &_streamPos);
return Stream->Seek((Int64)offset, STREAM_SEEK_CUR, &_streamPos);
}
RINOK(Seek_SavePos(s.Size));
offset -= rem;
@@ -771,7 +780,7 @@ HRESULT CInArchive::IncreaseRealPosition(UInt64 offset, bool &isFinished)
isFinished = true;
return S_OK;
}
const CVols::CSubStreamInfo &s2 = Vols.Streams[Vols.StreamIndex];
const CVols::CSubStreamInfo &s2 = Vols.Streams[(unsigned)Vols.StreamIndex];
if (!s2.Stream)
{
isFinished = true;
@@ -834,7 +843,7 @@ HRESULT CInArchive::LookAhead(size_t minRequired)
|| (unsigned)Vols.StreamIndex + 1 >= Vols.Streams.Size())
return S_OK;
const CVols::CSubStreamInfo &s = Vols.Streams[Vols.StreamIndex + 1];
const CVols::CSubStreamInfo &s = Vols.Streams[(unsigned)Vols.StreamIndex + 1];
if (!s.Stream)
return S_OK;
@@ -979,7 +988,7 @@ bool CInArchive::ReadFileName(unsigned size, AString &s)
#define ZIP64_IS_16_MAX(n) ((n) == 0xFFFF)
bool CInArchive::ReadExtra(unsigned extraSize, CExtraBlock &extra,
bool CInArchive::ReadExtra(const CLocalItem &item, unsigned extraSize, CExtraBlock &extra,
UInt64 &unpackSize, UInt64 &packSize, UInt64 &localOffset, UInt32 &disk)
{
extra.Clear();
@@ -1010,16 +1019,16 @@ bool CInArchive::ReadExtra(unsigned extraSize, CExtraBlock &extra,
bool isOK = true;
if (ZIP64_IS_32_MAX(unpackSize))
if (size < 8) isOK = false; else { size -= 8; unpackSize = ReadUInt64(); }
{ if (size < 8) isOK = false; else { size -= 8; unpackSize = ReadUInt64(); }}
if (isOK && ZIP64_IS_32_MAX(packSize))
if (size < 8) isOK = false; else { size -= 8; packSize = ReadUInt64(); }
{ if (size < 8) isOK = false; else { size -= 8; packSize = ReadUInt64(); }}
if (isOK && ZIP64_IS_32_MAX(localOffset))
if (size < 8) isOK = false; else { size -= 8; localOffset = ReadUInt64(); }
{ if (size < 8) isOK = false; else { size -= 8; localOffset = ReadUInt64(); }}
if (isOK && ZIP64_IS_16_MAX(disk))
if (size < 4) isOK = false; else { size -= 4; disk = ReadUInt32(); }
{ if (size < 4) isOK = false; else { size -= 4; disk = ReadUInt32(); }}
if (!isOK || size != 0)
{
@@ -1033,6 +1042,11 @@ bool CInArchive::ReadExtra(unsigned extraSize, CExtraBlock &extra,
{
ReadBuffer(subBlock.Data, size);
extra.SubBlocks.Add(subBlock);
if (subBlock.ID == NFileHeader::NExtraID::kIzUnicodeName)
{
if (!subBlock.CheckIzUnicode(item.Name))
extra.Error = true;
}
}
}
@@ -1054,7 +1068,7 @@ bool CInArchive::ReadLocalItem(CItemEx &item)
{
item.Disk = 0;
if (IsMultiVol && Vols.StreamIndex >= 0)
item.Disk = Vols.StreamIndex;
item.Disk = (UInt32)Vols.StreamIndex;
const unsigned kPureHeaderSize = kLocalHeaderSize - 4;
Byte p[kPureHeaderSize];
SafeRead(p, kPureHeaderSize);
@@ -1088,7 +1102,7 @@ bool CInArchive::ReadLocalItem(CItemEx &item)
{
UInt64 localOffset = 0;
UInt32 disk = 0;
if (!ReadExtra(extraSize, item.LocalExtra, item.Size, item.PackSize, localOffset, disk))
if (!ReadExtra(item, extraSize, item.LocalExtra, item.Size, item.PackSize, localOffset, disk))
{
/* Most of archives are OK for Extra. But there are some rare cases
that have error. And if error in first item, it can't open archive.
@@ -1111,33 +1125,39 @@ bool CInArchive::ReadLocalItem(CItemEx &item)
HeadersWarning = true;
}
return item.LocalFullHeaderSize <= ((UInt32)1 << 16);
// return item.LocalFullHeaderSize <= ((UInt32)1 << 16);
return true;
}
static bool FlagsAreSame(const CItem &i1, const CItem &i2)
static bool FlagsAreSame(const CItem &i1, const CItem &i2_cd)
{
if (i1.Method != i2.Method)
if (i1.Method != i2_cd.Method)
return false;
if (i1.Flags == i2.Flags)
UInt32 mask = i1.Flags ^ i2_cd.Flags;
if (mask == 0)
return true;
UInt32 mask = 0xFFFF;
switch (i1.Method)
{
case NFileHeader::NCompressionMethod::kDeflate:
mask = 0x7FF9;
mask &= 0x7FF9;
break;
default:
if (i1.Method <= NFileHeader::NCompressionMethod::kImplode)
mask = 0x7FFF;
mask &= 0x7FFF;
}
// we can ignore utf8 flag, if name is ascii
if ((i1.Flags ^ i2.Flags) & NFileHeader::NFlags::kUtf8)
if (i1.Name.IsAscii() && i2.Name.IsAscii())
if (mask & NFileHeader::NFlags::kUtf8)
if (i1.Name.IsAscii() && i2_cd.Name.IsAscii())
mask &= ~NFileHeader::NFlags::kUtf8;
// some bad archive in rare case can use descriptor without descriptor flag in Central Dir
// if (i1.HasDescriptor())
mask &= ~NFileHeader::NFlags::kDescriptorUsedMask;
return ((i1.Flags & mask) == (i2.Flags & mask));
return (mask == 0);
}
@@ -1167,13 +1187,13 @@ static bool AreEqualPaths_IgnoreSlashes(const char *s1, const char *s2)
static bool AreItemsEqual(const CItemEx &localItem, const CItemEx &cdItem)
{
if (!FlagsAreSame(cdItem, localItem))
if (!FlagsAreSame(localItem, cdItem))
return false;
if (!localItem.HasDescriptor())
{
if (cdItem.PackSize != localItem.PackSize
|| cdItem.Size != localItem.Size
|| cdItem.Crc != localItem.Crc && cdItem.Crc != 0) // some program writes 0 to crc field in central directory
|| (cdItem.Crc != localItem.Crc && cdItem.Crc != 0)) // some program writes 0 to crc field in central directory
return false;
}
/* pkzip 2.50 creates incorrect archives. It uses
@@ -1235,7 +1255,7 @@ HRESULT CInArchive::ReadLocalItemAfterCdItem(CItemEx &item, bool &isAvail, bool
return S_FALSE;
}
Stream = Vols.Streams[item.Disk].Stream;
Vols.StreamIndex = item.Disk;
Vols.StreamIndex = (int)item.Disk;
if (!Stream)
{
isAvail = false;
@@ -1251,7 +1271,7 @@ HRESULT CInArchive::ReadLocalItemAfterCdItem(CItemEx &item, bool &isAvail, bool
}
Stream = StreamRef;
offset += ArcInfo.Base;
offset = (UInt64)((Int64)offset + ArcInfo.Base);
if (ArcInfo.Base < 0 && (Int64)offset < 0)
{
isAvail = false;
@@ -1281,6 +1301,11 @@ HRESULT CInArchive::ReadLocalItemAfterCdItem(CItemEx &item, bool &isAvail, bool
item.Crc = localItem.Crc;
headersError = true;
}
if ((item.Flags ^ localItem.Flags) & NFileHeader::NFlags::kDescriptorUsedMask)
{
item.Flags = (UInt16)(item.Flags ^ NFileHeader::NFlags::kDescriptorUsedMask);
headersError = true;
}
item.FromLocal = true;
}
catch(...) { return S_FALSE; }
@@ -1351,8 +1376,11 @@ HRESULT CInArchive::FindDescriptor(CItemEx &item, unsigned numFiles)
{
// we write to packSize all these available bytes.
// later it's simpler to work with such value than with 0
if (item.PackSize == 0)
// if (item.PackSize == 0)
item.PackSize = packedSize + avail;
if (item.Method == 0)
item.Size = item.PackSize;
SkipLookahed(avail);
return S_OK;
}
@@ -1384,7 +1412,7 @@ HRESULT CInArchive::FindDescriptor(CItemEx &item, unsigned numFiles)
&& sig != NSignature::kCentralFileHeader)
continue;
const UInt64 packSizeCur = packedSize + (p - pStart);
const UInt64 packSizeCur = packedSize + (size_t)(p - pStart);
if (descriptorSize4 == kDataDescriptorSize64 + kNextSignatureSize) // if (item.LocalExtra.IsZip64)
{
const UInt64 descriptorPackSize = Get64(p + 8);
@@ -1406,14 +1434,14 @@ HRESULT CInArchive::FindDescriptor(CItemEx &item, unsigned numFiles)
item.DescriptorWasRead = true;
item.Crc = Get32(p + 4);
const size_t skip = (p - pStart) + descriptorSize4 - kNextSignatureSize;
const size_t skip = (size_t)(p - pStart) + descriptorSize4 - kNextSignatureSize;
SkipLookahed(skip);
return S_OK;
}
const size_t skip = (p - pStart);
const size_t skip = (size_t)(p - pStart);
SkipLookahed(skip);
packedSize += skip;
@@ -1529,7 +1557,7 @@ HRESULT CInArchive::ReadCdItem(CItemEx &item)
ReadFileName(nameSize, item.Name);
if (extraSize > 0)
ReadExtra(extraSize, item.CentralExtra, item.Size, item.PackSize, item.LocalHeaderPos, item.Disk);
ReadExtra(item, extraSize, item.CentralExtra, item.Size, item.PackSize, item.LocalHeaderPos, item.Disk);
// May be these strings must be deleted
/*
@@ -1549,11 +1577,7 @@ HRESULT CInArchive::TryEcd64(UInt64 offset, CCdInfo &cdInfo)
Byte buf[kEcd64_FullSize];
RINOK(SeekToVol(Vols.StreamIndex, offset));
unsigned processed = 0;
ReadFromCache(buf, kEcd64_FullSize, processed);
if (processed != kEcd64_FullSize)
return S_FALSE;
RINOK(ReadFromCache_FALSE(buf, kEcd64_FullSize));
if (Get32(buf) != NSignature::kEcd64)
return S_FALSE;
@@ -1636,8 +1660,12 @@ HRESULT CInArchive::FindCd(bool checkOffsetMode)
{
CLocator locator;
locator.Parse(buf + locatorIndex + 4);
if ((cdInfo.ThisDisk == locator.NumDisks - 1 || ZIP64_IS_16_MAX(cdInfo.ThisDisk))
&& locator.Ecd64Disk < locator.NumDisks)
UInt32 numDisks = locator.NumDisks;
// we ignore the error, where some zip creators use (NumDisks == 0)
if (numDisks == 0)
numDisks = 1;
if ((cdInfo.ThisDisk == numDisks - 1 || ZIP64_IS_16_MAX(cdInfo.ThisDisk))
&& locator.Ecd64Disk < numDisks)
{
if (locator.Ecd64Disk != cdInfo.ThisDisk && !ZIP64_IS_16_MAX(cdInfo.ThisDisk))
return E_NOTIMPL;
@@ -1657,7 +1685,7 @@ HRESULT CInArchive::FindCd(bool checkOffsetMode)
if (mainEcd64Size == kEcd64_MainSize)
{
cdInfo.ParseEcd64e(ecd64 + 12);
ArcInfo.Base = absEcd64 - locator.Ecd64Offset;
ArcInfo.Base = (Int64)(absEcd64 - locator.Ecd64Offset);
// ArcInfo.BaseVolIndex = cdInfo.ThisDisk;
return S_OK;
}
@@ -1685,7 +1713,7 @@ HRESULT CInArchive::FindCd(bool checkOffsetMode)
{
if (TryEcd64(ArcInfo.MarkerPos + locator.Ecd64Offset, cdInfo) == S_OK)
{
ArcInfo.Base = ArcInfo.MarkerPos;
ArcInfo.Base = (Int64)ArcInfo.MarkerPos;
// ArcInfo.BaseVolIndex = cdInfo.ThisDisk;
return S_OK;
}
@@ -1719,7 +1747,7 @@ HRESULT CInArchive::FindCd(bool checkOffsetMode)
}
else
*/
ArcInfo.Base = absEcdPos - cdEnd;
ArcInfo.Base = (Int64)(absEcdPos - cdEnd);
}
return S_OK;
}
@@ -1730,11 +1758,12 @@ HRESULT CInArchive::FindCd(bool checkOffsetMode)
HRESULT CInArchive::TryReadCd(CObjectVector<CItemEx> &items, const CCdInfo &cdInfo, UInt64 cdOffset, UInt64 cdSize)
{
items.Clear();
IsCdUnsorted = false;
// _startLocalFromCd_Disk = (UInt32)(Int32)-1;
// _startLocalFromCd_Offset = (UInt64)(Int64)-1;
RINOK(SeekToVol(IsMultiVol ? cdInfo.CdDisk : -1, cdOffset));
RINOK(SeekToVol(IsMultiVol ? (int)cdInfo.CdDisk : -1, cdOffset));
_inBufMode = true;
_cnt = 0;
@@ -1767,6 +1796,15 @@ HRESULT CInArchive::TryReadCd(CObjectVector<CItemEx> &items, const CCdInfo &cdIn
}
*/
if (items.Size() > 0 && !IsCdUnsorted)
{
const CItemEx &prev = items.Back();
if (cdItem.Disk < prev.Disk
|| (cdItem.Disk == prev.Disk &&
cdItem.LocalHeaderPos < prev.LocalHeaderPos))
IsCdUnsorted = true;
}
items.Add(cdItem);
}
if (Callback && (items.Size() & 0xFFF) == 0)
@@ -1793,6 +1831,22 @@ HRESULT CInArchive::TryReadCd(CObjectVector<CItemEx> &items, const CCdInfo &cdIn
}
/*
static int CompareCdItems(void *const *elem1, void *const *elem2, void *)
{
const CItemEx *i1 = *(const CItemEx **)elem1;
const CItemEx *i2 = *(const CItemEx **)elem2;
if (i1->Disk < i2->Disk) return -1;
if (i1->Disk > i2->Disk) return 1;
if (i1->LocalHeaderPos < i2->LocalHeaderPos) return -1;
if (i1->LocalHeaderPos > i2->LocalHeaderPos) return 1;
if (i1 < i2) return -1;
if (i1 > i2) return 1;
return 0;
}
*/
HRESULT CInArchive::ReadCd(CObjectVector<CItemEx> &items, UInt32 &cdDisk, UInt64 &cdOffset, UInt64 &cdSize)
{
bool checkOffsetMode = true;
@@ -1801,7 +1855,7 @@ HRESULT CInArchive::ReadCd(CObjectVector<CItemEx> &items, UInt32 &cdDisk, UInt64
{
if (Vols.EndVolIndex == -1)
return S_FALSE;
Stream = Vols.Streams[Vols.EndVolIndex].Stream;
Stream = Vols.Streams[(unsigned)Vols.EndVolIndex].Stream;
if (!Vols.StartIsZip)
checkOffsetMode = false;
}
@@ -1827,7 +1881,7 @@ HRESULT CInArchive::ReadCd(CObjectVector<CItemEx> &items, UInt32 &cdDisk, UInt64
return S_FALSE;
}
const UInt64 base = (IsMultiVol ? 0 : ArcInfo.Base);
const UInt64 base = (IsMultiVol ? 0 : (UInt64)ArcInfo.Base);
res = TryReadCd(items, cdInfo, base + cdOffset, cdSize);
if (res == S_FALSE && !IsMultiVol && base != ArcInfo.MarkerPos)
@@ -1835,9 +1889,11 @@ HRESULT CInArchive::ReadCd(CObjectVector<CItemEx> &items, UInt32 &cdDisk, UInt64
// do we need that additional attempt to read cd?
res = TryReadCd(items, cdInfo, ArcInfo.MarkerPos + cdOffset, cdSize);
if (res == S_OK)
ArcInfo.Base = ArcInfo.MarkerPos;
ArcInfo.Base = (Int64)ArcInfo.MarkerPos;
}
// Some rare case files are unsorted
// items.Sort(CompareCdItems, NULL);
return res;
}
@@ -1849,14 +1905,14 @@ static int FindItem(const CObjectVector<CItemEx> &items, const CItemEx &item)
{
if (left >= right)
return -1;
unsigned index = (left + right) / 2;
const unsigned index = (left + right) / 2;
const CItemEx &item2 = items[index];
if (item.Disk < item2.Disk)
right = index;
else if (item.Disk > item2.Disk)
left = index + 1;
else if (item.LocalHeaderPos == item2.LocalHeaderPos)
return index;
return (int)index;
else if (item.LocalHeaderPos < item2.LocalHeaderPos)
right = index;
else
@@ -1921,7 +1977,7 @@ HRESULT CInArchive::ReadLocals(CObjectVector<CItemEx> &items)
item.LocalHeaderPos = GetVirtStreamPos() - 4;
if (!IsMultiVol)
item.LocalHeaderPos -= ArcInfo.Base;
item.LocalHeaderPos = (UInt64)((Int64)item.LocalHeaderPos - ArcInfo.Base);
try
{
@@ -1950,7 +2006,7 @@ HRESULT CInArchive::ReadLocals(CObjectVector<CItemEx> &items)
}
catch (CUnexpectEnd &)
{
if (items.IsEmpty() || items.Size() == 1 && IsStrangeItem(items[0]))
if (items.IsEmpty() || (items.Size() == 1 && IsStrangeItem(items[0])))
return S_FALSE;
throw;
}
@@ -1986,11 +2042,11 @@ HRESULT CVols::ParseArcName(IArchiveOpenVolumeCallback *volCallback)
name = prop.bstrVal;
}
int dotPos = name.ReverseFind_Dot();
const int dotPos = name.ReverseFind_Dot();
if (dotPos < 0)
return S_OK;
const UString ext = name.Ptr(dotPos + 1);
name.DeleteFrom(dotPos + 1);
const UString ext = name.Ptr((unsigned)(dotPos + 1));
name.DeleteFrom((unsigned)(dotPos + 1));
StartVolIndex = (Int32)(-1);
@@ -2047,7 +2103,7 @@ HRESULT CVols::ParseArcName(IArchiveOpenVolumeCallback *volCallback)
UInt32 volNum = ConvertStringToUInt32(ext.Ptr(1), &end);
if (*end != 0 || volNum < 1 || volNum > ((UInt32)1 << 30))
return S_OK;
StartVolIndex = volNum - 1;
StartVolIndex = (Int32)(volNum - 1);
BaseName = name;
StartIsZ = true;
}
@@ -2147,7 +2203,7 @@ HRESULT CInArchive::ReadVols2(IArchiveOpenVolumeCallback *volCallback,
UInt64 pos;
RINOK(stream->Seek(0, STREAM_SEEK_CUR, &pos));
RINOK(stream->Seek(0, STREAM_SEEK_END, &size));
RINOK(stream->Seek(pos, STREAM_SEEK_SET, NULL));
RINOK(stream->Seek((Int64)pos, STREAM_SEEK_SET, NULL));
while (i >= Vols.Streams.Size())
Vols.Streams.AddNew();
@@ -2161,7 +2217,7 @@ HRESULT CInArchive::ReadVols2(IArchiveOpenVolumeCallback *volCallback,
if ((int)i == zipDisk)
{
Vols.EndVolIndex = Vols.Streams.Size() - 1;
Vols.EndVolIndex = (int)(Vols.Streams.Size() - 1);
break;
}
}
@@ -2211,7 +2267,7 @@ HRESULT CInArchive::ReadVols()
CCdInfo &ecd = Vols.ecd;
if (res == S_OK)
{
zipDisk = ecd.ThisDisk;
zipDisk = (int)ecd.ThisDisk;
Vols.ecd_wasRead = true;
// if is not multivol or bad multivol, we return to main single stream code
@@ -2220,9 +2276,9 @@ HRESULT CInArchive::ReadVols()
|| ecd.ThisDisk < ecd.CdDisk)
return S_OK;
cdDisk = ecd.CdDisk;
cdDisk = (int)ecd.CdDisk;
if (Vols.StartVolIndex < 0)
Vols.StartVolIndex = ecd.ThisDisk;
Vols.StartVolIndex = (Int32)ecd.ThisDisk;
else if ((UInt32)Vols.StartVolIndex >= ecd.ThisDisk)
return S_OK;
@@ -2232,7 +2288,7 @@ HRESULT CInArchive::ReadVols()
if (cdDisk != zipDisk)
{
// get volumes required for cd.
RINOK(ReadVols2(volCallback, cdDisk, zipDisk, zipDisk, 0, numMissingVols));
RINOK(ReadVols2(volCallback, (unsigned)cdDisk, zipDisk, zipDisk, 0, numMissingVols));
if (numMissingVols != 0)
{
// cdOK = false;
@@ -2269,10 +2325,10 @@ HRESULT CInArchive::ReadVols()
if (Vols.StartVolIndex > (1 << 20))
return S_OK;
if ((unsigned)Vols.StartVolIndex >= Vols.Streams.Size()
|| !Vols.Streams[Vols.StartVolIndex].Stream)
|| !Vols.Streams[(unsigned)Vols.StartVolIndex].Stream)
{
// we get volumes starting from StartVolIndex, if they we not requested before know the volume index (if FindCd() was ok)
RINOK(ReadVols2(volCallback, Vols.StartVolIndex, zipDisk, zipDisk, 0, numMissingVols));
RINOK(ReadVols2(volCallback, (unsigned)Vols.StartVolIndex, zipDisk, zipDisk, 0, numMissingVols));
}
}
@@ -2285,7 +2341,7 @@ HRESULT CInArchive::ReadVols()
if (zipDisk >= 0)
{
// we create item in Streams for ZipStream, if we know the volume index (if FindCd() was ok)
RINOK(ReadVols2(volCallback, zipDisk, zipDisk + 1, zipDisk, 0, numMissingVols));
RINOK(ReadVols2(volCallback, (unsigned)zipDisk, zipDisk + 1, zipDisk, 0, numMissingVols));
}
}
@@ -2331,7 +2387,7 @@ HRESULT CVols::Read(void *data, UInt32 size, UInt32 *processedSize)
return S_OK;
if ((unsigned)StreamIndex >= Streams.Size())
return S_OK;
const CVols::CSubStreamInfo &s = Streams[StreamIndex];
const CVols::CSubStreamInfo &s = Streams[(unsigned)StreamIndex];
if (!s.Stream)
return S_FALSE;
if (NeedSeek)
@@ -2473,7 +2529,7 @@ HRESULT CInArchive::ReadHeaders(CObjectVector<CItemEx> &items)
if (!ecd.IsEmptyArc())
return S_FALSE;
ArcInfo.Base = ArcInfo.MarkerPos;
ArcInfo.Base = (Int64)ArcInfo.MarkerPos;
IsArc = true; // check it: we need more tests?
RINOK(SeekToVol(ArcInfo.MarkerVolIndex, ArcInfo.MarkerPos2));
@@ -2514,16 +2570,44 @@ HRESULT CInArchive::ReadHeaders(CObjectVector<CItemEx> &items)
res = S_FALSE;
else
{
firstItem.LocalHeaderPos = ArcInfo.MarkerPos2 - ArcInfo.Base;
int index = FindItem(items, firstItem);
firstItem.LocalHeaderPos = (UInt64)((Int64)ArcInfo.MarkerPos2 - ArcInfo.Base);
int index = -1;
UInt32 min_Disk = (UInt32)(Int32)-1;
UInt64 min_LocalHeaderPos = (UInt64)(Int64)-1;
if (!IsCdUnsorted)
index = FindItem(items, firstItem);
else
{
FOR_VECTOR (i, items)
{
const CItemEx &cdItem = items[i];
if (cdItem.Disk == firstItem.Disk
&& (cdItem.LocalHeaderPos == firstItem.LocalHeaderPos))
index = (int)i;
if (i == 0
|| cdItem.Disk < min_Disk
|| (cdItem.Disk == min_Disk && cdItem.LocalHeaderPos < min_LocalHeaderPos))
{
min_Disk = cdItem.Disk;
min_LocalHeaderPos = cdItem.LocalHeaderPos;
}
}
}
if (index == -1)
res = S_FALSE;
else if (!AreItemsEqual(firstItem, items[index]))
else if (!AreItemsEqual(firstItem, items[(unsigned)index]))
res = S_FALSE;
else
{
ArcInfo.CdWasRead = true;
ArcInfo.FirstItemRelatOffset = items[0].LocalHeaderPos;
if (IsCdUnsorted)
ArcInfo.FirstItemRelatOffset = min_LocalHeaderPos;
else
ArcInfo.FirstItemRelatOffset = items[0].LocalHeaderPos;
// ArcInfo.FirstItemRelatOffset = _startLocalFromCd_Offset;
}
@@ -2588,7 +2672,7 @@ HRESULT CInArchive::ReadHeaders(CObjectVector<CItemEx> &items)
The (Base) can be corrected later after ECD reading.
But sfx volume with stub and (No)Span-marker in (!IsMultiVol) mode will have incorrect (Base) here.
*/
ArcInfo.Base = ArcInfo.MarkerPos2;
ArcInfo.Base = (Int64)ArcInfo.MarkerPos2;
}
RINOK(SeekToVol(ArcInfo.MarkerVolIndex, ArcInfo.MarkerPos2));
@@ -2607,15 +2691,42 @@ HRESULT CInArchive::ReadHeaders(CObjectVector<CItemEx> &items)
// GetVirtStreamPos() - 4
if (items.IsEmpty())
return S_FALSE;
NoCentralDir = true;
HeadersError = true;
return S_OK;
bool isError = true;
const UInt32 apkSize = _signature;
const unsigned kApkFooterSize = 16 + 8;
if (apkSize >= kApkFooterSize && apkSize <= (1 << 20))
{
if (ReadUInt32() == 0)
{
CByteBuffer apk;
apk.Alloc(apkSize);
SafeRead(apk, apkSize);
ReadSignature();
const Byte *footer = apk + apkSize - kApkFooterSize;
if (_signature == NSignature::kCentralFileHeader)
if (GetUi64(footer) == apkSize)
if (memcmp(footer + 8, "APK Sig Block 42", 16) == 0)
{
isError = false;
IsApk = true;
}
}
}
if (isError)
{
NoCentralDir = true;
HeadersError = true;
return S_OK;
}
}
_inBufMode = true;
cdAbsOffset = GetVirtStreamPos() - 4;
cdDisk = Vols.StreamIndex;
cdDisk = (UInt32)Vols.StreamIndex;
#ifdef ZIP_SELF_CHECK
if (!IsMultiVol && _cnt != GetVirtStreamPos() - ArcInfo.MarkerPos2)
@@ -2656,7 +2767,7 @@ HRESULT CInArchive::ReadHeaders(CObjectVector<CItemEx> &items)
needSetBase = true;
numCdItems = cdItems.Size();
cdRelatOffset = cdAbsOffset - ArcInfo.Base;
cdRelatOffset = (UInt64)((Int64)cdAbsOffset - ArcInfo.Base);
if (!cdItems.IsEmpty())
{
@@ -2712,6 +2823,8 @@ HRESULT CInArchive::ReadHeaders(CObjectVector<CItemEx> &items)
Byte buf[kBufSize];
SafeRead(buf, kBufSize);
locator.Parse(buf);
// we ignore the error, where some zip creators use (NumDisks == 0)
// if (locator.NumDisks == 0) HeadersWarning = true;
}
ReadSignature();
@@ -2764,12 +2877,12 @@ HRESULT CInArchive::ReadHeaders(CObjectVector<CItemEx> &items)
if (IsMultiVol)
{
if (cdDisk != (int)cdInfo.CdDisk)
if (cdDisk != cdInfo.CdDisk)
HeadersError = true;
}
else if (needSetBase && cdOK)
{
const UInt64 oldBase = ArcInfo.Base;
const UInt64 oldBase = (UInt64)ArcInfo.Base;
// localsWereRead == true
// ArcInfo.Base == ArcInfo.MarkerPos2
// cdRelatOffset == (cdAbsOffset - ArcInfo.Base)
@@ -2778,13 +2891,13 @@ HRESULT CInArchive::ReadHeaders(CObjectVector<CItemEx> &items)
{
if (ecd64Disk == Vols.StartVolIndex)
{
const Int64 newBase = (Int64)ecd64AbsOffset - locator.Ecd64Offset;
const Int64 newBase = (Int64)ecd64AbsOffset - (Int64)locator.Ecd64Offset;
if (newBase <= (Int64)ecd64AbsOffset)
{
if (!localsWereRead || newBase <= (Int64)ArcInfo.MarkerPos2)
{
ArcInfo.Base = newBase;
cdRelatOffset = cdAbsOffset - newBase;
cdRelatOffset = (UInt64)((Int64)cdAbsOffset - newBase);
}
else
cdOK = false;
@@ -2795,7 +2908,7 @@ HRESULT CInArchive::ReadHeaders(CObjectVector<CItemEx> &items)
{
if ((int)cdDisk == Vols.StartVolIndex)
{
const Int64 newBase = (Int64)cdAbsOffset - cdInfo.Offset;
const Int64 newBase = (Int64)cdAbsOffset - (Int64)cdInfo.Offset;
if (newBase <= (Int64)cdAbsOffset)
{
if (!localsWereRead || newBase <= (Int64)ArcInfo.MarkerPos2)
@@ -2828,7 +2941,7 @@ HRESULT CInArchive::ReadHeaders(CObjectVector<CItemEx> &items)
if (localsWereRead)
{
const UInt64 delta = oldBase - ArcInfo.Base;
const UInt64 delta = (UInt64)((Int64)oldBase - ArcInfo.Base);
if (delta != 0)
{
FOR_VECTOR (i, items)
@@ -2864,7 +2977,7 @@ HRESULT CInArchive::ReadHeaders(CObjectVector<CItemEx> &items)
if (isZip64)
{
if (cdInfo.ThisDisk == 0 && ecd64AbsOffset != ArcInfo.Base + locator.Ecd64Offset
if ((cdInfo.ThisDisk == 0 && ecd64AbsOffset != (UInt64)(ArcInfo.Base + (Int64)locator.Ecd64Offset))
// || cdInfo.NumEntries_in_ThisDisk != numCdItems
|| cdInfo.NumEntries != numCdItems
|| cdInfo.Size != cdSize
@@ -2902,10 +3015,10 @@ HRESULT CInArchive::ReadHeaders(CObjectVector<CItemEx> &items)
{
if ((unsigned)nextLocalIndex < items.Size())
{
CItemEx &item = items[nextLocalIndex];
CItemEx &item = items[(unsigned)nextLocalIndex];
if (item.Disk == cdItem.Disk &&
(item.LocalHeaderPos == cdItem.LocalHeaderPos
|| Overflow32bit && (UInt32)item.LocalHeaderPos == cdItem.LocalHeaderPos))
|| (Overflow32bit && (UInt32)item.LocalHeaderPos == cdItem.LocalHeaderPos)))
index = nextLocalIndex++;
else
nextLocalIndex = -1;
@@ -2924,7 +3037,7 @@ HRESULT CInArchive::ReadHeaders(CObjectVector<CItemEx> &items)
continue;
}
CItemEx &item = items[index];
CItemEx &item = items[(unsigned)index];
if (item.Name != cdItem.Name
// || item.Name.Len() != cdItem.Name.Len()
|| item.PackSize != cdItem.PackSize
@@ -2965,7 +3078,7 @@ HRESULT CInArchive::ReadHeaders(CObjectVector<CItemEx> &items)
if (isZip64)
{
if (cdInfo.NumEntries != items.Size()
|| ecd.NumEntries != items.Size() && ecd.NumEntries != 0xFFFF)
|| (ecd.NumEntries != items.Size() && ecd.NumEntries != 0xFFFF))
HeadersError = true;
}
else
@@ -3069,7 +3182,9 @@ HRESULT CInArchive::Open(IInStream *stream, const UInt64 *searchLimit,
else
{
// printf("\nOpen offset = %u\n", (unsigned)startPos);
if (IsMultiVol && (unsigned)Vols.StartParsingVol < Vols.Streams.Size() && Vols.Streams[Vols.StartParsingVol].Stream)
if (IsMultiVol
&& (unsigned)Vols.StartParsingVol < Vols.Streams.Size()
&& Vols.Streams[(unsigned)Vols.StartParsingVol].Stream)
{
RINOK(SeekToVol(Vols.StartParsingVol, Vols.StreamIndex == Vols.StartVolIndex ? startPos : 0));
}
@@ -3117,7 +3232,7 @@ HRESULT CInArchive::Open(IInStream *stream, const UInt64 *searchLimit,
{
if ((unsigned)Vols.StartVolIndex < Vols.Streams.Size())
{
Stream = Vols.Streams[Vols.StartVolIndex].Stream;
Stream = Vols.Streams[(unsigned)Vols.StartVolIndex].Stream;
if (Stream)
{
RINOK(Seek_SavePos(curPos));
@@ -3173,7 +3288,7 @@ HRESULT CInArchive::Open(IInStream *stream, const UInt64 *searchLimit,
{
ArcInfo.FinishPos = ArcInfo.FileEndPos;
if ((unsigned)Vols.StreamIndex < Vols.Streams.Size())
if (GetVirtStreamPos() < Vols.Streams[Vols.StreamIndex].Size)
if (GetVirtStreamPos() < Vols.Streams[(unsigned)Vols.StreamIndex].Size)
ArcInfo.ThereIsTail = true;
}
else
@@ -3204,8 +3319,8 @@ HRESULT CInArchive::GetItemStream(const CItemEx &item, bool seekPackData, CMyCom
{
if (UseDisk_in_SingleVol && item.Disk != EcdVolIndex)
return S_OK;
pos += ArcInfo.Base;
RINOK(StreamRef->Seek(pos, STREAM_SEEK_SET, NULL));
pos = (UInt64)((Int64)pos + ArcInfo.Base);
RINOK(StreamRef->Seek((Int64)pos, STREAM_SEEK_SET, NULL));
stream = StreamRef;
return S_OK;
}
@@ -3216,10 +3331,10 @@ HRESULT CInArchive::GetItemStream(const CItemEx &item, bool seekPackData, CMyCom
IInStream *str2 = Vols.Streams[item.Disk].Stream;
if (!str2)
return S_OK;
RINOK(str2->Seek(pos, STREAM_SEEK_SET, NULL));
RINOK(str2->Seek((Int64)pos, STREAM_SEEK_SET, NULL));
Vols.NeedSeek = false;
Vols.StreamIndex = item.Disk;
Vols.StreamIndex = (int)item.Disk;
CVolStream *volsStreamSpec = new CVolStream;
volsStreamSpec->Vols = &Vols;

View File

@@ -32,6 +32,11 @@ public:
{ return LocalFullHeaderSize + GetPackSizeWithDescriptor(); }
UInt64 GetDataPosition() const
{ return LocalHeaderPos + LocalFullHeaderSize; }
bool IsBadDescriptor() const
{
return !FromCentral && FromLocal && HasDescriptor() && !DescriptorWasRead;
}
};
@@ -282,6 +287,7 @@ class CInArchive
HRESULT SeekToVol(int volIndex, UInt64 offset);
HRESULT ReadFromCache(Byte *data, unsigned size, unsigned &processed);
HRESULT ReadFromCache_FALSE(Byte *data, unsigned size);
HRESULT ReadVols2(IArchiveOpenVolumeCallback *volCallback,
unsigned start, int lastDisk, int zipDisk, unsigned numMissingVolsMax, unsigned &numMissingVols);
@@ -305,7 +311,7 @@ class CInArchive
bool ReadFileName(unsigned nameSize, AString &dest);
bool ReadExtra(unsigned extraSize, CExtraBlock &extra,
bool ReadExtra(const CLocalItem &item, unsigned extraSize, CExtraBlock &extra,
UInt64 &unpackSize, UInt64 &packSize, UInt64 &localOffset, UInt32 &disk);
bool ReadLocalItem(CItemEx &item);
HRESULT FindDescriptor(CItemEx &item, unsigned numFiles);
@@ -325,6 +331,9 @@ public:
bool IsArc;
bool IsZip64;
bool IsApk;
bool IsCdUnsorted;
bool HeadersError;
bool HeadersWarning;
@@ -345,14 +354,19 @@ public:
CVols Vols;
CInArchive(): Stream(NULL), StartStream(NULL), Callback(NULL), IsArcOpen(false) {}
CInArchive():
IsArcOpen(false),
Stream(NULL),
StartStream(NULL),
Callback(NULL)
{}
UInt64 GetPhySize() const
{
if (IsMultiVol)
return ArcInfo.FinishPos;
else
return ArcInfo.FinishPos - ArcInfo.Base;
return (UInt64)((Int64)ArcInfo.FinishPos - ArcInfo.Base);
}
UInt64 GetOffset() const
@@ -360,7 +374,7 @@ public:
if (IsMultiVol)
return 0;
else
return ArcInfo.Base;
return (UInt64)ArcInfo.Base;
}
@@ -393,7 +407,7 @@ public:
return ArcInfo.FirstItemRelatOffset;
if (IsMultiVol)
return 0;
return ArcInfo.MarkerPos2 - ArcInfo.Base;
return (UInt64)((Int64)ArcInfo.MarkerPos2 - ArcInfo.Base);
}
@@ -412,7 +426,9 @@ public:
|| ArcInfo.Base < 0
|| (Int64)ArcInfo.MarkerPos2 < ArcInfo.Base
|| ArcInfo.ThereIsTail
|| GetEmbeddedStubSize() != 0)
|| GetEmbeddedStubSize() != 0
|| IsApk
|| IsCdUnsorted)
return false;
// 7-zip probably can update archives with embedded stubs.

View File

@@ -33,9 +33,12 @@ static const CUInt32PCharPair g_ExtraTypes[] =
{ NExtraID::kStrongEncrypt, "StrongCrypto" },
{ NExtraID::kUnixTime, "UT" },
{ NExtraID::kUnixExtra, "UX" },
{ NExtraID::kUnix2Extra, "Ux" },
{ NExtraID::kUnix3Extra, "ux" },
{ NExtraID::kIzUnicodeComment, "uc" },
{ NExtraID::kIzUnicodeName, "up" },
{ NExtraID::kWzAES, "WzAES" }
{ NExtraID::kWzAES, "WzAES" },
{ NExtraID::kApkAlign, "ApkAlign" }
};
void CExtraSubBlock::PrintInfo(AString &s) const
@@ -46,6 +49,22 @@ void CExtraSubBlock::PrintInfo(AString &s) const
if (pair.Value == ID)
{
s += pair.Name;
/*
if (ID == NExtraID::kApkAlign && Data.Size() >= 2)
{
char sz[32];
sz[0] = ':';
ConvertUInt32ToHex(GetUi16(Data), sz + 1);
s += sz;
for (unsigned j = 2; j < Data.Size(); j++)
{
char sz[32];
sz[0] = '-';
ConvertUInt32ToHex(Data[j], sz + 1);
s += sz;
}
}
*/
return;
}
}
@@ -209,6 +228,7 @@ bool CLocalItem::IsDir() const
bool CItem::IsDir() const
{
// FIXME: we can check InfoZip UTF-8 name at first.
if (NItemName::HasTailSlash(Name, GetCodePage()))
return true;
@@ -315,10 +335,30 @@ bool CItem::GetPosixAttrib(UInt32 &attrib) const
return false;
}
bool CExtraSubBlock::CheckIzUnicode(const AString &s) const
{
size_t size = Data.Size();
if (size < 1 + 4)
return false;
const Byte *p = (const Byte *)Data;
if (p[0] > 1)
return false;
if (CrcCalc(s, s.Len()) != GetUi32(p + 1))
return false;
size -= 5;
p += 5;
for (size_t i = 0; i < size; i++)
if (p[i] == 0)
return false;
return Check_UTF8_Buf((const char *)(const void *)p, size, false);
}
void CItem::GetUnicodeString(UString &res, const AString &s, bool isComment, bool useSpecifiedCodePage, UINT codePage) const
{
bool isUtf8 = IsUtf8();
bool ignore_Utf8_Errors = true;
// bool ignore_Utf8_Errors = true;
if (!isUtf8)
{
@@ -333,10 +373,14 @@ void CItem::GetUnicodeString(UString &res, const AString &s, bool isComment, boo
const CExtraSubBlock &sb = subBlocks[i];
if (sb.ID == id)
{
AString utf;
if (sb.ExtractIzUnicode(CrcCalc(s, s.Len()), utf))
if (ConvertUTF8ToUnicode(utf, res))
if (sb.CheckIzUnicode(s))
{
// const unsigned kIzUnicodeHeaderSize = 5;
if (Convert_UTF8_Buf_To_Unicode(
(const char *)(const void *)(const Byte *)sb.Data + 5,
sb.Data.Size() - 5, res))
return;
}
break;
}
}
@@ -351,15 +395,21 @@ void CItem::GetUnicodeString(UString &res, const AString &s, bool isComment, boo
We try to get name as UTF-8.
Do we need to do it in POSIX version also? */
isUtf8 = true;
ignore_Utf8_Errors = false;
/* 21.02: we want to ignore UTF-8 errors to support file paths that are mixed
of UTF-8 and non-UTF-8 characters. */
// ignore_Utf8_Errors = false;
// ignore_Utf8_Errors = true;
}
#endif
}
if (isUtf8)
if (ConvertUTF8ToUnicode(s, res) || ignore_Utf8_Errors)
return;
{
ConvertUTF8ToUnicode(s, res);
return;
}
MultiByteToUnicodeString2(res, s, useSpecifiedCodePage ? codePage : GetCodePage());
}

View File

@@ -33,23 +33,8 @@ struct CExtraSubBlock
bool ExtractNtfsTime(unsigned index, FILETIME &ft) const;
bool ExtractUnixTime(bool isCentral, unsigned index, UInt32 &res) const;
bool ExtractUnixExtraTime(unsigned index, UInt32 &res) const;
bool ExtractIzUnicode(UInt32 crc, AString &name) const
{
unsigned size = (unsigned)Data.Size();
if (size < 1 + 4)
return false;
const Byte *p = (const Byte *)Data;
if (p[0] > 1)
return false;
if (crc != GetUi32(p + 1))
return false;
size -= 5;
name.SetFrom_CalcLen((const char *)p + 5, size);
if (size != name.Len())
return false;
return CheckUTF8(name, false);
}
bool CheckIzUnicode(const AString &s) const;
void PrintInfo(AString &s) const;
};
@@ -202,8 +187,14 @@ struct CExtraBlock
for (unsigned i = SubBlocks.Size(); i != 0;)
{
i--;
if (SubBlocks[i].ID != NFileHeader::NExtraID::kWzAES)
SubBlocks.Delete(i);
switch (SubBlocks[i].ID)
{
case NFileHeader::NExtraID::kStrongEncrypt:
case NFileHeader::NExtraID::kWzAES:
break;
default:
SubBlocks.Delete(i);
}
}
}
};
@@ -266,9 +257,9 @@ private:
void SetFlag(unsigned bitMask, bool enable)
{
if (enable)
Flags |= bitMask;
Flags = (UInt16)(Flags | bitMask);
else
Flags &= ~bitMask;
Flags = (UInt16)(Flags & ~bitMask);
}
public:
@@ -279,7 +270,12 @@ public:
// void SetFlag_AltStream(bool isAltStream) { SetFlag(NFileHeader::NFlags::kAltStream, isAltStream); }
void SetDescriptorMode(bool useDescriptor) { SetFlag(NFileHeader::NFlags::kDescriptorUsedMask, useDescriptor); }
UINT GetCodePage() const { return CP_OEMCP; }
UINT GetCodePage() const
{
if (IsUtf8())
return CP_UTF8;
return CP_OEMCP;
}
};
@@ -330,10 +326,19 @@ public:
}
return (Crc != 0 || !IsDir());
}
bool Is_MadeBy_Unix() const
{
if (!FromCentral)
return false;
return (MadeByVersion.HostOS == NFileHeader::NHostOS::kUnix);
}
UINT GetCodePage() const
{
// 18.06: now we use HostOS only from Central::MadeByVersion
if (IsUtf8())
return CP_UTF8;
if (!FromCentral)
return CP_OEMCP;
Byte hostOS = MadeByVersion.HostOS;

View File

@@ -2,6 +2,8 @@
#include "StdAfx.h"
#include "../../../../C/7zCrc.h"
#include "../../Common/OffsetStream.h"
#include "ZipOut.h"
@@ -23,7 +25,7 @@ HRESULT COutArchive::Create(IOutStream *outStream)
void COutArchive::SeekToCurPos()
{
HRESULT res = m_Stream->Seek(m_Base + m_CurPos, STREAM_SEEK_SET, NULL);
HRESULT res = m_Stream->Seek((Int64)(m_Base + m_CurPos), STREAM_SEEK_SET, NULL);
if (res != S_OK)
throw CSystemException(res);
}
@@ -97,6 +99,17 @@ void COutArchive::WriteCommonItemInfo(const CLocalItem &item, bool isZip64)
#define WRITE_32_VAL_SPEC(__v, __isZip64) Write32((__isZip64) ? 0xFFFFFFFF : (UInt32)(__v));
void COutArchive::WriteUtfName(const CItemOut &item)
{
if (item.Name_Utf.Size() == 0)
return;
Write16(NFileHeader::NExtraID::kIzUnicodeName);
Write16((UInt16)(5 + item.Name_Utf.Size()));
Write8(1); // (1 = version) of that extra field
Write32(CrcCalc(item.Name.Ptr(), item.Name.Len()));
WriteBytes(item.Name_Utf, (UInt16)item.Name_Utf.Size());
}
void COutArchive::WriteLocalHeader(CItemOut &item, bool needCheck)
{
m_LocalHeaderPos = m_CurPos;
@@ -109,7 +122,10 @@ void COutArchive::WriteLocalHeader(CItemOut &item, bool needCheck)
if (needCheck && m_IsZip64)
isZip64 = true;
const UInt32 localExtraSize = (UInt32)((isZip64 ? (4 + 8 + 8): 0) + item.LocalExtra.GetSize());
const UInt32 localExtraSize = (UInt32)(
(isZip64 ? (4 + 8 + 8): 0)
+ item.Get_UtfName_ExtraSize()
+ item.LocalExtra.GetSize());
if ((UInt16)localExtraSize != localExtraSize)
throw CSystemException(E_FAIL);
if (needCheck && m_ExtraSize != localExtraSize)
@@ -152,6 +168,8 @@ void COutArchive::WriteLocalHeader(CItemOut &item, bool needCheck)
Write64(packSize);
}
WriteUtfName(item);
WriteExtra(item.LocalExtra);
// Why don't we write NTFS timestamps to local header?
@@ -230,14 +248,19 @@ void COutArchive::WriteCentralHeader(const CItemOut &item)
Write16((UInt16)item.Name.Len());
UInt16 zip64ExtraSize = (UInt16)((isUnPack64 ? 8: 0) + (isPack64 ? 8: 0) + (isPosition64 ? 8: 0));
const UInt16 zip64ExtraSize = (UInt16)((isUnPack64 ? 8: 0) + (isPack64 ? 8: 0) + (isPosition64 ? 8: 0));
const UInt16 kNtfsExtraSize = 4 + 2 + 2 + (3 * 8);
const UInt16 centralExtraSize = (UInt16)(
(isZip64 ? 4 + zip64ExtraSize : 0) +
(item.NtfsTimeIsDefined ? 4 + kNtfsExtraSize : 0) +
item.CentralExtra.GetSize());
const size_t centralExtraSize =
(isZip64 ? 4 + zip64ExtraSize : 0)
+ (item.NtfsTimeIsDefined ? 4 + kNtfsExtraSize : 0)
+ item.Get_UtfName_ExtraSize()
+ item.CentralExtra.GetSize();
Write16(centralExtraSize); // test it;
const UInt16 centralExtraSize16 = (UInt16)centralExtraSize;
if (centralExtraSize16 != centralExtraSize)
throw CSystemException(E_FAIL);
Write16(centralExtraSize16);
const UInt16 commentSize = (UInt16)item.Comment.Size();
@@ -271,6 +294,8 @@ void COutArchive::WriteCentralHeader(const CItemOut &item)
WriteNtfsTime(item.Ntfs_ATime);
WriteNtfsTime(item.Ntfs_CTime);
}
WriteUtfName(item);
WriteExtra(item.CentralExtra);
if (commentSize != 0)

View File

@@ -21,6 +21,16 @@ public:
bool NtfsTimeIsDefined;
// It's possible that NtfsTime is not defined, but there is NtfsTime in Extra.
CByteBuffer Name_Utf; // for Info-Zip (kIzUnicodeName) Extra
size_t Get_UtfName_ExtraSize() const
{
const size_t size = Name_Utf.Size();
if (size == 0)
return 0;
return 4 + 5 + size;
}
CItemOut(): NtfsTimeIsDefined(false) {}
};
@@ -52,6 +62,7 @@ class COutArchive
Write32(ft.dwHighDateTime);
}
void WriteUtfName(const CItemOut &item);
void WriteExtra(const CExtraBlock &extra);
void WriteCommonItemInfo(const CLocalItem &item, bool isZip64);
void WriteCentralHeader(const CItemOut &item);

View File

@@ -62,6 +62,21 @@ static void AddAesExtra(CItem &item, Byte aesKeyMode, UInt16 method)
}
static void Copy_From_UpdateItem_To_ItemOut(const CUpdateItem &ui, CItemOut &item)
{
item.Name = ui.Name;
item.Name_Utf = ui.Name_Utf;
item.Comment = ui.Comment;
item.SetUtf8(ui.IsUtf8);
// item.SetFlag_AltStream(ui.IsAltStream);
// item.ExternalAttrib = ui.Attrib;
item.Time = ui.Time;
item.Ntfs_MTime = ui.Ntfs_MTime;
item.Ntfs_ATime = ui.Ntfs_ATime;
item.Ntfs_CTime = ui.Ntfs_CTime;
item.NtfsTimeIsDefined = ui.NtfsTimeIsDefined;
}
static void SetFileHeader(
const CCompressionMethodMode &options,
const CUpdateItem &ui,
@@ -69,22 +84,15 @@ static void SetFileHeader(
CItemOut &item)
{
item.Size = ui.Size;
bool isDir = ui.IsDir;
const bool isDir = ui.IsDir;
item.ClearFlags();
if (ui.NewProps)
{
item.Name = ui.Name;
item.Comment = ui.Comment;
item.SetUtf8(ui.IsUtf8);
Copy_From_UpdateItem_To_ItemOut(ui, item);
// item.SetFlag_AltStream(ui.IsAltStream);
item.ExternalAttrib = ui.Attrib;
item.Time = ui.Time;
item.Ntfs_MTime = ui.Ntfs_MTime;
item.Ntfs_ATime = ui.Ntfs_ATime;
item.Ntfs_CTime = ui.Ntfs_CTime;
item.NtfsTimeIsDefined = ui.NtfsTimeIsDefined;
}
/*
else
@@ -148,6 +156,35 @@ static void SetItemInfoFromCompressingResult(const CCompressingResult &compressi
#ifndef _7ZIP_ST
struct CMtSem
{
NWindows::NSynchronization::CSemaphore Semaphore;
NWindows::NSynchronization::CCriticalSection CS;
CIntVector Indexes;
int Head;
void ReleaseItem(unsigned index)
{
{
CCriticalSectionLock lock(CS);
Indexes[index] = Head;
Head = (int)index;
}
Semaphore.Release();
}
int GetFreeItem()
{
int i;
{
CCriticalSectionLock lock(CS);
i = Head;
Head = Indexes[(unsigned)i];
}
return i;
}
};
static THREAD_FUNC_DECL CoderThread(void *threadCoderInfo);
struct CThreadInfo
@@ -156,7 +193,9 @@ struct CThreadInfo
NWindows::CThread Thread;
NWindows::NSynchronization::CAutoResetEvent CompressEvent;
NWindows::NSynchronization::CAutoResetEvent CompressionCompletedEvent;
CMtSem *MtSem;
unsigned ThreadIndex;
bool ExitThread;
CMtCompressProgress *ProgressSpec;
@@ -177,34 +216,43 @@ struct CThreadInfo
UInt32 FileTime;
UInt64 ExpectedDataSize;
CThreadInfo(const CCompressionMethodMode &options):
CThreadInfo():
ExitThread(false),
ProgressSpec(0),
OutStreamSpec(0),
Coder(options),
ProgressSpec(NULL),
OutStreamSpec(NULL),
InSeqMode(false),
OutSeqMode(false),
FileTime(0),
ExpectedDataSize((UInt64)(Int64)-1)
{}
void SetOptions(const CCompressionMethodMode &options)
{
Coder.SetOptions(options);
}
HRESULT CreateEvents()
{
RINOK(CompressEvent.CreateIfNotCreated());
return CompressionCompletedEvent.CreateIfNotCreated();
WRes wres = CompressEvent.CreateIfNotCreated_Reset();
return HRESULT_FROM_WIN32(wres);
}
HRESULT CreateThread()
{
WRes wres = Thread.Create(CoderThread, this);
return HRESULT_FROM_WIN32(wres);
}
HRes CreateThread() { return Thread.Create(CoderThread, this); }
void WaitAndCode();
void StopWaitClose()
void StopWait_Close()
{
ExitThread = true;
if (OutStreamSpec != 0)
if (OutStreamSpec)
OutStreamSpec->StopWriting(E_ABORT);
if (CompressEvent.IsCreated())
CompressEvent.Set();
Thread.Wait();
Thread.Close();
Thread.Wait_Close();
}
};
@@ -215,7 +263,7 @@ void CThreadInfo::WaitAndCode()
CompressEvent.Lock();
if (ExitThread)
return;
Result = Coder.Compress(
EXTERNAL_CODECS_LOC_VARS
InStream, OutStream,
@@ -224,7 +272,8 @@ void CThreadInfo::WaitAndCode()
if (Result == S_OK && Progress)
Result = Progress->SetRatioInfo(&CompressingResult.UnpackSize, &CompressingResult.PackSize);
CompressionCompletedEvent.Set();
MtSem->ReleaseItem(ThreadIndex);
}
}
@@ -241,7 +290,7 @@ public:
~CThreads()
{
FOR_VECTOR (i, Threads)
Threads[i].StopWaitClose();
Threads[i].StopWait_Close();
}
};
@@ -253,7 +302,8 @@ struct CMemBlocks2: public CMemLockBlocks
bool Finished;
CCompressingResult CompressingResult;
CMemBlocks2(): Skip(false), InSeqMode(false), PreDescriptorMode(false), Finished(false) {}
CMemBlocks2(): Skip(false), InSeqMode(false), PreDescriptorMode(false), Finished(false),
CompressingResult() {}
};
class CMemRefs
@@ -359,7 +409,6 @@ STDMETHODIMP CMtProgressMixer::SetRatioInfo(const UInt64 *inSize, const UInt64 *
#endif
static HRESULT UpdateItemOldData(
COutArchive &archive,
CInArchive *inArchive,
@@ -385,21 +434,11 @@ static HRESULT UpdateItemOldData(
if (item.HasDescriptor())
return E_NOTIMPL;
// use old name size.
// 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);
Copy_From_UpdateItem_To_ItemOut(ui, item);
// item.SetFlag_AltStream(ui.IsAltStream);
item.Time = ui.Time;
item.Ntfs_MTime = ui.Ntfs_MTime;
item.Ntfs_ATime = ui.Ntfs_ATime;
item.Ntfs_CTime = ui.Ntfs_CTime;
item.NtfsTimeIsDefined = ui.NtfsTimeIsDefined;
item.CentralExtra.RemoveUnknownSubBlocks();
item.LocalExtra.RemoveUnknownSubBlocks();
@@ -452,16 +491,16 @@ static void UpdatePropsFromStream(CUpdateItem &item, ISequentialInStream *fileIn
FILETIME cTime, aTime, mTime;
UInt64 size;
// UInt32 attrib;
if (getProps->GetProps(&size, &cTime, &aTime, &mTime, NULL) != S_OK)
UInt32 attrib;
if (getProps->GetProps(&size, &cTime, &aTime, &mTime, &attrib) != S_OK)
return;
if (size != item.Size && size != (UInt64)(Int64)-1)
{
Int64 newComplexity = totalComplexity + ((Int64)size - (Int64)item.Size);
const Int64 newComplexity = (Int64)totalComplexity + ((Int64)size - (Int64)item.Size);
if (newComplexity > 0)
{
totalComplexity = newComplexity;
totalComplexity = (UInt64)newComplexity;
updateCallback->SetTotal(totalComplexity);
}
item.Size = size;
@@ -481,7 +520,7 @@ static void UpdatePropsFromStream(CUpdateItem &item, ISequentialInStream *fileIn
if (!IsZero_FILETIME(cTime)) item.Ntfs_CTime = cTime;
if (!IsZero_FILETIME(aTime)) item.Ntfs_ATime = aTime;
// item.Attrib = attrib;
item.Attrib = attrib;
}
@@ -501,7 +540,8 @@ static HRESULT Update2St(
CMyComPtr<ICompressProgressInfo> progress = lps;
lps->Init(updateCallback, true);
CAddCommon compressor(*options);
CAddCommon compressor;
compressor.SetOptions(*options);
CObjectVector<CItemOut> items;
UInt64 unpackSizeTotal = 0, packSizeTotal = 0;
@@ -519,7 +559,7 @@ static HRESULT Update2St(
{
// 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];
itemEx = inputItems[(unsigned)ui.IndexInArc];
if (inArchive->ReadLocalItemAfterCdItemFull(itemEx) != S_OK)
return E_NOTIMPL;
(CItem &)item = itemEx;
@@ -659,7 +699,7 @@ static HRESULT Update2(
}
else
{
CItemEx inputItem = inputItems[ui.IndexInArc];
CItemEx inputItem = inputItems[(unsigned)ui.IndexInArc];
if (inArchive->ReadLocalItemAfterCdItemFull(inputItem) != S_OK)
return E_NOTIMPL;
complexity += inputItem.GetLocalFullSize();
@@ -686,7 +726,8 @@ static HRESULT Update2(
options2._methods.AddNew();
}
CAddCommon compressor(options2);
CAddCommon compressor;
compressor.SetOptions(options2);
complexity = 0;
@@ -715,15 +756,24 @@ static HRESULT Update2(
UInt32 numThreads = options._numThreads;
const UInt32 kNumMaxThreads = 64;
if (numThreads > kNumMaxThreads)
numThreads = kNumMaxThreads;
if (numThreads > MAXIMUM_WAIT_OBJECTS) // is 64 in Windows (is it 64 in all versions?)
{
const UInt32 kNumMaxThreads =
#ifdef _WIN32
64; // _WIN32 supports only 64 threads in one group. So no need for more threads here
#else
128;
#endif
if (numThreads > kNumMaxThreads)
numThreads = kNumMaxThreads;
}
/*
if (numThreads > MAXIMUM_WAIT_OBJECTS) // is 64 in Windows
numThreads = MAXIMUM_WAIT_OBJECTS;
*/
if (numThreads < 1)
numThreads = 1;
const size_t kMemPerThread = (1 << 25);
const size_t kMemPerThread = (size_t)1 << 25;
const size_t kBlockSize = 1 << 16;
bool mtMode = (numThreads > 1);
@@ -731,6 +781,8 @@ static HRESULT Update2(
if (numFilesToCompress <= 1)
mtMode = false;
// mtMode = true; // debug: to test mtMode
if (!mtMode)
{
FOR_VECTOR (mi, options2._methods)
@@ -788,7 +840,7 @@ static HRESULT Update2(
if (t > numThreads)
t = numThreads;
oneMethodMain->AddProp_NumThreads(t);
numXzThreads = t;
numXzThreads = (int)t;
}
numThreads /= (unsigned)numXzThreads;
}
@@ -830,8 +882,16 @@ static HRESULT Update2(
CMemBlockManagerMt memManager(kBlockSize);
CMemRefs refs(&memManager);
CMtSem mtSem;
CThreads threads;
CRecordVector<HANDLE> compressingCompletedEvents;
mtSem.Head = -1;
mtSem.Indexes.ClearAndSetSize(numThreads);
{
WRes wres = mtSem.Semaphore.Create(0, numThreads);
if (wres != 0)
return HRESULT_FROM_WIN32(wres);
}
CUIntVector threadIndices; // list threads in order of updateItems
{
@@ -840,26 +900,32 @@ static HRESULT Update2(
refs.Refs.Add(CMemBlocks2());
for (i = 0; i < numThreads; i++)
threads.Threads.Add(CThreadInfo(options2));
{
threads.Threads.AddNew();
// mtSem.Indexes[i] = -1; // actually we don't use these values
}
for (i = 0; i < numThreads; i++)
{
CThreadInfo &threadInfo = threads.Threads[i];
threadInfo.SetOptions(options2); ;
#ifdef EXTERNAL_CODECS
threadInfo.__externalCodecs = __externalCodecs;
#endif
RINOK(threadInfo.CreateEvents());
threadInfo.OutStreamSpec = new COutMemStream(&memManager);
RINOK(threadInfo.OutStreamSpec->CreateEvents());
RINOK(threadInfo.OutStreamSpec->CreateEvents(SYNC_WFMO(&memManager.Synchro)));
threadInfo.OutStream = threadInfo.OutStreamSpec;
threadInfo.IsFree = true;
threadInfo.ProgressSpec = new CMtCompressProgress();
threadInfo.Progress = threadInfo.ProgressSpec;
threadInfo.ProgressSpec->Init(&mtCompressProgressMixer, (int)i);
threadInfo.ProgressSpec->Init(&mtCompressProgressMixer, i);
threadInfo.InSeqMode = false;
threadInfo.OutSeqMode = false;
threadInfo.FileTime = 0;
threadInfo.ExpectedDataSize = (UInt64)(Int64)-1;
threadInfo.ThreadIndex = i;
threadInfo.MtSem = &mtSem;
RINOK(threadInfo.CreateThread());
}
}
@@ -890,7 +956,7 @@ static HRESULT Update2(
}
else
{
itemEx = inputItems[ui.IndexInArc];
itemEx = inputItems[(unsigned)ui.IndexInArc];
if (inArchive->ReadLocalItemAfterCdItemFull(itemEx) != S_OK)
return E_NOTIMPL;
(CItem &)item = itemEx;
@@ -958,10 +1024,9 @@ static HRESULT Update2(
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);
}
}
@@ -982,7 +1047,7 @@ static HRESULT Update2(
if (!ui.NewProps || !ui.NewData)
{
itemEx = inputItems[ui.IndexInArc];
itemEx = inputItems[(unsigned)ui.IndexInArc];
if (inArchive->ReadLocalItemAfterCdItemFull(itemEx) != S_OK)
return E_NOTIMPL;
(CItem &)item = itemEx;
@@ -1004,7 +1069,7 @@ static HRESULT Update2(
if (memRef.Finished)
{
if (lastRealStreamItemIndex < (int)itemIndex)
lastRealStreamItemIndex = itemIndex;
lastRealStreamItemIndex = (int)itemIndex;
SetFileHeader(options, ui, memRef.CompressingResult.DescriptorMode, item);
@@ -1030,7 +1095,7 @@ static HRESULT Update2(
{
// LocalHeader was not written for current itemIndex still
lastRealStreamItemIndex = itemIndex;
lastRealStreamItemIndex = (int)itemIndex;
// thread was started before for that item already, and memRef.SeqMode was set
@@ -1060,24 +1125,30 @@ static HRESULT Update2(
}
}
DWORD result = ::WaitForMultipleObjects(compressingCompletedEvents.Size(),
&compressingCompletedEvents.Front(), FALSE, INFINITE);
if (result == WAIT_FAILED)
{
DWORD lastError = GetLastError();
return lastError != 0 ? lastError : E_FAIL;
}
unsigned t = (unsigned)(result - WAIT_OBJECT_0);
if (t >= compressingCompletedEvents.Size())
WRes wres = mtSem.Semaphore.Lock();
if (wres != 0)
return HRESULT_FROM_WIN32(wres);
int ti = mtSem.GetFreeItem();
if (ti < 0)
return E_FAIL;
CThreadInfo &threadInfo = threads.Threads[threadIndices[t]];
CThreadInfo &threadInfo = threads.Threads[(unsigned)ti];
threadInfo.InStream.Release();
threadInfo.IsFree = true;
RINOK(threadInfo.Result);
unsigned t = 0;
for (;;)
{
if (t == threadIndices.Size())
return E_FAIL;
if (threadIndices[t] == (unsigned)ti)
break;
t++;
}
threadIndices.Delete(t);
compressingCompletedEvents.Delete(t);
if (t == 0)
{
@@ -1187,7 +1258,7 @@ HRESULT CCacheOutStream::Init(ISequentialOutStream *seqStream, IOutStream *strea
{
RINOK(_stream->Seek(0, STREAM_SEEK_CUR, &_virtPos));
RINOK(_stream->Seek(0, STREAM_SEEK_END, &_virtSize));
RINOK(_stream->Seek(_virtPos, STREAM_SEEK_SET, &_virtPos));
RINOK(_stream->Seek((Int64)_virtPos, STREAM_SEEK_SET, &_virtPos));
}
_phyPos = _virtPos;
_phySize = _virtSize;
@@ -1204,7 +1275,7 @@ HRESULT CCacheOutStream::MyWrite(size_t size)
{
if (!_stream)
return E_FAIL;
RINOK(_stream->Seek(_cachedPos, STREAM_SEEK_SET, &_phyPos));
RINOK(_stream->Seek((Int64)_cachedPos, STREAM_SEEK_SET, &_phyPos));
}
size_t pos = (size_t)_cachedPos & kCacheMask;
size_t curSize = MyMin(kCacheSize - pos, _cachedSize);
@@ -1233,7 +1304,7 @@ CCacheOutStream::~CCacheOutStream()
if (_virtSize != _phySize)
_stream->SetSize(_virtSize);
if (_virtPos != _phyPos)
_stream->Seek(_virtPos, STREAM_SEEK_SET, NULL);
_stream->Seek((Int64)_virtPos, STREAM_SEEK_SET, NULL);
}
::MidFree(_cache);
}
@@ -1332,9 +1403,9 @@ STDMETHODIMP CCacheOutStream::Seek(Int64 offset, UInt32 seekOrigin, UInt64 *newP
}
if (offset < 0)
return HRESULT_WIN32_ERROR_NEGATIVE_SEEK;
_virtPos = offset;
_virtPos = (UInt64)offset;
if (newPosition)
*newPosition = offset;
*newPosition = (UInt64)offset;
return S_OK;
}
@@ -1391,7 +1462,7 @@ HRESULT Update(
{
IInStream *baseStream = inArchive->GetBaseStream();
RINOK(baseStream->Seek(0, STREAM_SEEK_SET, NULL));
RINOK(NCompress::CopyStream_ExactSize(baseStream, seqOutStream, inArchive->ArcInfo.Base, NULL));
RINOK(NCompress::CopyStream_ExactSize(baseStream, seqOutStream, (UInt64)inArchive->ArcInfo.Base, NULL));
}
}
@@ -1412,7 +1483,7 @@ HRESULT Update(
{
IInStream *baseStream = inArchive->GetBaseStream();
RINOK(baseStream->Seek(inArchive->ArcInfo.Base, STREAM_SEEK_SET, NULL));
UInt64 embStubSize = inArchive->ArcInfo.MarkerPos2 - inArchive->ArcInfo.Base;
const UInt64 embStubSize = (UInt64)((Int64)inArchive->ArcInfo.MarkerPos2 - inArchive->ArcInfo.Base);
RINOK(NCompress::CopyStream_ExactSize(baseStream, outStream, embStubSize, NULL));
outArchive.MoveCurPos(embStubSize);
}

View File

@@ -34,11 +34,12 @@ struct CUpdateItem
bool IsUtf8;
// bool IsAltStream;
int IndexInArc;
int IndexInClient;
unsigned IndexInClient;
UInt32 Attrib;
UInt32 Time;
UInt64 Size;
AString Name;
CByteBuffer Name_Utf; // for Info-Zip (kIzUnicodeName) Extra
CByteBuffer Comment;
// bool Commented;
// CUpdateRange CommentRange;
@@ -54,6 +55,7 @@ struct CUpdateItem
// IsAltStream = false;
Size = 0;
Name.Empty();
Name_Utf.Free();
Comment.Free();
}