1 /**************************************************************
2 *
3 * Licensed to the Apache Software Foundation (ASF) under one
4 * or more contributor license agreements. See the NOTICE file
5 * distributed with this work for additional information
6 * regarding copyright ownership. The ASF licenses this file
7 * to you under the Apache License, Version 2.0 (the
8 * "License"); you may not use this file except in compliance
9 * with the License. You may obtain a copy of the License at
10 *
11 * http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing,
14 * software distributed under the License is distributed on an
15 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16 * KIND, either express or implied. See the License for the
17 * specific language governing permissions and limitations
18 * under the License.
19 *
20 *************************************************************/
21
22
23
24 #include "precompiled_configmgr.hxx"
25 #include "sal/config.h"
26
27 #include <algorithm>
28 #include <cstddef>
29 #include <list>
30
31 #include "com/sun/star/beans/Optional.hpp"
32 #include "com/sun/star/beans/UnknownPropertyException.hpp"
33 #include "com/sun/star/beans/XPropertySet.hpp"
34 #include "com/sun/star/container/NoSuchElementException.hpp"
35 #include "com/sun/star/lang/WrappedTargetException.hpp"
36 #include "com/sun/star/lang/XMultiComponentFactory.hpp"
37 #include "com/sun/star/uno/Any.hxx"
38 #include "com/sun/star/uno/Exception.hpp"
39 #include "com/sun/star/uno/Reference.hxx"
40 #include "com/sun/star/uno/RuntimeException.hpp"
41 #include "com/sun/star/uno/XComponentContext.hpp"
42 #include "com/sun/star/uno/XInterface.hpp"
43 #include "osl/conditn.hxx"
44 #include "osl/diagnose.h"
45 #include "osl/file.hxx"
46 #include "osl/mutex.hxx"
47 #include "osl/thread.hxx"
48 #include "rtl/bootstrap.hxx"
49 #include "rtl/logfile.h"
50 #include "rtl/ref.hxx"
51 #include "rtl/string.h"
52 #include "rtl/textenc.h"
53 #include "rtl/ustring.h"
54 #include "rtl/ustring.hxx"
55 #include "sal/types.h"
56 #include "salhelper/simplereferenceobject.hxx"
57
58 #include "additions.hxx"
59 #include "components.hxx"
60 #include "data.hxx"
61 #include "lock.hxx"
62 #include "modifications.hxx"
63 #include "node.hxx"
64 #include "nodemap.hxx"
65 #include "parsemanager.hxx"
66 #include "partial.hxx"
67 #include "rootaccess.hxx"
68 #include "writemodfile.hxx"
69 #include "xcdparser.hxx"
70 #include "xcuparser.hxx"
71 #include "xcsparser.hxx"
72
73 namespace configmgr {
74
75 namespace {
76
77 namespace css = com::sun::star;
78
79 struct UnresolvedListItem {
80 rtl::OUString name;
81 rtl::Reference< ParseManager > manager;
82
UnresolvedListItemconfigmgr::__anon2c4db4280111::UnresolvedListItem83 UnresolvedListItem(
84 rtl::OUString const & theName,
85 rtl::Reference< ParseManager > theManager):
86 name(theName), manager(theManager) {}
87 };
88
89 typedef std::list< UnresolvedListItem > UnresolvedList;
90
parseXcsFile(rtl::OUString const & url,int layer,Data & data,Partial const * partial,Modifications * modifications,Additions * additions)91 void parseXcsFile(
92 rtl::OUString const & url, int layer, Data & data, Partial const * partial,
93 Modifications * modifications, Additions * additions)
94 SAL_THROW((
95 css::container::NoSuchElementException, css::uno::RuntimeException))
96 {
97 OSL_ASSERT(partial == 0 && modifications == 0 && additions == 0);
98 (void) partial; (void) modifications; (void) additions;
99 OSL_VERIFY(
100 rtl::Reference< ParseManager >(
101 new ParseManager(url, new XcsParser(layer, data)))->parse());
102 }
103
parseXcuFile(rtl::OUString const & url,int layer,Data & data,Partial const * partial,Modifications * modifications,Additions * additions)104 void parseXcuFile(
105 rtl::OUString const & url, int layer, Data & data, Partial const * partial,
106 Modifications * modifications, Additions * additions)
107 SAL_THROW((
108 css::container::NoSuchElementException, css::uno::RuntimeException))
109 {
110 OSL_VERIFY(
111 rtl::Reference< ParseManager >(
112 new ParseManager(
113 url,
114 new XcuParser(
115 layer, data, partial, modifications, additions)))->
116 parse());
117 }
118
expand(rtl::OUString const & str)119 rtl::OUString expand(rtl::OUString const & str) {
120 rtl::OUString s(str);
121 rtl::Bootstrap::expandMacros(s); //TODO: detect failure
122 return s;
123 }
124
canRemoveFromLayer(int layer,rtl::Reference<Node> const & node)125 bool canRemoveFromLayer(int layer, rtl::Reference< Node > const & node) {
126 OSL_ASSERT(node.is());
127 if (node->getLayer() > layer && node->getLayer() < Data::NO_LAYER) {
128 return false;
129 }
130 switch (node->kind()) {
131 case Node::KIND_LOCALIZED_PROPERTY:
132 case Node::KIND_GROUP:
133 for (NodeMap::iterator i(node->getMembers().begin());
134 i != node->getMembers().end(); ++i)
135 {
136 if (!canRemoveFromLayer(layer, i->second)) {
137 return false;
138 }
139 }
140 return true;
141 case Node::KIND_SET:
142 return node->getMembers().empty();
143 default: // Node::KIND_PROPERTY, Node::KIND_LOCALIZED_VALUE
144 return true;
145 }
146 }
147
148 static bool singletonCreated = false;
149 static Components * singleton = 0;
150
151 }
152
153 class Components::WriteThread:
154 public osl::Thread, public salhelper::SimpleReferenceObject
155 {
156 public:
operator new(std::size_t size)157 static void * operator new(std::size_t size)
158 { return Thread::operator new(size); }
159
operator delete(void * pointer)160 static void operator delete(void * pointer)
161 { Thread::operator delete(pointer); }
162
163 WriteThread(
164 rtl::Reference< WriteThread > * reference, Components & components,
165 rtl::OUString const & url, Data const & data);
166
flush()167 void flush() { delay_.set(); }
168
169 private:
~WriteThread()170 virtual ~WriteThread() {}
171
172 virtual void SAL_CALL run();
173
onTerminated()174 virtual void SAL_CALL onTerminated() { release(); }
175
176 rtl::Reference< WriteThread > * reference_;
177 Components & components_;
178 rtl::OUString url_;
179 Data const & data_;
180 osl::Condition delay_;
181 };
182
WriteThread(rtl::Reference<WriteThread> * reference,Components & components,rtl::OUString const & url,Data const & data)183 Components::WriteThread::WriteThread(
184 rtl::Reference< WriteThread > * reference, Components & components,
185 rtl::OUString const & url, Data const & data):
186 reference_(reference), components_(components), url_(url), data_(data)
187 {
188 OSL_ASSERT(reference != 0);
189 acquire();
190 }
191
run()192 void Components::WriteThread::run() {
193 TimeValue t = { 1, 0 }; // 1 sec
194 delay_.wait(&t); // must not throw; result_error is harmless and ignored
195 osl::MutexGuard g(lock); // must not throw
196 try {
197 try {
198 writeModFile(components_, url_, data_);
199 } catch (css::uno::RuntimeException & e) {
200 // Silently ignore write errors, instead of aborting:
201 OSL_TRACE(
202 "configmgr error writing modifications: %s",
203 rtl::OUStringToOString(
204 e.Message, RTL_TEXTENCODING_UTF8).getStr());
205 }
206 } catch (...) {
207 reference_->clear();
208 throw;
209 }
210 reference_->clear();
211 }
212
getSingleton(css::uno::Reference<css::uno::XComponentContext> const & context)213 Components & Components::getSingleton(
214 css::uno::Reference< css::uno::XComponentContext > const & context)
215 {
216 OSL_ASSERT(context.is());
217 if (!singletonCreated) {
218 singletonCreated = true;
219 static Components theSingleton(context);
220 singleton = &theSingleton;
221 }
222 if (singleton == 0) {
223 throw css::uno::RuntimeException(
224 rtl::OUString(
225 RTL_CONSTASCII_USTRINGPARAM(
226 "configmgr no Components singleton")),
227 css::uno::Reference< css::uno::XInterface >());
228 }
229 return *singleton;
230 }
231
allLocales(rtl::OUString const & locale)232 bool Components::allLocales(rtl::OUString const & locale) {
233 return locale.equalsAsciiL(RTL_CONSTASCII_STRINGPARAM("*"));
234 }
235
resolvePathRepresentation(rtl::OUString const & pathRepresentation,rtl::OUString * canonicRepresentation,Path * path,int * finalizedLayer) const236 rtl::Reference< Node > Components::resolvePathRepresentation(
237 rtl::OUString const & pathRepresentation,
238 rtl::OUString * canonicRepresentation, Path * path, int * finalizedLayer)
239 const
240 {
241 return data_.resolvePathRepresentation(
242 pathRepresentation, canonicRepresentation, path, finalizedLayer);
243 }
244
getTemplate(int layer,rtl::OUString const & fullName) const245 rtl::Reference< Node > Components::getTemplate(
246 int layer, rtl::OUString const & fullName) const
247 {
248 return data_.getTemplate(layer, fullName);
249 }
250
addRootAccess(rtl::Reference<RootAccess> const & access)251 void Components::addRootAccess(rtl::Reference< RootAccess > const & access) {
252 roots_.insert(access.get());
253 }
254
removeRootAccess(RootAccess * access)255 void Components::removeRootAccess(RootAccess * access) {
256 roots_.erase(access);
257 }
258
initGlobalBroadcaster(Modifications const & modifications,rtl::Reference<RootAccess> const & exclude,Broadcaster * broadcaster)259 void Components::initGlobalBroadcaster(
260 Modifications const & modifications,
261 rtl::Reference< RootAccess > const & exclude, Broadcaster * broadcaster)
262 {
263 //TODO: Iterate only over roots w/ listeners:
264 for (WeakRootSet::iterator i(roots_.begin()); i != roots_.end(); ++i) {
265 rtl::Reference< RootAccess > root;
266 if ((*i)->acquireCounting() > 1) {
267 root.set(*i); // must not throw
268 }
269 (*i)->releaseNondeleting();
270 if (root.is()) {
271 if (root != exclude) {
272 Path path(root->getAbsolutePath());
273 Modifications::Node const * mods = &modifications.getRoot();
274 for (Path::iterator j(path.begin()); j != path.end(); ++j) {
275 Modifications::Node::Children::const_iterator k(
276 mods->children.find(*j));
277 if (k == mods->children.end()) {
278 mods = 0;
279 break;
280 }
281 mods = &k->second;
282 }
283 //TODO: If the complete tree of which root is a part is deleted,
284 // or replaced, mods will be null, but some of the listeners
285 // from within root should probably fire nonetheless:
286 if (mods != 0) {
287 root->initBroadcaster(*mods, broadcaster);
288 }
289 }
290 }
291 }
292 }
293
addModification(Path const & path)294 void Components::addModification(Path const & path) {
295 data_.modifications.add(path);
296 }
297
writeModifications()298 void Components::writeModifications() {
299 if (!writeThread_.is()) {
300 writeThread_ = new WriteThread(
301 &writeThread_, *this, getModificationFileUrl(), data_);
302 writeThread_->create();
303 }
304 }
305
flushModifications()306 void Components::flushModifications() {
307 rtl::Reference< WriteThread > thread;
308 {
309 osl::MutexGuard g(lock);
310 thread = writeThread_;
311 }
312 if (thread.is()) {
313 thread->flush();
314 thread->join();
315 }
316 }
317
insertExtensionXcsFile(bool shared,rtl::OUString const & fileUri)318 void Components::insertExtensionXcsFile(
319 bool shared, rtl::OUString const & fileUri)
320 {
321 try {
322 parseXcsFile(fileUri, shared ? 9 : 13, data_, 0, 0, 0);
323 } catch (css::container::NoSuchElementException & e) {
324 throw css::uno::RuntimeException(
325 (rtl::OUString(
326 RTL_CONSTASCII_USTRINGPARAM(
327 "insertExtensionXcsFile does not exist: ")) +
328 e.Message),
329 css::uno::Reference< css::uno::XInterface >());
330 }
331 }
332
insertExtensionXcuFile(bool shared,rtl::OUString const & fileUri,Modifications * modifications)333 void Components::insertExtensionXcuFile(
334 bool shared, rtl::OUString const & fileUri, Modifications * modifications)
335 {
336 OSL_ASSERT(modifications != 0);
337 int layer = shared ? 10 : 14;
338 Additions * adds = data_.addExtensionXcuAdditions(fileUri, layer);
339 try {
340 parseXcuFile(fileUri, layer, data_, 0, modifications, adds);
341 } catch (css::container::NoSuchElementException & e) {
342 data_.removeExtensionXcuAdditions(fileUri);
343 throw css::uno::RuntimeException(
344 (rtl::OUString(
345 RTL_CONSTASCII_USTRINGPARAM(
346 "insertExtensionXcuFile does not exist: ")) +
347 e.Message),
348 css::uno::Reference< css::uno::XInterface >());
349 }
350 }
351
removeExtensionXcuFile(rtl::OUString const & fileUri,Modifications * modifications)352 void Components::removeExtensionXcuFile(
353 rtl::OUString const & fileUri, Modifications * modifications)
354 {
355 //TODO: Ideally, exactly the data coming from the specified xcu file would
356 // be removed. However, not enough information is recorded in the in-memory
357 // data structures to do so. So, as a workaround, all those set elements
358 // that were freshly added by the xcu and have afterwards been left
359 // unchanged or have only had their properties changed in the user layer are
360 // removed (and nothing else). The heuristic to determine
361 // whether a node has been left unchanged is to check the layer ID (as
362 // usual) and additionally to check that the node does not recursively
363 // contain any non-empty sets (multiple extension xcu files are merged into
364 // one layer, so checking layer ID alone is not enough). Since
365 // item->additions records all additions of set members in textual order,
366 // the latter check works well when iterating through item->additions in
367 // reverse order.
368 OSL_ASSERT(modifications != 0);
369 rtl::Reference< Data::ExtensionXcu > item(
370 data_.removeExtensionXcuAdditions(fileUri));
371 if (item.is()) {
372 for (Additions::reverse_iterator i(item->additions.rbegin());
373 i != item->additions.rend(); ++i)
374 {
375 rtl::Reference< Node > parent;
376 NodeMap const * map = &data_.components;
377 rtl::Reference< Node > node;
378 for (Path::const_iterator j(i->begin()); j != i->end(); ++j) {
379 parent = node;
380 node = Data::findNode(Data::NO_LAYER, *map, *j);
381 if (!node.is()) {
382 break;
383 }
384 map = &node->getMembers();
385 }
386 if (node.is()) {
387 OSL_ASSERT(parent.is());
388 if (parent->kind() == Node::KIND_SET) {
389 OSL_ASSERT(
390 node->kind() == Node::KIND_GROUP ||
391 node->kind() == Node::KIND_SET);
392 if (canRemoveFromLayer(item->layer, node)) {
393 parent->getMembers().erase(i->back());
394 data_.modifications.remove(*i);
395 modifications->add(*i);
396 }
397 }
398 }
399 }
400 writeModifications();
401 }
402 }
403
insertModificationXcuFile(rtl::OUString const & fileUri,std::set<rtl::OUString> const & includedPaths,std::set<rtl::OUString> const & excludedPaths,Modifications * modifications)404 void Components::insertModificationXcuFile(
405 rtl::OUString const & fileUri,
406 std::set< rtl::OUString > const & includedPaths,
407 std::set< rtl::OUString > const & excludedPaths,
408 Modifications * modifications)
409 {
410 OSL_ASSERT(modifications != 0);
411 Partial part(includedPaths, excludedPaths);
412 try {
413 parseFileLeniently(
414 &parseXcuFile, fileUri, Data::NO_LAYER, data_, &part, modifications,
415 0);
416 } catch (css::container::NoSuchElementException & e) {
417 OSL_TRACE(
418 "configmgr error inserting non-existing %s: %s",
419 rtl::OUStringToOString(fileUri, RTL_TEXTENCODING_UTF8).getStr(),
420 rtl::OUStringToOString(e.Message, RTL_TEXTENCODING_UTF8).getStr());
421 }
422 }
423
getExternalValue(rtl::OUString const & descriptor)424 css::beans::Optional< css::uno::Any > Components::getExternalValue(
425 rtl::OUString const & descriptor)
426 {
427 sal_Int32 i = descriptor.indexOf(' ');
428 if (i <= 0) {
429 throw css::uno::RuntimeException(
430 (rtl::OUString(
431 RTL_CONSTASCII_USTRINGPARAM("bad external value descriptor ")) +
432 descriptor),
433 css::uno::Reference< css::uno::XInterface >());
434 }
435 //TODO: Do not make calls with mutex locked:
436 rtl::OUString name(descriptor.copy(0, i));
437 ExternalServices::iterator j(externalServices_.find(name));
438 if (j == externalServices_.end()) {
439 css::uno::Reference< css::uno::XInterface > service;
440 try {
441 service = css::uno::Reference< css::lang::XMultiComponentFactory >(
442 context_->getServiceManager(), css::uno::UNO_SET_THROW)->
443 createInstanceWithContext(name, context_);
444 } catch (css::uno::RuntimeException &) {
445 // Assuming these exceptions are real errors:
446 throw;
447 } catch (css::uno::Exception & e) {
448 // Assuming these exceptions indicate that the service is not
449 // installed:
450 OSL_TRACE(
451 "createInstance(%s) failed with %s",
452 rtl::OUStringToOString(name, RTL_TEXTENCODING_UTF8).getStr(),
453 rtl::OUStringToOString(
454 e.Message, RTL_TEXTENCODING_UTF8).getStr());
455 }
456 css::uno::Reference< css::beans::XPropertySet > propset;
457 if (service.is()) {
458 propset = css::uno::Reference< css::beans::XPropertySet >(
459 service, css::uno::UNO_QUERY_THROW);
460 }
461 j = externalServices_.insert(
462 ExternalServices::value_type(name, propset)).first;
463 }
464 css::beans::Optional< css::uno::Any > value;
465 if (j->second.is()) {
466 try {
467 if (!(j->second->getPropertyValue(descriptor.copy(i + 1)) >>=
468 value))
469 {
470 throw css::uno::RuntimeException(
471 (rtl::OUString(
472 RTL_CONSTASCII_USTRINGPARAM(
473 "cannot obtain external value through ")) +
474 descriptor),
475 css::uno::Reference< css::uno::XInterface >());
476 }
477 } catch (css::beans::UnknownPropertyException & e) {
478 throw css::uno::RuntimeException(
479 (rtl::OUString(
480 RTL_CONSTASCII_USTRINGPARAM(
481 "unknwon external value descriptor ID: ")) +
482 e.Message),
483 css::uno::Reference< css::uno::XInterface >());
484 } catch (css::lang::WrappedTargetException & e) {
485 throw css::uno::RuntimeException(
486 (rtl::OUString(
487 RTL_CONSTASCII_USTRINGPARAM(
488 "cannot obtain external value: ")) +
489 e.Message),
490 css::uno::Reference< css::uno::XInterface >());
491 }
492 }
493 return value;
494 }
495
Components(css::uno::Reference<css::uno::XComponentContext> const & context)496 Components::Components(
497 css::uno::Reference< css::uno::XComponentContext > const & context):
498 context_(context)
499 {
500 OSL_ASSERT(context.is());
501 RTL_LOGFILE_TRACE_AUTHOR("configmgr", "sb", "begin parsing");
502 parseXcsXcuLayer(
503 0,
504 expand(
505 rtl::OUString(
506 RTL_CONSTASCII_USTRINGPARAM("$OOO_BASE_DIR/share/registry"))));
507 parseModuleLayer(
508 2,
509 expand(
510 rtl::OUString(
511 RTL_CONSTASCII_USTRINGPARAM(
512 "$OOO_BASE_DIR/share/registry/modules"))));
513 parseResLayer(
514 3,
515 expand(
516 rtl::OUString(
517 RTL_CONSTASCII_USTRINGPARAM("$OOO_BASE_DIR/share/registry"))));
518 parseXcsXcuIniLayer(
519 7,
520 expand(
521 rtl::OUString(
522 RTL_CONSTASCII_USTRINGPARAM(
523 "${$OOO_BASE_DIR/program/" SAL_CONFIGFILE("uno")
524 ":BUNDLED_EXTENSIONS_USER}/registry/"
525 "com.sun.star.comp.deployment.configuration."
526 "PackageRegistryBackend/configmgr.ini"))),
527 false);
528 parseXcsXcuIniLayer(
529 9,
530 expand(
531 rtl::OUString(
532 RTL_CONSTASCII_USTRINGPARAM(
533 "${$OOO_BASE_DIR/program/" SAL_CONFIGFILE("uno")
534 ":SHARED_EXTENSIONS_USER}/registry/"
535 "com.sun.star.comp.deployment.configuration."
536 "PackageRegistryBackend/configmgr.ini"))),
537 true);
538 parseXcsXcuLayer(
539 11,
540 expand(
541 rtl::OUString(
542 RTL_CONSTASCII_USTRINGPARAM(
543 "${$OOO_BASE_DIR/program/" SAL_CONFIGFILE("uno")
544 ":UNO_USER_PACKAGES_CACHE}/registry/"
545 "com.sun.star.comp.deployment.configuration."
546 "PackageRegistryBackend/registry"))));
547 // can be dropped once old UserInstallation format can no longer exist
548 // (probably OOo 4)
549 parseXcsXcuIniLayer(
550 13,
551 expand(
552 rtl::OUString(
553 RTL_CONSTASCII_USTRINGPARAM(
554 "${$OOO_BASE_DIR/program/" SAL_CONFIGFILE("uno")
555 ":UNO_USER_PACKAGES_CACHE}/registry/"
556 "com.sun.star.comp.deployment.configuration."
557 "PackageRegistryBackend/configmgr.ini"))),
558 true);
559 parseModificationLayer();
560 RTL_LOGFILE_TRACE_AUTHOR("configmgr", "sb", "end parsing");
561 }
562
~Components()563 Components::~Components() {}
564
parseFileLeniently(FileParser * parseFile,rtl::OUString const & url,int layer,Data & data,Partial const * partial,Modifications * modifications,Additions * additions)565 void Components::parseFileLeniently(
566 FileParser * parseFile, rtl::OUString const & url, int layer, Data & data,
567 Partial const * partial, Modifications * modifications,
568 Additions * additions)
569 {
570 OSL_ASSERT(parseFile != 0);
571 try {
572 (*parseFile)(url, layer, data, partial, modifications, additions);
573 } catch (css::container::NoSuchElementException &) {
574 throw;
575 } catch (css::uno::Exception & e) { //TODO: more specific exception catching
576 // Silently ignore invalid XML files, instead of completely preventing
577 // OOo from starting:
578 OSL_TRACE(
579 "configmgr error reading %s: %s",
580 rtl::OUStringToOString(url, RTL_TEXTENCODING_UTF8).getStr(),
581 rtl::OUStringToOString(e.Message, RTL_TEXTENCODING_UTF8).getStr());
582 }
583 }
584
parseFiles(int layer,rtl::OUString const & extension,FileParser * parseFile,rtl::OUString const & url,bool recursive)585 void Components::parseFiles(
586 int layer, rtl::OUString const & extension, FileParser * parseFile,
587 rtl::OUString const & url, bool recursive)
588 {
589 osl::Directory dir(url);
590 switch (dir.open()) {
591 case osl::FileBase::E_None:
592 break;
593 case osl::FileBase::E_NOENT:
594 if (!recursive) {
595 return;
596 }
597 // fall through
598 default:
599 throw css::uno::RuntimeException(
600 (rtl::OUString(
601 RTL_CONSTASCII_USTRINGPARAM("cannot open directory ")) +
602 url),
603 css::uno::Reference< css::uno::XInterface >());
604 }
605 for (;;) {
606 osl::DirectoryItem i;
607 osl::FileBase::RC rc = dir.getNextItem(i, SAL_MAX_UINT32);
608 if (rc == osl::FileBase::E_NOENT) {
609 break;
610 }
611 if (rc != osl::FileBase::E_None) {
612 throw css::uno::RuntimeException(
613 (rtl::OUString(
614 RTL_CONSTASCII_USTRINGPARAM("cannot iterate directory ")) +
615 url),
616 css::uno::Reference< css::uno::XInterface >());
617 }
618 osl::FileStatus stat(
619 FileStatusMask_Type | FileStatusMask_FileName |
620 FileStatusMask_FileURL);
621 if (i.getFileStatus(stat) != osl::FileBase::E_None) {
622 throw css::uno::RuntimeException(
623 (rtl::OUString(
624 RTL_CONSTASCII_USTRINGPARAM("cannot stat in directory ")) +
625 url),
626 css::uno::Reference< css::uno::XInterface >());
627 }
628 if (stat.getFileType() == osl::FileStatus::Directory) { //TODO: symlinks
629 parseFiles(layer, extension, parseFile, stat.getFileURL(), true);
630 } else {
631 rtl::OUString file(stat.getFileName());
632 if (file.getLength() >= extension.getLength() &&
633 file.match(extension, file.getLength() - extension.getLength()))
634 {
635 try {
636 parseFileLeniently(
637 parseFile, stat.getFileURL(), layer, data_, 0, 0, 0);
638 } catch (css::container::NoSuchElementException & e) {
639 throw css::uno::RuntimeException(
640 (rtl::OUString(
641 RTL_CONSTASCII_USTRINGPARAM(
642 "stat'ed file does not exist: ")) +
643 e.Message),
644 css::uno::Reference< css::uno::XInterface >());
645 }
646 }
647 }
648 }
649 }
650
parseFileList(int layer,FileParser * parseFile,rtl::OUString const & urls,rtl::Bootstrap const & ini,bool recordAdditions)651 void Components::parseFileList(
652 int layer, FileParser * parseFile, rtl::OUString const & urls,
653 rtl::Bootstrap const & ini, bool recordAdditions)
654 {
655 for (sal_Int32 i = 0;;) {
656 rtl::OUString url(urls.getToken(0, ' ', i));
657 if (url.getLength() != 0) {
658 ini.expandMacrosFrom(url); //TODO: detect failure
659 Additions * adds = 0;
660 if (recordAdditions) {
661 adds = data_.addExtensionXcuAdditions(url, layer);
662 }
663 try {
664 parseFileLeniently(parseFile, url, layer, data_, 0, 0, adds);
665 } catch (css::container::NoSuchElementException & e) {
666 OSL_TRACE(
667 "configmgr file does not exist: %s",
668 rtl::OUStringToOString(
669 e.Message, RTL_TEXTENCODING_UTF8).getStr());
670 if (adds != 0) {
671 data_.removeExtensionXcuAdditions(url);
672 }
673 }
674 }
675 if (i == -1) {
676 break;
677 }
678 }
679 }
680
parseXcdFiles(int layer,rtl::OUString const & url)681 void Components::parseXcdFiles(int layer, rtl::OUString const & url) {
682 osl::Directory dir(url);
683 switch (dir.open()) {
684 case osl::FileBase::E_None:
685 break;
686 case osl::FileBase::E_NOENT:
687 return;
688 default:
689 throw css::uno::RuntimeException(
690 (rtl::OUString(
691 RTL_CONSTASCII_USTRINGPARAM("cannot open directory ")) +
692 url),
693 css::uno::Reference< css::uno::XInterface >());
694 }
695 UnresolvedList unres;
696 XcdParser::Dependencies deps;
697 for (;;) {
698 osl::DirectoryItem i;
699 osl::FileBase::RC rc = dir.getNextItem(i, SAL_MAX_UINT32);
700 if (rc == osl::FileBase::E_NOENT) {
701 break;
702 }
703 if (rc != osl::FileBase::E_None) {
704 throw css::uno::RuntimeException(
705 (rtl::OUString(
706 RTL_CONSTASCII_USTRINGPARAM("cannot iterate directory ")) +
707 url),
708 css::uno::Reference< css::uno::XInterface >());
709 }
710 osl::FileStatus stat(
711 FileStatusMask_Type | FileStatusMask_FileName |
712 FileStatusMask_FileURL);
713 if (i.getFileStatus(stat) != osl::FileBase::E_None) {
714 throw css::uno::RuntimeException(
715 (rtl::OUString(
716 RTL_CONSTASCII_USTRINGPARAM("cannot stat in directory ")) +
717 url),
718 css::uno::Reference< css::uno::XInterface >());
719 }
720 if (stat.getFileType() != osl::FileStatus::Directory) { //TODO: symlinks
721 rtl::OUString file(stat.getFileName());
722 if (file.getLength() >= RTL_CONSTASCII_LENGTH(".xcd") &&
723 file.matchAsciiL(
724 RTL_CONSTASCII_STRINGPARAM(".xcd"),
725 file.getLength() - RTL_CONSTASCII_LENGTH(".xcd")))
726 {
727 rtl::OUString name(
728 file.copy(
729 0, file.getLength() - RTL_CONSTASCII_LENGTH(".xcd")));
730 rtl::Reference< ParseManager > manager;
731 try {
732 manager = new ParseManager(
733 stat.getFileURL(), new XcdParser(layer, deps, data_));
734 } catch (css::container::NoSuchElementException & e) {
735 throw css::uno::RuntimeException(
736 (rtl::OUString(
737 RTL_CONSTASCII_USTRINGPARAM(
738 "stat'ed file does not exist: ")) +
739 e.Message),
740 css::uno::Reference< css::uno::XInterface >());
741 }
742 if (manager->parse()) {
743 deps.insert(name);
744 } else {
745 unres.push_back(UnresolvedListItem(name, manager));
746 }
747 }
748 }
749 }
750 while (!unres.empty()) {
751 bool resolved = false;
752 for (UnresolvedList::iterator i(unres.begin()); i != unres.end();) {
753 if (i->manager->parse()) {
754 deps.insert(i->name);
755 unres.erase(i++);
756 resolved = true;
757 } else {
758 ++i;
759 }
760 }
761 if (!resolved) {
762 throw css::uno::RuntimeException(
763 (rtl::OUString(
764 RTL_CONSTASCII_USTRINGPARAM(
765 "xcd: unresolved dependencies in ")) +
766 url),
767 css::uno::Reference< css::uno::XInterface >());
768 }
769 }
770 }
771
parseXcsXcuLayer(int layer,rtl::OUString const & url)772 void Components::parseXcsXcuLayer(int layer, rtl::OUString const & url) {
773 parseXcdFiles(layer, url);
774 parseFiles(
775 layer, rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(".xcs")),
776 &parseXcsFile,
777 url + rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("/schema")), false);
778 parseFiles(
779 layer + 1, rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(".xcu")),
780 &parseXcuFile,
781 url + rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("/data")), false);
782 }
783
parseXcsXcuIniLayer(int layer,rtl::OUString const & url,bool recordAdditions)784 void Components::parseXcsXcuIniLayer(
785 int layer, rtl::OUString const & url, bool recordAdditions)
786 {
787 //TODO: rtl::Bootstrap::getFrom "first trie[s] to retrieve the value via the
788 // global function"
789 rtl::Bootstrap ini(url);
790 rtl::OUString urls;
791 if (ini.getFrom(rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("SCHEMA")), urls))
792 {
793 parseFileList(layer, &parseXcsFile, urls, ini, false);
794 }
795 if (ini.getFrom(rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("DATA")), urls))
796 {
797 parseFileList(layer + 1, &parseXcuFile, urls, ini, recordAdditions);
798 }
799 }
800
parseModuleLayer(int layer,rtl::OUString const & url)801 void Components::parseModuleLayer(int layer, rtl::OUString const & url) {
802 parseFiles(
803 layer, rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(".xcu")),
804 &parseXcuFile, url, false);
805 }
806
parseResLayer(int layer,rtl::OUString const & url)807 void Components::parseResLayer(int layer, rtl::OUString const & url) {
808 rtl::OUString resUrl(
809 url + rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("/res")));
810 parseXcdFiles(layer, resUrl);
811 parseFiles(
812 layer, rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(".xcu")),
813 &parseXcuFile, resUrl, false);
814 }
815
getModificationFileUrl() const816 rtl::OUString Components::getModificationFileUrl() const {
817 return expand(
818 rtl::OUString(
819 RTL_CONSTASCII_USTRINGPARAM(
820 "${$OOO_BASE_DIR/program/" SAL_CONFIGFILE("bootstrap")
821 ":UserInstallation}/user/registrymodifications.xcu")));
822 }
823
parseModificationLayer()824 void Components::parseModificationLayer() {
825 try {
826 parseFileLeniently(
827 &parseXcuFile, getModificationFileUrl(), Data::NO_LAYER, data_, 0,
828 0, 0);
829 } catch (css::container::NoSuchElementException &) {
830 OSL_TRACE(
831 "configmgr user registrymodifications.xcu does not (yet) exist");
832 // Migrate old user layer data (can be removed once migration is no
833 // longer relevant, probably OOo 4; also see hack for xsi namespace in
834 // xmlreader::XmlReader::registerNamespaceIri):
835 parseFiles(
836 Data::NO_LAYER, rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(".xcu")),
837 &parseXcuFile,
838 expand(
839 rtl::OUString(
840 RTL_CONSTASCII_USTRINGPARAM(
841 "${$OOO_BASE_DIR/program/" SAL_CONFIGFILE("bootstrap")
842 ":UserInstallation}/user/registry/data"))),
843 false);
844 }
845 }
846
847 }
848