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