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/RuntimeException.hpp>
28 #include <rtl/ref.hxx>
29 #include <rtl/strbuf.hxx>
30 #include <rtl/string.hxx>
31 #include <rtl/ustring.hxx>
32 #include <sal/log.hxx>
33 #include <xmlreader/span.hxx>
34 #include <xmlreader/xmlreader.hxx>
37 #include "localizedpropertynode.hxx"
38 #include "localizedvaluenode.hxx"
39 #include "groupnode.hxx"
40 #include "modifications.hxx"
42 #include "nodemap.hxx"
43 #include "parsemanager.hxx"
44 #include "partial.hxx"
45 #include "propertynode.hxx"
46 #include "setnode.hxx"
47 #include "xcuparser.hxx"
48 #include "xmldata.hxx"
53 int layer
, Data
& data
, Partial
const * partial
,
54 Modifications
* broadcastModifications
, Additions
* additions
):
55 valueParser_(layer
), data_(data
),
56 partial_(partial
), broadcastModifications_(broadcastModifications
),
57 additions_(additions
), recordModifications_(layer
== Data::NO_LAYER
),
59 partial_
!= nullptr || broadcastModifications_
!= nullptr || additions_
!= nullptr ||
63 XcuParser::~XcuParser() {}
65 xmlreader::XmlReader::Text
XcuParser::getTextMode() {
66 return valueParser_
.getTextMode();
69 bool XcuParser::startElement(
70 xmlreader::XmlReader
& reader
, int nsId
, xmlreader::Span
const & name
,
71 std::set
< OUString
> const * /*existingDependencies*/)
73 if (valueParser_
.startElement(reader
, nsId
, name
)) {
77 if (nsId
== ParseManager::NAMESPACE_OOR
&&
78 name
== "component-data")
80 handleComponentData(reader
);
81 } else if (nsId
== ParseManager::NAMESPACE_OOR
&& name
== "items")
83 state_
.push(State::Modify(rtl::Reference
< Node
>()));
85 throw css::uno::RuntimeException(
86 "bad root element <" + name
.convertFromUtf8() + "> in " +
89 } else if (state_
.top().ignore
) {
90 state_
.push(State::Ignore(false));
91 } else if (!state_
.top().node
.is()) {
92 if (nsId
!= xmlreader::XmlReader::NAMESPACE_NONE
|| name
!= "item")
94 throw css::uno::RuntimeException(
95 "bad items node member <" + name
.convertFromUtf8() + "> in " +
100 switch (state_
.top().node
->kind()) {
101 case Node::KIND_PROPERTY
:
102 if (nsId
!= xmlreader::XmlReader::NAMESPACE_NONE
||
105 throw css::uno::RuntimeException(
106 "bad property node member <" + name
.convertFromUtf8() +
107 "> in " + reader
.getUrl());
111 static_cast< PropertyNode
* >(state_
.top().node
.get()));
113 case Node::KIND_LOCALIZED_PROPERTY
:
114 if (nsId
!= xmlreader::XmlReader::NAMESPACE_NONE
||
117 throw css::uno::RuntimeException(
118 "bad localized property node member <" +
119 name
.convertFromUtf8() + "> in " + reader
.getUrl());
123 static_cast< LocalizedPropertyNode
* >(
124 state_
.top().node
.get()));
126 case Node::KIND_LOCALIZED_VALUE
:
127 throw css::uno::RuntimeException(
128 "bad member <" + name
.convertFromUtf8() + "> in " +
130 case Node::KIND_GROUP
:
131 if (nsId
== xmlreader::XmlReader::NAMESPACE_NONE
&&
136 static_cast< GroupNode
* >(state_
.top().node
.get()));
137 } else if (nsId
== xmlreader::XmlReader::NAMESPACE_NONE
&&
140 handleGroupNode(reader
, state_
.top().node
);
142 throw css::uno::RuntimeException(
143 "bad group node member <" + name
.convertFromUtf8() +
144 "> in " + reader
.getUrl());
148 if (nsId
== xmlreader::XmlReader::NAMESPACE_NONE
&&
152 reader
, static_cast< SetNode
* >(state_
.top().node
.get()));
153 } else if (nsId
== xmlreader::XmlReader::NAMESPACE_NONE
&&
158 "bad set node <prop> member in \"" << reader
.getUrl()
160 state_
.push(State::Ignore(false));
162 throw css::uno::RuntimeException(
163 "bad set node member <" + name
.convertFromUtf8() +
164 "> in " + reader
.getUrl());
167 case Node::KIND_ROOT
:
168 assert(false); // this cannot happen
175 void XcuParser::endElement(xmlreader::XmlReader
const &) {
176 if (valueParser_
.endElement()) {
179 assert(!state_
.empty());
180 bool pop
= state_
.top().pop
;
181 rtl::Reference
< Node
> insert
;
183 if (state_
.top().insert
) {
184 insert
= state_
.top().node
;
186 name
= state_
.top().name
;
190 assert(!state_
.empty() && state_
.top().node
.is());
191 state_
.top().node
->getMembers()[name
] = std::move(insert
);
193 if (pop
&& !path_
.empty()) {
195 // </item> will pop less than <item> pushed, but that is harmless,
196 // as the next <item> will reset path_
200 void XcuParser::characters(xmlreader::Span
const & text
) {
201 valueParser_
.characters(text
);
204 XcuParser::Operation
XcuParser::parseOperation(xmlreader::Span
const & text
) {
206 if (text
== "modify") {
207 return OPERATION_MODIFY
;
209 if (text
== "replace") {
210 return OPERATION_REPLACE
;
212 if (text
== "fuse") {
213 return OPERATION_FUSE
;
215 if (text
== "remove") {
216 return OPERATION_REMOVE
;
218 throw css::uno::RuntimeException(
219 "invalid op " + text
.convertFromUtf8());
222 bool XcuParser::isAlreadyFinalized(int finalizedLayer
) const {
223 return finalizedLayer
!= Data::NO_LAYER
&& finalizedLayer
<= valueParser_
.getLayer();
226 void XcuParser::handleComponentData(xmlreader::XmlReader
& reader
) {
227 OStringBuffer
buf(256);
229 bool hasPackage
= false;
230 bool hasName
= false;
231 Operation op
= OPERATION_MODIFY
;
232 bool finalized
= false;
235 xmlreader::Span attrLn
;
236 if (!reader
.nextAttribute(&attrNsId
, &attrLn
)) {
239 if (attrNsId
== ParseManager::NAMESPACE_OOR
&& attrLn
== "package")
242 throw css::uno::RuntimeException(
243 "multiple component-update package attributes in " +
247 xmlreader::Span
s(reader
.getAttributeValue(false));
248 buf
.insert(0, s
.begin
, s
.length
);
249 } else if (attrNsId
== ParseManager::NAMESPACE_OOR
&&
253 throw css::uno::RuntimeException(
254 "multiple component-update name attributes in " +
258 xmlreader::Span
s(reader
.getAttributeValue(false));
259 buf
.append(s
.begin
, s
.length
);
260 } else if (attrNsId
== ParseManager::NAMESPACE_OOR
&&
263 op
= parseOperation(reader
.getAttributeValue(true));
264 } else if (attrNsId
== ParseManager::NAMESPACE_OOR
&&
265 attrLn
== "finalized")
267 finalized
= xmldata::parseBoolean(reader
.getAttributeValue(true));
271 throw css::uno::RuntimeException(
272 "no component-data package attribute in " + reader
.getUrl());
275 throw css::uno::RuntimeException(
276 "no component-data name attribute in " + reader
.getUrl());
278 componentName_
= xmlreader::Span(buf
.getStr(), buf
.getLength()).
281 assert(path_
.empty());
282 path_
.push_back(componentName_
);
283 if (partial_
!= nullptr && partial_
->contains(path_
) == Partial::CONTAINS_NOT
)
285 state_
.push(State::Ignore(true));
289 rtl::Reference
< Node
> node(
290 data_
.getComponents().findNode(valueParser_
.getLayer(),
295 "unknown component \"" << componentName_
<< "\" in \""
296 << reader
.getUrl() << '"');
297 state_
.push(State::Ignore(true));
301 case OPERATION_MODIFY
:
305 throw css::uno::RuntimeException(
306 "invalid operation on root node in " + reader
.getUrl());
308 if (isAlreadyFinalized(node
->getFinalized())) {
309 state_
.push(State::Ignore(true));
313 node
->setFinalized(valueParser_
.getLayer());
315 state_
.push(State::Modify(node
));
318 void XcuParser::handleItem(xmlreader::XmlReader
& reader
) {
319 xmlreader::Span attrPath
;
322 xmlreader::Span attrLn
;
323 if (!reader
.nextAttribute(&attrNsId
, &attrLn
)) {
326 if (attrNsId
== ParseManager::NAMESPACE_OOR
&& attrLn
== "path") {
327 attrPath
= reader
.getAttributeValue(false);
330 if (!attrPath
.is()) {
331 throw css::uno::RuntimeException(
332 "missing path attribute in " + reader
.getUrl());
334 OUString
path(attrPath
.convertFromUtf8());
336 rtl::Reference
< Node
> node(
337 data_
.resolvePathRepresentation(
338 path
, nullptr, &path_
, &finalizedLayer
));
342 "unknown item \"" << path
<< "\" in \"" << reader
.getUrl() << '"');
343 state_
.push(State::Ignore(true));
346 assert(!path_
.empty());
347 componentName_
= path_
.front();
349 if (partial_
!= nullptr && partial_
->contains(path_
) == Partial::CONTAINS_NOT
)
351 state_
.push(State::Ignore(true));
357 switch (node
->kind()) {
358 case Node::KIND_PROPERTY
:
359 case Node::KIND_LOCALIZED_VALUE
:
362 "item of bad type \"" << path
<< "\" in \"" << reader
.getUrl()
364 state_
.push(State::Ignore(true));
366 case Node::KIND_LOCALIZED_PROPERTY
:
367 valueParser_
.type_
= static_cast< LocalizedPropertyNode
* >(
368 node
.get())->getStaticType();
373 if (isAlreadyFinalized(finalizedLayer
)) {
374 state_
.push(State::Ignore(true));
377 state_
.push(State::Modify(node
));
380 void XcuParser::handlePropValue(
381 xmlreader::XmlReader
& reader
, PropertyNode
* prop
)
388 xmlreader::Span attrLn
;
389 if (!reader
.nextAttribute(&attrNsId
, &attrLn
)) {
392 if (attrNsId
== ParseManager::NAMESPACE_XSI
&& attrLn
== "nil") {
393 nil
= xmldata::parseBoolean(reader
.getAttributeValue(true));
394 } else if (attrNsId
== ParseManager::NAMESPACE_OOR
&&
397 Type type
= xmldata::parseType(
398 reader
, reader
.getAttributeValue(true));
399 if (valueParser_
.type_
!= TYPE_ANY
&& type
!= valueParser_
.type_
) {
400 throw css::uno::RuntimeException(
401 "invalid value type in " + reader
.getUrl());
403 valueParser_
.type_
= type
;
404 } else if (attrNsId
== ParseManager::NAMESPACE_OOR
&&
405 attrLn
== "separator")
407 xmlreader::Span
s(reader
.getAttributeValue(false));
409 throw css::uno::RuntimeException(
410 "bad oor:separator attribute in " + reader
.getUrl());
412 separator
= OString(s
.begin
, s
.length
);
413 } else if (attrNsId
== ParseManager::NAMESPACE_OOR
&&
414 attrLn
== "external")
416 external
= reader
.getAttributeValue(true).convertFromUtf8();
417 if (external
.isEmpty()) {
418 throw css::uno::RuntimeException(
419 "bad oor:external attribute value in " + reader
.getUrl());
424 if (!prop
->isNillable()) {
425 throw css::uno::RuntimeException(
426 "xsi:nil attribute for non-nillable prop in " + reader
.getUrl());
428 if (!external
.isEmpty()) {
429 throw css::uno::RuntimeException(
430 "xsi:nil and oor:external attributes for prop in " +
433 prop
->setValue(valueParser_
.getLayer(), css::uno::Any(), valueParser_
.getLayer() == Data::NO_LAYER
);
434 state_
.push(State::Ignore(false));
435 } else if (external
.isEmpty()) {
436 valueParser_
.separator_
= separator
;
437 valueParser_
.start(prop
);
439 prop
->setExternal(valueParser_
.getLayer(), external
);
440 state_
.push(State::Ignore(false));
444 void XcuParser::handleLocpropValue(
445 xmlreader::XmlReader
& reader
, LocalizedPropertyNode
* locprop
)
450 Operation op
= OPERATION_FUSE
;
453 xmlreader::Span attrLn
;
454 if (!reader
.nextAttribute(&attrNsId
, &attrLn
)) {
457 if (attrNsId
== xmlreader::XmlReader::NAMESPACE_XML
&&
460 name
= reader
.getAttributeValue(false).convertFromUtf8();
461 } else if (attrNsId
== ParseManager::NAMESPACE_XSI
&&
464 nil
= xmldata::parseBoolean(reader
.getAttributeValue(true));
465 } else if (attrNsId
== ParseManager::NAMESPACE_OOR
&&
468 Type type
= xmldata::parseType(
469 reader
, reader
.getAttributeValue(true));
470 if (valueParser_
.type_
!= TYPE_ANY
&& type
!= valueParser_
.type_
) {
471 throw css::uno::RuntimeException(
472 "invalid value type in " + reader
.getUrl());
474 valueParser_
.type_
= type
;
475 } else if (attrNsId
== ParseManager::NAMESPACE_OOR
&&
476 attrLn
== "separator")
478 xmlreader::Span
s(reader
.getAttributeValue(false));
480 throw css::uno::RuntimeException(
481 "bad oor:separator attribute in " + reader
.getUrl());
483 separator
= OString(s
.begin
, s
.length
);
484 } else if (attrNsId
== ParseManager::NAMESPACE_OOR
&&
487 op
= parseOperation(reader
.getAttributeValue(true));
491 path_
.push_back(name
);
492 if (partial_
!= nullptr &&
493 partial_
->contains(path_
) != Partial::CONTAINS_NODE
)
495 state_
.push(State::Ignore(true));
499 NodeMap
& members
= locprop
->getMembers();
500 NodeMap::iterator
i(members
.find(name
));
501 if (i
!= members
.end() && i
->second
->getLayer() > valueParser_
.getLayer()) {
502 state_
.push(State::Ignore(true));
505 if (nil
&& !locprop
->isNillable()) {
506 throw css::uno::RuntimeException(
507 "xsi:nil attribute for non-nillable prop in " + reader
.getUrl());
514 if (i
== members
.end()) {
515 members
[name
] = new LocalizedValueNode(
516 valueParser_
.getLayer(), css::uno::Any());
518 static_cast< LocalizedValueNode
* >(
519 i
->second
.get())->setValue(
520 valueParser_
.getLayer(), css::uno::Any(), valueParser_
.getLayer() == Data::NO_LAYER
);
522 state_
.push(State::Ignore(true));
524 valueParser_
.separator_
= separator
;
525 valueParser_
.start(locprop
, name
);
529 recordModification(false);
536 case OPERATION_REMOVE
:
537 //TODO: only allow if parent.op == OPERATION_FUSE
538 //TODO: disallow removing when e.g. lang=""?
539 if (i
!= members
.end()) {
542 state_
.push(State::Ignore(true));
543 recordModification(false);
546 throw css::uno::RuntimeException(
547 "bad op attribute for value element in " + reader
.getUrl());
551 void XcuParser::handleGroupProp(
552 xmlreader::XmlReader
& reader
, GroupNode
* group
)
554 bool hasName
= false;
556 Type type
= TYPE_ERROR
;
557 Operation op
= OPERATION_MODIFY
;
558 bool finalized
= false;
561 xmlreader::Span attrLn
;
562 if (!reader
.nextAttribute(&attrNsId
, &attrLn
)) {
565 if (attrNsId
== ParseManager::NAMESPACE_OOR
&& attrLn
== "name") {
567 name
= reader
.getAttributeValue(false).convertFromUtf8();
568 } else if (attrNsId
== ParseManager::NAMESPACE_OOR
&&
571 type
= xmldata::parseType(reader
, reader
.getAttributeValue(true));
572 } else if (attrNsId
== ParseManager::NAMESPACE_OOR
&&
575 op
= parseOperation(reader
.getAttributeValue(true));
576 } else if (attrNsId
== ParseManager::NAMESPACE_OOR
&&
577 attrLn
== "finalized")
579 finalized
= xmldata::parseBoolean(reader
.getAttributeValue(true));
583 throw css::uno::RuntimeException(
584 "no prop name attribute in " + reader
.getUrl());
587 path_
.push_back(name
);
588 //TODO: This ignores locprop values for which specific include paths
589 // exist (i.e., for which contains(locprop path) = CONTAINS_SUBNODES):
590 if (partial_
!= nullptr &&
591 partial_
->contains(path_
) != Partial::CONTAINS_NODE
)
593 state_
.push(State::Ignore(true));
597 NodeMap
& members
= group
->getMembers();
598 NodeMap::iterator
i(members
.find(name
));
599 if (i
== members
.end()) {
600 handleUnknownGroupProp(reader
, group
, name
, type
, op
, finalized
);
602 switch (i
->second
->kind()) {
603 case Node::KIND_PROPERTY
:
604 handlePlainGroupProp(reader
, group
, i
, name
, type
, op
, finalized
);
606 case Node::KIND_LOCALIZED_PROPERTY
:
607 handleLocalizedGroupProp(
609 static_cast< LocalizedPropertyNode
* >(i
->second
.get()), name
,
610 type
, op
, finalized
);
613 throw css::uno::RuntimeException(
614 "inappropriate prop " + name
+ " in " + reader
.getUrl());
619 void XcuParser::handleUnknownGroupProp(
620 xmlreader::XmlReader
const & reader
, GroupNode
const * group
,
621 OUString
const & name
, Type type
, Operation operation
, bool finalized
)
624 case OPERATION_REPLACE
:
626 if (group
->isExtensible()) {
627 if (type
== TYPE_ERROR
) {
628 throw css::uno::RuntimeException(
629 "missing type attribute for prop " + name
+ " in " +
632 valueParser_
.type_
= type
;
633 rtl::Reference
< Node
> prop(
635 valueParser_
.getLayer(), TYPE_ANY
, true, css::uno::Any(),
638 prop
->setFinalized(valueParser_
.getLayer());
640 state_
.push(State::Insert(prop
, name
));
641 recordModification(false);
648 "unknown property \"" << name
<< "\" in \"" << reader
.getUrl()
650 state_
.push(State::Ignore(true));
655 void XcuParser::handlePlainGroupProp(
656 xmlreader::XmlReader
const & reader
, GroupNode
* group
,
657 NodeMap::iterator
const & propertyIndex
, std::u16string_view name
,
658 Type type
, Operation operation
, bool finalized
)
660 PropertyNode
* property
= static_cast< PropertyNode
* >(
661 propertyIndex
->second
.get());
662 if (property
->getLayer() > valueParser_
.getLayer()) {
663 state_
.push(State::Ignore(true));
666 if (isAlreadyFinalized(property
->getFinalized())) {
667 state_
.push(State::Ignore(true));
671 property
->setFinalized(valueParser_
.getLayer());
673 if (type
!= TYPE_ERROR
&& property
->getStaticType() != TYPE_ANY
&&
674 type
!= property
->getStaticType())
676 throw css::uno::RuntimeException(
677 OUString::Concat("invalid type for prop ") + name
+ " in " + reader
.getUrl());
679 valueParser_
.type_
= type
== TYPE_ERROR
? property
->getStaticType() : type
;
681 case OPERATION_MODIFY
:
682 case OPERATION_REPLACE
:
684 state_
.push(State::Modify(property
));
685 recordModification(false);
687 case OPERATION_REMOVE
:
688 if (!property
->isExtension()) {
689 throw css::uno::RuntimeException(
690 OUString::Concat("invalid remove of non-extension prop ") + name
+ " in " +
693 group
->getMembers().erase(propertyIndex
);
694 state_
.push(State::Ignore(true));
695 recordModification(false);
700 void XcuParser::handleLocalizedGroupProp(
701 xmlreader::XmlReader
const & reader
, LocalizedPropertyNode
* property
,
702 OUString
const & name
, Type type
, Operation operation
, bool finalized
)
704 if (property
->getLayer() > valueParser_
.getLayer()) {
705 state_
.push(State::Ignore(true));
708 if (isAlreadyFinalized(property
->getFinalized())) {
709 state_
.push(State::Ignore(true));
713 property
->setFinalized(valueParser_
.getLayer());
715 if (type
!= TYPE_ERROR
&& property
->getStaticType() != TYPE_ANY
&&
716 type
!= property
->getStaticType())
718 throw css::uno::RuntimeException(
719 "invalid type for prop " + name
+ " in " + reader
.getUrl());
721 valueParser_
.type_
= type
== TYPE_ERROR
? property
->getStaticType() : type
;
723 case OPERATION_MODIFY
:
725 state_
.push(State::Modify(property
));
727 case OPERATION_REPLACE
:
729 rtl::Reference
< Node
> replacement(
730 new LocalizedPropertyNode(
731 valueParser_
.getLayer(), property
->getStaticType(),
732 property
->isNillable()));
733 replacement
->setFinalized(property
->getFinalized());
734 state_
.push(State::Insert(replacement
, name
));
735 recordModification(false);
738 case OPERATION_REMOVE
:
739 throw css::uno::RuntimeException(
740 "invalid remove of non-extension prop " + name
+ " in " +
745 void XcuParser::handleGroupNode(
746 xmlreader::XmlReader
& reader
, rtl::Reference
< Node
> const & group
)
748 bool hasName
= false;
750 Operation op
= OPERATION_MODIFY
;
751 bool finalized
= false;
754 xmlreader::Span attrLn
;
755 if (!reader
.nextAttribute(&attrNsId
, &attrLn
)) {
758 if (attrNsId
== ParseManager::NAMESPACE_OOR
&& attrLn
== "name") {
760 name
= reader
.getAttributeValue(false).convertFromUtf8();
761 } else if (attrNsId
== ParseManager::NAMESPACE_OOR
&&
764 op
= parseOperation(reader
.getAttributeValue(true));
765 } else if (attrNsId
== ParseManager::NAMESPACE_OOR
&&
766 attrLn
== "finalized")
768 finalized
= xmldata::parseBoolean(reader
.getAttributeValue(true));
772 throw css::uno::RuntimeException(
773 "no node name attribute in " + reader
.getUrl());
776 path_
.push_back(name
);
777 if (partial_
!= nullptr && partial_
->contains(path_
) == Partial::CONTAINS_NOT
)
779 state_
.push(State::Ignore(true));
783 rtl::Reference
< Node
> child(
784 group
->getMembers().findNode(valueParser_
.getLayer(), name
));
788 "unknown node \"" << name
<< "\" in \"" << reader
.getUrl() << '"');
789 state_
.push(State::Ignore(true));
792 Node::Kind kind
= child
->kind();
793 if (kind
!= Node::KIND_GROUP
&& kind
!= Node::KIND_SET
) {
794 throw css::uno::RuntimeException(
795 "bad <node> \"" + name
+ "\" of non group/set kind in " +
798 if (op
!= OPERATION_MODIFY
&& op
!= OPERATION_FUSE
) {
799 throw css::uno::RuntimeException(
800 "invalid operation on group node in " + reader
.getUrl());
802 if (isAlreadyFinalized(child
->getFinalized())) {
803 state_
.push(State::Ignore(true));
807 child
->setFinalized(valueParser_
.getLayer());
809 state_
.push(State::Modify(child
));
812 void XcuParser::handleSetNode(xmlreader::XmlReader
& reader
, SetNode
* set
) {
813 bool hasName
= false;
815 OUString
component(componentName_
);
816 bool hasNodeType
= false;
818 Operation op
= OPERATION_MODIFY
;
819 bool finalized
= false;
820 bool mandatory
= false;
823 xmlreader::Span attrLn
;
824 if (!reader
.nextAttribute(&attrNsId
, &attrLn
)) {
827 if (attrNsId
== ParseManager::NAMESPACE_OOR
&& attrLn
== "name") {
829 name
= reader
.getAttributeValue(false).convertFromUtf8();
830 } else if (attrNsId
== ParseManager::NAMESPACE_OOR
&&
831 attrLn
== "component")
833 component
= reader
.getAttributeValue(false).convertFromUtf8();
834 } else if (attrNsId
== ParseManager::NAMESPACE_OOR
&&
835 attrLn
== "node-type")
838 nodeType
= reader
.getAttributeValue(false).convertFromUtf8();
839 } else if (attrNsId
== ParseManager::NAMESPACE_OOR
&&
842 op
= parseOperation(reader
.getAttributeValue(true));
843 } else if (attrNsId
== ParseManager::NAMESPACE_OOR
&&
844 attrLn
== "finalized")
846 finalized
= xmldata::parseBoolean(reader
.getAttributeValue(true));
847 } else if (attrNsId
== ParseManager::NAMESPACE_OOR
&&
848 attrLn
== "mandatory")
850 mandatory
= xmldata::parseBoolean(reader
.getAttributeValue(true));
854 throw css::uno::RuntimeException(
855 "no node name attribute in " + reader
.getUrl());
858 path_
.push_back(name
);
859 if (partial_
!= nullptr && partial_
->contains(path_
) == Partial::CONTAINS_NOT
)
861 state_
.push(State::Ignore(true));
865 OUString
templateName(
866 xmldata::parseTemplateReference(
867 component
, hasNodeType
, nodeType
, &set
->getDefaultTemplateName()));
868 if (!set
->isValidTemplate(templateName
)) {
869 throw css::uno::RuntimeException(
870 "set member node " + name
+ " references invalid template " +
871 templateName
+ " in " + reader
.getUrl());
873 rtl::Reference
< Node
> tmpl(
874 data_
.getTemplate(valueParser_
.getLayer(), templateName
));
876 throw css::uno::RuntimeException(
877 "set member node " + name
+ " references undefined template " +
878 templateName
+ " in " + reader
.getUrl());
880 bool alreadyFinalized
= false;
881 int finalizedLayer
= finalized
? valueParser_
.getLayer() : Data::NO_LAYER
;
882 int mandatoryLayer
= mandatory
? valueParser_
.getLayer() : Data::NO_LAYER
;
883 NodeMap
& members
= set
->getMembers();
884 NodeMap::iterator
i(members
.find(name
));
885 if (i
!= members
.end()) {
886 auto const fin
= i
->second
->getFinalized();
887 alreadyFinalized
= isAlreadyFinalized(fin
);
888 finalizedLayer
= std::min(finalizedLayer
, fin
);
889 i
->second
->setFinalized(finalizedLayer
);
890 mandatoryLayer
= std::min(mandatoryLayer
, i
->second
->getMandatory());
891 i
->second
->setMandatory(mandatoryLayer
);
892 if (i
->second
->getLayer() > valueParser_
.getLayer()) {
893 state_
.push(State::Ignore(true));
897 if (alreadyFinalized
) {
898 state_
.push(State::Ignore(true));
902 case OPERATION_MODIFY
:
903 if (i
== members
.end()) {
906 "ignoring modify of unknown set member node \"" << name
907 << "\" in \"" << reader
.getUrl() << '"');
908 state_
.push(State::Ignore(true));
910 state_
.push(State::Modify(i
->second
));
913 case OPERATION_REPLACE
:
915 rtl::Reference
< Node
> member(tmpl
->clone(true));
916 member
->setLayer(valueParser_
.getLayer());
917 member
->setFinalized(finalizedLayer
);
918 member
->setMandatory(mandatoryLayer
);
919 state_
.push(State::Insert(member
, name
));
920 recordModification(i
== members
.end());
924 if (i
== members
.end()) {
925 rtl::Reference
< Node
> member(tmpl
->clone(true));
926 member
->setLayer(valueParser_
.getLayer());
927 member
->setFinalized(finalizedLayer
);
928 member
->setMandatory(mandatoryLayer
);
929 state_
.push(State::Insert(member
, name
));
930 recordModification(true);
932 state_
.push(State::Modify(i
->second
));
935 case OPERATION_REMOVE
:
937 // Ignore removal of unknown members and members made mandatory in
938 // this or a lower layer; forget about user-layer removals that no
939 // longer remove anything (so that paired additions/removals in the
940 // user layer do not grow registrymodifications.xcu unbounded):
941 bool known
= i
!= members
.end();
943 (mandatoryLayer
== Data::NO_LAYER
||
944 mandatoryLayer
> valueParser_
.getLayer()))
948 state_
.push(State::Ignore(true));
950 recordModification(false);
957 void XcuParser::recordModification(bool addition
) {
958 if (broadcastModifications_
!= nullptr) {
959 broadcastModifications_
->add(path_
);
961 if (addition
&& additions_
!= nullptr) {
962 additions_
->push_back(path_
);
964 if (recordModifications_
) {
965 data_
.modifications
.add(path_
);
971 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */