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