27 #include <com/sun/star/beans/Optional.hpp>
28 #include <com/sun/star/beans/UnknownPropertyException.hpp>
29 #include <com/sun/star/beans/XPropertySet.hpp>
30 #include <com/sun/star/container/NoSuchElementException.hpp>
31 #include <com/sun/star/lang/WrappedTargetException.hpp>
32 #include <com/sun/star/lang/WrappedTargetRuntimeException.hpp>
33 #include <com/sun/star/uno/Any.hxx>
34 #include <com/sun/star/uno/Exception.hpp>
35 #include <com/sun/star/uno/Reference.hxx>
36 #include <com/sun/star/uno/RuntimeException.hpp>
37 #include <com/sun/star/uno/XComponentContext.hpp>
38 #include <com/sun/star/uno/XInterface.hpp>
40 #include <config_dconf.h>
41 #include <config_folders.h>
42 #include <osl/conditn.hxx>
43 #include <osl/file.hxx>
44 #include <osl/mutex.hxx>
45 #include <rtl/bootstrap.hxx>
46 #include <rtl/ref.hxx>
47 #include <rtl/ustrbuf.hxx>
48 #include <rtl/ustring.hxx>
83 struct UnresolvedVectorItem {
88 OUString
const & theName,
90 name(theName), manager(theManager) {}
93 typedef std::vector< UnresolvedVectorItem > UnresolvedVector;
96 OUString
const & url,
int layer, Data & data, Partial
const * partial,
97 Modifications * modifications,
Additions * additions)
99 assert(partial ==
nullptr && modifications ==
nullptr && additions ==
nullptr);
102 new ParseManager(url,
new XcsParser(layer, data)))->
parse(
nullptr);
108 OUString
const & url,
int layer, Data & data, Partial
const * partial,
109 Modifications * modifications,
Additions * additions)
114 new XcuParser(layer, data, partial, modifications, additions)))->
120 OUString expand(OUString
const & str) {
122 rtl::Bootstrap::expandMacros(s);
128 if (node->getLayer() > layer && node->getLayer() <
Data::NO_LAYER) {
131 switch (node->kind()) {
134 for (
auto const& member : node->getMembers())
136 if (!canRemoveFromLayer(layer, member.second)) {
142 return node->getMembers().empty();
154 OUString
const & url,
Data const & data);
161 virtual void execute()
override;
173 OUString
const & url,
Data const & data):
174 Thread(
"configmgrWriter"), reference_(reference), components_(components),
175 url_(url), data_(data),
178 assert(reference !=
nullptr);
182 delay_.wait(std::chrono::seconds(1));
183 osl::MutexGuard g(*
lock_);
187 }
catch (css::uno::RuntimeException &) {
199 css::uno::Reference< css::uno::XComponentContext >
const & context)
201 assert(context.is());
207 return locale ==
u"*";
211 OUString
const & pathRepresentation,
212 OUString * canonicRepresentation, std::vector<OUString> * path,
int * finalizedLayer)
216 pathRepresentation, canonicRepresentation, path, finalizedLayer);
225 roots_.insert(access.get());
237 for (
auto const& elemRoot :
roots_)
240 if (elemRoot->acquireCounting() > 1) {
243 elemRoot->releaseNondeleting();
245 if (root != exclude) {
246 std::vector<OUString> path(root->getAbsolutePath());
248 for (
auto const& pathElem : path)
250 Modifications::Node::Children::const_iterator k(
251 mods->children.find(pathElem));
252 if (k == mods->children.end()) {
261 if (mods !=
nullptr) {
262 root->initBroadcaster(*mods, broadcaster);
279 case ModificationTarget::None:
281 case ModificationTarget::File:
288 case ModificationTarget::Dconf:
299 osl::MutexGuard g(*
lock_);
309 bool shared, OUString
const & fileUri)
313 parseXcsFile(fileUri, layer,
data_,
nullptr,
nullptr,
nullptr);
314 }
catch (css::container::NoSuchElementException & e) {
315 throw css::uno::RuntimeException(
316 "insertExtensionXcsFile does not exist: " + e.Message);
321 bool shared, OUString
const & fileUri,
Modifications * modifications)
323 assert(modifications !=
nullptr);
327 parseXcuFile(fileUri, layer,
data_,
nullptr, modifications, adds);
328 }
catch (css::container::NoSuchElementException & e) {
330 throw css::uno::RuntimeException(
331 "insertExtensionXcuFile does not exist: " + e.Message);
351 assert(modifications !=
nullptr);
357 for (Additions::reverse_iterator
i(item->additions.rbegin());
358 i != item->additions.rend(); ++
i)
363 for (
auto const& j : *
i)
370 map = &node->getMembers();
378 if (canRemoveFromLayer(item->layer, node)) {
379 parent->getMembers().erase(i->back());
381 modifications->
add(*i);
390 OUString
const & fileUri,
391 std::set< OUString >
const & includedPaths,
392 std::set< OUString >
const & excludedPaths,
395 assert(modifications !=
nullptr);
396 Partial part(includedPaths, excludedPaths);
399 &parseXcuFile, fileUri,
Data::NO_LAYER, &part, modifications,
nullptr);
400 }
catch (
const css::container::NoSuchElementException &) {
403 "error inserting non-existing \"" << fileUri <<
"\"");
408 std::u16string_view descriptor)
410 size_t i = descriptor.find(
' ');
411 if (i == 0 || i == std::u16string_view::npos) {
412 throw css::uno::RuntimeException(
413 OUString::Concat(
"bad external value descriptor ") + descriptor);
416 OUString
name(descriptor.substr(0, i));
419 css::uno::Reference< css::uno::XInterface > service;
421 service =
context_->getServiceManager()->createInstanceWithContext(
423 }
catch (
const css::uno::RuntimeException &) {
426 }
catch (
const css::uno::Exception &) {
431 "createInstance(" <<
name <<
") failed");
433 css::uno::Reference< css::beans::XPropertySet > propset;
435 propset.set( service, css::uno::UNO_QUERY_THROW);
439 css::beans::Optional< css::uno::Any >
value;
440 if (j->second.is()) {
442 if (!(j->second->getPropertyValue(OUString(descriptor.substr(i + 1))) >>=
445 throw css::uno::RuntimeException(
446 OUString::Concat(
"cannot obtain external value through ") + descriptor);
448 }
catch (css::beans::UnknownPropertyException & e) {
449 throw css::uno::RuntimeException(
450 "unknown external value descriptor ID: " + e.Message);
451 }
catch (css::lang::WrappedTargetException & e) {
453 throw css::lang::WrappedTargetRuntimeException(
454 "cannot obtain external value: " + e.Message,
462 css::uno::Reference< css::uno::XComponentContext >
const & context):
466 assert(context.is());
468 OUString conf(expand(
"${CONFIGURATION_LAYERS}"));
470 for (sal_Int32
i = 0;;) {
471 while (
i != conf.getLength() && conf[
i] ==
' ') {
474 if (
i == conf.getLength()) {
478 throw css::uno::RuntimeException(
479 "CONFIGURATION_LAYERS: modification target layer followed by"
484 if (c == conf.getLength() || conf[c] ==
' ') {
485 throw css::uno::RuntimeException(
486 "CONFIGURATION_LAYERS: missing ':' in \"" + conf +
"\"");
488 if (conf[c] ==
':') {
492 sal_Int32
n = conf.indexOf(
' ', c + 1);
494 n = conf.getLength();
496 OUString
type(conf.copy(
i, c -
i));
497 OUString url(conf.copy(c + 1, n - c - 1));
498 if (
type ==
"xcsxcu") {
499 sal_uInt32 nStartTime = osl_getGlobalTimer();
501 SAL_INFO(
"configmgr",
"parseXcsXcuLayer() took " << (osl_getGlobalTimer() - nStartTime) <<
" ms");
503 }
else if (
type ==
"bundledext") {
506 }
else if (
type ==
"sharedext") {
508 throw css::uno::RuntimeException(
509 "CONFIGURATION_LAYERS: multiple \"sharedext\" layers");
514 }
else if (
type ==
"userext") {
516 throw css::uno::RuntimeException(
517 "CONFIGURATION_LAYERS: multiple \"userext\" layers");
522 }
else if (
type ==
"res") {
523 sal_uInt32 nStartTime = osl_getGlobalTimer();
525 SAL_INFO(
"configmgr",
"parseResLayer() took " << (osl_getGlobalTimer() - nStartTime) <<
" ms");
528 }
else if (
type ==
"dconf") {
532 }
else if (url ==
"*") {
535 throw css::uno::RuntimeException(
536 "CONFIGURATION_LAYERS: unknown \"dconf\" kind \"" + url
542 }
else if (
type ==
"winreg") {
544 if (url ==
"LOCAL_MACHINE" || url.isEmpty()) {
546 }
else if (url ==
"CURRENT_USER") {
549 throw css::uno::RuntimeException(
550 "CONFIGURATION_LAYERS: unknown \"winreg\" kind \"" + url
553 OUString aTempFileURL;
556 if (!getenv(
"SAL_CONFIG_WINREG_RETAIN_TMP"))
557 osl::File::remove(aTempFileURL);
561 }
else if (
type ==
"user") {
563 if (url.startsWith(
"!", &url)) {
565 }
else if (url.startsWith(
"*", &url)) {
571 throw css::uno::RuntimeException(
572 "CONFIGURATION_LAYERS: empty \"user\" URL");
578 expand(
"${SYSUSERCONFIG}/libreoffice/dconfwrite"));
579 osl::DirectoryItem it;
580 osl::FileBase::RC e = osl::DirectoryItem::get(token, it);
581 ignore = e == osl::FileBase::E_None;
584 "dconf write (<" << token <<
"> " << +e <<
"): "
600 throw css::uno::RuntimeException(
601 "CONFIGURATION_LAYERS: unknown layer type \"" +
type +
"\"");
619 SAL_WARN_IF(bExitWasCalled,
"configmgr",
"Components::~Components() called after _exit() call");
625 osl::MutexGuard g(*
lock_);
638 for (
auto const& rootElem :
roots_)
640 rootElem->setAlive(
false);
645 FileParser * parseFile, OUString
const & url,
int layer,
649 assert(parseFile !=
nullptr);
651 (*parseFile)(url, layer,
data_, partial, modifications, additions);
652 }
catch (
const css::container::NoSuchElementException &) {
654 }
catch (
const css::uno::Exception &) {
659 "error reading \"" << url <<
"\"");
664 int layer, OUString
const & extension, FileParser * parseFile,
665 OUString
const & url,
bool recursive)
667 osl::Directory dir(url);
668 switch (dir.open()) {
669 case osl::FileBase::E_None:
671 case osl::FileBase::E_NOENT:
677 throw css::uno::RuntimeException(
678 "cannot open directory " + url);
681 osl::DirectoryItem
i;
683 if (rc == osl::FileBase::E_NOENT) {
686 if (rc != osl::FileBase::E_None) {
687 throw css::uno::RuntimeException(
688 "cannot iterate directory " + url);
690 osl::FileStatus stat(
691 osl_FileStatus_Mask_Type | osl_FileStatus_Mask_FileName |
692 osl_FileStatus_Mask_FileURL);
693 if (i.getFileStatus(stat) != osl::FileBase::E_None) {
694 throw css::uno::RuntimeException(
695 "cannot stat in directory " + url);
697 if (stat.getFileType() == osl::FileStatus::Directory) {
698 parseFiles(layer, extension, parseFile, stat.getFileURL(),
true);
700 OUString file(stat.getFileName());
701 if (file.endsWith(extension)) {
704 parseFile, stat.getFileURL(), layer,
nullptr,
nullptr,
nullptr);
705 }
catch (css::container::NoSuchElementException & e) {
706 if (stat.getFileType() == osl::FileStatus::Link) {
707 SAL_WARN(
"configmgr",
"dangling link <" << stat.getFileURL() <<
">");
710 throw css::uno::RuntimeException(
711 "stat'ed file does not exist: " + e.Message);
719 int layer, FileParser * parseFile, std::u16string_view urls,
720 bool recordAdditions)
722 for (sal_Int32
i = 0;;) {
724 if (!url.isEmpty()) {
726 if (recordAdditions) {
731 }
catch (
const css::container::NoSuchElementException &) {
733 if (adds !=
nullptr) {
745 osl::Directory dir(url);
746 switch (dir.open()) {
747 case osl::FileBase::E_None:
749 case osl::FileBase::E_NOENT:
752 throw css::uno::RuntimeException(
753 "cannot open directory " + url);
755 UnresolvedVector unres;
756 std::set< OUString > existingDeps;
757 std::set< OUString > processedDeps;
759 osl::DirectoryItem
i;
761 if (rc == osl::FileBase::E_NOENT) {
764 if (rc != osl::FileBase::E_None) {
765 throw css::uno::RuntimeException(
766 "cannot iterate directory " + url);
768 osl::FileStatus stat(
769 osl_FileStatus_Mask_Type | osl_FileStatus_Mask_FileName |
770 osl_FileStatus_Mask_FileURL);
771 if (i.getFileStatus(stat) != osl::FileBase::E_None) {
772 throw css::uno::RuntimeException(
773 "cannot stat in directory " + url);
775 if (stat.getFileType() != osl::FileStatus::Directory) {
776 OUString file(stat.getFileName());
778 if (file.endsWith(
".xcd", &name)) {
779 existingDeps.insert(name);
785 }
catch (css::container::NoSuchElementException & e) {
786 if (stat.getFileType() == osl::FileStatus::Link) {
787 SAL_WARN(
"configmgr",
"dangling link <" << stat.getFileURL() <<
">");
790 throw css::uno::RuntimeException(
791 "stat'ed file does not exist: " + e.Message);
793 if (manager->parse(
nullptr)) {
794 processedDeps.insert(name);
796 unres.emplace_back(name, manager);
801 while (!unres.empty()) {
802 bool resolved =
false;
803 for (UnresolvedVector::iterator
i(unres.begin());
i != unres.end();) {
804 if (
i->manager->parse(&existingDeps)) {
805 processedDeps.insert(
i->name);
813 throw css::uno::RuntimeException(
814 "xcd: unresolved dependencies in " + url);
821 parseFiles(layer,
".xcs", &parseXcsFile, url +
"/schema",
false);
822 parseFiles(layer + 1,
".xcu", &parseXcuFile, url +
"/data",
false);
826 int layer, OUString
const & url,
bool recordAdditions)
831 if (rtl::Bootstrap(url).getHandle() ==
nullptr)
return;
833 OUStringBuffer
prefix(
"${.override:");
834 for (sal_Int32
i = 0;
i != url.getLength(); ++
i) {
847 OUString urls(prefix +
"SCHEMA}");
848 rtl::Bootstrap::expandMacros(urls);
849 if (!urls.isEmpty()) {
852 urls = prefix.makeStringAndClear() +
"DATA}";
853 rtl::Bootstrap::expandMacros(urls);
854 if (!urls.isEmpty()) {
855 parseFileList(layer + 1, &parseXcuFile, urls, recordAdditions);
860 OUString resUrl(OUString::Concat(url) +
"/res");
862 parseFiles(layer,
".xcu", &parseXcuFile, resUrl,
false);
868 }
catch (css::container::NoSuchElementException &) {
870 "configmgr",
"user registrymodifications.xcu does not (yet) exist");
875 layer,
".xcu", &parseXcuFile,
877 "${$BRAND_BASE_DIR/" LIBO_ETC_FOLDER
"/" SAL_CONFIGFILE(
"bootstrap")
878 ":UserInstallation}/user/registry/data"),
886 throw css::uno::RuntimeException(
887 "insert extension xcs/xcu file into undefined layer");
rtl::Reference< WriteThread > * reference_
void insertExtensionXcsFile(bool shared, OUString const &fileUri)
void remove(std::vector< OUString > const &path)
Node const & getRoot() const
static bool allLocales(std::u16string_view locale)
void writeModifications(Components &components, Data &data)
static bool getExitWasCalled()
void writeModFile(Components &components, OUString const &url, Data const &data)
rtl::Reference< Node > resolvePathRepresentation(OUString const &pathRepresentation, OUString *canonicRepresentation, std::vector< OUString > *path, int *finalizedLayer) const
std::shared_ptr< osl::Mutex > lock_
void insertExtensionXcuFile(bool shared, OUString const &fileUri, Modifications *modifications)
void parseXcsXcuIniLayer(int layer, OUString const &url, bool recordAdditions)
std::basic_string_view< charT, traits > getToken(std::basic_string_view< charT, traits > sv, charT delimiter, std::size_t &position)
rtl::Reference< WriteThread > writeThread_
virtual void execute() override
std::shared_ptr< osl::Mutex > lock_
void parseXcdFiles(int layer, OUString const &url)
rtl::Reference< ExtensionXcu > removeExtensionXcuAdditions(OUString const &url)
Any SAL_CALL getCaughtException()
Additions * addExtensionXcuAdditions(OUString const &url, int layer)
css::uno::Reference< css::uno::XComponentContext > context_
Modifications modifications
Components(const Components &)=delete
void insertModificationXcuFile(OUString const &fileUri, std::set< OUString > const &includedPaths, std::set< OUString > const &excludedPaths, Modifications *modifications)
void removeRootAccess(RootAccess *access)
rtl::Reference< Node > getTemplate(OUString const &fullName) const
std::vector< std::vector< OUString > > Additions
#define SAL_CONFIGFILE(name)
void add(std::vector< OUString > const &path)
#define TOOLS_WARN_EXCEPTION(area, stream)
void readLayer(Data &data, int layer)
int sharedExtensionLayer_
rtl::Reference< Node > resolvePathRepresentation(OUString const &pathRepresentation, OUString *canonicRepresentation, std::vector< OUString > *path, int *finalizedLayer) const
int getExtensionLayer(bool shared) const
OUString modificationFileUrl_
rtl::Reference< ParseManager > manager
virtual ~WriteThread() override
void addRootAccess(rtl::Reference< RootAccess > const &access)
css::beans::Optional< css::uno::Any > getExternalValue(std::u16string_view descriptor)
void addModification(std::vector< OUString > const &path)
void writeModifications()
ModificationTarget modificationTarget_
void parseFiles(int layer, OUString const &extension, FileParser *parseFile, OUString const &url, bool recursive)
void parseFileLeniently(FileParser *parseFile, OUString const &url, int layer, Partial const *partial, Modifications *modifications, Additions *additions)
NodeMap & getComponents() const
ExternalServices externalServices_
void parseModificationLayer(int layer, OUString const &url)
void removeExtensionXcuFile(OUString const &fileUri, Modifications *modifications)
void parseXcsXcuLayer(int layer, OUString const &url)
#define SAL_WARN_IF(condition, area, stream)
#define SAL_INFO(area, stream)
std::map< OUString, rtl::Reference< Entity > > map
void parseFileList(int layer, FileParser *parseFile, std::u16string_view urls, bool recordAdditions)
o3tl::sorted_vector< RootAccess * > roots_
void parseResLayer(int layer, std::u16string_view url)
rtl::Reference< Node > getTemplate(int layer, OUString const &fullName) const
#define SAL_WARN(area, stream)
bool dumpWindowsRegistry(OUString *pFileURL, WinRegType eType)
void initGlobalBroadcaster(Modifications const &modifications, rtl::Reference< RootAccess > const &exclude, Broadcaster *broadcaster)
std::shared_ptr< osl::Mutex > lock_
bool parse(OUString const &uri, SourceProviderScannerData *data)
rtl::Reference< Node > findNode(int layer, OUString const &name) const
WriteThread(rtl::Reference< WriteThread > *reference, Components &components, OUString const &url, Data const &data)
std::shared_ptr< osl::Mutex > const & lock()
void flushModifications()
static Components & getSingleton(css::uno::Reference< css::uno::XComponentContext > const &context)