LCOV - code coverage report
Current view: top level - libreoffice/configmgr/source - xcuparser.cxx (source / functions) Hit Total Coverage
Test: libreoffice_filtered.info Lines: 329 567 58.0 %
Date: 2012-12-27 Functions: 18 19 94.7 %
Legend: Lines: hit not hit

          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: */

Generated by: LCOV version 1.10