fdo#74697 Add Bluez 5 support for impress remote.
[LibreOffice.git] / configmgr / source / xcuparser.cxx
blobe77025fb70b23f727e8c15d68e559ba33098a71b
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("component-data"))
85 handleComponentData(reader);
86 } else if (nsId == ParseManager::NAMESPACE_OOR && name.equals("items"))
88 state_.push(State(rtl::Reference< Node >(), false));
89 } else {
90 throw css::uno::RuntimeException(
91 ("bad root element <" + name.convertFromUtf8() + "> in " +
92 reader.getUrl()),
93 css::uno::Reference< css::uno::XInterface >());
95 } else if (state_.top().ignore) {
96 state_.push(State(false));
97 } else if (!state_.top().node.is()) {
98 if (nsId == xmlreader::XmlReader::NAMESPACE_NONE && name.equals("item"))
100 handleItem(reader);
101 } else {
102 throw css::uno::RuntimeException(
103 ("bad items node member <" + name.convertFromUtf8() + "> in " +
104 reader.getUrl()),
105 css::uno::Reference< css::uno::XInterface >());
107 } else {
108 switch (state_.top().node->kind()) {
109 case Node::KIND_PROPERTY:
110 if (nsId == xmlreader::XmlReader::NAMESPACE_NONE &&
111 name.equals("value"))
113 handlePropValue(
114 reader,
115 dynamic_cast< PropertyNode * >(state_.top().node.get()));
116 } else {
117 throw css::uno::RuntimeException(
118 ("bad property node member <" + name.convertFromUtf8() +
119 "> in " + reader.getUrl()),
120 css::uno::Reference< css::uno::XInterface >());
122 break;
123 case Node::KIND_LOCALIZED_PROPERTY:
124 if (nsId == xmlreader::XmlReader::NAMESPACE_NONE &&
125 name.equals("value"))
127 handleLocpropValue(
128 reader,
129 dynamic_cast< LocalizedPropertyNode * >(
130 state_.top().node.get()));
131 } else {
132 throw css::uno::RuntimeException(
133 ("bad localized property node member <" +
134 name.convertFromUtf8() + "> in " + reader.getUrl()),
135 css::uno::Reference< css::uno::XInterface >());
137 break;
138 case Node::KIND_LOCALIZED_VALUE:
139 throw css::uno::RuntimeException(
140 ("bad member <" + name.convertFromUtf8() + "> in " +
141 reader.getUrl()),
142 css::uno::Reference< css::uno::XInterface >());
143 case Node::KIND_GROUP:
144 if (nsId == xmlreader::XmlReader::NAMESPACE_NONE &&
145 name.equals("prop"))
147 handleGroupProp(
148 reader,
149 dynamic_cast< GroupNode * >(state_.top().node.get()));
150 } else if (nsId == xmlreader::XmlReader::NAMESPACE_NONE &&
151 name.equals("node"))
153 handleGroupNode(reader, state_.top().node);
154 } else {
155 throw css::uno::RuntimeException(
156 ("bad group node member <" + name.convertFromUtf8() +
157 "> in " + reader.getUrl()),
158 css::uno::Reference< css::uno::XInterface >());
160 break;
161 case Node::KIND_SET:
162 if (nsId == xmlreader::XmlReader::NAMESPACE_NONE &&
163 name.equals("node"))
165 handleSetNode(
166 reader, dynamic_cast< SetNode * >(state_.top().node.get()));
167 } else if (nsId == xmlreader::XmlReader::NAMESPACE_NONE &&
168 name.equals("prop"))
170 SAL_WARN(
171 "configmgr",
172 "bad set node <prop> member in \"" << reader.getUrl()
173 << '"');
174 state_.push(State(true)); // ignored
175 } else {
176 throw css::uno::RuntimeException(
177 ("bad set node member <" + name.convertFromUtf8() +
178 "> in " + reader.getUrl()),
179 css::uno::Reference< css::uno::XInterface >());
181 break;
182 case Node::KIND_ROOT:
183 assert(false); // this cannot happen
184 break;
187 return true;
190 void XcuParser::endElement(xmlreader::XmlReader const &) {
191 if (valueParser_.endElement()) {
192 return;
194 assert(!state_.empty());
195 bool pop = state_.top().pop;
196 rtl::Reference< Node > insert;
197 OUString name;
198 if (state_.top().insert) {
199 insert = state_.top().node;
200 assert(insert.is());
201 name = state_.top().name;
203 state_.pop();
204 if (insert.is()) {
205 assert(!state_.empty() && state_.top().node.is());
206 state_.top().node->getMembers()[name] = insert;
208 if (pop && !path_.empty()) {
209 path_.pop_back();
210 // </item> will pop less than <item> pushed, but that is harmless,
211 // as the next <item> will reset path_
215 void XcuParser::characters(xmlreader::Span const & text) {
216 valueParser_.characters(text);
219 XcuParser::Operation XcuParser::parseOperation(xmlreader::Span const & text) {
220 assert(text.is());
221 if (text.equals("modify")) {
222 return OPERATION_MODIFY;
224 if (text.equals("replace")) {
225 return OPERATION_REPLACE;
227 if (text.equals("fuse")) {
228 return OPERATION_FUSE;
230 if (text.equals("remove")) {
231 return OPERATION_REMOVE;
233 throw css::uno::RuntimeException(
234 "invalid op " + text.convertFromUtf8(),
235 css::uno::Reference< css::uno::XInterface >());
238 void XcuParser::handleComponentData(xmlreader::XmlReader & reader) {
239 OStringBuffer buf;
240 buf.append('.');
241 bool hasPackage = false;
242 bool hasName = false;
243 Operation op = OPERATION_MODIFY;
244 bool finalized = false;
245 for (;;) {
246 int attrNsId;
247 xmlreader::Span attrLn;
248 if (!reader.nextAttribute(&attrNsId, &attrLn)) {
249 break;
251 if (attrNsId == ParseManager::NAMESPACE_OOR && attrLn.equals("package"))
253 if (hasPackage) {
254 throw css::uno::RuntimeException(
255 ("multiple component-update package attributes in " +
256 reader.getUrl()),
257 css::uno::Reference< css::uno::XInterface >());
259 hasPackage = true;
260 xmlreader::Span s(reader.getAttributeValue(false));
261 buf.insert(0, s.begin, s.length);
262 } else if (attrNsId == ParseManager::NAMESPACE_OOR &&
263 attrLn.equals("name"))
265 if (hasName) {
266 throw css::uno::RuntimeException(
267 ("multiple component-update name attributes in " +
268 reader.getUrl()),
269 css::uno::Reference< css::uno::XInterface >());
271 hasName = true;
272 xmlreader::Span s(reader.getAttributeValue(false));
273 buf.append(s.begin, s.length);
274 } else if (attrNsId == ParseManager::NAMESPACE_OOR &&
275 attrLn.equals("op"))
277 op = parseOperation(reader.getAttributeValue(true));
278 } else if (attrNsId == ParseManager::NAMESPACE_OOR &&
279 attrLn.equals("finalized"))
281 finalized = xmldata::parseBoolean(reader.getAttributeValue(true));
284 if (!hasPackage) {
285 throw css::uno::RuntimeException(
286 "no component-data package attribute in " + reader.getUrl(),
287 css::uno::Reference< css::uno::XInterface >());
289 if (!hasName) {
290 throw css::uno::RuntimeException(
291 "no component-data name attribute in " + reader.getUrl(),
292 css::uno::Reference< css::uno::XInterface >());
294 componentName_ = xmlreader::Span(buf.getStr(), buf.getLength()).
295 convertFromUtf8();
296 if (trackPath_) {
297 assert(path_.empty());
298 path_.push_back(componentName_);
299 if (partial_ != 0 && partial_->contains(path_) == Partial::CONTAINS_NOT)
301 state_.push(State(true)); // ignored
302 return;
305 rtl::Reference< Node > node(
306 Data::findNode(
307 valueParser_.getLayer(), data_.getComponents(), componentName_));
308 if (!node.is()) {
309 SAL_WARN(
310 "configmgr",
311 "unknown component \"" << componentName_ << "\" in \""
312 << reader.getUrl() << '"');
313 state_.push(State(true)); // ignored
314 return;
316 switch (op) {
317 case OPERATION_MODIFY:
318 case OPERATION_FUSE:
319 break;
320 default:
321 throw css::uno::RuntimeException(
322 "invalid operation on root node in " + reader.getUrl(),
323 css::uno::Reference< css::uno::XInterface >());
325 int finalizedLayer = std::min(
326 finalized ? valueParser_.getLayer() : Data::NO_LAYER,
327 node->getFinalized());
328 node->setFinalized(finalizedLayer);
329 state_.push(State(node, finalizedLayer < valueParser_.getLayer()));
332 void XcuParser::handleItem(xmlreader::XmlReader & reader) {
333 xmlreader::Span attrPath;
334 for (;;) {
335 int attrNsId;
336 xmlreader::Span attrLn;
337 if (!reader.nextAttribute(&attrNsId, &attrLn)) {
338 break;
340 if (attrNsId == ParseManager::NAMESPACE_OOR && attrLn.equals("path")) {
341 attrPath = reader.getAttributeValue(false);
344 if (!attrPath.is()) {
345 throw css::uno::RuntimeException(
346 "missing path attribute in " + reader.getUrl(),
347 css::uno::Reference< css::uno::XInterface >());
349 OUString path(attrPath.convertFromUtf8());
350 int finalizedLayer;
351 rtl::Reference< Node > node(
352 data_.resolvePathRepresentation(
353 path, 0, &path_, &finalizedLayer));
354 if (!node.is()) {
355 SAL_WARN(
356 "configmgr",
357 "unknown item \"" << path << "\" in \"" << reader.getUrl() << '"');
358 state_.push(State(true)); // ignored
359 return;
361 assert(!path_.empty());
362 componentName_ = path_.front();
363 if (trackPath_) {
364 if (partial_ != 0 && partial_->contains(path_) == Partial::CONTAINS_NOT)
366 state_.push(State(true)); // ignored
367 return;
369 } else {
370 path_.clear();
372 switch (node->kind()) {
373 case Node::KIND_PROPERTY:
374 case Node::KIND_LOCALIZED_VALUE:
375 SAL_WARN(
376 "configmgr",
377 "item of bad type \"" << path << "\" in \"" << reader.getUrl()
378 << '"');
379 state_.push(State(true)); // ignored
380 return;
381 case Node::KIND_LOCALIZED_PROPERTY:
382 valueParser_.type_ = dynamic_cast< LocalizedPropertyNode * >(
383 node.get())->getStaticType();
384 break;
385 default:
386 break;
388 state_.push(State(node, finalizedLayer < valueParser_.getLayer()));
391 void XcuParser::handlePropValue(
392 xmlreader::XmlReader & reader, PropertyNode * prop)
394 bool nil = false;
395 OString separator;
396 OUString external;
397 for (;;) {
398 int attrNsId;
399 xmlreader::Span attrLn;
400 if (!reader.nextAttribute(&attrNsId, &attrLn)) {
401 break;
403 if (attrNsId == ParseManager::NAMESPACE_XSI && attrLn.equals("nil")) {
404 nil = xmldata::parseBoolean(reader.getAttributeValue(true));
405 } else if (attrNsId == ParseManager::NAMESPACE_OOR &&
406 attrLn.equals("type"))
408 Type type = xmldata::parseType(
409 reader, reader.getAttributeValue(true));
410 if (valueParser_.type_ != TYPE_ANY && type != valueParser_.type_) {
411 throw css::uno::RuntimeException(
412 "invalid value type in " + reader.getUrl(),
413 css::uno::Reference< css::uno::XInterface >());
415 valueParser_.type_ = type;
416 } else if (attrNsId == ParseManager::NAMESPACE_OOR &&
417 attrLn.equals("separator"))
419 xmlreader::Span s(reader.getAttributeValue(false));
420 if (s.length == 0) {
421 throw css::uno::RuntimeException(
422 "bad oor:separator attribute in " + reader.getUrl(),
423 css::uno::Reference< css::uno::XInterface >());
425 separator = OString(s.begin, s.length);
426 } else if (attrNsId == ParseManager::NAMESPACE_OOR &&
427 attrLn.equals("external"))
429 external = reader.getAttributeValue(true).convertFromUtf8();
430 if (external.isEmpty()) {
431 throw css::uno::RuntimeException(
432 "bad oor:external attribute value in " + reader.getUrl(),
433 css::uno::Reference< css::uno::XInterface >());
437 if (nil) {
438 if (!prop->isNillable()) {
439 throw css::uno::RuntimeException(
440 "xsi:nil attribute for non-nillable prop in " + reader.getUrl(),
441 css::uno::Reference< css::uno::XInterface >());
443 if (!external.isEmpty()) {
444 throw css::uno::RuntimeException(
445 ("xsi:nil and oor:external attributes for prop in " +
446 reader.getUrl()),
447 css::uno::Reference< css::uno::XInterface >());
449 prop->setValue(valueParser_.getLayer(), css::uno::Any());
450 state_.push(State(false));
451 } else if (external.isEmpty()) {
452 valueParser_.separator_ = separator;
453 valueParser_.start(prop);
454 } else {
455 prop->setExternal(valueParser_.getLayer(), external);
456 state_.push(State(false));
460 void XcuParser::handleLocpropValue(
461 xmlreader::XmlReader & reader, LocalizedPropertyNode * locprop)
463 OUString name;
464 bool nil = false;
465 OString separator;
466 Operation op = OPERATION_FUSE;
467 for (;;) {
468 int attrNsId;
469 xmlreader::Span attrLn;
470 if (!reader.nextAttribute(&attrNsId, &attrLn)) {
471 break;
473 if (attrNsId == xmlreader::XmlReader::NAMESPACE_XML &&
474 attrLn.equals("lang"))
476 name = reader.getAttributeValue(false).convertFromUtf8();
477 } else if (attrNsId == ParseManager::NAMESPACE_XSI &&
478 attrLn.equals("nil"))
480 nil = xmldata::parseBoolean(reader.getAttributeValue(true));
481 } else if (attrNsId == ParseManager::NAMESPACE_OOR &&
482 attrLn.equals("type"))
484 Type type = xmldata::parseType(
485 reader, reader.getAttributeValue(true));
486 if (valueParser_.type_ != TYPE_ANY && type != valueParser_.type_) {
487 throw css::uno::RuntimeException(
488 "invalid value type in " + reader.getUrl(),
489 css::uno::Reference< css::uno::XInterface >());
491 valueParser_.type_ = type;
492 } else if (attrNsId == ParseManager::NAMESPACE_OOR &&
493 attrLn.equals("separator"))
495 xmlreader::Span s(reader.getAttributeValue(false));
496 if (s.length == 0) {
497 throw css::uno::RuntimeException(
498 "bad oor:separator attribute in " + reader.getUrl(),
499 css::uno::Reference< css::uno::XInterface >());
501 separator = OString(s.begin, s.length);
502 } else if (attrNsId == ParseManager::NAMESPACE_OOR &&
503 attrLn.equals("op"))
505 op = parseOperation(reader.getAttributeValue(true));
508 if (trackPath_) {
509 path_.push_back(name);
510 if (partial_ != 0 &&
511 partial_->contains(path_) != Partial::CONTAINS_NODE)
513 state_.push(State(true)); // ignored
514 return;
517 NodeMap & members = locprop->getMembers();
518 NodeMap::iterator i(members.find(name));
519 if (i != members.end() && i->second->getLayer() > valueParser_.getLayer()) {
520 state_.push(State(true)); // ignored
521 return;
523 if (nil && !locprop->isNillable()) {
524 throw css::uno::RuntimeException(
525 "xsi:nil attribute for non-nillable prop in " + reader.getUrl(),
526 css::uno::Reference< css::uno::XInterface >());
528 switch (op) {
529 case OPERATION_FUSE:
531 bool pop = false;
532 if (nil) {
533 if (i == members.end()) {
534 members[name] = new LocalizedValueNode(
535 valueParser_.getLayer(), css::uno::Any());
536 } else {
537 dynamic_cast< LocalizedValueNode * >(
538 i->second.get())->setValue(
539 valueParser_.getLayer(), css::uno::Any());
541 state_.push(State(true));
542 } else {
543 valueParser_.separator_ = separator;
544 valueParser_.start(locprop, name);
545 pop = true;
547 if (trackPath_) {
548 recordModification(false);
549 if (pop) {
550 path_.pop_back();
554 break;
555 case OPERATION_REMOVE:
556 //TODO: only allow if parent.op == OPERATION_FUSE
557 //TODO: disallow removing when e.g. lang=""?
558 if (i != members.end()) {
559 members.erase(i);
561 state_.push(State(true));
562 recordModification(false);
563 break;
564 default:
565 throw css::uno::RuntimeException(
566 "bad op attribute for value element in " + reader.getUrl(),
567 css::uno::Reference< css::uno::XInterface >());
571 void XcuParser::handleGroupProp(
572 xmlreader::XmlReader & reader, GroupNode * group)
574 bool hasName = false;
575 OUString name;
576 Type type = TYPE_ERROR;
577 Operation op = OPERATION_MODIFY;
578 bool finalized = false;
579 for (;;) {
580 int attrNsId;
581 xmlreader::Span attrLn;
582 if (!reader.nextAttribute(&attrNsId, &attrLn)) {
583 break;
585 if (attrNsId == ParseManager::NAMESPACE_OOR && attrLn.equals("name")) {
586 hasName = true;
587 name = reader.getAttributeValue(false).convertFromUtf8();
588 } else if (attrNsId == ParseManager::NAMESPACE_OOR &&
589 attrLn.equals("type"))
591 type = xmldata::parseType(reader, reader.getAttributeValue(true));
592 } else if (attrNsId == ParseManager::NAMESPACE_OOR &&
593 attrLn.equals("op"))
595 op = parseOperation(reader.getAttributeValue(true));
596 } else if (attrNsId == ParseManager::NAMESPACE_OOR &&
597 attrLn.equals("finalized"))
599 finalized = xmldata::parseBoolean(reader.getAttributeValue(true));
602 if (!hasName) {
603 throw css::uno::RuntimeException(
604 "no prop name attribute in " + reader.getUrl(),
605 css::uno::Reference< css::uno::XInterface >());
607 if (trackPath_) {
608 path_.push_back(name);
609 //TODO: This ignores locprop values for which specific include paths
610 // exist (i.e., for which contains(locprop path) = CONTAINS_SUBNODES):
611 if (partial_ != 0 &&
612 partial_->contains(path_) != Partial::CONTAINS_NODE)
614 state_.push(State(true)); // ignored
615 return;
618 NodeMap & members = group->getMembers();
619 NodeMap::iterator i(members.find(name));
620 if (i == members.end()) {
621 handleUnknownGroupProp(reader, group, name, type, op, finalized);
622 } else {
623 switch (i->second->kind()) {
624 case Node::KIND_PROPERTY:
625 handlePlainGroupProp(reader, group, i, name, type, op, finalized);
626 break;
627 case Node::KIND_LOCALIZED_PROPERTY:
628 handleLocalizedGroupProp(
629 reader,
630 dynamic_cast< LocalizedPropertyNode * >(i->second.get()), name,
631 type, op, finalized);
632 break;
633 default:
634 throw css::uno::RuntimeException(
635 "inappropriate prop " + name + " in " + reader.getUrl(),
636 css::uno::Reference< css::uno::XInterface >());
641 void XcuParser::handleUnknownGroupProp(
642 xmlreader::XmlReader const & reader, GroupNode * group,
643 OUString const & name, Type type, Operation operation, bool finalized)
645 switch (operation) {
646 case OPERATION_REPLACE:
647 case OPERATION_FUSE:
648 if (group->isExtensible()) {
649 if (type == TYPE_ERROR) {
650 throw css::uno::RuntimeException(
651 ("missing type attribute for prop " + name + " in " +
652 reader.getUrl()),
653 css::uno::Reference< css::uno::XInterface >());
655 valueParser_.type_ = type;
656 rtl::Reference< Node > prop(
657 new PropertyNode(
658 valueParser_.getLayer(), TYPE_ANY, true, css::uno::Any(),
659 true));
660 if (finalized) {
661 prop->setFinalized(valueParser_.getLayer());
663 state_.push(State(prop, name, state_.top().locked));
664 recordModification(false);
665 break;
667 // fall through
668 default:
669 SAL_WARN(
670 "configmgr",
671 "unknown property \"" << name << "\" in \"" << reader.getUrl()
672 << '"');
673 state_.push(State(true)); // ignored
674 break;
678 void XcuParser::handlePlainGroupProp(
679 xmlreader::XmlReader const & reader, GroupNode * group,
680 NodeMap::iterator const & propertyIndex, OUString const & name,
681 Type type, Operation operation, bool finalized)
683 PropertyNode * property = dynamic_cast< PropertyNode * >(
684 propertyIndex->second.get());
685 if (property->getLayer() > valueParser_.getLayer()) {
686 state_.push(State(true)); // ignored
687 return;
689 int finalizedLayer = std::min(
690 finalized ? valueParser_.getLayer() : Data::NO_LAYER,
691 property->getFinalized());
692 property->setFinalized(finalizedLayer);
693 if (type != TYPE_ERROR && property->getStaticType() != TYPE_ANY &&
694 type != property->getStaticType())
696 throw css::uno::RuntimeException(
697 "invalid type for prop " + name + " in " + reader.getUrl(),
698 css::uno::Reference< css::uno::XInterface >());
700 valueParser_.type_ = type == TYPE_ERROR ? property->getStaticType() : type;
701 switch (operation) {
702 case OPERATION_MODIFY:
703 case OPERATION_REPLACE:
704 case OPERATION_FUSE:
705 state_.push(
706 State(
707 property,
708 (state_.top().locked ||
709 finalizedLayer < valueParser_.getLayer())));
710 recordModification(false);
711 break;
712 case OPERATION_REMOVE:
713 if (!property->isExtension()) {
714 throw css::uno::RuntimeException(
715 ("invalid remove of non-extension prop " + name + " in " +
716 reader.getUrl()),
717 css::uno::Reference< css::uno::XInterface >());
719 group->getMembers().erase(propertyIndex);
720 state_.push(State(true)); // ignore children
721 recordModification(false);
722 break;
726 void XcuParser::handleLocalizedGroupProp(
727 xmlreader::XmlReader const & reader, LocalizedPropertyNode * property,
728 OUString const & name, Type type, Operation operation, bool finalized)
730 if (property->getLayer() > valueParser_.getLayer()) {
731 state_.push(State(true)); // ignored
732 return;
734 int finalizedLayer = std::min(
735 finalized ? valueParser_.getLayer() : Data::NO_LAYER,
736 property->getFinalized());
737 property->setFinalized(finalizedLayer);
738 if (type != TYPE_ERROR && property->getStaticType() != TYPE_ANY &&
739 type != property->getStaticType())
741 throw css::uno::RuntimeException(
742 "invalid type for prop " + name + " in " + reader.getUrl(),
743 css::uno::Reference< css::uno::XInterface >());
745 valueParser_.type_ = type == TYPE_ERROR ? property->getStaticType() : type;
746 switch (operation) {
747 case OPERATION_MODIFY:
748 case OPERATION_FUSE:
749 state_.push(
750 State(
751 property,
752 (state_.top().locked ||
753 finalizedLayer < valueParser_.getLayer())));
754 break;
755 case OPERATION_REPLACE:
757 rtl::Reference< Node > replacement(
758 new LocalizedPropertyNode(
759 valueParser_.getLayer(), property->getStaticType(),
760 property->isNillable()));
761 replacement->setFinalized(property->getFinalized());
762 state_.push(
763 State(
764 replacement, name,
765 (state_.top().locked ||
766 finalizedLayer < valueParser_.getLayer())));
767 recordModification(false);
769 break;
770 case OPERATION_REMOVE:
771 throw css::uno::RuntimeException(
772 ("invalid remove of non-extension prop " + name + " in " +
773 reader.getUrl()),
774 css::uno::Reference< css::uno::XInterface >());
778 void XcuParser::handleGroupNode(
779 xmlreader::XmlReader & reader, rtl::Reference< Node > const & group)
781 bool hasName = false;
782 OUString name;
783 Operation op = OPERATION_MODIFY;
784 bool finalized = false;
785 for (;;) {
786 int attrNsId;
787 xmlreader::Span attrLn;
788 if (!reader.nextAttribute(&attrNsId, &attrLn)) {
789 break;
791 if (attrNsId == ParseManager::NAMESPACE_OOR && attrLn.equals("name")) {
792 hasName = true;
793 name = reader.getAttributeValue(false).convertFromUtf8();
794 } else if (attrNsId == ParseManager::NAMESPACE_OOR &&
795 attrLn.equals("op"))
797 op = parseOperation(reader.getAttributeValue(true));
798 } else if (attrNsId == ParseManager::NAMESPACE_OOR &&
799 attrLn.equals("finalized"))
801 finalized = xmldata::parseBoolean(reader.getAttributeValue(true));
804 if (!hasName) {
805 throw css::uno::RuntimeException(
806 "no node name attribute in " + reader.getUrl(),
807 css::uno::Reference< css::uno::XInterface >());
809 if (trackPath_) {
810 path_.push_back(name);
811 if (partial_ != 0 && partial_->contains(path_) == Partial::CONTAINS_NOT)
813 state_.push(State(true)); // ignored
814 return;
817 rtl::Reference< Node > child(
818 Data::findNode(valueParser_.getLayer(), group->getMembers(), name));
819 if (!child.is()) {
820 SAL_WARN(
821 "configmgr",
822 "unknown node \"" << name << "\" in \"" << reader.getUrl() << '"');
823 state_.push(State(true)); // ignored
824 return;
826 Node::Kind kind = child->kind();
827 if (kind != Node::KIND_GROUP && kind != Node::KIND_SET) {
828 throw css::uno::RuntimeException(
829 ("bad <node> \"" + name + "\" of non group/set kind in " +
830 reader.getUrl()),
831 css::uno::Reference< css::uno::XInterface >());
833 if (op != OPERATION_MODIFY && op != OPERATION_FUSE) {
834 throw css::uno::RuntimeException(
835 "invalid operation on group node in " + reader.getUrl(),
836 css::uno::Reference< css::uno::XInterface >());
838 int finalizedLayer = std::min(
839 finalized ? valueParser_.getLayer() : Data::NO_LAYER,
840 child->getFinalized());
841 child->setFinalized(finalizedLayer);
842 state_.push(
843 State(
844 child,
845 state_.top().locked || finalizedLayer < valueParser_.getLayer()));
848 void XcuParser::handleSetNode(xmlreader::XmlReader & reader, SetNode * set) {
849 bool hasName = false;
850 OUString name;
851 OUString component(componentName_);
852 bool hasNodeType = false;
853 OUString nodeType;
854 Operation op = OPERATION_MODIFY;
855 bool finalized = false;
856 bool mandatory = false;
857 for (;;) {
858 int attrNsId;
859 xmlreader::Span attrLn;
860 if (!reader.nextAttribute(&attrNsId, &attrLn)) {
861 break;
863 if (attrNsId == ParseManager::NAMESPACE_OOR && attrLn.equals("name")) {
864 hasName = true;
865 name = reader.getAttributeValue(false).convertFromUtf8();
866 } else if (attrNsId == ParseManager::NAMESPACE_OOR &&
867 attrLn.equals("component"))
869 component = reader.getAttributeValue(false).convertFromUtf8();
870 } else if (attrNsId == ParseManager::NAMESPACE_OOR &&
871 attrLn.equals("node-type"))
873 hasNodeType = true;
874 nodeType = reader.getAttributeValue(false).convertFromUtf8();
875 } else if (attrNsId == ParseManager::NAMESPACE_OOR &&
876 attrLn.equals("op"))
878 op = parseOperation(reader.getAttributeValue(true));
879 } else if (attrNsId == ParseManager::NAMESPACE_OOR &&
880 attrLn.equals("finalized"))
882 finalized = xmldata::parseBoolean(reader.getAttributeValue(true));
883 } else if (attrNsId == ParseManager::NAMESPACE_OOR &&
884 attrLn.equals("mandatory"))
886 mandatory = xmldata::parseBoolean(reader.getAttributeValue(true));
889 if (!hasName) {
890 throw css::uno::RuntimeException(
891 "no node name attribute in " + reader.getUrl(),
892 css::uno::Reference< css::uno::XInterface >());
894 if (trackPath_) {
895 path_.push_back(name);
896 if (partial_ != 0 && partial_->contains(path_) == Partial::CONTAINS_NOT)
898 state_.push(State(true)); // ignored
899 return;
902 OUString templateName(
903 xmldata::parseTemplateReference(
904 component, hasNodeType, nodeType, &set->getDefaultTemplateName()));
905 if (!set->isValidTemplate(templateName)) {
906 throw css::uno::RuntimeException(
907 ("set member node " + name + " references invalid template " +
908 templateName + " in " + reader.getUrl()),
909 css::uno::Reference< css::uno::XInterface >());
911 rtl::Reference< Node > tmpl(
912 data_.getTemplate(valueParser_.getLayer(), templateName));
913 if (!tmpl.is()) {
914 throw css::uno::RuntimeException(
915 ("set member node " + name + " references undefined template " +
916 templateName + " in " + reader.getUrl()),
917 css::uno::Reference< css::uno::XInterface >());
919 int finalizedLayer = finalized ? valueParser_.getLayer() : Data::NO_LAYER;
920 int mandatoryLayer = mandatory ? valueParser_.getLayer() : Data::NO_LAYER;
921 NodeMap & members = set->getMembers();
922 NodeMap::iterator i(members.find(name));
923 if (i != members.end()) {
924 finalizedLayer = std::min(finalizedLayer, i->second->getFinalized());
925 i->second->setFinalized(finalizedLayer);
926 mandatoryLayer = std::min(mandatoryLayer, i->second->getMandatory());
927 i->second->setMandatory(mandatoryLayer);
928 if (i->second->getLayer() > valueParser_.getLayer()) {
929 state_.push(State(true)); // ignored
930 return;
933 switch (op) {
934 case OPERATION_MODIFY:
935 if (i == members.end()) {
936 SAL_WARN(
937 "configmgr",
938 "ignoring modify of unknown set member node \"" << name
939 << "\" in \"" << reader.getUrl() << '"');
940 state_.push(State(true)); // ignored
941 } else {
942 state_.push(
943 State(
944 i->second,
945 (state_.top().locked ||
946 finalizedLayer < valueParser_.getLayer())));
948 break;
949 case OPERATION_REPLACE:
950 if (state_.top().locked || finalizedLayer < valueParser_.getLayer()) {
951 state_.push(State(true)); // ignored
952 } else {
953 rtl::Reference< Node > member(tmpl->clone(true));
954 member->setLayer(valueParser_.getLayer());
955 member->setFinalized(finalizedLayer);
956 member->setMandatory(mandatoryLayer);
957 state_.push(State(member, name, false));
958 recordModification(i == members.end());
960 break;
961 case OPERATION_FUSE:
962 if (i == members.end()) {
963 if (state_.top().locked || finalizedLayer < valueParser_.getLayer())
965 state_.push(State(true)); // ignored
966 } else {
967 rtl::Reference< Node > member(tmpl->clone(true));
968 member->setLayer(valueParser_.getLayer());
969 member->setFinalized(finalizedLayer);
970 member->setMandatory(mandatoryLayer);
971 state_.push(State(member, name, false));
972 recordModification(true);
974 } else {
975 state_.push(
976 State(
977 i->second,
978 (state_.top().locked ||
979 finalizedLayer < valueParser_.getLayer())));
981 break;
982 case OPERATION_REMOVE:
984 // Ignore removal of unknown members, members finalized in a lower
985 // layer, and members made mandatory in this or a lower layer;
986 // forget about user-layer removals that no longer remove anything
987 // (so that paired additions/removals in the user layer do not grow
988 // registrymodifications.xcu unbounded):
989 bool known = i != members.end();
990 if (known && !state_.top().locked &&
991 finalizedLayer >= valueParser_.getLayer() &&
992 (mandatoryLayer == Data::NO_LAYER ||
993 mandatoryLayer > valueParser_.getLayer()))
995 members.erase(i);
997 state_.push(State(true));
998 if (known) {
999 recordModification(false);
1001 break;
1006 void XcuParser::recordModification(bool addition) {
1007 if (broadcastModifications_ != 0) {
1008 broadcastModifications_->add(path_);
1010 if (addition && additions_ != 0) {
1011 additions_->push_back(path_);
1013 if (recordModifications_) {
1014 data_.modifications.add(path_);
1020 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */