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