Impress Remote 1.0.5, tag sdremote-1.0.5
[LibreOffice.git] / configmgr / source / xcuparser.cxx
blob3515cce905c12d1bde575738ad7104cda2d68425
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include "sal/config.h"
22 #include <algorithm>
23 #include <cassert>
24 #include <set>
26 #include "com/sun/star/uno/Any.hxx"
27 #include "com/sun/star/uno/Reference.hxx"
28 #include "com/sun/star/uno/RuntimeException.hpp"
29 #include "com/sun/star/uno/XInterface.hpp"
30 #include "rtl/ref.hxx"
31 #include "rtl/strbuf.hxx"
32 #include "rtl/string.h"
33 #include "rtl/string.hxx"
34 #include "rtl/ustring.h"
35 #include "rtl/ustring.hxx"
36 #include "sal/log.hxx"
37 #include "xmlreader/span.hxx"
38 #include "xmlreader/xmlreader.hxx"
40 #include "data.hxx"
41 #include "localizedpropertynode.hxx"
42 #include "localizedvaluenode.hxx"
43 #include "groupnode.hxx"
44 #include "modifications.hxx"
45 #include "node.hxx"
46 #include "nodemap.hxx"
47 #include "parsemanager.hxx"
48 #include "partial.hxx"
49 #include "path.hxx"
50 #include "propertynode.hxx"
51 #include "setnode.hxx"
52 #include "xcuparser.hxx"
53 #include "xmldata.hxx"
55 namespace configmgr {
57 XcuParser::XcuParser(
58 int layer, Data & data, Partial const * partial,
59 Modifications * broadcastModifications, Additions * additions):
60 valueParser_(layer), data_(data),
61 partial_(partial), broadcastModifications_(broadcastModifications),
62 additions_(additions), recordModifications_(layer == Data::NO_LAYER),
63 trackPath_(
64 partial_ != 0 || broadcastModifications_ != 0 || additions_ != 0 ||
65 recordModifications_)
68 XcuParser::~XcuParser() {}
70 xmlreader::XmlReader::Text XcuParser::getTextMode() {
71 return valueParser_.getTextMode();
74 bool XcuParser::startElement(
75 xmlreader::XmlReader & reader, int nsId, xmlreader::Span const & name,
76 std::set< OUString > const * existingDependencies)
78 if (valueParser_.startElement(reader, nsId, name, existingDependencies)) {
79 return true;
81 if (state_.empty()) {
82 if (nsId == ParseManager::NAMESPACE_OOR &&
83 name.equals(RTL_CONSTASCII_STRINGPARAM("component-data")))
85 handleComponentData(reader);
86 } else if (nsId == ParseManager::NAMESPACE_OOR &&
87 name.equals(RTL_CONSTASCII_STRINGPARAM("items")))
89 state_.push(State(rtl::Reference< Node >(), false));
90 } else {
91 throw css::uno::RuntimeException(
92 (rtl::OUString(
93 RTL_CONSTASCII_USTRINGPARAM("bad root element <")) +
94 name.convertFromUtf8() +
95 rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("> in ")) +
96 reader.getUrl()),
97 css::uno::Reference< css::uno::XInterface >());
99 } else if (state_.top().ignore) {
100 state_.push(State(false));
101 } else if (!state_.top().node.is()) {
102 if (nsId == xmlreader::XmlReader::NAMESPACE_NONE &&
103 name.equals(RTL_CONSTASCII_STRINGPARAM("item")))
105 handleItem(reader);
106 } else {
107 throw css::uno::RuntimeException(
108 (rtl::OUString(
109 RTL_CONSTASCII_USTRINGPARAM("bad items node member <")) +
110 name.convertFromUtf8() +
111 rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("> in ")) +
112 reader.getUrl()),
113 css::uno::Reference< css::uno::XInterface >());
115 } else {
116 switch (state_.top().node->kind()) {
117 case Node::KIND_PROPERTY:
118 if (nsId == xmlreader::XmlReader::NAMESPACE_NONE &&
119 name.equals(RTL_CONSTASCII_STRINGPARAM("value")))
121 handlePropValue(
122 reader,
123 dynamic_cast< PropertyNode * >(state_.top().node.get()));
124 } else {
125 throw css::uno::RuntimeException(
126 (rtl::OUString(
127 RTL_CONSTASCII_USTRINGPARAM(
128 "bad property node member <")) +
129 name.convertFromUtf8() +
130 rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("> in ")) +
131 reader.getUrl()),
132 css::uno::Reference< css::uno::XInterface >());
134 break;
135 case Node::KIND_LOCALIZED_PROPERTY:
136 if (nsId == xmlreader::XmlReader::NAMESPACE_NONE &&
137 name.equals(RTL_CONSTASCII_STRINGPARAM("value")))
139 handleLocpropValue(
140 reader,
141 dynamic_cast< LocalizedPropertyNode * >(
142 state_.top().node.get()));
143 } else {
144 throw css::uno::RuntimeException(
145 (rtl::OUString(
146 RTL_CONSTASCII_USTRINGPARAM(
147 "bad localized property node member <")) +
148 name.convertFromUtf8() +
149 rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("> in ")) +
150 reader.getUrl()),
151 css::uno::Reference< css::uno::XInterface >());
153 break;
154 case Node::KIND_LOCALIZED_VALUE:
155 throw css::uno::RuntimeException(
156 (rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("bad member <")) +
157 name.convertFromUtf8() +
158 rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("> in ")) +
159 reader.getUrl()),
160 css::uno::Reference< css::uno::XInterface >());
161 case Node::KIND_GROUP:
162 if (nsId == xmlreader::XmlReader::NAMESPACE_NONE &&
163 name.equals(RTL_CONSTASCII_STRINGPARAM("prop")))
165 handleGroupProp(
166 reader,
167 dynamic_cast< GroupNode * >(state_.top().node.get()));
168 } else if (nsId == xmlreader::XmlReader::NAMESPACE_NONE &&
169 name.equals(RTL_CONSTASCII_STRINGPARAM("node")))
171 handleGroupNode(reader, state_.top().node);
172 } else {
173 throw css::uno::RuntimeException(
174 (rtl::OUString(
175 RTL_CONSTASCII_USTRINGPARAM(
176 "bad group node member <")) +
177 name.convertFromUtf8() +
178 rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("> in ")) +
179 reader.getUrl()),
180 css::uno::Reference< css::uno::XInterface >());
182 break;
183 case Node::KIND_SET:
184 if (nsId == xmlreader::XmlReader::NAMESPACE_NONE &&
185 name.equals(RTL_CONSTASCII_STRINGPARAM("node")))
187 handleSetNode(
188 reader, dynamic_cast< SetNode * >(state_.top().node.get()));
189 } else if (nsId == xmlreader::XmlReader::NAMESPACE_NONE &&
190 name.equals(RTL_CONSTASCII_STRINGPARAM("prop")))
192 SAL_WARN(
193 "configmgr",
194 "bad set node <prop> member in \"" << reader.getUrl()
195 << '"');
196 state_.push(State(true)); // ignored
197 } else {
198 throw css::uno::RuntimeException(
199 (rtl::OUString(
200 RTL_CONSTASCII_USTRINGPARAM("bad set node member <")) +
201 name.convertFromUtf8() +
202 rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("> in ")) +
203 reader.getUrl()),
204 css::uno::Reference< css::uno::XInterface >());
206 break;
207 case Node::KIND_ROOT:
208 assert(false); // this cannot happen
209 break;
212 return true;
215 void XcuParser::endElement(xmlreader::XmlReader const &) {
216 if (valueParser_.endElement()) {
217 return;
219 assert(!state_.empty());
220 bool pop = state_.top().pop;
221 rtl::Reference< Node > insert;
222 rtl::OUString name;
223 if (state_.top().insert) {
224 insert = state_.top().node;
225 assert(insert.is());
226 name = state_.top().name;
228 state_.pop();
229 if (insert.is()) {
230 assert(!state_.empty() && state_.top().node.is());
231 state_.top().node->getMembers()[name] = insert;
233 if (pop && !path_.empty()) {
234 path_.pop_back();
235 // </item> will pop less than <item> pushed, but that is harmless,
236 // as the next <item> will reset path_
240 void XcuParser::characters(xmlreader::Span const & text) {
241 valueParser_.characters(text);
244 XcuParser::Operation XcuParser::parseOperation(xmlreader::Span const & text) {
245 assert(text.is());
246 if (text.equals(RTL_CONSTASCII_STRINGPARAM("modify"))) {
247 return OPERATION_MODIFY;
249 if (text.equals(RTL_CONSTASCII_STRINGPARAM("replace"))) {
250 return OPERATION_REPLACE;
252 if (text.equals(RTL_CONSTASCII_STRINGPARAM("fuse"))) {
253 return OPERATION_FUSE;
255 if (text.equals(RTL_CONSTASCII_STRINGPARAM("remove"))) {
256 return OPERATION_REMOVE;
258 throw css::uno::RuntimeException(
259 (rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("invalid op ")) +
260 text.convertFromUtf8()),
261 css::uno::Reference< css::uno::XInterface >());
264 void XcuParser::handleComponentData(xmlreader::XmlReader & reader) {
265 rtl::OStringBuffer buf;
266 buf.append('.');
267 bool hasPackage = false;
268 bool hasName = false;
269 Operation op = OPERATION_MODIFY;
270 bool finalized = false;
271 for (;;) {
272 int attrNsId;
273 xmlreader::Span attrLn;
274 if (!reader.nextAttribute(&attrNsId, &attrLn)) {
275 break;
277 if (attrNsId == ParseManager::NAMESPACE_OOR &&
278 attrLn.equals(RTL_CONSTASCII_STRINGPARAM("package")))
280 if (hasPackage) {
281 throw css::uno::RuntimeException(
282 (rtl::OUString(
283 RTL_CONSTASCII_USTRINGPARAM(
284 "multiple component-update package attributes"
285 " in ")) +
286 reader.getUrl()),
287 css::uno::Reference< css::uno::XInterface >());
289 hasPackage = true;
290 xmlreader::Span s(reader.getAttributeValue(false));
291 buf.insert(0, s.begin, s.length);
292 } else if (attrNsId == ParseManager::NAMESPACE_OOR &&
293 attrLn.equals(RTL_CONSTASCII_STRINGPARAM("name")))
295 if (hasName) {
296 throw css::uno::RuntimeException(
297 (rtl::OUString(
298 RTL_CONSTASCII_USTRINGPARAM(
299 "multiple component-update name attributes in ")) +
300 reader.getUrl()),
301 css::uno::Reference< css::uno::XInterface >());
303 hasName = true;
304 xmlreader::Span s(reader.getAttributeValue(false));
305 buf.append(s.begin, s.length);
306 } else if (attrNsId == ParseManager::NAMESPACE_OOR &&
307 attrLn.equals(RTL_CONSTASCII_STRINGPARAM("op")))
309 op = parseOperation(reader.getAttributeValue(true));
310 } else if (attrNsId == ParseManager::NAMESPACE_OOR &&
311 attrLn.equals(RTL_CONSTASCII_STRINGPARAM("finalized")))
313 finalized = xmldata::parseBoolean(reader.getAttributeValue(true));
316 if (!hasPackage) {
317 throw css::uno::RuntimeException(
318 (rtl::OUString(
319 RTL_CONSTASCII_USTRINGPARAM(
320 "no component-data package attribute in ")) +
321 reader.getUrl()),
322 css::uno::Reference< css::uno::XInterface >());
324 if (!hasName) {
325 throw css::uno::RuntimeException(
326 (rtl::OUString(
327 RTL_CONSTASCII_USTRINGPARAM(
328 "no component-data name attribute in ")) +
329 reader.getUrl()),
330 css::uno::Reference< css::uno::XInterface >());
332 componentName_ = xmlreader::Span(buf.getStr(), buf.getLength()).
333 convertFromUtf8();
334 if (trackPath_) {
335 assert(path_.empty());
336 path_.push_back(componentName_);
337 if (partial_ != 0 && partial_->contains(path_) == Partial::CONTAINS_NOT)
339 state_.push(State(true)); // ignored
340 return;
343 rtl::Reference< Node > node(
344 Data::findNode(
345 valueParser_.getLayer(), data_.getComponents(), componentName_));
346 if (!node.is()) {
347 SAL_WARN(
348 "configmgr",
349 "unknown component \"" << componentName_ << "\" in \""
350 << reader.getUrl() << '"');
351 state_.push(State(true)); // ignored
352 return;
354 switch (op) {
355 case OPERATION_MODIFY:
356 case OPERATION_FUSE:
357 break;
358 default:
359 throw css::uno::RuntimeException(
360 (rtl::OUString(
361 RTL_CONSTASCII_USTRINGPARAM(
362 "invalid operation on root node in ")) +
363 reader.getUrl()),
364 css::uno::Reference< css::uno::XInterface >());
366 int finalizedLayer = std::min(
367 finalized ? valueParser_.getLayer() : Data::NO_LAYER,
368 node->getFinalized());
369 node->setFinalized(finalizedLayer);
370 state_.push(State(node, finalizedLayer < valueParser_.getLayer()));
373 void XcuParser::handleItem(xmlreader::XmlReader & reader) {
374 xmlreader::Span attrPath;
375 for (;;) {
376 int attrNsId;
377 xmlreader::Span attrLn;
378 if (!reader.nextAttribute(&attrNsId, &attrLn)) {
379 break;
381 if (attrNsId == ParseManager::NAMESPACE_OOR &&
382 attrLn.equals(RTL_CONSTASCII_STRINGPARAM("path")))
384 attrPath = reader.getAttributeValue(false);
387 if (!attrPath.is()) {
388 throw css::uno::RuntimeException(
389 (rtl::OUString(
390 RTL_CONSTASCII_USTRINGPARAM("missing path attribute in ")) +
391 reader.getUrl()),
392 css::uno::Reference< css::uno::XInterface >());
394 rtl::OUString path(attrPath.convertFromUtf8());
395 int finalizedLayer;
396 rtl::Reference< Node > node(
397 data_.resolvePathRepresentation(
398 path, 0, &path_, &finalizedLayer));
399 if (!node.is()) {
400 SAL_WARN(
401 "configmgr",
402 "unknown item \"" << path << "\" in \"" << reader.getUrl() << '"');
403 state_.push(State(true)); // ignored
404 return;
406 assert(!path_.empty());
407 componentName_ = path_.front();
408 if (trackPath_) {
409 if (partial_ != 0 && partial_->contains(path_) == Partial::CONTAINS_NOT)
411 state_.push(State(true)); // ignored
412 return;
414 } else {
415 path_.clear();
417 switch (node->kind()) {
418 case Node::KIND_PROPERTY:
419 case Node::KIND_LOCALIZED_VALUE:
420 SAL_WARN(
421 "configmgr",
422 "item of bad type \"" << path << "\" in \"" << reader.getUrl()
423 << '"');
424 state_.push(State(true)); // ignored
425 return;
426 case Node::KIND_LOCALIZED_PROPERTY:
427 valueParser_.type_ = dynamic_cast< LocalizedPropertyNode * >(
428 node.get())->getStaticType();
429 break;
430 default:
431 break;
433 state_.push(State(node, finalizedLayer < valueParser_.getLayer()));
436 void XcuParser::handlePropValue(
437 xmlreader::XmlReader & reader, PropertyNode * prop)
439 bool nil = false;
440 rtl::OString separator;
441 rtl::OUString external;
442 for (;;) {
443 int attrNsId;
444 xmlreader::Span attrLn;
445 if (!reader.nextAttribute(&attrNsId, &attrLn)) {
446 break;
448 if (attrNsId == ParseManager::NAMESPACE_XSI &&
449 attrLn.equals(RTL_CONSTASCII_STRINGPARAM("nil")))
451 nil = xmldata::parseBoolean(reader.getAttributeValue(true));
452 } else if (attrNsId == ParseManager::NAMESPACE_OOR &&
453 attrLn.equals(RTL_CONSTASCII_STRINGPARAM("type")))
455 Type type = xmldata::parseType(
456 reader, reader.getAttributeValue(true));
457 if (valueParser_.type_ != TYPE_ANY && type != valueParser_.type_) {
458 throw css::uno::RuntimeException(
459 (rtl::OUString(
460 RTL_CONSTASCII_USTRINGPARAM("invalid value type in ")) +
461 reader.getUrl()),
462 css::uno::Reference< css::uno::XInterface >());
464 valueParser_.type_ = type;
465 } else if (attrNsId == ParseManager::NAMESPACE_OOR &&
466 attrLn.equals(RTL_CONSTASCII_STRINGPARAM("separator")))
468 xmlreader::Span s(reader.getAttributeValue(false));
469 if (s.length == 0) {
470 throw css::uno::RuntimeException(
471 (rtl::OUString(
472 RTL_CONSTASCII_USTRINGPARAM(
473 "bad oor:separator attribute in ")) +
474 reader.getUrl()),
475 css::uno::Reference< css::uno::XInterface >());
477 separator = rtl::OString(s.begin, s.length);
478 } else if (attrNsId == ParseManager::NAMESPACE_OOR &&
479 attrLn.equals(RTL_CONSTASCII_STRINGPARAM("external")))
481 external = reader.getAttributeValue(true).convertFromUtf8();
482 if (external.isEmpty()) {
483 throw css::uno::RuntimeException(
484 (rtl::OUString(
485 RTL_CONSTASCII_USTRINGPARAM(
486 "bad oor:external attribute value in ")) +
487 reader.getUrl()),
488 css::uno::Reference< css::uno::XInterface >());
492 if (nil) {
493 if (!prop->isNillable()) {
494 throw css::uno::RuntimeException(
495 (rtl::OUString(
496 RTL_CONSTASCII_USTRINGPARAM(
497 "xsi:nil attribute for non-nillable prop in ")) +
498 reader.getUrl()),
499 css::uno::Reference< css::uno::XInterface >());
501 if (!external.isEmpty()) {
502 throw css::uno::RuntimeException(
503 (rtl::OUString(
504 RTL_CONSTASCII_USTRINGPARAM(
505 "xsi:nil and oor:external attributes for prop in ")) +
506 reader.getUrl()),
507 css::uno::Reference< css::uno::XInterface >());
509 prop->setValue(valueParser_.getLayer(), css::uno::Any());
510 state_.push(State(false));
511 } else if (external.isEmpty()) {
512 valueParser_.separator_ = separator;
513 valueParser_.start(prop);
514 } else {
515 prop->setExternal(valueParser_.getLayer(), external);
516 state_.push(State(false));
520 void XcuParser::handleLocpropValue(
521 xmlreader::XmlReader & reader, LocalizedPropertyNode * locprop)
523 rtl::OUString name;
524 bool nil = false;
525 rtl::OString separator;
526 Operation op = OPERATION_FUSE;
527 for (;;) {
528 int attrNsId;
529 xmlreader::Span attrLn;
530 if (!reader.nextAttribute(&attrNsId, &attrLn)) {
531 break;
533 if (attrNsId == xmlreader::XmlReader::NAMESPACE_XML &&
534 attrLn.equals(RTL_CONSTASCII_STRINGPARAM("lang")))
536 name = reader.getAttributeValue(false).convertFromUtf8();
537 } else if (attrNsId == ParseManager::NAMESPACE_XSI &&
538 attrLn.equals(RTL_CONSTASCII_STRINGPARAM("nil")))
540 nil = xmldata::parseBoolean(reader.getAttributeValue(true));
541 } else if (attrNsId == ParseManager::NAMESPACE_OOR &&
542 attrLn.equals(RTL_CONSTASCII_STRINGPARAM("type")))
544 Type type = xmldata::parseType(
545 reader, reader.getAttributeValue(true));
546 if (valueParser_.type_ != TYPE_ANY && type != valueParser_.type_) {
547 throw css::uno::RuntimeException(
548 (rtl::OUString(
549 RTL_CONSTASCII_USTRINGPARAM("invalid value type in ")) +
550 reader.getUrl()),
551 css::uno::Reference< css::uno::XInterface >());
553 valueParser_.type_ = type;
554 } else if (attrNsId == ParseManager::NAMESPACE_OOR &&
555 attrLn.equals(RTL_CONSTASCII_STRINGPARAM("separator")))
557 xmlreader::Span s(reader.getAttributeValue(false));
558 if (s.length == 0) {
559 throw css::uno::RuntimeException(
560 (rtl::OUString(
561 RTL_CONSTASCII_USTRINGPARAM(
562 "bad oor:separator attribute in ")) +
563 reader.getUrl()),
564 css::uno::Reference< css::uno::XInterface >());
566 separator = rtl::OString(s.begin, s.length);
567 } else if (attrNsId == ParseManager::NAMESPACE_OOR &&
568 attrLn.equals(RTL_CONSTASCII_STRINGPARAM("op")))
570 op = parseOperation(reader.getAttributeValue(true));
573 if (trackPath_) {
574 path_.push_back(name);
575 if (partial_ != 0 &&
576 partial_->contains(path_) != Partial::CONTAINS_NODE)
578 state_.push(State(true)); // ignored
579 return;
582 NodeMap & members = locprop->getMembers();
583 NodeMap::iterator i(members.find(name));
584 if (i != members.end() && i->second->getLayer() > valueParser_.getLayer()) {
585 state_.push(State(true)); // ignored
586 return;
588 if (nil && !locprop->isNillable()) {
589 throw css::uno::RuntimeException(
590 (rtl::OUString(
591 RTL_CONSTASCII_USTRINGPARAM(
592 "xsi:nil attribute for non-nillable prop in ")) +
593 reader.getUrl()),
594 css::uno::Reference< css::uno::XInterface >());
596 switch (op) {
597 case OPERATION_FUSE:
599 bool pop = false;
600 if (nil) {
601 if (i == members.end()) {
602 members[name] = new LocalizedValueNode(
603 valueParser_.getLayer(), css::uno::Any());
604 } else {
605 dynamic_cast< LocalizedValueNode * >(
606 i->second.get())->setValue(
607 valueParser_.getLayer(), css::uno::Any());
609 state_.push(State(true));
610 } else {
611 valueParser_.separator_ = separator;
612 valueParser_.start(locprop, name);
613 pop = true;
615 if (trackPath_) {
616 recordModification(false);
617 if (pop) {
618 path_.pop_back();
622 break;
623 case OPERATION_REMOVE:
624 //TODO: only allow if parent.op == OPERATION_FUSE
625 //TODO: disallow removing when e.g. lang=""?
626 if (i != members.end()) {
627 members.erase(i);
629 state_.push(State(true));
630 recordModification(false);
631 break;
632 default:
633 throw css::uno::RuntimeException(
634 (rtl::OUString(
635 RTL_CONSTASCII_USTRINGPARAM(
636 "bad op attribute for value element in ")) +
637 reader.getUrl()),
638 css::uno::Reference< css::uno::XInterface >());
642 void XcuParser::handleGroupProp(
643 xmlreader::XmlReader & reader, GroupNode * group)
645 bool hasName = false;
646 rtl::OUString name;
647 Type type = TYPE_ERROR;
648 Operation op = OPERATION_MODIFY;
649 bool finalized = false;
650 for (;;) {
651 int attrNsId;
652 xmlreader::Span attrLn;
653 if (!reader.nextAttribute(&attrNsId, &attrLn)) {
654 break;
656 if (attrNsId == ParseManager::NAMESPACE_OOR &&
657 attrLn.equals(RTL_CONSTASCII_STRINGPARAM("name")))
659 hasName = true;
660 name = reader.getAttributeValue(false).convertFromUtf8();
661 } else if (attrNsId == ParseManager::NAMESPACE_OOR &&
662 attrLn.equals(RTL_CONSTASCII_STRINGPARAM("type")))
664 type = xmldata::parseType(reader, reader.getAttributeValue(true));
665 } else if (attrNsId == ParseManager::NAMESPACE_OOR &&
666 attrLn.equals(RTL_CONSTASCII_STRINGPARAM("op")))
668 op = parseOperation(reader.getAttributeValue(true));
669 } else if (attrNsId == ParseManager::NAMESPACE_OOR &&
670 attrLn.equals(RTL_CONSTASCII_STRINGPARAM("finalized")))
672 finalized = xmldata::parseBoolean(reader.getAttributeValue(true));
675 if (!hasName) {
676 throw css::uno::RuntimeException(
677 (rtl::OUString(
678 RTL_CONSTASCII_USTRINGPARAM("no prop name attribute in ")) +
679 reader.getUrl()),
680 css::uno::Reference< css::uno::XInterface >());
682 if (trackPath_) {
683 path_.push_back(name);
684 //TODO: This ignores locprop values for which specific include paths
685 // exist (i.e., for which contains(locprop path) = CONTAINS_SUBNODES):
686 if (partial_ != 0 &&
687 partial_->contains(path_) != Partial::CONTAINS_NODE)
689 state_.push(State(true)); // ignored
690 return;
693 NodeMap & members = group->getMembers();
694 NodeMap::iterator i(members.find(name));
695 if (i == members.end()) {
696 handleUnknownGroupProp(reader, group, name, type, op, finalized);
697 } else {
698 switch (i->second->kind()) {
699 case Node::KIND_PROPERTY:
700 handlePlainGroupProp(reader, group, i, name, type, op, finalized);
701 break;
702 case Node::KIND_LOCALIZED_PROPERTY:
703 handleLocalizedGroupProp(
704 reader,
705 dynamic_cast< LocalizedPropertyNode * >(i->second.get()), name,
706 type, op, finalized);
707 break;
708 default:
709 throw css::uno::RuntimeException(
710 (rtl::OUString(
711 RTL_CONSTASCII_USTRINGPARAM("inappropriate prop ")) +
712 name + rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(" in ")) +
713 reader.getUrl()),
714 css::uno::Reference< css::uno::XInterface >());
719 void XcuParser::handleUnknownGroupProp(
720 xmlreader::XmlReader const & reader, GroupNode * group,
721 rtl::OUString const & name, Type type, Operation operation, bool finalized)
723 switch (operation) {
724 case OPERATION_REPLACE:
725 case OPERATION_FUSE:
726 if (group->isExtensible()) {
727 if (type == TYPE_ERROR) {
728 throw css::uno::RuntimeException(
729 (rtl::OUString(
730 RTL_CONSTASCII_USTRINGPARAM(
731 "missing type attribute for prop ")) +
732 name + rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(" in ")) +
733 reader.getUrl()),
734 css::uno::Reference< css::uno::XInterface >());
736 valueParser_.type_ = type;
737 rtl::Reference< Node > prop(
738 new PropertyNode(
739 valueParser_.getLayer(), TYPE_ANY, true, css::uno::Any(),
740 true));
741 if (finalized) {
742 prop->setFinalized(valueParser_.getLayer());
744 state_.push(State(prop, name, state_.top().locked));
745 recordModification(false);
746 break;
748 // fall through
749 default:
750 SAL_WARN(
751 "configmgr",
752 "unknown property \"" << name << "\" in \"" << reader.getUrl()
753 << '"');
754 state_.push(State(true)); // ignored
755 break;
759 void XcuParser::handlePlainGroupProp(
760 xmlreader::XmlReader const & reader, GroupNode * group,
761 NodeMap::iterator const & propertyIndex, rtl::OUString const & name,
762 Type type, Operation operation, bool finalized)
764 PropertyNode * property = dynamic_cast< PropertyNode * >(
765 propertyIndex->second.get());
766 if (property->getLayer() > valueParser_.getLayer()) {
767 state_.push(State(true)); // ignored
768 return;
770 int finalizedLayer = std::min(
771 finalized ? valueParser_.getLayer() : Data::NO_LAYER,
772 property->getFinalized());
773 property->setFinalized(finalizedLayer);
774 if (type != TYPE_ERROR && property->getStaticType() != TYPE_ANY &&
775 type != property->getStaticType())
777 throw css::uno::RuntimeException(
778 (rtl::OUString(
779 RTL_CONSTASCII_USTRINGPARAM("invalid type for prop ")) +
780 name + rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(" in ")) +
781 reader.getUrl()),
782 css::uno::Reference< css::uno::XInterface >());
784 valueParser_.type_ = type == TYPE_ERROR ? property->getStaticType() : type;
785 switch (operation) {
786 case OPERATION_MODIFY:
787 case OPERATION_REPLACE:
788 case OPERATION_FUSE:
789 state_.push(
790 State(
791 property,
792 (state_.top().locked ||
793 finalizedLayer < valueParser_.getLayer())));
794 recordModification(false);
795 break;
796 case OPERATION_REMOVE:
797 if (!property->isExtension()) {
798 throw css::uno::RuntimeException(
799 (rtl::OUString(
800 RTL_CONSTASCII_USTRINGPARAM(
801 "invalid remove of non-extension prop ")) +
802 name + rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(" in ")) +
803 reader.getUrl()),
804 css::uno::Reference< css::uno::XInterface >());
806 group->getMembers().erase(propertyIndex);
807 state_.push(State(true)); // ignore children
808 recordModification(false);
809 break;
813 void XcuParser::handleLocalizedGroupProp(
814 xmlreader::XmlReader const & reader, LocalizedPropertyNode * property,
815 rtl::OUString const & name, Type type, Operation operation, bool finalized)
817 if (property->getLayer() > valueParser_.getLayer()) {
818 state_.push(State(true)); // ignored
819 return;
821 int finalizedLayer = std::min(
822 finalized ? valueParser_.getLayer() : Data::NO_LAYER,
823 property->getFinalized());
824 property->setFinalized(finalizedLayer);
825 if (type != TYPE_ERROR && property->getStaticType() != TYPE_ANY &&
826 type != property->getStaticType())
828 throw css::uno::RuntimeException(
829 (rtl::OUString(
830 RTL_CONSTASCII_USTRINGPARAM("invalid type for prop ")) +
831 name + rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(" in ")) +
832 reader.getUrl()),
833 css::uno::Reference< css::uno::XInterface >());
835 valueParser_.type_ = type == TYPE_ERROR ? property->getStaticType() : type;
836 switch (operation) {
837 case OPERATION_MODIFY:
838 case OPERATION_FUSE:
839 state_.push(
840 State(
841 property,
842 (state_.top().locked ||
843 finalizedLayer < valueParser_.getLayer())));
844 break;
845 case OPERATION_REPLACE:
847 rtl::Reference< Node > replacement(
848 new LocalizedPropertyNode(
849 valueParser_.getLayer(), property->getStaticType(),
850 property->isNillable()));
851 replacement->setFinalized(property->getFinalized());
852 state_.push(
853 State(
854 replacement, name,
855 (state_.top().locked ||
856 finalizedLayer < valueParser_.getLayer())));
857 recordModification(false);
859 break;
860 case OPERATION_REMOVE:
861 throw css::uno::RuntimeException(
862 (rtl::OUString(
863 RTL_CONSTASCII_USTRINGPARAM(
864 "invalid remove of non-extension prop ")) +
865 name + rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(" in ")) +
866 reader.getUrl()),
867 css::uno::Reference< css::uno::XInterface >());
871 void XcuParser::handleGroupNode(
872 xmlreader::XmlReader & reader, rtl::Reference< Node > const & group)
874 bool hasName = false;
875 rtl::OUString name;
876 Operation op = OPERATION_MODIFY;
877 bool finalized = false;
878 for (;;) {
879 int attrNsId;
880 xmlreader::Span attrLn;
881 if (!reader.nextAttribute(&attrNsId, &attrLn)) {
882 break;
884 if (attrNsId == ParseManager::NAMESPACE_OOR &&
885 attrLn.equals(RTL_CONSTASCII_STRINGPARAM("name")))
887 hasName = true;
888 name = reader.getAttributeValue(false).convertFromUtf8();
889 } else if (attrNsId == ParseManager::NAMESPACE_OOR &&
890 attrLn.equals(RTL_CONSTASCII_STRINGPARAM("op")))
892 op = parseOperation(reader.getAttributeValue(true));
893 } else if (attrNsId == ParseManager::NAMESPACE_OOR &&
894 attrLn.equals(RTL_CONSTASCII_STRINGPARAM("finalized")))
896 finalized = xmldata::parseBoolean(reader.getAttributeValue(true));
899 if (!hasName) {
900 throw css::uno::RuntimeException(
901 (rtl::OUString(
902 RTL_CONSTASCII_USTRINGPARAM("no node name attribute in ")) +
903 reader.getUrl()),
904 css::uno::Reference< css::uno::XInterface >());
906 if (trackPath_) {
907 path_.push_back(name);
908 if (partial_ != 0 && partial_->contains(path_) == Partial::CONTAINS_NOT)
910 state_.push(State(true)); // ignored
911 return;
914 rtl::Reference< Node > child(
915 Data::findNode(valueParser_.getLayer(), group->getMembers(), name));
916 if (!child.is()) {
917 SAL_WARN(
918 "configmgr",
919 "unknown node \"" << name << "\" in \"" << reader.getUrl() << '"');
920 state_.push(State(true)); // ignored
921 return;
923 Node::Kind kind = child->kind();
924 if (kind != Node::KIND_GROUP && kind != Node::KIND_SET) {
925 throw css::uno::RuntimeException(
926 (rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("bad <node> \"")) +
927 name +
928 rtl::OUString(
929 RTL_CONSTASCII_USTRINGPARAM("\" of non group/set kind in ")) +
930 reader.getUrl()),
931 css::uno::Reference< css::uno::XInterface >());
933 if (op != OPERATION_MODIFY && op != OPERATION_FUSE) {
934 throw css::uno::RuntimeException(
935 (rtl::OUString(
936 RTL_CONSTASCII_USTRINGPARAM(
937 "invalid operation on group node in ")) +
938 reader.getUrl()),
939 css::uno::Reference< css::uno::XInterface >());
941 int finalizedLayer = std::min(
942 finalized ? valueParser_.getLayer() : Data::NO_LAYER,
943 child->getFinalized());
944 child->setFinalized(finalizedLayer);
945 state_.push(
946 State(
947 child,
948 state_.top().locked || finalizedLayer < valueParser_.getLayer()));
951 void XcuParser::handleSetNode(xmlreader::XmlReader & reader, SetNode * set) {
952 bool hasName = false;
953 rtl::OUString name;
954 rtl::OUString component(componentName_);
955 bool hasNodeType = false;
956 rtl::OUString nodeType;
957 Operation op = OPERATION_MODIFY;
958 bool finalized = false;
959 bool mandatory = false;
960 for (;;) {
961 int attrNsId;
962 xmlreader::Span attrLn;
963 if (!reader.nextAttribute(&attrNsId, &attrLn)) {
964 break;
966 if (attrNsId == ParseManager::NAMESPACE_OOR &&
967 attrLn.equals(RTL_CONSTASCII_STRINGPARAM("name")))
969 hasName = true;
970 name = reader.getAttributeValue(false).convertFromUtf8();
971 } else if (attrNsId == ParseManager::NAMESPACE_OOR &&
972 attrLn.equals(RTL_CONSTASCII_STRINGPARAM("component")))
974 component = reader.getAttributeValue(false).convertFromUtf8();
975 } else if (attrNsId == ParseManager::NAMESPACE_OOR &&
976 attrLn.equals(RTL_CONSTASCII_STRINGPARAM("node-type")))
978 hasNodeType = true;
979 nodeType = reader.getAttributeValue(false).convertFromUtf8();
980 } else if (attrNsId == ParseManager::NAMESPACE_OOR &&
981 attrLn.equals(RTL_CONSTASCII_STRINGPARAM("op")))
983 op = parseOperation(reader.getAttributeValue(true));
984 } else if (attrNsId == ParseManager::NAMESPACE_OOR &&
985 attrLn.equals(RTL_CONSTASCII_STRINGPARAM("finalized")))
987 finalized = xmldata::parseBoolean(reader.getAttributeValue(true));
988 } else if (attrNsId == ParseManager::NAMESPACE_OOR &&
989 attrLn.equals(RTL_CONSTASCII_STRINGPARAM("mandatory")))
991 mandatory = xmldata::parseBoolean(reader.getAttributeValue(true));
994 if (!hasName) {
995 throw css::uno::RuntimeException(
996 (rtl::OUString(
997 RTL_CONSTASCII_USTRINGPARAM("no node name attribute in ")) +
998 reader.getUrl()),
999 css::uno::Reference< css::uno::XInterface >());
1001 if (trackPath_) {
1002 path_.push_back(name);
1003 if (partial_ != 0 && partial_->contains(path_) == Partial::CONTAINS_NOT)
1005 state_.push(State(true)); // ignored
1006 return;
1009 rtl::OUString templateName(
1010 xmldata::parseTemplateReference(
1011 component, hasNodeType, nodeType, &set->getDefaultTemplateName()));
1012 if (!set->isValidTemplate(templateName)) {
1013 throw css::uno::RuntimeException(
1014 (rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("set member node ")) +
1015 name +
1016 rtl::OUString(
1017 RTL_CONSTASCII_USTRINGPARAM(" references invalid template ")) +
1018 templateName + rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(" in ")) +
1019 reader.getUrl()),
1020 css::uno::Reference< css::uno::XInterface >());
1022 rtl::Reference< Node > tmpl(
1023 data_.getTemplate(valueParser_.getLayer(), templateName));
1024 if (!tmpl.is()) {
1025 throw css::uno::RuntimeException(
1026 (rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("set member node ")) +
1027 name +
1028 rtl::OUString(
1029 RTL_CONSTASCII_USTRINGPARAM(
1030 " references undefined template ")) +
1031 templateName + rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(" in ")) +
1032 reader.getUrl()),
1033 css::uno::Reference< css::uno::XInterface >());
1035 int finalizedLayer = finalized ? valueParser_.getLayer() : Data::NO_LAYER;
1036 int mandatoryLayer = mandatory ? valueParser_.getLayer() : Data::NO_LAYER;
1037 NodeMap & members = set->getMembers();
1038 NodeMap::iterator i(members.find(name));
1039 if (i != members.end()) {
1040 finalizedLayer = std::min(finalizedLayer, i->second->getFinalized());
1041 i->second->setFinalized(finalizedLayer);
1042 mandatoryLayer = std::min(mandatoryLayer, i->second->getMandatory());
1043 i->second->setMandatory(mandatoryLayer);
1044 if (i->second->getLayer() > valueParser_.getLayer()) {
1045 state_.push(State(true)); // ignored
1046 return;
1049 switch (op) {
1050 case OPERATION_MODIFY:
1051 if (i == members.end()) {
1052 SAL_WARN(
1053 "configmgr",
1054 "ignoring modify of unknown set member node \"" << name
1055 << "\" in \"" << reader.getUrl() << '"');
1056 state_.push(State(true)); // ignored
1057 } else {
1058 state_.push(
1059 State(
1060 i->second,
1061 (state_.top().locked ||
1062 finalizedLayer < valueParser_.getLayer())));
1064 break;
1065 case OPERATION_REPLACE:
1066 if (state_.top().locked || finalizedLayer < valueParser_.getLayer()) {
1067 state_.push(State(true)); // ignored
1068 } else {
1069 rtl::Reference< Node > member(tmpl->clone(true));
1070 member->setLayer(valueParser_.getLayer());
1071 member->setFinalized(finalizedLayer);
1072 member->setMandatory(mandatoryLayer);
1073 state_.push(State(member, name, false));
1074 recordModification(i == members.end());
1076 break;
1077 case OPERATION_FUSE:
1078 if (i == members.end()) {
1079 if (state_.top().locked || finalizedLayer < valueParser_.getLayer())
1081 state_.push(State(true)); // ignored
1082 } else {
1083 rtl::Reference< Node > member(tmpl->clone(true));
1084 member->setLayer(valueParser_.getLayer());
1085 member->setFinalized(finalizedLayer);
1086 member->setMandatory(mandatoryLayer);
1087 state_.push(State(member, name, false));
1088 recordModification(true);
1090 } else {
1091 state_.push(
1092 State(
1093 i->second,
1094 (state_.top().locked ||
1095 finalizedLayer < valueParser_.getLayer())));
1097 break;
1098 case OPERATION_REMOVE:
1100 // Ignore removal of unknown members, members finalized in a lower
1101 // layer, and members made mandatory in this or a lower layer;
1102 // forget about user-layer removals that no longer remove anything
1103 // (so that paired additions/removals in the user layer do not grow
1104 // registrymodifications.xcu unbounded):
1105 bool known = i != members.end();
1106 if (known && !state_.top().locked &&
1107 finalizedLayer >= valueParser_.getLayer() &&
1108 (mandatoryLayer == Data::NO_LAYER ||
1109 mandatoryLayer > valueParser_.getLayer()))
1111 members.erase(i);
1113 state_.push(State(true));
1114 if (known) {
1115 recordModification(false);
1117 break;
1122 void XcuParser::recordModification(bool addition) {
1123 if (broadcastModifications_ != 0) {
1124 broadcastModifications_->add(path_);
1126 if (addition && additions_ != 0) {
1127 additions_->push_back(path_);
1129 if (recordModifications_) {
1130 data_.modifications.add(path_);
1136 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */