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
] = 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 void XcuParser::handleComponentData(xmlreader::XmlReader
& reader
) {
223 OStringBuffer
buf(256);
225 bool hasPackage
= false;
226 bool hasName
= false;
227 Operation op
= OPERATION_MODIFY
;
228 bool finalized
= false;
231 xmlreader::Span attrLn
;
232 if (!reader
.nextAttribute(&attrNsId
, &attrLn
)) {
235 if (attrNsId
== ParseManager::NAMESPACE_OOR
&& attrLn
== "package")
238 throw css::uno::RuntimeException(
239 "multiple component-update package attributes in " +
243 xmlreader::Span
s(reader
.getAttributeValue(false));
244 buf
.insert(0, s
.begin
, s
.length
);
245 } else if (attrNsId
== ParseManager::NAMESPACE_OOR
&&
249 throw css::uno::RuntimeException(
250 "multiple component-update name attributes in " +
254 xmlreader::Span
s(reader
.getAttributeValue(false));
255 buf
.append(s
.begin
, s
.length
);
256 } else if (attrNsId
== ParseManager::NAMESPACE_OOR
&&
259 op
= parseOperation(reader
.getAttributeValue(true));
260 } else if (attrNsId
== ParseManager::NAMESPACE_OOR
&&
261 attrLn
== "finalized")
263 finalized
= xmldata::parseBoolean(reader
.getAttributeValue(true));
267 throw css::uno::RuntimeException(
268 "no component-data package attribute in " + reader
.getUrl());
271 throw css::uno::RuntimeException(
272 "no component-data name attribute in " + reader
.getUrl());
274 componentName_
= xmlreader::Span(buf
.getStr(), buf
.getLength()).
277 assert(path_
.empty());
278 path_
.push_back(componentName_
);
279 if (partial_
!= nullptr && partial_
->contains(path_
) == Partial::CONTAINS_NOT
)
281 state_
.push(State::Ignore(true));
285 rtl::Reference
< Node
> node(
286 data_
.getComponents().findNode(valueParser_
.getLayer(),
291 "unknown component \"" << componentName_
<< "\" in \""
292 << reader
.getUrl() << '"');
293 state_
.push(State::Ignore(true));
297 case OPERATION_MODIFY
:
301 throw css::uno::RuntimeException(
302 "invalid operation on root node in " + reader
.getUrl());
304 int finalizedLayer
= std::min(
305 finalized
? valueParser_
.getLayer() : Data::NO_LAYER
,
306 node
->getFinalized());
307 node
->setFinalized(finalizedLayer
);
308 if (finalizedLayer
< valueParser_
.getLayer()) {
309 state_
.push(State::Ignore(true));
312 state_
.push(State::Modify(node
));
315 void XcuParser::handleItem(xmlreader::XmlReader
& reader
) {
316 xmlreader::Span attrPath
;
319 xmlreader::Span attrLn
;
320 if (!reader
.nextAttribute(&attrNsId
, &attrLn
)) {
323 if (attrNsId
== ParseManager::NAMESPACE_OOR
&& attrLn
== "path") {
324 attrPath
= reader
.getAttributeValue(false);
327 if (!attrPath
.is()) {
328 throw css::uno::RuntimeException(
329 "missing path attribute in " + reader
.getUrl());
331 OUString
path(attrPath
.convertFromUtf8());
333 rtl::Reference
< Node
> node(
334 data_
.resolvePathRepresentation(
335 path
, nullptr, &path_
, &finalizedLayer
));
339 "unknown item \"" << path
<< "\" in \"" << reader
.getUrl() << '"');
340 state_
.push(State::Ignore(true));
343 assert(!path_
.empty());
344 componentName_
= path_
.front();
346 if (partial_
!= nullptr && partial_
->contains(path_
) == Partial::CONTAINS_NOT
)
348 state_
.push(State::Ignore(true));
354 switch (node
->kind()) {
355 case Node::KIND_PROPERTY
:
356 case Node::KIND_LOCALIZED_VALUE
:
359 "item of bad type \"" << path
<< "\" in \"" << reader
.getUrl()
361 state_
.push(State::Ignore(true));
363 case Node::KIND_LOCALIZED_PROPERTY
:
364 valueParser_
.type_
= static_cast< LocalizedPropertyNode
* >(
365 node
.get())->getStaticType();
370 if (finalizedLayer
< valueParser_
.getLayer()) {
371 state_
.push(State::Ignore(true));
374 state_
.push(State::Modify(node
));
377 void XcuParser::handlePropValue(
378 xmlreader::XmlReader
& reader
, PropertyNode
* prop
)
385 xmlreader::Span attrLn
;
386 if (!reader
.nextAttribute(&attrNsId
, &attrLn
)) {
389 if (attrNsId
== ParseManager::NAMESPACE_XSI
&& attrLn
== "nil") {
390 nil
= xmldata::parseBoolean(reader
.getAttributeValue(true));
391 } else if (attrNsId
== ParseManager::NAMESPACE_OOR
&&
394 Type type
= xmldata::parseType(
395 reader
, reader
.getAttributeValue(true));
396 if (valueParser_
.type_
!= TYPE_ANY
&& type
!= valueParser_
.type_
) {
397 throw css::uno::RuntimeException(
398 "invalid value type in " + reader
.getUrl());
400 valueParser_
.type_
= type
;
401 } else if (attrNsId
== ParseManager::NAMESPACE_OOR
&&
402 attrLn
== "separator")
404 xmlreader::Span
s(reader
.getAttributeValue(false));
406 throw css::uno::RuntimeException(
407 "bad oor:separator attribute in " + reader
.getUrl());
409 separator
= OString(s
.begin
, s
.length
);
410 } else if (attrNsId
== ParseManager::NAMESPACE_OOR
&&
411 attrLn
== "external")
413 external
= reader
.getAttributeValue(true).convertFromUtf8();
414 if (external
.isEmpty()) {
415 throw css::uno::RuntimeException(
416 "bad oor:external attribute value in " + reader
.getUrl());
421 if (!prop
->isNillable()) {
422 throw css::uno::RuntimeException(
423 "xsi:nil attribute for non-nillable prop in " + reader
.getUrl());
425 if (!external
.isEmpty()) {
426 throw css::uno::RuntimeException(
427 "xsi:nil and oor:external attributes for prop in " +
430 prop
->setValue(valueParser_
.getLayer(), css::uno::Any());
431 state_
.push(State::Ignore(false));
432 } else if (external
.isEmpty()) {
433 valueParser_
.separator_
= separator
;
434 valueParser_
.start(prop
);
436 prop
->setExternal(valueParser_
.getLayer(), external
);
437 state_
.push(State::Ignore(false));
441 void XcuParser::handleLocpropValue(
442 xmlreader::XmlReader
& reader
, LocalizedPropertyNode
* locprop
)
447 Operation op
= OPERATION_FUSE
;
450 xmlreader::Span attrLn
;
451 if (!reader
.nextAttribute(&attrNsId
, &attrLn
)) {
454 if (attrNsId
== xmlreader::XmlReader::NAMESPACE_XML
&&
457 name
= reader
.getAttributeValue(false).convertFromUtf8();
458 } else if (attrNsId
== ParseManager::NAMESPACE_XSI
&&
461 nil
= xmldata::parseBoolean(reader
.getAttributeValue(true));
462 } else if (attrNsId
== ParseManager::NAMESPACE_OOR
&&
465 Type type
= xmldata::parseType(
466 reader
, reader
.getAttributeValue(true));
467 if (valueParser_
.type_
!= TYPE_ANY
&& type
!= valueParser_
.type_
) {
468 throw css::uno::RuntimeException(
469 "invalid value type in " + reader
.getUrl());
471 valueParser_
.type_
= type
;
472 } else if (attrNsId
== ParseManager::NAMESPACE_OOR
&&
473 attrLn
== "separator")
475 xmlreader::Span
s(reader
.getAttributeValue(false));
477 throw css::uno::RuntimeException(
478 "bad oor:separator attribute in " + reader
.getUrl());
480 separator
= OString(s
.begin
, s
.length
);
481 } else if (attrNsId
== ParseManager::NAMESPACE_OOR
&&
484 op
= parseOperation(reader
.getAttributeValue(true));
488 path_
.push_back(name
);
489 if (partial_
!= nullptr &&
490 partial_
->contains(path_
) != Partial::CONTAINS_NODE
)
492 state_
.push(State::Ignore(true));
496 NodeMap
& members
= locprop
->getMembers();
497 NodeMap::iterator
i(members
.find(name
));
498 if (i
!= members
.end() && i
->second
->getLayer() > valueParser_
.getLayer()) {
499 state_
.push(State::Ignore(true));
502 if (nil
&& !locprop
->isNillable()) {
503 throw css::uno::RuntimeException(
504 "xsi:nil attribute for non-nillable prop in " + reader
.getUrl());
511 if (i
== members
.end()) {
512 members
[name
] = new LocalizedValueNode(
513 valueParser_
.getLayer(), css::uno::Any());
515 static_cast< LocalizedValueNode
* >(
516 i
->second
.get())->setValue(
517 valueParser_
.getLayer(), css::uno::Any());
519 state_
.push(State::Ignore(true));
521 valueParser_
.separator_
= separator
;
522 valueParser_
.start(locprop
, name
);
526 recordModification(false);
533 case OPERATION_REMOVE
:
534 //TODO: only allow if parent.op == OPERATION_FUSE
535 //TODO: disallow removing when e.g. lang=""?
536 if (i
!= members
.end()) {
539 state_
.push(State::Ignore(true));
540 recordModification(false);
543 throw css::uno::RuntimeException(
544 "bad op attribute for value element in " + reader
.getUrl());
548 void XcuParser::handleGroupProp(
549 xmlreader::XmlReader
& reader
, GroupNode
* group
)
551 bool hasName
= false;
553 Type type
= TYPE_ERROR
;
554 Operation op
= OPERATION_MODIFY
;
555 bool finalized
= false;
558 xmlreader::Span attrLn
;
559 if (!reader
.nextAttribute(&attrNsId
, &attrLn
)) {
562 if (attrNsId
== ParseManager::NAMESPACE_OOR
&& attrLn
== "name") {
564 name
= reader
.getAttributeValue(false).convertFromUtf8();
565 } else if (attrNsId
== ParseManager::NAMESPACE_OOR
&&
568 type
= xmldata::parseType(reader
, reader
.getAttributeValue(true));
569 } else if (attrNsId
== ParseManager::NAMESPACE_OOR
&&
572 op
= parseOperation(reader
.getAttributeValue(true));
573 } else if (attrNsId
== ParseManager::NAMESPACE_OOR
&&
574 attrLn
== "finalized")
576 finalized
= xmldata::parseBoolean(reader
.getAttributeValue(true));
580 throw css::uno::RuntimeException(
581 "no prop name attribute in " + reader
.getUrl());
584 path_
.push_back(name
);
585 //TODO: This ignores locprop values for which specific include paths
586 // exist (i.e., for which contains(locprop path) = CONTAINS_SUBNODES):
587 if (partial_
!= nullptr &&
588 partial_
->contains(path_
) != Partial::CONTAINS_NODE
)
590 state_
.push(State::Ignore(true));
594 NodeMap
& members
= group
->getMembers();
595 NodeMap::iterator
i(members
.find(name
));
596 if (i
== members
.end()) {
597 handleUnknownGroupProp(reader
, group
, name
, type
, op
, finalized
);
599 switch (i
->second
->kind()) {
600 case Node::KIND_PROPERTY
:
601 handlePlainGroupProp(reader
, group
, i
, name
, type
, op
, finalized
);
603 case Node::KIND_LOCALIZED_PROPERTY
:
604 handleLocalizedGroupProp(
606 static_cast< LocalizedPropertyNode
* >(i
->second
.get()), name
,
607 type
, op
, finalized
);
610 throw css::uno::RuntimeException(
611 "inappropriate prop " + name
+ " in " + reader
.getUrl());
616 void XcuParser::handleUnknownGroupProp(
617 xmlreader::XmlReader
const & reader
, GroupNode
const * group
,
618 OUString
const & name
, Type type
, Operation operation
, bool finalized
)
621 case OPERATION_REPLACE
:
623 if (group
->isExtensible()) {
624 if (type
== TYPE_ERROR
) {
625 throw css::uno::RuntimeException(
626 "missing type attribute for prop " + name
+ " in " +
629 valueParser_
.type_
= type
;
630 rtl::Reference
< Node
> prop(
632 valueParser_
.getLayer(), TYPE_ANY
, true, css::uno::Any(),
635 prop
->setFinalized(valueParser_
.getLayer());
637 state_
.push(State::Insert(prop
, name
));
638 recordModification(false);
645 "unknown property \"" << name
<< "\" in \"" << reader
.getUrl()
647 state_
.push(State::Ignore(true));
652 void XcuParser::handlePlainGroupProp(
653 xmlreader::XmlReader
const & reader
, GroupNode
* group
,
654 NodeMap::iterator
const & propertyIndex
, std::u16string_view name
,
655 Type type
, Operation operation
, bool finalized
)
657 PropertyNode
* property
= static_cast< PropertyNode
* >(
658 propertyIndex
->second
.get());
659 if (property
->getLayer() > valueParser_
.getLayer()) {
660 state_
.push(State::Ignore(true));
663 int finalizedLayer
= std::min(
664 finalized
? valueParser_
.getLayer() : Data::NO_LAYER
,
665 property
->getFinalized());
666 property
->setFinalized(finalizedLayer
);
667 if (finalizedLayer
< valueParser_
.getLayer()) {
668 state_
.push(State::Ignore(true));
671 if (type
!= TYPE_ERROR
&& property
->getStaticType() != TYPE_ANY
&&
672 type
!= property
->getStaticType())
674 throw css::uno::RuntimeException(
675 OUString::Concat("invalid type for prop ") + name
+ " in " + reader
.getUrl());
677 valueParser_
.type_
= type
== TYPE_ERROR
? property
->getStaticType() : type
;
679 case OPERATION_MODIFY
:
680 case OPERATION_REPLACE
:
682 state_
.push(State::Modify(property
));
683 recordModification(false);
685 case OPERATION_REMOVE
:
686 if (!property
->isExtension()) {
687 throw css::uno::RuntimeException(
688 OUString::Concat("invalid remove of non-extension prop ") + name
+ " in " +
691 group
->getMembers().erase(propertyIndex
);
692 state_
.push(State::Ignore(true));
693 recordModification(false);
698 void XcuParser::handleLocalizedGroupProp(
699 xmlreader::XmlReader
const & reader
, LocalizedPropertyNode
* property
,
700 OUString
const & name
, Type type
, Operation operation
, bool finalized
)
702 if (property
->getLayer() > valueParser_
.getLayer()) {
703 state_
.push(State::Ignore(true));
706 int finalizedLayer
= std::min(
707 finalized
? valueParser_
.getLayer() : Data::NO_LAYER
,
708 property
->getFinalized());
709 property
->setFinalized(finalizedLayer
);
710 if (finalizedLayer
< valueParser_
.getLayer()) {
711 state_
.push(State::Ignore(true));
714 if (type
!= TYPE_ERROR
&& property
->getStaticType() != TYPE_ANY
&&
715 type
!= property
->getStaticType())
717 throw css::uno::RuntimeException(
718 "invalid type for prop " + name
+ " in " + reader
.getUrl());
720 valueParser_
.type_
= type
== TYPE_ERROR
? property
->getStaticType() : type
;
722 case OPERATION_MODIFY
:
724 state_
.push(State::Modify(property
));
726 case OPERATION_REPLACE
:
728 rtl::Reference
< Node
> replacement(
729 new LocalizedPropertyNode(
730 valueParser_
.getLayer(), property
->getStaticType(),
731 property
->isNillable()));
732 replacement
->setFinalized(property
->getFinalized());
733 state_
.push(State::Insert(replacement
, name
));
734 recordModification(false);
737 case OPERATION_REMOVE
:
738 throw css::uno::RuntimeException(
739 "invalid remove of non-extension prop " + name
+ " in " +
744 void XcuParser::handleGroupNode(
745 xmlreader::XmlReader
& reader
, rtl::Reference
< Node
> const & group
)
747 bool hasName
= false;
749 Operation op
= OPERATION_MODIFY
;
750 bool finalized
= false;
753 xmlreader::Span attrLn
;
754 if (!reader
.nextAttribute(&attrNsId
, &attrLn
)) {
757 if (attrNsId
== ParseManager::NAMESPACE_OOR
&& attrLn
== "name") {
759 name
= reader
.getAttributeValue(false).convertFromUtf8();
760 } else if (attrNsId
== ParseManager::NAMESPACE_OOR
&&
763 op
= parseOperation(reader
.getAttributeValue(true));
764 } else if (attrNsId
== ParseManager::NAMESPACE_OOR
&&
765 attrLn
== "finalized")
767 finalized
= xmldata::parseBoolean(reader
.getAttributeValue(true));
771 throw css::uno::RuntimeException(
772 "no node name attribute in " + reader
.getUrl());
775 path_
.push_back(name
);
776 if (partial_
!= nullptr && partial_
->contains(path_
) == Partial::CONTAINS_NOT
)
778 state_
.push(State::Ignore(true));
782 rtl::Reference
< Node
> child(
783 group
->getMembers().findNode(valueParser_
.getLayer(), name
));
787 "unknown node \"" << name
<< "\" in \"" << reader
.getUrl() << '"');
788 state_
.push(State::Ignore(true));
791 Node::Kind kind
= child
->kind();
792 if (kind
!= Node::KIND_GROUP
&& kind
!= Node::KIND_SET
) {
793 throw css::uno::RuntimeException(
794 "bad <node> \"" + name
+ "\" of non group/set kind in " +
797 if (op
!= OPERATION_MODIFY
&& op
!= OPERATION_FUSE
) {
798 throw css::uno::RuntimeException(
799 "invalid operation on group node in " + reader
.getUrl());
801 int finalizedLayer
= std::min(
802 finalized
? valueParser_
.getLayer() : Data::NO_LAYER
,
803 child
->getFinalized());
804 child
->setFinalized(finalizedLayer
);
805 if (finalizedLayer
< valueParser_
.getLayer()) {
806 state_
.push(State::Ignore(true));
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 int finalizedLayer
= finalized
? valueParser_
.getLayer() : Data::NO_LAYER
;
881 int mandatoryLayer
= mandatory
? valueParser_
.getLayer() : Data::NO_LAYER
;
882 NodeMap
& members
= set
->getMembers();
883 NodeMap::iterator
i(members
.find(name
));
884 if (i
!= members
.end()) {
885 finalizedLayer
= std::min(finalizedLayer
, i
->second
->getFinalized());
886 i
->second
->setFinalized(finalizedLayer
);
887 mandatoryLayer
= std::min(mandatoryLayer
, i
->second
->getMandatory());
888 i
->second
->setMandatory(mandatoryLayer
);
889 if (i
->second
->getLayer() > valueParser_
.getLayer()) {
890 state_
.push(State::Ignore(true));
894 if (finalizedLayer
< valueParser_
.getLayer()) {
895 state_
.push(State::Ignore(true));
899 case OPERATION_MODIFY
:
900 if (i
== members
.end()) {
903 "ignoring modify of unknown set member node \"" << name
904 << "\" in \"" << reader
.getUrl() << '"');
905 state_
.push(State::Ignore(true));
907 state_
.push(State::Modify(i
->second
));
910 case OPERATION_REPLACE
:
912 rtl::Reference
< Node
> member(tmpl
->clone(true));
913 member
->setLayer(valueParser_
.getLayer());
914 member
->setFinalized(finalizedLayer
);
915 member
->setMandatory(mandatoryLayer
);
916 state_
.push(State::Insert(member
, name
));
917 recordModification(i
== members
.end());
921 if (i
== members
.end()) {
922 rtl::Reference
< Node
> member(tmpl
->clone(true));
923 member
->setLayer(valueParser_
.getLayer());
924 member
->setFinalized(finalizedLayer
);
925 member
->setMandatory(mandatoryLayer
);
926 state_
.push(State::Insert(member
, name
));
927 recordModification(true);
929 state_
.push(State::Modify(i
->second
));
932 case OPERATION_REMOVE
:
934 // Ignore removal of unknown members and members made mandatory in
935 // this or a lower layer; forget about user-layer removals that no
936 // longer remove anything (so that paired additions/removals in the
937 // user layer do not grow registrymodifications.xcu unbounded):
938 bool known
= i
!= members
.end();
940 (mandatoryLayer
== Data::NO_LAYER
||
941 mandatoryLayer
> valueParser_
.getLayer()))
945 state_
.push(State::Ignore(true));
947 recordModification(false);
954 void XcuParser::recordModification(bool addition
) {
955 if (broadcastModifications_
!= nullptr) {
956 broadcastModifications_
->add(path_
);
958 if (addition
&& additions_
!= nullptr) {
959 additions_
->push_back(path_
);
961 if (recordModifications_
) {
962 data_
.modifications
.add(path_
);
968 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */