LibreOffice Module desktop (master)  1
dp_descriptioninfoset.cxx
Go to the documentation of this file.
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3  * This file is part of the LibreOffice project.
4  *
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/.
8  *
9  * This file incorporates work covered by the following license notice:
10  *
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 .
18  */
19 
20 #include <sal/config.h>
21 
22 #include <string_view>
23 
25 
26 #include <dp_resource.h>
27 
28 #include <comphelper/sequence.hxx>
31 #include <optional>
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>
60 
61 namespace {
62 
63 using css::uno::Reference;
64 
65 class EmptyNodeList:
66  public cppu::WeakImplHelper<css::xml::dom::XNodeList>
67 {
68 public:
69  EmptyNodeList();
70 
71  EmptyNodeList(const EmptyNodeList&) = delete;
72  const EmptyNodeList& operator=(const EmptyNodeList&) = delete;
73 
74  virtual ::sal_Int32 SAL_CALL getLength() override;
75 
76  virtual css::uno::Reference< css::xml::dom::XNode > SAL_CALL
77  item(::sal_Int32 index) override;
78 };
79 
80 EmptyNodeList::EmptyNodeList() {}
81 
82 ::sal_Int32 EmptyNodeList::getLength() {
83  return 0;
84 }
85 
86 css::uno::Reference< css::xml::dom::XNode > EmptyNodeList::item(::sal_Int32)
87 {
88  throw css::uno::RuntimeException("bad EmptyNodeList com.sun.star.xml.dom.XNodeList.item call",
89  static_cast< ::cppu::OWeakObject * >(this));
90 }
91 
92 OUString getNodeValue(
93  css::uno::Reference< css::xml::dom::XNode > const & node)
94 {
95  OSL_ASSERT(node.is());
96  try {
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,
102  nullptr, anyEx );
103  }
104 }
105 
111 class ExtensionDescription
112 {
113 public:
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);
127 
128  const css::uno::Reference<css::xml::dom::XNode>& getRootElement() const
129  {
130  return m_xRoot;
131  }
132 
133 private:
134  css::uno::Reference<css::xml::dom::XNode> m_xRoot;
135 };
136 
137 class NoDescriptionException
138 {
139 };
140 
141 class FileDoesNotExistFilter
142  : public ::cppu::WeakImplHelper< css::ucb::XCommandEnvironment,
143  css::task::XInteractionHandler >
144 
145 {
146  bool m_bExist;
147  css::uno::Reference< css::ucb::XCommandEnvironment > m_xCommandEnv;
148 
149 public:
150  explicit FileDoesNotExistFilter(
151  const css::uno::Reference< css::ucb::XCommandEnvironment >& xCmdEnv);
152 
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;
159 
160  // XInteractionHandler
161  virtual void SAL_CALL handle(
162  css::uno::Reference<css::task::XInteractionRequest > const & xRequest ) override;
163 };
164 
165 ExtensionDescription::ExtensionDescription(
166  const Reference<css::uno::XComponentContext>& xContext,
167  std::u16string_view installDir,
169 {
170  try {
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);
178 
179  //throws a css::uno::Exception if the file is not available
180  Reference<css::io::XInputStream> xIn;
181  try
182  { //throws com.sun.star.ucb.InteractiveIOException
183  xIn = descContent.openStream();
184  }
185  catch ( const css::uno::Exception& )
186  {
187  if ( ! static_cast<FileDoesNotExistFilter*>(xFilter.get())->exist())
188  throw NoDescriptionException();
189  throw;
190  }
191  if (!xIn.is())
192  {
193  throw css::uno::Exception(
194  "Could not get XInputStream for description.xml of extension " +
195  sDescriptionUri, nullptr);
196  }
197 
198  //get root node of description.xml
199  Reference<css::xml::dom::XDocumentBuilder> xDocBuilder(
201 
202  if (!xDocBuilder->isNamespaceAware())
203  {
204  throw css::uno::Exception(
205  "Service com.sun.star.xml.dom.DocumentBuilder is not namespace aware.", nullptr);
206  }
207 
208  Reference<css::xml::dom::XDocument> xDoc = xDocBuilder->parse(xIn);
209  if (!xDoc.is())
210  {
211  throw css::uno::Exception(sDescriptionUri + " contains data which cannot be parsed. ", nullptr);
212  }
213 
214  //check for proper root element and namespace
215  Reference<css::xml::dom::XElement> xRoot = xDoc->getDocumentElement();
216  if (!xRoot.is())
217  {
218  throw css::uno::Exception(
219  sDescriptionUri + " contains no root element.", nullptr);
220  }
221 
222  if ( xRoot->getTagName() != "description")
223  {
224  throw css::uno::Exception(
225  sDescriptionUri + " does not contain the root element <description>.", nullptr);
226  }
227 
228  m_xRoot.set(xRoot, css::uno::UNO_QUERY_THROW);
229  OUString nsDescription = xRoot->getNamespaceURI();
230 
231  //check if this namespace is supported
232  if ( nsDescription != "http://openoffice.org/extensions/description/2006")
233  {
234  throw css::uno::Exception(sDescriptionUri + " contains a root element with an unsupported namespace. ", nullptr);
235  }
236  } catch (const css::uno::RuntimeException &) {
237  throw;
238  } catch (const css::deployment::DeploymentException &) {
239  throw;
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);
244  }
245 }
246 
247 FileDoesNotExistFilter::FileDoesNotExistFilter(
249  m_bExist(true), m_xCommandEnv(xCmdEnv)
250 {}
251 
252  // XCommandEnvironment
253 Reference<css::task::XInteractionHandler >
254  FileDoesNotExistFilter::getInteractionHandler()
255 {
256  return static_cast<css::task::XInteractionHandler*>(this);
257 }
258 
259 Reference<css::ucb::XProgressHandler >
260  FileDoesNotExistFilter::getProgressHandler()
261 {
262  return m_xCommandEnv.is()
263  ? m_xCommandEnv->getProgressHandler()
264  : Reference<css::ucb::XProgressHandler>();
265 }
266 
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 )
272 {
273  css::uno::Any request( xRequest->getRequest() );
274 
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))
279  {
280  m_bExist = false;
281  return;
282  }
283  Reference<css::task::XInteractionHandler> xInteraction;
284  if (m_xCommandEnv.is()) {
285  xInteraction = m_xCommandEnv->getInteractionHandler();
286  }
287  if (xInteraction.is()) {
288  xInteraction->handle(xRequest);
289  }
290 }
291 
292 }
293 
294 namespace dp_misc {
295 
296 DescriptionInfoset getDescriptionInfoset(std::u16string_view sExtensionFolderURL)
297 {
298  Reference< css::xml::dom::XNode > root;
299  Reference<css::uno::XComponentContext> context(
301  try {
302  root =
303  ExtensionDescription(
304  context, sExtensionFolderURL,
306  getRootElement();
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,
312  nullptr, anyEx );
313  }
314  return DescriptionInfoset(context, root);
315 }
316 
318  css::uno::Reference< css::uno::XComponentContext > const & context,
319  css::uno::Reference< css::xml::dom::XNode > const & element):
320  m_context(context),
321  m_element(element)
322 {
323  if (m_element.is()) {
325  m_xpath->registerNS("desc", element->getNamespaceURI());
326  m_xpath->registerNS("xlink", "http://www.w3.org/1999/xlink");
327  }
328 }
329 
331 
332 ::std::optional< OUString > DescriptionInfoset::getIdentifier() const {
333  return getOptionalValue("desc:identifier/@value");
334 }
335 
336 OUString DescriptionInfoset::getNodeValueFromExpression(OUString const & expression) const
337 {
338  css::uno::Reference< css::xml::dom::XNode > n;
339  if (m_element.is()) {
340  try {
341  n = m_xpath->selectSingleNode(m_element, expression);
342  } catch (const css::xml::xpath::XPathException &) {
343  // ignore
344  }
345  }
346  return n.is() ? getNodeValue(n) : OUString();
347 }
348 
350 {
351  if (!m_element.is())
352  return;
353 
354  std::optional< OUString > id(getIdentifier());
355  if (!id)
356  return; // nothing to check
357  OUString currentversion(getVersion());
358  if (currentversion.getLength() == 0)
359  return; // nothing to check
360 
361  css::uno::Sequence<css::uno::Any> args(comphelper::InitAnyPropertySequence(
362  {
363  {"nodepath", css::uno::Any(OUString("/org.openoffice.Office.ExtensionDependencies/Extensions"))}
364  }));
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);
370 
371  // check first if a denylist entry is available
372  if (!(denylist.is() && denylist->hasByName(*id))) return;
373 
374  css::uno::Reference< css::beans::XPropertySet > extProps(
375  denylist->getByName(*id), css::uno::UNO_QUERY_THROW);
376 
377  css::uno::Any anyValue = extProps->getPropertyValue("Versions");
378 
379  css::uno::Sequence< OUString > blversions;
380  anyValue >>= blversions;
381 
382  // check if the current version requires further dependency checks from the denylist
383  if (!checkDenylistVersion(currentversion, blversions)) return;
384 
385  anyValue = extProps->getPropertyValue("Dependencies");
386  OUString udeps;
387  anyValue >>= udeps;
388 
389  if (udeps.getLength() == 0)
390  return; // nothing todo
391 
392  OString xmlDependencies = OUStringToOString(udeps, RTL_TEXTENCODING_UNICODE);
393 
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);
397 
398  css::uno::Sequence< sal_Int8 > byteSeq(reinterpret_cast<const sal_Int8*>(xmlDependencies.getStr()), xmlDependencies.getLength());
399 
400  css::uno::Reference< css::io::XInputStream> inputstream( css::io::SequenceInputStream::createStreamFromSequence(m_context, byteSeq),
401  css::uno::UNO_QUERY_THROW);
402 
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();
407 
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());
410 
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"));
414 
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");
423  }
424 
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);
428  if (xDep.is()) {
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);
432  }
433  }
434 }
435 
437  std::u16string_view currentversion,
438  css::uno::Sequence< OUString > const & versions)
439 {
440  sal_Int32 nLen = versions.getLength();
441  for (sal_Int32 i=0; i<nLen; i++) {
442  if (currentversion == versions[i])
443  return true;
444  }
445 
446  return false;
447 }
448 
450 {
451  return getNodeValueFromExpression( "desc:version/@value" );
452 }
453 
454 css::uno::Sequence< OUString > DescriptionInfoset::getSupportedPlatforms() const
455 {
456  //When there is no description.xml then we assume that we support all platforms
457  if (! m_element.is())
458  {
459  return { OUString("all") };
460  }
461 
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())
466  {
467  return { OUString("all") };
468  }
469 
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;
475  do
476  {
477  const OUString aToken( o3tl::trim(o3tl::getToken(value, 0, ',', nIndex )) );
478  if (!aToken.isEmpty())
479  vec.push_back(aToken);
480 
481  }
482  while (nIndex >= 0);
483 
485 }
486 
487 css::uno::Reference< css::xml::dom::XNodeList >
489  if (m_element.is()) {
490  try {
491  // check the extension denylist first and expand the dependencies if applicable
492  checkDenylist();
493 
494  return m_xpath->selectNodeList(m_element, "desc:dependencies/*");
495  } catch (const css::xml::xpath::XPathException &) {
496  // ignore
497  }
498  }
499  return new EmptyNodeList;
500 }
501 
502 css::uno::Sequence< OUString >
504  return getUrls("desc:update-information/desc:src/@xlink:href");
505 }
506 
507 css::uno::Sequence< OUString >
509 {
510  return getUrls("desc:update-download/desc:src/@xlink:href");
511 }
512 
513 OUString DescriptionInfoset::getIconURL( bool bHighContrast ) const
514 {
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" );
517 
518  if ( bHighContrast && aStrListHC.hasElements() && !aStrListHC[0].isEmpty() )
519  return aStrListHC[0];
520 
521  if ( aStrList.hasElements() && !aStrList[0].isEmpty() )
522  return aStrList[0];
523 
524  return OUString();
525 }
526 
528  const
529 {
530  bool bParentExists = false;
531  const OUString sURL (getLocalizedHREFAttrFromChild("/desc:description/desc:update-website", &bParentExists ));
532 
533  if (!sURL.isEmpty())
534  return ::std::optional< OUString >(sURL);
535  else
536  return bParentExists ? ::std::optional< OUString >(OUString()) :
537  ::std::optional< OUString >();
538 }
539 
540 ::std::optional< OUString > DescriptionInfoset::getOptionalValue(
541  OUString const & expression) const
542 {
543  css::uno::Reference< css::xml::dom::XNode > n;
544  if (m_element.is()) {
545  try {
546  n = m_xpath->selectSingleNode(m_element, expression);
547  } catch (const css::xml::xpath::XPathException &) {
548  // ignore
549  }
550  }
551  return n.is()
552  ? ::std::optional< OUString >(getNodeValue(n))
553  : ::std::optional< OUString >();
554 }
555 
556 css::uno::Sequence< OUString > DescriptionInfoset::getUrls(
557  OUString const & expression) const
558 {
559  css::uno::Reference< css::xml::dom::XNodeList > ns;
560  if (m_element.is()) {
561  try {
562  ns = m_xpath->selectNodeList(m_element, expression);
563  } catch (const css::xml::xpath::XPathException &) {
564  // ignore
565  }
566  }
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));
571  }
572  return urls;
573 }
574 
575 std::pair< OUString, OUString > DescriptionInfoset::getLocalizedPublisherNameAndURL() const
576 {
577  css::uno::Reference< css::xml::dom::XNode > node =
578  getLocalizedChild("desc:publisher");
579 
580  OUString sPublisherName;
581  OUString sURL;
582  if (node.is())
583  {
584  css::uno::Reference< css::xml::dom::XNode > xPathName;
585  try {
586  xPathName = m_xpath->selectSingleNode(node, "text()");
587  } catch (const css::xml::xpath::XPathException &) {
588  // ignore
589  }
590  OSL_ASSERT(xPathName.is());
591  if (xPathName.is())
592  sPublisherName = xPathName->getNodeValue();
593 
594  css::uno::Reference< css::xml::dom::XNode > xURL;
595  try {
596  xURL = m_xpath->selectSingleNode(node, "@xlink:href");
597  } catch (const css::xml::xpath::XPathException &) {
598  // ignore
599  }
600  OSL_ASSERT(xURL.is());
601  if (xURL.is())
602  sURL = xURL->getNodeValue();
603  }
604  return std::make_pair(sPublisherName, sURL);
605 }
606 
608 {
609  return getLocalizedHREFAttrFromChild("/desc:description/desc:release-notes", nullptr);
610 }
611 
613 {
614  css::uno::Reference< css::xml::dom::XNode > node =
615  getLocalizedChild("desc:display-name");
616  if (node.is())
617  {
618  css::uno::Reference< css::xml::dom::XNode > xtext;
619  try {
620  xtext = m_xpath->selectSingleNode(node, "text()");
621  } catch (const css::xml::xpath::XPathException &) {
622  // ignore
623  }
624  if (xtext.is())
625  return xtext->getNodeValue();
626  }
627  return OUString();
628 }
629 
631 {
632  return getLocalizedHREFAttrFromChild("/desc:description/desc:registration/desc:simple-license", nullptr);
633 
634 }
635 
636 ::std::optional<SimpleLicenseAttributes>
638 {
639  //Check if the node exist
640  css::uno::Reference< css::xml::dom::XNode > n;
641  if (m_element.is()) {
642  try {
643  n = m_xpath->selectSingleNode(m_element, "/desc:description/desc:registration/desc:simple-license/@accept-by");
644  } catch (const css::xml::xpath::XPathException &) {
645  // ignore
646  }
647  if (n.is())
648  {
649  SimpleLicenseAttributes attributes;
650  attributes.acceptBy =
651  getNodeValueFromExpression("/desc:description/desc:registration/desc:simple-license/@accept-by");
652 
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");
656  else
657  attributes.suppressOnUpdate = false;
658 
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");
662  else
663  attributes.suppressIfRequired = false;
664 
665  return ::std::optional<SimpleLicenseAttributes>(attributes);
666  }
667  }
668  return ::std::optional<SimpleLicenseAttributes>();
669 }
670 
672 {
673  return getLocalizedHREFAttrFromChild("/desc:description/desc:extension-description", nullptr);
674 }
675 
676 css::uno::Reference< css::xml::dom::XNode >
677 DescriptionInfoset::getLocalizedChild( const OUString & sParent) const
678 {
679  if ( ! m_element.is() || sParent.isEmpty())
680  return css::uno::Reference< css::xml::dom::XNode > ();
681 
682  css::uno::Reference< css::xml::dom::XNode > xParent;
683  try {
684  xParent = m_xpath->selectSingleNode(m_element, sParent);
685  } catch (const css::xml::xpath::XPathException &) {
686  // ignore
687  }
688  css::uno::Reference<css::xml::dom::XNode> nodeMatch;
689  if (xParent.is())
690  {
691  nodeMatch = matchLanguageTag(xParent, getOfficeLanguageTag().getBcp47());
692 
693  //office: en-DE, en, en-DE-altmark
694  if (! nodeMatch.is())
695  {
696  // Already tried full tag, continue with first fallback.
697  const std::vector< OUString > aFallbacks( getOfficeLanguageTag().getFallbackStrings( false));
698  for (auto const& fallback : aFallbacks)
699  {
700  nodeMatch = matchLanguageTag(xParent, fallback);
701  if (nodeMatch.is())
702  break;
703  }
704  if (! nodeMatch.is())
705  nodeMatch = getChildWithDefaultLocale(xParent);
706  }
707  }
708 
709  return nodeMatch;
710 }
711 
712 css::uno::Reference<css::xml::dom::XNode>
714  css::uno::Reference< css::xml::dom::XNode > const & xParent, std::u16string_view rTag) const
715 {
716  OSL_ASSERT(xParent.is());
717  css::uno::Reference<css::xml::dom::XNode> nodeMatch;
718 
719  //first try exact match for lang
720  const OUString exp1(OUString::Concat("*[@lang=\"") + rTag + "\"]");
721  try {
722  nodeMatch = m_xpath->selectSingleNode(xParent, exp1);
723  } catch (const css::xml::xpath::XPathException &) {
724  // ignore
725  }
726 
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
729  if (!nodeMatch.is())
730  {
731  const OUString exp2(
732  OUString::Concat("*[starts-with(@lang,\"") + rTag + "-\")]");
733  try {
734  nodeMatch = m_xpath->selectSingleNode(xParent, exp2);
735  } catch (const css::xml::xpath::XPathException &) {
736  // ignore
737  }
738  }
739  return nodeMatch;
740 }
741 
742 css::uno::Reference<css::xml::dom::XNode>
743 DescriptionInfoset::getChildWithDefaultLocale(css::uno::Reference< css::xml::dom::XNode >
744  const & xParent) const
745 {
746  OSL_ASSERT(xParent.is());
747  if ( xParent->getNodeName() == "simple-license" )
748  {
749  css::uno::Reference<css::xml::dom::XNode> nodeDefault;
750  try {
751  nodeDefault = m_xpath->selectSingleNode(xParent, "@default-license-id");
752  } catch (const css::xml::xpath::XPathException &) {
753  // ignore
754  }
755  if (nodeDefault.is())
756  {
757  //The old way
758  const OUString exp1("desc:license-text[@license-id = \""
759  + nodeDefault->getNodeValue()
760  + "\"]");
761  try {
762  return m_xpath->selectSingleNode(xParent, exp1);
763  } catch (const css::xml::xpath::XPathException &) {
764  // ignore
765  }
766  }
767  }
768 
769  try {
770  return m_xpath->selectSingleNode(xParent, "*[1]");
771  } catch (const css::xml::xpath::XPathException &) {
772  // ignore
773  return nullptr;
774  }
775 }
776 
778  OUString const & sXPathParent, bool * out_bParentExists)
779  const
780 {
781  css::uno::Reference< css::xml::dom::XNode > node =
782  getLocalizedChild(sXPathParent);
783 
784  OUString sURL;
785  if (node.is())
786  {
787  if (out_bParentExists)
788  *out_bParentExists = true;
789  css::uno::Reference< css::xml::dom::XNode > xURL;
790  try {
791  xURL = m_xpath->selectSingleNode(node, "@xlink:href");
792  } catch (const css::xml::xpath::XPathException &) {
793  // ignore
794  }
795  OSL_ASSERT(xURL.is());
796  if (xURL.is())
797  sURL = xURL->getNodeValue();
798  }
799  else
800  {
801  if (out_bParentExists)
802  *out_bParentExists = false;
803  }
804  return sURL;
805 }
806 
807 }
808 
809 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
DESKTOP_DEPLOYMENTMISC_DLLPUBLIC const LanguageTag & getOfficeLanguageTag()
Definition: dp_resource.cxx:29
OUString getLocalizedLicenseURL() const
returns the relative path to the license file.
sal_Int32 nIndex
OUString getLocalizedReleaseNotesURL() const
Returns the URL for the release notes corresponding to the office's locale.
tuple ns
css::uno::Sequence< OUString > getUpdateInformationUrls() const
Return the update information URLs.
css::uno::Sequence< OUString > getUpdateDownloadUrls() const
Return the download URLs from the update information.
css::uno::Reference< css::xml::dom::XNodeList > getDependencies() const
Return the dependencies.
sal_Int64 n
tuple args
std::basic_string_view< charT, traits > getToken(std::basic_string_view< charT, traits > sv, charT delimiter, std::size_t &position)
SAL_DLLPRIVATE css::uno::Reference< css::xml::dom::XNode > getChildWithDefaultLocale(css::uno::Reference< css::xml::dom::XNode > const &xParent) const
If there is no child element with a locale matching the office locale, then we use the first child...
css::uno::Reference< css::deployment::XPackageRegistry > create(css::uno::Reference< css::deployment::XPackageRegistry > const &xRootRegistry, OUString const &context, OUString const &cachePath, css::uno::Reference< css::uno::XComponentContext > const &xComponentContext)
std::pair< OUString, OUString > getLocalizedPublisherNameAndURL() const
Returns the localized publisher name and the corresponding URL.
OUString getVersion() const
Return the textual version representation.
DescriptionInfoset(css::uno::Reference< css::uno::XComponentContext > const &context, css::uno::Reference< css::xml::dom::XNode > const &element)
Create an instance.
Any SAL_CALL getCaughtException()
OString OUStringToOString(std::u16string_view str, ConnectionSettings const *settings)
OUString getLocalizedDisplayName() const
returns the localized display name of the extensions.
css::uno::Reference< css::xml::xpath::XXPathAPI > m_xpath
DESKTOP_DEPLOYMENTMISC_DLLPUBLIC DescriptionInfoset getDescriptionInfoset(std::u16string_view sExtensionFolderURL)
creates a DescriptionInfoset object.
static SAL_DLLPRIVATE bool checkDenylistVersion(std::u16string_view currentversion, css::uno::Sequence< OUString > const &versions)
Helper method to compare the versions with the current version.
int i
uno_Any a
css::uno::Sequence< css::uno::Any > InitAnyPropertySequence(::std::initializer_list< ::std::pair< OUString, css::uno::Any > > vInit)
SAL_DLLPRIVATE OUString getNodeValueFromExpression(OUString const &expression) const
Gets the node value for a given expression.
float u
::std::optional< OUString > getIdentifier() const
Return the identifier.
SAL_DLLPRIVATE OUString getLocalizedHREFAttrFromChild(OUString const &sXPathParent, bool *out_bParentExists) const
SAL_DLLPRIVATE::std::optional< OUString > getOptionalValue(OUString const &expression) const
static uno::Reference< css::uno::XComponentContext > xContext
Definition: init.cxx:2429
Reference< xml::input::XRoot > m_xRoot
bool equalsIgnoreAsciiCase(std::u16string_view s1, std::u16string_view s2)
css::uno::Sequence< DstElementType > containerToSequence(const SrcType &i_Container)
SAL_DLLPRIVATE css::uno::Sequence< OUString > getUrls(OUString const &expression) const
std::u16string_view trim(std::u16string_view str)
Reference< XComponentContext > getProcessComponentContext()
double getLength(const B2DPolygon &rCandidate)
Any value
::std::optional< SimpleLicenseAttributes > getSimpleLicenseAttributes() const
returns the attributes of the simple-license element
css::uno::Reference< css::xml::dom::XNode > m_element
css::uno::Sequence< OUString > getSupportedPlatforms() const
Returns a list of supported platforms.
SAL_DLLPRIVATE css::uno::Reference< css::xml::dom::XNode > matchLanguageTag(css::uno::Reference< css::xml::dom::XNode > const &xParent, std::u16string_view rTag) const
OUString getLocalizedDescriptionURL() const
returns the relative URL to the description.
css::uno::Reference< css::uno::XComponentContext > m_context
OUString getIconURL(bool bHighContrast) const
Returns the URL for the icon image.
SAL_DLLPRIVATE css::uno::Reference< css::xml::dom::XNode > getLocalizedChild(OUString const &sParent) const
Retrieves a child element which as lang attribute which matches the office locale.
SAL_DLLPRIVATE void checkDenylist() const
Check the extensions denylist if additional extension meta data (e.g.
::std::optional< OUString > getLocalizedUpdateWebsiteURL() const
returns the download website URL from the update information.
Access to the content of an XML description element.