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