include/com/sun/star/uno/Any.h                       |    1 
 include/com/sun/star/uno/Any.hxx                     |    2 
 sw/qa/extras/ooxmlexport/data/glossaryWithEmail.docx |binary
 sw/qa/extras/ooxmlexport/ooxmlexport3.cxx            |   11 +
 sw/source/filter/ww8/docxexport.cxx                  |   42 +++-
 writerfilter/inc/ooxml/OOXMLDocument.hxx             |    3 
 writerfilter/source/ooxml/OOXMLDocumentImpl.cxx      |  163 +++++++++----------
 writerfilter/source/ooxml/OOXMLDocumentImpl.hxx      |    4 
 8 files changed, 132 insertions(+), 94 deletions(-)

New commits:
commit dda4867a0b5a2d29d8a01a3656e0c8dac7626d2f
Author:     Mike Kaganski <mike.kagan...@collabora.com>
AuthorDate: Tue Nov 29 20:23:13 2022 +0300
Commit:     Mike Kaganski <mike.kagan...@collabora.com>
CommitDate: Wed Nov 30 06:52:09 2022 +0100

    tdf#152289: implement external glossary relations roundtrip
    
    Change-Id: I20f4439abfbf73485734fd8373fffb2916d390f0
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/143470
    Tested-by: Jenkins
    Reviewed-by: Mike Kaganski <mike.kagan...@collabora.com>

diff --git a/include/com/sun/star/uno/Any.h b/include/com/sun/star/uno/Any.h
index 123952142517..f232ccd90fe9 100644
--- a/include/com/sun/star/uno/Any.h
+++ b/include/com/sun/star/uno/Any.h
@@ -88,6 +88,7 @@ public:
     explicit Any(rtl::OUStringConcat<T1, T2> const &) = delete;
     template<typename T> explicit inline Any(rtl::OUStringNumber<T> && value);
     template<typename T> explicit Any(rtl::OUStringNumber<T> const &) = delete;
+    template <std::size_t N> explicit inline Any(const 
rtl::OUStringLiteral<N>& value);
 #endif
 
     /** Copy constructor: Sets value of the given any.
diff --git a/include/com/sun/star/uno/Any.hxx b/include/com/sun/star/uno/Any.hxx
index fbceffa5e241..d73b2a586d61 100644
--- a/include/com/sun/star/uno/Any.hxx
+++ b/include/com/sun/star/uno/Any.hxx
@@ -86,6 +86,8 @@ Any::Any(rtl::OUStringConcat<T1, T2> && value):
 {}
 template<typename T>
 Any::Any(rtl::OUStringNumber<T> && value): 
Any(rtl::OUString(std::move(value))) {}
+template <std::size_t N>
+Any::Any(const rtl::OUStringLiteral<N>& value): Any(rtl::OUString(value)) {}
 #endif
 
 inline Any::Any( const Any & rAny )
diff --git a/sw/qa/extras/ooxmlexport/data/glossaryWithEmail.docx 
b/sw/qa/extras/ooxmlexport/data/glossaryWithEmail.docx
new file mode 100644
index 000000000000..5ec375adf3ac
Binary files /dev/null and 
b/sw/qa/extras/ooxmlexport/data/glossaryWithEmail.docx differ
diff --git a/sw/qa/extras/ooxmlexport/ooxmlexport3.cxx 
b/sw/qa/extras/ooxmlexport/ooxmlexport3.cxx
index fe1aa44d75e7..9930fa27b768 100644
--- a/sw/qa/extras/ooxmlexport/ooxmlexport3.cxx
+++ b/sw/qa/extras/ooxmlexport/ooxmlexport3.cxx
@@ -991,6 +991,17 @@ CPPUNIT_TEST_FIXTURE(Test, testGlossary)
     assertXPath(pXmlDoc, "/w:glossaryDocument", "Ignorable", "w14 wp14");
 }
 
+CPPUNIT_TEST_FIXTURE(Test, testGlossaryWithEmail)
+{
+    // tdf#152289
+    loadAndSave("glossaryWithEmail.docx");
+    xmlDocUniquePtr pXmlDoc = 
parseExport("word/glossary/_rels/document.xml.rels");
+    assertXPath(pXmlDoc, "/rels:Relationships/rels:Relationship[@Id='rId4' "
+        "and 
@Type='http://schemas.openxmlformats.org/officeDocument/2006/relationships/hyperlink'
 "
+        "and @Target='mailto:emailgoesh...@example.com' "
+        "and @TargetMode='External']");
+}
+
 DECLARE_OOXMLEXPORT_TEST(testFdo71785, "fdo71785.docx")
 {
     // crashtest
diff --git a/sw/source/filter/ww8/docxexport.cxx 
b/sw/source/filter/ww8/docxexport.cxx
index 97875b28817d..ea59775eda15 100644
--- a/sw/source/filter/ww8/docxexport.cxx
+++ b/sw/source/filter/ww8/docxexport.cxx
@@ -1484,6 +1484,7 @@ void DocxExport::WriteTheme()
         uno::Sequence< beans::StringPair >() );
 }
 
+// See OOXMLDocumentImpl::resolveGlossaryStream
 void DocxExport::WriteGlossary()
 {
     uno::Reference< beans::XPropertySet > xPropSet( 
m_rDoc.GetDocShell()->GetBaseModel(), uno::UNO_QUERY_THROW );
@@ -1494,7 +1495,7 @@ void DocxExport::WriteGlossary()
         return;
 
     uno::Reference<xml::dom::XDocument> glossaryDocDom;
-    uno::Sequence< uno::Sequence< uno::Any> > glossaryDomList;
+    uno::Sequence< uno::Sequence<beans::NamedValue> > glossaryDomList;
     uno::Sequence< beans::PropertyValue > propList;
     xPropSet->getPropertyValue( aName ) >>= propList;
     sal_Int32 collectedProperties = 0;
@@ -1532,20 +1533,43 @@ void DocxExport::WriteGlossary()
     serializer->serialize( uno::Reference< xml::sax::XDocumentHandler >( 
writer, uno::UNO_QUERY_THROW ),
         uno::Sequence< beans::StringPair >() );
 
-    for ( const uno::Sequence< uno::Any>& glossaryElement : 
std::as_const(glossaryDomList))
+    for (const uno::Sequence<beans::NamedValue>& glossaryElement : 
glossaryDomList)
     {
-        OUString gTarget, gType, gId, contentType;
+        OUString gTarget, gType, gId, contentType, targetMode;
         uno::Reference<xml::dom::XDocument> xDom;
-        glossaryElement[0] >>= xDom;
-        glossaryElement[1] >>= gId;
-        glossaryElement[2] >>= gType;
-        glossaryElement[3] >>= gTarget;
-        glossaryElement[4] >>= contentType;
+        for (const auto& [name, value] : glossaryElement)
+        {
+            if (name == "Id")
+                value >>= gId;
+            else if (name == "Type")
+                value >>= gType;
+            else if (name == "Target")
+                value >>= gTarget;
+            else if (name == "TargetMode")
+                value >>= targetMode;
+            else if (name == "_contentType")
+                value >>= contentType;
+            else if (name == "_relDom")
+                value >>= xDom;
+        }
+        if (gId.isEmpty() || gType.isEmpty() || gTarget.isEmpty())
+            continue;
+        const bool bExternal = targetMode == "External";
+        if (!bExternal && !xDom)
+        {
+            // Some internal relation, but we didn't create a DOM for it
+            // in OOXMLDocumentImpl::resolveGlossaryStream?
+            SAL_WARN("sw.ww8", "Glossary internal relation without DOM: Id=\"" 
+ gId
+                                   + "\" Type=\"" + gType + "\" Target=\"" + 
gTarget + "\"");
+            continue;
+        }
         gId = gId.copy(3); //"rId" only save the numeric value
 
         PropertySet aProps(xOutputStream);
         aProps.setAnyProperty( PROP_RelId, uno::Any( gId.toInt32() ));
-        m_rFilter.addRelation( xOutputStream, gType, gTarget);
+        m_rFilter.addRelation(xOutputStream, gType, gTarget, bExternal);
+        if (!xDom)
+            continue; // External relation, no stream to write
         uno::Reference< xml::sax::XSAXSerializable > gserializer( xDom, 
uno::UNO_QUERY );
         writer->setOutputStream(GetFilter().openFragmentStream( 
"word/glossary/" + gTarget, contentType ) );
         gserializer->serialize( uno::Reference< xml::sax::XDocumentHandler >( 
writer, uno::UNO_QUERY_THROW ),
diff --git a/writerfilter/inc/ooxml/OOXMLDocument.hxx 
b/writerfilter/inc/ooxml/OOXMLDocument.hxx
index 8bf1502848ec..1179be43c8ac 100644
--- a/writerfilter/inc/ooxml/OOXMLDocument.hxx
+++ b/writerfilter/inc/ooxml/OOXMLDocument.hxx
@@ -19,6 +19,7 @@
 #pragma once
 
 #include <sal/types.h>
+#include <com/sun/star/beans/NamedValue.hpp>
 #include <com/sun/star/uno/Reference.hxx>
 #include <com/sun/star/io/XInputStream.hpp>
 #include <com/sun/star/uno/XComponentContext.hpp>
@@ -219,7 +220,7 @@ public:
     virtual void popShapeContext() = 0;
     virtual css::uno::Reference<css::xml::dom::XDocument> getThemeDom( ) = 0;
     virtual css::uno::Reference<css::xml::dom::XDocument> getGlossaryDocDom( ) 
= 0;
-    virtual css::uno::Sequence<css::uno::Sequence< css::uno::Any> > 
getGlossaryDomList() = 0;
+    virtual css::uno::Sequence<css::uno::Sequence< css::beans::NamedValue> > 
getGlossaryDomList() = 0;
     virtual css::uno::Sequence<css::uno::Reference<css::xml::dom::XDocument> > 
getCustomXmlDomList( ) = 0;
     virtual css::uno::Sequence<css::uno::Reference<css::xml::dom::XDocument> > 
getCustomXmlDomPropsList( ) = 0;
     virtual css::uno::Sequence<css::beans::PropertyValue > getEmbeddingsList() 
= 0;
diff --git a/writerfilter/source/ooxml/OOXMLDocumentImpl.cxx 
b/writerfilter/source/ooxml/OOXMLDocumentImpl.cxx
index 174549ed5e4b..fdfc1f1ed0ab 100644
--- a/writerfilter/source/ooxml/OOXMLDocumentImpl.cxx
+++ b/writerfilter/source/ooxml/OOXMLDocumentImpl.cxx
@@ -37,6 +37,7 @@
 #include <svx/dialmgr.hxx>
 #include <svx/strings.hrc>
 #include <comphelper/sequence.hxx>
+#include <comphelper/namedvaluecollection.hxx>
 #include <cppuhelper/exc_hlp.hxx>
 #include <unotools/mediadescriptor.hxx>
 
@@ -600,17 +601,32 @@ void OOXMLDocumentImpl::resolveCustomXmlStream(Stream & 
rStream)
     mxCustomXmlDomPropsList = 
comphelper::containerToSequence(aCustomXmlDomPropsList);
 }
 
-void OOXMLDocumentImpl::resolveGlossaryStream(Stream & /*rStream*/)
+namespace
 {
-    static const char sSettingsType[] = 
"http://schemas.openxmlformats.org/officeDocument/2006/relationships/settings";;
-    static const char sStylesType[] = 
"http://schemas.openxmlformats.org/officeDocument/2006/relationships/styles";;
-    static const char sFonttableType[] = 
"http://schemas.openxmlformats.org/officeDocument/2006/relationships/fontTable";;
-    static const char sWebSettings[] = 
"http://schemas.openxmlformats.org/officeDocument/2006/relationships/webSettings";;
-    static const char sSettingsTypeStrict[] = 
"http://purl.oclc.org/ooxml/officeDocument/relationships/settings";;
-    static const char sStylesTypeStrict[] = 
"http://purl.oclc.org/ooxml/officeDocument/relationships/styles";;
-    static const char sFonttableTypeStrict[] = 
"http://purl.oclc.org/ooxml/officeDocument/relationships/fontTable";;
-    static const char sWebSettingsStrict[] = 
"http://purl.oclc.org/ooxml/officeDocument/relationships/webSettings";;
+const char sSettingsType[] = 
"http://schemas.openxmlformats.org/officeDocument/2006/relationships/settings";;
+const char sStylesType[] = 
"http://schemas.openxmlformats.org/officeDocument/2006/relationships/styles";;
+const char sFonttableType[] = 
"http://schemas.openxmlformats.org/officeDocument/2006/relationships/fontTable";;
+const char sWebSettings[] = 
"http://schemas.openxmlformats.org/officeDocument/2006/relationships/webSettings";;
+const char sSettingsTypeStrict[] = 
"http://purl.oclc.org/ooxml/officeDocument/relationships/settings";;
+const char sStylesTypeStrict[] = 
"http://purl.oclc.org/ooxml/officeDocument/relationships/styles";;
+const char sFonttableTypeStrict[] = 
"http://purl.oclc.org/ooxml/officeDocument/relationships/fontTable";;
+const char sWebSettingsStrict[] = 
"http://purl.oclc.org/ooxml/officeDocument/relationships/webSettings";;
+
+constexpr OUStringLiteral sId = u"Id";
+constexpr OUStringLiteral sType = u"Type";
+constexpr OUStringLiteral sTarget = u"Target";
+constexpr OUStringLiteral sTargetMode = u"TargetMode";
+constexpr OUStringLiteral sContentType = u"_contentType";
+constexpr OUStringLiteral sRelDom = u"_relDom";
+constexpr OUStringLiteral sSettingsContentType = 
u"application/vnd.openxmlformats-officedocument.wordprocessingml.settings+xml";
+constexpr OUStringLiteral sStylesContentType = 
u"application/vnd.openxmlformats-officedocument.wordprocessingml.styles+xml";
+constexpr OUStringLiteral sWebsettingsContentType = 
u"application/vnd.openxmlformats-officedocument.wordprocessingml.webSettings+xml";
+constexpr OUStringLiteral sFonttableContentType = 
u"application/vnd.openxmlformats-officedocument.wordprocessingml.fontTable+xml";
+}
 
+// See DocxExport::WriteGlossary
+void OOXMLDocumentImpl::resolveGlossaryStream(Stream & /*rStream*/)
+{
     OOXMLStream::Pointer_t pStream;
     try
     {
@@ -629,80 +645,63 @@ void OOXMLDocumentImpl::resolveGlossaryStream(Stream & 
/*rStream*/)
 
 
     const uno::Sequence< uno::Sequence< beans::StringPair > >aSeqs = 
xRelationshipAccess->getAllRelationships();
-    std::vector< uno::Sequence<uno::Any> > aGlossaryDomList;
+    std::vector< uno::Sequence<beans::NamedValue> > aGlossaryDomList;
     for (const uno::Sequence< beans::StringPair >& aSeq : aSeqs)
     {
-          OOXMLStream::Pointer_t gStream;
-          //Follows following aSeq[0] is Id, aSeq[1] is Type, aSeq[2] is Target
-          if (aSeq.getLength() < 3)
-          {
-              SAL_WARN("writerfilter.ooxml", "too short sequence");
-              continue;
-          }
-
-          OUString gId(aSeq[0].Second);
-          OUString gType(aSeq[1].Second);
-          OUString gTarget(aSeq[2].Second);
-          OUString contentType;
-
-          OOXMLStream::StreamType_t nType(OOXMLStream::UNKNOWN);
-          bool bFound = true;
-          if(gType == sSettingsType ||
-                  gType == sSettingsTypeStrict)
-          {
-              nType = OOXMLStream::SETTINGS;
-              contentType = 
"application/vnd.openxmlformats-officedocument.wordprocessingml.settings+xml";
-          }
-          else if(gType == sStylesType ||
-                  gType == sStylesTypeStrict)
-          {
-              nType = OOXMLStream::STYLES;
-              contentType = 
"application/vnd.openxmlformats-officedocument.wordprocessingml.styles+xml";
-          }
-          else if(gType == sWebSettings ||
-                  gType == sWebSettingsStrict)
-          {
-              nType = OOXMLStream::WEBSETTINGS;
-              contentType = 
"application/vnd.openxmlformats-officedocument.wordprocessingml.webSettings+xml";
-          }
-          else if(gType == sFonttableType ||
-                  gType == sFonttableTypeStrict)
-          {
-              nType = OOXMLStream::FONTTABLE;
-              contentType = 
"application/vnd.openxmlformats-officedocument.wordprocessingml.fontTable+xml";
-          }
-          else
-          {
-              bFound = false;
-              //"Unhandled content-type while grab bagging Glossary Folder");
-          }
-
-          if (bFound)
-          {
-              uno::Reference<xml::dom::XDocument> xDom;
-              try
-              {
-                  gStream = OOXMLDocumentFactory::createStream(pStream, nType);
-                  uno::Reference<io::XInputStream> xInputStream = 
gStream->getDocumentStream();
-                  uno::Reference<uno::XComponentContext> 
xContext(pStream->getContext());
-                  uno::Reference<xml::dom::XDocumentBuilder> 
xDomBuilder(xml::dom::DocumentBuilder::create(xContext));
-                  xDom = xDomBuilder->parse(xInputStream);
-              }
-              catch (uno::Exception const&)
-              {
-                  TOOLS_INFO_EXCEPTION("writerfilter.ooxml", "importSubStream: 
exception while "
-                             "parsing stream of Type" << nType);
-                  return;
-              }
-
-              if (xDom.is())
-              {
-                  uno::Sequence< uno::Any > glossaryTuple{ uno::Any(xDom), 
uno::Any(gId),
-                                                           uno::Any(gType), 
uno::Any(gTarget),
-                                                           
uno::Any(contentType) };
-                  aGlossaryDomList.push_back(glossaryTuple);
-              }
-          }
+        comphelper::NamedValueCollection aRelDefinition;
+        for (const auto& [name, value] : aSeq)
+            aRelDefinition.put(name, value);
+
+        const OUString gType = aRelDefinition.getOrDefault(sType, OUString{});
+        OOXMLStream::StreamType_t nType(OOXMLStream::UNKNOWN);
+        if (gType == sSettingsType || gType == sSettingsTypeStrict)
+        {
+            nType = OOXMLStream::SETTINGS;
+            aRelDefinition.put(sContentType, sSettingsContentType);
+        }
+        else if (gType == sStylesType || gType == sStylesTypeStrict)
+        {
+            nType = OOXMLStream::STYLES;
+            aRelDefinition.put(sContentType, sStylesContentType);
+        }
+        else if (gType == sWebSettings || gType == sWebSettingsStrict)
+        {
+            nType = OOXMLStream::WEBSETTINGS;
+            aRelDefinition.put(sContentType, sWebsettingsContentType);
+        }
+        else if (gType == sFonttableType || gType == sFonttableTypeStrict)
+        {
+            nType = OOXMLStream::FONTTABLE;
+            aRelDefinition.put(sContentType, sFonttableContentType);
+        }
+        else if (aRelDefinition.getOrDefault(sTargetMode, OUString{}) != 
"External")
+        {
+            // Some internal relation, but we don't create a DOM for it here 
yet?
+            SAL_WARN("writerfilter.ooxml", "Unknown type of glossary internal 
relation: "
+                "Id=\"" + aRelDefinition.getOrDefault<OUString>(sId, {}) + "\" 
"
+                "Type=\"" + gType + "\" "
+                "Target=\"" + aRelDefinition.getOrDefault<OUString>(sTarget, 
{}) + "\"");
+            continue;
+        }
+
+        if (nType != OOXMLStream::UNKNOWN)
+        {
+            try
+            {
+                auto gStream = OOXMLDocumentFactory::createStream(pStream, 
nType);
+                uno::Reference xInputStream = gStream->getDocumentStream();
+                uno::Reference xContext(pStream->getContext());
+                uno::Reference 
xDomBuilder(xml::dom::DocumentBuilder::create(xContext));
+                uno::Reference xDom = xDomBuilder->parse(xInputStream);
+                aRelDefinition.put(sRelDom, xDom);
+            }
+            catch (uno::Exception const&)
+            {
+                TOOLS_INFO_EXCEPTION("writerfilter.ooxml", "importSubStream: 
exception while "
+                    "parsing stream of Type" << nType);
+            }
+        }
+        aGlossaryDomList.push_back(aRelDefinition.getNamedValues());
     }
     mxGlossaryDomList = comphelper::containerToSequence(aGlossaryDomList);
 }
@@ -797,7 +796,7 @@ uno::Reference<xml::dom::XDocument> 
OOXMLDocumentImpl::getGlossaryDocDom( )
     return mxGlossaryDocDom;
 }
 
-uno::Sequence<uno::Sequence< uno::Any> > 
OOXMLDocumentImpl::getGlossaryDomList()
+uno::Sequence<uno::Sequence< beans::NamedValue> > 
OOXMLDocumentImpl::getGlossaryDomList()
 {
     return mxGlossaryDomList;
 }
diff --git a/writerfilter/source/ooxml/OOXMLDocumentImpl.hxx 
b/writerfilter/source/ooxml/OOXMLDocumentImpl.hxx
index d7a8a00bd58c..c896d7bf4901 100644
--- a/writerfilter/source/ooxml/OOXMLDocumentImpl.hxx
+++ b/writerfilter/source/ooxml/OOXMLDocumentImpl.hxx
@@ -44,7 +44,7 @@ class OOXMLDocumentImpl : public OOXMLDocument
     css::uno::Reference<css::frame::XModel> mxModel;
     css::uno::Reference<css::drawing::XDrawPage> mxDrawPage;
     css::uno::Reference<css::xml::dom::XDocument> mxGlossaryDocDom;
-    css::uno::Sequence < css::uno::Sequence< css::uno::Any > > 
mxGlossaryDomList;
+    css::uno::Sequence < css::uno::Sequence< css::beans::NamedValue > > 
mxGlossaryDomList;
     /// Stack of shape contexts, 1 element for VML, 1 element / nesting level 
for drawingML.
     std::stack< rtl::Reference<oox::shape::ShapeContextHandler> > 
maShapeContexts;
     css::uno::Reference<css::xml::dom::XDocument> mxThemeDom;
@@ -141,7 +141,7 @@ public:
     virtual css::uno::Sequence<css::uno::Reference<css::xml::dom::XDocument> > 
getCustomXmlDomList() override;
     virtual css::uno::Sequence<css::uno::Reference<css::xml::dom::XDocument> > 
getCustomXmlDomPropsList() override;
     virtual css::uno::Reference<css::xml::dom::XDocument> getGlossaryDocDom() 
override;
-    virtual css::uno::Sequence<css::uno::Sequence< css::uno::Any> >  
getGlossaryDomList() override;
+    virtual css::uno::Sequence<css::uno::Sequence< css::beans::NamedValue> >  
getGlossaryDomList() override;
     virtual css::uno::Sequence<css::beans::PropertyValue >  
getEmbeddingsList() override;
 
     void incrementProgress();

Reply via email to