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 the parent xml document of current description info for the import 483 css::uno::Reference< css::xml::dom::XDocument > xCurrentDescInfo(m_element->getOwnerDocument()); 484 485 // get dependency node of current description info to merge the new dependencies from the blacklist 486 css::uno::Reference< css::xml::dom::XNode > xCurrentDeps( 487 m_xpath->selectSingleNode(m_element, ::rtl::OUString( 488 RTL_CONSTASCII_USTRINGPARAM("desc:dependencies")))); 489 490 // if no dependency node exists, create a new one in the current description info 491 if (!xCurrentDeps.is()) { 492 css::uno::Reference< css::xml::dom::XNode > xNewDepNode( 493 xCurrentDescInfo->createElementNS( 494 ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("http://openoffice.org/extensions/description/2006")), 495 ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("dependencies"))), css::uno::UNO_QUERY_THROW); 496 m_element->appendChild(xNewDepNode); 497 xCurrentDeps = m_xpath->selectSingleNode(m_element, ::rtl::OUString( 498 RTL_CONSTASCII_USTRINGPARAM("desc:dependencies"))); 499 } 500 501 for (sal_Int32 i=0; i<nLen; i++) { 502 css::uno::Reference< css::xml::dom::XNode > xNode(xDeps->item(i)); 503 css::uno::Reference< css::xml::dom::XElement > xDep(xNode, css::uno::UNO_QUERY); 504 if (xDep.is()) { 505 // found valid blacklist dependency, import the node first and append it to the existing dependency node 506 css::uno::Reference< css::xml::dom::XNode > importedNode = xCurrentDescInfo->importNode(xNode, true); 507 xCurrentDeps->appendChild(importedNode); 508 } 509 } 510 } 511 } 512 } 513 } 514 515 bool DescriptionInfoset::checkBlacklistVersion( 516 ::rtl::OUString currentversion, 517 ::com::sun::star::uno::Sequence< ::rtl::OUString > const & versions) const 518 { 519 sal_Int32 nLen = versions.getLength(); 520 for (sal_Int32 i=0; i<nLen; i++) { 521 if (currentversion.equals(versions[i])) 522 return true; 523 } 524 525 return false; 526 } 527 528 ::rtl::OUString DescriptionInfoset::getVersion() const 529 { 530 return getNodeValueFromExpression( ::rtl::OUString( 531 RTL_CONSTASCII_USTRINGPARAM("desc:version/@value"))); 532 } 533 534 css::uno::Sequence< ::rtl::OUString > DescriptionInfoset::getSupportedPlaforms() const 535 { 536 //When there is no description.xml then we assume that we support all platforms 537 if (! m_element.is()) 538 { 539 return comphelper::makeSequence( 540 ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("all"))); 541 } 542 543 //Check if the <platform> element was provided. If not the default is "all" platforms 544 css::uno::Reference< css::xml::dom::XNode > nodePlatform( 545 m_xpath->selectSingleNode(m_element, ::rtl::OUString( 546 RTL_CONSTASCII_USTRINGPARAM("desc:platform")))); 547 if (!nodePlatform.is()) 548 { 549 return comphelper::makeSequence( 550 ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("all"))); 551 } 552 553 //There is a platform element. 554 const ::rtl::OUString value = getNodeValueFromExpression(::rtl::OUString( 555 RTL_CONSTASCII_USTRINGPARAM("desc:platform/@value"))); 556 //parse the string, it can contained multiple strings separated by commas 557 ::std::vector< ::rtl::OUString> vec; 558 sal_Int32 nIndex = 0; 559 do 560 { 561 ::rtl::OUString aToken = value.getToken( 0, ',', nIndex ); 562 aToken = aToken.trim(); 563 if (aToken.getLength()) 564 vec.push_back(aToken); 565 566 } 567 while (nIndex >= 0); 568 569 return comphelper::containerToSequence(vec); 570 } 571 572 css::uno::Reference< css::xml::dom::XNodeList > 573 DescriptionInfoset::getDependencies() const { 574 if (m_element.is()) { 575 try { 576 // check the extension blacklist first and expand the dependencies if applicable 577 checkBlacklist(); 578 579 return m_xpath->selectNodeList(m_element, ::rtl::OUString( 580 RTL_CONSTASCII_USTRINGPARAM("desc:dependencies/*"))); 581 } catch (css::xml::xpath::XPathException &) { 582 // ignore 583 } 584 } 585 return new EmptyNodeList; 586 } 587 588 css::uno::Sequence< ::rtl::OUString > 589 DescriptionInfoset::getUpdateInformationUrls() const { 590 return getUrls( 591 ::rtl::OUString( 592 RTL_CONSTASCII_USTRINGPARAM( 593 "desc:update-information/desc:src/@xlink:href"))); 594 } 595 596 css::uno::Sequence< ::rtl::OUString > 597 DescriptionInfoset::getUpdateDownloadUrls() const 598 { 599 return getUrls( 600 ::rtl::OUString( 601 RTL_CONSTASCII_USTRINGPARAM( 602 "desc:update-download/desc:src/@xlink:href"))); 603 } 604 605 ::rtl::OUString DescriptionInfoset::getIconURL( sal_Bool bHighContrast ) const 606 { 607 css::uno::Sequence< ::rtl::OUString > aStrList = getUrls( ::rtl::OUString( 608 RTL_CONSTASCII_USTRINGPARAM( "desc:icon/desc:default/@xlink:href"))); 609 css::uno::Sequence< ::rtl::OUString > aStrListHC = getUrls( ::rtl::OUString( 610 RTL_CONSTASCII_USTRINGPARAM( "desc:icon/desc:high-contrast/@xlink:href"))); 611 612 if ( bHighContrast && aStrListHC.hasElements() && aStrListHC[0].getLength() ) 613 return aStrListHC[0]; 614 615 if ( aStrList.hasElements() && aStrList[0].getLength() ) 616 return aStrList[0]; 617 618 return ::rtl::OUString(); 619 } 620 621 ::boost::optional< ::rtl::OUString > DescriptionInfoset::getLocalizedUpdateWebsiteURL() 622 const 623 { 624 bool bParentExists = false; 625 const ::rtl::OUString sURL (getLocalizedHREFAttrFromChild(::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM( 626 "/desc:description/desc:update-website")), &bParentExists )); 627 628 if (sURL.getLength() > 0) 629 return ::boost::optional< ::rtl::OUString >(sURL); 630 else 631 return bParentExists ? ::boost::optional< ::rtl::OUString >(::rtl::OUString()) : 632 ::boost::optional< ::rtl::OUString >(); 633 } 634 635 ::boost::optional< ::rtl::OUString > DescriptionInfoset::getOptionalValue( 636 ::rtl::OUString const & expression) const 637 { 638 css::uno::Reference< css::xml::dom::XNode > n; 639 if (m_element.is()) { 640 try { 641 n = m_xpath->selectSingleNode(m_element, expression); 642 } catch (css::xml::xpath::XPathException &) { 643 // ignore 644 } 645 } 646 return n.is() 647 ? ::boost::optional< ::rtl::OUString >(getNodeValue(n)) 648 : ::boost::optional< ::rtl::OUString >(); 649 } 650 651 css::uno::Sequence< ::rtl::OUString > DescriptionInfoset::getUrls( 652 ::rtl::OUString const & expression) const 653 { 654 css::uno::Reference< css::xml::dom::XNodeList > ns; 655 if (m_element.is()) { 656 try { 657 ns = m_xpath->selectNodeList(m_element, expression); 658 } catch (css::xml::xpath::XPathException &) { 659 // ignore 660 } 661 } 662 css::uno::Sequence< ::rtl::OUString > urls(ns.is() ? ns->getLength() : 0); 663 for (::sal_Int32 i = 0; i < urls.getLength(); ++i) { 664 urls[i] = getNodeValue(ns->item(i)); 665 } 666 return urls; 667 } 668 669 ::std::pair< ::rtl::OUString, ::rtl::OUString > DescriptionInfoset::getLocalizedPublisherNameAndURL() const 670 { 671 css::uno::Reference< css::xml::dom::XNode > node = 672 getLocalizedChild(::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("desc:publisher"))); 673 674 ::rtl::OUString sPublisherName; 675 ::rtl::OUString sURL; 676 if (node.is()) 677 { 678 const ::rtl::OUString exp1(RTL_CONSTASCII_USTRINGPARAM("text()")); 679 css::uno::Reference< css::xml::dom::XNode > xPathName; 680 try { 681 xPathName = m_xpath->selectSingleNode(node, exp1); 682 } catch (css::xml::xpath::XPathException &) { 683 // ignore 684 } 685 OSL_ASSERT(xPathName.is()); 686 if (xPathName.is()) 687 sPublisherName = xPathName->getNodeValue(); 688 689 const ::rtl::OUString exp2(RTL_CONSTASCII_USTRINGPARAM("@xlink:href")); 690 css::uno::Reference< css::xml::dom::XNode > xURL; 691 try { 692 xURL = m_xpath->selectSingleNode(node, exp2); 693 } catch (css::xml::xpath::XPathException &) { 694 // ignore 695 } 696 OSL_ASSERT(xURL.is()); 697 if (xURL.is()) 698 sURL = xURL->getNodeValue(); 699 } 700 return ::std::make_pair(sPublisherName, sURL); 701 } 702 703 ::rtl::OUString DescriptionInfoset::getLocalizedReleaseNotesURL() const 704 { 705 return getLocalizedHREFAttrFromChild(::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM( 706 "/desc:description/desc:release-notes")), NULL); 707 } 708 709 ::rtl::OUString DescriptionInfoset::getLocalizedDisplayName() const 710 { 711 css::uno::Reference< css::xml::dom::XNode > node = 712 getLocalizedChild(::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("desc:display-name"))); 713 if (node.is()) 714 { 715 const ::rtl::OUString exp(RTL_CONSTASCII_USTRINGPARAM("text()")); 716 css::uno::Reference< css::xml::dom::XNode > xtext; 717 try { 718 xtext = m_xpath->selectSingleNode(node, exp); 719 } catch (css::xml::xpath::XPathException &) { 720 // ignore 721 } 722 if (xtext.is()) 723 return xtext->getNodeValue(); 724 } 725 return ::rtl::OUString(); 726 } 727 728 ::rtl::OUString DescriptionInfoset::getLocalizedLicenseURL() const 729 { 730 return getLocalizedHREFAttrFromChild(::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM( 731 "/desc:description/desc:registration/desc:simple-license")), NULL); 732 733 } 734 735 ::boost::optional<SimpleLicenseAttributes> 736 DescriptionInfoset::getSimpleLicenseAttributes() const 737 { 738 //Check if the node exist 739 css::uno::Reference< css::xml::dom::XNode > n; 740 if (m_element.is()) { 741 try { 742 n = m_xpath->selectSingleNode(m_element, 743 ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM( 744 "/desc:description/desc:registration/desc:simple-license/@accept-by"))); 745 } catch (css::xml::xpath::XPathException &) { 746 // ignore 747 } 748 if (n.is()) 749 { 750 SimpleLicenseAttributes attributes; 751 attributes.acceptBy = 752 getNodeValueFromExpression(::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM( 753 "/desc:description/desc:registration/desc:simple-license/@accept-by"))); 754 755 ::boost::optional< ::rtl::OUString > suppressOnUpdate = getOptionalValue( 756 ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM( 757 "/desc:description/desc:registration/desc:simple-license/@suppress-on-update"))); 758 if (suppressOnUpdate) 759 attributes.suppressOnUpdate = (*suppressOnUpdate).trim().equalsIgnoreAsciiCase( 760 ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("true"))); 761 else 762 attributes.suppressOnUpdate = false; 763 764 ::boost::optional< ::rtl::OUString > suppressIfRequired = getOptionalValue( 765 ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM( 766 "/desc:description/desc:registration/desc:simple-license/@suppress-if-required"))); 767 if (suppressIfRequired) 768 attributes.suppressIfRequired = (*suppressIfRequired).trim().equalsIgnoreAsciiCase( 769 ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("true"))); 770 else 771 attributes.suppressIfRequired = false; 772 773 return ::boost::optional<SimpleLicenseAttributes>(attributes); 774 } 775 } 776 return ::boost::optional<SimpleLicenseAttributes>(); 777 } 778 779 ::rtl::OUString DescriptionInfoset::getLocalizedDescriptionURL() const 780 { 781 return getLocalizedHREFAttrFromChild(::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM( 782 "/desc:description/desc:extension-description")), NULL); 783 } 784 785 css::uno::Reference< css::xml::dom::XNode > 786 DescriptionInfoset::getLocalizedChild( const ::rtl::OUString & sParent) const 787 { 788 if ( ! m_element.is() || !sParent.getLength()) 789 return css::uno::Reference< css::xml::dom::XNode > (); 790 791 css::uno::Reference< css::xml::dom::XNode > xParent; 792 try { 793 xParent = m_xpath->selectSingleNode(m_element, sParent); 794 } catch (css::xml::xpath::XPathException &) { 795 // ignore 796 } 797 css::uno::Reference<css::xml::dom::XNode> nodeMatch; 798 if (xParent.is()) 799 { 800 const ::rtl::OUString sLocale = getOfficeLocaleString(); 801 nodeMatch = matchFullLocale(xParent, sLocale); 802 803 //office: en-DE, en, en-DE-altmark 804 if (! nodeMatch.is()) 805 { 806 const css::lang::Locale officeLocale = getOfficeLocale(); 807 nodeMatch = matchCountryAndLanguage(xParent, officeLocale); 808 if ( ! nodeMatch.is()) 809 { 810 nodeMatch = matchLanguage(xParent, officeLocale); 811 if (! nodeMatch.is()) 812 nodeMatch = getChildWithDefaultLocale(xParent); 813 } 814 } 815 } 816 817 return nodeMatch; 818 } 819 820 css::uno::Reference<css::xml::dom::XNode> 821 DescriptionInfoset::matchFullLocale(css::uno::Reference< css::xml::dom::XNode > 822 const & xParent, ::rtl::OUString const & sLocale) const 823 { 824 OSL_ASSERT(xParent.is()); 825 const ::rtl::OUString exp1( 826 ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("*[@lang=\"")) 827 + sLocale + 828 ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("\"]"))); 829 try { 830 return m_xpath->selectSingleNode(xParent, exp1); 831 } catch (css::xml::xpath::XPathException &) { 832 // ignore 833 return 0; 834 } 835 } 836 837 css::uno::Reference<css::xml::dom::XNode> 838 DescriptionInfoset::matchCountryAndLanguage( 839 css::uno::Reference< css::xml::dom::XNode > const & xParent, css::lang::Locale const & officeLocale) const 840 { 841 OSL_ASSERT(xParent.is()); 842 css::uno::Reference<css::xml::dom::XNode> nodeMatch; 843 844 if (officeLocale.Country.getLength()) 845 { 846 const ::rtl::OUString sLangCountry(officeLocale.Language + 847 ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("-")) + 848 officeLocale.Country); 849 //first try exact match for lang-country 850 const ::rtl::OUString exp1( 851 ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("*[@lang=\"")) 852 + sLangCountry + 853 ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("\"]"))); 854 try { 855 nodeMatch = m_xpath->selectSingleNode(xParent, exp1); 856 } catch (css::xml::xpath::XPathException &) { 857 // ignore 858 } 859 860 //try to match in strings that also have a variant, for example en-US matches in 861 //en-US-montana 862 if (!nodeMatch.is()) 863 { 864 const ::rtl::OUString exp2( 865 ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("*[starts-with(@lang,\"")) 866 + sLangCountry + 867 ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("-\")]"))); 868 try { 869 nodeMatch = m_xpath->selectSingleNode(xParent, exp2); 870 } catch (css::xml::xpath::XPathException &) { 871 // ignore 872 } 873 } 874 } 875 876 return nodeMatch; 877 } 878 879 880 css::uno::Reference<css::xml::dom::XNode> 881 DescriptionInfoset::matchLanguage( 882 css::uno::Reference< css::xml::dom::XNode > const & xParent, css::lang::Locale const & officeLocale) const 883 { 884 OSL_ASSERT(xParent.is()); 885 css::uno::Reference<css::xml::dom::XNode> nodeMatch; 886 887 //first try exact match for lang 888 const ::rtl::OUString exp1( 889 ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("*[@lang=\"")) 890 + officeLocale.Language 891 + ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("\"]"))); 892 try { 893 nodeMatch = m_xpath->selectSingleNode(xParent, exp1); 894 } catch (css::xml::xpath::XPathException &) { 895 // ignore 896 } 897 898 //try to match in strings that also have a country and/orvariant, for example en matches in 899 //en-US-montana, en-US, en-montana 900 if (!nodeMatch.is()) 901 { 902 const ::rtl::OUString exp2( 903 ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("*[starts-with(@lang,\"")) 904 + officeLocale.Language 905 + ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("-\")]"))); 906 try { 907 nodeMatch = m_xpath->selectSingleNode(xParent, exp2); 908 } catch (css::xml::xpath::XPathException &) { 909 // ignore 910 } 911 } 912 return nodeMatch; 913 } 914 915 css::uno::Reference<css::xml::dom::XNode> 916 DescriptionInfoset::getChildWithDefaultLocale(css::uno::Reference< css::xml::dom::XNode > 917 const & xParent) const 918 { 919 OSL_ASSERT(xParent.is()); 920 if (xParent->getNodeName().equals(::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("simple-license")))) 921 { 922 css::uno::Reference<css::xml::dom::XNode> nodeDefault; 923 try { 924 nodeDefault = m_xpath->selectSingleNode(xParent, ::rtl::OUString( 925 RTL_CONSTASCII_USTRINGPARAM("@default-license-id"))); 926 } catch (css::xml::xpath::XPathException &) { 927 // ignore 928 } 929 if (nodeDefault.is()) 930 { 931 //The old way 932 const ::rtl::OUString exp1( 933 ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("desc:license-text[@license-id = \"")) 934 + nodeDefault->getNodeValue() 935 + ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("\"]"))); 936 try { 937 return m_xpath->selectSingleNode(xParent, exp1); 938 } catch (css::xml::xpath::XPathException &) { 939 // ignore 940 } 941 } 942 } 943 944 const ::rtl::OUString exp2(RTL_CONSTASCII_USTRINGPARAM("*[1]")); 945 try { 946 return m_xpath->selectSingleNode(xParent, exp2); 947 } catch (css::xml::xpath::XPathException &) { 948 // ignore 949 return 0; 950 } 951 } 952 953 ::rtl::OUString DescriptionInfoset::getLocalizedHREFAttrFromChild( 954 ::rtl::OUString const & sXPathParent, bool * out_bParentExists) 955 const 956 { 957 css::uno::Reference< css::xml::dom::XNode > node = 958 getLocalizedChild(sXPathParent); 959 960 ::rtl::OUString sURL; 961 if (node.is()) 962 { 963 if (out_bParentExists) 964 *out_bParentExists = true; 965 const ::rtl::OUString exp(RTL_CONSTASCII_USTRINGPARAM("@xlink:href")); 966 css::uno::Reference< css::xml::dom::XNode > xURL; 967 try { 968 xURL = m_xpath->selectSingleNode(node, exp); 969 } catch (css::xml::xpath::XPathException &) { 970 // ignore 971 } 972 OSL_ASSERT(xURL.is()); 973 if (xURL.is()) 974 sURL = xURL->getNodeValue(); 975 } 976 else 977 { 978 if (out_bParentExists) 979 *out_bParentExists = false; 980 } 981 return sURL; 982 } 983 984 } 985