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"
49 #include "propertynode.hxx"
50 #include "setnode.hxx"
51 #include "xcuparser.hxx"
52 #include "xmldata.hxx"
57 int layer
, Data
& data
, Partial
const * partial
,
58 Modifications
* broadcastModifications
, Additions
* additions
):
59 valueParser_(layer
), data_(data
),
60 partial_(partial
), broadcastModifications_(broadcastModifications
),
61 additions_(additions
), recordModifications_(layer
== Data::NO_LAYER
),
63 partial_
!= nullptr || broadcastModifications_
!= nullptr || additions_
!= nullptr ||
67 XcuParser::~XcuParser() {}
69 xmlreader::XmlReader::Text
XcuParser::getTextMode() {
70 return valueParser_
.getTextMode();
73 bool XcuParser::startElement(
74 xmlreader::XmlReader
& reader
, int nsId
, xmlreader::Span
const & name
,
75 std::set
< OUString
> const * /*existingDependencies*/)
77 if (valueParser_
.startElement(reader
, nsId
, name
)) {
81 if (nsId
== ParseManager::NAMESPACE_OOR
&&
82 name
.equals("component-data"))
84 handleComponentData(reader
);
85 } else if (nsId
== ParseManager::NAMESPACE_OOR
&& name
.equals("items"))
87 state_
.push(State::Modify(rtl::Reference
< Node
>()));
89 throw css::uno::RuntimeException(
90 "bad root element <" + name
.convertFromUtf8() + "> in " +
93 } else if (state_
.top().ignore
) {
94 state_
.push(State::Ignore(false));
95 } else if (!state_
.top().node
.is()) {
96 if (nsId
!= xmlreader::XmlReader::NAMESPACE_NONE
|| !name
.equals("item"))
98 throw css::uno::RuntimeException(
99 "bad items node member <" + name
.convertFromUtf8() + "> in " +
104 switch (state_
.top().node
->kind()) {
105 case Node::KIND_PROPERTY
:
106 if (nsId
!= xmlreader::XmlReader::NAMESPACE_NONE
||
107 !name
.equals("value"))
109 throw css::uno::RuntimeException(
110 "bad property node member <" + name
.convertFromUtf8() +
111 "> in " + reader
.getUrl());
115 static_cast< PropertyNode
* >(state_
.top().node
.get()));
117 case Node::KIND_LOCALIZED_PROPERTY
:
118 if (nsId
!= xmlreader::XmlReader::NAMESPACE_NONE
||
119 !name
.equals("value"))
121 throw css::uno::RuntimeException(
122 "bad localized property node member <" +
123 name
.convertFromUtf8() + "> in " + reader
.getUrl());
127 static_cast< LocalizedPropertyNode
* >(
128 state_
.top().node
.get()));
130 case Node::KIND_LOCALIZED_VALUE
:
131 throw css::uno::RuntimeException(
132 "bad member <" + name
.convertFromUtf8() + "> in " +
134 case Node::KIND_GROUP
:
135 if (nsId
== xmlreader::XmlReader::NAMESPACE_NONE
&&
140 static_cast< GroupNode
* >(state_
.top().node
.get()));
141 } else if (nsId
== xmlreader::XmlReader::NAMESPACE_NONE
&&
144 handleGroupNode(reader
, state_
.top().node
);
146 throw css::uno::RuntimeException(
147 "bad group node member <" + name
.convertFromUtf8() +
148 "> in " + reader
.getUrl());
152 if (nsId
== xmlreader::XmlReader::NAMESPACE_NONE
&&
156 reader
, static_cast< SetNode
* >(state_
.top().node
.get()));
157 } else if (nsId
== xmlreader::XmlReader::NAMESPACE_NONE
&&
162 "bad set node <prop> member in \"" << reader
.getUrl()
164 state_
.push(State::Ignore(true));
166 throw css::uno::RuntimeException(
167 "bad set node member <" + name
.convertFromUtf8() +
168 "> in " + reader
.getUrl());
171 case Node::KIND_ROOT
:
172 assert(false); // this cannot happen
179 void XcuParser::endElement(xmlreader::XmlReader
const &) {
180 if (valueParser_
.endElement()) {
183 assert(!state_
.empty());
184 bool pop
= state_
.top().pop
;
185 rtl::Reference
< Node
> insert
;
187 if (state_
.top().insert
) {
188 insert
= state_
.top().node
;
190 name
= state_
.top().name
;
194 assert(!state_
.empty() && state_
.top().node
.is());
195 state_
.top().node
->getMembers()[name
] = insert
;
197 if (pop
&& !path_
.empty()) {
199 // </item> will pop less than <item> pushed, but that is harmless,
200 // as the next <item> will reset path_
204 void XcuParser::characters(xmlreader::Span
const & text
) {
205 valueParser_
.characters(text
);
208 XcuParser::Operation
XcuParser::parseOperation(xmlreader::Span
const & text
) {
210 if (text
.equals("modify")) {
211 return OPERATION_MODIFY
;
213 if (text
.equals("replace")) {
214 return OPERATION_REPLACE
;
216 if (text
.equals("fuse")) {
217 return OPERATION_FUSE
;
219 if (text
.equals("remove")) {
220 return OPERATION_REMOVE
;
222 throw css::uno::RuntimeException(
223 "invalid op " + text
.convertFromUtf8());
226 void XcuParser::handleComponentData(xmlreader::XmlReader
& reader
) {
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
.equals("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
&&
250 attrLn
.equals("name"))
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
.equals("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 int finalizedLayer
= std::min(
309 finalized
? valueParser_
.getLayer() : Data::NO_LAYER
,
310 node
->getFinalized());
311 node
->setFinalized(finalizedLayer
);
312 if (finalizedLayer
< valueParser_
.getLayer()) {
313 state_
.push(State::Ignore(true));
316 state_
.push(State::Modify(node
));
319 void XcuParser::handleItem(xmlreader::XmlReader
& reader
) {
320 xmlreader::Span attrPath
;
323 xmlreader::Span attrLn
;
324 if (!reader
.nextAttribute(&attrNsId
, &attrLn
)) {
327 if (attrNsId
== ParseManager::NAMESPACE_OOR
&& attrLn
.equals("path")) {
328 attrPath
= reader
.getAttributeValue(false);
331 if (!attrPath
.is()) {
332 throw css::uno::RuntimeException(
333 "missing path attribute in " + reader
.getUrl());
335 OUString
path(attrPath
.convertFromUtf8());
337 rtl::Reference
< Node
> node(
338 data_
.resolvePathRepresentation(
339 path
, nullptr, &path_
, &finalizedLayer
));
343 "unknown item \"" << path
<< "\" in \"" << reader
.getUrl() << '"');
344 state_
.push(State::Ignore(true));
347 assert(!path_
.empty());
348 componentName_
= path_
.front();
350 if (partial_
!= nullptr && partial_
->contains(path_
) == Partial::CONTAINS_NOT
)
352 state_
.push(State::Ignore(true));
358 switch (node
->kind()) {
359 case Node::KIND_PROPERTY
:
360 case Node::KIND_LOCALIZED_VALUE
:
363 "item of bad type \"" << path
<< "\" in \"" << reader
.getUrl()
365 state_
.push(State::Ignore(true));
367 case Node::KIND_LOCALIZED_PROPERTY
:
368 valueParser_
.type_
= static_cast< LocalizedPropertyNode
* >(
369 node
.get())->getStaticType();
374 if (finalizedLayer
< valueParser_
.getLayer()) {
375 state_
.push(State::Ignore(true));
378 state_
.push(State::Modify(node
));
381 void XcuParser::handlePropValue(
382 xmlreader::XmlReader
& reader
, PropertyNode
* prop
)
389 xmlreader::Span attrLn
;
390 if (!reader
.nextAttribute(&attrNsId
, &attrLn
)) {
393 if (attrNsId
== ParseManager::NAMESPACE_XSI
&& attrLn
.equals("nil")) {
394 nil
= xmldata::parseBoolean(reader
.getAttributeValue(true));
395 } else if (attrNsId
== ParseManager::NAMESPACE_OOR
&&
396 attrLn
.equals("type"))
398 Type type
= xmldata::parseType(
399 reader
, reader
.getAttributeValue(true));
400 if (valueParser_
.type_
!= TYPE_ANY
&& type
!= valueParser_
.type_
) {
401 throw css::uno::RuntimeException(
402 "invalid value type in " + reader
.getUrl());
404 valueParser_
.type_
= type
;
405 } else if (attrNsId
== ParseManager::NAMESPACE_OOR
&&
406 attrLn
.equals("separator"))
408 xmlreader::Span
s(reader
.getAttributeValue(false));
410 throw css::uno::RuntimeException(
411 "bad oor:separator attribute in " + reader
.getUrl());
413 separator
= OString(s
.begin
, s
.length
);
414 } else if (attrNsId
== ParseManager::NAMESPACE_OOR
&&
415 attrLn
.equals("external"))
417 external
= reader
.getAttributeValue(true).convertFromUtf8();
418 if (external
.isEmpty()) {
419 throw css::uno::RuntimeException(
420 "bad oor:external attribute value in " + reader
.getUrl());
425 if (!prop
->isNillable()) {
426 throw css::uno::RuntimeException(
427 "xsi:nil attribute for non-nillable prop in " + reader
.getUrl());
429 if (!external
.isEmpty()) {
430 throw css::uno::RuntimeException(
431 "xsi:nil and oor:external attributes for prop in " +
434 prop
->setValue(valueParser_
.getLayer(), css::uno::Any());
435 state_
.push(State::Ignore(false));
436 } else if (external
.isEmpty()) {
437 valueParser_
.separator_
= separator
;
438 valueParser_
.start(prop
);
440 prop
->setExternal(valueParser_
.getLayer(), external
);
441 state_
.push(State::Ignore(false));
445 void XcuParser::handleLocpropValue(
446 xmlreader::XmlReader
& reader
, LocalizedPropertyNode
* locprop
)
451 Operation op
= OPERATION_FUSE
;
454 xmlreader::Span attrLn
;
455 if (!reader
.nextAttribute(&attrNsId
, &attrLn
)) {
458 if (attrNsId
== xmlreader::XmlReader::NAMESPACE_XML
&&
459 attrLn
.equals("lang"))
461 name
= reader
.getAttributeValue(false).convertFromUtf8();
462 } else if (attrNsId
== ParseManager::NAMESPACE_XSI
&&
463 attrLn
.equals("nil"))
465 nil
= xmldata::parseBoolean(reader
.getAttributeValue(true));
466 } else if (attrNsId
== ParseManager::NAMESPACE_OOR
&&
467 attrLn
.equals("type"))
469 Type type
= xmldata::parseType(
470 reader
, reader
.getAttributeValue(true));
471 if (valueParser_
.type_
!= TYPE_ANY
&& type
!= valueParser_
.type_
) {
472 throw css::uno::RuntimeException(
473 "invalid value type in " + reader
.getUrl());
475 valueParser_
.type_
= type
;
476 } else if (attrNsId
== ParseManager::NAMESPACE_OOR
&&
477 attrLn
.equals("separator"))
479 xmlreader::Span
s(reader
.getAttributeValue(false));
481 throw css::uno::RuntimeException(
482 "bad oor:separator attribute in " + reader
.getUrl());
484 separator
= OString(s
.begin
, s
.length
);
485 } else if (attrNsId
== ParseManager::NAMESPACE_OOR
&&
488 op
= parseOperation(reader
.getAttributeValue(true));
492 path_
.push_back(name
);
493 if (partial_
!= nullptr &&
494 partial_
->contains(path_
) != Partial::CONTAINS_NODE
)
496 state_
.push(State::Ignore(true));
500 NodeMap
& members
= locprop
->getMembers();
501 NodeMap::iterator
i(members
.find(name
));
502 if (i
!= members
.end() && i
->second
->getLayer() > valueParser_
.getLayer()) {
503 state_
.push(State::Ignore(true));
506 if (nil
&& !locprop
->isNillable()) {
507 throw css::uno::RuntimeException(
508 "xsi:nil attribute for non-nillable prop in " + reader
.getUrl());
515 if (i
== members
.end()) {
516 members
[name
] = new LocalizedValueNode(
517 valueParser_
.getLayer(), css::uno::Any());
519 static_cast< LocalizedValueNode
* >(
520 i
->second
.get())->setValue(
521 valueParser_
.getLayer(), css::uno::Any());
523 state_
.push(State::Ignore(true));
525 valueParser_
.separator_
= separator
;
526 valueParser_
.start(locprop
, name
);
530 recordModification(false);
537 case OPERATION_REMOVE
:
538 //TODO: only allow if parent.op == OPERATION_FUSE
539 //TODO: disallow removing when e.g. lang=""?
540 if (i
!= members
.end()) {
543 state_
.push(State::Ignore(true));
544 recordModification(false);
547 throw css::uno::RuntimeException(
548 "bad op attribute for value element in " + reader
.getUrl());
552 void XcuParser::handleGroupProp(
553 xmlreader::XmlReader
& reader
, GroupNode
* group
)
555 bool hasName
= false;
557 Type type
= TYPE_ERROR
;
558 Operation op
= OPERATION_MODIFY
;
559 bool finalized
= false;
562 xmlreader::Span attrLn
;
563 if (!reader
.nextAttribute(&attrNsId
, &attrLn
)) {
566 if (attrNsId
== ParseManager::NAMESPACE_OOR
&& attrLn
.equals("name")) {
568 name
= reader
.getAttributeValue(false).convertFromUtf8();
569 } else if (attrNsId
== ParseManager::NAMESPACE_OOR
&&
570 attrLn
.equals("type"))
572 type
= xmldata::parseType(reader
, reader
.getAttributeValue(true));
573 } else if (attrNsId
== ParseManager::NAMESPACE_OOR
&&
576 op
= parseOperation(reader
.getAttributeValue(true));
577 } else if (attrNsId
== ParseManager::NAMESPACE_OOR
&&
578 attrLn
.equals("finalized"))
580 finalized
= xmldata::parseBoolean(reader
.getAttributeValue(true));
584 throw css::uno::RuntimeException(
585 "no prop name attribute in " + reader
.getUrl());
588 path_
.push_back(name
);
589 //TODO: This ignores locprop values for which specific include paths
590 // exist (i.e., for which contains(locprop path) = CONTAINS_SUBNODES):
591 if (partial_
!= nullptr &&
592 partial_
->contains(path_
) != Partial::CONTAINS_NODE
)
594 state_
.push(State::Ignore(true));
598 NodeMap
& members
= group
->getMembers();
599 NodeMap::iterator
i(members
.find(name
));
600 if (i
== members
.end()) {
601 handleUnknownGroupProp(reader
, group
, name
, type
, op
, finalized
);
603 switch (i
->second
->kind()) {
604 case Node::KIND_PROPERTY
:
605 handlePlainGroupProp(reader
, group
, i
, name
, type
, op
, finalized
);
607 case Node::KIND_LOCALIZED_PROPERTY
:
608 handleLocalizedGroupProp(
610 static_cast< LocalizedPropertyNode
* >(i
->second
.get()), name
,
611 type
, op
, finalized
);
614 throw css::uno::RuntimeException(
615 "inappropriate prop " + name
+ " in " + reader
.getUrl());
620 void XcuParser::handleUnknownGroupProp(
621 xmlreader::XmlReader
const & reader
, GroupNode
const * group
,
622 OUString
const & name
, Type type
, Operation operation
, bool finalized
)
625 case OPERATION_REPLACE
:
627 if (group
->isExtensible()) {
628 if (type
== TYPE_ERROR
) {
629 throw css::uno::RuntimeException(
630 "missing type attribute for prop " + name
+ " in " +
633 valueParser_
.type_
= type
;
634 rtl::Reference
< Node
> prop(
636 valueParser_
.getLayer(), TYPE_ANY
, true, css::uno::Any(),
639 prop
->setFinalized(valueParser_
.getLayer());
641 state_
.push(State::Insert(prop
, name
));
642 recordModification(false);
649 "unknown property \"" << name
<< "\" in \"" << reader
.getUrl()
651 state_
.push(State::Ignore(true));
656 void XcuParser::handlePlainGroupProp(
657 xmlreader::XmlReader
const & reader
, GroupNode
* group
,
658 NodeMap::iterator
const & propertyIndex
, OUString
const & name
,
659 Type type
, Operation operation
, bool finalized
)
661 PropertyNode
* property
= static_cast< PropertyNode
* >(
662 propertyIndex
->second
.get());
663 if (property
->getLayer() > valueParser_
.getLayer()) {
664 state_
.push(State::Ignore(true));
667 int finalizedLayer
= std::min(
668 finalized
? valueParser_
.getLayer() : Data::NO_LAYER
,
669 property
->getFinalized());
670 property
->setFinalized(finalizedLayer
);
671 if (finalizedLayer
< valueParser_
.getLayer()) {
672 state_
.push(State::Ignore(true));
675 if (type
!= TYPE_ERROR
&& property
->getStaticType() != TYPE_ANY
&&
676 type
!= property
->getStaticType())
678 throw css::uno::RuntimeException(
679 "invalid type for prop " + name
+ " in " + reader
.getUrl());
681 valueParser_
.type_
= type
== TYPE_ERROR
? property
->getStaticType() : type
;
683 case OPERATION_MODIFY
:
684 case OPERATION_REPLACE
:
686 state_
.push(State::Modify(property
));
687 recordModification(false);
689 case OPERATION_REMOVE
:
690 if (!property
->isExtension()) {
691 throw css::uno::RuntimeException(
692 "invalid remove of non-extension prop " + name
+ " in " +
695 group
->getMembers().erase(propertyIndex
);
696 state_
.push(State::Ignore(true));
697 recordModification(false);
702 void XcuParser::handleLocalizedGroupProp(
703 xmlreader::XmlReader
const & reader
, LocalizedPropertyNode
* property
,
704 OUString
const & name
, Type type
, Operation operation
, bool finalized
)
706 if (property
->getLayer() > valueParser_
.getLayer()) {
707 state_
.push(State::Ignore(true));
710 int finalizedLayer
= std::min(
711 finalized
? valueParser_
.getLayer() : Data::NO_LAYER
,
712 property
->getFinalized());
713 property
->setFinalized(finalizedLayer
);
714 if (finalizedLayer
< valueParser_
.getLayer()) {
715 state_
.push(State::Ignore(true));
718 if (type
!= TYPE_ERROR
&& property
->getStaticType() != TYPE_ANY
&&
719 type
!= property
->getStaticType())
721 throw css::uno::RuntimeException(
722 "invalid type for prop " + name
+ " in " + reader
.getUrl());
724 valueParser_
.type_
= type
== TYPE_ERROR
? property
->getStaticType() : type
;
726 case OPERATION_MODIFY
:
728 state_
.push(State::Modify(property
));
730 case OPERATION_REPLACE
:
732 rtl::Reference
< Node
> replacement(
733 new LocalizedPropertyNode(
734 valueParser_
.getLayer(), property
->getStaticType(),
735 property
->isNillable()));
736 replacement
->setFinalized(property
->getFinalized());
737 state_
.push(State::Insert(replacement
, name
));
738 recordModification(false);
741 case OPERATION_REMOVE
:
742 throw css::uno::RuntimeException(
743 "invalid remove of non-extension prop " + name
+ " in " +
748 void XcuParser::handleGroupNode(
749 xmlreader::XmlReader
& reader
, rtl::Reference
< Node
> const & group
)
751 bool hasName
= false;
753 Operation op
= OPERATION_MODIFY
;
754 bool finalized
= false;
757 xmlreader::Span attrLn
;
758 if (!reader
.nextAttribute(&attrNsId
, &attrLn
)) {
761 if (attrNsId
== ParseManager::NAMESPACE_OOR
&& attrLn
.equals("name")) {
763 name
= reader
.getAttributeValue(false).convertFromUtf8();
764 } else if (attrNsId
== ParseManager::NAMESPACE_OOR
&&
767 op
= parseOperation(reader
.getAttributeValue(true));
768 } else if (attrNsId
== ParseManager::NAMESPACE_OOR
&&
769 attrLn
.equals("finalized"))
771 finalized
= xmldata::parseBoolean(reader
.getAttributeValue(true));
775 throw css::uno::RuntimeException(
776 "no node name attribute in " + reader
.getUrl());
779 path_
.push_back(name
);
780 if (partial_
!= nullptr && partial_
->contains(path_
) == Partial::CONTAINS_NOT
)
782 state_
.push(State::Ignore(true));
786 rtl::Reference
< Node
> child(
787 group
->getMembers().findNode(valueParser_
.getLayer(), name
));
791 "unknown node \"" << name
<< "\" in \"" << reader
.getUrl() << '"');
792 state_
.push(State::Ignore(true));
795 Node::Kind kind
= child
->kind();
796 if (kind
!= Node::KIND_GROUP
&& kind
!= Node::KIND_SET
) {
797 throw css::uno::RuntimeException(
798 "bad <node> \"" + name
+ "\" of non group/set kind in " +
801 if (op
!= OPERATION_MODIFY
&& op
!= OPERATION_FUSE
) {
802 throw css::uno::RuntimeException(
803 "invalid operation on group node in " + reader
.getUrl());
805 int finalizedLayer
= std::min(
806 finalized
? valueParser_
.getLayer() : Data::NO_LAYER
,
807 child
->getFinalized());
808 child
->setFinalized(finalizedLayer
);
809 if (finalizedLayer
< valueParser_
.getLayer()) {
810 state_
.push(State::Ignore(true));
813 state_
.push(State::Modify(child
));
816 void XcuParser::handleSetNode(xmlreader::XmlReader
& reader
, SetNode
* set
) {
817 bool hasName
= false;
819 OUString
component(componentName_
);
820 bool hasNodeType
= false;
822 Operation op
= OPERATION_MODIFY
;
823 bool finalized
= false;
824 bool mandatory
= false;
827 xmlreader::Span attrLn
;
828 if (!reader
.nextAttribute(&attrNsId
, &attrLn
)) {
831 if (attrNsId
== ParseManager::NAMESPACE_OOR
&& attrLn
.equals("name")) {
833 name
= reader
.getAttributeValue(false).convertFromUtf8();
834 } else if (attrNsId
== ParseManager::NAMESPACE_OOR
&&
835 attrLn
.equals("component"))
837 component
= reader
.getAttributeValue(false).convertFromUtf8();
838 } else if (attrNsId
== ParseManager::NAMESPACE_OOR
&&
839 attrLn
.equals("node-type"))
842 nodeType
= reader
.getAttributeValue(false).convertFromUtf8();
843 } else if (attrNsId
== ParseManager::NAMESPACE_OOR
&&
846 op
= parseOperation(reader
.getAttributeValue(true));
847 } else if (attrNsId
== ParseManager::NAMESPACE_OOR
&&
848 attrLn
.equals("finalized"))
850 finalized
= xmldata::parseBoolean(reader
.getAttributeValue(true));
851 } else if (attrNsId
== ParseManager::NAMESPACE_OOR
&&
852 attrLn
.equals("mandatory"))
854 mandatory
= xmldata::parseBoolean(reader
.getAttributeValue(true));
858 throw css::uno::RuntimeException(
859 "no node name attribute in " + reader
.getUrl());
862 path_
.push_back(name
);
863 if (partial_
!= nullptr && partial_
->contains(path_
) == Partial::CONTAINS_NOT
)
865 state_
.push(State::Ignore(true));
869 OUString
templateName(
870 xmldata::parseTemplateReference(
871 component
, hasNodeType
, nodeType
, &set
->getDefaultTemplateName()));
872 if (!set
->isValidTemplate(templateName
)) {
873 throw css::uno::RuntimeException(
874 "set member node " + name
+ " references invalid template " +
875 templateName
+ " in " + reader
.getUrl());
877 rtl::Reference
< Node
> tmpl(
878 data_
.getTemplate(valueParser_
.getLayer(), templateName
));
880 throw css::uno::RuntimeException(
881 "set member node " + name
+ " references undefined template " +
882 templateName
+ " in " + reader
.getUrl());
884 int finalizedLayer
= finalized
? valueParser_
.getLayer() : Data::NO_LAYER
;
885 int mandatoryLayer
= mandatory
? valueParser_
.getLayer() : Data::NO_LAYER
;
886 NodeMap
& members
= set
->getMembers();
887 NodeMap::iterator
i(members
.find(name
));
888 if (i
!= members
.end()) {
889 finalizedLayer
= std::min(finalizedLayer
, i
->second
->getFinalized());
890 i
->second
->setFinalized(finalizedLayer
);
891 mandatoryLayer
= std::min(mandatoryLayer
, i
->second
->getMandatory());
892 i
->second
->setMandatory(mandatoryLayer
);
893 if (i
->second
->getLayer() > valueParser_
.getLayer()) {
894 state_
.push(State::Ignore(true));
898 if (finalizedLayer
< valueParser_
.getLayer()) {
899 state_
.push(State::Ignore(true));
903 case OPERATION_MODIFY
:
904 if (i
== members
.end()) {
907 "ignoring modify of unknown set member node \"" << name
908 << "\" in \"" << reader
.getUrl() << '"');
909 state_
.push(State::Ignore(true));
911 state_
.push(State::Modify(i
->second
));
914 case OPERATION_REPLACE
:
916 rtl::Reference
< Node
> member(tmpl
->clone(true));
917 member
->setLayer(valueParser_
.getLayer());
918 member
->setFinalized(finalizedLayer
);
919 member
->setMandatory(mandatoryLayer
);
920 state_
.push(State::Insert(member
, name
));
921 recordModification(i
== members
.end());
925 if (i
== members
.end()) {
926 rtl::Reference
< Node
> member(tmpl
->clone(true));
927 member
->setLayer(valueParser_
.getLayer());
928 member
->setFinalized(finalizedLayer
);
929 member
->setMandatory(mandatoryLayer
);
930 state_
.push(State::Insert(member
, name
));
931 recordModification(true);
933 state_
.push(State::Modify(i
->second
));
936 case OPERATION_REMOVE
:
938 // Ignore removal of unknown members and members made mandatory in
939 // this or a lower layer; forget about user-layer removals that no
940 // longer remove anything (so that paired additions/removals in the
941 // user layer do not grow registrymodifications.xcu unbounded):
942 bool known
= i
!= members
.end();
944 (mandatoryLayer
== Data::NO_LAYER
||
945 mandatoryLayer
> valueParser_
.getLayer()))
949 state_
.push(State::Ignore(true));
951 recordModification(false);
958 void XcuParser::recordModification(bool addition
) {
959 if (broadcastModifications_
!= nullptr) {
960 broadcastModifications_
->add(path_
);
962 if (addition
&& additions_
!= nullptr) {
963 additions_
->push_back(path_
);
965 if (recordModifications_
) {
966 data_
.modifications
.add(path_
);
972 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */