Version 4.0.0.1, tag libreoffice-4.0.0.1
[LibreOffice.git] / configmgr / source / components.cxx
blob779a030ce72fa0a9cd11fbbfd70909fcbe9461d1
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 rtl::OUString name;
75 rtl::Reference< ParseManager > manager;
77 UnresolvedListItem(
78 rtl::OUString const & theName,
79 rtl::Reference< ParseManager > theManager):
80 name(theName), manager(theManager) {}
83 typedef std::list< UnresolvedListItem > UnresolvedList;
85 void parseXcsFile(
86 rtl::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 rtl::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 rtl::OUString expand(rtl::OUString const & str) {
115 rtl::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 rtl::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 rtl::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 rtl::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(rtl::OUString const & locale) {
212 return locale == "*";
215 rtl::Reference< Node > Components::resolvePathRepresentation(
216 rtl::OUString const & pathRepresentation,
217 rtl::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, rtl::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, rtl::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 (rtl::OUString(
316 RTL_CONSTASCII_USTRINGPARAM(
317 "insertExtensionXcsFile does not exist: ")) +
318 e.Message),
319 css::uno::Reference< css::uno::XInterface >());
323 void Components::insertExtensionXcuFile(
324 bool shared, rtl::OUString const & fileUri, Modifications * modifications)
326 assert(modifications != 0);
327 int layer = getExtensionLayer(shared) + 1;
328 Additions * adds = data_.addExtensionXcuAdditions(fileUri, layer);
329 try {
330 parseXcuFile(fileUri, layer, data_, 0, modifications, adds);
331 } catch (css::container::NoSuchElementException & e) {
332 data_.removeExtensionXcuAdditions(fileUri);
333 throw css::uno::RuntimeException(
334 (rtl::OUString(
335 RTL_CONSTASCII_USTRINGPARAM(
336 "insertExtensionXcuFile does not exist: ")) +
337 e.Message),
338 css::uno::Reference< css::uno::XInterface >());
342 void Components::removeExtensionXcuFile(
343 rtl::OUString const & fileUri, Modifications * modifications)
345 //TODO: Ideally, exactly the data coming from the specified xcu file would
346 // be removed. However, not enough information is recorded in the in-memory
347 // data structures to do so. So, as a workaround, all those set elements
348 // that were freshly added by the xcu and have afterwards been left
349 // unchanged or have only had their properties changed in the user layer are
350 // removed (and nothing else). The heuristic to determine
351 // whether a node has been left unchanged is to check the layer ID (as
352 // usual) and additionally to check that the node does not recursively
353 // contain any non-empty sets (multiple extension xcu files are merged into
354 // one layer, so checking layer ID alone is not enough). Since
355 // item->additions records all additions of set members in textual order,
356 // the latter check works well when iterating through item->additions in
357 // reverse order.
358 assert(modifications != 0);
359 rtl::Reference< Data::ExtensionXcu > item(
360 data_.removeExtensionXcuAdditions(fileUri));
361 if (item.is()) {
362 for (Additions::reverse_iterator i(item->additions.rbegin());
363 i != item->additions.rend(); ++i)
365 rtl::Reference< Node > parent;
366 NodeMap const * map = &data_.getComponents();
367 rtl::Reference< Node > node;
368 for (Path::const_iterator j(i->begin()); j != i->end(); ++j) {
369 parent = node;
370 node = Data::findNode(Data::NO_LAYER, *map, *j);
371 if (!node.is()) {
372 break;
374 map = &node->getMembers();
376 if (node.is()) {
377 assert(parent.is());
378 if (parent->kind() == Node::KIND_SET) {
379 assert(
380 node->kind() == Node::KIND_GROUP ||
381 node->kind() == Node::KIND_SET);
382 if (canRemoveFromLayer(item->layer, node)) {
383 parent->getMembers().erase(i->back());
384 data_.modifications.remove(*i);
385 modifications->add(*i);
390 writeModifications();
394 void Components::insertModificationXcuFile(
395 rtl::OUString const & fileUri,
396 std::set< rtl::OUString > const & includedPaths,
397 std::set< rtl::OUString > const & excludedPaths,
398 Modifications * modifications)
400 assert(modifications != 0);
401 Partial part(includedPaths, excludedPaths);
402 try {
403 parseFileLeniently(
404 &parseXcuFile, fileUri, Data::NO_LAYER, data_, &part, modifications,
406 } catch (css::container::NoSuchElementException & e) {
407 SAL_WARN(
408 "configmgr",
409 "error inserting non-existing \"" << fileUri << "\": \""
410 << e.Message << '"');
414 css::beans::Optional< css::uno::Any > Components::getExternalValue(
415 rtl::OUString const & descriptor)
417 sal_Int32 i = descriptor.indexOf(' ');
418 if (i <= 0) {
419 throw css::uno::RuntimeException(
420 (rtl::OUString(
421 RTL_CONSTASCII_USTRINGPARAM("bad external value descriptor ")) +
422 descriptor),
423 css::uno::Reference< css::uno::XInterface >());
425 //TODO: Do not make calls with mutex locked:
426 rtl::OUString name(descriptor.copy(0, i));
427 ExternalServices::iterator j(externalServices_.find(name));
428 if (j == externalServices_.end()) {
429 css::uno::Reference< css::uno::XInterface > service;
430 try {
431 service = context_->getServiceManager()->createInstanceWithContext(
432 name, context_);
433 } catch (css::uno::RuntimeException &) {
434 // Assuming these exceptions are real errors:
435 throw;
436 } catch (css::uno::Exception & e) {
437 // Assuming these exceptions indicate that the service is not
438 // installed:
439 SAL_WARN(
440 "configmgr",
441 "createInstance(" << name << ") failed with \"" << e.Message
442 << '"');
444 css::uno::Reference< css::beans::XPropertySet > propset;
445 if (service.is()) {
446 propset = css::uno::Reference< css::beans::XPropertySet >(
447 service, css::uno::UNO_QUERY_THROW);
449 j = externalServices_.insert(
450 ExternalServices::value_type(name, propset)).first;
452 css::beans::Optional< css::uno::Any > value;
453 if (j->second.is()) {
454 try {
455 if (!(j->second->getPropertyValue(descriptor.copy(i + 1)) >>=
456 value))
458 throw css::uno::RuntimeException(
459 (rtl::OUString(
460 RTL_CONSTASCII_USTRINGPARAM(
461 "cannot obtain external value through ")) +
462 descriptor),
463 css::uno::Reference< css::uno::XInterface >());
465 } catch (css::beans::UnknownPropertyException & e) {
466 throw css::uno::RuntimeException(
467 (rtl::OUString(
468 RTL_CONSTASCII_USTRINGPARAM(
469 "unknown external value descriptor ID: ")) +
470 e.Message),
471 css::uno::Reference< css::uno::XInterface >());
472 } catch (css::lang::WrappedTargetException & e) {
473 throw css::uno::RuntimeException(
474 (rtl::OUString(
475 RTL_CONSTASCII_USTRINGPARAM(
476 "cannot obtain external value: ")) +
477 e.Message),
478 css::uno::Reference< css::uno::XInterface >());
481 return value;
484 Components::Components(
485 css::uno::Reference< css::uno::XComponentContext > const & context):
486 context_(context), sharedExtensionLayer_(-1), userExtensionLayer_(-1)
488 assert(context.is());
489 lock_ = lock();
490 rtl::OUString conf(
491 expand(
492 rtl::OUString(
493 RTL_CONSTASCII_USTRINGPARAM("${CONFIGURATION_LAYERS}"))));
494 RTL_LOGFILE_TRACE("configmgr : begin parsing");
495 int layer = 0;
496 for (sal_Int32 i = 0;;) {
497 while (i != conf.getLength() && conf[i] == ' ') {
498 ++i;
500 if (i == conf.getLength()) {
501 break;
503 if (!modificationFileUrl_.isEmpty()) {
504 throw css::uno::RuntimeException(
505 rtl::OUString(
506 RTL_CONSTASCII_USTRINGPARAM(
507 "CONFIGURATION_LAYERS: \"user\" followed by further"
508 " layers")),
509 css::uno::Reference< css::uno::XInterface >());
511 sal_Int32 c = i;
512 for (;; ++c) {
513 if (c == conf.getLength() || conf[c] == ' ') {
514 throw css::uno::RuntimeException(
515 rtl::OUString(
516 RTL_CONSTASCII_USTRINGPARAM(
517 "CONFIGURATION_LAYERS: missing \":\"")),
518 css::uno::Reference< css::uno::XInterface >());
520 if (conf[c] == ':') {
521 break;
524 sal_Int32 n = conf.indexOf(' ', c + 1);
525 if (n == -1) {
526 n = conf.getLength();
528 rtl::OUString type(conf.copy(i, c - i));
529 rtl::OUString url(conf.copy(c + 1, n - c - 1));
530 if ( type == "xcsxcu" ) {
531 parseXcsXcuLayer(layer, url);
532 layer += 2; //TODO: overflow
533 } else if ( type == "bundledext" )
535 parseXcsXcuIniLayer(layer, url, false);
536 layer += 2; //TODO: overflow
537 } else if ( type == "sharedext" ) {
538 if (sharedExtensionLayer_ != -1) {
539 throw css::uno::RuntimeException(
540 rtl::OUString(
541 RTL_CONSTASCII_USTRINGPARAM(
542 "CONFIGURATION_LAYERS: multiple \"sharedext\""
543 " layers")),
544 css::uno::Reference< css::uno::XInterface >());
546 sharedExtensionLayer_ = layer;
547 parseXcsXcuIniLayer(layer, url, true);
548 layer += 2; //TODO: overflow
549 } else if ( type == "userext" ) {
550 if (userExtensionLayer_ != -1) {
551 throw css::uno::RuntimeException(
552 rtl::OUString(
553 RTL_CONSTASCII_USTRINGPARAM(
554 "CONFIGURATION_LAYERS: multiple \"userext\""
555 " layers")),
556 css::uno::Reference< css::uno::XInterface >());
558 userExtensionLayer_ = layer;
559 parseXcsXcuIniLayer(layer, url, true);
560 layer += 2; //TODO: overflow
561 } else if ( type == "module" ) {
562 parseModuleLayer(layer, url);
563 ++layer; //TODO: overflow
564 } else if ( type == "res" ) {
565 parseResLayer(layer, url);
566 ++layer; //TODO: overflow
567 } else if ( type == "user" ) {
568 if (url.isEmpty()) {
569 throw css::uno::RuntimeException(
570 rtl::OUString(
571 RTL_CONSTASCII_USTRINGPARAM(
572 "CONFIGURATION_LAYERS: empty \"user\" URL")),
573 css::uno::Reference< css::uno::XInterface >());
575 modificationFileUrl_ = url;
576 parseModificationLayer(url);
577 } else {
578 throw css::uno::RuntimeException(
579 (rtl::OUString(
580 RTL_CONSTASCII_USTRINGPARAM(
581 "CONFIGURATION_LAYERS: unknown layer type \"")) +
582 type +
583 rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("\""))),
584 css::uno::Reference< css::uno::XInterface >());
586 i = n;
588 RTL_LOGFILE_TRACE("configmgr : end parsing");
591 Components::~Components()
593 flushModifications();
594 for (WeakRootSet::iterator i(roots_.begin()); i != roots_.end(); ++i) {
595 (*i)->setAlive(false);
599 void Components::parseFileLeniently(
600 FileParser * parseFile, rtl::OUString const & url, int layer, Data & data,
601 Partial const * partial, Modifications * modifications,
602 Additions * additions)
604 assert(parseFile != 0);
605 try {
606 (*parseFile)(url, layer, data, partial, modifications, additions);
607 } catch (css::container::NoSuchElementException &) {
608 throw;
609 } catch (css::uno::Exception & e) { //TODO: more specific exception catching
610 // Ignore invalid XML files, instead of completely preventing OOo from
611 // starting:
612 SAL_WARN(
613 "configmgr",
614 "error reading \"" << url << "\": \"" << e.Message << '"');
618 void Components::parseFiles(
619 int layer, rtl::OUString const & extension, FileParser * parseFile,
620 rtl::OUString const & url, bool recursive)
622 osl::Directory dir(url);
623 switch (dir.open()) {
624 case osl::FileBase::E_None:
625 break;
626 case osl::FileBase::E_NOENT:
627 if (!recursive) {
628 return;
630 // fall through
631 default:
632 throw css::uno::RuntimeException(
633 (rtl::OUString(
634 RTL_CONSTASCII_USTRINGPARAM("cannot open directory ")) +
635 url),
636 css::uno::Reference< css::uno::XInterface >());
638 for (;;) {
639 osl::DirectoryItem i;
640 osl::FileBase::RC rc = dir.getNextItem(i, SAL_MAX_UINT32);
641 if (rc == osl::FileBase::E_NOENT) {
642 break;
644 if (rc != osl::FileBase::E_None) {
645 throw css::uno::RuntimeException(
646 (rtl::OUString(
647 RTL_CONSTASCII_USTRINGPARAM("cannot iterate directory ")) +
648 url),
649 css::uno::Reference< css::uno::XInterface >());
651 osl::FileStatus stat(
652 osl_FileStatus_Mask_Type | osl_FileStatus_Mask_FileName |
653 osl_FileStatus_Mask_FileURL);
654 if (i.getFileStatus(stat) != osl::FileBase::E_None) {
655 throw css::uno::RuntimeException(
656 (rtl::OUString(
657 RTL_CONSTASCII_USTRINGPARAM("cannot stat in directory ")) +
658 url),
659 css::uno::Reference< css::uno::XInterface >());
661 if (stat.getFileType() == osl::FileStatus::Directory) { //TODO: symlinks
662 parseFiles(layer, extension, parseFile, stat.getFileURL(), true);
663 } else {
664 rtl::OUString file(stat.getFileName());
665 if (file.getLength() >= extension.getLength() &&
666 file.match(extension, file.getLength() - extension.getLength()))
668 try {
669 parseFileLeniently(
670 parseFile, stat.getFileURL(), layer, data_, 0, 0, 0);
671 } catch (css::container::NoSuchElementException & e) {
672 throw css::uno::RuntimeException(
673 (rtl::OUString(
674 RTL_CONSTASCII_USTRINGPARAM(
675 "stat'ed file does not exist: ")) +
676 e.Message),
677 css::uno::Reference< css::uno::XInterface >());
684 void Components::parseFileList(
685 int layer, FileParser * parseFile, rtl::OUString const & urls,
686 bool recordAdditions)
688 for (sal_Int32 i = 0;;) {
689 rtl::OUString url(urls.getToken(0, ' ', i));
690 if (!url.isEmpty()) {
691 Additions * adds = 0;
692 if (recordAdditions) {
693 adds = data_.addExtensionXcuAdditions(url, layer);
695 try {
696 parseFileLeniently(parseFile, url, layer, data_, 0, 0, adds);
697 } catch (css::container::NoSuchElementException & e) {
698 SAL_WARN(
699 "configmgr", "file does not exist: \"" << e.Message << '"');
700 if (adds != 0) {
701 data_.removeExtensionXcuAdditions(url);
705 if (i == -1) {
706 break;
711 void Components::parseXcdFiles(int layer, rtl::OUString const & url) {
712 osl::Directory dir(url);
713 switch (dir.open()) {
714 case osl::FileBase::E_None:
715 break;
716 case osl::FileBase::E_NOENT:
717 return;
718 default:
719 throw css::uno::RuntimeException(
720 (rtl::OUString(
721 RTL_CONSTASCII_USTRINGPARAM("cannot open directory ")) +
722 url),
723 css::uno::Reference< css::uno::XInterface >());
725 UnresolvedList unres;
726 std::set< OUString > existingDeps;
727 std::set< OUString > processedDeps;
728 for (;;) {
729 osl::DirectoryItem i;
730 osl::FileBase::RC rc = dir.getNextItem(i, SAL_MAX_UINT32);
731 if (rc == osl::FileBase::E_NOENT) {
732 break;
734 if (rc != osl::FileBase::E_None) {
735 throw css::uno::RuntimeException(
736 (rtl::OUString(
737 RTL_CONSTASCII_USTRINGPARAM("cannot iterate directory ")) +
738 url),
739 css::uno::Reference< css::uno::XInterface >());
741 osl::FileStatus stat(
742 osl_FileStatus_Mask_Type | osl_FileStatus_Mask_FileName |
743 osl_FileStatus_Mask_FileURL);
744 if (i.getFileStatus(stat) != osl::FileBase::E_None) {
745 throw css::uno::RuntimeException(
746 (rtl::OUString(
747 RTL_CONSTASCII_USTRINGPARAM("cannot stat in directory ")) +
748 url),
749 css::uno::Reference< css::uno::XInterface >());
751 if (stat.getFileType() != osl::FileStatus::Directory) { //TODO: symlinks
752 rtl::OUString file(stat.getFileName());
753 if (file.getLength() >= RTL_CONSTASCII_LENGTH(".xcd") &&
754 file.matchAsciiL(
755 RTL_CONSTASCII_STRINGPARAM(".xcd"),
756 file.getLength() - RTL_CONSTASCII_LENGTH(".xcd")))
758 rtl::OUString name(
759 file.copy(
760 0, file.getLength() - RTL_CONSTASCII_LENGTH(".xcd")));
761 existingDeps.insert(name);
762 rtl::Reference< ParseManager > manager;
763 try {
764 manager = new ParseManager(
765 stat.getFileURL(),
766 new XcdParser(layer, processedDeps, data_));
767 } catch (css::container::NoSuchElementException & e) {
768 throw css::uno::RuntimeException(
769 (rtl::OUString(
770 RTL_CONSTASCII_USTRINGPARAM(
771 "stat'ed file does not exist: ")) +
772 e.Message),
773 css::uno::Reference< css::uno::XInterface >());
775 if (manager->parse(0)) {
776 processedDeps.insert(name);
777 } else {
778 unres.push_back(UnresolvedListItem(name, manager));
783 while (!unres.empty()) {
784 bool resolved = false;
785 for (UnresolvedList::iterator i(unres.begin()); i != unres.end();) {
786 if (i->manager->parse(&existingDeps)) {
787 processedDeps.insert(i->name);
788 unres.erase(i++);
789 resolved = true;
790 } else {
791 ++i;
794 if (!resolved) {
795 throw css::uno::RuntimeException(
796 (rtl::OUString(
797 RTL_CONSTASCII_USTRINGPARAM(
798 "xcd: unresolved dependencies in ")) +
799 url),
800 css::uno::Reference< css::uno::XInterface >());
805 void Components::parseXcsXcuLayer(int layer, rtl::OUString const & url) {
806 parseXcdFiles(layer, url);
807 parseFiles(
808 layer, rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(".xcs")),
809 &parseXcsFile,
810 url + rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("/schema")), false);
811 parseFiles(
812 layer + 1, rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(".xcu")),
813 &parseXcuFile,
814 url + rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("/data")), false);
817 void Components::parseXcsXcuIniLayer(
818 int layer, rtl::OUString const & url, bool recordAdditions)
820 // Check if ini file exists (otherwise .override would still read global
821 // SCHEMA/DATA variables, which could interfere with unrelated environment
822 // variables):
823 if (rtl::Bootstrap(url).getHandle() != 0) {
824 rtl::OUStringBuffer prefix("${.override:");
825 for (sal_Int32 i = 0; i != url.getLength(); ++i) {
826 sal_Unicode c = url[i];
827 switch (c) {
828 case '$':
829 case ':':
830 case '\\':
831 prefix.append('\\');
832 // fall through
833 default:
834 prefix.append(c);
837 prefix.append(':');
838 rtl::OUString urls(prefix.toString() + rtl::OUString("SCHEMA}"));
839 rtl::Bootstrap::expandMacros(urls);
840 if (!urls.isEmpty())
842 parseFileList(layer, &parseXcsFile, urls, false);
844 urls = prefix.makeStringAndClear() + rtl::OUString("DATA}");
845 rtl::Bootstrap::expandMacros(urls);
846 if (!urls.isEmpty())
848 parseFileList(layer + 1, &parseXcuFile, urls, recordAdditions);
853 void Components::parseModuleLayer(int layer, rtl::OUString const & url) {
854 parseFiles(
855 layer, rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(".xcu")),
856 &parseXcuFile, url, false);
859 void Components::parseResLayer(int layer, rtl::OUString const & url) {
860 rtl::OUString resUrl(
861 url + rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("/res")));
862 parseXcdFiles(layer, resUrl);
863 parseFiles(
864 layer, rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(".xcu")),
865 &parseXcuFile, resUrl, false);
868 void Components::parseModificationLayer(rtl::OUString const & url) {
869 try {
870 parseFileLeniently(&parseXcuFile, url, Data::NO_LAYER, data_, 0, 0, 0);
871 } catch (css::container::NoSuchElementException &) {
872 SAL_INFO(
873 "configmgr", "user registrymodifications.xcu does not (yet) exist");
874 // Migrate old user layer data (can be removed once migration is no
875 // longer relevant, probably OOo 4; also see hack for xsi namespace in
876 // xmlreader::XmlReader::registerNamespaceIri):
877 parseFiles(
878 Data::NO_LAYER, rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(".xcu")),
879 &parseXcuFile,
880 expand(
881 rtl::OUString(
882 RTL_CONSTASCII_USTRINGPARAM(
883 "${$BRAND_BASE_DIR/program/" SAL_CONFIGFILE("bootstrap")
884 ":UserInstallation}/user/registry/data"))),
885 false);
889 int Components::getExtensionLayer(bool shared) {
890 int layer = shared ? sharedExtensionLayer_ : userExtensionLayer_;
891 if (layer == -1) {
892 throw css::uno::RuntimeException(
893 rtl::OUString(
894 RTL_CONSTASCII_USTRINGPARAM(
895 "insert extension xcs/xcu file into undefined layer")),
896 css::uno::Reference< css::uno::XInterface >());
898 return layer;
903 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */