Line data Source code
1 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : /*
3 : * This file is part of the LibreOffice project.
4 : *
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/.
8 : *
9 : * This file incorporates work covered by the following license notice:
10 : *
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 .
18 : */
19 :
20 : #include "sal/config.h"
21 :
22 : #include <algorithm>
23 : #include <cassert>
24 : #include <set>
25 :
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"
39 :
40 : #include "data.hxx"
41 : #include "localizedpropertynode.hxx"
42 : #include "localizedvaluenode.hxx"
43 : #include "groupnode.hxx"
44 : #include "modifications.hxx"
45 : #include "node.hxx"
46 : #include "nodemap.hxx"
47 : #include "parsemanager.hxx"
48 : #include "partial.hxx"
49 : #include "path.hxx"
50 : #include "propertynode.hxx"
51 : #include "setnode.hxx"
52 : #include "xcuparser.hxx"
53 : #include "xmldata.hxx"
54 :
55 : namespace configmgr {
56 :
57 24969 : XcuParser::XcuParser(
58 : int layer, Data & data, Partial const * partial,
59 : Modifications * broadcastModifications, Additions * additions):
60 : valueParser_(layer), data_(data),
61 : partial_(partial), broadcastModifications_(broadcastModifications),
62 24969 : additions_(additions), recordModifications_(layer == Data::NO_LAYER),
63 : trackPath_(
64 24969 : partial_ != 0 || broadcastModifications_ != 0 || additions_ != 0 ||
65 74907 : recordModifications_)
66 24969 : {}
67 :
68 49938 : XcuParser::~XcuParser() {}
69 :
70 15297909 : xmlreader::XmlReader::Text XcuParser::getTextMode() {
71 15297909 : return valueParser_.getTextMode();
72 : }
73 :
74 6431153 : bool XcuParser::startElement(
75 : xmlreader::XmlReader & reader, int nsId, xmlreader::Span const & name,
76 : std::set< OUString > const * existingDependencies)
77 : {
78 6431153 : if (valueParser_.startElement(reader, nsId, name, existingDependencies)) {
79 18861 : return true;
80 : }
81 6412292 : if (state_.empty()) {
82 49872 : if (nsId == ParseManager::NAMESPACE_OOR &&
83 24936 : name.equals("component-data"))
84 : {
85 24884 : handleComponentData(reader);
86 52 : } else if (nsId == ParseManager::NAMESPACE_OOR && name.equals("items"))
87 : {
88 52 : state_.push(State(rtl::Reference< Node >(), false));
89 : } else {
90 : throw css::uno::RuntimeException(
91 0 : ("bad root element <" + name.convertFromUtf8() + "> in " +
92 0 : reader.getUrl()),
93 0 : css::uno::Reference< css::uno::XInterface >());
94 : }
95 6387356 : } else if (state_.top().ignore) {
96 0 : state_.push(State(false));
97 6387356 : } else if (!state_.top().node.is()) {
98 2713 : if (nsId == xmlreader::XmlReader::NAMESPACE_NONE && name.equals("item"))
99 : {
100 2713 : handleItem(reader);
101 : } else {
102 : throw css::uno::RuntimeException(
103 0 : ("bad items node member <" + name.convertFromUtf8() + "> in " +
104 0 : reader.getUrl()),
105 0 : css::uno::Reference< css::uno::XInterface >());
106 : }
107 : } else {
108 6384643 : switch (state_.top().node->kind()) {
109 : case Node::KIND_PROPERTY:
110 3343564 : if (nsId == xmlreader::XmlReader::NAMESPACE_NONE &&
111 1671782 : name.equals("value"))
112 : {
113 : handlePropValue(
114 : reader,
115 1671782 : dynamic_cast< PropertyNode * >(state_.top().node.get()));
116 : } else {
117 : throw css::uno::RuntimeException(
118 0 : ("bad property node member <" + name.convertFromUtf8() +
119 0 : "> in " + reader.getUrl()),
120 0 : css::uno::Reference< css::uno::XInterface >());
121 : }
122 1671782 : break;
123 : case Node::KIND_LOCALIZED_PROPERTY:
124 1797802 : if (nsId == xmlreader::XmlReader::NAMESPACE_NONE &&
125 898901 : name.equals("value"))
126 : {
127 : handleLocpropValue(
128 : reader,
129 : dynamic_cast< LocalizedPropertyNode * >(
130 898901 : state_.top().node.get()));
131 : } else {
132 : throw css::uno::RuntimeException(
133 0 : ("bad localized property node member <" +
134 0 : name.convertFromUtf8() + "> in " + reader.getUrl()),
135 0 : css::uno::Reference< css::uno::XInterface >());
136 : }
137 898901 : break;
138 : case Node::KIND_LOCALIZED_VALUE:
139 : throw css::uno::RuntimeException(
140 0 : ("bad member <" + name.convertFromUtf8() + "> in " +
141 0 : reader.getUrl()),
142 0 : css::uno::Reference< css::uno::XInterface >());
143 : case Node::KIND_GROUP:
144 5655574 : if (nsId == xmlreader::XmlReader::NAMESPACE_NONE &&
145 2827787 : name.equals("prop"))
146 : {
147 : handleGroupProp(
148 : reader,
149 2723737 : dynamic_cast< GroupNode * >(state_.top().node.get()));
150 208100 : } else if (nsId == xmlreader::XmlReader::NAMESPACE_NONE &&
151 104050 : name.equals("node"))
152 : {
153 104050 : handleGroupNode(reader, state_.top().node);
154 : } else {
155 : throw css::uno::RuntimeException(
156 0 : ("bad group node member <" + name.convertFromUtf8() +
157 0 : "> in " + reader.getUrl()),
158 0 : css::uno::Reference< css::uno::XInterface >());
159 : }
160 2827787 : break;
161 : case Node::KIND_SET:
162 1972346 : if (nsId == xmlreader::XmlReader::NAMESPACE_NONE &&
163 986173 : name.equals("node"))
164 : {
165 : handleSetNode(
166 986173 : reader, dynamic_cast< SetNode * >(state_.top().node.get()));
167 0 : } else if (nsId == xmlreader::XmlReader::NAMESPACE_NONE &&
168 0 : name.equals("prop"))
169 : {
170 : SAL_WARN(
171 : "configmgr",
172 : "bad set node <prop> member in \"" << reader.getUrl()
173 : << '"');
174 0 : state_.push(State(true)); // ignored
175 : } else {
176 : throw css::uno::RuntimeException(
177 0 : ("bad set node member <" + name.convertFromUtf8() +
178 0 : "> in " + reader.getUrl()),
179 0 : css::uno::Reference< css::uno::XInterface >());
180 : }
181 986173 : break;
182 : case Node::KIND_ROOT:
183 : assert(false); // this cannot happen
184 0 : break;
185 : }
186 : }
187 6412292 : return true;
188 : }
189 :
190 6431153 : void XcuParser::endElement(xmlreader::XmlReader const &) {
191 6431153 : if (valueParser_.endElement()) {
192 9016163 : return;
193 : }
194 : assert(!state_.empty());
195 3846143 : bool pop = state_.top().pop;
196 3846143 : rtl::Reference< Node > insert;
197 7692286 : OUString name;
198 3846143 : if (state_.top().insert) {
199 1014964 : insert = state_.top().node;
200 : assert(insert.is());
201 1014964 : name = state_.top().name;
202 : }
203 3846143 : state_.pop();
204 3846143 : if (insert.is()) {
205 : assert(!state_.empty() && state_.top().node.is());
206 1014964 : state_.top().node->getMembers()[name] = insert;
207 : }
208 3846143 : if (pop && !path_.empty()) {
209 7198 : path_.pop_back();
210 : // </item> will pop less than <item> pushed, but that is harmless,
211 : // as the next <item> will reset path_
212 3846143 : }
213 : }
214 :
215 2439343 : void XcuParser::characters(xmlreader::Span const & text) {
216 2439343 : valueParser_.characters(text);
217 2439343 : }
218 :
219 1018018 : XcuParser::Operation XcuParser::parseOperation(xmlreader::Span const & text) {
220 : assert(text.is());
221 1018018 : if (text.equals("modify")) {
222 0 : return OPERATION_MODIFY;
223 : }
224 1018018 : if (text.equals("replace")) {
225 1004902 : return OPERATION_REPLACE;
226 : }
227 13116 : if (text.equals("fuse")) {
228 13116 : return OPERATION_FUSE;
229 : }
230 0 : if (text.equals("remove")) {
231 0 : return OPERATION_REMOVE;
232 : }
233 : throw css::uno::RuntimeException(
234 0 : "invalid op " + text.convertFromUtf8(),
235 0 : css::uno::Reference< css::uno::XInterface >());
236 : }
237 :
238 24884 : void XcuParser::handleComponentData(xmlreader::XmlReader & reader) {
239 24884 : OStringBuffer buf;
240 24884 : buf.append('.');
241 24884 : bool hasPackage = false;
242 24884 : bool hasName = false;
243 24884 : Operation op = OPERATION_MODIFY;
244 24884 : bool finalized = false;
245 : for (;;) {
246 : int attrNsId;
247 74652 : xmlreader::Span attrLn;
248 74652 : if (!reader.nextAttribute(&attrNsId, &attrLn)) {
249 24884 : break;
250 : }
251 49768 : if (attrNsId == ParseManager::NAMESPACE_OOR && attrLn.equals("package"))
252 : {
253 24884 : if (hasPackage) {
254 : throw css::uno::RuntimeException(
255 0 : ("multiple component-update package attributes in " +
256 0 : reader.getUrl()),
257 0 : css::uno::Reference< css::uno::XInterface >());
258 : }
259 24884 : hasPackage = true;
260 24884 : xmlreader::Span s(reader.getAttributeValue(false));
261 24884 : buf.insert(0, s.begin, s.length);
262 49768 : } else if (attrNsId == ParseManager::NAMESPACE_OOR &&
263 24884 : attrLn.equals("name"))
264 : {
265 24884 : if (hasName) {
266 : throw css::uno::RuntimeException(
267 0 : ("multiple component-update name attributes in " +
268 0 : reader.getUrl()),
269 0 : css::uno::Reference< css::uno::XInterface >());
270 : }
271 24884 : hasName = true;
272 24884 : xmlreader::Span s(reader.getAttributeValue(false));
273 24884 : buf.append(s.begin, s.length);
274 0 : } else if (attrNsId == ParseManager::NAMESPACE_OOR &&
275 0 : attrLn.equals("op"))
276 : {
277 0 : op = parseOperation(reader.getAttributeValue(true));
278 0 : } else if (attrNsId == ParseManager::NAMESPACE_OOR &&
279 0 : attrLn.equals("finalized"))
280 : {
281 0 : finalized = xmldata::parseBoolean(reader.getAttributeValue(true));
282 : }
283 49768 : }
284 24884 : if (!hasPackage) {
285 : throw css::uno::RuntimeException(
286 0 : "no component-data package attribute in " + reader.getUrl(),
287 0 : css::uno::Reference< css::uno::XInterface >());
288 : }
289 24884 : if (!hasName) {
290 : throw css::uno::RuntimeException(
291 0 : "no component-data name attribute in " + reader.getUrl(),
292 0 : css::uno::Reference< css::uno::XInterface >());
293 : }
294 49768 : componentName_ = xmlreader::Span(buf.getStr(), buf.getLength()).
295 24884 : convertFromUtf8();
296 24884 : if (trackPath_) {
297 : assert(path_.empty());
298 0 : path_.push_back(componentName_);
299 0 : if (partial_ != 0 && partial_->contains(path_) == Partial::CONTAINS_NOT)
300 : {
301 0 : state_.push(State(true)); // ignored
302 0 : return;
303 : }
304 : }
305 : rtl::Reference< Node > node(
306 : Data::findNode(
307 49768 : valueParser_.getLayer(), data_.getComponents(), componentName_));
308 24884 : if (!node.is()) {
309 : SAL_WARN(
310 : "configmgr",
311 : "unknown component \"" << componentName_ << "\" in \""
312 : << reader.getUrl() << '"');
313 0 : state_.push(State(true)); // ignored
314 0 : return;
315 : }
316 24884 : switch (op) {
317 : case OPERATION_MODIFY:
318 : case OPERATION_FUSE:
319 24884 : break;
320 : default:
321 : throw css::uno::RuntimeException(
322 0 : "invalid operation on root node in " + reader.getUrl(),
323 0 : css::uno::Reference< css::uno::XInterface >());
324 : }
325 : int finalizedLayer = std::min(
326 0 : finalized ? valueParser_.getLayer() : Data::NO_LAYER,
327 24884 : node->getFinalized());
328 24884 : node->setFinalized(finalizedLayer);
329 49768 : state_.push(State(node, finalizedLayer < valueParser_.getLayer()));
330 : }
331 :
332 2713 : void XcuParser::handleItem(xmlreader::XmlReader & reader) {
333 2713 : xmlreader::Span attrPath;
334 : for (;;) {
335 : int attrNsId;
336 5426 : xmlreader::Span attrLn;
337 5426 : if (!reader.nextAttribute(&attrNsId, &attrLn)) {
338 2713 : break;
339 : }
340 2713 : if (attrNsId == ParseManager::NAMESPACE_OOR && attrLn.equals("path")) {
341 2713 : attrPath = reader.getAttributeValue(false);
342 : }
343 2713 : }
344 2713 : if (!attrPath.is()) {
345 : throw css::uno::RuntimeException(
346 0 : "missing path attribute in " + reader.getUrl(),
347 0 : css::uno::Reference< css::uno::XInterface >());
348 : }
349 2713 : OUString path(attrPath.convertFromUtf8());
350 : int finalizedLayer;
351 : rtl::Reference< Node > node(
352 : data_.resolvePathRepresentation(
353 5426 : path, 0, &path_, &finalizedLayer));
354 2713 : if (!node.is()) {
355 : SAL_WARN(
356 : "configmgr",
357 : "unknown item \"" << path << "\" in \"" << reader.getUrl() << '"');
358 0 : state_.push(State(true)); // ignored
359 0 : return;
360 : }
361 : assert(!path_.empty());
362 2713 : componentName_ = path_.front();
363 2713 : if (trackPath_) {
364 2713 : if (partial_ != 0 && partial_->contains(path_) == Partial::CONTAINS_NOT)
365 : {
366 0 : state_.push(State(true)); // ignored
367 0 : return;
368 : }
369 : } else {
370 0 : path_.clear();
371 : }
372 2713 : switch (node->kind()) {
373 : case Node::KIND_PROPERTY:
374 : case Node::KIND_LOCALIZED_VALUE:
375 : SAL_WARN(
376 : "configmgr",
377 : "item of bad type \"" << path << "\" in \"" << reader.getUrl()
378 : << '"');
379 0 : state_.push(State(true)); // ignored
380 0 : return;
381 : case Node::KIND_LOCALIZED_PROPERTY:
382 : valueParser_.type_ = dynamic_cast< LocalizedPropertyNode * >(
383 40 : node.get())->getStaticType();
384 40 : break;
385 : default:
386 2673 : break;
387 : }
388 5426 : state_.push(State(node, finalizedLayer < valueParser_.getLayer()));
389 : }
390 :
391 1671782 : void XcuParser::handlePropValue(
392 : xmlreader::XmlReader & reader, PropertyNode * prop)
393 : {
394 1671782 : bool nil = false;
395 1671782 : OString separator;
396 3343564 : OUString external;
397 : for (;;) {
398 : int attrNsId;
399 1691778 : xmlreader::Span attrLn;
400 1691778 : if (!reader.nextAttribute(&attrNsId, &attrLn)) {
401 1671782 : break;
402 : }
403 19996 : if (attrNsId == ParseManager::NAMESPACE_XSI && attrLn.equals("nil")) {
404 190 : nil = xmldata::parseBoolean(reader.getAttributeValue(true));
405 39612 : } else if (attrNsId == ParseManager::NAMESPACE_OOR &&
406 19806 : attrLn.equals("type"))
407 : {
408 : Type type = xmldata::parseType(
409 0 : reader, reader.getAttributeValue(true));
410 0 : if (valueParser_.type_ != TYPE_ANY && type != valueParser_.type_) {
411 : throw css::uno::RuntimeException(
412 0 : "invalid value type in " + reader.getUrl(),
413 0 : css::uno::Reference< css::uno::XInterface >());
414 : }
415 0 : valueParser_.type_ = type;
416 39612 : } else if (attrNsId == ParseManager::NAMESPACE_OOR &&
417 19806 : attrLn.equals("separator"))
418 : {
419 15462 : xmlreader::Span s(reader.getAttributeValue(false));
420 15462 : if (s.length == 0) {
421 : throw css::uno::RuntimeException(
422 0 : "bad oor:separator attribute in " + reader.getUrl(),
423 0 : css::uno::Reference< css::uno::XInterface >());
424 : }
425 15462 : separator = OString(s.begin, s.length);
426 8688 : } else if (attrNsId == ParseManager::NAMESPACE_OOR &&
427 4344 : attrLn.equals("external"))
428 : {
429 4344 : external = reader.getAttributeValue(true).convertFromUtf8();
430 4344 : if (external.isEmpty()) {
431 : throw css::uno::RuntimeException(
432 0 : "bad oor:external attribute value in " + reader.getUrl(),
433 0 : css::uno::Reference< css::uno::XInterface >());
434 : }
435 : }
436 19996 : }
437 1671782 : if (nil) {
438 190 : if (!prop->isNillable()) {
439 : throw css::uno::RuntimeException(
440 0 : "xsi:nil attribute for non-nillable prop in " + reader.getUrl(),
441 0 : css::uno::Reference< css::uno::XInterface >());
442 : }
443 190 : if (!external.isEmpty()) {
444 : throw css::uno::RuntimeException(
445 0 : ("xsi:nil and oor:external attributes for prop in " +
446 0 : reader.getUrl()),
447 0 : css::uno::Reference< css::uno::XInterface >());
448 : }
449 190 : prop->setValue(valueParser_.getLayer(), css::uno::Any());
450 190 : state_.push(State(false));
451 1671592 : } else if (external.isEmpty()) {
452 1667248 : valueParser_.separator_ = separator;
453 1667248 : valueParser_.start(prop);
454 : } else {
455 4344 : prop->setExternal(valueParser_.getLayer(), external);
456 4344 : state_.push(State(false));
457 1671782 : }
458 1671782 : }
459 :
460 898901 : void XcuParser::handleLocpropValue(
461 : xmlreader::XmlReader & reader, LocalizedPropertyNode * locprop)
462 : {
463 898901 : OUString name;
464 898901 : bool nil = false;
465 1797802 : OString separator;
466 898901 : Operation op = OPERATION_FUSE;
467 : for (;;) {
468 : int attrNsId;
469 1754681 : xmlreader::Span attrLn;
470 1754681 : if (!reader.nextAttribute(&attrNsId, &attrLn)) {
471 898901 : break;
472 : }
473 1710971 : if (attrNsId == xmlreader::XmlReader::NAMESPACE_XML &&
474 855191 : attrLn.equals("lang"))
475 : {
476 855191 : name = reader.getAttributeValue(false).convertFromUtf8();
477 589 : } else if (attrNsId == ParseManager::NAMESPACE_XSI &&
478 0 : attrLn.equals("nil"))
479 : {
480 0 : nil = xmldata::parseBoolean(reader.getAttributeValue(true));
481 1178 : } else if (attrNsId == ParseManager::NAMESPACE_OOR &&
482 589 : attrLn.equals("type"))
483 : {
484 : Type type = xmldata::parseType(
485 0 : reader, reader.getAttributeValue(true));
486 0 : if (valueParser_.type_ != TYPE_ANY && type != valueParser_.type_) {
487 : throw css::uno::RuntimeException(
488 0 : "invalid value type in " + reader.getUrl(),
489 0 : css::uno::Reference< css::uno::XInterface >());
490 : }
491 0 : valueParser_.type_ = type;
492 1178 : } else if (attrNsId == ParseManager::NAMESPACE_OOR &&
493 589 : attrLn.equals("separator"))
494 : {
495 589 : xmlreader::Span s(reader.getAttributeValue(false));
496 589 : if (s.length == 0) {
497 : throw css::uno::RuntimeException(
498 0 : "bad oor:separator attribute in " + reader.getUrl(),
499 0 : css::uno::Reference< css::uno::XInterface >());
500 : }
501 589 : separator = OString(s.begin, s.length);
502 0 : } else if (attrNsId == ParseManager::NAMESPACE_OOR &&
503 0 : attrLn.equals("op"))
504 : {
505 0 : op = parseOperation(reader.getAttributeValue(true));
506 : }
507 855780 : }
508 898901 : if (trackPath_) {
509 40 : path_.push_back(name);
510 40 : if (partial_ != 0 &&
511 0 : partial_->contains(path_) != Partial::CONTAINS_NODE)
512 : {
513 0 : state_.push(State(true)); // ignored
514 0 : return;
515 : }
516 : }
517 898901 : NodeMap & members = locprop->getMembers();
518 898901 : NodeMap::iterator i(members.find(name));
519 898901 : if (i != members.end() && i->second->getLayer() > valueParser_.getLayer()) {
520 0 : state_.push(State(true)); // ignored
521 0 : return;
522 : }
523 898901 : if (nil && !locprop->isNillable()) {
524 : throw css::uno::RuntimeException(
525 0 : "xsi:nil attribute for non-nillable prop in " + reader.getUrl(),
526 0 : css::uno::Reference< css::uno::XInterface >());
527 : }
528 898901 : switch (op) {
529 : case OPERATION_FUSE:
530 : {
531 898901 : bool pop = false;
532 898901 : if (nil) {
533 0 : if (i == members.end()) {
534 0 : members[name] = new LocalizedValueNode(
535 0 : valueParser_.getLayer(), css::uno::Any());
536 : } else {
537 : dynamic_cast< LocalizedValueNode * >(
538 0 : i->second.get())->setValue(
539 0 : valueParser_.getLayer(), css::uno::Any());
540 : }
541 0 : state_.push(State(true));
542 : } else {
543 898901 : valueParser_.separator_ = separator;
544 898901 : valueParser_.start(locprop, name);
545 898901 : pop = true;
546 : }
547 898901 : if (trackPath_) {
548 40 : recordModification(false);
549 40 : if (pop) {
550 40 : path_.pop_back();
551 : }
552 : }
553 : }
554 898901 : break;
555 : case OPERATION_REMOVE:
556 : //TODO: only allow if parent.op == OPERATION_FUSE
557 : //TODO: disallow removing when e.g. lang=""?
558 0 : if (i != members.end()) {
559 0 : members.erase(i);
560 : }
561 0 : state_.push(State(true));
562 0 : recordModification(false);
563 0 : break;
564 : default:
565 : throw css::uno::RuntimeException(
566 0 : "bad op attribute for value element in " + reader.getUrl(),
567 0 : css::uno::Reference< css::uno::XInterface >());
568 898901 : }
569 : }
570 :
571 2723737 : void XcuParser::handleGroupProp(
572 : xmlreader::XmlReader & reader, GroupNode * group)
573 : {
574 2723737 : bool hasName = false;
575 2723737 : OUString name;
576 2723737 : Type type = TYPE_ERROR;
577 2723737 : Operation op = OPERATION_MODIFY;
578 2723737 : bool finalized = false;
579 : for (;;) {
580 : int attrNsId;
581 6460919 : xmlreader::Span attrLn;
582 6460919 : if (!reader.nextAttribute(&attrNsId, &attrLn)) {
583 2723737 : break;
584 : }
585 3737182 : if (attrNsId == ParseManager::NAMESPACE_OOR && attrLn.equals("name")) {
586 2723737 : hasName = true;
587 2723737 : name = reader.getAttributeValue(false).convertFromUtf8();
588 2026890 : } else if (attrNsId == ParseManager::NAMESPACE_OOR &&
589 1013445 : attrLn.equals("type"))
590 : {
591 955899 : type = xmldata::parseType(reader, reader.getAttributeValue(true));
592 115092 : } else if (attrNsId == ParseManager::NAMESPACE_OOR &&
593 57546 : attrLn.equals("op"))
594 : {
595 43512 : op = parseOperation(reader.getAttributeValue(true));
596 28068 : } else if (attrNsId == ParseManager::NAMESPACE_OOR &&
597 14034 : attrLn.equals("finalized"))
598 : {
599 14034 : finalized = xmldata::parseBoolean(reader.getAttributeValue(true));
600 : }
601 3737182 : }
602 2723737 : if (!hasName) {
603 : throw css::uno::RuntimeException(
604 0 : "no prop name attribute in " + reader.getUrl(),
605 0 : css::uno::Reference< css::uno::XInterface >());
606 : }
607 2723737 : if (trackPath_) {
608 3625 : path_.push_back(name);
609 : //TODO: This ignores locprop values for which specific include paths
610 : // exist (i.e., for which contains(locprop path) = CONTAINS_SUBNODES):
611 3625 : if (partial_ != 0 &&
612 0 : partial_->contains(path_) != Partial::CONTAINS_NODE)
613 : {
614 0 : state_.push(State(true)); // ignored
615 2723737 : return;
616 : }
617 : }
618 2723737 : NodeMap & members = group->getMembers();
619 2723737 : NodeMap::iterator i(members.find(name));
620 2723737 : if (i == members.end()) {
621 40611 : handleUnknownGroupProp(reader, group, name, type, op, finalized);
622 : } else {
623 2683126 : switch (i->second->kind()) {
624 : case Node::KIND_PROPERTY:
625 1767848 : handlePlainGroupProp(reader, group, i, name, type, op, finalized);
626 1767848 : break;
627 : case Node::KIND_LOCALIZED_PROPERTY:
628 : handleLocalizedGroupProp(
629 : reader,
630 915278 : dynamic_cast< LocalizedPropertyNode * >(i->second.get()), name,
631 1830556 : type, op, finalized);
632 915278 : break;
633 : default:
634 : throw css::uno::RuntimeException(
635 0 : "inappropriate prop " + name + " in " + reader.getUrl(),
636 0 : css::uno::Reference< css::uno::XInterface >());
637 : }
638 2723737 : }
639 : }
640 :
641 40611 : void XcuParser::handleUnknownGroupProp(
642 : xmlreader::XmlReader const & reader, GroupNode * group,
643 : OUString const & name, Type type, Operation operation, bool finalized)
644 : {
645 40611 : switch (operation) {
646 : case OPERATION_REPLACE:
647 : case OPERATION_FUSE:
648 40611 : if (group->isExtensible()) {
649 40611 : if (type == TYPE_ERROR) {
650 : throw css::uno::RuntimeException(
651 0 : ("missing type attribute for prop " + name + " in " +
652 0 : reader.getUrl()),
653 0 : css::uno::Reference< css::uno::XInterface >());
654 : }
655 40611 : valueParser_.type_ = type;
656 : rtl::Reference< Node > prop(
657 : new PropertyNode(
658 40611 : valueParser_.getLayer(), TYPE_ANY, true, css::uno::Any(),
659 40611 : true));
660 40611 : if (finalized) {
661 0 : prop->setFinalized(valueParser_.getLayer());
662 : }
663 40611 : state_.push(State(prop, name, state_.top().locked));
664 40611 : recordModification(false);
665 40611 : break;
666 : }
667 : // fall through
668 : default:
669 : SAL_WARN(
670 : "configmgr",
671 : "unknown property \"" << name << "\" in \"" << reader.getUrl()
672 : << '"');
673 0 : state_.push(State(true)); // ignored
674 0 : break;
675 : }
676 40611 : }
677 :
678 1767848 : void XcuParser::handlePlainGroupProp(
679 : xmlreader::XmlReader const & reader, GroupNode * group,
680 : NodeMap::iterator const & propertyIndex, OUString const & name,
681 : Type type, Operation operation, bool finalized)
682 : {
683 : PropertyNode * property = dynamic_cast< PropertyNode * >(
684 1767848 : propertyIndex->second.get());
685 1767848 : if (property->getLayer() > valueParser_.getLayer()) {
686 0 : state_.push(State(true)); // ignored
687 1767848 : return;
688 : }
689 : int finalizedLayer = std::min(
690 14034 : finalized ? valueParser_.getLayer() : Data::NO_LAYER,
691 1781882 : property->getFinalized());
692 1767848 : property->setFinalized(finalizedLayer);
693 2213526 : if (type != TYPE_ERROR && property->getStaticType() != TYPE_ANY &&
694 445678 : type != property->getStaticType())
695 : {
696 : throw css::uno::RuntimeException(
697 0 : "invalid type for prop " + name + " in " + reader.getUrl(),
698 0 : css::uno::Reference< css::uno::XInterface >());
699 : }
700 1767848 : valueParser_.type_ = type == TYPE_ERROR ? property->getStaticType() : type;
701 1767848 : switch (operation) {
702 : case OPERATION_MODIFY:
703 : case OPERATION_REPLACE:
704 : case OPERATION_FUSE:
705 : state_.push(
706 : State(
707 : property,
708 3535696 : (state_.top().locked ||
709 3535696 : finalizedLayer < valueParser_.getLayer())));
710 1767848 : recordModification(false);
711 1767848 : break;
712 : case OPERATION_REMOVE:
713 0 : if (!property->isExtension()) {
714 : throw css::uno::RuntimeException(
715 0 : ("invalid remove of non-extension prop " + name + " in " +
716 0 : reader.getUrl()),
717 0 : css::uno::Reference< css::uno::XInterface >());
718 : }
719 0 : group->getMembers().erase(propertyIndex);
720 0 : state_.push(State(true)); // ignore children
721 0 : recordModification(false);
722 0 : break;
723 : }
724 : }
725 :
726 915278 : void XcuParser::handleLocalizedGroupProp(
727 : xmlreader::XmlReader const & reader, LocalizedPropertyNode * property,
728 : OUString const & name, Type type, Operation operation, bool finalized)
729 : {
730 915278 : if (property->getLayer() > valueParser_.getLayer()) {
731 0 : state_.push(State(true)); // ignored
732 915278 : return;
733 : }
734 : int finalizedLayer = std::min(
735 0 : finalized ? valueParser_.getLayer() : Data::NO_LAYER,
736 915278 : property->getFinalized());
737 915278 : property->setFinalized(finalizedLayer);
738 1375196 : if (type != TYPE_ERROR && property->getStaticType() != TYPE_ANY &&
739 459918 : type != property->getStaticType())
740 : {
741 : throw css::uno::RuntimeException(
742 0 : "invalid type for prop " + name + " in " + reader.getUrl(),
743 0 : css::uno::Reference< css::uno::XInterface >());
744 : }
745 915278 : valueParser_.type_ = type == TYPE_ERROR ? property->getStaticType() : type;
746 915278 : switch (operation) {
747 : case OPERATION_MODIFY:
748 : case OPERATION_FUSE:
749 : state_.push(
750 : State(
751 : property,
752 1830556 : (state_.top().locked ||
753 1830556 : finalizedLayer < valueParser_.getLayer())));
754 915278 : break;
755 : case OPERATION_REPLACE:
756 : {
757 : rtl::Reference< Node > replacement(
758 : new LocalizedPropertyNode(
759 0 : valueParser_.getLayer(), property->getStaticType(),
760 0 : property->isNillable()));
761 0 : replacement->setFinalized(property->getFinalized());
762 : state_.push(
763 : State(
764 : replacement, name,
765 0 : (state_.top().locked ||
766 0 : finalizedLayer < valueParser_.getLayer())));
767 0 : recordModification(false);
768 : }
769 0 : break;
770 : case OPERATION_REMOVE:
771 : throw css::uno::RuntimeException(
772 0 : ("invalid remove of non-extension prop " + name + " in " +
773 0 : reader.getUrl()),
774 0 : css::uno::Reference< css::uno::XInterface >());
775 : }
776 : }
777 :
778 104050 : void XcuParser::handleGroupNode(
779 : xmlreader::XmlReader & reader, rtl::Reference< Node > const & group)
780 : {
781 104050 : bool hasName = false;
782 104050 : OUString name;
783 104050 : Operation op = OPERATION_MODIFY;
784 104050 : bool finalized = false;
785 : for (;;) {
786 : int attrNsId;
787 209324 : xmlreader::Span attrLn;
788 209324 : if (!reader.nextAttribute(&attrNsId, &attrLn)) {
789 104050 : break;
790 : }
791 105274 : if (attrNsId == ParseManager::NAMESPACE_OOR && attrLn.equals("name")) {
792 104050 : hasName = true;
793 104050 : name = reader.getAttributeValue(false).convertFromUtf8();
794 2448 : } else if (attrNsId == ParseManager::NAMESPACE_OOR &&
795 1224 : attrLn.equals("op"))
796 : {
797 153 : op = parseOperation(reader.getAttributeValue(true));
798 2142 : } else if (attrNsId == ParseManager::NAMESPACE_OOR &&
799 1071 : attrLn.equals("finalized"))
800 : {
801 765 : finalized = xmldata::parseBoolean(reader.getAttributeValue(true));
802 : }
803 105274 : }
804 104050 : if (!hasName) {
805 : throw css::uno::RuntimeException(
806 0 : "no node name attribute in " + reader.getUrl(),
807 0 : css::uno::Reference< css::uno::XInterface >());
808 : }
809 104050 : if (trackPath_) {
810 298 : path_.push_back(name);
811 298 : if (partial_ != 0 && partial_->contains(path_) == Partial::CONTAINS_NOT)
812 : {
813 0 : state_.push(State(true)); // ignored
814 0 : return;
815 : }
816 : }
817 : rtl::Reference< Node > child(
818 208100 : Data::findNode(valueParser_.getLayer(), group->getMembers(), name));
819 104050 : if (!child.is()) {
820 : SAL_WARN(
821 : "configmgr",
822 : "unknown node \"" << name << "\" in \"" << reader.getUrl() << '"');
823 0 : state_.push(State(true)); // ignored
824 0 : return;
825 : }
826 104050 : Node::Kind kind = child->kind();
827 104050 : if (kind != Node::KIND_GROUP && kind != Node::KIND_SET) {
828 : throw css::uno::RuntimeException(
829 0 : ("bad <node> \"" + name + "\" of non group/set kind in " +
830 0 : reader.getUrl()),
831 0 : css::uno::Reference< css::uno::XInterface >());
832 : }
833 104050 : if (op != OPERATION_MODIFY && op != OPERATION_FUSE) {
834 : throw css::uno::RuntimeException(
835 0 : "invalid operation on group node in " + reader.getUrl(),
836 0 : css::uno::Reference< css::uno::XInterface >());
837 : }
838 : int finalizedLayer = std::min(
839 765 : finalized ? valueParser_.getLayer() : Data::NO_LAYER,
840 104815 : child->getFinalized());
841 104050 : child->setFinalized(finalizedLayer);
842 : state_.push(
843 : State(
844 : child,
845 208100 : state_.top().locked || finalizedLayer < valueParser_.getLayer()));
846 : }
847 :
848 986173 : void XcuParser::handleSetNode(xmlreader::XmlReader & reader, SetNode * set) {
849 986173 : bool hasName = false;
850 986173 : OUString name;
851 1972346 : OUString component(componentName_);
852 986173 : bool hasNodeType = false;
853 1972346 : OUString nodeType;
854 986173 : Operation op = OPERATION_MODIFY;
855 986173 : bool finalized = false;
856 986173 : bool mandatory = false;
857 : for (;;) {
858 : int attrNsId;
859 2953087 : xmlreader::Span attrLn;
860 2953087 : if (!reader.nextAttribute(&attrNsId, &attrLn)) {
861 986173 : break;
862 : }
863 1966914 : if (attrNsId == ParseManager::NAMESPACE_OOR && attrLn.equals("name")) {
864 986173 : hasName = true;
865 986173 : name = reader.getAttributeValue(false).convertFromUtf8();
866 1961482 : } else if (attrNsId == ParseManager::NAMESPACE_OOR &&
867 980741 : attrLn.equals("component"))
868 : {
869 0 : component = reader.getAttributeValue(false).convertFromUtf8();
870 1961482 : } else if (attrNsId == ParseManager::NAMESPACE_OOR &&
871 980741 : attrLn.equals("node-type"))
872 : {
873 0 : hasNodeType = true;
874 0 : nodeType = reader.getAttributeValue(false).convertFromUtf8();
875 1961482 : } else if (attrNsId == ParseManager::NAMESPACE_OOR &&
876 980741 : attrLn.equals("op"))
877 : {
878 974353 : op = parseOperation(reader.getAttributeValue(true));
879 12776 : } else if (attrNsId == ParseManager::NAMESPACE_OOR &&
880 6388 : attrLn.equals("finalized"))
881 : {
882 826 : finalized = xmldata::parseBoolean(reader.getAttributeValue(true));
883 11124 : } else if (attrNsId == ParseManager::NAMESPACE_OOR &&
884 5562 : attrLn.equals("mandatory"))
885 : {
886 5307 : mandatory = xmldata::parseBoolean(reader.getAttributeValue(true));
887 : }
888 1966914 : }
889 986173 : if (!hasName) {
890 : throw css::uno::RuntimeException(
891 0 : "no node name attribute in " + reader.getUrl(),
892 0 : css::uno::Reference< css::uno::XInterface >());
893 : }
894 986173 : if (trackPath_) {
895 510 : path_.push_back(name);
896 510 : if (partial_ != 0 && partial_->contains(path_) == Partial::CONTAINS_NOT)
897 : {
898 0 : state_.push(State(true)); // ignored
899 0 : return;
900 : }
901 : }
902 : OUString templateName(
903 : xmldata::parseTemplateReference(
904 1972346 : component, hasNodeType, nodeType, &set->getDefaultTemplateName()));
905 986173 : if (!set->isValidTemplate(templateName)) {
906 : throw css::uno::RuntimeException(
907 0 : ("set member node " + name + " references invalid template " +
908 0 : templateName + " in " + reader.getUrl()),
909 0 : css::uno::Reference< css::uno::XInterface >());
910 : }
911 : rtl::Reference< Node > tmpl(
912 1972346 : data_.getTemplate(valueParser_.getLayer(), templateName));
913 986173 : if (!tmpl.is()) {
914 : throw css::uno::RuntimeException(
915 0 : ("set member node " + name + " references undefined template " +
916 0 : templateName + " in " + reader.getUrl()),
917 0 : css::uno::Reference< css::uno::XInterface >());
918 : }
919 986173 : int finalizedLayer = finalized ? valueParser_.getLayer() : Data::NO_LAYER;
920 986173 : int mandatoryLayer = mandatory ? valueParser_.getLayer() : Data::NO_LAYER;
921 986173 : NodeMap & members = set->getMembers();
922 986173 : NodeMap::iterator i(members.find(name));
923 986173 : if (i != members.end()) {
924 20904 : finalizedLayer = std::min(finalizedLayer, i->second->getFinalized());
925 20904 : i->second->setFinalized(finalizedLayer);
926 20904 : mandatoryLayer = std::min(mandatoryLayer, i->second->getMandatory());
927 20904 : i->second->setMandatory(mandatoryLayer);
928 20904 : if (i->second->getLayer() > valueParser_.getLayer()) {
929 0 : state_.push(State(true)); // ignored
930 0 : return;
931 : }
932 : }
933 986173 : switch (op) {
934 : case OPERATION_MODIFY:
935 11820 : if (i == members.end()) {
936 : SAL_WARN(
937 : "configmgr",
938 : "ignoring modify of unknown set member node \"" << name
939 : << "\" in \"" << reader.getUrl() << '"');
940 0 : state_.push(State(true)); // ignored
941 : } else {
942 : state_.push(
943 : State(
944 11820 : i->second,
945 23640 : (state_.top().locked ||
946 35460 : finalizedLayer < valueParser_.getLayer())));
947 : }
948 11820 : break;
949 : case OPERATION_REPLACE:
950 965015 : if (state_.top().locked || finalizedLayer < valueParser_.getLayer()) {
951 0 : state_.push(State(true)); // ignored
952 : } else {
953 965015 : rtl::Reference< Node > member(tmpl->clone(true));
954 965015 : member->setLayer(valueParser_.getLayer());
955 965015 : member->setFinalized(finalizedLayer);
956 965015 : member->setMandatory(mandatoryLayer);
957 965015 : state_.push(State(member, name, false));
958 965015 : recordModification(i == members.end());
959 : }
960 965015 : break;
961 : case OPERATION_FUSE:
962 9338 : if (i == members.end()) {
963 9338 : if (state_.top().locked || finalizedLayer < valueParser_.getLayer())
964 : {
965 0 : state_.push(State(true)); // ignored
966 : } else {
967 9338 : rtl::Reference< Node > member(tmpl->clone(true));
968 9338 : member->setLayer(valueParser_.getLayer());
969 9338 : member->setFinalized(finalizedLayer);
970 9338 : member->setMandatory(mandatoryLayer);
971 9338 : state_.push(State(member, name, false));
972 9338 : recordModification(true);
973 : }
974 : } else {
975 : state_.push(
976 : State(
977 0 : i->second,
978 0 : (state_.top().locked ||
979 0 : finalizedLayer < valueParser_.getLayer())));
980 : }
981 9338 : break;
982 : case OPERATION_REMOVE:
983 : {
984 : // Ignore removal of unknown members, members finalized in a lower
985 : // layer, and members made mandatory in this or a lower layer;
986 : // forget about user-layer removals that no longer remove anything
987 : // (so that paired additions/removals in the user layer do not grow
988 : // registrymodifications.xcu unbounded):
989 0 : bool known = i != members.end();
990 0 : if (known && !state_.top().locked &&
991 0 : finalizedLayer >= valueParser_.getLayer() &&
992 0 : (mandatoryLayer == Data::NO_LAYER ||
993 0 : mandatoryLayer > valueParser_.getLayer()))
994 : {
995 0 : members.erase(i);
996 : }
997 0 : state_.push(State(true));
998 0 : if (known) {
999 0 : recordModification(false);
1000 : }
1001 0 : break;
1002 : }
1003 986173 : }
1004 : }
1005 :
1006 2782852 : void XcuParser::recordModification(bool addition) {
1007 2782852 : if (broadcastModifications_ != 0) {
1008 0 : broadcastModifications_->add(path_);
1009 : }
1010 2782852 : if (addition && additions_ != 0) {
1011 0 : additions_->push_back(path_);
1012 : }
1013 2782852 : if (recordModifications_) {
1014 4175 : data_.modifications.add(path_);
1015 : }
1016 2782852 : }
1017 :
1018 : }
1019 :
1020 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|