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 <dp_descriptioninfoset.hxx>
22 #include <dp_resource.h>
23 #include <sal/config.h>
25 #include <comphelper/sequence.hxx>
26 #include <comphelper/seqstream.hxx>
27 #include <comphelper/processfactory.hxx>
28 #include <comphelper/propertysequence.hxx>
29 #include <boost/optional.hpp>
30 #include <com/sun/star/configuration/theDefaultProvider.hpp>
31 #include <com/sun/star/container/XNameAccess.hpp>
32 #include <com/sun/star/deployment/DeploymentException.hpp>
33 #include <com/sun/star/beans/Optional.hpp>
34 #include <com/sun/star/beans/PropertyValue.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/uno/Reference.hxx>
40 #include <com/sun/star/uno/RuntimeException.hpp>
41 #include <com/sun/star/uno/Sequence.hxx>
42 #include <com/sun/star/uno/XComponentContext.hpp>
43 #include <com/sun/star/uno/XInterface.hpp>
44 #include <com/sun/star/xml/dom/DOMException.hpp>
45 #include <com/sun/star/xml/dom/XNode.hpp>
46 #include <com/sun/star/xml/dom/XNodeList.hpp>
47 #include <com/sun/star/xml/dom/DocumentBuilder.hpp>
48 #include <com/sun/star/xml/xpath/XPathAPI.hpp>
49 #include <com/sun/star/xml/xpath/XPathException.hpp>
50 #include <com/sun/star/ucb/InteractiveIOException.hpp>
51 #include <cppuhelper/implbase.hxx>
52 #include <cppuhelper/weak.hxx>
53 #include <cppuhelper/exc_hlp.hxx>
54 #include <rtl/ustring.h>
55 #include <rtl/ustring.hxx>
56 #include <sal/types.h>
57 #include <ucbhelper/content.hxx>
61 using css::uno::Reference
;
64 public cppu::WeakImplHelper
<css::xml::dom::XNodeList
>
69 EmptyNodeList(const EmptyNodeList
&) = delete;
70 const EmptyNodeList
& operator=(const EmptyNodeList
&) = delete;
72 virtual ::sal_Int32 SAL_CALL
getLength() override
;
74 virtual css::uno::Reference
< css::xml::dom::XNode
> SAL_CALL
75 item(::sal_Int32 index
) override
;
78 EmptyNodeList::EmptyNodeList() {}
80 ::sal_Int32
EmptyNodeList::getLength() {
84 css::uno::Reference
< css::xml::dom::XNode
> EmptyNodeList::item(::sal_Int32
)
86 throw css::uno::RuntimeException("bad EmptyNodeList com.sun.star.xml.dom.XNodeList.item call",
87 static_cast< ::cppu::OWeakObject
* >(this));
90 OUString
getNodeValue(
91 css::uno::Reference
< css::xml::dom::XNode
> const & node
)
93 OSL_ASSERT(node
.is());
95 return node
->getNodeValue();
96 } catch (const css::xml::dom::DOMException
& e
) {
97 css::uno::Any anyEx
= cppu::getCaughtException();
98 throw css::lang::WrappedTargetRuntimeException(
99 "com.sun.star.xml.dom.DOMException: " + e
.Message
,
104 /**The class uses the UCB to access the description.xml file in an
105 extension. The UCB must have been initialized already. It also
106 requires that the extension has already be unzipped to a particular
109 class ExtensionDescription
112 /**throws an exception if the description.xml is not
113 available, cannot be read, does not contain the expected data,
114 or any other error occurred. Therefore it should only be used with
117 Throws css::uno::RuntimeException,
118 css::deployment::DeploymentException,
119 dp_registry::backend::bundle::NoDescriptionException.
121 ExtensionDescription(
122 const css::uno::Reference
<css::uno::XComponentContext
>& xContext
,
123 const OUString
& installDir
,
124 const css::uno::Reference
< css::ucb::XCommandEnvironment
>& xCmdEnv
);
126 const css::uno::Reference
<css::xml::dom::XNode
>& getRootElement() const
132 css::uno::Reference
<css::xml::dom::XNode
> m_xRoot
;
135 class NoDescriptionException
139 class FileDoesNotExistFilter
140 : public ::cppu::WeakImplHelper
< css::ucb::XCommandEnvironment
,
141 css::task::XInteractionHandler
>
145 css::uno::Reference
< css::ucb::XCommandEnvironment
> m_xCommandEnv
;
148 explicit FileDoesNotExistFilter(
149 const css::uno::Reference
< css::ucb::XCommandEnvironment
>& xCmdEnv
);
151 bool exist() { return m_bExist
;}
152 // XCommandEnvironment
153 virtual css::uno::Reference
<css::task::XInteractionHandler
> SAL_CALL
154 getInteractionHandler() override
;
155 virtual css::uno::Reference
<css::ucb::XProgressHandler
>
156 SAL_CALL
getProgressHandler() override
;
158 // XInteractionHandler
159 virtual void SAL_CALL
handle(
160 css::uno::Reference
<css::task::XInteractionRequest
> const & xRequest
) override
;
163 ExtensionDescription::ExtensionDescription(
164 const Reference
<css::uno::XComponentContext
>& xContext
,
165 const OUString
& installDir
,
166 const Reference
< css::ucb::XCommandEnvironment
>& xCmdEnv
)
169 //may throw css::ucb::ContentCreationException
170 //If there is no description.xml then ucb will start an interaction which
171 //brings up a dialog.We want to prevent this. Therefore we wrap the xCmdEnv
172 //and filter the respective exception out.
173 OUString
sDescriptionUri(installDir
+ "/description.xml");
174 Reference
<css::ucb::XCommandEnvironment
> xFilter
= new FileDoesNotExistFilter(xCmdEnv
);
175 ::ucbhelper::Content
descContent(sDescriptionUri
, xFilter
, xContext
);
177 //throws a css::uno::Exception if the file is not available
178 Reference
<css::io::XInputStream
> xIn
;
180 { //throws com.sun.star.ucb.InteractiveIOException
181 xIn
= descContent
.openStream();
183 catch ( const css::uno::Exception
& )
185 if ( ! static_cast<FileDoesNotExistFilter
*>(xFilter
.get())->exist())
186 throw NoDescriptionException();
191 throw css::uno::Exception(
192 "Could not get XInputStream for description.xml of extension " +
193 sDescriptionUri
, nullptr);
196 //get root node of description.xml
197 Reference
<css::xml::dom::XDocumentBuilder
> xDocBuilder(
198 css::xml::dom::DocumentBuilder::create(xContext
) );
200 if (!xDocBuilder
->isNamespaceAware())
202 throw css::uno::Exception(
203 "Service com.sun.star.xml.dom.DocumentBuilder is not namespace aware.", nullptr);
206 Reference
<css::xml::dom::XDocument
> xDoc
= xDocBuilder
->parse(xIn
);
209 throw css::uno::Exception(sDescriptionUri
+ " contains data which cannot be parsed. ", nullptr);
212 //check for proper root element and namespace
213 Reference
<css::xml::dom::XElement
> xRoot
= xDoc
->getDocumentElement();
216 throw css::uno::Exception(
217 sDescriptionUri
+ " contains no root element.", nullptr);
220 if ( xRoot
->getTagName() != "description")
222 throw css::uno::Exception(
223 sDescriptionUri
+ " does not contain the root element <description>.", nullptr);
226 m_xRoot
.set(xRoot
, css::uno::UNO_QUERY_THROW
);
227 OUString nsDescription
= xRoot
->getNamespaceURI();
229 //check if this namespace is supported
230 if ( nsDescription
!= "http://openoffice.org/extensions/description/2006")
232 throw css::uno::Exception(sDescriptionUri
+ " contains a root element with an unsupported namespace. ", nullptr);
234 } catch (const css::uno::RuntimeException
&) {
236 } catch (const css::deployment::DeploymentException
&) {
238 } catch (const css::uno::Exception
& e
) {
239 css::uno::Any
a(cppu::getCaughtException());
240 throw css::deployment::DeploymentException(
241 e
.Message
, Reference
< css::uno::XInterface
>(), a
);
245 FileDoesNotExistFilter::FileDoesNotExistFilter(
246 const Reference
< css::ucb::XCommandEnvironment
>& xCmdEnv
):
247 m_bExist(true), m_xCommandEnv(xCmdEnv
)
250 // XCommandEnvironment
251 Reference
<css::task::XInteractionHandler
>
252 FileDoesNotExistFilter::getInteractionHandler()
254 return static_cast<css::task::XInteractionHandler
*>(this);
257 Reference
<css::ucb::XProgressHandler
>
258 FileDoesNotExistFilter::getProgressHandler()
260 return m_xCommandEnv
.is()
261 ? m_xCommandEnv
->getProgressHandler()
262 : Reference
<css::ucb::XProgressHandler
>();
265 // XInteractionHandler
266 //If the interaction was caused by a non-existing file which is specified in the ctor
267 //of FileDoesNotExistFilter, then we do nothing
268 void FileDoesNotExistFilter::handle(
269 Reference
<css::task::XInteractionRequest
> const & xRequest
)
271 css::uno::Any
request( xRequest
->getRequest() );
273 css::ucb::InteractiveIOException ioexc
;
274 if ((request
>>= ioexc
)
275 && (ioexc
.Code
== css::ucb::IOErrorCode_NOT_EXISTING
276 || ioexc
.Code
== css::ucb::IOErrorCode_NOT_EXISTING_PATH
))
281 Reference
<css::task::XInteractionHandler
> xInteraction
;
282 if (m_xCommandEnv
.is()) {
283 xInteraction
= m_xCommandEnv
->getInteractionHandler();
285 if (xInteraction
.is()) {
286 xInteraction
->handle(xRequest
);
294 DescriptionInfoset
getDescriptionInfoset(OUString
const & sExtensionFolderURL
)
296 Reference
< css::xml::dom::XNode
> root
;
297 Reference
<css::uno::XComponentContext
> context(
298 comphelper::getProcessComponentContext());
301 ExtensionDescription(
302 context
, sExtensionFolderURL
,
303 Reference
< css::ucb::XCommandEnvironment
>()).
305 } catch (const NoDescriptionException
&) {
306 } catch (const css::deployment::DeploymentException
& e
) {
307 css::uno::Any anyEx
= cppu::getCaughtException();
308 throw css::lang::WrappedTargetRuntimeException(
309 "com.sun.star.deployment.DeploymentException: " + e
.Message
,
312 return DescriptionInfoset(context
, root
);
315 DescriptionInfoset::DescriptionInfoset(
316 css::uno::Reference
< css::uno::XComponentContext
> const & context
,
317 css::uno::Reference
< css::xml::dom::XNode
> const & element
):
321 if (m_element
.is()) {
322 m_xpath
= css::xml::xpath::XPathAPI::create(context
);
323 m_xpath
->registerNS("desc", element
->getNamespaceURI());
324 m_xpath
->registerNS("xlink", "http://www.w3.org/1999/xlink");
328 DescriptionInfoset::~DescriptionInfoset() {}
330 ::boost::optional
< OUString
> DescriptionInfoset::getIdentifier() const {
331 return getOptionalValue("desc:identifier/@value");
334 OUString
DescriptionInfoset::getNodeValueFromExpression(OUString
const & expression
) const
336 css::uno::Reference
< css::xml::dom::XNode
> n
;
337 if (m_element
.is()) {
339 n
= m_xpath
->selectSingleNode(m_element
, expression
);
340 } catch (const css::xml::xpath::XPathException
&) {
344 return n
.is() ? getNodeValue(n
) : OUString();
347 void DescriptionInfoset::checkBlacklist() const
349 if (m_element
.is()) {
350 boost::optional
< OUString
> id(getIdentifier());
352 return; // nothing to check
353 OUString
currentversion(getVersion());
354 if (currentversion
.getLength() == 0)
355 return; // nothing to check
357 css::uno::Sequence
<css::uno::Any
> args(comphelper::InitAnyPropertySequence(
359 {"nodepath", css::uno::Any(OUString("/org.openoffice.Office.ExtensionDependencies/Extensions"))}
361 css::uno::Reference
< css::container::XNameAccess
> blacklist(
362 (css::configuration::theDefaultProvider::get(m_context
)
363 ->createInstanceWithArguments(
364 "com.sun.star.configuration.ConfigurationAccess", args
)),
365 css::uno::UNO_QUERY_THROW
);
367 // check first if a blacklist entry is available
368 if (blacklist
.is() && blacklist
->hasByName(*id
)) {
369 css::uno::Reference
< css::beans::XPropertySet
> extProps(
370 blacklist
->getByName(*id
), css::uno::UNO_QUERY_THROW
);
372 css::uno::Any anyValue
= extProps
->getPropertyValue("Versions");
374 css::uno::Sequence
< OUString
> blversions
;
375 anyValue
>>= blversions
;
377 // check if the current version requires further dependency checks from the blacklist
378 if (checkBlacklistVersion(currentversion
, blversions
)) {
379 anyValue
= extProps
->getPropertyValue("Dependencies");
383 if (udeps
.getLength() == 0)
384 return; // nothing todo
386 OString xmlDependencies
= OUStringToOString(udeps
, RTL_TEXTENCODING_UNICODE
);
388 css::uno::Reference
< css::xml::dom::XDocumentBuilder
> docbuilder(
389 m_context
->getServiceManager()->createInstanceWithContext("com.sun.star.xml.dom.DocumentBuilder", m_context
),
390 css::uno::UNO_QUERY_THROW
);
392 css::uno::Sequence
< sal_Int8
> byteSeq(reinterpret_cast<const sal_Int8
*>(xmlDependencies
.getStr()), xmlDependencies
.getLength());
394 css::uno::Reference
< css::io::XInputStream
> inputstream( css::io::SequenceInputStream::createStreamFromSequence(m_context
, byteSeq
),
395 css::uno::UNO_QUERY_THROW
);
397 css::uno::Reference
< css::xml::dom::XDocument
> xDocument(docbuilder
->parse(inputstream
));
398 css::uno::Reference
< css::xml::dom::XElement
> xElement(xDocument
->getDocumentElement());
399 css::uno::Reference
< css::xml::dom::XNodeList
> xDeps(xElement
->getChildNodes());
400 sal_Int32 nLen
= xDeps
->getLength();
402 // get the parent xml document of current description info for the import
403 css::uno::Reference
< css::xml::dom::XDocument
> xCurrentDescInfo(m_element
->getOwnerDocument());
405 // get dependency node of current description info to merge the new dependencies from the blacklist
406 css::uno::Reference
< css::xml::dom::XNode
> xCurrentDeps(
407 m_xpath
->selectSingleNode(m_element
, "desc:dependencies"));
409 // if no dependency node exists, create a new one in the current description info
410 if (!xCurrentDeps
.is()) {
411 css::uno::Reference
< css::xml::dom::XNode
> xNewDepNode(
412 xCurrentDescInfo
->createElementNS(
413 "http://openoffice.org/extensions/description/2006",
414 "dependencies"), css::uno::UNO_QUERY_THROW
);
415 m_element
->appendChild(xNewDepNode
);
416 xCurrentDeps
= m_xpath
->selectSingleNode(m_element
, "desc:dependencies");
419 for (sal_Int32 i
=0; i
<nLen
; i
++) {
420 css::uno::Reference
< css::xml::dom::XNode
> xNode(xDeps
->item(i
));
421 css::uno::Reference
< css::xml::dom::XElement
> xDep(xNode
, css::uno::UNO_QUERY
);
423 // found valid blacklist dependency, import the node first and append it to the existing dependency node
424 css::uno::Reference
< css::xml::dom::XNode
> importedNode
= xCurrentDescInfo
->importNode(xNode
, true);
425 xCurrentDeps
->appendChild(importedNode
);
433 bool DescriptionInfoset::checkBlacklistVersion(
434 const OUString
& currentversion
,
435 css::uno::Sequence
< OUString
> const & versions
)
437 sal_Int32 nLen
= versions
.getLength();
438 for (sal_Int32 i
=0; i
<nLen
; i
++) {
439 if (currentversion
== versions
[i
])
446 OUString
DescriptionInfoset::getVersion() const
448 return getNodeValueFromExpression( "desc:version/@value" );
451 css::uno::Sequence
< OUString
> DescriptionInfoset::getSupportedPlatforms() const
453 //When there is no description.xml then we assume that we support all platforms
454 if (! m_element
.is())
456 return { OUString("all") };
459 //Check if the <platform> element was provided. If not the default is "all" platforms
460 css::uno::Reference
< css::xml::dom::XNode
> nodePlatform(
461 m_xpath
->selectSingleNode(m_element
, "desc:platform"));
462 if (!nodePlatform
.is())
464 return { OUString("all") };
467 //There is a platform element.
468 const OUString value
= getNodeValueFromExpression("desc:platform/@value");
469 //parse the string, it can contained multiple strings separated by commas
470 std::vector
< OUString
> vec
;
471 sal_Int32 nIndex
= 0;
474 const OUString aToken
= value
.getToken( 0, ',', nIndex
).trim();
475 if (!aToken
.isEmpty())
476 vec
.push_back(aToken
);
481 return comphelper::containerToSequence(vec
);
484 css::uno::Reference
< css::xml::dom::XNodeList
>
485 DescriptionInfoset::getDependencies() const {
486 if (m_element
.is()) {
488 // check the extension blacklist first and expand the dependencies if applicable
491 return m_xpath
->selectNodeList(m_element
, "desc:dependencies/*");
492 } catch (const css::xml::xpath::XPathException
&) {
496 return new EmptyNodeList
;
499 css::uno::Sequence
< OUString
>
500 DescriptionInfoset::getUpdateInformationUrls() const {
501 return getUrls("desc:update-information/desc:src/@xlink:href");
504 css::uno::Sequence
< OUString
>
505 DescriptionInfoset::getUpdateDownloadUrls() const
507 return getUrls("desc:update-download/desc:src/@xlink:href");
510 OUString
DescriptionInfoset::getIconURL( bool bHighContrast
) const
512 css::uno::Sequence
< OUString
> aStrList
= getUrls( "desc:icon/desc:default/@xlink:href" );
513 css::uno::Sequence
< OUString
> aStrListHC
= getUrls( "desc:icon/desc:high-contrast/@xlink:href" );
515 if ( bHighContrast
&& aStrListHC
.hasElements() && !aStrListHC
[0].isEmpty() )
516 return aStrListHC
[0];
518 if ( aStrList
.hasElements() && !aStrList
[0].isEmpty() )
524 ::boost::optional
< OUString
> DescriptionInfoset::getLocalizedUpdateWebsiteURL()
527 bool bParentExists
= false;
528 const OUString
sURL (getLocalizedHREFAttrFromChild("/desc:description/desc:update-website", &bParentExists
));
531 return ::boost::optional
< OUString
>(sURL
);
533 return bParentExists
? ::boost::optional
< OUString
>(OUString()) :
534 ::boost::optional
< OUString
>();
537 ::boost::optional
< OUString
> DescriptionInfoset::getOptionalValue(
538 OUString
const & expression
) const
540 css::uno::Reference
< css::xml::dom::XNode
> n
;
541 if (m_element
.is()) {
543 n
= m_xpath
->selectSingleNode(m_element
, expression
);
544 } catch (const css::xml::xpath::XPathException
&) {
549 ? ::boost::optional
< OUString
>(getNodeValue(n
))
550 : ::boost::optional
< OUString
>();
553 css::uno::Sequence
< OUString
> DescriptionInfoset::getUrls(
554 OUString
const & expression
) const
556 css::uno::Reference
< css::xml::dom::XNodeList
> ns
;
557 if (m_element
.is()) {
559 ns
= m_xpath
->selectNodeList(m_element
, expression
);
560 } catch (const css::xml::xpath::XPathException
&) {
564 css::uno::Sequence
< OUString
> urls(ns
.is() ? ns
->getLength() : 0);
565 for (::sal_Int32 i
= 0; i
< urls
.getLength(); ++i
) {
566 urls
[i
] = getNodeValue(ns
->item(i
));
571 std::pair
< OUString
, OUString
> DescriptionInfoset::getLocalizedPublisherNameAndURL() const
573 css::uno::Reference
< css::xml::dom::XNode
> node
=
574 getLocalizedChild("desc:publisher");
576 OUString sPublisherName
;
580 const OUString
exp1("text()");
581 css::uno::Reference
< css::xml::dom::XNode
> xPathName
;
583 xPathName
= m_xpath
->selectSingleNode(node
, exp1
);
584 } catch (const css::xml::xpath::XPathException
&) {
587 OSL_ASSERT(xPathName
.is());
589 sPublisherName
= xPathName
->getNodeValue();
591 const OUString
exp2("@xlink:href");
592 css::uno::Reference
< css::xml::dom::XNode
> xURL
;
594 xURL
= m_xpath
->selectSingleNode(node
, exp2
);
595 } catch (const css::xml::xpath::XPathException
&) {
598 OSL_ASSERT(xURL
.is());
600 sURL
= xURL
->getNodeValue();
602 return std::make_pair(sPublisherName
, sURL
);
605 OUString
DescriptionInfoset::getLocalizedReleaseNotesURL() const
607 return getLocalizedHREFAttrFromChild("/desc:description/desc:release-notes", nullptr);
610 OUString
DescriptionInfoset::getLocalizedDisplayName() const
612 css::uno::Reference
< css::xml::dom::XNode
> node
=
613 getLocalizedChild("desc:display-name");
616 const OUString
exp("text()");
617 css::uno::Reference
< css::xml::dom::XNode
> xtext
;
619 xtext
= m_xpath
->selectSingleNode(node
, exp
);
620 } catch (const css::xml::xpath::XPathException
&) {
624 return xtext
->getNodeValue();
629 OUString
DescriptionInfoset::getLocalizedLicenseURL() const
631 return getLocalizedHREFAttrFromChild("/desc:description/desc:registration/desc:simple-license", nullptr);
635 ::boost::optional
<SimpleLicenseAttributes
>
636 DescriptionInfoset::getSimpleLicenseAttributes() const
638 //Check if the node exist
639 css::uno::Reference
< css::xml::dom::XNode
> n
;
640 if (m_element
.is()) {
642 n
= m_xpath
->selectSingleNode(m_element
, "/desc:description/desc:registration/desc:simple-license/@accept-by");
643 } catch (const css::xml::xpath::XPathException
&) {
648 SimpleLicenseAttributes attributes
;
649 attributes
.acceptBy
=
650 getNodeValueFromExpression("/desc:description/desc:registration/desc:simple-license/@accept-by");
652 ::boost::optional
< OUString
> suppressOnUpdate
= getOptionalValue("/desc:description/desc:registration/desc:simple-license/@suppress-on-update");
653 if (suppressOnUpdate
)
654 attributes
.suppressOnUpdate
= (*suppressOnUpdate
).trim().equalsIgnoreAsciiCase("true");
656 attributes
.suppressOnUpdate
= false;
658 ::boost::optional
< OUString
> suppressIfRequired
= getOptionalValue("/desc:description/desc:registration/desc:simple-license/@suppress-if-required");
659 if (suppressIfRequired
)
660 attributes
.suppressIfRequired
= (*suppressIfRequired
).trim().equalsIgnoreAsciiCase("true");
662 attributes
.suppressIfRequired
= false;
664 return ::boost::optional
<SimpleLicenseAttributes
>(attributes
);
667 return ::boost::optional
<SimpleLicenseAttributes
>();
670 OUString
DescriptionInfoset::getLocalizedDescriptionURL() const
672 return getLocalizedHREFAttrFromChild("/desc:description/desc:extension-description", nullptr);
675 css::uno::Reference
< css::xml::dom::XNode
>
676 DescriptionInfoset::getLocalizedChild( const OUString
& sParent
) const
678 if ( ! m_element
.is() || sParent
.isEmpty())
679 return css::uno::Reference
< css::xml::dom::XNode
> ();
681 css::uno::Reference
< css::xml::dom::XNode
> xParent
;
683 xParent
= m_xpath
->selectSingleNode(m_element
, sParent
);
684 } catch (const css::xml::xpath::XPathException
&) {
687 css::uno::Reference
<css::xml::dom::XNode
> nodeMatch
;
690 nodeMatch
= matchLanguageTag(xParent
, getOfficeLanguageTag().getBcp47());
692 //office: en-DE, en, en-DE-altmark
693 if (! nodeMatch
.is())
695 // Already tried full tag, continue with first fallback.
696 const std::vector
< OUString
> aFallbacks( getOfficeLanguageTag().getFallbackStrings( false));
697 for (auto const& fallback
: aFallbacks
)
699 nodeMatch
= matchLanguageTag(xParent
, fallback
);
703 if (! nodeMatch
.is())
704 nodeMatch
= getChildWithDefaultLocale(xParent
);
711 css::uno::Reference
<css::xml::dom::XNode
>
712 DescriptionInfoset::matchLanguageTag(
713 css::uno::Reference
< css::xml::dom::XNode
> const & xParent
, OUString
const & rTag
) const
715 OSL_ASSERT(xParent
.is());
716 css::uno::Reference
<css::xml::dom::XNode
> nodeMatch
;
718 //first try exact match for lang
719 const OUString
exp1("*[@lang=\"" + rTag
+ "\"]");
721 nodeMatch
= m_xpath
->selectSingleNode(xParent
, exp1
);
722 } catch (const css::xml::xpath::XPathException
&) {
726 //try to match in strings that also have a country and/or variant, for
727 //example en matches in en-US-montana, en-US, en-montana
731 "*[starts-with(@lang,\"" + rTag
+ "-\")]");
733 nodeMatch
= m_xpath
->selectSingleNode(xParent
, exp2
);
734 } catch (const css::xml::xpath::XPathException
&) {
741 css::uno::Reference
<css::xml::dom::XNode
>
742 DescriptionInfoset::getChildWithDefaultLocale(css::uno::Reference
< css::xml::dom::XNode
>
743 const & xParent
) const
745 OSL_ASSERT(xParent
.is());
746 if ( xParent
->getNodeName() == "simple-license" )
748 css::uno::Reference
<css::xml::dom::XNode
> nodeDefault
;
750 nodeDefault
= m_xpath
->selectSingleNode(xParent
, "@default-license-id");
751 } catch (const css::xml::xpath::XPathException
&) {
754 if (nodeDefault
.is())
757 const OUString
exp1("desc:license-text[@license-id = \""
758 + nodeDefault
->getNodeValue()
761 return m_xpath
->selectSingleNode(xParent
, exp1
);
762 } catch (const css::xml::xpath::XPathException
&) {
768 const OUString
exp2("*[1]");
770 return m_xpath
->selectSingleNode(xParent
, exp2
);
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 const OUString
exp("@xlink:href");
790 css::uno::Reference
< css::xml::dom::XNode
> xURL
;
792 xURL
= m_xpath
->selectSingleNode(node
, exp
);
793 } catch (const css::xml::xpath::XPathException
&) {
796 OSL_ASSERT(xURL
.is());
798 sURL
= xURL
->getNodeValue();
802 if (out_bParentExists
)
803 *out_bParentExists
= false;
810 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */