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