sfx2/source/control/thumbnailview.cxx |  149 +++++++++++++++++++++-------------
 1 file changed, 94 insertions(+), 55 deletions(-)

New commits:
commit bf2b5b64b2ab3d4082c766fc64b3cf8f27125ff4
Author:     Mike Kaganski <mike.kagan...@collabora.com>
AuthorDate: Mon Apr 28 11:19:04 2025 -0400
Commit:     Justin Luth <justin.l...@collabora.com>
CommitDate: Thu May 1 17:42:40 2025 +0200

    Refactor getting thumbnail a bit
    
    This backport includes 7cad6f88cc6fdef91e7a71b9b4694559517c2e28
      tdf#166035 thumbnailview: recognize some MS-format thumbnails
    
    Use OOXML package relations (and XRelationshipAccess) to access
    OOXML's thumbnails.
    Unify obtaining the bitmap.
    This change also fixes a possible nullptr dereference when trying
    to read the older Thumbnail/thumbnail.png - access to xDocStorage
    wasn't checked before.
    
    Change-Id: Iff9d85cb461960d2b11acaa008ba9ae69af475a9
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/184750
    Reviewed-by: Mike Kaganski <mike.kagan...@collabora.com>
    Tested-by: Jenkins
    (cherry picked from commit b4965d0a7875384d1fedc7d43762c94b30e5e90f)
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/184767
    Reviewed-by: Miklos Vajna <vmik...@collabora.com>
    Tested-by: Jenkins CollaboraOffice <jenkinscollaboraoff...@gmail.com>
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/184845
    Reviewed-by: Justin Luth <jl...@mail.com>

diff --git a/sfx2/source/control/thumbnailview.cxx 
b/sfx2/source/control/thumbnailview.cxx
index 1ae47016935e..e87080fe2085 100644
--- a/sfx2/source/control/thumbnailview.cxx
+++ b/sfx2/source/control/thumbnailview.cxx
@@ -18,6 +18,7 @@
 
 #include <basegfx/color/bcolortools.hxx>
 #include <comphelper/processfactory.hxx>
+#include <comphelper/propertyvalue.hxx>
 #include <drawinglayer/attribute/fontattribute.hxx>
 #include <drawinglayer/primitive2d/PolyPolygonColorPrimitive2D.hxx>
 #include <drawinglayer/primitive2d/Primitive2DContainer.hxx>
@@ -34,12 +35,17 @@
 #include <vcl/settings.hxx>
 #include <vcl/event.hxx>
 #include <vcl/filter/PngImageReader.hxx>
+#include <vcl/graphicfilter.hxx>
 #include <vcl/weldutils.hxx>
 
 #include <com/sun/star/accessibility/AccessibleEventId.hpp>
 #include <com/sun/star/embed/ElementModes.hpp>
 #include <com/sun/star/embed/StorageFactory.hpp>
+#include <com/sun/star/embed/StorageFormats.hpp>
+#include <com/sun/star/embed/XHierarchicalStorageAccess.hpp>
+#include <com/sun/star/embed/XRelationshipAccess.hpp>
 #include <com/sun/star/embed/XStorage.hpp>
+#include <com/sun/star/packages/zip/ZipFileAccess.hpp>
 
 #include <memory>
 #if !ENABLE_WASM_STRIP_RECENT
@@ -59,72 +65,90 @@ bool ThumbnailView::renameItem(ThumbnailViewItem*, const 
OUString&)
     return false;
 }
 
-BitmapEx ThumbnailView::readThumbnail(const OUString &msURL)
+static css::uno::Reference<css::embed::XHierarchicalStorageAccess>
+getStorageAccess(const OUString& URL, sal_Int32 format)
 {
-    using namespace ::com::sun::star;
-    using namespace ::com::sun::star::uno;
+    auto xFactory = 
css::embed::StorageFactory::create(comphelper::getProcessComponentContext());
+    css::uno::Sequence descriptor{ 
comphelper::makePropertyValue(u"StorageFormat"_ustr, format) };
+    css::uno::Sequence args{ css::uno::Any(URL), 
css::uno::Any(css::embed::ElementModes::READ),
+                             css::uno::Any(descriptor) };
+    return xFactory->createInstanceWithArguments(args)
+        .queryThrow<css::embed::XHierarchicalStorageAccess>();
+}
 
-    // Load the thumbnail from a template document.
-    uno::Reference<io::XInputStream> xIStream;
+static css::uno::Reference<css::io::XInputStream>
+getHierarchicalStream(const 
css::uno::Reference<css::embed::XHierarchicalStorageAccess>& xStorage,
+                      const OUString& name)
+{
+    auto xStream
+        = xStorage->openStreamElementByHierarchicalName(name, 
css::embed::ElementModes::READ);
+    return xStream->getInputStream();
+}
 
-    uno::Reference< uno::XComponentContext > 
xContext(::comphelper::getProcessComponentContext());
-    try
+static css::uno::Reference<css::io::XInputStream>
+getFirstHierarchicalStream(const OUString& URL, sal_Int32 format,
+                           std::initializer_list<OUString> names)
+{
+    auto xStorage(getStorageAccess(URL, format));
+    for (const auto& name : names)
     {
-        uno::Reference<lang::XSingleServiceFactory> xStorageFactory = 
embed::StorageFactory::create(xContext);
-
-        uno::Sequence<uno::Any> aArgs{ uno::Any(msURL), 
uno::Any(embed::ElementModes::READ) };
-        uno::Reference<embed::XStorage> xDocStorage (
-            xStorageFactory->createInstanceWithArguments(aArgs),
-            uno::UNO_QUERY);
-
         try
         {
-            if (xDocStorage.is())
-            {
-                uno::Reference<embed::XStorage> xStorage (
-                    xDocStorage->openStorageElement(
-                        "Thumbnails",
-                        embed::ElementModes::READ));
-                if (xStorage.is())
-                {
-                    uno::Reference<io::XStream> xThumbnailCopy (
-                        xStorage->cloneStreamElement("thumbnail.png"));
-                    if (xThumbnailCopy.is())
-                        xIStream = xThumbnailCopy->getInputStream();
-                }
-            }
+            return getHierarchicalStream(xStorage, name);
         }
-        catch (const uno::Exception&)
+        catch (const css::uno::Exception&)
         {
-            TOOLS_WARN_EXCEPTION("sfx",
-                "caught exception while trying to access 
Thumbnail/thumbnail.png of " << msURL);
+            TOOLS_WARN_EXCEPTION("sfx", "caught exception while trying to 
access " << name << " of "
+                                                                               
    << URL);
         }
+    }
+    return {};
+}
 
-        try
+static css::uno::Reference<css::io::XInputStream>
+getFirstStreamByRelType(const OUString& URL, std::initializer_list<OUString> 
types)
+{
+    auto xStorage(getStorageAccess(URL, css::embed::StorageFormats::OFOPXML));
+    if (auto xRelationshipAccess = 
xStorage.query<css::embed::XRelationshipAccess>())
+    {
+        for (const auto& type : types)
         {
-            // An (older) implementation had a bug - The storage
-            // name was "Thumbnail" instead of "Thumbnails".  The
-            // old name is still used as fallback but this code can
-            // be removed soon.
-            if ( ! xIStream.is())
+            auto rels = xRelationshipAccess->getRelationshipsByType(type);
+            if (rels.hasElements())
             {
-                uno::Reference<embed::XStorage> xStorage (
-                    xDocStorage->openStorageElement( "Thumbnail",
-                        embed::ElementModes::READ));
-                if (xStorage.is())
+                // ISO/IEC 29500-1:2016(E) 15.2.16 Thumbnail Part: "Packages 
shall not contain
+                // more than one thumbnail relationship associated with the 
package as a whole"
+                for (const auto& [tag, value] : rels[0])
                 {
-                    uno::Reference<io::XStream> xThumbnailCopy (
-                        xStorage->cloneStreamElement("thumbnail.png"));
-                    if (xThumbnailCopy.is())
-                        xIStream = xThumbnailCopy->getInputStream();
+                    if (tag == "Id")
+                    {
+                        return getHierarchicalStream(xStorage,
+                                                     
xRelationshipAccess->getTargetByID(value));
+                    }
                 }
             }
         }
-        catch (const uno::Exception&)
-        {
-            TOOLS_WARN_EXCEPTION("sfx",
-                "caught exception while trying to access 
Thumbnails/thumbnail.png of " << msURL);
-        }
+    }
+    return {};
+}
+
+BitmapEx ThumbnailView::readThumbnail(const OUString &msURL)
+{
+    using namespace ::com::sun::star;
+    using namespace ::com::sun::star::uno;
+
+    // Load the thumbnail from a template document.
+    uno::Reference<io::XInputStream> xIStream;
+
+    try
+    {
+        // An (older) implementation had a bug - The storage
+        // name was "Thumbnail" instead of "Thumbnails".  The
+        // old name is still used as fallback but this code can
+        // be removed soon.
+        xIStream = getFirstHierarchicalStream(
+            msURL, embed::StorageFormats::PACKAGE,
+            { u"Thumbnails/thumbnail.png"_ustr, 
u"Thumbnail/thumbnail.png"_ustr });
     }
     catch (const uno::Exception&)
     {
@@ -133,14 +157,29 @@ BitmapEx ThumbnailView::readThumbnail(const OUString 
&msURL)
             << msURL);
     }
 
+    if (!xIStream.is())
+    {
+        // OOXML?
+        try
+        {
+            // Check both Transitional and Strict relationships
+            xIStream = getFirstStreamByRelType(
+                msURL,
+                { 
u"http://schemas.openxmlformats.org/package/2006/relationships/metadata/thumbnail"_ustr,
+                  
u"http://purl.oclc.org/ooxml/officeDocument/relationships/metadata/thumbnail"_ustr
 });
+        }
+        catch (const uno::Exception&)
+        {
+            // Not an OOXML; fine
+        }
+    }
+
     // Extract the image from the stream.
     BitmapEx aThumbnail;
-    if (xIStream.is())
+    if (auto pStream = utl::UcbStreamHelper::CreateStream(xIStream, 
/*CloseStream=*/true))
     {
-        std::unique_ptr<SvStream> pStream (
-            ::utl::UcbStreamHelper::CreateStream (xIStream));
-        vcl::PngImageReader aReader (*pStream);
-        aThumbnail = aReader.read ();
+        Graphic aGraphic = 
GraphicFilter::GetGraphicFilter().ImportUnloadedGraphic(*pStream);
+        aThumbnail = aGraphic.GetBitmapEx();
     }
 
     // Note that the preview is returned without scaling it to the desired

Reply via email to