Bump version to 4.1-6
[LibreOffice.git] / configmgr / source / components.cxx
blob6dc34a974976006e84fa07c9ed46d12da6a243f4
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"
68 #ifdef WNT
69 #include "winreg.hxx"
70 #endif
72 namespace configmgr {
74 namespace {
76 struct UnresolvedListItem {
77 OUString name;
78 rtl::Reference< ParseManager > manager;
80 UnresolvedListItem(
81 OUString const & theName,
82 rtl::Reference< ParseManager > theManager):
83 name(theName), manager(theManager) {}
86 typedef std::list< UnresolvedListItem > UnresolvedList;
88 void parseXcsFile(
89 OUString const & url, int layer, Data & data, Partial const * partial,
90 Modifications * modifications, Additions * additions)
91 SAL_THROW((
92 css::container::NoSuchElementException, css::uno::RuntimeException))
94 assert(partial == 0 && modifications == 0 && additions == 0);
95 (void) partial; (void) modifications; (void) additions;
96 bool ok = rtl::Reference< ParseManager >(
97 new ParseManager(url, new XcsParser(layer, data)))->parse(0);
98 assert(ok);
99 (void) ok; // avoid warnings
102 void parseXcuFile(
103 OUString const & url, int layer, Data & data, Partial const * partial,
104 Modifications * modifications, Additions * additions)
105 SAL_THROW((
106 css::container::NoSuchElementException, css::uno::RuntimeException))
108 bool ok = rtl::Reference< ParseManager >(
109 new ParseManager(
110 url,
111 new XcuParser(layer, data, partial, modifications, additions)))->
112 parse(0);
113 assert(ok);
114 (void) ok; // avoid warnings
117 OUString expand(OUString const & str) {
118 OUString s(str);
119 rtl::Bootstrap::expandMacros(s); //TODO: detect failure
120 return s;
123 bool canRemoveFromLayer(int layer, rtl::Reference< Node > const & node) {
124 assert(node.is());
125 if (node->getLayer() > layer && node->getLayer() < Data::NO_LAYER) {
126 return false;
128 switch (node->kind()) {
129 case Node::KIND_LOCALIZED_PROPERTY:
130 case Node::KIND_GROUP:
131 for (NodeMap::const_iterator i(node->getMembers().begin());
132 i != node->getMembers().end(); ++i)
134 if (!canRemoveFromLayer(layer, i->second)) {
135 return false;
138 return true;
139 case Node::KIND_SET:
140 return node->getMembers().empty();
141 default: // Node::KIND_PROPERTY, Node::KIND_LOCALIZED_VALUE
142 return true;
148 class Components::WriteThread: public salhelper::Thread {
149 public:
150 WriteThread(
151 rtl::Reference< WriteThread > * reference, Components & components,
152 OUString const & url, Data const & data);
154 void flush() { delay_.set(); }
156 private:
157 virtual ~WriteThread() {}
159 virtual void execute();
161 rtl::Reference< WriteThread > * reference_;
162 Components & components_;
163 OUString url_;
164 Data const & data_;
165 osl::Condition delay_;
166 boost::shared_ptr<osl::Mutex> lock_;
169 Components::WriteThread::WriteThread(
170 rtl::Reference< WriteThread > * reference, Components & components,
171 OUString const & url, Data const & data):
172 Thread("configmgrWriter"), reference_(reference), components_(components),
173 url_(url), data_(data)
175 lock_ = lock();
176 assert(reference != 0);
179 void Components::WriteThread::execute() {
180 TimeValue t = { 1, 0 }; // 1 sec
181 delay_.wait(&t); // must not throw; result_error is harmless and ignored
182 osl::MutexGuard g(*lock_); // must not throw
183 try {
184 try {
185 writeModFile(components_, url_, data_);
186 } catch (css::uno::RuntimeException & e) {
187 // Ignore write errors, instead of aborting:
188 SAL_WARN(
189 "configmgr",
190 "error writing modifications: \"" << e.Message << '"');
192 } catch (...) {
193 reference_->clear();
194 throw;
196 reference_->clear();
199 class theComponentsSingleton :
200 public rtl::StaticWithArg<
201 Components,
202 css::uno::Reference< css::uno::XComponentContext >,
203 theComponentsSingleton>
207 Components & Components::getSingleton(
208 css::uno::Reference< css::uno::XComponentContext > const & context)
210 assert(context.is());
211 return theComponentsSingleton::get(context);
214 bool Components::allLocales(OUString const & locale) {
215 return locale == "*";
218 rtl::Reference< Node > Components::resolvePathRepresentation(
219 OUString const & pathRepresentation,
220 OUString * canonicRepresentation, Path * path, int * finalizedLayer)
221 const
223 return data_.resolvePathRepresentation(
224 pathRepresentation, canonicRepresentation, path, finalizedLayer);
227 rtl::Reference< Node > Components::getTemplate(
228 int layer, OUString const & fullName) const
230 return data_.getTemplate(layer, fullName);
233 void Components::addRootAccess(rtl::Reference< RootAccess > const & access) {
234 roots_.insert(access.get());
237 void Components::removeRootAccess(RootAccess * access) {
238 roots_.erase(access);
241 void Components::initGlobalBroadcaster(
242 Modifications const & modifications,
243 rtl::Reference< RootAccess > const & exclude, Broadcaster * broadcaster)
245 //TODO: Iterate only over roots w/ listeners:
246 for (WeakRootSet::iterator i(roots_.begin()); i != roots_.end(); ++i) {
247 rtl::Reference< RootAccess > root;
248 if ((*i)->acquireCounting() > 1) {
249 root.set(*i); // must not throw
251 (*i)->releaseNondeleting();
252 if (root.is()) {
253 if (root != exclude) {
254 Path path(root->getAbsolutePath());
255 Modifications::Node const * mods = &modifications.getRoot();
256 for (Path::iterator j(path.begin()); j != path.end(); ++j) {
257 Modifications::Node::Children::const_iterator k(
258 mods->children.find(*j));
259 if (k == mods->children.end()) {
260 mods = 0;
261 break;
263 mods = &k->second;
265 //TODO: If the complete tree of which root is a part is deleted,
266 // or replaced, mods will be null, but some of the listeners
267 // from within root should probably fire nonetheless:
268 if (mods != 0) {
269 root->initBroadcaster(*mods, broadcaster);
276 void Components::addModification(Path const & path) {
277 data_.modifications.add(path);
280 bool Components::hasModifications() const
282 return data_.modifications.getRoot().children.begin() !=
283 data_.modifications.getRoot().children.end();
286 void Components::writeModifications() {
288 if (!hasModifications() || modificationFileUrl_.isEmpty())
289 return;
291 if (!writeThread_.is()) {
292 writeThread_ = new WriteThread(
293 &writeThread_, *this, modificationFileUrl_, data_);
294 writeThread_->launch();
298 void Components::flushModifications() {
299 rtl::Reference< WriteThread > thread;
301 osl::MutexGuard g(*lock_);
302 thread = writeThread_;
304 if (thread.is()) {
305 thread->flush();
306 thread->join();
310 void Components::insertExtensionXcsFile(
311 bool shared, OUString const & fileUri)
313 int layer = getExtensionLayer(shared);
314 try {
315 parseXcsFile(fileUri, layer, data_, 0, 0, 0);
316 } catch (css::container::NoSuchElementException & e) {
317 throw css::uno::RuntimeException(
318 (OUString("insertExtensionXcsFile does not exist: ") +
319 e.Message),
320 css::uno::Reference< css::uno::XInterface >());
324 void Components::insertExtensionXcuFile(
325 bool shared, OUString const & fileUri, Modifications * modifications)
327 assert(modifications != 0);
328 int layer = getExtensionLayer(shared) + 1;
329 Additions * adds = data_.addExtensionXcuAdditions(fileUri, layer);
330 try {
331 parseXcuFile(fileUri, layer, data_, 0, modifications, adds);
332 } catch (css::container::NoSuchElementException & e) {
333 data_.removeExtensionXcuAdditions(fileUri);
334 throw css::uno::RuntimeException(
335 (OUString("insertExtensionXcuFile does not exist: ") +
336 e.Message),
337 css::uno::Reference< css::uno::XInterface >());
341 void Components::removeExtensionXcuFile(
342 OUString const & fileUri, Modifications * modifications)
344 //TODO: Ideally, exactly the data coming from the specified xcu file would
345 // be removed. However, not enough information is recorded in the in-memory
346 // data structures to do so. So, as a workaround, all those set elements
347 // that were freshly added by the xcu and have afterwards been left
348 // unchanged or have only had their properties changed in the user layer are
349 // removed (and nothing else). The heuristic to determine
350 // whether a node has been left unchanged is to check the layer ID (as
351 // usual) and additionally to check that the node does not recursively
352 // contain any non-empty sets (multiple extension xcu files are merged into
353 // one layer, so checking layer ID alone is not enough). Since
354 // item->additions records all additions of set members in textual order,
355 // the latter check works well when iterating through item->additions in
356 // reverse order.
357 assert(modifications != 0);
358 rtl::Reference< Data::ExtensionXcu > item(
359 data_.removeExtensionXcuAdditions(fileUri));
360 if (item.is()) {
361 for (Additions::reverse_iterator i(item->additions.rbegin());
362 i != item->additions.rend(); ++i)
364 rtl::Reference< Node > parent;
365 NodeMap const * map = &data_.getComponents();
366 rtl::Reference< Node > node;
367 for (Path::const_iterator j(i->begin()); j != i->end(); ++j) {
368 parent = node;
369 node = Data::findNode(Data::NO_LAYER, *map, *j);
370 if (!node.is()) {
371 break;
373 map = &node->getMembers();
375 if (node.is()) {
376 assert(parent.is());
377 if (parent->kind() == Node::KIND_SET) {
378 assert(
379 node->kind() == Node::KIND_GROUP ||
380 node->kind() == Node::KIND_SET);
381 if (canRemoveFromLayer(item->layer, node)) {
382 parent->getMembers().erase(i->back());
383 data_.modifications.remove(*i);
384 modifications->add(*i);
389 writeModifications();
393 void Components::insertModificationXcuFile(
394 OUString const & fileUri,
395 std::set< OUString > const & includedPaths,
396 std::set< OUString > const & excludedPaths,
397 Modifications * modifications)
399 assert(modifications != 0);
400 Partial part(includedPaths, excludedPaths);
401 try {
402 parseFileLeniently(
403 &parseXcuFile, fileUri, Data::NO_LAYER, data_, &part, modifications,
405 } catch (css::container::NoSuchElementException & e) {
406 SAL_WARN(
407 "configmgr",
408 "error inserting non-existing \"" << fileUri << "\": \""
409 << e.Message << '"');
413 css::beans::Optional< css::uno::Any > Components::getExternalValue(
414 OUString const & descriptor)
416 sal_Int32 i = descriptor.indexOf(' ');
417 if (i <= 0) {
418 throw css::uno::RuntimeException(
419 (OUString("bad external value descriptor ") +
420 descriptor),
421 css::uno::Reference< css::uno::XInterface >());
423 //TODO: Do not make calls with mutex locked:
424 OUString name(descriptor.copy(0, i));
425 ExternalServices::iterator j(externalServices_.find(name));
426 if (j == externalServices_.end()) {
427 css::uno::Reference< css::uno::XInterface > service;
428 try {
429 service = context_->getServiceManager()->createInstanceWithContext(
430 name, context_);
431 } catch (css::uno::RuntimeException &) {
432 // Assuming these exceptions are real errors:
433 throw;
434 } catch (css::uno::Exception & e) {
435 // Assuming these exceptions indicate that the service is not
436 // installed:
437 SAL_WARN(
438 "configmgr",
439 "createInstance(" << name << ") failed with \"" << e.Message
440 << '"');
442 css::uno::Reference< css::beans::XPropertySet > propset;
443 if (service.is()) {
444 propset = css::uno::Reference< css::beans::XPropertySet >(
445 service, css::uno::UNO_QUERY_THROW);
447 j = externalServices_.insert(
448 ExternalServices::value_type(name, propset)).first;
450 css::beans::Optional< css::uno::Any > value;
451 if (j->second.is()) {
452 try {
453 if (!(j->second->getPropertyValue(descriptor.copy(i + 1)) >>=
454 value))
456 throw css::uno::RuntimeException(
457 (OUString("cannot obtain external value through ") +
458 descriptor),
459 css::uno::Reference< css::uno::XInterface >());
461 } catch (css::beans::UnknownPropertyException & e) {
462 throw css::uno::RuntimeException(
463 (OUString("unknown external value descriptor ID: ") +
464 e.Message),
465 css::uno::Reference< css::uno::XInterface >());
466 } catch (css::lang::WrappedTargetException & e) {
467 throw css::uno::RuntimeException(
468 (OUString("cannot obtain external value: ") +
469 e.Message),
470 css::uno::Reference< css::uno::XInterface >());
473 return value;
476 Components::Components(
477 css::uno::Reference< css::uno::XComponentContext > const & context):
478 context_(context), sharedExtensionLayer_(-1), userExtensionLayer_(-1)
480 assert(context.is());
481 lock_ = lock();
482 OUString conf(
483 expand(
484 OUString("${CONFIGURATION_LAYERS}")));
485 RTL_LOGFILE_TRACE("configmgr : begin parsing");
486 int layer = 0;
487 for (sal_Int32 i = 0;;) {
488 while (i != conf.getLength() && conf[i] == ' ') {
489 ++i;
491 if (i == conf.getLength()) {
492 break;
494 if (!modificationFileUrl_.isEmpty()) {
495 throw css::uno::RuntimeException(
496 OUString("CONFIGURATION_LAYERS: \"user\" followed by further"
497 " layers"),
498 css::uno::Reference< css::uno::XInterface >());
500 sal_Int32 c = i;
501 for (;; ++c) {
502 if (c == conf.getLength() || conf[c] == ' ') {
503 throw css::uno::RuntimeException(
504 OUString("CONFIGURATION_LAYERS: missing \":\""),
505 css::uno::Reference< css::uno::XInterface >());
507 if (conf[c] == ':') {
508 break;
511 sal_Int32 n = conf.indexOf(' ', c + 1);
512 if (n == -1) {
513 n = conf.getLength();
515 OUString type(conf.copy(i, c - i));
516 OUString url(conf.copy(c + 1, n - c - 1));
517 if ( type == "xcsxcu" ) {
518 parseXcsXcuLayer(layer, url);
519 layer += 2; //TODO: overflow
520 } else if ( type == "bundledext" )
522 parseXcsXcuIniLayer(layer, url, false);
523 layer += 2; //TODO: overflow
524 } else if ( type == "sharedext" ) {
525 if (sharedExtensionLayer_ != -1) {
526 throw css::uno::RuntimeException(
527 OUString("CONFIGURATION_LAYERS: multiple \"sharedext\""
528 " layers"),
529 css::uno::Reference< css::uno::XInterface >());
531 sharedExtensionLayer_ = layer;
532 parseXcsXcuIniLayer(layer, url, true);
533 layer += 2; //TODO: overflow
534 } else if ( type == "userext" ) {
535 if (userExtensionLayer_ != -1) {
536 throw css::uno::RuntimeException(
537 OUString("CONFIGURATION_LAYERS: multiple \"userext\""
538 " layers"),
539 css::uno::Reference< css::uno::XInterface >());
541 userExtensionLayer_ = layer;
542 parseXcsXcuIniLayer(layer, url, true);
543 layer += 2; //TODO: overflow
544 } else if ( type == "module" ) {
545 parseModuleLayer(layer, url);
546 ++layer; //TODO: overflow
547 } else if ( type == "res" ) {
548 parseResLayer(layer, url);
549 ++layer; //TODO: overflow
550 } else if ( type == "user" ) {
551 if (url.isEmpty()) {
552 throw css::uno::RuntimeException(
553 OUString("CONFIGURATION_LAYERS: empty \"user\" URL"),
554 css::uno::Reference< css::uno::XInterface >());
556 modificationFileUrl_ = url;
557 parseModificationLayer(url);
559 #ifdef WNT
560 else if ( type == "winreg" )
562 if (!url.isEmpty()) {
563 SAL_WARN(
564 "configmgr",
565 "winreg URL is not empty, URL handling is not implemented for winreg");
567 OUString aTempFileURL;
568 if ( dumpWindowsRegistry(&aTempFileURL) )
570 parseFileLeniently(&parseXcuFile, aTempFileURL, layer, data_, 0, 0, 0);
571 layer++;
572 osl::File::remove(aTempFileURL);
575 #endif
576 else {
577 throw css::uno::RuntimeException(
578 (OUString("CONFIGURATION_LAYERS: unknown layer type \"") +
579 type +
580 OUString("\"")),
581 css::uno::Reference< css::uno::XInterface >());
583 i = n;
585 RTL_LOGFILE_TRACE("configmgr : end parsing");
588 Components::~Components()
590 flushModifications();
591 for (WeakRootSet::iterator i(roots_.begin()); i != roots_.end(); ++i) {
592 (*i)->setAlive(false);
596 void Components::parseFileLeniently(
597 FileParser * parseFile, OUString const & url, int layer, Data & data,
598 Partial const * partial, Modifications * modifications,
599 Additions * additions)
601 assert(parseFile != 0);
602 try {
603 (*parseFile)(url, layer, data, partial, modifications, additions);
604 } catch (css::container::NoSuchElementException &) {
605 throw;
606 } catch (css::uno::Exception & e) { //TODO: more specific exception catching
607 // Ignore invalid XML files, instead of completely preventing OOo from
608 // starting:
609 SAL_WARN(
610 "configmgr",
611 "error reading \"" << url << "\": \"" << e.Message << '"');
615 void Components::parseFiles(
616 int layer, OUString const & extension, FileParser * parseFile,
617 OUString const & url, bool recursive)
619 osl::Directory dir(url);
620 switch (dir.open()) {
621 case osl::FileBase::E_None:
622 break;
623 case osl::FileBase::E_NOENT:
624 if (!recursive) {
625 return;
627 // fall through
628 default:
629 throw css::uno::RuntimeException(
630 (OUString("cannot open directory ") +
631 url),
632 css::uno::Reference< css::uno::XInterface >());
634 for (;;) {
635 osl::DirectoryItem i;
636 osl::FileBase::RC rc = dir.getNextItem(i, SAL_MAX_UINT32);
637 if (rc == osl::FileBase::E_NOENT) {
638 break;
640 if (rc != osl::FileBase::E_None) {
641 throw css::uno::RuntimeException(
642 (OUString("cannot iterate directory ") +
643 url),
644 css::uno::Reference< css::uno::XInterface >());
646 osl::FileStatus stat(
647 osl_FileStatus_Mask_Type | osl_FileStatus_Mask_FileName |
648 osl_FileStatus_Mask_FileURL);
649 if (i.getFileStatus(stat) != osl::FileBase::E_None) {
650 throw css::uno::RuntimeException(
651 (OUString("cannot stat in directory ") +
652 url),
653 css::uno::Reference< css::uno::XInterface >());
655 if (stat.getFileType() == osl::FileStatus::Directory) { //TODO: symlinks
656 parseFiles(layer, extension, parseFile, stat.getFileURL(), true);
657 } else {
658 OUString file(stat.getFileName());
659 if (file.getLength() >= extension.getLength() &&
660 file.match(extension, file.getLength() - extension.getLength()))
662 try {
663 parseFileLeniently(
664 parseFile, stat.getFileURL(), layer, data_, 0, 0, 0);
665 } catch (css::container::NoSuchElementException & e) {
666 throw css::uno::RuntimeException(
667 (OUString("stat'ed file does not exist: ") +
668 e.Message),
669 css::uno::Reference< css::uno::XInterface >());
676 void Components::parseFileList(
677 int layer, FileParser * parseFile, OUString const & urls,
678 bool recordAdditions)
680 for (sal_Int32 i = 0;;) {
681 OUString url(urls.getToken(0, ' ', i));
682 if (!url.isEmpty()) {
683 Additions * adds = 0;
684 if (recordAdditions) {
685 adds = data_.addExtensionXcuAdditions(url, layer);
687 try {
688 parseFileLeniently(parseFile, url, layer, data_, 0, 0, adds);
689 } catch (css::container::NoSuchElementException & e) {
690 SAL_WARN(
691 "configmgr", "file does not exist: \"" << e.Message << '"');
692 if (adds != 0) {
693 data_.removeExtensionXcuAdditions(url);
697 if (i == -1) {
698 break;
703 void Components::parseXcdFiles(int layer, OUString const & url) {
704 osl::Directory dir(url);
705 switch (dir.open()) {
706 case osl::FileBase::E_None:
707 break;
708 case osl::FileBase::E_NOENT:
709 return;
710 default:
711 throw css::uno::RuntimeException(
712 (OUString("cannot open directory ") +
713 url),
714 css::uno::Reference< css::uno::XInterface >());
716 UnresolvedList unres;
717 std::set< OUString > existingDeps;
718 std::set< OUString > processedDeps;
719 for (;;) {
720 osl::DirectoryItem i;
721 osl::FileBase::RC rc = dir.getNextItem(i, SAL_MAX_UINT32);
722 if (rc == osl::FileBase::E_NOENT) {
723 break;
725 if (rc != osl::FileBase::E_None) {
726 throw css::uno::RuntimeException(
727 (OUString("cannot iterate directory ") +
728 url),
729 css::uno::Reference< css::uno::XInterface >());
731 osl::FileStatus stat(
732 osl_FileStatus_Mask_Type | osl_FileStatus_Mask_FileName |
733 osl_FileStatus_Mask_FileURL);
734 if (i.getFileStatus(stat) != osl::FileBase::E_None) {
735 throw css::uno::RuntimeException(
736 (OUString("cannot stat in directory ") +
737 url),
738 css::uno::Reference< css::uno::XInterface >());
740 if (stat.getFileType() != osl::FileStatus::Directory) { //TODO: symlinks
741 OUString file(stat.getFileName());
742 if (file.getLength() >= RTL_CONSTASCII_LENGTH(".xcd") &&
743 file.matchAsciiL(
744 RTL_CONSTASCII_STRINGPARAM(".xcd"),
745 file.getLength() - RTL_CONSTASCII_LENGTH(".xcd")))
747 OUString name(
748 file.copy(
749 0, file.getLength() - RTL_CONSTASCII_LENGTH(".xcd")));
750 existingDeps.insert(name);
751 rtl::Reference< ParseManager > manager;
752 try {
753 manager = new ParseManager(
754 stat.getFileURL(),
755 new XcdParser(layer, processedDeps, data_));
756 } catch (css::container::NoSuchElementException & e) {
757 throw css::uno::RuntimeException(
758 (OUString("stat'ed file does not exist: ") +
759 e.Message),
760 css::uno::Reference< css::uno::XInterface >());
762 if (manager->parse(0)) {
763 processedDeps.insert(name);
764 } else {
765 unres.push_back(UnresolvedListItem(name, manager));
770 while (!unres.empty()) {
771 bool resolved = false;
772 for (UnresolvedList::iterator i(unres.begin()); i != unres.end();) {
773 if (i->manager->parse(&existingDeps)) {
774 processedDeps.insert(i->name);
775 unres.erase(i++);
776 resolved = true;
777 } else {
778 ++i;
781 if (!resolved) {
782 throw css::uno::RuntimeException(
783 (OUString("xcd: unresolved dependencies in ") +
784 url),
785 css::uno::Reference< css::uno::XInterface >());
790 void Components::parseXcsXcuLayer(int layer, OUString const & url) {
791 parseXcdFiles(layer, url);
792 parseFiles(
793 layer, OUString(".xcs"),
794 &parseXcsFile,
795 url + OUString("/schema"), false);
796 parseFiles(
797 layer + 1, OUString(".xcu"),
798 &parseXcuFile,
799 url + OUString("/data"), false);
802 void Components::parseXcsXcuIniLayer(
803 int layer, OUString const & url, bool recordAdditions)
805 // Check if ini file exists (otherwise .override would still read global
806 // SCHEMA/DATA variables, which could interfere with unrelated environment
807 // variables):
808 if (rtl::Bootstrap(url).getHandle() != 0) {
809 OUStringBuffer prefix("${.override:");
810 for (sal_Int32 i = 0; i != url.getLength(); ++i) {
811 sal_Unicode c = url[i];
812 switch (c) {
813 case '$':
814 case ':':
815 case '\\':
816 prefix.append('\\');
817 // fall through
818 default:
819 prefix.append(c);
822 prefix.append(':');
823 OUString urls(prefix.toString() + OUString("SCHEMA}"));
824 rtl::Bootstrap::expandMacros(urls);
825 if (!urls.isEmpty())
827 parseFileList(layer, &parseXcsFile, urls, false);
829 urls = prefix.makeStringAndClear() + OUString("DATA}");
830 rtl::Bootstrap::expandMacros(urls);
831 if (!urls.isEmpty())
833 parseFileList(layer + 1, &parseXcuFile, urls, recordAdditions);
838 void Components::parseModuleLayer(int layer, OUString const & url) {
839 parseFiles(
840 layer, OUString(".xcu"),
841 &parseXcuFile, url, false);
844 void Components::parseResLayer(int layer, OUString const & url) {
845 OUString resUrl(
846 url + OUString("/res"));
847 parseXcdFiles(layer, resUrl);
848 parseFiles(
849 layer, OUString(".xcu"),
850 &parseXcuFile, resUrl, false);
853 void Components::parseModificationLayer(OUString const & url) {
854 try {
855 parseFileLeniently(&parseXcuFile, url, Data::NO_LAYER, data_, 0, 0, 0);
856 } catch (css::container::NoSuchElementException &) {
857 SAL_INFO(
858 "configmgr", "user registrymodifications.xcu does not (yet) exist");
859 // Migrate old user layer data (can be removed once migration is no
860 // longer relevant, probably OOo 4; also see hack for xsi namespace in
861 // xmlreader::XmlReader::registerNamespaceIri):
862 parseFiles(
863 Data::NO_LAYER, OUString(".xcu"),
864 &parseXcuFile,
865 expand(
866 OUString("${$BRAND_BASE_DIR/program/" SAL_CONFIGFILE("bootstrap")
867 ":UserInstallation}/user/registry/data")),
868 false);
872 int Components::getExtensionLayer(bool shared) {
873 int layer = shared ? sharedExtensionLayer_ : userExtensionLayer_;
874 if (layer == -1) {
875 throw css::uno::RuntimeException(
876 OUString("insert extension xcs/xcu file into undefined layer"),
877 css::uno::Reference< css::uno::XInterface >());
879 return layer;
884 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */