diff --git a/package/inc/ZipFile.hxx b/package/inc/ZipFile.hxx index b2f3e6ecf131..8828d929273f 100644 --- a/package/inc/ZipFile.hxx +++ b/package/inc/ZipFile.hxx @@ -30,6 +30,7 @@ #include "EncryptionData.hxx" #include +#include class MemoryByteGrabber; namespace com::sun::star { @@ -50,10 +51,13 @@ namespace rtl class ZipEnumeration; + class ZipFile { rtl::Reference m_aMutexHolder; + std::unordered_set m_EntriesInsensitive; + EntryHash aEntries; ByteGrabber aGrabber; ZipUtils::Inflater aInflater; diff --git a/package/source/zipapi/ZipFile.cxx b/package/source/zipapi/ZipFile.cxx index fa8d74b37b80..f7713b8665c1 100644 --- a/package/source/zipapi/ZipFile.cxx +++ b/package/source/zipapi/ZipFile.cxx @@ -94,6 +94,7 @@ ZipFile::ZipFile( rtl::Reference aMutexHolder, if (bInitialise && readCEN() == -1 ) { aEntries.clear(); + m_EntriesInsensitive.clear(); throw ZipException( u"stream data looks to be broken"_ustr ); } } @@ -118,6 +119,7 @@ ZipFile::ZipFile( rtl::Reference< comphelper::RefCountedMutex > aMutexHolder, else if ( readCEN() == -1 ) { aEntries.clear(); + m_EntriesInsensitive.clear(); throw ZipException(u"stream data looks to be broken"_ustr ); } } @@ -1156,15 +1158,19 @@ sal_Int32 ZipFile::readCEN() continue; // This is a directory entry, not a stream - skip it } - if (auto it = aEntries.find(aEntry.sPath); it == aEntries.end()) - { - aEntries[aEntry.sPath] = aEntry; - } - else + if (aEntries.find(aEntry.sPath) != aEntries.end()) { SAL_INFO("package", "Duplicate CEN entry: \"" << aEntry.sPath << "\""); throw ZipException(u"Duplicate CEN entry"_ustr); } + // this is required for OOXML, but not for ODF + auto const lowerPath(aEntry.sPath.toAsciiLowerCase()); + if (!m_EntriesInsensitive.insert(lowerPath).second) + { + SAL_INFO("package", "Duplicate CEN entry (case insensitive): \"" << aEntry.sPath << "\""); + throw ZipException(u"Duplicate CEN entry (case insensitive)"_ustr); + } + aEntries[aEntry.sPath] = aEntry; } if (nCount != nTotal) @@ -1335,6 +1341,12 @@ void ZipFile::HandlePK34(std::span data, sal_Int64 dataOffset, s != aEntries.end()) return; + auto const lowerPath(aEntry.sPath.toAsciiLowerCase()); + if (m_EntriesInsensitive.find(lowerPath) != m_EntriesInsensitive.end()) + { // this is required for OOXML, but not for ODF + return; + } + m_EntriesInsensitive.insert(lowerPath); aEntries.emplace(aEntry.sPath, aEntry); // Drop any "directory" entry corresponding to this one's path; since we don't use