Update to 7-Zip 17.00 Beta

This commit is contained in:
Tino Reichardt
2017-04-30 14:14:14 +02:00
parent 54389d6e2f
commit aa5ba75da0
451 changed files with 15746 additions and 8574 deletions

View File

@@ -3,10 +3,10 @@
#include "StdAfx.h"
#include "../../../Common/ComTry.h"
#include "../../../Common/IntToString.h"
#include "../../../Common/StringConvert.h"
#include "../../../Windows/PropVariant.h"
#include "../../../Windows/PropVariantUtils.h"
#include "../../../Windows/TimeUtils.h"
#include "../../IPassword.h"
@@ -22,6 +22,7 @@
#include "../../Compress/ImplodeDecoder.h"
#include "../../Compress/PpmdZip.h"
#include "../../Compress/ShrinkDecoder.h"
#include "../../Compress/XzDecoder.h"
#include "../../Crypto/WzAes.h"
#include "../../Crypto/ZipCrypto.h"
@@ -30,7 +31,6 @@
#include "../Common/ItemNameUtils.h"
#include "../Common/OutStreamWithCRC.h"
#include "../XzHandler.h"
#include "ZipHandler.h"
@@ -39,9 +39,6 @@ using namespace NWindows;
namespace NArchive {
namespace NZip {
static const CMethodId kMethodId_ZipBase = 0x040100;
static const CMethodId kMethodId_BZip2 = 0x040202;
static const char * const kHostOS[] =
{
"FAT"
@@ -66,24 +63,57 @@ static const char * const kHostOS[] =
, "OS/X"
};
static const char * const kMethods[] =
const char * const kMethodNames1[kNumMethodNames1] =
{
"Store"
, "Shrink"
, "Reduced1"
, "Reduced2"
, "Reduced3"
, "Reduced4"
, "Reduce1"
, "Reduce2"
, "Reduce3"
, "Reduce4"
, "Implode"
, "Tokenizing"
, NULL // "Tokenize"
, "Deflate"
, "Deflate64"
, "PKImploding"
, NULL
, "BZip2"
, NULL
, "LZMA"
};
static const char *kMethod_AES = "AES";
static const char *kMethod_ZipCrypto = "ZipCrypto";
static const char *kMethod_StrongCrypto = "StrongCrypto";
const char * const kMethodNames2[kNumMethodNames2] =
{
"xz"
, "Jpeg"
, "WavPack"
, "PPMd"
, "WzAES"
};
#define kMethod_AES "AES"
#define kMethod_ZipCrypto "ZipCrypto"
#define kMethod_StrongCrypto "StrongCrypto"
static const char * const kDeflateLevels[4] =
{
"Normal"
, "Maximum"
, "Fast"
, "Fastest"
};
static const CUInt32PCharPair g_HeaderCharacts[] =
{
{ 0, "Encrypt" },
{ 3, "Descriptor" },
// { 5, "Patched" },
{ 6, kMethod_StrongCrypto },
{ 11, "UTF8" }
};
struct CIdToNamePair
{
@@ -91,15 +121,6 @@ struct CIdToNamePair
const char *Name;
};
static const CIdToNamePair k_MethodIdNamePairs[] =
{
{ NFileHeader::NCompressionMethod::kBZip2, "BZip2" },
{ NFileHeader::NCompressionMethod::kLZMA, "LZMA" },
{ NFileHeader::NCompressionMethod::kXz, "xz" },
{ NFileHeader::NCompressionMethod::kJpeg, "Jpeg" },
{ NFileHeader::NCompressionMethod::kWavPack, "WavPack" },
{ NFileHeader::NCompressionMethod::kPPMd, "PPMd" }
};
static const CIdToNamePair k_StrongCryptoPairs[] =
{
@@ -116,7 +137,7 @@ static const CIdToNamePair k_StrongCryptoPairs[] =
{ NStrongCrypto_AlgId::kRC4, "RC4" }
};
const char *FindNameForId(const CIdToNamePair *pairs, unsigned num, unsigned id)
static const char *FindNameForId(const CIdToNamePair *pairs, unsigned num, unsigned id)
{
for (unsigned i = 0; i < num; i++)
{
@@ -127,6 +148,7 @@ const char *FindNameForId(const CIdToNamePair *pairs, unsigned num, unsigned id)
return NULL;
}
static const Byte kProps[] =
{
kpidPath,
@@ -142,9 +164,11 @@ static const Byte kProps[] =
kpidComment,
kpidCRC,
kpidMethod,
kpidCharacts,
kpidHostOS,
kpidUnpackVer,
kpidVolumeIndex
kpidVolumeIndex,
kpidOffset
};
static const Byte kArcProps[] =
@@ -152,6 +176,7 @@ static const Byte kArcProps[] =
kpidEmbeddedStubSize,
kpidBit64,
kpidComment,
kpidCharacts,
kpidTotalPhySize,
kpidIsVolume,
kpidVolumeIndex,
@@ -193,11 +218,34 @@ STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)
break;
}
case kpidTotalPhySize: if (m_Archive.IsMultiVol) prop = m_Archive.Vols.GetTotalSize(); break;
case kpidTotalPhySize: if (m_Archive.IsMultiVol) prop = m_Archive.Vols.TotalBytesSize; break;
case kpidVolumeIndex: if (m_Archive.IsMultiVol) prop = (UInt32)m_Archive.Vols.StartVolIndex; break;
case kpidIsVolume: if (m_Archive.IsMultiVol) prop = true; break;
case kpidNumVolumes: if (m_Archive.IsMultiVol) prop = (UInt32)m_Archive.Vols.Streams.Size(); break;
case kpidCharacts:
{
AString s;
if (m_Archive.LocalsWereRead)
{
s.Add_OptSpaced("Local");
if (m_Archive.LocalsCenterMerged)
s.Add_OptSpaced("Central");
}
if (m_Archive.IsZip64)
s.Add_OptSpaced("Zip64");
if (m_Archive.ExtraMinorError)
s.Add_OptSpaced("Minor_Extra_ERROR");
if (!s.IsEmpty())
prop = s;
break;
}
case kpidWarningFlags:
{
UInt32 v = 0;
@@ -208,12 +256,23 @@ STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)
break;
}
case kpidWarning:
{
AString s;
if (m_Archive.Overflow32bit)
s.Add_OptSpaced("32-bit overflow in headers");
if (m_Archive.Cd_NumEntries_Overflow_16bit)
s.Add_OptSpaced("16-bit overflow for number of files in headers");
if (!s.IsEmpty())
prop = s;
break;
}
case kpidError:
{
if (!m_Archive.Vols.MissingName.IsEmpty())
{
UString s;
s.SetFromAscii("Missing volume : ");
UString s("Missing volume : ");
s += m_Archive.Vols.MissingName;
prop = s;
}
@@ -273,13 +332,19 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val
{
UString res;
item.GetUnicodeString(res, item.Name, false, _forceCodePage, _specifiedCodePage);
NItemName::ConvertToOSName2(res);
NItemName::ReplaceToOsSlashes_Remove_TailSlash(res);
prop = res;
break;
}
case kpidIsDir: prop = item.IsDir(); break;
case kpidSize: prop = item.Size; break;
case kpidSize:
{
if (item.FromCentral || !item.FromLocal || !item.HasDescriptor() || item.DescriptorWasRead)
prop = item.Size;
break;
}
case kpidPackSize: prop = item.PackSize; break;
case kpidTimeType:
@@ -299,17 +364,36 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val
case kpidCTime:
{
FILETIME ft;
if (extra.GetNtfsTime(NFileHeader::NNtfsExtra::kCTime, ft))
prop = ft;
FILETIME utc;
bool defined = true;
if (!extra.GetNtfsTime(NFileHeader::NNtfsExtra::kCTime, utc))
{
UInt32 unixTime = 0;
if (extra.GetUnixTime(true, NFileHeader::NUnixTime::kCTime, unixTime))
NTime::UnixTimeToFileTime(unixTime, utc);
else
defined = false;
}
if (defined)
prop = utc;
break;
}
case kpidATime:
{
FILETIME ft;
if (extra.GetNtfsTime(NFileHeader::NNtfsExtra::kATime, ft))
prop = ft;
FILETIME utc;
bool defined = true;
if (!extra.GetNtfsTime(NFileHeader::NNtfsExtra::kATime, utc))
{
UInt32 unixTime = 0;
if (extra.GetUnixTime(true, NFileHeader::NUnixTime::kATime, unixTime))
NTime::UnixTimeToFileTime(unixTime, utc);
else
defined = false;
}
if (defined)
prop = utc;
break;
}
@@ -375,10 +459,8 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val
CWzAesExtra aesField;
if (extra.GetWzAes(aesField))
{
char s[16];
s[0] = '-';
ConvertUInt32ToString(((unsigned)aesField.Strength + 1) * 64 , s + 1);
m += s;
m += '-';
m.Add_UInt32(((unsigned)aesField.Strength + 1) * 64);
id = aesField.Method;
}
}
@@ -394,10 +476,8 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val
else
{
m += kMethod_StrongCrypto;
char temp[16];
temp[0] = ':';
ConvertUInt32ToString(f.AlgId, temp + 1);
m += temp;
m += ':';
m.Add_UInt32(f.AlgId);
}
if (f.CertificateIsUsed())
m += "-Cert";
@@ -411,41 +491,96 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val
}
{
char temp[16];
const char *s = NULL;
if (id < ARRAY_SIZE(kMethods))
s = kMethods[id];
if (id < kNumMethodNames1)
s = kMethodNames1[id];
else
{
s = FindNameForId(k_MethodIdNamePairs, ARRAY_SIZE(k_MethodIdNamePairs), id);
if (!s)
int id2 = (int)id - (int)kMethodNames2Start;
if (id2 >= 0 && id2 < kNumMethodNames2)
s = kMethodNames2[id2];
}
if (s)
m += s;
else
m.Add_UInt32(id);
}
{
unsigned level = item.GetDeflateLevel();
if (level != 0)
{
if (id == NFileHeader::NCompressionMethod::kLZMA)
{
ConvertUInt32ToString(id, temp);
s = temp;
if (level & 1)
m += ":eos";
level &= ~1;
}
else if (id == NFileHeader::NCompressionMethod::kDeflate)
{
m += ':';
m += kDeflateLevels[level];
level = 0;
}
if (level != 0)
{
m += ":v";
m.Add_UInt32(level);
}
}
m += s;
if (id == NFileHeader::NCompressionMethod::kLZMA && item.IsLzmaEOS())
m += ":EOS";
}
prop = m;
break;
}
case kpidCharacts:
{
AString s;
if (item.FromLocal)
{
s.Add_OptSpaced("Local");
item.LocalExtra.PrintInfo(s);
if (item.FromCentral)
{
s.Add_OptSpaced(":");
s.Add_OptSpaced("Central");
}
}
if (item.FromCentral)
{
item.CentralExtra.PrintInfo(s);
}
UInt32 flags = item.Flags;
flags &= ~(6); // we don't need compression related bits here.
if (flags != 0)
{
AString s2 = FlagsToString(g_HeaderCharacts, ARRAY_SIZE(g_HeaderCharacts), flags);
if (!s2.IsEmpty())
{
s.Add_OptSpaced(":");
s.Add_OptSpaced(s2);
}
}
if (!item.FromCentral && item.FromLocal && item.HasDescriptor() && !item.DescriptorWasRead)
s.Add_OptSpaced("Descriptor_ERROR");
if (!s.IsEmpty())
prop = s;
break;
}
case kpidHostOS:
{
Byte hostOS = item.GetHostOS();
char temp[16];
const char *s = NULL;
if (hostOS < ARRAY_SIZE(kHostOS))
s = kHostOS[hostOS];
else
{
ConvertUInt32ToString(hostOS, temp);
s = temp;
}
prop = s;
const Byte hostOS = item.GetHostOS();
TYPE_TO_PROP(kHostOS, hostOS, prop);
break;
}
@@ -456,6 +591,10 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val
case kpidVolumeIndex:
prop = item.Disk;
break;
case kpidOffset:
prop = item.LocalHeaderPos;
break;
}
prop.Detach(value);
@@ -475,7 +614,7 @@ STDMETHODIMP CHandler::Open(IInStream *inStream,
if (res != S_OK)
{
m_Items.Clear();
m_Archive.ClearRefs();
m_Archive.ClearRefs(); // we don't want to clear error flags
}
return res;
}
@@ -493,16 +632,24 @@ STDMETHODIMP CHandler::Close()
class CLzmaDecoder:
public ICompressCoder,
public ICompressSetFinishMode,
public ICompressGetInStreamProcessedSize,
public CMyUnknownImp
{
public:
NCompress::NLzma::CDecoder *DecoderSpec;
CMyComPtr<ICompressCoder> Decoder;
public:
CLzmaDecoder();
MY_UNKNOWN_IMP2(
ICompressSetFinishMode,
ICompressGetInStreamProcessedSize)
STDMETHOD(Code)(ISequentialInStream *inStream, ISequentialOutStream *outStream,
const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress);
STDMETHOD(SetFinishMode)(UInt32 finishMode);
STDMETHOD(GetInStreamProcessedSize)(UInt64 *value);
MY_UNKNOWN_IMP
CLzmaDecoder();
};
CLzmaDecoder::CLzmaDecoder()
@@ -511,43 +658,44 @@ CLzmaDecoder::CLzmaDecoder()
Decoder = DecoderSpec;
}
static const unsigned kZipLzmaPropsSize = 4 + LZMA_PROPS_SIZE;
HRESULT CLzmaDecoder::Code(ISequentialInStream *inStream, ISequentialOutStream *outStream,
const UInt64 * /* inSize */, const UInt64 *outSize, ICompressProgressInfo *progress)
const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress)
{
Byte buf[9];
RINOK(ReadStream_FALSE(inStream, buf, 9));
if (buf[2] != 5 || buf[3] != 0)
Byte buf[kZipLzmaPropsSize];
RINOK(ReadStream_FALSE(inStream, buf, kZipLzmaPropsSize));
if (buf[2] != LZMA_PROPS_SIZE || buf[3] != 0)
return E_NOTIMPL;
RINOK(DecoderSpec->SetDecoderProperties2(buf + 4, 5));
return Decoder->Code(inStream, outStream, NULL, outSize, progress);
RINOK(DecoderSpec->SetDecoderProperties2(buf + 4, LZMA_PROPS_SIZE));
UInt64 inSize2 = 0;
if (inSize)
{
inSize2 = *inSize;
if (inSize2 < kZipLzmaPropsSize)
return S_FALSE;
inSize2 -= kZipLzmaPropsSize;
}
return Decoder->Code(inStream, outStream, inSize ? &inSize2 : NULL, outSize, progress);
}
class CXzDecoder:
public ICompressCoder,
public CMyUnknownImp
STDMETHODIMP CLzmaDecoder::SetFinishMode(UInt32 finishMode)
{
NArchive::NXz::CDecoder _decoder;
public:
STDMETHOD(Code)(ISequentialInStream *inStream, ISequentialOutStream *outStream,
const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress);
MY_UNKNOWN_IMP
};
HRESULT CXzDecoder::Code(ISequentialInStream *inStream, ISequentialOutStream *outStream,
const UInt64 * /* inSize */, const UInt64 * /* outSize */, ICompressProgressInfo *progress)
{
RINOK(_decoder.Decode(inStream, outStream, progress));
Int32 opRes = _decoder.Get_Extract_OperationResult();
if (opRes == NExtract::NOperationResult::kUnsupportedMethod)
return E_NOTIMPL;
if (opRes != NExtract::NOperationResult::kOK)
return S_FALSE;
DecoderSpec->FinishStream = (finishMode != 0);
return S_OK;
}
STDMETHODIMP CLzmaDecoder::GetInStreamProcessedSize(UInt64 *value)
{
*value = DecoderSpec->GetInputProcessedSize() + kZipLzmaPropsSize;
return S_OK;
}
struct CMethodItem
{
@@ -572,12 +720,15 @@ class CZipDecoder
CMyComPtr<ICryptoGetTextPassword> getTextPassword;
CObjectVector<CMethodItem> methodItems;
CLzmaDecoder *lzmaDecoderSpec;
public:
CZipDecoder():
_zipCryptoDecoderSpec(0),
_pkAesDecoderSpec(0),
_wzAesDecoderSpec(0),
filterStreamSpec(0) {}
filterStreamSpec(0),
lzmaDecoderSpec(0)
{}
HRESULT Decode(
DECL_EXTERNAL_CODECS_LOC_VARS
@@ -592,19 +743,18 @@ public:
};
static HRESULT SkipStreamData(ISequentialInStream *stream, UInt64 size)
static HRESULT SkipStreamData(ISequentialInStream *stream, bool &thereAreData)
{
thereAreData = false;
const size_t kBufSize = 1 << 12;
Byte buf[kBufSize];
for (;;)
{
size_t size = kBufSize;
RINOK(ReadStream(stream, buf, &size));
if (size == 0)
return S_OK;
size_t curSize = kBufSize;
if (curSize > size)
curSize = (size_t)size;
RINOK(ReadStream_FALSE(stream, buf, curSize));
size -= curSize;
thereAreData = true;
}
}
@@ -620,12 +770,15 @@ HRESULT CZipDecoder::Decode(
#endif
Int32 &res)
{
res = NExtract::NOperationResult::kDataError;
res = NExtract::NOperationResult::kHeadersError;
CFilterCoder::C_InStream_Releaser inStreamReleaser;
CFilterCoder::C_Filter_Releaser filterReleaser;
bool needCRC = true;
bool wzAesMode = false;
bool pkAesMode = false;
unsigned id = item.Method;
if (item.IsEncrypted())
@@ -633,27 +786,23 @@ HRESULT CZipDecoder::Decode(
if (item.IsStrongEncrypted())
{
CStrongCryptoExtra f;
if (item.CentralExtra.GetStrongCrypto(f))
{
pkAesMode = true;
}
if (!pkAesMode)
if (!item.CentralExtra.GetStrongCrypto(f))
{
res = NExtract::NOperationResult::kUnsupportedMethod;
return S_OK;
}
pkAesMode = true;
}
if (!pkAesMode && id == NFileHeader::NCompressionMethod::kWzAES)
else if (id == NFileHeader::NCompressionMethod::kWzAES)
{
CWzAesExtra aesField;
if (item.GetMainExtra().GetWzAes(aesField))
{
wzAesMode = true;
needCRC = aesField.NeedCrc();
}
if (!item.GetMainExtra().GetWzAes(aesField))
return S_OK;
wzAesMode = true;
needCRC = aesField.NeedCrc();
}
}
COutStreamWithCRC *outStreamSpec = new COutStreamWithCRC;
CMyComPtr<ISequentialOutStream> outStream = outStreamSpec;
outStreamSpec->SetStream(realOutStream);
@@ -681,6 +830,9 @@ HRESULT CZipDecoder::Decode(
limitedStreamSpec->SetStream(packStream);
limitedStreamSpec->Init(packSize);
}
res = NExtract::NOperationResult::kDataError;
CMyComPtr<ICompressFilter> cryptoFilter;
@@ -725,6 +877,8 @@ HRESULT CZipDecoder::Decode(
CMyComPtr<ICryptoSetPassword> cryptoSetPassword;
RINOK(cryptoFilter.QueryInterface(IID_ICryptoSetPassword, &cryptoSetPassword));
if (!cryptoSetPassword)
return E_FAIL;
if (!getTextPassword)
extractCallback->QueryInterface(IID_ICryptoGetTextPassword, (void **)&getTextPassword);
@@ -736,39 +890,35 @@ HRESULT CZipDecoder::Decode(
AString charPassword;
if (password)
{
UnicodeStringToMultiByte2(charPassword, (const wchar_t *)password, CP_ACP);
/*
if (wzAesMode || pkAesMode)
{
charPassword = UnicodeStringToMultiByte((const wchar_t *)password, CP_ACP);
/*
for (unsigned i = 0;; i++)
{
wchar_t c = password[i];
if (c == 0)
break;
if (c >= 0x80)
{
res = NExtract::NOperationResult::kDataError;
return S_OK;
}
charPassword += (char)c;
}
*/
}
else
{
/* pkzip25 / WinZip / Windows probably use ANSI for some files
We use OEM for compatibility with previous versions of 7-Zip? */
charPassword = UnicodeStringToMultiByte((const wchar_t *)password, CP_OEMCP);
// PASSWORD encoding for ZipCrypto:
// pkzip25 / WinZip / Windows probably use ANSI
// 7-Zip < 4.43 creates ZIP archives with OEM encoding in password
// 7-Zip >= 4.43 creates ZIP archives only with ASCII characters in password
// 7-Zip < 17.00 uses CP_OEMCP for password decoding
// 7-Zip >= 17.00 uses CP_ACP for password decoding
}
*/
}
HRESULT result = cryptoSetPassword->CryptoSetPassword(
(const Byte *)(const char *)charPassword, charPassword.Len());
if (result != S_OK)
{
res = NExtract::NOperationResult::kWrongPassword;
return S_OK;
}
}
else
{
RINOK(cryptoSetPassword->CryptoSetPassword(0, 0));
res = NExtract::NOperationResult::kWrongPassword;
return S_OK;
// RINOK(cryptoSetPassword->CryptoSetPassword(NULL, 0));
}
}
@@ -781,16 +931,19 @@ HRESULT CZipDecoder::Decode(
{
CMethodItem mi;
mi.ZipMethod = id;
if (id == NFileHeader::NCompressionMethod::kStored)
if (id == NFileHeader::NCompressionMethod::kStore)
mi.Coder = new NCompress::CCopyCoder;
else if (id == NFileHeader::NCompressionMethod::kShrunk)
else if (id == NFileHeader::NCompressionMethod::kShrink)
mi.Coder = new NCompress::NShrink::CDecoder;
else if (id == NFileHeader::NCompressionMethod::kImploded)
else if (id == NFileHeader::NCompressionMethod::kImplode)
mi.Coder = new NCompress::NImplode::NDecoder::CCoder;
else if (id == NFileHeader::NCompressionMethod::kLZMA)
mi.Coder = new CLzmaDecoder;
{
lzmaDecoderSpec = new CLzmaDecoder;
mi.Coder = lzmaDecoderSpec;
}
else if (id == NFileHeader::NCompressionMethod::kXz)
mi.Coder = new CXzDecoder;
mi.Coder = new NCompress::NXz::CComDecoder;
else if (id == NFileHeader::NCompressionMethod::kPPMd)
mi.Coder = new NCompress::NPpmdZip::CDecoder(true);
else
@@ -810,7 +963,7 @@ HRESULT CZipDecoder::Decode(
RINOK(CreateCoder(EXTERNAL_CODECS_LOC_VARS szMethodID, false, mi.Coder));
if (mi.Coder == 0)
if (!mi.Coder)
{
res = NExtract::NOperationResult::kUnsupportedMethod;
return S_OK;
@@ -842,9 +995,17 @@ HRESULT CZipDecoder::Decode(
}
#endif
CMyComPtr<ISequentialInStream> inStreamNew;
bool isFullStreamExpected = (!item.HasDescriptor() || item.PackSize != 0);
bool needReminderCheck = false;
bool dataAfterEnd = false;
bool truncatedError = false;
bool lzmaEosError = false;
{
HRESULT result = S_OK;
CMyComPtr<ISequentialInStream> inStreamNew;
if (item.IsEncrypted())
{
if (!filterStream)
@@ -853,6 +1014,7 @@ HRESULT CZipDecoder::Decode(
filterStream = filterStreamSpec;
}
filterReleaser.FilterCoder = filterStreamSpec;
filterStreamSpec->Filter = cryptoFilter;
if (wzAesMode)
@@ -869,6 +1031,7 @@ HRESULT CZipDecoder::Decode(
}
else if (pkAesMode)
{
isFullStreamExpected = false;
result =_pkAesDecoderSpec->ReadHeader(inStream, item.Crc, item.Size);
if (result == S_OK)
{
@@ -926,7 +1089,70 @@ HRESULT CZipDecoder::Decode(
inStreamNew = inStream;
if (result == S_OK)
result = coder->Code(inStreamNew, outStream, NULL, &item.Size, compressProgress);
{
CMyComPtr<ICompressSetFinishMode> setFinishMode;
coder->QueryInterface(IID_ICompressSetFinishMode, (void **)&setFinishMode);
if (setFinishMode)
{
RINOK(setFinishMode->SetFinishMode(BoolToInt(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)
{
CMyComPtr<ICompressGetInStreamProcessedSize> getInStreamProcessedSize;
coder->QueryInterface(IID_ICompressGetInStreamProcessedSize, (void **)&getInStreamProcessedSize);
if (getInStreamProcessedSize && setFinishMode)
{
UInt64 processed;
RINOK(getInStreamProcessedSize->GetInStreamProcessedSize(&processed));
if (processed != (UInt64)(Int64)-1)
{
if (pkAesMode)
{
const UInt32 padSize = _pkAesDecoderSpec->GetPadSize((UInt32)processed);
if (processed + padSize > coderPackSize)
truncatedError = true;
else
{
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
{
if (processed < coderPackSize)
{
if (isFullStreamExpected)
dataAfterEnd = true;
}
else if (processed > coderPackSize)
truncatedError = true;
needReminderCheck = isFullStreamExpected;
}
}
}
}
if (result == S_OK && id == NFileHeader::NCompressionMethod::kLZMA)
if (!lzmaDecoderSpec->DecoderSpec->CheckFinishStatus(item.IsLzmaEOS()))
lzmaEosError = true;
}
if (result == S_FALSE)
return S_OK;
@@ -947,19 +1173,40 @@ HRESULT CZipDecoder::Decode(
if (wzAesMode)
{
const UInt64 rem = limitedStreamSpec->GetRem();
if (rem != 0)
if (SkipStreamData(inStream, rem) != S_OK)
authOk = false;
bool thereAreData = false;
if (SkipStreamData(inStreamNew, thereAreData) != S_OK)
authOk = false;
if (needReminderCheck && thereAreData)
dataAfterEnd = true;
limitedStreamSpec->Init(NCrypto::NWzAes::kMacSize);
if (_wzAesDecoderSpec->CheckMac(inStream, authOk) != S_OK)
authOk = false;
}
res = ((crcOK && authOk) ?
NExtract::NOperationResult::kOK :
NExtract::NOperationResult::kCRCError);
res = NExtract::NOperationResult::kCRCError;
if (crcOK && authOk)
{
res = NExtract::NOperationResult::kOK;
if (dataAfterEnd)
res = NExtract::NOperationResult::kDataAfterEnd;
else if (truncatedError)
res = NExtract::NOperationResult::kUnexpectedEnd;
else if (lzmaEosError)
res = NExtract::NOperationResult::kHeadersError;
// CheckDescriptor() supports only data descriptor with signature and
// it doesn't support "old" pkzip's data descriptor without signature.
// So we disable that check.
/*
if (item.HasDescriptor() && archive.CheckDescriptor(item) != S_OK)
res = NExtract::NOperationResult::kHeadersError;
*/
}
return S_OK;
}
@@ -1026,11 +1273,13 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kUnavailable));
continue;
}
bool headersError = false;
if (!item.FromLocal)
{
bool isAvail = true;
HRESULT res = m_Archive.ReadLocalItemAfterCdItem(item, isAvail);
HRESULT res = m_Archive.ReadLocalItemAfterCdItem(item, isAvail, headersError);
if (res == S_FALSE)
{
if (item.IsDir() || realOutStream || testMode)
@@ -1069,12 +1318,16 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
m_Archive, item, realOutStream, extractCallback,
progress,
#ifndef _7ZIP_ST
_props.NumThreads,
_props._numThreads,
#endif
res);
RINOK(hres);
realOutStream.Release();
if (res == NExtract::NOperationResult::kOK && headersError)
res = NExtract::NOperationResult::kHeadersError;
RINOK(extractCallback->SetOperationResult(res))
}