Line data Source code
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 "dp_descriptioninfoset.hxx"
21 :
22 : #include "dp_resource.h"
23 : #include "sal/config.h"
24 :
25 : #include "comphelper/sequence.hxx"
26 : #include "comphelper/seqstream.hxx"
27 : #include "comphelper/makesequence.hxx"
28 : #include "comphelper/processfactory.hxx"
29 : #include "boost/optional.hpp"
30 : #include "com/sun/star/container/XNameAccess.hpp"
31 : #include "com/sun/star/beans/Optional.hpp"
32 : #include "com/sun/star/beans/PropertyValue.hpp"
33 : #include "com/sun/star/beans/XPropertySet.hpp"
34 : #include "com/sun/star/io/SequenceInputStream.hpp"
35 : #include "com/sun/star/lang/XMultiComponentFactory.hpp"
36 : #include "com/sun/star/uno/Reference.hxx"
37 : #include "com/sun/star/uno/RuntimeException.hpp"
38 : #include "com/sun/star/uno/Sequence.hxx"
39 : #include "com/sun/star/uno/XComponentContext.hpp"
40 : #include "com/sun/star/uno/XInterface.hpp"
41 : #include "com/sun/star/xml/dom/DOMException.hpp"
42 : #include "com/sun/star/xml/dom/XNode.hpp"
43 : #include "com/sun/star/xml/dom/XNodeList.hpp"
44 : #include "com/sun/star/xml/dom/DocumentBuilder.hpp"
45 : #include "com/sun/star/xml/xpath/XPathAPI.hpp"
46 : #include "com/sun/star/ucb/InteractiveIOException.hpp"
47 : #include "cppuhelper/implbase1.hxx"
48 : #include "cppuhelper/implbase2.hxx"
49 : #include "cppuhelper/weak.hxx"
50 : #include "cppuhelper/exc_hlp.hxx"
51 : #include "rtl/ustring.h"
52 : #include "rtl/ustring.hxx"
53 : #include "sal/types.h"
54 : #include "ucbhelper/content.hxx"
55 :
56 : namespace {
57 :
58 : using css::uno::Reference;
59 :
60 : class EmptyNodeList: public ::cppu::WeakImplHelper1< css::xml::dom::XNodeList >
61 : {
62 : public:
63 : EmptyNodeList();
64 :
65 : virtual ~EmptyNodeList();
66 :
67 : virtual ::sal_Int32 SAL_CALL getLength() throw (css::uno::RuntimeException);
68 :
69 : virtual css::uno::Reference< css::xml::dom::XNode > SAL_CALL
70 : item(::sal_Int32 index) throw (css::uno::RuntimeException);
71 :
72 : private:
73 : EmptyNodeList(EmptyNodeList &); // not defined
74 : void operator =(EmptyNodeList &); // not defined
75 : };
76 :
77 0 : EmptyNodeList::EmptyNodeList() {}
78 :
79 0 : EmptyNodeList::~EmptyNodeList() {}
80 :
81 0 : ::sal_Int32 EmptyNodeList::getLength() throw (css::uno::RuntimeException) {
82 0 : return 0;
83 : }
84 :
85 0 : css::uno::Reference< css::xml::dom::XNode > EmptyNodeList::item(::sal_Int32)
86 : throw (css::uno::RuntimeException)
87 : {
88 : throw css::uno::RuntimeException("bad EmptyNodeList com.sun.star.xml.dom.XNodeList.item call",
89 0 : static_cast< ::cppu::OWeakObject * >(this));
90 : }
91 :
92 243 : OUString getNodeValue(
93 : css::uno::Reference< css::xml::dom::XNode > const & node)
94 : {
95 : OSL_ASSERT(node.is());
96 : try {
97 243 : return node->getNodeValue();
98 0 : } catch (const css::xml::dom::DOMException & e) {
99 : throw css::uno::RuntimeException(
100 0 : "com.sun.star.xml.dom.DOMException: " + e.Message,
101 0 : css::uno::Reference< css::uno::XInterface >());
102 : }
103 : }
104 :
105 : /**The class uses the UCB to access the description.xml file in an
106 : extension. The UCB must have been initialized already. It also
107 : requires that the extension has already be unzipped to a particular
108 : location.
109 : */
110 : class ExtensionDescription
111 : {
112 : public:
113 : /**throws an exception if the description.xml is not
114 : available, cannot be read, does not contain the expected data,
115 : or any other error occurred. Therefore it shoult only be used with
116 : new extensions.
117 :
118 : Throws com::sun::star::uno::RuntimeException,
119 : com::sun::star::deployment::DeploymentException,
120 : dp_registry::backend::bundle::NoDescriptionException.
121 : */
122 : ExtensionDescription(
123 : const css::uno::Reference<css::uno::XComponentContext>& xContext,
124 : const OUString& installDir,
125 : const css::uno::Reference< css::ucb::XCommandEnvironment >& xCmdEnv);
126 :
127 : ~ExtensionDescription();
128 :
129 279 : css::uno::Reference<css::xml::dom::XNode> getRootElement() const
130 : {
131 279 : return m_xRoot;
132 : }
133 :
134 : OUString getExtensionRootUrl() const
135 : {
136 : return m_sExtensionRootUrl;
137 : }
138 :
139 :
140 : private:
141 : css::uno::Reference<css::xml::dom::XNode> m_xRoot;
142 : OUString m_sExtensionRootUrl;
143 : };
144 :
145 : class NoDescriptionException
146 : {
147 : };
148 :
149 : class FileDoesNotExistFilter
150 : : public ::cppu::WeakImplHelper2< css::ucb::XCommandEnvironment,
151 : css::task::XInteractionHandler >
152 :
153 : {
154 : bool m_bExist;
155 : css::uno::Reference< css::ucb::XCommandEnvironment > m_xCommandEnv;
156 :
157 : public:
158 : virtual ~FileDoesNotExistFilter();
159 : FileDoesNotExistFilter(
160 : const css::uno::Reference< css::ucb::XCommandEnvironment >& xCmdEnv);
161 :
162 : bool exist();
163 : // XCommandEnvironment
164 : virtual css::uno::Reference<css::task::XInteractionHandler > SAL_CALL
165 : getInteractionHandler() throw (css::uno::RuntimeException);
166 : virtual css::uno::Reference<css::ucb::XProgressHandler >
167 : SAL_CALL getProgressHandler() throw (css::uno::RuntimeException);
168 :
169 : // XInteractionHandler
170 : virtual void SAL_CALL handle(
171 : css::uno::Reference<css::task::XInteractionRequest > const & xRequest )
172 : throw (css::uno::RuntimeException);
173 : };
174 :
175 279 : ExtensionDescription::ExtensionDescription(
176 : const Reference<css::uno::XComponentContext>& xContext,
177 : const OUString& installDir,
178 279 : const Reference< css::ucb::XCommandEnvironment >& xCmdEnv)
179 : {
180 : try {
181 279 : m_sExtensionRootUrl = installDir;
182 : //may throw ::com::sun::star::ucb::ContentCreationException
183 : //If there is no description.xml then ucb will start an interaction which
184 : //brings up a dialog.We want to prevent this. Therefore we wrap the xCmdEnv
185 : //and filter the respective exception out.
186 279 : OUString sDescriptionUri(installDir + "/description.xml");
187 : Reference<css::ucb::XCommandEnvironment> xFilter =
188 : static_cast<css::ucb::XCommandEnvironment*>(
189 558 : new FileDoesNotExistFilter(xCmdEnv));
190 558 : ::ucbhelper::Content descContent(sDescriptionUri, xFilter, xContext);
191 :
192 : //throws an com::sun::star::uno::Exception if the file is not available
193 558 : Reference<css::io::XInputStream> xIn;
194 : try
195 : { //throws com.sun.star.ucb.InteractiveIOException
196 279 : xIn = descContent.openStream();
197 : }
198 0 : catch ( const css::uno::Exception& )
199 : {
200 0 : if ( ! static_cast<FileDoesNotExistFilter*>(xFilter.get())->exist())
201 0 : throw NoDescriptionException();
202 0 : throw;
203 : }
204 279 : if (!xIn.is())
205 : {
206 : throw css::uno::Exception(
207 0 : "Could not get XInputStream for description.xml of extension " +
208 0 : sDescriptionUri, 0);
209 : }
210 :
211 : //get root node of description.xml
212 : Reference<css::xml::dom::XDocumentBuilder> xDocBuilder(
213 558 : css::xml::dom::DocumentBuilder::create(xContext) );
214 :
215 279 : if (xDocBuilder->isNamespaceAware() == sal_False)
216 : {
217 : throw css::uno::Exception(
218 0 : "Service com.sun.star.xml.dom.DocumentBuilder is not namespace aware.", 0);
219 : }
220 :
221 558 : Reference<css::xml::dom::XDocument> xDoc = xDocBuilder->parse(xIn);
222 279 : if (!xDoc.is())
223 : {
224 0 : throw css::uno::Exception(sDescriptionUri + " contains data which cannot be parsed. ", 0);
225 : }
226 :
227 : //check for proper root element and namespace
228 558 : Reference<css::xml::dom::XElement> xRoot = xDoc->getDocumentElement();
229 279 : if (!xRoot.is())
230 : {
231 : throw css::uno::Exception(
232 0 : sDescriptionUri + " contains no root element.", 0);
233 : }
234 :
235 279 : if ( ! (xRoot->getTagName() == "description"))
236 : {
237 : throw css::uno::Exception(
238 0 : sDescriptionUri + " does not contain the root element <description>.", 0);
239 : }
240 :
241 558 : m_xRoot = Reference<css::xml::dom::XNode>(
242 279 : xRoot, css::uno::UNO_QUERY_THROW);
243 558 : OUString nsDescription = xRoot->getNamespaceURI();
244 :
245 : //check if this namespace is supported
246 279 : if ( ! (nsDescription == "http://openoffice.org/extensions/description/2006"))
247 : {
248 0 : throw css::uno::Exception(sDescriptionUri + " contains a root element with an unsupported namespace. ", 0);
249 279 : }
250 0 : } catch (const css::uno::RuntimeException &) {
251 0 : throw;
252 0 : } catch (const css::deployment::DeploymentException &) {
253 0 : throw;
254 0 : } catch (const css::uno::Exception & e) {
255 0 : css::uno::Any a(cppu::getCaughtException());
256 : throw css::deployment::DeploymentException(
257 0 : e.Message, Reference< css::uno::XInterface >(), a);
258 : }
259 279 : }
260 :
261 279 : ExtensionDescription::~ExtensionDescription()
262 : {
263 279 : }
264 :
265 : //======================================================================
266 279 : FileDoesNotExistFilter::FileDoesNotExistFilter(
267 : const Reference< css::ucb::XCommandEnvironment >& xCmdEnv):
268 279 : m_bExist(true), m_xCommandEnv(xCmdEnv)
269 279 : {}
270 :
271 558 : FileDoesNotExistFilter::~FileDoesNotExistFilter()
272 : {
273 558 : };
274 :
275 0 : bool FileDoesNotExistFilter::exist()
276 : {
277 0 : return m_bExist;
278 : }
279 : // XCommandEnvironment
280 : Reference<css::task::XInteractionHandler >
281 0 : FileDoesNotExistFilter::getInteractionHandler() throw (css::uno::RuntimeException)
282 : {
283 0 : return static_cast<css::task::XInteractionHandler*>(this);
284 : }
285 :
286 : Reference<css::ucb::XProgressHandler >
287 0 : FileDoesNotExistFilter::getProgressHandler() throw (css::uno::RuntimeException)
288 : {
289 0 : return m_xCommandEnv.is()
290 0 : ? m_xCommandEnv->getProgressHandler()
291 0 : : Reference<css::ucb::XProgressHandler>();
292 : }
293 :
294 : // XInteractionHandler
295 : //If the interaction was caused by a non-existing file which is specified in the ctor
296 : //of FileDoesNotExistFilter, then we do nothing
297 0 : void FileDoesNotExistFilter::handle(
298 : Reference<css::task::XInteractionRequest > const & xRequest )
299 : throw (css::uno::RuntimeException)
300 : {
301 0 : css::uno::Any request( xRequest->getRequest() );
302 :
303 0 : css::ucb::InteractiveIOException ioexc;
304 0 : if ((request>>= ioexc)
305 0 : && (ioexc.Code == css::ucb::IOErrorCode_NOT_EXISTING
306 0 : || ioexc.Code == css::ucb::IOErrorCode_NOT_EXISTING_PATH))
307 : {
308 0 : m_bExist = false;
309 0 : return;
310 : }
311 0 : Reference<css::task::XInteractionHandler> xInteraction;
312 0 : if (m_xCommandEnv.is()) {
313 0 : xInteraction = m_xCommandEnv->getInteractionHandler();
314 : }
315 0 : if (xInteraction.is()) {
316 0 : xInteraction->handle(xRequest);
317 0 : }
318 : }
319 :
320 : }
321 :
322 : namespace dp_misc {
323 :
324 279 : DescriptionInfoset getDescriptionInfoset(OUString const & sExtensionFolderURL)
325 : {
326 279 : Reference< css::xml::dom::XNode > root;
327 : Reference<css::uno::XComponentContext> context =
328 558 : comphelper_getProcessComponentContext();
329 : OSL_ASSERT(context.is());
330 : try {
331 558 : root =
332 : ExtensionDescription(
333 : context, sExtensionFolderURL,
334 : Reference< css::ucb::XCommandEnvironment >()).
335 279 : getRootElement();
336 0 : } catch (const NoDescriptionException &) {
337 0 : } catch (const css::deployment::DeploymentException & e) {
338 : throw css::uno::RuntimeException(
339 0 : "com.sun.star.deployment.DeploymentException: " + e.Message, 0);
340 : }
341 558 : return DescriptionInfoset(context, root);
342 : }
343 :
344 279 : DescriptionInfoset::DescriptionInfoset(
345 : css::uno::Reference< css::uno::XComponentContext > const & context,
346 : css::uno::Reference< css::xml::dom::XNode > const & element):
347 : m_context(context),
348 279 : m_element(element)
349 : {
350 279 : if (m_element.is()) {
351 279 : m_xpath = css::xml::xpath::XPathAPI::create(context);
352 279 : m_xpath->registerNS("desc", element->getNamespaceURI());
353 279 : m_xpath->registerNS("xlink", "http://www.w3.org/1999/xlink");
354 : }
355 279 : }
356 :
357 279 : DescriptionInfoset::~DescriptionInfoset() {}
358 :
359 141 : ::boost::optional< OUString > DescriptionInfoset::getIdentifier() const {
360 141 : return getOptionalValue("desc:identifier/@value");
361 : }
362 :
363 102 : OUString DescriptionInfoset::getNodeValueFromExpression(OUString const & expression) const
364 : {
365 102 : css::uno::Reference< css::xml::dom::XNode > n;
366 102 : if (m_element.is()) {
367 : try {
368 102 : n = m_xpath->selectSingleNode(m_element, expression);
369 0 : } catch (const css::xml::xpath::XPathException &) {
370 : // ignore
371 : }
372 : }
373 102 : return n.is() ? getNodeValue(n) : OUString();
374 : }
375 :
376 34 : void DescriptionInfoset::checkBlacklist() const
377 : {
378 34 : if (m_element.is()) {
379 34 : boost::optional< OUString > id(getIdentifier());
380 34 : if (!id)
381 0 : return; // nothing to check
382 68 : OUString currentversion(getVersion());
383 34 : if (currentversion.getLength() == 0)
384 0 : return; // nothing to check
385 :
386 : css::uno::Reference< css::lang::XMultiComponentFactory > manager(
387 68 : m_context->getServiceManager(), css::uno::UNO_QUERY_THROW);
388 : css::uno::Reference< css::lang::XMultiServiceFactory> provider(
389 34 : manager->createInstanceWithContext("com.sun.star.configuration.ConfigurationProvider", m_context),
390 68 : css::uno::UNO_QUERY_THROW);
391 :
392 68 : css::uno::Sequence< css::uno::Any > args = css::uno::Sequence< css::uno::Any >(1);
393 68 : css::beans::PropertyValue prop;
394 34 : prop.Name = OUString("nodepath");
395 34 : prop.Value <<= OUString("/org.openoffice.Office.ExtensionDependencies/Extensions");
396 34 : args[0] <<= prop;
397 :
398 : css::uno::Reference< css::container::XNameAccess > blacklist(
399 34 : provider->createInstanceWithArguments("com.sun.star.configuration.ConfigurationAccess", args),
400 68 : css::uno::UNO_QUERY_THROW);
401 :
402 : // check first if a blacklist entry is available
403 34 : if (blacklist.is() && blacklist->hasByName(*id)) {
404 : css::uno::Reference< css::beans::XPropertySet > extProps(
405 0 : blacklist->getByName(*id), css::uno::UNO_QUERY_THROW);
406 :
407 0 : css::uno::Any anyValue = extProps->getPropertyValue("Versions");
408 :
409 0 : css::uno::Sequence< OUString > blversions;
410 0 : anyValue >>= blversions;
411 :
412 : // check if the current version requires further dependency checks from the blacklist
413 0 : if (checkBlacklistVersion(currentversion, blversions)) {
414 0 : anyValue = extProps->getPropertyValue("Dependencies");
415 0 : OUString udeps;
416 0 : anyValue >>= udeps;
417 :
418 0 : if (udeps.getLength() == 0)
419 0 : return; // nothing todo
420 :
421 0 : OString xmlDependencies = OUStringToOString(udeps, RTL_TEXTENCODING_UNICODE);
422 :
423 : css::uno::Reference< css::xml::dom::XDocumentBuilder> docbuilder(
424 0 : manager->createInstanceWithContext("com.sun.star.xml.dom.DocumentBuilder", m_context),
425 0 : css::uno::UNO_QUERY_THROW);
426 :
427 0 : css::uno::Sequence< sal_Int8 > byteSeq((const sal_Int8*)xmlDependencies.getStr(), xmlDependencies.getLength());
428 :
429 : css::uno::Reference< css::io::XInputStream> inputstream( css::io::SequenceInputStream::createStreamFromSequence(m_context, byteSeq),
430 0 : css::uno::UNO_QUERY_THROW);
431 :
432 0 : css::uno::Reference< css::xml::dom::XDocument > xDocument(docbuilder->parse(inputstream));
433 0 : css::uno::Reference< css::xml::dom::XElement > xElement(xDocument->getDocumentElement());
434 0 : css::uno::Reference< css::xml::dom::XNodeList > xDeps(xElement->getChildNodes());
435 0 : sal_Int32 nLen = xDeps->getLength();
436 :
437 : // get the parent xml document of current description info for the import
438 0 : css::uno::Reference< css::xml::dom::XDocument > xCurrentDescInfo(m_element->getOwnerDocument());
439 :
440 : // get dependency node of current description info to merge the new dependencies from the blacklist
441 : css::uno::Reference< css::xml::dom::XNode > xCurrentDeps(
442 0 : m_xpath->selectSingleNode(m_element, "desc:dependencies"));
443 :
444 : // if no dependency node exists, create a new one in the current description info
445 0 : if (!xCurrentDeps.is()) {
446 : css::uno::Reference< css::xml::dom::XNode > xNewDepNode(
447 0 : xCurrentDescInfo->createElementNS(
448 : "http://openoffice.org/extensions/description/2006",
449 0 : "dependencies"), css::uno::UNO_QUERY_THROW);
450 0 : m_element->appendChild(xNewDepNode);
451 0 : xCurrentDeps = m_xpath->selectSingleNode(m_element, "desc:dependencies");
452 : }
453 :
454 0 : for (sal_Int32 i=0; i<nLen; i++) {
455 0 : css::uno::Reference< css::xml::dom::XNode > xNode(xDeps->item(i));
456 0 : css::uno::Reference< css::xml::dom::XElement > xDep(xNode, css::uno::UNO_QUERY);
457 0 : if (xDep.is()) {
458 : // found valid blacklist dependency, import the node first and append it to the existing dependency node
459 0 : css::uno::Reference< css::xml::dom::XNode > importedNode = xCurrentDescInfo->importNode(xNode, true);
460 0 : xCurrentDeps->appendChild(importedNode);
461 : }
462 0 : }
463 0 : }
464 34 : }
465 : }
466 : }
467 :
468 0 : bool DescriptionInfoset::checkBlacklistVersion(
469 : OUString currentversion,
470 : ::com::sun::star::uno::Sequence< OUString > const & versions) const
471 : {
472 0 : sal_Int32 nLen = versions.getLength();
473 0 : for (sal_Int32 i=0; i<nLen; i++) {
474 0 : if (currentversion == versions[i])
475 0 : return true;
476 : }
477 :
478 0 : return false;
479 : }
480 :
481 70 : OUString DescriptionInfoset::getVersion() const
482 : {
483 70 : return getNodeValueFromExpression( "desc:version/@value" );
484 : }
485 :
486 34 : css::uno::Sequence< OUString > DescriptionInfoset::getSupportedPlaforms() const
487 : {
488 : //When there is no description.xml then we assume that we support all platforms
489 34 : if (! m_element.is())
490 : {
491 0 : return comphelper::makeSequence( OUString("all") );
492 : }
493 :
494 : //Check if the <platform> element was provided. If not the default is "all" platforms
495 : css::uno::Reference< css::xml::dom::XNode > nodePlatform(
496 34 : m_xpath->selectSingleNode(m_element, "desc:platform"));
497 34 : if (!nodePlatform.is())
498 : {
499 2 : return comphelper::makeSequence( OUString("all") );
500 : }
501 :
502 : //There is a platform element.
503 64 : const OUString value = getNodeValueFromExpression("desc:platform/@value");
504 : //parse the string, it can contained multiple strings separated by commas
505 64 : ::std::vector< OUString> vec;
506 32 : sal_Int32 nIndex = 0;
507 32 : do
508 : {
509 32 : OUString aToken = value.getToken( 0, ',', nIndex );
510 32 : aToken = aToken.trim();
511 32 : if (!aToken.isEmpty())
512 32 : vec.push_back(aToken);
513 :
514 : }
515 32 : while (nIndex >= 0);
516 :
517 66 : return comphelper::containerToSequence(vec);
518 : }
519 :
520 : css::uno::Reference< css::xml::dom::XNodeList >
521 34 : DescriptionInfoset::getDependencies() const {
522 34 : if (m_element.is()) {
523 : try {
524 : // check the extension blacklist first and expand the dependencies if applicable
525 34 : checkBlacklist();
526 :
527 34 : return m_xpath->selectNodeList(m_element, "desc:dependencies/*");
528 0 : } catch (const css::xml::xpath::XPathException &) {
529 : // ignore
530 : }
531 : }
532 0 : return new EmptyNodeList;
533 : }
534 :
535 : css::uno::Sequence< OUString >
536 0 : DescriptionInfoset::getUpdateInformationUrls() const {
537 0 : return getUrls("desc:update-information/desc:src/@xlink:href");
538 : }
539 :
540 : css::uno::Sequence< OUString >
541 0 : DescriptionInfoset::getUpdateDownloadUrls() const
542 : {
543 0 : return getUrls("desc:update-download/desc:src/@xlink:href");
544 : }
545 :
546 0 : OUString DescriptionInfoset::getIconURL( sal_Bool bHighContrast ) const
547 : {
548 0 : css::uno::Sequence< OUString > aStrList = getUrls( "desc:icon/desc:default/@xlink:href" );
549 0 : css::uno::Sequence< OUString > aStrListHC = getUrls( "desc:icon/desc:high-contrast/@xlink:href" );
550 :
551 0 : if ( bHighContrast && aStrListHC.hasElements() && !aStrListHC[0].isEmpty() )
552 0 : return aStrListHC[0];
553 :
554 0 : if ( aStrList.hasElements() && !aStrList[0].isEmpty() )
555 0 : return aStrList[0];
556 :
557 0 : return OUString();
558 : }
559 :
560 0 : ::boost::optional< OUString > DescriptionInfoset::getLocalizedUpdateWebsiteURL()
561 : const
562 : {
563 0 : bool bParentExists = false;
564 0 : const OUString sURL (getLocalizedHREFAttrFromChild("/desc:description/desc:update-website", &bParentExists ));
565 :
566 0 : if (!sURL.isEmpty())
567 0 : return ::boost::optional< OUString >(sURL);
568 : else
569 : return bParentExists ? ::boost::optional< OUString >(OUString()) :
570 0 : ::boost::optional< OUString >();
571 : }
572 :
573 141 : ::boost::optional< OUString > DescriptionInfoset::getOptionalValue(
574 : OUString const & expression) const
575 : {
576 141 : css::uno::Reference< css::xml::dom::XNode > n;
577 141 : if (m_element.is()) {
578 : try {
579 141 : n = m_xpath->selectSingleNode(m_element, expression);
580 0 : } catch (const css::xml::xpath::XPathException &) {
581 : // ignore
582 : }
583 : }
584 141 : return n.is()
585 : ? ::boost::optional< OUString >(getNodeValue(n))
586 141 : : ::boost::optional< OUString >();
587 : }
588 :
589 0 : css::uno::Sequence< OUString > DescriptionInfoset::getUrls(
590 : OUString const & expression) const
591 : {
592 0 : css::uno::Reference< css::xml::dom::XNodeList > ns;
593 0 : if (m_element.is()) {
594 : try {
595 0 : ns = m_xpath->selectNodeList(m_element, expression);
596 0 : } catch (const css::xml::xpath::XPathException &) {
597 : // ignore
598 : }
599 : }
600 0 : css::uno::Sequence< OUString > urls(ns.is() ? ns->getLength() : 0);
601 0 : for (::sal_Int32 i = 0; i < urls.getLength(); ++i) {
602 0 : urls[i] = getNodeValue(ns->item(i));
603 : }
604 0 : return urls;
605 : }
606 :
607 0 : ::std::pair< OUString, OUString > DescriptionInfoset::getLocalizedPublisherNameAndURL() const
608 : {
609 : css::uno::Reference< css::xml::dom::XNode > node =
610 0 : getLocalizedChild("desc:publisher");
611 :
612 0 : OUString sPublisherName;
613 0 : OUString sURL;
614 0 : if (node.is())
615 : {
616 0 : const OUString exp1("text()");
617 0 : css::uno::Reference< css::xml::dom::XNode > xPathName;
618 : try {
619 0 : xPathName = m_xpath->selectSingleNode(node, exp1);
620 0 : } catch (const css::xml::xpath::XPathException &) {
621 : // ignore
622 : }
623 : OSL_ASSERT(xPathName.is());
624 0 : if (xPathName.is())
625 0 : sPublisherName = xPathName->getNodeValue();
626 :
627 0 : const OUString exp2("@xlink:href");
628 0 : css::uno::Reference< css::xml::dom::XNode > xURL;
629 : try {
630 0 : xURL = m_xpath->selectSingleNode(node, exp2);
631 0 : } catch (const css::xml::xpath::XPathException &) {
632 : // ignore
633 : }
634 : OSL_ASSERT(xURL.is());
635 0 : if (xURL.is())
636 0 : sURL = xURL->getNodeValue();
637 : }
638 0 : return ::std::make_pair(sPublisherName, sURL);
639 : }
640 :
641 0 : OUString DescriptionInfoset::getLocalizedReleaseNotesURL() const
642 : {
643 0 : return getLocalizedHREFAttrFromChild("/desc:description/desc:release-notes", NULL);
644 : }
645 :
646 35 : OUString DescriptionInfoset::getLocalizedDisplayName() const
647 : {
648 : css::uno::Reference< css::xml::dom::XNode > node =
649 35 : getLocalizedChild("desc:display-name");
650 35 : if (node.is())
651 : {
652 32 : const OUString exp("text()");
653 32 : css::uno::Reference< css::xml::dom::XNode > xtext;
654 : try {
655 32 : xtext = m_xpath->selectSingleNode(node, exp);
656 0 : } catch (const css::xml::xpath::XPathException &) {
657 : // ignore
658 : }
659 32 : if (xtext.is())
660 32 : return xtext->getNodeValue();
661 : }
662 3 : return OUString();
663 : }
664 :
665 0 : OUString DescriptionInfoset::getLocalizedLicenseURL() const
666 : {
667 0 : return getLocalizedHREFAttrFromChild("/desc:description/desc:registration/desc:simple-license", NULL);
668 :
669 : }
670 :
671 : ::boost::optional<SimpleLicenseAttributes>
672 67 : DescriptionInfoset::getSimpleLicenseAttributes() const
673 : {
674 : //Check if the node exist
675 67 : css::uno::Reference< css::xml::dom::XNode > n;
676 67 : if (m_element.is()) {
677 : try {
678 67 : n = m_xpath->selectSingleNode(m_element, "/desc:description/desc:registration/desc:simple-license/@accept-by");
679 0 : } catch (const css::xml::xpath::XPathException &) {
680 : // ignore
681 : }
682 67 : if (n.is())
683 : {
684 0 : SimpleLicenseAttributes attributes;
685 0 : attributes.acceptBy =
686 0 : getNodeValueFromExpression("/desc:description/desc:registration/desc:simple-license/@accept-by");
687 :
688 0 : ::boost::optional< OUString > suppressOnUpdate = getOptionalValue("/desc:description/desc:registration/desc:simple-license/@suppress-on-update");
689 0 : if (suppressOnUpdate)
690 0 : attributes.suppressOnUpdate = (*suppressOnUpdate).trim().equalsIgnoreAsciiCase("true");
691 : else
692 0 : attributes.suppressOnUpdate = false;
693 :
694 0 : ::boost::optional< OUString > suppressIfRequired = getOptionalValue("/desc:description/desc:registration/desc:simple-license/@suppress-if-required");
695 0 : if (suppressIfRequired)
696 0 : attributes.suppressIfRequired = (*suppressIfRequired).trim().equalsIgnoreAsciiCase("true");
697 : else
698 0 : attributes.suppressIfRequired = false;
699 :
700 0 : return ::boost::optional<SimpleLicenseAttributes>(attributes);
701 : }
702 : }
703 67 : return ::boost::optional<SimpleLicenseAttributes>();
704 : }
705 :
706 0 : OUString DescriptionInfoset::getLocalizedDescriptionURL() const
707 : {
708 0 : return getLocalizedHREFAttrFromChild("/desc:description/desc:extension-description", NULL);
709 : }
710 :
711 : css::uno::Reference< css::xml::dom::XNode >
712 35 : DescriptionInfoset::getLocalizedChild( const OUString & sParent) const
713 : {
714 35 : if ( ! m_element.is() || sParent.isEmpty())
715 0 : return css::uno::Reference< css::xml::dom::XNode > ();
716 :
717 35 : css::uno::Reference< css::xml::dom::XNode > xParent;
718 : try {
719 35 : xParent = m_xpath->selectSingleNode(m_element, sParent);
720 0 : } catch (const css::xml::xpath::XPathException &) {
721 : // ignore
722 : }
723 70 : css::uno::Reference<css::xml::dom::XNode> nodeMatch;
724 35 : if (xParent.is())
725 : {
726 32 : nodeMatch = matchLanguageTag(xParent, getOfficeLanguageTag().getBcp47());
727 :
728 : //office: en-DE, en, en-DE-altmark
729 32 : if (! nodeMatch.is())
730 : {
731 0 : const ::std::vector< OUString > aFallbacks = getOfficeLanguageTag().getFallbackStrings();
732 : // Already tried full tag, continue with first fallback.
733 0 : ::std::vector< OUString >::const_iterator it( aFallbacks.begin());
734 0 : if (it != aFallbacks.end())
735 0 : ++it;
736 0 : for ( ; it != aFallbacks.end(); ++it)
737 : {
738 0 : nodeMatch = matchLanguageTag(xParent, *it);
739 0 : if (nodeMatch.is())
740 0 : break;
741 : }
742 0 : if (! nodeMatch.is())
743 0 : nodeMatch = getChildWithDefaultLocale(xParent);
744 : }
745 : }
746 :
747 70 : return nodeMatch;
748 : }
749 :
750 : css::uno::Reference<css::xml::dom::XNode>
751 32 : DescriptionInfoset::matchLanguageTag(
752 : css::uno::Reference< css::xml::dom::XNode > const & xParent, OUString const & rTag) const
753 : {
754 : OSL_ASSERT(xParent.is());
755 32 : css::uno::Reference<css::xml::dom::XNode> nodeMatch;
756 :
757 : //first try exact match for lang
758 64 : const OUString exp1("*[@lang=\"" + rTag + "\"]");
759 : try {
760 32 : nodeMatch = m_xpath->selectSingleNode(xParent, exp1);
761 0 : } catch (const css::xml::xpath::XPathException &) {
762 : // ignore
763 : }
764 :
765 : //try to match in strings that also have a country and/or variant, for
766 : //example en matches in en-US-montana, en-US, en-montana
767 32 : if (!nodeMatch.is())
768 : {
769 : const OUString exp2(
770 0 : "*[starts-with(@lang,\"" + rTag + "-\")]");
771 : try {
772 0 : nodeMatch = m_xpath->selectSingleNode(xParent, exp2);
773 0 : } catch (const css::xml::xpath::XPathException &) {
774 : // ignore
775 0 : }
776 : }
777 64 : return nodeMatch;
778 : }
779 :
780 : css::uno::Reference<css::xml::dom::XNode>
781 0 : DescriptionInfoset::getChildWithDefaultLocale(css::uno::Reference< css::xml::dom::XNode >
782 : const & xParent) const
783 : {
784 : OSL_ASSERT(xParent.is());
785 0 : if ( xParent->getNodeName() == "simple-license" )
786 : {
787 0 : css::uno::Reference<css::xml::dom::XNode> nodeDefault;
788 : try {
789 0 : nodeDefault = m_xpath->selectSingleNode(xParent, "@default-license-id");
790 0 : } catch (const css::xml::xpath::XPathException &) {
791 : // ignore
792 : }
793 0 : if (nodeDefault.is())
794 : {
795 : //The old way
796 : const OUString exp1("desc:license-text[@license-id = \""
797 0 : + nodeDefault->getNodeValue()
798 0 : + "\"]");
799 : try {
800 0 : return m_xpath->selectSingleNode(xParent, exp1);
801 0 : } catch (const css::xml::xpath::XPathException &) {
802 : // ignore
803 0 : }
804 0 : }
805 : }
806 :
807 0 : const OUString exp2("*[1]");
808 : try {
809 0 : return m_xpath->selectSingleNode(xParent, exp2);
810 0 : } catch (const css::xml::xpath::XPathException &) {
811 : // ignore
812 0 : return 0;
813 0 : }
814 : }
815 :
816 0 : OUString DescriptionInfoset::getLocalizedHREFAttrFromChild(
817 : OUString const & sXPathParent, bool * out_bParentExists)
818 : const
819 : {
820 : css::uno::Reference< css::xml::dom::XNode > node =
821 0 : getLocalizedChild(sXPathParent);
822 :
823 0 : OUString sURL;
824 0 : if (node.is())
825 : {
826 0 : if (out_bParentExists)
827 0 : *out_bParentExists = true;
828 0 : const OUString exp("@xlink:href");
829 0 : css::uno::Reference< css::xml::dom::XNode > xURL;
830 : try {
831 0 : xURL = m_xpath->selectSingleNode(node, exp);
832 0 : } catch (const css::xml::xpath::XPathException &) {
833 : // ignore
834 : }
835 : OSL_ASSERT(xURL.is());
836 0 : if (xURL.is())
837 0 : sURL = xURL->getNodeValue();
838 : }
839 : else
840 : {
841 0 : if (out_bParentExists)
842 0 : *out_bParentExists = false;
843 : }
844 0 : return sURL;
845 : }
846 :
847 : }
848 :
849 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|