filter/Library_filterconfig.mk                      |    1 
 filter/source/config/cache/typedetection.cxx        |  109 ++++++++++++++++++++
 filter/source/storagefilterdetect/filterdetect.cxx  |   50 ++++-----
 include/oox/helper/zipstorage.hxx                   |    3 
 oox/source/core/filterdetect.cxx                    |   14 +-
 oox/source/core/xmlfilterbase.cxx                   |    8 +
 oox/source/dump/pptxdumper.cxx                      |    2 
 oox/source/helper/zipstorage.cxx                    |    4 
 package/source/xstor/xstorage.cxx                   |    6 +
 package/source/xstor/xstorage.hxx                   |    1 
 package/source/zipapi/ZipFile.cxx                   |   45 +++++++-
 package/source/zippackage/ZipPackage.cxx            |    4 
 sc/qa/unit/data/xlsx/tdf131575.xlsx                 |binary
 sc/qa/unit/data/xlsx/tdf76115.xlsx                  |binary
 sc/qa/unit/subsequent_filters_test2.cxx             |   33 ++++++
 sfx2/source/doc/docfile.cxx                         |   46 ++++----
 sw/qa/extras/odfimport/data/unreferenced_stream.odt |binary
 sw/qa/extras/odfimport/odfimport.cxx                |   16 ++
 18 files changed, 282 insertions(+), 60 deletions(-)

New commits:
commit c63fd0899374515738b1afb330f541f35b8948de
Author:     Xisco Fauli <xiscofa...@libreoffice.org>
AuthorDate: Thu Feb 1 10:59:09 2024 +0100
Commit:     Mike Kaganski <mike.kagan...@collabora.com>
CommitDate: Fri Feb 2 17:49:57 2024 +0600

    tdf#76115: sc_subsequent_filters: Add unittest
    
    Change-Id: I355eef6b0f145da8aacdd3b395ce3dcbecfb3e42
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/162870
    Tested-by: Jenkins
    Reviewed-by: Xisco Fauli <xiscofa...@libreoffice.org>

diff --git a/sc/qa/unit/data/xlsx/tdf76115.xlsx 
b/sc/qa/unit/data/xlsx/tdf76115.xlsx
new file mode 100644
index 000000000000..ebc6126dcbde
Binary files /dev/null and b/sc/qa/unit/data/xlsx/tdf76115.xlsx differ
diff --git a/sc/qa/unit/subsequent_filters_test2.cxx 
b/sc/qa/unit/subsequent_filters_test2.cxx
index 29eebbececdd..892f5c64446c 100644
--- a/sc/qa/unit/subsequent_filters_test2.cxx
+++ b/sc/qa/unit/subsequent_filters_test2.cxx
@@ -193,6 +193,7 @@ public:
     void testTdf151818_SmartArtFontColor();
     void testNamedTableRef();
     void testTdf131575();
+    void testTdf76115();
 
     CPPUNIT_TEST_SUITE(ScFiltersTest2);
 
@@ -315,6 +316,7 @@ public:
     CPPUNIT_TEST(testTdf151818_SmartArtFontColor);
     CPPUNIT_TEST(testNamedTableRef);
     CPPUNIT_TEST(testTdf131575);
+    CPPUNIT_TEST(testTdf76115);
 
     CPPUNIT_TEST_SUITE_END();
 };
@@ -3069,6 +3071,20 @@ void ScFiltersTest2::testTdf131575()
     CPPUNIT_ASSERT_EQUAL(OUString("ETAT DES SORTIES"), pDoc->GetString(1, 0, 
0));
 }
 
+void ScFiltersTest2::testTdf76115()
+{
+    // It expectedly fails to load normally
+    CPPUNIT_ASSERT_ASSERTION_FAIL(createScDoc("xlsx/tdf76115.xlsx"));
+
+    // importing it must succeed with RepairPackage set to true.
+    uno::Sequence<beans::PropertyValue> aParams
+        = { comphelper::makePropertyValue("RepairPackage", true) };
+    mxComponent = loadFromDesktop(createFileURL(u"xlsx/tdf76115.xlsx"), {}, 
aParams);
+    ScDocument* pDoc = getScDoc();
+
+    CPPUNIT_ASSERT_EQUAL(OUString("Filial"), pDoc->GetString(0, 0, 0));
+}
+
 CPPUNIT_TEST_SUITE_REGISTRATION(ScFiltersTest2);
 
 CPPUNIT_PLUGIN_IMPLEMENT();
commit 68da1c50a89cb2f3d8087273725b756a2c575566
Author:     Xisco Fauli <xiscofa...@libreoffice.org>
AuthorDate: Thu Feb 1 11:22:32 2024 +0100
Commit:     Mike Kaganski <mike.kagan...@collabora.com>
CommitDate: Fri Feb 2 17:40:32 2024 +0600

    tdf#131575: sc_subsequent_filters: Add unittest
    
    Change-Id: I6f4bcc3da028dc9b2cd86ed06e309bed8d808ca9
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/162872
    Tested-by: Jenkins
    Reviewed-by: Xisco Fauli <xiscofa...@libreoffice.org>

diff --git a/sc/qa/unit/data/xlsx/tdf131575.xlsx 
b/sc/qa/unit/data/xlsx/tdf131575.xlsx
new file mode 100644
index 000000000000..307d7dea5cf8
Binary files /dev/null and b/sc/qa/unit/data/xlsx/tdf131575.xlsx differ
diff --git a/sc/qa/unit/subsequent_filters_test2.cxx 
b/sc/qa/unit/subsequent_filters_test2.cxx
index 177fcc773ed7..29eebbececdd 100644
--- a/sc/qa/unit/subsequent_filters_test2.cxx
+++ b/sc/qa/unit/subsequent_filters_test2.cxx
@@ -56,6 +56,7 @@
 #include <com/sun/star/text/WritingMode2.hpp>
 #include <com/sun/star/text/XTextRange.hpp>
 
+#include <comphelper/propertyvalue.hxx>
 #include <comphelper/scopeguard.hxx>
 #include <tools/UnitConversion.hxx>
 #include <unotools/syslocaleoptions.hxx>
@@ -191,6 +192,7 @@ public:
     void testTdf83671_SmartArt_import2();
     void testTdf151818_SmartArtFontColor();
     void testNamedTableRef();
+    void testTdf131575();
 
     CPPUNIT_TEST_SUITE(ScFiltersTest2);
 
@@ -312,6 +314,7 @@ public:
     CPPUNIT_TEST(testTdf83671_SmartArt_import2);
     CPPUNIT_TEST(testTdf151818_SmartArtFontColor);
     CPPUNIT_TEST(testNamedTableRef);
+    CPPUNIT_TEST(testTdf131575);
 
     CPPUNIT_TEST_SUITE_END();
 };
@@ -3052,6 +3055,20 @@ void ScFiltersTest2::testNamedTableRef()
     }
 }
 
+void ScFiltersTest2::testTdf131575()
+{
+    // It expectedly fails to load normally
+    CPPUNIT_ASSERT_ASSERTION_FAIL(createScDoc("xlsx/tdf131575.xlsx"));
+
+    // importing it must succeed with RepairPackage set to true.
+    uno::Sequence<beans::PropertyValue> aParams
+        = { comphelper::makePropertyValue("RepairPackage", true) };
+    mxComponent = loadFromDesktop(createFileURL(u"xlsx/tdf131575.xlsx"), {}, 
aParams);
+    ScDocument* pDoc = getScDoc();
+
+    CPPUNIT_ASSERT_EQUAL(OUString("ETAT DES SORTIES"), pDoc->GetString(1, 0, 
0));
+}
+
 CPPUNIT_TEST_SUITE_REGISTRATION(ScFiltersTest2);
 
 CPPUNIT_PLUGIN_IMPLEMENT();
commit 0224086c0574ea332db1ea6ce5b3455e99e1190c
Author:     Mike Kaganski <mike.kagan...@collabora.com>
AuthorDate: Thu Feb 1 20:55:40 2024 +0600
Commit:     Mike Kaganski <mike.kagan...@collabora.com>
CommitDate: Fri Feb 2 17:26:33 2024 +0600

    tdf#154587: allow directory entries in ZIP packages
    
    The problem in the bugdoc was the directory entries. These entries
    are valid in ZIP packages (even if not common); they may be useful
    to e.g. define per-directory permissions (ACLs).
    
    In normal mode, ZipFile reads central directory; there we can read
    if the entry has FAT file attributes; and then, if the entry is a
    directory. Then it is OK to skip it.
    
    In repair mode, central directory is not used, local file headers
    don't contain a "directory" flag. A workaround is used, checking
    if there are entries that represent directories of other entries.
    
    Also this change fixes some places that didn't pass the recovery
    flag correctly.
    
    Change-Id: I324671841a2c4d0f279b03801d95c8f2eeb99b46
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/162888
    Tested-by: Jenkins
    Reviewed-by: Mike Kaganski <mike.kagan...@collabora.com>

diff --git a/oox/source/core/xmlfilterbase.cxx 
b/oox/source/core/xmlfilterbase.cxx
index d4838bb25db6..ddd227340cbf 100644
--- a/oox/source/core/xmlfilterbase.cxx
+++ b/oox/source/core/xmlfilterbase.cxx
@@ -285,8 +285,10 @@ void XmlFilterBase::importDocumentProperties()
     rtl::Reference< ::oox::core::FilterDetect > xDetector( new 
::oox::core::FilterDetect( xContext ) );
     xInputStream = xDetector->extractUnencryptedPackage( aMediaDesc );
     Reference< XComponent > xModel = getModel();
+    const bool repairPackage = 
aMediaDesc.getUnpackedValueOrDefault("RepairPackage", false);
     Reference< XStorage > xDocumentStorage (
-            ::comphelper::OStorageHelper::GetStorageOfFormatFromInputStream( 
OFOPXML_STORAGE_FORMAT_STRING, xInputStream ) );
+        ::comphelper::OStorageHelper::GetStorageOfFormatFromInputStream(
+            OFOPXML_STORAGE_FORMAT_STRING, xInputStream, {}, repairPackage));
     Reference< XInterface > xTemp = 
xContext->getServiceManager()->createInstanceWithContext(
             "com.sun.star.document.OOXMLDocumentPropertiesImporter",
             xContext);
diff --git a/package/source/zipapi/ZipFile.cxx 
b/package/source/zipapi/ZipFile.cxx
index d5c6411e48a6..f3e9bb7b2b65 100644
--- a/package/source/zipapi/ZipFile.cxx
+++ b/package/source/zipapi/ZipFile.cxx
@@ -38,6 +38,7 @@
 #include <rtl/digest.h>
 #include <sal/log.hxx>
 #include <o3tl/safeint.hxx>
+#include <o3tl/string_view.hxx>
 #include <osl/diagnose.h>
 
 #include <algorithm>
@@ -949,7 +950,7 @@ sal_Int32 ZipFile::readCEN()
             if ( nTestSig != CENSIG )
                 throw ZipException("Invalid CEN header (bad signature)" );
 
-            aMemGrabber.skipBytes ( 2 );
+            sal_uInt16 versionMadeBy = 
static_cast<sal_uInt16>(aMemGrabber.ReadInt16());
             aEntry.nVersion = aMemGrabber.ReadInt16();
             aEntry.nFlag = aMemGrabber.ReadInt16();
 
@@ -969,7 +970,8 @@ sal_Int32 ZipFile::readCEN()
             aEntry.nPathLen = aMemGrabber.ReadInt16();
             aEntry.nExtraLen = aMemGrabber.ReadInt16();
             nCommentLen = aMemGrabber.ReadInt16();
-            aMemGrabber.skipBytes ( 8 );
+            aMemGrabber.skipBytes ( 4 );
+            sal_uInt32 externalFileAttributes = aMemGrabber.ReadUInt32();
             sal_uInt32 nOffset = aMemGrabber.ReadUInt32();
 
             // FIXME64: need to read the 64bit header instead
@@ -1006,6 +1008,15 @@ sal_Int32 ZipFile::readCEN()
                 throw ZipException("Zip entry has an invalid name." );
 
             aMemGrabber.skipBytes( aEntry.nPathLen + aEntry.nExtraLen + 
nCommentLen );
+
+            // Is this a FAT-compatible empty entry?
+            if (aEntry.nSize == 0 && (versionMadeBy & 0xff00) == 0)
+            {
+                constexpr sal_uInt32 FILE_ATTRIBUTE_DIRECTORY = 16;
+                if (externalFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
+                    continue; // This is a directory entry, not a stream - 
skip it
+            }
+
             aEntries[aEntry.sPath] = aEntry;
         }
 
@@ -1101,6 +1112,7 @@ void ZipFile::recover()
                                                               
RTL_TEXTENCODING_UTF8 );
                                     aEntry.nPathLen = static_cast< sal_Int16 
>(aFileName.getLength());
                                 }
+                                aEntry.sPath = aEntry.sPath.replace('\', '/');
 
                                 aEntry.nOffset = nGenPos + nPos + 30 + 
aEntry.nPathLen + aEntry.nExtraLen;
 
@@ -1111,7 +1123,36 @@ void ZipFile::recover()
                                     aEntry.nSize = 0;
                                 }
 
+                                // Do not add this entry, if it is empty and 
is a directory of
+                                // an already existing entry
+                                if (aEntry.nSize == 0 && 
aEntry.nCompressedSize == 0
+                                    && std::find_if(
+                                           aEntries.begin(), aEntries.end(),
+                                           [path = OUString(aEntry.sPath + 
"/")](const auto& r)
+                                           { return r.first.startsWith(path); 
})
+                                           != aEntries.end())
+                                {
+                                    nPos += 4;
+                                    continue;
+                                }
+
                                 aEntries.emplace( aEntry.sPath, aEntry );
+
+                                // Drop any "directory" entry corresponding to 
this one's path;
+                                // since we don't use central directory, we 
don't see external
+                                // file attributes, so sanitize here
+                                sal_Int32 i = 0;
+                                for (OUString subdir = 
aEntry.sPath.getToken(0, '/', i); i >= 0;
+                                     subdir += OUString::Concat("/")
+                                               + o3tl::getToken(aEntry.sPath, 
0, '/', i))
+                                {
+                                    if (auto it = aEntries.find(subdir); it != 
aEntries.end())
+                                    {
+                                        // if not empty, let it fail later in 
ZipPackage::getZipFileContents
+                                        if (it->second.nSize == 0 && 
it->second.nCompressedSize == 0)
+                                            aEntries.erase(it);
+                                    }
+                                }
                             }
                         }
                     }
diff --git a/sfx2/source/doc/docfile.cxx b/sfx2/source/doc/docfile.cxx
index 0a0e1c35e91c..e3b9a1e18fd2 100644
--- a/sfx2/source/doc/docfile.cxx
+++ b/sfx2/source/doc/docfile.cxx
@@ -1884,15 +1884,21 @@ uno::Reference< embed::XStorage > const & 
SfxMedium::GetZipStorageToSign_Impl( b
 
         try
         {
+            const SfxBoolItem* pRepairItem = 
GetItemSet()->GetItem(SID_REPAIRPACKAGE, false);
+            const bool bRepairPackage = pRepairItem && pRepairItem->GetValue();
             // we can not sign document if there is no stream
             // should it be possible at all?
             if ( !bReadOnly && pImpl->xStream.is() )
             {
-                pImpl->m_xZipStorage = 
::comphelper::OStorageHelper::GetStorageOfFormatFromStream( 
ZIP_STORAGE_FORMAT_STRING, pImpl->xStream );
+                pImpl->m_xZipStorage = 
::comphelper::OStorageHelper::GetStorageOfFormatFromStream(
+                    ZIP_STORAGE_FORMAT_STRING, pImpl->xStream, 
css::embed::ElementModes::READWRITE,
+                    {}, bRepairPackage);
             }
             else if ( pImpl->xInputStream.is() )
             {
-                pImpl->m_xZipStorage = 
::comphelper::OStorageHelper::GetStorageOfFormatFromInputStream( 
ZIP_STORAGE_FORMAT_STRING, pImpl->xInputStream );
+                pImpl->m_xZipStorage
+                    = 
::comphelper::OStorageHelper::GetStorageOfFormatFromInputStream(
+                        ZIP_STORAGE_FORMAT_STRING, pImpl->xInputStream, {}, 
bRepairPackage);
             }
         }
         catch( const uno::Exception& )
commit 78063ca395433afbe053d388a2e228e876ccfdfd
Author:     Mike Kaganski <mike.kagan...@collabora.com>
AuthorDate: Thu Dec 14 12:56:03 2023 +0300
Commit:     Mike Kaganski <mike.kagan...@collabora.com>
CommitDate: Fri Feb 2 15:57:04 2024 +0600

    tdf#131575: in repair mode, match names ASCII case-insensitively
    
    It would work for the bugdoc in tdf#131575; but not if the wrong case
    is the only problem in the package, because then there would be no
    repairment mode active. An alternative could be to use case insensitive
    match always, but that looks wrong.
    
    Change-Id: Ie405d37e1dc639482bd2608e4479de5b707a07d4
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/160761
    Tested-by: Jenkins
    Reviewed-by: Mike Kaganski <mike.kagan...@collabora.com>
    Signed-off-by: Xisco Fauli <xiscofa...@libreoffice.org>
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/160783

diff --git a/package/source/xstor/xstorage.cxx 
b/package/source/xstor/xstorage.cxx
index 31aa1924048b..651f8b9a1628 100644
--- a/package/source/xstor/xstorage.cxx
+++ b/package/source/xstor/xstorage.cxx
@@ -404,6 +404,8 @@ void OStorage_Impl::OpenOwnPackage()
                     aArguments.realloc( ++nArgNum );
                     pArguments = aArguments.getArray();
                     pArguments[nArgNum-1] <<= aNamedValue;
+                    if (rProp.Name == "RepairPackage")
+                        rProp.Value >>= m_bRepairPackage;
                 }
                 else if ( rProp.Name == "Password" )
                 {
@@ -1265,6 +1267,10 @@ SotElement_Impl* OStorage_Impl::FindElement( const 
OUString& rName )
     ReadContents();
 
     auto mapIt = m_aChildrenMap.find(rName);
+    if (mapIt == m_aChildrenMap.end() && m_bRepairPackage)
+        mapIt = std::find_if(m_aChildrenMap.begin(), m_aChildrenMap.end(),
+                             [&rName](const auto& pair)
+                             { return rName.equalsIgnoreAsciiCase(pair.first); 
});
     if (mapIt == m_aChildrenMap.end())
         return nullptr;
     for (auto pElement : mapIt->second)
diff --git a/package/source/xstor/xstorage.hxx 
b/package/source/xstor/xstorage.hxx
index 1fefb8f4671a..ce91543d3660 100644
--- a/package/source/xstor/xstorage.hxx
+++ b/package/source/xstor/xstorage.hxx
@@ -121,6 +121,7 @@ struct OStorage_Impl
 
     bool                        m_bIsRoot;      // marks this storage as root 
storages that manages all commits and reverts
     bool                        m_bListCreated;
+    bool                        m_bRepairPackage = false;
 
     /// Count of registered modification listeners
     oslInterlockedCount         m_nModifiedListenerCount;
commit 557aca2460d93ed41ece9b2f786643a57bb9e9ff
Author:     Mike Kaganski <mike.kagan...@collabora.com>
AuthorDate: Thu Dec 14 12:54:15 2023 +0300
Commit:     Mike Kaganski <mike.kagan...@collabora.com>
CommitDate: Fri Feb 2 15:34:21 2024 +0600

    Related: tdf#76115 Also pass RepairPackage to FilterDetect
    
    And drop the default argument value from ZipStorage ctor.
    Always pass it explicitly.
    
    Change-Id: I8bcf78dc4db7763567f9d6873841d75c328ede7e
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/160760
    Tested-by: Mike Kaganski <mike.kagan...@collabora.com>
    Reviewed-by: Mike Kaganski <mike.kagan...@collabora.com>
    Signed-off-by: Xisco Fauli <xiscofa...@libreoffice.org>
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/160782
    Tested-by: Jenkins

diff --git a/include/oox/helper/zipstorage.hxx 
b/include/oox/helper/zipstorage.hxx
index dabb714d7db8..dd56a1f75a71 100644
--- a/include/oox/helper/zipstorage.hxx
+++ b/include/oox/helper/zipstorage.hxx
@@ -44,7 +44,7 @@ public:
     explicit            ZipStorage(
                             const css::uno::Reference< 
css::uno::XComponentContext >& rxContext,
                             const css::uno::Reference< css::io::XInputStream 
>& rxInStream,
-                            bool bRepairStorage = false );
+                            bool bRepairStorage );
 
     explicit            ZipStorage(
                             const css::uno::Reference< 
css::uno::XComponentContext >& rxContext,
diff --git a/oox/source/core/filterdetect.cxx b/oox/source/core/filterdetect.cxx
index db711770832c..7f6140264530 100644
--- a/oox/source/core/filterdetect.cxx
+++ b/oox/source/core/filterdetect.cxx
@@ -268,9 +268,9 @@ FilterDetect::~FilterDetect()
 namespace
 {
 
-bool lclIsZipPackage( const Reference< XComponentContext >& rxContext, const 
Reference< XInputStream >& rxInStrm )
+bool lclIsZipPackage( const Reference< XComponentContext >& rxContext, const 
Reference< XInputStream >& rxInStrm, bool bRepairPackage )
 {
-    ZipStorage aZipStorage( rxContext, rxInStrm );
+    ZipStorage aZipStorage(rxContext, rxInStrm, bRepairPackage);
     return aZipStorage.isStorage();
 }
 
@@ -315,9 +315,10 @@ comphelper::DocPasswordVerifierResult 
PasswordVerifier::verifyEncryptionData( co
 
 Reference< XInputStream > FilterDetect::extractUnencryptedPackage( 
MediaDescriptor& rMediaDescriptor ) const
 {
+    const bool 
bRepairPackage(rMediaDescriptor.getUnpackedValueOrDefault("RepairPackage", 
false));
     // try the plain input stream
     Reference<XInputStream> xInputStream( rMediaDescriptor[ 
MediaDescriptor::PROP_INPUTSTREAM ], UNO_QUERY );
-    if( !xInputStream.is() || lclIsZipPackage( mxContext, xInputStream ) )
+    if (!xInputStream.is() || lclIsZipPackage(mxContext, xInputStream, 
bRepairPackage))
         return xInputStream;
 
     // check if a temporary file is passed in the 'ComponentData' property
@@ -325,7 +326,7 @@ Reference< XInputStream > 
FilterDetect::extractUnencryptedPackage( MediaDescript
     if( xDecrypted.is() )
     {
         Reference<XInputStream> xDecryptedInputStream = 
xDecrypted->getInputStream();
-        if( lclIsZipPackage( mxContext, xDecryptedInputStream ) )
+        if (lclIsZipPackage(mxContext, xDecryptedInputStream, bRepairPackage))
             return xDecryptedInputStream;
     }
 
@@ -379,7 +380,7 @@ Reference< XInputStream > 
FilterDetect::extractUnencryptedPackage( MediaDescript
                         rMediaDescriptor.setComponentDataEntry( 
"DecryptedPackage", Any( xTempStream ) );
 
                         Reference<XInputStream> xDecryptedInputStream = 
xTempStream->getInputStream();
-                        if( lclIsZipPackage( mxContext, xDecryptedInputStream 
) )
+                        if (lclIsZipPackage(mxContext, xDecryptedInputStream, 
bRepairPackage))
                             return xDecryptedInputStream;
                     }
                 }
diff --git a/oox/source/dump/pptxdumper.cxx b/oox/source/dump/pptxdumper.cxx
index c65b792063b2..5a386359d477 100644
--- a/oox/source/dump/pptxdumper.cxx
+++ b/oox/source/dump/pptxdumper.cxx
@@ -113,7 +113,7 @@ Dumper::Dumper( const Reference< XComponentContext >& 
rxContext, const Reference
 {
     if( rxContext.is() && rxInStrm.is() )
     {
-        StorageRef xStrg = std::make_shared<ZipStorage>( rxContext, rxInStrm );
+        StorageRef xStrg = std::make_shared<ZipStorage>( rxContext, rxInStrm, 
false );
         ConfigRef xCfg = std::make_shared<Config>( DUMP_PPTX_CONFIG_ENVVAR, 
rxContext, xStrg, rSysFileName );
         DumperBase::construct( xCfg );
     }
commit 2224d1bbe3c0d9015e7c5bd102866902d45ea70a
Author:     Mike Kaganski <mike.kagan...@collabora.com>
AuthorDate: Thu Dec 14 11:51:42 2023 +0300
Commit:     Mike Kaganski <mike.kagan...@collabora.com>
CommitDate: Fri Feb 2 15:08:00 2024 +0600

    tdf#76115: pass RepairPackage property from media descriptor to ZipStorage
    
    See commit 86c682273d907c77404637c89e584047de1c1099.
    
    Change-Id: I51a3beb00f635554ac73cc9ea957e18fb8e84349
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/160757
    Tested-by: Jenkins
    Reviewed-by: Mike Kaganski <mike.kagan...@collabora.com>
    Signed-off-by: Xisco Fauli <xiscofa...@libreoffice.org>
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/160781

diff --git a/oox/source/core/xmlfilterbase.cxx 
b/oox/source/core/xmlfilterbase.cxx
index c2911a756047..d4838bb25db6 100644
--- a/oox/source/core/xmlfilterbase.cxx
+++ b/oox/source/core/xmlfilterbase.cxx
@@ -1012,7 +1012,9 @@ bool XmlFilterBase::implFinalizeExport( MediaDescriptor& 
rMediaDescriptor )
 
 StorageRef XmlFilterBase::implCreateStorage( const Reference< XInputStream >& 
rxInStream ) const
 {
-    return std::make_shared<ZipStorage>( getComponentContext(), rxInStream );
+    return std::make_shared<ZipStorage>(
+        getComponentContext(), rxInStream,
+        getMediaDescriptor().getUnpackedValueOrDefault("RepairPackage", 
false));
 }
 
 StorageRef XmlFilterBase::implCreateStorage( const Reference< XStream >& 
rxOutStream ) const
commit cdd1c424ed6a6c822467af9c95f3734363215da2
Author:     Mike Kaganski <mike.kagan...@collabora.com>
AuthorDate: Thu Feb 1 09:30:50 2024 +0600
Commit:     Mike Kaganski <mike.kagan...@collabora.com>
CommitDate: Fri Feb 2 14:42:24 2024 +0600

    tdf#159474: fix handling of pre-set RepairPackage property
    
    StorageFilterDetect::detect had a wrong logic here, only honoring
    repair request in case it haappened interactively inside it. The
    pre-existing RepairPackage set to true was treated as "do not try
    to repair".
    
    Change-Id: I3fb63a5d72097a79977e8ed734f8e69dd2ea999a
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/162858
    Tested-by: Jenkins
    Reviewed-by: Mike Kaganski <mike.kagan...@collabora.com>

diff --git a/filter/source/storagefilterdetect/filterdetect.cxx 
b/filter/source/storagefilterdetect/filterdetect.cxx
index c73355e02a9d..1d0d7557d273 100644
--- a/filter/source/storagefilterdetect/filterdetect.cxx
+++ b/filter/source/storagefilterdetect/filterdetect.cxx
@@ -121,44 +121,44 @@ OUString SAL_CALL 
StorageFilterDetect::detect(uno::Sequence<beans::PropertyValue
         if ( ( aWrap.TargetException >>= aZipException ) && 
!aRequestedTypeName.isEmpty() )
         {
             // The package is a broken one.
-            uno::Reference< task::XInteractionHandler > xInteraction =
-                aMediaDesc.getUnpackedValueOrDefault( 
MediaDescriptor::PROP_INTERACTIONHANDLER, uno::Reference< 
task::XInteractionHandler >() );
-
-            if ( xInteraction.is() )
+            INetURLObject aParser(
+                
aMediaDesc.getUnpackedValueOrDefault(MediaDescriptor::PROP_URL, OUString()));
+            OUString aDocumentTitle = 
aParser.getName(INetURLObject::LAST_SEGMENT, true,
+                                                      
INetURLObject::DecodeMechanism::WithCharset);
+            bool bRepairPackage = 
aMediaDesc.getUnpackedValueOrDefault("RepairPackage", false);
+            // fdo#46310 Don't ask to repair if the user rejected it once.
+            if (!bRepairPackage && 
aMediaDesc.getUnpackedValueOrDefault("RepairAllowed", true))
             {
-                INetURLObject aParser( aMediaDesc.getUnpackedValueOrDefault( 
MediaDescriptor::PROP_URL, OUString() ) );
-                OUString aDocumentTitle = aParser.getName( 
INetURLObject::LAST_SEGMENT, true, INetURLObject::DecodeMechanism::WithCharset 
);
-                bool bRepairPackage = aMediaDesc.getUnpackedValueOrDefault( 
"RepairPackage", false );
-                // fdo#46310 Don't try to repair if the user rejected it once.
-                bool bRepairAllowed = aMediaDesc.getUnpackedValueOrDefault( 
"RepairAllowed", true );
+                uno::Reference< task::XInteractionHandler > xInteraction =
+                    aMediaDesc.getUnpackedValueOrDefault( 
MediaDescriptor::PROP_INTERACTIONHANDLER, uno::Reference< 
task::XInteractionHandler >() );
 
-                if ( !bRepairPackage && bRepairAllowed )
+                if ( xInteraction.is() )
                 {
                     // Ask the user whether he wants to try to repair.
-                    RequestPackageReparation aRequest( aDocumentTitle );
-                    xInteraction->handle( aRequest.GetRequest() );
-
-                    if ( aRequest.isApproved() )
-                    {
-                        aTypeName = aRequestedTypeName;
-                        // lok: we want to overwrite file in jail, so don't 
use template flag
-                        const bool bIsLOK = 
comphelper::LibreOfficeKit::isActive();
-                        aMediaDesc[MediaDescriptor::PROP_DOCUMENTTITLE] <<= 
aDocumentTitle;
-                        aMediaDesc[MediaDescriptor::PROP_ASTEMPLATE] <<= 
!bIsLOK;
-                        aMediaDesc["RepairPackage"] <<= true;
-                    }
-                    else
+                    RequestPackageReparation aRequest(aDocumentTitle);
+                    xInteraction->handle(aRequest.GetRequest());
+                    bRepairPackage = aRequest.isApproved();
+                    if (!bRepairPackage)
                     {
                         // Repair either not allowed or not successful.
                         NotifyBrokenPackage aNotifyRequest( aDocumentTitle );
                         xInteraction->handle( aNotifyRequest.GetRequest() );
                         aMediaDesc["RepairAllowed"] <<= false;
                     }
-
-                    // Write the changes back.
-                    aMediaDesc >> rDescriptor;
                 }
             }
+            if (bRepairPackage)
+            {
+                aTypeName = aRequestedTypeName;
+                // lok: we want to overwrite file in jail, so don't use 
template flag
+                const bool bIsLOK = comphelper::LibreOfficeKit::isActive();
+                aMediaDesc[MediaDescriptor::PROP_DOCUMENTTITLE] <<= 
aDocumentTitle;
+                aMediaDesc[MediaDescriptor::PROP_ASTEMPLATE] <<= !bIsLOK;
+                aMediaDesc["RepairPackage"] <<= true;
+            }
+
+            // Write the changes back.
+            aMediaDesc >> rDescriptor;
         }
     }
     catch( uno::RuntimeException& )
diff --git a/sw/qa/extras/odfimport/data/unreferenced_stream.odt 
b/sw/qa/extras/odfimport/data/unreferenced_stream.odt
new file mode 100644
index 000000000000..0cdba0d48529
Binary files /dev/null and 
b/sw/qa/extras/odfimport/data/unreferenced_stream.odt differ
diff --git a/sw/qa/extras/odfimport/odfimport.cxx 
b/sw/qa/extras/odfimport/odfimport.cxx
index 6370d8dc4e8c..7a0ee371b13d 100644
--- a/sw/qa/extras/odfimport/odfimport.cxx
+++ b/sw/qa/extras/odfimport/odfimport.cxx
@@ -43,6 +43,7 @@
 #include <com/sun/star/style/ParagraphAdjust.hpp>
 
 #include <comphelper/propertysequence.hxx>
+#include <comphelper/propertyvalue.hxx>
 #include <editeng/boxitem.hxx>
 #include <vcl/scheduler.hxx>
 
@@ -1404,5 +1405,20 @@ CPPUNIT_TEST_FIXTURE(Test, testEmptyTrailingSpans)
     CPPUNIT_ASSERT_DOUBLES_EQUAL(184, height2, 1); // allow a bit of room for 
rounding just in case
 }
 
+CPPUNIT_TEST_FIXTURE(Test, testBrokenPackage_Tdf159474)
+{
+    // Given an invalid ODF having a stream not referenced in manifest.xml
+    const OUString url = createFileURL(u"unreferenced_stream.odt");
+    // It expectedly fails to load normally:
+    CPPUNIT_ASSERT_ASSERTION_FAIL(loadFromDesktop(url, {}, {}));
+    // importing it must succeed with RepairPackage set to true.
+    mxComponent
+        = loadFromDesktop(url, {}, { 
comphelper::makePropertyValue("RepairPackage", true) });
+    // The document imports in repair mode; the original broken package is 
used as a template,
+    // and the loaded document has no URL:
+    CPPUNIT_ASSERT(uno::Reference<frame::XModel>(mxComponent, 
uno::UNO_QUERY_THROW)->getURL().isEmpty());
+    CPPUNIT_ASSERT_EQUAL(OUString("Empty document"), 
getParagraph(1)->getString());
+}
+
 CPPUNIT_PLUGIN_IMPLEMENT();
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
commit a9091bcfbafa1324bac8771056a42fbe690e0f28
Author:     Mike Kaganski <mike.kagan...@collabora.com>
AuthorDate: Tue Nov 28 08:44:23 2023 +0300
Commit:     Mike Kaganski <mike.kagan...@collabora.com>
CommitDate: Fri Feb 2 14:12:39 2024 +0600

    lok: don't use template flag in more places
    
    Similar to commit e2ee3dd61ab8ea5d970d8da5df3233e7bba5909e (lok: add
    broken package interaction handler, 2023-10-02), all places of broken
    package handling should allow replacing the original document.
    
    Change-Id: I8450dfc0ab60444fa08014cc952ac857998d35ee
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/160009
    Tested-by: Jenkins
    Reviewed-by: Mike Kaganski <mike.kagan...@collabora.com>

diff --git a/filter/source/config/cache/typedetection.cxx 
b/filter/source/config/cache/typedetection.cxx
index dca10ad94cb1..bc0a9af92c83 100644
--- a/filter/source/config/cache/typedetection.cxx
+++ b/filter/source/config/cache/typedetection.cxx
@@ -40,6 +40,7 @@
 #include <comphelper/diagnose_ex.hxx>
 #include <tools/urlobj.hxx>
 #include <comphelper/fileurl.hxx>
+#include <comphelper/lok.hxx>
 #include <comphelper/sequence.hxx>
 #include <utility>
 
@@ -952,8 +953,10 @@ OUString TypeDetection::impl_detectTypeFlatAndDeep(      
utl::MediaDescriptor& r
 
                         if (aRequest.isApproved())
                         {
+                            // lok: we want to overwrite file in jail, so 
don't use template flag
+                            const bool bIsLOK = 
comphelper::LibreOfficeKit::isActive();
                             
rDescriptor[utl::MediaDescriptor::PROP_DOCUMENTTITLE] <<= aDocumentTitle;
-                            rDescriptor[utl::MediaDescriptor::PROP_ASTEMPLATE] 
<<= true;
+                            rDescriptor[utl::MediaDescriptor::PROP_ASTEMPLATE] 
<<= !bIsLOK;
                             rDescriptor["RepairPackage"] <<= true;
                         }
                         else
diff --git a/filter/source/storagefilterdetect/filterdetect.cxx 
b/filter/source/storagefilterdetect/filterdetect.cxx
index 8312726e11da..c73355e02a9d 100644
--- a/filter/source/storagefilterdetect/filterdetect.cxx
+++ b/filter/source/storagefilterdetect/filterdetect.cxx
@@ -141,8 +141,10 @@ OUString SAL_CALL 
StorageFilterDetect::detect(uno::Sequence<beans::PropertyValue
                     if ( aRequest.isApproved() )
                     {
                         aTypeName = aRequestedTypeName;
+                        // lok: we want to overwrite file in jail, so don't 
use template flag
+                        const bool bIsLOK = 
comphelper::LibreOfficeKit::isActive();
                         aMediaDesc[MediaDescriptor::PROP_DOCUMENTTITLE] <<= 
aDocumentTitle;
-                        aMediaDesc[MediaDescriptor::PROP_ASTEMPLATE] <<= true;
+                        aMediaDesc[MediaDescriptor::PROP_ASTEMPLATE] <<= 
!bIsLOK;
                         aMediaDesc["RepairPackage"] <<= true;
                     }
                     else
commit dfd7f6dea66b04e65704a96a701ba1ad91af927f
Author:     Mike Kaganski <mike.kagan...@collabora.com>
AuthorDate: Mon Nov 27 12:21:30 2023 +0300
Commit:     Mike Kaganski <mike.kagan...@collabora.com>
CommitDate: Fri Feb 2 13:41:20 2024 +0600

    Related: tdf#96401 Set PROP_ASTEMPLATE for broken ZIP package
    
    Same as in StorageFilterDetect::detect. It would prompt user on save
    to provide a new file name, instead of silently rewriting (possibly
    recovered with errors) document.
    
    Change-Id: I8ede6d01e2d482f409e8b3f7452deb1e4bd02a85
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/159985
    Tested-by: Jenkins
    Reviewed-by: Mike Kaganski <mike.kagan...@collabora.com>

diff --git a/filter/source/config/cache/typedetection.cxx 
b/filter/source/config/cache/typedetection.cxx
index 954a4fd24226..dca10ad94cb1 100644
--- a/filter/source/config/cache/typedetection.cxx
+++ b/filter/source/config/cache/typedetection.cxx
@@ -951,7 +951,11 @@ OUString TypeDetection::impl_detectTypeFlatAndDeep(      
utl::MediaDescriptor& r
                         xInteraction->handle(aRequest.GetRequest());
 
                         if (aRequest.isApproved())
+                        {
+                            
rDescriptor[utl::MediaDescriptor::PROP_DOCUMENTTITLE] <<= aDocumentTitle;
+                            rDescriptor[utl::MediaDescriptor::PROP_ASTEMPLATE] 
<<= true;
                             rDescriptor["RepairPackage"] <<= true;
+                        }
                         else
                             rDescriptor["RepairAllowed"] <<= false; // Do not 
ask again
                     }
commit 09989e73256d1561d4d38fdd4675f3bfcd4a6c49
Author:     Mike Kaganski <mike.kagan...@collabora.com>
AuthorDate: Sun Nov 26 20:18:34 2023 +0300
Commit:     Mike Kaganski <mike.kagan...@collabora.com>
CommitDate: Fri Feb 2 13:11:30 2024 +0600

    tdf#96401: allow to detect a broken ZIP package
    
    In deep detection, first check if it's a broken ZIP package. If it is,
    set the RepairPackage media descriptor property to true.
    
    Pass the RepairPackage value to the OOXML filter detection.
    
    Change-Id: Ic958283f3cce92ac29ce93ac330cc9e409e3eb78
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/159976
    Tested-by: Jenkins
    Reviewed-by: Mike Kaganski <mike.kagan...@collabora.com>

diff --git a/filter/Library_filterconfig.mk b/filter/Library_filterconfig.mk
index 38251aa313f0..7d9318781eb3 100644
--- a/filter/Library_filterconfig.mk
+++ b/filter/Library_filterconfig.mk
@@ -41,6 +41,7 @@ $(eval $(call gb_Library_use_libraries,filterconfig,\
        cppu \
        sal \
        salhelper \
+       sfx \
        i18nlangtag \
 ))
 
diff --git a/filter/source/config/cache/typedetection.cxx 
b/filter/source/config/cache/typedetection.cxx
index 0aaa2ffa6c3d..954a4fd24226 100644
--- a/filter/source/config/cache/typedetection.cxx
+++ b/filter/source/config/cache/typedetection.cxx
@@ -25,9 +25,14 @@
 #include <com/sun/star/util/URLTransformer.hpp>
 #include <com/sun/star/util/XURLTransformer.hpp>
 
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <com/sun/star/embed/StorageFormats.hpp>
 #include <com/sun/star/io/XInputStream.hpp>
 #include <com/sun/star/io/XSeekable.hpp>
+#include <com/sun/star/packages/zip/ZipIOException.hpp>
 #include <com/sun/star/task/XInteractionHandler.hpp>
+
+#include <sfx2/brokenpackageint.hxx>
 #include <o3tl/string_view.hxx>
 #include <tools/wldcrd.hxx>
 #include <sal/log.hxx>
@@ -853,6 +858,50 @@ void TypeDetection::impl_getAllFormatTypes(
 }
 
 
+static bool isBrokenZIP(const css::uno::Reference<css::io::XInputStream>& 
xStream,
+                        const 
css::uno::Reference<css::uno::XComponentContext>& xContext)
+{
+    std::vector<css::uno::Any> aArguments{
+        css::uno::Any(xStream),
+        css::uno::Any(css::beans::NamedValue("AllowRemoveOnInsert", 
css::uno::Any(false))),
+        css::uno::Any(css::beans::NamedValue("StorageFormat",
+                                             
css::uno::Any(css::embed::StorageFormats::ZIP))),
+    };
+    try
+    {
+        // If this is a broken ZIP package, or not a ZIP, this would throw 
ZipIOException
+        xContext->getServiceManager()->createInstanceWithArgumentsAndContext(
+            "com.sun.star.packages.comp.ZipPackage", 
comphelper::containerToSequence(aArguments),
+            xContext);
+    }
+    catch (const css::packages::zip::ZipIOException&)
+    {
+        // Now test if repair will succeed
+        aArguments.emplace_back(css::beans::NamedValue("RepairPackage", 
css::uno::Any(true)));
+        try
+        {
+            // If this is a broken ZIP package that can be repaired, this 
would succeed,
+            // and the result will be not empty
+            if (css::uno::Reference<css::beans::XPropertySet> xPackage{
+                    
xContext->getServiceManager()->createInstanceWithArgumentsAndContext(
+                        "com.sun.star.packages.comp.ZipPackage",
+                        comphelper::containerToSequence(aArguments), xContext),
+                    css::uno::UNO_QUERY })
+                if (bool bHasElements; 
xPackage->getPropertyValue("HasElements") >>= bHasElements)
+                    return bHasElements;
+        }
+        catch (const css::uno::Exception&)
+        {
+        }
+    }
+    catch (const css::uno::Exception&)
+    {
+    }
+    // The package is either not broken, or is not a repairable ZIP
+    return false;
+}
+
+
 OUString TypeDetection::impl_detectTypeFlatAndDeep(      utl::MediaDescriptor& 
rDescriptor   ,
                                                           const FlatDetection& 
                lFlatTypes    ,
                                                                 bool           
            bAllowDeep    ,
@@ -862,6 +911,59 @@ OUString TypeDetection::impl_detectTypeFlatAndDeep(      
utl::MediaDescriptor& r
     // a set and a not set value.
     rLastChance.clear();
 
+    // tdf#96401: First of all, check if this is a broken ZIP package. Not 
doing this here would
+    // make some filters silently not recognize their content in broken 
packages, and some filters
+    // show a warning and mistakenly claim own content based on user choice.
+    if (bAllowDeep && !rDescriptor.getUnpackedValueOrDefault("RepairPackage", 
false)
+        && rDescriptor.getUnpackedValueOrDefault("RepairAllowed", true)
+        && rDescriptor.find(utl::MediaDescriptor::PROP_INTERACTIONHANDLER) != 
rDescriptor.end())
+    {
+        try
+        {
+            impl_openStream(rDescriptor);
+            if (auto xStream = rDescriptor.getUnpackedValueOrDefault(
+                    utl::MediaDescriptor::PROP_INPUTSTREAM,
+                    css::uno::Reference<css::io::XInputStream>()))
+            {
+                css::uno::Reference<css::uno::XComponentContext> xContext;
+
+                // SAFE ->
+                {
+                    osl::ClearableMutexGuard aLock(m_aMutex);
+                    xContext = m_xContext;
+                }
+                // <- SAFE
+
+                if (isBrokenZIP(xStream, xContext))
+                {
+                    if (css::uno::Reference<css::task::XInteractionHandler> 
xInteraction{
+                            
rDescriptor.getValue(utl::MediaDescriptor::PROP_INTERACTIONHANDLER),
+                            css::uno::UNO_QUERY })
+                    {
+                        INetURLObject 
aURL(rDescriptor.getUnpackedValueOrDefault(
+                            utl::MediaDescriptor::PROP_URL, OUString()));
+                        OUString aDocumentTitle
+                            = aURL.getName(INetURLObject::LAST_SEGMENT, true,
+                                           
INetURLObject::DecodeMechanism::WithCharset);
+
+                        // Ask the user whether they wants to try to repair
+                        RequestPackageReparation aRequest(aDocumentTitle);
+                        xInteraction->handle(aRequest.GetRequest());
+
+                        if (aRequest.isApproved())
+                            rDescriptor["RepairPackage"] <<= true;
+                        else
+                            rDescriptor["RepairAllowed"] <<= false; // Do not 
ask again
+                    }
+                }
+            }
+        }
+        catch (const css::uno::Exception&)
+        {
+            // No problem
+        }
+    }
+
     // step over all possible types for this URL.
     // solutions:
     // a) no types                                => no detection
diff --git a/include/oox/helper/zipstorage.hxx 
b/include/oox/helper/zipstorage.hxx
index dec4b483ea3f..dabb714d7db8 100644
--- a/include/oox/helper/zipstorage.hxx
+++ b/include/oox/helper/zipstorage.hxx
@@ -43,7 +43,8 @@ class ZipStorage final : public StorageBase
 public:
     explicit            ZipStorage(
                             const css::uno::Reference< 
css::uno::XComponentContext >& rxContext,
-                            const css::uno::Reference< css::io::XInputStream 
>& rxInStream );
+                            const css::uno::Reference< css::io::XInputStream 
>& rxInStream,
+                            bool bRepairStorage = false );
 
     explicit            ZipStorage(
                             const css::uno::Reference< 
css::uno::XComponentContext >& rxContext,
diff --git a/oox/source/core/filterdetect.cxx b/oox/source/core/filterdetect.cxx
index 6f22d612aa13..db711770832c 100644
--- a/oox/source/core/filterdetect.cxx
+++ b/oox/source/core/filterdetect.cxx
@@ -427,7 +427,8 @@ OUString SAL_CALL FilterDetect::detect( Sequence< 
PropertyValue >& rMediaDescSeq
         Reference< XInputStream > xInputStream( extractUnencryptedPackage( 
aMediaDescriptor ), UNO_SET_THROW );
 
         // stream must be a ZIP package
-        ZipStorage aZipStorage( mxContext, xInputStream );
+        ZipStorage aZipStorage(mxContext, xInputStream,
+                               
aMediaDescriptor.getUnpackedValueOrDefault("RepairPackage", false));
         if( aZipStorage.isStorage() )
         {
             // create the fast parser, register the XML namespaces, set 
document handler
diff --git a/oox/source/helper/zipstorage.cxx b/oox/source/helper/zipstorage.cxx
index 10f7d79c25f1..db73b14bdd6c 100644
--- a/oox/source/helper/zipstorage.cxx
+++ b/oox/source/helper/zipstorage.cxx
@@ -38,7 +38,7 @@ using namespace ::com::sun::star::io;
 using namespace ::com::sun::star::lang;
 using namespace ::com::sun::star::uno;
 
-ZipStorage::ZipStorage( const Reference< XComponentContext >& rxContext, const 
Reference< XInputStream >& rxInStream ) :
+ZipStorage::ZipStorage( const Reference< XComponentContext >& rxContext, const 
Reference< XInputStream >& rxInStream, bool bRepairStorage ) :
     StorageBase( rxInStream, false )
 {
     OSL_ENSURE( rxContext.is(), "ZipStorage::ZipStorage - missing component 
context" );
@@ -61,7 +61,7 @@ ZipStorage::ZipStorage( const Reference< XComponentContext >& 
rxContext, const R
             implementation of relations handling.
          */
         mxStorage = 
::comphelper::OStorageHelper::GetStorageOfFormatFromInputStream(
-            ZIP_STORAGE_FORMAT_STRING, rxInStream, rxContext, false);
+            ZIP_STORAGE_FORMAT_STRING, rxInStream, rxContext, bRepairStorage);
     }
     catch (Exception const&)
     {
diff --git a/package/source/zippackage/ZipPackage.cxx 
b/package/source/zippackage/ZipPackage.cxx
index 6316498ef0b8..a0e1a4c1b72c 100644
--- a/package/source/zippackage/ZipPackage.cxx
+++ b/package/source/zippackage/ZipPackage.cxx
@@ -1814,6 +1814,10 @@ Any SAL_CALL ZipPackage::getPropertyValue( const 
OUString& PropertyName )
     {
         return Any(m_bMediaTypeFallbackUsed);
     }
+    else if (PropertyName == "HasElements")
+    {
+        return Any(m_pZipFile && m_pZipFile->entries().hasMoreElements());
+    }
     throw UnknownPropertyException(PropertyName);
 }
 void SAL_CALL ZipPackage::addPropertyChangeListener( const OUString& 
/*aPropertyName*/, const uno::Reference< XPropertyChangeListener >& 
/*xListener*/ )
commit 8925680370ce952c56e4debd23793c0fbf693044
Author:     Mike Kaganski <mike.kagan...@collabora.com>
AuthorDate: Sun Nov 26 00:23:39 2023 +0300
Commit:     Mike Kaganski <mike.kagan...@collabora.com>
CommitDate: Wed Jan 31 17:38:56 2024 +0600

    *DocumentLockFile ctor may throw
    
    ... e.g., when passed URL is invalid, as seen after opening
    https://bugs.documentfoundation.org/attachment.cgi?id=121217
    using "Office Open XML Text" filter, which sets "RepairPackage"
    in the media descriptor, which makes the opened file unnamed.
    
    Since the code is called from SfxMedium dtor, this crashed on
    closing this file.
    
    Change-Id: I95f6b16f1421abd55e6739ed431878bb72cf3a8e
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/159964
    Tested-by: Mike Kaganski <mike.kagan...@collabora.com>
    Reviewed-by: Mike Kaganski <mike.kagan...@collabora.com>

diff --git a/sfx2/source/doc/docfile.cxx b/sfx2/source/doc/docfile.cxx
index 8690da98913e..0a0e1c35e91c 100644
--- a/sfx2/source/doc/docfile.cxx
+++ b/sfx2/source/doc/docfile.cxx
@@ -3212,23 +3212,21 @@ void SfxMedium::UnlockFile( bool bReleaseLockStream )
     if ( !pImpl->m_bLocked )
         return;
 
-    ::svt::DocumentLockFile aLockFile( pImpl->m_aLogicName );
-
     try
     {
-        pImpl->m_bLocked = false;
-        // TODO/LATER: A warning could be shown in case the file is not the 
own one
-        aLockFile.RemoveFile();
-    }
-    catch( const io::WrongFormatException& )
-    {
+        ::svt::DocumentLockFile aLockFile(pImpl->m_aLogicName);
+
         try
+        {
+            pImpl->m_bLocked = false;
+            // TODO/LATER: A warning could be shown in case the file is not 
the own one
+            aLockFile.RemoveFile();
+        }
+        catch (const io::WrongFormatException&)
         {
             // erase the empty or corrupt file
             aLockFile.RemoveFileDirectly();
         }
-        catch( const uno::Exception& )
-        {}
     }
     catch( const uno::Exception& )
     {}
@@ -3236,23 +3234,21 @@ void SfxMedium::UnlockFile( bool bReleaseLockStream )
     if(!pImpl->m_bMSOLockFileCreated)
         return;
 
-    ::svt::MSODocumentLockFile aMSOLockFile( pImpl->m_aLogicName );
-
     try
     {
-        pImpl->m_bLocked = false;
-        // TODO/LATER: A warning could be shown in case the file is not the 
own one
-        aMSOLockFile.RemoveFile();
-    }
-    catch( const io::WrongFormatException& )
-    {
+        ::svt::MSODocumentLockFile aMSOLockFile(pImpl->m_aLogicName);
+
         try
+        {
+            pImpl->m_bLocked = false;
+            // TODO/LATER: A warning could be shown in case the file is not 
the own one
+            aMSOLockFile.RemoveFile();
+        }
+        catch (const io::WrongFormatException&)
         {
             // erase the empty or corrupt file
             aMSOLockFile.RemoveFileDirectly();
         }
-        catch( const uno::Exception& )
-        {}
     }
     catch( const uno::Exception& )
     {}

Reply via email to