1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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"
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"
41 #include "localizedpropertynode.hxx"
42 #include "localizedvaluenode.hxx"
43 #include "groupnode.hxx"
44 #include "modifications.hxx"
46 #include "nodemap.hxx"
47 #include "parsemanager.hxx"
48 #include "partial.hxx"
50 #include "propertynode.hxx"
51 #include "setnode.hxx"
52 #include "xcuparser.hxx"
53 #include "xmldata.hxx"
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
),
64 partial_
!= 0 || broadcastModifications_
!= 0 || additions_
!= 0 ||
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
)) {
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));
90 throw css::uno::RuntimeException(
91 ("bad root element <" + name
.convertFromUtf8() + "> in " +
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"))
102 throw css::uno::RuntimeException(
103 ("bad items node member <" + name
.convertFromUtf8() + "> in " +
105 css::uno::Reference
< css::uno::XInterface
>());
108 switch (state_
.top().node
->kind()) {
109 case Node::KIND_PROPERTY
:
110 if (nsId
== xmlreader::XmlReader::NAMESPACE_NONE
&&
111 name
.equals("value"))
115 dynamic_cast< PropertyNode
* >(state_
.top().node
.get()));
117 throw css::uno::RuntimeException(
118 ("bad property node member <" + name
.convertFromUtf8() +
119 "> in " + reader
.getUrl()),
120 css::uno::Reference
< css::uno::XInterface
>());
123 case Node::KIND_LOCALIZED_PROPERTY
:
124 if (nsId
== xmlreader::XmlReader::NAMESPACE_NONE
&&
125 name
.equals("value"))
129 dynamic_cast< LocalizedPropertyNode
* >(
130 state_
.top().node
.get()));
132 throw css::uno::RuntimeException(
133 ("bad localized property node member <" +
134 name
.convertFromUtf8() + "> in " + reader
.getUrl()),
135 css::uno::Reference
< css::uno::XInterface
>());
138 case Node::KIND_LOCALIZED_VALUE
:
139 throw css::uno::RuntimeException(
140 ("bad member <" + name
.convertFromUtf8() + "> in " +
142 css::uno::Reference
< css::uno::XInterface
>());
143 case Node::KIND_GROUP
:
144 if (nsId
== xmlreader::XmlReader::NAMESPACE_NONE
&&
149 dynamic_cast< GroupNode
* >(state_
.top().node
.get()));
150 } else if (nsId
== xmlreader::XmlReader::NAMESPACE_NONE
&&
153 handleGroupNode(reader
, state_
.top().node
);
155 throw css::uno::RuntimeException(
156 ("bad group node member <" + name
.convertFromUtf8() +
157 "> in " + reader
.getUrl()),
158 css::uno::Reference
< css::uno::XInterface
>());
162 if (nsId
== xmlreader::XmlReader::NAMESPACE_NONE
&&
166 reader
, dynamic_cast< SetNode
* >(state_
.top().node
.get()));
167 } else if (nsId
== xmlreader::XmlReader::NAMESPACE_NONE
&&
172 "bad set node <prop> member in \"" << reader
.getUrl()
174 state_
.push(State(true)); // ignored
176 throw css::uno::RuntimeException(
177 ("bad set node member <" + name
.convertFromUtf8() +
178 "> in " + reader
.getUrl()),
179 css::uno::Reference
< css::uno::XInterface
>());
182 case Node::KIND_ROOT
:
183 assert(false); // this cannot happen
190 void XcuParser::endElement(xmlreader::XmlReader
const &) {
191 if (valueParser_
.endElement()) {
194 assert(!state_
.empty());
195 bool pop
= state_
.top().pop
;
196 rtl::Reference
< Node
> insert
;
198 if (state_
.top().insert
) {
199 insert
= state_
.top().node
;
201 name
= state_
.top().name
;
205 assert(!state_
.empty() && state_
.top().node
.is());
206 state_
.top().node
->getMembers()[name
] = insert
;
208 if (pop
&& !path_
.empty()) {
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
) {
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
) {
241 bool hasPackage
= false;
242 bool hasName
= false;
243 Operation op
= OPERATION_MODIFY
;
244 bool finalized
= false;
247 xmlreader::Span attrLn
;
248 if (!reader
.nextAttribute(&attrNsId
, &attrLn
)) {
251 if (attrNsId
== ParseManager::NAMESPACE_OOR
&& attrLn
.equals("package"))
254 throw css::uno::RuntimeException(
255 ("multiple component-update package attributes in " +
257 css::uno::Reference
< css::uno::XInterface
>());
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"))
266 throw css::uno::RuntimeException(
267 ("multiple component-update name attributes in " +
269 css::uno::Reference
< css::uno::XInterface
>());
272 xmlreader::Span
s(reader
.getAttributeValue(false));
273 buf
.append(s
.begin
, s
.length
);
274 } else if (attrNsId
== ParseManager::NAMESPACE_OOR
&&
277 op
= parseOperation(reader
.getAttributeValue(true));
278 } else if (attrNsId
== ParseManager::NAMESPACE_OOR
&&
279 attrLn
.equals("finalized"))
281 finalized
= xmldata::parseBoolean(reader
.getAttributeValue(true));
285 throw css::uno::RuntimeException(
286 "no component-data package attribute in " + reader
.getUrl(),
287 css::uno::Reference
< css::uno::XInterface
>());
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()).
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
305 rtl::Reference
< Node
> node(
307 valueParser_
.getLayer(), data_
.getComponents(), componentName_
));
311 "unknown component \"" << componentName_
<< "\" in \""
312 << reader
.getUrl() << '"');
313 state_
.push(State(true)); // ignored
317 case OPERATION_MODIFY
:
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
;
336 xmlreader::Span attrLn
;
337 if (!reader
.nextAttribute(&attrNsId
, &attrLn
)) {
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());
351 rtl::Reference
< Node
> node(
352 data_
.resolvePathRepresentation(
353 path
, 0, &path_
, &finalizedLayer
));
357 "unknown item \"" << path
<< "\" in \"" << reader
.getUrl() << '"');
358 state_
.push(State(true)); // ignored
361 assert(!path_
.empty());
362 componentName_
= path_
.front();
364 if (partial_
!= 0 && partial_
->contains(path_
) == Partial::CONTAINS_NOT
)
366 state_
.push(State(true)); // ignored
372 switch (node
->kind()) {
373 case Node::KIND_PROPERTY
:
374 case Node::KIND_LOCALIZED_VALUE
:
377 "item of bad type \"" << path
<< "\" in \"" << reader
.getUrl()
379 state_
.push(State(true)); // ignored
381 case Node::KIND_LOCALIZED_PROPERTY
:
382 valueParser_
.type_
= dynamic_cast< LocalizedPropertyNode
* >(
383 node
.get())->getStaticType();
388 state_
.push(State(node
, finalizedLayer
< valueParser_
.getLayer()));
391 void XcuParser::handlePropValue(
392 xmlreader::XmlReader
& reader
, PropertyNode
* prop
)
399 xmlreader::Span attrLn
;
400 if (!reader
.nextAttribute(&attrNsId
, &attrLn
)) {
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));
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
>());
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 " +
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
);
455 prop
->setExternal(valueParser_
.getLayer(), external
);
456 state_
.push(State(false));
460 void XcuParser::handleLocpropValue(
461 xmlreader::XmlReader
& reader
, LocalizedPropertyNode
* locprop
)
466 Operation op
= OPERATION_FUSE
;
469 xmlreader::Span attrLn
;
470 if (!reader
.nextAttribute(&attrNsId
, &attrLn
)) {
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));
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
&&
505 op
= parseOperation(reader
.getAttributeValue(true));
509 path_
.push_back(name
);
511 partial_
->contains(path_
) != Partial::CONTAINS_NODE
)
513 state_
.push(State(true)); // ignored
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
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
>());
533 if (i
== members
.end()) {
534 members
[name
] = new LocalizedValueNode(
535 valueParser_
.getLayer(), css::uno::Any());
537 dynamic_cast< LocalizedValueNode
* >(
538 i
->second
.get())->setValue(
539 valueParser_
.getLayer(), css::uno::Any());
541 state_
.push(State(true));
543 valueParser_
.separator_
= separator
;
544 valueParser_
.start(locprop
, name
);
548 recordModification(false);
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()) {
561 state_
.push(State(true));
562 recordModification(false);
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;
576 Type type
= TYPE_ERROR
;
577 Operation op
= OPERATION_MODIFY
;
578 bool finalized
= false;
581 xmlreader::Span attrLn
;
582 if (!reader
.nextAttribute(&attrNsId
, &attrLn
)) {
585 if (attrNsId
== ParseManager::NAMESPACE_OOR
&& attrLn
.equals("name")) {
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
&&
595 op
= parseOperation(reader
.getAttributeValue(true));
596 } else if (attrNsId
== ParseManager::NAMESPACE_OOR
&&
597 attrLn
.equals("finalized"))
599 finalized
= xmldata::parseBoolean(reader
.getAttributeValue(true));
603 throw css::uno::RuntimeException(
604 "no prop name attribute in " + reader
.getUrl(),
605 css::uno::Reference
< css::uno::XInterface
>());
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):
612 partial_
->contains(path_
) != Partial::CONTAINS_NODE
)
614 state_
.push(State(true)); // ignored
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
);
623 switch (i
->second
->kind()) {
624 case Node::KIND_PROPERTY
:
625 handlePlainGroupProp(reader
, group
, i
, name
, type
, op
, finalized
);
627 case Node::KIND_LOCALIZED_PROPERTY
:
628 handleLocalizedGroupProp(
630 dynamic_cast< LocalizedPropertyNode
* >(i
->second
.get()), name
,
631 type
, op
, finalized
);
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
)
646 case OPERATION_REPLACE
:
648 if (group
->isExtensible()) {
649 if (type
== TYPE_ERROR
) {
650 throw css::uno::RuntimeException(
651 ("missing type attribute for prop " + name
+ " in " +
653 css::uno::Reference
< css::uno::XInterface
>());
655 valueParser_
.type_
= type
;
656 rtl::Reference
< Node
> prop(
658 valueParser_
.getLayer(), TYPE_ANY
, true, css::uno::Any(),
661 prop
->setFinalized(valueParser_
.getLayer());
663 state_
.push(State(prop
, name
, state_
.top().locked
));
664 recordModification(false);
671 "unknown property \"" << name
<< "\" in \"" << reader
.getUrl()
673 state_
.push(State(true)); // ignored
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
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
;
702 case OPERATION_MODIFY
:
703 case OPERATION_REPLACE
:
708 (state_
.top().locked
||
709 finalizedLayer
< valueParser_
.getLayer())));
710 recordModification(false);
712 case OPERATION_REMOVE
:
713 if (!property
->isExtension()) {
714 throw css::uno::RuntimeException(
715 ("invalid remove of non-extension prop " + name
+ " in " +
717 css::uno::Reference
< css::uno::XInterface
>());
719 group
->getMembers().erase(propertyIndex
);
720 state_
.push(State(true)); // ignore children
721 recordModification(false);
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
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
;
747 case OPERATION_MODIFY
:
752 (state_
.top().locked
||
753 finalizedLayer
< valueParser_
.getLayer())));
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());
765 (state_
.top().locked
||
766 finalizedLayer
< valueParser_
.getLayer())));
767 recordModification(false);
770 case OPERATION_REMOVE
:
771 throw css::uno::RuntimeException(
772 ("invalid remove of non-extension prop " + name
+ " in " +
774 css::uno::Reference
< css::uno::XInterface
>());
778 void XcuParser::handleGroupNode(
779 xmlreader::XmlReader
& reader
, rtl::Reference
< Node
> const & group
)
781 bool hasName
= false;
783 Operation op
= OPERATION_MODIFY
;
784 bool finalized
= false;
787 xmlreader::Span attrLn
;
788 if (!reader
.nextAttribute(&attrNsId
, &attrLn
)) {
791 if (attrNsId
== ParseManager::NAMESPACE_OOR
&& attrLn
.equals("name")) {
793 name
= reader
.getAttributeValue(false).convertFromUtf8();
794 } else if (attrNsId
== ParseManager::NAMESPACE_OOR
&&
797 op
= parseOperation(reader
.getAttributeValue(true));
798 } else if (attrNsId
== ParseManager::NAMESPACE_OOR
&&
799 attrLn
.equals("finalized"))
801 finalized
= xmldata::parseBoolean(reader
.getAttributeValue(true));
805 throw css::uno::RuntimeException(
806 "no node name attribute in " + reader
.getUrl(),
807 css::uno::Reference
< css::uno::XInterface
>());
810 path_
.push_back(name
);
811 if (partial_
!= 0 && partial_
->contains(path_
) == Partial::CONTAINS_NOT
)
813 state_
.push(State(true)); // ignored
817 rtl::Reference
< Node
> child(
818 Data::findNode(valueParser_
.getLayer(), group
->getMembers(), name
));
822 "unknown node \"" << name
<< "\" in \"" << reader
.getUrl() << '"');
823 state_
.push(State(true)); // ignored
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 " +
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
);
845 state_
.top().locked
|| finalizedLayer
< valueParser_
.getLayer()));
848 void XcuParser::handleSetNode(xmlreader::XmlReader
& reader
, SetNode
* set
) {
849 bool hasName
= false;
851 OUString
component(componentName_
);
852 bool hasNodeType
= false;
854 Operation op
= OPERATION_MODIFY
;
855 bool finalized
= false;
856 bool mandatory
= false;
859 xmlreader::Span attrLn
;
860 if (!reader
.nextAttribute(&attrNsId
, &attrLn
)) {
863 if (attrNsId
== ParseManager::NAMESPACE_OOR
&& attrLn
.equals("name")) {
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"))
874 nodeType
= reader
.getAttributeValue(false).convertFromUtf8();
875 } else if (attrNsId
== ParseManager::NAMESPACE_OOR
&&
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));
890 throw css::uno::RuntimeException(
891 "no node name attribute in " + reader
.getUrl(),
892 css::uno::Reference
< css::uno::XInterface
>());
895 path_
.push_back(name
);
896 if (partial_
!= 0 && partial_
->contains(path_
) == Partial::CONTAINS_NOT
)
898 state_
.push(State(true)); // ignored
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
));
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
934 case OPERATION_MODIFY
:
935 if (i
== members
.end()) {
938 "ignoring modify of unknown set member node \"" << name
939 << "\" in \"" << reader
.getUrl() << '"');
940 state_
.push(State(true)); // ignored
945 (state_
.top().locked
||
946 finalizedLayer
< valueParser_
.getLayer())));
949 case OPERATION_REPLACE
:
950 if (state_
.top().locked
|| finalizedLayer
< valueParser_
.getLayer()) {
951 state_
.push(State(true)); // ignored
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());
962 if (i
== members
.end()) {
963 if (state_
.top().locked
|| finalizedLayer
< valueParser_
.getLayer())
965 state_
.push(State(true)); // ignored
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);
978 (state_
.top().locked
||
979 finalizedLayer
< valueParser_
.getLayer())));
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()))
997 state_
.push(State(true));
999 recordModification(false);
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: */