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