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 48015 : 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 48015 : additions_(additions), recordModifications_(layer == Data::NO_LAYER),
63 : trackPath_(
64 48015 : partial_ != 0 || broadcastModifications_ != 0 || additions_ != 0 ||
65 144045 : recordModifications_)
66 48015 : {}
67 :
68 96030 : XcuParser::~XcuParser() {}
69 :
70 26792447 : xmlreader::XmlReader::Text XcuParser::getTextMode() {
71 26792447 : return valueParser_.getTextMode();
72 : }
73 :
74 11279369 : bool XcuParser::startElement(
75 : xmlreader::XmlReader & reader, int nsId, xmlreader::Span const & name,
76 : std::set< OUString > const * existingDependencies)
77 : {
78 11279369 : if (valueParser_.startElement(reader, nsId, name, existingDependencies)) {
79 31660 : return true;
80 : }
81 11247709 : if (state_.empty()) {
82 95920 : if (nsId == ParseManager::NAMESPACE_OOR &&
83 47960 : name.equals("component-data"))
84 : {
85 47896 : handleComponentData(reader);
86 64 : } else if (nsId == ParseManager::NAMESPACE_OOR && name.equals("items"))
87 : {
88 64 : state_.push(State::Modify(rtl::Reference< Node >()));
89 : } else {
90 : throw css::uno::RuntimeException(
91 0 : "bad root element <" + name.convertFromUtf8() + "> in " +
92 0 : reader.getUrl());
93 : }
94 11199749 : } else if (state_.top().ignore) {
95 714 : state_.push(State::Ignore(false));
96 11199035 : } else if (!state_.top().node.is()) {
97 1903 : if (nsId == xmlreader::XmlReader::NAMESPACE_NONE && name.equals("item"))
98 : {
99 1903 : handleItem(reader);
100 : } else {
101 : throw css::uno::RuntimeException(
102 0 : "bad items node member <" + name.convertFromUtf8() + "> in " +
103 0 : reader.getUrl());
104 : }
105 : } else {
106 11197132 : switch (state_.top().node->kind()) {
107 : case Node::KIND_PROPERTY:
108 5912592 : if (nsId == xmlreader::XmlReader::NAMESPACE_NONE &&
109 2956296 : name.equals("value"))
110 : {
111 : handlePropValue(
112 : reader,
113 2956296 : static_cast< PropertyNode * >(state_.top().node.get()));
114 : } else {
115 : throw css::uno::RuntimeException(
116 0 : "bad property node member <" + name.convertFromUtf8() +
117 0 : "> in " + reader.getUrl());
118 : }
119 2956296 : break;
120 : case Node::KIND_LOCALIZED_PROPERTY:
121 3122984 : if (nsId == xmlreader::XmlReader::NAMESPACE_NONE &&
122 1561492 : name.equals("value"))
123 : {
124 : handleLocpropValue(
125 : reader,
126 : static_cast< LocalizedPropertyNode * >(
127 1561492 : state_.top().node.get()));
128 : } else {
129 : throw css::uno::RuntimeException(
130 0 : "bad localized property node member <" +
131 0 : name.convertFromUtf8() + "> in " + reader.getUrl());
132 : }
133 1561492 : break;
134 : case Node::KIND_LOCALIZED_VALUE:
135 : throw css::uno::RuntimeException(
136 0 : "bad member <" + name.convertFromUtf8() + "> in " +
137 0 : reader.getUrl());
138 : case Node::KIND_GROUP:
139 9997356 : if (nsId == xmlreader::XmlReader::NAMESPACE_NONE &&
140 4998678 : name.equals("prop"))
141 : {
142 : handleGroupProp(
143 : reader,
144 4828511 : static_cast< GroupNode * >(state_.top().node.get()));
145 340334 : } else if (nsId == xmlreader::XmlReader::NAMESPACE_NONE &&
146 170167 : name.equals("node"))
147 : {
148 170167 : handleGroupNode(reader, state_.top().node);
149 : } else {
150 : throw css::uno::RuntimeException(
151 0 : "bad group node member <" + name.convertFromUtf8() +
152 0 : "> in " + reader.getUrl());
153 : }
154 4998678 : break;
155 : case Node::KIND_SET:
156 3361332 : if (nsId == xmlreader::XmlReader::NAMESPACE_NONE &&
157 1680666 : name.equals("node"))
158 : {
159 : handleSetNode(
160 1680666 : reader, static_cast< SetNode * >(state_.top().node.get()));
161 0 : } else if (nsId == xmlreader::XmlReader::NAMESPACE_NONE &&
162 0 : name.equals("prop"))
163 : {
164 : SAL_WARN(
165 : "configmgr",
166 : "bad set node <prop> member in \"" << reader.getUrl()
167 : << '"');
168 0 : state_.push(State::Ignore(true));
169 : } else {
170 : throw css::uno::RuntimeException(
171 0 : "bad set node member <" + name.convertFromUtf8() +
172 0 : "> in " + reader.getUrl());
173 : }
174 1680666 : break;
175 : case Node::KIND_ROOT:
176 : assert(false); // this cannot happen
177 0 : break;
178 : }
179 : }
180 11247709 : return true;
181 : }
182 :
183 11279369 : void XcuParser::endElement(xmlreader::XmlReader const &) {
184 11279369 : if (valueParser_.endElement()) {
185 15823910 : return;
186 : }
187 : assert(!state_.empty());
188 6734828 : bool pop = state_.top().pop;
189 6734828 : rtl::Reference< Node > insert;
190 13469656 : OUString name;
191 6734828 : if (state_.top().insert) {
192 1702845 : insert = state_.top().node;
193 : assert(insert.is());
194 1702845 : name = state_.top().name;
195 : }
196 6734828 : state_.pop();
197 6734828 : if (insert.is()) {
198 : assert(!state_.empty() && state_.top().node.is());
199 1702845 : state_.top().node->getMembers()[name] = insert;
200 : }
201 6734828 : if (pop && !path_.empty()) {
202 4219 : path_.pop_back();
203 : // </item> will pop less than <item> pushed, but that is harmless,
204 : // as the next <item> will reset path_
205 6734828 : }
206 : }
207 :
208 4281541 : void XcuParser::characters(xmlreader::Span const & text) {
209 4281541 : valueParser_.characters(text);
210 4281541 : }
211 :
212 1704914 : XcuParser::Operation XcuParser::parseOperation(xmlreader::Span const & text) {
213 : assert(text.is());
214 1704914 : if (text.equals("modify")) {
215 0 : return OPERATION_MODIFY;
216 : }
217 1704914 : if (text.equals("replace")) {
218 1686973 : return OPERATION_REPLACE;
219 : }
220 17941 : if (text.equals("fuse")) {
221 17941 : return OPERATION_FUSE;
222 : }
223 0 : if (text.equals("remove")) {
224 0 : return OPERATION_REMOVE;
225 : }
226 : throw css::uno::RuntimeException(
227 0 : "invalid op " + text.convertFromUtf8());
228 : }
229 :
230 47896 : void XcuParser::handleComponentData(xmlreader::XmlReader & reader) {
231 47896 : OStringBuffer buf;
232 47896 : buf.append('.');
233 47896 : bool hasPackage = false;
234 47896 : bool hasName = false;
235 47896 : Operation op = OPERATION_MODIFY;
236 47896 : bool finalized = false;
237 : for (;;) {
238 : int attrNsId;
239 143688 : xmlreader::Span attrLn;
240 143688 : if (!reader.nextAttribute(&attrNsId, &attrLn)) {
241 47896 : break;
242 : }
243 95792 : if (attrNsId == ParseManager::NAMESPACE_OOR && attrLn.equals("package"))
244 : {
245 47896 : if (hasPackage) {
246 : throw css::uno::RuntimeException(
247 0 : "multiple component-update package attributes in " +
248 0 : reader.getUrl());
249 : }
250 47896 : hasPackage = true;
251 47896 : xmlreader::Span s(reader.getAttributeValue(false));
252 47896 : buf.insert(0, s.begin, s.length);
253 95792 : } else if (attrNsId == ParseManager::NAMESPACE_OOR &&
254 47896 : attrLn.equals("name"))
255 : {
256 47896 : if (hasName) {
257 : throw css::uno::RuntimeException(
258 0 : "multiple component-update name attributes in " +
259 0 : reader.getUrl());
260 : }
261 47896 : hasName = true;
262 47896 : xmlreader::Span s(reader.getAttributeValue(false));
263 47896 : buf.append(s.begin, s.length);
264 0 : } else if (attrNsId == ParseManager::NAMESPACE_OOR &&
265 0 : attrLn.equals("op"))
266 : {
267 0 : op = parseOperation(reader.getAttributeValue(true));
268 0 : } else if (attrNsId == ParseManager::NAMESPACE_OOR &&
269 0 : attrLn.equals("finalized"))
270 : {
271 0 : finalized = xmldata::parseBoolean(reader.getAttributeValue(true));
272 : }
273 95792 : }
274 47896 : if (!hasPackage) {
275 : throw css::uno::RuntimeException(
276 0 : "no component-data package attribute in " + reader.getUrl());
277 : }
278 47896 : if (!hasName) {
279 : throw css::uno::RuntimeException(
280 0 : "no component-data name attribute in " + reader.getUrl());
281 : }
282 95792 : componentName_ = xmlreader::Span(buf.getStr(), buf.getLength()).
283 47896 : convertFromUtf8();
284 47896 : if (trackPath_) {
285 : assert(path_.empty());
286 0 : path_.push_back(componentName_);
287 0 : if (partial_ != 0 && partial_->contains(path_) == Partial::CONTAINS_NOT)
288 : {
289 0 : state_.push(State::Ignore(true));
290 0 : return;
291 : }
292 : }
293 : rtl::Reference< Node > node(
294 47896 : data_.getComponents().findNode(valueParser_.getLayer(),
295 143450 : componentName_));
296 47896 : if (!node.is()) {
297 : SAL_WARN(
298 : "configmgr",
299 : "unknown component \"" << componentName_ << "\" in \""
300 : << reader.getUrl() << '"');
301 238 : state_.push(State::Ignore(true));
302 238 : return;
303 : }
304 47658 : switch (op) {
305 : case OPERATION_MODIFY:
306 : case OPERATION_FUSE:
307 47658 : break;
308 : default:
309 : throw css::uno::RuntimeException(
310 0 : "invalid operation on root node in " + reader.getUrl());
311 : }
312 : int finalizedLayer = std::min(
313 0 : finalized ? valueParser_.getLayer() : Data::NO_LAYER,
314 47658 : node->getFinalized());
315 47658 : node->setFinalized(finalizedLayer);
316 47658 : if (finalizedLayer < valueParser_.getLayer()) {
317 0 : state_.push(State::Ignore(true));
318 0 : return;
319 : }
320 95316 : state_.push(State::Modify(node));
321 : }
322 :
323 1903 : void XcuParser::handleItem(xmlreader::XmlReader & reader) {
324 1903 : xmlreader::Span attrPath;
325 : for (;;) {
326 : int attrNsId;
327 3806 : xmlreader::Span attrLn;
328 3806 : if (!reader.nextAttribute(&attrNsId, &attrLn)) {
329 1903 : break;
330 : }
331 1903 : if (attrNsId == ParseManager::NAMESPACE_OOR && attrLn.equals("path")) {
332 1903 : attrPath = reader.getAttributeValue(false);
333 : }
334 1903 : }
335 1903 : if (!attrPath.is()) {
336 : throw css::uno::RuntimeException(
337 0 : "missing path attribute in " + reader.getUrl());
338 : }
339 1903 : OUString path(attrPath.convertFromUtf8());
340 : int finalizedLayer;
341 : rtl::Reference< Node > node(
342 : data_.resolvePathRepresentation(
343 3806 : path, 0, &path_, &finalizedLayer));
344 1903 : if (!node.is()) {
345 : SAL_WARN(
346 : "configmgr",
347 : "unknown item \"" << path << "\" in \"" << reader.getUrl() << '"');
348 0 : state_.push(State::Ignore(true));
349 0 : return;
350 : }
351 : assert(!path_.empty());
352 1903 : componentName_ = path_.front();
353 1903 : if (trackPath_) {
354 1903 : if (partial_ != 0 && partial_->contains(path_) == Partial::CONTAINS_NOT)
355 : {
356 0 : state_.push(State::Ignore(true));
357 0 : return;
358 : }
359 : } else {
360 0 : path_.clear();
361 : }
362 1903 : switch (node->kind()) {
363 : case Node::KIND_PROPERTY:
364 : case Node::KIND_LOCALIZED_VALUE:
365 : SAL_WARN(
366 : "configmgr",
367 : "item of bad type \"" << path << "\" in \"" << reader.getUrl()
368 : << '"');
369 0 : state_.push(State::Ignore(true));
370 0 : return;
371 : case Node::KIND_LOCALIZED_PROPERTY:
372 : valueParser_.type_ = static_cast< LocalizedPropertyNode * >(
373 27 : node.get())->getStaticType();
374 27 : break;
375 : default:
376 1876 : break;
377 : }
378 1903 : if (finalizedLayer < valueParser_.getLayer()) {
379 0 : state_.push(State::Ignore(true));
380 0 : return;
381 : }
382 3806 : state_.push(State::Modify(node));
383 : }
384 :
385 2956296 : void XcuParser::handlePropValue(
386 : xmlreader::XmlReader & reader, PropertyNode * prop)
387 : {
388 2956296 : bool nil = false;
389 2956296 : OString separator;
390 5912592 : OUString external;
391 : for (;;) {
392 : int attrNsId;
393 2990203 : xmlreader::Span attrLn;
394 2990203 : if (!reader.nextAttribute(&attrNsId, &attrLn)) {
395 2956296 : break;
396 : }
397 33907 : if (attrNsId == ParseManager::NAMESPACE_XSI && attrLn.equals("nil")) {
398 157 : nil = xmldata::parseBoolean(reader.getAttributeValue(true));
399 65500 : } else if (attrNsId == ParseManager::NAMESPACE_OOR &&
400 31750 : attrLn.equals("type"))
401 : {
402 : Type type = xmldata::parseType(
403 0 : reader, reader.getAttributeValue(true));
404 0 : if (valueParser_.type_ != TYPE_ANY && type != valueParser_.type_) {
405 : throw css::uno::RuntimeException(
406 0 : "invalid value type in " + reader.getUrl());
407 : }
408 0 : valueParser_.type_ = type;
409 65500 : } else if (attrNsId == ParseManager::NAMESPACE_OOR &&
410 31750 : attrLn.equals("separator"))
411 : {
412 27000 : xmlreader::Span s(reader.getAttributeValue(false));
413 27000 : if (s.length == 0) {
414 : throw css::uno::RuntimeException(
415 0 : "bad oor:separator attribute in " + reader.getUrl());
416 : }
417 27000 : separator = OString(s.begin, s.length);
418 11500 : } else if (attrNsId == ParseManager::NAMESPACE_OOR &&
419 4750 : attrLn.equals("external"))
420 : {
421 4750 : external = reader.getAttributeValue(true).convertFromUtf8();
422 4750 : if (external.isEmpty()) {
423 : throw css::uno::RuntimeException(
424 0 : "bad oor:external attribute value in " + reader.getUrl());
425 : }
426 : }
427 33907 : }
428 2956296 : if (nil) {
429 157 : if (!prop->isNillable()) {
430 : throw css::uno::RuntimeException(
431 0 : "xsi:nil attribute for non-nillable prop in " + reader.getUrl());
432 : }
433 157 : if (!external.isEmpty()) {
434 : throw css::uno::RuntimeException(
435 0 : "xsi:nil and oor:external attributes for prop in " +
436 0 : reader.getUrl());
437 : }
438 157 : prop->setValue(valueParser_.getLayer(), css::uno::Any());
439 157 : state_.push(State::Ignore(false));
440 2956139 : } else if (external.isEmpty()) {
441 2951389 : valueParser_.separator_ = separator;
442 2951389 : valueParser_.start(prop);
443 : } else {
444 4750 : prop->setExternal(valueParser_.getLayer(), external);
445 4750 : state_.push(State::Ignore(false));
446 2956296 : }
447 2956296 : }
448 :
449 1561492 : void XcuParser::handleLocpropValue(
450 : xmlreader::XmlReader & reader, LocalizedPropertyNode * locprop)
451 : {
452 1561492 : OUString name;
453 1561492 : bool nil = false;
454 3122984 : OString separator;
455 1561492 : Operation op = OPERATION_FUSE;
456 : for (;;) {
457 : int attrNsId;
458 3030484 : xmlreader::Span attrLn;
459 3030484 : if (!reader.nextAttribute(&attrNsId, &attrLn)) {
460 1561492 : break;
461 : }
462 2936984 : if (attrNsId == xmlreader::XmlReader::NAMESPACE_XML &&
463 1467992 : attrLn.equals("lang"))
464 : {
465 1467992 : name = reader.getAttributeValue(false).convertFromUtf8();
466 1000 : } else if (attrNsId == ParseManager::NAMESPACE_XSI &&
467 0 : attrLn.equals("nil"))
468 : {
469 0 : nil = xmldata::parseBoolean(reader.getAttributeValue(true));
470 2000 : } else if (attrNsId == ParseManager::NAMESPACE_OOR &&
471 1000 : attrLn.equals("type"))
472 : {
473 : Type type = xmldata::parseType(
474 0 : reader, reader.getAttributeValue(true));
475 0 : if (valueParser_.type_ != TYPE_ANY && type != valueParser_.type_) {
476 : throw css::uno::RuntimeException(
477 0 : "invalid value type in " + reader.getUrl());
478 : }
479 0 : valueParser_.type_ = type;
480 2000 : } else if (attrNsId == ParseManager::NAMESPACE_OOR &&
481 1000 : attrLn.equals("separator"))
482 : {
483 1000 : xmlreader::Span s(reader.getAttributeValue(false));
484 1000 : if (s.length == 0) {
485 : throw css::uno::RuntimeException(
486 0 : "bad oor:separator attribute in " + reader.getUrl());
487 : }
488 1000 : separator = OString(s.begin, s.length);
489 0 : } else if (attrNsId == ParseManager::NAMESPACE_OOR &&
490 0 : attrLn.equals("op"))
491 : {
492 0 : op = parseOperation(reader.getAttributeValue(true));
493 : }
494 1468992 : }
495 1561492 : if (trackPath_) {
496 27 : path_.push_back(name);
497 27 : if (partial_ != 0 &&
498 0 : partial_->contains(path_) != Partial::CONTAINS_NODE)
499 : {
500 0 : state_.push(State::Ignore(true));
501 0 : return;
502 : }
503 : }
504 1561492 : NodeMap & members = locprop->getMembers();
505 1561492 : NodeMap::iterator i(members.find(name));
506 1561492 : if (i != members.end() && i->second->getLayer() > valueParser_.getLayer()) {
507 0 : state_.push(State::Ignore(true));
508 0 : return;
509 : }
510 1561492 : if (nil && !locprop->isNillable()) {
511 : throw css::uno::RuntimeException(
512 0 : "xsi:nil attribute for non-nillable prop in " + reader.getUrl());
513 : }
514 1561492 : switch (op) {
515 : case OPERATION_FUSE:
516 : {
517 1561492 : bool pop = false;
518 1561492 : if (nil) {
519 0 : if (i == members.end()) {
520 0 : members[name] = new LocalizedValueNode(
521 0 : valueParser_.getLayer(), css::uno::Any());
522 : } else {
523 : static_cast< LocalizedValueNode * >(
524 0 : i->second.get())->setValue(
525 0 : valueParser_.getLayer(), css::uno::Any());
526 : }
527 0 : state_.push(State::Ignore(true));
528 : } else {
529 1561492 : valueParser_.separator_ = separator;
530 1561492 : valueParser_.start(locprop, name);
531 1561492 : pop = true;
532 : }
533 1561492 : if (trackPath_) {
534 27 : recordModification(false);
535 27 : if (pop) {
536 27 : path_.pop_back();
537 : }
538 : }
539 : }
540 1561492 : break;
541 : case OPERATION_REMOVE:
542 : //TODO: only allow if parent.op == OPERATION_FUSE
543 : //TODO: disallow removing when e.g. lang=""?
544 0 : if (i != members.end()) {
545 0 : members.erase(i);
546 : }
547 0 : state_.push(State::Ignore(true));
548 0 : recordModification(false);
549 0 : break;
550 : default:
551 : throw css::uno::RuntimeException(
552 0 : "bad op attribute for value element in " + reader.getUrl());
553 1561492 : }
554 : }
555 :
556 4828511 : void XcuParser::handleGroupProp(
557 : xmlreader::XmlReader & reader, GroupNode * group)
558 : {
559 4828511 : bool hasName = false;
560 4828511 : OUString name;
561 4828511 : Type type = TYPE_ERROR;
562 4828511 : Operation op = OPERATION_MODIFY;
563 4828511 : bool finalized = false;
564 : for (;;) {
565 : int attrNsId;
566 11352593 : xmlreader::Span attrLn;
567 11352593 : if (!reader.nextAttribute(&attrNsId, &attrLn)) {
568 4828511 : break;
569 : }
570 6524082 : if (attrNsId == ParseManager::NAMESPACE_OOR && attrLn.equals("name")) {
571 4828511 : hasName = true;
572 4828511 : name = reader.getAttributeValue(false).convertFromUtf8();
573 3391142 : } else if (attrNsId == ParseManager::NAMESPACE_OOR &&
574 1695571 : attrLn.equals("type"))
575 : {
576 1603251 : type = xmldata::parseType(reader, reader.getAttributeValue(true));
577 184640 : } else if (attrNsId == ParseManager::NAMESPACE_OOR &&
578 92320 : attrLn.equals("op"))
579 : {
580 66570 : op = parseOperation(reader.getAttributeValue(true));
581 51500 : } else if (attrNsId == ParseManager::NAMESPACE_OOR &&
582 25750 : attrLn.equals("finalized"))
583 : {
584 25750 : finalized = xmldata::parseBoolean(reader.getAttributeValue(true));
585 : }
586 6524082 : }
587 4828511 : if (!hasName) {
588 : throw css::uno::RuntimeException(
589 0 : "no prop name attribute in " + reader.getUrl());
590 : }
591 4828511 : if (trackPath_) {
592 2070 : path_.push_back(name);
593 : //TODO: This ignores locprop values for which specific include paths
594 : // exist (i.e., for which contains(locprop path) = CONTAINS_SUBNODES):
595 2070 : if (partial_ != 0 &&
596 0 : partial_->contains(path_) != Partial::CONTAINS_NODE)
597 : {
598 0 : state_.push(State::Ignore(true));
599 4828511 : return;
600 : }
601 : }
602 4828511 : NodeMap & members = group->getMembers();
603 4828511 : NodeMap::iterator i(members.find(name));
604 4828511 : if (i == members.end()) {
605 64751 : handleUnknownGroupProp(reader, group, name, type, op, finalized);
606 : } else {
607 4763760 : switch (i->second->kind()) {
608 : case Node::KIND_PROPERTY:
609 3177545 : handlePlainGroupProp(reader, group, i, name, type, op, finalized);
610 3177545 : break;
611 : case Node::KIND_LOCALIZED_PROPERTY:
612 : handleLocalizedGroupProp(
613 : reader,
614 1586215 : static_cast< LocalizedPropertyNode * >(i->second.get()), name,
615 3172430 : type, op, finalized);
616 1586215 : break;
617 : default:
618 : throw css::uno::RuntimeException(
619 0 : "inappropriate prop " + name + " in " + reader.getUrl());
620 : }
621 4828511 : }
622 : }
623 :
624 64751 : void XcuParser::handleUnknownGroupProp(
625 : xmlreader::XmlReader const & reader, GroupNode * group,
626 : OUString const & name, Type type, Operation operation, bool finalized)
627 : {
628 64751 : switch (operation) {
629 : case OPERATION_REPLACE:
630 : case OPERATION_FUSE:
631 64751 : if (group->isExtensible()) {
632 64751 : if (type == TYPE_ERROR) {
633 : throw css::uno::RuntimeException(
634 0 : "missing type attribute for prop " + name + " in " +
635 0 : reader.getUrl());
636 : }
637 64751 : valueParser_.type_ = type;
638 : rtl::Reference< Node > prop(
639 : new PropertyNode(
640 64751 : valueParser_.getLayer(), TYPE_ANY, true, css::uno::Any(),
641 64751 : true));
642 64751 : if (finalized) {
643 0 : prop->setFinalized(valueParser_.getLayer());
644 : }
645 64751 : state_.push(State::Insert(prop, name));
646 64751 : recordModification(false);
647 64751 : break;
648 : }
649 : // fall through
650 : default:
651 : SAL_WARN(
652 : "configmgr",
653 : "unknown property \"" << name << "\" in \"" << reader.getUrl()
654 : << '"');
655 0 : state_.push(State::Ignore(true));
656 0 : break;
657 : }
658 64751 : }
659 :
660 3177545 : void XcuParser::handlePlainGroupProp(
661 : xmlreader::XmlReader const & reader, GroupNode * group,
662 : NodeMap::iterator const & propertyIndex, OUString const & name,
663 : Type type, Operation operation, bool finalized)
664 : {
665 : PropertyNode * property = static_cast< PropertyNode * >(
666 3177545 : propertyIndex->second.get());
667 3177545 : if (property->getLayer() > valueParser_.getLayer()) {
668 0 : state_.push(State::Ignore(true));
669 0 : return;
670 : }
671 : int finalizedLayer = std::min(
672 25750 : finalized ? valueParser_.getLayer() : Data::NO_LAYER,
673 3203295 : property->getFinalized());
674 3177545 : property->setFinalized(finalizedLayer);
675 3177545 : if (finalizedLayer < valueParser_.getLayer()) {
676 0 : state_.push(State::Ignore(true));
677 0 : return;
678 : }
679 3935795 : if (type != TYPE_ERROR && property->getStaticType() != TYPE_ANY &&
680 758250 : type != property->getStaticType())
681 : {
682 : throw css::uno::RuntimeException(
683 0 : "invalid type for prop " + name + " in " + reader.getUrl());
684 : }
685 3177545 : valueParser_.type_ = type == TYPE_ERROR ? property->getStaticType() : type;
686 3177545 : switch (operation) {
687 : case OPERATION_MODIFY:
688 : case OPERATION_REPLACE:
689 : case OPERATION_FUSE:
690 3177545 : state_.push(State::Modify(property));
691 3177545 : recordModification(false);
692 3177545 : break;
693 : case OPERATION_REMOVE:
694 0 : if (!property->isExtension()) {
695 : throw css::uno::RuntimeException(
696 0 : "invalid remove of non-extension prop " + name + " in " +
697 0 : reader.getUrl());
698 : }
699 0 : group->getMembers().erase(propertyIndex);
700 0 : state_.push(State::Ignore(true));
701 0 : recordModification(false);
702 0 : break;
703 : }
704 : }
705 :
706 1586215 : void XcuParser::handleLocalizedGroupProp(
707 : xmlreader::XmlReader const & reader, LocalizedPropertyNode * property,
708 : OUString const & name, Type type, Operation operation, bool finalized)
709 : {
710 1586215 : if (property->getLayer() > valueParser_.getLayer()) {
711 0 : state_.push(State::Ignore(true));
712 0 : return;
713 : }
714 : int finalizedLayer = std::min(
715 0 : finalized ? valueParser_.getLayer() : Data::NO_LAYER,
716 1586215 : property->getFinalized());
717 1586215 : property->setFinalized(finalizedLayer);
718 1586215 : if (finalizedLayer < valueParser_.getLayer()) {
719 0 : state_.push(State::Ignore(true));
720 0 : return;
721 : }
722 2348715 : if (type != TYPE_ERROR && property->getStaticType() != TYPE_ANY &&
723 762500 : type != property->getStaticType())
724 : {
725 : throw css::uno::RuntimeException(
726 0 : "invalid type for prop " + name + " in " + reader.getUrl());
727 : }
728 1586215 : valueParser_.type_ = type == TYPE_ERROR ? property->getStaticType() : type;
729 1586215 : switch (operation) {
730 : case OPERATION_MODIFY:
731 : case OPERATION_FUSE:
732 1586215 : state_.push(State::Modify(property));
733 1586215 : break;
734 : case OPERATION_REPLACE:
735 : {
736 : rtl::Reference< Node > replacement(
737 : new LocalizedPropertyNode(
738 0 : valueParser_.getLayer(), property->getStaticType(),
739 0 : property->isNillable()));
740 0 : replacement->setFinalized(property->getFinalized());
741 0 : state_.push(State::Insert(replacement, name));
742 0 : recordModification(false);
743 : }
744 0 : break;
745 : case OPERATION_REMOVE:
746 : throw css::uno::RuntimeException(
747 0 : "invalid remove of non-extension prop " + name + " in " +
748 0 : reader.getUrl());
749 : }
750 : }
751 :
752 170167 : void XcuParser::handleGroupNode(
753 : xmlreader::XmlReader & reader, rtl::Reference< Node > const & group)
754 : {
755 170167 : bool hasName = false;
756 170167 : OUString name;
757 170167 : Operation op = OPERATION_MODIFY;
758 170167 : bool finalized = false;
759 : for (;;) {
760 : int attrNsId;
761 342084 : xmlreader::Span attrLn;
762 342084 : if (!reader.nextAttribute(&attrNsId, &attrLn)) {
763 170167 : break;
764 : }
765 171917 : if (attrNsId == ParseManager::NAMESPACE_OOR && attrLn.equals("name")) {
766 170167 : hasName = true;
767 170167 : name = reader.getAttributeValue(false).convertFromUtf8();
768 3500 : } else if (attrNsId == ParseManager::NAMESPACE_OOR &&
769 1750 : attrLn.equals("op"))
770 : {
771 250 : op = parseOperation(reader.getAttributeValue(true));
772 3000 : } else if (attrNsId == ParseManager::NAMESPACE_OOR &&
773 1500 : attrLn.equals("finalized"))
774 : {
775 1250 : finalized = xmldata::parseBoolean(reader.getAttributeValue(true));
776 : }
777 171917 : }
778 170167 : if (!hasName) {
779 : throw css::uno::RuntimeException(
780 0 : "no node name attribute in " + reader.getUrl());
781 : }
782 170167 : if (trackPath_) {
783 80 : path_.push_back(name);
784 80 : if (partial_ != 0 && partial_->contains(path_) == Partial::CONTAINS_NOT)
785 : {
786 0 : state_.push(State::Ignore(true));
787 0 : return;
788 : }
789 : }
790 : rtl::Reference< Node > child(
791 340334 : group->getMembers().findNode(valueParser_.getLayer(), name));
792 170167 : if (!child.is()) {
793 : SAL_WARN(
794 : "configmgr",
795 : "unknown node \"" << name << "\" in \"" << reader.getUrl() << '"');
796 0 : state_.push(State::Ignore(true));
797 0 : return;
798 : }
799 170167 : Node::Kind kind = child->kind();
800 170167 : if (kind != Node::KIND_GROUP && kind != Node::KIND_SET) {
801 : throw css::uno::RuntimeException(
802 0 : "bad <node> \"" + name + "\" of non group/set kind in " +
803 0 : reader.getUrl());
804 : }
805 170167 : if (op != OPERATION_MODIFY && op != OPERATION_FUSE) {
806 : throw css::uno::RuntimeException(
807 0 : "invalid operation on group node in " + reader.getUrl());
808 : }
809 : int finalizedLayer = std::min(
810 1250 : finalized ? valueParser_.getLayer() : Data::NO_LAYER,
811 171417 : child->getFinalized());
812 170167 : child->setFinalized(finalizedLayer);
813 170167 : if (finalizedLayer < valueParser_.getLayer()) {
814 0 : state_.push(State::Ignore(true));
815 0 : return;
816 : }
817 340334 : state_.push(State::Modify(child));
818 : }
819 :
820 1680666 : void XcuParser::handleSetNode(xmlreader::XmlReader & reader, SetNode * set) {
821 1680666 : bool hasName = false;
822 1680666 : OUString name;
823 3361213 : OUString component(componentName_);
824 1680666 : bool hasNodeType = false;
825 3361213 : OUString nodeType;
826 1680666 : Operation op = OPERATION_MODIFY;
827 1680666 : bool finalized = false;
828 1680666 : bool mandatory = false;
829 : for (;;) {
830 : int attrNsId;
831 5009676 : xmlreader::Span attrLn;
832 5009676 : if (!reader.nextAttribute(&attrNsId, &attrLn)) {
833 1680666 : break;
834 : }
835 3329010 : if (attrNsId == ParseManager::NAMESPACE_OOR && attrLn.equals("name")) {
836 1680666 : hasName = true;
837 1680666 : name = reader.getAttributeValue(false).convertFromUtf8();
838 3296688 : } else if (attrNsId == ParseManager::NAMESPACE_OOR &&
839 1648344 : attrLn.equals("component"))
840 : {
841 0 : component = reader.getAttributeValue(false).convertFromUtf8();
842 3296688 : } else if (attrNsId == ParseManager::NAMESPACE_OOR &&
843 1648344 : attrLn.equals("node-type"))
844 : {
845 0 : hasNodeType = true;
846 0 : nodeType = reader.getAttributeValue(false).convertFromUtf8();
847 3296688 : } else if (attrNsId == ParseManager::NAMESPACE_OOR &&
848 1648344 : attrLn.equals("op"))
849 : {
850 1638094 : op = parseOperation(reader.getAttributeValue(true));
851 20500 : } else if (attrNsId == ParseManager::NAMESPACE_OOR &&
852 10250 : attrLn.equals("finalized"))
853 : {
854 1000 : finalized = xmldata::parseBoolean(reader.getAttributeValue(true));
855 18500 : } else if (attrNsId == ParseManager::NAMESPACE_OOR &&
856 9250 : attrLn.equals("mandatory"))
857 : {
858 8500 : mandatory = xmldata::parseBoolean(reader.getAttributeValue(true));
859 : }
860 3329010 : }
861 1680666 : if (!hasName) {
862 : throw css::uno::RuntimeException(
863 0 : "no node name attribute in " + reader.getUrl());
864 : }
865 1680666 : if (trackPath_) {
866 102 : path_.push_back(name);
867 102 : if (partial_ != 0 && partial_->contains(path_) == Partial::CONTAINS_NOT)
868 : {
869 0 : state_.push(State::Ignore(true));
870 0 : return;
871 : }
872 : }
873 : OUString templateName(
874 : xmldata::parseTemplateReference(
875 3361213 : component, hasNodeType, nodeType, &set->getDefaultTemplateName()));
876 1680666 : if (!set->isValidTemplate(templateName)) {
877 : throw css::uno::RuntimeException(
878 0 : "set member node " + name + " references invalid template " +
879 0 : templateName + " in " + reader.getUrl());
880 : }
881 : rtl::Reference< Node > tmpl(
882 3361213 : data_.getTemplate(valueParser_.getLayer(), templateName));
883 1680666 : if (!tmpl.is()) {
884 : throw css::uno::RuntimeException(
885 0 : "set member node " + name + " references undefined template " +
886 0 : templateName + " in " + reader.getUrl());
887 : }
888 1680666 : int finalizedLayer = finalized ? valueParser_.getLayer() : Data::NO_LAYER;
889 1680666 : int mandatoryLayer = mandatory ? valueParser_.getLayer() : Data::NO_LAYER;
890 1680666 : NodeMap & members = set->getMembers();
891 1680666 : NodeMap::iterator i(members.find(name));
892 1680666 : if (i != members.end()) {
893 60205 : finalizedLayer = std::min(finalizedLayer, i->second->getFinalized());
894 60205 : i->second->setFinalized(finalizedLayer);
895 60205 : mandatoryLayer = std::min(mandatoryLayer, i->second->getMandatory());
896 60205 : i->second->setMandatory(mandatoryLayer);
897 60205 : if (i->second->getLayer() > valueParser_.getLayer()) {
898 0 : state_.push(State::Ignore(true));
899 0 : return;
900 : }
901 : }
902 1680666 : if (finalizedLayer < valueParser_.getLayer()) {
903 119 : state_.push(State::Ignore(true));
904 119 : return;
905 : }
906 1680547 : switch (op) {
907 : case OPERATION_MODIFY:
908 42453 : if (i == members.end()) {
909 : SAL_WARN(
910 : "configmgr",
911 : "ignoring modify of unknown set member node \"" << name
912 : << "\" in \"" << reader.getUrl() << '"');
913 238 : state_.push(State::Ignore(true));
914 : } else {
915 42215 : state_.push(State::Modify(i->second));
916 : }
917 42453 : break;
918 : case OPERATION_REPLACE:
919 : {
920 1622473 : rtl::Reference< Node > member(tmpl->clone(true));
921 1622473 : member->setLayer(valueParser_.getLayer());
922 1622473 : member->setFinalized(finalizedLayer);
923 1622473 : member->setMandatory(mandatoryLayer);
924 1622473 : state_.push(State::Insert(member, name));
925 1622473 : recordModification(i == members.end());
926 : }
927 1622473 : break;
928 : case OPERATION_FUSE:
929 15621 : if (i == members.end()) {
930 15621 : rtl::Reference< Node > member(tmpl->clone(true));
931 15621 : member->setLayer(valueParser_.getLayer());
932 15621 : member->setFinalized(finalizedLayer);
933 15621 : member->setMandatory(mandatoryLayer);
934 15621 : state_.push(State::Insert(member, name));
935 15621 : recordModification(true);
936 : } else {
937 0 : state_.push(State::Modify(i->second));
938 : }
939 15621 : break;
940 : case OPERATION_REMOVE:
941 : {
942 : // Ignore removal of unknown members and members made mandatory in
943 : // this or a lower layer; forget about user-layer removals that no
944 : // longer remove anything (so that paired additions/removals in the
945 : // user layer do not grow registrymodifications.xcu unbounded):
946 0 : bool known = i != members.end();
947 0 : if (known &&
948 0 : (mandatoryLayer == Data::NO_LAYER ||
949 0 : mandatoryLayer > valueParser_.getLayer()))
950 : {
951 0 : members.erase(i);
952 : }
953 0 : state_.push(State::Ignore(true));
954 0 : if (known) {
955 0 : recordModification(false);
956 : }
957 0 : break;
958 : }
959 1680547 : }
960 : }
961 :
962 4880417 : void XcuParser::recordModification(bool addition) {
963 4880417 : if (broadcastModifications_ != 0) {
964 0 : broadcastModifications_->add(path_);
965 : }
966 4880417 : if (addition && additions_ != 0) {
967 0 : additions_->push_back(path_);
968 : }
969 4880417 : if (recordModifications_) {
970 2199 : data_.modifications.add(path_);
971 : }
972 4880417 : }
973 :
974 : }
975 :
976 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|