From 54490d51d5c6b0d794dcbad2d634d4c95fc25b6c Mon Sep 17 00:00:00 2001 From: Igor Pavlov Date: Mon, 15 Jun 2015 00:00:00 +0000 Subject: 15.05 --- CPP/7zip/Archive/Zip/ZipAddCommon.cpp | 116 ++++++++++++++------- CPP/7zip/Archive/Zip/ZipAddCommon.h | 6 ++ CPP/7zip/Archive/Zip/ZipHandler.cpp | 180 +++++++++++++++++++++++---------- CPP/7zip/Archive/Zip/ZipHandler.h | 2 +- CPP/7zip/Archive/Zip/ZipHandlerOut.cpp | 24 ++--- CPP/7zip/Archive/Zip/ZipHeader.h | 2 + CPP/7zip/Archive/Zip/ZipIn.cpp | 23 +++-- CPP/7zip/Archive/Zip/ZipIn.h | 4 +- CPP/7zip/Archive/Zip/ZipItem.cpp | 7 +- CPP/7zip/Archive/Zip/ZipItem.h | 16 ++- CPP/7zip/Archive/Zip/ZipOut.h | 2 +- CPP/7zip/Archive/Zip/ZipRegister.cpp | 21 ++-- CPP/7zip/Archive/Zip/ZipUpdate.cpp | 80 ++++++++++++--- 13 files changed, 336 insertions(+), 147 deletions(-) (limited to 'CPP/7zip/Archive/Zip') diff --git a/CPP/7zip/Archive/Zip/ZipAddCommon.cpp b/CPP/7zip/Archive/Zip/ZipAddCommon.cpp index 9a0d7515..c9c290aa 100644 --- a/CPP/7zip/Archive/Zip/ZipAddCommon.cpp +++ b/CPP/7zip/Archive/Zip/ZipAddCommon.cpp @@ -3,6 +3,7 @@ #include "StdAfx.h" #include "../../../../C/7zCrc.h" +#include "../../../../C/Alloc.h" #include "../../../Windows/PropVariant.h" @@ -77,32 +78,46 @@ STDMETHODIMP CLzmaEncoder::Code(ISequentialInStream *inStream, ISequentialOutStr CAddCommon::CAddCommon(const CCompressionMethodMode &options): - _options(options), - _copyCoderSpec(NULL), - _cryptoStreamSpec(0) - {} + _options(options), + _copyCoderSpec(NULL), + _cryptoStreamSpec(NULL), + _buf(NULL) + {} -static HRESULT GetStreamCRC(ISequentialInStream *inStream, UInt32 &resultCRC) +CAddCommon::~CAddCommon() { + MidFree(_buf); +} + +static const UInt32 kBufSize = ((UInt32)1 << 16); + +HRESULT CAddCommon::CalcStreamCRC(ISequentialInStream *inStream, UInt32 &resultCRC) +{ + if (!_buf) + { + _buf = (Byte *)MidAlloc(kBufSize); + if (!_buf) + return E_OUTOFMEMORY; + } + UInt32 crc = CRC_INIT_VAL; - const UInt32 kBufSize = (1 << 14); - Byte buf[kBufSize]; for (;;) { UInt32 processed; - RINOK(inStream->Read(buf, kBufSize, &processed)); + RINOK(inStream->Read(_buf, kBufSize, &processed)); if (processed == 0) { resultCRC = CRC_GET_DIGEST(crc); return S_OK; } - crc = CrcUpdate(crc, buf, (size_t)processed); + crc = CrcUpdate(crc, _buf, (size_t)processed); } } HRESULT CAddCommon::Compress( DECL_EXTERNAL_CODECS_LOC_VARS ISequentialInStream *inStream, IOutStream *outStream, + UInt32 /* fileTime */, ICompressProgressInfo *progress, CCompressingResult &opRes) { if (!inStream) @@ -111,13 +126,14 @@ HRESULT CAddCommon::Compress( return E_INVALIDARG; } - CSequentialInStreamWithCRC *inSecCrcStreamSpec = NULL; + // CSequentialInStreamWithCRC *inSecCrcStreamSpec = NULL; CInStreamWithCRC *inCrcStreamSpec = NULL; CMyComPtr inCrcStream; { CMyComPtr inStream2; - // we don't support stdin, since stream from stdin can require 64-bit size header - RINOK(inStream->QueryInterface(IID_IInStream, (void **)&inStream2)); + + inStream->QueryInterface(IID_IInStream, (void **)&inStream2); + if (inStream2) { inCrcStreamSpec = new CInStreamWithCRC; @@ -127,28 +143,29 @@ HRESULT CAddCommon::Compress( } else { + // we don't support stdin, since stream from stdin can require 64-bit size header + return E_NOTIMPL; + /* inSecCrcStreamSpec = new CSequentialInStreamWithCRC; inCrcStream = inSecCrcStreamSpec; inSecCrcStreamSpec->SetStream(inStream); inSecCrcStreamSpec->Init(); + */ } } unsigned numTestMethods = _options.MethodSequence.Size(); - if (numTestMethods > 1 || _options.PasswordIsDefined) - { - if (!inCrcStreamSpec) - { - if (_options.PasswordIsDefined) - return E_NOTIMPL; - numTestMethods = 1; - } - } + if (numTestMethods > 1 && !inCrcStreamSpec) + numTestMethods = 1; + + UInt32 crc = 0; + bool crc_IsCalculated = false; Byte method = 0; - COutStreamReleaser outStreamReleaser; + CFilterCoder::C_OutStream_Releaser outStreamReleaser; opRes.ExtractVersion = NFileHeader::NCompressionMethod::kExtractVersion_Default; + opRes.FileTimeWasUsed = false; for (unsigned i = 0; i < numTestMethods; i++) { @@ -164,7 +181,7 @@ HRESULT CAddCommon::Compress( if (!_cryptoStream) { - _cryptoStreamSpec = new CFilterCoder; + _cryptoStreamSpec = new CFilterCoder(true); _cryptoStream = _cryptoStreamSpec; } @@ -186,13 +203,32 @@ HRESULT CAddCommon::Compress( _cryptoStreamSpec->Filter = _filterSpec = new NCrypto::NZip::CEncoder; _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)); + + UInt32 check; + + // if (inCrcStreamSpec) + { + if (!crc_IsCalculated) + { + RINOK(CalcStreamCRC(inStream, crc)); + crc_IsCalculated = true; + RINOK(inCrcStreamSpec->Seek(0, STREAM_SEEK_SET, NULL)); + } + check = (crc >> 16); + } + /* + else + { + opRes.FileTimeWasUsed = true; + check = (fileTime & 0xFFFF); + } + */ + + RINOK(_filterSpec->WriteHeader_Check16(outStream, (UInt16)check)); } RINOK(_cryptoStreamSpec->SetOutStream(outStream)); + RINOK(_cryptoStreamSpec->InitEncoder()); outStreamReleaser.FilterCoder = _cryptoStreamSpec; } @@ -250,7 +286,7 @@ HRESULT CAddCommon::Compress( } RINOK(CreateCoder( EXTERNAL_CODECS_LOC_VARS - methodId, _compressEncoder, true)); + methodId, true, _compressEncoder)); if (!_compressEncoder) return E_NOTIMPL; @@ -284,34 +320,42 @@ HRESULT CAddCommon::Compress( } } + if (_options.PasswordIsDefined) + { + RINOK(_cryptoStreamSpec->OutStreamFinish()); + + if (_options.IsAesMode) + { + RINOK(_filterAesSpec->WriteFooter(outStream)); + } + } + RINOK(outStream->Seek(0, STREAM_SEEK_CUR, &opRes.PackSize)); - if (inCrcStreamSpec) + // if (inCrcStreamSpec) { opRes.CRC = inCrcStreamSpec->GetCRC(); opRes.UnpackSize = inCrcStreamSpec->GetSize(); } + /* else { opRes.CRC = inSecCrcStreamSpec->GetCRC(); opRes.UnpackSize = inSecCrcStreamSpec->GetSize(); } + */ if (_options.PasswordIsDefined) { if (opRes.PackSize < opRes.UnpackSize + - (_options.IsAesMode ? _filterAesSpec->GetHeaderSize() : NCrypto::NZip::kHeaderSize)) + (_options.IsAesMode ? _filterAesSpec->GetAddPackSize() : NCrypto::NZip::kHeaderSize)) break; } else if (opRes.PackSize < opRes.UnpackSize) break; } - - if (_options.PasswordIsDefined && _options.IsAesMode) - { - RINOK(_filterAesSpec->WriteFooter(outStream)); - RINOK(outStream->Seek(0, STREAM_SEEK_CUR, &opRes.PackSize)); - } + + opRes.Method = method; return S_OK; } diff --git a/CPP/7zip/Archive/Zip/ZipAddCommon.h b/CPP/7zip/Archive/Zip/ZipAddCommon.h index e4c02db3..1e0c3bfa 100644 --- a/CPP/7zip/Archive/Zip/ZipAddCommon.h +++ b/CPP/7zip/Archive/Zip/ZipAddCommon.h @@ -26,6 +26,7 @@ struct CCompressingResult UInt32 CRC; UInt16 Method; Byte ExtractVersion; + bool FileTimeWasUsed; }; class CAddCommon @@ -43,11 +44,16 @@ class CAddCommon NCrypto::NZip::CEncoder *_filterSpec; NCrypto::NWzAes::CEncoder *_filterAesSpec; + Byte *_buf; + + HRESULT CalcStreamCRC(ISequentialInStream *inStream, UInt32 &resultCRC); public: CAddCommon(const CCompressionMethodMode &options); + ~CAddCommon(); HRESULT Compress( DECL_EXTERNAL_CODECS_LOC_VARS ISequentialInStream *inStream, IOutStream *outStream, + UInt32 fileTime, ICompressProgressInfo *progress, CCompressingResult &operationResult); }; diff --git a/CPP/7zip/Archive/Zip/ZipHandler.cpp b/CPP/7zip/Archive/Zip/ZipHandler.cpp index f556068c..3e29a880 100644 --- a/CPP/7zip/Archive/Zip/ZipHandler.cpp +++ b/CPP/7zip/Archive/Zip/ZipHandler.cpp @@ -28,6 +28,8 @@ #include "../Common/ItemNameUtils.h" #include "../Common/OutStreamWithCRC.h" +#include "../XzHandler.h" + #include "ZipHandler.h" using namespace NWindows; @@ -38,7 +40,7 @@ namespace NZip { static const CMethodId kMethodId_ZipBase = 0x040100; static const CMethodId kMethodId_BZip2 = 0x040202; -static const char *kHostOS[] = +static const char * const kHostOS[] = { "FAT" , "AMIGA" @@ -62,7 +64,7 @@ static const char *kHostOS[] = , "OS/X" }; -static const char *kMethods[] = +static const char * const kMethods[] = { "Store" , "Shrink" @@ -91,6 +93,7 @@ static const CIdToNamePair k_MethodIdNamePairs[] = { { NFileHeader::NCompressionMethod::kBZip2, "BZip2" }, { NFileHeader::NCompressionMethod::kLZMA, "LZMA" }, + { NFileHeader::NCompressionMethod::kXz, "xz" }, { NFileHeader::NCompressionMethod::kJpeg, "Jpeg" }, { NFileHeader::NCompressionMethod::kWavPack, "WavPack" }, { NFileHeader::NCompressionMethod::kPPMd, "PPMd" } @@ -156,14 +159,7 @@ CHandler::CHandler() static AString BytesToString(const CByteBuffer &data) { AString s; - unsigned size = (unsigned)data.Size(); - if (size > 0) - { - char *p = s.GetBuffer(size); - memcpy(p, (const Byte *)data, size); - p[size] = 0; - s.ReleaseBuffer(); - } + s.SetFrom_CalcLen((const char *)(const Byte *)data, (unsigned)data.Size()); return s; } @@ -220,6 +216,14 @@ STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value) prop = v; break; } + + case kpidReadOnly: + { + if (m_Archive.IsOpen()) + if (!m_Archive.CanUpdate()) + prop = true; + break; + } } prop.Detach(value); COM_TRY_END @@ -334,12 +338,12 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val case kpidMethod: { - UInt16 methodId = item.Method; + unsigned id = item.Method; AString m; if (item.IsEncrypted()) { - if (methodId == NFileHeader::NCompressionMethod::kWzAES) + if (id == NFileHeader::NCompressionMethod::kWzAES) { m += kMethod_AES; CWzAesExtra aesField; @@ -349,7 +353,7 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val s[0] = '-'; ConvertUInt32ToString(((unsigned)aesField.Strength + 1) * 64 , s + 1); m += s; - methodId = aesField.Method; + id = aesField.Method; } } else if (item.IsStrongEncrypted()) @@ -381,19 +385,19 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val { char temp[16]; const char *s = NULL; - if (methodId < ARRAY_SIZE(kMethods)) - s = kMethods[methodId]; + if (id < ARRAY_SIZE(kMethods)) + s = kMethods[id]; else { - s = FindNameForId(k_MethodIdNamePairs, ARRAY_SIZE(k_MethodIdNamePairs), methodId); + s = FindNameForId(k_MethodIdNamePairs, ARRAY_SIZE(k_MethodIdNamePairs), id); if (!s) { - ConvertUInt32ToString(methodId, temp); + ConvertUInt32ToString(id, temp); s = temp; } } m += s; - if (methodId == NFileHeader::NCompressionMethod::kLZMA && item.IsLzmaEOS()) + if (id == NFileHeader::NCompressionMethod::kLZMA && item.IsLzmaEOS()) m += ":EOS"; } @@ -507,9 +511,36 @@ HRESULT CLzmaDecoder::Code(ISequentialInStream *inStream, ISequentialOutStream * return Decoder->Code(inStream, outStream, NULL, outSize, progress); } + +class CXzDecoder: + public ICompressCoder, + public CMyUnknownImp +{ + NArchive::NXz::CDecoder _decoder; +public: + + STDMETHOD(Code)(ISequentialInStream *inStream, ISequentialOutStream *outStream, + const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress); + + MY_UNKNOWN_IMP +}; + +HRESULT CXzDecoder::Code(ISequentialInStream *inStream, ISequentialOutStream *outStream, + const UInt64 * /* inSize */, const UInt64 * /* outSize */, ICompressProgressInfo *progress) +{ + RINOK(_decoder.Decode(inStream, outStream, progress)); + Int32 opRes = _decoder.Get_Extract_OperationResult(); + if (opRes == NExtract::NOperationResult::kUnsupportedMethod) + return E_NOTIMPL; + if (opRes != NExtract::NOperationResult::kOK) + return S_FALSE; + return S_OK; +} + + struct CMethodItem { - UInt16 ZipMethod; + unsigned ZipMethod; CMyComPtr Coder; }; @@ -559,12 +590,13 @@ HRESULT CZipDecoder::Decode( Int32 &res) { res = NExtract::NOperationResult::kDataError; - CInStreamReleaser inStreamReleaser; + CFilterCoder::C_InStream_Releaser inStreamReleaser; bool needCRC = true; bool wzAesMode = false; bool pkAesMode = false; - UInt16 methodId = item.Method; + unsigned id = item.Method; + if (item.IsEncrypted()) { if (item.IsStrongEncrypted()) @@ -580,7 +612,7 @@ HRESULT CZipDecoder::Decode( return S_OK; } } - if (!pkAesMode && methodId == NFileHeader::NCompressionMethod::kWzAES) + if (!pkAesMode && id == NFileHeader::NCompressionMethod::kWzAES) { CWzAesExtra aesField; if (item.CentralExtra.GetWzAes(aesField)) @@ -613,6 +645,7 @@ HRESULT CZipDecoder::Decode( } CMyComPtr cryptoFilter; + if (item.IsEncrypted()) { if (wzAesMode) @@ -620,15 +653,18 @@ HRESULT CZipDecoder::Decode( CWzAesExtra aesField; if (!item.CentralExtra.GetWzAes(aesField)) return S_OK; - methodId = aesField.Method; + id = aesField.Method; if (!_wzAesDecoder) { _wzAesDecoderSpec = new NCrypto::NWzAes::CDecoder; _wzAesDecoder = _wzAesDecoderSpec; } cryptoFilter = _wzAesDecoder; - Byte properties = aesField.Strength; - RINOK(_wzAesDecoderSpec->SetDecoderProperties2(&properties, 1)); + if (!_wzAesDecoderSpec->SetKeyMode(aesField.Strength)) + { + res = NExtract::NOperationResult::kUnsupportedMethod; + return S_OK; + } } else if (pkAesMode) { @@ -648,6 +684,7 @@ HRESULT CZipDecoder::Decode( } cryptoFilter = _zipCryptoDecoder; } + CMyComPtr cryptoSetPassword; RINOK(cryptoFilter.QueryInterface(IID_ICryptoSetPassword, &cryptoSetPassword)); @@ -699,39 +736,41 @@ HRESULT CZipDecoder::Decode( unsigned m; for (m = 0; m < methodItems.Size(); m++) - if (methodItems[m].ZipMethod == methodId) + if (methodItems[m].ZipMethod == id) break; if (m == methodItems.Size()) { CMethodItem mi; - mi.ZipMethod = methodId; - if (methodId == NFileHeader::NCompressionMethod::kStored) + mi.ZipMethod = id; + if (id == NFileHeader::NCompressionMethod::kStored) mi.Coder = new NCompress::CCopyCoder; - else if (methodId == NFileHeader::NCompressionMethod::kShrunk) + else if (id == NFileHeader::NCompressionMethod::kShrunk) mi.Coder = new NCompress::NShrink::CDecoder; - else if (methodId == NFileHeader::NCompressionMethod::kImploded) + else if (id == NFileHeader::NCompressionMethod::kImploded) mi.Coder = new NCompress::NImplode::NDecoder::CCoder; - else if (methodId == NFileHeader::NCompressionMethod::kLZMA) + else if (id == NFileHeader::NCompressionMethod::kLZMA) mi.Coder = new CLzmaDecoder; - else if (methodId == NFileHeader::NCompressionMethod::kPPMd) + else if (id == NFileHeader::NCompressionMethod::kXz) + mi.Coder = new CXzDecoder; + else if (id == NFileHeader::NCompressionMethod::kPPMd) mi.Coder = new NCompress::NPpmdZip::CDecoder(true); else { CMethodId szMethodID; - if (methodId == NFileHeader::NCompressionMethod::kBZip2) + if (id == NFileHeader::NCompressionMethod::kBZip2) szMethodID = kMethodId_BZip2; else { - if (methodId > 0xFF) + if (id > 0xFF) { res = NExtract::NOperationResult::kUnsupportedMethod; return S_OK; } - szMethodID = kMethodId_ZipBase + (Byte)methodId; + szMethodID = kMethodId_ZipBase + (Byte)id; } - RINOK(CreateCoder(EXTERNAL_CODECS_LOC_VARS szMethodID, mi.Coder, false)); + RINOK(CreateCoder(EXTERNAL_CODECS_LOC_VARS szMethodID, false, mi.Coder)); if (mi.Coder == 0) { @@ -741,6 +780,7 @@ HRESULT CZipDecoder::Decode( } m = methodItems.Add(mi); } + ICompressCoder *coder = methodItems[m].Coder; { @@ -771,13 +811,23 @@ HRESULT CZipDecoder::Decode( { if (!filterStream) { - filterStreamSpec = new CFilterCoder; + filterStreamSpec = new CFilterCoder(false); filterStream = filterStreamSpec; } + filterStreamSpec->Filter = cryptoFilter; + if (wzAesMode) { result = _wzAesDecoderSpec->ReadHeader(inStream); + if (result == S_OK) + { + if (!_wzAesDecoderSpec->Init_and_CheckPassword()) + { + res = NExtract::NOperationResult::kWrongPassword; + return S_OK; + } + } } else if (pkAesMode) { @@ -785,43 +835,64 @@ HRESULT CZipDecoder::Decode( if (result == S_OK) { bool passwOK; - result = _pkAesDecoderSpec->CheckPassword(passwOK); + result = _pkAesDecoderSpec->Init_and_CheckPassword(passwOK); if (result == S_OK && !passwOK) - result = S_FALSE; + { + res = NExtract::NOperationResult::kWrongPassword; + return S_OK; + } } } else { result = _zipCryptoDecoderSpec->ReadHeader(inStream); + if (result == S_OK) + { + _zipCryptoDecoderSpec->Init_BeforeDecode(); + + /* Info-ZIP modification to ZipCrypto format: + if bit 3 of the general purpose bit flag is set, + it uses high byte of 16-bit File Time. + Info-ZIP code probably writes 2 bytes of File Time. + We check only 1 byte. */ + + // UInt32 v1 = GetUi16(_zipCryptoDecoderSpec->_header + NCrypto::NZip::kHeaderSize - 2); + // UInt32 v2 = (item.HasDescriptor() ? (item.Time & 0xFFFF) : (item.Crc >> 16)); + + Byte v1 = _zipCryptoDecoderSpec->_header[NCrypto::NZip::kHeaderSize - 1]; + Byte v2 = (Byte)(item.HasDescriptor() ? (item.Time >> 8) : (item.Crc >> 24)); + + if (v1 != v2) + { + res = NExtract::NOperationResult::kWrongPassword; + return S_OK; + } + } } if (result == S_OK) { - 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; + RINOK(filterStreamSpec->SetInStream(inStream)); + + /* IFilter::Init() does nothing in all zip crypto filters. + So we can call any Initialize function in CFilterCoder. */ + + RINOK(filterStreamSpec->Init_NoSubFilterInit()); + // RINOK(filterStreamSpec->SetOutStreamSize(NULL)); + inStreamNew = filterStream; - if (wzAesMode) - { - if (!_wzAesDecoderSpec->CheckPasswordVerifyCode()) - result = S_FALSE; - } } } else inStreamNew = inStream; + if (result == S_OK) result = coder->Code(inStreamNew, outStream, NULL, &item.Size, compressProgress); + if (result == S_FALSE) return S_OK; + if (result == E_NOTIMPL) { res = NExtract::NOperationResult::kUnsupportedMethod; @@ -830,6 +901,7 @@ HRESULT CZipDecoder::Decode( RINOK(result); } + bool crcOK = true; bool authOk = true; if (needCRC) diff --git a/CPP/7zip/Archive/Zip/ZipHandler.h b/CPP/7zip/Archive/Zip/ZipHandler.h index 7f1d2eba..c2a362a7 100644 --- a/CPP/7zip/Archive/Zip/ZipHandler.h +++ b/CPP/7zip/Archive/Zip/ZipHandler.h @@ -33,7 +33,7 @@ public: INTERFACE_IInArchive(;) INTERFACE_IOutArchive(;) - STDMETHOD(SetProperties)(const wchar_t **names, const PROPVARIANT *values, UInt32 numProps); + STDMETHOD(SetProperties)(const wchar_t * const *names, const PROPVARIANT *values, UInt32 numProps); DECL_ISetCompressCodecsInfo diff --git a/CPP/7zip/Archive/Zip/ZipHandlerOut.cpp b/CPP/7zip/Archive/Zip/ZipHandlerOut.cpp index ae58cbe2..f1c8b227 100644 --- a/CPP/7zip/Archive/Zip/ZipHandlerOut.cpp +++ b/CPP/7zip/Archive/Zip/ZipHandlerOut.cpp @@ -34,15 +34,16 @@ STDMETHODIMP CHandler::GetFileTimeType(UInt32 *timeType) return S_OK; } -static bool IsAsciiString(const UString &s) +static bool IsSimpleAsciiString(const wchar_t *s) { - for (unsigned i = 0; i < s.Len(); i++) + for (;;) { - wchar_t c = s[i]; + wchar_t c = *s++; + if (c == 0) + return true; if (c < 0x20 || c > 0x7F) return false; } - return true; } #define COM_TRY_BEGIN2 try { @@ -180,11 +181,8 @@ STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numIt if (tryUtf8) { - 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; + ui.IsUtf8 = !name.IsAscii(); + ConvertUnicodeToUTF8(name, ui.Name); } if (ui.Name.Len() >= (1 << 16)) @@ -249,10 +247,10 @@ STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numIt if (!m_ForceAesMode) options.IsAesMode = thereAreAesUpdates; - if (!IsAsciiString((BSTR)password)) + if (!IsSimpleAsciiString(password)) return E_INVALIDARG; if (password) - options.Password = UnicodeStringToMultiByte((BSTR)password, CP_OEMCP); + options.Password = UnicodeStringToMultiByte((LPCOLESTR)password, CP_OEMCP); if (options.IsAesMode) { if (options.Password.Len() > NCrypto::NWzAes::kPasswordSizeMax) @@ -297,7 +295,7 @@ static const CMethodIndexToName k_SupportedMethods[] = { NFileHeader::NCompressionMethod::kPPMd, "ppmd" } }; -STDMETHODIMP CHandler::SetProperties(const wchar_t **names, const PROPVARIANT *values, UInt32 numProps) +STDMETHODIMP CHandler::SetProperties(const wchar_t * const *names, const PROPVARIANT *values, UInt32 numProps) { InitMethodProps(); #ifndef _7ZIP_ST @@ -318,7 +316,7 @@ STDMETHODIMP CHandler::SetProperties(const wchar_t **names, const PROPVARIANT *v UInt32 level = 9; RINOK(ParsePropToUInt32(name.Ptr(1), prop, level)); _props.Level = level; - _props.MethodInfo.AddLevelProp(level); + _props.MethodInfo.AddProp_Level(level); } else if (name == L"m") { diff --git a/CPP/7zip/Archive/Zip/ZipHeader.h b/CPP/7zip/Archive/Zip/ZipHeader.h index 1391cdf4..c109992c 100644 --- a/CPP/7zip/Archive/Zip/ZipHeader.h +++ b/CPP/7zip/Archive/Zip/ZipHeader.h @@ -54,6 +54,8 @@ namespace NFileHeader kLZMA = 14, kTerse = 18, kLz77 = 19, + + kXz = 0x5F, kJpeg = 0x60, kWavPack = 0x61, kPPMd = 0x62, diff --git a/CPP/7zip/Archive/Zip/ZipIn.cpp b/CPP/7zip/Archive/Zip/ZipIn.cpp index 345fbf56..6f495305 100644 --- a/CPP/7zip/Archive/Zip/ZipIn.cpp +++ b/CPP/7zip/Archive/Zip/ZipIn.cpp @@ -348,7 +348,7 @@ HRESULT CInArchive::FindAndReadMarker(IInStream *stream, const UInt64 *searchLim return S_FALSE; } -HRESULT CInArchive::IncreaseRealPosition(UInt64 addValue) +HRESULT CInArchive::IncreaseRealPosition(Int64 addValue) { return Stream->Seek(addValue, STREAM_SEEK_CUR, &m_Position); } @@ -439,10 +439,9 @@ void CInArchive::ReadFileName(unsigned size, AString &s) s.Empty(); return; } - char *p = s.GetBuffer(size); + char *p = s.GetBuf(size); SafeReadBytes(p, size); - p[size] = 0; - s.ReleaseBuffer(); + s.ReleaseBuf_CalcLen(size); } bool CInArchive::ReadExtra(unsigned extraSize, CExtraBlock &extraBlock, @@ -556,7 +555,12 @@ bool CInArchive::ReadLocalItem(CItemEx &item) UInt32 diskStartNumber = 0; if (!ReadExtra(extraSize, item.LocalExtra, item.Size, item.PackSize, localHeaderOffset, diskStartNumber)) - return false; + { + /* Most of archives are OK for Extra. But there are some rare cases + that have error. And if error in first item, it can't open archive. + So we ignore that error */ + // return false; + } } if (!CheckDosTime(item.Time)) { @@ -650,6 +654,7 @@ HRESULT CInArchive::ReadLocalItemDescriptor(CItemEx &item) numBytesInBuffer += processedSize; if (numBytesInBuffer < kDataDescriptorSize) return S_FALSE; + UInt32 i; for (i = 0; i <= numBytesInBuffer - kDataDescriptorSize; i++) { @@ -666,10 +671,11 @@ HRESULT CInArchive::ReadLocalItemDescriptor(CItemEx &item) item.Crc = Get32(buf + i + 4); item.PackSize = descriptorPackSize; item.Size = Get32(buf + i + 12); - return IncreaseRealPosition(Int64(Int32(0 - (numBytesInBuffer - i - kDataDescriptorSize)))); + return IncreaseRealPosition((Int64)(Int32)(0 - (numBytesInBuffer - i - kDataDescriptorSize))); } } } + packedSize += i; unsigned j; for (j = 0; i < numBytesInBuffer; i++, j++) @@ -1262,7 +1268,10 @@ HRESULT CInArchive::ReadHeaders2(CObjectVector &items, CProgressVirt *p (UInt32)ecd64.cdSize != (UInt32)cdSize || ((UInt32)(ecd64.cdStartOffset) != (UInt32)cdRelatOffset && (!items.IsEmpty()))) - return S_FALSE; + { + // return S_FALSE; + HeadersError = true; + } // printf("\nOpen OK"); return S_OK; diff --git a/CPP/7zip/Archive/Zip/ZipIn.h b/CPP/7zip/Archive/Zip/ZipIn.h index f6b349b1..734d3bcb 100644 --- a/CPP/7zip/Archive/Zip/ZipIn.h +++ b/CPP/7zip/Archive/Zip/ZipIn.h @@ -25,7 +25,7 @@ public: UInt64 GetLocalFullSize() const { return LocalFullHeaderSize + PackSize + (HasDescriptor() ? kDataDescriptorSize : 0); } UInt64 GetDataPosition() const - { return LocalHeaderPos + LocalFullHeaderSize; }; + { return LocalHeaderPos + LocalFullHeaderSize; } }; struct CInArchiveInfo @@ -107,7 +107,7 @@ class CInArchive HRESULT Seek(UInt64 offset); HRESULT FindAndReadMarker(IInStream *stream, const UInt64 *searchHeaderSizeLimit); - HRESULT IncreaseRealPosition(UInt64 addValue); + HRESULT IncreaseRealPosition(Int64 addValue); HRESULT ReadBytes(void *data, UInt32 size, UInt32 *processedSize); void SafeReadBytes(void *data, unsigned size); diff --git a/CPP/7zip/Archive/Zip/ZipItem.cpp b/CPP/7zip/Archive/Zip/ZipItem.cpp index ae88944d..f2ccc814 100644 --- a/CPP/7zip/Archive/Zip/ZipItem.cpp +++ b/CPP/7zip/Archive/Zip/ZipItem.cpp @@ -114,7 +114,7 @@ bool CItem::IsDir() const case NHostOS::kMVS: return false; // change it throw kUnknownAttributes; case NHostOS::kUnix: - return (highAttrib & NUnixAttrib::kIFDIR) != 0; + return ((highAttrib & NUnixAttrib::kIFMT) == NUnixAttrib::kIFDIR); default: return false; } @@ -130,6 +130,11 @@ UInt32 CItem::GetWinAttrib() const if (FromCentral) winAttrib = ExternalAttrib; break; + case NHostOS::kUnix: + // do we need to clear 16 low bits in this case? + if (FromCentral) + winAttrib = ExternalAttrib & 0xFFFF0000; + break; } if (IsDir()) // test it; winAttrib |= FILE_ATTRIBUTE_DIRECTORY; diff --git a/CPP/7zip/Archive/Zip/ZipItem.h b/CPP/7zip/Archive/Zip/ZipItem.h index d50c3ae9..98afdf1d 100644 --- a/CPP/7zip/Archive/Zip/ZipItem.h +++ b/CPP/7zip/Archive/Zip/ZipItem.h @@ -179,9 +179,12 @@ struct CExtraBlock void RemoveUnknownSubBlocks() { - for (int i = SubBlocks.Size() - 1; i >= 0; i--) + for (unsigned i = SubBlocks.Size(); i != 0;) + { + i--; if (SubBlocks[i].ID != NFileHeader::NExtraID::kWzAES) SubBlocks.Delete(i); + } } }; @@ -204,8 +207,8 @@ public: 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() || Method == NFileHeader::NCompressionMethod::kWzAES); }; + bool IsStrongEncrypted() const { return IsEncrypted() && (Flags & NFileHeader::NFlags::kStrongEncrypted) != 0; } + 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; } @@ -237,6 +240,7 @@ public: void ClearFlags() { Flags = 0; } void SetEncrypted(bool encrypted) { SetFlag(NFileHeader::NFlags::kEncrypted, encrypted); } void SetUtf8(bool isUtf8) { SetFlag(NFileHeader::NFlags::kUtf8, isUtf8); } + void SetDescriptorMode(bool useDescriptor) { SetFlag(NFileHeader::NFlags::kDescriptorUsedMask, useDescriptor); } UINT GetCodePage() const { return CP_OEMCP; } }; @@ -277,6 +281,7 @@ public: void GetUnicodeString(const AString &s, UString &res, bool useSpecifiedCodePage, UINT codePage) const { bool isUtf8 = IsUtf8(); + bool ignore_Utf8_Errors = true; #ifdef _WIN32 if (!isUtf8) @@ -287,14 +292,15 @@ public: { /* 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? */ + Do we need to do it in POSIX version also? */ isUtf8 = true; + ignore_Utf8_Errors = false; } } #endif if (isUtf8) - if (ConvertUTF8ToUnicode(s, res)) + if (ConvertUTF8ToUnicode(s, res) || ignore_Utf8_Errors) return; MultiByteToUnicodeString2(res, s, useSpecifiedCodePage ? codePage : GetCodePage()); } diff --git a/CPP/7zip/Archive/Zip/ZipOut.h b/CPP/7zip/Archive/Zip/ZipOut.h index eaaa0320..056d0d09 100644 --- a/CPP/7zip/Archive/Zip/ZipOut.h +++ b/CPP/7zip/Archive/Zip/ZipOut.h @@ -63,7 +63,7 @@ public: HRESULT Create(IOutStream *outStream); void MoveCurPos(UInt64 distanceToMove); - UInt64 GetCurPos() const { return m_CurPos; }; + UInt64 GetCurPos() const { return m_CurPos; } void SeekToCurPos(); diff --git a/CPP/7zip/Archive/Zip/ZipRegister.cpp b/CPP/7zip/Archive/Zip/ZipRegister.cpp index 545e76c6..2be783e6 100644 --- a/CPP/7zip/Archive/Zip/ZipRegister.cpp +++ b/CPP/7zip/Archive/Zip/ZipRegister.cpp @@ -9,23 +9,18 @@ namespace NArchive { namespace NZip { -IMP_CreateArcIn -IMP_CreateArcOut - -static CArcInfo g_ArcInfo = - { "zip", "zip zipx jar xpi odt ods docx xlsx epub", 0, 1, - 3 + 4 + 4 + 6, - { +static const Byte k_Signature[] = { 4, 0x50, 0x4B, 0x03, 0x04, 4, 0x50, 0x4B, 0x05, 0x06, - 6, 0x50, 0x4B, 0x30, 0x30, 0x50, 0x4B, - }, + 6, 0x50, 0x4B, 0x30, 0x30, 0x50, 0x4B }; + +REGISTER_ARC_IO( + "zip", "zip zipx jar xpi odt ods docx xlsx epub", 0, 1, + k_Signature, 0, NArcInfoFlags::kFindSignature | NArcInfoFlags::kMultiSignature | NArcInfoFlags::kUseGlobalOffset, - REF_CreateArc_Pair, IsArc_Zip }; - -REGISTER_ARC(Zip) - + IsArc_Zip) + }} diff --git a/CPP/7zip/Archive/Zip/ZipUpdate.cpp b/CPP/7zip/Archive/Zip/ZipUpdate.cpp index 97cce5ac..9a9526cc 100644 --- a/CPP/7zip/Archive/Zip/ZipUpdate.cpp +++ b/CPP/7zip/Archive/Zip/ZipUpdate.cpp @@ -65,6 +65,7 @@ static void SetFileHeader( COutArchive &archive, const CCompressionMethodMode &options, const CUpdateItem &ui, + // bool isSeqMode, CItemOut &item) { item.Size = ui.Size; @@ -95,6 +96,8 @@ static void SetFileHeader( item.InternalAttrib = 0; // test it item.SetEncrypted(!isDir && options.PasswordIsDefined); + // item.SetDescriptorMode(isSeqMode); + if (isDir) { item.ExtractVersion.Version = NFileHeader::NCompressionMethod::kExtractVersion_Dir; @@ -156,12 +159,14 @@ struct CThreadInfo bool IsFree; UInt32 UpdateIndex; + UInt32 FileTime; CThreadInfo(const CCompressionMethodMode &options): ExitThread(false), ProgressSpec(0), OutStreamSpec(0), - Coder(options) + Coder(options), + FileTime(0) {} HRESULT CreateEvents() @@ -192,9 +197,11 @@ void CThreadInfo::WaitAndCode() CompressEvent.Lock(); if (ExitThread) return; + Result = Coder.Compress( EXTERNAL_CODECS_LOC_VARS - InStream, OutStream, Progress, CompressingResult); + InStream, OutStream, FileTime, Progress, CompressingResult); + if (Result == S_OK && Progress) Result = Progress->SetRatioInfo(&CompressingResult.UnpackSize, &CompressingResult.PackSize); CompressionCompletedEvent.Set(); @@ -254,7 +261,7 @@ public: MY_UNKNOWN_IMP void Create(IProgress *progress, bool inSizeIsMain); void SetProgressOffset(UInt64 progressOffset); - HRESULT SetRatioInfo(int index, const UInt64 *inSize, const UInt64 *outSize); + HRESULT SetRatioInfo(unsigned index, const UInt64 *inSize, const UInt64 *outSize); STDMETHOD(SetRatioInfo)(const UInt64 *inSize, const UInt64 *outSize); }; @@ -274,16 +281,16 @@ void CMtProgressMixer2::SetProgressOffset(UInt64 progressOffset) CriticalSection.Leave(); } -HRESULT CMtProgressMixer2::SetRatioInfo(int index, const UInt64 *inSize, const UInt64 *outSize) +HRESULT CMtProgressMixer2::SetRatioInfo(unsigned index, const UInt64 *inSize, const UInt64 *outSize) { NWindows::NSynchronization::CCriticalSectionLock lock(CriticalSection); if (index == 0 && RatioProgress) { RINOK(RatioProgress->SetRatioInfo(inSize, outSize)); } - if (inSize != 0) + if (inSize) InSizes[index] = *inSize; - if (outSize != 0) + if (outSize) OutSizes[index] = *outSize; UInt64 v = ProgressOffset + (_inSizeIsMain ? (InSizes[0] + InSizes[1]) : @@ -332,8 +339,16 @@ static HRESULT UpdateItemOldData( CItemOut &item, /* bool izZip64, */ ICompressProgressInfo *progress, + IArchiveUpdateCallbackFile *opCallback, UInt64 &complexity) { + if (opCallback) + { + RINOK(opCallback->ReportOperation( + NEventIndexType::kInArcIndex, (UInt32)ui.IndexInArc, + NUpdateNotifyOp::kReplicate)) + } + if (ui.NewProps) { if (item.HasDescriptor()) @@ -396,7 +411,8 @@ static HRESULT Update2St( const CObjectVector &updateItems, const CCompressionMethodMode *options, const CByteBuffer *comment, - IArchiveUpdateCallback *updateCallback) + IArchiveUpdateCallback *updateCallback, + IArchiveUpdateCallbackFile *opCallback) { CLocalProgress *lps = new CLocalProgress; CMyComPtr progress = lps; @@ -445,15 +461,37 @@ static HRESULT Update2St( if (!fileInStream) return E_INVALIDARG; + // bool isSeqMode = false; + /* + { + CMyComPtr inStream2; + fileInStream->QueryInterface(IID_IInStream, (void **)&inStream2); + isSeqMode = (inStream2 == NULL); + } + */ + // file Size can be 64-bit !!! SetFileHeader(archive, *options, ui, item); archive.PrepareWriteCompressedData(item.Name.Len(), ui.Size, options->IsRealAesMode()); CCompressingResult compressingResult; CMyComPtr outStream; archive.CreateStreamForCompressing(&outStream); + RINOK(compressor.Compress( EXTERNAL_CODECS_LOC_VARS - fileInStream, outStream, progress, compressingResult)); + fileInStream, outStream, + ui.Time, + progress, compressingResult)); + + if (compressingResult.FileTimeWasUsed) + { + /* + if (!item.HasDescriptor()) + return E_FAIL; + */ + item.SetDescriptorMode(true); + } + SetItemInfoFromCompressingResult(compressingResult, options->IsRealAesMode(), options->AesKeyMode, item); archive.WriteLocalHeader_And_SeekToNextFile(item); RINOK(updateCallback->SetOperationResult(NArchive::NUpdate::NOperationResult::kOK)); @@ -465,13 +503,14 @@ static HRESULT Update2St( { UInt64 complexity = 0; lps->SendRatio = false; - RINOK(UpdateItemOldData(archive, inArchive, itemEx, ui, item, progress, complexity)); + RINOK(UpdateItemOldData(archive, inArchive, itemEx, ui, item, progress, opCallback, complexity)); lps->SendRatio = true; lps->ProgressOffset += complexity; } items.Add(item); lps->ProgressOffset += kLocalHeaderSize; } + lps->InSize = unpackSizeTotal; lps->OutSize = packSizeTotal; RINOK(lps->SetCur()); @@ -489,6 +528,9 @@ static HRESULT Update2( const CByteBuffer *comment, IArchiveUpdateCallback *updateCallback) { + CMyComPtr opCallback; + updateCallback->QueryInterface(IID_IArchiveUpdateCallbackFile, (void **)&opCallback); + UInt64 complexity = 0; UInt64 numFilesToCompress = 0; UInt64 numBytesToCompress = 0; @@ -542,6 +584,7 @@ static HRESULT Update2( numThreads = MAXIMUM_WAIT_OBJECTS; if (numThreads < 1) numThreads = 1; + const size_t kMemPerThread = (1 << 25); const size_t kBlockSize = 1 << 16; @@ -558,7 +601,7 @@ static HRESULT Update2( { // fixed for 9.31. bzip2 default is just one thread. if (options2.NumThreadsWasChanged || method == NFileHeader::NCompressionMethod::kBZip2) - options2.MethodInfo.AddNumThreadsProp(numThreads); + options2.MethodInfo.AddProp_NumThreads(numThreads); } } else @@ -577,7 +620,7 @@ static HRESULT Update2( numBZip2Threads = 32; if (averageNumberOfBlocks < numBZip2Threads) numBZip2Threads = (UInt32)averageNumberOfBlocks; - options2.MethodInfo.AddNumThreadsProp(numBZip2Threads); + options2.MethodInfo.AddProp_NumThreads(numBZip2Threads); } numThreads /= numBZip2Threads; } @@ -599,7 +642,7 @@ static HRESULT Update2( return Update2St( EXTERNAL_CODECS_LOC_VARS archive, inArchive, - inputItems, updateItems, &options2, comment, updateCallback); + inputItems, updateItems, &options2, comment, updateCallback, opCallback); #ifndef _7ZIP_ST @@ -643,6 +686,7 @@ static HRESULT Update2( threadInfo.ProgressSpec = new CMtCompressProgress(); threadInfo.Progress = threadInfo.ProgressSpec; threadInfo.ProgressSpec->Init(&mtCompressProgressMixer, (int)i); + threadInfo.FileTime = 0; // fix it ! RINOK(threadInfo.CreateThread()); } } @@ -784,7 +828,15 @@ static HRESULT Update2( DWORD result = ::WaitForMultipleObjects(compressingCompletedEvents.Size(), &compressingCompletedEvents.Front(), FALSE, INFINITE); - int t = (int)(result - WAIT_OBJECT_0); + if (result == WAIT_FAILED) + { + DWORD lastError = GetLastError(); + return lastError != 0 ? lastError : E_FAIL; + } + unsigned t = (unsigned)(result - WAIT_OBJECT_0); + if (t >= compressingCompletedEvents.Size()) + return E_FAIL; + CThreadInfo &threadInfo = threads.Threads[threadIndices[t]]; threadInfo.InStream.Release(); threadInfo.IsFree = true; @@ -813,7 +865,7 @@ static HRESULT Update2( } else { - RINOK(UpdateItemOldData(archive, inArchive, itemEx, ui, item, progress, complexity)); + RINOK(UpdateItemOldData(archive, inArchive, itemEx, ui, item, progress, opCallback, complexity)); } items.Add(item); complexity += kLocalHeaderSize; -- cgit v1.2.3