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