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