diff options
-rw-r--r-- | include/com/sun/star/uno/Any.h | 1 | ||||
-rw-r--r-- | include/com/sun/star/uno/Any.hxx | 2 | ||||
-rw-r--r-- | sw/qa/extras/ooxmlexport/data/glossaryWithEmail.docx | bin | 0 -> 19290 bytes | |||
-rw-r--r-- | sw/qa/extras/ooxmlexport/ooxmlexport3.cxx | 11 | ||||
-rw-r--r-- | sw/source/filter/ww8/docxexport.cxx | 42 | ||||
-rw-r--r-- | writerfilter/inc/ooxml/OOXMLDocument.hxx | 3 | ||||
-rw-r--r-- | writerfilter/source/ooxml/OOXMLDocumentImpl.cxx | 163 | ||||
-rw-r--r-- | writerfilter/source/ooxml/OOXMLDocumentImpl.hxx | 4 |
8 files changed, 132 insertions, 94 deletions
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 Binary files differnew file mode 100644 index 000000000000..5ec375adf3ac --- /dev/null +++ b/sw/qa/extras/ooxmlexport/data/glossaryWithEmail.docx 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:emailgoeshere@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(); |