28#include <com/sun/star/beans/Optional.hpp>
29#include <com/sun/star/beans/UnknownPropertyException.hpp>
30#include <com/sun/star/beans/XPropertySet.hpp>
31#include <com/sun/star/container/NoSuchElementException.hpp>
32#include <com/sun/star/lang/WrappedTargetException.hpp>
33#include <com/sun/star/lang/WrappedTargetRuntimeException.hpp>
34#include <com/sun/star/uno/Any.hxx>
35#include <com/sun/star/uno/Exception.hpp>
36#include <com/sun/star/uno/Reference.hxx>
37#include <com/sun/star/uno/RuntimeException.hpp>
38#include <com/sun/star/uno/XComponentContext.hpp>
39#include <com/sun/star/uno/XInterface.hpp>
41#include <config_dconf.h>
42#include <config_folders.h>
43#include <osl/conditn.hxx>
44#include <osl/file.hxx>
45#include <osl/mutex.hxx>
46#include <rtl/bootstrap.hxx>
48#include <rtl/ustrbuf.hxx>
49#include <rtl/ustring.hxx>
84struct UnresolvedVectorItem {
94typedef std::vector< UnresolvedVectorItem > UnresolvedVector;
97 OUString
const & url,
int layer, Data & data, Partial
const * partial,
98 Modifications * modifications,
Additions * additions)
100 assert(partial ==
nullptr && modifications ==
nullptr && additions ==
nullptr);
101 (void) partial; (void) modifications; (void) additions;
103 new ParseManager(url,
new XcsParser(layer, data)))->parse(
nullptr);
109 OUString
const & url,
int layer, Data & data, Partial
const * partial,
110 Modifications * modifications,
Additions * additions)
115 new XcuParser(layer, data, partial, modifications, additions)))->
121OUString expand(OUString
const & str) {
123 rtl::Bootstrap::expandMacros(s);
129 if (node->getLayer() > layer && node->getLayer() <
Data::NO_LAYER) {
132 switch (node->kind()) {
135 for (
auto const& member : node->getMembers())
137 if (!canRemoveFromLayer(layer, member.second)) {
143 return node->getMembers().empty();
155 OUString url,
Data const & data);
162 virtual void execute()
override;
174 OUString url,
Data const & data):
175 Thread(
"configmgrWriter"), reference_(reference), components_(components),
176 url_(
std::move(url)), data_(data),
179 assert(reference !=
nullptr);
183 delay_.wait(std::chrono::seconds(1));
184 osl::MutexGuard g(*
lock_);
188 }
catch (css::uno::RuntimeException &) {
200 css::uno::Reference< css::uno::XComponentContext >
const & context)
202 assert(context.is());
208 return locale ==
u"*";
212 OUString
const & pathRepresentation,
213 OUString * canonicRepresentation, std::vector<OUString> * path,
int * finalizedLayer)
217 pathRepresentation, canonicRepresentation, path, finalizedLayer);
226 roots_.insert(access.get());
238 for (
auto const& elemRoot :
roots_)
241 if (elemRoot->acquireCounting() > 1) {
244 elemRoot->releaseNondeleting();
246 if (root != exclude) {
247 std::vector<OUString> path(root->getAbsolutePath());
249 for (
auto const& pathElem : path)
251 Modifications::Node::Children::const_iterator k(
262 if (mods !=
nullptr) {
263 root->initBroadcaster(*mods, broadcaster);
280 case ModificationTarget::None:
282 case ModificationTarget::File:
289 case ModificationTarget::Dconf:
300 osl::MutexGuard g(*
lock_);
310 bool shared, OUString
const & fileUri)
314 parseXcsFile(fileUri, layer,
data_,
nullptr,
nullptr,
nullptr);
315 }
catch (css::container::NoSuchElementException & e) {
316 throw css::uno::RuntimeException(
317 "insertExtensionXcsFile does not exist: " + e.Message);
322 bool shared, OUString
const & fileUri,
Modifications * modifications)
324 assert(modifications !=
nullptr);
328 parseXcuFile(fileUri, layer,
data_,
nullptr, modifications, adds);
329 }
catch (css::container::NoSuchElementException & e) {
331 throw css::uno::RuntimeException(
332 "insertExtensionXcuFile does not exist: " + e.Message);
352 assert(modifications !=
nullptr);
358 for (Additions::reverse_iterator
i(item->additions.rbegin());
359 i != item->additions.rend(); ++
i)
364 for (
auto const& j : *
i)
371 map = &node->getMembers();
379 if (canRemoveFromLayer(item->layer, node)) {
380 parent->getMembers().erase(
i->back());
382 modifications->
add(*
i);
391 OUString
const & fileUri,
392 std::set< OUString >
const & includedPaths,
393 std::set< OUString >
const & excludedPaths,
396 assert(modifications !=
nullptr);
400 &parseXcuFile, fileUri,
Data::NO_LAYER, &part, modifications,
nullptr);
401 }
catch (
const css::container::NoSuchElementException &) {
404 "error inserting non-existing \"" << fileUri <<
"\"");
409 std::u16string_view descriptor)
411 size_t i = descriptor.find(
' ');
412 if (
i == 0 ||
i == std::u16string_view::npos) {
413 throw css::uno::RuntimeException(
414 OUString::Concat(
"bad external value descriptor ") + descriptor);
417 OUString
name(descriptor.substr(0,
i));
420 css::uno::Reference< css::uno::XInterface > service;
422 service =
context_->getServiceManager()->createInstanceWithContext(
424 }
catch (
const css::uno::RuntimeException &) {
427 }
catch (
const css::uno::Exception &) {
432 "createInstance(" <<
name <<
") failed");
434 css::uno::Reference< css::beans::XPropertySet > propset;
436 propset.set( service, css::uno::UNO_QUERY_THROW);
440 css::beans::Optional< css::uno::Any >
value;
441 if (j->second.is()) {
443 if (!(j->second->getPropertyValue(OUString(descriptor.substr(
i + 1))) >>=
446 throw css::uno::RuntimeException(
447 OUString::Concat(
"cannot obtain external value through ") + descriptor);
449 }
catch (css::beans::UnknownPropertyException & e) {
450 throw css::uno::RuntimeException(
451 "unknown external value descriptor ID: " + e.Message);
452 }
catch (css::lang::WrappedTargetException & e) {
454 throw css::lang::WrappedTargetRuntimeException(
455 "cannot obtain external value: " + e.Message,
463 css::uno::Reference< css::uno::XComponentContext >
const & context):
467 assert(context.is());
469 OUString conf(expand(
"${CONFIGURATION_LAYERS}"));
471 for (sal_Int32
i = 0;;) {
472 while (
i != conf.getLength() && conf[
i] ==
' ') {
475 if (
i == conf.getLength()) {
479 throw css::uno::RuntimeException(
480 "CONFIGURATION_LAYERS: modification target layer followed by"
485 if (c == conf.getLength() || conf[c] ==
' ') {
486 throw css::uno::RuntimeException(
487 "CONFIGURATION_LAYERS: missing ':' in \"" + conf +
"\"");
489 if (conf[c] ==
':') {
493 sal_Int32
n = conf.indexOf(
' ', c + 1);
495 n = conf.getLength();
497 OUString
type(conf.copy(
i, c -
i));
498 OUString url(conf.copy(c + 1,
n - c - 1));
499 if (
type ==
"xcsxcu") {
500 sal_uInt32 nStartTime = osl_getGlobalTimer();
502 SAL_INFO(
"configmgr",
"parseXcsXcuLayer() took " << (osl_getGlobalTimer() - nStartTime) <<
" ms");
504 }
else if (
type ==
"bundledext") {
507 }
else if (
type ==
"sharedext") {
509 throw css::uno::RuntimeException(
510 "CONFIGURATION_LAYERS: multiple \"sharedext\" layers");
515 }
else if (
type ==
"userext") {
517 throw css::uno::RuntimeException(
518 "CONFIGURATION_LAYERS: multiple \"userext\" layers");
523 }
else if (
type ==
"res") {
524 sal_uInt32 nStartTime = osl_getGlobalTimer();
526 SAL_INFO(
"configmgr",
"parseResLayer() took " << (osl_getGlobalTimer() - nStartTime) <<
" ms");
529 }
else if (
type ==
"dconf") {
533 }
else if (url ==
"*") {
536 throw css::uno::RuntimeException(
537 "CONFIGURATION_LAYERS: unknown \"dconf\" kind \"" + url
543 }
else if (
type ==
"winreg") {
545 if (url ==
"LOCAL_MACHINE" || url.isEmpty()) {
547 }
else if (url ==
"CURRENT_USER") {
550 throw css::uno::RuntimeException(
551 "CONFIGURATION_LAYERS: unknown \"winreg\" kind \"" + url
554 OUString aTempFileURL;
557 if (!getenv(
"SAL_CONFIG_WINREG_RETAIN_TMP"))
558 osl::File::remove(aTempFileURL);
562 }
else if (
type ==
"user") {
564 if (url.startsWith(
"!", &url)) {
566 }
else if (url.startsWith(
"*", &url)) {
572 throw css::uno::RuntimeException(
573 "CONFIGURATION_LAYERS: empty \"user\" URL");
579 expand(
"${SYSUSERCONFIG}/libreoffice/dconfwrite"));
580 osl::DirectoryItem it;
581 osl::FileBase::RC e = osl::DirectoryItem::get(token, it);
582 ignore = e == osl::FileBase::E_None;
585 "dconf write (<" << token <<
"> " << +e <<
"): "
601 throw css::uno::RuntimeException(
602 "CONFIGURATION_LAYERS: unknown layer type \"" +
type +
"\"");
620 SAL_WARN_IF(bExitWasCalled,
"configmgr",
"Components::~Components() called after _exit() call");
626 osl::MutexGuard g(*
lock_);
639 for (
auto const& rootElem :
roots_)
641 rootElem->setAlive(
false);
646 FileParser * parseFile, OUString
const & url,
int layer,
650 assert(parseFile !=
nullptr);
652 (*parseFile)(url, layer,
data_, partial, modifications, additions);
653 }
catch (
const css::container::NoSuchElementException &) {
655 }
catch (
const css::uno::Exception &) {
660 "error reading \"" << url <<
"\"");
665 int layer, OUString
const & extension, FileParser * parseFile,
666 OUString
const & url,
bool recursive)
668 osl::Directory dir(url);
669 switch (dir.open()) {
670 case osl::FileBase::E_None:
672 case osl::FileBase::E_NOENT:
678 throw css::uno::RuntimeException(
679 "cannot open directory " + url);
682 osl::DirectoryItem
i;
684 if (rc == osl::FileBase::E_NOENT) {
687 if (rc != osl::FileBase::E_None) {
688 throw css::uno::RuntimeException(
689 "cannot iterate directory " + url);
691 osl::FileStatus stat(
692 osl_FileStatus_Mask_Type | osl_FileStatus_Mask_FileName |
693 osl_FileStatus_Mask_FileURL);
694 if (
i.getFileStatus(stat) != osl::FileBase::E_None) {
695 throw css::uno::RuntimeException(
696 "cannot stat in directory " + url);
698 if (stat.getFileType() == osl::FileStatus::Directory) {
699 parseFiles(layer, extension, parseFile, stat.getFileURL(),
true);
701 OUString file(stat.getFileName());
702 if (file.endsWith(extension)) {
705 parseFile, stat.getFileURL(), layer,
nullptr,
nullptr,
nullptr);
706 }
catch (css::container::NoSuchElementException & e) {
707 if (stat.getFileType() == osl::FileStatus::Link) {
708 SAL_WARN(
"configmgr",
"dangling link <" << stat.getFileURL() <<
">");
711 throw css::uno::RuntimeException(
712 "stat'ed file does not exist: " + e.Message);
720 int layer, FileParser * parseFile, std::u16string_view urls,
721 bool recordAdditions)
723 for (sal_Int32
i = 0;;) {
725 if (!url.isEmpty()) {
727 if (recordAdditions) {
732 }
catch (
const css::container::NoSuchElementException &) {
734 if (adds !=
nullptr) {
746 osl::Directory dir(url);
747 switch (dir.open()) {
748 case osl::FileBase::E_None:
750 case osl::FileBase::E_NOENT:
753 throw css::uno::RuntimeException(
754 "cannot open directory " + url);
756 UnresolvedVector unres;
757 std::set< OUString > existingDeps;
758 std::set< OUString > processedDeps;
760 osl::DirectoryItem
i;
762 if (rc == osl::FileBase::E_NOENT) {
765 if (rc != osl::FileBase::E_None) {
766 throw css::uno::RuntimeException(
767 "cannot iterate directory " + url);
769 osl::FileStatus stat(
770 osl_FileStatus_Mask_Type | osl_FileStatus_Mask_FileName |
771 osl_FileStatus_Mask_FileURL);
772 if (
i.getFileStatus(stat) != osl::FileBase::E_None) {
773 throw css::uno::RuntimeException(
774 "cannot stat in directory " + url);
776 if (stat.getFileType() != osl::FileStatus::Directory) {
777 OUString file(stat.getFileName());
779 if (file.endsWith(
".xcd", &
name)) {
780 existingDeps.insert(
name);
786 }
catch (css::container::NoSuchElementException & e) {
787 if (stat.getFileType() == osl::FileStatus::Link) {
788 SAL_WARN(
"configmgr",
"dangling link <" << stat.getFileURL() <<
">");
791 throw css::uno::RuntimeException(
792 "stat'ed file does not exist: " + e.Message);
795 processedDeps.insert(
name);
802 while (!unres.empty()) {
803 bool resolved =
false;
804 for (UnresolvedVector::iterator
i(unres.begin());
i != unres.end();) {
805 if (
i->manager->parse(&existingDeps)) {
806 processedDeps.insert(
i->name);
814 throw css::uno::RuntimeException(
815 "xcd: unresolved dependencies in " + url);
822 parseFiles(layer,
".xcs", &parseXcsFile, url +
"/schema",
false);
823 parseFiles(layer + 1,
".xcu", &parseXcuFile, url +
"/data",
false);
827 int layer, OUString
const & url,
bool recordAdditions)
832 if (rtl::Bootstrap(url).getHandle() ==
nullptr)
return;
834 OUStringBuffer
prefix(
"${.override:");
835 for (sal_Int32
i = 0;
i != url.getLength(); ++
i) {
848 OUString urls(
prefix +
"SCHEMA}");
849 rtl::Bootstrap::expandMacros(urls);
850 if (!urls.isEmpty()) {
854 rtl::Bootstrap::expandMacros(urls);
855 if (!urls.isEmpty()) {
856 parseFileList(layer + 1, &parseXcuFile, urls, recordAdditions);
861 OUString resUrl(OUString::Concat(url) +
"/res");
863 parseFiles(layer,
".xcu", &parseXcuFile, resUrl,
false);
869 }
catch (css::container::NoSuchElementException &) {
871 "configmgr",
"user registrymodifications.xcu does not (yet) exist");
876 layer,
".xcu", &parseXcuFile,
878 "${$BRAND_BASE_DIR/" LIBO_ETC_FOLDER
"/" SAL_CONFIGFILE(
"bootstrap")
879 ":UserInstallation}/user/registry/data"),
887 throw css::uno::RuntimeException(
888 "insert extension xcs/xcu file into undefined layer");
static bool getExitWasCalled()
rtl::Reference< WriteThread > * reference_
virtual ~WriteThread() override
virtual void execute() override
WriteThread(rtl::Reference< WriteThread > *reference, Components &components, OUString url, Data const &data)
std::shared_ptr< osl::Mutex > lock_
void parseFileList(int layer, FileParser *parseFile, std::u16string_view urls, bool recordAdditions)
void insertModificationXcuFile(OUString const &fileUri, std::set< OUString > const &includedPaths, std::set< OUString > const &excludedPaths, Modifications *modifications)
void removeRootAccess(RootAccess *access)
void initGlobalBroadcaster(Modifications const &modifications, rtl::Reference< RootAccess > const &exclude, Broadcaster *broadcaster)
Components(const Components &)=delete
static bool allLocales(std::u16string_view locale)
void removeExtensionXcuFile(OUString const &fileUri, Modifications *modifications)
void addModification(std::vector< OUString > const &path)
void parseXcdFiles(int layer, OUString const &url)
void parseResLayer(int layer, std::u16string_view url)
rtl::Reference< Node > resolvePathRepresentation(OUString const &pathRepresentation, OUString *canonicRepresentation, std::vector< OUString > *path, int *finalizedLayer) const
OUString modificationFileUrl_
std::shared_ptr< osl::Mutex > lock_
void writeModifications()
void flushModifications()
int sharedExtensionLayer_
void insertExtensionXcsFile(bool shared, OUString const &fileUri)
void parseModificationLayer(int layer, OUString const &url)
css::uno::Reference< css::uno::XComponentContext > context_
int getExtensionLayer(bool shared) const
o3tl::sorted_vector< RootAccess * > roots_
void parseFileLeniently(FileParser *parseFile, OUString const &url, int layer, Partial const *partial, Modifications *modifications, Additions *additions)
rtl::Reference< WriteThread > writeThread_
void addRootAccess(rtl::Reference< RootAccess > const &access)
rtl::Reference< Node > getTemplate(OUString const &fullName) const
void parseXcsXcuIniLayer(int layer, OUString const &url, bool recordAdditions)
ModificationTarget modificationTarget_
void insertExtensionXcuFile(bool shared, OUString const &fileUri, Modifications *modifications)
void parseFiles(int layer, OUString const &extension, FileParser *parseFile, OUString const &url, bool recursive)
ExternalServices externalServices_
void parseXcsXcuLayer(int layer, OUString const &url)
css::beans::Optional< css::uno::Any > getExternalValue(std::u16string_view descriptor)
static Components & getSingleton(css::uno::Reference< css::uno::XComponentContext > const &context)
void add(std::vector< OUString > const &path)
void remove(std::vector< OUString > const &path)
Node const & getRoot() const
@ KIND_LOCALIZED_PROPERTY
rtl::Reference< ParseManager > manager
#define SAL_CONFIGFILE(name)
std::shared_ptr< osl::Mutex > lock_
#define TOOLS_WARN_EXCEPTION(area, stream)
#define SAL_WARN_IF(condition, area, stream)
#define SAL_WARN(area, stream)
#define SAL_INFO(area, stream)
std::set< OUString > includedPaths
std::set< OUString > excludedPaths
void readLayer(Data &data, int layer)
void writeModifications(Components &components, Data &data)
bool dumpWindowsRegistry(OUString *pFileURL, WinRegType eType)
std::shared_ptr< osl::Mutex > const & lock()
std::vector< std::vector< OUString > > Additions
void writeModFile(Components &components, OUString const &url, Data const &data)
Any SAL_CALL getCaughtException()
std::basic_string_view< charT, traits > getToken(std::basic_string_view< charT, traits > sv, charT delimiter, std::size_t &position)
bool parse(OUString const &uri, SourceProviderScannerData *data)
std::map< OUString, rtl::Reference< Entity > > map
rtl::Reference< ExtensionXcu > removeExtensionXcuAdditions(OUString const &url)
Modifications modifications
rtl::Reference< Node > resolvePathRepresentation(OUString const &pathRepresentation, OUString *canonicRepresentation, std::vector< OUString > *path, int *finalizedLayer) const
NodeMap & getComponents() const
Additions * addExtensionXcuAdditions(OUString const &url, int layer)
rtl::Reference< Node > getTemplate(int layer, OUString const &fullName) const