1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <sal/config.h>
22 #include <string_view>
24 #include <dp_descriptioninfoset.hxx>
26 #include <dp_resource.h>
28 #include <comphelper/sequence.hxx>
29 #include <comphelper/processfactory.hxx>
30 #include <comphelper/propertysequence.hxx>
32 #include <com/sun/star/configuration/theDefaultProvider.hpp>
33 #include <com/sun/star/container/XNameAccess.hpp>
34 #include <com/sun/star/deployment/DeploymentException.hpp>
35 #include <com/sun/star/beans/XPropertySet.hpp>
36 #include <com/sun/star/io/SequenceInputStream.hpp>
37 #include <com/sun/star/lang/XMultiComponentFactory.hpp>
38 #include <com/sun/star/lang/WrappedTargetRuntimeException.hpp>
39 #include <com/sun/star/task/XInteractionHandler.hpp>
40 #include <com/sun/star/ucb/XCommandEnvironment.hpp>
41 #include <com/sun/star/ucb/XProgressHandler.hpp>
42 #include <com/sun/star/uno/Reference.hxx>
43 #include <com/sun/star/uno/RuntimeException.hpp>
44 #include <com/sun/star/uno/Sequence.hxx>
45 #include <com/sun/star/uno/XInterface.hpp>
46 #include <com/sun/star/xml/dom/DOMException.hpp>
47 #include <com/sun/star/xml/dom/XNode.hpp>
48 #include <com/sun/star/xml/dom/XNodeList.hpp>
49 #include <com/sun/star/xml/dom/DocumentBuilder.hpp>
50 #include <com/sun/star/xml/xpath/XPathAPI.hpp>
51 #include <com/sun/star/xml/xpath/XPathException.hpp>
52 #include <com/sun/star/ucb/InteractiveIOException.hpp>
53 #include <cppuhelper/implbase.hxx>
54 #include <cppuhelper/weak.hxx>
55 #include <cppuhelper/exc_hlp.hxx>
56 #include <rtl/ustring.hxx>
57 #include <sal/types.h>
58 #include <ucbhelper/content.hxx>
59 #include <o3tl/string_view.hxx>
63 using css::uno::Reference
;
66 public cppu::WeakImplHelper
<css::xml::dom::XNodeList
>
71 EmptyNodeList(const EmptyNodeList
&) = delete;
72 const EmptyNodeList
& operator=(const EmptyNodeList
&) = delete;
74 virtual ::sal_Int32 SAL_CALL
getLength() override
;
76 virtual css::uno::Reference
< css::xml::dom::XNode
> SAL_CALL
77 item(::sal_Int32 index
) override
;
80 EmptyNodeList::EmptyNodeList() {}
82 ::sal_Int32
EmptyNodeList::getLength() {
86 css::uno::Reference
< css::xml::dom::XNode
> EmptyNodeList::item(::sal_Int32
)
88 throw css::uno::RuntimeException("bad EmptyNodeList com.sun.star.xml.dom.XNodeList.item call",
89 static_cast< ::cppu::OWeakObject
* >(this));
92 OUString
getNodeValue(
93 css::uno::Reference
< css::xml::dom::XNode
> const & node
)
95 OSL_ASSERT(node
.is());
97 return node
->getNodeValue();
98 } catch (const css::xml::dom::DOMException
& e
) {
99 css::uno::Any anyEx
= cppu::getCaughtException();
100 throw css::lang::WrappedTargetRuntimeException(
101 "com.sun.star.xml.dom.DOMException: " + e
.Message
,
106 /**The class uses the UCB to access the description.xml file in an
107 extension. The UCB must have been initialized already. It also
108 requires that the extension has already be unzipped to a particular
111 class ExtensionDescription
114 /**throws an exception if the description.xml is not
115 available, cannot be read, does not contain the expected data,
116 or any other error occurred. Therefore it should only be used with
119 Throws css::uno::RuntimeException,
120 css::deployment::DeploymentException,
121 dp_registry::backend::bundle::NoDescriptionException.
123 ExtensionDescription(
124 const css::uno::Reference
<css::uno::XComponentContext
>& xContext
,
125 std::u16string_view installDir
,
126 const css::uno::Reference
< css::ucb::XCommandEnvironment
>& xCmdEnv
);
128 const css::uno::Reference
<css::xml::dom::XNode
>& getRootElement() const
134 css::uno::Reference
<css::xml::dom::XNode
> m_xRoot
;
137 class NoDescriptionException
141 class FileDoesNotExistFilter
142 : public ::cppu::WeakImplHelper
< css::ucb::XCommandEnvironment
,
143 css::task::XInteractionHandler
>
147 css::uno::Reference
< css::ucb::XCommandEnvironment
> m_xCommandEnv
;
150 explicit FileDoesNotExistFilter(
151 const css::uno::Reference
< css::ucb::XCommandEnvironment
>& xCmdEnv
);
153 bool exist() { return m_bExist
;}
154 // XCommandEnvironment
155 virtual css::uno::Reference
<css::task::XInteractionHandler
> SAL_CALL
156 getInteractionHandler() override
;
157 virtual css::uno::Reference
<css::ucb::XProgressHandler
>
158 SAL_CALL
getProgressHandler() override
;
160 // XInteractionHandler
161 virtual void SAL_CALL
handle(
162 css::uno::Reference
<css::task::XInteractionRequest
> const & xRequest
) override
;
165 ExtensionDescription::ExtensionDescription(
166 const Reference
<css::uno::XComponentContext
>& xContext
,
167 std::u16string_view installDir
,
168 const Reference
< css::ucb::XCommandEnvironment
>& xCmdEnv
)
171 //may throw css::ucb::ContentCreationException
172 //If there is no description.xml then ucb will start an interaction which
173 //brings up a dialog.We want to prevent this. Therefore we wrap the xCmdEnv
174 //and filter the respective exception out.
175 OUString
sDescriptionUri(OUString::Concat(installDir
) + "/description.xml");
176 Reference
<css::ucb::XCommandEnvironment
> xFilter
= new FileDoesNotExistFilter(xCmdEnv
);
177 ::ucbhelper::Content
descContent(sDescriptionUri
, xFilter
, xContext
);
179 //throws a css::uno::Exception if the file is not available
180 Reference
<css::io::XInputStream
> xIn
;
182 { //throws com.sun.star.ucb.InteractiveIOException
183 xIn
= descContent
.openStream();
185 catch ( const css::uno::Exception
& )
187 if ( ! static_cast<FileDoesNotExistFilter
*>(xFilter
.get())->exist())
188 throw NoDescriptionException();
193 throw css::uno::Exception(
194 "Could not get XInputStream for description.xml of extension " +
195 sDescriptionUri
, nullptr);
198 //get root node of description.xml
199 Reference
<css::xml::dom::XDocumentBuilder
> xDocBuilder(
200 css::xml::dom::DocumentBuilder::create(xContext
) );
202 if (!xDocBuilder
->isNamespaceAware())
204 throw css::uno::Exception(
205 "Service com.sun.star.xml.dom.DocumentBuilder is not namespace aware.", nullptr);
208 Reference
<css::xml::dom::XDocument
> xDoc
= xDocBuilder
->parse(xIn
);
211 throw css::uno::Exception(sDescriptionUri
+ " contains data which cannot be parsed. ", nullptr);
214 //check for proper root element and namespace
215 Reference
<css::xml::dom::XElement
> xRoot
= xDoc
->getDocumentElement();
218 throw css::uno::Exception(
219 sDescriptionUri
+ " contains no root element.", nullptr);
222 if ( xRoot
->getTagName() != "description")
224 throw css::uno::Exception(
225 sDescriptionUri
+ " does not contain the root element <description>.", nullptr);
228 m_xRoot
.set(xRoot
, css::uno::UNO_QUERY_THROW
);
229 OUString nsDescription
= xRoot
->getNamespaceURI();
231 //check if this namespace is supported
232 if ( nsDescription
!= "http://openoffice.org/extensions/description/2006")
234 throw css::uno::Exception(sDescriptionUri
+ " contains a root element with an unsupported namespace. ", nullptr);
236 } catch (const css::uno::RuntimeException
&) {
238 } catch (const css::deployment::DeploymentException
&) {
240 } catch (const css::uno::Exception
& e
) {
241 css::uno::Any
a(cppu::getCaughtException());
242 throw css::deployment::DeploymentException(
243 e
.Message
, Reference
< css::uno::XInterface
>(), a
);
247 FileDoesNotExistFilter::FileDoesNotExistFilter(
248 const Reference
< css::ucb::XCommandEnvironment
>& xCmdEnv
):
249 m_bExist(true), m_xCommandEnv(xCmdEnv
)
252 // XCommandEnvironment
253 Reference
<css::task::XInteractionHandler
>
254 FileDoesNotExistFilter::getInteractionHandler()
256 return static_cast<css::task::XInteractionHandler
*>(this);
259 Reference
<css::ucb::XProgressHandler
>
260 FileDoesNotExistFilter::getProgressHandler()
262 return m_xCommandEnv
.is()
263 ? m_xCommandEnv
->getProgressHandler()
264 : Reference
<css::ucb::XProgressHandler
>();
267 // XInteractionHandler
268 //If the interaction was caused by a non-existing file which is specified in the ctor
269 //of FileDoesNotExistFilter, then we do nothing
270 void FileDoesNotExistFilter::handle(
271 Reference
<css::task::XInteractionRequest
> const & xRequest
)
273 css::uno::Any
request( xRequest
->getRequest() );
275 css::ucb::InteractiveIOException ioexc
;
276 if ((request
>>= ioexc
)
277 && (ioexc
.Code
== css::ucb::IOErrorCode_NOT_EXISTING
278 || ioexc
.Code
== css::ucb::IOErrorCode_NOT_EXISTING_PATH
))
283 Reference
<css::task::XInteractionHandler
> xInteraction
;
284 if (m_xCommandEnv
.is()) {
285 xInteraction
= m_xCommandEnv
->getInteractionHandler();
287 if (xInteraction
.is()) {
288 xInteraction
->handle(xRequest
);
296 DescriptionInfoset
getDescriptionInfoset(std::u16string_view sExtensionFolderURL
)
298 Reference
< css::xml::dom::XNode
> root
;
299 Reference
<css::uno::XComponentContext
> context(
300 comphelper::getProcessComponentContext());
303 ExtensionDescription(
304 context
, sExtensionFolderURL
,
305 Reference
< css::ucb::XCommandEnvironment
>()).
307 } catch (const NoDescriptionException
&) {
308 } catch (const css::deployment::DeploymentException
& e
) {
309 css::uno::Any anyEx
= cppu::getCaughtException();
310 throw css::lang::WrappedTargetRuntimeException(
311 "com.sun.star.deployment.DeploymentException: " + e
.Message
,
314 return DescriptionInfoset(context
, root
);
317 DescriptionInfoset::DescriptionInfoset(
318 css::uno::Reference
< css::uno::XComponentContext
> const & context
,
319 css::uno::Reference
< css::xml::dom::XNode
> const & element
):
323 if (m_element
.is()) {
324 m_xpath
= css::xml::xpath::XPathAPI::create(context
);
325 m_xpath
->registerNS("desc", element
->getNamespaceURI());
326 m_xpath
->registerNS("xlink", "http://www.w3.org/1999/xlink");
330 DescriptionInfoset::~DescriptionInfoset() {}
332 ::std::optional
< OUString
> DescriptionInfoset::getIdentifier() const {
333 return getOptionalValue("desc:identifier/@value");
336 OUString
DescriptionInfoset::getNodeValueFromExpression(OUString
const & expression
) const
338 css::uno::Reference
< css::xml::dom::XNode
> n
;
339 if (m_element
.is()) {
341 n
= m_xpath
->selectSingleNode(m_element
, expression
);
342 } catch (const css::xml::xpath::XPathException
&) {
346 return n
.is() ? getNodeValue(n
) : OUString();
349 void DescriptionInfoset::checkDenylist() const
354 std::optional
< OUString
> id(getIdentifier());
356 return; // nothing to check
357 OUString
currentversion(getVersion());
358 if (currentversion
.getLength() == 0)
359 return; // nothing to check
361 css::uno::Sequence
<css::uno::Any
> args(comphelper::InitAnyPropertySequence(
363 {"nodepath", css::uno::Any(OUString("/org.openoffice.Office.ExtensionDependencies/Extensions"))}
365 css::uno::Reference
< css::container::XNameAccess
> denylist(
366 (css::configuration::theDefaultProvider::get(m_context
)
367 ->createInstanceWithArguments(
368 "com.sun.star.configuration.ConfigurationAccess", args
)),
369 css::uno::UNO_QUERY_THROW
);
371 // check first if a denylist entry is available
372 if (!(denylist
.is() && denylist
->hasByName(*id
))) return;
374 css::uno::Reference
< css::beans::XPropertySet
> extProps(
375 denylist
->getByName(*id
), css::uno::UNO_QUERY_THROW
);
377 css::uno::Any anyValue
= extProps
->getPropertyValue("Versions");
379 css::uno::Sequence
< OUString
> blversions
;
380 anyValue
>>= blversions
;
382 // check if the current version requires further dependency checks from the denylist
383 if (!checkDenylistVersion(currentversion
, blversions
)) return;
385 anyValue
= extProps
->getPropertyValue("Dependencies");
389 if (udeps
.getLength() == 0)
390 return; // nothing todo
392 OString xmlDependencies
= OUStringToOString(udeps
, RTL_TEXTENCODING_UNICODE
);
394 css::uno::Reference
< css::xml::dom::XDocumentBuilder
> docbuilder(
395 m_context
->getServiceManager()->createInstanceWithContext("com.sun.star.xml.dom.DocumentBuilder", m_context
),
396 css::uno::UNO_QUERY_THROW
);
398 css::uno::Sequence
< sal_Int8
> byteSeq(reinterpret_cast<const sal_Int8
*>(xmlDependencies
.getStr()), xmlDependencies
.getLength());
400 css::uno::Reference
< css::io::XInputStream
> inputstream( css::io::SequenceInputStream::createStreamFromSequence(m_context
, byteSeq
),
401 css::uno::UNO_QUERY_THROW
);
403 css::uno::Reference
< css::xml::dom::XDocument
> xDocument(docbuilder
->parse(inputstream
));
404 css::uno::Reference
< css::xml::dom::XElement
> xElement(xDocument
->getDocumentElement());
405 css::uno::Reference
< css::xml::dom::XNodeList
> xDeps(xElement
->getChildNodes());
406 sal_Int32 nLen
= xDeps
->getLength();
408 // get the parent xml document of current description info for the import
409 css::uno::Reference
< css::xml::dom::XDocument
> xCurrentDescInfo(m_element
->getOwnerDocument());
411 // get dependency node of current description info to merge the new dependencies from the denylist
412 css::uno::Reference
< css::xml::dom::XNode
> xCurrentDeps(
413 m_xpath
->selectSingleNode(m_element
, "desc:dependencies"));
415 // if no dependency node exists, create a new one in the current description info
416 if (!xCurrentDeps
.is()) {
417 css::uno::Reference
< css::xml::dom::XNode
> xNewDepNode(
418 xCurrentDescInfo
->createElementNS(
419 "http://openoffice.org/extensions/description/2006",
420 "dependencies"), css::uno::UNO_QUERY_THROW
);
421 m_element
->appendChild(xNewDepNode
);
422 xCurrentDeps
= m_xpath
->selectSingleNode(m_element
, "desc:dependencies");
425 for (sal_Int32 i
=0; i
<nLen
; i
++) {
426 css::uno::Reference
< css::xml::dom::XNode
> xNode(xDeps
->item(i
));
427 css::uno::Reference
< css::xml::dom::XElement
> xDep(xNode
, css::uno::UNO_QUERY
);
429 // found valid denylist dependency, import the node first and append it to the existing dependency node
430 css::uno::Reference
< css::xml::dom::XNode
> importedNode
= xCurrentDescInfo
->importNode(xNode
, true);
431 xCurrentDeps
->appendChild(importedNode
);
436 bool DescriptionInfoset::checkDenylistVersion(
437 std::u16string_view currentversion
,
438 css::uno::Sequence
< OUString
> const & versions
)
440 sal_Int32 nLen
= versions
.getLength();
441 for (sal_Int32 i
=0; i
<nLen
; i
++) {
442 if (currentversion
== versions
[i
])
449 OUString
DescriptionInfoset::getVersion() const
451 return getNodeValueFromExpression( "desc:version/@value" );
454 css::uno::Sequence
< OUString
> DescriptionInfoset::getSupportedPlatforms() const
456 //When there is no description.xml then we assume that we support all platforms
457 if (! m_element
.is())
459 return { OUString("all") };
462 //Check if the <platform> element was provided. If not the default is "all" platforms
463 css::uno::Reference
< css::xml::dom::XNode
> nodePlatform(
464 m_xpath
->selectSingleNode(m_element
, "desc:platform"));
465 if (!nodePlatform
.is())
467 return { OUString("all") };
470 //There is a platform element.
471 const OUString value
= getNodeValueFromExpression("desc:platform/@value");
472 //parse the string, it can contained multiple strings separated by commas
473 std::vector
< OUString
> vec
;
474 sal_Int32 nIndex
= 0;
477 const OUString
aToken( o3tl::trim(o3tl::getToken(value
, 0, ',', nIndex
)) );
478 if (!aToken
.isEmpty())
479 vec
.push_back(aToken
);
484 return comphelper::containerToSequence(vec
);
487 css::uno::Reference
< css::xml::dom::XNodeList
>
488 DescriptionInfoset::getDependencies() const {
489 if (m_element
.is()) {
491 // check the extension denylist first and expand the dependencies if applicable
494 return m_xpath
->selectNodeList(m_element
, "desc:dependencies/*");
495 } catch (const css::xml::xpath::XPathException
&) {
499 return new EmptyNodeList
;
502 css::uno::Sequence
< OUString
>
503 DescriptionInfoset::getUpdateInformationUrls() const {
504 return getUrls("desc:update-information/desc:src/@xlink:href");
507 css::uno::Sequence
< OUString
>
508 DescriptionInfoset::getUpdateDownloadUrls() const
510 return getUrls("desc:update-download/desc:src/@xlink:href");
513 OUString
DescriptionInfoset::getIconURL( bool bHighContrast
) const
515 css::uno::Sequence
< OUString
> aStrList
= getUrls( "desc:icon/desc:default/@xlink:href" );
516 css::uno::Sequence
< OUString
> aStrListHC
= getUrls( "desc:icon/desc:high-contrast/@xlink:href" );
518 if ( bHighContrast
&& aStrListHC
.hasElements() && !aStrListHC
[0].isEmpty() )
519 return aStrListHC
[0];
521 if ( aStrList
.hasElements() && !aStrList
[0].isEmpty() )
527 ::std::optional
< OUString
> DescriptionInfoset::getLocalizedUpdateWebsiteURL()
530 bool bParentExists
= false;
531 const OUString
sURL (getLocalizedHREFAttrFromChild("/desc:description/desc:update-website", &bParentExists
));
534 return ::std::optional
< OUString
>(sURL
);
536 return bParentExists
? ::std::optional
< OUString
>(OUString()) :
537 ::std::optional
< OUString
>();
540 ::std::optional
< OUString
> DescriptionInfoset::getOptionalValue(
541 OUString
const & expression
) const
543 css::uno::Reference
< css::xml::dom::XNode
> n
;
544 if (m_element
.is()) {
546 n
= m_xpath
->selectSingleNode(m_element
, expression
);
547 } catch (const css::xml::xpath::XPathException
&) {
552 ? ::std::optional
< OUString
>(getNodeValue(n
))
553 : ::std::optional
< OUString
>();
556 css::uno::Sequence
< OUString
> DescriptionInfoset::getUrls(
557 OUString
const & expression
) const
559 css::uno::Reference
< css::xml::dom::XNodeList
> ns
;
560 if (m_element
.is()) {
562 ns
= m_xpath
->selectNodeList(m_element
, expression
);
563 } catch (const css::xml::xpath::XPathException
&) {
567 css::uno::Sequence
< OUString
> urls(ns
.is() ? ns
->getLength() : 0);
568 auto urlsRange
= asNonConstRange(urls
);
569 for (::sal_Int32 i
= 0; i
< urls
.getLength(); ++i
) {
570 urlsRange
[i
] = getNodeValue(ns
->item(i
));
575 std::pair
< OUString
, OUString
> DescriptionInfoset::getLocalizedPublisherNameAndURL() const
577 css::uno::Reference
< css::xml::dom::XNode
> node
=
578 getLocalizedChild("desc:publisher");
580 OUString sPublisherName
;
584 css::uno::Reference
< css::xml::dom::XNode
> xPathName
;
586 xPathName
= m_xpath
->selectSingleNode(node
, "text()");
587 } catch (const css::xml::xpath::XPathException
&) {
590 OSL_ASSERT(xPathName
.is());
592 sPublisherName
= xPathName
->getNodeValue();
594 css::uno::Reference
< css::xml::dom::XNode
> xURL
;
596 xURL
= m_xpath
->selectSingleNode(node
, "@xlink:href");
597 } catch (const css::xml::xpath::XPathException
&) {
600 OSL_ASSERT(xURL
.is());
602 sURL
= xURL
->getNodeValue();
604 return std::make_pair(sPublisherName
, sURL
);
607 OUString
DescriptionInfoset::getLocalizedReleaseNotesURL() const
609 return getLocalizedHREFAttrFromChild("/desc:description/desc:release-notes", nullptr);
612 OUString
DescriptionInfoset::getLocalizedDisplayName() const
614 css::uno::Reference
< css::xml::dom::XNode
> node
=
615 getLocalizedChild("desc:display-name");
618 css::uno::Reference
< css::xml::dom::XNode
> xtext
;
620 xtext
= m_xpath
->selectSingleNode(node
, "text()");
621 } catch (const css::xml::xpath::XPathException
&) {
625 return xtext
->getNodeValue();
630 OUString
DescriptionInfoset::getLocalizedLicenseURL() const
632 return getLocalizedHREFAttrFromChild("/desc:description/desc:registration/desc:simple-license", nullptr);
636 ::std::optional
<SimpleLicenseAttributes
>
637 DescriptionInfoset::getSimpleLicenseAttributes() const
639 //Check if the node exist
640 css::uno::Reference
< css::xml::dom::XNode
> n
;
641 if (m_element
.is()) {
643 n
= m_xpath
->selectSingleNode(m_element
, "/desc:description/desc:registration/desc:simple-license/@accept-by");
644 } catch (const css::xml::xpath::XPathException
&) {
649 SimpleLicenseAttributes attributes
;
650 attributes
.acceptBy
=
651 getNodeValueFromExpression("/desc:description/desc:registration/desc:simple-license/@accept-by");
653 ::std::optional
< OUString
> suppressOnUpdate
= getOptionalValue("/desc:description/desc:registration/desc:simple-license/@suppress-on-update");
654 if (suppressOnUpdate
)
655 attributes
.suppressOnUpdate
= o3tl::equalsIgnoreAsciiCase(o3tl::trim(*suppressOnUpdate
), u
"true");
657 attributes
.suppressOnUpdate
= false;
659 ::std::optional
< OUString
> suppressIfRequired
= getOptionalValue("/desc:description/desc:registration/desc:simple-license/@suppress-if-required");
660 if (suppressIfRequired
)
661 attributes
.suppressIfRequired
= o3tl::equalsIgnoreAsciiCase(o3tl::trim(*suppressIfRequired
), u
"true");
663 attributes
.suppressIfRequired
= false;
665 return ::std::optional
<SimpleLicenseAttributes
>(attributes
);
668 return ::std::optional
<SimpleLicenseAttributes
>();
671 OUString
DescriptionInfoset::getLocalizedDescriptionURL() const
673 return getLocalizedHREFAttrFromChild("/desc:description/desc:extension-description", nullptr);
676 css::uno::Reference
< css::xml::dom::XNode
>
677 DescriptionInfoset::getLocalizedChild( const OUString
& sParent
) const
679 if ( ! m_element
.is() || sParent
.isEmpty())
680 return css::uno::Reference
< css::xml::dom::XNode
> ();
682 css::uno::Reference
< css::xml::dom::XNode
> xParent
;
684 xParent
= m_xpath
->selectSingleNode(m_element
, sParent
);
685 } catch (const css::xml::xpath::XPathException
&) {
688 css::uno::Reference
<css::xml::dom::XNode
> nodeMatch
;
691 nodeMatch
= matchLanguageTag(xParent
, getOfficeLanguageTag().getBcp47());
693 //office: en-DE, en, en-DE-altmark
694 if (! nodeMatch
.is())
696 // Already tried full tag, continue with first fallback.
697 const std::vector
< OUString
> aFallbacks( getOfficeLanguageTag().getFallbackStrings( false));
698 for (auto const& fallback
: aFallbacks
)
700 nodeMatch
= matchLanguageTag(xParent
, fallback
);
704 if (! nodeMatch
.is())
705 nodeMatch
= getChildWithDefaultLocale(xParent
);
712 css::uno::Reference
<css::xml::dom::XNode
>
713 DescriptionInfoset::matchLanguageTag(
714 css::uno::Reference
< css::xml::dom::XNode
> const & xParent
, std::u16string_view rTag
) const
716 OSL_ASSERT(xParent
.is());
717 css::uno::Reference
<css::xml::dom::XNode
> nodeMatch
;
719 //first try exact match for lang
720 const OUString
exp1(OUString::Concat("*[@lang=\"") + rTag
+ "\"]");
722 nodeMatch
= m_xpath
->selectSingleNode(xParent
, exp1
);
723 } catch (const css::xml::xpath::XPathException
&) {
727 //try to match in strings that also have a country and/or variant, for
728 //example en matches in en-US-montana, en-US, en-montana
732 OUString::Concat("*[starts-with(@lang,\"") + rTag
+ "-\")]");
734 nodeMatch
= m_xpath
->selectSingleNode(xParent
, exp2
);
735 } catch (const css::xml::xpath::XPathException
&) {
742 css::uno::Reference
<css::xml::dom::XNode
>
743 DescriptionInfoset::getChildWithDefaultLocale(css::uno::Reference
< css::xml::dom::XNode
>
744 const & xParent
) const
746 OSL_ASSERT(xParent
.is());
747 if ( xParent
->getNodeName() == "simple-license" )
749 css::uno::Reference
<css::xml::dom::XNode
> nodeDefault
;
751 nodeDefault
= m_xpath
->selectSingleNode(xParent
, "@default-license-id");
752 } catch (const css::xml::xpath::XPathException
&) {
755 if (nodeDefault
.is())
758 const OUString
exp1("desc:license-text[@license-id = \""
759 + nodeDefault
->getNodeValue()
762 return m_xpath
->selectSingleNode(xParent
, exp1
);
763 } catch (const css::xml::xpath::XPathException
&) {
770 return m_xpath
->selectSingleNode(xParent
, "*[1]");
771 } catch (const css::xml::xpath::XPathException
&) {
777 OUString
DescriptionInfoset::getLocalizedHREFAttrFromChild(
778 OUString
const & sXPathParent
, bool * out_bParentExists
)
781 css::uno::Reference
< css::xml::dom::XNode
> node
=
782 getLocalizedChild(sXPathParent
);
787 if (out_bParentExists
)
788 *out_bParentExists
= true;
789 css::uno::Reference
< css::xml::dom::XNode
> xURL
;
791 xURL
= m_xpath
->selectSingleNode(node
, "@xlink:href");
792 } catch (const css::xml::xpath::XPathException
&) {
795 OSL_ASSERT(xURL
.is());
797 sURL
= xURL
->getNodeValue();
801 if (out_bParentExists
)
802 *out_bParentExists
= false;
809 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */