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 34349 : 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 34349 : additions_(additions), recordModifications_(layer == Data::NO_LAYER),
63 : trackPath_(
64 34349 : partial_ != 0 || broadcastModifications_ != 0 || additions_ != 0 ||
65 103047 : recordModifications_)
66 34349 : {}
67 :
68 68698 : XcuParser::~XcuParser() {}
69 :
70 17606120 : xmlreader::XmlReader::Text XcuParser::getTextMode() {
71 17606120 : return valueParser_.getTextMode();
72 : }
73 :
74 7416262 : bool XcuParser::startElement(
75 : xmlreader::XmlReader & reader, int nsId, xmlreader::Span const & name,
76 : std::set< OUString > const * existingDependencies)
77 : {
78 7416262 : if (valueParser_.startElement(reader, nsId, name, existingDependencies)) {
79 21360 : return true;
80 : }
81 7394902 : if (state_.empty()) {
82 68632 : if (nsId == ParseManager::NAMESPACE_OOR &&
83 34316 : name.equals("component-data"))
84 : {
85 34267 : handleComponentData(reader);
86 49 : } else if (nsId == ParseManager::NAMESPACE_OOR && name.equals("items"))
87 : {
88 49 : 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 0 : css::uno::Reference< css::uno::XInterface >());
94 : }
95 7360586 : } else if (state_.top().ignore) {
96 0 : state_.push(State::Ignore(false));
97 7360586 : } else if (!state_.top().node.is()) {
98 2126 : if (nsId == xmlreader::XmlReader::NAMESPACE_NONE && name.equals("item"))
99 : {
100 2126 : 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 7358460 : switch (state_.top().node->kind()) {
109 : case Node::KIND_PROPERTY:
110 3882170 : if (nsId == xmlreader::XmlReader::NAMESPACE_NONE &&
111 1941085 : name.equals("value"))
112 : {
113 : handlePropValue(
114 : reader,
115 1941085 : static_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 1941085 : break;
123 : case Node::KIND_LOCALIZED_PROPERTY:
124 2044192 : if (nsId == xmlreader::XmlReader::NAMESPACE_NONE &&
125 1022096 : name.equals("value"))
126 : {
127 : handleLocpropValue(
128 : reader,
129 : static_cast< LocalizedPropertyNode * >(
130 1022096 : 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 1022096 : 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 6556212 : if (nsId == xmlreader::XmlReader::NAMESPACE_NONE &&
145 3278106 : name.equals("prop"))
146 : {
147 : handleGroupProp(
148 : reader,
149 3159539 : static_cast< GroupNode * >(state_.top().node.get()));
150 237134 : } else if (nsId == xmlreader::XmlReader::NAMESPACE_NONE &&
151 118567 : name.equals("node"))
152 : {
153 118567 : 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 3278106 : break;
161 : case Node::KIND_SET:
162 2234346 : if (nsId == xmlreader::XmlReader::NAMESPACE_NONE &&
163 1117173 : name.equals("node"))
164 : {
165 : handleSetNode(
166 1117173 : reader, static_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::Ignore(true));
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 1117173 : break;
182 : case Node::KIND_ROOT:
183 : assert(false); // this cannot happen
184 0 : break;
185 : }
186 : }
187 7394902 : return true;
188 : }
189 :
190 7416262 : void XcuParser::endElement(xmlreader::XmlReader const &) {
191 7416262 : if (valueParser_.endElement()) {
192 10397452 : return;
193 : }
194 : assert(!state_.empty());
195 4435072 : bool pop = state_.top().pop;
196 4435072 : rtl::Reference< Node > insert;
197 8870144 : OUString name;
198 4435072 : if (state_.top().insert) {
199 1146561 : insert = state_.top().node;
200 : assert(insert.is());
201 1146561 : name = state_.top().name;
202 : }
203 4435072 : state_.pop();
204 4435072 : if (insert.is()) {
205 : assert(!state_.empty() && state_.top().node.is());
206 1146561 : state_.top().node->getMembers()[name] = insert;
207 : }
208 4435072 : if (pop && !path_.empty()) {
209 4688 : path_.pop_back();
210 : // </item> will pop less than <item> pushed, but that is harmless,
211 : // as the next <item> will reset path_
212 4435072 : }
213 : }
214 :
215 2807814 : void XcuParser::characters(xmlreader::Span const & text) {
216 2807814 : valueParser_.characters(text);
217 2807814 : }
218 :
219 1148430 : XcuParser::Operation XcuParser::parseOperation(xmlreader::Span const & text) {
220 : assert(text.is());
221 1148430 : if (text.equals("modify")) {
222 0 : return OPERATION_MODIFY;
223 : }
224 1148430 : if (text.equals("replace")) {
225 1135498 : return OPERATION_REPLACE;
226 : }
227 12932 : if (text.equals("fuse")) {
228 12932 : 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 34267 : void XcuParser::handleComponentData(xmlreader::XmlReader & reader) {
239 34267 : OStringBuffer buf;
240 34267 : buf.append('.');
241 34267 : bool hasPackage = false;
242 34267 : bool hasName = false;
243 34267 : Operation op = OPERATION_MODIFY;
244 34267 : bool finalized = false;
245 : for (;;) {
246 : int attrNsId;
247 102801 : xmlreader::Span attrLn;
248 102801 : if (!reader.nextAttribute(&attrNsId, &attrLn)) {
249 34267 : break;
250 : }
251 68534 : if (attrNsId == ParseManager::NAMESPACE_OOR && attrLn.equals("package"))
252 : {
253 34267 : 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 34267 : hasPackage = true;
260 34267 : xmlreader::Span s(reader.getAttributeValue(false));
261 34267 : buf.insert(0, s.begin, s.length);
262 68534 : } else if (attrNsId == ParseManager::NAMESPACE_OOR &&
263 34267 : attrLn.equals("name"))
264 : {
265 34267 : 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 34267 : hasName = true;
272 34267 : xmlreader::Span s(reader.getAttributeValue(false));
273 34267 : 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 68534 : }
284 34267 : 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 34267 : 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 68534 : componentName_ = xmlreader::Span(buf.getStr(), buf.getLength()).
295 34267 : convertFromUtf8();
296 34267 : 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::Ignore(true));
302 0 : return;
303 : }
304 : }
305 : rtl::Reference< Node > node(
306 : Data::findNode(
307 68534 : valueParser_.getLayer(), data_.getComponents(), componentName_));
308 34267 : if (!node.is()) {
309 : SAL_WARN(
310 : "configmgr",
311 : "unknown component \"" << componentName_ << "\" in \""
312 : << reader.getUrl() << '"');
313 0 : state_.push(State::Ignore(true));
314 0 : return;
315 : }
316 34267 : switch (op) {
317 : case OPERATION_MODIFY:
318 : case OPERATION_FUSE:
319 34267 : 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 34267 : node->getFinalized());
328 34267 : node->setFinalized(finalizedLayer);
329 34267 : if (finalizedLayer < valueParser_.getLayer()) {
330 0 : state_.push(State::Ignore(true));
331 0 : return;
332 : }
333 68534 : state_.push(State::Modify(node));
334 : }
335 :
336 2126 : void XcuParser::handleItem(xmlreader::XmlReader & reader) {
337 2126 : xmlreader::Span attrPath;
338 : for (;;) {
339 : int attrNsId;
340 4252 : xmlreader::Span attrLn;
341 4252 : if (!reader.nextAttribute(&attrNsId, &attrLn)) {
342 2126 : break;
343 : }
344 2126 : if (attrNsId == ParseManager::NAMESPACE_OOR && attrLn.equals("path")) {
345 2126 : attrPath = reader.getAttributeValue(false);
346 : }
347 2126 : }
348 2126 : if (!attrPath.is()) {
349 : throw css::uno::RuntimeException(
350 0 : "missing path attribute in " + reader.getUrl(),
351 0 : css::uno::Reference< css::uno::XInterface >());
352 : }
353 2126 : OUString path(attrPath.convertFromUtf8());
354 : int finalizedLayer;
355 : rtl::Reference< Node > node(
356 : data_.resolvePathRepresentation(
357 4252 : path, 0, &path_, &finalizedLayer));
358 2126 : if (!node.is()) {
359 : SAL_WARN(
360 : "configmgr",
361 : "unknown item \"" << path << "\" in \"" << reader.getUrl() << '"');
362 0 : state_.push(State::Ignore(true));
363 0 : return;
364 : }
365 : assert(!path_.empty());
366 2126 : componentName_ = path_.front();
367 2126 : if (trackPath_) {
368 2126 : if (partial_ != 0 && partial_->contains(path_) == Partial::CONTAINS_NOT)
369 : {
370 0 : state_.push(State::Ignore(true));
371 0 : return;
372 : }
373 : } else {
374 0 : path_.clear();
375 : }
376 2126 : switch (node->kind()) {
377 : case Node::KIND_PROPERTY:
378 : case Node::KIND_LOCALIZED_VALUE:
379 : SAL_WARN(
380 : "configmgr",
381 : "item of bad type \"" << path << "\" in \"" << reader.getUrl()
382 : << '"');
383 0 : state_.push(State::Ignore(true));
384 0 : return;
385 : case Node::KIND_LOCALIZED_PROPERTY:
386 : valueParser_.type_ = static_cast< LocalizedPropertyNode * >(
387 34 : node.get())->getStaticType();
388 34 : break;
389 : default:
390 2092 : break;
391 : }
392 2126 : if (finalizedLayer < valueParser_.getLayer()) {
393 0 : state_.push(State::Ignore(true));
394 0 : return;
395 : }
396 4252 : state_.push(State::Modify(node));
397 : }
398 :
399 1941085 : void XcuParser::handlePropValue(
400 : xmlreader::XmlReader & reader, PropertyNode * prop)
401 : {
402 1941085 : bool nil = false;
403 1941085 : OString separator;
404 3882170 : OUString external;
405 : for (;;) {
406 : int attrNsId;
407 1963588 : xmlreader::Span attrLn;
408 1963588 : if (!reader.nextAttribute(&attrNsId, &attrLn)) {
409 1941085 : break;
410 : }
411 22503 : if (attrNsId == ParseManager::NAMESPACE_XSI && attrLn.equals("nil")) {
412 159 : nil = xmldata::parseBoolean(reader.getAttributeValue(true));
413 43176 : } else if (attrNsId == ParseManager::NAMESPACE_OOR &&
414 20832 : attrLn.equals("type"))
415 : {
416 : Type type = xmldata::parseType(
417 0 : reader, reader.getAttributeValue(true));
418 0 : if (valueParser_.type_ != TYPE_ANY && type != valueParser_.type_) {
419 : throw css::uno::RuntimeException(
420 0 : "invalid value type in " + reader.getUrl(),
421 0 : css::uno::Reference< css::uno::XInterface >());
422 : }
423 0 : valueParser_.type_ = type;
424 43176 : } else if (attrNsId == ParseManager::NAMESPACE_OOR &&
425 20832 : attrLn.equals("separator"))
426 : {
427 17640 : xmlreader::Span s(reader.getAttributeValue(false));
428 17640 : if (s.length == 0) {
429 : throw css::uno::RuntimeException(
430 0 : "bad oor:separator attribute in " + reader.getUrl(),
431 0 : css::uno::Reference< css::uno::XInterface >());
432 : }
433 17640 : separator = OString(s.begin, s.length);
434 7896 : } else if (attrNsId == ParseManager::NAMESPACE_OOR &&
435 3192 : attrLn.equals("external"))
436 : {
437 3192 : external = reader.getAttributeValue(true).convertFromUtf8();
438 3192 : if (external.isEmpty()) {
439 : throw css::uno::RuntimeException(
440 0 : "bad oor:external attribute value in " + reader.getUrl(),
441 0 : css::uno::Reference< css::uno::XInterface >());
442 : }
443 : }
444 22503 : }
445 1941085 : if (nil) {
446 159 : if (!prop->isNillable()) {
447 : throw css::uno::RuntimeException(
448 0 : "xsi:nil attribute for non-nillable prop in " + reader.getUrl(),
449 0 : css::uno::Reference< css::uno::XInterface >());
450 : }
451 159 : if (!external.isEmpty()) {
452 : throw css::uno::RuntimeException(
453 0 : ("xsi:nil and oor:external attributes for prop in " +
454 0 : reader.getUrl()),
455 0 : css::uno::Reference< css::uno::XInterface >());
456 : }
457 159 : prop->setValue(valueParser_.getLayer(), css::uno::Any());
458 159 : state_.push(State::Ignore(false));
459 1940926 : } else if (external.isEmpty()) {
460 1937734 : valueParser_.separator_ = separator;
461 1937734 : valueParser_.start(prop);
462 : } else {
463 3192 : prop->setExternal(valueParser_.getLayer(), external);
464 3192 : state_.push(State::Ignore(false));
465 1941085 : }
466 1941085 : }
467 :
468 1022096 : void XcuParser::handleLocpropValue(
469 : xmlreader::XmlReader & reader, LocalizedPropertyNode * locprop)
470 : {
471 1022096 : OUString name;
472 1022096 : bool nil = false;
473 2044192 : OString separator;
474 1022096 : Operation op = OPERATION_FUSE;
475 : for (;;) {
476 : int attrNsId;
477 1983880 : xmlreader::Span attrLn;
478 1983880 : if (!reader.nextAttribute(&attrNsId, &attrLn)) {
479 1022096 : break;
480 : }
481 1922896 : if (attrNsId == xmlreader::XmlReader::NAMESPACE_XML &&
482 961112 : attrLn.equals("lang"))
483 : {
484 961112 : name = reader.getAttributeValue(false).convertFromUtf8();
485 672 : } else if (attrNsId == ParseManager::NAMESPACE_XSI &&
486 0 : attrLn.equals("nil"))
487 : {
488 0 : nil = xmldata::parseBoolean(reader.getAttributeValue(true));
489 1344 : } else if (attrNsId == ParseManager::NAMESPACE_OOR &&
490 672 : attrLn.equals("type"))
491 : {
492 : Type type = xmldata::parseType(
493 0 : reader, reader.getAttributeValue(true));
494 0 : if (valueParser_.type_ != TYPE_ANY && type != valueParser_.type_) {
495 : throw css::uno::RuntimeException(
496 0 : "invalid value type in " + reader.getUrl(),
497 0 : css::uno::Reference< css::uno::XInterface >());
498 : }
499 0 : valueParser_.type_ = type;
500 1344 : } else if (attrNsId == ParseManager::NAMESPACE_OOR &&
501 672 : attrLn.equals("separator"))
502 : {
503 672 : xmlreader::Span s(reader.getAttributeValue(false));
504 672 : if (s.length == 0) {
505 : throw css::uno::RuntimeException(
506 0 : "bad oor:separator attribute in " + reader.getUrl(),
507 0 : css::uno::Reference< css::uno::XInterface >());
508 : }
509 672 : separator = OString(s.begin, s.length);
510 0 : } else if (attrNsId == ParseManager::NAMESPACE_OOR &&
511 0 : attrLn.equals("op"))
512 : {
513 0 : op = parseOperation(reader.getAttributeValue(true));
514 : }
515 961784 : }
516 1022096 : if (trackPath_) {
517 34 : path_.push_back(name);
518 34 : if (partial_ != 0 &&
519 0 : partial_->contains(path_) != Partial::CONTAINS_NODE)
520 : {
521 0 : state_.push(State::Ignore(true));
522 0 : return;
523 : }
524 : }
525 1022096 : NodeMap & members = locprop->getMembers();
526 1022096 : NodeMap::iterator i(members.find(name));
527 1022096 : if (i != members.end() && i->second->getLayer() > valueParser_.getLayer()) {
528 0 : state_.push(State::Ignore(true));
529 0 : return;
530 : }
531 1022096 : if (nil && !locprop->isNillable()) {
532 : throw css::uno::RuntimeException(
533 0 : "xsi:nil attribute for non-nillable prop in " + reader.getUrl(),
534 0 : css::uno::Reference< css::uno::XInterface >());
535 : }
536 1022096 : switch (op) {
537 : case OPERATION_FUSE:
538 : {
539 1022096 : bool pop = false;
540 1022096 : if (nil) {
541 0 : if (i == members.end()) {
542 0 : members[name] = new LocalizedValueNode(
543 0 : valueParser_.getLayer(), css::uno::Any());
544 : } else {
545 : static_cast< LocalizedValueNode * >(
546 0 : i->second.get())->setValue(
547 0 : valueParser_.getLayer(), css::uno::Any());
548 : }
549 0 : state_.push(State::Ignore(true));
550 : } else {
551 1022096 : valueParser_.separator_ = separator;
552 1022096 : valueParser_.start(locprop, name);
553 1022096 : pop = true;
554 : }
555 1022096 : if (trackPath_) {
556 34 : recordModification(false);
557 34 : if (pop) {
558 34 : path_.pop_back();
559 : }
560 : }
561 : }
562 1022096 : break;
563 : case OPERATION_REMOVE:
564 : //TODO: only allow if parent.op == OPERATION_FUSE
565 : //TODO: disallow removing when e.g. lang=""?
566 0 : if (i != members.end()) {
567 0 : members.erase(i);
568 : }
569 0 : state_.push(State::Ignore(true));
570 0 : recordModification(false);
571 0 : break;
572 : default:
573 : throw css::uno::RuntimeException(
574 0 : "bad op attribute for value element in " + reader.getUrl(),
575 0 : css::uno::Reference< css::uno::XInterface >());
576 1022096 : }
577 : }
578 :
579 3159539 : void XcuParser::handleGroupProp(
580 : xmlreader::XmlReader & reader, GroupNode * group)
581 : {
582 3159539 : bool hasName = false;
583 3159539 : OUString name;
584 3159539 : Type type = TYPE_ERROR;
585 3159539 : Operation op = OPERATION_MODIFY;
586 3159539 : bool finalized = false;
587 : for (;;) {
588 : int attrNsId;
589 7450959 : xmlreader::Span attrLn;
590 7450959 : if (!reader.nextAttribute(&attrNsId, &attrLn)) {
591 3159539 : break;
592 : }
593 4291420 : if (attrNsId == ParseManager::NAMESPACE_OOR && attrLn.equals("name")) {
594 3159539 : hasName = true;
595 3159539 : name = reader.getAttributeValue(false).convertFromUtf8();
596 2263762 : } else if (attrNsId == ParseManager::NAMESPACE_OOR &&
597 1131881 : attrLn.equals("type"))
598 : {
599 1068418 : type = xmldata::parseType(reader, reader.getAttributeValue(true));
600 126926 : } else if (attrNsId == ParseManager::NAMESPACE_OOR &&
601 63463 : attrLn.equals("op"))
602 : {
603 46159 : op = parseOperation(reader.getAttributeValue(true));
604 34608 : } else if (attrNsId == ParseManager::NAMESPACE_OOR &&
605 17304 : attrLn.equals("finalized"))
606 : {
607 17304 : finalized = xmldata::parseBoolean(reader.getAttributeValue(true));
608 : }
609 4291420 : }
610 3159539 : if (!hasName) {
611 : throw css::uno::RuntimeException(
612 0 : "no prop name attribute in " + reader.getUrl(),
613 0 : css::uno::Reference< css::uno::XInterface >());
614 : }
615 3159539 : if (trackPath_) {
616 2311 : path_.push_back(name);
617 : //TODO: This ignores locprop values for which specific include paths
618 : // exist (i.e., for which contains(locprop path) = CONTAINS_SUBNODES):
619 2311 : if (partial_ != 0 &&
620 0 : partial_->contains(path_) != Partial::CONTAINS_NODE)
621 : {
622 0 : state_.push(State::Ignore(true));
623 3159539 : return;
624 : }
625 : }
626 3159539 : NodeMap & members = group->getMembers();
627 3159539 : NodeMap::iterator i(members.find(name));
628 3159539 : if (i == members.end()) {
629 44458 : handleUnknownGroupProp(reader, group, name, type, op, finalized);
630 : } else {
631 3115081 : switch (i->second->kind()) {
632 : case Node::KIND_PROPERTY:
633 2076387 : handlePlainGroupProp(reader, group, i, name, type, op, finalized);
634 2076387 : break;
635 : case Node::KIND_LOCALIZED_PROPERTY:
636 : handleLocalizedGroupProp(
637 : reader,
638 1038694 : static_cast< LocalizedPropertyNode * >(i->second.get()), name,
639 2077388 : type, op, finalized);
640 1038694 : break;
641 : default:
642 : throw css::uno::RuntimeException(
643 0 : "inappropriate prop " + name + " in " + reader.getUrl(),
644 0 : css::uno::Reference< css::uno::XInterface >());
645 : }
646 3159539 : }
647 : }
648 :
649 44458 : void XcuParser::handleUnknownGroupProp(
650 : xmlreader::XmlReader const & reader, GroupNode * group,
651 : OUString const & name, Type type, Operation operation, bool finalized)
652 : {
653 44458 : switch (operation) {
654 : case OPERATION_REPLACE:
655 : case OPERATION_FUSE:
656 44458 : if (group->isExtensible()) {
657 44458 : if (type == TYPE_ERROR) {
658 : throw css::uno::RuntimeException(
659 0 : ("missing type attribute for prop " + name + " in " +
660 0 : reader.getUrl()),
661 0 : css::uno::Reference< css::uno::XInterface >());
662 : }
663 44458 : valueParser_.type_ = type;
664 : rtl::Reference< Node > prop(
665 : new PropertyNode(
666 44458 : valueParser_.getLayer(), TYPE_ANY, true, css::uno::Any(),
667 44458 : true));
668 44458 : if (finalized) {
669 0 : prop->setFinalized(valueParser_.getLayer());
670 : }
671 44458 : state_.push(State::Insert(prop, name));
672 44458 : recordModification(false);
673 44458 : break;
674 : }
675 : // fall through
676 : default:
677 : SAL_WARN(
678 : "configmgr",
679 : "unknown property \"" << name << "\" in \"" << reader.getUrl()
680 : << '"');
681 0 : state_.push(State::Ignore(true));
682 0 : break;
683 : }
684 44458 : }
685 :
686 2076387 : void XcuParser::handlePlainGroupProp(
687 : xmlreader::XmlReader const & reader, GroupNode * group,
688 : NodeMap::iterator const & propertyIndex, OUString const & name,
689 : Type type, Operation operation, bool finalized)
690 : {
691 : PropertyNode * property = static_cast< PropertyNode * >(
692 2076387 : propertyIndex->second.get());
693 2076387 : if (property->getLayer() > valueParser_.getLayer()) {
694 0 : state_.push(State::Ignore(true));
695 0 : return;
696 : }
697 : int finalizedLayer = std::min(
698 17304 : finalized ? valueParser_.getLayer() : Data::NO_LAYER,
699 2093691 : property->getFinalized());
700 2076387 : property->setFinalized(finalizedLayer);
701 2076387 : if (finalizedLayer < valueParser_.getLayer()) {
702 0 : state_.push(State::Ignore(true));
703 0 : return;
704 : }
705 2575515 : if (type != TYPE_ERROR && property->getStaticType() != TYPE_ANY &&
706 499128 : type != property->getStaticType())
707 : {
708 : throw css::uno::RuntimeException(
709 0 : "invalid type for prop " + name + " in " + reader.getUrl(),
710 0 : css::uno::Reference< css::uno::XInterface >());
711 : }
712 2076387 : valueParser_.type_ = type == TYPE_ERROR ? property->getStaticType() : type;
713 2076387 : switch (operation) {
714 : case OPERATION_MODIFY:
715 : case OPERATION_REPLACE:
716 : case OPERATION_FUSE:
717 2076387 : state_.push(State::Modify(property));
718 2076387 : recordModification(false);
719 2076387 : break;
720 : case OPERATION_REMOVE:
721 0 : if (!property->isExtension()) {
722 : throw css::uno::RuntimeException(
723 0 : ("invalid remove of non-extension prop " + name + " in " +
724 0 : reader.getUrl()),
725 0 : css::uno::Reference< css::uno::XInterface >());
726 : }
727 0 : group->getMembers().erase(propertyIndex);
728 0 : state_.push(State::Ignore(true));
729 0 : recordModification(false);
730 0 : break;
731 : }
732 : }
733 :
734 1038694 : void XcuParser::handleLocalizedGroupProp(
735 : xmlreader::XmlReader const & reader, LocalizedPropertyNode * property,
736 : OUString const & name, Type type, Operation operation, bool finalized)
737 : {
738 1038694 : if (property->getLayer() > valueParser_.getLayer()) {
739 0 : state_.push(State::Ignore(true));
740 0 : return;
741 : }
742 : int finalizedLayer = std::min(
743 0 : finalized ? valueParser_.getLayer() : Data::NO_LAYER,
744 1038694 : property->getFinalized());
745 1038694 : property->setFinalized(finalizedLayer);
746 1038694 : if (finalizedLayer < valueParser_.getLayer()) {
747 0 : state_.push(State::Ignore(true));
748 0 : return;
749 : }
750 1549750 : if (type != TYPE_ERROR && property->getStaticType() != TYPE_ANY &&
751 511056 : type != property->getStaticType())
752 : {
753 : throw css::uno::RuntimeException(
754 0 : "invalid type for prop " + name + " in " + reader.getUrl(),
755 0 : css::uno::Reference< css::uno::XInterface >());
756 : }
757 1038694 : valueParser_.type_ = type == TYPE_ERROR ? property->getStaticType() : type;
758 1038694 : switch (operation) {
759 : case OPERATION_MODIFY:
760 : case OPERATION_FUSE:
761 1038694 : state_.push(State::Modify(property));
762 1038694 : break;
763 : case OPERATION_REPLACE:
764 : {
765 : rtl::Reference< Node > replacement(
766 : new LocalizedPropertyNode(
767 0 : valueParser_.getLayer(), property->getStaticType(),
768 0 : property->isNillable()));
769 0 : replacement->setFinalized(property->getFinalized());
770 0 : state_.push(State::Insert(replacement, name));
771 0 : recordModification(false);
772 : }
773 0 : break;
774 : case OPERATION_REMOVE:
775 : throw css::uno::RuntimeException(
776 0 : ("invalid remove of non-extension prop " + name + " in " +
777 0 : reader.getUrl()),
778 0 : css::uno::Reference< css::uno::XInterface >());
779 : }
780 : }
781 :
782 118567 : void XcuParser::handleGroupNode(
783 : xmlreader::XmlReader & reader, rtl::Reference< Node > const & group)
784 : {
785 118567 : bool hasName = false;
786 118567 : OUString name;
787 118567 : Operation op = OPERATION_MODIFY;
788 118567 : bool finalized = false;
789 : for (;;) {
790 : int attrNsId;
791 238478 : xmlreader::Span attrLn;
792 238478 : if (!reader.nextAttribute(&attrNsId, &attrLn)) {
793 118567 : break;
794 : }
795 119911 : if (attrNsId == ParseManager::NAMESPACE_OOR && attrLn.equals("name")) {
796 118567 : hasName = true;
797 118567 : name = reader.getAttributeValue(false).convertFromUtf8();
798 2688 : } else if (attrNsId == ParseManager::NAMESPACE_OOR &&
799 1344 : attrLn.equals("op"))
800 : {
801 168 : op = parseOperation(reader.getAttributeValue(true));
802 2352 : } else if (attrNsId == ParseManager::NAMESPACE_OOR &&
803 1176 : attrLn.equals("finalized"))
804 : {
805 840 : finalized = xmldata::parseBoolean(reader.getAttributeValue(true));
806 : }
807 119911 : }
808 118567 : if (!hasName) {
809 : throw css::uno::RuntimeException(
810 0 : "no node name attribute in " + reader.getUrl(),
811 0 : css::uno::Reference< css::uno::XInterface >());
812 : }
813 118567 : if (trackPath_) {
814 85 : path_.push_back(name);
815 85 : if (partial_ != 0 && partial_->contains(path_) == Partial::CONTAINS_NOT)
816 : {
817 0 : state_.push(State::Ignore(true));
818 0 : return;
819 : }
820 : }
821 : rtl::Reference< Node > child(
822 237134 : Data::findNode(valueParser_.getLayer(), group->getMembers(), name));
823 118567 : if (!child.is()) {
824 : SAL_WARN(
825 : "configmgr",
826 : "unknown node \"" << name << "\" in \"" << reader.getUrl() << '"');
827 0 : state_.push(State::Ignore(true));
828 0 : return;
829 : }
830 118567 : Node::Kind kind = child->kind();
831 118567 : if (kind != Node::KIND_GROUP && kind != Node::KIND_SET) {
832 : throw css::uno::RuntimeException(
833 0 : ("bad <node> \"" + name + "\" of non group/set kind in " +
834 0 : reader.getUrl()),
835 0 : css::uno::Reference< css::uno::XInterface >());
836 : }
837 118567 : if (op != OPERATION_MODIFY && op != OPERATION_FUSE) {
838 : throw css::uno::RuntimeException(
839 0 : "invalid operation on group node in " + reader.getUrl(),
840 0 : css::uno::Reference< css::uno::XInterface >());
841 : }
842 : int finalizedLayer = std::min(
843 840 : finalized ? valueParser_.getLayer() : Data::NO_LAYER,
844 119407 : child->getFinalized());
845 118567 : child->setFinalized(finalizedLayer);
846 118567 : if (finalizedLayer < valueParser_.getLayer()) {
847 0 : state_.push(State::Ignore(true));
848 0 : return;
849 : }
850 237134 : state_.push(State::Modify(child));
851 : }
852 :
853 1117173 : void XcuParser::handleSetNode(xmlreader::XmlReader & reader, SetNode * set) {
854 1117173 : bool hasName = false;
855 1117173 : OUString name;
856 2234346 : OUString component(componentName_);
857 1117173 : bool hasNodeType = false;
858 2234346 : OUString nodeType;
859 1117173 : Operation op = OPERATION_MODIFY;
860 1117173 : bool finalized = false;
861 1117173 : bool mandatory = false;
862 : for (;;) {
863 : int attrNsId;
864 3343337 : xmlreader::Span attrLn;
865 3343337 : if (!reader.nextAttribute(&attrNsId, &attrLn)) {
866 1117173 : break;
867 : }
868 2226164 : if (attrNsId == ParseManager::NAMESPACE_OOR && attrLn.equals("name")) {
869 1117173 : hasName = true;
870 1117173 : name = reader.getAttributeValue(false).convertFromUtf8();
871 2217982 : } else if (attrNsId == ParseManager::NAMESPACE_OOR &&
872 1108991 : attrLn.equals("component"))
873 : {
874 0 : component = reader.getAttributeValue(false).convertFromUtf8();
875 2217982 : } else if (attrNsId == ParseManager::NAMESPACE_OOR &&
876 1108991 : attrLn.equals("node-type"))
877 : {
878 0 : hasNodeType = true;
879 0 : nodeType = reader.getAttributeValue(false).convertFromUtf8();
880 2217982 : } else if (attrNsId == ParseManager::NAMESPACE_OOR &&
881 1108991 : attrLn.equals("op"))
882 : {
883 1102103 : op = parseOperation(reader.getAttributeValue(true));
884 13776 : } else if (attrNsId == ParseManager::NAMESPACE_OOR &&
885 6888 : attrLn.equals("finalized"))
886 : {
887 672 : finalized = xmldata::parseBoolean(reader.getAttributeValue(true));
888 12432 : } else if (attrNsId == ParseManager::NAMESPACE_OOR &&
889 6216 : attrLn.equals("mandatory"))
890 : {
891 5712 : mandatory = xmldata::parseBoolean(reader.getAttributeValue(true));
892 : }
893 2226164 : }
894 1117173 : if (!hasName) {
895 : throw css::uno::RuntimeException(
896 0 : "no node name attribute in " + reader.getUrl(),
897 0 : css::uno::Reference< css::uno::XInterface >());
898 : }
899 1117173 : if (trackPath_) {
900 117 : path_.push_back(name);
901 117 : if (partial_ != 0 && partial_->contains(path_) == Partial::CONTAINS_NOT)
902 : {
903 0 : state_.push(State::Ignore(true));
904 0 : return;
905 : }
906 : }
907 : OUString templateName(
908 : xmldata::parseTemplateReference(
909 2234346 : component, hasNodeType, nodeType, &set->getDefaultTemplateName()));
910 1117173 : if (!set->isValidTemplate(templateName)) {
911 : throw css::uno::RuntimeException(
912 0 : ("set member node " + name + " references invalid template " +
913 0 : templateName + " in " + reader.getUrl()),
914 0 : css::uno::Reference< css::uno::XInterface >());
915 : }
916 : rtl::Reference< Node > tmpl(
917 2234346 : data_.getTemplate(valueParser_.getLayer(), templateName));
918 1117173 : if (!tmpl.is()) {
919 : throw css::uno::RuntimeException(
920 0 : ("set member node " + name + " references undefined template " +
921 0 : templateName + " in " + reader.getUrl()),
922 0 : css::uno::Reference< css::uno::XInterface >());
923 : }
924 1117173 : int finalizedLayer = finalized ? valueParser_.getLayer() : Data::NO_LAYER;
925 1117173 : int mandatoryLayer = mandatory ? valueParser_.getLayer() : Data::NO_LAYER;
926 1117173 : NodeMap & members = set->getMembers();
927 1117173 : NodeMap::iterator i(members.find(name));
928 1117173 : if (i != members.end()) {
929 27035 : finalizedLayer = std::min(finalizedLayer, i->second->getFinalized());
930 27035 : i->second->setFinalized(finalizedLayer);
931 27035 : mandatoryLayer = std::min(mandatoryLayer, i->second->getMandatory());
932 27035 : i->second->setMandatory(mandatoryLayer);
933 27035 : if (i->second->getLayer() > valueParser_.getLayer()) {
934 0 : state_.push(State::Ignore(true));
935 0 : return;
936 : }
937 : }
938 1117173 : if (finalizedLayer < valueParser_.getLayer()) {
939 0 : state_.push(State::Ignore(true));
940 0 : return;
941 : }
942 1117173 : switch (op) {
943 : case OPERATION_MODIFY:
944 15070 : if (i == members.end()) {
945 : SAL_WARN(
946 : "configmgr",
947 : "ignoring modify of unknown set member node \"" << name
948 : << "\" in \"" << reader.getUrl() << '"');
949 0 : state_.push(State::Ignore(true));
950 : } else {
951 15070 : state_.push(State::Modify(i->second));
952 : }
953 15070 : break;
954 : case OPERATION_REPLACE:
955 : {
956 1091650 : rtl::Reference< Node > member(tmpl->clone(true));
957 1091650 : member->setLayer(valueParser_.getLayer());
958 1091650 : member->setFinalized(finalizedLayer);
959 1091650 : member->setMandatory(mandatoryLayer);
960 1091650 : state_.push(State::Insert(member, name));
961 1091650 : recordModification(i == members.end());
962 : }
963 1091650 : break;
964 : case OPERATION_FUSE:
965 10453 : if (i == members.end()) {
966 10453 : rtl::Reference< Node > member(tmpl->clone(true));
967 10453 : member->setLayer(valueParser_.getLayer());
968 10453 : member->setFinalized(finalizedLayer);
969 10453 : member->setMandatory(mandatoryLayer);
970 10453 : state_.push(State::Insert(member, name));
971 10453 : recordModification(true);
972 : } else {
973 0 : state_.push(State::Modify(i->second));
974 : }
975 10453 : break;
976 : case OPERATION_REMOVE:
977 : {
978 : // Ignore removal of unknown members and members made mandatory in
979 : // this or a lower layer; forget about user-layer removals that no
980 : // longer remove anything (so that paired additions/removals in the
981 : // user layer do not grow registrymodifications.xcu unbounded):
982 0 : bool known = i != members.end();
983 0 : if (known &&
984 0 : (mandatoryLayer == Data::NO_LAYER ||
985 0 : mandatoryLayer > valueParser_.getLayer()))
986 : {
987 0 : members.erase(i);
988 : }
989 0 : state_.push(State::Ignore(true));
990 0 : if (known) {
991 0 : recordModification(false);
992 : }
993 0 : break;
994 : }
995 1117173 : }
996 : }
997 :
998 3222982 : void XcuParser::recordModification(bool addition) {
999 3222982 : if (broadcastModifications_ != 0) {
1000 0 : broadcastModifications_->add(path_);
1001 : }
1002 3222982 : if (addition && additions_ != 0) {
1003 0 : additions_->push_back(path_);
1004 : }
1005 3222982 : if (recordModifications_) {
1006 2462 : data_.modifications.add(path_);
1007 : }
1008 3222982 : }
1009 :
1010 : }
1011 :
1012 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|