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 76935 : 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 76935 : additions_(additions), recordModifications_(layer == Data::NO_LAYER),
63 : trackPath_(
64 76935 : partial_ != 0 || broadcastModifications_ != 0 || additions_ != 0 ||
65 230805 : recordModifications_)
66 76935 : {}
67 :
68 153870 : XcuParser::~XcuParser() {}
69 :
70 40538935 : xmlreader::XmlReader::Text XcuParser::getTextMode() {
71 40538935 : return valueParser_.getTextMode();
72 : }
73 :
74 17073906 : bool XcuParser::startElement(
75 : xmlreader::XmlReader & reader, int nsId, xmlreader::Span const & name,
76 : std::set< OUString > const * existingDependencies)
77 : {
78 17073906 : if (valueParser_.startElement(reader, nsId, name, existingDependencies)) {
79 49210 : return true;
80 : }
81 17024696 : if (state_.empty()) {
82 153734 : if (nsId == ParseManager::NAMESPACE_OOR &&
83 76867 : name.equals("component-data"))
84 : {
85 76769 : handleComponentData(reader);
86 98 : } else if (nsId == ParseManager::NAMESPACE_OOR && name.equals("items"))
87 : {
88 98 : 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 16947829 : } else if (state_.top().ignore) {
95 0 : state_.push(State::Ignore(false));
96 16947829 : } else if (!state_.top().node.is()) {
97 4892 : if (nsId == xmlreader::XmlReader::NAMESPACE_NONE && name.equals("item"))
98 : {
99 4892 : 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 16942937 : switch (state_.top().node->kind()) {
107 : case Node::KIND_PROPERTY:
108 8992114 : if (nsId == xmlreader::XmlReader::NAMESPACE_NONE &&
109 4496057 : name.equals("value"))
110 : {
111 : handlePropValue(
112 : reader,
113 4496057 : 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 4496057 : break;
120 : case Node::KIND_LOCALIZED_PROPERTY:
121 4660208 : if (nsId == xmlreader::XmlReader::NAMESPACE_NONE &&
122 2330104 : name.equals("value"))
123 : {
124 : handleLocpropValue(
125 : reader,
126 : static_cast< LocalizedPropertyNode * >(
127 2330104 : 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 2330104 : 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 15129778 : if (nsId == xmlreader::XmlReader::NAMESPACE_NONE &&
140 7564889 : name.equals("prop"))
141 : {
142 : handleGroupProp(
143 : reader,
144 7295122 : static_cast< GroupNode * >(state_.top().node.get()));
145 539534 : } else if (nsId == xmlreader::XmlReader::NAMESPACE_NONE &&
146 269767 : name.equals("node"))
147 : {
148 269767 : 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 7564889 : break;
155 : case Node::KIND_SET:
156 5103774 : if (nsId == xmlreader::XmlReader::NAMESPACE_NONE &&
157 2551887 : name.equals("node"))
158 : {
159 : handleSetNode(
160 2551887 : 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 2551887 : break;
175 : case Node::KIND_ROOT:
176 : assert(false); // this cannot happen
177 0 : break;
178 : }
179 : }
180 17024696 : return true;
181 : }
182 :
183 17073906 : void XcuParser::endElement(xmlreader::XmlReader const &) {
184 17073906 : if (valueParser_.endElement()) {
185 23941750 : return;
186 : }
187 : assert(!state_.empty());
188 10206062 : bool pop = state_.top().pop;
189 10206062 : rtl::Reference< Node > insert;
190 20412124 : OUString name;
191 10206062 : if (state_.top().insert) {
192 2620443 : insert = state_.top().node;
193 : assert(insert.is());
194 2620443 : name = state_.top().name;
195 : }
196 10206062 : state_.pop();
197 10206062 : if (insert.is()) {
198 : assert(!state_.empty() && state_.top().node.is());
199 2620443 : state_.top().node->getMembers()[name] = insert;
200 : }
201 10206062 : if (pop && !path_.empty()) {
202 10830 : path_.pop_back();
203 : // </item> will pop less than <item> pushed, but that is harmless,
204 : // as the next <item> will reset path_
205 10206062 : }
206 : }
207 :
208 6467794 : void XcuParser::characters(xmlreader::Span const & text) {
209 6467794 : valueParser_.characters(text);
210 6467794 : }
211 :
212 2624076 : XcuParser::Operation XcuParser::parseOperation(xmlreader::Span const & text) {
213 : assert(text.is());
214 2624076 : if (text.equals("modify")) {
215 0 : return OPERATION_MODIFY;
216 : }
217 2624076 : if (text.equals("replace")) {
218 2594601 : return OPERATION_REPLACE;
219 : }
220 29475 : if (text.equals("fuse")) {
221 29475 : 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 76769 : void XcuParser::handleComponentData(xmlreader::XmlReader & reader) {
231 76769 : OStringBuffer buf;
232 76769 : buf.append('.');
233 76769 : bool hasPackage = false;
234 76769 : bool hasName = false;
235 76769 : Operation op = OPERATION_MODIFY;
236 76769 : bool finalized = false;
237 : for (;;) {
238 : int attrNsId;
239 230307 : xmlreader::Span attrLn;
240 230307 : if (!reader.nextAttribute(&attrNsId, &attrLn)) {
241 76769 : break;
242 : }
243 153538 : if (attrNsId == ParseManager::NAMESPACE_OOR && attrLn.equals("package"))
244 : {
245 76769 : if (hasPackage) {
246 : throw css::uno::RuntimeException(
247 0 : "multiple component-update package attributes in " +
248 0 : reader.getUrl());
249 : }
250 76769 : hasPackage = true;
251 76769 : xmlreader::Span s(reader.getAttributeValue(false));
252 76769 : buf.insert(0, s.begin, s.length);
253 153538 : } else if (attrNsId == ParseManager::NAMESPACE_OOR &&
254 76769 : attrLn.equals("name"))
255 : {
256 76769 : if (hasName) {
257 : throw css::uno::RuntimeException(
258 0 : "multiple component-update name attributes in " +
259 0 : reader.getUrl());
260 : }
261 76769 : hasName = true;
262 76769 : xmlreader::Span s(reader.getAttributeValue(false));
263 76769 : 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 153538 : }
274 76769 : if (!hasPackage) {
275 : throw css::uno::RuntimeException(
276 0 : "no component-data package attribute in " + reader.getUrl());
277 : }
278 76769 : if (!hasName) {
279 : throw css::uno::RuntimeException(
280 0 : "no component-data name attribute in " + reader.getUrl());
281 : }
282 153538 : componentName_ = xmlreader::Span(buf.getStr(), buf.getLength()).
283 76769 : convertFromUtf8();
284 76769 : 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 76769 : data_.getComponents().findNode(valueParser_.getLayer(),
295 230307 : componentName_));
296 76769 : if (!node.is()) {
297 : SAL_WARN(
298 : "configmgr",
299 : "unknown component \"" << componentName_ << "\" in \""
300 : << reader.getUrl() << '"');
301 0 : state_.push(State::Ignore(true));
302 0 : return;
303 : }
304 76769 : switch (op) {
305 : case OPERATION_MODIFY:
306 : case OPERATION_FUSE:
307 76769 : 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 76769 : node->getFinalized());
315 76769 : node->setFinalized(finalizedLayer);
316 76769 : if (finalizedLayer < valueParser_.getLayer()) {
317 0 : state_.push(State::Ignore(true));
318 0 : return;
319 : }
320 153538 : state_.push(State::Modify(node));
321 : }
322 :
323 4892 : void XcuParser::handleItem(xmlreader::XmlReader & reader) {
324 4892 : xmlreader::Span attrPath;
325 : for (;;) {
326 : int attrNsId;
327 9784 : xmlreader::Span attrLn;
328 9784 : if (!reader.nextAttribute(&attrNsId, &attrLn)) {
329 4892 : break;
330 : }
331 4892 : if (attrNsId == ParseManager::NAMESPACE_OOR && attrLn.equals("path")) {
332 4892 : attrPath = reader.getAttributeValue(false);
333 : }
334 4892 : }
335 4892 : if (!attrPath.is()) {
336 : throw css::uno::RuntimeException(
337 0 : "missing path attribute in " + reader.getUrl());
338 : }
339 4892 : OUString path(attrPath.convertFromUtf8());
340 : int finalizedLayer;
341 : rtl::Reference< Node > node(
342 : data_.resolvePathRepresentation(
343 9784 : path, 0, &path_, &finalizedLayer));
344 4892 : 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 4892 : componentName_ = path_.front();
353 4892 : if (trackPath_) {
354 4892 : 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 4892 : 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 50 : node.get())->getStaticType();
374 50 : break;
375 : default:
376 4842 : break;
377 : }
378 4892 : if (finalizedLayer < valueParser_.getLayer()) {
379 0 : state_.push(State::Ignore(true));
380 0 : return;
381 : }
382 9784 : state_.push(State::Modify(node));
383 : }
384 :
385 4496057 : void XcuParser::handlePropValue(
386 : xmlreader::XmlReader & reader, PropertyNode * prop)
387 : {
388 4496057 : bool nil = false;
389 4496057 : OString separator;
390 8992114 : OUString external;
391 : for (;;) {
392 : int attrNsId;
393 4547018 : xmlreader::Span attrLn;
394 4547018 : if (!reader.nextAttribute(&attrNsId, &attrLn)) {
395 4496057 : break;
396 : }
397 50961 : if (attrNsId == ParseManager::NAMESPACE_XSI && attrLn.equals("nil")) {
398 288 : nil = xmldata::parseBoolean(reader.getAttributeValue(true));
399 97917 : } else if (attrNsId == ParseManager::NAMESPACE_OOR &&
400 47244 : 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 97917 : } else if (attrNsId == ParseManager::NAMESPACE_OOR &&
410 47244 : attrLn.equals("separator"))
411 : {
412 40005 : xmlreader::Span s(reader.getAttributeValue(false));
413 40005 : if (s.length == 0) {
414 : throw css::uno::RuntimeException(
415 0 : "bad oor:separator attribute in " + reader.getUrl());
416 : }
417 40005 : separator = OString(s.begin, s.length);
418 17907 : } else if (attrNsId == ParseManager::NAMESPACE_OOR &&
419 7239 : attrLn.equals("external"))
420 : {
421 7239 : external = reader.getAttributeValue(true).convertFromUtf8();
422 7239 : if (external.isEmpty()) {
423 : throw css::uno::RuntimeException(
424 0 : "bad oor:external attribute value in " + reader.getUrl());
425 : }
426 : }
427 50961 : }
428 4496057 : if (nil) {
429 288 : if (!prop->isNillable()) {
430 : throw css::uno::RuntimeException(
431 0 : "xsi:nil attribute for non-nillable prop in " + reader.getUrl());
432 : }
433 288 : 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 288 : prop->setValue(valueParser_.getLayer(), css::uno::Any());
439 288 : state_.push(State::Ignore(false));
440 4495769 : } else if (external.isEmpty()) {
441 4488530 : valueParser_.separator_ = separator;
442 4488530 : valueParser_.start(prop);
443 : } else {
444 7239 : prop->setExternal(valueParser_.getLayer(), external);
445 7239 : state_.push(State::Ignore(false));
446 4496057 : }
447 4496057 : }
448 :
449 2330104 : void XcuParser::handleLocpropValue(
450 : xmlreader::XmlReader & reader, LocalizedPropertyNode * locprop)
451 : {
452 2330104 : OUString name;
453 2330104 : bool nil = false;
454 4660208 : OString separator;
455 2330104 : Operation op = OPERATION_FUSE;
456 : for (;;) {
457 : int attrNsId;
458 4516190 : xmlreader::Span attrLn;
459 4516190 : if (!reader.nextAttribute(&attrNsId, &attrLn)) {
460 2330104 : break;
461 : }
462 4370648 : if (attrNsId == xmlreader::XmlReader::NAMESPACE_XML &&
463 2184562 : attrLn.equals("lang"))
464 : {
465 2184562 : name = reader.getAttributeValue(false).convertFromUtf8();
466 1524 : } else if (attrNsId == ParseManager::NAMESPACE_XSI &&
467 0 : attrLn.equals("nil"))
468 : {
469 0 : nil = xmldata::parseBoolean(reader.getAttributeValue(true));
470 3048 : } else if (attrNsId == ParseManager::NAMESPACE_OOR &&
471 1524 : 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 3048 : } else if (attrNsId == ParseManager::NAMESPACE_OOR &&
481 1524 : attrLn.equals("separator"))
482 : {
483 1524 : xmlreader::Span s(reader.getAttributeValue(false));
484 1524 : if (s.length == 0) {
485 : throw css::uno::RuntimeException(
486 0 : "bad oor:separator attribute in " + reader.getUrl());
487 : }
488 1524 : 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 2186086 : }
495 2330104 : if (trackPath_) {
496 50 : path_.push_back(name);
497 50 : 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 2330104 : NodeMap & members = locprop->getMembers();
505 2330104 : NodeMap::iterator i(members.find(name));
506 2330104 : if (i != members.end() && i->second->getLayer() > valueParser_.getLayer()) {
507 0 : state_.push(State::Ignore(true));
508 0 : return;
509 : }
510 2330104 : if (nil && !locprop->isNillable()) {
511 : throw css::uno::RuntimeException(
512 0 : "xsi:nil attribute for non-nillable prop in " + reader.getUrl());
513 : }
514 2330104 : switch (op) {
515 : case OPERATION_FUSE:
516 : {
517 2330104 : bool pop = false;
518 2330104 : 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 2330104 : valueParser_.separator_ = separator;
530 2330104 : valueParser_.start(locprop, name);
531 2330104 : pop = true;
532 : }
533 2330104 : if (trackPath_) {
534 50 : recordModification(false);
535 50 : if (pop) {
536 50 : path_.pop_back();
537 : }
538 : }
539 : }
540 2330104 : 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 2330104 : }
554 : }
555 :
556 7295122 : void XcuParser::handleGroupProp(
557 : xmlreader::XmlReader & reader, GroupNode * group)
558 : {
559 7295122 : bool hasName = false;
560 7295122 : OUString name;
561 7295122 : Type type = TYPE_ERROR;
562 7295122 : Operation op = OPERATION_MODIFY;
563 7295122 : bool finalized = false;
564 : for (;;) {
565 : int attrNsId;
566 17157324 : xmlreader::Span attrLn;
567 17157324 : if (!reader.nextAttribute(&attrNsId, &attrLn)) {
568 7295122 : break;
569 : }
570 9862202 : if (attrNsId == ParseManager::NAMESPACE_OOR && attrLn.equals("name")) {
571 7295122 : hasName = true;
572 7295122 : name = reader.getAttributeValue(false).convertFromUtf8();
573 5134160 : } else if (attrNsId == ParseManager::NAMESPACE_OOR &&
574 2567080 : attrLn.equals("type"))
575 : {
576 2423024 : type = xmldata::parseType(reader, reader.getAttributeValue(true));
577 288112 : } else if (attrNsId == ParseManager::NAMESPACE_OOR &&
578 144056 : attrLn.equals("op"))
579 : {
580 104813 : op = parseOperation(reader.getAttributeValue(true));
581 78486 : } else if (attrNsId == ParseManager::NAMESPACE_OOR &&
582 39243 : attrLn.equals("finalized"))
583 : {
584 39243 : finalized = xmldata::parseBoolean(reader.getAttributeValue(true));
585 : }
586 9862202 : }
587 7295122 : if (!hasName) {
588 : throw css::uno::RuntimeException(
589 0 : "no prop name attribute in " + reader.getUrl());
590 : }
591 7295122 : if (trackPath_) {
592 5372 : 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 5372 : if (partial_ != 0 &&
596 0 : partial_->contains(path_) != Partial::CONTAINS_NODE)
597 : {
598 0 : state_.push(State::Ignore(true));
599 7295122 : return;
600 : }
601 : }
602 7295122 : NodeMap & members = group->getMembers();
603 7295122 : NodeMap::iterator i(members.find(name));
604 7295122 : if (i == members.end()) {
605 101561 : handleUnknownGroupProp(reader, group, name, type, op, finalized);
606 : } else {
607 7193561 : switch (i->second->kind()) {
608 : case Node::KIND_PROPERTY:
609 4825788 : handlePlainGroupProp(reader, group, i, name, type, op, finalized);
610 4825788 : break;
611 : case Node::KIND_LOCALIZED_PROPERTY:
612 : handleLocalizedGroupProp(
613 : reader,
614 2367773 : static_cast< LocalizedPropertyNode * >(i->second.get()), name,
615 4735546 : type, op, finalized);
616 2367773 : break;
617 : default:
618 : throw css::uno::RuntimeException(
619 0 : "inappropriate prop " + name + " in " + reader.getUrl());
620 : }
621 7295122 : }
622 : }
623 :
624 101561 : void XcuParser::handleUnknownGroupProp(
625 : xmlreader::XmlReader const & reader, GroupNode * group,
626 : OUString const & name, Type type, Operation operation, bool finalized)
627 : {
628 101561 : switch (operation) {
629 : case OPERATION_REPLACE:
630 : case OPERATION_FUSE:
631 101561 : if (group->isExtensible()) {
632 101561 : if (type == TYPE_ERROR) {
633 : throw css::uno::RuntimeException(
634 0 : "missing type attribute for prop " + name + " in " +
635 0 : reader.getUrl());
636 : }
637 101561 : valueParser_.type_ = type;
638 : rtl::Reference< Node > prop(
639 : new PropertyNode(
640 101561 : valueParser_.getLayer(), TYPE_ANY, true, css::uno::Any(),
641 101561 : true));
642 101561 : if (finalized) {
643 0 : prop->setFinalized(valueParser_.getLayer());
644 : }
645 101561 : state_.push(State::Insert(prop, name));
646 101561 : recordModification(false);
647 101561 : 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 101561 : }
659 :
660 4825788 : 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 4825788 : propertyIndex->second.get());
667 4825788 : if (property->getLayer() > valueParser_.getLayer()) {
668 0 : state_.push(State::Ignore(true));
669 0 : return;
670 : }
671 : int finalizedLayer = std::min(
672 39243 : finalized ? valueParser_.getLayer() : Data::NO_LAYER,
673 4865031 : property->getFinalized());
674 4825788 : property->setFinalized(finalizedLayer);
675 4825788 : if (finalizedLayer < valueParser_.getLayer()) {
676 0 : state_.push(State::Ignore(true));
677 0 : return;
678 : }
679 5958882 : if (type != TYPE_ERROR && property->getStaticType() != TYPE_ANY &&
680 1133094 : type != property->getStaticType())
681 : {
682 : throw css::uno::RuntimeException(
683 0 : "invalid type for prop " + name + " in " + reader.getUrl());
684 : }
685 4825788 : valueParser_.type_ = type == TYPE_ERROR ? property->getStaticType() : type;
686 4825788 : switch (operation) {
687 : case OPERATION_MODIFY:
688 : case OPERATION_REPLACE:
689 : case OPERATION_FUSE:
690 4825788 : state_.push(State::Modify(property));
691 4825788 : recordModification(false);
692 4825788 : 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 2367773 : void XcuParser::handleLocalizedGroupProp(
707 : xmlreader::XmlReader const & reader, LocalizedPropertyNode * property,
708 : OUString const & name, Type type, Operation operation, bool finalized)
709 : {
710 2367773 : 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 2367773 : property->getFinalized());
717 2367773 : property->setFinalized(finalizedLayer);
718 2367773 : if (finalizedLayer < valueParser_.getLayer()) {
719 0 : state_.push(State::Ignore(true));
720 0 : return;
721 : }
722 3524870 : if (type != TYPE_ERROR && property->getStaticType() != TYPE_ANY &&
723 1157097 : type != property->getStaticType())
724 : {
725 : throw css::uno::RuntimeException(
726 0 : "invalid type for prop " + name + " in " + reader.getUrl());
727 : }
728 2367773 : valueParser_.type_ = type == TYPE_ERROR ? property->getStaticType() : type;
729 2367773 : switch (operation) {
730 : case OPERATION_MODIFY:
731 : case OPERATION_FUSE:
732 2367773 : state_.push(State::Modify(property));
733 2367773 : 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 269767 : void XcuParser::handleGroupNode(
753 : xmlreader::XmlReader & reader, rtl::Reference< Node > const & group)
754 : {
755 269767 : bool hasName = false;
756 269767 : OUString name;
757 269767 : Operation op = OPERATION_MODIFY;
758 269767 : bool finalized = false;
759 : for (;;) {
760 : int attrNsId;
761 542582 : xmlreader::Span attrLn;
762 542582 : if (!reader.nextAttribute(&attrNsId, &attrLn)) {
763 269767 : break;
764 : }
765 272815 : if (attrNsId == ParseManager::NAMESPACE_OOR && attrLn.equals("name")) {
766 269767 : hasName = true;
767 269767 : name = reader.getAttributeValue(false).convertFromUtf8();
768 6096 : } else if (attrNsId == ParseManager::NAMESPACE_OOR &&
769 3048 : attrLn.equals("op"))
770 : {
771 381 : op = parseOperation(reader.getAttributeValue(true));
772 5334 : } else if (attrNsId == ParseManager::NAMESPACE_OOR &&
773 2667 : attrLn.equals("finalized"))
774 : {
775 1905 : finalized = xmldata::parseBoolean(reader.getAttributeValue(true));
776 : }
777 272815 : }
778 269767 : if (!hasName) {
779 : throw css::uno::RuntimeException(
780 0 : "no node name attribute in " + reader.getUrl());
781 : }
782 269767 : if (trackPath_) {
783 196 : path_.push_back(name);
784 196 : 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 539534 : group->getMembers().findNode(valueParser_.getLayer(), name));
792 269767 : 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 269767 : Node::Kind kind = child->kind();
800 269767 : 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 269767 : 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 1905 : finalized ? valueParser_.getLayer() : Data::NO_LAYER,
811 271672 : child->getFinalized());
812 269767 : child->setFinalized(finalizedLayer);
813 269767 : if (finalizedLayer < valueParser_.getLayer()) {
814 0 : state_.push(State::Ignore(true));
815 0 : return;
816 : }
817 539534 : state_.push(State::Modify(child));
818 : }
819 :
820 2551887 : void XcuParser::handleSetNode(xmlreader::XmlReader & reader, SetNode * set) {
821 2551887 : bool hasName = false;
822 2551887 : OUString name;
823 5103774 : OUString component(componentName_);
824 2551887 : bool hasNodeType = false;
825 5103774 : OUString nodeType;
826 2551887 : Operation op = OPERATION_MODIFY;
827 2551887 : bool finalized = false;
828 2551887 : bool mandatory = false;
829 : for (;;) {
830 : int attrNsId;
831 7638277 : xmlreader::Span attrLn;
832 7638277 : if (!reader.nextAttribute(&attrNsId, &attrLn)) {
833 2551887 : break;
834 : }
835 5086390 : if (attrNsId == ParseManager::NAMESPACE_OOR && attrLn.equals("name")) {
836 2551887 : hasName = true;
837 2551887 : name = reader.getAttributeValue(false).convertFromUtf8();
838 5069006 : } else if (attrNsId == ParseManager::NAMESPACE_OOR &&
839 2534503 : attrLn.equals("component"))
840 : {
841 0 : component = reader.getAttributeValue(false).convertFromUtf8();
842 5069006 : } else if (attrNsId == ParseManager::NAMESPACE_OOR &&
843 2534503 : attrLn.equals("node-type"))
844 : {
845 0 : hasNodeType = true;
846 0 : nodeType = reader.getAttributeValue(false).convertFromUtf8();
847 5069006 : } else if (attrNsId == ParseManager::NAMESPACE_OOR &&
848 2534503 : attrLn.equals("op"))
849 : {
850 2518882 : op = parseOperation(reader.getAttributeValue(true));
851 31242 : } else if (attrNsId == ParseManager::NAMESPACE_OOR &&
852 15621 : attrLn.equals("finalized"))
853 : {
854 1524 : finalized = xmldata::parseBoolean(reader.getAttributeValue(true));
855 28194 : } else if (attrNsId == ParseManager::NAMESPACE_OOR &&
856 14097 : attrLn.equals("mandatory"))
857 : {
858 12954 : mandatory = xmldata::parseBoolean(reader.getAttributeValue(true));
859 : }
860 5086390 : }
861 2551887 : if (!hasName) {
862 : throw css::uno::RuntimeException(
863 0 : "no node name attribute in " + reader.getUrl());
864 : }
865 2551887 : if (trackPath_) {
866 272 : path_.push_back(name);
867 272 : 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 5103774 : component, hasNodeType, nodeType, &set->getDefaultTemplateName()));
876 2551887 : 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 5103774 : data_.getTemplate(valueParser_.getLayer(), templateName));
883 2551887 : 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 2551887 : int finalizedLayer = finalized ? valueParser_.getLayer() : Data::NO_LAYER;
889 2551887 : int mandatoryLayer = mandatory ? valueParser_.getLayer() : Data::NO_LAYER;
890 2551887 : NodeMap & members = set->getMembers();
891 2551887 : NodeMap::iterator i(members.find(name));
892 2551887 : if (i != members.end()) {
893 60156 : finalizedLayer = std::min(finalizedLayer, i->second->getFinalized());
894 60156 : i->second->setFinalized(finalizedLayer);
895 60156 : mandatoryLayer = std::min(mandatoryLayer, i->second->getMandatory());
896 60156 : i->second->setMandatory(mandatoryLayer);
897 60156 : if (i->second->getLayer() > valueParser_.getLayer()) {
898 0 : state_.push(State::Ignore(true));
899 0 : return;
900 : }
901 : }
902 2551887 : if (finalizedLayer < valueParser_.getLayer()) {
903 0 : state_.push(State::Ignore(true));
904 0 : return;
905 : }
906 2551887 : switch (op) {
907 : case OPERATION_MODIFY:
908 33005 : if (i == members.end()) {
909 : SAL_WARN(
910 : "configmgr",
911 : "ignoring modify of unknown set member node \"" << name
912 : << "\" in \"" << reader.getUrl() << '"');
913 0 : state_.push(State::Ignore(true));
914 : } else {
915 33005 : state_.push(State::Modify(i->second));
916 : }
917 33005 : break;
918 : case OPERATION_REPLACE:
919 : {
920 2495160 : rtl::Reference< Node > member(tmpl->clone(true));
921 2495160 : member->setLayer(valueParser_.getLayer());
922 2495160 : member->setFinalized(finalizedLayer);
923 2495160 : member->setMandatory(mandatoryLayer);
924 2495160 : state_.push(State::Insert(member, name));
925 2495160 : recordModification(i == members.end());
926 : }
927 2495160 : break;
928 : case OPERATION_FUSE:
929 23722 : if (i == members.end()) {
930 23722 : rtl::Reference< Node > member(tmpl->clone(true));
931 23722 : member->setLayer(valueParser_.getLayer());
932 23722 : member->setFinalized(finalizedLayer);
933 23722 : member->setMandatory(mandatoryLayer);
934 23722 : state_.push(State::Insert(member, name));
935 23722 : recordModification(true);
936 : } else {
937 0 : state_.push(State::Modify(i->second));
938 : }
939 23722 : 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 2551887 : }
960 : }
961 :
962 7446281 : void XcuParser::recordModification(bool addition) {
963 7446281 : if (broadcastModifications_ != 0) {
964 0 : broadcastModifications_->add(path_);
965 : }
966 7446281 : if (addition && additions_ != 0) {
967 0 : additions_->push_back(path_);
968 : }
969 7446281 : if (recordModifications_) {
970 5694 : data_.modifications.add(path_);
971 : }
972 7446281 : }
973 :
974 : }
975 :
976 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|