/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ /* * This file is part of the LibreOffice project. * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * This file incorporates work covered by the following license notice: * * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed * with this work for additional information regarding copyright * ownership. The ASF licenses this file to you under the Apache * License, Version 2.0 (the "License"); you may not use this file * except in compliance with the License. You may obtain a copy of * the License at http://www.apache.org/licenses/LICENSE-2.0 . */ #include "dp_descriptioninfoset.hxx" #include "dp_resource.h" #include "sal/config.h" #include "comphelper/sequence.hxx" #include "comphelper/seqstream.hxx" #include "comphelper/makesequence.hxx" #include "comphelper/processfactory.hxx" #include "boost/optional.hpp" #include "com/sun/star/container/XNameAccess.hpp" #include "com/sun/star/beans/Optional.hpp" #include "com/sun/star/beans/PropertyValue.hpp" #include "com/sun/star/beans/XPropertySet.hpp" #include "com/sun/star/io/SequenceInputStream.hpp" #include "com/sun/star/lang/XMultiComponentFactory.hpp" #include "com/sun/star/lang/Locale.hpp" #include "com/sun/star/uno/Reference.hxx" #include "com/sun/star/uno/RuntimeException.hpp" #include "com/sun/star/uno/Sequence.hxx" #include "com/sun/star/uno/XComponentContext.hpp" #include "com/sun/star/uno/XInterface.hpp" #include "com/sun/star/xml/dom/DOMException.hpp" #include "com/sun/star/xml/dom/XNode.hpp" #include "com/sun/star/xml/dom/XNodeList.hpp" #include "com/sun/star/xml/dom/DocumentBuilder.hpp" #include "com/sun/star/xml/xpath/XXPathAPI.hpp" #include "com/sun/star/ucb/InteractiveIOException.hpp" #include "cppuhelper/implbase1.hxx" #include "cppuhelper/implbase2.hxx" #include "cppuhelper/weak.hxx" #include "cppuhelper/exc_hlp.hxx" #include "rtl/ustring.h" #include "rtl/ustring.hxx" #include "sal/types.h" #include "ucbhelper/content.hxx" namespace { namespace css = ::com::sun::star; using css::uno::Reference; using ::rtl::OUString; class EmptyNodeList: public ::cppu::WeakImplHelper1< css::xml::dom::XNodeList > { public: EmptyNodeList(); virtual ~EmptyNodeList(); virtual ::sal_Int32 SAL_CALL getLength() throw (css::uno::RuntimeException); virtual css::uno::Reference< css::xml::dom::XNode > SAL_CALL item(::sal_Int32 index) throw (css::uno::RuntimeException); private: EmptyNodeList(EmptyNodeList &); // not defined void operator =(EmptyNodeList &); // not defined }; EmptyNodeList::EmptyNodeList() {} EmptyNodeList::~EmptyNodeList() {} ::sal_Int32 EmptyNodeList::getLength() throw (css::uno::RuntimeException) { return 0; } css::uno::Reference< css::xml::dom::XNode > EmptyNodeList::item(::sal_Int32) throw (css::uno::RuntimeException) { throw css::uno::RuntimeException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "bad EmptyNodeList com.sun.star.xml.dom.XNodeList.item call")), static_cast< ::cppu::OWeakObject * >(this)); } ::rtl::OUString getNodeValue( css::uno::Reference< css::xml::dom::XNode > const & node) { OSL_ASSERT(node.is()); try { return node->getNodeValue(); } catch (const css::xml::dom::DOMException & e) { throw css::uno::RuntimeException( (::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.xml.dom.DOMException: ")) + e.Message), css::uno::Reference< css::uno::XInterface >()); } } /**The class uses the UCB to access the description.xml file in an extension. The UCB must have been initialized already. It also requires that the extension has already be unzipped to a particular location. */ class ExtensionDescription { public: /**throws an exception if the description.xml is not available, cannot be read, does not contain the expected data, or any other error occurred. Therefore it shoult only be used with new extensions. Throws com::sun::star::uno::RuntimeException, com::sun::star::deployment::DeploymentException, dp_registry::backend::bundle::NoDescriptionException. */ ExtensionDescription( const css::uno::Reference& xContext, const ::rtl::OUString& installDir, const css::uno::Reference< css::ucb::XCommandEnvironment >& xCmdEnv); ~ExtensionDescription(); css::uno::Reference getRootElement() const { return m_xRoot; } ::rtl::OUString getExtensionRootUrl() const { return m_sExtensionRootUrl; } private: css::uno::Reference m_xRoot; ::rtl::OUString m_sExtensionRootUrl; }; class NoDescriptionException { }; class FileDoesNotExistFilter : public ::cppu::WeakImplHelper2< css::ucb::XCommandEnvironment, css::task::XInteractionHandler > { bool m_bExist; css::uno::Reference< css::ucb::XCommandEnvironment > m_xCommandEnv; public: virtual ~FileDoesNotExistFilter(); FileDoesNotExistFilter( const css::uno::Reference< css::ucb::XCommandEnvironment >& xCmdEnv); bool exist(); // XCommandEnvironment virtual css::uno::Reference SAL_CALL getInteractionHandler() throw (css::uno::RuntimeException); virtual css::uno::Reference SAL_CALL getProgressHandler() throw (css::uno::RuntimeException); // XInteractionHandler virtual void SAL_CALL handle( css::uno::Reference const & xRequest ) throw (css::uno::RuntimeException); }; ExtensionDescription::ExtensionDescription( const Reference& xContext, const OUString& installDir, const Reference< css::ucb::XCommandEnvironment >& xCmdEnv) { try { m_sExtensionRootUrl = installDir; //may throw ::com::sun::star::ucb::ContentCreationException //If there is no description.xml then ucb will start an interaction which //brings up a dialog.We want to prevent this. Therefore we wrap the xCmdEnv //and filter the respective exception out. OUString sDescriptionUri(installDir + OUSTR("/description.xml")); Reference xFilter = static_cast( new FileDoesNotExistFilter(xCmdEnv)); ::ucbhelper::Content descContent(sDescriptionUri, xFilter, xContext); //throws an com::sun::star::uno::Exception if the file is not available Reference xIn; try { //throws com.sun.star.ucb.InteractiveIOException xIn = descContent.openStream(); } catch ( const css::uno::Exception& ) { if ( ! static_cast(xFilter.get())->exist()) throw NoDescriptionException(); throw; } if (!xIn.is()) { throw css::uno::Exception( OUSTR("Could not get XInputStream for description.xml of extension ") + sDescriptionUri, 0); } //get root node of description.xml Reference xDocBuilder( css::xml::dom::DocumentBuilder::create(xContext) ); if (xDocBuilder->isNamespaceAware() == sal_False) { throw css::uno::Exception( OUSTR("Service com.sun.star.xml.dom.DocumentBuilder is not namespace aware."), 0); } Reference xDoc = xDocBuilder->parse(xIn); if (!xDoc.is()) { throw css::uno::Exception(sDescriptionUri + OUSTR(" contains data which cannot be parsed. "), 0); } //check for proper root element and namespace Reference xRoot = xDoc->getDocumentElement(); if (!xRoot.is()) { throw css::uno::Exception( sDescriptionUri + OUSTR(" contains no root element."), 0); } if ( ! xRoot->getTagName().equals(OUSTR("description"))) { throw css::uno::Exception( sDescriptionUri + OUSTR(" does not contain the root element ."), 0); } m_xRoot = Reference( xRoot, css::uno::UNO_QUERY_THROW); OUString nsDescription = xRoot->getNamespaceURI(); //check if this namespace is supported if ( ! nsDescription.equals(OUSTR("http://openoffice.org/extensions/description/2006"))) { throw css::uno::Exception(sDescriptionUri + OUSTR(" contains a root element with an unsupported namespace. "), 0); } } catch (const css::uno::RuntimeException &) { throw; } catch (const css::deployment::DeploymentException &) { throw; } catch (const css::uno::Exception & e) { css::uno::Any a(cppu::getCaughtException()); throw css::deployment::DeploymentException( e.Message, Reference< css::uno::XInterface >(), a); } } ExtensionDescription::~ExtensionDescription() { } //====================================================================== FileDoesNotExistFilter::FileDoesNotExistFilter( const Reference< css::ucb::XCommandEnvironment >& xCmdEnv): m_bExist(true), m_xCommandEnv(xCmdEnv) {} FileDoesNotExistFilter::~FileDoesNotExistFilter() { }; bool FileDoesNotExistFilter::exist() { return m_bExist; } // XCommandEnvironment Reference FileDoesNotExistFilter::getInteractionHandler() throw (css::uno::RuntimeException) { return static_cast(this); } Reference FileDoesNotExistFilter::getProgressHandler() throw (css::uno::RuntimeException) { return m_xCommandEnv.is() ? m_xCommandEnv->getProgressHandler() : Reference(); } // XInteractionHandler //If the interaction was caused by a non-existing file which is specified in the ctor //of FileDoesNotExistFilter, then we do nothing void FileDoesNotExistFilter::handle( Reference const & xRequest ) throw (css::uno::RuntimeException) { css::uno::Any request( xRequest->getRequest() ); css::ucb::InteractiveIOException ioexc; if ((request>>= ioexc) && (ioexc.Code == css::ucb::IOErrorCode_NOT_EXISTING || ioexc.Code == css::ucb::IOErrorCode_NOT_EXISTING_PATH)) { m_bExist = false; return; } Reference xInteraction; if (m_xCommandEnv.is()) { xInteraction = m_xCommandEnv->getInteractionHandler(); } if (xInteraction.is()) { xInteraction->handle(xRequest); } } } namespace dp_misc { DescriptionInfoset getDescriptionInfoset(OUString const & sExtensionFolderURL) { Reference< css::xml::dom::XNode > root; Reference context = comphelper_getProcessComponentContext(); OSL_ASSERT(context.is()); try { root = ExtensionDescription( context, sExtensionFolderURL, Reference< css::ucb::XCommandEnvironment >()). getRootElement(); } catch (const NoDescriptionException &) { } catch (const css::deployment::DeploymentException & e) { throw css::uno::RuntimeException( (OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.deployment.DeploymentException: ")) + e.Message), 0); } return DescriptionInfoset(context, root); } DescriptionInfoset::DescriptionInfoset( css::uno::Reference< css::uno::XComponentContext > const & context, css::uno::Reference< css::xml::dom::XNode > const & element): m_context(context), m_element(element) { css::uno::Reference< css::lang::XMultiComponentFactory > manager( context->getServiceManager(), css::uno::UNO_QUERY_THROW); if (m_element.is()) { m_xpath = css::uno::Reference< css::xml::xpath::XXPathAPI >( manager->createInstanceWithContext( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.xml.xpath.XPathAPI")), context), css::uno::UNO_QUERY_THROW); m_xpath->registerNS( ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("desc")), element->getNamespaceURI()); m_xpath->registerNS( ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("xlink")), ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("http://www.w3.org/1999/xlink"))); } } DescriptionInfoset::~DescriptionInfoset() {} ::boost::optional< ::rtl::OUString > DescriptionInfoset::getIdentifier() const { return getOptionalValue( ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("desc:identifier/@value"))); } ::rtl::OUString DescriptionInfoset::getNodeValueFromExpression(::rtl::OUString const & expression) const { css::uno::Reference< css::xml::dom::XNode > n; if (m_element.is()) { try { n = m_xpath->selectSingleNode(m_element, expression); } catch (const css::xml::xpath::XPathException &) { // ignore } } return n.is() ? getNodeValue(n) : ::rtl::OUString(); } void DescriptionInfoset::checkBlacklist() const { if (m_element.is()) { boost::optional< OUString > id(getIdentifier()); if (!id) return; // nothing to check OUString currentversion(getVersion()); if (currentversion.getLength() == 0) return; // nothing to check css::uno::Reference< css::lang::XMultiComponentFactory > manager( m_context->getServiceManager(), css::uno::UNO_QUERY_THROW); css::uno::Reference< css::lang::XMultiServiceFactory> provider( manager->createInstanceWithContext( ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("com.sun.star.configuration.ConfigurationProvider")), m_context), css::uno::UNO_QUERY_THROW); css::uno::Sequence< css::uno::Any > args = css::uno::Sequence< css::uno::Any >(1); css::beans::PropertyValue prop; prop.Name = ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("nodepath")); prop.Value <<= ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("/org.openoffice.Office.ExtensionDependencies/Extensions")); args[0] <<= prop; css::uno::Reference< css::container::XNameAccess > blacklist( provider->createInstanceWithArguments( ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("com.sun.star.configuration.ConfigurationAccess")), args), css::uno::UNO_QUERY_THROW); // check first if a blacklist entry is available if (blacklist.is() && blacklist->hasByName(*id)) { css::uno::Reference< css::beans::XPropertySet > extProps( blacklist->getByName(*id), css::uno::UNO_QUERY_THROW); css::uno::Any anyValue = extProps->getPropertyValue( ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("Versions"))); css::uno::Sequence< ::rtl::OUString > blversions; anyValue >>= blversions; // check if the current version requires further dependency checks from the blacklist if (checkBlacklistVersion(currentversion, blversions)) { anyValue = extProps->getPropertyValue( ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("Dependencies"))); ::rtl::OUString udeps; anyValue >>= udeps; if (udeps.getLength() == 0) return; // nothing todo ::rtl::OString xmlDependencies = ::rtl::OUStringToOString(udeps, RTL_TEXTENCODING_UNICODE); css::uno::Reference< css::xml::dom::XDocumentBuilder> docbuilder( manager->createInstanceWithContext( ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("com.sun.star.xml.dom.DocumentBuilder")), m_context), css::uno::UNO_QUERY_THROW); css::uno::Sequence< sal_Int8 > byteSeq((const sal_Int8*)xmlDependencies.getStr(), xmlDependencies.getLength()); css::uno::Reference< css::io::XInputStream> inputstream( css::io::SequenceInputStream::createStreamFromSequence(m_context, byteSeq), css::uno::UNO_QUERY_THROW); css::uno::Reference< css::xml::dom::XDocument > xDocument(docbuilder->parse(inputstream)); css::uno::Reference< css::xml::dom::XElement > xElement(xDocument->getDocumentElement()); css::uno::Reference< css::xml::dom::XNodeList > xDeps(xElement->getChildNodes()); sal_Int32 nLen = xDeps->getLength(); // get the parent xml document of current description info for the import css::uno::Reference< css::xml::dom::XDocument > xCurrentDescInfo(m_element->getOwnerDocument()); // get dependency node of current description info to merge the new dependencies from the blacklist css::uno::Reference< css::xml::dom::XNode > xCurrentDeps( m_xpath->selectSingleNode(m_element, ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("desc:dependencies")))); // if no dependency node exists, create a new one in the current description info if (!xCurrentDeps.is()) { css::uno::Reference< css::xml::dom::XNode > xNewDepNode( xCurrentDescInfo->createElementNS( ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("http://openoffice.org/extensions/description/2006")), ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("dependencies"))), css::uno::UNO_QUERY_THROW); m_element->appendChild(xNewDepNode); xCurrentDeps = m_xpath->selectSingleNode(m_element, ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("desc:dependencies"))); } for (sal_Int32 i=0; i xNode(xDeps->item(i)); css::uno::Reference< css::xml::dom::XElement > xDep(xNode, css::uno::UNO_QUERY); if (xDep.is()) { // found valid blacklist dependency, import the node first and append it to the existing dependency node css::uno::Reference< css::xml::dom::XNode > importedNode = xCurrentDescInfo->importNode(xNode, true); xCurrentDeps->appendChild(importedNode); } } } } } } bool DescriptionInfoset::checkBlacklistVersion( ::rtl::OUString currentversion, ::com::sun::star::uno::Sequence< ::rtl::OUString > const & versions) const { sal_Int32 nLen = versions.getLength(); for (sal_Int32 i=0; i DescriptionInfoset::getSupportedPlaforms() const { //When there is no description.xml then we assume that we support all platforms if (! m_element.is()) { return comphelper::makeSequence( ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("all"))); } //Check if the element was provided. If not the default is "all" platforms css::uno::Reference< css::xml::dom::XNode > nodePlatform( m_xpath->selectSingleNode(m_element, ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("desc:platform")))); if (!nodePlatform.is()) { return comphelper::makeSequence( ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("all"))); } //There is a platform element. const ::rtl::OUString value = getNodeValueFromExpression(::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("desc:platform/@value"))); //parse the string, it can contained multiple strings separated by commas ::std::vector< ::rtl::OUString> vec; sal_Int32 nIndex = 0; do { ::rtl::OUString aToken = value.getToken( 0, ',', nIndex ); aToken = aToken.trim(); if (!aToken.isEmpty()) vec.push_back(aToken); } while (nIndex >= 0); return comphelper::containerToSequence(vec); } css::uno::Reference< css::xml::dom::XNodeList > DescriptionInfoset::getDependencies() const { if (m_element.is()) { try { // check the extension blacklist first and expand the dependencies if applicable checkBlacklist(); return m_xpath->selectNodeList(m_element, ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("desc:dependencies/*"))); } catch (const css::xml::xpath::XPathException &) { // ignore } } return new EmptyNodeList; } css::uno::Sequence< ::rtl::OUString > DescriptionInfoset::getUpdateInformationUrls() const { return getUrls( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "desc:update-information/desc:src/@xlink:href"))); } css::uno::Sequence< ::rtl::OUString > DescriptionInfoset::getUpdateDownloadUrls() const { return getUrls( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "desc:update-download/desc:src/@xlink:href"))); } ::rtl::OUString DescriptionInfoset::getIconURL( sal_Bool bHighContrast ) const { css::uno::Sequence< ::rtl::OUString > aStrList = getUrls( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "desc:icon/desc:default/@xlink:href"))); css::uno::Sequence< ::rtl::OUString > aStrListHC = getUrls( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "desc:icon/desc:high-contrast/@xlink:href"))); if ( bHighContrast && aStrListHC.hasElements() && !aStrListHC[0].isEmpty() ) return aStrListHC[0]; if ( aStrList.hasElements() && !aStrList[0].isEmpty() ) return aStrList[0]; return ::rtl::OUString(); } ::boost::optional< ::rtl::OUString > DescriptionInfoset::getLocalizedUpdateWebsiteURL() const { bool bParentExists = false; const ::rtl::OUString sURL (getLocalizedHREFAttrFromChild(::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM( "/desc:description/desc:update-website")), &bParentExists )); if (!sURL.isEmpty()) return ::boost::optional< ::rtl::OUString >(sURL); else return bParentExists ? ::boost::optional< ::rtl::OUString >(::rtl::OUString()) : ::boost::optional< ::rtl::OUString >(); } ::boost::optional< ::rtl::OUString > DescriptionInfoset::getOptionalValue( ::rtl::OUString const & expression) const { css::uno::Reference< css::xml::dom::XNode > n; if (m_element.is()) { try { n = m_xpath->selectSingleNode(m_element, expression); } catch (const css::xml::xpath::XPathException &) { // ignore } } return n.is() ? ::boost::optional< ::rtl::OUString >(getNodeValue(n)) : ::boost::optional< ::rtl::OUString >(); } css::uno::Sequence< ::rtl::OUString > DescriptionInfoset::getUrls( ::rtl::OUString const & expression) const { css::uno::Reference< css::xml::dom::XNodeList > ns; if (m_element.is()) { try { ns = m_xpath->selectNodeList(m_element, expression); } catch (const css::xml::xpath::XPathException &) { // ignore } } css::uno::Sequence< ::rtl::OUString > urls(ns.is() ? ns->getLength() : 0); for (::sal_Int32 i = 0; i < urls.getLength(); ++i) { urls[i] = getNodeValue(ns->item(i)); } return urls; } ::std::pair< ::rtl::OUString, ::rtl::OUString > DescriptionInfoset::getLocalizedPublisherNameAndURL() const { css::uno::Reference< css::xml::dom::XNode > node = getLocalizedChild(::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("desc:publisher"))); ::rtl::OUString sPublisherName; ::rtl::OUString sURL; if (node.is()) { const ::rtl::OUString exp1(RTL_CONSTASCII_USTRINGPARAM("text()")); css::uno::Reference< css::xml::dom::XNode > xPathName; try { xPathName = m_xpath->selectSingleNode(node, exp1); } catch (const css::xml::xpath::XPathException &) { // ignore } OSL_ASSERT(xPathName.is()); if (xPathName.is()) sPublisherName = xPathName->getNodeValue(); const ::rtl::OUString exp2(RTL_CONSTASCII_USTRINGPARAM("@xlink:href")); css::uno::Reference< css::xml::dom::XNode > xURL; try { xURL = m_xpath->selectSingleNode(node, exp2); } catch (const css::xml::xpath::XPathException &) { // ignore } OSL_ASSERT(xURL.is()); if (xURL.is()) sURL = xURL->getNodeValue(); } return ::std::make_pair(sPublisherName, sURL); } ::rtl::OUString DescriptionInfoset::getLocalizedReleaseNotesURL() const { return getLocalizedHREFAttrFromChild(::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM( "/desc:description/desc:release-notes")), NULL); } ::rtl::OUString DescriptionInfoset::getLocalizedDisplayName() const { css::uno::Reference< css::xml::dom::XNode > node = getLocalizedChild(::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("desc:display-name"))); if (node.is()) { const ::rtl::OUString exp(RTL_CONSTASCII_USTRINGPARAM("text()")); css::uno::Reference< css::xml::dom::XNode > xtext; try { xtext = m_xpath->selectSingleNode(node, exp); } catch (const css::xml::xpath::XPathException &) { // ignore } if (xtext.is()) return xtext->getNodeValue(); } return ::rtl::OUString(); } ::rtl::OUString DescriptionInfoset::getLocalizedLicenseURL() const { return getLocalizedHREFAttrFromChild(::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM( "/desc:description/desc:registration/desc:simple-license")), NULL); } ::boost::optional DescriptionInfoset::getSimpleLicenseAttributes() const { //Check if the node exist css::uno::Reference< css::xml::dom::XNode > n; if (m_element.is()) { try { n = m_xpath->selectSingleNode(m_element, ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM( "/desc:description/desc:registration/desc:simple-license/@accept-by"))); } catch (const css::xml::xpath::XPathException &) { // ignore } if (n.is()) { SimpleLicenseAttributes attributes; attributes.acceptBy = getNodeValueFromExpression(::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM( "/desc:description/desc:registration/desc:simple-license/@accept-by"))); ::boost::optional< ::rtl::OUString > suppressOnUpdate = getOptionalValue( ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM( "/desc:description/desc:registration/desc:simple-license/@suppress-on-update"))); if (suppressOnUpdate) attributes.suppressOnUpdate = (*suppressOnUpdate).trim().equalsIgnoreAsciiCase( ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("true"))); else attributes.suppressOnUpdate = false; ::boost::optional< ::rtl::OUString > suppressIfRequired = getOptionalValue( ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM( "/desc:description/desc:registration/desc:simple-license/@suppress-if-required"))); if (suppressIfRequired) attributes.suppressIfRequired = (*suppressIfRequired).trim().equalsIgnoreAsciiCase( ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("true"))); else attributes.suppressIfRequired = false; return ::boost::optional(attributes); } } return ::boost::optional(); } ::rtl::OUString DescriptionInfoset::getLocalizedDescriptionURL() const { return getLocalizedHREFAttrFromChild(::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM( "/desc:description/desc:extension-description")), NULL); } css::uno::Reference< css::xml::dom::XNode > DescriptionInfoset::getLocalizedChild( const ::rtl::OUString & sParent) const { if ( ! m_element.is() || sParent.isEmpty()) return css::uno::Reference< css::xml::dom::XNode > (); css::uno::Reference< css::xml::dom::XNode > xParent; try { xParent = m_xpath->selectSingleNode(m_element, sParent); } catch (const css::xml::xpath::XPathException &) { // ignore } css::uno::Reference nodeMatch; if (xParent.is()) { const ::rtl::OUString sLocale = getOfficeLocaleString(); nodeMatch = matchFullLocale(xParent, sLocale); //office: en-DE, en, en-DE-altmark if (! nodeMatch.is()) { const css::lang::Locale officeLocale = getOfficeLocale(); nodeMatch = matchCountryAndLanguage(xParent, officeLocale); if ( ! nodeMatch.is()) { nodeMatch = matchLanguage(xParent, officeLocale); if (! nodeMatch.is()) nodeMatch = getChildWithDefaultLocale(xParent); } } } return nodeMatch; } css::uno::Reference DescriptionInfoset::matchFullLocale(css::uno::Reference< css::xml::dom::XNode > const & xParent, ::rtl::OUString const & sLocale) const { OSL_ASSERT(xParent.is()); const ::rtl::OUString exp1( ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("*[@lang=\"")) + sLocale + ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("\"]"))); try { return m_xpath->selectSingleNode(xParent, exp1); } catch (const css::xml::xpath::XPathException &) { // ignore return 0; } } css::uno::Reference DescriptionInfoset::matchCountryAndLanguage( css::uno::Reference< css::xml::dom::XNode > const & xParent, css::lang::Locale const & officeLocale) const { OSL_ASSERT(xParent.is()); css::uno::Reference nodeMatch; if (!officeLocale.Country.isEmpty()) { const ::rtl::OUString sLangCountry(officeLocale.Language + ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("-")) + officeLocale.Country); //first try exact match for lang-country const ::rtl::OUString exp1( ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("*[@lang=\"")) + sLangCountry + ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("\"]"))); try { nodeMatch = m_xpath->selectSingleNode(xParent, exp1); } catch (const css::xml::xpath::XPathException &) { // ignore } //try to match in strings that also have a variant, for example en-US matches in //en-US-montana if (!nodeMatch.is()) { const ::rtl::OUString exp2( ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("*[starts-with(@lang,\"")) + sLangCountry + ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("-\")]"))); try { nodeMatch = m_xpath->selectSingleNode(xParent, exp2); } catch (const css::xml::xpath::XPathException &) { // ignore } } } return nodeMatch; } css::uno::Reference DescriptionInfoset::matchLanguage( css::uno::Reference< css::xml::dom::XNode > const & xParent, css::lang::Locale const & officeLocale) const { OSL_ASSERT(xParent.is()); css::uno::Reference nodeMatch; //first try exact match for lang const ::rtl::OUString exp1( ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("*[@lang=\"")) + officeLocale.Language + ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("\"]"))); try { nodeMatch = m_xpath->selectSingleNode(xParent, exp1); } catch (const css::xml::xpath::XPathException &) { // ignore } //try to match in strings that also have a country and/orvariant, for example en matches in //en-US-montana, en-US, en-montana if (!nodeMatch.is()) { const ::rtl::OUString exp2( ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("*[starts-with(@lang,\"")) + officeLocale.Language + ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("-\")]"))); try { nodeMatch = m_xpath->selectSingleNode(xParent, exp2); } catch (const css::xml::xpath::XPathException &) { // ignore } } return nodeMatch; } css::uno::Reference DescriptionInfoset::getChildWithDefaultLocale(css::uno::Reference< css::xml::dom::XNode > const & xParent) const { OSL_ASSERT(xParent.is()); if ( xParent->getNodeName() == "simple-license" ) { css::uno::Reference nodeDefault; try { nodeDefault = m_xpath->selectSingleNode(xParent, ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("@default-license-id"))); } catch (const css::xml::xpath::XPathException &) { // ignore } if (nodeDefault.is()) { //The old way const ::rtl::OUString exp1( ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("desc:license-text[@license-id = \"")) + nodeDefault->getNodeValue() + ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("\"]"))); try { return m_xpath->selectSingleNode(xParent, exp1); } catch (const css::xml::xpath::XPathException &) { // ignore } } } const ::rtl::OUString exp2(RTL_CONSTASCII_USTRINGPARAM("*[1]")); try { return m_xpath->selectSingleNode(xParent, exp2); } catch (const css::xml::xpath::XPathException &) { // ignore return 0; } } ::rtl::OUString DescriptionInfoset::getLocalizedHREFAttrFromChild( ::rtl::OUString const & sXPathParent, bool * out_bParentExists) const { css::uno::Reference< css::xml::dom::XNode > node = getLocalizedChild(sXPathParent); ::rtl::OUString sURL; if (node.is()) { if (out_bParentExists) *out_bParentExists = true; const ::rtl::OUString exp(RTL_CONSTASCII_USTRINGPARAM("@xlink:href")); css::uno::Reference< css::xml::dom::XNode > xURL; try { xURL = m_xpath->selectSingleNode(node, exp); } catch (const css::xml::xpath::XPathException &) { // ignore } OSL_ASSERT(xURL.is()); if (xURL.is()) sURL = xURL->getNodeValue(); } else { if (out_bParentExists) *out_bParentExists = false; } return sURL; } } /* vim:set shiftwidth=4 softtabstop=4 expandtab: */