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