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>
26 #include <dp_interact.h>
27 #include <dp_dependencies.hxx>
28 #include <dp_platform.hxx>
29 #include <dp_descriptioninfoset.hxx>
30 #include <dp_identifier.hxx>
31 #include <dp_resource.h>
32 #include <rtl/uri.hxx>
33 #include <rtl/ustrbuf.hxx>
34 #include <sal/log.hxx>
35 #include <o3tl/string_view.hxx>
36 #include <cppuhelper/exc_hlp.hxx>
37 #include <cppuhelper/implbase.hxx>
38 #include <cppuhelper/supportsservice.hxx>
39 #include <ucbhelper/content.hxx>
40 #include <svl/inettype.hxx>
41 #include <comphelper/propertyvalue.hxx>
42 #include <comphelper/sequence.hxx>
43 #include <com/sun/star/lang/WrappedTargetException.hpp>
44 #include <com/sun/star/graphic/XGraphic.hpp>
45 #include <com/sun/star/graphic/GraphicProvider.hpp>
46 #include <com/sun/star/graphic/XGraphicProvider.hpp>
47 #include <com/sun/star/io/Pipe.hpp>
48 #include <com/sun/star/io/XOutputStream.hpp>
49 #include <com/sun/star/io/XInputStream.hpp>
50 #include <com/sun/star/task/InteractionClassification.hpp>
51 #include <com/sun/star/task/XInteractionApprove.hpp>
52 #include <com/sun/star/ucb/CommandAbortedException.hpp>
53 #include <com/sun/star/ucb/CommandFailedException.hpp>
54 #include <com/sun/star/ucb/ContentCreationException.hpp>
55 #include <com/sun/star/ucb/XInteractionReplaceExistingData.hpp>
56 #include <com/sun/star/ucb/NameClashResolveRequest.hpp>
57 #include <com/sun/star/ucb/XContentAccess.hpp>
58 #include <com/sun/star/ucb/NameClash.hpp>
59 #include <com/sun/star/ucb/UnsupportedCommandException.hpp>
60 #include <com/sun/star/sdbc/XResultSet.hpp>
61 #include <com/sun/star/sdbc/XRow.hpp>
62 #include <com/sun/star/packages/manifest/ManifestReader.hpp>
63 #include <com/sun/star/packages/manifest/ManifestWriter.hpp>
64 #include <com/sun/star/deployment/DependencyException.hpp>
65 #include <com/sun/star/deployment/DeploymentException.hpp>
66 #include <com/sun/star/deployment/ExtensionRemovedException.hpp>
67 #include <com/sun/star/deployment/LicenseException.hpp>
68 #include <com/sun/star/deployment/PlatformException.hpp>
69 #include <com/sun/star/deployment/Prerequisites.hpp>
71 #include <comphelper/diagnose_ex.hxx>
75 #include <string_view>
79 #include "dp_extbackenddb.hxx"
80 using namespace ::dp_misc
;
81 using namespace ::com::sun::star
;
82 using namespace ::com::sun::star::uno
;
85 namespace dp_registry::backend::bundle
{
88 typedef cppu::ImplInheritanceHelper
<PackageRegistryBackend
> ImplBaseT
;
91 class BackendImpl
: public ImplBaseT
93 class PackageImpl
: public ::dp_registry::backend::Package
95 BackendImpl
* getMyBackend() const;
96 /** contains the old tooltip description for the Extension Manager GUI in OOo v.2.x
97 We keep it for backward compatibility.
99 OUString m_oldDescription
;
100 OUString m_url_expanded
;
101 const bool m_legacyBundle
;
102 Sequence
< Reference
<deployment::XPackage
> > m_bundle
;
103 Sequence
< Reference
<deployment::XPackage
> > * m_pBundle
;
105 ExtensionBackendDb::Data m_dbData
;
107 Reference
<deployment::XPackage
> bindBundleItem(
108 OUString
const & url
, OUString
const & mediaType
,
109 bool bRemoved
, //that is, using data base information
110 OUString
const & identifier
,
111 Reference
<ucb::XCommandEnvironment
> const & xCmdEnv
,
112 bool notifyDetectionError
= true );
114 typedef std::vector
< Reference
<deployment::XPackage
> > t_packagevec
;
116 t_packagevec
& bundle
,
117 ::rtl::Reference
<AbortChannel
> const & abortChannel
,
118 Reference
<ucb::XCommandEnvironment
> const & xCmdEnv
);
119 void scanLegacyBundle(
120 t_packagevec
& bundle
,
121 OUString
const & url
,
122 ::rtl::Reference
<AbortChannel
> const & abortChannel
,
123 Reference
<ucb::XCommandEnvironment
> const & xCmdEnv
,
124 bool skip_registration
= false );
125 std::vector
<Reference
<deployment::XPackage
> > getPackagesFromDb(
126 Reference
<ucb::XCommandEnvironment
> const & xCmdEnv
);
128 Reference
<ucb::XCommandEnvironment
> const & environment
);
130 bool checkDependencies(
131 Reference
<ucb::XCommandEnvironment
> const &
133 DescriptionInfoset
const & description
);
134 // throws css::uno::RuntimeException,
135 // css::deployment::DeploymentException
137 /// @throws deployment::DeploymentException
138 /// @throws ucb::CommandFailedException
139 /// @throws ucb::CommandAbortedException
140 /// @throws RuntimeException
142 Reference
< ucb::XCommandEnvironment
> const & xCmdEnv
,
143 DescriptionInfoset
const & description
, bool bNoLicenseChecking
);
144 // @throws DeploymentException
145 OUString
getTextFromURL(
146 const Reference
< ucb::XCommandEnvironment
>& xCmdEnv
,
147 const OUString
& licenseUrl
);
149 DescriptionInfoset
getDescriptionInfoset() const;
152 virtual beans::Optional
< beans::Ambiguous
<sal_Bool
> > isRegistered_(
153 ::osl::ResettableMutexGuard
& guard
,
154 ::rtl::Reference
<AbortChannel
> const & abortChannel
,
155 Reference
<ucb::XCommandEnvironment
> const & xCmdEnv
) override
;
156 virtual void processPackage_(
157 ::osl::ResettableMutexGuard
& guard
,
158 bool registerPackage
,
160 ::rtl::Reference
<AbortChannel
> const & abortChannel
,
161 Reference
<ucb::XCommandEnvironment
> const & xCmdEnv
) override
;
163 virtual void SAL_CALL
disposing() override
;
168 ::rtl::Reference
<PackageRegistryBackend
> const & myBackend
,
169 OUString
const & url
,
170 OUString
const & name
,
171 Reference
<deployment::XPackageTypeInfo
> const & xPackageType
,
174 OUString
const & identifier
);
177 virtual sal_Bool SAL_CALL
isBundle() override
;
179 virtual Sequence
< Reference
<deployment::XPackage
> > SAL_CALL
getBundle(
180 Reference
<task::XAbortChannel
> const & xAbortChannel
,
181 Reference
<ucb::XCommandEnvironment
> const & xCmdEnv
) override
;
182 virtual OUString SAL_CALL
getDescription() override
;
184 virtual OUString SAL_CALL
getLicenseText() override
;
186 virtual void SAL_CALL
exportTo(
187 OUString
const & destFolderURL
, OUString
const & newTitle
,
188 sal_Int32 nameClashAction
,
189 Reference
<ucb::XCommandEnvironment
> const & xCmdEnv
) override
;
191 virtual ::sal_Int32 SAL_CALL
checkPrerequisites(
192 const Reference
< task::XAbortChannel
>& xAbortChannel
,
193 const Reference
< ucb::XCommandEnvironment
>& xCmdEnv
,
194 sal_Bool noLicenseChecking
) override
;
196 virtual sal_Bool SAL_CALL
checkDependencies(
197 const Reference
< ucb::XCommandEnvironment
>& xCmdEnv
) override
;
199 virtual beans::Optional
<OUString
> SAL_CALL
getIdentifier() override
;
201 virtual OUString SAL_CALL
getVersion() override
;
203 virtual Sequence
<OUString
> SAL_CALL
getUpdateInformationURLs() override
;
205 virtual beans::StringPair SAL_CALL
getPublisherInfo() override
;
207 virtual OUString SAL_CALL
getDisplayName() override
;
209 virtual Reference
< graphic::XGraphic
> SAL_CALL
210 getIcon( sal_Bool bHighContrast
) override
;
212 friend class PackageImpl
;
214 Reference
<deployment::XPackageRegistry
> m_xRootRegistry
;
215 const Reference
<deployment::XPackageTypeInfo
> m_xBundleTypeInfo
;
216 const Reference
<deployment::XPackageTypeInfo
> m_xLegacyBundleTypeInfo
;
217 Sequence
< Reference
<deployment::XPackageTypeInfo
> > m_typeInfos
;
219 std::unique_ptr
<ExtensionBackendDb
> m_backendDb
;
221 void addDataToDb(OUString
const & url
, ExtensionBackendDb::Data
const & data
);
222 ExtensionBackendDb::Data
readDataFromDb(std::u16string_view url
);
223 void revokeEntryFromDb(std::u16string_view url
);
225 // PackageRegistryBackend
226 virtual Reference
<deployment::XPackage
> bindPackage_(
227 OUString
const & url
, OUString
const & mediaType
,
228 bool bRemoved
, OUString
const & identifier
,
229 Reference
<ucb::XCommandEnvironment
> const & xCmdEnv
) override
;
231 virtual void SAL_CALL
disposing() override
;
235 Sequence
<Any
> const & args
,
236 Reference
<XComponentContext
> const & xComponentContext
,
237 Reference
<deployment::XPackageRegistry
> const & xRootRegistry
);
240 virtual OUString SAL_CALL
getImplementationName() override
;
241 virtual sal_Bool SAL_CALL
supportsService( OUString
const& name
) override
;
242 virtual Sequence
<OUString
> SAL_CALL
getSupportedServiceNames() override
;
245 virtual Sequence
< Reference
<deployment::XPackageTypeInfo
> > SAL_CALL
246 getSupportedPackageTypes() override
;
247 virtual void SAL_CALL
packageRemoved(OUString
const & url
, OUString
const & mediaType
) override
;
249 using ImplBaseT::disposing
;
252 //Used to find a XPackage with a particular URL
257 explicit XPackage_eq(OUString s
) : m_URL(std::move(s
)) {}
258 bool operator() (const Reference
<deployment::XPackage
> & p
) const
260 return m_URL
== p
->getURL();
265 BackendImpl::BackendImpl(
266 Sequence
<Any
> const & args
,
267 Reference
<XComponentContext
> const & xComponentContext
,
268 Reference
<deployment::XPackageRegistry
> const & xRootRegistry
)
269 : ImplBaseT( args
, xComponentContext
),
270 m_xRootRegistry( xRootRegistry
),
271 m_xBundleTypeInfo( new Package::TypeInfo(
272 u
"application/vnd.sun.star.package-bundle"_ustr
,
273 u
"*.oxt;*.uno.pkg"_ustr
,
274 DpResId(RID_STR_PACKAGE_BUNDLE
)
276 m_xLegacyBundleTypeInfo( new Package::TypeInfo(
277 u
"application/vnd.sun.star.legacy-package-bundle"_ustr
,
279 m_xBundleTypeInfo
->getShortDescription()
281 m_typeInfos
{ m_xBundleTypeInfo
, m_xLegacyBundleTypeInfo
}
283 if (!transientMode())
285 OUString dbFile
= makeURL(getCachePath(), getImplementationName());
286 dbFile
= makeURL(dbFile
, u
"backenddb.xml"_ustr
);
288 new ExtensionBackendDb(getComponentContext(), dbFile
));
293 void BackendImpl::disposing()
295 m_xRootRegistry
.clear();
296 PackageRegistryBackend::disposing();
300 OUString
BackendImpl::getImplementationName()
302 return u
"com.sun.star.comp.deployment.bundle.PackageRegistryBackend"_ustr
;
305 sal_Bool
BackendImpl::supportsService(OUString
const & ServiceName
)
307 return cppu::supportsService(this, ServiceName
);
310 Sequence
<OUString
> BackendImpl::getSupportedServiceNames()
312 return { BACKEND_SERVICE_NAME
};
317 Sequence
< Reference
<deployment::XPackageTypeInfo
> >
318 BackendImpl::getSupportedPackageTypes()
323 void BackendImpl::packageRemoved(OUString
const & url
, OUString
const & /*mediaType*/)
325 //Notify the backend responsible for processing the different media
326 //types that this extension was removed.
327 ExtensionBackendDb::Data data
= readDataFromDb(url
);
328 for (auto const& item
: data
.items
)
330 m_xRootRegistry
->packageRemoved(item
.first
, item
.second
);
334 m_backendDb
->removeEntry(url
);
338 // PackageRegistryBackend
340 Reference
<deployment::XPackage
> BackendImpl::bindPackage_(
341 OUString
const & url
, OUString
const & mediaType_
,
342 bool bRemoved
, OUString
const & identifier
,
343 Reference
<ucb::XCommandEnvironment
> const & xCmdEnv
)
345 OUString
mediaType( mediaType_
);
346 if (mediaType
.isEmpty())
348 // detect media-type:
349 ::ucbhelper::Content ucbContent
;
350 if (create_ucb_content( &ucbContent
, url
, xCmdEnv
))
352 if (ucbContent
.isFolder())
354 //Every .oxt, uno.pkg file must contain a META-INF folder
355 ::ucbhelper::Content metaInfContent
;
356 if (create_ucb_content(
357 &metaInfContent
, makeURL( url
, u
"META-INF"_ustr
),
358 xCmdEnv
, false /* no throw */ ))
360 mediaType
= "application/vnd.sun.star.package-bundle";
362 //No support of legacy bundles, because every folder could be one.
366 const OUString
title( StrTitle::getTitle( ucbContent
) );
367 if (title
.endsWithIgnoreAsciiCase(".oxt") ||
368 title
.endsWithIgnoreAsciiCase(".uno.pkg"))
369 mediaType
= "application/vnd.sun.star.package-bundle";
370 else if (title
.endsWithIgnoreAsciiCase(".zip"))
371 mediaType
= "application/vnd.sun.star.legacy-package-bundle";
374 if (mediaType
.isEmpty())
375 throw lang::IllegalArgumentException(
376 StrCannotDetectMediaType() + url
,
377 static_cast<OWeakObject
*>(this), static_cast<sal_Int16
>(-1) );
380 OUString type
, subType
;
381 INetContentTypeParameterList params
;
382 if (INetContentTypes::parse( mediaType
, type
, subType
, ¶ms
))
384 if (type
.equalsIgnoreAsciiCase("application"))
387 //In case a XPackage is created for a removed extension, we cannot
392 ::ucbhelper::Content
ucbContent(
393 url
, xCmdEnv
, getComponentContext() );
394 name
= StrTitle::getTitle( ucbContent
);
396 if (subType
.equalsIgnoreAsciiCase("vnd.sun.star.package-bundle"))
398 return new PackageImpl(
399 this, url
, name
, m_xBundleTypeInfo
, false, bRemoved
,
402 else if (subType
.equalsIgnoreAsciiCase( "vnd.sun.star.legacy-package-bundle"))
404 return new PackageImpl(
405 this, url
, name
, m_xLegacyBundleTypeInfo
, true, bRemoved
,
410 throw lang::IllegalArgumentException(
411 StrUnsupportedMediaType() + mediaType
,
412 static_cast<OWeakObject
*>(this),
413 static_cast<sal_Int16
>(-1) );
416 void BackendImpl::addDataToDb(
417 OUString
const & url
, ExtensionBackendDb::Data
const & data
)
420 m_backendDb
->addEntry(url
, data
);
423 ExtensionBackendDb::Data
BackendImpl::readDataFromDb(
424 std::u16string_view url
)
426 ExtensionBackendDb::Data data
;
428 data
= m_backendDb
->getEntry(url
);
432 void BackendImpl::revokeEntryFromDb(std::u16string_view url
)
435 m_backendDb
->revokeEntry(url
);
439 BackendImpl::PackageImpl::PackageImpl(
440 ::rtl::Reference
<PackageRegistryBackend
> const & myBackend
,
441 OUString
const & url
,
442 OUString
const & name
,
443 Reference
<deployment::XPackageTypeInfo
> const & xPackageType
,
444 bool legacyBundle
, bool bRemoved
, OUString
const & identifier
)
445 : Package( myBackend
, url
, name
, name
/* display-name */,
446 xPackageType
, bRemoved
, identifier
),
447 m_url_expanded( expandUnoRcUrl( url
) ),
448 m_legacyBundle( legacyBundle
),
452 m_dbData
= getMyBackend()->readDataFromDb(url
);
455 BackendImpl
* BackendImpl::PackageImpl::getMyBackend() const
457 BackendImpl
* pBackend
= static_cast<BackendImpl
*>(m_myBackend
.get());
458 if (nullptr == pBackend
)
460 //May throw a DisposedException
462 //We should never get here...
463 throw RuntimeException(u
"Failed to get the BackendImpl"_ustr
,
464 static_cast<OWeakObject
*>(const_cast<PackageImpl
*>(this)));
469 void BackendImpl::PackageImpl::disposing()
471 for (auto& xPackage
: m_bundle
)
472 try_dispose(xPackage
);
473 m_bundle
.realloc( 0 );
475 Package::disposing();
480 beans::Optional
< beans::Ambiguous
<sal_Bool
> >
481 BackendImpl::PackageImpl::isRegistered_(
482 ::osl::ResettableMutexGuard
&,
483 ::rtl::Reference
<AbortChannel
> const & abortChannel
,
484 Reference
<ucb::XCommandEnvironment
> const & xCmdEnv
)
486 //In case the object was created for a removed extension (m_bRemoved = true)
487 //but the extension is not registered, then bundle will be empty. Then
488 //the return value will be Optional<...>.IsPresent= false. Although this is
489 //not true, this does not matter. Then registerPackage or revokePackage
490 //would never be called for the items. But since the extension is removed
491 //and not registered anyway, this does not matter.
492 const Sequence
< Reference
<deployment::XPackage
> > bundle(
493 getBundle( abortChannel
, xCmdEnv
) );
496 bool present
= false;
498 for ( sal_Int32 pos
= bundle
.getLength(); pos
--; )
500 Reference
<deployment::XPackage
> const & xPackage
= bundle
[ pos
];
501 Reference
<task::XAbortChannel
> xSubAbortChannel(
502 xPackage
->createAbortChannel() );
503 AbortChannel::Chain
chain( abortChannel
, xSubAbortChannel
);
504 beans::Optional
< beans::Ambiguous
<sal_Bool
> > option(
505 xPackage
->isRegistered( xSubAbortChannel
, xCmdEnv
) );
507 //present = true if at least one bundle item has this value.
508 //reg = true if all bundle items have an option value (option.IsPresent == 1)
509 //and all have value of true (option.Value.Value == true)
510 //If not, then the bundle has the status of not registered and ambiguous.
511 if (option
.IsPresent
)
513 beans::Ambiguous
<sal_Bool
> const & status
= option
.Value
;
516 //we never come here in the first iteration
517 if (reg
!= bool(status
.Value
)) {
526 //we always come here in the first iteration
532 return beans::Optional
< beans::Ambiguous
<sal_Bool
> >(
533 present
, beans::Ambiguous
<sal_Bool
>(reg
, ambig
) );
536 OUString
BackendImpl::PackageImpl::getTextFromURL(
537 const css::uno::Reference
< css::ucb::XCommandEnvironment
>& xCmdEnv
,
538 const OUString
& licenseUrl
)
542 ::ucbhelper::Content
descContent(
543 licenseUrl
, xCmdEnv
, getMyBackend()->getComponentContext());
544 std::vector
<sal_Int8
> seq
= dp_misc::readFile(descContent
);
545 return OUString( reinterpret_cast<char const *>(
546 seq
.data()), seq
.size(), RTL_TEXTENCODING_UTF8
);
548 catch (const css::uno::Exception
&)
550 Any
exc( ::cppu::getCaughtException() );
551 throw css::deployment::DeploymentException(
552 "Could not read file " + licenseUrl
, nullptr, exc
);
557 DescriptionInfoset
BackendImpl::PackageImpl::getDescriptionInfoset() const
559 return dp_misc::getDescriptionInfoset(m_url_expanded
);
562 bool BackendImpl::PackageImpl::checkPlatform(
563 css::uno::Reference
< css::ucb::XCommandEnvironment
> const & environment
)
566 DescriptionInfoset
info(getDescriptionInfoset());
567 Sequence
<OUString
> platforms(info
.getSupportedPlatforms());
568 if (hasValidPlatform(platforms
))
576 u
"unsupported platform"_ustr
);
578 css::deployment::PlatformException(
579 msg
, static_cast<OWeakObject
*>(this), this));
580 if (!interactContinuation(
581 e
, cppu::UnoType
< css::task::XInteractionApprove
>::get(),
582 environment
, nullptr, nullptr))
584 throw css::deployment::DeploymentException(
585 msg
, static_cast<OWeakObject
*>(this), e
);
592 bool BackendImpl::PackageImpl::checkDependencies(
593 css::uno::Reference
< css::ucb::XCommandEnvironment
> const & environment
,
594 DescriptionInfoset
const & description
)
596 css::uno::Sequence
< css::uno::Reference
< css::xml::dom::XElement
> >
597 unsatisfied(dp_misc::Dependencies::check(description
));
599 if (!unsatisfied
.hasElements()) {
603 u
"unsatisfied dependencies"_ustr
);
605 css::deployment::DependencyException(
606 msg
, static_cast<OWeakObject
*>(this), unsatisfied
));
607 if (!interactContinuation(
608 e
, cppu::UnoType
< css::task::XInteractionApprove
>::get(),
609 environment
, nullptr, nullptr))
611 throw css::deployment::DeploymentException(
612 msg
, static_cast<OWeakObject
*>(this), e
);
618 bool BackendImpl::PackageImpl::checkLicense(
619 css::uno::Reference
< css::ucb::XCommandEnvironment
> const & xCmdEnv
,
620 DescriptionInfoset
const & info
, bool alreadyInstalled
)
624 ::std::optional
<SimpleLicenseAttributes
> simplLicAttr
625 = info
.getSimpleLicenseAttributes();
628 OUString sLic
= info
.getLocalizedLicenseURL();
629 //If we do not get a localized licence then there is an error in the description.xml
630 //This should be handled by using a validating parser. Therefore we assume that no
631 //license is available.
633 throw css::deployment::DeploymentException(
634 u
"Could not obtain path to license. Possible error in description.xml"_ustr
, nullptr, Any());
635 OUString sHref
= m_url_expanded
+ "/" + sLic
;
636 OUString sLicense
= getTextFromURL(xCmdEnv
, sHref
);
637 ////determine who has to agree to the license
638 //check correct value for attribute
639 if ( simplLicAttr
->acceptBy
!= "user" && simplLicAttr
->acceptBy
!= "admin")
640 throw css::deployment::DeploymentException(
641 u
"Could not obtain attribute simple-license@accept-by or it has no valid value"_ustr
, nullptr, Any());
644 //Only use interaction if there is no version of this extension already installed
645 //and the suppress-on-update flag is not set for the new extension
646 // alreadyInstalled | bSuppressOnUpdate | show license
653 if ( !(alreadyInstalled
&& simplLicAttr
->suppressOnUpdate
))
655 css::deployment::LicenseException
licExc(
656 OUString(), nullptr, getDisplayName(), sLicense
,
657 simplLicAttr
->acceptBy
);
658 bool approve
= false;
660 if (! interactContinuation(
661 Any(licExc
), cppu::UnoType
<task::XInteractionApprove
>::get(), xCmdEnv
, &approve
, &abort
))
662 throw css::deployment::DeploymentException(
663 u
"Could not interact with user."_ustr
, nullptr, Any());
668 } catch (const css::ucb::CommandFailedException
&) {
670 } catch (const css::ucb::CommandAbortedException
&) {
672 } catch (const css::deployment::DeploymentException
&) {
674 } catch (const css::uno::RuntimeException
&) {
676 } catch (const css::uno::Exception
&) {
677 Any anyExc
= cppu::getCaughtException();
678 throw css::deployment::DeploymentException(u
"Unexpected exception"_ustr
, nullptr, anyExc
);
682 ::sal_Int32
BackendImpl::PackageImpl::checkPrerequisites(
683 const css::uno::Reference
< css::task::XAbortChannel
>&,
684 const css::uno::Reference
< css::ucb::XCommandEnvironment
>& xCmdEnv
,
685 sal_Bool alreadyInstalled
)
688 throw deployment::ExtensionRemovedException();
689 DescriptionInfoset info
= getDescriptionInfoset();
690 if (!info
.hasDescription())
693 //always return LICENSE as long as the user did not accept the license
694 //so that XExtensionManager::checkPrerequisitesAndEnable will again
696 if (!checkPlatform(xCmdEnv
))
697 return deployment::Prerequisites::PLATFORM
|
698 deployment::Prerequisites::LICENSE
;
699 else if(!checkDependencies(xCmdEnv
, info
))
700 return deployment::Prerequisites::DEPENDENCIES
|
701 deployment::Prerequisites::LICENSE
;
702 else if(!checkLicense(xCmdEnv
, info
, alreadyInstalled
))
703 return deployment::Prerequisites::LICENSE
;
708 sal_Bool
BackendImpl::PackageImpl::checkDependencies(
709 const css::uno::Reference
< css::ucb::XCommandEnvironment
>& xCmdEnv
)
712 throw deployment::ExtensionRemovedException();
713 DescriptionInfoset info
= getDescriptionInfoset();
714 if (!info
.hasDescription())
717 return checkDependencies(xCmdEnv
, info
);
720 beans::Optional
<OUString
> BackendImpl::PackageImpl::getIdentifier()
724 identifier
= m_identifier
;
726 identifier
= dp_misc::generateIdentifier(
727 getDescriptionInfoset().getIdentifier(), m_name
);
729 return beans::Optional
<OUString
>(
733 OUString
BackendImpl::PackageImpl::getVersion()
736 throw deployment::ExtensionRemovedException();
737 return getDescriptionInfoset().getVersion();
740 Sequence
<OUString
> BackendImpl::PackageImpl::getUpdateInformationURLs()
743 throw deployment::ExtensionRemovedException();
744 return getDescriptionInfoset().getUpdateInformationUrls();
747 beans::StringPair
BackendImpl::PackageImpl::getPublisherInfo()
750 throw deployment::ExtensionRemovedException();
751 std::pair
< OUString
, OUString
> aInfo
= getDescriptionInfoset().getLocalizedPublisherNameAndURL();
752 beans::StringPair
aStrPair( aInfo
.first
, aInfo
.second
);
757 uno::Reference
< graphic::XGraphic
> BackendImpl::PackageImpl::getIcon( sal_Bool bHighContrast
)
760 throw deployment::ExtensionRemovedException();
762 uno::Reference
< graphic::XGraphic
> xGraphic
;
764 OUString aIconURL
= getDescriptionInfoset().getIconURL( bHighContrast
);
765 if ( !aIconURL
.isEmpty() )
767 OUString aFullIconURL
= m_url_expanded
+ "/" + aIconURL
;
769 uno::Reference
< XComponentContext
> xContext( getMyBackend()->getComponentContext() );
770 uno::Reference
< graphic::XGraphicProvider
> xGraphProvider( graphic::GraphicProvider::create(xContext
) );
772 uno::Sequence
< beans::PropertyValue
> aMediaProps
{ comphelper::makePropertyValue(
773 u
"URL"_ustr
, aFullIconURL
) };
774 xGraphic
= xGraphProvider
->queryGraphic( aMediaProps
);
781 void BackendImpl::PackageImpl::processPackage_(
782 ::osl::ResettableMutexGuard
& guard
,
783 bool doRegisterPackage
,
785 ::rtl::Reference
<AbortChannel
> const & abortChannel
,
786 Reference
<ucb::XCommandEnvironment
> const & xCmdEnv
)
788 const Sequence
< Reference
<deployment::XPackage
> > bundle(
789 getBundle( abortChannel
, xCmdEnv
) );
791 if (doRegisterPackage
)
793 ExtensionBackendDb::Data data
;
794 const sal_Int32 len
= bundle
.getLength();
795 for ( sal_Int32 pos
= 0; pos
< len
; ++pos
)
797 checkAborted(abortChannel
);
798 Reference
<deployment::XPackage
> const & xPackage
= bundle
[ pos
];
799 Reference
<task::XAbortChannel
> xSubAbortChannel(
800 xPackage
->createAbortChannel() );
801 AbortChannel::Chain
chain( abortChannel
, xSubAbortChannel
);
803 // tdf#159790 temporarily release mutex for child packages
804 // This code is normally run on a separate thread so if a
805 // child package tries to acquire the solar mutex, a deadlock
806 // can occur if the main thread calls isRegistered() on this
807 // package or any of its parents. So, temporarily release
808 // this package's mutex while registering the child package.
809 osl::ResettableMutexGuardScopedReleaser
releaser(guard
);
810 xPackage
->registerPackage( startup
, xSubAbortChannel
, xCmdEnv
);
812 catch (const Exception
&)
814 //We even try a rollback if the user cancelled the action (CommandAbortedException)
815 //in order to prevent invalid database entries.
816 Any
exc( ::cppu::getCaughtException() );
817 // try to handle exception, notify:
818 bool approve
= false, abort
= false;
819 if (! interactContinuation(
820 Any( lang::WrappedTargetException(
821 u
"bundle item registration error!"_ustr
,
822 static_cast<OWeakObject
*>(this), exc
) ),
823 cppu::UnoType
<task::XInteractionApprove
>::get(), xCmdEnv
,
824 &approve
, &abort
)) {
825 OSL_ASSERT( !approve
&& !abort
);
826 if (m_legacyBundle
) // default for legacy packages: ignore
828 // no selection at all, so rethrow;
829 // no C++ rethrow after getCaughtException(),
830 // see cppuhelper/exc_hlp.hxx:
831 ::cppu::throwException(exc
);
833 if (approve
&& !abort
) // ignore error, just continue
837 ProgressLevel
progress( xCmdEnv
, u
"rollback..."_ustr
);
842 bundle
[ pos
]->revokePackage(
843 startup
, xSubAbortChannel
, xCmdEnv
);
845 catch (const Exception
&)
847 TOOLS_WARN_EXCEPTION( "desktop", "" );
848 // ignore any errors of rollback
851 progress
.update( u
"rollback finished."_ustr
);
854 deployment::DeploymentException dpExc
;
856 throw ucb::CommandFailedException(
857 dpExc
.Message
, dpExc
.Context
, dpExc
.Cause
);
860 // rethrow CommandFailedException
861 ::cppu::throwException(exc
);
865 data
.items
.emplace_back(xPackage
->getURL(),
866 xPackage
->getPackageType()->getMediaType());
868 getMyBackend()->addDataToDb(getURL(), data
);
872 // revoke in reverse order:
873 for ( sal_Int32 pos
= bundle
.getLength(); pos
--; )
875 checkAborted(abortChannel
);
876 Reference
<deployment::XPackage
> const & xPackage
= bundle
[ pos
];
877 Reference
<task::XAbortChannel
> xSubAbortChannel(
878 xPackage
->createAbortChannel() );
879 AbortChannel::Chain
chain( abortChannel
, xSubAbortChannel
);
881 bundle
[ pos
]->revokePackage(
882 startup
, xSubAbortChannel
, xCmdEnv
);
884 catch (const RuntimeException
&) {
887 catch (const ucb::CommandAbortedException
&) {
890 catch (const Exception
&) {
891 // CommandFailedException, DeploymentException:
892 Any
exc( ::cppu::getCaughtException() );
893 // try to handle exception, notify:
894 bool approve
= false, abort
= false;
895 if (! interactContinuation(
896 Any( lang::WrappedTargetException(
897 u
"bundle item revocation error!"_ustr
,
898 static_cast<OWeakObject
*>(this), exc
) ),
899 cppu::UnoType
<task::XInteractionApprove
>::get(), xCmdEnv
,
900 &approve
, &abort
)) {
901 OSL_ASSERT( !approve
&& !abort
);
902 if (m_legacyBundle
) // default for legacy packages: ignore
904 // no selection at all, so rethrow
905 // no C++ rethrow after getCaughtException(),
906 // see cppuhelper/exc_hlp.hxx:
907 ::cppu::throwException(exc
);
909 // ignore errors when revoking, although abort may have been
913 getMyBackend()->revokeEntryFromDb(getURL());
918 OUString
BackendImpl::PackageImpl::getDescription()
921 throw deployment::ExtensionRemovedException();
923 const OUString
sRelativeURL(getDescriptionInfoset().getLocalizedDescriptionURL());
924 OUString sDescription
;
925 if (!sRelativeURL
.isEmpty())
927 OUString sURL
= m_url_expanded
+ "/" + sRelativeURL
;
931 sDescription
= getTextFromURL( css::uno::Reference
< css::ucb::XCommandEnvironment
>(), sURL
);
933 catch ( const css::deployment::DeploymentException
& )
935 TOOLS_WARN_EXCEPTION( "desktop", "" );
939 if (!sDescription
.isEmpty())
941 return m_oldDescription
;
945 OUString
BackendImpl::PackageImpl::getLicenseText()
948 throw deployment::ExtensionRemovedException();
951 DescriptionInfoset aInfo
= getDescriptionInfoset();
953 ::std::optional
< SimpleLicenseAttributes
> aSimplLicAttr
= aInfo
.getSimpleLicenseAttributes();
956 OUString aLicenseURL
= aInfo
.getLocalizedLicenseURL();
958 if ( !aLicenseURL
.isEmpty() )
960 OUString aFullURL
= m_url_expanded
+ "/" + aLicenseURL
;
961 sLicense
= getTextFromURL( Reference
< ucb::XCommandEnvironment
>(), aFullURL
);
969 void BackendImpl::PackageImpl::exportTo(
970 OUString
const & destFolderURL
, OUString
const & newTitle
,
971 sal_Int32 nameClashAction
, Reference
<ucb::XCommandEnvironment
> const & xCmdEnv
)
974 throw deployment::ExtensionRemovedException();
976 ::ucbhelper::Content
sourceContent(
977 m_url_expanded
, xCmdEnv
, getMyBackend()->getComponentContext() );
978 OUString
title(newTitle
);
980 sourceContent
.getPropertyValue( u
"Title"_ustr
) >>= title
;
981 OUString
destURL( makeURL( destFolderURL
, ::rtl::Uri::encode(
982 title
, rtl_UriCharClassPchar
,
983 rtl_UriEncodeIgnoreEscapes
,
984 RTL_TEXTENCODING_UTF8
) ) );
986 if (nameClashAction
== ucb::NameClash::ASK
)
988 if (create_ucb_content(
989 nullptr, destURL
, xCmdEnv
, false /* no throw */ )) {
990 bool replace
= false, abort
= false;
991 if (! interactContinuation(
992 Any( ucb::NameClashResolveRequest(
993 "file already exists: " + title
,
994 static_cast<OWeakObject
*>(this),
995 task::InteractionClassification_QUERY
,
996 destFolderURL
, title
, OUString() ) ),
997 cppu::UnoType
<ucb::XInteractionReplaceExistingData
>::get(), xCmdEnv
,
998 &replace
, &abort
) || !replace
) {
1003 else if (nameClashAction
!= ucb::NameClash::OVERWRITE
) {
1004 throw ucb::CommandFailedException(u
"unsupported nameClashAction!"_ustr
,
1005 static_cast<OWeakObject
*>(this), Any() );
1007 erase_path( destURL
, xCmdEnv
);
1009 OUString destFolder
=
1010 "vnd.sun.star.zip://" +
1011 ::rtl::Uri::encode( destURL
,
1012 rtl_UriCharClassRegName
,
1013 rtl_UriEncodeIgnoreEscapes
,
1014 RTL_TEXTENCODING_UTF8
) +
1017 ::ucbhelper::Content
destFolderContent(
1018 destFolder
, xCmdEnv
, getMyBackend()->getComponentContext() );
1020 // transfer every item of folder into zip:
1021 Reference
<sdbc::XResultSet
> xResultSet(
1022 sourceContent
.createCursor( Sequence
<OUString
>() ) );
1023 ProgressLevel
progress( xCmdEnv
, OUString() );
1024 while (xResultSet
->next())
1026 ::ucbhelper::Content
subContent(
1027 Reference
<ucb::XContentAccess
>(
1028 xResultSet
, UNO_QUERY_THROW
)->queryContent(),
1029 xCmdEnv
, getMyBackend()->getComponentContext() );
1030 destFolderContent
.transferContent(
1031 subContent
, ::ucbhelper::InsertOperation::Copy
,
1032 OUString(), ucb::NameClash::OVERWRITE
);
1033 progress
.update( Any() ); // animating progress bar
1037 // assure META-INF folder:
1038 ::ucbhelper::Content metainfFolderContent
;
1039 create_folder( &metainfFolderContent
,
1040 makeURL( destFolderContent
.getURL(), u
"META-INF"_ustr
),
1045 // easy to migrate legacy bundles to new format:
1046 // just export them once using a .oxt name!
1047 // set detected media-types of any bundle item:
1049 // collect all manifest entries:
1050 Sequence
< Reference
<deployment::XPackage
> > bundle
;
1052 bundle
= getBundle( Reference
<task::XAbortChannel
>(), xCmdEnv
);
1054 // xxx todo: think about exception specs:
1055 catch (const deployment::DeploymentException
&) {
1056 TOOLS_WARN_EXCEPTION( "desktop", "" );
1058 catch (const lang::IllegalArgumentException
&) {
1059 TOOLS_WARN_EXCEPTION( "desktop", "" );
1062 std::vector
< Sequence
<beans::PropertyValue
> > manifest
;
1063 manifest
.reserve( bundle
.getLength() );
1064 sal_Int32 baseURLlen
= m_url_expanded
.getLength();
1065 static constexpr OUStringLiteral
strMediaType( u
"MediaType" );
1066 static constexpr OUStringLiteral
strFullPath( u
"FullPath" );
1067 static constexpr OUStringLiteral
strIsFolder( u
"IsFolder" );
1068 for ( sal_Int32 pos
= bundle
.getLength(); pos
--; )
1070 Reference
<deployment::XPackage
> const& xPackage
= bundle
[pos
];
1071 OUString
url_( expandUnoRcUrl( xPackage
->getURL() ) );
1072 OSL_ASSERT( url_
.getLength() >= baseURLlen
);
1074 if (url_
.getLength() > baseURLlen
)
1075 fullPath
= url_
.copy( baseURLlen
+ 1 );
1076 ::ucbhelper::Content
ucbContent(
1077 url_
, xCmdEnv
, getMyBackend()->getComponentContext() );
1078 if (ucbContent
.getPropertyValue(strIsFolder
).get
<bool>())
1080 Sequence
<beans::PropertyValue
> attribs( 2 );
1081 beans::PropertyValue
* pattribs
= attribs
.getArray();
1082 pattribs
[ 0 ].Name
= strFullPath
;
1083 pattribs
[ 0 ].Value
<<= fullPath
;
1084 pattribs
[ 1 ].Name
= strMediaType
;
1085 const Reference
<deployment::XPackageTypeInfo
> xPackageType(
1086 xPackage
->getPackageType() );
1088 OSL_ASSERT( xPackageType
.is() );
1089 if (xPackageType
.is())
1090 mediaType
= xPackageType
->getMediaType();
1092 mediaType
= "unknown";
1093 pattribs
[ 1 ].Value
<<= mediaType
;
1094 manifest
.push_back( attribs
);
1098 Reference
<XComponentContext
> xContext(
1099 getMyBackend()->getComponentContext() );
1100 Reference
<packages::manifest::XManifestWriter
> xManifestWriter
=
1101 packages::manifest::ManifestWriter::create( xContext
);
1102 Reference
<io::XOutputStream
> xPipe( io::Pipe::create(xContext
), UNO_QUERY_THROW
);
1103 xManifestWriter
->writeManifestSequence(
1104 xPipe
, comphelper::containerToSequence(manifest
) );
1106 // write buffered pipe data to content:
1107 ::ucbhelper::Content
manifestContent(
1108 makeURL( metainfFolderContent
.getURL(), u
"manifest.xml"_ustr
),
1109 xCmdEnv
, getMyBackend()->getComponentContext() );
1110 manifestContent
.writeStream(
1111 Reference
<io::XInputStream
>( xPipe
, UNO_QUERY_THROW
),
1112 true /* replace existing */ );
1116 bool bSuccess
= false;
1119 // overwrite manifest.xml:
1120 ::ucbhelper::Content manifestContent
;
1121 if ( ! create_ucb_content(
1123 makeURL( m_url_expanded
, u
"META-INF/manifest.xml"_ustr
),
1126 OSL_FAIL( "### missing META-INF/manifest.xml file!" );
1130 metainfFolderContent
.transferContent(
1131 manifestContent
, ::ucbhelper::InsertOperation::Copy
,
1132 OUString(), ucb::NameClash::OVERWRITE
);
1135 catch (const css::ucb::ContentCreationException
&)
1137 TOOLS_WARN_EXCEPTION("desktop.deployment", "exception on overwriting manifest");
1141 throw RuntimeException( u
"UCB transferContent() failed!"_ustr
,
1142 static_cast<OWeakObject
*>(this) );
1145 // xxx todo: maybe obsolete in the future
1147 destFolderContent
.executeCommand( u
"flush"_ustr
, Any() );
1149 catch (const ucb::UnsupportedCommandException
&) {
1154 sal_Bool
BackendImpl::PackageImpl::isBundle()
1160 Sequence
< Reference
<deployment::XPackage
> > BackendImpl::PackageImpl::getBundle(
1161 Reference
<task::XAbortChannel
> const & xAbortChannel
,
1162 Reference
<ucb::XCommandEnvironment
> const & xCmdEnv
)
1164 Sequence
< Reference
<deployment::XPackage
> > * pBundle
= m_pBundle
;
1165 if (pBundle
== nullptr)
1167 t_packagevec bundle
;
1170 bundle
= getPackagesFromDb(xCmdEnv
);
1177 // .zip legacy packages allow script.xlb, dialog.xlb in bundle
1180 // probe for script.xlb:
1181 if (create_ucb_content(
1182 nullptr, makeURL( m_url_expanded
, u
"script.xlb"_ustr
),
1183 xCmdEnv
, false /* no throw */ )) {
1184 mediaType
= "application/vnd.sun.star.basic-library";
1186 // probe for dialog.xlb:
1187 else if (create_ucb_content(
1188 nullptr, makeURL( m_url_expanded
, u
"dialog.xlb"_ustr
),
1189 xCmdEnv
, false /* no throw */ ))
1190 mediaType
= "application/vnd.sun.star.dialog-library";
1192 if (!mediaType
.isEmpty()) {
1193 const Reference
<deployment::XPackage
> xPackage(
1194 bindBundleItem( getURL(), mediaType
, false, OUString(),
1197 bundle
.push_back( xPackage
);
1198 // continue scanning:
1200 scanLegacyBundle( bundle
, getURL(),
1201 AbortChannel::get(xAbortChannel
), xCmdEnv
);
1206 scanBundle( bundle
, AbortChannel::get(xAbortChannel
), xCmdEnv
);
1210 catch (const RuntimeException
&) {
1213 catch (const ucb::CommandFailedException
&) {
1216 catch (const ucb::CommandAbortedException
&) {
1219 catch (const deployment::DeploymentException
&) {
1222 catch (const Exception
&) {
1223 Any
exc( ::cppu::getCaughtException() );
1224 throw deployment::DeploymentException(
1225 "error scanning bundle: " + getURL(),
1226 static_cast<OWeakObject
*>(this), exc
);
1230 // sort: schema before config data, typelibs before components:
1231 Sequence
< Reference
<deployment::XPackage
> > ret( bundle
.size() );
1232 Reference
<deployment::XPackage
> * pret
= ret
.getArray();
1233 sal_Int32 lower_end
= 0;
1234 sal_Int32 upper_end
= ret
.getLength();
1235 for (auto const& elem
: bundle
)
1237 const Reference
<deployment::XPackageTypeInfo
> xPackageType(
1238 elem
->getPackageType() );
1239 OSL_ASSERT( xPackageType
.is() );
1240 if (xPackageType
.is())
1242 const OUString
mediaType( xPackageType
->getMediaType() );
1243 OUString type
, subType
;
1244 INetContentTypeParameterList params
;
1245 if (INetContentTypes::parse( mediaType
, type
, subType
, ¶ms
) &&
1246 type
.equalsIgnoreAsciiCase("application") &&
1247 (subType
.equalsIgnoreAsciiCase( "vnd.sun.star.uno-component") ||
1248 subType
.equalsIgnoreAsciiCase( "vnd.sun.star.configuration-data")))
1251 pret
[ upper_end
] = elem
;
1255 pret
[ lower_end
] = elem
;
1258 OSL_ASSERT( lower_end
== upper_end
);
1260 const ::osl::MutexGuard
guard( m_aMutex
);
1261 pBundle
= m_pBundle
;
1262 if (pBundle
== nullptr) {
1263 m_bundle
= std::move(ret
);
1264 pBundle
= &m_bundle
;
1265 OSL_DOUBLE_CHECKED_LOCKING_MEMORY_BARRIER();
1266 m_pBundle
= pBundle
;
1270 OSL_DOUBLE_CHECKED_LOCKING_MEMORY_BARRIER();
1275 bool isBundle_( std::u16string_view mediaType
)
1277 // xxx todo: additional parsing?
1278 return !mediaType
.empty() &&
1279 (o3tl::matchIgnoreAsciiCase( mediaType
, u
"application/vnd.sun.star.package-bundle") ||
1280 o3tl::matchIgnoreAsciiCase( mediaType
, u
"application/vnd.sun.star.legacy-package-bundle"));
1284 Reference
<deployment::XPackage
> BackendImpl::PackageImpl::bindBundleItem(
1285 OUString
const & url
, OUString
const & mediaType
,
1286 bool bRemoved
, OUString
const & identifier
,
1287 Reference
<ucb::XCommandEnvironment
> const & xCmdEnv
,
1288 bool notifyDetectionError
)
1290 // ignore any nested bundles:
1291 if (isBundle_(mediaType
))
1292 return Reference
<deployment::XPackage
>();
1294 Reference
<deployment::XPackage
>xPackage
;
1297 xPackage
.set( getMyBackend()->m_xRootRegistry
->bindPackage(
1298 url
, mediaType
, bRemoved
, identifier
, xCmdEnv
) );
1299 OSL_ASSERT( xPackage
.is() );
1300 } catch (css::lang::IllegalArgumentException
& e
) {
1301 css::uno::Any
exc(cppu::getCaughtException());
1302 throw css::lang::WrappedTargetException(
1303 "wrapped: " + e
.Message
, e
.Context
, exc
);
1306 catch (const RuntimeException
&) {
1309 catch (const ucb::CommandFailedException
&) {
1310 // ignore already handled error
1312 catch (const Exception
&) {
1313 const Any
exc( ::cppu::getCaughtException() );
1314 if (notifyDetectionError
||
1315 !exc
.isExtractableTo( cppu::UnoType
<lang::IllegalArgumentException
>::get()) )
1317 (void)interactContinuation(
1318 Any( lang::WrappedTargetException(u
"bundle item error!"_ustr
,
1319 static_cast<OWeakObject
*>(this), exc
) ),
1320 cppu::UnoType
<task::XInteractionApprove
>::get(), xCmdEnv
, nullptr, nullptr );
1324 if (xPackage
.is()) {
1325 const Reference
<deployment::XPackageTypeInfo
> xPackageType(
1326 xPackage
->getPackageType() );
1327 OSL_ASSERT( xPackageType
.is() );
1328 // ignore any nested bundles:
1329 if (xPackageType
.is() && isBundle_( xPackageType
->getMediaType() ))
1336 void BackendImpl::PackageImpl::scanBundle(
1337 t_packagevec
& bundle
,
1338 ::rtl::Reference
<AbortChannel
> const & abortChannel
,
1339 Reference
<ucb::XCommandEnvironment
> const & xCmdEnv
)
1341 OSL_ASSERT( !m_legacyBundle
);
1343 OUString
mfUrl( makeURL( m_url_expanded
, u
"META-INF/manifest.xml"_ustr
) );
1344 ::ucbhelper::Content manifestContent
;
1345 if (! create_ucb_content(
1346 &manifestContent
, mfUrl
, xCmdEnv
, false /* no throw */ ))
1349 "desktop.deployment",
1350 "cannot create UCB Content for <" << mfUrl
<< ">" );
1355 const LanguageTag
& officeLocale
= getOfficeLanguageTag();
1356 const std::vector
< OUString
> officeFallbacks( officeLocale
.getFallbackStrings( true));
1357 const size_t nPenaltyMax
= std::numeric_limits
<size_t>::max();
1358 size_t descrPenalty
= nPenaltyMax
;
1361 const Reference
<XComponentContext
> xContext(
1362 getMyBackend()->getComponentContext() );
1363 Reference
<packages::manifest::XManifestReader
> xManifestReader
=
1364 packages::manifest::ManifestReader::create( xContext
);
1365 const Sequence
< Sequence
<beans::PropertyValue
> > manifestSeq(
1366 xManifestReader
->readManifestSequence( manifestContent
.openStream() ) );
1367 const OUString
packageRootURL( getURL() );
1368 for ( sal_Int32 pos
= manifestSeq
.getLength(); pos
--; )
1370 OUString fullPath
, mediaType
;
1371 Sequence
<beans::PropertyValue
> const & attribs
= manifestSeq
[ pos
];
1372 for ( sal_Int32 i
= attribs
.getLength(); i
--; )
1374 if (!(fullPath
.isEmpty() || mediaType
.isEmpty()))
1376 if ( attribs
[i
].Name
== "FullPath" )
1377 attribs
[i
].Value
>>= fullPath
;
1378 else if ( attribs
[i
].Name
== "MediaType" )
1379 attribs
[i
].Value
>>= mediaType
;
1382 if ( fullPath
.isEmpty() || mediaType
.isEmpty() || mediaType
== "text/xml" )// opt: exclude common text/xml
1385 OUString type
, subType
;
1386 INetContentTypeParameterList params
;
1387 if (! INetContentTypes::parse( mediaType
, type
, subType
, ¶ms
))
1391 auto const iter
= params
.find("platform"_ostr
);
1392 if (iter
!= params
.end() && !platform_fits(iter
->second
.m_sValue
))
1395 const OUString
url( makeURL( packageRootURL
, fullPath
) );
1397 // check for bundle description:
1398 if (type
.equalsIgnoreAsciiCase("application") &&
1399 subType
.equalsIgnoreAsciiCase( "vnd.sun.star.package-bundle-description"))
1402 auto const iter
= params
.find("locale"_ostr
);
1403 if (iter
== params
.end())
1405 if (descrFile
.isEmpty())
1409 // match best locale:
1410 LanguageTag
descrTag(iter
->second
.m_sValue
);
1411 if (officeLocale
.getLanguage() == descrTag
.getLanguage())
1413 size_t nPenalty
= nPenaltyMax
;
1414 const std::vector
< OUString
> descrFallbacks( descrTag
.getFallbackStrings( true));
1415 for (size_t o
=0; o
< officeFallbacks
.size() && nPenalty
== nPenaltyMax
; ++o
)
1417 for (size_t d
=0; d
< descrFallbacks
.size() && nPenalty
== nPenaltyMax
; ++d
)
1419 if (officeFallbacks
[o
] == descrFallbacks
[d
])
1421 // The last fallbacks are always language-only
1422 // fallbacks, so we _will_ have _some_ match if
1423 // we ever entered the overall if() condition.
1424 nPenalty
= o
* 1000 + d
;
1425 if (descrPenalty
> nPenalty
)
1427 descrPenalty
= nPenalty
;
1434 // TODO: we could break here if descrPenalty==0 for an exact
1435 // match of officeLocale, but the previous code didn't; are
1436 // there side effects?
1441 checkAborted( abortChannel
);
1443 //We make sure that we only create one XPackage for a particular URL.
1444 //Sometime programmers insert the same URL several times in the manifest
1445 //which may lead to DisposedExceptions.
1446 if (std::none_of(bundle
.begin(), bundle
.end(), XPackage_eq(url
)))
1448 const Reference
<deployment::XPackage
> xPackage(
1449 bindBundleItem( url
, mediaType
, false, OUString(), xCmdEnv
) );
1451 bundle
.push_back( xPackage
);
1455 SAL_WARN("desktop.deployment", "manifest.xml contains a duplicate entry (from " << url
<< ")");
1459 if (descrFile
.isEmpty())
1462 ::ucbhelper::Content descrFileContent
;
1463 if (!create_ucb_content( &descrFileContent
, descrFile
,
1464 xCmdEnv
, false /* no throw */ ))
1467 // patch description:
1468 std::vector
<sal_Int8
> bytes( readFile( descrFileContent
) );
1470 if ( !bytes
.empty() )
1472 buf
.append( OUString( reinterpret_cast<char const *>(
1474 bytes
.size(), RTL_TEXTENCODING_UTF8
) );
1478 buf
.append( Package::getDescription() );
1480 m_oldDescription
= buf
.makeStringAndClear();
1484 void BackendImpl::PackageImpl::scanLegacyBundle(
1485 t_packagevec
& bundle
,
1486 OUString
const & url
,
1487 ::rtl::Reference
<AbortChannel
> const & abortChannel
,
1488 Reference
<ucb::XCommandEnvironment
> const & xCmdEnv
,
1489 bool skip_registration
)
1491 ::ucbhelper::Content
ucbContent(
1492 url
, xCmdEnv
, getMyBackend()->getComponentContext() );
1494 // check for platform paths:
1495 const OUString
title( StrTitle::getTitle( ucbContent
) );
1496 if (title
.endsWithIgnoreAsciiCase( ".plt" ) &&
1497 !platform_fits( title
.subView( 0, title
.getLength() - 4 ) )) {
1500 if (title
.endsWithIgnoreAsciiCase("skip_registration") )
1501 skip_registration
= true;
1503 Sequence
<OUString
> ar
{ u
"Title"_ustr
, u
"IsFolder"_ustr
};
1504 Reference
<sdbc::XResultSet
> xResultSet( ucbContent
.createCursor( ar
) );
1505 while (xResultSet
->next())
1507 checkAborted( abortChannel
);
1509 const Reference
<sdbc::XRow
> xRow( xResultSet
, UNO_QUERY_THROW
);
1510 const OUString
title_enc( ::rtl::Uri::encode(
1511 xRow
->getString( 1 /* Title */ ),
1512 rtl_UriCharClassPchar
,
1513 rtl_UriEncodeIgnoreEscapes
,
1514 RTL_TEXTENCODING_UTF8
) );
1515 const OUString
path( makeURL( url
, title_enc
) );
1518 const Reference
<deployment::XPackage
> xPackage(
1519 bindBundleItem( path
, OUString() /* detect */, false, OUString(),
1520 xCmdEnv
, false /* ignore detection errors */ ) );
1521 if (xPackage
.is()) {
1522 const Reference
<deployment::XPackageTypeInfo
> xPackageType(
1523 xPackage
->getPackageType() );
1524 OSL_ASSERT( xPackageType
.is() );
1525 if (xPackageType
.is())
1526 mediaType
= xPackageType
->getMediaType();
1528 if (skip_registration
&&
1529 // xxx todo: additional parsing?
1530 mediaType
.matchIgnoreAsciiCase("application/vnd.sun.star.uno-component"))
1533 bundle
.push_back( xPackage
);
1536 if (mediaType
.isEmpty() ||
1537 // script.xlb, dialog.xlb can be met everywhere:
1538 mediaType
.matchIgnoreAsciiCase("application/vnd.sun.star.basic-library") ||
1539 mediaType
.matchIgnoreAsciiCase("application/vnd.sun.star.dialog-library"))
1541 if (xRow
->getBoolean( 2 /* IsFolder */ )) { // recurse into folder:
1543 bundle
, path
, abortChannel
, xCmdEnv
, skip_registration
);
1549 OUString
BackendImpl::PackageImpl::getDisplayName()
1552 throw deployment::ExtensionRemovedException();
1554 OUString sName
= getDescriptionInfoset().getLocalizedDisplayName();
1555 if (sName
.isEmpty())
1556 return m_displayName
;
1561 std::vector
<Reference
<deployment::XPackage
> >
1562 BackendImpl::PackageImpl::getPackagesFromDb(
1563 Reference
<ucb::XCommandEnvironment
> const & xCmdEnv
)
1565 std::vector
<Reference
<deployment::XPackage
> > retVector
;
1567 for (auto const& item
: m_dbData
.items
)
1569 Reference
<deployment::XPackage
> xExtension
=
1570 bindBundleItem(item
.first
, item
.second
, true, m_identifier
, xCmdEnv
);
1571 OSL_ASSERT(xExtension
.is());
1572 if (xExtension
.is())
1573 retVector
.push_back(xExtension
);
1582 Reference
<deployment::XPackageRegistry
> create(
1583 Reference
<deployment::XPackageRegistry
> const & xRootRegistry
,
1584 OUString
const & context
, OUString
const & cachePath
,
1585 Reference
<XComponentContext
> const & xComponentContext
)
1587 Sequence
<Any
> args(cachePath
.isEmpty() ? 1 : 3 );
1588 auto pArgs
= args
.getArray();
1589 pArgs
[ 0 ] <<= context
;
1590 if (!cachePath
.isEmpty()) {
1591 pArgs
[ 1 ] <<= cachePath
;
1592 pArgs
[ 2 ] <<= false; // readOnly
1594 return new BackendImpl( args
, xComponentContext
, xRootRegistry
);
1597 } // namespace dp_registry
1599 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */