1 /*************************************************************************
2  *
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * Copyright 2000, 2010 Oracle and/or its affiliates.
6  *
7  * OpenOffice.org - a multi-platform office productivity suite
8  *
9  * This file is part of OpenOffice.org.
10  *
11  * OpenOffice.org is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU Lesser General Public License version 3
13  * only, as published by the Free Software Foundation.
14  *
15  * OpenOffice.org is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU Lesser General Public License version 3 for more details
19  * (a copy is included in the LICENSE file that accompanied this code).
20  *
21  * You should have received a copy of the GNU Lesser General Public License
22  * version 3 along with OpenOffice.org.  If not, see
23  * <http://www.openoffice.org/license.html>
24  * for a copy of the LGPLv3 License.
25  *
26  ************************************************************************/
27 
28 // MARKER(update_precomp.py): autogen include statement, do not remove
29 #include "precompiled_desktop.hxx"
30 
31 #include "dp_descriptioninfoset.hxx"
32 
33 #include "dp_resource.h"
34 #include "sal/config.h"
35 
36 #include "comphelper/sequence.hxx"
37 #include "comphelper/makesequence.hxx"
38 #include "comphelper/processfactory.hxx"
39 #include "boost/optional.hpp"
40 #include "com/sun/star/beans/Optional.hpp"
41 #include "com/sun/star/lang/XMultiComponentFactory.hpp"
42 #include "com/sun/star/lang/Locale.hpp"
43 #include "com/sun/star/uno/Reference.hxx"
44 #include "com/sun/star/uno/RuntimeException.hpp"
45 #include "com/sun/star/uno/Sequence.hxx"
46 #include "com/sun/star/uno/XComponentContext.hpp"
47 #include "com/sun/star/uno/XInterface.hpp"
48 #include "com/sun/star/xml/dom/DOMException.hpp"
49 #include "com/sun/star/xml/dom/XNode.hpp"
50 #include "com/sun/star/xml/dom/XNodeList.hpp"
51 #include "com/sun/star/xml/dom/XDocumentBuilder.hpp"
52 #include "com/sun/star/xml/xpath/XXPathAPI.hpp"
53 #include "com/sun/star/ucb/InteractiveAugmentedIOException.hpp"
54 #include "cppuhelper/implbase1.hxx"
55 #include "cppuhelper/implbase2.hxx"
56 #include "cppuhelper/weak.hxx"
57 #include "cppuhelper/exc_hlp.hxx"
58 #include "rtl/ustring.h"
59 #include "rtl/ustring.hxx"
60 #include "sal/types.h"
61 #include "ucbhelper/content.hxx"
62 
63 namespace {
64 
65 namespace css = ::com::sun::star;
66 using css::uno::Reference;
67 using ::rtl::OUString;
68 
69 class EmptyNodeList: public ::cppu::WeakImplHelper1< css::xml::dom::XNodeList >
70 {
71 public:
72     EmptyNodeList();
73 
74     virtual ~EmptyNodeList();
75 
76     virtual ::sal_Int32 SAL_CALL getLength() throw (css::uno::RuntimeException);
77 
78     virtual css::uno::Reference< css::xml::dom::XNode > SAL_CALL
79     item(::sal_Int32 index) throw (css::uno::RuntimeException);
80 
81 private:
82     EmptyNodeList(EmptyNodeList &); // not defined
83     void operator =(EmptyNodeList &); // not defined
84 };
85 
86 EmptyNodeList::EmptyNodeList() {}
87 
88 EmptyNodeList::~EmptyNodeList() {}
89 
90 ::sal_Int32 EmptyNodeList::getLength() throw (css::uno::RuntimeException) {
91     return 0;
92 }
93 
94 css::uno::Reference< css::xml::dom::XNode > EmptyNodeList::item(::sal_Int32)
95     throw (css::uno::RuntimeException)
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 
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 occured. Therefore it shoult 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 
144 	css::uno::Reference<css::xml::dom::XNode> getRootElement() const
145 	{
146 		return m_xRoot;
147 	}
148 
149 	::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() throw (css::uno::RuntimeException);
182     virtual css::uno::Reference<css::ucb::XProgressHandler >
183     SAL_CALL getProgressHandler() throw (css::uno::RuntimeException);
184 
185     // XInteractionHandler
186     virtual void SAL_CALL handle(
187         css::uno::Reference<css::task::XInteractionRequest > const & xRequest )
188         throw (css::uno::RuntimeException);
189 };
190 
191 ExtensionDescription::ExtensionDescription(
192     const Reference<css::uno::XComponentContext>& xContext,
193     const OUString& installDir,
194     const Reference< css::ucb::XCommandEnvironment >& xCmdEnv)
195 {
196     try {
197         m_sExtensionRootUrl = installDir;
198         //may throw ::com::sun::star::ucb::ContentCreationException
199         //If there is no description.xml then ucb will start an interaction which
200         //brings up a dialog.We want to prevent this. Therefore we wrap the xCmdEnv
201         //and filter the respective exception out.
202         OUString sDescriptionUri(installDir + OUSTR("/description.xml"));
203         Reference<css::ucb::XCommandEnvironment> xFilter =
204             static_cast<css::ucb::XCommandEnvironment*>(
205                 new FileDoesNotExistFilter(xCmdEnv));
206         ::ucbhelper::Content descContent(sDescriptionUri, xFilter);
207 
208         //throws an com::sun::star::uno::Exception if the file is not available
209         Reference<css::io::XInputStream> xIn;
210         try
211         {	//throws com.sun.star.ucb.InteractiveAugmentedIOException
212             xIn = descContent.openStream();
213         }
214         catch (css::uno::Exception& )
215         {
216             if ( ! static_cast<FileDoesNotExistFilter*>(xFilter.get())->exist())
217                 throw NoDescriptionException();
218             throw;
219         }
220         if (!xIn.is())
221         {
222             throw css::uno::Exception(
223                 OUSTR("Could not get XInputStream for description.xml of extension ") +
224                 sDescriptionUri, 0);
225         }
226 
227         //get root node of description.xml
228         Reference<css::xml::dom::XDocumentBuilder> xDocBuilder(
229             xContext->getServiceManager()->createInstanceWithContext(
230                 OUSTR("com.sun.star.xml.dom.DocumentBuilder"),
231                 xContext ), css::uno::UNO_QUERY);
232         if (!xDocBuilder.is())
233             throw css::uno::Exception(OUSTR(" Could not create service com.sun.star.xml.dom.DocumentBuilder"), 0);
234 
235         if (xDocBuilder->isNamespaceAware() == sal_False)
236         {
237             throw css::uno::Exception(
238                 OUSTR("Service com.sun.star.xml.dom.DocumentBuilder is not namespace aware."), 0);
239         }
240 
241         Reference<css::xml::dom::XDocument> xDoc = xDocBuilder->parse(xIn);
242         if (!xDoc.is())
243         {
244             throw css::uno::Exception(sDescriptionUri + OUSTR(" contains data which cannot be parsed. "), 0);
245         }
246 
247         //check for proper root element and namespace
248         Reference<css::xml::dom::XElement> xRoot = xDoc->getDocumentElement();
249         if (!xRoot.is())
250         {
251             throw css::uno::Exception(
252                 sDescriptionUri + OUSTR(" contains no root element."), 0);
253         }
254 
255         if ( ! xRoot->getTagName().equals(OUSTR("description")))
256         {
257             throw css::uno::Exception(
258                 sDescriptionUri + OUSTR(" does not contain the root element <description>."), 0);
259         }
260 
261         m_xRoot = Reference<css::xml::dom::XNode>(
262             xRoot, css::uno::UNO_QUERY_THROW);
263         OUString nsDescription = xRoot->getNamespaceURI();
264 
265         //check if this namespace is supported
266         if ( ! nsDescription.equals(OUSTR("http://openoffice.org/extensions/description/2006")))
267         {
268             throw css::uno::Exception(sDescriptionUri + OUSTR(" contains a root element with an unsupported namespace. "), 0);
269         }
270     } catch (css::uno::RuntimeException &) {
271         throw;
272     } catch (css::deployment::DeploymentException &) {
273         throw;
274     } catch (css::uno::Exception & e) {
275         css::uno::Any a(cppu::getCaughtException());
276         throw css::deployment::DeploymentException(
277 			e.Message, Reference< css::uno::XInterface >(), a);
278     }
279 }
280 
281 ExtensionDescription::~ExtensionDescription()
282 {
283 }
284 
285 //======================================================================
286 FileDoesNotExistFilter::FileDoesNotExistFilter(
287 	const Reference< css::ucb::XCommandEnvironment >& xCmdEnv):
288 	m_bExist(true), m_xCommandEnv(xCmdEnv)
289 {}
290 
291 FileDoesNotExistFilter::~FileDoesNotExistFilter()
292 {
293 };
294 
295 bool FileDoesNotExistFilter::exist()
296 {
297 	return m_bExist;
298 }
299     // XCommandEnvironment
300 Reference<css::task::XInteractionHandler >
301     FileDoesNotExistFilter::getInteractionHandler() throw (css::uno::RuntimeException)
302 {
303 	return static_cast<css::task::XInteractionHandler*>(this);
304 }
305 
306 Reference<css::ucb::XProgressHandler >
307     FileDoesNotExistFilter::getProgressHandler() throw (css::uno::RuntimeException)
308 {
309 	return m_xCommandEnv.is()
310         ? m_xCommandEnv->getProgressHandler()
311         : Reference<css::ucb::XProgressHandler>();
312 }
313 
314 // XInteractionHandler
315 //If the interaction was caused by a non-existing file which is specified in the ctor
316 //of FileDoesNotExistFilter, then we do nothing
317 void  FileDoesNotExistFilter::handle(
318         Reference<css::task::XInteractionRequest > const & xRequest )
319         throw (css::uno::RuntimeException)
320 {
321 	css::uno::Any request( xRequest->getRequest() );
322 
323 	css::ucb::InteractiveAugmentedIOException ioexc;
324 	if ((request>>= ioexc) && ioexc.Code == css::ucb::IOErrorCode_NOT_EXISTING )
325 	{
326 		m_bExist = false;
327 		return;
328 	}
329 	Reference<css::task::XInteractionHandler> xInteraction;
330     if (m_xCommandEnv.is()) {
331         xInteraction = m_xCommandEnv->getInteractionHandler();
332     }
333     if (xInteraction.is()) {
334         xInteraction->handle(xRequest);
335     }
336 }
337 
338 }
339 
340 namespace dp_misc {
341 
342 DescriptionInfoset getDescriptionInfoset(OUString const & sExtensionFolderURL)
343 {
344     Reference< css::xml::dom::XNode > root;
345     Reference<css::uno::XComponentContext> context =
346         comphelper_getProcessComponentContext();
347     OSL_ASSERT(context.is());
348     try {
349         root =
350             ExtensionDescription(
351                 context, sExtensionFolderURL,
352                 Reference< css::ucb::XCommandEnvironment >()).
353             getRootElement();
354     } catch (NoDescriptionException &) {
355     } catch (css::deployment::DeploymentException & e) {
356         throw css::uno::RuntimeException(
357             (OUString(
358                 RTL_CONSTASCII_USTRINGPARAM(
359                     "com.sun.star.deployment.DeploymentException: ")) +
360              e.Message), 0);
361     }
362     return DescriptionInfoset(context, root);
363 }
364 
365 DescriptionInfoset::DescriptionInfoset(
366     css::uno::Reference< css::uno::XComponentContext > const & context,
367     css::uno::Reference< css::xml::dom::XNode > const & element):
368     m_element(element)
369 {
370     css::uno::Reference< css::lang::XMultiComponentFactory > manager(
371         context->getServiceManager(), css::uno::UNO_QUERY_THROW);
372     if (m_element.is()) {
373         m_xpath = css::uno::Reference< css::xml::xpath::XXPathAPI >(
374             manager->createInstanceWithContext(
375                 ::rtl::OUString(
376                     RTL_CONSTASCII_USTRINGPARAM(
377                         "com.sun.star.xml.xpath.XPathAPI")),
378                 context),
379             css::uno::UNO_QUERY_THROW);
380         m_xpath->registerNS(
381             ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("desc")),
382             element->getNamespaceURI());
383         m_xpath->registerNS(
384             ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("xlink")),
385             ::rtl::OUString(
386                 RTL_CONSTASCII_USTRINGPARAM("http://www.w3.org/1999/xlink")));
387     }
388 }
389 
390 DescriptionInfoset::~DescriptionInfoset() {}
391 
392 ::boost::optional< ::rtl::OUString > DescriptionInfoset::getIdentifier() const {
393     return getOptionalValue(
394         ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("desc:identifier/@value")));
395 }
396 
397 ::rtl::OUString DescriptionInfoset::getNodeValueFromExpression(::rtl::OUString const & expression) const
398 {
399     css::uno::Reference< css::xml::dom::XNode > n;
400     if (m_element.is()) {
401         try {
402             n = m_xpath->selectSingleNode(m_element, expression);
403         } catch (css::xml::xpath::XPathException &) {
404             // ignore
405         }
406     }
407     return n.is() ? getNodeValue(n) : ::rtl::OUString();
408 }
409 
410 
411 ::rtl::OUString DescriptionInfoset::getVersion() const
412 {
413     return getNodeValueFromExpression( ::rtl::OUString(
414             RTL_CONSTASCII_USTRINGPARAM("desc:version/@value")));
415 }
416 
417 css::uno::Sequence< ::rtl::OUString > DescriptionInfoset::getSupportedPlaforms() const
418 {
419     //When there is no description.xml then we assume that we support all platforms
420     if (! m_element.is())
421     {
422         return comphelper::makeSequence(
423             ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("all")));
424     }
425 
426     //Check if the <platform> element was provided. If not the default is "all" platforms
427     css::uno::Reference< css::xml::dom::XNode > nodePlatform(
428         m_xpath->selectSingleNode(m_element, ::rtl::OUString(
429             RTL_CONSTASCII_USTRINGPARAM("desc:platform"))));
430     if (!nodePlatform.is())
431     {
432         return comphelper::makeSequence(
433             ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("all")));
434     }
435 
436     //There is a platform element.
437     const ::rtl::OUString value = getNodeValueFromExpression(::rtl::OUString(
438             RTL_CONSTASCII_USTRINGPARAM("desc:platform/@value")));
439     //parse the string, it can contained multiple strings separated by commas
440     ::std::vector< ::rtl::OUString> vec;
441     sal_Int32 nIndex = 0;
442     do
443     {
444         ::rtl::OUString aToken = value.getToken( 0, ',', nIndex );
445         aToken = aToken.trim();
446         if (aToken.getLength())
447             vec.push_back(aToken);
448 
449     }
450     while (nIndex >= 0);
451 
452     return comphelper::containerToSequence(vec);
453 }
454 
455 css::uno::Reference< css::xml::dom::XNodeList >
456 DescriptionInfoset::getDependencies() const {
457     if (m_element.is()) {
458         try {
459             return m_xpath->selectNodeList(m_element, ::rtl::OUString(
460                         RTL_CONSTASCII_USTRINGPARAM("desc:dependencies/*")));
461         } catch (css::xml::xpath::XPathException &) {
462             // ignore
463         }
464     }
465     return new EmptyNodeList;
466 }
467 
468 css::uno::Sequence< ::rtl::OUString >
469 DescriptionInfoset::getUpdateInformationUrls() const {
470     return getUrls(
471         ::rtl::OUString(
472             RTL_CONSTASCII_USTRINGPARAM(
473                 "desc:update-information/desc:src/@xlink:href")));
474 }
475 
476 css::uno::Sequence< ::rtl::OUString >
477 DescriptionInfoset::getUpdateDownloadUrls() const
478 {
479     return getUrls(
480         ::rtl::OUString(
481             RTL_CONSTASCII_USTRINGPARAM(
482                 "desc:update-download/desc:src/@xlink:href")));
483 }
484 
485 ::rtl::OUString DescriptionInfoset::getIconURL( sal_Bool bHighContrast ) const
486 {
487     css::uno::Sequence< ::rtl::OUString > aStrList = getUrls( ::rtl::OUString(
488             RTL_CONSTASCII_USTRINGPARAM( "desc:icon/desc:default/@xlink:href")));
489     css::uno::Sequence< ::rtl::OUString > aStrListHC = getUrls( ::rtl::OUString(
490             RTL_CONSTASCII_USTRINGPARAM( "desc:icon/desc:high-contrast/@xlink:href")));
491 
492     if ( bHighContrast && aStrListHC.hasElements() && aStrListHC[0].getLength() )
493         return aStrListHC[0];
494 
495     if ( aStrList.hasElements() && aStrList[0].getLength() )
496         return aStrList[0];
497 
498     return ::rtl::OUString();
499 }
500 
501 ::boost::optional< ::rtl::OUString > DescriptionInfoset::getLocalizedUpdateWebsiteURL()
502     const
503 {
504     bool bParentExists = false;
505     const ::rtl::OUString sURL (getLocalizedHREFAttrFromChild(::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(
506         "/desc:description/desc:update-website")), &bParentExists ));
507 
508     if (sURL.getLength() > 0)
509         return ::boost::optional< ::rtl::OUString >(sURL);
510     else
511         return bParentExists ? ::boost::optional< ::rtl::OUString >(::rtl::OUString()) :
512             ::boost::optional< ::rtl::OUString >();
513 }
514 
515 ::boost::optional< ::rtl::OUString > DescriptionInfoset::getOptionalValue(
516     ::rtl::OUString const & expression) const
517 {
518     css::uno::Reference< css::xml::dom::XNode > n;
519     if (m_element.is()) {
520         try {
521             n = m_xpath->selectSingleNode(m_element, expression);
522         } catch (css::xml::xpath::XPathException &) {
523             // ignore
524         }
525     }
526     return n.is()
527         ? ::boost::optional< ::rtl::OUString >(getNodeValue(n))
528         : ::boost::optional< ::rtl::OUString >();
529 }
530 
531 css::uno::Sequence< ::rtl::OUString > DescriptionInfoset::getUrls(
532     ::rtl::OUString const & expression) const
533 {
534     css::uno::Reference< css::xml::dom::XNodeList > ns;
535     if (m_element.is()) {
536         try {
537             ns = m_xpath->selectNodeList(m_element, expression);
538         } catch (css::xml::xpath::XPathException &) {
539             // ignore
540         }
541     }
542     css::uno::Sequence< ::rtl::OUString > urls(ns.is() ? ns->getLength() : 0);
543     for (::sal_Int32 i = 0; i < urls.getLength(); ++i) {
544         urls[i] = getNodeValue(ns->item(i));
545     }
546     return urls;
547 }
548 
549 ::std::pair< ::rtl::OUString, ::rtl::OUString > DescriptionInfoset::getLocalizedPublisherNameAndURL() const
550 {
551     css::uno::Reference< css::xml::dom::XNode > node =
552         getLocalizedChild(::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("desc:publisher")));
553 
554     ::rtl::OUString sPublisherName;
555     ::rtl::OUString sURL;
556     if (node.is())
557     {
558         const ::rtl::OUString exp1(RTL_CONSTASCII_USTRINGPARAM("text()"));
559         css::uno::Reference< css::xml::dom::XNode > xPathName;
560         try {
561             xPathName = m_xpath->selectSingleNode(node, exp1);
562         } catch (css::xml::xpath::XPathException &) {
563             // ignore
564         }
565         OSL_ASSERT(xPathName.is());
566         if (xPathName.is())
567             sPublisherName = xPathName->getNodeValue();
568 
569         const ::rtl::OUString exp2(RTL_CONSTASCII_USTRINGPARAM("@xlink:href"));
570         css::uno::Reference< css::xml::dom::XNode > xURL;
571         try {
572             xURL = m_xpath->selectSingleNode(node, exp2);
573         } catch (css::xml::xpath::XPathException &) {
574             // ignore
575         }
576         OSL_ASSERT(xURL.is());
577         if (xURL.is())
578            sURL = xURL->getNodeValue();
579     }
580     return ::std::make_pair(sPublisherName, sURL);
581 }
582 
583 ::rtl::OUString DescriptionInfoset::getLocalizedReleaseNotesURL() const
584 {
585     return getLocalizedHREFAttrFromChild(::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(
586         "/desc:description/desc:release-notes")), NULL);
587 }
588 
589 ::rtl::OUString DescriptionInfoset::getLocalizedDisplayName() const
590 {
591     css::uno::Reference< css::xml::dom::XNode > node =
592         getLocalizedChild(::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("desc:display-name")));
593     if (node.is())
594     {
595         const ::rtl::OUString exp(RTL_CONSTASCII_USTRINGPARAM("text()"));
596         css::uno::Reference< css::xml::dom::XNode > xtext;
597         try {
598             xtext = m_xpath->selectSingleNode(node, exp);
599         } catch (css::xml::xpath::XPathException &) {
600             // ignore
601         }
602         if (xtext.is())
603             return xtext->getNodeValue();
604     }
605     return ::rtl::OUString();
606 }
607 
608 ::rtl::OUString DescriptionInfoset::getLocalizedLicenseURL() const
609 {
610     return getLocalizedHREFAttrFromChild(::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(
611         "/desc:description/desc:registration/desc:simple-license")), NULL);
612 
613 }
614 
615 ::boost::optional<SimpleLicenseAttributes>
616 DescriptionInfoset::getSimpleLicenseAttributes() const
617 {
618     //Check if the node exist
619     css::uno::Reference< css::xml::dom::XNode > n;
620     if (m_element.is()) {
621         try {
622             n = m_xpath->selectSingleNode(m_element,
623                 ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(
624                 "/desc:description/desc:registration/desc:simple-license/@accept-by")));
625         } catch (css::xml::xpath::XPathException &) {
626             // ignore
627         }
628         if (n.is())
629         {
630             SimpleLicenseAttributes attributes;
631             attributes.acceptBy =
632                 getNodeValueFromExpression(::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(
633                 "/desc:description/desc:registration/desc:simple-license/@accept-by")));
634 
635             ::boost::optional< ::rtl::OUString > suppressOnUpdate = getOptionalValue(
636                 ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(
637                 "/desc:description/desc:registration/desc:simple-license/@suppress-on-update")));
638             if (suppressOnUpdate)
639                 attributes.suppressOnUpdate = (*suppressOnUpdate).trim().equalsIgnoreAsciiCase(
640                 ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("true")));
641             else
642                 attributes.suppressOnUpdate = false;
643 
644             ::boost::optional< ::rtl::OUString > suppressIfRequired = getOptionalValue(
645                 ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(
646                 "/desc:description/desc:registration/desc:simple-license/@suppress-if-required")));
647             if (suppressIfRequired)
648                 attributes.suppressIfRequired = (*suppressIfRequired).trim().equalsIgnoreAsciiCase(
649                 ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("true")));
650             else
651                 attributes.suppressIfRequired = false;
652 
653             return ::boost::optional<SimpleLicenseAttributes>(attributes);
654         }
655     }
656     return ::boost::optional<SimpleLicenseAttributes>();
657 }
658 
659 ::rtl::OUString DescriptionInfoset::getLocalizedDescriptionURL() const
660 {
661     return getLocalizedHREFAttrFromChild(::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(
662         "/desc:description/desc:extension-description")), NULL);
663 }
664 
665 css::uno::Reference< css::xml::dom::XNode >
666 DescriptionInfoset::getLocalizedChild( const ::rtl::OUString & sParent) const
667 {
668     if ( ! m_element.is() || !sParent.getLength())
669         return css::uno::Reference< css::xml::dom::XNode > ();
670 
671     css::uno::Reference< css::xml::dom::XNode > xParent;
672     try {
673         xParent = m_xpath->selectSingleNode(m_element, sParent);
674     } catch (css::xml::xpath::XPathException &) {
675         // ignore
676     }
677     css::uno::Reference<css::xml::dom::XNode> nodeMatch;
678     if (xParent.is())
679     {
680         const ::rtl::OUString sLocale = getOfficeLocaleString();
681         nodeMatch = matchFullLocale(xParent, sLocale);
682 
683         //office: en-DE, en, en-DE-altmark
684         if (! nodeMatch.is())
685         {
686             const css::lang::Locale officeLocale = getOfficeLocale();
687             nodeMatch = matchCountryAndLanguage(xParent, officeLocale);
688             if ( ! nodeMatch.is())
689             {
690                 nodeMatch = matchLanguage(xParent, officeLocale);
691                 if (! nodeMatch.is())
692                     nodeMatch = getChildWithDefaultLocale(xParent);
693             }
694         }
695     }
696 
697     return nodeMatch;
698 }
699 
700 css::uno::Reference<css::xml::dom::XNode>
701 DescriptionInfoset::matchFullLocale(css::uno::Reference< css::xml::dom::XNode >
702                                     const & xParent, ::rtl::OUString const & sLocale) const
703 {
704     OSL_ASSERT(xParent.is());
705     const ::rtl::OUString exp1(
706         ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("*[@lang=\""))
707         + sLocale +
708         ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("\"]")));
709     try {
710         return m_xpath->selectSingleNode(xParent, exp1);
711     } catch (css::xml::xpath::XPathException &) {
712         // ignore
713         return 0;
714     }
715 }
716 
717 css::uno::Reference<css::xml::dom::XNode>
718 DescriptionInfoset::matchCountryAndLanguage(
719     css::uno::Reference< css::xml::dom::XNode > const & xParent, css::lang::Locale const & officeLocale) const
720 {
721     OSL_ASSERT(xParent.is());
722     css::uno::Reference<css::xml::dom::XNode> nodeMatch;
723 
724     if (officeLocale.Country.getLength())
725     {
726         const ::rtl::OUString sLangCountry(officeLocale.Language +
727             ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("-")) +
728             officeLocale.Country);
729         //first try exact match for lang-country
730         const ::rtl::OUString exp1(
731             ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("*[@lang=\""))
732             + sLangCountry +
733             ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("\"]")));
734         try {
735             nodeMatch = m_xpath->selectSingleNode(xParent, exp1);
736         } catch (css::xml::xpath::XPathException &) {
737             // ignore
738         }
739 
740         //try to match in strings that also have a variant, for example en-US matches in
741         //en-US-montana
742         if (!nodeMatch.is())
743         {
744             const ::rtl::OUString exp2(
745                 ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("*[starts-with(@lang,\""))
746                 + sLangCountry +
747                 ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("-\")]")));
748             try {
749                 nodeMatch = m_xpath->selectSingleNode(xParent, exp2);
750             } catch (css::xml::xpath::XPathException &) {
751                 // ignore
752             }
753         }
754     }
755 
756     return nodeMatch;
757 }
758 
759 
760 css::uno::Reference<css::xml::dom::XNode>
761 DescriptionInfoset::matchLanguage(
762     css::uno::Reference< css::xml::dom::XNode > const & xParent, css::lang::Locale const & officeLocale) const
763 {
764     OSL_ASSERT(xParent.is());
765     css::uno::Reference<css::xml::dom::XNode> nodeMatch;
766 
767     //first try exact match for lang
768     const ::rtl::OUString exp1(
769         ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("*[@lang=\""))
770         + officeLocale.Language
771         + ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("\"]")));
772     try {
773         nodeMatch = m_xpath->selectSingleNode(xParent, exp1);
774     } catch (css::xml::xpath::XPathException &) {
775         // ignore
776     }
777 
778     //try to match in strings that also have a country and/orvariant, for example en  matches in
779     //en-US-montana, en-US, en-montana
780     if (!nodeMatch.is())
781     {
782         const ::rtl::OUString exp2(
783             ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("*[starts-with(@lang,\""))
784             + officeLocale.Language
785             + ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("-\")]")));
786         try {
787             nodeMatch = m_xpath->selectSingleNode(xParent, exp2);
788         } catch (css::xml::xpath::XPathException &) {
789             // ignore
790         }
791     }
792     return nodeMatch;
793 }
794 
795 css::uno::Reference<css::xml::dom::XNode>
796 DescriptionInfoset::getChildWithDefaultLocale(css::uno::Reference< css::xml::dom::XNode >
797                                     const & xParent) const
798 {
799     OSL_ASSERT(xParent.is());
800     if (xParent->getNodeName().equals(::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("simple-license"))))
801     {
802         css::uno::Reference<css::xml::dom::XNode> nodeDefault;
803         try {
804             nodeDefault = m_xpath->selectSingleNode(xParent, ::rtl::OUString(
805                 RTL_CONSTASCII_USTRINGPARAM("@default-license-id")));
806         } catch (css::xml::xpath::XPathException &) {
807             // ignore
808         }
809         if (nodeDefault.is())
810         {
811             //The old way
812             const ::rtl::OUString exp1(
813                 ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("desc:license-text[@license-id = \""))
814                 + nodeDefault->getNodeValue()
815                 + ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("\"]")));
816             try {
817                 return m_xpath->selectSingleNode(xParent, exp1);
818             } catch (css::xml::xpath::XPathException &) {
819                 // ignore
820             }
821         }
822     }
823 
824     const ::rtl::OUString exp2(RTL_CONSTASCII_USTRINGPARAM("*[1]"));
825     try {
826         return m_xpath->selectSingleNode(xParent, exp2);
827     } catch (css::xml::xpath::XPathException &) {
828         // ignore
829         return 0;
830     }
831 }
832 
833 ::rtl::OUString DescriptionInfoset::getLocalizedHREFAttrFromChild(
834     ::rtl::OUString const & sXPathParent, bool * out_bParentExists)
835     const
836 {
837     css::uno::Reference< css::xml::dom::XNode > node =
838         getLocalizedChild(sXPathParent);
839 
840     ::rtl::OUString sURL;
841     if (node.is())
842     {
843         if (out_bParentExists)
844             *out_bParentExists = true;
845         const ::rtl::OUString exp(RTL_CONSTASCII_USTRINGPARAM("@xlink:href"));
846         css::uno::Reference< css::xml::dom::XNode > xURL;
847         try {
848             xURL = m_xpath->selectSingleNode(node, exp);
849         } catch (css::xml::xpath::XPathException &) {
850             // ignore
851         }
852         OSL_ASSERT(xURL.is());
853         if (xURL.is())
854             sURL = xURL->getNodeValue();
855     }
856     else
857     {
858         if (out_bParentExists)
859             *out_bParentExists = false;
860     }
861     return sURL;
862 }
863 
864 }
865