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 0 : 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 0 : additions_(additions), recordModifications_(layer == Data::NO_LAYER),
63 : trackPath_(
64 0 : partial_ != 0 || broadcastModifications_ != 0 || additions_ != 0 ||
65 0 : recordModifications_)
66 0 : {}
67 :
68 0 : XcuParser::~XcuParser() {}
69 :
70 0 : xmlreader::XmlReader::Text XcuParser::getTextMode() {
71 0 : return valueParser_.getTextMode();
72 : }
73 :
74 0 : bool XcuParser::startElement(
75 : xmlreader::XmlReader & reader, int nsId, xmlreader::Span const & name,
76 : std::set< OUString > const * existingDependencies)
77 : {
78 0 : if (valueParser_.startElement(reader, nsId, name, existingDependencies)) {
79 0 : return true;
80 : }
81 0 : if (state_.empty()) {
82 0 : if (nsId == ParseManager::NAMESPACE_OOR &&
83 0 : name.equals("component-data"))
84 : {
85 0 : handleComponentData(reader);
86 0 : } else if (nsId == ParseManager::NAMESPACE_OOR && name.equals("items"))
87 : {
88 0 : 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 0 : } else if (state_.top().ignore) {
96 0 : state_.push(State::Ignore(false));
97 0 : } else if (!state_.top().node.is()) {
98 0 : if (nsId == xmlreader::XmlReader::NAMESPACE_NONE && name.equals("item"))
99 : {
100 0 : 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 0 : switch (state_.top().node->kind()) {
109 : case Node::KIND_PROPERTY:
110 0 : if (nsId == xmlreader::XmlReader::NAMESPACE_NONE &&
111 0 : name.equals("value"))
112 : {
113 : handlePropValue(
114 : reader,
115 0 : 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 0 : break;
123 : case Node::KIND_LOCALIZED_PROPERTY:
124 0 : if (nsId == xmlreader::XmlReader::NAMESPACE_NONE &&
125 0 : name.equals("value"))
126 : {
127 : handleLocpropValue(
128 : reader,
129 : static_cast< LocalizedPropertyNode * >(
130 0 : 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 0 : 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 0 : if (nsId == xmlreader::XmlReader::NAMESPACE_NONE &&
145 0 : name.equals("prop"))
146 : {
147 : handleGroupProp(
148 : reader,
149 0 : static_cast< GroupNode * >(state_.top().node.get()));
150 0 : } else if (nsId == xmlreader::XmlReader::NAMESPACE_NONE &&
151 0 : name.equals("node"))
152 : {
153 0 : 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 0 : break;
161 : case Node::KIND_SET:
162 0 : if (nsId == xmlreader::XmlReader::NAMESPACE_NONE &&
163 0 : name.equals("node"))
164 : {
165 : handleSetNode(
166 0 : 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 0 : break;
182 : case Node::KIND_ROOT:
183 : assert(false); // this cannot happen
184 0 : break;
185 : }
186 : }
187 0 : return true;
188 : }
189 :
190 0 : void XcuParser::endElement(xmlreader::XmlReader const &) {
191 0 : if (valueParser_.endElement()) {
192 0 : return;
193 : }
194 : assert(!state_.empty());
195 0 : bool pop = state_.top().pop;
196 0 : rtl::Reference< Node > insert;
197 0 : OUString name;
198 0 : if (state_.top().insert) {
199 0 : insert = state_.top().node;
200 : assert(insert.is());
201 0 : name = state_.top().name;
202 : }
203 0 : state_.pop();
204 0 : if (insert.is()) {
205 : assert(!state_.empty() && state_.top().node.is());
206 0 : state_.top().node->getMembers()[name] = insert;
207 : }
208 0 : if (pop && !path_.empty()) {
209 0 : path_.pop_back();
210 : // </item> will pop less than <item> pushed, but that is harmless,
211 : // as the next <item> will reset path_
212 0 : }
213 : }
214 :
215 0 : void XcuParser::characters(xmlreader::Span const & text) {
216 0 : valueParser_.characters(text);
217 0 : }
218 :
219 0 : XcuParser::Operation XcuParser::parseOperation(xmlreader::Span const & text) {
220 : assert(text.is());
221 0 : if (text.equals("modify")) {
222 0 : return OPERATION_MODIFY;
223 : }
224 0 : if (text.equals("replace")) {
225 0 : return OPERATION_REPLACE;
226 : }
227 0 : if (text.equals("fuse")) {
228 0 : 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 0 : void XcuParser::handleComponentData(xmlreader::XmlReader & reader) {
239 0 : OStringBuffer buf;
240 0 : buf.append('.');
241 0 : bool hasPackage = false;
242 0 : bool hasName = false;
243 0 : Operation op = OPERATION_MODIFY;
244 0 : bool finalized = false;
245 : for (;;) {
246 : int attrNsId;
247 0 : xmlreader::Span attrLn;
248 0 : if (!reader.nextAttribute(&attrNsId, &attrLn)) {
249 0 : break;
250 : }
251 0 : if (attrNsId == ParseManager::NAMESPACE_OOR && attrLn.equals("package"))
252 : {
253 0 : 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 0 : hasPackage = true;
260 0 : xmlreader::Span s(reader.getAttributeValue(false));
261 0 : buf.insert(0, s.begin, s.length);
262 0 : } else if (attrNsId == ParseManager::NAMESPACE_OOR &&
263 0 : attrLn.equals("name"))
264 : {
265 0 : 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 0 : hasName = true;
272 0 : xmlreader::Span s(reader.getAttributeValue(false));
273 0 : 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 0 : }
284 0 : 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 0 : 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 0 : componentName_ = xmlreader::Span(buf.getStr(), buf.getLength()).
295 0 : convertFromUtf8();
296 0 : 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 0 : valueParser_.getLayer(), data_.getComponents(), componentName_));
308 0 : 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 0 : switch (op) {
317 : case OPERATION_MODIFY:
318 : case OPERATION_FUSE:
319 0 : 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 0 : node->getFinalized());
328 0 : node->setFinalized(finalizedLayer);
329 0 : if (finalizedLayer < valueParser_.getLayer()) {
330 0 : state_.push(State::Ignore(true));
331 0 : return;
332 : }
333 0 : state_.push(State::Modify(node));
334 : }
335 :
336 0 : void XcuParser::handleItem(xmlreader::XmlReader & reader) {
337 0 : xmlreader::Span attrPath;
338 : for (;;) {
339 : int attrNsId;
340 0 : xmlreader::Span attrLn;
341 0 : if (!reader.nextAttribute(&attrNsId, &attrLn)) {
342 0 : break;
343 : }
344 0 : if (attrNsId == ParseManager::NAMESPACE_OOR && attrLn.equals("path")) {
345 0 : attrPath = reader.getAttributeValue(false);
346 : }
347 0 : }
348 0 : 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 0 : OUString path(attrPath.convertFromUtf8());
354 : int finalizedLayer;
355 : rtl::Reference< Node > node(
356 : data_.resolvePathRepresentation(
357 0 : path, 0, &path_, &finalizedLayer));
358 0 : 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 0 : componentName_ = path_.front();
367 0 : if (trackPath_) {
368 0 : 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 0 : 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 0 : node.get())->getStaticType();
388 0 : break;
389 : default:
390 0 : break;
391 : }
392 0 : if (finalizedLayer < valueParser_.getLayer()) {
393 0 : state_.push(State::Ignore(true));
394 0 : return;
395 : }
396 0 : state_.push(State::Modify(node));
397 : }
398 :
399 0 : void XcuParser::handlePropValue(
400 : xmlreader::XmlReader & reader, PropertyNode * prop)
401 : {
402 0 : bool nil = false;
403 0 : OString separator;
404 0 : OUString external;
405 : for (;;) {
406 : int attrNsId;
407 0 : xmlreader::Span attrLn;
408 0 : if (!reader.nextAttribute(&attrNsId, &attrLn)) {
409 0 : break;
410 : }
411 0 : if (attrNsId == ParseManager::NAMESPACE_XSI && attrLn.equals("nil")) {
412 0 : nil = xmldata::parseBoolean(reader.getAttributeValue(true));
413 0 : } else if (attrNsId == ParseManager::NAMESPACE_OOR &&
414 0 : 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 0 : } else if (attrNsId == ParseManager::NAMESPACE_OOR &&
425 0 : attrLn.equals("separator"))
426 : {
427 0 : xmlreader::Span s(reader.getAttributeValue(false));
428 0 : 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 0 : separator = OString(s.begin, s.length);
434 0 : } else if (attrNsId == ParseManager::NAMESPACE_OOR &&
435 0 : attrLn.equals("external"))
436 : {
437 0 : external = reader.getAttributeValue(true).convertFromUtf8();
438 0 : 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 0 : }
445 0 : if (nil) {
446 0 : 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 0 : 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 0 : prop->setValue(valueParser_.getLayer(), css::uno::Any());
458 0 : state_.push(State::Ignore(false));
459 0 : } else if (external.isEmpty()) {
460 0 : valueParser_.separator_ = separator;
461 0 : valueParser_.start(prop);
462 : } else {
463 0 : prop->setExternal(valueParser_.getLayer(), external);
464 0 : state_.push(State::Ignore(false));
465 0 : }
466 0 : }
467 :
468 0 : void XcuParser::handleLocpropValue(
469 : xmlreader::XmlReader & reader, LocalizedPropertyNode * locprop)
470 : {
471 0 : OUString name;
472 0 : bool nil = false;
473 0 : OString separator;
474 0 : Operation op = OPERATION_FUSE;
475 : for (;;) {
476 : int attrNsId;
477 0 : xmlreader::Span attrLn;
478 0 : if (!reader.nextAttribute(&attrNsId, &attrLn)) {
479 0 : break;
480 : }
481 0 : if (attrNsId == xmlreader::XmlReader::NAMESPACE_XML &&
482 0 : attrLn.equals("lang"))
483 : {
484 0 : name = reader.getAttributeValue(false).convertFromUtf8();
485 0 : } else if (attrNsId == ParseManager::NAMESPACE_XSI &&
486 0 : attrLn.equals("nil"))
487 : {
488 0 : nil = xmldata::parseBoolean(reader.getAttributeValue(true));
489 0 : } else if (attrNsId == ParseManager::NAMESPACE_OOR &&
490 0 : 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 0 : } else if (attrNsId == ParseManager::NAMESPACE_OOR &&
501 0 : attrLn.equals("separator"))
502 : {
503 0 : xmlreader::Span s(reader.getAttributeValue(false));
504 0 : 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 0 : 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 0 : }
516 0 : if (trackPath_) {
517 0 : path_.push_back(name);
518 0 : 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 0 : NodeMap & members = locprop->getMembers();
526 0 : NodeMap::iterator i(members.find(name));
527 0 : if (i != members.end() && i->second->getLayer() > valueParser_.getLayer()) {
528 0 : state_.push(State::Ignore(true));
529 0 : return;
530 : }
531 0 : 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 0 : switch (op) {
537 : case OPERATION_FUSE:
538 : {
539 0 : bool pop = false;
540 0 : 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 0 : valueParser_.separator_ = separator;
552 0 : valueParser_.start(locprop, name);
553 0 : pop = true;
554 : }
555 0 : if (trackPath_) {
556 0 : recordModification(false);
557 0 : if (pop) {
558 0 : path_.pop_back();
559 : }
560 : }
561 : }
562 0 : 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 0 : }
577 : }
578 :
579 0 : void XcuParser::handleGroupProp(
580 : xmlreader::XmlReader & reader, GroupNode * group)
581 : {
582 0 : bool hasName = false;
583 0 : OUString name;
584 0 : Type type = TYPE_ERROR;
585 0 : Operation op = OPERATION_MODIFY;
586 0 : bool finalized = false;
587 : for (;;) {
588 : int attrNsId;
589 0 : xmlreader::Span attrLn;
590 0 : if (!reader.nextAttribute(&attrNsId, &attrLn)) {
591 0 : break;
592 : }
593 0 : if (attrNsId == ParseManager::NAMESPACE_OOR && attrLn.equals("name")) {
594 0 : hasName = true;
595 0 : name = reader.getAttributeValue(false).convertFromUtf8();
596 0 : } else if (attrNsId == ParseManager::NAMESPACE_OOR &&
597 0 : attrLn.equals("type"))
598 : {
599 0 : type = xmldata::parseType(reader, reader.getAttributeValue(true));
600 0 : } else if (attrNsId == ParseManager::NAMESPACE_OOR &&
601 0 : attrLn.equals("op"))
602 : {
603 0 : op = parseOperation(reader.getAttributeValue(true));
604 0 : } else if (attrNsId == ParseManager::NAMESPACE_OOR &&
605 0 : attrLn.equals("finalized"))
606 : {
607 0 : finalized = xmldata::parseBoolean(reader.getAttributeValue(true));
608 : }
609 0 : }
610 0 : 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 0 : if (trackPath_) {
616 0 : 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 0 : if (partial_ != 0 &&
620 0 : partial_->contains(path_) != Partial::CONTAINS_NODE)
621 : {
622 0 : state_.push(State::Ignore(true));
623 0 : return;
624 : }
625 : }
626 0 : NodeMap & members = group->getMembers();
627 0 : NodeMap::iterator i(members.find(name));
628 0 : if (i == members.end()) {
629 0 : handleUnknownGroupProp(reader, group, name, type, op, finalized);
630 : } else {
631 0 : switch (i->second->kind()) {
632 : case Node::KIND_PROPERTY:
633 0 : handlePlainGroupProp(reader, group, i, name, type, op, finalized);
634 0 : break;
635 : case Node::KIND_LOCALIZED_PROPERTY:
636 : handleLocalizedGroupProp(
637 : reader,
638 0 : static_cast< LocalizedPropertyNode * >(i->second.get()), name,
639 0 : type, op, finalized);
640 0 : 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 0 : }
647 : }
648 :
649 0 : void XcuParser::handleUnknownGroupProp(
650 : xmlreader::XmlReader const & reader, GroupNode * group,
651 : OUString const & name, Type type, Operation operation, bool finalized)
652 : {
653 0 : switch (operation) {
654 : case OPERATION_REPLACE:
655 : case OPERATION_FUSE:
656 0 : if (group->isExtensible()) {
657 0 : 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 0 : valueParser_.type_ = type;
664 : rtl::Reference< Node > prop(
665 : new PropertyNode(
666 0 : valueParser_.getLayer(), TYPE_ANY, true, css::uno::Any(),
667 0 : true));
668 0 : if (finalized) {
669 0 : prop->setFinalized(valueParser_.getLayer());
670 : }
671 0 : state_.push(State::Insert(prop, name));
672 0 : recordModification(false);
673 0 : 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 0 : }
685 :
686 0 : 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 0 : propertyIndex->second.get());
693 0 : if (property->getLayer() > valueParser_.getLayer()) {
694 0 : state_.push(State::Ignore(true));
695 0 : return;
696 : }
697 : int finalizedLayer = std::min(
698 0 : finalized ? valueParser_.getLayer() : Data::NO_LAYER,
699 0 : property->getFinalized());
700 0 : property->setFinalized(finalizedLayer);
701 0 : if (finalizedLayer < valueParser_.getLayer()) {
702 0 : state_.push(State::Ignore(true));
703 0 : return;
704 : }
705 0 : if (type != TYPE_ERROR && property->getStaticType() != TYPE_ANY &&
706 0 : 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 0 : valueParser_.type_ = type == TYPE_ERROR ? property->getStaticType() : type;
713 0 : switch (operation) {
714 : case OPERATION_MODIFY:
715 : case OPERATION_REPLACE:
716 : case OPERATION_FUSE:
717 0 : state_.push(State::Modify(property));
718 0 : recordModification(false);
719 0 : 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 0 : void XcuParser::handleLocalizedGroupProp(
735 : xmlreader::XmlReader const & reader, LocalizedPropertyNode * property,
736 : OUString const & name, Type type, Operation operation, bool finalized)
737 : {
738 0 : 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 0 : property->getFinalized());
745 0 : property->setFinalized(finalizedLayer);
746 0 : if (finalizedLayer < valueParser_.getLayer()) {
747 0 : state_.push(State::Ignore(true));
748 0 : return;
749 : }
750 0 : if (type != TYPE_ERROR && property->getStaticType() != TYPE_ANY &&
751 0 : 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 0 : valueParser_.type_ = type == TYPE_ERROR ? property->getStaticType() : type;
758 0 : switch (operation) {
759 : case OPERATION_MODIFY:
760 : case OPERATION_FUSE:
761 0 : state_.push(State::Modify(property));
762 0 : 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 0 : void XcuParser::handleGroupNode(
783 : xmlreader::XmlReader & reader, rtl::Reference< Node > const & group)
784 : {
785 0 : bool hasName = false;
786 0 : OUString name;
787 0 : Operation op = OPERATION_MODIFY;
788 0 : bool finalized = false;
789 : for (;;) {
790 : int attrNsId;
791 0 : xmlreader::Span attrLn;
792 0 : if (!reader.nextAttribute(&attrNsId, &attrLn)) {
793 0 : break;
794 : }
795 0 : if (attrNsId == ParseManager::NAMESPACE_OOR && attrLn.equals("name")) {
796 0 : hasName = true;
797 0 : name = reader.getAttributeValue(false).convertFromUtf8();
798 0 : } else if (attrNsId == ParseManager::NAMESPACE_OOR &&
799 0 : attrLn.equals("op"))
800 : {
801 0 : op = parseOperation(reader.getAttributeValue(true));
802 0 : } else if (attrNsId == ParseManager::NAMESPACE_OOR &&
803 0 : attrLn.equals("finalized"))
804 : {
805 0 : finalized = xmldata::parseBoolean(reader.getAttributeValue(true));
806 : }
807 0 : }
808 0 : 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 0 : if (trackPath_) {
814 0 : path_.push_back(name);
815 0 : 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 0 : Data::findNode(valueParser_.getLayer(), group->getMembers(), name));
823 0 : 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 0 : Node::Kind kind = child->kind();
831 0 : 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 0 : 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 0 : finalized ? valueParser_.getLayer() : Data::NO_LAYER,
844 0 : child->getFinalized());
845 0 : child->setFinalized(finalizedLayer);
846 0 : if (finalizedLayer < valueParser_.getLayer()) {
847 0 : state_.push(State::Ignore(true));
848 0 : return;
849 : }
850 0 : state_.push(State::Modify(child));
851 : }
852 :
853 0 : void XcuParser::handleSetNode(xmlreader::XmlReader & reader, SetNode * set) {
854 0 : bool hasName = false;
855 0 : OUString name;
856 0 : OUString component(componentName_);
857 0 : bool hasNodeType = false;
858 0 : OUString nodeType;
859 0 : Operation op = OPERATION_MODIFY;
860 0 : bool finalized = false;
861 0 : bool mandatory = false;
862 : for (;;) {
863 : int attrNsId;
864 0 : xmlreader::Span attrLn;
865 0 : if (!reader.nextAttribute(&attrNsId, &attrLn)) {
866 0 : break;
867 : }
868 0 : if (attrNsId == ParseManager::NAMESPACE_OOR && attrLn.equals("name")) {
869 0 : hasName = true;
870 0 : name = reader.getAttributeValue(false).convertFromUtf8();
871 0 : } else if (attrNsId == ParseManager::NAMESPACE_OOR &&
872 0 : attrLn.equals("component"))
873 : {
874 0 : component = reader.getAttributeValue(false).convertFromUtf8();
875 0 : } else if (attrNsId == ParseManager::NAMESPACE_OOR &&
876 0 : attrLn.equals("node-type"))
877 : {
878 0 : hasNodeType = true;
879 0 : nodeType = reader.getAttributeValue(false).convertFromUtf8();
880 0 : } else if (attrNsId == ParseManager::NAMESPACE_OOR &&
881 0 : attrLn.equals("op"))
882 : {
883 0 : op = parseOperation(reader.getAttributeValue(true));
884 0 : } else if (attrNsId == ParseManager::NAMESPACE_OOR &&
885 0 : attrLn.equals("finalized"))
886 : {
887 0 : finalized = xmldata::parseBoolean(reader.getAttributeValue(true));
888 0 : } else if (attrNsId == ParseManager::NAMESPACE_OOR &&
889 0 : attrLn.equals("mandatory"))
890 : {
891 0 : mandatory = xmldata::parseBoolean(reader.getAttributeValue(true));
892 : }
893 0 : }
894 0 : 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 0 : if (trackPath_) {
900 0 : path_.push_back(name);
901 0 : 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 0 : component, hasNodeType, nodeType, &set->getDefaultTemplateName()));
910 0 : 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 0 : data_.getTemplate(valueParser_.getLayer(), templateName));
918 0 : 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 0 : int finalizedLayer = finalized ? valueParser_.getLayer() : Data::NO_LAYER;
925 0 : int mandatoryLayer = mandatory ? valueParser_.getLayer() : Data::NO_LAYER;
926 0 : NodeMap & members = set->getMembers();
927 0 : NodeMap::iterator i(members.find(name));
928 0 : if (i != members.end()) {
929 0 : finalizedLayer = std::min(finalizedLayer, i->second->getFinalized());
930 0 : i->second->setFinalized(finalizedLayer);
931 0 : mandatoryLayer = std::min(mandatoryLayer, i->second->getMandatory());
932 0 : i->second->setMandatory(mandatoryLayer);
933 0 : if (i->second->getLayer() > valueParser_.getLayer()) {
934 0 : state_.push(State::Ignore(true));
935 0 : return;
936 : }
937 : }
938 0 : if (finalizedLayer < valueParser_.getLayer()) {
939 0 : state_.push(State::Ignore(true));
940 0 : return;
941 : }
942 0 : switch (op) {
943 : case OPERATION_MODIFY:
944 0 : 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 0 : state_.push(State::Modify(i->second));
952 : }
953 0 : break;
954 : case OPERATION_REPLACE:
955 : {
956 0 : rtl::Reference< Node > member(tmpl->clone(true));
957 0 : member->setLayer(valueParser_.getLayer());
958 0 : member->setFinalized(finalizedLayer);
959 0 : member->setMandatory(mandatoryLayer);
960 0 : state_.push(State::Insert(member, name));
961 0 : recordModification(i == members.end());
962 : }
963 0 : break;
964 : case OPERATION_FUSE:
965 0 : if (i == members.end()) {
966 0 : rtl::Reference< Node > member(tmpl->clone(true));
967 0 : member->setLayer(valueParser_.getLayer());
968 0 : member->setFinalized(finalizedLayer);
969 0 : member->setMandatory(mandatoryLayer);
970 0 : state_.push(State::Insert(member, name));
971 0 : recordModification(true);
972 : } else {
973 0 : state_.push(State::Modify(i->second));
974 : }
975 0 : 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 0 : }
996 : }
997 :
998 0 : void XcuParser::recordModification(bool addition) {
999 0 : if (broadcastModifications_ != 0) {
1000 0 : broadcastModifications_->add(path_);
1001 : }
1002 0 : if (addition && additions_ != 0) {
1003 0 : additions_->push_back(path_);
1004 : }
1005 0 : if (recordModifications_) {
1006 0 : data_.modifications.add(path_);
1007 : }
1008 0 : }
1009 :
1010 : }
1011 :
1012 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|