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

github.com/kornelski/7z.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'CPP/7zip/Archive/Zip/ZipHandler.cpp')
-rw-r--r--CPP/7zip/Archive/Zip/ZipHandler.cpp555
1 files changed, 404 insertions, 151 deletions
diff --git a/CPP/7zip/Archive/Zip/ZipHandler.cpp b/CPP/7zip/Archive/Zip/ZipHandler.cpp
index 75034de0..75fad760 100644
--- a/CPP/7zip/Archive/Zip/ZipHandler.cpp
+++ b/CPP/7zip/Archive/Zip/ZipHandler.cpp
@@ -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"
+};
+
+
+const char * const kMethodNames2[kNumMethodNames2] =
+{
+ "xz"
+ , "Jpeg"
+ , "WavPack"
+ , "PPMd"
+ , "WzAES"
};
-static const char *kMethod_AES = "AES";
-static const char *kMethod_ZipCrypto = "ZipCrypto";
-static const char *kMethod_StrongCrypto = "StrongCrypto";
+#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)
+ {
+ if (level & 1)
+ m += ":eos";
+ level &= ~1;
+ }
+ else if (id == NFileHeader::NCompressionMethod::kDeflate)
{
- ConvertUInt32ToString(id, temp);
- s = temp;
+ 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 kpidHostOS:
+ case kpidCharacts:
{
- Byte hostOS = item.GetHostOS();
- char temp[16];
- const char *s = NULL;
- if (hostOS < ARRAY_SIZE(kHostOS))
- s = kHostOS[hostOS];
- else
+ 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)
{
- ConvertUInt32ToString(hostOS, temp);
- s = temp;
+ item.CentralExtra.PrintInfo(s);
}
- prop = 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:
+ {
+ 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,44 +658,45 @@ 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
-};
+ DecoderSpec->FinishStream = (finishMode != 0);
+ return S_OK;
+}
-HRESULT CXzDecoder::Code(ISequentialInStream *inStream, ISequentialOutStream *outStream,
- const UInt64 * /* inSize */, const UInt64 * /* outSize */, ICompressProgressInfo *progress)
+STDMETHODIMP CLzmaDecoder::GetInStreamProcessedSize(UInt64 *value)
{
- 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;
+ *value = DecoderSpec->GetInputProcessedSize() + kZipLzmaPropsSize;
return S_OK;
}
+
+
+
+
+
struct CMethodItem
{
unsigned ZipMethod;
@@ -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))
}