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