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(RTL_CONSTASCII_STRINGPARAM("component-data")))
85 handleComponentData(reader
);
86 } else if (nsId
== ParseManager::NAMESPACE_OOR
&&
87 name
.equals(RTL_CONSTASCII_STRINGPARAM("items")))
89 state_
.push(State(rtl::Reference
< Node
>(), false));
91 throw css::uno::RuntimeException(
93 RTL_CONSTASCII_USTRINGPARAM("bad root element <")) +
94 name
.convertFromUtf8() +
95 rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("> in ")) +
97 css::uno::Reference
< css::uno::XInterface
>());
99 } else if (state_
.top().ignore
) {
100 state_
.push(State(false));
101 } else if (!state_
.top().node
.is()) {
102 if (nsId
== xmlreader::XmlReader::NAMESPACE_NONE
&&
103 name
.equals(RTL_CONSTASCII_STRINGPARAM("item")))
107 throw css::uno::RuntimeException(
109 RTL_CONSTASCII_USTRINGPARAM("bad items node member <")) +
110 name
.convertFromUtf8() +
111 rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("> in ")) +
113 css::uno::Reference
< css::uno::XInterface
>());
116 switch (state_
.top().node
->kind()) {
117 case Node::KIND_PROPERTY
:
118 if (nsId
== xmlreader::XmlReader::NAMESPACE_NONE
&&
119 name
.equals(RTL_CONSTASCII_STRINGPARAM("value")))
123 dynamic_cast< PropertyNode
* >(state_
.top().node
.get()));
125 throw css::uno::RuntimeException(
127 RTL_CONSTASCII_USTRINGPARAM(
128 "bad property node member <")) +
129 name
.convertFromUtf8() +
130 rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("> in ")) +
132 css::uno::Reference
< css::uno::XInterface
>());
135 case Node::KIND_LOCALIZED_PROPERTY
:
136 if (nsId
== xmlreader::XmlReader::NAMESPACE_NONE
&&
137 name
.equals(RTL_CONSTASCII_STRINGPARAM("value")))
141 dynamic_cast< LocalizedPropertyNode
* >(
142 state_
.top().node
.get()));
144 throw css::uno::RuntimeException(
146 RTL_CONSTASCII_USTRINGPARAM(
147 "bad localized property node member <")) +
148 name
.convertFromUtf8() +
149 rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("> in ")) +
151 css::uno::Reference
< css::uno::XInterface
>());
154 case Node::KIND_LOCALIZED_VALUE
:
155 throw css::uno::RuntimeException(
156 (rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("bad member <")) +
157 name
.convertFromUtf8() +
158 rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("> in ")) +
160 css::uno::Reference
< css::uno::XInterface
>());
161 case Node::KIND_GROUP
:
162 if (nsId
== xmlreader::XmlReader::NAMESPACE_NONE
&&
163 name
.equals(RTL_CONSTASCII_STRINGPARAM("prop")))
167 dynamic_cast< GroupNode
* >(state_
.top().node
.get()));
168 } else if (nsId
== xmlreader::XmlReader::NAMESPACE_NONE
&&
169 name
.equals(RTL_CONSTASCII_STRINGPARAM("node")))
171 handleGroupNode(reader
, state_
.top().node
);
173 throw css::uno::RuntimeException(
175 RTL_CONSTASCII_USTRINGPARAM(
176 "bad group node member <")) +
177 name
.convertFromUtf8() +
178 rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("> in ")) +
180 css::uno::Reference
< css::uno::XInterface
>());
184 if (nsId
== xmlreader::XmlReader::NAMESPACE_NONE
&&
185 name
.equals(RTL_CONSTASCII_STRINGPARAM("node")))
188 reader
, dynamic_cast< SetNode
* >(state_
.top().node
.get()));
189 } else if (nsId
== xmlreader::XmlReader::NAMESPACE_NONE
&&
190 name
.equals(RTL_CONSTASCII_STRINGPARAM("prop")))
194 "bad set node <prop> member in \"" << reader
.getUrl()
196 state_
.push(State(true)); // ignored
198 throw css::uno::RuntimeException(
200 RTL_CONSTASCII_USTRINGPARAM("bad set node member <")) +
201 name
.convertFromUtf8() +
202 rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("> in ")) +
204 css::uno::Reference
< css::uno::XInterface
>());
207 case Node::KIND_ROOT
:
208 assert(false); // this cannot happen
215 void XcuParser::endElement(xmlreader::XmlReader
const &) {
216 if (valueParser_
.endElement()) {
219 assert(!state_
.empty());
220 bool pop
= state_
.top().pop
;
221 rtl::Reference
< Node
> insert
;
223 if (state_
.top().insert
) {
224 insert
= state_
.top().node
;
226 name
= state_
.top().name
;
230 assert(!state_
.empty() && state_
.top().node
.is());
231 state_
.top().node
->getMembers()[name
] = insert
;
233 if (pop
&& !path_
.empty()) {
235 // </item> will pop less than <item> pushed, but that is harmless,
236 // as the next <item> will reset path_
240 void XcuParser::characters(xmlreader::Span
const & text
) {
241 valueParser_
.characters(text
);
244 XcuParser::Operation
XcuParser::parseOperation(xmlreader::Span
const & text
) {
246 if (text
.equals(RTL_CONSTASCII_STRINGPARAM("modify"))) {
247 return OPERATION_MODIFY
;
249 if (text
.equals(RTL_CONSTASCII_STRINGPARAM("replace"))) {
250 return OPERATION_REPLACE
;
252 if (text
.equals(RTL_CONSTASCII_STRINGPARAM("fuse"))) {
253 return OPERATION_FUSE
;
255 if (text
.equals(RTL_CONSTASCII_STRINGPARAM("remove"))) {
256 return OPERATION_REMOVE
;
258 throw css::uno::RuntimeException(
259 (rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("invalid op ")) +
260 text
.convertFromUtf8()),
261 css::uno::Reference
< css::uno::XInterface
>());
264 void XcuParser::handleComponentData(xmlreader::XmlReader
& reader
) {
265 rtl::OStringBuffer buf
;
267 bool hasPackage
= false;
268 bool hasName
= false;
269 Operation op
= OPERATION_MODIFY
;
270 bool finalized
= false;
273 xmlreader::Span attrLn
;
274 if (!reader
.nextAttribute(&attrNsId
, &attrLn
)) {
277 if (attrNsId
== ParseManager::NAMESPACE_OOR
&&
278 attrLn
.equals(RTL_CONSTASCII_STRINGPARAM("package")))
281 throw css::uno::RuntimeException(
283 RTL_CONSTASCII_USTRINGPARAM(
284 "multiple component-update package attributes"
287 css::uno::Reference
< css::uno::XInterface
>());
290 xmlreader::Span
s(reader
.getAttributeValue(false));
291 buf
.insert(0, s
.begin
, s
.length
);
292 } else if (attrNsId
== ParseManager::NAMESPACE_OOR
&&
293 attrLn
.equals(RTL_CONSTASCII_STRINGPARAM("name")))
296 throw css::uno::RuntimeException(
298 RTL_CONSTASCII_USTRINGPARAM(
299 "multiple component-update name attributes in ")) +
301 css::uno::Reference
< css::uno::XInterface
>());
304 xmlreader::Span
s(reader
.getAttributeValue(false));
305 buf
.append(s
.begin
, s
.length
);
306 } else if (attrNsId
== ParseManager::NAMESPACE_OOR
&&
307 attrLn
.equals(RTL_CONSTASCII_STRINGPARAM("op")))
309 op
= parseOperation(reader
.getAttributeValue(true));
310 } else if (attrNsId
== ParseManager::NAMESPACE_OOR
&&
311 attrLn
.equals(RTL_CONSTASCII_STRINGPARAM("finalized")))
313 finalized
= xmldata::parseBoolean(reader
.getAttributeValue(true));
317 throw css::uno::RuntimeException(
319 RTL_CONSTASCII_USTRINGPARAM(
320 "no component-data package attribute in ")) +
322 css::uno::Reference
< css::uno::XInterface
>());
325 throw css::uno::RuntimeException(
327 RTL_CONSTASCII_USTRINGPARAM(
328 "no component-data name attribute in ")) +
330 css::uno::Reference
< css::uno::XInterface
>());
332 componentName_
= xmlreader::Span(buf
.getStr(), buf
.getLength()).
335 assert(path_
.empty());
336 path_
.push_back(componentName_
);
337 if (partial_
!= 0 && partial_
->contains(path_
) == Partial::CONTAINS_NOT
)
339 state_
.push(State(true)); // ignored
343 rtl::Reference
< Node
> node(
345 valueParser_
.getLayer(), data_
.getComponents(), componentName_
));
349 "unknown component \"" << componentName_
<< "\" in \""
350 << reader
.getUrl() << '"');
351 state_
.push(State(true)); // ignored
355 case OPERATION_MODIFY
:
359 throw css::uno::RuntimeException(
361 RTL_CONSTASCII_USTRINGPARAM(
362 "invalid operation on root node in ")) +
364 css::uno::Reference
< css::uno::XInterface
>());
366 int finalizedLayer
= std::min(
367 finalized
? valueParser_
.getLayer() : Data::NO_LAYER
,
368 node
->getFinalized());
369 node
->setFinalized(finalizedLayer
);
370 state_
.push(State(node
, finalizedLayer
< valueParser_
.getLayer()));
373 void XcuParser::handleItem(xmlreader::XmlReader
& reader
) {
374 xmlreader::Span attrPath
;
377 xmlreader::Span attrLn
;
378 if (!reader
.nextAttribute(&attrNsId
, &attrLn
)) {
381 if (attrNsId
== ParseManager::NAMESPACE_OOR
&&
382 attrLn
.equals(RTL_CONSTASCII_STRINGPARAM("path")))
384 attrPath
= reader
.getAttributeValue(false);
387 if (!attrPath
.is()) {
388 throw css::uno::RuntimeException(
390 RTL_CONSTASCII_USTRINGPARAM("missing path attribute in ")) +
392 css::uno::Reference
< css::uno::XInterface
>());
394 rtl::OUString
path(attrPath
.convertFromUtf8());
396 rtl::Reference
< Node
> node(
397 data_
.resolvePathRepresentation(
398 path
, 0, &path_
, &finalizedLayer
));
402 "unknown item \"" << path
<< "\" in \"" << reader
.getUrl() << '"');
403 state_
.push(State(true)); // ignored
406 assert(!path_
.empty());
407 componentName_
= path_
.front();
409 if (partial_
!= 0 && partial_
->contains(path_
) == Partial::CONTAINS_NOT
)
411 state_
.push(State(true)); // ignored
417 switch (node
->kind()) {
418 case Node::KIND_PROPERTY
:
419 case Node::KIND_LOCALIZED_VALUE
:
422 "item of bad type \"" << path
<< "\" in \"" << reader
.getUrl()
424 state_
.push(State(true)); // ignored
426 case Node::KIND_LOCALIZED_PROPERTY
:
427 valueParser_
.type_
= dynamic_cast< LocalizedPropertyNode
* >(
428 node
.get())->getStaticType();
433 state_
.push(State(node
, finalizedLayer
< valueParser_
.getLayer()));
436 void XcuParser::handlePropValue(
437 xmlreader::XmlReader
& reader
, PropertyNode
* prop
)
440 rtl::OString separator
;
441 rtl::OUString external
;
444 xmlreader::Span attrLn
;
445 if (!reader
.nextAttribute(&attrNsId
, &attrLn
)) {
448 if (attrNsId
== ParseManager::NAMESPACE_XSI
&&
449 attrLn
.equals(RTL_CONSTASCII_STRINGPARAM("nil")))
451 nil
= xmldata::parseBoolean(reader
.getAttributeValue(true));
452 } else if (attrNsId
== ParseManager::NAMESPACE_OOR
&&
453 attrLn
.equals(RTL_CONSTASCII_STRINGPARAM("type")))
455 Type type
= xmldata::parseType(
456 reader
, reader
.getAttributeValue(true));
457 if (valueParser_
.type_
!= TYPE_ANY
&& type
!= valueParser_
.type_
) {
458 throw css::uno::RuntimeException(
460 RTL_CONSTASCII_USTRINGPARAM("invalid value type in ")) +
462 css::uno::Reference
< css::uno::XInterface
>());
464 valueParser_
.type_
= type
;
465 } else if (attrNsId
== ParseManager::NAMESPACE_OOR
&&
466 attrLn
.equals(RTL_CONSTASCII_STRINGPARAM("separator")))
468 xmlreader::Span
s(reader
.getAttributeValue(false));
470 throw css::uno::RuntimeException(
472 RTL_CONSTASCII_USTRINGPARAM(
473 "bad oor:separator attribute in ")) +
475 css::uno::Reference
< css::uno::XInterface
>());
477 separator
= rtl::OString(s
.begin
, s
.length
);
478 } else if (attrNsId
== ParseManager::NAMESPACE_OOR
&&
479 attrLn
.equals(RTL_CONSTASCII_STRINGPARAM("external")))
481 external
= reader
.getAttributeValue(true).convertFromUtf8();
482 if (external
.isEmpty()) {
483 throw css::uno::RuntimeException(
485 RTL_CONSTASCII_USTRINGPARAM(
486 "bad oor:external attribute value in ")) +
488 css::uno::Reference
< css::uno::XInterface
>());
493 if (!prop
->isNillable()) {
494 throw css::uno::RuntimeException(
496 RTL_CONSTASCII_USTRINGPARAM(
497 "xsi:nil attribute for non-nillable prop in ")) +
499 css::uno::Reference
< css::uno::XInterface
>());
501 if (!external
.isEmpty()) {
502 throw css::uno::RuntimeException(
504 RTL_CONSTASCII_USTRINGPARAM(
505 "xsi:nil and oor:external attributes for prop in ")) +
507 css::uno::Reference
< css::uno::XInterface
>());
509 prop
->setValue(valueParser_
.getLayer(), css::uno::Any());
510 state_
.push(State(false));
511 } else if (external
.isEmpty()) {
512 valueParser_
.separator_
= separator
;
513 valueParser_
.start(prop
);
515 prop
->setExternal(valueParser_
.getLayer(), external
);
516 state_
.push(State(false));
520 void XcuParser::handleLocpropValue(
521 xmlreader::XmlReader
& reader
, LocalizedPropertyNode
* locprop
)
525 rtl::OString separator
;
526 Operation op
= OPERATION_FUSE
;
529 xmlreader::Span attrLn
;
530 if (!reader
.nextAttribute(&attrNsId
, &attrLn
)) {
533 if (attrNsId
== xmlreader::XmlReader::NAMESPACE_XML
&&
534 attrLn
.equals(RTL_CONSTASCII_STRINGPARAM("lang")))
536 name
= reader
.getAttributeValue(false).convertFromUtf8();
537 } else if (attrNsId
== ParseManager::NAMESPACE_XSI
&&
538 attrLn
.equals(RTL_CONSTASCII_STRINGPARAM("nil")))
540 nil
= xmldata::parseBoolean(reader
.getAttributeValue(true));
541 } else if (attrNsId
== ParseManager::NAMESPACE_OOR
&&
542 attrLn
.equals(RTL_CONSTASCII_STRINGPARAM("type")))
544 Type type
= xmldata::parseType(
545 reader
, reader
.getAttributeValue(true));
546 if (valueParser_
.type_
!= TYPE_ANY
&& type
!= valueParser_
.type_
) {
547 throw css::uno::RuntimeException(
549 RTL_CONSTASCII_USTRINGPARAM("invalid value type in ")) +
551 css::uno::Reference
< css::uno::XInterface
>());
553 valueParser_
.type_
= type
;
554 } else if (attrNsId
== ParseManager::NAMESPACE_OOR
&&
555 attrLn
.equals(RTL_CONSTASCII_STRINGPARAM("separator")))
557 xmlreader::Span
s(reader
.getAttributeValue(false));
559 throw css::uno::RuntimeException(
561 RTL_CONSTASCII_USTRINGPARAM(
562 "bad oor:separator attribute in ")) +
564 css::uno::Reference
< css::uno::XInterface
>());
566 separator
= rtl::OString(s
.begin
, s
.length
);
567 } else if (attrNsId
== ParseManager::NAMESPACE_OOR
&&
568 attrLn
.equals(RTL_CONSTASCII_STRINGPARAM("op")))
570 op
= parseOperation(reader
.getAttributeValue(true));
574 path_
.push_back(name
);
576 partial_
->contains(path_
) != Partial::CONTAINS_NODE
)
578 state_
.push(State(true)); // ignored
582 NodeMap
& members
= locprop
->getMembers();
583 NodeMap::iterator
i(members
.find(name
));
584 if (i
!= members
.end() && i
->second
->getLayer() > valueParser_
.getLayer()) {
585 state_
.push(State(true)); // ignored
588 if (nil
&& !locprop
->isNillable()) {
589 throw css::uno::RuntimeException(
591 RTL_CONSTASCII_USTRINGPARAM(
592 "xsi:nil attribute for non-nillable prop in ")) +
594 css::uno::Reference
< css::uno::XInterface
>());
601 if (i
== members
.end()) {
602 members
[name
] = new LocalizedValueNode(
603 valueParser_
.getLayer(), css::uno::Any());
605 dynamic_cast< LocalizedValueNode
* >(
606 i
->second
.get())->setValue(
607 valueParser_
.getLayer(), css::uno::Any());
609 state_
.push(State(true));
611 valueParser_
.separator_
= separator
;
612 valueParser_
.start(locprop
, name
);
616 recordModification(false);
623 case OPERATION_REMOVE
:
624 //TODO: only allow if parent.op == OPERATION_FUSE
625 //TODO: disallow removing when e.g. lang=""?
626 if (i
!= members
.end()) {
629 state_
.push(State(true));
630 recordModification(false);
633 throw css::uno::RuntimeException(
635 RTL_CONSTASCII_USTRINGPARAM(
636 "bad op attribute for value element in ")) +
638 css::uno::Reference
< css::uno::XInterface
>());
642 void XcuParser::handleGroupProp(
643 xmlreader::XmlReader
& reader
, GroupNode
* group
)
645 bool hasName
= false;
647 Type type
= TYPE_ERROR
;
648 Operation op
= OPERATION_MODIFY
;
649 bool finalized
= false;
652 xmlreader::Span attrLn
;
653 if (!reader
.nextAttribute(&attrNsId
, &attrLn
)) {
656 if (attrNsId
== ParseManager::NAMESPACE_OOR
&&
657 attrLn
.equals(RTL_CONSTASCII_STRINGPARAM("name")))
660 name
= reader
.getAttributeValue(false).convertFromUtf8();
661 } else if (attrNsId
== ParseManager::NAMESPACE_OOR
&&
662 attrLn
.equals(RTL_CONSTASCII_STRINGPARAM("type")))
664 type
= xmldata::parseType(reader
, reader
.getAttributeValue(true));
665 } else if (attrNsId
== ParseManager::NAMESPACE_OOR
&&
666 attrLn
.equals(RTL_CONSTASCII_STRINGPARAM("op")))
668 op
= parseOperation(reader
.getAttributeValue(true));
669 } else if (attrNsId
== ParseManager::NAMESPACE_OOR
&&
670 attrLn
.equals(RTL_CONSTASCII_STRINGPARAM("finalized")))
672 finalized
= xmldata::parseBoolean(reader
.getAttributeValue(true));
676 throw css::uno::RuntimeException(
678 RTL_CONSTASCII_USTRINGPARAM("no prop name attribute in ")) +
680 css::uno::Reference
< css::uno::XInterface
>());
683 path_
.push_back(name
);
684 //TODO: This ignores locprop values for which specific include paths
685 // exist (i.e., for which contains(locprop path) = CONTAINS_SUBNODES):
687 partial_
->contains(path_
) != Partial::CONTAINS_NODE
)
689 state_
.push(State(true)); // ignored
693 NodeMap
& members
= group
->getMembers();
694 NodeMap::iterator
i(members
.find(name
));
695 if (i
== members
.end()) {
696 handleUnknownGroupProp(reader
, group
, name
, type
, op
, finalized
);
698 switch (i
->second
->kind()) {
699 case Node::KIND_PROPERTY
:
700 handlePlainGroupProp(reader
, group
, i
, name
, type
, op
, finalized
);
702 case Node::KIND_LOCALIZED_PROPERTY
:
703 handleLocalizedGroupProp(
705 dynamic_cast< LocalizedPropertyNode
* >(i
->second
.get()), name
,
706 type
, op
, finalized
);
709 throw css::uno::RuntimeException(
711 RTL_CONSTASCII_USTRINGPARAM("inappropriate prop ")) +
712 name
+ rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(" in ")) +
714 css::uno::Reference
< css::uno::XInterface
>());
719 void XcuParser::handleUnknownGroupProp(
720 xmlreader::XmlReader
const & reader
, GroupNode
* group
,
721 rtl::OUString
const & name
, Type type
, Operation operation
, bool finalized
)
724 case OPERATION_REPLACE
:
726 if (group
->isExtensible()) {
727 if (type
== TYPE_ERROR
) {
728 throw css::uno::RuntimeException(
730 RTL_CONSTASCII_USTRINGPARAM(
731 "missing type attribute for prop ")) +
732 name
+ rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(" in ")) +
734 css::uno::Reference
< css::uno::XInterface
>());
736 valueParser_
.type_
= type
;
737 rtl::Reference
< Node
> prop(
739 valueParser_
.getLayer(), TYPE_ANY
, true, css::uno::Any(),
742 prop
->setFinalized(valueParser_
.getLayer());
744 state_
.push(State(prop
, name
, state_
.top().locked
));
745 recordModification(false);
752 "unknown property \"" << name
<< "\" in \"" << reader
.getUrl()
754 state_
.push(State(true)); // ignored
759 void XcuParser::handlePlainGroupProp(
760 xmlreader::XmlReader
const & reader
, GroupNode
* group
,
761 NodeMap::iterator
const & propertyIndex
, rtl::OUString
const & name
,
762 Type type
, Operation operation
, bool finalized
)
764 PropertyNode
* property
= dynamic_cast< PropertyNode
* >(
765 propertyIndex
->second
.get());
766 if (property
->getLayer() > valueParser_
.getLayer()) {
767 state_
.push(State(true)); // ignored
770 int finalizedLayer
= std::min(
771 finalized
? valueParser_
.getLayer() : Data::NO_LAYER
,
772 property
->getFinalized());
773 property
->setFinalized(finalizedLayer
);
774 if (type
!= TYPE_ERROR
&& property
->getStaticType() != TYPE_ANY
&&
775 type
!= property
->getStaticType())
777 throw css::uno::RuntimeException(
779 RTL_CONSTASCII_USTRINGPARAM("invalid type for prop ")) +
780 name
+ rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(" in ")) +
782 css::uno::Reference
< css::uno::XInterface
>());
784 valueParser_
.type_
= type
== TYPE_ERROR
? property
->getStaticType() : type
;
786 case OPERATION_MODIFY
:
787 case OPERATION_REPLACE
:
792 (state_
.top().locked
||
793 finalizedLayer
< valueParser_
.getLayer())));
794 recordModification(false);
796 case OPERATION_REMOVE
:
797 if (!property
->isExtension()) {
798 throw css::uno::RuntimeException(
800 RTL_CONSTASCII_USTRINGPARAM(
801 "invalid remove of non-extension prop ")) +
802 name
+ rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(" in ")) +
804 css::uno::Reference
< css::uno::XInterface
>());
806 group
->getMembers().erase(propertyIndex
);
807 state_
.push(State(true)); // ignore children
808 recordModification(false);
813 void XcuParser::handleLocalizedGroupProp(
814 xmlreader::XmlReader
const & reader
, LocalizedPropertyNode
* property
,
815 rtl::OUString
const & name
, Type type
, Operation operation
, bool finalized
)
817 if (property
->getLayer() > valueParser_
.getLayer()) {
818 state_
.push(State(true)); // ignored
821 int finalizedLayer
= std::min(
822 finalized
? valueParser_
.getLayer() : Data::NO_LAYER
,
823 property
->getFinalized());
824 property
->setFinalized(finalizedLayer
);
825 if (type
!= TYPE_ERROR
&& property
->getStaticType() != TYPE_ANY
&&
826 type
!= property
->getStaticType())
828 throw css::uno::RuntimeException(
830 RTL_CONSTASCII_USTRINGPARAM("invalid type for prop ")) +
831 name
+ rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(" in ")) +
833 css::uno::Reference
< css::uno::XInterface
>());
835 valueParser_
.type_
= type
== TYPE_ERROR
? property
->getStaticType() : type
;
837 case OPERATION_MODIFY
:
842 (state_
.top().locked
||
843 finalizedLayer
< valueParser_
.getLayer())));
845 case OPERATION_REPLACE
:
847 rtl::Reference
< Node
> replacement(
848 new LocalizedPropertyNode(
849 valueParser_
.getLayer(), property
->getStaticType(),
850 property
->isNillable()));
851 replacement
->setFinalized(property
->getFinalized());
855 (state_
.top().locked
||
856 finalizedLayer
< valueParser_
.getLayer())));
857 recordModification(false);
860 case OPERATION_REMOVE
:
861 throw css::uno::RuntimeException(
863 RTL_CONSTASCII_USTRINGPARAM(
864 "invalid remove of non-extension prop ")) +
865 name
+ rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(" in ")) +
867 css::uno::Reference
< css::uno::XInterface
>());
871 void XcuParser::handleGroupNode(
872 xmlreader::XmlReader
& reader
, rtl::Reference
< Node
> const & group
)
874 bool hasName
= false;
876 Operation op
= OPERATION_MODIFY
;
877 bool finalized
= false;
880 xmlreader::Span attrLn
;
881 if (!reader
.nextAttribute(&attrNsId
, &attrLn
)) {
884 if (attrNsId
== ParseManager::NAMESPACE_OOR
&&
885 attrLn
.equals(RTL_CONSTASCII_STRINGPARAM("name")))
888 name
= reader
.getAttributeValue(false).convertFromUtf8();
889 } else if (attrNsId
== ParseManager::NAMESPACE_OOR
&&
890 attrLn
.equals(RTL_CONSTASCII_STRINGPARAM("op")))
892 op
= parseOperation(reader
.getAttributeValue(true));
893 } else if (attrNsId
== ParseManager::NAMESPACE_OOR
&&
894 attrLn
.equals(RTL_CONSTASCII_STRINGPARAM("finalized")))
896 finalized
= xmldata::parseBoolean(reader
.getAttributeValue(true));
900 throw css::uno::RuntimeException(
902 RTL_CONSTASCII_USTRINGPARAM("no node name attribute in ")) +
904 css::uno::Reference
< css::uno::XInterface
>());
907 path_
.push_back(name
);
908 if (partial_
!= 0 && partial_
->contains(path_
) == Partial::CONTAINS_NOT
)
910 state_
.push(State(true)); // ignored
914 rtl::Reference
< Node
> child(
915 Data::findNode(valueParser_
.getLayer(), group
->getMembers(), name
));
919 "unknown node \"" << name
<< "\" in \"" << reader
.getUrl() << '"');
920 state_
.push(State(true)); // ignored
923 Node::Kind kind
= child
->kind();
924 if (kind
!= Node::KIND_GROUP
&& kind
!= Node::KIND_SET
) {
925 throw css::uno::RuntimeException(
926 (rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("bad <node> \"")) +
929 RTL_CONSTASCII_USTRINGPARAM("\" of non group/set kind in ")) +
931 css::uno::Reference
< css::uno::XInterface
>());
933 if (op
!= OPERATION_MODIFY
&& op
!= OPERATION_FUSE
) {
934 throw css::uno::RuntimeException(
936 RTL_CONSTASCII_USTRINGPARAM(
937 "invalid operation on group node in ")) +
939 css::uno::Reference
< css::uno::XInterface
>());
941 int finalizedLayer
= std::min(
942 finalized
? valueParser_
.getLayer() : Data::NO_LAYER
,
943 child
->getFinalized());
944 child
->setFinalized(finalizedLayer
);
948 state_
.top().locked
|| finalizedLayer
< valueParser_
.getLayer()));
951 void XcuParser::handleSetNode(xmlreader::XmlReader
& reader
, SetNode
* set
) {
952 bool hasName
= false;
954 rtl::OUString
component(componentName_
);
955 bool hasNodeType
= false;
956 rtl::OUString nodeType
;
957 Operation op
= OPERATION_MODIFY
;
958 bool finalized
= false;
959 bool mandatory
= false;
962 xmlreader::Span attrLn
;
963 if (!reader
.nextAttribute(&attrNsId
, &attrLn
)) {
966 if (attrNsId
== ParseManager::NAMESPACE_OOR
&&
967 attrLn
.equals(RTL_CONSTASCII_STRINGPARAM("name")))
970 name
= reader
.getAttributeValue(false).convertFromUtf8();
971 } else if (attrNsId
== ParseManager::NAMESPACE_OOR
&&
972 attrLn
.equals(RTL_CONSTASCII_STRINGPARAM("component")))
974 component
= reader
.getAttributeValue(false).convertFromUtf8();
975 } else if (attrNsId
== ParseManager::NAMESPACE_OOR
&&
976 attrLn
.equals(RTL_CONSTASCII_STRINGPARAM("node-type")))
979 nodeType
= reader
.getAttributeValue(false).convertFromUtf8();
980 } else if (attrNsId
== ParseManager::NAMESPACE_OOR
&&
981 attrLn
.equals(RTL_CONSTASCII_STRINGPARAM("op")))
983 op
= parseOperation(reader
.getAttributeValue(true));
984 } else if (attrNsId
== ParseManager::NAMESPACE_OOR
&&
985 attrLn
.equals(RTL_CONSTASCII_STRINGPARAM("finalized")))
987 finalized
= xmldata::parseBoolean(reader
.getAttributeValue(true));
988 } else if (attrNsId
== ParseManager::NAMESPACE_OOR
&&
989 attrLn
.equals(RTL_CONSTASCII_STRINGPARAM("mandatory")))
991 mandatory
= xmldata::parseBoolean(reader
.getAttributeValue(true));
995 throw css::uno::RuntimeException(
997 RTL_CONSTASCII_USTRINGPARAM("no node name attribute in ")) +
999 css::uno::Reference
< css::uno::XInterface
>());
1002 path_
.push_back(name
);
1003 if (partial_
!= 0 && partial_
->contains(path_
) == Partial::CONTAINS_NOT
)
1005 state_
.push(State(true)); // ignored
1009 rtl::OUString
templateName(
1010 xmldata::parseTemplateReference(
1011 component
, hasNodeType
, nodeType
, &set
->getDefaultTemplateName()));
1012 if (!set
->isValidTemplate(templateName
)) {
1013 throw css::uno::RuntimeException(
1014 (rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("set member node ")) +
1017 RTL_CONSTASCII_USTRINGPARAM(" references invalid template ")) +
1018 templateName
+ rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(" in ")) +
1020 css::uno::Reference
< css::uno::XInterface
>());
1022 rtl::Reference
< Node
> tmpl(
1023 data_
.getTemplate(valueParser_
.getLayer(), templateName
));
1025 throw css::uno::RuntimeException(
1026 (rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("set member node ")) +
1029 RTL_CONSTASCII_USTRINGPARAM(
1030 " references undefined template ")) +
1031 templateName
+ rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(" in ")) +
1033 css::uno::Reference
< css::uno::XInterface
>());
1035 int finalizedLayer
= finalized
? valueParser_
.getLayer() : Data::NO_LAYER
;
1036 int mandatoryLayer
= mandatory
? valueParser_
.getLayer() : Data::NO_LAYER
;
1037 NodeMap
& members
= set
->getMembers();
1038 NodeMap::iterator
i(members
.find(name
));
1039 if (i
!= members
.end()) {
1040 finalizedLayer
= std::min(finalizedLayer
, i
->second
->getFinalized());
1041 i
->second
->setFinalized(finalizedLayer
);
1042 mandatoryLayer
= std::min(mandatoryLayer
, i
->second
->getMandatory());
1043 i
->second
->setMandatory(mandatoryLayer
);
1044 if (i
->second
->getLayer() > valueParser_
.getLayer()) {
1045 state_
.push(State(true)); // ignored
1050 case OPERATION_MODIFY
:
1051 if (i
== members
.end()) {
1054 "ignoring modify of unknown set member node \"" << name
1055 << "\" in \"" << reader
.getUrl() << '"');
1056 state_
.push(State(true)); // ignored
1061 (state_
.top().locked
||
1062 finalizedLayer
< valueParser_
.getLayer())));
1065 case OPERATION_REPLACE
:
1066 if (state_
.top().locked
|| finalizedLayer
< valueParser_
.getLayer()) {
1067 state_
.push(State(true)); // ignored
1069 rtl::Reference
< Node
> member(tmpl
->clone(true));
1070 member
->setLayer(valueParser_
.getLayer());
1071 member
->setFinalized(finalizedLayer
);
1072 member
->setMandatory(mandatoryLayer
);
1073 state_
.push(State(member
, name
, false));
1074 recordModification(i
== members
.end());
1077 case OPERATION_FUSE
:
1078 if (i
== members
.end()) {
1079 if (state_
.top().locked
|| finalizedLayer
< valueParser_
.getLayer())
1081 state_
.push(State(true)); // ignored
1083 rtl::Reference
< Node
> member(tmpl
->clone(true));
1084 member
->setLayer(valueParser_
.getLayer());
1085 member
->setFinalized(finalizedLayer
);
1086 member
->setMandatory(mandatoryLayer
);
1087 state_
.push(State(member
, name
, false));
1088 recordModification(true);
1094 (state_
.top().locked
||
1095 finalizedLayer
< valueParser_
.getLayer())));
1098 case OPERATION_REMOVE
:
1100 // Ignore removal of unknown members, members finalized in a lower
1101 // layer, and members made mandatory in this or a lower layer;
1102 // forget about user-layer removals that no longer remove anything
1103 // (so that paired additions/removals in the user layer do not grow
1104 // registrymodifications.xcu unbounded):
1105 bool known
= i
!= members
.end();
1106 if (known
&& !state_
.top().locked
&&
1107 finalizedLayer
>= valueParser_
.getLayer() &&
1108 (mandatoryLayer
== Data::NO_LAYER
||
1109 mandatoryLayer
> valueParser_
.getLayer()))
1113 state_
.push(State(true));
1115 recordModification(false);
1122 void XcuParser::recordModification(bool addition
) {
1123 if (broadcastModifications_
!= 0) {
1124 broadcastModifications_
->add(path_
);
1126 if (addition
&& additions_
!= 0) {
1127 additions_
->push_back(path_
);
1129 if (recordModifications_
) {
1130 data_
.modifications
.add(path_
);
1136 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */