From f08f4dcc3c02464c17753b3feafcfe5243b9e236 Mon Sep 17 00:00:00 2001 From: Igor Pavlov Date: Sun, 23 Nov 2014 00:00:00 +0000 Subject: 9.34 --- CPP/7zip/Archive/Zip/StdAfx.h | 2 +- CPP/7zip/Archive/Zip/ZipAddCommon.cpp | 49 +- CPP/7zip/Archive/Zip/ZipAddCommon.h | 0 CPP/7zip/Archive/Zip/ZipCompressionMode.h | 2 +- CPP/7zip/Archive/Zip/ZipHandler.cpp | 531 +++++++----- CPP/7zip/Archive/Zip/ZipHandler.h | 10 +- CPP/7zip/Archive/Zip/ZipHandlerOut.cpp | 151 ++-- CPP/7zip/Archive/Zip/ZipHeader.cpp | 36 - CPP/7zip/Archive/Zip/ZipHeader.h | 264 ++---- CPP/7zip/Archive/Zip/ZipIn.cpp | 1323 +++++++++++++++++++---------- CPP/7zip/Archive/Zip/ZipIn.h | 178 ++-- CPP/7zip/Archive/Zip/ZipItem.cpp | 109 +-- CPP/7zip/Archive/Zip/ZipItem.h | 226 +++-- CPP/7zip/Archive/Zip/ZipItemEx.h | 34 - CPP/7zip/Archive/Zip/ZipOut.cpp | 331 ++++---- CPP/7zip/Archive/Zip/ZipOut.h | 68 +- CPP/7zip/Archive/Zip/ZipRegister.cpp | 27 +- CPP/7zip/Archive/Zip/ZipUpdate.cpp | 296 ++++--- CPP/7zip/Archive/Zip/ZipUpdate.h | 19 +- 19 files changed, 2130 insertions(+), 1526 deletions(-) mode change 100755 => 100644 CPP/7zip/Archive/Zip/StdAfx.h mode change 100755 => 100644 CPP/7zip/Archive/Zip/ZipAddCommon.cpp mode change 100755 => 100644 CPP/7zip/Archive/Zip/ZipAddCommon.h mode change 100755 => 100644 CPP/7zip/Archive/Zip/ZipCompressionMode.h mode change 100755 => 100644 CPP/7zip/Archive/Zip/ZipHandler.cpp mode change 100755 => 100644 CPP/7zip/Archive/Zip/ZipHandler.h mode change 100755 => 100644 CPP/7zip/Archive/Zip/ZipHandlerOut.cpp delete mode 100755 CPP/7zip/Archive/Zip/ZipHeader.cpp mode change 100755 => 100644 CPP/7zip/Archive/Zip/ZipHeader.h mode change 100755 => 100644 CPP/7zip/Archive/Zip/ZipIn.cpp mode change 100755 => 100644 CPP/7zip/Archive/Zip/ZipIn.h mode change 100755 => 100644 CPP/7zip/Archive/Zip/ZipItem.cpp mode change 100755 => 100644 CPP/7zip/Archive/Zip/ZipItem.h delete mode 100755 CPP/7zip/Archive/Zip/ZipItemEx.h mode change 100755 => 100644 CPP/7zip/Archive/Zip/ZipOut.cpp mode change 100755 => 100644 CPP/7zip/Archive/Zip/ZipOut.h mode change 100755 => 100644 CPP/7zip/Archive/Zip/ZipRegister.cpp mode change 100755 => 100644 CPP/7zip/Archive/Zip/ZipUpdate.cpp mode change 100755 => 100644 CPP/7zip/Archive/Zip/ZipUpdate.h (limited to 'CPP/7zip/Archive/Zip') diff --git a/CPP/7zip/Archive/Zip/StdAfx.h b/CPP/7zip/Archive/Zip/StdAfx.h old mode 100755 new mode 100644 index e7fb6986..2854ff3e --- a/CPP/7zip/Archive/Zip/StdAfx.h +++ b/CPP/7zip/Archive/Zip/StdAfx.h @@ -3,6 +3,6 @@ #ifndef __STDAFX_H #define __STDAFX_H -#include "../../../Common/MyWindows.h" +#include "../../../Common/Common.h" #endif diff --git a/CPP/7zip/Archive/Zip/ZipAddCommon.cpp b/CPP/7zip/Archive/Zip/ZipAddCommon.cpp old mode 100755 new mode 100644 index f77e4f23..9a0d7515 --- a/CPP/7zip/Archive/Zip/ZipAddCommon.cpp +++ b/CPP/7zip/Archive/Zip/ZipAddCommon.cpp @@ -4,7 +4,7 @@ #include "../../../../C/7zCrc.h" -#include "Windows/PropVariant.h" +#include "../../../Windows/PropVariant.h" #include "../../ICoder.h" #include "../../IPassword.h" @@ -85,18 +85,18 @@ CAddCommon::CAddCommon(const CCompressionMethodMode &options): static HRESULT GetStreamCRC(ISequentialInStream *inStream, UInt32 &resultCRC) { UInt32 crc = CRC_INIT_VAL; - const UInt32 kBufferSize = (1 << 14); - Byte buffer[kBufferSize]; + const UInt32 kBufSize = (1 << 14); + Byte buf[kBufSize]; for (;;) { - UInt32 realProcessedSize; - RINOK(inStream->Read(buffer, kBufferSize, &realProcessedSize)); - if (realProcessedSize == 0) + UInt32 processed; + RINOK(inStream->Read(buf, kBufSize, &processed)); + if (processed == 0) { resultCRC = CRC_GET_DIGEST(crc); return S_OK; } - crc = CrcUpdate(crc, buffer, (size_t)realProcessedSize); + crc = CrcUpdate(crc, buf, (size_t)processed); } } @@ -105,8 +105,14 @@ HRESULT CAddCommon::Compress( ISequentialInStream *inStream, IOutStream *outStream, ICompressProgressInfo *progress, CCompressingResult &opRes) { - CSequentialInStreamWithCRC *inSecCrcStreamSpec = 0; - CInStreamWithCRC *inCrcStreamSpec = 0; + if (!inStream) + { + // We can create empty stream here. But it was already implemented in caller code in 9.33+ + return E_INVALIDARG; + } + + CSequentialInStreamWithCRC *inSecCrcStreamSpec = NULL; + CInStreamWithCRC *inCrcStreamSpec = NULL; CMyComPtr inCrcStream; { CMyComPtr inStream2; @@ -128,26 +134,30 @@ HRESULT CAddCommon::Compress( } } - int numTestMethods = _options.MethodSequence.Size(); + unsigned numTestMethods = _options.MethodSequence.Size(); + if (numTestMethods > 1 || _options.PasswordIsDefined) { - if (inCrcStreamSpec == 0) + if (!inCrcStreamSpec) { if (_options.PasswordIsDefined) return E_NOTIMPL; numTestMethods = 1; } } + Byte method = 0; COutStreamReleaser outStreamReleaser; opRes.ExtractVersion = NFileHeader::NCompressionMethod::kExtractVersion_Default; - for (int i = 0; i < numTestMethods; i++) + + for (unsigned i = 0; i < numTestMethods; i++) { opRes.ExtractVersion = NFileHeader::NCompressionMethod::kExtractVersion_Default; - if (inCrcStreamSpec != 0) + if (inCrcStreamSpec) RINOK(inCrcStreamSpec->Seek(0, STREAM_SEEK_SET, NULL)); RINOK(outStream->SetSize(0)); RINOK(outStream->Seek(0, STREAM_SEEK_SET, NULL)); + if (_options.PasswordIsDefined) { opRes.ExtractVersion = NFileHeader::NCompressionMethod::kExtractVersion_ZipCrypto; @@ -157,6 +167,7 @@ HRESULT CAddCommon::Compress( _cryptoStreamSpec = new CFilterCoder; _cryptoStream = _cryptoStreamSpec; } + if (_options.IsAesMode) { opRes.ExtractVersion = NFileHeader::NCompressionMethod::kExtractVersion_Aes; @@ -164,7 +175,7 @@ HRESULT CAddCommon::Compress( { _cryptoStreamSpec->Filter = _filterAesSpec = new NCrypto::NWzAes::CEncoder; _filterAesSpec->SetKeyMode(_options.AesKeyMode); - RINOK(_filterAesSpec->CryptoSetPassword((const Byte *)(const char *)_options.Password, _options.Password.Length())); + RINOK(_filterAesSpec->CryptoSetPassword((const Byte *)(const char *)_options.Password, _options.Password.Len())); } RINOK(_filterAesSpec->WriteHeader(outStream)); } @@ -173,19 +184,21 @@ HRESULT CAddCommon::Compress( if (!_cryptoStreamSpec->Filter) { _cryptoStreamSpec->Filter = _filterSpec = new NCrypto::NZip::CEncoder; - _filterSpec->CryptoSetPassword((const Byte *)(const char *)_options.Password, _options.Password.Length()); + _filterSpec->CryptoSetPassword((const Byte *)(const char *)_options.Password, _options.Password.Len()); } UInt32 crc = 0; RINOK(GetStreamCRC(inStream, crc)); RINOK(inCrcStreamSpec->Seek(0, STREAM_SEEK_SET, NULL)); RINOK(_filterSpec->WriteHeader(outStream, crc)); } + RINOK(_cryptoStreamSpec->SetOutStream(outStream)); outStreamReleaser.FilterCoder = _cryptoStreamSpec; } method = _options.MethodSequence[i]; - switch(method) + + switch (method) { case NFileHeader::NCompressionMethod::kStored: { @@ -202,6 +215,7 @@ HRESULT CAddCommon::Compress( RINOK(_copyCoder->Code(inCrcStream, outStreamNew, NULL, NULL, progress)); break; } + default: { if (!_compressEncoder) @@ -272,7 +286,7 @@ HRESULT CAddCommon::Compress( RINOK(outStream->Seek(0, STREAM_SEEK_CUR, &opRes.PackSize)); - if (inCrcStreamSpec != 0) + if (inCrcStreamSpec) { opRes.CRC = inCrcStreamSpec->GetCRC(); opRes.UnpackSize = inCrcStreamSpec->GetSize(); @@ -292,6 +306,7 @@ HRESULT CAddCommon::Compress( else if (opRes.PackSize < opRes.UnpackSize) break; } + if (_options.PasswordIsDefined && _options.IsAesMode) { RINOK(_filterAesSpec->WriteFooter(outStream)); diff --git a/CPP/7zip/Archive/Zip/ZipAddCommon.h b/CPP/7zip/Archive/Zip/ZipAddCommon.h old mode 100755 new mode 100644 diff --git a/CPP/7zip/Archive/Zip/ZipCompressionMode.h b/CPP/7zip/Archive/Zip/ZipCompressionMode.h old mode 100755 new mode 100644 index 893daaab..86548d95 --- a/CPP/7zip/Archive/Zip/ZipCompressionMode.h +++ b/CPP/7zip/Archive/Zip/ZipCompressionMode.h @@ -3,7 +3,7 @@ #ifndef __ZIP_COMPRESSION_MODE_H #define __ZIP_COMPRESSION_MODE_H -#include "Common/MyString.h" +#include "../../../Common/MyString.h" #ifndef _7ZIP_ST #include "../../../Windows/System.h" diff --git a/CPP/7zip/Archive/Zip/ZipHandler.cpp b/CPP/7zip/Archive/Zip/ZipHandler.cpp old mode 100755 new mode 100644 index 2281ed5b..f556068c --- a/CPP/7zip/Archive/Zip/ZipHandler.cpp +++ b/CPP/7zip/Archive/Zip/ZipHandler.cpp @@ -2,11 +2,11 @@ #include "StdAfx.h" -#include "Common/ComTry.h" -#include "Common/IntToString.h" +#include "../../../Common/ComTry.h" +#include "../../../Common/IntToString.h" -#include "Windows/PropVariant.h" -#include "Windows/Time.h" +#include "../../../Windows/PropVariant.h" +#include "../../../Windows/TimeUtils.h" #include "../../IPassword.h" @@ -40,98 +40,112 @@ static const CMethodId kMethodId_BZip2 = 0x040202; static const char *kHostOS[] = { - "FAT", - "AMIGA", - "VMS", - "Unix", - "VM/CMS", - "Atari", - "HPFS", - "Macintosh", - "Z-System", - "CP/M", - "TOPS-20", - "NTFS", - "SMS/QDOS", - "Acorn", - "VFAT", - "MVS", - "BeOS", - "Tandem", - "OS/400", - "OS/X" + "FAT" + , "AMIGA" + , "VMS" + , "Unix" + , "VM/CMS" + , "Atari" + , "HPFS" + , "Macintosh" + , "Z-System" + , "CP/M" + , "TOPS-20" + , "NTFS" + , "SMS/QDOS" + , "Acorn" + , "VFAT" + , "MVS" + , "BeOS" + , "Tandem" + , "OS/400" + , "OS/X" }; -static const char *kUnknownOS = "Unknown"; - static const char *kMethods[] = { - "Store", - "Shrink", - "Reduced1", - "Reduced2", - "Reduced3", - "Reduced4", - "Implode", - "Tokenizing", - "Deflate", - "Deflate64", - "PKImploding" + "Store" + , "Shrink" + , "Reduced1" + , "Reduced2" + , "Reduced3" + , "Reduced4" + , "Implode" + , "Tokenizing" + , "Deflate" + , "Deflate64" + , "PKImploding" }; -static const char *kBZip2Method = "BZip2"; -static const char *kLZMAMethod = "LZMA"; -static const char *kJpegMethod = "Jpeg"; -static const char *kWavPackMethod = "WavPack"; -static const char *kPPMdMethod = "PPMd"; -static const char *kAESMethod = "AES"; -static const char *kZipCryptoMethod = "ZipCrypto"; -static const char *kStrongCryptoMethod = "StrongCrypto"; +static const char *kMethod_AES = "AES"; +static const char *kMethod_ZipCrypto = "ZipCrypto"; +static const char *kMethod_StrongCrypto = "StrongCrypto"; -static struct CStrongCryptoPair +struct CIdToNamePair { - UInt16 Id; + unsigned Id; const char *Name; -} g_StrongCryptoPairs[] = +}; + +static const CIdToNamePair k_MethodIdNamePairs[] = +{ + { NFileHeader::NCompressionMethod::kBZip2, "BZip2" }, + { NFileHeader::NCompressionMethod::kLZMA, "LZMA" }, + { NFileHeader::NCompressionMethod::kJpeg, "Jpeg" }, + { NFileHeader::NCompressionMethod::kWavPack, "WavPack" }, + { NFileHeader::NCompressionMethod::kPPMd, "PPMd" } +}; + +static const CIdToNamePair k_StrongCryptoPairs[] = { - { NStrongCryptoFlags::kDES, "DES" }, - { NStrongCryptoFlags::kRC2old, "RC2a" }, - { NStrongCryptoFlags::k3DES168, "3DES-168" }, - { NStrongCryptoFlags::k3DES112, "3DES-112" }, - { NStrongCryptoFlags::kAES128, "pkAES-128" }, - { NStrongCryptoFlags::kAES192, "pkAES-192" }, - { NStrongCryptoFlags::kAES256, "pkAES-256" }, - { NStrongCryptoFlags::kRC2, "RC2" }, - { NStrongCryptoFlags::kBlowfish, "Blowfish" }, - { NStrongCryptoFlags::kTwofish, "Twofish" }, - { NStrongCryptoFlags::kRC4, "RC4" } + { NStrongCrypto_AlgId::kDES, "DES" }, + { NStrongCrypto_AlgId::kRC2old, "RC2a" }, + { NStrongCrypto_AlgId::k3DES168, "3DES-168" }, + { NStrongCrypto_AlgId::k3DES112, "3DES-112" }, + { NStrongCrypto_AlgId::kAES128, "pkAES-128" }, + { NStrongCrypto_AlgId::kAES192, "pkAES-192" }, + { NStrongCrypto_AlgId::kAES256, "pkAES-256" }, + { NStrongCrypto_AlgId::kRC2, "RC2" }, + { NStrongCrypto_AlgId::kBlowfish, "Blowfish" }, + { NStrongCrypto_AlgId::kTwofish, "Twofish" }, + { NStrongCrypto_AlgId::kRC4, "RC4" } }; -static const STATPROPSTG kProps[] = +const char *FindNameForId(const CIdToNamePair *pairs, unsigned num, unsigned id) +{ + for (unsigned i = 0; i < num; i++) + { + const CIdToNamePair &pair = pairs[i]; + if (id == pair.Id) + return pair.Name; + } + return NULL; +} + +static const Byte kProps[] = { - { NULL, kpidPath, VT_BSTR}, - { NULL, kpidIsDir, VT_BOOL}, - { NULL, kpidSize, VT_UI8}, - { NULL, kpidPackSize, VT_UI8}, - { NULL, kpidMTime, VT_FILETIME}, - { NULL, kpidCTime, VT_FILETIME}, - { NULL, kpidATime, VT_FILETIME}, - { NULL, kpidAttrib, VT_UI4}, - // { NULL, kpidPosixAttrib, VT_UI4}, - { NULL, kpidEncrypted, VT_BOOL}, - { NULL, kpidComment, VT_BSTR}, - { NULL, kpidCRC, VT_UI4}, - { NULL, kpidMethod, VT_BSTR}, - { NULL, kpidHostOS, VT_BSTR}, - { NULL, kpidUnpackVer, VT_UI4} + kpidPath, + kpidIsDir, + kpidSize, + kpidPackSize, + kpidMTime, + kpidCTime, + kpidATime, + kpidAttrib, + // kpidPosixAttrib, + kpidEncrypted, + kpidComment, + kpidCRC, + kpidMethod, + kpidHostOS, + kpidUnpackVer }; -static const STATPROPSTG kArcProps[] = +static const Byte kArcProps[] = { - { NULL, kpidBit64, VT_BOOL}, - { NULL, kpidComment, VT_BSTR}, - { NULL, kpidPhySize, VT_UI8}, - { NULL, kpidOffset, VT_UI8} + kpidEmbeddedStubSize, + kpidBit64, + kpidComment }; CHandler::CHandler() @@ -142,12 +156,12 @@ CHandler::CHandler() static AString BytesToString(const CByteBuffer &data) { AString s; - int size = (int)data.GetCapacity(); + unsigned size = (unsigned)data.Size(); if (size > 0) { - char *p = s.GetBuffer(size + 1); + char *p = s.GetBuffer(size); memcpy(p, (const Byte *)data, size); - p[size] = '\0'; + p[size] = 0; s.ReleaseBuffer(); } return s; @@ -160,13 +174,52 @@ STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value) { COM_TRY_BEGIN NWindows::NCOM::CPropVariant prop; - switch(propID) + switch (propID) { case kpidBit64: if (m_Archive.IsZip64) prop = m_Archive.IsZip64; break; - case kpidComment: prop = MultiByteToUnicodeString(BytesToString(m_Archive.ArcInfo.Comment), CP_ACP); break; + case kpidComment: if (m_Archive.ArcInfo.Comment.Size() != 0) prop = MultiByteToUnicodeString(BytesToString(m_Archive.ArcInfo.Comment), CP_ACP); break; case kpidPhySize: prop = m_Archive.ArcInfo.GetPhySize(); break; - case kpidOffset: if (m_Archive.ArcInfo.StartPosition != 0) prop = m_Archive.ArcInfo.StartPosition; break; - case kpidError: if (!m_Archive.IsOkHeaders) prop = "Incorrect headers"; break; + case kpidOffset: /* if (m_Archive.ArcInfo.Base != 0) */ + prop = m_Archive.ArcInfo.Base; break; + + case kpidEmbeddedStubSize: + { + UInt64 stubSize = m_Archive.ArcInfo.GetEmbeddedStubSize(); + if (stubSize != 0) + prop = stubSize; + break; + } + + case kpidWarningFlags: + { + UInt32 v = 0; + // if (m_Archive.ExtraMinorError) v |= kpv_ErrorFlags_HeadersError; + if (m_Archive.HeadersWarning) v |= kpv_ErrorFlags_HeadersError; + if (v != 0) + prop = v; + break; + } + + case kpidErrorFlags: + { + UInt32 v = 0; + if (!m_Archive.IsArc) v |= kpv_ErrorFlags_IsNotArc; + if (m_Archive.HeadersError) v |= kpv_ErrorFlags_HeadersError; + if (m_Archive.UnexpectedEnd) v |= kpv_ErrorFlags_UnexpectedEnd; + if (m_Archive.ArcInfo.Base < 0) + { + /* We try to support case when we have sfx-zip with embedded stub, + but the stream has access only to zip part. + In that case we ignore UnavailableStart error. + maybe we must show warning in that case. */ + UInt64 stubSize = m_Archive.ArcInfo.GetEmbeddedStubSize(); + if (stubSize < (UInt64)-m_Archive.ArcInfo.Base) + v |= kpv_ErrorFlags_UnavailableStart; + } + if (m_Archive.NoCentralDir) v |= kpv_ErrorFlags_UnconfirmedStart; + prop = v; + break; + } } prop.Detach(value); COM_TRY_END @@ -184,24 +237,36 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val COM_TRY_BEGIN NWindows::NCOM::CPropVariant prop; const CItemEx &item = m_Items[index]; - switch(propID) + switch (propID) { - case kpidPath: prop = NItemName::GetOSName2(item.GetUnicodeString(item.Name)); break; + case kpidPath: + { + UString res; + item.GetUnicodeString(item.Name, res, _forceCodePage, _specifiedCodePage); + NItemName::ConvertToOSName2(res); + prop = res; + break; + } + case kpidIsDir: prop = item.IsDir(); break; - case kpidSize: prop = item.UnPackSize; break; + case kpidSize: prop = item.Size; break; case kpidPackSize: prop = item.PackSize; break; + case kpidTimeType: { FILETIME ft; UInt32 unixTime; + UInt32 type; if (item.CentralExtra.GetNtfsTime(NFileHeader::NNtfsExtra::kMTime, ft)) - prop = (UInt32)NFileTimeType::kWindows; + type = NFileTimeType::kWindows; else if (item.CentralExtra.GetUnixTime(true, NFileHeader::NUnixTime::kMTime, unixTime)) - prop = (UInt32)NFileTimeType::kUnix; + type = NFileTimeType::kUnix; else - prop = (UInt32)NFileTimeType::kDOS; + type = NFileTimeType::kDOS; + prop = type; break; } + case kpidCTime: { FILETIME ft; @@ -209,6 +274,7 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val prop = ft; break; } + case kpidATime: { FILETIME ft; @@ -216,26 +282,33 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val prop = ft; break; } + case kpidMTime: { FILETIME utc; + bool defined = true; if (!item.CentralExtra.GetNtfsTime(NFileHeader::NNtfsExtra::kMTime, utc)) { - UInt32 unixTime; + UInt32 unixTime = 0; if (item.CentralExtra.GetUnixTime(true, NFileHeader::NUnixTime::kMTime, unixTime)) NTime::UnixTimeToFileTime(unixTime, utc); else { FILETIME localFileTime; - if (!NTime::DosTimeToFileTime(item.Time, localFileTime) || + if (item.Time == 0) + defined = false; + else if (!NTime::DosTimeToFileTime(item.Time, localFileTime) || !LocalFileTimeToFileTime(&localFileTime, &utc)) utc.dwHighDateTime = utc.dwLowDateTime = 0; } } - prop = utc; + if (defined) + prop = utc; break; } + case kpidAttrib: prop = item.GetWinAttrib(); break; + case kpidPosixAttrib: { UInt32 attrib; @@ -243,83 +316,107 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val prop = attrib; break; } + case kpidEncrypted: prop = item.IsEncrypted(); break; - case kpidComment: prop = item.GetUnicodeString(BytesToString(item.Comment)); break; - case kpidCRC: if (item.IsThereCrc()) prop = item.FileCRC; break; + + case kpidComment: + { + if (item.Comment.Size() != 0) + { + UString res; + item.GetUnicodeString(BytesToString(item.Comment), res, _forceCodePage, _specifiedCodePage); + prop = res; + } + break; + } + + case kpidCRC: if (item.IsThereCrc()) prop = item.Crc; break; + case kpidMethod: { - UInt16 methodId = item.CompressionMethod; - AString method; + UInt16 methodId = item.Method; + AString m; + if (item.IsEncrypted()) { if (methodId == NFileHeader::NCompressionMethod::kWzAES) { - method = kAESMethod; - CWzAesExtraField aesField; - if (item.CentralExtra.GetWzAesField(aesField)) + m += kMethod_AES; + CWzAesExtra aesField; + if (item.CentralExtra.GetWzAes(aesField)) { - method += '-'; - char s[32]; - ConvertUInt64ToString((aesField.Strength + 1) * 64 , s); - method += s; - method += ' '; + char s[16]; + s[0] = '-'; + ConvertUInt32ToString(((unsigned)aesField.Strength + 1) * 64 , s + 1); + m += s; methodId = aesField.Method; } } - else + else if (item.IsStrongEncrypted()) { - if (item.IsStrongEncrypted()) + CStrongCryptoExtra f; + f.AlgId = 0; + if (item.CentralExtra.GetStrongCrypto(f)) { - CStrongCryptoField f; - bool finded = false; - if (item.CentralExtra.GetStrongCryptoField(f)) + const char *s = FindNameForId(k_StrongCryptoPairs, ARRAY_SIZE(k_StrongCryptoPairs), f.AlgId); + if (s) + m += s; + else { - for (int i = 0; i < sizeof(g_StrongCryptoPairs) / sizeof(g_StrongCryptoPairs[0]); i++) - { - const CStrongCryptoPair &pair = g_StrongCryptoPairs[i]; - if (f.AlgId == pair.Id) - { - method += pair.Name; - finded = true; - break; - } - } + m += kMethod_StrongCrypto; + char temp[16]; + temp[0] = ':'; + ConvertUInt32ToString(f.AlgId, temp + 1); + m += temp; } - if (!finded) - method += kStrongCryptoMethod; } else - method += kZipCryptoMethod; - method += ' '; + m += kMethod_StrongCrypto; } + else + m += kMethod_ZipCrypto; + m += ' '; } - if (methodId < sizeof(kMethods) / sizeof(kMethods[0])) - method += kMethods[methodId]; - else switch (methodId) + { - case NFileHeader::NCompressionMethod::kLZMA: - method += kLZMAMethod; - if (item.IsLzmaEOS()) - method += ":EOS"; - break; - case NFileHeader::NCompressionMethod::kBZip2: method += kBZip2Method; break; - case NFileHeader::NCompressionMethod::kJpeg: method += kJpegMethod; break; - case NFileHeader::NCompressionMethod::kWavPack: method += kWavPackMethod; break; - case NFileHeader::NCompressionMethod::kPPMd: method += kPPMdMethod; break; - default: + char temp[16]; + const char *s = NULL; + if (methodId < ARRAY_SIZE(kMethods)) + s = kMethods[methodId]; + else { - char s[32]; - ConvertUInt64ToString(methodId, s); - method += s; + s = FindNameForId(k_MethodIdNamePairs, ARRAY_SIZE(k_MethodIdNamePairs), methodId); + if (!s) + { + ConvertUInt32ToString(methodId, temp); + s = temp; + } } + m += s; + if (methodId == NFileHeader::NCompressionMethod::kLZMA && item.IsLzmaEOS()) + m += ":EOS"; } - prop = method; + + prop = m; break; } + case kpidHostOS: - prop = (item.MadeByVersion.HostOS < sizeof(kHostOS) / sizeof(kHostOS[0])) ? - (kHostOS[item.MadeByVersion.HostOS]) : kUnknownOS; + { + 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; break; + } + case kpidUnpackVer: prop = (UInt32)item.ExtractVersion.Version; break; @@ -333,23 +430,25 @@ class CProgressImp: public CProgressVirt { CMyComPtr _callback; public: - STDMETHOD(SetTotal)(UInt64 numFiles); - STDMETHOD(SetCompleted)(UInt64 numFiles); + virtual HRESULT SetCompletedLocal(UInt64 numFiles, UInt64 numBytes); + virtual HRESULT SetTotalCD(UInt64 numFiles); + virtual HRESULT SetCompletedCD(UInt64 numFiles); CProgressImp(IArchiveOpenCallback *callback): _callback(callback) {} }; -STDMETHODIMP CProgressImp::SetTotal(UInt64 numFiles) +HRESULT CProgressImp::SetCompletedLocal(UInt64 numFiles, UInt64 numBytes) { - if (_callback) - return _callback->SetTotal(&numFiles, NULL); - return S_OK; + return _callback->SetCompleted(&numFiles, &numBytes); } -STDMETHODIMP CProgressImp::SetCompleted(UInt64 numFiles) +HRESULT CProgressImp::SetTotalCD(UInt64 numFiles) { - if (_callback) - return _callback->SetCompleted(&numFiles, NULL); - return S_OK; + return _callback->SetTotal(&numFiles, NULL); +} + +HRESULT CProgressImp::SetCompletedCD(UInt64 numFiles) +{ + return _callback->SetCompleted(&numFiles, NULL); } STDMETHODIMP CHandler::Open(IInStream *inStream, @@ -359,12 +458,10 @@ STDMETHODIMP CHandler::Open(IInStream *inStream, try { Close(); - RINOK(inStream->Seek(0, STREAM_SEEK_SET, NULL)); RINOK(m_Archive.Open(inStream, maxCheckStartPosition)); CProgressImp progressImp(callback); - return m_Archive.ReadHeaders(m_Items, &progressImp); + return m_Archive.ReadHeaders(m_Items, callback ? &progressImp : NULL); } - catch(const CInArchiveException &) { Close(); return S_FALSE; } catch(...) { Close(); throw; } COM_TRY_END } @@ -467,26 +564,26 @@ HRESULT CZipDecoder::Decode( bool needCRC = true; bool wzAesMode = false; bool pkAesMode = false; - UInt16 methodId = item.CompressionMethod; + UInt16 methodId = item.Method; if (item.IsEncrypted()) { if (item.IsStrongEncrypted()) { - CStrongCryptoField f; - if (item.CentralExtra.GetStrongCryptoField(f)) + CStrongCryptoExtra f; + if (item.CentralExtra.GetStrongCrypto(f)) { pkAesMode = true; } if (!pkAesMode) { - res = NExtract::NOperationResult::kUnSupportedMethod; + res = NExtract::NOperationResult::kUnsupportedMethod; return S_OK; } } - if (methodId == NFileHeader::NCompressionMethod::kWzAES) + if (!pkAesMode && methodId == NFileHeader::NCompressionMethod::kWzAES) { - CWzAesExtraField aesField; - if (item.CentralExtra.GetWzAesField(aesField)) + CWzAesExtra aesField; + if (item.CentralExtra.GetWzAes(aesField)) { wzAesMode = true; needCRC = aesField.NeedCrc(); @@ -520,8 +617,8 @@ HRESULT CZipDecoder::Decode( { if (wzAesMode) { - CWzAesExtraField aesField; - if (!item.CentralExtra.GetWzAesField(aesField)) + CWzAesExtra aesField; + if (!item.CentralExtra.GetWzAes(aesField)) return S_OK; methodId = aesField.Method; if (!_wzAesDecoder) @@ -562,31 +659,35 @@ HRESULT CZipDecoder::Decode( CMyComBSTR password; RINOK(getTextPassword->CryptoGetTextPassword(&password)); AString charPassword; - if (wzAesMode || pkAesMode) + if (password) { - charPassword = UnicodeStringToMultiByte((const wchar_t *)password, CP_ACP); - /* - for (int i = 0;; i++) + if (wzAesMode || pkAesMode) { - wchar_t c = password[i]; - if (c == 0) - break; - if (c >= 0x80) + charPassword = UnicodeStringToMultiByte((const wchar_t *)password, CP_ACP); + /* + for (unsigned i = 0;; i++) { - res = NExtract::NOperationResult::kDataError; - return S_OK; + wchar_t c = password[i]; + if (c == 0) + break; + if (c >= 0x80) + { + res = NExtract::NOperationResult::kDataError; + return S_OK; + } + charPassword += (char)c; } - 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); } - */ - } - else - { - // we use OEM. WinZip/Windows probably use ANSI for some files - charPassword = UnicodeStringToMultiByte((const wchar_t *)password, CP_OEMCP); } HRESULT result = cryptoSetPassword->CryptoSetPassword( - (const Byte *)(const char *)charPassword, charPassword.Length()); + (const Byte *)(const char *)charPassword, charPassword.Len()); if (result != S_OK) return S_OK; } @@ -596,7 +697,7 @@ HRESULT CZipDecoder::Decode( } } - int m; + unsigned m; for (m = 0; m < methodItems.Size(); m++) if (methodItems[m].ZipMethod == methodId) break; @@ -624,7 +725,7 @@ HRESULT CZipDecoder::Decode( { if (methodId > 0xFF) { - res = NExtract::NOperationResult::kUnSupportedMethod; + res = NExtract::NOperationResult::kUnsupportedMethod; return S_OK; } szMethodID = kMethodId_ZipBase + (Byte)methodId; @@ -634,7 +735,7 @@ HRESULT CZipDecoder::Decode( if (mi.Coder == 0) { - res = NExtract::NOperationResult::kUnSupportedMethod; + res = NExtract::NOperationResult::kUnsupportedMethod; return S_OK; } } @@ -680,7 +781,7 @@ HRESULT CZipDecoder::Decode( } else if (pkAesMode) { - result =_pkAesDecoderSpec->ReadHeader(inStream, item.FileCRC, item.UnPackSize); + result =_pkAesDecoderSpec->ReadHeader(inStream, item.Crc, item.Size); if (result == S_OK) { bool passwOK; @@ -696,7 +797,16 @@ HRESULT CZipDecoder::Decode( if (result == S_OK) { - RINOK(filterStreamSpec->SetInStream(inStream)); + if (pkAesMode) + { + /* 9.31: The BUG in 9.24-9.30 was fixed. pkAes archives didn't work. + We don't need to call CAesCbcCoder::Init() to reset IV for data. */ + filterStreamSpec->SetInStream_NoSubFilterInit(inStream); + } + else + { + RINOK(filterStreamSpec->SetInStream(inStream)); + } inStreamReleaser.FilterCoder = filterStreamSpec; inStreamNew = filterStream; if (wzAesMode) @@ -709,12 +819,12 @@ HRESULT CZipDecoder::Decode( else inStreamNew = inStream; if (result == S_OK) - result = coder->Code(inStreamNew, outStream, NULL, &item.UnPackSize, compressProgress); + result = coder->Code(inStreamNew, outStream, NULL, &item.Size, compressProgress); if (result == S_FALSE) return S_OK; if (result == E_NOTIMPL) { - res = NExtract::NOperationResult::kUnSupportedMethod; + res = NExtract::NOperationResult::kUnsupportedMethod; return S_OK; } @@ -723,7 +833,7 @@ HRESULT CZipDecoder::Decode( bool crcOK = true; bool authOk = true; if (needCRC) - crcOK = (outStreamSpec->GetCRC() == item.FileCRC); + crcOK = (outStreamSpec->GetCRC() == item.Crc); if (wzAesMode) { inStream.Attach(archive.CreateLimitedStream(authenticationPos, NCrypto::NWzAes::kMacSize)); @@ -744,7 +854,7 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, COM_TRY_BEGIN CZipDecoder myDecoder; UInt64 totalUnPacked = 0, totalPacked = 0; - bool allFilesMode = (numItems == (UInt32)-1); + bool allFilesMode = (numItems == (UInt32)(Int32)-1); if (allFilesMode) numItems = m_Items.Size(); if(numItems == 0) @@ -753,7 +863,7 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, for (i = 0; i < numItems; i++) { const CItemEx &item = m_Items[allFilesMode ? i : indices[i]]; - totalUnPacked += item.UnPackSize; + totalUnPacked += item.Size; totalPacked += item.PackSize; } RINOK(extractCallback->SetTotal(totalUnPacked)); @@ -765,7 +875,8 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, CMyComPtr progress = lps; lps->Init(extractCallback, false); - for (i = 0; i < numItems; i++, currentTotalUnPacked += currentItemUnPacked, + for (i = 0; i < numItems; i++, + currentTotalUnPacked += currentItemUnPacked, currentTotalPacked += currentItemPacked) { currentItemUnPacked = 0; @@ -779,11 +890,26 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, Int32 askMode = testMode ? NExtract::NAskMode::kTest : NExtract::NAskMode::kExtract; - Int32 index = allFilesMode ? i : indices[i]; + UInt32 index = allFilesMode ? i : indices[i]; + + CItemEx item = m_Items[index]; + bool isLocalOffsetOK = m_Archive.IsLocalOffsetOK(item); + bool skip = !isLocalOffsetOK && !item.IsDir(); + if (skip) + askMode = NExtract::NAskMode::kSkip; + + currentItemUnPacked = item.Size; + currentItemPacked = item.PackSize; RINOK(extractCallback->GetStream(index, &realOutStream, askMode)); - CItemEx item = m_Items[index]; + if (!isLocalOffsetOK) + { + RINOK(extractCallback->PrepareOperation(askMode)); + realOutStream.Release(); + RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kUnavailable)); + continue; + } if (!item.FromLocal) { HRESULT res = m_Archive.ReadLocalItemAfterCdItem(item); @@ -793,14 +919,14 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, { RINOK(extractCallback->PrepareOperation(askMode)); realOutStream.Release(); - RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kUnSupportedMethod)); + RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kHeadersError)); } continue; } RINOK(res); } - if (item.IsDir() || item.IgnoreItem()) + if (item.IsDir()) { // if (!testMode) { @@ -811,9 +937,6 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, continue; } - currentItemUnPacked = item.UnPackSize; - currentItemPacked = item.PackSize; - if (!testMode && !realOutStream) continue; diff --git a/CPP/7zip/Archive/Zip/ZipHandler.h b/CPP/7zip/Archive/Zip/ZipHandler.h old mode 100755 new mode 100644 index 33cf6fdc..7f1d2eba --- a/CPP/7zip/Archive/Zip/ZipHandler.h +++ b/CPP/7zip/Archive/Zip/ZipHandler.h @@ -3,7 +3,7 @@ #ifndef __ZIP_HANDLER_H #define __ZIP_HANDLER_H -#include "Common/DynamicBuffer.h" +#include "../../../Common/DynamicBuffer.h" #include "../../ICoder.h" #include "../IArchive.h" @@ -33,7 +33,7 @@ public: INTERFACE_IInArchive(;) INTERFACE_IOutArchive(;) - STDMETHOD(SetProperties)(const wchar_t **names, const PROPVARIANT *values, Int32 numProperties); + STDMETHOD(SetProperties)(const wchar_t **names, const PROPVARIANT *values, UInt32 numProps); DECL_ISetCompressCodecsInfo @@ -47,8 +47,11 @@ private: int m_MainMethod; bool m_ForceAesMode; bool m_WriteNtfsTimeExtra; + bool _removeSfxBlock; bool m_ForceLocal; bool m_ForceUtf8; + bool _forceCodePage; + UInt32 _specifiedCodePage; DECL_EXTERNAL_CODECS_VARS @@ -58,8 +61,11 @@ private: m_MainMethod = -1; m_ForceAesMode = false; m_WriteNtfsTimeExtra = true; + _removeSfxBlock = false; m_ForceLocal = false; m_ForceUtf8 = false; + _forceCodePage = false; + _specifiedCodePage = CP_OEMCP; } }; diff --git a/CPP/7zip/Archive/Zip/ZipHandlerOut.cpp b/CPP/7zip/Archive/Zip/ZipHandlerOut.cpp old mode 100755 new mode 100644 index dd1ca136..ae58cbe2 --- a/CPP/7zip/Archive/Zip/ZipHandlerOut.cpp +++ b/CPP/7zip/Archive/Zip/ZipHandlerOut.cpp @@ -2,12 +2,12 @@ #include "StdAfx.h" -#include "Common/ComTry.h" -#include "Common/StringConvert.h" -#include "Common/StringToInt.h" +#include "../../../Common/ComTry.h" +#include "../../../Common/StringConvert.h" +#include "../../../Common/StringToInt.h" -#include "Windows/PropVariant.h" -#include "Windows/Time.h" +#include "../../../Windows/PropVariant.h" +#include "../../../Windows/TimeUtils.h" #include "../../IPassword.h" @@ -36,7 +36,7 @@ STDMETHODIMP CHandler::GetFileTimeType(UInt32 *timeType) static bool IsAsciiString(const UString &s) { - for (int i = 0; i < s.Length(); i++) + for (unsigned i = 0; i < s.Len(); i++) { wchar_t c = s[i]; if (c < 0x20 || c > 0x7F) @@ -66,40 +66,48 @@ STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numIt IArchiveUpdateCallback *callback) { COM_TRY_BEGIN2 + + if (m_Archive.IsOpen()) + { + if (!m_Archive.CanUpdate()) + return E_NOTIMPL; + } + CObjectVector updateItems; bool thereAreAesUpdates = false; UInt64 largestSize = 0; bool largestSizeDefined = false; + for (UInt32 i = 0; i < numItems; i++) { CUpdateItem ui; Int32 newData; - Int32 newProperties; + Int32 newProps; UInt32 indexInArchive; if (!callback) return E_FAIL; - RINOK(callback->GetUpdateItemInfo(i, &newData, &newProperties, &indexInArchive)); - ui.NewProperties = IntToBool(newProperties); + RINOK(callback->GetUpdateItemInfo(i, &newData, &newProps, &indexInArchive)); + ui.NewProps = IntToBool(newProps); ui.NewData = IntToBool(newData); - ui.IndexInArchive = indexInArchive; + ui.IndexInArc = indexInArchive; ui.IndexInClient = i; - bool existInArchive = (indexInArchive != (UInt32)-1); + bool existInArchive = (indexInArchive != (UInt32)(Int32)-1); if (existInArchive && newData) if (m_Items[indexInArchive].IsAesEncrypted()) thereAreAesUpdates = true; - if (IntToBool(newProperties)) + if (IntToBool(newProps)) { UString name; { NCOM::CPropVariant prop; RINOK(callback->GetProperty(i, kpidAttrib, &prop)); if (prop.vt == VT_EMPTY) - ui.Attributes = 0; + ui.Attrib = 0; else if (prop.vt != VT_UI4) return E_INVALIDARG; else - ui.Attributes = prop.ulVal; + ui.Attrib = prop.ulVal; } { @@ -131,15 +139,15 @@ STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numIt else ui.NtfsTimeIsDefined = m_WriteNtfsTimeExtra; } - RINOK(GetTime(callback, i, kpidMTime, ui.NtfsMTime)); - RINOK(GetTime(callback, i, kpidATime, ui.NtfsATime)); - RINOK(GetTime(callback, i, kpidCTime, ui.NtfsCTime)); + RINOK(GetTime(callback, i, kpidMTime, ui.Ntfs_MTime)); + RINOK(GetTime(callback, i, kpidATime, ui.Ntfs_ATime)); + RINOK(GetTime(callback, i, kpidCTime, ui.Ntfs_CTime)); { FILETIME localFileTime = { 0, 0 }; - if (ui.NtfsMTime.dwHighDateTime != 0 || - ui.NtfsMTime.dwLowDateTime != 0) - if (!FileTimeToLocalFileTime(&ui.NtfsMTime, &localFileTime)) + if (ui.Ntfs_MTime.dwHighDateTime != 0 || + ui.Ntfs_MTime.dwLowDateTime != 0) + if (!FileTimeToLocalFileTime(&ui.Ntfs_MTime, &localFileTime)) return E_INVALIDARG; FileTimeToDosTime(localFileTime, ui.Time); } @@ -159,25 +167,27 @@ STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numIt if (needSlash) name += kSlash; + UINT codePage = _forceCodePage ? _specifiedCodePage : CP_OEMCP; + bool tryUtf8 = true; - if (m_ForceLocal || !m_ForceUtf8) + if ((m_ForceLocal || !m_ForceUtf8) && codePage != CP_UTF8) { bool defaultCharWasUsed; - ui.Name = UnicodeStringToMultiByte(name, CP_OEMCP, '_', defaultCharWasUsed); + ui.Name = UnicodeStringToMultiByte(name, codePage, '_', defaultCharWasUsed); tryUtf8 = (!m_ForceLocal && (defaultCharWasUsed || - MultiByteToUnicodeString(ui.Name, CP_OEMCP) != name)); + MultiByteToUnicodeString(ui.Name, codePage) != name)); } if (tryUtf8) { - int i; - for (i = 0; i < name.Length() && (unsigned)name[i] < 0x80; i++); - ui.IsUtf8 = (i != name.Length()); + unsigned i; + for (i = 0; i < name.Len() && (unsigned)name[i] < 0x80; i++); + ui.IsUtf8 = (i != name.Len()); if (!ConvertUnicodeToUTF8(name, ui.Name)) return E_INVALIDARG; } - if (ui.Name.Length() >= (1 << 16)) + if (ui.Name.Len() >= (1 << 16)) return E_INVALIDARG; ui.IndexInClient = i; @@ -211,6 +221,7 @@ STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numIt largestSizeDefined = true; } ui.Size = size; + // ui.Size -= ui.Size / 2; } updateItems.Add(ui); } @@ -225,6 +236,8 @@ STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numIt options._dataSizeReduce = largestSize; options._dataSizeReduceDefined = largestSizeDefined; + options.PasswordIsDefined = false; + options.Password.Empty(); if (getTextPassword) { CMyComBSTR password; @@ -236,18 +249,17 @@ STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numIt if (!m_ForceAesMode) options.IsAesMode = thereAreAesUpdates; - if (!IsAsciiString((const wchar_t *)password)) + if (!IsAsciiString((BSTR)password)) return E_INVALIDARG; + if (password) + options.Password = UnicodeStringToMultiByte((BSTR)password, CP_OEMCP); if (options.IsAesMode) { - if (options.Password.Length() > NCrypto::NWzAes::kPasswordSizeMax) + if (options.Password.Len() > NCrypto::NWzAes::kPasswordSizeMax) return E_INVALIDARG; } - options.Password = UnicodeStringToMultiByte((const wchar_t *)password, CP_OEMCP); } } - else - options.PasswordIsDefined = false; Byte mainMethod; if (m_MainMethod < 0) @@ -263,68 +275,68 @@ STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numIt return Update( EXTERNAL_CODECS_VARS m_Items, updateItems, outStream, - m_Archive.IsOpen() ? &m_Archive : NULL, &options, callback); + m_Archive.IsOpen() ? &m_Archive : NULL, _removeSfxBlock, + &options, callback); + COM_TRY_END2 } struct CMethodIndexToName { unsigned Method; - const wchar_t *Name; + const char *Name; }; static const CMethodIndexToName k_SupportedMethods[] = { - { NFileHeader::NCompressionMethod::kStored, L"COPY" }, - { NFileHeader::NCompressionMethod::kDeflated, L"DEFLATE" }, - { NFileHeader::NCompressionMethod::kDeflated64, L"DEFLATE64" }, - { NFileHeader::NCompressionMethod::kBZip2, L"BZIP2" }, - { NFileHeader::NCompressionMethod::kLZMA, L"LZMA" }, - { NFileHeader::NCompressionMethod::kPPMd, L"PPMD" } + { NFileHeader::NCompressionMethod::kStored, "copy" }, + { NFileHeader::NCompressionMethod::kDeflated, "deflate" }, + { NFileHeader::NCompressionMethod::kDeflated64, "deflate64" }, + { NFileHeader::NCompressionMethod::kBZip2, "bzip2" }, + { NFileHeader::NCompressionMethod::kLZMA, "lzma" }, + { NFileHeader::NCompressionMethod::kPPMd, "ppmd" } }; -#define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0])) - -STDMETHODIMP CHandler::SetProperties(const wchar_t **names, const PROPVARIANT *values, Int32 numProps) +STDMETHODIMP CHandler::SetProperties(const wchar_t **names, const PROPVARIANT *values, UInt32 numProps) { InitMethodProps(); #ifndef _7ZIP_ST const UInt32 numProcessors = _props.NumThreads; #endif - for (int i = 0; i < numProps; i++) + for (UInt32 i = 0; i < numProps; i++) { UString name = names[i]; - name.MakeUpper(); + name.MakeLower_Ascii(); if (name.IsEmpty()) return E_INVALIDARG; const PROPVARIANT &prop = values[i]; - if (name[0] == L'X') + if (name[0] == L'x') { UInt32 level = 9; - RINOK(ParsePropToUInt32(name.Mid(1), prop, level)); + RINOK(ParsePropToUInt32(name.Ptr(1), prop, level)); _props.Level = level; _props.MethodInfo.AddLevelProp(level); } - else if (name == L"M") + else if (name == L"m") { if (prop.vt == VT_BSTR) { UString m = prop.bstrVal, m2; - m.MakeUpper(); + m.MakeLower_Ascii(); int colonPos = m.Find(L':'); if (colonPos >= 0) { - m2 = m.Mid(colonPos + 1); - m = m.Left(colonPos); + m2 = m.Ptr(colonPos + 1); + m.DeleteFrom(colonPos); } - int k; + unsigned k; for (k = 0; k < ARRAY_SIZE(k_SupportedMethods); k++) { const CMethodIndexToName &pair = k_SupportedMethods[k]; - if (m == pair.Name) + if (m.IsEqualTo(pair.Name)) { if (!m2.IsEmpty()) { @@ -339,7 +351,7 @@ STDMETHODIMP CHandler::SetProperties(const wchar_t **names, const PROPVARIANT *v } else if (prop.vt == VT_UI4) { - int k; + unsigned k; for (k = 0; k < ARRAY_SIZE(k_SupportedMethods); k++) { unsigned method = k_SupportedMethods[k].Method; @@ -355,16 +367,16 @@ STDMETHODIMP CHandler::SetProperties(const wchar_t **names, const PROPVARIANT *v else return E_INVALIDARG; } - else if (name.Left(2) == L"EM") + else if (name.IsPrefixedBy(L"em")) { if (prop.vt != VT_BSTR) return E_INVALIDARG; { UString m = prop.bstrVal; - m.MakeUpper(); - if (m.Left(3) == L"AES") + m.MakeLower_Ascii(); + if (m.IsPrefixedBy(L"aes")) { - m = m.Mid(3); + m.DeleteFrontal(3); if (m == L"128") _props.AesKeyMode = 1; else if (m == L"192") @@ -376,7 +388,7 @@ STDMETHODIMP CHandler::SetProperties(const wchar_t **names, const PROPVARIANT *v _props.IsAesMode = true; m_ForceAesMode = true; } - else if (m == L"ZIPCRYPTO") + else if (m == L"zipcrypto") { _props.IsAesMode = false; m_ForceAesMode = true; @@ -385,29 +397,40 @@ STDMETHODIMP CHandler::SetProperties(const wchar_t **names, const PROPVARIANT *v return E_INVALIDARG; } } - else if (name.Left(2) == L"MT") + else if (name.IsPrefixedBy(L"mt")) { #ifndef _7ZIP_ST - RINOK(ParseMtProp(name.Mid(2), prop, numProcessors, _props.NumThreads)); + RINOK(ParseMtProp(name.Ptr(2), prop, numProcessors, _props.NumThreads)); _props.NumThreadsWasChanged = true; #endif } - else if (name.CompareNoCase(L"TC") == 0) + else if (name.IsEqualTo("tc")) { RINOK(PROPVARIANT_to_bool(prop, m_WriteNtfsTimeExtra)); } - else if (name.CompareNoCase(L"CL") == 0) + else if (name.IsEqualTo("cl")) { RINOK(PROPVARIANT_to_bool(prop, m_ForceLocal)); if (m_ForceLocal) m_ForceUtf8 = false; } - else if (name.CompareNoCase(L"CU") == 0) + else if (name.IsEqualTo("cu")) { RINOK(PROPVARIANT_to_bool(prop, m_ForceUtf8)); if (m_ForceUtf8) m_ForceLocal = false; } + else if (name.IsEqualTo("cp")) + { + UInt32 cp = CP_OEMCP; + RINOK(ParsePropToUInt32(L"", prop, cp)); + _forceCodePage = true; + _specifiedCodePage = cp; + } + else if (name.IsEqualTo("rsfx")) + { + RINOK(PROPVARIANT_to_bool(prop, _removeSfxBlock)); + } else { RINOK(_props.MethodInfo.ParseParamsFromPROPVARIANT(name, prop)); diff --git a/CPP/7zip/Archive/Zip/ZipHeader.cpp b/CPP/7zip/Archive/Zip/ZipHeader.cpp deleted file mode 100755 index 582187b5..00000000 --- a/CPP/7zip/Archive/Zip/ZipHeader.cpp +++ /dev/null @@ -1,36 +0,0 @@ -// Archive/Zip/Header.h - -#include "StdAfx.h" - -#include "ZipHeader.h" - -namespace NArchive { -namespace NZip { - -namespace NSignature -{ - UInt32 kLocalFileHeader = 0x04034B50 + 1; - UInt32 kDataDescriptor = 0x08074B50 + 1; - UInt32 kCentralFileHeader = 0x02014B50 + 1; - UInt32 kEndOfCentralDir = 0x06054B50 + 1; - UInt32 kZip64EndOfCentralDir = 0x06064B50 + 1; - UInt32 kZip64EndOfCentralDirLocator = 0x07064B50 + 1; - - class CMarkersInitializer - { - public: - CMarkersInitializer() - { - kLocalFileHeader--; - kDataDescriptor--; - kCentralFileHeader--; - kEndOfCentralDir--; - kZip64EndOfCentralDir--; - kZip64EndOfCentralDirLocator--; - } - }; - static CMarkersInitializer g_MarkerInitializer; -} - -}} - diff --git a/CPP/7zip/Archive/Zip/ZipHeader.h b/CPP/7zip/Archive/Zip/ZipHeader.h old mode 100755 new mode 100644 index ce8c1e4f..1391cdf4 --- a/CPP/7zip/Archive/Zip/ZipHeader.h +++ b/CPP/7zip/Archive/Zip/ZipHeader.h @@ -1,57 +1,39 @@ -// Archive/Zip/Header.h +// ZipHeader.h #ifndef __ARCHIVE_ZIP_HEADER_H #define __ARCHIVE_ZIP_HEADER_H -#include "Common/Types.h" +#include "../../../Common/MyTypes.h" namespace NArchive { namespace NZip { +const unsigned kMarkerSize = 4; + namespace NSignature { - extern UInt32 kLocalFileHeader; - extern UInt32 kDataDescriptor; - extern UInt32 kCentralFileHeader; - extern UInt32 kEndOfCentralDir; - extern UInt32 kZip64EndOfCentralDir; - extern UInt32 kZip64EndOfCentralDirLocator; - - static const UInt32 kMarkerSize = 4; + const UInt32 kLocalFileHeader = 0x04034B50; + const UInt32 kDataDescriptor = 0x08074B50; + const UInt32 kCentralFileHeader = 0x02014B50; + const UInt32 kEcd = 0x06054B50; + const UInt32 kEcd64 = 0x06064B50; + const UInt32 kEcd64Locator = 0x07064B50; + + // const UInt32 kSpan = 0x08074B50; + const UInt32 kNoSpan = 0x30304b50; // PK00, replaces kSpan, if there is only 1 segment } -const UInt32 kEcdSize = 22; -const UInt32 kZip64EcdSize = 44; -const UInt32 kZip64EcdLocatorSize = 20; -/* -struct CEndOfCentralDirectoryRecord -{ - UInt16 ThisDiskNumber; - UInt16 StartCentralDirectoryDiskNumber; - UInt16 NumEntriesInCentaralDirectoryOnThisDisk; - UInt16 NumEntriesInCentaralDirectory; - UInt32 CentralDirectorySize; - UInt32 CentralDirectoryStartOffset; - UInt16 CommentSize; -}; +const unsigned kLocalHeaderSize = 4 + 26; // including signature +const unsigned kDataDescriptorSize = 4 + 12; // including signature +const unsigned kCentralHeaderSize = 4 + 42; // including signature -struct CEndOfCentralDirectoryRecordFull -{ - UInt32 Signature; - CEndOfCentralDirectoryRecord Header; -}; -*/ +const unsigned kEcdSize = 22; // including signature +const unsigned kEcd64_MainSize = 44; +const unsigned kEcd64_FullSize = 12 + kEcd64_MainSize; +const unsigned kEcd64Locator_Size = 20; namespace NFileHeader { - /* - struct CVersion - { - Byte Version; - Byte HostOS; - }; - */ - namespace NCompressionMethod { enum EType @@ -77,7 +59,7 @@ namespace NFileHeader kPPMd = 0x62, kWzAES = 0x63 }; - const int kNumCompressionMethods = 11; + const Byte kMadeByProgramVersion = 63; const Byte kExtractVersion_Default = 10; @@ -90,8 +72,6 @@ namespace NFileHeader const Byte kExtractVersion_Aes = 51; const Byte kExtractVersion_LZMA = 63; const Byte kExtractVersion_PPMd = 63; - - // const Byte kSupportedVersion = 20; } namespace NExtraID @@ -127,155 +107,93 @@ namespace NFileHeader }; } - const UInt32 kLocalBlockSize = 26; - /* - struct CLocalBlock - { - CVersion ExtractVersion; - - UInt16 Flags; - UInt16 CompressionMethod; - UInt32 Time; - UInt32 FileCRC; - UInt32 PackSize; - UInt32 UnPackSize; - UInt16 NameSize; - UInt16 ExtraSize; - }; - */ - - const UInt32 kDataDescriptorSize = 16; - // const UInt32 kDataDescriptor64Size = 16 + 8; - /* - struct CDataDescriptor - { - UInt32 Signature; - UInt32 FileCRC; - UInt32 PackSize; - UInt32 UnPackSize; - }; - - struct CLocalBlockFull - { - UInt32 Signature; - CLocalBlock Header; - }; - */ - - const UInt32 kCentralBlockSize = 42; - /* - struct CBlock - { - CVersion MadeByVersion; - CVersion ExtractVersion; - UInt16 Flags; - UInt16 CompressionMethod; - UInt32 Time; - UInt32 FileCRC; - UInt32 PackSize; - UInt32 UnPackSize; - UInt16 NameSize; - UInt16 ExtraSize; - UInt16 CommentSize; - UInt16 DiskNumberStart; - UInt16 InternalAttributes; - UInt32 ExternalAttributes; - UInt32 LocalHeaderOffset; - }; - - struct CBlockFull - { - UInt32 Signature; - CBlock Header; - }; - */ - namespace NFlags { - const int kEncrypted = 1 << 0; - const int kLzmaEOS = 1 << 1; - const int kDescriptorUsedMask = 1 << 3; - const int kStrongEncrypted = 1 << 6; - const int kUtf8 = 1 << 11; - - const int kImplodeDictionarySizeMask = 1 << 1; - const int kImplodeLiteralsOnMask = 1 << 2; + const unsigned kEncrypted = 1 << 0; + const unsigned kLzmaEOS = 1 << 1; + const unsigned kDescriptorUsedMask = 1 << 3; + const unsigned kStrongEncrypted = 1 << 6; + const unsigned kUtf8 = 1 << 11; + + const unsigned kImplodeDictionarySizeMask = 1 << 1; + const unsigned kImplodeLiteralsOnMask = 1 << 2; - const int kDeflateTypeBitStart = 1; - const int kNumDeflateTypeBits = 2; - const int kNumDeflateTypes = (1 << kNumDeflateTypeBits); - const int kDeflateTypeMask = (1 << kNumDeflateTypeBits) - 1; + const unsigned kDeflateTypeBitStart = 1; + const unsigned kNumDeflateTypeBits = 2; + const unsigned kNumDeflateTypes = (1 << kNumDeflateTypeBits); + const unsigned kDeflateTypeMask = (1 << kNumDeflateTypeBits) - 1; } namespace NHostOS { enum EEnum { - kFAT = 0, - kAMIGA = 1, - kVMS = 2, // VAX/VMS - kUnix = 3, - kVM_CMS = 4, - kAtari = 5, // what if it's a minix filesystem? [cjh] - kHPFS = 6, // filesystem used by OS/2 (and NT 3.x) - kMac = 7, - kZ_System = 8, - kCPM = 9, - kTOPS20 = 10, // pkzip 2.50 NTFS - kNTFS = 11, // filesystem used by Windows NT - kQDOS = 12, // SMS/QDOS - kAcorn = 13, // Archimedes Acorn RISC OS - kVFAT = 14, // filesystem used by Windows 95, NT - kMVS = 15, - kBeOS = 16, // hybrid POSIX/database filesystem - kTandem = 17, - kOS400 = 18, - kOSX = 19 + kFAT = 0, + kAMIGA = 1, + kVMS = 2, // VAX/VMS + kUnix = 3, + kVM_CMS = 4, + kAtari = 5, // what if it's a minix filesystem? [cjh] + kHPFS = 6, // filesystem used by OS/2 (and NT 3.x) + kMac = 7, + kZ_System = 8, + kCPM = 9, + kTOPS20 = 10, // pkzip 2.50 NTFS + kNTFS = 11, // filesystem used by Windows NT + kQDOS = 12, // SMS/QDOS + kAcorn = 13, // Archimedes Acorn RISC OS + kVFAT = 14, // filesystem used by Windows 95, NT + kMVS = 15, + kBeOS = 16, // hybrid POSIX/database filesystem + kTandem = 17, + kOS400 = 18, + kOSX = 19 }; } - namespace NUnixAttribute + + namespace NUnixAttrib { - const UInt32 kIFMT = 0170000; /* Unix file type mask */ + const UInt32 kIFMT = 0170000; // file type mask - const UInt32 kIFDIR = 0040000; /* Unix directory */ - const UInt32 kIFREG = 0100000; /* Unix regular file */ - const UInt32 kIFSOCK = 0140000; /* Unix socket (BSD, not SysV or Amiga) */ - const UInt32 kIFLNK = 0120000; /* Unix symbolic link (not SysV, Amiga) */ - const UInt32 kIFBLK = 0060000; /* Unix block special (not Amiga) */ - const UInt32 kIFCHR = 0020000; /* Unix character special (not Amiga) */ - const UInt32 kIFIFO = 0010000; /* Unix fifo (BCC, not MSC or Amiga) */ + const UInt32 kIFDIR = 0040000; // directory + const UInt32 kIFREG = 0100000; // regular file + const UInt32 kIFSOCK = 0140000; // socket (BSD, not SysV or Amiga) + const UInt32 kIFLNK = 0120000; // symbolic link (not SysV, Amiga) + const UInt32 kIFBLK = 0060000; // block special (not Amiga) + const UInt32 kIFCHR = 0020000; // character special (not Amiga) + const UInt32 kIFIFO = 0010000; // fifo (BCC, not MSC or Amiga) - const UInt32 kISUID = 04000; /* Unix set user id on execution */ - const UInt32 kISGID = 02000; /* Unix set group id on execution */ - const UInt32 kISVTX = 01000; /* Unix directory permissions control */ - const UInt32 kENFMT = kISGID; /* Unix record locking enforcement flag */ - const UInt32 kIRWXU = 00700; /* Unix read, write, execute: owner */ - const UInt32 kIRUSR = 00400; /* Unix read permission: owner */ - const UInt32 kIWUSR = 00200; /* Unix write permission: owner */ - const UInt32 kIXUSR = 00100; /* Unix execute permission: owner */ - const UInt32 kIRWXG = 00070; /* Unix read, write, execute: group */ - const UInt32 kIRGRP = 00040; /* Unix read permission: group */ - const UInt32 kIWGRP = 00020; /* Unix write permission: group */ - const UInt32 kIXGRP = 00010; /* Unix execute permission: group */ - const UInt32 kIRWXO = 00007; /* Unix read, write, execute: other */ - const UInt32 kIROTH = 00004; /* Unix read permission: other */ - const UInt32 kIWOTH = 00002; /* Unix write permission: other */ - const UInt32 kIXOTH = 00001; /* Unix execute permission: other */ + const UInt32 kISUID = 04000; // set user id on execution + const UInt32 kISGID = 02000; // set group id on execution + const UInt32 kISVTX = 01000; // directory permissions control + const UInt32 kENFMT = kISGID; // record locking enforcement flag + const UInt32 kIRWXU = 00700; // read, write, execute: owner + const UInt32 kIRUSR = 00400; // read permission: owner + const UInt32 kIWUSR = 00200; // write permission: owner + const UInt32 kIXUSR = 00100; // execute permission: owner + const UInt32 kIRWXG = 00070; // read, write, execute: group + const UInt32 kIRGRP = 00040; // read permission: group + const UInt32 kIWGRP = 00020; // write permission: group + const UInt32 kIXGRP = 00010; // execute permission: group + const UInt32 kIRWXO = 00007; // read, write, execute: other + const UInt32 kIROTH = 00004; // read permission: other + const UInt32 kIWOTH = 00002; // write permission: other + const UInt32 kIXOTH = 00001; // execute permission: other } - namespace NAmigaAttribute + namespace NAmigaAttrib { - const UInt32 kIFMT = 06000; /* Amiga file type mask */ - const UInt32 kIFDIR = 04000; /* Amiga directory */ - const UInt32 kIFREG = 02000; /* Amiga regular file */ - const UInt32 kIHIDDEN = 00200; /* to be supported in AmigaDOS 3.x */ - const UInt32 kISCRIPT = 00100; /* executable script (text command file) */ - const UInt32 kIPURE = 00040; /* allow loading into resident memory */ - const UInt32 kIARCHIVE = 00020; /* not modified since bit was last set */ - const UInt32 kIREAD = 00010; /* can be opened for reading */ - const UInt32 kIWRITE = 00004; /* can be opened for writing */ - const UInt32 kIEXECUTE = 00002; /* executable image, a loadable runfile */ - const UInt32 kIDELETE = 00001; /* can be deleted */ + const UInt32 kIFMT = 06000; // Amiga file type mask + const UInt32 kIFDIR = 04000; // Amiga directory + const UInt32 kIFREG = 02000; // Amiga regular file + const UInt32 kIHIDDEN = 00200; // to be supported in AmigaDOS 3.x + const UInt32 kISCRIPT = 00100; // executable script (text command file) + const UInt32 kIPURE = 00040; // allow loading into resident memory + const UInt32 kIARCHIVE = 00020; // not modified since bit was last set + const UInt32 kIREAD = 00010; // can be opened for reading + const UInt32 kIWRITE = 00004; // can be opened for writing + const UInt32 kIEXECUTE = 00002; // executable image, a loadable runfile + const UInt32 kIDELETE = 00001; // can be deleted } } diff --git a/CPP/7zip/Archive/Zip/ZipIn.cpp b/CPP/7zip/Archive/Zip/ZipIn.cpp old mode 100755 new mode 100644 index e930488f..345fbf56 --- a/CPP/7zip/Archive/Zip/ZipIn.cpp +++ b/CPP/7zip/Archive/Zip/ZipIn.cpp @@ -2,13 +2,15 @@ #include "StdAfx.h" -#include "../../../../C/CpuArch.h" +// #include -#include "Common/DynamicBuffer.h" +#include "../../../Common/DynamicBuffer.h" #include "../../Common/LimitedStreams.h" #include "../../Common/StreamUtils.h" +#include "../IArchive.h" + #include "ZipIn.h" #define Get16(p) GetUi16(p) @@ -17,100 +19,342 @@ namespace NArchive { namespace NZip { - + +struct CEcd +{ + UInt16 thisDiskNumber; + UInt16 startCDDiskNumber; + UInt16 numEntriesInCDOnThisDisk; + UInt16 numEntriesInCD; + UInt32 cdSize; + UInt32 cdStartOffset; + UInt16 commentSize; + + void Parse(const Byte *p); + + bool IsEmptyArc() + { + return thisDiskNumber == 0 && startCDDiskNumber == 0 && + numEntriesInCDOnThisDisk == 0 && numEntriesInCD == 0 && cdSize == 0 + && cdStartOffset == 0 // test it + ; + } +}; + +void CEcd::Parse(const Byte *p) +{ + thisDiskNumber = Get16(p); + startCDDiskNumber = Get16(p + 2); + numEntriesInCDOnThisDisk = Get16(p + 4); + numEntriesInCD = Get16(p + 6); + cdSize = Get32(p + 8); + cdStartOffset = Get32(p + 12); + commentSize = Get16(p + 16); +} + +struct CEcd64 +{ + UInt16 versionMade; + UInt16 versionNeedExtract; + UInt32 thisDiskNumber; + UInt32 startCDDiskNumber; + UInt64 numEntriesInCDOnThisDisk; + UInt64 numEntriesInCD; + UInt64 cdSize; + UInt64 cdStartOffset; + + void Parse(const Byte *p); + CEcd64() { memset(this, 0, sizeof(*this)); } +}; + +void CEcd64::Parse(const Byte *p) +{ + versionMade = Get16(p); + versionNeedExtract = Get16(p + 2); + thisDiskNumber = Get32(p + 4); + startCDDiskNumber = Get32(p + 8); + numEntriesInCDOnThisDisk = Get64(p + 12); + numEntriesInCD = Get64(p + 20); + cdSize = Get64(p + 28); + cdStartOffset = Get64(p + 36); +} + HRESULT CInArchive::Open(IInStream *stream, const UInt64 *searchHeaderSizeLimit) { _inBufMode = false; Close(); - RINOK(stream->Seek(0, STREAM_SEEK_CUR, &m_StreamStartPosition)); - m_Position = m_StreamStartPosition; + RINOK(stream->Seek(0, STREAM_SEEK_CUR, &m_Position)); + RINOK(stream->Seek(0, STREAM_SEEK_END, &ArcInfo.FileEndPos)); + RINOK(stream->Seek(m_Position, STREAM_SEEK_SET, NULL)); + + // printf("\nOpen offset = %d", (int)m_Position); RINOK(FindAndReadMarker(stream, searchHeaderSizeLimit)); RINOK(stream->Seek(m_Position, STREAM_SEEK_SET, NULL)); - m_Stream = stream; + Stream = stream; return S_OK; } void CInArchive::Close() { - _inBuffer.ReleaseStream(); - m_Stream.Release(); + IsArc = false; + HeadersError = false; + HeadersWarning = false; + ExtraMinorError = false; + UnexpectedEnd = false; + NoCentralDir = false; + IsZip64 = false; + Stream.Release(); } HRESULT CInArchive::Seek(UInt64 offset) { - return m_Stream->Seek(offset, STREAM_SEEK_SET, NULL); + return Stream->Seek(offset, STREAM_SEEK_SET, NULL); } -////////////////////////////////////// -// Markers +static bool CheckDosTime(UInt32 dosTime) +{ + if (dosTime == 0) + return true; + unsigned month = (dosTime >> 21) & 0xF; + unsigned day = (dosTime >> 16) & 0x1F; + unsigned hour = (dosTime >> 11) & 0x1F; + unsigned min = (dosTime >> 5) & 0x3F; + unsigned sec = (dosTime & 0x1F) * 2; + if (month < 1 || month > 12 || day < 1 || day > 31 || hour > 23 || min > 59 || sec > 59) + return false; + return true; +} -static inline bool TestMarkerCandidate(const Byte *p, UInt32 &value) +API_FUNC_IsArc IsArc_Zip(const Byte *p, size_t size) { + if (size < 8) + return k_IsArc_Res_NEED_MORE; + if (p[0] != 'P') + return k_IsArc_Res_NO; + + UInt32 value = Get32(p); + + if (value == NSignature::kNoSpan) + { + p += 4; + size -= 4; + } + value = Get32(p); - return - (value == NSignature::kLocalFileHeader) || - (value == NSignature::kEndOfCentralDir); + + if (value == NSignature::kEcd) + { + if (size < kEcdSize) + return k_IsArc_Res_NEED_MORE; + CEcd ecd; + ecd.Parse(p + 4); + // if (ecd.cdSize != 0) + if (!ecd.IsEmptyArc()) + return k_IsArc_Res_NO; + return k_IsArc_Res_YES; // k_IsArc_Res_YES_2; + } + + if (value != NSignature::kLocalFileHeader) + return k_IsArc_Res_NO; + + if (size < kLocalHeaderSize) + return k_IsArc_Res_NEED_MORE; + + p += 4; + + { + const unsigned kPureHeaderSize = kLocalHeaderSize - 4; + unsigned i; + for (i = 0; i < kPureHeaderSize && p[i] == 0; i++); + if (i == kPureHeaderSize) + return k_IsArc_Res_NEED_MORE; + } + + /* + if (p[0] >= 128) // ExtractVersion.Version; + return k_IsArc_Res_NO; + */ + + // ExtractVersion.Version = p[0]; + // ExtractVersion.HostOS = p[1]; + // Flags = Get16(p + 2); + // Method = Get16(p + 4); + /* + // 9.33: some zip archives contain incorrect value in timestamp. So we don't check it now + UInt32 dosTime = Get32(p + 6); + if (!CheckDosTime(dosTime)) + return k_IsArc_Res_NO; + */ + // Crc = Get32(p + 10); + // PackSize = Get32(p + 14); + // Size = Get32(p + 18); + unsigned nameSize = Get16(p + 22); + unsigned extraSize = Get16(p + 24); + UInt32 extraOffset = kLocalHeaderSize + (UInt32)nameSize; + if (extraOffset + extraSize > (1 << 16)) + return k_IsArc_Res_NO; + + p -= 4; + + { + size_t rem = size - kLocalHeaderSize; + if (rem > nameSize) + rem = nameSize; + const Byte *p2 = p + kLocalHeaderSize; + for (size_t i = 0; i < rem; i++) + if (p2[i] == 0) + return k_IsArc_Res_NO; + } + + if (size < extraOffset) + return k_IsArc_Res_NEED_MORE; + + if (extraSize > 0) + { + p += extraOffset; + size -= extraOffset; + while (extraSize != 0) + { + if (extraSize < 4) + { + // 7-Zip before 9.31 created incorrect WsAES Extra in folder's local headers. + // so we return k_IsArc_Res_YES to support such archives. + // return k_IsArc_Res_NO; // do we need to support such extra ? + return k_IsArc_Res_YES; + } + if (size < 4) + return k_IsArc_Res_NEED_MORE; + unsigned dataSize = Get16(p + 2); + size -= 4; + extraSize -= 4; + p += 4; + if (dataSize > extraSize) + return k_IsArc_Res_NO; + if (dataSize > size) + return k_IsArc_Res_NEED_MORE; + size -= dataSize; + extraSize -= dataSize; + p += dataSize; + } + } + + return k_IsArc_Res_YES; } -static const UInt32 kNumMarkerAddtionalBytes = 2; -static inline bool TestMarkerCandidate2(const Byte *p, UInt32 &value) +static UInt32 IsArc_Zip_2(const Byte *p, size_t size, bool isFinal) { - value = Get32(p); - if (value == NSignature::kEndOfCentralDir) - return (Get16(p + 4) == 0); - return (value == NSignature::kLocalFileHeader && p[4] < 128); + UInt32 res = IsArc_Zip(p, size); + if (res == k_IsArc_Res_NEED_MORE && isFinal) + return k_IsArc_Res_NO; + return res; } -HRESULT CInArchive::FindAndReadMarker(IInStream *stream, const UInt64 *searchHeaderSizeLimit) +HRESULT CInArchive::FindAndReadMarker(IInStream *stream, const UInt64 *searchLimit) { ArcInfo.Clear(); - m_Position = m_StreamStartPosition; + ArcInfo.MarkerPos = m_Position; + ArcInfo.MarkerPos2 = m_Position; - Byte marker[NSignature::kMarkerSize]; - RINOK(ReadStream_FALSE(stream, marker, NSignature::kMarkerSize)); - m_Position += NSignature::kMarkerSize; - if (TestMarkerCandidate(marker, m_Signature)) - return S_OK; + if (searchLimit && *searchLimit == 0) + { + const unsigned kStartBufSize = kMarkerSize; + Byte startBuf[kStartBufSize]; + size_t processed = kStartBufSize; + RINOK(ReadStream(stream, startBuf, &processed)); + m_Position += processed; + if (processed < kMarkerSize) + return S_FALSE; + m_Signature = Get32(startBuf); + if (m_Signature != NSignature::kEcd && + m_Signature != NSignature::kLocalFileHeader) + { + if (m_Signature != NSignature::kNoSpan) + return S_FALSE; + size_t processed = kStartBufSize; + RINOK(ReadStream(stream, startBuf, &processed)); + m_Position += processed; + if (processed < kMarkerSize) + return S_FALSE; + m_Signature = Get32(startBuf); + if (m_Signature != NSignature::kEcd && + m_Signature != NSignature::kLocalFileHeader) + return S_FALSE; + ArcInfo.MarkerPos2 += 4; + } + + // we use weak test in case of *searchLimit == 0) + // since error will be detected later in Open function + // m_Position = ArcInfo.MarkerPos2 + 4; + return S_OK; // maybe we need to search backward. + } + + const size_t kBufSize = (size_t)1 << 18; // must be larger than kCheckSize + const size_t kCheckSize = (size_t)1 << 16; // must be smaller than kBufSize + CByteArr buffer(kBufSize); + + size_t numBytesInBuffer = 0; + UInt64 curScanPos = 0; - CByteDynamicBuffer dynamicBuffer; - const UInt32 kSearchMarkerBufferSize = 0x10000; - dynamicBuffer.EnsureCapacity(kSearchMarkerBufferSize); - Byte *buffer = dynamicBuffer; - UInt32 numBytesPrev = NSignature::kMarkerSize - 1; - memcpy(buffer, marker + 1, numBytesPrev); - UInt64 curTestPos = m_StreamStartPosition + 1; for (;;) { - if (searchHeaderSizeLimit != NULL) - if (curTestPos - m_StreamStartPosition > *searchHeaderSizeLimit) - break; - size_t numReadBytes = kSearchMarkerBufferSize - numBytesPrev; - RINOK(ReadStream(stream, buffer + numBytesPrev, &numReadBytes)); + size_t numReadBytes = kBufSize - numBytesInBuffer; + RINOK(ReadStream(stream, buffer + numBytesInBuffer, &numReadBytes)); m_Position += numReadBytes; - UInt32 numBytesInBuffer = numBytesPrev + (UInt32)numReadBytes; - const UInt32 kMarker2Size = NSignature::kMarkerSize + kNumMarkerAddtionalBytes; - if (numBytesInBuffer < kMarker2Size) + numBytesInBuffer += numReadBytes; + bool isFinished = (numBytesInBuffer != kBufSize); + + size_t limit = (isFinished ? numBytesInBuffer : numBytesInBuffer - kCheckSize); + + if (searchLimit && curScanPos + limit > *searchLimit) + limit = (size_t)(*searchLimit - curScanPos + 1); + + if (limit < 1) break; - UInt32 numTests = numBytesInBuffer - kMarker2Size + 1; - for (UInt32 pos = 0; pos < numTests; pos++) + + const Byte *buf = buffer; + for (size_t pos = 0; pos < limit; pos++) { - if (buffer[pos] != 0x50) + if (buf[pos] != 0x50) + continue; + if (buf[pos + 1] != 0x4B) continue; - if (TestMarkerCandidate2(buffer + pos, m_Signature)) + size_t rem = numBytesInBuffer - pos; + UInt32 res = IsArc_Zip_2(buf + pos, rem, isFinished); + if (res != k_IsArc_Res_NO) { - curTestPos += pos; - ArcInfo.StartPosition = curTestPos; - m_Position = curTestPos + NSignature::kMarkerSize; + if (rem < kMarkerSize) + return S_FALSE; + m_Signature = Get32(buf + pos); + ArcInfo.MarkerPos += curScanPos + pos; + ArcInfo.MarkerPos2 = ArcInfo.MarkerPos; + if (m_Signature == NSignature::kNoSpan) + { + m_Signature = Get32(buf + pos + 4); + ArcInfo.MarkerPos2 += 4; + } + m_Position = ArcInfo.MarkerPos2 + kMarkerSize; return S_OK; } } - curTestPos += numTests; - numBytesPrev = numBytesInBuffer - numTests; - memmove(buffer, buffer + numTests, numBytesPrev); + + if (isFinished) + break; + + curScanPos += limit; + numBytesInBuffer -= limit; + memmove(buffer, buffer + limit, numBytesInBuffer); } + return S_FALSE; } +HRESULT CInArchive::IncreaseRealPosition(UInt64 addValue) +{ + return Stream->Seek(addValue, STREAM_SEEK_CUR, &m_Position); +} + +class CUnexpectEnd {}; + HRESULT CInArchive::ReadBytes(void *data, UInt32 size, UInt32 *processedSize) { size_t realProcessedSize = size; @@ -121,42 +365,35 @@ HRESULT CInArchive::ReadBytes(void *data, UInt32 size, UInt32 *processedSize) catch (const CInBufferException &e) { return e.ErrorCode; } } else - result = ReadStream(m_Stream, data, &realProcessedSize); - if (processedSize != NULL) + result = ReadStream(Stream, data, &realProcessedSize); + if (processedSize) *processedSize = (UInt32)realProcessedSize; m_Position += realProcessedSize; return result; } -void CInArchive::Skip(UInt64 num) -{ - for (UInt64 i = 0; i < num; i++) - ReadByte(); -} - -void CInArchive::IncreaseRealPosition(UInt64 addValue) -{ - if (m_Stream->Seek(addValue, STREAM_SEEK_CUR, &m_Position) != S_OK) - throw CInArchiveException(CInArchiveException::kSeekStreamError); -} - -bool CInArchive::ReadBytesAndTestSize(void *data, UInt32 size) -{ - UInt32 realProcessedSize; - if (ReadBytes(data, size, &realProcessedSize) != S_OK) - throw CInArchiveException(CInArchiveException::kReadStreamError); - return (realProcessedSize == size); -} - -void CInArchive::SafeReadBytes(void *data, UInt32 size) +void CInArchive::SafeReadBytes(void *data, unsigned size) { - if (!ReadBytesAndTestSize(data, size)) - throw CInArchiveException(CInArchiveException::kUnexpectedEndOfArchive); + size_t processed = size; + if (_inBufMode) + { + processed = _inBuffer.ReadBytes((Byte *)data, size); + m_Position += processed; + } + else + { + HRESULT result = ReadStream(Stream, data, &processed); + m_Position += processed; + if (result != S_OK) + throw CSystemException(result); + } + if (processed != size) + throw CUnexpectEnd(); } -void CInArchive::ReadBuffer(CByteBuffer &buffer, UInt32 size) +void CInArchive::ReadBuffer(CByteBuffer &buffer, unsigned size) { - buffer.SetCapacity(size); + buffer.Alloc(size); if (size > 0) SafeReadBytes(buffer, size); } @@ -168,65 +405,73 @@ Byte CInArchive::ReadByte() return b; } -UInt16 CInArchive::ReadUInt16() -{ - Byte buf[2]; - SafeReadBytes(buf, 2); - return Get16(buf); -} +UInt16 CInArchive::ReadUInt16() { Byte buf[2]; SafeReadBytes(buf, 2); return Get16(buf); } +UInt32 CInArchive::ReadUInt32() { Byte buf[4]; SafeReadBytes(buf, 4); return Get32(buf); } +UInt64 CInArchive::ReadUInt64() { Byte buf[8]; SafeReadBytes(buf, 8); return Get64(buf); } -UInt32 CInArchive::ReadUInt32() +void CInArchive::Skip(unsigned num) { - Byte buf[4]; - SafeReadBytes(buf, 4); - return Get32(buf); + if (_inBufMode) + { + size_t skip = _inBuffer.Skip(num); + m_Position += skip; + if (skip != num) + throw CUnexpectEnd(); + } + else + { + for (unsigned i = 0; i < num; i++) + ReadByte(); + } } -UInt64 CInArchive::ReadUInt64() +void CInArchive::Skip64(UInt64 num) { - Byte buf[8]; - SafeReadBytes(buf, 8); - return Get64(buf); + for (UInt64 i = 0; i < num; i++) + ReadByte(); } -bool CInArchive::ReadUInt32(UInt32 &value) -{ - Byte buf[4]; - if (!ReadBytesAndTestSize(buf, 4)) - return false; - value = Get32(buf); - return true; -} -void CInArchive::ReadFileName(UInt32 nameSize, AString &dest) +void CInArchive::ReadFileName(unsigned size, AString &s) { - if (nameSize == 0) - dest.Empty(); - char *p = dest.GetBuffer((int)nameSize); - SafeReadBytes(p, nameSize); - p[nameSize] = 0; - dest.ReleaseBuffer(); + if (size == 0) + { + s.Empty(); + return; + } + char *p = s.GetBuffer(size); + SafeReadBytes(p, size); + p[size] = 0; + s.ReleaseBuffer(); } -void CInArchive::ReadExtra(UInt32 extraSize, CExtraBlock &extraBlock, +bool CInArchive::ReadExtra(unsigned extraSize, CExtraBlock &extraBlock, UInt64 &unpackSize, UInt64 &packSize, UInt64 &localHeaderOffset, UInt32 &diskStartNumber) { extraBlock.Clear(); UInt32 remain = extraSize; - while(remain >= 4) + while (remain >= 4) { CExtraSubBlock subBlock; subBlock.ID = ReadUInt16(); - UInt32 dataSize = ReadUInt16(); + unsigned dataSize = ReadUInt16(); remain -= 4; if (dataSize > remain) // it's bug - dataSize = remain; + { + HeadersWarning = true; + Skip(remain); + return false; + } if (subBlock.ID == NFileHeader::NExtraID::kZip64) { if (unpackSize == 0xFFFFFFFF) { if (dataSize < 8) - break; + { + HeadersWarning = true; + Skip(remain); + return false; + } unpackSize = ReadUInt64(); remain -= 8; dataSize -= 8; @@ -255,8 +500,7 @@ void CInArchive::ReadExtra(UInt32 extraSize, CExtraBlock &extraBlock, remain -= 4; dataSize -= 4; } - for (UInt32 i = 0; i < dataSize; i++) - ReadByte(); + Skip(dataSize); } else { @@ -265,88 +509,125 @@ void CInArchive::ReadExtra(UInt32 extraSize, CExtraBlock &extraBlock, } remain -= dataSize; } + if (remain != 0) + { + ExtraMinorError = true; + // 7-Zip before 9.31 created incorrect WsAES Extra in folder's local headers. + // so we don't return false, but just set warning flag + // return false; + } Skip(remain); + return true; } -HRESULT CInArchive::ReadLocalItem(CItemEx &item) +bool CInArchive::ReadLocalItem(CItemEx &item) { - const int kBufSize = 26; - Byte p[kBufSize]; - SafeReadBytes(p, kBufSize); + const unsigned kPureHeaderSize = kLocalHeaderSize - 4; + Byte p[kPureHeaderSize]; + SafeReadBytes(p, kPureHeaderSize); + { + unsigned i; + for (i = 0; i < kPureHeaderSize && p[i] == 0; i++); + if (i == kPureHeaderSize) + return false; + } item.ExtractVersion.Version = p[0]; item.ExtractVersion.HostOS = p[1]; item.Flags = Get16(p + 2); - item.CompressionMethod = Get16(p + 4); + item.Method = Get16(p + 4); item.Time = Get32(p + 6); - item.FileCRC = Get32(p + 10); + item.Crc = Get32(p + 10); item.PackSize = Get32(p + 14); - item.UnPackSize = Get32(p + 18); - UInt32 fileNameSize = Get16(p + 22); - item.LocalExtraSize = Get16(p + 24); - ReadFileName(fileNameSize, item.Name); - item.FileHeaderWithNameSize = 4 + NFileHeader::kLocalBlockSize + fileNameSize; - if (item.LocalExtraSize > 0) + item.Size = Get32(p + 18); + unsigned nameSize = Get16(p + 22); + unsigned extraSize = Get16(p + 24); + ReadFileName(nameSize, item.Name); + item.LocalFullHeaderSize = kLocalHeaderSize + (UInt32)nameSize + extraSize; + + /* + if (item.IsDir()) + item.Size = 0; // check It + */ + + if (extraSize > 0) { UInt64 localHeaderOffset = 0; UInt32 diskStartNumber = 0; - ReadExtra(item.LocalExtraSize, item.LocalExtra, item.UnPackSize, item.PackSize, - localHeaderOffset, diskStartNumber); + if (!ReadExtra(extraSize, item.LocalExtra, item.Size, item.PackSize, + localHeaderOffset, diskStartNumber)) + return false; } - /* - if (item.IsDir()) - item.UnPackSize = 0; // check It - */ - return S_OK; + if (!CheckDosTime(item.Time)) + { + HeadersWarning = true; + // return false; + } + if (item.Name.Len() != nameSize) + return false; + return item.LocalFullHeaderSize <= ((UInt32)1 << 16); } -static bool FlagsAreSame(CItem &i1, CItem &i2) +static bool FlagsAreSame(const CItem &i1, const CItem &i2) { - if (i1.CompressionMethod != i2.CompressionMethod) + if (i1.Method != i2.Method) return false; - // i1.Time - if (i1.Flags == i2.Flags) return true; UInt32 mask = 0xFFFF; - switch(i1.CompressionMethod) + switch(i1.Method) { case NFileHeader::NCompressionMethod::kDeflated: mask = 0x7FF9; break; default: - if (i1.CompressionMethod <= NFileHeader::NCompressionMethod::kImploded) + if (i1.Method <= NFileHeader::NCompressionMethod::kImploded) mask = 0x7FFF; } return ((i1.Flags & mask) == (i2.Flags & mask)); } +static bool AreItemsEqual(const CItemEx &localItem, const CItemEx &cdItem) +{ + if (!FlagsAreSame(cdItem, localItem)) + return false; + if (!localItem.HasDescriptor()) + { + if (cdItem.Crc != localItem.Crc || + cdItem.PackSize != localItem.PackSize || + cdItem.Size != localItem.Size) + return false; + } + /* pkzip 2.50 creates incorrect archives. It uses + - WIN encoding for name in local header + - OEM encoding for name in central header + We don't support these strange items. */ + + /* if (cdItem.Name.Len() != localItem.Name.Len()) + return false; + */ + if (cdItem.Name != localItem.Name) + return false; + return true; +} + HRESULT CInArchive::ReadLocalItemAfterCdItem(CItemEx &item) { if (item.FromLocal) return S_OK; try { - RINOK(Seek(ArcInfo.Base + item.LocalHeaderPosition)); + UInt64 offset = ArcInfo.Base + item.LocalHeaderPos; + if (ArcInfo.Base < 0 && (Int64)offset < 0) + return S_FALSE; + RINOK(Seek(offset)); CItemEx localItem; if (ReadUInt32() != NSignature::kLocalFileHeader) return S_FALSE; - RINOK(ReadLocalItem(localItem)); - if (!FlagsAreSame(item, localItem)) + ReadLocalItem(localItem); + if (!AreItemsEqual(localItem, item)) return S_FALSE; - - if ((!localItem.HasDescriptor() && - ( - item.FileCRC != localItem.FileCRC || - item.PackSize != localItem.PackSize || - item.UnPackSize != localItem.UnPackSize - ) - ) || - item.Name.Length() != localItem.Name.Length() - ) - return S_FALSE; - item.FileHeaderWithNameSize = localItem.FileHeaderWithNameSize; - item.LocalExtraSize = localItem.LocalExtraSize; + item.LocalFullHeaderSize = localItem.LocalFullHeaderSize; item.LocalExtra = localItem.LocalExtra; item.FromLocal = true; } @@ -356,53 +637,45 @@ HRESULT CInArchive::ReadLocalItemAfterCdItem(CItemEx &item) HRESULT CInArchive::ReadLocalItemDescriptor(CItemEx &item) { - if (item.HasDescriptor()) + const unsigned kBufSize = (1 << 12); + Byte buf[kBufSize]; + + UInt32 numBytesInBuffer = 0; + UInt32 packedSize = 0; + + for (;;) { - const int kBufferSize = (1 << 12); - Byte buffer[kBufferSize]; - - UInt32 numBytesInBuffer = 0; - UInt32 packedSize = 0; - - bool descriptorWasFound = false; - for (;;) + UInt32 processedSize; + RINOK(ReadBytes(buf + numBytesInBuffer, kBufSize - numBytesInBuffer, &processedSize)); + numBytesInBuffer += processedSize; + if (numBytesInBuffer < kDataDescriptorSize) + return S_FALSE; + UInt32 i; + for (i = 0; i <= numBytesInBuffer - kDataDescriptorSize; i++) { - UInt32 processedSize; - RINOK(ReadBytes(buffer + numBytesInBuffer, kBufferSize - numBytesInBuffer, &processedSize)); - numBytesInBuffer += processedSize; - if (numBytesInBuffer < NFileHeader::kDataDescriptorSize) - return S_FALSE; - UInt32 i; - for (i = 0; i <= numBytesInBuffer - NFileHeader::kDataDescriptorSize; i++) + // descriptor signature field is Info-ZIP's extension to pkware Zip specification. + // New ZIP specification also allows descriptorSignature. + if (buf[i] != 0x50) + continue; + // !!!! It must be fixed for Zip64 archives + if (Get32(buf + i) == NSignature::kDataDescriptor) { - // descriptorSignature field is Info-ZIP's extension - // to Zip specification. - UInt32 descriptorSignature = Get32(buffer + i); - - // !!!! It must be fixed for Zip64 archives - UInt32 descriptorPackSize = Get32(buffer + i + 8); - if (descriptorSignature== NSignature::kDataDescriptor && descriptorPackSize == packedSize + i) + UInt32 descriptorPackSize = Get32(buf + i + 8); + if (descriptorPackSize == packedSize + i) { - descriptorWasFound = true; - item.FileCRC = Get32(buffer + i + 4); + item.Crc = Get32(buf + i + 4); item.PackSize = descriptorPackSize; - item.UnPackSize = Get32(buffer + i + 12); - IncreaseRealPosition(Int64(Int32(0 - (numBytesInBuffer - i - NFileHeader::kDataDescriptorSize)))); - break; + item.Size = Get32(buf + i + 12); + return IncreaseRealPosition(Int64(Int32(0 - (numBytesInBuffer - i - kDataDescriptorSize)))); } } - if (descriptorWasFound) - break; - packedSize += i; - int j; - for (j = 0; i < numBytesInBuffer; i++, j++) - buffer[j] = buffer[i]; - numBytesInBuffer = j; } + packedSize += i; + unsigned j; + for (j = 0; i < numBytesInBuffer; i++, j++) + buf[j] = buf[i]; + numBytesInBuffer = j; } - else - IncreaseRealPosition(item.PackSize); - return S_OK; } HRESULT CInArchive::ReadLocalItemAfterCdItemFull(CItemEx &item) @@ -433,7 +706,7 @@ HRESULT CInArchive::ReadLocalItemAfterCdItemFull(CItemEx &item) unpackSize = ReadUInt32(); } - if (crc != item.FileCRC || item.PackSize != packSize || item.UnPackSize != unpackSize) + if (crc != item.Crc || item.PackSize != packSize || item.Size != unpackSize) return S_FALSE; } } @@ -444,106 +717,161 @@ HRESULT CInArchive::ReadLocalItemAfterCdItemFull(CItemEx &item) HRESULT CInArchive::ReadCdItem(CItemEx &item) { item.FromCentral = true; - const int kBufSize = 42; - Byte p[kBufSize]; - SafeReadBytes(p, kBufSize); + Byte p[kCentralHeaderSize - 4]; + SafeReadBytes(p, kCentralHeaderSize - 4); + item.MadeByVersion.Version = p[0]; item.MadeByVersion.HostOS = p[1]; item.ExtractVersion.Version = p[2]; item.ExtractVersion.HostOS = p[3]; item.Flags = Get16(p + 4); - item.CompressionMethod = Get16(p + 6); + item.Method = Get16(p + 6); item.Time = Get32(p + 8); - item.FileCRC = Get32(p + 12); + item.Crc = Get32(p + 12); item.PackSize = Get32(p + 16); - item.UnPackSize = Get32(p + 20); - UInt16 headerNameSize = Get16(p + 24); - UInt16 headerExtraSize = Get16(p + 26); - UInt16 headerCommentSize = Get16(p + 28); - UInt32 headerDiskNumberStart = Get16(p + 30); - item.InternalAttributes = Get16(p + 32); - item.ExternalAttributes = Get32(p + 34); - item.LocalHeaderPosition = Get32(p + 38); - ReadFileName(headerNameSize, item.Name); + item.Size = Get32(p + 20); + unsigned nameSize = Get16(p + 24); + UInt16 extraSize = Get16(p + 26); + UInt16 commentSize = Get16(p + 28); + UInt32 diskNumberStart = Get16(p + 30); + item.InternalAttrib = Get16(p + 32); + item.ExternalAttrib = Get32(p + 34); + item.LocalHeaderPos = Get32(p + 38); + ReadFileName(nameSize, item.Name); - if (headerExtraSize > 0) + if (extraSize > 0) { - ReadExtra(headerExtraSize, item.CentralExtra, item.UnPackSize, item.PackSize, - item.LocalHeaderPosition, headerDiskNumberStart); + ReadExtra(extraSize, item.CentralExtra, item.Size, item.PackSize, + item.LocalHeaderPos, diskNumberStart); } - if (headerDiskNumberStart != 0) - throw CInArchiveException(CInArchiveException::kMultiVolumeArchiveAreNotSupported); + if (diskNumberStart != 0) + return E_NOTIMPL; // May be these strings must be deleted /* if (item.IsDir()) - item.UnPackSize = 0; + item.Size = 0; */ - ReadBuffer(item.Comment, headerCommentSize); + ReadBuffer(item.Comment, commentSize); return S_OK; } +void CCdInfo::ParseEcd(const Byte *p) +{ + NumEntries = Get16(p + 10); + Size = Get32(p + 12); + Offset = Get32(p + 16); +} + +void CCdInfo::ParseEcd64(const Byte *p) +{ + NumEntries = Get64(p + 24); + Size = Get64(p + 40); + Offset = Get64(p + 48); +} + HRESULT CInArchive::TryEcd64(UInt64 offset, CCdInfo &cdInfo) { + if (offset >= ((UInt64)1 << 63)) + return S_FALSE; RINOK(Seek(offset)); - const UInt32 kEcd64Size = 56; - Byte buf[kEcd64Size]; - if (!ReadBytesAndTestSize(buf, kEcd64Size)) + Byte buf[kEcd64_FullSize]; + + RINOK(ReadStream_FALSE(Stream, buf, kEcd64_FullSize)); + + if (Get32(buf) != NSignature::kEcd64) return S_FALSE; - if (Get32(buf) != NSignature::kZip64EndOfCentralDir) + UInt64 mainSize = Get64(buf + 4); + if (mainSize < kEcd64_MainSize || mainSize > ((UInt64)1 << 32)) return S_FALSE; - // cdInfo.NumEntries = Get64(buf + 24); - cdInfo.Size = Get64(buf + 40); - cdInfo.Offset = Get64(buf + 48); + cdInfo.ParseEcd64(buf); return S_OK; } HRESULT CInArchive::FindCd(CCdInfo &cdInfo) { UInt64 endPosition; - RINOK(m_Stream->Seek(0, STREAM_SEEK_END, &endPosition)); - const UInt32 kBufSizeMax = (1 << 16) + kEcdSize + kZip64EcdLocatorSize; - CByteBuffer byteBuffer; - byteBuffer.SetCapacity(kBufSizeMax); - Byte *buf = byteBuffer; + RINOK(Stream->Seek(0, STREAM_SEEK_END, &endPosition)); + + const UInt32 kBufSizeMax = ((UInt32)1 << 16) + kEcdSize + kEcd64Locator_Size + kEcd64_FullSize; UInt32 bufSize = (endPosition < kBufSizeMax) ? (UInt32)endPosition : kBufSizeMax; if (bufSize < kEcdSize) return S_FALSE; + CByteArr byteBuffer(bufSize); + UInt64 startPosition = endPosition - bufSize; - RINOK(m_Stream->Seek(startPosition, STREAM_SEEK_SET, &m_Position)); + RINOK(Stream->Seek(startPosition, STREAM_SEEK_SET, &m_Position)); if (m_Position != startPosition) return S_FALSE; - if (!ReadBytesAndTestSize(buf, bufSize)) - return S_FALSE; - for (int i = (int)(bufSize - kEcdSize); i >= 0; i--) + + RINOK(ReadStream_FALSE(Stream, byteBuffer, bufSize)); + + const Byte *buf = byteBuffer; + for (UInt32 i = bufSize - kEcdSize;; i--) { - if (Get32(buf + i) == NSignature::kEndOfCentralDir) + if (buf[i] != 0x50) { - if (i >= kZip64EcdLocatorSize) + if (i == 0) return S_FALSE; + i--; + if (buf[i] != 0x50) { - const Byte *locator = buf + i - kZip64EcdLocatorSize; - if (Get32(locator) == NSignature::kZip64EndOfCentralDirLocator) + if (i == 0) return S_FALSE; + continue; + } + } + if (Get32(buf + i) == NSignature::kEcd) + { + if (i >= kEcd64_FullSize + kEcd64Locator_Size) + { + const Byte *locator = buf + i - kEcd64Locator_Size; + if (Get32(locator) == NSignature::kEcd64Locator && + Get32(locator + 4) == 0) // number of the disk with the start of the zip64 ECD { + // Most of the zip64 use fixed size Zip64 ECD + UInt64 ecd64Offset = Get64(locator + 8); - if (TryEcd64(ecd64Offset, cdInfo) == S_OK) - return S_OK; - if (TryEcd64(ArcInfo.StartPosition + ecd64Offset, cdInfo) == S_OK) + UInt64 absEcd64 = endPosition - bufSize + i - (kEcd64Locator_Size + kEcd64_FullSize); + { + const Byte *ecd64 = locator - kEcd64_FullSize; + if (Get32(ecd64) == NSignature::kEcd64 && + Get64(ecd64 + 4) == kEcd64_MainSize) + { + cdInfo.ParseEcd64(ecd64); + ArcInfo.Base = absEcd64 - ecd64Offset; + return S_OK; + } + } + + // some zip64 use variable size Zip64 ECD. + // we try to find it + if (absEcd64 != ecd64Offset) + { + if (TryEcd64(ecd64Offset, cdInfo) == S_OK) + { + ArcInfo.Base = 0; + return S_OK; + } + } + if (ArcInfo.MarkerPos != 0 && + ArcInfo.MarkerPos + ecd64Offset != absEcd64) { - ArcInfo.Base = ArcInfo.StartPosition; - return S_OK; + if (TryEcd64(ArcInfo.MarkerPos + ecd64Offset, cdInfo) == S_OK) + { + ArcInfo.Base = ArcInfo.MarkerPos; + return S_OK; + } } } } - if (Get32(buf + i + 4) == 0) + if (Get32(buf + i + 4) == 0) // ThisDiskNumber, StartCentralDirectoryDiskNumber; { - // cdInfo.NumEntries = GetUInt16(buf + i + 10); - cdInfo.Size = Get32(buf + i + 12); - cdInfo.Offset = Get32(buf + i + 16); - UInt64 curPos = endPosition - bufSize + i; + cdInfo.ParseEcd(buf + i); + UInt64 absEcdPos = endPosition - bufSize + i; UInt64 cdEnd = cdInfo.Size + cdInfo.Offset; - if (curPos != cdEnd) + ArcInfo.Base = 0; + if (absEcdPos != cdEnd) { /* if (cdInfo.Offset <= 16 && cdInfo.Size != 0) @@ -553,290 +881,301 @@ HRESULT CInArchive::FindCd(CCdInfo &cdInfo) } else */ - ArcInfo.Base = curPos - cdEnd; + ArcInfo.Base = absEcdPos - cdEnd; } return S_OK; } } + if (i == 0) + return S_FALSE; } - return S_FALSE; } + HRESULT CInArchive::TryReadCd(CObjectVector &items, UInt64 cdOffset, UInt64 cdSize, CProgressVirt *progress) { items.Clear(); - RINOK(m_Stream->Seek(cdOffset, STREAM_SEEK_SET, &m_Position)); + RINOK(Stream->Seek(cdOffset, STREAM_SEEK_SET, &m_Position)); if (m_Position != cdOffset) return S_FALSE; - if (!_inBuffer.Create(1 << 15)) - return E_OUTOFMEMORY; - _inBuffer.SetStream(m_Stream); _inBuffer.Init(); _inBufMode = true; - while(m_Position - cdOffset < cdSize) + while (m_Position - cdOffset < cdSize) { if (ReadUInt32() != NSignature::kCentralFileHeader) return S_FALSE; CItemEx cdItem; RINOK(ReadCdItem(cdItem)); items.Add(cdItem); - if (progress && items.Size() % 1000 == 0) - RINOK(progress->SetCompleted(items.Size())); + if (progress && items.Size() % 1 == 0) + RINOK(progress->SetCompletedCD(items.Size())); } return (m_Position - cdOffset == cdSize) ? S_OK : S_FALSE; } HRESULT CInArchive::ReadCd(CObjectVector &items, UInt64 &cdOffset, UInt64 &cdSize, CProgressVirt *progress) { - ArcInfo.Base = 0; CCdInfo cdInfo; RINOK(FindCd(cdInfo)); HRESULT res = S_FALSE; cdSize = cdInfo.Size; cdOffset = cdInfo.Offset; + if (progress) + progress->SetTotalCD(cdInfo.NumEntries); res = TryReadCd(items, ArcInfo.Base + cdOffset, cdSize, progress); if (res == S_FALSE && ArcInfo.Base == 0) { - res = TryReadCd(items, cdInfo.Offset + ArcInfo.StartPosition, cdSize, progress); + res = TryReadCd(items, ArcInfo.MarkerPos + cdOffset, cdSize, progress); if (res == S_OK) - ArcInfo.Base = ArcInfo.StartPosition; + ArcInfo.Base = ArcInfo.MarkerPos; } - if (!ReadUInt32(m_Signature)) - return S_FALSE; return res; } -HRESULT CInArchive::ReadLocalsAndCd(CObjectVector &items, CProgressVirt *progress, UInt64 &cdOffset, int &numCdItems) +static HRESULT FindItem(const CObjectVector &items, UInt64 offset) { - items.Clear(); - numCdItems = 0; - while (m_Signature == NSignature::kLocalFileHeader) + unsigned left = 0, right = items.Size(); + for (;;) { - // FSeek points to next byte after signature - // NFileHeader::CLocalBlock localHeader; - CItemEx item; - item.LocalHeaderPosition = m_Position - m_StreamStartPosition - 4; // points to signature; - RINOK(ReadLocalItem(item)); - item.FromLocal = true; - ReadLocalItemDescriptor(item); - items.Add(item); - if (progress && items.Size() % 100 == 0) - RINOK(progress->SetCompleted(items.Size())); - if (!ReadUInt32(m_Signature)) - break; + if (left >= right) + return -1; + unsigned index = (left + right) / 2; + UInt64 position = items[index].LocalHeaderPos; + if (offset == position) + return index; + if (offset < position) + right = index; + else + left = index + 1; } - cdOffset = m_Position - 4; - int i; - for (i = 0; i < items.Size(); i++, numCdItems++) - { - if (progress && i % 1000 == 0) - RINOK(progress->SetCompleted(items.Size())); - if (m_Signature == NSignature::kEndOfCentralDir) - break; - - if (m_Signature != NSignature::kCentralFileHeader) - return S_FALSE; +} - CItemEx cdItem; - RINOK(ReadCdItem(cdItem)); +bool IsStrangeItem(const CItem &item) +{ + return item.Name.Len() > (1 << 14) || item.Method > (1 << 8); +} - if (i == 0) +HRESULT CInArchive::ReadLocals( + CObjectVector &items, CProgressVirt *progress) +{ + items.Clear(); + while (m_Signature == NSignature::kLocalFileHeader) + { + CItemEx item; + item.LocalHeaderPos = m_Position - 4 - ArcInfo.MarkerPos; + // we write ralative LocalHeaderPos here. Later we can correct it to real Base. + try { - int j; - for (j = 0; j < items.Size(); j++) + ReadLocalItem(item); + item.FromLocal = true; + if (item.HasDescriptor()) + ReadLocalItemDescriptor(item); + else { - CItemEx &item = items[j]; - if (item.Name == cdItem.Name) - { - ArcInfo.Base = item.LocalHeaderPosition - cdItem.LocalHeaderPosition; - break; - } + RINOK(IncreaseRealPosition(item.PackSize)); } - if (j == items.Size()) - return S_FALSE; + items.Add(item); + m_Signature = ReadUInt32(); } - - int index; - int left = 0, right = items.Size(); - for (;;) + catch (CUnexpectEnd &) { - if (left >= right) + if (items.IsEmpty() || items.Size() == 1 && IsStrangeItem(items[0])) return S_FALSE; - index = (left + right) / 2; - UInt64 position = items[index].LocalHeaderPosition - ArcInfo.Base; - if (cdItem.LocalHeaderPosition == position) - break; - if (cdItem.LocalHeaderPosition < position) - right = index; - else - left = index + 1; + throw; } - CItemEx &item = items[index]; - // item.LocalHeaderPosition = cdItem.LocalHeaderPosition; - item.MadeByVersion = cdItem.MadeByVersion; - item.CentralExtra = cdItem.CentralExtra; - - if ( - // item.ExtractVersion != cdItem.ExtractVersion || - !FlagsAreSame(item, cdItem) || - item.FileCRC != cdItem.FileCRC) - return S_FALSE; + if (progress && items.Size() % 1 == 0) + RINOK(progress->SetCompletedLocal(items.Size(), item.LocalHeaderPos)); + } - if (item.Name.Length() != cdItem.Name.Length() || - item.PackSize != cdItem.PackSize || - item.UnPackSize != cdItem.UnPackSize - ) - return S_FALSE; - item.Name = cdItem.Name; - item.InternalAttributes = cdItem.InternalAttributes; - item.ExternalAttributes = cdItem.ExternalAttributes; - item.Comment = cdItem.Comment; - item.FromCentral = cdItem.FromCentral; - if (!ReadUInt32(m_Signature)) + if (items.Size() == 1 && m_Signature != NSignature::kCentralFileHeader) + if (IsStrangeItem(items[0])) return S_FALSE; - } - for (i = 0; i < items.Size(); i++) - items[i].LocalHeaderPosition -= ArcInfo.Base; return S_OK; } -struct CEcd -{ - UInt16 thisDiskNumber; - UInt16 startCDDiskNumber; - UInt16 numEntriesInCDOnThisDisk; - UInt16 numEntriesInCD; - UInt32 cdSize; - UInt32 cdStartOffset; - UInt16 commentSize; - void Parse(const Byte *p); -}; - -void CEcd::Parse(const Byte *p) -{ - thisDiskNumber = Get16(p); - startCDDiskNumber = Get16(p + 2); - numEntriesInCDOnThisDisk = Get16(p + 4); - numEntriesInCD = Get16(p + 6); - cdSize = Get32(p + 8); - cdStartOffset = Get32(p + 12); - commentSize = Get16(p + 16); -} - -struct CEcd64 -{ - UInt16 versionMade; - UInt16 versionNeedExtract; - UInt32 thisDiskNumber; - UInt32 startCDDiskNumber; - UInt64 numEntriesInCDOnThisDisk; - UInt64 numEntriesInCD; - UInt64 cdSize; - UInt64 cdStartOffset; - void Parse(const Byte *p); - CEcd64() { memset(this, 0, sizeof(*this)); } -}; - -void CEcd64::Parse(const Byte *p) -{ - versionMade = Get16(p); - versionNeedExtract = Get16(p + 2); - thisDiskNumber = Get32(p + 4); - startCDDiskNumber = Get32(p + 8); - numEntriesInCDOnThisDisk = Get64(p + 12); - numEntriesInCD = Get64(p + 20); - cdSize = Get64(p + 28); - cdStartOffset = Get64(p + 36); -} #define COPY_ECD_ITEM_16(n) if (!isZip64 || ecd. n != 0xFFFF) ecd64. n = ecd. n; #define COPY_ECD_ITEM_32(n) if (!isZip64 || ecd. n != 0xFFFFFFFF) ecd64. n = ecd. n; -HRESULT CInArchive::ReadHeaders(CObjectVector &items, CProgressVirt *progress) +HRESULT CInArchive::ReadHeaders2(CObjectVector &items, CProgressVirt *progress) { - IsOkHeaders = true; - // m_Signature must be kLocalFileHeaderSignature or - // kEndOfCentralDirSignature + items.Clear(); + + // m_Signature must be kLocalFileHeader or kEcd // m_Position points to next byte after signature + RINOK(Stream->Seek(m_Position, STREAM_SEEK_SET, NULL)); - IsZip64 = false; - items.Clear(); + if (!_inBuffer.Create(1 << 15)) + return E_OUTOFMEMORY; + _inBuffer.SetStream(Stream); - UInt64 cdSize, cdStartOffset; - HRESULT res; - try + bool needReadCd = true; + bool localsWereRead = false; + if (m_Signature == NSignature::kEcd) { - res = ReadCd(items, cdStartOffset, cdSize, progress); + // It must be empty archive or backware archive + // we don't support backware archive still + + const unsigned kBufSize = kEcdSize - 4; + Byte buf[kBufSize]; + SafeReadBytes(buf, kBufSize); + CEcd ecd; + ecd.Parse(buf); + // if (ecd.cdSize != 0) + // Do we need also to support the case where empty zip archive with PK00 uses cdOffset = 4 ?? + if (!ecd.IsEmptyArc()) + return S_FALSE; + + ArcInfo.Base = ArcInfo.MarkerPos; + needReadCd = false; + IsArc = true; // check it: we need more tests? + RINOK(Stream->Seek(ArcInfo.MarkerPos2 + 4, STREAM_SEEK_SET, &m_Position)); } - catch(CInArchiveException &) + + UInt64 cdSize = 0, cdRelatOffset = 0, cdAbsOffset = 0; + HRESULT res = S_OK; + + if (needReadCd) { - res = S_FALSE; + CItemEx firstItem; + // try + { + try + { + if (!ReadLocalItem(firstItem)) + return S_FALSE; + } + catch(CUnexpectEnd &) + { + return S_FALSE; + } + + IsArc = true; + res = ReadCd(items, cdRelatOffset, cdSize, progress); + if (res == S_OK) + m_Signature = ReadUInt32(); + } + // catch() { res = S_FALSE; } + if (res != S_FALSE && res != S_OK) + return res; + + if (res == S_OK && items.Size() == 0) + res = S_FALSE; + + if (res == S_OK) + { + // we can't read local items here to keep _inBufMode state + firstItem.LocalHeaderPos = ArcInfo.MarkerPos2 - ArcInfo.Base; + int index = FindItem(items, firstItem.LocalHeaderPos); + if (index == -1) + res = S_FALSE; + else if (!AreItemsEqual(firstItem, items[index])) + res = S_FALSE; + ArcInfo.CdWasRead = true; + ArcInfo.FirstItemRelatOffset = items[0].LocalHeaderPos; + } } - if (res != S_FALSE && res != S_OK) - return res; - /* - if (res != S_OK) - return res; - res = S_FALSE; - */ + CObjectVector cdItems; - int numCdItems = items.Size(); + bool needSetBase = false; + unsigned numCdItems = items.Size(); + if (res == S_FALSE) { + // CD doesn't match firstItem so we clear items and read Locals. + items.Clear(); + localsWereRead = true; _inBufMode = false; - ArcInfo.Base = 0; - RINOK(m_Stream->Seek(ArcInfo.StartPosition, STREAM_SEEK_SET, &m_Position)); - if (m_Position != ArcInfo.StartPosition) - return S_FALSE; - if (!ReadUInt32(m_Signature)) - return S_FALSE; - RINOK(ReadLocalsAndCd(items, progress, cdStartOffset, numCdItems)); - cdSize = (m_Position - 4) - cdStartOffset; - cdStartOffset -= ArcInfo.Base; + ArcInfo.Base = ArcInfo.MarkerPos; + RINOK(Stream->Seek(ArcInfo.MarkerPos2, STREAM_SEEK_SET, &m_Position)); + m_Signature = ReadUInt32(); + + RINOK(ReadLocals(items, progress)); + + if (m_Signature != NSignature::kCentralFileHeader) + { + m_Position -= 4; + NoCentralDir = true; + HeadersError = true; + return S_OK; + } + _inBufMode = true; + _inBuffer.Init(); + cdAbsOffset = m_Position - 4; + for (;;) + { + CItemEx cdItem; + RINOK(ReadCdItem(cdItem)); + cdItems.Add(cdItem); + if (progress && cdItems.Size() % 1 == 0) + RINOK(progress->SetCompletedCD(items.Size())); + m_Signature = ReadUInt32(); + if (m_Signature != NSignature::kCentralFileHeader) + break; + } + + cdSize = (m_Position - 4) - cdAbsOffset; + needSetBase = true; + numCdItems = cdItems.Size(); + + if (!cdItems.IsEmpty()) + { + ArcInfo.CdWasRead = true; + ArcInfo.FirstItemRelatOffset = cdItems[0].LocalHeaderPos; + } } CEcd64 ecd64; bool isZip64 = false; - UInt64 zip64EcdStartOffset = m_Position - 4 - ArcInfo.Base; - if (m_Signature == NSignature::kZip64EndOfCentralDir) + UInt64 ecd64AbsOffset = m_Position - 4; + if (m_Signature == NSignature::kEcd64) { IsZip64 = isZip64 = true; UInt64 recordSize = ReadUInt64(); - const int kBufSize = kZip64EcdSize; + const unsigned kBufSize = kEcd64_MainSize; Byte buf[kBufSize]; SafeReadBytes(buf, kBufSize); ecd64.Parse(buf); - Skip(recordSize - kZip64EcdSize); - if (!ReadUInt32(m_Signature)) - return S_FALSE; + Skip64(recordSize - kEcd64_MainSize); + m_Signature = ReadUInt32(); + if (ecd64.thisDiskNumber != 0 || ecd64.startCDDiskNumber != 0) - throw CInArchiveException(CInArchiveException::kMultiVolumeArchiveAreNotSupported); + return E_NOTIMPL; + + if (needSetBase) + { + ArcInfo.Base = cdAbsOffset - ecd64.cdStartOffset; + cdRelatOffset = ecd64.cdStartOffset; + needSetBase = false; + } + if (ecd64.numEntriesInCDOnThisDisk != numCdItems || ecd64.numEntriesInCD != numCdItems || ecd64.cdSize != cdSize || - (ecd64.cdStartOffset != cdStartOffset && + (ecd64.cdStartOffset != cdRelatOffset && (!items.IsEmpty()))) return S_FALSE; } - if (m_Signature == NSignature::kZip64EndOfCentralDirLocator) + if (m_Signature == NSignature::kEcd64Locator) { + if (!isZip64) + return S_FALSE; /* UInt32 startEndCDDiskNumber = */ ReadUInt32(); - UInt64 endCDStartOffset = ReadUInt64(); + UInt64 ecd64RelatOffset = ReadUInt64(); /* UInt32 numberOfDisks = */ ReadUInt32(); - if (zip64EcdStartOffset != endCDStartOffset) - return S_FALSE; - if (!ReadUInt32(m_Signature)) + if (ecd64AbsOffset != ArcInfo.Base + ecd64RelatOffset) return S_FALSE; + m_Signature = ReadUInt32(); } - if (m_Signature != NSignature::kEndOfCentralDir) + if (m_Signature != NSignature::kEcd) return S_FALSE; - const int kBufSize = kEcdSize - 4; + const unsigned kBufSize = kEcdSize - 4; Byte buf[kBufSize]; SafeReadBytes(buf, kBufSize); CEcd ecd; @@ -849,47 +1188,119 @@ HRESULT CInArchive::ReadHeaders(CObjectVector &items, CProgressVirt *pr COPY_ECD_ITEM_32(cdSize); COPY_ECD_ITEM_32(cdStartOffset); - ReadBuffer(ArcInfo.Comment, ecd.commentSize); + if (needSetBase) + { + ArcInfo.Base = cdAbsOffset - ecd64.cdStartOffset; + cdRelatOffset = ecd64.cdStartOffset; + needSetBase = false; + } + + if (localsWereRead && (UInt64)ArcInfo.Base != ArcInfo.MarkerPos) + { + UInt64 delta = ArcInfo.MarkerPos - ArcInfo.Base; + for (unsigned i = 0; i < items.Size(); i++) + items[i].LocalHeaderPos += delta; + } + + + // ---------- merge Central Directory Items ---------- + + if (!cdItems.IsEmpty()) + { + for (unsigned i = 0; i < cdItems.Size(); i++) + { + const CItemEx &cdItem = cdItems[i]; + int index = FindItem(items, cdItem.LocalHeaderPos); + if (index == -1) + { + items.Add(cdItem); + continue; + } + CItemEx &item = items[index]; + if (item.Name != cdItem.Name + // || item.Name.Len() != cdItem.Name.Len() + || item.PackSize != cdItem.PackSize + || item.Size != cdItem.Size + // item.ExtractVersion != cdItem.ExtractVersion + || !FlagsAreSame(item, cdItem) + || item.Crc != cdItem.Crc) + continue; + + // item.LocalHeaderPos = cdItem.LocalHeaderPos; + // item.Name = cdItem.Name; + item.MadeByVersion = cdItem.MadeByVersion; + item.CentralExtra = cdItem.CentralExtra; + item.InternalAttrib = cdItem.InternalAttrib; + item.ExternalAttrib = cdItem.ExternalAttrib; + item.Comment = cdItem.Comment; + item.FromCentral = cdItem.FromCentral; + } + } if (ecd64.thisDiskNumber != 0 || ecd64.startCDDiskNumber != 0) - throw CInArchiveException(CInArchiveException::kMultiVolumeArchiveAreNotSupported); - if (numCdItems != items.Size()) - IsOkHeaders = false; - if ((UInt16)ecd64.numEntriesInCDOnThisDisk != ((UInt16)numCdItems) || + return E_NOTIMPL; + + if (isZip64) + { + if (ecd64.numEntriesInCDOnThisDisk != items.Size()) + HeadersError = true; + } + else + { + // old 7-zip could store 32-bit number of CD items to 16-bit field. + if ((UInt16)ecd64.numEntriesInCDOnThisDisk != (UInt16)numCdItems || + (UInt16)ecd64.numEntriesInCDOnThisDisk != (UInt16)items.Size()) + HeadersError = true; + } + + ReadBuffer(ArcInfo.Comment, ecd.commentSize); + _inBufMode = false; + _inBuffer.Free(); + + if ( (UInt16)ecd64.numEntriesInCD != ((UInt16)numCdItems) || (UInt32)ecd64.cdSize != (UInt32)cdSize || - ((UInt32)(ecd64.cdStartOffset) != (UInt32)cdStartOffset && + ((UInt32)(ecd64.cdStartOffset) != (UInt32)cdRelatOffset && (!items.IsEmpty()))) return S_FALSE; - _inBufMode = false; - _inBuffer.Free(); - ArcInfo.FinishPosition = m_Position; + // printf("\nOpen OK"); return S_OK; } +HRESULT CInArchive::ReadHeaders(CObjectVector &items, CProgressVirt *progress) +{ + HRESULT res; + try + { + res = ReadHeaders2(items, progress); + } + catch (const CInBufferException &e) { res = e.ErrorCode; } + catch (const CUnexpectEnd &) + { + if (items.IsEmpty()) + return S_FALSE; + UnexpectedEnd = true; + res = S_OK; + } + catch (...) + { + _inBufMode = false; + throw; + } + ArcInfo.FinishPos = m_Position; + _inBufMode = false; + return res; +} + ISequentialInStream* CInArchive::CreateLimitedStream(UInt64 position, UInt64 size) { CLimitedSequentialInStream *streamSpec = new CLimitedSequentialInStream; CMyComPtr stream(streamSpec); - SeekInArchive(ArcInfo.Base + position); - streamSpec->SetStream(m_Stream); + Stream->Seek(ArcInfo.Base + position, STREAM_SEEK_SET, NULL); + streamSpec->SetStream(Stream); streamSpec->Init(size); return stream.Detach(); } -IInStream* CInArchive::CreateStream() -{ - CMyComPtr stream = m_Stream; - return stream.Detach(); -} - -bool CInArchive::SeekInArchive(UInt64 position) -{ - UInt64 newPosition; - if (m_Stream->Seek(position, STREAM_SEEK_SET, &newPosition) != S_OK) - return false; - return (newPosition == position); -} - }} diff --git a/CPP/7zip/Archive/Zip/ZipIn.h b/CPP/7zip/Archive/Zip/ZipIn.h old mode 100755 new mode 100644 index 0565339a..f6b349b1 --- a/CPP/7zip/Archive/Zip/ZipIn.h +++ b/CPP/7zip/Archive/Zip/ZipIn.h @@ -3,121 +3,187 @@ #ifndef __ZIP_IN_H #define __ZIP_IN_H -#include "Common/MyCom.h" +#include "../../../Common/MyCom.h" #include "../../IStream.h" #include "../../Common/InBuffer.h" #include "ZipHeader.h" -#include "ZipItemEx.h" +#include "ZipItem.h" + +API_FUNC_IsArc IsArc_Zip(const Byte *p, size_t size); namespace NArchive { namespace NZip { -class CInArchiveException +class CItemEx: public CItem { public: - enum ECauseType - { - kUnexpectedEndOfArchive = 0, - kArchiceHeaderCRCError, - kFileHeaderCRCError, - kIncorrectArchive, - kDataDescroptorsAreNotSupported, - kMultiVolumeArchiveAreNotSupported, - kReadStreamError, - kSeekStreamError - } - Cause; - CInArchiveException(ECauseType cause): Cause(cause) {} + UInt32 LocalFullHeaderSize; // including Name and Extra + + UInt64 GetLocalFullSize() const + { return LocalFullHeaderSize + PackSize + (HasDescriptor() ? kDataDescriptorSize : 0); } + UInt64 GetDataPosition() const + { return LocalHeaderPos + LocalFullHeaderSize; }; }; -class CInArchiveInfo +struct CInArchiveInfo { -public: - UInt64 Base; - UInt64 StartPosition; - UInt64 FinishPosition; + Int64 Base; /* Base offset of start of archive in stream. + Offsets in headers must be calculated from that Base. + Base is equal to MarkerPos for normal ZIPs. + Base can point to PE stub for some ZIP SFXs. + if CentralDir was read, + Base can be negative, if start of data is not available, + if CentralDirs was not read, + Base = ArcInfo.MarkerPos; */ + + /* The following *Pos variables contain absolute offsets in Stream */ + UInt64 MarkerPos; /* Pos of first signature, it can point to PK00 signature + = MarkerPos2 in most archives + = MarkerPos2 - 4 if there is PK00 signature */ + UInt64 MarkerPos2; // Pos of first local item signature in stream + UInt64 FinishPos; // Finish pos of archive data + UInt64 FileEndPos; // Finish pos of stream + + UInt64 FirstItemRelatOffset; /* Relative offset of first local (read from cd) (relative to Base). + = 0 in most archives + = size of stub for some SFXs */ + bool CdWasRead; + CByteBuffer Comment; - CInArchiveInfo(): Base(0), StartPosition(0) {} - UInt64 GetPhySize() const { return FinishPosition - StartPosition; } + CInArchiveInfo(): Base(0), MarkerPos(0), MarkerPos2(0), FinishPos(0), FileEndPos(0), + FirstItemRelatOffset(0), CdWasRead(false) {} + + UInt64 GetPhySize() const { return FinishPos - Base; } + UInt64 GetEmbeddedStubSize() const + { + if (CdWasRead) + return FirstItemRelatOffset; + return MarkerPos2 - Base; + } + bool ThereIsTail() const { return FileEndPos > FinishPos; } + void Clear() { Base = 0; - StartPosition = 0; - Comment.SetCapacity(0); + MarkerPos = 0; + MarkerPos2 = 0; + FinishPos = 0; + FileEndPos = 0; + + FirstItemRelatOffset = 0; + CdWasRead = false; + + Comment.Free(); } }; -class CProgressVirt +struct CProgressVirt { -public: - STDMETHOD(SetTotal)(UInt64 numFiles) PURE; - STDMETHOD(SetCompleted)(UInt64 numFiles) PURE; + virtual HRESULT SetCompletedLocal(UInt64 numFiles, UInt64 numBytes) = 0; + virtual HRESULT SetTotalCD(UInt64 numFiles) = 0; + virtual HRESULT SetCompletedCD(UInt64 numFiles) = 0; }; struct CCdInfo { - // UInt64 NumEntries; + UInt64 NumEntries; UInt64 Size; UInt64 Offset; + + void ParseEcd(const Byte *p); + void ParseEcd64(const Byte *p); }; class CInArchive { - CMyComPtr m_Stream; + CInBuffer _inBuffer; + bool _inBufMode; UInt32 m_Signature; - UInt64 m_StreamStartPosition; UInt64 m_Position; - - bool _inBufMode; - CInBuffer _inBuffer; HRESULT Seek(UInt64 offset); - HRESULT FindAndReadMarker(IInStream *stream, const UInt64 *searchHeaderSizeLimit); - void ReadFileName(UInt32 nameSize, AString &dest); - + HRESULT IncreaseRealPosition(UInt64 addValue); + HRESULT ReadBytes(void *data, UInt32 size, UInt32 *processedSize); - bool ReadBytesAndTestSize(void *data, UInt32 size); - void SafeReadBytes(void *data, UInt32 size); - void ReadBuffer(CByteBuffer &buffer, UInt32 size); + void SafeReadBytes(void *data, unsigned size); + void ReadBuffer(CByteBuffer &buffer, unsigned size); Byte ReadByte(); UInt16 ReadUInt16(); UInt32 ReadUInt32(); UInt64 ReadUInt64(); - bool ReadUInt32(UInt32 &signature); - - void Skip(UInt64 num); - void IncreaseRealPosition(UInt64 addValue); - - void ReadExtra(UInt32 extraSize, CExtraBlock &extraBlock, + void Skip(unsigned num); + void Skip64(UInt64 num); + void ReadFileName(unsigned nameSize, AString &dest); + + bool ReadExtra(unsigned extraSize, CExtraBlock &extraBlock, UInt64 &unpackSize, UInt64 &packSize, UInt64 &localHeaderOffset, UInt32 &diskStartNumber); - HRESULT ReadLocalItem(CItemEx &item); + bool ReadLocalItem(CItemEx &item); HRESULT ReadLocalItemDescriptor(CItemEx &item); HRESULT ReadCdItem(CItemEx &item); HRESULT TryEcd64(UInt64 offset, CCdInfo &cdInfo); HRESULT FindCd(CCdInfo &cdInfo); HRESULT TryReadCd(CObjectVector &items, UInt64 cdOffset, UInt64 cdSize, CProgressVirt *progress); HRESULT ReadCd(CObjectVector &items, UInt64 &cdOffset, UInt64 &cdSize, CProgressVirt *progress); - HRESULT ReadLocalsAndCd(CObjectVector &items, CProgressVirt *progress, UInt64 &cdOffset, int &numCdItems); + HRESULT ReadLocals(CObjectVector &localItems, CProgressVirt *progress); + + HRESULT ReadHeaders2(CObjectVector &items, CProgressVirt *progress); public: CInArchiveInfo ArcInfo; + + bool IsArc; bool IsZip64; - bool IsOkHeaders; - + bool HeadersError; + bool HeadersWarning; + bool ExtraMinorError; + bool UnexpectedEnd; + bool NoCentralDir; + + CMyComPtr Stream; + + void Close(); + HRESULT Open(IInStream *stream, const UInt64 *searchHeaderSizeLimit); HRESULT ReadHeaders(CObjectVector &items, CProgressVirt *progress); + + bool IsOpen() const { return Stream != NULL; } + bool AreThereErrors() const { return HeadersError || UnexpectedEnd; } + + bool IsLocalOffsetOK(const CItemEx &item) const + { + if (item.FromLocal) + return true; + return /* ArcInfo.Base >= 0 || */ ArcInfo.Base + (Int64)item.LocalHeaderPos >= 0; + } + HRESULT ReadLocalItemAfterCdItem(CItemEx &item); HRESULT ReadLocalItemAfterCdItemFull(CItemEx &item); - HRESULT Open(IInStream *stream, const UInt64 *searchHeaderSizeLimit); - void Close(); - bool SeekInArchive(UInt64 position); + ISequentialInStream *CreateLimitedStream(UInt64 position, UInt64 size); - IInStream* CreateStream(); - bool IsOpen() const { return m_Stream != NULL; } + UInt64 GetOffsetInStream(UInt64 offsetFromArc) const { return ArcInfo.Base + offsetFromArc; } + + bool CanUpdate() const + { + if (AreThereErrors()) + return false; + if (ArcInfo.Base < 0) + return false; + if ((Int64)ArcInfo.MarkerPos2 < ArcInfo.Base) + return false; + + // 7-zip probably can update archives with embedded stubs. + // we just disable that feature for more safety. + if (ArcInfo.GetEmbeddedStubSize() != 0) + return false; + + if (ArcInfo.ThereIsTail()) + return false; + return true; + } }; }} diff --git a/CPP/7zip/Archive/Zip/ZipItem.cpp b/CPP/7zip/Archive/Zip/ZipItem.cpp old mode 100755 new mode 100644 index ad89f558..ae88944d --- a/CPP/7zip/Archive/Zip/ZipItem.cpp +++ b/CPP/7zip/Archive/Zip/ZipItem.cpp @@ -10,21 +10,13 @@ namespace NArchive { namespace NZip { -bool operator==(const CVersion &v1, const CVersion &v2) -{ - return (v1.Version == v2.Version) && (v1.HostOS == v2.HostOS); -} +using namespace NFileHeader; -bool operator!=(const CVersion &v1, const CVersion &v2) -{ - return !(v1 == v2); -} - -bool CExtraSubBlock::ExtractNtfsTime(int index, FILETIME &ft) const +bool CExtraSubBlock::ExtractNtfsTime(unsigned index, FILETIME &ft) const { ft.dwHighDateTime = ft.dwLowDateTime = 0; - UInt32 size = (UInt32)Data.GetCapacity(); - if (ID != NFileHeader::NExtraID::kNTFS || size < 32) + UInt32 size = (UInt32)Data.Size(); + if (ID != NExtraID::kNTFS || size < 32) return false; const Byte *p = (const Byte *)Data; p += 4; // for reserved @@ -32,13 +24,13 @@ bool CExtraSubBlock::ExtractNtfsTime(int index, FILETIME &ft) const while (size > 4) { UInt16 tag = GetUi16(p); - UInt32 attrSize = GetUi16(p + 2); + unsigned attrSize = GetUi16(p + 2); p += 4; size -= 4; if (attrSize > size) attrSize = size; - if (tag == NFileHeader::NNtfsExtra::kTagTime && attrSize >= 24) + if (tag == NNtfsExtra::kTagTime && attrSize >= 24) { p += 8 * index; ft.dwLowDateTime = GetUi32(p); @@ -51,25 +43,25 @@ bool CExtraSubBlock::ExtractNtfsTime(int index, FILETIME &ft) const return false; } -bool CExtraSubBlock::ExtractUnixTime(bool isCentral, int index, UInt32 &res) const +bool CExtraSubBlock::ExtractUnixTime(bool isCentral, unsigned index, UInt32 &res) const { res = 0; - UInt32 size = (UInt32)Data.GetCapacity(); - if (ID != NFileHeader::NExtraID::kUnixTime || size < 5) + UInt32 size = (UInt32)Data.Size(); + if (ID != NExtraID::kUnixTime || size < 5) return false; const Byte *p = (const Byte *)Data; Byte flags = *p++; size--; if (isCentral) { - if (index != NFileHeader::NUnixTime::kMTime || - (flags & (1 << NFileHeader::NUnixTime::kMTime)) == 0 || + if (index != NUnixTime::kMTime || + (flags & (1 << NUnixTime::kMTime)) == 0 || size < 4) return false; res = GetUi32(p); return true; } - for (int i = 0; i < 3; i++) + for (unsigned i = 0; i < 3; i++) if ((flags & (1 << i)) != 0) { if (size < 4) @@ -96,30 +88,33 @@ bool CItem::IsDir() const return true; if (!FromCentral) return false; - WORD highAttributes = WORD((ExternalAttributes >> 16 ) & 0xFFFF); - switch (MadeByVersion.HostOS) + + UInt16 highAttrib = (UInt16)((ExternalAttrib >> 16 ) & 0xFFFF); + + Byte hostOS = GetHostOS(); + switch (hostOS) { - case NFileHeader::NHostOS::kAMIGA: - switch (highAttributes & NFileHeader::NAmigaAttribute::kIFMT) + case NHostOS::kAMIGA: + switch (highAttrib & NAmigaAttrib::kIFMT) { - case NFileHeader::NAmigaAttribute::kIFDIR: return true; - case NFileHeader::NAmigaAttribute::kIFREG: return false; + case NAmigaAttrib::kIFDIR: return true; + case NAmigaAttrib::kIFREG: return false; default: return false; // change it throw kUnknownAttributes; } - case NFileHeader::NHostOS::kFAT: - case NFileHeader::NHostOS::kNTFS: - case NFileHeader::NHostOS::kHPFS: - case NFileHeader::NHostOS::kVFAT: - return ((ExternalAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0); - case NFileHeader::NHostOS::kAtari: - case NFileHeader::NHostOS::kMac: - case NFileHeader::NHostOS::kVMS: - case NFileHeader::NHostOS::kVM_CMS: - case NFileHeader::NHostOS::kAcorn: - case NFileHeader::NHostOS::kMVS: + case NHostOS::kFAT: + case NHostOS::kNTFS: + case NHostOS::kHPFS: + case NHostOS::kVFAT: + return ((ExternalAttrib & FILE_ATTRIBUTE_DIRECTORY) != 0); + case NHostOS::kAtari: + case NHostOS::kMac: + case NHostOS::kVMS: + case NHostOS::kVM_CMS: + case NHostOS::kAcorn: + case NHostOS::kMVS: return false; // change it throw kUnknownAttributes; - case NFileHeader::NHostOS::kUnix: - return (highAttributes & NFileHeader::NUnixAttribute::kIFDIR) != 0; + case NHostOS::kUnix: + return (highAttrib & NUnixAttrib::kIFDIR) != 0; default: return false; } @@ -127,13 +122,13 @@ bool CItem::IsDir() const UInt32 CItem::GetWinAttrib() const { - DWORD winAttrib = 0; - switch (MadeByVersion.HostOS) + UInt32 winAttrib = 0; + switch (GetHostOS()) { - case NFileHeader::NHostOS::kFAT: - case NFileHeader::NHostOS::kNTFS: + case NHostOS::kFAT: + case NHostOS::kNTFS: if (FromCentral) - winAttrib = ExternalAttributes; + winAttrib = ExternalAttrib; break; } if (IsDir()) // test it; @@ -144,35 +139,15 @@ UInt32 CItem::GetWinAttrib() const bool CItem::GetPosixAttrib(UInt32 &attrib) const { // some archivers can store PosixAttrib in high 16 bits even with HostOS=FAT. - if (FromCentral && MadeByVersion.HostOS == NFileHeader::NHostOS::kUnix) + if (FromCentral && GetHostOS() == NHostOS::kUnix) { - attrib = ExternalAttributes >> 16; + attrib = ExternalAttrib >> 16; return (attrib != 0); } attrib = 0; if (IsDir()) - attrib = NFileHeader::NUnixAttribute::kIFDIR; + attrib = NUnixAttrib::kIFDIR; return false; } -void CLocalItem::SetFlagBits(int startBitNumber, int numBits, int value) -{ - UInt16 mask = (UInt16)(((1 << numBits) - 1) << startBitNumber); - Flags &= ~mask; - Flags |= value << startBitNumber; -} - -void CLocalItem::SetBitMask(int bitMask, bool enable) -{ - if(enable) - Flags |= bitMask; - else - Flags &= ~bitMask; -} - -void CLocalItem::SetEncrypted(bool encrypted) - { SetBitMask(NFileHeader::NFlags::kEncrypted, encrypted); } -void CLocalItem::SetUtf8(bool isUtf8) - { SetBitMask(NFileHeader::NFlags::kUtf8, isUtf8); } - }} diff --git a/CPP/7zip/Archive/Zip/ZipItem.h b/CPP/7zip/Archive/Zip/ZipItem.h old mode 100755 new mode 100644 index 5efd433a..d50c3ae9 --- a/CPP/7zip/Archive/Zip/ZipItem.h +++ b/CPP/7zip/Archive/Zip/ZipItem.h @@ -3,10 +3,12 @@ #ifndef __ARCHIVE_ZIP_ITEM_H #define __ARCHIVE_ZIP_ITEM_H -#include "Common/MyString.h" -#include "Common/Buffer.h" -#include "Common/UTFConvert.h" -#include "Common/StringConvert.h" +#include "../../../../C/CpuArch.h" + +#include "../../../Common/MyBuffer.h" +#include "../../../Common/MyString.h" +#include "../../../Common/StringConvert.h" +#include "../../../Common/UTFConvert.h" #include "ZipHeader.h" @@ -19,25 +21,25 @@ struct CVersion Byte HostOS; }; -bool operator==(const CVersion &v1, const CVersion &v2); -bool operator!=(const CVersion &v1, const CVersion &v2); - struct CExtraSubBlock { UInt16 ID; CByteBuffer Data; - bool ExtractNtfsTime(int index, FILETIME &ft) const; - bool ExtractUnixTime(bool isCentral, int index, UInt32 &res) const; + + bool ExtractNtfsTime(unsigned index, FILETIME &ft) const; + bool ExtractUnixTime(bool isCentral, unsigned index, UInt32 &res) const; }; -struct CWzAesExtraField +const unsigned k_WzAesExtra_Size = 7; + +struct CWzAesExtra { - UInt16 VendorVersion; // 0x0001 - AE-1, 0x0002 - AE-2, - // UInt16 VendorId; // "AE" - Byte Strength; // 1 - 128-bit , 2 - 192-bit , 3 - 256-bit + UInt16 VendorVersion; // 1: AE-1, 2: AE-2, + // UInt16 VendorId; // 'A' 'E' + Byte Strength; // 1: 128-bit, 2: 192-bit, 3: 256-bit UInt16 Method; - CWzAesExtraField(): VendorVersion(2), Strength(3), Method(0) {} + CWzAesExtra(): VendorVersion(2), Strength(3), Method(0) {} bool NeedCrc() const { return (VendorVersion == 1); } @@ -45,19 +47,21 @@ struct CWzAesExtraField { if (sb.ID != NFileHeader::NExtraID::kWzAES) return false; - if (sb.Data.GetCapacity() < 7) + if (sb.Data.Size() < k_WzAesExtra_Size) return false; const Byte *p = (const Byte *)sb.Data; - VendorVersion = (((UInt16)p[1]) << 8) | p[0]; + VendorVersion = GetUi16(p); if (p[2] != 'A' || p[3] != 'E') return false; Strength = p[4]; - Method = (((UInt16)p[6]) << 16) | p[5]; + // 9.31: The BUG was fixed: + Method = GetUi16(p + 5); return true; } + void SetSubBlock(CExtraSubBlock &sb) const { - sb.Data.SetCapacity(7); + sb.Data.Alloc(k_WzAesExtra_Size); sb.ID = NFileHeader::NExtraID::kWzAES; Byte *p = (Byte *)sb.Data; p[0] = (Byte)VendorVersion; @@ -70,7 +74,7 @@ struct CWzAesExtraField } }; -namespace NStrongCryptoFlags +namespace NStrongCrypto_AlgId { const UInt16 kDES = 0x6601; const UInt16 kRC2old = 0x6602; @@ -85,7 +89,7 @@ namespace NStrongCryptoFlags const UInt16 kRC4 = 0x6801; } -struct CStrongCryptoField +struct CStrongCryptoExtra { UInt16 Format; UInt16 AlgId; @@ -97,12 +101,12 @@ struct CStrongCryptoField if (sb.ID != NFileHeader::NExtraID::kStrongEncrypt) return false; const Byte *p = (const Byte *)sb.Data; - if (sb.Data.GetCapacity() < 8) + if (sb.Data.Size() < 8) return false; - Format = (((UInt16)p[1]) << 8) | p[0]; - AlgId = (((UInt16)p[3]) << 8) | p[2]; - BitLen = (((UInt16)p[5]) << 8) | p[4]; - Flags = (((UInt16)p[7]) << 8) | p[6]; + Format = GetUi16(p + 0); + AlgId = GetUi16(p + 2); + BitLen = GetUi16(p + 4); + Flags = GetUi16(p + 6); return (Format == 2); } }; @@ -110,39 +114,50 @@ struct CStrongCryptoField struct CExtraBlock { CObjectVector SubBlocks; + void Clear() { SubBlocks.Clear(); } + size_t GetSize() const { size_t res = 0; - for (int i = 0; i < SubBlocks.Size(); i++) - res += SubBlocks[i].Data.GetCapacity() + 2 + 2; + FOR_VECTOR (i, SubBlocks) + res += SubBlocks[i].Data.Size() + 2 + 2; return res; } - bool GetWzAesField(CWzAesExtraField &aesField) const + + bool GetWzAes(CWzAesExtra &e) const { - for (int i = 0; i < SubBlocks.Size(); i++) - if (aesField.ParseFromSubBlock(SubBlocks[i])) + FOR_VECTOR (i, SubBlocks) + if (e.ParseFromSubBlock(SubBlocks[i])) return true; return false; } - bool GetStrongCryptoField(CStrongCryptoField &f) const + bool HasWzAes() const + { + CWzAesExtra e; + return GetWzAes(e); + } + + bool GetStrongCrypto(CStrongCryptoExtra &e) const { - for (int i = 0; i < SubBlocks.Size(); i++) - if (f.ParseFromSubBlock(SubBlocks[i])) + FOR_VECTOR (i, SubBlocks) + if (e.ParseFromSubBlock(SubBlocks[i])) return true; return false; } - bool HasWzAesField() const + /* + bool HasStrongCrypto() const { - CWzAesExtraField aesField; - return GetWzAesField(aesField); + CStrongCryptoExtra e; + return GetStrongCrypto(e); } + */ - bool GetNtfsTime(int index, FILETIME &ft) const + bool GetNtfsTime(unsigned index, FILETIME &ft) const { - for (int i = 0; i < SubBlocks.Size(); i++) + FOR_VECTOR (i, SubBlocks) { const CExtraSubBlock &sb = SubBlocks[i]; if (sb.ID == NFileHeader::NExtraID::kNTFS) @@ -151,9 +166,9 @@ struct CExtraBlock return false; } - bool GetUnixTime(bool isCentral, int index, UInt32 &res) const + bool GetUnixTime(bool isCentral, unsigned index, UInt32 &res) const { - for (int i = 0; i < SubBlocks.Size(); i++) + FOR_VECTOR (i, SubBlocks) { const CExtraSubBlock &sb = SubBlocks[i]; if (sb.ID == NFileHeader::NExtraID::kUnixTime) @@ -162,14 +177,6 @@ struct CExtraBlock return false; } - /* - bool HasStrongCryptoField() const - { - CStrongCryptoField f; - return GetStrongCryptoField(f); - } - */ - void RemoveUnknownSubBlocks() { for (int i = SubBlocks.Size() - 1; i >= 0; i--) @@ -182,95 +189,134 @@ struct CExtraBlock class CLocalItem { public: - CVersion ExtractVersion; UInt16 Flags; - UInt16 CompressionMethod; - UInt32 Time; - UInt32 FileCRC; + UInt16 Method; + CVersion ExtractVersion; + + UInt64 Size; UInt64 PackSize; - UInt64 UnPackSize; + UInt32 Time; + UInt32 Crc; AString Name; CExtraBlock LocalExtra; bool IsUtf8() const { return (Flags & NFileHeader::NFlags::kUtf8) != 0; } - bool IsEncrypted() const { return (Flags & NFileHeader::NFlags::kEncrypted) != 0; } bool IsStrongEncrypted() const { return IsEncrypted() && (Flags & NFileHeader::NFlags::kStrongEncrypted) != 0; }; - bool IsAesEncrypted() const { return IsEncrypted() && (IsStrongEncrypted() || CompressionMethod == NFileHeader::NCompressionMethod::kWzAES); }; - + bool IsAesEncrypted() const { return IsEncrypted() && (IsStrongEncrypted() || Method == NFileHeader::NCompressionMethod::kWzAES); }; bool IsLzmaEOS() const { return (Flags & NFileHeader::NFlags::kLzmaEOS) != 0; } + bool HasDescriptor() const { return (Flags & NFileHeader::NFlags::kDescriptorUsedMask) != 0; } bool IsDir() const; - bool IgnoreItem() const { return false; } - - bool HasDescriptor() const { return (Flags & NFileHeader::NFlags::kDescriptorUsedMask) != 0; } - UString GetUnicodeString(const AString &s) const + /* + void GetUnicodeString(const AString &s, UString &res) const { - UString res; - if (IsUtf8()) - if (!ConvertUTF8ToUnicode(s, res)) - res.Empty(); - if (res.IsEmpty()) - res = MultiByteToUnicodeString(s, GetCodePage()); - return res; + bool isUtf8 = IsUtf8(); + if (isUtf8) + if (ConvertUTF8ToUnicode(s, res)) + return; + MultiByteToUnicodeString2(res, s, GetCodePage()); } - + */ + private: - void SetFlagBits(int startBitNumber, int numBits, int value); - void SetBitMask(int bitMask, bool enable); + + void SetFlag(unsigned bitMask, bool enable) + { + if (enable) + Flags |= bitMask; + else + Flags &= ~bitMask; + } + public: + void ClearFlags() { Flags = 0; } - void SetEncrypted(bool encrypted); - void SetUtf8(bool isUtf8); + void SetEncrypted(bool encrypted) { SetFlag(NFileHeader::NFlags::kEncrypted, encrypted); } + void SetUtf8(bool isUtf8) { SetFlag(NFileHeader::NFlags::kUtf8, isUtf8); } - WORD GetCodePage() const { return CP_OEMCP; } + UINT GetCodePage() const { return CP_OEMCP; } }; + class CItem: public CLocalItem { public: CVersion MadeByVersion; - UInt16 InternalAttributes; - UInt32 ExternalAttributes; + UInt16 InternalAttrib; + UInt32 ExternalAttrib; - UInt64 LocalHeaderPosition; + UInt64 LocalHeaderPos; - FILETIME NtfsMTime; - FILETIME NtfsATime; - FILETIME NtfsCTime; - CExtraBlock CentralExtra; CByteBuffer Comment; bool FromLocal; bool FromCentral; - bool NtfsTimeIsDefined; + // CItem can be used as CLocalItem. So we must clear unused fields + CItem(): + InternalAttrib(0), + ExternalAttrib(0), + FromLocal(false), + FromCentral(false) + { + MadeByVersion.Version = 0; + MadeByVersion.HostOS = 0; + } + bool IsDir() const; UInt32 GetWinAttrib() const; bool GetPosixAttrib(UInt32 &attrib) const; + Byte GetHostOS() const { return FromCentral ? MadeByVersion.HostOS : ExtractVersion.HostOS; } + + void GetUnicodeString(const AString &s, UString &res, bool useSpecifiedCodePage, UINT codePage) const + { + bool isUtf8 = IsUtf8(); + + #ifdef _WIN32 + if (!isUtf8) + { + if (useSpecifiedCodePage) + isUtf8 = (codePage == CP_UTF8); + else if (GetHostOS() == NFileHeader::NHostOS::kUnix) + { + /* Some ZIP archives in Unix use UTF-8 encoding without Utf8 flag in header. + We try to get name as UTF-8. + Do we need to do it in POSIX version also? */ + isUtf8 = true; + } + } + #endif + + if (isUtf8) + if (ConvertUTF8ToUnicode(s, res)) + return; + MultiByteToUnicodeString2(res, s, useSpecifiedCodePage ? codePage : GetCodePage()); + } + bool IsThereCrc() const { - if (CompressionMethod == NFileHeader::NCompressionMethod::kWzAES) + if (Method == NFileHeader::NCompressionMethod::kWzAES) { - CWzAesExtraField aesField; - if (CentralExtra.GetWzAesField(aesField)) + CWzAesExtra aesField; + if (CentralExtra.GetWzAes(aesField)) return aesField.NeedCrc(); } - return (FileCRC != 0 || !IsDir()); + return (Crc != 0 || !IsDir()); } - WORD GetCodePage() const + UINT GetCodePage() const { - return (WORD)((MadeByVersion.HostOS == NFileHeader::NHostOS::kFAT - || MadeByVersion.HostOS == NFileHeader::NHostOS::kNTFS - ) ? CP_OEMCP : CP_ACP); + Byte hostOS = GetHostOS(); + return (UINT)(( + hostOS == NFileHeader::NHostOS::kFAT || + hostOS == NFileHeader::NHostOS::kNTFS) ? CP_OEMCP : CP_ACP); } - CItem() : FromLocal(false), FromCentral(false), NtfsTimeIsDefined(false) {} }; }} diff --git a/CPP/7zip/Archive/Zip/ZipItemEx.h b/CPP/7zip/Archive/Zip/ZipItemEx.h deleted file mode 100755 index ab62cdbb..00000000 --- a/CPP/7zip/Archive/Zip/ZipItemEx.h +++ /dev/null @@ -1,34 +0,0 @@ -// Archive/ZipItemEx.h - -#ifndef __ARCHIVE_ZIP_ITEMEX_H -#define __ARCHIVE_ZIP_ITEMEX_H - -#include "ZipHeader.h" -#include "ZipItem.h" - -namespace NArchive { -namespace NZip { - -class CItemEx: public CItem -{ -public: - UInt32 FileHeaderWithNameSize; - UInt16 LocalExtraSize; - - UInt64 GetLocalFullSize() const - { return FileHeaderWithNameSize + LocalExtraSize + PackSize + - (HasDescriptor() ? NFileHeader::kDataDescriptorSize : 0); }; - /* - UInt64 GetLocalFullSize(bool isZip64) const - { return FileHeaderWithNameSize + LocalExtraSize + PackSize + - (HasDescriptor() ? (isZip64 ? NFileHeader::kDataDescriptor64Size : NFileHeader::kDataDescriptorSize) : 0); }; - */ - UInt64 GetLocalExtraPosition() const - { return LocalHeaderPosition + FileHeaderWithNameSize; }; - UInt64 GetDataPosition() const - { return GetLocalExtraPosition() + LocalExtraSize; }; -}; - -}} - -#endif diff --git a/CPP/7zip/Archive/Zip/ZipOut.cpp b/CPP/7zip/Archive/Zip/ZipOut.cpp old mode 100755 new mode 100644 index aa82143e..2a1ba2c4 --- a/CPP/7zip/Archive/Zip/ZipOut.cpp +++ b/CPP/7zip/Archive/Zip/ZipOut.cpp @@ -9,80 +9,93 @@ namespace NArchive { namespace NZip { -void COutArchive::Create(IOutStream *outStream) +HRESULT COutArchive::Create(IOutStream *outStream) { + m_CurPos = 0; if (!m_OutBuffer.Create(1 << 16)) - throw CSystemException(E_OUTOFMEMORY); + return E_OUTOFMEMORY; m_Stream = outStream; m_OutBuffer.SetStream(outStream); m_OutBuffer.Init(); - m_BasePosition = 0; + + return m_Stream->Seek(0, STREAM_SEEK_CUR, &m_Base); +} + +void COutArchive::MoveCurPos(UInt64 distanceToMove) +{ + m_CurPos += distanceToMove; // test overflow } -void COutArchive::MoveBasePosition(UInt64 distanceToMove) +void COutArchive::SeekToRelatPos(UInt64 offset) { - m_BasePosition += distanceToMove; // test overflow + HRESULT res = m_Stream->Seek(m_Base + offset, STREAM_SEEK_SET, NULL); + if (res != S_OK) + throw CSystemException(res); } -void COutArchive::PrepareWriteCompressedDataZip64(UInt16 fileNameLength, bool isZip64, bool aesEncryption) +void COutArchive::PrepareWriteCompressedDataZip64(unsigned fileNameLen, bool isZip64, bool aesEncryption) { m_IsZip64 = isZip64; m_ExtraSize = isZip64 ? (4 + 8 + 8) : 0; if (aesEncryption) - m_ExtraSize += 4 + 7; - m_LocalFileHeaderSize = 4 + NFileHeader::kLocalBlockSize + fileNameLength + m_ExtraSize; + m_ExtraSize += 4 + k_WzAesExtra_Size; + m_LocalFileHeaderSize = kLocalHeaderSize + fileNameLen + m_ExtraSize; } -void COutArchive::PrepareWriteCompressedData(UInt16 fileNameLength, UInt64 unPackSize, bool aesEncryption) +void COutArchive::PrepareWriteCompressedData(unsigned fileNameLen, UInt64 unPackSize, bool aesEncryption) { - // We test it to 0xF8000000 to support case when compressed size - // can be larger than uncompressed size. - PrepareWriteCompressedDataZip64(fileNameLength, unPackSize >= 0xF8000000, aesEncryption); + // We use Zip64, if unPackSize size is larger than 0xF8000000 to support + // cases when compressed size can be about 3% larger than uncompressed size + + PrepareWriteCompressedDataZip64(fileNameLen, unPackSize >= (UInt32)0xF8000000, aesEncryption); } -void COutArchive::PrepareWriteCompressedData2(UInt16 fileNameLength, UInt64 unPackSize, UInt64 packSize, bool aesEncryption) +#define DOES_NEED_ZIP64(v) (v >= (UInt32)0xFFFFFFFF) + +void COutArchive::PrepareWriteCompressedData2(unsigned fileNameLen, UInt64 unPackSize, UInt64 packSize, bool aesEncryption) { - bool isUnPack64 = unPackSize >= 0xFFFFFFFF; - bool isPack64 = packSize >= 0xFFFFFFFF; - bool isZip64 = isPack64 || isUnPack64; - PrepareWriteCompressedDataZip64(fileNameLength, isZip64, aesEncryption); + bool isZip64 = + DOES_NEED_ZIP64(unPackSize) || + DOES_NEED_ZIP64(packSize); + PrepareWriteCompressedDataZip64(fileNameLen, isZip64, aesEncryption); } void COutArchive::WriteBytes(const void *buffer, UInt32 size) { m_OutBuffer.WriteBytes(buffer, size); - m_BasePosition += size; + m_CurPos += size; } -void COutArchive::WriteByte(Byte b) +void COutArchive::Write8(Byte b) { - WriteBytes(&b, 1); + m_OutBuffer.WriteByte(b); + m_CurPos++; } -void COutArchive::WriteUInt16(UInt16 value) +void COutArchive::Write16(UInt16 val) { for (int i = 0; i < 2; i++) { - WriteByte((Byte)value); - value >>= 8; + Write8((Byte)val); + val >>= 8; } } -void COutArchive::WriteUInt32(UInt32 value) +void COutArchive::Write32(UInt32 val) { for (int i = 0; i < 4; i++) { - WriteByte((Byte)value); - value >>= 8; + Write8((Byte)val); + val >>= 8; } } -void COutArchive::WriteUInt64(UInt64 value) +void COutArchive::Write64(UInt64 val) { for (int i = 0; i < 8; i++) { - WriteByte((Byte)value); - value >>= 8; + Write8((Byte)val); + val >>= 8; } } @@ -90,178 +103,181 @@ void COutArchive::WriteExtra(const CExtraBlock &extra) { if (extra.SubBlocks.Size() != 0) { - for (int i = 0; i < extra.SubBlocks.Size(); i++) + FOR_VECTOR (i, extra.SubBlocks) { const CExtraSubBlock &subBlock = extra.SubBlocks[i]; - WriteUInt16(subBlock.ID); - WriteUInt16((UInt16)subBlock.Data.GetCapacity()); - WriteBytes(subBlock.Data, (UInt32)subBlock.Data.GetCapacity()); + Write16(subBlock.ID); + Write16((UInt16)subBlock.Data.Size()); + WriteBytes(subBlock.Data, (UInt32)subBlock.Data.Size()); } } } -void COutArchive::SeekTo(UInt64 offset) +void COutArchive::WriteCommonItemInfo(const CLocalItem &item, bool isZip64) { - HRESULT res = m_Stream->Seek(offset, STREAM_SEEK_SET, NULL); - if (res != S_OK) - throw CSystemException(res); + { + Byte ver = item.ExtractVersion.Version; + if (isZip64 && ver < NFileHeader::NCompressionMethod::kExtractVersion_Zip64) + ver = NFileHeader::NCompressionMethod::kExtractVersion_Zip64; + Write8(ver); + } + Write8(item.ExtractVersion.HostOS); + Write16(item.Flags); + Write16(item.Method); + Write32(item.Time); + Write32(item.Crc); } +#define WRITE_32_VAL_SPEC(__v, __isZip64) Write32((__isZip64) ? 0xFFFFFFFF : (UInt32)(__v)); + void COutArchive::WriteLocalHeader(const CLocalItem &item) { - SeekTo(m_BasePosition); + SeekToCurPos(); - bool isZip64 = m_IsZip64 || item.PackSize >= 0xFFFFFFFF || item.UnPackSize >= 0xFFFFFFFF; + bool isZip64 = m_IsZip64 || + DOES_NEED_ZIP64(item.PackSize) || + DOES_NEED_ZIP64(item.Size); - WriteUInt32(NSignature::kLocalFileHeader); - { - Byte ver = item.ExtractVersion.Version; - if (isZip64 && ver < NFileHeader::NCompressionMethod::kExtractVersion_Zip64) - ver = NFileHeader::NCompressionMethod::kExtractVersion_Zip64; - WriteByte(ver); - } - WriteByte(item.ExtractVersion.HostOS); - WriteUInt16(item.Flags); - WriteUInt16(item.CompressionMethod); - WriteUInt32(item.Time); - WriteUInt32(item.FileCRC); - WriteUInt32(isZip64 ? 0xFFFFFFFF: (UInt32)item.PackSize); - WriteUInt32(isZip64 ? 0xFFFFFFFF: (UInt32)item.UnPackSize); - WriteUInt16((UInt16)item.Name.Length()); + Write32(NSignature::kLocalFileHeader); + WriteCommonItemInfo(item, isZip64); + + WRITE_32_VAL_SPEC(item.PackSize, isZip64); + WRITE_32_VAL_SPEC(item.Size, isZip64); + + Write16((UInt16)item.Name.Len()); { - UInt16 localExtraSize = (UInt16)((isZip64 ? (4 + 16): 0) + item.LocalExtra.GetSize()); - if (localExtraSize > m_ExtraSize) + UInt16 localExtraSize = (UInt16)((isZip64 ? (4 + 8 + 8): 0) + item.LocalExtra.GetSize()); + if (localExtraSize != m_ExtraSize) throw CSystemException(E_FAIL); } - WriteUInt16((UInt16)m_ExtraSize); // test it; - WriteBytes((const char *)item.Name, item.Name.Length()); + Write16((UInt16)m_ExtraSize); + WriteBytes((const char *)item.Name, item.Name.Len()); - UInt32 extraPos = 0; if (isZip64) { - extraPos += 4 + 16; - WriteUInt16(NFileHeader::NExtraID::kZip64); - WriteUInt16(16); - WriteUInt64(item.UnPackSize); - WriteUInt64(item.PackSize); + Write16(NFileHeader::NExtraID::kZip64); + Write16(8 + 8); + Write64(item.Size); + Write64(item.PackSize); } WriteExtra(item.LocalExtra); - extraPos += (UInt32)item.LocalExtra.GetSize(); - for (; extraPos < m_ExtraSize; extraPos++) - WriteByte(0); + + // Why don't we write NTFS timestamps to local header? + // Probably we want to reduce size of archive? m_OutBuffer.FlushWithCheck(); - MoveBasePosition(item.PackSize); - SeekTo(m_BasePosition); + MoveCurPos(item.PackSize); } -void COutArchive::WriteCentralHeader(const CItem &item) +void COutArchive::WriteCentralHeader(const CItemOut &item) { - bool isUnPack64 = item.UnPackSize >= 0xFFFFFFFF; - bool isPack64 = item.PackSize >= 0xFFFFFFFF; - bool isPosition64 = item.LocalHeaderPosition >= 0xFFFFFFFF; - bool isZip64 = isPack64 || isUnPack64 || isPosition64; + bool isUnPack64 = DOES_NEED_ZIP64(item.Size); + bool isPack64 = DOES_NEED_ZIP64(item.PackSize); + bool isPosition64 = DOES_NEED_ZIP64(item.LocalHeaderPos); + bool isZip64 = isPack64 || isUnPack64 || isPosition64; - WriteUInt32(NSignature::kCentralFileHeader); - WriteByte(item.MadeByVersion.Version); - WriteByte(item.MadeByVersion.HostOS); - { - Byte ver = item.ExtractVersion.Version; - if (isZip64 && ver < NFileHeader::NCompressionMethod::kExtractVersion_Zip64) - ver = NFileHeader::NCompressionMethod::kExtractVersion_Zip64; - WriteByte(ver); - } - WriteByte(item.ExtractVersion.HostOS); - WriteUInt16(item.Flags); - WriteUInt16(item.CompressionMethod); - WriteUInt32(item.Time); - WriteUInt32(item.FileCRC); - WriteUInt32(isPack64 ? 0xFFFFFFFF: (UInt32)item.PackSize); - WriteUInt32(isUnPack64 ? 0xFFFFFFFF: (UInt32)item.UnPackSize); - WriteUInt16((UInt16)item.Name.Length()); - UInt16 zip64ExtraSize = (UInt16)((isUnPack64 ? 8: 0) + (isPack64 ? 8: 0) + (isPosition64 ? 8: 0)); + Write32(NSignature::kCentralFileHeader); + Write8(item.MadeByVersion.Version); + Write8(item.MadeByVersion.HostOS); + + WriteCommonItemInfo(item, isZip64); + + WRITE_32_VAL_SPEC(item.PackSize, isPack64); + WRITE_32_VAL_SPEC(item.Size, isUnPack64); + + Write16((UInt16)item.Name.Len()); + + UInt16 zip64ExtraSize = (UInt16)((isUnPack64 ? 8: 0) + (isPack64 ? 8: 0) + (isPosition64 ? 8: 0)); const UInt16 kNtfsExtraSize = 4 + 2 + 2 + (3 * 8); - UInt16 centralExtraSize = (UInt16)(isZip64 ? (4 + zip64ExtraSize) : 0) + (item.NtfsTimeIsDefined ? (4 + kNtfsExtraSize) : 0); - centralExtraSize = (UInt16)(centralExtraSize + item.CentralExtra.GetSize()); - WriteUInt16(centralExtraSize); // test it; - WriteUInt16((UInt16)item.Comment.GetCapacity()); - WriteUInt16(0); // DiskNumberStart; - WriteUInt16(item.InternalAttributes); - WriteUInt32(item.ExternalAttributes); - WriteUInt32(isPosition64 ? 0xFFFFFFFF: (UInt32)item.LocalHeaderPosition); - WriteBytes((const char *)item.Name, item.Name.Length()); + const UInt16 centralExtraSize = (UInt16)( + (isZip64 ? 4 + zip64ExtraSize : 0) + + (item.NtfsTimeIsDefined ? 4 + kNtfsExtraSize : 0) + + item.CentralExtra.GetSize()); + + Write16(centralExtraSize); // test it; + Write16((UInt16)item.Comment.Size()); + Write16(0); // DiskNumberStart; + Write16(item.InternalAttrib); + Write32(item.ExternalAttrib); + WRITE_32_VAL_SPEC(item.LocalHeaderPos, isPosition64); + WriteBytes((const char *)item.Name, item.Name.Len()); + if (isZip64) { - WriteUInt16(NFileHeader::NExtraID::kZip64); - WriteUInt16(zip64ExtraSize); - if(isUnPack64) - WriteUInt64(item.UnPackSize); - if(isPack64) - WriteUInt64(item.PackSize); - if(isPosition64) - WriteUInt64(item.LocalHeaderPosition); + Write16(NFileHeader::NExtraID::kZip64); + Write16(zip64ExtraSize); + if (isUnPack64) + Write64(item.Size); + if (isPack64) + Write64(item.PackSize); + if (isPosition64) + Write64(item.LocalHeaderPos); } + if (item.NtfsTimeIsDefined) { - WriteUInt16(NFileHeader::NExtraID::kNTFS); - WriteUInt16(kNtfsExtraSize); - WriteUInt32(0); // reserved - WriteUInt16(NFileHeader::NNtfsExtra::kTagTime); - WriteUInt16(8 * 3); - WriteUInt32(item.NtfsMTime.dwLowDateTime); - WriteUInt32(item.NtfsMTime.dwHighDateTime); - WriteUInt32(item.NtfsATime.dwLowDateTime); - WriteUInt32(item.NtfsATime.dwHighDateTime); - WriteUInt32(item.NtfsCTime.dwLowDateTime); - WriteUInt32(item.NtfsCTime.dwHighDateTime); + Write16(NFileHeader::NExtraID::kNTFS); + Write16(kNtfsExtraSize); + Write32(0); // reserved + Write16(NFileHeader::NNtfsExtra::kTagTime); + Write16(8 * 3); + WriteNtfsTime(item.Ntfs_MTime); + WriteNtfsTime(item.Ntfs_ATime); + WriteNtfsTime(item.Ntfs_CTime); } + WriteExtra(item.CentralExtra); - if (item.Comment.GetCapacity() > 0) - WriteBytes(item.Comment, (UInt32)item.Comment.GetCapacity()); + if (item.Comment.Size() > 0) + WriteBytes(item.Comment, (UInt32)item.Comment.Size()); } -void COutArchive::WriteCentralDir(const CObjectVector &items, const CByteBuffer *comment) +void COutArchive::WriteCentralDir(const CObjectVector &items, const CByteBuffer *comment) { - SeekTo(m_BasePosition); + SeekToCurPos(); - UInt64 cdOffset = GetCurrentPosition(); - for(int i = 0; i < items.Size(); i++) + UInt64 cdOffset = GetCurPos(); + FOR_VECTOR (i, items) WriteCentralHeader(items[i]); - UInt64 cd64EndOffset = GetCurrentPosition(); + UInt64 cd64EndOffset = GetCurPos(); UInt64 cdSize = cd64EndOffset - cdOffset; - bool cdOffset64 = cdOffset >= 0xFFFFFFFF; - bool cdSize64 = cdSize >= 0xFFFFFFFF; + bool cdOffset64 = DOES_NEED_ZIP64(cdOffset); + bool cdSize64 = DOES_NEED_ZIP64(cdSize); bool items64 = items.Size() >= 0xFFFF; bool isZip64 = (cdOffset64 || cdSize64 || items64); + + // isZip64 = true; // to test Zip64 if (isZip64) { - WriteUInt32(NSignature::kZip64EndOfCentralDir); - WriteUInt64(kZip64EcdSize); // ThisDiskNumber = 0; - WriteUInt16(45); // version - WriteUInt16(45); // version - WriteUInt32(0); // ThisDiskNumber = 0; - WriteUInt32(0); // StartCentralDirectoryDiskNumber;; - WriteUInt64((UInt64)items.Size()); - WriteUInt64((UInt64)items.Size()); - WriteUInt64((UInt64)cdSize); - WriteUInt64((UInt64)cdOffset); - - WriteUInt32(NSignature::kZip64EndOfCentralDirLocator); - WriteUInt32(0); // number of the disk with the start of the zip64 end of central directory - WriteUInt64(cd64EndOffset); - WriteUInt32(1); // total number of disks + Write32(NSignature::kEcd64); + Write64(kEcd64_MainSize); + Write16(45); // made by version + Write16(45); // extract version + Write32(0); // ThisDiskNumber = 0; + Write32(0); // StartCentralDirectoryDiskNumber;; + Write64((UInt64)items.Size()); + Write64((UInt64)items.Size()); + Write64((UInt64)cdSize); + Write64((UInt64)cdOffset); + + Write32(NSignature::kEcd64Locator); + Write32(0); // number of the disk with the start of the zip64 end of central directory + Write64(cd64EndOffset); + Write32(1); // total number of disks } - WriteUInt32(NSignature::kEndOfCentralDir); - WriteUInt16(0); // ThisDiskNumber = 0; - WriteUInt16(0); // StartCentralDirectoryDiskNumber; - WriteUInt16((UInt16)(items64 ? 0xFFFF: items.Size())); - WriteUInt16((UInt16)(items64 ? 0xFFFF: items.Size())); - WriteUInt32(cdSize64 ? 0xFFFFFFFF: (UInt32)cdSize); - WriteUInt32(cdOffset64 ? 0xFFFFFFFF: (UInt32)cdOffset); - UInt32 commentSize = (UInt32)(comment ? comment->GetCapacity() : 0); - WriteUInt16((UInt16)commentSize); + + Write32(NSignature::kEcd); + Write16(0); // ThisDiskNumber = 0; + Write16(0); // StartCentralDirectoryDiskNumber; + Write16((UInt16)(items64 ? 0xFFFF: items.Size())); + Write16((UInt16)(items64 ? 0xFFFF: items.Size())); + + WRITE_32_VAL_SPEC(cdSize, cdSize64); + WRITE_32_VAL_SPEC(cdOffset, cdOffset64); + + UInt32 commentSize = (UInt32)(comment ? comment->Size() : 0); + Write16((UInt16)commentSize); if (commentSize > 0) WriteBytes((const Byte *)*comment, commentSize); m_OutBuffer.FlushWithCheck(); @@ -271,14 +287,21 @@ void COutArchive::CreateStreamForCompressing(IOutStream **outStream) { COffsetOutStream *streamSpec = new COffsetOutStream; CMyComPtr tempStream(streamSpec); - streamSpec->Init(m_Stream, m_BasePosition + m_LocalFileHeaderSize); + streamSpec->Init(m_Stream, m_Base + m_CurPos + m_LocalFileHeaderSize); *outStream = tempStream.Detach(); } +/* void COutArchive::SeekToPackedDataPosition() { SeekTo(m_BasePosition + m_LocalFileHeaderSize); } +*/ + +void COutArchive::SeekToCurPos() +{ + SeekToRelatPos(m_CurPos); +} void COutArchive::CreateStreamForCopying(ISequentialOutStream **outStream) { diff --git a/CPP/7zip/Archive/Zip/ZipOut.h b/CPP/7zip/Archive/Zip/ZipOut.h old mode 100755 new mode 100644 index 2f6349e5..eaaa0320 --- a/CPP/7zip/Archive/Zip/ZipOut.h +++ b/CPP/7zip/Archive/Zip/ZipOut.h @@ -3,7 +3,7 @@ #ifndef __ZIP_OUT_H #define __ZIP_OUT_H -#include "Common/MyCom.h" +#include "../../../Common/MyCom.h" #include "../../IStream.h" #include "../../Common/OutBuffer.h" @@ -14,41 +14,73 @@ namespace NArchive { namespace NZip { // can throw CSystemException and COutBufferException - + +class CItemOut: public CItem +{ +public: + FILETIME Ntfs_MTime; + FILETIME Ntfs_ATime; + FILETIME Ntfs_CTime; + bool NtfsTimeIsDefined; + + // It's possible that NtfsTime is not defined, but there is NtfsTime in Extra. + + CItemOut(): NtfsTimeIsDefined(false) {} +}; + class COutArchive { CMyComPtr m_Stream; COutBuffer m_OutBuffer; - UInt64 m_BasePosition; + UInt64 m_Base; // Base of arc (offset in output Stream) + UInt64 m_CurPos; // Curent position in archive (relative from m_Base) + UInt32 m_LocalFileHeaderSize; UInt32 m_ExtraSize; bool m_IsZip64; + void SeekToRelatPos(UInt64 offset); + void WriteBytes(const void *buffer, UInt32 size); - void WriteByte(Byte b); - void WriteUInt16(UInt16 value); - void WriteUInt32(UInt32 value); - void WriteUInt64(UInt64 value); + void Write8(Byte b); + void Write16(UInt16 val); + void Write32(UInt32 val); + void Write64(UInt64 val); + void WriteNtfsTime(const FILETIME &ft) + { + Write32(ft.dwLowDateTime); + Write32(ft.dwHighDateTime); + } - void WriteExtraHeader(const CItem &item); - void WriteCentralHeader(const CItem &item); void WriteExtra(const CExtraBlock &extra); - void SeekTo(UInt64 offset); + void WriteCommonItemInfo(const CLocalItem &item, bool isZip64); + void WriteCentralHeader(const CItemOut &item); + + void PrepareWriteCompressedDataZip64(unsigned fileNameLen, bool isZip64, bool aesEncryption); + public: - void Create(IOutStream *outStream); - void MoveBasePosition(UInt64 distanceToMove); - UInt64 GetCurrentPosition() const { return m_BasePosition; }; - void PrepareWriteCompressedDataZip64(UInt16 fileNameLength, bool isZip64, bool aesEncryption); - void PrepareWriteCompressedData(UInt16 fileNameLength, UInt64 unPackSize, bool aesEncryption); - void PrepareWriteCompressedData2(UInt16 fileNameLength, UInt64 unPackSize, UInt64 packSize, bool aesEncryption); + HRESULT Create(IOutStream *outStream); + + void MoveCurPos(UInt64 distanceToMove); + UInt64 GetCurPos() const { return m_CurPos; }; + + void SeekToCurPos(); + + void PrepareWriteCompressedData(unsigned fileNameLen, UInt64 unPackSize, bool aesEncryption); + void PrepareWriteCompressedData2(unsigned fileNameLen, UInt64 unPackSize, UInt64 packSize, bool aesEncryption); void WriteLocalHeader(const CLocalItem &item); - void WriteCentralDir(const CObjectVector &items, const CByteBuffer *comment); + void WriteLocalHeader_And_SeekToNextFile(const CLocalItem &item) + { + WriteLocalHeader(item); + SeekToCurPos(); + } + + void WriteCentralDir(const CObjectVector &items, const CByteBuffer *comment); void CreateStreamForCompressing(IOutStream **outStream); void CreateStreamForCopying(ISequentialOutStream **outStream); - void SeekToPackedDataPosition(); }; }} diff --git a/CPP/7zip/Archive/Zip/ZipRegister.cpp b/CPP/7zip/Archive/Zip/ZipRegister.cpp old mode 100755 new mode 100644 index 3e7aade8..545e76c6 --- a/CPP/7zip/Archive/Zip/ZipRegister.cpp +++ b/CPP/7zip/Archive/Zip/ZipRegister.cpp @@ -5,14 +5,27 @@ #include "../../Common/RegisterArc.h" #include "ZipHandler.h" -static IInArchive *CreateArc() { return new NArchive::NZip::CHandler; } -#ifndef EXTRACT_ONLY -static IOutArchive *CreateArcOut() { return new NArchive::NZip::CHandler; } -#else -#define CreateArcOut 0 -#endif + +namespace NArchive { +namespace NZip { + +IMP_CreateArcIn +IMP_CreateArcOut static CArcInfo g_ArcInfo = - { L"zip", L"zip jar xpi odt ods docx xlsx", 0, 1, { 0x50, 0x4B, 0x03, 0x04 }, 4, false, CreateArc, CreateArcOut }; + { "zip", "zip zipx jar xpi odt ods docx xlsx epub", 0, 1, + 3 + 4 + 4 + 6, + { + 4, 0x50, 0x4B, 0x03, 0x04, + 4, 0x50, 0x4B, 0x05, 0x06, + 6, 0x50, 0x4B, 0x30, 0x30, 0x50, 0x4B, + }, + 0, + NArcInfoFlags::kFindSignature | + NArcInfoFlags::kMultiSignature | + NArcInfoFlags::kUseGlobalOffset, + REF_CreateArc_Pair, IsArc_Zip }; REGISTER_ARC(Zip) + +}} diff --git a/CPP/7zip/Archive/Zip/ZipUpdate.cpp b/CPP/7zip/Archive/Zip/ZipUpdate.cpp old mode 100755 new mode 100644 index a91364be..2978e387 --- a/CPP/7zip/Archive/Zip/ZipUpdate.cpp +++ b/CPP/7zip/Archive/Zip/ZipUpdate.cpp @@ -4,12 +4,12 @@ #include "../../../../C/Alloc.h" -#include "Common/AutoPtr.h" -#include "Common/Defs.h" -#include "Common/StringConvert.h" +#include "../../../Common/AutoPtr.h" +#include "../../../Common/Defs.h" +#include "../../../Common/StringConvert.h" -#include "Windows/Defs.h" -#include "Windows/Thread.h" +#include "../../../Windows/Defs.h" +#include "../../../Windows/Thread.h" #include "../../Common/CreateCoder.h" #include "../../Common/LimitedStreams.h" @@ -44,12 +44,12 @@ static const Byte kExtractHostOS = kHostOS; static const Byte kMethodForDirectory = NFileHeader::NCompressionMethod::kStored; -static HRESULT CopyBlockToArchive(ISequentialInStream *inStream, +static HRESULT CopyBlockToArchive(ISequentialInStream *inStream, UInt64 size, COutArchive &outArchive, ICompressProgressInfo *progress) { CMyComPtr outStream; outArchive.CreateStreamForCopying(&outStream); - return NCompress::CopyStream(inStream, outStream, progress); + return NCompress::CopyStream_ExactSize(inStream, outStream, size, progress); } static HRESULT WriteRange(IInStream *inStream, COutArchive &outArchive, @@ -57,13 +57,7 @@ static HRESULT WriteRange(IInStream *inStream, COutArchive &outArchive, { UInt64 position; RINOK(inStream->Seek(range.Position, STREAM_SEEK_SET, &position)); - - CLimitedSequentialInStream *streamSpec = new CLimitedSequentialInStream; - CMyComPtr inStreamLimited(streamSpec); - streamSpec->SetStream(inStream); - streamSpec->Init(range.Size); - - RINOK(CopyBlockToArchive(inStreamLimited, outArchive, progress)); + RINOK(CopyBlockToArchive(inStream, range.Size, outArchive, progress)); return progress->SetRatioInfo(&range.Size, &range.Size); } @@ -71,42 +65,42 @@ static void SetFileHeader( COutArchive &archive, const CCompressionMethodMode &options, const CUpdateItem &ui, - CItem &item) + CItemOut &item) { - item.UnPackSize = ui.Size; + item.Size = ui.Size; bool isDir; item.ClearFlags(); - if (ui.NewProperties) + if (ui.NewProps) { isDir = ui.IsDir; item.Name = ui.Name; item.SetUtf8(ui.IsUtf8); - item.ExternalAttributes = ui.Attributes; + item.ExternalAttrib = ui.Attrib; item.Time = ui.Time; - item.NtfsMTime = ui.NtfsMTime; - item.NtfsATime = ui.NtfsATime; - item.NtfsCTime = ui.NtfsCTime; + item.Ntfs_MTime = ui.Ntfs_MTime; + item.Ntfs_ATime = ui.Ntfs_ATime; + item.Ntfs_CTime = ui.Ntfs_CTime; item.NtfsTimeIsDefined = ui.NtfsTimeIsDefined; } else isDir = item.IsDir(); - item.LocalHeaderPosition = archive.GetCurrentPosition(); + item.LocalHeaderPos = archive.GetCurPos(); item.MadeByVersion.HostOS = kMadeByHostOS; item.MadeByVersion.Version = NFileHeader::NCompressionMethod::kMadeByProgramVersion; item.ExtractVersion.HostOS = kExtractHostOS; - item.InternalAttributes = 0; // test it + item.InternalAttrib = 0; // test it item.SetEncrypted(!isDir && options.PasswordIsDefined); if (isDir) { item.ExtractVersion.Version = NFileHeader::NCompressionMethod::kExtractVersion_Dir; - item.CompressionMethod = kMethodForDirectory; + item.Method = kMethodForDirectory; item.PackSize = 0; - item.FileCRC = 0; // test it + item.Crc = 0; // test it } } @@ -114,9 +108,9 @@ static void SetItemInfoFromCompressingResult(const CCompressingResult &compressi bool isAesMode, Byte aesKeyMode, CItem &item) { item.ExtractVersion.Version = compressingResult.ExtractVersion; - item.CompressionMethod = compressingResult.Method; - item.FileCRC = compressingResult.CRC; - item.UnPackSize = compressingResult.UnpackSize; + item.Method = compressingResult.Method; + item.Crc = compressingResult.CRC; + item.Size = compressingResult.UnpackSize; item.PackSize = compressingResult.PackSize; item.LocalExtra.Clear(); @@ -124,11 +118,11 @@ static void SetItemInfoFromCompressingResult(const CCompressingResult &compressi if (isAesMode) { - CWzAesExtraField wzAesField; + CWzAesExtra wzAesField; wzAesField.Strength = aesKeyMode; wzAesField.Method = compressingResult.Method; - item.CompressionMethod = NFileHeader::NCompressionMethod::kWzAES; - item.FileCRC = 0; + item.Method = NFileHeader::NCompressionMethod::kWzAES; + item.Crc = 0; CExtraSubBlock sb; wzAesField.SetSubBlock(sb); item.LocalExtra.SubBlocks.Add(sb); @@ -142,10 +136,7 @@ static THREAD_FUNC_DECL CoderThread(void *threadCoderInfo); struct CThreadInfo { - #ifdef EXTERNAL_CODECS - CMyComPtr _codecsInfo; - const CObjectVector *_externalCodecs; - #endif + DECL_EXTERNAL_CODECS_LOC_VARS2; NWindows::CThread Thread; NWindows::NSynchronization::CAutoResetEvent CompressEvent; @@ -202,9 +193,7 @@ void CThreadInfo::WaitAndCode() if (ExitThread) return; Result = Coder.Compress( - #ifdef EXTERNAL_CODECS - _codecsInfo, _externalCodecs, - #endif + EXTERNAL_CODECS_LOC_VARS InStream, OutStream, Progress, CompressingResult); if (Result == S_OK && Progress) Result = Progress->SetRatioInfo(&CompressingResult.UnpackSize, &CompressingResult.PackSize); @@ -224,7 +213,7 @@ public: CObjectVector Threads; ~CThreads() { - for (int i = 0; i < Threads.Size(); i++) + FOR_VECTOR (i, Threads) Threads[i].StopWaitClose(); } }; @@ -245,7 +234,7 @@ public: CMemRefs(CMemBlockManagerMt *manager): Manager(manager) {} ; ~CMemRefs() { - for (int i = 0; i < Refs.Size(); i++) + FOR_VECTOR (i, Refs) Refs[i].FreeOpt(Manager); } }; @@ -335,69 +324,74 @@ STDMETHODIMP CMtProgressMixer::SetRatioInfo(const UInt64 *inSize, const UInt64 * #endif -static HRESULT UpdateItemOldData(COutArchive &archive, - IInStream *inStream, - const CUpdateItem &ui, CItemEx &item, +static HRESULT UpdateItemOldData( + COutArchive &archive, + CInArchive *inArchive, + const CItemEx &itemEx, + const CUpdateItem &ui, + CItemOut &item, /* bool izZip64, */ ICompressProgressInfo *progress, UInt64 &complexity) { - if (ui.NewProperties) + if (ui.NewProps) { if (item.HasDescriptor()) return E_NOTIMPL; // use old name size. // CUpdateRange range(item.GetLocalExtraPosition(), item.LocalExtraSize + item.PackSize); - CUpdateRange range(item.GetDataPosition(), item.PackSize); + CUpdateRange range(inArchive->GetOffsetInStream(itemEx.GetDataPosition()), itemEx.PackSize); - // item.ExternalAttributes = ui.Attributes; - // Test it + // we keep ExternalAttrib and some another properties from old archive + // item.ExternalAttrib = ui.Attrib; + item.Name = ui.Name; item.SetUtf8(ui.IsUtf8); item.Time = ui.Time; - item.NtfsMTime = ui.NtfsMTime; - item.NtfsATime = ui.NtfsATime; - item.NtfsCTime = ui.NtfsCTime; + 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(); - - archive.PrepareWriteCompressedData2((UInt16)item.Name.Length(), item.UnPackSize, item.PackSize, item.LocalExtra.HasWzAesField()); - item.LocalHeaderPosition = archive.GetCurrentPosition(); - archive.SeekToPackedDataPosition(); - RINOK(WriteRange(inStream, archive, range, progress)); - complexity += range.Size; + item.LocalHeaderPos = archive.GetCurPos(); + + archive.PrepareWriteCompressedData2(item.Name.Len(), item.Size, item.PackSize, item.LocalExtra.HasWzAes()); archive.WriteLocalHeader(item); + RINOK(WriteRange(inArchive->Stream, archive, range, progress)); + complexity += range.Size; } else { - CUpdateRange range(item.LocalHeaderPosition, item.GetLocalFullSize()); + CUpdateRange range(inArchive->GetOffsetInStream(itemEx.LocalHeaderPos), itemEx.GetLocalFullSize()); // set new header position - item.LocalHeaderPosition = archive.GetCurrentPosition(); + item.LocalHeaderPos = archive.GetCurPos(); - RINOK(WriteRange(inStream, archive, range, progress)); + RINOK(WriteRange(inArchive->Stream, archive, range, progress)); complexity += range.Size; - archive.MoveBasePosition(range.Size); + archive.MoveCurPos(range.Size); } return S_OK; } static void WriteDirHeader(COutArchive &archive, const CCompressionMethodMode *options, - const CUpdateItem &ui, CItemEx &item) + const CUpdateItem &ui, CItemOut &item) { SetFileHeader(archive, *options, ui, item); - archive.PrepareWriteCompressedData((UInt16)item.Name.Length(), ui.Size, options->IsRealAesMode()); - archive.WriteLocalHeader(item); + archive.PrepareWriteCompressedData(item.Name.Len(), ui.Size, + // options->IsRealAesMode() + false // fixed 9.31 + ); + archive.WriteLocalHeader_And_SeekToNextFile(item); } static HRESULT Update2St( DECL_EXTERNAL_CODECS_LOC_VARS COutArchive &archive, CInArchive *inArchive, - IInStream *inStream, const CObjectVector &inputItems, const CObjectVector &updateItems, const CCompressionMethodMode *options, @@ -410,26 +404,29 @@ static HRESULT Update2St( CAddCommon compressor(*options); - CObjectVector items; + CObjectVector items; UInt64 unpackSizeTotal = 0, packSizeTotal = 0; - for (int itemIndex = 0; itemIndex < updateItems.Size(); itemIndex++) + FOR_VECTOR (itemIndex, updateItems) { lps->InSize = unpackSizeTotal; lps->OutSize = packSizeTotal; RINOK(lps->SetCur()); const CUpdateItem &ui = updateItems[itemIndex]; - CItemEx item; - if (!ui.NewProperties || !ui.NewData) + CItemEx itemEx; + CItemOut item; + + if (!ui.NewProps || !ui.NewData) { - item = inputItems[ui.IndexInArchive]; - if (inArchive->ReadLocalItemAfterCdItemFull(item) != S_OK) + itemEx = inputItems[ui.IndexInArc]; + if (inArchive->ReadLocalItemAfterCdItemFull(itemEx) != S_OK) return E_NOTIMPL; + (CItem &)item = itemEx; } if (ui.NewData) { - bool isDir = ((ui.NewProperties) ? ui.IsDir : item.IsDir()); + bool isDir = ((ui.NewProps) ? ui.IsDir : item.IsDir()); if (isDir) { WriteDirHeader(archive, options, ui, item); @@ -445,10 +442,12 @@ static HRESULT Update2St( continue; } RINOK(res); + if (!fileInStream) + return E_INVALIDARG; // file Size can be 64-bit !!! SetFileHeader(archive, *options, ui, item); - archive.PrepareWriteCompressedData((UInt16)item.Name.Length(), ui.Size, options->IsRealAesMode()); + archive.PrepareWriteCompressedData(item.Name.Len(), ui.Size, options->IsRealAesMode()); CCompressingResult compressingResult; CMyComPtr outStream; archive.CreateStreamForCompressing(&outStream); @@ -456,9 +455,9 @@ static HRESULT Update2St( EXTERNAL_CODECS_LOC_VARS fileInStream, outStream, progress, compressingResult)); SetItemInfoFromCompressingResult(compressingResult, options->IsRealAesMode(), options->AesKeyMode, item); - archive.WriteLocalHeader(item); + archive.WriteLocalHeader_And_SeekToNextFile(item); RINOK(updateCallback->SetOperationResult(NArchive::NUpdate::NOperationResult::kOK)); - unpackSizeTotal += item.UnPackSize; + unpackSizeTotal += item.Size; packSizeTotal += item.PackSize; } } @@ -466,12 +465,12 @@ static HRESULT Update2St( { UInt64 complexity = 0; lps->SendRatio = false; - RINOK(UpdateItemOldData(archive, inStream, ui, item, progress, complexity)); + RINOK(UpdateItemOldData(archive, inArchive, itemEx, ui, item, progress, complexity)); lps->SendRatio = true; lps->ProgressOffset += complexity; } items.Add(item); - lps->ProgressOffset += NFileHeader::kLocalBlockSize; + lps->ProgressOffset += kLocalHeaderSize; } lps->InSize = unpackSizeTotal; lps->OutSize = packSizeTotal; @@ -484,7 +483,6 @@ static HRESULT Update2( DECL_EXTERNAL_CODECS_LOC_VARS COutArchive &archive, CInArchive *inArchive, - IInStream *inStream, const CObjectVector &inputItems, const CObjectVector &updateItems, const CCompressionMethodMode *options, @@ -495,7 +493,7 @@ static HRESULT Update2( UInt64 numFilesToCompress = 0; UInt64 numBytesToCompress = 0; - int i; + unsigned i; for (i = 0; i < updateItems.Size(); i++) { const CUpdateItem &ui = updateItems[i]; @@ -511,18 +509,18 @@ static HRESULT Update2( } else { - CItemEx inputItem = inputItems[ui.IndexInArchive]; + CItemEx inputItem = inputItems[ui.IndexInArc]; if (inArchive->ReadLocalItemAfterCdItemFull(inputItem) != S_OK) return E_NOTIMPL; complexity += inputItem.GetLocalFullSize(); // complexity += inputItem.GetCentralExtraPlusCommentSize(); } - complexity += NFileHeader::kLocalBlockSize; - complexity += NFileHeader::kCentralBlockSize; + complexity += kLocalHeaderSize; + complexity += kCentralHeaderSize; } if (comment) - complexity += comment->GetCapacity(); + complexity += comment->Size(); complexity++; // end of central updateCallback->SetTotal(complexity); @@ -540,6 +538,9 @@ static HRESULT Update2( UInt32 numThreads = options->NumThreads; if (numThreads > kNumMaxThreads) numThreads = kNumMaxThreads; + if (numThreads < 1) + numThreads = 1; + const size_t kMemPerThread = (1 << 25); const size_t kBlockSize = 1 << 16; @@ -549,16 +550,18 @@ static HRESULT Update2( if (numFilesToCompress <= 1) mtMode = false; + Byte method = options->MethodSequence.Front(); if (!mtMode) { - if (numThreads < 2) - if (options2.MethodInfo.FindProp(NCoderPropID::kNumThreads) < 0 && - options2.NumThreadsWasChanged) - options2.MethodInfo.AddNumThreadsProp(1); + if (options2.MethodInfo.FindProp(NCoderPropID::kNumThreads) < 0) + { + // fixed for 9.31. bzip2 default is just one thread. + if (options2.NumThreadsWasChanged || method == NFileHeader::NCompressionMethod::kBZip2) + options2.MethodInfo.AddNumThreadsProp(numThreads); + } } else { - Byte method = options->MethodSequence.Front(); if (method == NFileHeader::NCompressionMethod::kStored && !options->PasswordIsDefined) numThreads = 1; if (method == NFileHeader::NCompressionMethod::kBZip2) @@ -594,13 +597,13 @@ static HRESULT Update2( #endif return Update2St( EXTERNAL_CODECS_LOC_VARS - archive, inArchive, inStream, + archive, inArchive, inputItems, updateItems, &options2, comment, updateCallback); #ifndef _7ZIP_ST - CObjectVector items; + CObjectVector items; CMtProgressMixer *mtProgressMixerSpec = new CMtProgressMixer; CMyComPtr progress = mtProgressMixerSpec; @@ -629,8 +632,7 @@ static HRESULT Update2( { CThreadInfo &threadInfo = threads.Threads[i]; #ifdef EXTERNAL_CODECS - threadInfo._codecsInfo = codecsInfo; - threadInfo._externalCodecs = externalCodecs; + threadInfo.__externalCodecs = __externalCodecs; #endif RINOK(threadInfo.CreateEvents()); threadInfo.OutStreamSpec = new COutMemStream(&memManager); @@ -643,9 +645,9 @@ static HRESULT Update2( RINOK(threadInfo.CreateThread()); } } - int mtItemIndex = 0; + unsigned mtItemIndex = 0; - int itemIndex = 0; + unsigned itemIndex = 0; int lastRealStreamItemIndex = -1; while (itemIndex < updateItems.Size()) @@ -655,17 +657,19 @@ static HRESULT Update2( const CUpdateItem &ui = updateItems[mtItemIndex++]; if (!ui.NewData) continue; - CItemEx item; - if (ui.NewProperties) + CItemEx itemEx; + CItemOut item; + if (ui.NewProps) { if (ui.IsDir) continue; } else { - item = inputItems[ui.IndexInArchive]; - if (inArchive->ReadLocalItemAfterCdItemFull(item) != S_OK) + itemEx = inputItems[ui.IndexInArc]; + if (inArchive->ReadLocalItemAfterCdItemFull(itemEx) != S_OK) return E_NOTIMPL; + (CItem &)item = itemEx; if (item.IsDir()) continue; } @@ -676,13 +680,15 @@ static HRESULT Update2( if (res == S_FALSE) { complexity += ui.Size; - complexity += NFileHeader::kLocalBlockSize; + complexity += kLocalHeaderSize; mtProgressMixerSpec->Mixer2->SetProgressOffset(complexity); RINOK(updateCallback->SetOperationResult(NArchive::NUpdate::NOperationResult::kOK)); refs.Refs[mtItemIndex - 1].Skip = true; continue; } RINOK(res); + if (!fileInStream) + return E_INVALIDARG; RINOK(updateCallback->SetOperationResult(NArchive::NUpdate::NOperationResult::kOK)); } @@ -719,29 +725,31 @@ static HRESULT Update2( const CUpdateItem &ui = updateItems[itemIndex]; - CItemEx item; - if (!ui.NewProperties || !ui.NewData) + CItemEx itemEx; + CItemOut item; + if (!ui.NewProps || !ui.NewData) { - item = inputItems[ui.IndexInArchive]; - if (inArchive->ReadLocalItemAfterCdItemFull(item) != S_OK) + itemEx = inputItems[ui.IndexInArc]; + if (inArchive->ReadLocalItemAfterCdItemFull(itemEx) != S_OK) return E_NOTIMPL; + (CItem &)item = itemEx; } if (ui.NewData) { - bool isDir = ((ui.NewProperties) ? ui.IsDir : item.IsDir()); + bool isDir = ((ui.NewProps) ? ui.IsDir : item.IsDir()); if (isDir) { WriteDirHeader(archive, options, ui, item); } else { - if (lastRealStreamItemIndex < itemIndex) + if (lastRealStreamItemIndex < (int)itemIndex) { lastRealStreamItemIndex = itemIndex; SetFileHeader(archive, *options, ui, item); // file Size can be 64-bit !!! - archive.PrepareWriteCompressedData((UInt16)item.Name.Length(), ui.Size, options->IsRealAesMode()); + archive.PrepareWriteCompressedData(item.Name.Len(), ui.Size, options->IsRealAesMode()); } CMemBlocks2 &memRef = refs.Refs[itemIndex]; @@ -750,10 +758,13 @@ static HRESULT Update2( CMyComPtr outStream; archive.CreateStreamForCompressing(&outStream); memRef.WriteToStream(memManager.GetBlockSize(), outStream); + SetFileHeader(archive, *options, ui, item); + // the BUG was fixed in 9.26: + // SetItemInfoFromCompressingResult must be after SetFileHeader + // to write correct Size. SetItemInfoFromCompressingResult(memRef.CompressingResult, options->IsRealAesMode(), options->AesKeyMode, item); - SetFileHeader(archive, *options, ui, item); - archive.WriteLocalHeader(item); + archive.WriteLocalHeader_And_SeekToNextFile(item); // RINOK(updateCallback->SetOperationResult(NArchive::NUpdate::NOperationResult::kOK)); memRef.FreeOpt(&memManager); } @@ -783,10 +794,10 @@ static HRESULT Update2( { RINOK(threadInfo.OutStreamSpec->WriteToRealStream()); threadInfo.OutStreamSpec->ReleaseOutStream(); + SetFileHeader(archive, *options, ui, item); SetItemInfoFromCompressingResult(threadInfo.CompressingResult, options->IsRealAesMode(), options->AesKeyMode, item); - SetFileHeader(archive, *options, ui, item); - archive.WriteLocalHeader(item); + archive.WriteLocalHeader_And_SeekToNextFile(item); } else { @@ -801,10 +812,10 @@ static HRESULT Update2( } else { - RINOK(UpdateItemOldData(archive, inStream, ui, item, progress, complexity)); + RINOK(UpdateItemOldData(archive, inArchive, itemEx, ui, item, progress, complexity)); } items.Add(item); - complexity += NFileHeader::kLocalBlockSize; + complexity += kLocalHeaderSize; mtProgressMixerSpec->Mixer2->SetProgressOffset(complexity); itemIndex++; } @@ -993,15 +1004,18 @@ STDMETHODIMP CCacheOutStream::Write(const void *data, UInt32 size, UInt32 *proce STDMETHODIMP CCacheOutStream::Seek(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition) { - switch(seekOrigin) + switch (seekOrigin) { - case STREAM_SEEK_SET: _virtPos = offset; break; - case STREAM_SEEK_CUR: _virtPos += offset; break; - case STREAM_SEEK_END: _virtPos = _virtSize + offset; break; + case STREAM_SEEK_SET: break; + case STREAM_SEEK_CUR: offset += _virtPos; break; + case STREAM_SEEK_END: offset += _virtSize; break; default: return STG_E_INVALIDFUNCTION; } + if (offset < 0) + return HRESULT_WIN32_ERROR_NEGATIVE_SEEK; + _virtPos = offset; if (newPosition) - *newPosition = _virtPos; + *newPosition = offset; return S_OK; } @@ -1029,16 +1043,33 @@ HRESULT Update( const CObjectVector &inputItems, const CObjectVector &updateItems, ISequentialOutStream *seqOutStream, - CInArchive *inArchive, + CInArchive *inArchive, bool removeSfx, CCompressionMethodMode *compressionMethodMode, IArchiveUpdateCallback *updateCallback) { + if (inArchive) + { + if (!inArchive->CanUpdate()) + return E_NOTIMPL; + } + + CMyComPtr outStream; { CMyComPtr outStreamReal; seqOutStream->QueryInterface(IID_IOutStream, (void **)&outStreamReal); if (!outStreamReal) return E_NOTIMPL; + + if (inArchive) + { + if (inArchive->ArcInfo.Base > 0 && !removeSfx) + { + RINOK(inArchive->Stream->Seek(0, STREAM_SEEK_SET, NULL)); + RINOK(NCompress::CopyStream_ExactSize(inArchive->Stream, outStreamReal, inArchive->ArcInfo.Base, NULL)); + } + } + CCacheOutStream *cacheStream = new CCacheOutStream(); outStream = cacheStream; if (!cacheStream->Allocate()) @@ -1046,32 +1077,23 @@ HRESULT Update( RINOK(cacheStream->Init(outStreamReal)); } - if (inArchive) - { - if (inArchive->ArcInfo.Base != 0 || - inArchive->ArcInfo.StartPosition != 0 || - !inArchive->IsOkHeaders) - return E_NOTIMPL; - } - COutArchive outArchive; - outArchive.Create(outStream); - /* - if (inArchive && inArchive->ArcInfo.StartPosition > 0) + RINOK(outArchive.Create(outStream)); + + if (inArchive) { - CMyComPtr inStream; - inStream.Attach(inArchive->CreateLimitedStream(0, inArchive->ArcInfo.StartPosition)); - RINOK(CopyBlockToArchive(inStream, outArchive, NULL)); - outArchive.MoveBasePosition(inArchive->ArcInfo.StartPosition); + if ((Int64)inArchive->ArcInfo.MarkerPos2 > inArchive->ArcInfo.Base) + { + RINOK(inArchive->Stream->Seek(inArchive->ArcInfo.Base, STREAM_SEEK_SET, NULL)); + UInt64 embStubSize = inArchive->ArcInfo.MarkerPos2 - inArchive->ArcInfo.Base; + RINOK(NCompress::CopyStream_ExactSize(inArchive->Stream, outStream, embStubSize, NULL)); + outArchive.MoveCurPos(embStubSize); + } } - */ - CMyComPtr inStream; - if (inArchive) - inStream.Attach(inArchive->CreateStream()); return Update2( EXTERNAL_CODECS_LOC_VARS - outArchive, inArchive, inStream, + outArchive, inArchive, inputItems, updateItems, compressionMethodMode, inArchive ? &inArchive->ArcInfo.Comment : NULL, diff --git a/CPP/7zip/Archive/Zip/ZipUpdate.h b/CPP/7zip/Archive/Zip/ZipUpdate.h old mode 100755 new mode 100644 index eee16738..747c07bc --- a/CPP/7zip/Archive/Zip/ZipUpdate.h +++ b/CPP/7zip/Archive/Zip/ZipUpdate.h @@ -1,4 +1,4 @@ -// Zip/Update.h +// ZipUpdate.h #ifndef __ZIP_UPDATE_H #define __ZIP_UPDATE_H @@ -18,28 +18,29 @@ struct CUpdateRange { UInt64 Position; UInt64 Size; - CUpdateRange() {}; + + // CUpdateRange() {}; CUpdateRange(UInt64 position, UInt64 size): Position(position), Size(size) {}; }; struct CUpdateItem { bool NewData; - bool NewProperties; + bool NewProps; bool IsDir; bool NtfsTimeIsDefined; bool IsUtf8; - int IndexInArchive; + int IndexInArc; int IndexInClient; - UInt32 Attributes; + UInt32 Attrib; UInt32 Time; UInt64 Size; AString Name; // bool Commented; // CUpdateRange CommentRange; - FILETIME NtfsMTime; - FILETIME NtfsATime; - FILETIME NtfsCTime; + FILETIME Ntfs_MTime; + FILETIME Ntfs_ATime; + FILETIME Ntfs_CTime; CUpdateItem(): NtfsTimeIsDefined(false), IsUtf8(false), Size(0) {} }; @@ -49,7 +50,7 @@ HRESULT Update( const CObjectVector &inputItems, const CObjectVector &updateItems, ISequentialOutStream *seqOutStream, - CInArchive *inArchive, + CInArchive *inArchive, bool removeSfx, CCompressionMethodMode *compressionMethodMode, IArchiveUpdateCallback *updateCallback); -- cgit v1.2.3