1 /**************************************************************
2 *
3 * Licensed to the Apache Software Foundation (ASF) under one
4 * or more contributor license agreements. See the NOTICE file
5 * distributed with this work for additional information
6 * regarding copyright ownership. The ASF licenses this file
7 * to you under the Apache License, Version 2.0 (the
8 * "License"); you may not use this file except in compliance
9 * with the License. You may obtain a copy of the License at
10 *
11 * http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing,
14 * software distributed under the License is distributed on an
15 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16 * KIND, either express or implied. See the License for the
17 * specific language governing permissions and limitations
18 * under the License.
19 *
20 *************************************************************/
21
22
23
24 #include "precompiled_configmgr.hxx"
25 #include "sal/config.h"
26
27 #include <algorithm>
28
29 #include "com/sun/star/uno/Any.hxx"
30 #include "com/sun/star/uno/Reference.hxx"
31 #include "com/sun/star/uno/RuntimeException.hpp"
32 #include "com/sun/star/uno/XInterface.hpp"
33 #include "osl/diagnose.h"
34 #include "rtl/ref.hxx"
35 #include "rtl/strbuf.hxx"
36 #include "rtl/string.h"
37 #include "rtl/string.hxx"
38 #include "rtl/ustring.h"
39 #include "rtl/ustring.hxx"
40 #include "xmlreader/span.hxx"
41 #include "xmlreader/xmlreader.hxx"
42
43 #include "data.hxx"
44 #include "localizedpropertynode.hxx"
45 #include "localizedvaluenode.hxx"
46 #include "groupnode.hxx"
47 #include "modifications.hxx"
48 #include "node.hxx"
49 #include "nodemap.hxx"
50 #include "parsemanager.hxx"
51 #include "partial.hxx"
52 #include "path.hxx"
53 #include "propertynode.hxx"
54 #include "setnode.hxx"
55 #include "xcuparser.hxx"
56 #include "xmldata.hxx"
57
58 namespace configmgr {
59
60 namespace {
61
62 namespace css = com::sun::star;
63
64 }
65
XcuParser(int layer,Data & data,Partial const * partial,Modifications * broadcastModifications,Additions * additions)66 XcuParser::XcuParser(
67 int layer, Data & data, Partial const * partial,
68 Modifications * broadcastModifications, Additions * additions):
69 valueParser_(layer), data_(data),
70 partial_(partial), broadcastModifications_(broadcastModifications),
71 additions_(additions), recordModifications_(layer == Data::NO_LAYER),
72 trackPath_(
73 partial_ != 0 || broadcastModifications_ != 0 || additions_ != 0 ||
74 recordModifications_)
75 {}
76
~XcuParser()77 XcuParser::~XcuParser() {}
78
getTextMode()79 xmlreader::XmlReader::Text XcuParser::getTextMode() {
80 return valueParser_.getTextMode();
81 }
82
startElement(xmlreader::XmlReader & reader,int nsId,xmlreader::Span const & name)83 bool XcuParser::startElement(
84 xmlreader::XmlReader & reader, int nsId, xmlreader::Span const & name)
85 {
86 if (valueParser_.startElement(reader, nsId, name)) {
87 return true;
88 }
89 if (state_.empty()) {
90 if (nsId == ParseManager::NAMESPACE_OOR &&
91 name.equals(RTL_CONSTASCII_STRINGPARAM("component-data")))
92 {
93 handleComponentData(reader);
94 } else if (nsId == ParseManager::NAMESPACE_OOR &&
95 name.equals(RTL_CONSTASCII_STRINGPARAM("items")))
96 {
97 state_.push(State(rtl::Reference< Node >(), false));
98 } else {
99 throw css::uno::RuntimeException(
100 (rtl::OUString(
101 RTL_CONSTASCII_USTRINGPARAM("bad root element <")) +
102 name.convertFromUtf8() +
103 rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("> in ")) +
104 reader.getUrl()),
105 css::uno::Reference< css::uno::XInterface >());
106 }
107 } else if (state_.top().ignore) {
108 state_.push(State(false));
109 } else if (!state_.top().node.is()) {
110 if (nsId == xmlreader::XmlReader::NAMESPACE_NONE &&
111 name.equals(RTL_CONSTASCII_STRINGPARAM("item")))
112 {
113 handleItem(reader);
114 } else {
115 throw css::uno::RuntimeException(
116 (rtl::OUString(
117 RTL_CONSTASCII_USTRINGPARAM("bad items node member <")) +
118 name.convertFromUtf8() +
119 rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("> in ")) +
120 reader.getUrl()),
121 css::uno::Reference< css::uno::XInterface >());
122 }
123 } else {
124 switch (state_.top().node->kind()) {
125 case Node::KIND_PROPERTY:
126 if (nsId == xmlreader::XmlReader::NAMESPACE_NONE &&
127 name.equals(RTL_CONSTASCII_STRINGPARAM("value")))
128 {
129 handlePropValue(
130 reader,
131 dynamic_cast< PropertyNode * >(state_.top().node.get()));
132 } else {
133 throw css::uno::RuntimeException(
134 (rtl::OUString(
135 RTL_CONSTASCII_USTRINGPARAM(
136 "bad property node member <")) +
137 name.convertFromUtf8() +
138 rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("> in ")) +
139 reader.getUrl()),
140 css::uno::Reference< css::uno::XInterface >());
141 }
142 break;
143 case Node::KIND_LOCALIZED_PROPERTY:
144 if (nsId == xmlreader::XmlReader::NAMESPACE_NONE &&
145 name.equals(RTL_CONSTASCII_STRINGPARAM("value")))
146 {
147 handleLocpropValue(
148 reader,
149 dynamic_cast< LocalizedPropertyNode * >(
150 state_.top().node.get()));
151 } else {
152 throw css::uno::RuntimeException(
153 (rtl::OUString(
154 RTL_CONSTASCII_USTRINGPARAM(
155 "bad localized property node member <")) +
156 name.convertFromUtf8() +
157 rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("> in ")) +
158 reader.getUrl()),
159 css::uno::Reference< css::uno::XInterface >());
160 }
161 break;
162 case Node::KIND_LOCALIZED_VALUE:
163 throw css::uno::RuntimeException(
164 (rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("bad member <")) +
165 name.convertFromUtf8() +
166 rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("> in ")) +
167 reader.getUrl()),
168 css::uno::Reference< css::uno::XInterface >());
169 case Node::KIND_GROUP:
170 if (nsId == xmlreader::XmlReader::NAMESPACE_NONE &&
171 name.equals(RTL_CONSTASCII_STRINGPARAM("prop")))
172 {
173 handleGroupProp(
174 reader,
175 dynamic_cast< GroupNode * >(state_.top().node.get()));
176 } else if (nsId == xmlreader::XmlReader::NAMESPACE_NONE &&
177 name.equals(RTL_CONSTASCII_STRINGPARAM("node")))
178 {
179 handleGroupNode(reader, state_.top().node);
180 } else {
181 throw css::uno::RuntimeException(
182 (rtl::OUString(
183 RTL_CONSTASCII_USTRINGPARAM(
184 "bad group node member <")) +
185 name.convertFromUtf8() +
186 rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("> in ")) +
187 reader.getUrl()),
188 css::uno::Reference< css::uno::XInterface >());
189 }
190 break;
191 case Node::KIND_SET:
192 if (nsId == xmlreader::XmlReader::NAMESPACE_NONE &&
193 name.equals(RTL_CONSTASCII_STRINGPARAM("node")))
194 {
195 handleSetNode(
196 reader, dynamic_cast< SetNode * >(state_.top().node.get()));
197 } else if (nsId == xmlreader::XmlReader::NAMESPACE_NONE &&
198 name.equals(RTL_CONSTASCII_STRINGPARAM("prop")))
199 {
200 OSL_TRACE(
201 "configmgr bad set node <prop> member in %s",
202 rtl::OUStringToOString(
203 reader.getUrl(), RTL_TEXTENCODING_UTF8).getStr());
204 state_.push(State(true)); // ignored
205 } else {
206 throw css::uno::RuntimeException(
207 (rtl::OUString(
208 RTL_CONSTASCII_USTRINGPARAM("bad set node member <")) +
209 name.convertFromUtf8() +
210 rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("> in ")) +
211 reader.getUrl()),
212 css::uno::Reference< css::uno::XInterface >());
213 }
214 break;
215 }
216 }
217 return true;
218 }
219
endElement(xmlreader::XmlReader const &)220 void XcuParser::endElement(xmlreader::XmlReader const &) {
221 if (valueParser_.endElement()) {
222 return;
223 }
224 OSL_ASSERT(!state_.empty());
225 bool pop = state_.top().pop;
226 rtl::Reference< Node > insert;
227 rtl::OUString name;
228 if (state_.top().insert) {
229 insert = state_.top().node;
230 OSL_ASSERT(insert.is());
231 name = state_.top().name;
232 }
233 state_.pop();
234 if (insert.is()) {
235 OSL_ASSERT(!state_.empty() && state_.top().node.is());
236 state_.top().node->getMembers()[name] = insert;
237 }
238 if (pop && !path_.empty()) {
239 path_.pop_back();
240 // </item> will pop less than <item> pushed, but that is harmless,
241 // as the next <item> will reset path_
242 }
243 }
244
characters(xmlreader::Span const & text)245 void XcuParser::characters(xmlreader::Span const & text) {
246 valueParser_.characters(text);
247 }
248
parseOperation(xmlreader::Span const & text)249 XcuParser::Operation XcuParser::parseOperation(xmlreader::Span const & text) {
250 OSL_ASSERT(text.is());
251 if (text.equals(RTL_CONSTASCII_STRINGPARAM("modify"))) {
252 return OPERATION_MODIFY;
253 }
254 if (text.equals(RTL_CONSTASCII_STRINGPARAM("replace"))) {
255 return OPERATION_REPLACE;
256 }
257 if (text.equals(RTL_CONSTASCII_STRINGPARAM("fuse"))) {
258 return OPERATION_FUSE;
259 }
260 if (text.equals(RTL_CONSTASCII_STRINGPARAM("remove"))) {
261 return OPERATION_REMOVE;
262 }
263 throw css::uno::RuntimeException(
264 (rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("invalid op ")) +
265 text.convertFromUtf8()),
266 css::uno::Reference< css::uno::XInterface >());
267 }
268
handleComponentData(xmlreader::XmlReader & reader)269 void XcuParser::handleComponentData(xmlreader::XmlReader & reader) {
270 rtl::OStringBuffer buf;
271 buf.append('.');
272 bool hasPackage = false;
273 bool hasName = false;
274 Operation op = OPERATION_MODIFY;
275 bool finalized = false;
276 for (;;) {
277 int attrNsId;
278 xmlreader::Span attrLn;
279 if (!reader.nextAttribute(&attrNsId, &attrLn)) {
280 break;
281 }
282 if (attrNsId == ParseManager::NAMESPACE_OOR &&
283 attrLn.equals(RTL_CONSTASCII_STRINGPARAM("package")))
284 {
285 if (hasPackage) {
286 throw css::uno::RuntimeException(
287 (rtl::OUString(
288 RTL_CONSTASCII_USTRINGPARAM(
289 "multiple component-update package attributes"
290 " in ")) +
291 reader.getUrl()),
292 css::uno::Reference< css::uno::XInterface >());
293 }
294 hasPackage = true;
295 xmlreader::Span s(reader.getAttributeValue(false));
296 buf.insert(0, s.begin, s.length);
297 } else if (attrNsId == ParseManager::NAMESPACE_OOR &&
298 attrLn.equals(RTL_CONSTASCII_STRINGPARAM("name")))
299 {
300 if (hasName) {
301 throw css::uno::RuntimeException(
302 (rtl::OUString(
303 RTL_CONSTASCII_USTRINGPARAM(
304 "multiple component-update name attributes in ")) +
305 reader.getUrl()),
306 css::uno::Reference< css::uno::XInterface >());
307 }
308 hasName = true;
309 xmlreader::Span s(reader.getAttributeValue(false));
310 buf.append(s.begin, s.length);
311 } else if (attrNsId == ParseManager::NAMESPACE_OOR &&
312 attrLn.equals(RTL_CONSTASCII_STRINGPARAM("op")))
313 {
314 op = parseOperation(reader.getAttributeValue(true));
315 } else if (attrNsId == ParseManager::NAMESPACE_OOR &&
316 attrLn.equals(RTL_CONSTASCII_STRINGPARAM("finalized")))
317 {
318 finalized = xmldata::parseBoolean(reader.getAttributeValue(true));
319 }
320 }
321 if (!hasPackage) {
322 throw css::uno::RuntimeException(
323 (rtl::OUString(
324 RTL_CONSTASCII_USTRINGPARAM(
325 "no component-data package attribute in ")) +
326 reader.getUrl()),
327 css::uno::Reference< css::uno::XInterface >());
328 }
329 if (!hasName) {
330 throw css::uno::RuntimeException(
331 (rtl::OUString(
332 RTL_CONSTASCII_USTRINGPARAM(
333 "no component-data name attribute in ")) +
334 reader.getUrl()),
335 css::uno::Reference< css::uno::XInterface >());
336 }
337 componentName_ = xmlreader::Span(buf.getStr(), buf.getLength()).
338 convertFromUtf8();
339 if (trackPath_) {
340 OSL_ASSERT(path_.empty());
341 path_.push_back(componentName_);
342 if (partial_ != 0 && partial_->contains(path_) == Partial::CONTAINS_NOT)
343 {
344 state_.push(State(true)); // ignored
345 return;
346 }
347 }
348 rtl::Reference< Node > node(
349 Data::findNode(
350 valueParser_.getLayer(), data_.components, componentName_));
351 if (!node.is()) {
352 OSL_TRACE(
353 "configmgr unknown component %s in %s",
354 rtl::OUStringToOString(
355 componentName_, RTL_TEXTENCODING_UTF8).getStr(),
356 rtl::OUStringToOString(
357 reader.getUrl(), RTL_TEXTENCODING_UTF8).getStr());
358 state_.push(State(true)); // ignored
359 return;
360 }
361 switch (op) {
362 case OPERATION_MODIFY:
363 case OPERATION_FUSE:
364 break;
365 default:
366 throw css::uno::RuntimeException(
367 (rtl::OUString(
368 RTL_CONSTASCII_USTRINGPARAM(
369 "invalid operation on root node in ")) +
370 reader.getUrl()),
371 css::uno::Reference< css::uno::XInterface >());
372 }
373 int finalizedLayer = std::min(
374 finalized ? valueParser_.getLayer() : Data::NO_LAYER,
375 node->getFinalized());
376 node->setFinalized(finalizedLayer);
377 state_.push(State(node, finalizedLayer < valueParser_.getLayer()));
378 }
379
handleItem(xmlreader::XmlReader & reader)380 void XcuParser::handleItem(xmlreader::XmlReader & reader) {
381 xmlreader::Span attrPath;
382 for (;;) {
383 int attrNsId;
384 xmlreader::Span attrLn;
385 if (!reader.nextAttribute(&attrNsId, &attrLn)) {
386 break;
387 }
388 if (attrNsId == ParseManager::NAMESPACE_OOR &&
389 attrLn.equals(RTL_CONSTASCII_STRINGPARAM("path")))
390 {
391 attrPath = reader.getAttributeValue(false);
392 }
393 }
394 if (!attrPath.is()) {
395 throw css::uno::RuntimeException(
396 (rtl::OUString(
397 RTL_CONSTASCII_USTRINGPARAM("missing path attribute in ")) +
398 reader.getUrl()),
399 css::uno::Reference< css::uno::XInterface >());
400 }
401 rtl::OUString path(attrPath.convertFromUtf8());
402 int finalizedLayer;
403 rtl::Reference< Node > node(
404 data_.resolvePathRepresentation(
405 path, 0, &path_, &finalizedLayer));
406 if (!node.is()) {
407 OSL_TRACE(
408 "configmgr unknown item %s in %s",
409 rtl::OUStringToOString(path, RTL_TEXTENCODING_UTF8).getStr(),
410 rtl::OUStringToOString(
411 reader.getUrl(), RTL_TEXTENCODING_UTF8).getStr());
412 state_.push(State(true)); // ignored
413 return;
414 }
415 OSL_ASSERT(!path_.empty());
416 componentName_ = path_.front();
417 if (trackPath_) {
418 if (partial_ != 0 && partial_->contains(path_) == Partial::CONTAINS_NOT)
419 {
420 state_.push(State(true)); // ignored
421 return;
422 }
423 } else {
424 path_.clear();
425 }
426 switch (node->kind()) {
427 case Node::KIND_PROPERTY:
428 case Node::KIND_LOCALIZED_VALUE:
429 OSL_TRACE(
430 "configmgr item of bad type %s in %s",
431 rtl::OUStringToOString(path, RTL_TEXTENCODING_UTF8).getStr(),
432 rtl::OUStringToOString(
433 reader.getUrl(), RTL_TEXTENCODING_UTF8).getStr());
434 state_.push(State(true)); // ignored
435 return;
436 case Node::KIND_LOCALIZED_PROPERTY:
437 valueParser_.type_ = dynamic_cast< LocalizedPropertyNode * >(
438 node.get())->getStaticType();
439 break;
440 default:
441 break;
442 }
443 state_.push(State(node, finalizedLayer < valueParser_.getLayer()));
444 }
445
handlePropValue(xmlreader::XmlReader & reader,PropertyNode * prop)446 void XcuParser::handlePropValue(
447 xmlreader::XmlReader & reader, PropertyNode * prop)
448 {
449 bool nil = false;
450 rtl::OString separator;
451 rtl::OUString external;
452 for (;;) {
453 int attrNsId;
454 xmlreader::Span attrLn;
455 if (!reader.nextAttribute(&attrNsId, &attrLn)) {
456 break;
457 }
458 if (attrNsId == ParseManager::NAMESPACE_XSI &&
459 attrLn.equals(RTL_CONSTASCII_STRINGPARAM("nil")))
460 {
461 nil = xmldata::parseBoolean(reader.getAttributeValue(true));
462 } else if (attrNsId == ParseManager::NAMESPACE_OOR &&
463 attrLn.equals(RTL_CONSTASCII_STRINGPARAM("type")))
464 {
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 (rtl::OUString(
470 RTL_CONSTASCII_USTRINGPARAM("invalid value type in ")) +
471 reader.getUrl()),
472 css::uno::Reference< css::uno::XInterface >());
473 }
474 valueParser_.type_ = type;
475 } else if (attrNsId == ParseManager::NAMESPACE_OOR &&
476 attrLn.equals(RTL_CONSTASCII_STRINGPARAM("separator")))
477 {
478 xmlreader::Span s(reader.getAttributeValue(false));
479 if (s.length == 0) {
480 throw css::uno::RuntimeException(
481 (rtl::OUString(
482 RTL_CONSTASCII_USTRINGPARAM(
483 "bad oor:separator attribute in ")) +
484 reader.getUrl()),
485 css::uno::Reference< css::uno::XInterface >());
486 }
487 separator = rtl::OString(s.begin, s.length);
488 } else if (attrNsId == ParseManager::NAMESPACE_OOR &&
489 attrLn.equals(RTL_CONSTASCII_STRINGPARAM("external")))
490 {
491 external = reader.getAttributeValue(true).convertFromUtf8();
492 if (external.getLength() == 0) {
493 throw css::uno::RuntimeException(
494 (rtl::OUString(
495 RTL_CONSTASCII_USTRINGPARAM(
496 "bad oor:external attribute value in ")) +
497 reader.getUrl()),
498 css::uno::Reference< css::uno::XInterface >());
499 }
500 }
501 }
502 if (nil) {
503 if (!prop->isNillable()) {
504 throw css::uno::RuntimeException(
505 (rtl::OUString(
506 RTL_CONSTASCII_USTRINGPARAM(
507 "xsi:nil attribute for non-nillable prop in ")) +
508 reader.getUrl()),
509 css::uno::Reference< css::uno::XInterface >());
510 }
511 if (external.getLength() != 0) {
512 throw css::uno::RuntimeException(
513 (rtl::OUString(
514 RTL_CONSTASCII_USTRINGPARAM(
515 "xsi:nil and oor:external attributes for prop in ")) +
516 reader.getUrl()),
517 css::uno::Reference< css::uno::XInterface >());
518 }
519 prop->setValue(valueParser_.getLayer(), css::uno::Any());
520 state_.push(State(false));
521 } else if (external.getLength() == 0) {
522 valueParser_.separator_ = separator;
523 valueParser_.start(prop);
524 } else {
525 prop->setExternal(valueParser_.getLayer(), external);
526 state_.push(State(false));
527 }
528 }
529
handleLocpropValue(xmlreader::XmlReader & reader,LocalizedPropertyNode * locprop)530 void XcuParser::handleLocpropValue(
531 xmlreader::XmlReader & reader, LocalizedPropertyNode * locprop)
532 {
533 rtl::OUString name;
534 bool nil = false;
535 rtl::OString separator;
536 Operation op = OPERATION_FUSE;
537 for (;;) {
538 int attrNsId;
539 xmlreader::Span attrLn;
540 if (!reader.nextAttribute(&attrNsId, &attrLn)) {
541 break;
542 }
543 if (attrNsId == xmlreader::XmlReader::NAMESPACE_XML &&
544 attrLn.equals(RTL_CONSTASCII_STRINGPARAM("lang")))
545 {
546 name = reader.getAttributeValue(false).convertFromUtf8();
547 } else if (attrNsId == ParseManager::NAMESPACE_XSI &&
548 attrLn.equals(RTL_CONSTASCII_STRINGPARAM("nil")))
549 {
550 nil = xmldata::parseBoolean(reader.getAttributeValue(true));
551 } else if (attrNsId == ParseManager::NAMESPACE_OOR &&
552 attrLn.equals(RTL_CONSTASCII_STRINGPARAM("type")))
553 {
554 Type type = xmldata::parseType(
555 reader, reader.getAttributeValue(true));
556 if (valueParser_.type_ != TYPE_ANY && type != valueParser_.type_) {
557 throw css::uno::RuntimeException(
558 (rtl::OUString(
559 RTL_CONSTASCII_USTRINGPARAM("invalid value type in ")) +
560 reader.getUrl()),
561 css::uno::Reference< css::uno::XInterface >());
562 }
563 valueParser_.type_ = type;
564 } else if (attrNsId == ParseManager::NAMESPACE_OOR &&
565 attrLn.equals(RTL_CONSTASCII_STRINGPARAM("separator")))
566 {
567 xmlreader::Span s(reader.getAttributeValue(false));
568 if (s.length == 0) {
569 throw css::uno::RuntimeException(
570 (rtl::OUString(
571 RTL_CONSTASCII_USTRINGPARAM(
572 "bad oor:separator attribute in ")) +
573 reader.getUrl()),
574 css::uno::Reference< css::uno::XInterface >());
575 }
576 separator = rtl::OString(s.begin, s.length);
577 } else if (attrNsId == ParseManager::NAMESPACE_OOR &&
578 attrLn.equals(RTL_CONSTASCII_STRINGPARAM("op")))
579 {
580 op = parseOperation(reader.getAttributeValue(true));
581 }
582 }
583 if (trackPath_) {
584 path_.push_back(name);
585 if (partial_ != 0 &&
586 partial_->contains(path_) != Partial::CONTAINS_NODE)
587 {
588 state_.push(State(true)); // ignored
589 return;
590 }
591 }
592 NodeMap::iterator i(locprop->getMembers().find(name));
593 if (i != locprop->getMembers().end() &&
594 i->second->getLayer() > valueParser_.getLayer())
595 {
596 state_.push(State(true)); // ignored
597 return;
598 }
599 if (nil && !locprop->isNillable()) {
600 throw css::uno::RuntimeException(
601 (rtl::OUString(
602 RTL_CONSTASCII_USTRINGPARAM(
603 "xsi:nil attribute for non-nillable prop in ")) +
604 reader.getUrl()),
605 css::uno::Reference< css::uno::XInterface >());
606 }
607 switch (op) {
608 case OPERATION_FUSE:
609 {
610 bool pop = false;
611 if (nil) {
612 if (i == locprop->getMembers().end()) {
613 locprop->getMembers()[name] = new LocalizedValueNode(
614 valueParser_.getLayer(), css::uno::Any());
615 } else {
616 dynamic_cast< LocalizedValueNode * >(
617 i->second.get())->setValue(
618 valueParser_.getLayer(), css::uno::Any());
619 }
620 state_.push(State(true));
621 } else {
622 valueParser_.separator_ = separator;
623 valueParser_.start(locprop, name);
624 pop = true;
625 }
626 if (trackPath_) {
627 recordModification(false);
628 if (pop) {
629 path_.pop_back();
630 }
631 }
632 }
633 break;
634 case OPERATION_REMOVE:
635 //TODO: only allow if parent.op == OPERATION_FUSE
636 //TODO: disallow removing when e.g. lang=""?
637 if (i != locprop->getMembers().end()) {
638 locprop->getMembers().erase(i);
639 }
640 state_.push(State(true));
641 recordModification(false);
642 break;
643 default:
644 throw css::uno::RuntimeException(
645 (rtl::OUString(
646 RTL_CONSTASCII_USTRINGPARAM(
647 "bad op attribute for value element in ")) +
648 reader.getUrl()),
649 css::uno::Reference< css::uno::XInterface >());
650 }
651 }
652
handleGroupProp(xmlreader::XmlReader & reader,GroupNode * group)653 void XcuParser::handleGroupProp(
654 xmlreader::XmlReader & reader, GroupNode * group)
655 {
656 bool hasName = false;
657 rtl::OUString name;
658 Type type = TYPE_ERROR;
659 Operation op = OPERATION_MODIFY;
660 bool finalized = false;
661 for (;;) {
662 int attrNsId;
663 xmlreader::Span attrLn;
664 if (!reader.nextAttribute(&attrNsId, &attrLn)) {
665 break;
666 }
667 if (attrNsId == ParseManager::NAMESPACE_OOR &&
668 attrLn.equals(RTL_CONSTASCII_STRINGPARAM("name")))
669 {
670 hasName = true;
671 name = reader.getAttributeValue(false).convertFromUtf8();
672 } else if (attrNsId == ParseManager::NAMESPACE_OOR &&
673 attrLn.equals(RTL_CONSTASCII_STRINGPARAM("type")))
674 {
675 type = xmldata::parseType(reader, reader.getAttributeValue(true));
676 } else if (attrNsId == ParseManager::NAMESPACE_OOR &&
677 attrLn.equals(RTL_CONSTASCII_STRINGPARAM("op")))
678 {
679 op = parseOperation(reader.getAttributeValue(true));
680 } else if (attrNsId == ParseManager::NAMESPACE_OOR &&
681 attrLn.equals(RTL_CONSTASCII_STRINGPARAM("finalized")))
682 {
683 finalized = xmldata::parseBoolean(reader.getAttributeValue(true));
684 }
685 }
686 if (!hasName) {
687 throw css::uno::RuntimeException(
688 (rtl::OUString(
689 RTL_CONSTASCII_USTRINGPARAM("no prop name attribute in ")) +
690 reader.getUrl()),
691 css::uno::Reference< css::uno::XInterface >());
692 }
693 if (trackPath_) {
694 path_.push_back(name);
695 //TODO: This ignores locprop values for which specific include paths
696 // exist (i.e., for which contains(locprop path) = CONTAINS_SUBNODES):
697 if (partial_ != 0 &&
698 partial_->contains(path_) != Partial::CONTAINS_NODE)
699 {
700 state_.push(State(true)); // ignored
701 return;
702 }
703 }
704 NodeMap::iterator i(group->getMembers().find(name));
705 if (i == group->getMembers().end()) {
706 handleUnknownGroupProp(reader, group, name, type, op, finalized);
707 } else {
708 switch (i->second->kind()) {
709 case Node::KIND_PROPERTY:
710 handlePlainGroupProp(reader, group, i, name, type, op, finalized);
711 break;
712 case Node::KIND_LOCALIZED_PROPERTY:
713 handleLocalizedGroupProp(
714 reader,
715 dynamic_cast< LocalizedPropertyNode * >(i->second.get()), name,
716 type, op, finalized);
717 break;
718 default:
719 throw css::uno::RuntimeException(
720 (rtl::OUString(
721 RTL_CONSTASCII_USTRINGPARAM("inappropriate prop ")) +
722 name + rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(" in ")) +
723 reader.getUrl()),
724 css::uno::Reference< css::uno::XInterface >());
725 }
726 }
727 }
728
handleUnknownGroupProp(xmlreader::XmlReader const & reader,GroupNode * group,rtl::OUString const & name,Type type,Operation operation,bool finalized)729 void XcuParser::handleUnknownGroupProp(
730 xmlreader::XmlReader const & reader, GroupNode * group,
731 rtl::OUString const & name, Type type, Operation operation, bool finalized)
732 {
733 switch (operation) {
734 case OPERATION_REPLACE:
735 case OPERATION_FUSE:
736 if (group->isExtensible()) {
737 if (type == TYPE_ERROR) {
738 throw css::uno::RuntimeException(
739 (rtl::OUString(
740 RTL_CONSTASCII_USTRINGPARAM(
741 "missing type attribute for prop ")) +
742 name + rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(" in ")) +
743 reader.getUrl()),
744 css::uno::Reference< css::uno::XInterface >());
745 }
746 valueParser_.type_ = type;
747 rtl::Reference< Node > prop(
748 new PropertyNode(
749 valueParser_.getLayer(), TYPE_ANY, true, css::uno::Any(),
750 true));
751 if (finalized) {
752 prop->setFinalized(valueParser_.getLayer());
753 }
754 state_.push(State(prop, name, state_.top().locked));
755 recordModification(false);
756 break;
757 }
758 // fall through
759 default:
760 OSL_TRACE(
761 "configmgr unknown property %s in %s",
762 rtl::OUStringToOString(name, RTL_TEXTENCODING_UTF8).getStr(),
763 rtl::OUStringToOString(
764 reader.getUrl(), RTL_TEXTENCODING_UTF8).getStr());
765 state_.push(State(true)); // ignored
766 break;
767 }
768 }
769
handlePlainGroupProp(xmlreader::XmlReader const & reader,GroupNode * group,NodeMap::iterator const & propertyIndex,rtl::OUString const & name,Type type,Operation operation,bool finalized)770 void XcuParser::handlePlainGroupProp(
771 xmlreader::XmlReader const & reader, GroupNode * group,
772 NodeMap::iterator const & propertyIndex, rtl::OUString const & name,
773 Type type, Operation operation, bool finalized)
774 {
775 PropertyNode * property = dynamic_cast< PropertyNode * >(
776 propertyIndex->second.get());
777 if (property->getLayer() > valueParser_.getLayer()) {
778 state_.push(State(true)); // ignored
779 return;
780 }
781 int finalizedLayer = std::min(
782 finalized ? valueParser_.getLayer() : Data::NO_LAYER,
783 property->getFinalized());
784 property->setFinalized(finalizedLayer);
785 if (type != TYPE_ERROR && property->getStaticType() != TYPE_ANY &&
786 type != property->getStaticType())
787 {
788 throw css::uno::RuntimeException(
789 (rtl::OUString(
790 RTL_CONSTASCII_USTRINGPARAM("invalid type for prop ")) +
791 name + rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(" in ")) +
792 reader.getUrl()),
793 css::uno::Reference< css::uno::XInterface >());
794 }
795 valueParser_.type_ = type == TYPE_ERROR ? property->getStaticType() : type;
796 switch (operation) {
797 case OPERATION_MODIFY:
798 case OPERATION_REPLACE:
799 case OPERATION_FUSE:
800 state_.push(
801 State(
802 property,
803 (state_.top().locked ||
804 finalizedLayer < valueParser_.getLayer())));
805 recordModification(false);
806 break;
807 case OPERATION_REMOVE:
808 if (!property->isExtension()) {
809 throw css::uno::RuntimeException(
810 (rtl::OUString(
811 RTL_CONSTASCII_USTRINGPARAM(
812 "invalid remove of non-extension prop ")) +
813 name + rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(" in ")) +
814 reader.getUrl()),
815 css::uno::Reference< css::uno::XInterface >());
816 }
817 group->getMembers().erase(propertyIndex);
818 state_.push(State(true)); // ignore children
819 recordModification(false);
820 break;
821 }
822 }
823
handleLocalizedGroupProp(xmlreader::XmlReader const & reader,LocalizedPropertyNode * property,rtl::OUString const & name,Type type,Operation operation,bool finalized)824 void XcuParser::handleLocalizedGroupProp(
825 xmlreader::XmlReader const & reader, LocalizedPropertyNode * property,
826 rtl::OUString const & name, Type type, Operation operation, bool finalized)
827 {
828 if (property->getLayer() > valueParser_.getLayer()) {
829 state_.push(State(true)); // ignored
830 return;
831 }
832 int finalizedLayer = std::min(
833 finalized ? valueParser_.getLayer() : Data::NO_LAYER,
834 property->getFinalized());
835 property->setFinalized(finalizedLayer);
836 if (type != TYPE_ERROR && property->getStaticType() != TYPE_ANY &&
837 type != property->getStaticType())
838 {
839 throw css::uno::RuntimeException(
840 (rtl::OUString(
841 RTL_CONSTASCII_USTRINGPARAM("invalid type for prop ")) +
842 name + rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(" in ")) +
843 reader.getUrl()),
844 css::uno::Reference< css::uno::XInterface >());
845 }
846 valueParser_.type_ = type == TYPE_ERROR ? property->getStaticType() : type;
847 switch (operation) {
848 case OPERATION_MODIFY:
849 case OPERATION_FUSE:
850 state_.push(
851 State(
852 property,
853 (state_.top().locked ||
854 finalizedLayer < valueParser_.getLayer())));
855 break;
856 case OPERATION_REPLACE:
857 {
858 rtl::Reference< Node > replacement(
859 new LocalizedPropertyNode(
860 valueParser_.getLayer(), property->getStaticType(),
861 property->isNillable()));
862 replacement->setFinalized(property->getFinalized());
863 state_.push(
864 State(
865 replacement, name,
866 (state_.top().locked ||
867 finalizedLayer < valueParser_.getLayer())));
868 recordModification(false);
869 }
870 break;
871 case OPERATION_REMOVE:
872 throw css::uno::RuntimeException(
873 (rtl::OUString(
874 RTL_CONSTASCII_USTRINGPARAM(
875 "invalid remove of non-extension prop ")) +
876 name + rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(" in ")) +
877 reader.getUrl()),
878 css::uno::Reference< css::uno::XInterface >());
879 }
880 }
881
handleGroupNode(xmlreader::XmlReader & reader,rtl::Reference<Node> const & group)882 void XcuParser::handleGroupNode(
883 xmlreader::XmlReader & reader, rtl::Reference< Node > const & group)
884 {
885 bool hasName = false;
886 rtl::OUString name;
887 Operation op = OPERATION_MODIFY;
888 bool finalized = false;
889 for (;;) {
890 int attrNsId;
891 xmlreader::Span attrLn;
892 if (!reader.nextAttribute(&attrNsId, &attrLn)) {
893 break;
894 }
895 if (attrNsId == ParseManager::NAMESPACE_OOR &&
896 attrLn.equals(RTL_CONSTASCII_STRINGPARAM("name")))
897 {
898 hasName = true;
899 name = reader.getAttributeValue(false).convertFromUtf8();
900 } else if (attrNsId == ParseManager::NAMESPACE_OOR &&
901 attrLn.equals(RTL_CONSTASCII_STRINGPARAM("op")))
902 {
903 op = parseOperation(reader.getAttributeValue(true));
904 } else if (attrNsId == ParseManager::NAMESPACE_OOR &&
905 attrLn.equals(RTL_CONSTASCII_STRINGPARAM("finalized")))
906 {
907 finalized = xmldata::parseBoolean(reader.getAttributeValue(true));
908 }
909 }
910 if (!hasName) {
911 throw css::uno::RuntimeException(
912 (rtl::OUString(
913 RTL_CONSTASCII_USTRINGPARAM("no node name attribute in ")) +
914 reader.getUrl()),
915 css::uno::Reference< css::uno::XInterface >());
916 }
917 if (trackPath_) {
918 path_.push_back(name);
919 if (partial_ != 0 && partial_->contains(path_) == Partial::CONTAINS_NOT)
920 {
921 state_.push(State(true)); // ignored
922 return;
923 }
924 }
925 rtl::Reference< Node > child(
926 Data::findNode(valueParser_.getLayer(), group->getMembers(), name));
927 if (!child.is()) {
928 OSL_TRACE(
929 "configmgr unknown node %s in %s",
930 rtl::OUStringToOString(name, RTL_TEXTENCODING_UTF8).getStr(),
931 rtl::OUStringToOString(
932 reader.getUrl(), RTL_TEXTENCODING_UTF8).getStr());
933 state_.push(State(true)); // ignored
934 return;
935 }
936 if (op != OPERATION_MODIFY && op != OPERATION_FUSE) {
937 throw css::uno::RuntimeException(
938 (rtl::OUString(
939 RTL_CONSTASCII_USTRINGPARAM(
940 "invalid operation on group node in ")) +
941 reader.getUrl()),
942 css::uno::Reference< css::uno::XInterface >());
943 }
944 int finalizedLayer = std::min(
945 finalized ? valueParser_.getLayer() : Data::NO_LAYER,
946 child->getFinalized());
947 child->setFinalized(finalizedLayer);
948 state_.push(
949 State(
950 child,
951 state_.top().locked || finalizedLayer < valueParser_.getLayer()));
952 }
953
handleSetNode(xmlreader::XmlReader & reader,SetNode * set)954 void XcuParser::handleSetNode(xmlreader::XmlReader & reader, SetNode * set) {
955 bool hasName = false;
956 rtl::OUString name;
957 rtl::OUString component(componentName_);
958 bool hasNodeType = false;
959 rtl::OUString nodeType;
960 Operation op = OPERATION_MODIFY;
961 bool finalized = false;
962 bool mandatory = false;
963 for (;;) {
964 int attrNsId;
965 xmlreader::Span attrLn;
966 if (!reader.nextAttribute(&attrNsId, &attrLn)) {
967 break;
968 }
969 if (attrNsId == ParseManager::NAMESPACE_OOR &&
970 attrLn.equals(RTL_CONSTASCII_STRINGPARAM("name")))
971 {
972 hasName = true;
973 name = reader.getAttributeValue(false).convertFromUtf8();
974 } else if (attrNsId == ParseManager::NAMESPACE_OOR &&
975 attrLn.equals(RTL_CONSTASCII_STRINGPARAM("component")))
976 {
977 component = reader.getAttributeValue(false).convertFromUtf8();
978 } else if (attrNsId == ParseManager::NAMESPACE_OOR &&
979 attrLn.equals(RTL_CONSTASCII_STRINGPARAM("node-type")))
980 {
981 hasNodeType = true;
982 nodeType = reader.getAttributeValue(false).convertFromUtf8();
983 } else if (attrNsId == ParseManager::NAMESPACE_OOR &&
984 attrLn.equals(RTL_CONSTASCII_STRINGPARAM("op")))
985 {
986 op = parseOperation(reader.getAttributeValue(true));
987 } else if (attrNsId == ParseManager::NAMESPACE_OOR &&
988 attrLn.equals(RTL_CONSTASCII_STRINGPARAM("finalized")))
989 {
990 finalized = xmldata::parseBoolean(reader.getAttributeValue(true));
991 } else if (attrNsId == ParseManager::NAMESPACE_OOR &&
992 attrLn.equals(RTL_CONSTASCII_STRINGPARAM("mandatory")))
993 {
994 mandatory = xmldata::parseBoolean(reader.getAttributeValue(true));
995 }
996 }
997 if (!hasName) {
998 throw css::uno::RuntimeException(
999 (rtl::OUString(
1000 RTL_CONSTASCII_USTRINGPARAM("no node name attribute in ")) +
1001 reader.getUrl()),
1002 css::uno::Reference< css::uno::XInterface >());
1003 }
1004 if (trackPath_) {
1005 path_.push_back(name);
1006 if (partial_ != 0 && partial_->contains(path_) == Partial::CONTAINS_NOT)
1007 {
1008 state_.push(State(true)); // ignored
1009 return;
1010 }
1011 }
1012 rtl::OUString templateName(
1013 xmldata::parseTemplateReference(
1014 component, hasNodeType, nodeType, &set->getDefaultTemplateName()));
1015 if (!set->isValidTemplate(templateName)) {
1016 throw css::uno::RuntimeException(
1017 (rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("set member node ")) +
1018 name +
1019 rtl::OUString(
1020 RTL_CONSTASCII_USTRINGPARAM(" references invalid template ")) +
1021 templateName + rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(" in ")) +
1022 reader.getUrl()),
1023 css::uno::Reference< css::uno::XInterface >());
1024 }
1025 rtl::Reference< Node > tmpl(
1026 data_.getTemplate(valueParser_.getLayer(), templateName));
1027 if (!tmpl.is()) {
1028 throw css::uno::RuntimeException(
1029 (rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("set member node ")) +
1030 name +
1031 rtl::OUString(
1032 RTL_CONSTASCII_USTRINGPARAM(
1033 " references undefined template ")) +
1034 templateName + rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(" in ")) +
1035 reader.getUrl()),
1036 css::uno::Reference< css::uno::XInterface >());
1037 }
1038 int finalizedLayer = finalized ? valueParser_.getLayer() : Data::NO_LAYER;
1039 int mandatoryLayer = mandatory ? valueParser_.getLayer() : Data::NO_LAYER;
1040 NodeMap::iterator i(set->getMembers().find(name));
1041 if (i != set->getMembers().end()) {
1042 finalizedLayer = std::min(finalizedLayer, i->second->getFinalized());
1043 i->second->setFinalized(finalizedLayer);
1044 mandatoryLayer = std::min(mandatoryLayer, i->second->getMandatory());
1045 i->second->setMandatory(mandatoryLayer);
1046 if (i->second->getLayer() > valueParser_.getLayer()) {
1047 state_.push(State(true)); // ignored
1048 return;
1049 }
1050 }
1051 switch (op) {
1052 case OPERATION_MODIFY:
1053 if (i == set->getMembers().end()) {
1054 OSL_TRACE("ignoring modify of unknown set member node");
1055 state_.push(State(true)); // ignored
1056 } else {
1057 state_.push(
1058 State(
1059 i->second,
1060 (state_.top().locked ||
1061 finalizedLayer < valueParser_.getLayer())));
1062 }
1063 break;
1064 case OPERATION_REPLACE:
1065 if (state_.top().locked || finalizedLayer < valueParser_.getLayer()) {
1066 state_.push(State(true)); // ignored
1067 } else {
1068 rtl::Reference< Node > member(tmpl->clone(true));
1069 member->setLayer(valueParser_.getLayer());
1070 member->setFinalized(finalizedLayer);
1071 member->setMandatory(mandatoryLayer);
1072 state_.push(State(member, name, false));
1073 recordModification(i == set->getMembers().end());
1074 }
1075 break;
1076 case OPERATION_FUSE:
1077 if (i == set->getMembers().end()) {
1078 if (state_.top().locked || finalizedLayer < valueParser_.getLayer())
1079 {
1080 state_.push(State(true)); // ignored
1081 } else {
1082 rtl::Reference< Node > member(tmpl->clone(true));
1083 member->setLayer(valueParser_.getLayer());
1084 member->setFinalized(finalizedLayer);
1085 member->setMandatory(mandatoryLayer);
1086 state_.push(State(member, name, false));
1087 recordModification(true);
1088 }
1089 } else {
1090 state_.push(
1091 State(
1092 i->second,
1093 (state_.top().locked ||
1094 finalizedLayer < valueParser_.getLayer())));
1095 }
1096 break;
1097 case OPERATION_REMOVE:
1098 {
1099 // Ignore removal of unknown members, members finalized in a lower
1100 // layer, and members made mandatory in this or a lower layer;
1101 // forget about user-layer removals that no longer remove anything
1102 // (so that paired additions/removals in the user layer do not grow
1103 // registrymodifications.xcu unbounded):
1104 bool known = i != set->getMembers().end();
1105 if (known && !state_.top().locked &&
1106 finalizedLayer >= valueParser_.getLayer() &&
1107 mandatoryLayer > valueParser_.getLayer())
1108 {
1109 set->getMembers().erase(i);
1110 }
1111 state_.push(State(true));
1112 if (known) {
1113 recordModification(false);
1114 }
1115 break;
1116 }
1117 }
1118 }
1119
recordModification(bool addition)1120 void XcuParser::recordModification(bool addition) {
1121 if (broadcastModifications_ != 0) {
1122 broadcastModifications_->add(path_);
1123 }
1124 if (addition && additions_ != 0) {
1125 additions_->push_back(path_);
1126 }
1127 if (recordModifications_) {
1128 data_.modifications.add(path_);
1129 }
1130 }
1131
1132 }
1133