1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
21 #include <strings.hrc>
22 #include <dp_package.hxx>
23 #include <dp_backend.h>
25 #include <dp_interact.h>
26 #include <dp_dependencies.hxx>
27 #include <dp_platform.hxx>
28 #include <dp_descriptioninfoset.hxx>
29 #include <dp_identifier.hxx>
30 #include <rtl/uri.hxx>
31 #include <sal/log.hxx>
32 #include <cppuhelper/exc_hlp.hxx>
33 #include <cppuhelper/implbase.hxx>
34 #include <cppuhelper/supportsservice.hxx>
35 #include <ucbhelper/content.hxx>
36 #include <svl/inettype.hxx>
37 #include <comphelper/anytostring.hxx>
38 #include <comphelper/sequence.hxx>
39 #include <com/sun/star/lang/WrappedTargetException.hpp>
40 #include <com/sun/star/lang/XServiceInfo.hpp>
41 #include <com/sun/star/beans/UnknownPropertyException.hpp>
42 #include <com/sun/star/graphic/XGraphic.hpp>
43 #include <com/sun/star/graphic/GraphicProvider.hpp>
44 #include <com/sun/star/graphic/XGraphicProvider.hpp>
45 #include <com/sun/star/io/Pipe.hpp>
46 #include <com/sun/star/io/XOutputStream.hpp>
47 #include <com/sun/star/io/XInputStream.hpp>
48 #include <com/sun/star/task/InteractionClassification.hpp>
49 #include <com/sun/star/task/XInteractionApprove.hpp>
50 #include <com/sun/star/ucb/CommandAbortedException.hpp>
51 #include <com/sun/star/ucb/CommandFailedException.hpp>
52 #include <com/sun/star/ucb/ContentCreationException.hpp>
53 #include <com/sun/star/ucb/XInteractionReplaceExistingData.hpp>
54 #include <com/sun/star/ucb/NameClashResolveRequest.hpp>
55 #include <com/sun/star/ucb/XContentAccess.hpp>
56 #include <com/sun/star/ucb/NameClash.hpp>
57 #include <com/sun/star/ucb/UnsupportedCommandException.hpp>
58 #include <com/sun/star/sdbc/XResultSet.hpp>
59 #include <com/sun/star/sdbc/XRow.hpp>
60 #include <com/sun/star/packages/manifest/ManifestReader.hpp>
61 #include <com/sun/star/packages/manifest/ManifestWriter.hpp>
62 #include <com/sun/star/deployment/DependencyException.hpp>
63 #include <com/sun/star/deployment/DeploymentException.hpp>
64 #include <com/sun/star/deployment/ExtensionRemovedException.hpp>
65 #include <com/sun/star/deployment/LicenseException.hpp>
66 #include <com/sun/star/deployment/PlatformException.hpp>
67 #include <com/sun/star/deployment/Prerequisites.hpp>
68 #include <com/sun/star/xml/dom/XDocumentBuilder.hpp>
69 #include <com/sun/star/xml/xpath/XXPathAPI.hpp>
70 #include <com/sun/star/deployment/XPackageManager.hpp>
71 #include <boost/optional.hpp>
72 #include <tools/diagnose_ex.h>
78 #include "dp_extbackenddb.hxx"
79 using namespace ::dp_misc
;
80 using namespace ::com::sun::star
;
81 using namespace ::com::sun::star::uno
;
84 namespace dp_registry
{
89 typedef cppu::ImplInheritanceHelper
<PackageRegistryBackend
,
90 lang::XServiceInfo
> ImplBaseT
;
93 class BackendImpl
: public ImplBaseT
95 class PackageImpl
: public ::dp_registry::backend::Package
97 BackendImpl
* getMyBackend() const;
98 /** contains the old tooltip description for the Extension Manager GUI in OOo v.2.x
99 We keep it for backward compatibility.
101 OUString m_oldDescription
;
102 OUString m_url_expanded
;
103 const bool m_legacyBundle
;
104 Sequence
< Reference
<deployment::XPackage
> > m_bundle
;
105 Sequence
< Reference
<deployment::XPackage
> > * m_pBundle
;
107 ExtensionBackendDb::Data m_dbData
;
109 Reference
<deployment::XPackage
> bindBundleItem(
110 OUString
const & url
, OUString
const & mediaType
,
111 bool bRemoved
, //that is, using data base information
112 OUString
const & identifier
,
113 Reference
<ucb::XCommandEnvironment
> const & xCmdEnv
,
114 bool notifyDetectionError
= true );
116 typedef std::vector
< Reference
<deployment::XPackage
> > t_packagevec
;
118 t_packagevec
& bundle
,
119 ::rtl::Reference
<AbortChannel
> const & abortChannel
,
120 Reference
<ucb::XCommandEnvironment
> const & xCmdEnv
);
121 void scanLegacyBundle(
122 t_packagevec
& bundle
,
123 OUString
const & url
,
124 ::rtl::Reference
<AbortChannel
> const & abortChannel
,
125 Reference
<ucb::XCommandEnvironment
> const & xCmdEnv
,
126 bool skip_registration
= false );
127 std::vector
<Reference
<deployment::XPackage
> > getPackagesFromDb(
128 Reference
<ucb::XCommandEnvironment
> const & xCmdEnv
);
130 Reference
<ucb::XCommandEnvironment
> const & environment
);
132 bool checkDependencies(
133 Reference
<ucb::XCommandEnvironment
> const &
135 DescriptionInfoset
const & description
);
136 // throws css::uno::RuntimeException,
137 // css::deployment::DeploymentException
139 /// @throws deployment::DeploymentException
140 /// @throws ucb::CommandFailedException
141 /// @throws ucb::CommandAbortedException
142 /// @throws RuntimeException
144 Reference
< ucb::XCommandEnvironment
> const & xCmdEnv
,
145 DescriptionInfoset
const & description
, bool bNoLicenseChecking
);
146 // @throws DeploymentException
147 OUString
getTextFromURL(
148 const Reference
< ucb::XCommandEnvironment
>& xCmdEnv
,
149 const OUString
& licenseUrl
);
151 DescriptionInfoset
getDescriptionInfoset() const;
154 virtual beans::Optional
< beans::Ambiguous
<sal_Bool
> > isRegistered_(
155 ::osl::ResettableMutexGuard
& guard
,
156 ::rtl::Reference
<AbortChannel
> const & abortChannel
,
157 Reference
<ucb::XCommandEnvironment
> const & xCmdEnv
) override
;
158 virtual void processPackage_(
159 ::osl::ResettableMutexGuard
& guard
,
160 bool registerPackage
,
162 ::rtl::Reference
<AbortChannel
> const & abortChannel
,
163 Reference
<ucb::XCommandEnvironment
> const & xCmdEnv
) override
;
165 virtual void SAL_CALL
disposing() override
;
170 ::rtl::Reference
<PackageRegistryBackend
> const & myBackend
,
171 OUString
const & url
,
172 OUString
const & name
,
173 Reference
<deployment::XPackageTypeInfo
> const & xPackageType
,
176 OUString
const & identifier
);
179 virtual sal_Bool SAL_CALL
isBundle() override
;
181 virtual Sequence
< Reference
<deployment::XPackage
> > SAL_CALL
getBundle(
182 Reference
<task::XAbortChannel
> const & xAbortChannel
,
183 Reference
<ucb::XCommandEnvironment
> const & xCmdEnv
) override
;
184 virtual OUString SAL_CALL
getDescription() override
;
186 virtual OUString SAL_CALL
getLicenseText() override
;
188 virtual void SAL_CALL
exportTo(
189 OUString
const & destFolderURL
, OUString
const & newTitle
,
190 sal_Int32 nameClashAction
,
191 Reference
<ucb::XCommandEnvironment
> const & xCmdEnv
) override
;
193 virtual ::sal_Int32 SAL_CALL
checkPrerequisites(
194 const Reference
< task::XAbortChannel
>& xAbortChannel
,
195 const Reference
< ucb::XCommandEnvironment
>& xCmdEnv
,
196 sal_Bool noLicenseChecking
) override
;
198 virtual sal_Bool SAL_CALL
checkDependencies(
199 const Reference
< ucb::XCommandEnvironment
>& xCmdEnv
) override
;
201 virtual beans::Optional
<OUString
> SAL_CALL
getIdentifier() override
;
203 virtual OUString SAL_CALL
getVersion() override
;
205 virtual Sequence
<OUString
> SAL_CALL
getUpdateInformationURLs() override
;
207 virtual beans::StringPair SAL_CALL
getPublisherInfo() override
;
209 virtual OUString SAL_CALL
getDisplayName() override
;
211 virtual Reference
< graphic::XGraphic
> SAL_CALL
212 getIcon( sal_Bool bHighContrast
) override
;
214 friend class PackageImpl
;
216 Reference
<deployment::XPackageRegistry
> m_xRootRegistry
;
217 const Reference
<deployment::XPackageTypeInfo
> m_xBundleTypeInfo
;
218 const Reference
<deployment::XPackageTypeInfo
> m_xLegacyBundleTypeInfo
;
219 Sequence
< Reference
<deployment::XPackageTypeInfo
> > m_typeInfos
;
221 std::unique_ptr
<ExtensionBackendDb
> m_backendDb
;
223 void addDataToDb(OUString
const & url
, ExtensionBackendDb::Data
const & data
);
224 ExtensionBackendDb::Data
readDataFromDb(OUString
const & url
);
225 void revokeEntryFromDb(OUString
const & url
);
227 // PackageRegistryBackend
228 virtual Reference
<deployment::XPackage
> bindPackage_(
229 OUString
const & url
, OUString
const & mediaType
,
230 bool bRemoved
, OUString
const & identifier
,
231 Reference
<ucb::XCommandEnvironment
> const & xCmdEnv
) override
;
233 virtual void SAL_CALL
disposing() override
;
237 Sequence
<Any
> const & args
,
238 Reference
<XComponentContext
> const & xComponentContext
,
239 Reference
<deployment::XPackageRegistry
> const & xRootRegistry
);
242 virtual OUString SAL_CALL
getImplementationName() override
;
243 virtual sal_Bool SAL_CALL
supportsService( OUString
const& name
) override
;
244 virtual Sequence
<OUString
> SAL_CALL
getSupportedServiceNames() override
;
247 virtual Sequence
< Reference
<deployment::XPackageTypeInfo
> > SAL_CALL
248 getSupportedPackageTypes() override
;
249 virtual void SAL_CALL
packageRemoved(OUString
const & url
, OUString
const & mediaType
) override
;
251 using ImplBaseT::disposing
;
254 //Used to find a XPackage with a particular URL
259 explicit XPackage_eq(const OUString
& s
) : m_URL(s
) {}
260 bool operator() (const Reference
<deployment::XPackage
> & p
) const
262 return m_URL
== p
->getURL();
267 BackendImpl::BackendImpl(
268 Sequence
<Any
> const & args
,
269 Reference
<XComponentContext
> const & xComponentContext
,
270 Reference
<deployment::XPackageRegistry
> const & xRootRegistry
)
271 : ImplBaseT( args
, xComponentContext
),
272 m_xRootRegistry( xRootRegistry
),
273 m_xBundleTypeInfo( new Package::TypeInfo(
274 "application/vnd.sun.star.package-bundle",
276 DpResId(RID_STR_PACKAGE_BUNDLE
)
278 m_xLegacyBundleTypeInfo( new Package::TypeInfo(
279 "application/vnd.sun.star.legacy-package-bundle",
281 m_xBundleTypeInfo
->getShortDescription()
285 m_typeInfos
[ 0 ] = m_xBundleTypeInfo
;
286 m_typeInfos
[ 1 ] = m_xLegacyBundleTypeInfo
;
288 if (!transientMode())
290 OUString dbFile
= makeURL(getCachePath(), getImplementationName());
291 dbFile
= makeURL(dbFile
, "backenddb.xml");
293 new ExtensionBackendDb(getComponentContext(), dbFile
));
298 void BackendImpl::disposing()
300 m_xRootRegistry
.clear();
301 PackageRegistryBackend::disposing();
305 OUString
BackendImpl::getImplementationName()
307 return "com.sun.star.comp.deployment.bundle.PackageRegistryBackend";
310 sal_Bool
BackendImpl::supportsService(OUString
const & ServiceName
)
312 return cppu::supportsService(this, ServiceName
);
315 Sequence
<OUString
> BackendImpl::getSupportedServiceNames()
317 return { OUString(BACKEND_SERVICE_NAME
) };
322 Sequence
< Reference
<deployment::XPackageTypeInfo
> >
323 BackendImpl::getSupportedPackageTypes()
328 void BackendImpl::packageRemoved(OUString
const & url
, OUString
const & /*mediaType*/)
330 //Notify the backend responsible for processing the different media
331 //types that this extension was removed.
332 ExtensionBackendDb::Data data
= readDataFromDb(url
);
333 for (auto const& item
: data
.items
)
335 m_xRootRegistry
->packageRemoved(item
.first
, item
.second
);
339 m_backendDb
->removeEntry(url
);
343 // PackageRegistryBackend
345 Reference
<deployment::XPackage
> BackendImpl::bindPackage_(
346 OUString
const & url
, OUString
const & mediaType_
,
347 bool bRemoved
, OUString
const & identifier
,
348 Reference
<ucb::XCommandEnvironment
> const & xCmdEnv
)
350 OUString
mediaType( mediaType_
);
351 if (mediaType
.isEmpty())
353 // detect media-type:
354 ::ucbhelper::Content ucbContent
;
355 if (create_ucb_content( &ucbContent
, url
, xCmdEnv
))
357 if (ucbContent
.isFolder())
359 //Every .oxt, uno.pkg file must contain a META-INF folder
360 ::ucbhelper::Content metaInfContent
;
361 if (create_ucb_content(
362 &metaInfContent
, makeURL( url
, "META-INF" ),
363 xCmdEnv
, false /* no throw */ ))
365 mediaType
= "application/vnd.sun.star.package-bundle";
367 //No support of legacy bundles, because every folder could be one.
371 const OUString
title( StrTitle::getTitle( ucbContent
) );
372 if (title
.endsWithIgnoreAsciiCase(".oxt") ||
373 title
.endsWithIgnoreAsciiCase(".uno.pkg"))
374 mediaType
= "application/vnd.sun.star.package-bundle";
375 else if (title
.endsWithIgnoreAsciiCase(".zip"))
376 mediaType
= "application/vnd.sun.star.legacy-package-bundle";
379 if (mediaType
.isEmpty())
380 throw lang::IllegalArgumentException(
381 StrCannotDetectMediaType() + url
,
382 static_cast<OWeakObject
*>(this), static_cast<sal_Int16
>(-1) );
385 OUString type
, subType
;
386 INetContentTypeParameterList params
;
387 if (INetContentTypes::parse( mediaType
, type
, subType
, ¶ms
))
389 if (type
.equalsIgnoreAsciiCase("application"))
392 //In case a XPackage is created for a removed extension, we cannot
397 ::ucbhelper::Content
ucbContent(
398 url
, xCmdEnv
, getComponentContext() );
399 name
= StrTitle::getTitle( ucbContent
);
401 if (subType
.equalsIgnoreAsciiCase("vnd.sun.star.package-bundle"))
403 return new PackageImpl(
404 this, url
, name
, m_xBundleTypeInfo
, false, bRemoved
,
407 else if (subType
.equalsIgnoreAsciiCase( "vnd.sun.star.legacy-package-bundle"))
409 return new PackageImpl(
410 this, url
, name
, m_xLegacyBundleTypeInfo
, true, bRemoved
,
415 throw lang::IllegalArgumentException(
416 StrUnsupportedMediaType() + mediaType
,
417 static_cast<OWeakObject
*>(this),
418 static_cast<sal_Int16
>(-1) );
421 void BackendImpl::addDataToDb(
422 OUString
const & url
, ExtensionBackendDb::Data
const & data
)
425 m_backendDb
->addEntry(url
, data
);
428 ExtensionBackendDb::Data
BackendImpl::readDataFromDb(
429 OUString
const & url
)
431 ExtensionBackendDb::Data data
;
433 data
= m_backendDb
->getEntry(url
);
437 void BackendImpl::revokeEntryFromDb(OUString
const & url
)
440 m_backendDb
->revokeEntry(url
);
444 BackendImpl::PackageImpl::PackageImpl(
445 ::rtl::Reference
<PackageRegistryBackend
> const & myBackend
,
446 OUString
const & url
,
447 OUString
const & name
,
448 Reference
<deployment::XPackageTypeInfo
> const & xPackageType
,
449 bool legacyBundle
, bool bRemoved
, OUString
const & identifier
)
450 : Package( myBackend
, url
, name
, name
/* display-name */,
451 xPackageType
, bRemoved
, identifier
),
452 m_url_expanded( expandUnoRcUrl( url
) ),
453 m_legacyBundle( legacyBundle
),
457 m_dbData
= getMyBackend()->readDataFromDb(url
);
460 BackendImpl
* BackendImpl::PackageImpl::getMyBackend() const
462 BackendImpl
* pBackend
= static_cast<BackendImpl
*>(m_myBackend
.get());
463 if (nullptr == pBackend
)
465 //May throw a DisposedException
467 //We should never get here...
468 throw RuntimeException("Failed to get the BackendImpl",
469 static_cast<OWeakObject
*>(const_cast<PackageImpl
*>(this)));
474 void BackendImpl::PackageImpl::disposing()
476 sal_Int32 len
= m_bundle
.getLength();
477 Reference
<deployment::XPackage
> const * p
= m_bundle
.getConstArray();
478 for ( sal_Int32 pos
= 0; pos
< len
; ++pos
)
479 try_dispose( p
[ pos
] );
480 m_bundle
.realloc( 0 );
482 Package::disposing();
487 beans::Optional
< beans::Ambiguous
<sal_Bool
> >
488 BackendImpl::PackageImpl::isRegistered_(
489 ::osl::ResettableMutexGuard
&,
490 ::rtl::Reference
<AbortChannel
> const & abortChannel
,
491 Reference
<ucb::XCommandEnvironment
> const & xCmdEnv
)
493 //In case the object was created for a removed extension (m_bRemoved = true)
494 //but the extension is not registered, then bundle will be empty. Then
495 //the return value will be Optional<...>.IsPresent= false. Although this is
496 //not true, this does not matter. Then registerPackage or revokePackage
497 //would never be called for the items. But since the extension is removed
498 //and not registered anyway, this does not matter.
499 const Sequence
< Reference
<deployment::XPackage
> > bundle(
500 getBundle( abortChannel
.get(), xCmdEnv
) );
503 bool present
= false;
505 for ( sal_Int32 pos
= bundle
.getLength(); pos
--; )
507 Reference
<deployment::XPackage
> const & xPackage
= bundle
[ pos
];
508 Reference
<task::XAbortChannel
> xSubAbortChannel(
509 xPackage
->createAbortChannel() );
510 AbortChannel::Chain
chain( abortChannel
, xSubAbortChannel
);
511 beans::Optional
< beans::Ambiguous
<sal_Bool
> > option(
512 xPackage
->isRegistered( xSubAbortChannel
, xCmdEnv
) );
514 //present = true if at least one bundle item has this value.
515 //reg = true if all bundle items have an option value (option.IsPresent == 1)
516 //and all have value of true (option.Value.Value == true)
517 //If not, then the bundle has the status of not registered and ambiguous.
518 if (option
.IsPresent
)
520 beans::Ambiguous
<sal_Bool
> const & status
= option
.Value
;
523 //we never come here in the first iteration
524 if (reg
!= bool(status
.Value
)) {
533 //we always come here in the first iteration
539 return beans::Optional
< beans::Ambiguous
<sal_Bool
> >(
540 present
, beans::Ambiguous
<sal_Bool
>(reg
, ambig
) );
543 OUString
BackendImpl::PackageImpl::getTextFromURL(
544 const css::uno::Reference
< css::ucb::XCommandEnvironment
>& xCmdEnv
,
545 const OUString
& licenseUrl
)
549 ::ucbhelper::Content
descContent(
550 licenseUrl
, xCmdEnv
, getMyBackend()->getComponentContext());
551 std::vector
<sal_Int8
> seq
= dp_misc::readFile(descContent
);
552 return OUString( reinterpret_cast<sal_Char
const *>(
553 seq
.data()), seq
.size(), RTL_TEXTENCODING_UTF8
);
555 catch (const css::uno::Exception
&)
557 Any
exc( ::cppu::getCaughtException() );
558 throw css::deployment::DeploymentException(
559 "Could not read file " + licenseUrl
, nullptr, exc
);
564 DescriptionInfoset
BackendImpl::PackageImpl::getDescriptionInfoset() const
566 return dp_misc::getDescriptionInfoset(m_url_expanded
);
569 bool BackendImpl::PackageImpl::checkPlatform(
570 css::uno::Reference
< css::ucb::XCommandEnvironment
> const & environment
)
573 DescriptionInfoset
info(getDescriptionInfoset());
574 Sequence
<OUString
> platforms(info
.getSupportedPlatforms());
575 if (hasValidPlatform(platforms
))
583 "unsupported platform");
585 css::deployment::PlatformException(
586 msg
, static_cast<OWeakObject
*>(this), this));
587 if (!interactContinuation(
588 e
, cppu::UnoType
< css::task::XInteractionApprove
>::get(),
589 environment
, nullptr, nullptr))
591 throw css::deployment::DeploymentException(
592 msg
, static_cast<OWeakObject
*>(this), e
);
599 bool BackendImpl::PackageImpl::checkDependencies(
600 css::uno::Reference
< css::ucb::XCommandEnvironment
> const & environment
,
601 DescriptionInfoset
const & description
)
603 css::uno::Sequence
< css::uno::Reference
< css::xml::dom::XElement
> >
604 unsatisfied(dp_misc::Dependencies::check(description
));
606 if (!unsatisfied
.hasElements()) {
610 "unsatisfied dependencies");
612 css::deployment::DependencyException(
613 msg
, static_cast<OWeakObject
*>(this), unsatisfied
));
614 if (!interactContinuation(
615 e
, cppu::UnoType
< css::task::XInteractionApprove
>::get(),
616 environment
, nullptr, nullptr))
618 throw css::deployment::DeploymentException(
619 msg
, static_cast<OWeakObject
*>(this), e
);
625 bool BackendImpl::PackageImpl::checkLicense(
626 css::uno::Reference
< css::ucb::XCommandEnvironment
> const & xCmdEnv
,
627 DescriptionInfoset
const & info
, bool alreadyInstalled
)
631 ::boost::optional
<SimpleLicenseAttributes
> simplLicAttr
632 = info
.getSimpleLicenseAttributes();
635 OUString sLic
= info
.getLocalizedLicenseURL();
636 //If we do not get a localized licence then there is an error in the description.xml
637 //This should be handled by using a validating parser. Therefore we assume that no
638 //license is available.
640 throw css::deployment::DeploymentException(
641 "Could not obtain path to license. Possible error in description.xml", nullptr, Any());
642 OUString sHref
= m_url_expanded
+ "/" + sLic
;
643 OUString sLicense
= getTextFromURL(xCmdEnv
, sHref
);
644 ////determine who has to agree to the license
645 //check correct value for attribute
646 if ( ! (simplLicAttr
->acceptBy
== "user" || simplLicAttr
->acceptBy
== "admin"))
647 throw css::deployment::DeploymentException(
648 "Could not obtain attribute simple-license@accept-by or it has no valid value", nullptr, Any());
651 //Only use interaction if there is no version of this extension already installed
652 //and the suppress-on-update flag is not set for the new extension
653 // alreadyInstalled | bSuppressOnUpdate | show license
660 if ( !(alreadyInstalled
&& simplLicAttr
->suppressOnUpdate
))
662 css::deployment::LicenseException
licExc(
663 OUString(), nullptr, getDisplayName(), sLicense
,
664 simplLicAttr
->acceptBy
);
665 bool approve
= false;
667 if (! interactContinuation(
668 Any(licExc
), cppu::UnoType
<task::XInteractionApprove
>::get(), xCmdEnv
, &approve
, &abort
))
669 throw css::deployment::DeploymentException(
670 "Could not interact with user.", nullptr, Any());
675 } catch (const css::ucb::CommandFailedException
&) {
677 } catch (const css::ucb::CommandAbortedException
&) {
679 } catch (const css::deployment::DeploymentException
&) {
681 } catch (const css::uno::RuntimeException
&) {
683 } catch (const css::uno::Exception
&) {
684 Any anyExc
= cppu::getCaughtException();
685 throw css::deployment::DeploymentException("Unexpected exception", nullptr, anyExc
);
689 ::sal_Int32
BackendImpl::PackageImpl::checkPrerequisites(
690 const css::uno::Reference
< css::task::XAbortChannel
>&,
691 const css::uno::Reference
< css::ucb::XCommandEnvironment
>& xCmdEnv
,
692 sal_Bool alreadyInstalled
)
695 throw deployment::ExtensionRemovedException();
696 DescriptionInfoset info
= getDescriptionInfoset();
697 if (!info
.hasDescription())
700 //always return LICENSE as long as the user did not accept the license
701 //so that XExtensonManager::checkPrerequisitesAndEnable will again
703 if (!checkPlatform(xCmdEnv
))
704 return deployment::Prerequisites::PLATFORM
|
705 deployment::Prerequisites::LICENSE
;
706 else if(!checkDependencies(xCmdEnv
, info
))
707 return deployment::Prerequisites::DEPENDENCIES
|
708 deployment::Prerequisites::LICENSE
;
709 else if(!checkLicense(xCmdEnv
, info
, alreadyInstalled
))
710 return deployment::Prerequisites::LICENSE
;
715 sal_Bool
BackendImpl::PackageImpl::checkDependencies(
716 const css::uno::Reference
< css::ucb::XCommandEnvironment
>& xCmdEnv
)
719 throw deployment::ExtensionRemovedException();
720 DescriptionInfoset info
= getDescriptionInfoset();
721 if (!info
.hasDescription())
724 return checkDependencies(xCmdEnv
, info
);
727 beans::Optional
<OUString
> BackendImpl::PackageImpl::getIdentifier()
731 identifier
= m_identifier
;
733 identifier
= dp_misc::generateIdentifier(
734 getDescriptionInfoset().getIdentifier(), m_name
);
736 return beans::Optional
<OUString
>(
740 OUString
BackendImpl::PackageImpl::getVersion()
743 throw deployment::ExtensionRemovedException();
744 return getDescriptionInfoset().getVersion();
747 Sequence
<OUString
> BackendImpl::PackageImpl::getUpdateInformationURLs()
750 throw deployment::ExtensionRemovedException();
751 return getDescriptionInfoset().getUpdateInformationUrls();
754 beans::StringPair
BackendImpl::PackageImpl::getPublisherInfo()
757 throw deployment::ExtensionRemovedException();
758 std::pair
< OUString
, OUString
> aInfo
= getDescriptionInfoset().getLocalizedPublisherNameAndURL();
759 beans::StringPair
aStrPair( aInfo
.first
, aInfo
.second
);
764 uno::Reference
< graphic::XGraphic
> BackendImpl::PackageImpl::getIcon( sal_Bool bHighContrast
)
767 throw deployment::ExtensionRemovedException();
769 uno::Reference
< graphic::XGraphic
> xGraphic
;
771 OUString aIconURL
= getDescriptionInfoset().getIconURL( bHighContrast
);
772 if ( !aIconURL
.isEmpty() )
774 OUString aFullIconURL
= m_url_expanded
+ "/" + aIconURL
;
776 uno::Reference
< XComponentContext
> xContext( getMyBackend()->getComponentContext() );
777 uno::Reference
< graphic::XGraphicProvider
> xGraphProvider( graphic::GraphicProvider::create(xContext
) );
779 uno::Sequence
< beans::PropertyValue
> aMediaProps( 1 );
780 aMediaProps
[0].Name
= "URL";
781 aMediaProps
[0].Value
<<= aFullIconURL
;
783 xGraphic
= xGraphProvider
->queryGraphic( aMediaProps
);
790 void BackendImpl::PackageImpl::processPackage_(
791 ::osl::ResettableMutexGuard
&,
792 bool doRegisterPackage
,
794 ::rtl::Reference
<AbortChannel
> const & abortChannel
,
795 Reference
<ucb::XCommandEnvironment
> const & xCmdEnv
)
797 const Sequence
< Reference
<deployment::XPackage
> > bundle(
798 getBundle( abortChannel
.get(), xCmdEnv
) );
800 if (doRegisterPackage
)
802 ExtensionBackendDb::Data data
;
803 const sal_Int32 len
= bundle
.getLength();
804 for ( sal_Int32 pos
= 0; pos
< len
; ++pos
)
806 checkAborted(abortChannel
);
807 Reference
<deployment::XPackage
> const & xPackage
= bundle
[ pos
];
808 Reference
<task::XAbortChannel
> xSubAbortChannel(
809 xPackage
->createAbortChannel() );
810 AbortChannel::Chain
chain( abortChannel
, xSubAbortChannel
);
812 xPackage
->registerPackage( startup
, xSubAbortChannel
, xCmdEnv
);
814 catch (const Exception
&)
816 //We even try a rollback if the user cancelled the action (CommandAbortedException)
817 //in order to prevent invalid database entries.
818 Any
exc( ::cppu::getCaughtException() );
819 // try to handle exception, notify:
820 bool approve
= false, abort
= false;
821 if (! interactContinuation(
822 Any( lang::WrappedTargetException(
823 "bundle item registration error!",
824 static_cast<OWeakObject
*>(this), exc
) ),
825 cppu::UnoType
<task::XInteractionApprove
>::get(), xCmdEnv
,
826 &approve
, &abort
)) {
827 OSL_ASSERT( !approve
&& !abort
);
828 if (m_legacyBundle
) // default for legacy packages: ignore
830 // no selection at all, so rethrow;
831 // no C++ rethrow after getCaughtException(),
832 // see cppuhelper/exc_hlp.hxx:
833 ::cppu::throwException(exc
);
835 if (approve
&& !abort
) // ignore error, just continue
839 ProgressLevel
progress( xCmdEnv
, "rollback..." );
844 bundle
[ pos
]->revokePackage(
845 startup
, xSubAbortChannel
, xCmdEnv
);
847 catch (const Exception
&)
849 TOOLS_WARN_EXCEPTION( "desktop", "" );
850 // ignore any errors of rollback
853 progress
.update( "rollback finished." );
856 deployment::DeploymentException dpExc
;
858 throw ucb::CommandFailedException(
859 dpExc
.Message
, dpExc
.Context
, dpExc
.Cause
);
862 // rethrow CommandFailedException
863 ::cppu::throwException(exc
);
866 data
.items
.emplace_back(xPackage
->getURL(),
867 xPackage
->getPackageType()->getMediaType());
869 getMyBackend()->addDataToDb(getURL(), data
);
873 // revoke in reverse order:
874 for ( sal_Int32 pos
= bundle
.getLength(); pos
--; )
876 checkAborted(abortChannel
);
877 Reference
<deployment::XPackage
> const & xPackage
= bundle
[ pos
];
878 Reference
<task::XAbortChannel
> xSubAbortChannel(
879 xPackage
->createAbortChannel() );
880 AbortChannel::Chain
chain( abortChannel
, xSubAbortChannel
);
882 bundle
[ pos
]->revokePackage(
883 startup
, xSubAbortChannel
, xCmdEnv
);
885 catch (const RuntimeException
&) {
888 catch (const ucb::CommandAbortedException
&) {
891 catch (const Exception
&) {
892 // CommandFailedException, DeploymentException:
893 Any
exc( ::cppu::getCaughtException() );
894 // try to handle exception, notify:
895 bool approve
= false, abort
= false;
896 if (! interactContinuation(
897 Any( lang::WrappedTargetException(
898 "bundle item revocation error!",
899 static_cast<OWeakObject
*>(this), exc
) ),
900 cppu::UnoType
<task::XInteractionApprove
>::get(), xCmdEnv
,
901 &approve
, &abort
)) {
902 OSL_ASSERT( !approve
&& !abort
);
903 if (m_legacyBundle
) // default for legacy packages: ignore
905 // no selection at all, so rethrow
906 // no C++ rethrow after getCaughtException(),
907 // see cppuhelper/exc_hlp.hxx:
908 ::cppu::throwException(exc
);
910 // ignore errors when revoking, although abort may have been
914 getMyBackend()->revokeEntryFromDb(getURL());
919 OUString
BackendImpl::PackageImpl::getDescription()
922 throw deployment::ExtensionRemovedException();
924 const OUString
sRelativeURL(getDescriptionInfoset().getLocalizedDescriptionURL());
925 OUString sDescription
;
926 if (!sRelativeURL
.isEmpty())
928 OUString sURL
= m_url_expanded
+ "/" + sRelativeURL
;
932 sDescription
= getTextFromURL( css::uno::Reference
< css::ucb::XCommandEnvironment
>(), sURL
);
934 catch ( const css::deployment::DeploymentException
& )
936 TOOLS_WARN_EXCEPTION( "desktop", "" );
940 if (!sDescription
.isEmpty())
942 return m_oldDescription
;
946 OUString
BackendImpl::PackageImpl::getLicenseText()
949 throw deployment::ExtensionRemovedException();
952 DescriptionInfoset aInfo
= getDescriptionInfoset();
954 ::boost::optional
< SimpleLicenseAttributes
> aSimplLicAttr
= aInfo
.getSimpleLicenseAttributes();
957 OUString aLicenseURL
= aInfo
.getLocalizedLicenseURL();
959 if ( !aLicenseURL
.isEmpty() )
961 OUString aFullURL
= m_url_expanded
+ "/" + aLicenseURL
;
962 sLicense
= getTextFromURL( Reference
< ucb::XCommandEnvironment
>(), aFullURL
);
970 void BackendImpl::PackageImpl::exportTo(
971 OUString
const & destFolderURL
, OUString
const & newTitle
,
972 sal_Int32 nameClashAction
, Reference
<ucb::XCommandEnvironment
> const & xCmdEnv
)
975 throw deployment::ExtensionRemovedException();
977 ::ucbhelper::Content
sourceContent(
978 m_url_expanded
, xCmdEnv
, getMyBackend()->getComponentContext() );
979 OUString
title(newTitle
);
981 sourceContent
.getPropertyValue( "Title" ) >>= title
;
982 OUString
destURL( makeURL( destFolderURL
, ::rtl::Uri::encode(
983 title
, rtl_UriCharClassPchar
,
984 rtl_UriEncodeIgnoreEscapes
,
985 RTL_TEXTENCODING_UTF8
) ) );
987 if (nameClashAction
== ucb::NameClash::ASK
)
989 if (create_ucb_content(
990 nullptr, destURL
, xCmdEnv
, false /* no throw */ )) {
991 bool replace
= false, abort
= false;
992 if (! interactContinuation(
993 Any( ucb::NameClashResolveRequest(
994 "file already exists: " + title
,
995 static_cast<OWeakObject
*>(this),
996 task::InteractionClassification_QUERY
,
997 destFolderURL
, title
, OUString() ) ),
998 cppu::UnoType
<ucb::XInteractionReplaceExistingData
>::get(), xCmdEnv
,
999 &replace
, &abort
) || !replace
) {
1004 else if (nameClashAction
!= ucb::NameClash::OVERWRITE
) {
1005 throw ucb::CommandFailedException("unsupported nameClashAction!",
1006 static_cast<OWeakObject
*>(this), Any() );
1008 erase_path( destURL
, xCmdEnv
);
1011 buf
.append( "vnd.sun.star.zip://" );
1012 buf
.append( ::rtl::Uri::encode( destURL
,
1013 rtl_UriCharClassRegName
,
1014 rtl_UriEncodeIgnoreEscapes
,
1015 RTL_TEXTENCODING_UTF8
) );
1017 OUString
destFolder( buf
.makeStringAndClear() );
1019 ::ucbhelper::Content
destFolderContent(
1020 destFolder
, xCmdEnv
, getMyBackend()->getComponentContext() );
1022 // transfer every item of folder into zip:
1023 Reference
<sdbc::XResultSet
> xResultSet(
1024 sourceContent
.createCursor( Sequence
<OUString
>() ) );
1025 ProgressLevel
progress( xCmdEnv
, OUString() );
1026 while (xResultSet
->next())
1028 ::ucbhelper::Content
subContent(
1029 Reference
<ucb::XContentAccess
>(
1030 xResultSet
, UNO_QUERY_THROW
)->queryContent(),
1031 xCmdEnv
, getMyBackend()->getComponentContext() );
1032 destFolderContent
.transferContent(
1033 subContent
, ::ucbhelper::InsertOperation::Copy
,
1034 OUString(), ucb::NameClash::OVERWRITE
);
1035 progress
.update( Any() ); // animating progress bar
1039 // assure META-INF folder:
1040 ::ucbhelper::Content metainfFolderContent
;
1041 create_folder( &metainfFolderContent
,
1042 makeURL( destFolderContent
.getURL(), "META-INF" ),
1047 // easy to migrate legacy bundles to new format:
1048 // just export them once using a .oxt name!
1049 // set detected media-types of any bundle item:
1051 // collect all manifest entries:
1052 Sequence
< Reference
<deployment::XPackage
> > bundle
;
1054 bundle
= getBundle( Reference
<task::XAbortChannel
>(), xCmdEnv
);
1056 // xxx todo: think about exception specs:
1057 catch (const deployment::DeploymentException
&) {
1058 TOOLS_WARN_EXCEPTION( "desktop", "" );
1060 catch (const lang::IllegalArgumentException
&) {
1061 TOOLS_WARN_EXCEPTION( "desktop", "" );
1064 std::vector
< Sequence
<beans::PropertyValue
> > manifest
;
1065 manifest
.reserve( bundle
.getLength() );
1066 sal_Int32 baseURLlen
= m_url_expanded
.getLength();
1067 Reference
<deployment::XPackage
> const *pbundle
= bundle
.getConstArray();
1068 const OUString
strMediaType( "MediaType" );
1069 const OUString
strFullPath( "FullPath" );
1070 const OUString
strIsFolder( "IsFolder" );
1071 for ( sal_Int32 pos
= bundle
.getLength(); pos
--; )
1073 Reference
<deployment::XPackage
> const & xPackage
= pbundle
[ pos
];
1074 OUString
url_( expandUnoRcUrl( xPackage
->getURL() ) );
1075 OSL_ASSERT( url_
.getLength() >= baseURLlen
);
1077 if (url_
.getLength() > baseURLlen
)
1078 fullPath
= url_
.copy( baseURLlen
+ 1 );
1079 ::ucbhelper::Content
ucbContent(
1080 url_
, xCmdEnv
, getMyBackend()->getComponentContext() );
1081 if (ucbContent
.getPropertyValue(strIsFolder
).get
<bool>())
1083 Sequence
<beans::PropertyValue
> attribs( 2 );
1084 beans::PropertyValue
* pattribs
= attribs
.getArray();
1085 pattribs
[ 0 ].Name
= strFullPath
;
1086 pattribs
[ 0 ].Value
<<= fullPath
;
1087 pattribs
[ 1 ].Name
= strMediaType
;
1088 const Reference
<deployment::XPackageTypeInfo
> xPackageType(
1089 xPackage
->getPackageType() );
1091 OSL_ASSERT( xPackageType
.is() );
1092 if (xPackageType
.is())
1093 mediaType
= xPackageType
->getMediaType();
1095 mediaType
= "unknown";
1096 pattribs
[ 1 ].Value
<<= mediaType
;
1097 manifest
.push_back( attribs
);
1101 Reference
<XComponentContext
> xContext(
1102 getMyBackend()->getComponentContext() );
1103 Reference
<packages::manifest::XManifestWriter
> xManifestWriter
=
1104 packages::manifest::ManifestWriter::create( xContext
);
1105 Reference
<io::XOutputStream
> xPipe( io::Pipe::create(xContext
), UNO_QUERY_THROW
);
1106 xManifestWriter
->writeManifestSequence(
1107 xPipe
, comphelper::containerToSequence(manifest
) );
1109 // write buffered pipe data to content:
1110 ::ucbhelper::Content
manifestContent(
1111 makeURL( metainfFolderContent
.getURL(), "manifest.xml" ),
1112 xCmdEnv
, getMyBackend()->getComponentContext() );
1113 manifestContent
.writeStream(
1114 Reference
<io::XInputStream
>( xPipe
, UNO_QUERY_THROW
),
1115 true /* replace existing */ );
1119 bool bSuccess
= false;
1122 // overwrite manifest.xml:
1123 ::ucbhelper::Content manifestContent
;
1124 if ( ! create_ucb_content(
1126 makeURL( m_url_expanded
, "META-INF/manifest.xml" ),
1129 OSL_FAIL( "### missing META-INF/manifest.xml file!" );
1133 metainfFolderContent
.transferContent(
1134 manifestContent
, ::ucbhelper::InsertOperation::Copy
,
1135 OUString(), ucb::NameClash::OVERWRITE
);
1138 catch (const css::ucb::ContentCreationException
&)
1140 TOOLS_WARN_EXCEPTION("desktop.deployment", "exception on overwriting manifest");
1144 throw RuntimeException( "UCB transferContent() failed!",
1145 static_cast<OWeakObject
*>(this) );
1148 // xxx todo: maybe obsolete in the future
1150 destFolderContent
.executeCommand( "flush", Any() );
1152 catch (const ucb::UnsupportedCommandException
&) {
1157 sal_Bool
BackendImpl::PackageImpl::isBundle()
1163 Sequence
< Reference
<deployment::XPackage
> > BackendImpl::PackageImpl::getBundle(
1164 Reference
<task::XAbortChannel
> const & xAbortChannel
,
1165 Reference
<ucb::XCommandEnvironment
> const & xCmdEnv
)
1167 Sequence
< Reference
<deployment::XPackage
> > * pBundle
= m_pBundle
;
1168 if (pBundle
== nullptr)
1170 t_packagevec bundle
;
1173 bundle
= getPackagesFromDb(xCmdEnv
);
1180 // .zip legacy packages allow script.xlb, dialog.xlb in bundle
1183 // probe for script.xlb:
1184 if (create_ucb_content(
1185 nullptr, makeURL( m_url_expanded
, "script.xlb" ),
1186 xCmdEnv
, false /* no throw */ )) {
1187 mediaType
= "application/vnd.sun.star.basic-library";
1189 // probe for dialog.xlb:
1190 else if (create_ucb_content(
1191 nullptr, makeURL( m_url_expanded
, "dialog.xlb" ),
1192 xCmdEnv
, false /* no throw */ ))
1193 mediaType
= "application/vnd.sun.star.dialog-library";
1195 if (!mediaType
.isEmpty()) {
1196 const Reference
<deployment::XPackage
> xPackage(
1197 bindBundleItem( getURL(), mediaType
, false, OUString(),
1200 bundle
.push_back( xPackage
);
1201 // continue scanning:
1203 scanLegacyBundle( bundle
, getURL(),
1204 AbortChannel::get(xAbortChannel
), xCmdEnv
);
1209 scanBundle( bundle
, AbortChannel::get(xAbortChannel
), xCmdEnv
);
1213 catch (const RuntimeException
&) {
1216 catch (const ucb::CommandFailedException
&) {
1219 catch (const ucb::CommandAbortedException
&) {
1222 catch (const deployment::DeploymentException
&) {
1225 catch (const Exception
&) {
1226 Any
exc( ::cppu::getCaughtException() );
1227 throw deployment::DeploymentException(
1228 "error scanning bundle: " + getURL(),
1229 static_cast<OWeakObject
*>(this), exc
);
1233 // sort: schema before config data, typelibs before components:
1234 Sequence
< Reference
<deployment::XPackage
> > ret( bundle
.size() );
1235 Reference
<deployment::XPackage
> * pret
= ret
.getArray();
1236 sal_Int32 lower_end
= 0;
1237 sal_Int32 upper_end
= ret
.getLength();
1238 for (auto const& elem
: bundle
)
1240 const Reference
<deployment::XPackageTypeInfo
> xPackageType(
1241 elem
->getPackageType() );
1242 OSL_ASSERT( xPackageType
.is() );
1243 if (xPackageType
.is())
1245 const OUString
mediaType( xPackageType
->getMediaType() );
1246 OUString type
, subType
;
1247 INetContentTypeParameterList params
;
1248 if (INetContentTypes::parse( mediaType
, type
, subType
, ¶ms
) &&
1249 type
.equalsIgnoreAsciiCase("application") &&
1250 (subType
.equalsIgnoreAsciiCase( "vnd.sun.star.uno-component") ||
1251 subType
.equalsIgnoreAsciiCase( "vnd.sun.star.configuration-data")))
1254 pret
[ upper_end
] = elem
;
1258 pret
[ lower_end
] = elem
;
1261 OSL_ASSERT( lower_end
== upper_end
);
1263 const ::osl::MutexGuard
guard( getMutex() );
1264 pBundle
= m_pBundle
;
1265 if (pBundle
== nullptr) {
1267 pBundle
= &m_bundle
;
1268 OSL_DOUBLE_CHECKED_LOCKING_MEMORY_BARRIER();
1269 m_pBundle
= pBundle
;
1273 OSL_DOUBLE_CHECKED_LOCKING_MEMORY_BARRIER();
1278 bool isBundle_( OUString
const & mediaType
)
1280 // xxx todo: additional parsing?
1281 return !mediaType
.isEmpty() &&
1282 (mediaType
.matchIgnoreAsciiCase( "application/vnd.sun.star.package-bundle") ||
1283 mediaType
.matchIgnoreAsciiCase( "application/vnd.sun.star.legacy-package-bundle"));
1287 Reference
<deployment::XPackage
> BackendImpl::PackageImpl::bindBundleItem(
1288 OUString
const & url
, OUString
const & mediaType
,
1289 bool bRemoved
, OUString
const & identifier
,
1290 Reference
<ucb::XCommandEnvironment
> const & xCmdEnv
,
1291 bool notifyDetectionError
)
1293 // ignore any nested bundles:
1294 if (isBundle_(mediaType
))
1295 return Reference
<deployment::XPackage
>();
1297 Reference
<deployment::XPackage
>xPackage
;
1300 xPackage
.set( getMyBackend()->m_xRootRegistry
->bindPackage(
1301 url
, mediaType
, bRemoved
, identifier
, xCmdEnv
) );
1302 OSL_ASSERT( xPackage
.is() );
1303 } catch (css::lang::IllegalArgumentException
& e
) {
1304 css::uno::Any
exc(cppu::getCaughtException());
1305 throw css::lang::WrappedTargetException(
1306 "wrapped: " + e
.Message
, e
.Context
, exc
);
1309 catch (const RuntimeException
&) {
1312 catch (const ucb::CommandFailedException
&) {
1313 // ignore already handled error
1315 catch (const Exception
&) {
1316 const Any
exc( ::cppu::getCaughtException() );
1317 if (notifyDetectionError
||
1318 !exc
.isExtractableTo( cppu::UnoType
<lang::IllegalArgumentException
>::get()) )
1320 (void)interactContinuation(
1321 Any( lang::WrappedTargetException("bundle item error!",
1322 static_cast<OWeakObject
*>(this), exc
) ),
1323 cppu::UnoType
<task::XInteractionApprove
>::get(), xCmdEnv
, nullptr, nullptr );
1327 if (xPackage
.is()) {
1328 const Reference
<deployment::XPackageTypeInfo
> xPackageType(
1329 xPackage
->getPackageType() );
1330 OSL_ASSERT( xPackageType
.is() );
1331 // ignore any nested bundles:
1332 if (xPackageType
.is() && isBundle_( xPackageType
->getMediaType() ))
1339 void BackendImpl::PackageImpl::scanBundle(
1340 t_packagevec
& bundle
,
1341 ::rtl::Reference
<AbortChannel
> const & abortChannel
,
1342 Reference
<ucb::XCommandEnvironment
> const & xCmdEnv
)
1344 OSL_ASSERT( !m_legacyBundle
);
1346 OUString
mfUrl( makeURL( m_url_expanded
, "META-INF/manifest.xml" ) );
1347 ::ucbhelper::Content manifestContent
;
1348 if (! create_ucb_content(
1349 &manifestContent
, mfUrl
, xCmdEnv
, false /* no throw */ ))
1352 "desktop.deployment",
1353 "cannot create UCB Content for <" << mfUrl
<< ">" );
1358 const LanguageTag
& officeLocale
= getOfficeLanguageTag();
1359 const std::vector
< OUString
> officeFallbacks( officeLocale
.getFallbackStrings( true));
1360 const size_t nPenaltyMax
= std::numeric_limits
<size_t>::max();
1361 size_t descrPenalty
= nPenaltyMax
;
1364 const Reference
<XComponentContext
> xContext(
1365 getMyBackend()->getComponentContext() );
1366 Reference
<packages::manifest::XManifestReader
> xManifestReader
=
1367 packages::manifest::ManifestReader::create( xContext
);
1368 const Sequence
< Sequence
<beans::PropertyValue
> > manifestSeq(
1369 xManifestReader
->readManifestSequence( manifestContent
.openStream() ) );
1370 const OUString
packageRootURL( getURL() );
1371 for ( sal_Int32 pos
= manifestSeq
.getLength(); pos
--; )
1373 OUString fullPath
, mediaType
;
1374 Sequence
<beans::PropertyValue
> const & attribs
= manifestSeq
[ pos
];
1375 for ( sal_Int32 i
= attribs
.getLength(); i
--; )
1377 if (!(fullPath
.isEmpty() || mediaType
.isEmpty()))
1379 if ( attribs
[i
].Name
== "FullPath" )
1380 attribs
[i
].Value
>>= fullPath
;
1381 else if ( attribs
[i
].Name
== "MediaType" )
1382 attribs
[i
].Value
>>= mediaType
;
1385 if ( fullPath
.isEmpty() || mediaType
.isEmpty() || mediaType
== "text/xml" )// opt: exclude common text/xml
1388 OUString type
, subType
;
1389 INetContentTypeParameterList params
;
1390 if (! INetContentTypes::parse( mediaType
, type
, subType
, ¶ms
))
1394 auto const iter
= params
.find("platform");
1395 if (iter
!= params
.end() && !platform_fits(iter
->second
.m_sValue
))
1398 const OUString
url( makeURL( packageRootURL
, fullPath
) );
1400 // check for bundle description:
1401 if (type
.equalsIgnoreAsciiCase("application") &&
1402 subType
.equalsIgnoreAsciiCase( "vnd.sun.star.package-bundle-description"))
1405 auto const iter
= params
.find("locale");
1406 if (iter
== params
.end())
1408 if (descrFile
.isEmpty())
1412 // match best locale:
1413 LanguageTag
descrTag(iter
->second
.m_sValue
);
1414 if (officeLocale
.getLanguage() == descrTag
.getLanguage())
1416 size_t nPenalty
= nPenaltyMax
;
1417 const std::vector
< OUString
> descrFallbacks( descrTag
.getFallbackStrings( true));
1418 for (size_t o
=0; o
< officeFallbacks
.size() && nPenalty
== nPenaltyMax
; ++o
)
1420 for (size_t d
=0; d
< descrFallbacks
.size() && nPenalty
== nPenaltyMax
; ++d
)
1422 if (officeFallbacks
[o
] == descrFallbacks
[d
])
1424 // The last fallbacks are always language-only
1425 // fallbacks, so we _will_ have _some_ match if
1426 // we ever entered the overall if() condition.
1427 nPenalty
= o
* 1000 + d
;
1428 if (descrPenalty
> nPenalty
)
1430 descrPenalty
= nPenalty
;
1437 // TODO: we could break here if descrPenalty==0 for an exact
1438 // match of officeLocale, but the previous code didn't; are
1439 // there side effects?
1444 checkAborted( abortChannel
);
1446 //We make sure that we only create one XPackage for a particular URL.
1447 //Sometime programmers insert the same URL several times in the manifest
1448 //which may lead to DisposedExceptions.
1449 if (std::none_of(bundle
.begin(), bundle
.end(), XPackage_eq(url
)))
1451 const Reference
<deployment::XPackage
> xPackage(
1452 bindBundleItem( url
, mediaType
, false, OUString(), xCmdEnv
) );
1454 bundle
.push_back( xPackage
);
1458 SAL_WARN("desktop.deployment", "manifest.xml contains a duplicate entry (from " << url
<< ")");
1462 if (!descrFile
.isEmpty())
1464 ::ucbhelper::Content descrFileContent
;
1465 if (create_ucb_content( &descrFileContent
, descrFile
,
1466 xCmdEnv
, false /* no throw */ ))
1468 // patch description:
1469 std::vector
<sal_Int8
> bytes( readFile( descrFileContent
) );
1471 if ( !bytes
.empty() )
1473 buf
.append( OUString( reinterpret_cast<sal_Char
const *>(
1475 bytes
.size(), RTL_TEXTENCODING_UTF8
) );
1479 buf
.append( Package::getDescription() );
1481 m_oldDescription
= buf
.makeStringAndClear();
1487 void BackendImpl::PackageImpl::scanLegacyBundle(
1488 t_packagevec
& bundle
,
1489 OUString
const & url
,
1490 ::rtl::Reference
<AbortChannel
> const & abortChannel
,
1491 Reference
<ucb::XCommandEnvironment
> const & xCmdEnv
,
1492 bool skip_registration
)
1494 ::ucbhelper::Content
ucbContent(
1495 url
, xCmdEnv
, getMyBackend()->getComponentContext() );
1497 // check for platform paths:
1498 const OUString
title( StrTitle::getTitle( ucbContent
) );
1499 if (title
.endsWithIgnoreAsciiCase( ".plt" ) &&
1500 !platform_fits( title
.copy( 0, title
.getLength() - 4 ) )) {
1503 if (title
.endsWithIgnoreAsciiCase("skip_registration") )
1504 skip_registration
= true;
1506 Sequence
<OUString
> ar
{ OUString("Title"), OUString("IsFolder") };
1507 Reference
<sdbc::XResultSet
> xResultSet( ucbContent
.createCursor( ar
) );
1508 while (xResultSet
->next())
1510 checkAborted( abortChannel
);
1512 const Reference
<sdbc::XRow
> xRow( xResultSet
, UNO_QUERY_THROW
);
1513 const OUString
title_enc( ::rtl::Uri::encode(
1514 xRow
->getString( 1 /* Title */ ),
1515 rtl_UriCharClassPchar
,
1516 rtl_UriEncodeIgnoreEscapes
,
1517 RTL_TEXTENCODING_UTF8
) );
1518 const OUString
path( makeURL( url
, title_enc
) );
1521 const Reference
<deployment::XPackage
> xPackage(
1522 bindBundleItem( path
, OUString() /* detect */, false, OUString(),
1523 xCmdEnv
, false /* ignore detection errors */ ) );
1524 if (xPackage
.is()) {
1525 const Reference
<deployment::XPackageTypeInfo
> xPackageType(
1526 xPackage
->getPackageType() );
1527 OSL_ASSERT( xPackageType
.is() );
1528 if (xPackageType
.is())
1529 mediaType
= xPackageType
->getMediaType();
1531 if (skip_registration
&&
1532 // xxx todo: additional parsing?
1533 mediaType
.matchIgnoreAsciiCase("application/vnd.sun.star.uno-component"))
1536 bundle
.push_back( xPackage
);
1539 if (mediaType
.isEmpty() ||
1540 // script.xlb, dialog.xlb can be met everywhere:
1541 mediaType
.matchIgnoreAsciiCase("application/vnd.sun.star.basic-library") ||
1542 mediaType
.matchIgnoreAsciiCase("application/vnd.sun.star.dialog-library"))
1544 if (xRow
->getBoolean( 2 /* IsFolder */ )) { // recurse into folder:
1546 bundle
, path
, abortChannel
, xCmdEnv
, skip_registration
);
1552 OUString
BackendImpl::PackageImpl::getDisplayName()
1555 throw deployment::ExtensionRemovedException();
1557 OUString sName
= getDescriptionInfoset().getLocalizedDisplayName();
1558 if (sName
.isEmpty())
1559 return m_displayName
;
1564 std::vector
<Reference
<deployment::XPackage
> >
1565 BackendImpl::PackageImpl::getPackagesFromDb(
1566 Reference
<ucb::XCommandEnvironment
> const & xCmdEnv
)
1568 std::vector
<Reference
<deployment::XPackage
> > retVector
;
1570 for (auto const& item
: m_dbData
.items
)
1572 Reference
<deployment::XPackage
> xExtension
=
1573 bindBundleItem(item
.first
, item
.second
, true, m_identifier
, xCmdEnv
);
1574 OSL_ASSERT(xExtension
.is());
1575 if (xExtension
.is())
1576 retVector
.push_back(xExtension
);
1585 Reference
<deployment::XPackageRegistry
> create(
1586 Reference
<deployment::XPackageRegistry
> const & xRootRegistry
,
1587 OUString
const & context
, OUString
const & cachePath
,
1588 Reference
<XComponentContext
> const & xComponentContext
)
1590 Sequence
<Any
> args(cachePath
.isEmpty() ? 1 : 3 );
1591 args
[ 0 ] <<= context
;
1592 if (!cachePath
.isEmpty()) {
1593 args
[ 1 ] <<= cachePath
;
1594 args
[ 2 ] <<= false; // readOnly
1596 return new BackendImpl( args
, xComponentContext
, xRootRegistry
);
1599 } // namespace bundle
1600 } // namespace backend
1601 } // namespace dp_registry
1603 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */