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

Generated by: LCOV version 1.10