Line data Source code
1 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : /*
3 : * This file is part of the LibreOffice project.
4 : *
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/.
8 : *
9 : * This file incorporates work covered by the following license notice:
10 : *
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 .
18 : */
19 :
20 : #include <config_folders.h>
21 :
22 : #include "sal/config.h"
23 :
24 : #include <algorithm>
25 : #include <cassert>
26 : #include <cstddef>
27 : #include <list>
28 : #include <set>
29 :
30 : #include "com/sun/star/beans/Optional.hpp"
31 : #include "com/sun/star/beans/UnknownPropertyException.hpp"
32 : #include "com/sun/star/beans/XPropertySet.hpp"
33 : #include "com/sun/star/container/NoSuchElementException.hpp"
34 : #include "com/sun/star/lang/WrappedTargetException.hpp"
35 : #include "com/sun/star/uno/Any.hxx"
36 : #include "com/sun/star/uno/Exception.hpp"
37 : #include "com/sun/star/uno/Reference.hxx"
38 : #include "com/sun/star/uno/RuntimeException.hpp"
39 : #include "com/sun/star/uno/XComponentContext.hpp"
40 : #include "com/sun/star/uno/XInterface.hpp"
41 : #include "osl/conditn.hxx"
42 : #include "osl/file.hxx"
43 : #include "osl/mutex.hxx"
44 : #include "rtl/bootstrap.hxx"
45 : #include "rtl/ref.hxx"
46 : #include "rtl/ustrbuf.hxx"
47 : #include "rtl/ustring.hxx"
48 : #include "rtl/instance.hxx"
49 : #include "sal/log.hxx"
50 : #include "sal/types.h"
51 : #include "salhelper/thread.hxx"
52 :
53 : #include "additions.hxx"
54 : #include "components.hxx"
55 : #include "data.hxx"
56 : #include "lock.hxx"
57 : #include "modifications.hxx"
58 : #include "node.hxx"
59 : #include "nodemap.hxx"
60 : #include "parsemanager.hxx"
61 : #include "partial.hxx"
62 : #include "rootaccess.hxx"
63 : #include "writemodfile.hxx"
64 : #include "xcdparser.hxx"
65 : #include "xcuparser.hxx"
66 : #include "xcsparser.hxx"
67 : #ifdef WNT
68 : #include "winreg.hxx"
69 : #endif
70 :
71 : namespace configmgr {
72 :
73 : namespace {
74 :
75 0 : struct UnresolvedListItem {
76 : OUString name;
77 : rtl::Reference< ParseManager > manager;
78 :
79 0 : UnresolvedListItem(
80 : OUString const & theName,
81 : rtl::Reference< ParseManager > theManager):
82 0 : name(theName), manager(theManager) {}
83 : };
84 :
85 : typedef std::list< UnresolvedListItem > UnresolvedList;
86 :
87 0 : void parseXcsFile(
88 : OUString const & url, int layer, Data & data, Partial const * partial,
89 : Modifications * modifications, Additions * additions)
90 : SAL_THROW((
91 : css::container::NoSuchElementException, css::uno::RuntimeException))
92 : {
93 : assert(partial == 0 && modifications == 0 && additions == 0);
94 : (void) partial; (void) modifications; (void) additions;
95 : bool ok = rtl::Reference< ParseManager >(
96 0 : new ParseManager(url, new XcsParser(layer, data)))->parse(0);
97 : assert(ok);
98 : (void) ok; // avoid warnings
99 0 : }
100 :
101 0 : void parseXcuFile(
102 : OUString const & url, int layer, Data & data, Partial const * partial,
103 : Modifications * modifications, Additions * additions)
104 : SAL_THROW((
105 : css::container::NoSuchElementException, css::uno::RuntimeException))
106 : {
107 : bool ok = rtl::Reference< ParseManager >(
108 : new ParseManager(
109 : url,
110 0 : new XcuParser(layer, data, partial, modifications, additions)))->
111 0 : parse(0);
112 : assert(ok);
113 : (void) ok; // avoid warnings
114 0 : }
115 :
116 0 : OUString expand(OUString const & str) {
117 0 : OUString s(str);
118 0 : rtl::Bootstrap::expandMacros(s); //TODO: detect failure
119 0 : return s;
120 : }
121 :
122 0 : bool canRemoveFromLayer(int layer, rtl::Reference< Node > const & node) {
123 : assert(node.is());
124 0 : if (node->getLayer() > layer && node->getLayer() < Data::NO_LAYER) {
125 0 : return false;
126 : }
127 0 : switch (node->kind()) {
128 : case Node::KIND_LOCALIZED_PROPERTY:
129 : case Node::KIND_GROUP:
130 0 : for (NodeMap::const_iterator i(node->getMembers().begin());
131 0 : i != node->getMembers().end(); ++i)
132 : {
133 0 : if (!canRemoveFromLayer(layer, i->second)) {
134 0 : return false;
135 : }
136 : }
137 0 : return true;
138 : case Node::KIND_SET:
139 0 : return node->getMembers().empty();
140 : default: // Node::KIND_PROPERTY, Node::KIND_LOCALIZED_VALUE
141 0 : return true;
142 : }
143 : }
144 :
145 : }
146 :
147 : class Components::WriteThread: public salhelper::Thread {
148 : public:
149 : WriteThread(
150 : rtl::Reference< WriteThread > * reference, Components & components,
151 : OUString const & url, Data const & data);
152 :
153 0 : void flush() { delay_.set(); }
154 :
155 : private:
156 0 : virtual ~WriteThread() {}
157 :
158 : virtual void execute() SAL_OVERRIDE;
159 :
160 : rtl::Reference< WriteThread > * reference_;
161 : Components & components_;
162 : OUString url_;
163 : Data const & data_;
164 : osl::Condition delay_;
165 : boost::shared_ptr<osl::Mutex> lock_;
166 : };
167 :
168 0 : Components::WriteThread::WriteThread(
169 : rtl::Reference< WriteThread > * reference, Components & components,
170 : OUString const & url, Data const & data):
171 : Thread("configmgrWriter"), reference_(reference), components_(components),
172 0 : url_(url), data_(data)
173 : {
174 0 : lock_ = lock();
175 : assert(reference != 0);
176 0 : }
177 :
178 0 : void Components::WriteThread::execute() {
179 0 : TimeValue t = { 1, 0 }; // 1 sec
180 0 : delay_.wait(&t); // must not throw; result_error is harmless and ignored
181 0 : osl::MutexGuard g(*lock_); // must not throw
182 : try {
183 : try {
184 0 : writeModFile(components_, url_, data_);
185 0 : } catch (css::uno::RuntimeException & e) {
186 : // Ignore write errors, instead of aborting:
187 : SAL_WARN(
188 : "configmgr",
189 : "error writing modifications: \"" << e.Message << '"');
190 : }
191 0 : } catch (...) {
192 0 : reference_->clear();
193 0 : throw;
194 : }
195 0 : reference_->clear();
196 0 : }
197 :
198 : class theComponentsSingleton :
199 : public rtl::StaticWithArg<
200 : Components,
201 : css::uno::Reference< css::uno::XComponentContext >,
202 : theComponentsSingleton>
203 : {
204 : };
205 :
206 0 : Components & Components::getSingleton(
207 : css::uno::Reference< css::uno::XComponentContext > const & context)
208 : {
209 : assert(context.is());
210 0 : return theComponentsSingleton::get(context);
211 : }
212 :
213 0 : bool Components::allLocales(OUString const & locale) {
214 0 : return locale == "*";
215 : }
216 :
217 0 : rtl::Reference< Node > Components::resolvePathRepresentation(
218 : OUString const & pathRepresentation,
219 : OUString * canonicRepresentation, Path * path, int * finalizedLayer)
220 : const
221 : {
222 : return data_.resolvePathRepresentation(
223 0 : pathRepresentation, canonicRepresentation, path, finalizedLayer);
224 : }
225 :
226 0 : rtl::Reference< Node > Components::getTemplate(
227 : int layer, OUString const & fullName) const
228 : {
229 0 : return data_.getTemplate(layer, fullName);
230 : }
231 :
232 0 : void Components::addRootAccess(rtl::Reference< RootAccess > const & access) {
233 0 : roots_.insert(access.get());
234 0 : }
235 :
236 0 : void Components::removeRootAccess(RootAccess * access) {
237 0 : roots_.erase(access);
238 0 : }
239 :
240 0 : void Components::initGlobalBroadcaster(
241 : Modifications const & modifications,
242 : rtl::Reference< RootAccess > const & exclude, Broadcaster * broadcaster)
243 : {
244 : //TODO: Iterate only over roots w/ listeners:
245 0 : for (WeakRootSet::iterator i(roots_.begin()); i != roots_.end(); ++i) {
246 0 : rtl::Reference< RootAccess > root;
247 0 : if ((*i)->acquireCounting() > 1) {
248 0 : root.set(*i); // must not throw
249 : }
250 0 : (*i)->releaseNondeleting();
251 0 : if (root.is()) {
252 0 : if (root != exclude) {
253 0 : Path path(root->getAbsolutePath());
254 0 : Modifications::Node const * mods = &modifications.getRoot();
255 0 : for (Path::iterator j(path.begin()); j != path.end(); ++j) {
256 : Modifications::Node::Children::const_iterator k(
257 0 : mods->children.find(*j));
258 0 : if (k == mods->children.end()) {
259 0 : mods = 0;
260 0 : break;
261 : }
262 0 : mods = &k->second;
263 : }
264 : //TODO: If the complete tree of which root is a part is deleted,
265 : // or replaced, mods will be null, but some of the listeners
266 : // from within root should probably fire nonetheless:
267 0 : if (mods != 0) {
268 0 : root->initBroadcaster(*mods, broadcaster);
269 0 : }
270 : }
271 : }
272 0 : }
273 0 : }
274 :
275 0 : void Components::addModification(Path const & path) {
276 0 : data_.modifications.add(path);
277 0 : }
278 :
279 0 : bool Components::hasModifications() const
280 : {
281 0 : return data_.modifications.getRoot().children.begin() !=
282 0 : data_.modifications.getRoot().children.end();
283 : }
284 :
285 0 : void Components::writeModifications() {
286 :
287 0 : if (!hasModifications() || modificationFileUrl_.isEmpty())
288 0 : return;
289 :
290 0 : if (!writeThread_.is()) {
291 0 : writeThread_ = new WriteThread(
292 0 : &writeThread_, *this, modificationFileUrl_, data_);
293 0 : writeThread_->launch();
294 : }
295 : }
296 :
297 0 : void Components::flushModifications() {
298 0 : rtl::Reference< WriteThread > thread;
299 : {
300 0 : osl::MutexGuard g(*lock_);
301 0 : thread = writeThread_;
302 : }
303 0 : if (thread.is()) {
304 0 : thread->flush();
305 0 : thread->join();
306 0 : }
307 0 : }
308 :
309 0 : void Components::insertExtensionXcsFile(
310 : bool shared, OUString const & fileUri)
311 : {
312 0 : int layer = getExtensionLayer(shared);
313 : try {
314 0 : parseXcsFile(fileUri, layer, data_, 0, 0, 0);
315 0 : } catch (css::container::NoSuchElementException & e) {
316 : throw css::uno::RuntimeException(
317 0 : "insertExtensionXcsFile does not exist: " + e.Message,
318 0 : css::uno::Reference< css::uno::XInterface >());
319 : }
320 0 : }
321 :
322 0 : void Components::insertExtensionXcuFile(
323 : bool shared, OUString const & fileUri, Modifications * modifications)
324 : {
325 : assert(modifications != 0);
326 0 : int layer = getExtensionLayer(shared) + 1;
327 0 : Additions * adds = data_.addExtensionXcuAdditions(fileUri, layer);
328 : try {
329 0 : parseXcuFile(fileUri, layer, data_, 0, modifications, adds);
330 0 : } catch (css::container::NoSuchElementException & e) {
331 0 : data_.removeExtensionXcuAdditions(fileUri);
332 : throw css::uno::RuntimeException(
333 0 : "insertExtensionXcuFile does not exist: " + e.Message,
334 0 : css::uno::Reference< css::uno::XInterface >());
335 : }
336 0 : }
337 :
338 0 : void Components::removeExtensionXcuFile(
339 : OUString const & fileUri, Modifications * modifications)
340 : {
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 0 : data_.removeExtensionXcuAdditions(fileUri));
357 0 : if (item.is()) {
358 0 : for (Additions::reverse_iterator i(item->additions.rbegin());
359 0 : i != item->additions.rend(); ++i)
360 : {
361 0 : rtl::Reference< Node > parent;
362 0 : NodeMap const * map = &data_.getComponents();
363 0 : rtl::Reference< Node > node;
364 0 : for (Path::const_iterator j(i->begin()); j != i->end(); ++j) {
365 0 : parent = node;
366 0 : node = Data::findNode(Data::NO_LAYER, *map, *j);
367 0 : if (!node.is()) {
368 0 : break;
369 : }
370 0 : map = &node->getMembers();
371 : }
372 0 : if (node.is()) {
373 : assert(parent.is());
374 0 : if (parent->kind() == Node::KIND_SET) {
375 : assert(
376 : node->kind() == Node::KIND_GROUP ||
377 : node->kind() == Node::KIND_SET);
378 0 : if (canRemoveFromLayer(item->layer, node)) {
379 0 : parent->getMembers().erase(i->back());
380 0 : data_.modifications.remove(*i);
381 0 : modifications->add(*i);
382 : }
383 : }
384 : }
385 0 : }
386 0 : writeModifications();
387 0 : }
388 0 : }
389 :
390 0 : void Components::insertModificationXcuFile(
391 : OUString const & fileUri,
392 : std::set< OUString > const & includedPaths,
393 : std::set< OUString > const & excludedPaths,
394 : Modifications * modifications)
395 : {
396 : assert(modifications != 0);
397 0 : Partial part(includedPaths, excludedPaths);
398 : try {
399 : parseFileLeniently(
400 : &parseXcuFile, fileUri, Data::NO_LAYER, data_, &part, modifications,
401 0 : 0);
402 0 : } catch (css::container::NoSuchElementException & e) {
403 : SAL_WARN(
404 : "configmgr",
405 : "error inserting non-existing \"" << fileUri << "\": \""
406 : << e.Message << '"');
407 0 : }
408 0 : }
409 :
410 0 : css::beans::Optional< css::uno::Any > Components::getExternalValue(
411 : OUString const & descriptor)
412 : {
413 0 : sal_Int32 i = descriptor.indexOf(' ');
414 0 : if (i <= 0) {
415 : throw css::uno::RuntimeException(
416 0 : "bad external value descriptor " + descriptor,
417 0 : css::uno::Reference< css::uno::XInterface >());
418 : }
419 : //TODO: Do not make calls with mutex locked:
420 0 : OUString name(descriptor.copy(0, i));
421 0 : ExternalServices::iterator j(externalServices_.find(name));
422 0 : if (j == externalServices_.end()) {
423 0 : css::uno::Reference< css::uno::XInterface > service;
424 : try {
425 0 : service = context_->getServiceManager()->createInstanceWithContext(
426 0 : name, context_);
427 0 : } catch (css::uno::RuntimeException &) {
428 : // Assuming these exceptions are real errors:
429 0 : throw;
430 0 : } catch (css::uno::Exception & e) {
431 : // Assuming these exceptions indicate that the service is not
432 : // installed:
433 : SAL_WARN(
434 : "configmgr",
435 : "createInstance(" << name << ") failed with \"" << e.Message
436 : << '"');
437 : }
438 0 : css::uno::Reference< css::beans::XPropertySet > propset;
439 0 : if (service.is()) {
440 0 : propset = css::uno::Reference< css::beans::XPropertySet >(
441 0 : service, css::uno::UNO_QUERY_THROW);
442 : }
443 : j = externalServices_.insert(
444 0 : ExternalServices::value_type(name, propset)).first;
445 : }
446 0 : css::beans::Optional< css::uno::Any > value;
447 0 : if (j->second.is()) {
448 : try {
449 0 : if (!(j->second->getPropertyValue(descriptor.copy(i + 1)) >>=
450 : value))
451 : {
452 : throw css::uno::RuntimeException(
453 0 : "cannot obtain external value through " + descriptor,
454 0 : css::uno::Reference< css::uno::XInterface >());
455 : }
456 0 : } catch (css::beans::UnknownPropertyException & e) {
457 : throw css::uno::RuntimeException(
458 0 : "unknown external value descriptor ID: " + e.Message,
459 0 : css::uno::Reference< css::uno::XInterface >());
460 0 : } catch (css::lang::WrappedTargetException & e) {
461 : throw css::uno::RuntimeException(
462 0 : "cannot obtain external value: " + e.Message,
463 0 : css::uno::Reference< css::uno::XInterface >());
464 : }
465 : }
466 0 : return value;
467 : }
468 :
469 0 : Components::Components(
470 : css::uno::Reference< css::uno::XComponentContext > const & context):
471 0 : context_(context), sharedExtensionLayer_(-1), userExtensionLayer_(-1)
472 : {
473 : assert(context.is());
474 0 : lock_ = lock();
475 0 : OUString conf(expand("${CONFIGURATION_LAYERS}"));
476 0 : int layer = 0;
477 0 : for (sal_Int32 i = 0;;) {
478 0 : while (i != conf.getLength() && conf[i] == ' ') {
479 0 : ++i;
480 : }
481 0 : if (i == conf.getLength()) {
482 0 : break;
483 : }
484 0 : if (!modificationFileUrl_.isEmpty()) {
485 : throw css::uno::RuntimeException(
486 : "CONFIGURATION_LAYERS: \"user\" followed by further layers",
487 0 : css::uno::Reference< css::uno::XInterface >());
488 : }
489 0 : sal_Int32 c = i;
490 0 : for (;; ++c) {
491 0 : if (c == conf.getLength() || conf[c] == ' ') {
492 : throw css::uno::RuntimeException(
493 : "CONFIGURATION_LAYERS: missing \":\"",
494 0 : css::uno::Reference< css::uno::XInterface >());
495 : }
496 0 : if (conf[c] == ':') {
497 0 : break;
498 : }
499 : }
500 0 : sal_Int32 n = conf.indexOf(' ', c + 1);
501 0 : if (n == -1) {
502 0 : n = conf.getLength();
503 : }
504 0 : OUString type(conf.copy(i, c - i));
505 0 : OUString url(conf.copy(c + 1, n - c - 1));
506 0 : if ( type == "xcsxcu" ) {
507 0 : parseXcsXcuLayer(layer, url);
508 0 : layer += 2; //TODO: overflow
509 0 : } else if ( type == "bundledext" )
510 : {
511 0 : parseXcsXcuIniLayer(layer, url, false);
512 0 : layer += 2; //TODO: overflow
513 0 : } else if ( type == "sharedext" ) {
514 0 : if (sharedExtensionLayer_ != -1) {
515 : throw css::uno::RuntimeException(
516 : "CONFIGURATION_LAYERS: multiple \"sharedext\" layers",
517 0 : css::uno::Reference< css::uno::XInterface >());
518 : }
519 0 : sharedExtensionLayer_ = layer;
520 0 : parseXcsXcuIniLayer(layer, url, true);
521 0 : layer += 2; //TODO: overflow
522 0 : } else if ( type == "userext" ) {
523 0 : if (userExtensionLayer_ != -1) {
524 : throw css::uno::RuntimeException(
525 : "CONFIGURATION_LAYERS: multiple \"userext\" layers",
526 0 : css::uno::Reference< css::uno::XInterface >());
527 : }
528 0 : userExtensionLayer_ = layer;
529 0 : parseXcsXcuIniLayer(layer, url, true);
530 0 : layer += 2; //TODO: overflow
531 0 : } else if ( type == "module" ) {
532 0 : parseModuleLayer(layer, url);
533 0 : ++layer; //TODO: overflow
534 0 : } else if ( type == "res" ) {
535 0 : parseResLayer(layer, url);
536 0 : ++layer; //TODO: overflow
537 0 : } else if ( type == "user" ) {
538 0 : if (url.isEmpty()) {
539 : throw css::uno::RuntimeException(
540 : "CONFIGURATION_LAYERS: empty \"user\" URL",
541 0 : css::uno::Reference< css::uno::XInterface >());
542 : }
543 0 : modificationFileUrl_ = url;
544 0 : parseModificationLayer(url);
545 : }
546 : #ifdef WNT
547 : else if ( type == "winreg" )
548 : {
549 : if (!url.isEmpty()) {
550 : SAL_WARN(
551 : "configmgr",
552 : "winreg URL is not empty, URL handling is not implemented for winreg");
553 : }
554 : OUString aTempFileURL;
555 : if ( dumpWindowsRegistry(&aTempFileURL) )
556 : {
557 : parseFileLeniently(&parseXcuFile, aTempFileURL, layer, data_, 0, 0, 0);
558 : layer++;
559 : osl::File::remove(aTempFileURL);
560 : }
561 : }
562 : #endif
563 : else {
564 : throw css::uno::RuntimeException(
565 0 : "CONFIGURATION_LAYERS: unknown layer type \"" + type + "\"",
566 0 : css::uno::Reference< css::uno::XInterface >());
567 : }
568 0 : i = n;
569 0 : }
570 0 : }
571 :
572 0 : Components::~Components()
573 : {
574 0 : flushModifications();
575 0 : for (WeakRootSet::iterator i(roots_.begin()); i != roots_.end(); ++i) {
576 0 : (*i)->setAlive(false);
577 : }
578 0 : }
579 :
580 0 : void Components::parseFileLeniently(
581 : FileParser * parseFile, OUString const & url, int layer, Data & data,
582 : Partial const * partial, Modifications * modifications,
583 : Additions * additions)
584 : {
585 : assert(parseFile != 0);
586 : try {
587 0 : (*parseFile)(url, layer, data, partial, modifications, additions);
588 0 : } catch (css::container::NoSuchElementException &) {
589 0 : throw;
590 0 : } catch (css::uno::Exception & e) { //TODO: more specific exception catching
591 : // Ignore invalid XML files, instead of completely preventing OOo from
592 : // starting:
593 : SAL_WARN(
594 : "configmgr",
595 : "error reading \"" << url << "\": \"" << e.Message << '"');
596 : }
597 0 : }
598 :
599 0 : void Components::parseFiles(
600 : int layer, OUString const & extension, FileParser * parseFile,
601 : OUString const & url, bool recursive)
602 : {
603 0 : osl::Directory dir(url);
604 0 : switch (dir.open()) {
605 : case osl::FileBase::E_None:
606 0 : break;
607 : case osl::FileBase::E_NOENT:
608 0 : if (!recursive) {
609 0 : return;
610 : }
611 : // fall through
612 : default:
613 : throw css::uno::RuntimeException(
614 0 : "cannot open directory " + url,
615 0 : css::uno::Reference< css::uno::XInterface >());
616 : }
617 : for (;;) {
618 0 : osl::DirectoryItem i;
619 0 : osl::FileBase::RC rc = dir.getNextItem(i, SAL_MAX_UINT32);
620 0 : if (rc == osl::FileBase::E_NOENT) {
621 0 : break;
622 : }
623 0 : if (rc != osl::FileBase::E_None) {
624 : throw css::uno::RuntimeException(
625 0 : "cannot iterate directory " + url,
626 0 : css::uno::Reference< css::uno::XInterface >());
627 : }
628 : osl::FileStatus stat(
629 : osl_FileStatus_Mask_Type | osl_FileStatus_Mask_FileName |
630 0 : osl_FileStatus_Mask_FileURL);
631 0 : if (i.getFileStatus(stat) != osl::FileBase::E_None) {
632 : throw css::uno::RuntimeException(
633 0 : "cannot stat in directory " + url,
634 0 : css::uno::Reference< css::uno::XInterface >());
635 : }
636 0 : if (stat.getFileType() == osl::FileStatus::Directory) { //TODO: symlinks
637 0 : parseFiles(layer, extension, parseFile, stat.getFileURL(), true);
638 : } else {
639 0 : OUString file(stat.getFileName());
640 0 : if (file.endsWith(extension)) {
641 : try {
642 : parseFileLeniently(
643 0 : parseFile, stat.getFileURL(), layer, data_, 0, 0, 0);
644 0 : } catch (css::container::NoSuchElementException & e) {
645 : throw css::uno::RuntimeException(
646 0 : "stat'ed file does not exist: " + e.Message,
647 0 : css::uno::Reference< css::uno::XInterface >());
648 : }
649 0 : }
650 : }
651 0 : }
652 : }
653 :
654 0 : void Components::parseFileList(
655 : int layer, FileParser * parseFile, OUString const & urls,
656 : bool recordAdditions)
657 : {
658 0 : for (sal_Int32 i = 0;;) {
659 0 : OUString url(urls.getToken(0, ' ', i));
660 0 : if (!url.isEmpty()) {
661 0 : Additions * adds = 0;
662 0 : if (recordAdditions) {
663 0 : adds = data_.addExtensionXcuAdditions(url, layer);
664 : }
665 : try {
666 0 : parseFileLeniently(parseFile, url, layer, data_, 0, 0, adds);
667 0 : } catch (css::container::NoSuchElementException & e) {
668 : SAL_WARN(
669 : "configmgr", "file does not exist: \"" << e.Message << '"');
670 0 : if (adds != 0) {
671 0 : data_.removeExtensionXcuAdditions(url);
672 : }
673 : }
674 : }
675 0 : if (i == -1) {
676 0 : break;
677 : }
678 0 : }
679 0 : }
680 :
681 0 : void Components::parseXcdFiles(int layer, OUString const & url) {
682 0 : osl::Directory dir(url);
683 0 : switch (dir.open()) {
684 : case osl::FileBase::E_None:
685 0 : break;
686 : case osl::FileBase::E_NOENT:
687 0 : return;
688 : default:
689 : throw css::uno::RuntimeException(
690 0 : "cannot open directory " + url,
691 0 : css::uno::Reference< css::uno::XInterface >());
692 : }
693 0 : UnresolvedList unres;
694 0 : std::set< OUString > existingDeps;
695 0 : std::set< OUString > processedDeps;
696 : for (;;) {
697 0 : osl::DirectoryItem i;
698 0 : osl::FileBase::RC rc = dir.getNextItem(i, SAL_MAX_UINT32);
699 0 : if (rc == osl::FileBase::E_NOENT) {
700 0 : break;
701 : }
702 0 : if (rc != osl::FileBase::E_None) {
703 : throw css::uno::RuntimeException(
704 0 : "cannot iterate directory " + url,
705 0 : css::uno::Reference< css::uno::XInterface >());
706 : }
707 : osl::FileStatus stat(
708 : osl_FileStatus_Mask_Type | osl_FileStatus_Mask_FileName |
709 0 : osl_FileStatus_Mask_FileURL);
710 0 : if (i.getFileStatus(stat) != osl::FileBase::E_None) {
711 : throw css::uno::RuntimeException(
712 0 : "cannot stat in directory " + url,
713 0 : css::uno::Reference< css::uno::XInterface >());
714 : }
715 0 : if (stat.getFileType() != osl::FileStatus::Directory) { //TODO: symlinks
716 0 : OUString file(stat.getFileName());
717 0 : OUString name;
718 0 : if (file.endsWith(".xcd", &name)) {
719 0 : existingDeps.insert(name);
720 0 : rtl::Reference< ParseManager > manager;
721 : try {
722 0 : manager = new ParseManager(
723 : stat.getFileURL(),
724 0 : new XcdParser(layer, processedDeps, data_));
725 0 : } catch (css::container::NoSuchElementException & e) {
726 : throw css::uno::RuntimeException(
727 0 : "stat'ed file does not exist: " + e.Message,
728 0 : css::uno::Reference< css::uno::XInterface >());
729 : }
730 0 : if (manager->parse(0)) {
731 0 : processedDeps.insert(name);
732 : } else {
733 0 : unres.push_back(UnresolvedListItem(name, manager));
734 0 : }
735 0 : }
736 : }
737 0 : }
738 0 : while (!unres.empty()) {
739 0 : bool resolved = false;
740 0 : for (UnresolvedList::iterator i(unres.begin()); i != unres.end();) {
741 0 : if (i->manager->parse(&existingDeps)) {
742 0 : processedDeps.insert(i->name);
743 0 : unres.erase(i++);
744 0 : resolved = true;
745 : } else {
746 0 : ++i;
747 : }
748 : }
749 0 : if (!resolved) {
750 : throw css::uno::RuntimeException(
751 0 : "xcd: unresolved dependencies in " + url,
752 0 : css::uno::Reference< css::uno::XInterface >());
753 : }
754 0 : }
755 : }
756 :
757 0 : void Components::parseXcsXcuLayer(int layer, OUString const & url) {
758 0 : parseXcdFiles(layer, url);
759 0 : parseFiles(layer, ".xcs", &parseXcsFile, url + "/schema", false);
760 0 : parseFiles(layer + 1, ".xcu", &parseXcuFile, url + "/data", false);
761 0 : }
762 :
763 0 : void Components::parseXcsXcuIniLayer(
764 : int layer, OUString const & url, bool recordAdditions)
765 : {
766 : // Check if ini file exists (otherwise .override would still read global
767 : // SCHEMA/DATA variables, which could interfere with unrelated environment
768 : // variables):
769 0 : if (rtl::Bootstrap(url).getHandle() != 0) {
770 0 : OUStringBuffer prefix("${.override:");
771 0 : for (sal_Int32 i = 0; i != url.getLength(); ++i) {
772 0 : sal_Unicode c = url[i];
773 0 : switch (c) {
774 : case '$':
775 : case ':':
776 : case '\\':
777 0 : prefix.append('\\');
778 : // fall through
779 : default:
780 0 : prefix.append(c);
781 : }
782 : }
783 0 : prefix.append(':');
784 0 : OUString urls(prefix.toString() + "SCHEMA}");
785 0 : rtl::Bootstrap::expandMacros(urls);
786 0 : if (!urls.isEmpty()) {
787 0 : parseFileList(layer, &parseXcsFile, urls, false);
788 : }
789 0 : urls = prefix.makeStringAndClear() + "DATA}";
790 0 : rtl::Bootstrap::expandMacros(urls);
791 0 : if (!urls.isEmpty()) {
792 0 : parseFileList(layer + 1, &parseXcuFile, urls, recordAdditions);
793 0 : }
794 : }
795 0 : }
796 :
797 0 : void Components::parseModuleLayer(int layer, OUString const & url) {
798 0 : parseFiles(layer, ".xcu", &parseXcuFile, url, false);
799 0 : }
800 :
801 0 : void Components::parseResLayer(int layer, OUString const & url) {
802 0 : OUString resUrl(url + "/res");
803 0 : parseXcdFiles(layer, resUrl);
804 0 : parseFiles(layer, ".xcu", &parseXcuFile, resUrl, false);
805 0 : }
806 :
807 0 : void Components::parseModificationLayer(OUString const & url) {
808 : try {
809 0 : parseFileLeniently(&parseXcuFile, url, Data::NO_LAYER, data_, 0, 0, 0);
810 0 : } catch (css::container::NoSuchElementException &) {
811 : SAL_INFO(
812 : "configmgr", "user registrymodifications.xcu does not (yet) exist");
813 : // Migrate old user layer data (can be removed once migration is no
814 : // longer relevant, probably OOo 4; also see hack for xsi namespace in
815 : // xmlreader::XmlReader::registerNamespaceIri):
816 : parseFiles(
817 : Data::NO_LAYER, ".xcu", &parseXcuFile,
818 : expand(
819 : "${$BRAND_BASE_DIR/" LIBO_ETC_FOLDER "/" SAL_CONFIGFILE("bootstrap")
820 : ":UserInstallation}/user/registry/data"),
821 0 : false);
822 : }
823 0 : }
824 :
825 0 : int Components::getExtensionLayer(bool shared) {
826 0 : int layer = shared ? sharedExtensionLayer_ : userExtensionLayer_;
827 0 : if (layer == -1) {
828 : throw css::uno::RuntimeException(
829 : "insert extension xcs/xcu file into undefined layer",
830 0 : css::uno::Reference< css::uno::XInterface >());
831 : }
832 0 : return layer;
833 : }
834 :
835 : }
836 :
837 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|