bump product version to 4.1.6.2
[LibreOffice.git] / configmgr / source / components.cxx
blobfa1302a4eed4b479b3895d2b69819d61cf92cbe8
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
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 .
20 #include "sal/config.h"
22 #include <algorithm>
23 #include <cassert>
24 #include <cstddef>
25 #include <list>
26 #include <set>
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/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"
39 #include "osl/conditn.hxx"
40 #include "osl/file.hxx"
41 #include "osl/mutex.hxx"
42 #include "rtl/bootstrap.hxx"
43 #include "rtl/logfile.h"
44 #include "rtl/ref.hxx"
45 #include "rtl/string.h"
46 #include "rtl/ustrbuf.hxx"
47 #include "rtl/ustring.h"
48 #include "rtl/ustring.hxx"
49 #include "rtl/instance.hxx"
50 #include "sal/log.hxx"
51 #include "sal/types.h"
52 #include "salhelper/thread.hxx"
54 #include "additions.hxx"
55 #include "components.hxx"
56 #include "data.hxx"
57 #include "lock.hxx"
58 #include "modifications.hxx"
59 #include "node.hxx"
60 #include "nodemap.hxx"
61 #include "parsemanager.hxx"
62 #include "partial.hxx"
63 #include "rootaccess.hxx"
64 #include "writemodfile.hxx"
65 #include "xcdparser.hxx"
66 #include "xcuparser.hxx"
67 #include "xcsparser.hxx"
69 namespace configmgr {
71 namespace {
73 struct UnresolvedListItem {
74 OUString name;
75 rtl::Reference< ParseManager > manager;
77 UnresolvedListItem(
78 OUString const & theName,
79 rtl::Reference< ParseManager > theManager):
80 name(theName), manager(theManager) {}
83 typedef std::list< UnresolvedListItem > UnresolvedList;
85 void parseXcsFile(
86 OUString const & url, int layer, Data & data, Partial const * partial,
87 Modifications * modifications, Additions * additions)
88 SAL_THROW((
89 css::container::NoSuchElementException, css::uno::RuntimeException))
91 assert(partial == 0 && modifications == 0 && additions == 0);
92 (void) partial; (void) modifications; (void) additions;
93 bool ok = rtl::Reference< ParseManager >(
94 new ParseManager(url, new XcsParser(layer, data)))->parse(0);
95 assert(ok);
96 (void) ok; // avoid warnings
99 void parseXcuFile(
100 OUString const & url, int layer, Data & data, Partial const * partial,
101 Modifications * modifications, Additions * additions)
102 SAL_THROW((
103 css::container::NoSuchElementException, css::uno::RuntimeException))
105 bool ok = rtl::Reference< ParseManager >(
106 new ParseManager(
107 url,
108 new XcuParser(layer, data, partial, modifications, additions)))->
109 parse(0);
110 assert(ok);
111 (void) ok; // avoid warnings
114 OUString expand(OUString const & str) {
115 OUString s(str);
116 rtl::Bootstrap::expandMacros(s); //TODO: detect failure
117 return s;
120 bool canRemoveFromLayer(int layer, rtl::Reference< Node > const & node) {
121 assert(node.is());
122 if (node->getLayer() > layer && node->getLayer() < Data::NO_LAYER) {
123 return false;
125 switch (node->kind()) {
126 case Node::KIND_LOCALIZED_PROPERTY:
127 case Node::KIND_GROUP:
128 for (NodeMap::const_iterator i(node->getMembers().begin());
129 i != node->getMembers().end(); ++i)
131 if (!canRemoveFromLayer(layer, i->second)) {
132 return false;
135 return true;
136 case Node::KIND_SET:
137 return node->getMembers().empty();
138 default: // Node::KIND_PROPERTY, Node::KIND_LOCALIZED_VALUE
139 return true;
145 class Components::WriteThread: public salhelper::Thread {
146 public:
147 WriteThread(
148 rtl::Reference< WriteThread > * reference, Components & components,
149 OUString const & url, Data const & data);
151 void flush() { delay_.set(); }
153 private:
154 virtual ~WriteThread() {}
156 virtual void execute();
158 rtl::Reference< WriteThread > * reference_;
159 Components & components_;
160 OUString url_;
161 Data const & data_;
162 osl::Condition delay_;
163 boost::shared_ptr<osl::Mutex> lock_;
166 Components::WriteThread::WriteThread(
167 rtl::Reference< WriteThread > * reference, Components & components,
168 OUString const & url, Data const & data):
169 Thread("configmgrWriter"), reference_(reference), components_(components),
170 url_(url), data_(data)
172 lock_ = lock();
173 assert(reference != 0);
176 void Components::WriteThread::execute() {
177 TimeValue t = { 1, 0 }; // 1 sec
178 delay_.wait(&t); // must not throw; result_error is harmless and ignored
179 osl::MutexGuard g(*lock_); // must not throw
180 try {
181 try {
182 writeModFile(components_, url_, data_);
183 } catch (css::uno::RuntimeException & e) {
184 // Ignore write errors, instead of aborting:
185 SAL_WARN(
186 "configmgr",
187 "error writing modifications: \"" << e.Message << '"');
189 } catch (...) {
190 reference_->clear();
191 throw;
193 reference_->clear();
196 class theComponentsSingleton :
197 public rtl::StaticWithArg<
198 Components,
199 css::uno::Reference< css::uno::XComponentContext >,
200 theComponentsSingleton>
204 Components & Components::getSingleton(
205 css::uno::Reference< css::uno::XComponentContext > const & context)
207 assert(context.is());
208 return theComponentsSingleton::get(context);
211 bool Components::allLocales(OUString const & locale) {
212 return locale == "*";
215 rtl::Reference< Node > Components::resolvePathRepresentation(
216 OUString const & pathRepresentation,
217 OUString * canonicRepresentation, Path * path, int * finalizedLayer)
218 const
220 return data_.resolvePathRepresentation(
221 pathRepresentation, canonicRepresentation, path, finalizedLayer);
224 rtl::Reference< Node > Components::getTemplate(
225 int layer, OUString const & fullName) const
227 return data_.getTemplate(layer, fullName);
230 void Components::addRootAccess(rtl::Reference< RootAccess > const & access) {
231 roots_.insert(access.get());
234 void Components::removeRootAccess(RootAccess * access) {
235 roots_.erase(access);
238 void Components::initGlobalBroadcaster(
239 Modifications const & modifications,
240 rtl::Reference< RootAccess > const & exclude, Broadcaster * broadcaster)
242 //TODO: Iterate only over roots w/ listeners:
243 for (WeakRootSet::iterator i(roots_.begin()); i != roots_.end(); ++i) {
244 rtl::Reference< RootAccess > root;
245 if ((*i)->acquireCounting() > 1) {
246 root.set(*i); // must not throw
248 (*i)->releaseNondeleting();
249 if (root.is()) {
250 if (root != exclude) {
251 Path path(root->getAbsolutePath());
252 Modifications::Node const * mods = &modifications.getRoot();
253 for (Path::iterator j(path.begin()); j != path.end(); ++j) {
254 Modifications::Node::Children::const_iterator k(
255 mods->children.find(*j));
256 if (k == mods->children.end()) {
257 mods = 0;
258 break;
260 mods = &k->second;
262 //TODO: If the complete tree of which root is a part is deleted,
263 // or replaced, mods will be null, but some of the listeners
264 // from within root should probably fire nonetheless:
265 if (mods != 0) {
266 root->initBroadcaster(*mods, broadcaster);
273 void Components::addModification(Path const & path) {
274 data_.modifications.add(path);
277 bool Components::hasModifications() const
279 return data_.modifications.getRoot().children.begin() !=
280 data_.modifications.getRoot().children.end();
283 void Components::writeModifications() {
285 if (!hasModifications() || modificationFileUrl_.isEmpty())
286 return;
288 if (!writeThread_.is()) {
289 writeThread_ = new WriteThread(
290 &writeThread_, *this, modificationFileUrl_, data_);
291 writeThread_->launch();
295 void Components::flushModifications() {
296 rtl::Reference< WriteThread > thread;
298 osl::MutexGuard g(*lock_);
299 thread = writeThread_;
301 if (thread.is()) {
302 thread->flush();
303 thread->join();
307 void Components::insertExtensionXcsFile(
308 bool shared, OUString const & fileUri)
310 int layer = getExtensionLayer(shared);
311 try {
312 parseXcsFile(fileUri, layer, data_, 0, 0, 0);
313 } catch (css::container::NoSuchElementException & e) {
314 throw css::uno::RuntimeException(
315 (OUString("insertExtensionXcsFile does not exist: ") +
316 e.Message),
317 css::uno::Reference< css::uno::XInterface >());
321 void Components::insertExtensionXcuFile(
322 bool shared, OUString const & fileUri, Modifications * modifications)
324 assert(modifications != 0);
325 int layer = getExtensionLayer(shared) + 1;
326 Additions * adds = data_.addExtensionXcuAdditions(fileUri, layer);
327 try {
328 parseXcuFile(fileUri, layer, data_, 0, modifications, adds);
329 } catch (css::container::NoSuchElementException & e) {
330 data_.removeExtensionXcuAdditions(fileUri);
331 throw css::uno::RuntimeException(
332 (OUString("insertExtensionXcuFile does not exist: ") +
333 e.Message),
334 css::uno::Reference< css::uno::XInterface >());
338 void Components::removeExtensionXcuFile(
339 OUString const & fileUri, Modifications * modifications)
341 //TODO: Ideally, exactly the data coming from the specified xcu file would
342 // be removed. However, not enough information is recorded in the in-memory
343 // data structures to do so. So, as a workaround, all those set elements
344 // that were freshly added by the xcu and have afterwards been left
345 // unchanged or have only had their properties changed in the user layer are
346 // removed (and nothing else). The heuristic to determine
347 // whether a node has been left unchanged is to check the layer ID (as
348 // usual) and additionally to check that the node does not recursively
349 // contain any non-empty sets (multiple extension xcu files are merged into
350 // one layer, so checking layer ID alone is not enough). Since
351 // item->additions records all additions of set members in textual order,
352 // the latter check works well when iterating through item->additions in
353 // reverse order.
354 assert(modifications != 0);
355 rtl::Reference< Data::ExtensionXcu > item(
356 data_.removeExtensionXcuAdditions(fileUri));
357 if (item.is()) {
358 for (Additions::reverse_iterator i(item->additions.rbegin());
359 i != item->additions.rend(); ++i)
361 rtl::Reference< Node > parent;
362 NodeMap const * map = &data_.getComponents();
363 rtl::Reference< Node > node;
364 for (Path::const_iterator j(i->begin()); j != i->end(); ++j) {
365 parent = node;
366 node = Data::findNode(Data::NO_LAYER, *map, *j);
367 if (!node.is()) {
368 break;
370 map = &node->getMembers();
372 if (node.is()) {
373 assert(parent.is());
374 if (parent->kind() == Node::KIND_SET) {
375 assert(
376 node->kind() == Node::KIND_GROUP ||
377 node->kind() == Node::KIND_SET);
378 if (canRemoveFromLayer(item->layer, node)) {
379 parent->getMembers().erase(i->back());
380 data_.modifications.remove(*i);
381 modifications->add(*i);
386 writeModifications();
390 void Components::insertModificationXcuFile(
391 OUString const & fileUri,
392 std::set< OUString > const & includedPaths,
393 std::set< OUString > const & excludedPaths,
394 Modifications * modifications)
396 assert(modifications != 0);
397 Partial part(includedPaths, excludedPaths);
398 try {
399 parseFileLeniently(
400 &parseXcuFile, fileUri, Data::NO_LAYER, data_, &part, modifications,
402 } catch (css::container::NoSuchElementException & e) {
403 SAL_WARN(
404 "configmgr",
405 "error inserting non-existing \"" << fileUri << "\": \""
406 << e.Message << '"');
410 css::beans::Optional< css::uno::Any > Components::getExternalValue(
411 OUString const & descriptor)
413 sal_Int32 i = descriptor.indexOf(' ');
414 if (i <= 0) {
415 throw css::uno::RuntimeException(
416 (OUString("bad external value descriptor ") +
417 descriptor),
418 css::uno::Reference< css::uno::XInterface >());
420 //TODO: Do not make calls with mutex locked:
421 OUString name(descriptor.copy(0, i));
422 ExternalServices::iterator j(externalServices_.find(name));
423 if (j == externalServices_.end()) {
424 css::uno::Reference< css::uno::XInterface > service;
425 try {
426 service = context_->getServiceManager()->createInstanceWithContext(
427 name, context_);
428 } catch (css::uno::RuntimeException &) {
429 // Assuming these exceptions are real errors:
430 throw;
431 } catch (css::uno::Exception & e) {
432 // Assuming these exceptions indicate that the service is not
433 // installed:
434 SAL_WARN(
435 "configmgr",
436 "createInstance(" << name << ") failed with \"" << e.Message
437 << '"');
439 css::uno::Reference< css::beans::XPropertySet > propset;
440 if (service.is()) {
441 propset = css::uno::Reference< css::beans::XPropertySet >(
442 service, css::uno::UNO_QUERY_THROW);
444 j = externalServices_.insert(
445 ExternalServices::value_type(name, propset)).first;
447 css::beans::Optional< css::uno::Any > value;
448 if (j->second.is()) {
449 try {
450 if (!(j->second->getPropertyValue(descriptor.copy(i + 1)) >>=
451 value))
453 throw css::uno::RuntimeException(
454 (OUString("cannot obtain external value through ") +
455 descriptor),
456 css::uno::Reference< css::uno::XInterface >());
458 } catch (css::beans::UnknownPropertyException & e) {
459 throw css::uno::RuntimeException(
460 (OUString("unknown external value descriptor ID: ") +
461 e.Message),
462 css::uno::Reference< css::uno::XInterface >());
463 } catch (css::lang::WrappedTargetException & e) {
464 throw css::uno::RuntimeException(
465 (OUString("cannot obtain external value: ") +
466 e.Message),
467 css::uno::Reference< css::uno::XInterface >());
470 return value;
473 Components::Components(
474 css::uno::Reference< css::uno::XComponentContext > const & context):
475 context_(context), sharedExtensionLayer_(-1), userExtensionLayer_(-1)
477 assert(context.is());
478 lock_ = lock();
479 OUString conf(
480 expand(
481 OUString("${CONFIGURATION_LAYERS}")));
482 RTL_LOGFILE_TRACE("configmgr : begin parsing");
483 int layer = 0;
484 for (sal_Int32 i = 0;;) {
485 while (i != conf.getLength() && conf[i] == ' ') {
486 ++i;
488 if (i == conf.getLength()) {
489 break;
491 if (!modificationFileUrl_.isEmpty()) {
492 throw css::uno::RuntimeException(
493 OUString("CONFIGURATION_LAYERS: \"user\" followed by further"
494 " layers"),
495 css::uno::Reference< css::uno::XInterface >());
497 sal_Int32 c = i;
498 for (;; ++c) {
499 if (c == conf.getLength() || conf[c] == ' ') {
500 throw css::uno::RuntimeException(
501 OUString("CONFIGURATION_LAYERS: missing \":\""),
502 css::uno::Reference< css::uno::XInterface >());
504 if (conf[c] == ':') {
505 break;
508 sal_Int32 n = conf.indexOf(' ', c + 1);
509 if (n == -1) {
510 n = conf.getLength();
512 OUString type(conf.copy(i, c - i));
513 OUString url(conf.copy(c + 1, n - c - 1));
514 if ( type == "xcsxcu" ) {
515 parseXcsXcuLayer(layer, url);
516 layer += 2; //TODO: overflow
517 } else if ( type == "bundledext" )
519 parseXcsXcuIniLayer(layer, url, false);
520 layer += 2; //TODO: overflow
521 } else if ( type == "sharedext" ) {
522 if (sharedExtensionLayer_ != -1) {
523 throw css::uno::RuntimeException(
524 OUString("CONFIGURATION_LAYERS: multiple \"sharedext\""
525 " layers"),
526 css::uno::Reference< css::uno::XInterface >());
528 sharedExtensionLayer_ = layer;
529 parseXcsXcuIniLayer(layer, url, true);
530 layer += 2; //TODO: overflow
531 } else if ( type == "userext" ) {
532 if (userExtensionLayer_ != -1) {
533 throw css::uno::RuntimeException(
534 OUString("CONFIGURATION_LAYERS: multiple \"userext\""
535 " layers"),
536 css::uno::Reference< css::uno::XInterface >());
538 userExtensionLayer_ = layer;
539 parseXcsXcuIniLayer(layer, url, true);
540 layer += 2; //TODO: overflow
541 } else if ( type == "module" ) {
542 parseModuleLayer(layer, url);
543 ++layer; //TODO: overflow
544 } else if ( type == "res" ) {
545 parseResLayer(layer, url);
546 ++layer; //TODO: overflow
547 } else if ( type == "user" ) {
548 if (url.isEmpty()) {
549 throw css::uno::RuntimeException(
550 OUString("CONFIGURATION_LAYERS: empty \"user\" URL"),
551 css::uno::Reference< css::uno::XInterface >());
553 modificationFileUrl_ = url;
554 parseModificationLayer(url);
555 } else {
556 throw css::uno::RuntimeException(
557 (OUString("CONFIGURATION_LAYERS: unknown layer type \"") +
558 type +
559 OUString("\"")),
560 css::uno::Reference< css::uno::XInterface >());
562 i = n;
564 RTL_LOGFILE_TRACE("configmgr : end parsing");
567 Components::~Components()
569 flushModifications();
570 for (WeakRootSet::iterator i(roots_.begin()); i != roots_.end(); ++i) {
571 (*i)->setAlive(false);
575 void Components::parseFileLeniently(
576 FileParser * parseFile, OUString const & url, int layer, Data & data,
577 Partial const * partial, Modifications * modifications,
578 Additions * additions)
580 assert(parseFile != 0);
581 try {
582 (*parseFile)(url, layer, data, partial, modifications, additions);
583 } catch (css::container::NoSuchElementException &) {
584 throw;
585 } catch (css::uno::Exception & e) { //TODO: more specific exception catching
586 // Ignore invalid XML files, instead of completely preventing OOo from
587 // starting:
588 SAL_WARN(
589 "configmgr",
590 "error reading \"" << url << "\": \"" << e.Message << '"');
594 void Components::parseFiles(
595 int layer, OUString const & extension, FileParser * parseFile,
596 OUString const & url, bool recursive)
598 osl::Directory dir(url);
599 switch (dir.open()) {
600 case osl::FileBase::E_None:
601 break;
602 case osl::FileBase::E_NOENT:
603 if (!recursive) {
604 return;
606 // fall through
607 default:
608 throw css::uno::RuntimeException(
609 (OUString("cannot open directory ") +
610 url),
611 css::uno::Reference< css::uno::XInterface >());
613 for (;;) {
614 osl::DirectoryItem i;
615 osl::FileBase::RC rc = dir.getNextItem(i, SAL_MAX_UINT32);
616 if (rc == osl::FileBase::E_NOENT) {
617 break;
619 if (rc != osl::FileBase::E_None) {
620 throw css::uno::RuntimeException(
621 (OUString("cannot iterate directory ") +
622 url),
623 css::uno::Reference< css::uno::XInterface >());
625 osl::FileStatus stat(
626 osl_FileStatus_Mask_Type | osl_FileStatus_Mask_FileName |
627 osl_FileStatus_Mask_FileURL);
628 if (i.getFileStatus(stat) != osl::FileBase::E_None) {
629 throw css::uno::RuntimeException(
630 (OUString("cannot stat in directory ") +
631 url),
632 css::uno::Reference< css::uno::XInterface >());
634 if (stat.getFileType() == osl::FileStatus::Directory) { //TODO: symlinks
635 parseFiles(layer, extension, parseFile, stat.getFileURL(), true);
636 } else {
637 OUString file(stat.getFileName());
638 if (file.getLength() >= extension.getLength() &&
639 file.match(extension, file.getLength() - extension.getLength()))
641 try {
642 parseFileLeniently(
643 parseFile, stat.getFileURL(), layer, data_, 0, 0, 0);
644 } catch (css::container::NoSuchElementException & e) {
645 throw css::uno::RuntimeException(
646 (OUString("stat'ed file does not exist: ") +
647 e.Message),
648 css::uno::Reference< css::uno::XInterface >());
655 void Components::parseFileList(
656 int layer, FileParser * parseFile, OUString const & urls,
657 bool recordAdditions)
659 for (sal_Int32 i = 0;;) {
660 OUString url(urls.getToken(0, ' ', i));
661 if (!url.isEmpty()) {
662 Additions * adds = 0;
663 if (recordAdditions) {
664 adds = data_.addExtensionXcuAdditions(url, layer);
666 try {
667 parseFileLeniently(parseFile, url, layer, data_, 0, 0, adds);
668 } catch (css::container::NoSuchElementException & e) {
669 SAL_WARN(
670 "configmgr", "file does not exist: \"" << e.Message << '"');
671 if (adds != 0) {
672 data_.removeExtensionXcuAdditions(url);
676 if (i == -1) {
677 break;
682 void Components::parseXcdFiles(int layer, OUString const & url) {
683 osl::Directory dir(url);
684 switch (dir.open()) {
685 case osl::FileBase::E_None:
686 break;
687 case osl::FileBase::E_NOENT:
688 return;
689 default:
690 throw css::uno::RuntimeException(
691 (OUString("cannot open directory ") +
692 url),
693 css::uno::Reference< css::uno::XInterface >());
695 UnresolvedList unres;
696 std::set< OUString > existingDeps;
697 std::set< OUString > processedDeps;
698 for (;;) {
699 osl::DirectoryItem i;
700 osl::FileBase::RC rc = dir.getNextItem(i, SAL_MAX_UINT32);
701 if (rc == osl::FileBase::E_NOENT) {
702 break;
704 if (rc != osl::FileBase::E_None) {
705 throw css::uno::RuntimeException(
706 (OUString("cannot iterate directory ") +
707 url),
708 css::uno::Reference< css::uno::XInterface >());
710 osl::FileStatus stat(
711 osl_FileStatus_Mask_Type | osl_FileStatus_Mask_FileName |
712 osl_FileStatus_Mask_FileURL);
713 if (i.getFileStatus(stat) != osl::FileBase::E_None) {
714 throw css::uno::RuntimeException(
715 (OUString("cannot stat in directory ") +
716 url),
717 css::uno::Reference< css::uno::XInterface >());
719 if (stat.getFileType() != osl::FileStatus::Directory) { //TODO: symlinks
720 OUString file(stat.getFileName());
721 if (file.getLength() >= RTL_CONSTASCII_LENGTH(".xcd") &&
722 file.matchAsciiL(
723 RTL_CONSTASCII_STRINGPARAM(".xcd"),
724 file.getLength() - RTL_CONSTASCII_LENGTH(".xcd")))
726 OUString name(
727 file.copy(
728 0, file.getLength() - RTL_CONSTASCII_LENGTH(".xcd")));
729 existingDeps.insert(name);
730 rtl::Reference< ParseManager > manager;
731 try {
732 manager = new ParseManager(
733 stat.getFileURL(),
734 new XcdParser(layer, processedDeps, data_));
735 } catch (css::container::NoSuchElementException & e) {
736 throw css::uno::RuntimeException(
737 (OUString("stat'ed file does not exist: ") +
738 e.Message),
739 css::uno::Reference< css::uno::XInterface >());
741 if (manager->parse(0)) {
742 processedDeps.insert(name);
743 } else {
744 unres.push_back(UnresolvedListItem(name, manager));
749 while (!unres.empty()) {
750 bool resolved = false;
751 for (UnresolvedList::iterator i(unres.begin()); i != unres.end();) {
752 if (i->manager->parse(&existingDeps)) {
753 processedDeps.insert(i->name);
754 unres.erase(i++);
755 resolved = true;
756 } else {
757 ++i;
760 if (!resolved) {
761 throw css::uno::RuntimeException(
762 (OUString("xcd: unresolved dependencies in ") +
763 url),
764 css::uno::Reference< css::uno::XInterface >());
769 void Components::parseXcsXcuLayer(int layer, OUString const & url) {
770 parseXcdFiles(layer, url);
771 parseFiles(
772 layer, OUString(".xcs"),
773 &parseXcsFile,
774 url + OUString("/schema"), false);
775 parseFiles(
776 layer + 1, OUString(".xcu"),
777 &parseXcuFile,
778 url + OUString("/data"), false);
781 void Components::parseXcsXcuIniLayer(
782 int layer, OUString const & url, bool recordAdditions)
784 // Check if ini file exists (otherwise .override would still read global
785 // SCHEMA/DATA variables, which could interfere with unrelated environment
786 // variables):
787 if (rtl::Bootstrap(url).getHandle() != 0) {
788 OUStringBuffer prefix("${.override:");
789 for (sal_Int32 i = 0; i != url.getLength(); ++i) {
790 sal_Unicode c = url[i];
791 switch (c) {
792 case '$':
793 case ':':
794 case '\\':
795 prefix.append('\\');
796 // fall through
797 default:
798 prefix.append(c);
801 prefix.append(':');
802 OUString urls(prefix.toString() + OUString("SCHEMA}"));
803 rtl::Bootstrap::expandMacros(urls);
804 if (!urls.isEmpty())
806 parseFileList(layer, &parseXcsFile, urls, false);
808 urls = prefix.makeStringAndClear() + OUString("DATA}");
809 rtl::Bootstrap::expandMacros(urls);
810 if (!urls.isEmpty())
812 parseFileList(layer + 1, &parseXcuFile, urls, recordAdditions);
817 void Components::parseModuleLayer(int layer, OUString const & url) {
818 parseFiles(
819 layer, OUString(".xcu"),
820 &parseXcuFile, url, false);
823 void Components::parseResLayer(int layer, OUString const & url) {
824 OUString resUrl(
825 url + OUString("/res"));
826 parseXcdFiles(layer, resUrl);
827 parseFiles(
828 layer, OUString(".xcu"),
829 &parseXcuFile, resUrl, false);
832 void Components::parseModificationLayer(OUString const & url) {
833 try {
834 parseFileLeniently(&parseXcuFile, url, Data::NO_LAYER, data_, 0, 0, 0);
835 } catch (css::container::NoSuchElementException &) {
836 SAL_INFO(
837 "configmgr", "user registrymodifications.xcu does not (yet) exist");
838 // Migrate old user layer data (can be removed once migration is no
839 // longer relevant, probably OOo 4; also see hack for xsi namespace in
840 // xmlreader::XmlReader::registerNamespaceIri):
841 parseFiles(
842 Data::NO_LAYER, OUString(".xcu"),
843 &parseXcuFile,
844 expand(
845 OUString("${$BRAND_BASE_DIR/program/" SAL_CONFIGFILE("bootstrap")
846 ":UserInstallation}/user/registry/data")),
847 false);
851 int Components::getExtensionLayer(bool shared) {
852 int layer = shared ? sharedExtensionLayer_ : userExtensionLayer_;
853 if (layer == -1) {
854 throw css::uno::RuntimeException(
855 OUString("insert extension xcs/xcu file into undefined layer"),
856 css::uno::Reference< css::uno::XInterface >());
858 return layer;
863 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */