LCOV - code coverage report
Current view: top level - configmgr/source - xcuparser.cxx (source / functions) Hit Total Coverage
Test: commit 0e63ca4fde4e446f346e35849c756a30ca294aab Lines: 375 575 65.2 %
Date: 2014-04-11 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       34349 : 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       34349 :     additions_(additions), recordModifications_(layer == Data::NO_LAYER),
      63             :     trackPath_(
      64       34349 :         partial_ != 0 || broadcastModifications_ != 0 || additions_ != 0 ||
      65      103047 :         recordModifications_)
      66       34349 : {}
      67             : 
      68       68698 : XcuParser::~XcuParser() {}
      69             : 
      70    17606120 : xmlreader::XmlReader::Text XcuParser::getTextMode() {
      71    17606120 :     return valueParser_.getTextMode();
      72             : }
      73             : 
      74     7416262 : bool XcuParser::startElement(
      75             :     xmlreader::XmlReader & reader, int nsId, xmlreader::Span const & name,
      76             :     std::set< OUString > const * existingDependencies)
      77             : {
      78     7416262 :     if (valueParser_.startElement(reader, nsId, name, existingDependencies)) {
      79       21360 :         return true;
      80             :     }
      81     7394902 :     if (state_.empty()) {
      82       68632 :         if (nsId == ParseManager::NAMESPACE_OOR &&
      83       34316 :             name.equals("component-data"))
      84             :         {
      85       34267 :             handleComponentData(reader);
      86          49 :         } else if (nsId == ParseManager::NAMESPACE_OOR && name.equals("items"))
      87             :         {
      88          49 :             state_.push(State::Modify(rtl::Reference< Node >()));
      89             :         } else {
      90             :             throw css::uno::RuntimeException(
      91           0 :                 ("bad root element <" + name.convertFromUtf8() + "> in " +
      92           0 :                  reader.getUrl()),
      93           0 :                 css::uno::Reference< css::uno::XInterface >());
      94             :         }
      95     7360586 :     } else if (state_.top().ignore) {
      96           0 :         state_.push(State::Ignore(false));
      97     7360586 :     } else if (!state_.top().node.is()) {
      98        2126 :         if (nsId == xmlreader::XmlReader::NAMESPACE_NONE && name.equals("item"))
      99             :         {
     100        2126 :             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     7358460 :         switch (state_.top().node->kind()) {
     109             :         case Node::KIND_PROPERTY:
     110     3882170 :             if (nsId == xmlreader::XmlReader::NAMESPACE_NONE &&
     111     1941085 :                 name.equals("value"))
     112             :             {
     113             :                 handlePropValue(
     114             :                     reader,
     115     1941085 :                     static_cast< PropertyNode * >(state_.top().node.get()));
     116             :             } else {
     117             :                 throw css::uno::RuntimeException(
     118           0 :                     ("bad property node member <" + name.convertFromUtf8() +
     119           0 :                      "> in " + reader.getUrl()),
     120           0 :                     css::uno::Reference< css::uno::XInterface >());
     121             :             }
     122     1941085 :             break;
     123             :         case Node::KIND_LOCALIZED_PROPERTY:
     124     2044192 :             if (nsId == xmlreader::XmlReader::NAMESPACE_NONE &&
     125     1022096 :                 name.equals("value"))
     126             :             {
     127             :                 handleLocpropValue(
     128             :                     reader,
     129             :                     static_cast< LocalizedPropertyNode * >(
     130     1022096 :                         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     1022096 :             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     6556212 :             if (nsId == xmlreader::XmlReader::NAMESPACE_NONE &&
     145     3278106 :                 name.equals("prop"))
     146             :             {
     147             :                 handleGroupProp(
     148             :                     reader,
     149     3159539 :                     static_cast< GroupNode * >(state_.top().node.get()));
     150      237134 :             } else if (nsId == xmlreader::XmlReader::NAMESPACE_NONE &&
     151      118567 :                        name.equals("node"))
     152             :             {
     153      118567 :                 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     3278106 :             break;
     161             :         case Node::KIND_SET:
     162     2234346 :             if (nsId == xmlreader::XmlReader::NAMESPACE_NONE &&
     163     1117173 :                 name.equals("node"))
     164             :             {
     165             :                 handleSetNode(
     166     1117173 :                     reader, static_cast< SetNode * >(state_.top().node.get()));
     167           0 :             } else if (nsId == xmlreader::XmlReader::NAMESPACE_NONE &&
     168           0 :                        name.equals("prop"))
     169             :             {
     170             :                 SAL_WARN(
     171             :                     "configmgr",
     172             :                     "bad set node <prop> member in \"" << reader.getUrl()
     173             :                         << '"');
     174           0 :                 state_.push(State::Ignore(true));
     175             :             } else {
     176             :                 throw css::uno::RuntimeException(
     177           0 :                     ("bad set node member <" + name.convertFromUtf8() +
     178           0 :                      "> in " + reader.getUrl()),
     179           0 :                     css::uno::Reference< css::uno::XInterface >());
     180             :             }
     181     1117173 :             break;
     182             :         case Node::KIND_ROOT:
     183             :             assert(false); // this cannot happen
     184           0 :             break;
     185             :         }
     186             :     }
     187     7394902 :     return true;
     188             : }
     189             : 
     190     7416262 : void XcuParser::endElement(xmlreader::XmlReader const &) {
     191     7416262 :     if (valueParser_.endElement()) {
     192    10397452 :         return;
     193             :     }
     194             :     assert(!state_.empty());
     195     4435072 :     bool pop = state_.top().pop;
     196     4435072 :     rtl::Reference< Node > insert;
     197     8870144 :     OUString name;
     198     4435072 :     if (state_.top().insert) {
     199     1146561 :         insert = state_.top().node;
     200             :         assert(insert.is());
     201     1146561 :         name = state_.top().name;
     202             :     }
     203     4435072 :     state_.pop();
     204     4435072 :     if (insert.is()) {
     205             :         assert(!state_.empty() && state_.top().node.is());
     206     1146561 :         state_.top().node->getMembers()[name] = insert;
     207             :     }
     208     4435072 :     if (pop && !path_.empty()) {
     209        4688 :         path_.pop_back();
     210             :             // </item> will pop less than <item> pushed, but that is harmless,
     211             :             // as the next <item> will reset path_
     212     4435072 :     }
     213             : }
     214             : 
     215     2807814 : void XcuParser::characters(xmlreader::Span const & text) {
     216     2807814 :     valueParser_.characters(text);
     217     2807814 : }
     218             : 
     219     1148430 : XcuParser::Operation XcuParser::parseOperation(xmlreader::Span const & text) {
     220             :     assert(text.is());
     221     1148430 :     if (text.equals("modify")) {
     222           0 :         return OPERATION_MODIFY;
     223             :     }
     224     1148430 :     if (text.equals("replace")) {
     225     1135498 :         return OPERATION_REPLACE;
     226             :     }
     227       12932 :     if (text.equals("fuse")) {
     228       12932 :         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       34267 : void XcuParser::handleComponentData(xmlreader::XmlReader & reader) {
     239       34267 :     OStringBuffer buf;
     240       34267 :     buf.append('.');
     241       34267 :     bool hasPackage = false;
     242       34267 :     bool hasName = false;
     243       34267 :     Operation op = OPERATION_MODIFY;
     244       34267 :     bool finalized = false;
     245             :     for (;;) {
     246             :         int attrNsId;
     247      102801 :         xmlreader::Span attrLn;
     248      102801 :         if (!reader.nextAttribute(&attrNsId, &attrLn)) {
     249       34267 :             break;
     250             :         }
     251       68534 :         if (attrNsId == ParseManager::NAMESPACE_OOR && attrLn.equals("package"))
     252             :         {
     253       34267 :             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       34267 :             hasPackage = true;
     260       34267 :             xmlreader::Span s(reader.getAttributeValue(false));
     261       34267 :             buf.insert(0, s.begin, s.length);
     262       68534 :         } else if (attrNsId == ParseManager::NAMESPACE_OOR &&
     263       34267 :                    attrLn.equals("name"))
     264             :         {
     265       34267 :             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       34267 :             hasName = true;
     272       34267 :             xmlreader::Span s(reader.getAttributeValue(false));
     273       34267 :             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       68534 :     }
     284       34267 :     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       34267 :     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       68534 :     componentName_ = xmlreader::Span(buf.getStr(), buf.getLength()).
     295       34267 :         convertFromUtf8();
     296       34267 :     if (trackPath_) {
     297             :         assert(path_.empty());
     298           0 :         path_.push_back(componentName_);
     299           0 :         if (partial_ != 0 && partial_->contains(path_) == Partial::CONTAINS_NOT)
     300             :         {
     301           0 :             state_.push(State::Ignore(true));
     302           0 :             return;
     303             :         }
     304             :     }
     305             :     rtl::Reference< Node > node(
     306             :         Data::findNode(
     307       68534 :             valueParser_.getLayer(), data_.getComponents(), componentName_));
     308       34267 :     if (!node.is()) {
     309             :         SAL_WARN(
     310             :             "configmgr",
     311             :             "unknown component \"" << componentName_ << "\" in \""
     312             :                 << reader.getUrl() << '"');
     313           0 :         state_.push(State::Ignore(true));
     314           0 :         return;
     315             :     }
     316       34267 :     switch (op) {
     317             :     case OPERATION_MODIFY:
     318             :     case OPERATION_FUSE:
     319       34267 :         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       34267 :         node->getFinalized());
     328       34267 :     node->setFinalized(finalizedLayer);
     329       34267 :     if (finalizedLayer < valueParser_.getLayer()) {
     330           0 :         state_.push(State::Ignore(true));
     331           0 :         return;
     332             :     }
     333       68534 :     state_.push(State::Modify(node));
     334             : }
     335             : 
     336        2126 : void XcuParser::handleItem(xmlreader::XmlReader & reader) {
     337        2126 :     xmlreader::Span attrPath;
     338             :     for (;;) {
     339             :         int attrNsId;
     340        4252 :         xmlreader::Span attrLn;
     341        4252 :         if (!reader.nextAttribute(&attrNsId, &attrLn)) {
     342        2126 :             break;
     343             :         }
     344        2126 :         if (attrNsId == ParseManager::NAMESPACE_OOR && attrLn.equals("path")) {
     345        2126 :             attrPath = reader.getAttributeValue(false);
     346             :         }
     347        2126 :     }
     348        2126 :     if (!attrPath.is()) {
     349             :         throw css::uno::RuntimeException(
     350           0 :             "missing path attribute in " + reader.getUrl(),
     351           0 :             css::uno::Reference< css::uno::XInterface >());
     352             :     }
     353        2126 :     OUString path(attrPath.convertFromUtf8());
     354             :     int finalizedLayer;
     355             :     rtl::Reference< Node > node(
     356             :         data_.resolvePathRepresentation(
     357        4252 :             path, 0, &path_, &finalizedLayer));
     358        2126 :     if (!node.is()) {
     359             :         SAL_WARN(
     360             :             "configmgr",
     361             :             "unknown item \"" << path << "\" in \"" << reader.getUrl() << '"');
     362           0 :         state_.push(State::Ignore(true));
     363           0 :         return;
     364             :     }
     365             :     assert(!path_.empty());
     366        2126 :     componentName_ = path_.front();
     367        2126 :     if (trackPath_) {
     368        2126 :         if (partial_ != 0 && partial_->contains(path_) == Partial::CONTAINS_NOT)
     369             :         {
     370           0 :             state_.push(State::Ignore(true));
     371           0 :             return;
     372             :         }
     373             :     } else {
     374           0 :         path_.clear();
     375             :     }
     376        2126 :     switch (node->kind()) {
     377             :     case Node::KIND_PROPERTY:
     378             :     case Node::KIND_LOCALIZED_VALUE:
     379             :         SAL_WARN(
     380             :             "configmgr",
     381             :             "item of bad type \"" << path << "\" in \"" << reader.getUrl()
     382             :                 << '"');
     383           0 :         state_.push(State::Ignore(true));
     384           0 :         return;
     385             :     case Node::KIND_LOCALIZED_PROPERTY:
     386             :         valueParser_.type_ = static_cast< LocalizedPropertyNode * >(
     387          34 :             node.get())->getStaticType();
     388          34 :         break;
     389             :     default:
     390        2092 :         break;
     391             :     }
     392        2126 :     if (finalizedLayer < valueParser_.getLayer()) {
     393           0 :         state_.push(State::Ignore(true));
     394           0 :         return;
     395             :     }
     396        4252 :     state_.push(State::Modify(node));
     397             : }
     398             : 
     399     1941085 : void XcuParser::handlePropValue(
     400             :     xmlreader::XmlReader & reader, PropertyNode * prop)
     401             :  {
     402     1941085 :     bool nil = false;
     403     1941085 :     OString separator;
     404     3882170 :     OUString external;
     405             :     for (;;) {
     406             :         int attrNsId;
     407     1963588 :         xmlreader::Span attrLn;
     408     1963588 :         if (!reader.nextAttribute(&attrNsId, &attrLn)) {
     409     1941085 :             break;
     410             :         }
     411       22503 :         if (attrNsId == ParseManager::NAMESPACE_XSI && attrLn.equals("nil")) {
     412         159 :             nil = xmldata::parseBoolean(reader.getAttributeValue(true));
     413       43176 :         } else if (attrNsId == ParseManager::NAMESPACE_OOR &&
     414       20832 :                    attrLn.equals("type"))
     415             :         {
     416             :             Type type = xmldata::parseType(
     417           0 :                 reader, reader.getAttributeValue(true));
     418           0 :             if (valueParser_.type_ != TYPE_ANY && type != valueParser_.type_) {
     419             :                 throw css::uno::RuntimeException(
     420           0 :                     "invalid value type in " + reader.getUrl(),
     421           0 :                     css::uno::Reference< css::uno::XInterface >());
     422             :             }
     423           0 :             valueParser_.type_ = type;
     424       43176 :         } else if (attrNsId == ParseManager::NAMESPACE_OOR &&
     425       20832 :                    attrLn.equals("separator"))
     426             :         {
     427       17640 :             xmlreader::Span s(reader.getAttributeValue(false));
     428       17640 :             if (s.length == 0) {
     429             :                 throw css::uno::RuntimeException(
     430           0 :                     "bad oor:separator attribute in " + reader.getUrl(),
     431           0 :                     css::uno::Reference< css::uno::XInterface >());
     432             :             }
     433       17640 :             separator = OString(s.begin, s.length);
     434        7896 :         } else if (attrNsId == ParseManager::NAMESPACE_OOR &&
     435        3192 :                    attrLn.equals("external"))
     436             :         {
     437        3192 :             external = reader.getAttributeValue(true).convertFromUtf8();
     438        3192 :             if (external.isEmpty()) {
     439             :                 throw css::uno::RuntimeException(
     440           0 :                     "bad oor:external attribute value in " + reader.getUrl(),
     441           0 :                     css::uno::Reference< css::uno::XInterface >());
     442             :             }
     443             :         }
     444       22503 :     }
     445     1941085 :     if (nil) {
     446         159 :         if (!prop->isNillable()) {
     447             :             throw css::uno::RuntimeException(
     448           0 :                 "xsi:nil attribute for non-nillable prop in " + reader.getUrl(),
     449           0 :                 css::uno::Reference< css::uno::XInterface >());
     450             :         }
     451         159 :         if (!external.isEmpty()) {
     452             :             throw css::uno::RuntimeException(
     453           0 :                 ("xsi:nil and oor:external attributes for prop in " +
     454           0 :                  reader.getUrl()),
     455           0 :                 css::uno::Reference< css::uno::XInterface >());
     456             :         }
     457         159 :         prop->setValue(valueParser_.getLayer(), css::uno::Any());
     458         159 :         state_.push(State::Ignore(false));
     459     1940926 :     } else if (external.isEmpty()) {
     460     1937734 :         valueParser_.separator_ = separator;
     461     1937734 :         valueParser_.start(prop);
     462             :     } else {
     463        3192 :         prop->setExternal(valueParser_.getLayer(), external);
     464        3192 :         state_.push(State::Ignore(false));
     465     1941085 :     }
     466     1941085 : }
     467             : 
     468     1022096 : void XcuParser::handleLocpropValue(
     469             :     xmlreader::XmlReader & reader, LocalizedPropertyNode * locprop)
     470             : {
     471     1022096 :     OUString name;
     472     1022096 :     bool nil = false;
     473     2044192 :     OString separator;
     474     1022096 :     Operation op = OPERATION_FUSE;
     475             :     for (;;) {
     476             :         int attrNsId;
     477     1983880 :         xmlreader::Span attrLn;
     478     1983880 :         if (!reader.nextAttribute(&attrNsId, &attrLn)) {
     479     1022096 :             break;
     480             :         }
     481     1922896 :         if (attrNsId == xmlreader::XmlReader::NAMESPACE_XML &&
     482      961112 :             attrLn.equals("lang"))
     483             :         {
     484      961112 :             name = reader.getAttributeValue(false).convertFromUtf8();
     485         672 :         } else if (attrNsId == ParseManager::NAMESPACE_XSI &&
     486           0 :                    attrLn.equals("nil"))
     487             :         {
     488           0 :             nil = xmldata::parseBoolean(reader.getAttributeValue(true));
     489        1344 :         } else if (attrNsId == ParseManager::NAMESPACE_OOR &&
     490         672 :                    attrLn.equals("type"))
     491             :         {
     492             :             Type type = xmldata::parseType(
     493           0 :                 reader, reader.getAttributeValue(true));
     494           0 :             if (valueParser_.type_ != TYPE_ANY && type != valueParser_.type_) {
     495             :                 throw css::uno::RuntimeException(
     496           0 :                     "invalid value type in " + reader.getUrl(),
     497           0 :                     css::uno::Reference< css::uno::XInterface >());
     498             :             }
     499           0 :             valueParser_.type_ = type;
     500        1344 :         } else if (attrNsId == ParseManager::NAMESPACE_OOR &&
     501         672 :                    attrLn.equals("separator"))
     502             :         {
     503         672 :             xmlreader::Span s(reader.getAttributeValue(false));
     504         672 :             if (s.length == 0) {
     505             :                 throw css::uno::RuntimeException(
     506           0 :                     "bad oor:separator attribute in " + reader.getUrl(),
     507           0 :                     css::uno::Reference< css::uno::XInterface >());
     508             :             }
     509         672 :             separator = OString(s.begin, s.length);
     510           0 :         } else if (attrNsId == ParseManager::NAMESPACE_OOR &&
     511           0 :                    attrLn.equals("op"))
     512             :         {
     513           0 :             op = parseOperation(reader.getAttributeValue(true));
     514             :         }
     515      961784 :     }
     516     1022096 :     if (trackPath_) {
     517          34 :         path_.push_back(name);
     518          34 :         if (partial_ != 0 &&
     519           0 :             partial_->contains(path_) != Partial::CONTAINS_NODE)
     520             :         {
     521           0 :             state_.push(State::Ignore(true));
     522           0 :             return;
     523             :         }
     524             :     }
     525     1022096 :     NodeMap & members = locprop->getMembers();
     526     1022096 :     NodeMap::iterator i(members.find(name));
     527     1022096 :     if (i != members.end() && i->second->getLayer() > valueParser_.getLayer()) {
     528           0 :         state_.push(State::Ignore(true));
     529           0 :         return;
     530             :     }
     531     1022096 :     if (nil && !locprop->isNillable()) {
     532             :         throw css::uno::RuntimeException(
     533           0 :             "xsi:nil attribute for non-nillable prop in " + reader.getUrl(),
     534           0 :             css::uno::Reference< css::uno::XInterface >());
     535             :     }
     536     1022096 :     switch (op) {
     537             :     case OPERATION_FUSE:
     538             :         {
     539     1022096 :             bool pop = false;
     540     1022096 :             if (nil) {
     541           0 :                 if (i == members.end()) {
     542           0 :                     members[name] = new LocalizedValueNode(
     543           0 :                         valueParser_.getLayer(), css::uno::Any());
     544             :                 } else {
     545             :                     static_cast< LocalizedValueNode * >(
     546           0 :                         i->second.get())->setValue(
     547           0 :                             valueParser_.getLayer(), css::uno::Any());
     548             :                 }
     549           0 :                 state_.push(State::Ignore(true));
     550             :             } else {
     551     1022096 :                 valueParser_.separator_ = separator;
     552     1022096 :                 valueParser_.start(locprop, name);
     553     1022096 :                 pop = true;
     554             :             }
     555     1022096 :             if (trackPath_) {
     556          34 :                 recordModification(false);
     557          34 :                 if (pop) {
     558          34 :                     path_.pop_back();
     559             :                 }
     560             :             }
     561             :         }
     562     1022096 :         break;
     563             :     case OPERATION_REMOVE:
     564             :         //TODO: only allow if parent.op == OPERATION_FUSE
     565             :         //TODO: disallow removing when e.g. lang=""?
     566           0 :         if (i != members.end()) {
     567           0 :             members.erase(i);
     568             :         }
     569           0 :         state_.push(State::Ignore(true));
     570           0 :         recordModification(false);
     571           0 :         break;
     572             :     default:
     573             :         throw css::uno::RuntimeException(
     574           0 :             "bad op attribute for value element in " + reader.getUrl(),
     575           0 :             css::uno::Reference< css::uno::XInterface >());
     576     1022096 :     }
     577             : }
     578             : 
     579     3159539 : void XcuParser::handleGroupProp(
     580             :     xmlreader::XmlReader & reader, GroupNode * group)
     581             : {
     582     3159539 :     bool hasName = false;
     583     3159539 :     OUString name;
     584     3159539 :     Type type = TYPE_ERROR;
     585     3159539 :     Operation op = OPERATION_MODIFY;
     586     3159539 :     bool finalized = false;
     587             :     for (;;) {
     588             :         int attrNsId;
     589     7450959 :         xmlreader::Span attrLn;
     590     7450959 :         if (!reader.nextAttribute(&attrNsId, &attrLn)) {
     591     3159539 :             break;
     592             :         }
     593     4291420 :         if (attrNsId == ParseManager::NAMESPACE_OOR && attrLn.equals("name")) {
     594     3159539 :             hasName = true;
     595     3159539 :             name = reader.getAttributeValue(false).convertFromUtf8();
     596     2263762 :         } else if (attrNsId == ParseManager::NAMESPACE_OOR &&
     597     1131881 :                    attrLn.equals("type"))
     598             :         {
     599     1068418 :             type = xmldata::parseType(reader, reader.getAttributeValue(true));
     600      126926 :         } else if (attrNsId == ParseManager::NAMESPACE_OOR &&
     601       63463 :                    attrLn.equals("op"))
     602             :         {
     603       46159 :             op = parseOperation(reader.getAttributeValue(true));
     604       34608 :         } else if (attrNsId == ParseManager::NAMESPACE_OOR &&
     605       17304 :                    attrLn.equals("finalized"))
     606             :         {
     607       17304 :             finalized = xmldata::parseBoolean(reader.getAttributeValue(true));
     608             :         }
     609     4291420 :     }
     610     3159539 :     if (!hasName) {
     611             :         throw css::uno::RuntimeException(
     612           0 :             "no prop name attribute in " + reader.getUrl(),
     613           0 :             css::uno::Reference< css::uno::XInterface >());
     614             :     }
     615     3159539 :     if (trackPath_) {
     616        2311 :         path_.push_back(name);
     617             :         //TODO: This ignores locprop values for which specific include paths
     618             :         // exist (i.e., for which contains(locprop path) = CONTAINS_SUBNODES):
     619        2311 :         if (partial_ != 0 &&
     620           0 :             partial_->contains(path_) != Partial::CONTAINS_NODE)
     621             :         {
     622           0 :             state_.push(State::Ignore(true));
     623     3159539 :             return;
     624             :         }
     625             :     }
     626     3159539 :     NodeMap & members = group->getMembers();
     627     3159539 :     NodeMap::iterator i(members.find(name));
     628     3159539 :     if (i == members.end()) {
     629       44458 :         handleUnknownGroupProp(reader, group, name, type, op, finalized);
     630             :     } else {
     631     3115081 :         switch (i->second->kind()) {
     632             :         case Node::KIND_PROPERTY:
     633     2076387 :             handlePlainGroupProp(reader, group, i, name, type, op, finalized);
     634     2076387 :             break;
     635             :         case Node::KIND_LOCALIZED_PROPERTY:
     636             :             handleLocalizedGroupProp(
     637             :                 reader,
     638     1038694 :                 static_cast< LocalizedPropertyNode * >(i->second.get()), name,
     639     2077388 :                 type, op, finalized);
     640     1038694 :             break;
     641             :         default:
     642             :             throw css::uno::RuntimeException(
     643           0 :                 "inappropriate prop " + name + " in " + reader.getUrl(),
     644           0 :                 css::uno::Reference< css::uno::XInterface >());
     645             :         }
     646     3159539 :     }
     647             : }
     648             : 
     649       44458 : void XcuParser::handleUnknownGroupProp(
     650             :     xmlreader::XmlReader const & reader, GroupNode * group,
     651             :     OUString const & name, Type type, Operation operation, bool finalized)
     652             : {
     653       44458 :     switch (operation) {
     654             :     case OPERATION_REPLACE:
     655             :     case OPERATION_FUSE:
     656       44458 :         if (group->isExtensible()) {
     657       44458 :             if (type == TYPE_ERROR) {
     658             :                 throw css::uno::RuntimeException(
     659           0 :                     ("missing type attribute for prop " + name + " in " +
     660           0 :                      reader.getUrl()),
     661           0 :                     css::uno::Reference< css::uno::XInterface >());
     662             :             }
     663       44458 :             valueParser_.type_ = type;
     664             :             rtl::Reference< Node > prop(
     665             :                 new PropertyNode(
     666       44458 :                     valueParser_.getLayer(), TYPE_ANY, true, css::uno::Any(),
     667       44458 :                     true));
     668       44458 :             if (finalized) {
     669           0 :                 prop->setFinalized(valueParser_.getLayer());
     670             :             }
     671       44458 :             state_.push(State::Insert(prop, name));
     672       44458 :             recordModification(false);
     673       44458 :             break;
     674             :         }
     675             :         // fall through
     676             :     default:
     677             :         SAL_WARN(
     678             :             "configmgr",
     679             :             "unknown property \"" << name << "\" in \"" << reader.getUrl()
     680             :                 << '"');
     681           0 :         state_.push(State::Ignore(true));
     682           0 :         break;
     683             :     }
     684       44458 : }
     685             : 
     686     2076387 : void XcuParser::handlePlainGroupProp(
     687             :     xmlreader::XmlReader const & reader, GroupNode * group,
     688             :     NodeMap::iterator const & propertyIndex, OUString const & name,
     689             :     Type type, Operation operation, bool finalized)
     690             : {
     691             :     PropertyNode * property = static_cast< PropertyNode * >(
     692     2076387 :         propertyIndex->second.get());
     693     2076387 :     if (property->getLayer() > valueParser_.getLayer()) {
     694           0 :         state_.push(State::Ignore(true));
     695           0 :         return;
     696             :     }
     697             :     int finalizedLayer = std::min(
     698       17304 :         finalized ? valueParser_.getLayer() : Data::NO_LAYER,
     699     2093691 :         property->getFinalized());
     700     2076387 :     property->setFinalized(finalizedLayer);
     701     2076387 :     if (finalizedLayer < valueParser_.getLayer()) {
     702           0 :         state_.push(State::Ignore(true));
     703           0 :         return;
     704             :     }
     705     2575515 :     if (type != TYPE_ERROR && property->getStaticType() != TYPE_ANY &&
     706      499128 :         type != property->getStaticType())
     707             :     {
     708             :         throw css::uno::RuntimeException(
     709           0 :             "invalid type for prop " + name + " in " + reader.getUrl(),
     710           0 :             css::uno::Reference< css::uno::XInterface >());
     711             :     }
     712     2076387 :     valueParser_.type_ = type == TYPE_ERROR ? property->getStaticType() : type;
     713     2076387 :     switch (operation) {
     714             :     case OPERATION_MODIFY:
     715             :     case OPERATION_REPLACE:
     716             :     case OPERATION_FUSE:
     717     2076387 :         state_.push(State::Modify(property));
     718     2076387 :         recordModification(false);
     719     2076387 :         break;
     720             :     case OPERATION_REMOVE:
     721           0 :         if (!property->isExtension()) {
     722             :             throw css::uno::RuntimeException(
     723           0 :                 ("invalid remove of non-extension prop " + name + " in " +
     724           0 :                  reader.getUrl()),
     725           0 :                 css::uno::Reference< css::uno::XInterface >());
     726             :         }
     727           0 :         group->getMembers().erase(propertyIndex);
     728           0 :         state_.push(State::Ignore(true));
     729           0 :         recordModification(false);
     730           0 :         break;
     731             :     }
     732             : }
     733             : 
     734     1038694 : void XcuParser::handleLocalizedGroupProp(
     735             :     xmlreader::XmlReader const & reader, LocalizedPropertyNode * property,
     736             :     OUString const & name, Type type, Operation operation, bool finalized)
     737             : {
     738     1038694 :     if (property->getLayer() > valueParser_.getLayer()) {
     739           0 :         state_.push(State::Ignore(true));
     740           0 :         return;
     741             :     }
     742             :     int finalizedLayer = std::min(
     743           0 :         finalized ? valueParser_.getLayer() : Data::NO_LAYER,
     744     1038694 :         property->getFinalized());
     745     1038694 :     property->setFinalized(finalizedLayer);
     746     1038694 :     if (finalizedLayer < valueParser_.getLayer()) {
     747           0 :         state_.push(State::Ignore(true));
     748           0 :         return;
     749             :     }
     750     1549750 :     if (type != TYPE_ERROR && property->getStaticType() != TYPE_ANY &&
     751      511056 :         type != property->getStaticType())
     752             :     {
     753             :         throw css::uno::RuntimeException(
     754           0 :             "invalid type for prop " + name + " in " + reader.getUrl(),
     755           0 :             css::uno::Reference< css::uno::XInterface >());
     756             :     }
     757     1038694 :     valueParser_.type_ = type == TYPE_ERROR ? property->getStaticType() : type;
     758     1038694 :     switch (operation) {
     759             :     case OPERATION_MODIFY:
     760             :     case OPERATION_FUSE:
     761     1038694 :         state_.push(State::Modify(property));
     762     1038694 :         break;
     763             :     case OPERATION_REPLACE:
     764             :         {
     765             :             rtl::Reference< Node > replacement(
     766             :                 new LocalizedPropertyNode(
     767           0 :                     valueParser_.getLayer(), property->getStaticType(),
     768           0 :                     property->isNillable()));
     769           0 :             replacement->setFinalized(property->getFinalized());
     770           0 :             state_.push(State::Insert(replacement, name));
     771           0 :             recordModification(false);
     772             :         }
     773           0 :         break;
     774             :     case OPERATION_REMOVE:
     775             :         throw css::uno::RuntimeException(
     776           0 :             ("invalid remove of non-extension prop " + name + " in " +
     777           0 :              reader.getUrl()),
     778           0 :             css::uno::Reference< css::uno::XInterface >());
     779             :     }
     780             : }
     781             : 
     782      118567 : void XcuParser::handleGroupNode(
     783             :     xmlreader::XmlReader & reader, rtl::Reference< Node > const & group)
     784             : {
     785      118567 :     bool hasName = false;
     786      118567 :     OUString name;
     787      118567 :     Operation op = OPERATION_MODIFY;
     788      118567 :     bool finalized = false;
     789             :     for (;;) {
     790             :         int attrNsId;
     791      238478 :         xmlreader::Span attrLn;
     792      238478 :         if (!reader.nextAttribute(&attrNsId, &attrLn)) {
     793      118567 :             break;
     794             :         }
     795      119911 :         if (attrNsId == ParseManager::NAMESPACE_OOR && attrLn.equals("name")) {
     796      118567 :             hasName = true;
     797      118567 :             name = reader.getAttributeValue(false).convertFromUtf8();
     798        2688 :         } else if (attrNsId == ParseManager::NAMESPACE_OOR &&
     799        1344 :                    attrLn.equals("op"))
     800             :         {
     801         168 :             op = parseOperation(reader.getAttributeValue(true));
     802        2352 :         } else if (attrNsId == ParseManager::NAMESPACE_OOR &&
     803        1176 :                    attrLn.equals("finalized"))
     804             :         {
     805         840 :             finalized = xmldata::parseBoolean(reader.getAttributeValue(true));
     806             :         }
     807      119911 :     }
     808      118567 :     if (!hasName) {
     809             :         throw css::uno::RuntimeException(
     810           0 :             "no node name attribute in " + reader.getUrl(),
     811           0 :             css::uno::Reference< css::uno::XInterface >());
     812             :     }
     813      118567 :     if (trackPath_) {
     814          85 :         path_.push_back(name);
     815          85 :         if (partial_ != 0 && partial_->contains(path_) == Partial::CONTAINS_NOT)
     816             :         {
     817           0 :             state_.push(State::Ignore(true));
     818           0 :             return;
     819             :         }
     820             :     }
     821             :     rtl::Reference< Node > child(
     822      237134 :         Data::findNode(valueParser_.getLayer(), group->getMembers(), name));
     823      118567 :     if (!child.is()) {
     824             :         SAL_WARN(
     825             :             "configmgr",
     826             :             "unknown node \"" << name << "\" in \"" << reader.getUrl() << '"');
     827           0 :         state_.push(State::Ignore(true));
     828           0 :         return;
     829             :     }
     830      118567 :     Node::Kind kind = child->kind();
     831      118567 :     if (kind != Node::KIND_GROUP && kind != Node::KIND_SET) {
     832             :         throw css::uno::RuntimeException(
     833           0 :             ("bad <node> \"" + name + "\" of non group/set kind in " +
     834           0 :              reader.getUrl()),
     835           0 :             css::uno::Reference< css::uno::XInterface >());
     836             :     }
     837      118567 :     if (op != OPERATION_MODIFY && op != OPERATION_FUSE) {
     838             :         throw css::uno::RuntimeException(
     839           0 :             "invalid operation on group node in " + reader.getUrl(),
     840           0 :             css::uno::Reference< css::uno::XInterface >());
     841             :     }
     842             :     int finalizedLayer = std::min(
     843         840 :         finalized ? valueParser_.getLayer() : Data::NO_LAYER,
     844      119407 :         child->getFinalized());
     845      118567 :     child->setFinalized(finalizedLayer);
     846      118567 :     if (finalizedLayer < valueParser_.getLayer()) {
     847           0 :         state_.push(State::Ignore(true));
     848           0 :         return;
     849             :     }
     850      237134 :     state_.push(State::Modify(child));
     851             : }
     852             : 
     853     1117173 : void XcuParser::handleSetNode(xmlreader::XmlReader & reader, SetNode * set) {
     854     1117173 :     bool hasName = false;
     855     1117173 :     OUString name;
     856     2234346 :     OUString component(componentName_);
     857     1117173 :     bool hasNodeType = false;
     858     2234346 :     OUString nodeType;
     859     1117173 :     Operation op = OPERATION_MODIFY;
     860     1117173 :     bool finalized = false;
     861     1117173 :     bool mandatory = false;
     862             :     for (;;) {
     863             :         int attrNsId;
     864     3343337 :         xmlreader::Span attrLn;
     865     3343337 :         if (!reader.nextAttribute(&attrNsId, &attrLn)) {
     866     1117173 :             break;
     867             :         }
     868     2226164 :         if (attrNsId == ParseManager::NAMESPACE_OOR && attrLn.equals("name")) {
     869     1117173 :             hasName = true;
     870     1117173 :             name = reader.getAttributeValue(false).convertFromUtf8();
     871     2217982 :         } else if (attrNsId == ParseManager::NAMESPACE_OOR &&
     872     1108991 :                    attrLn.equals("component"))
     873             :         {
     874           0 :             component = reader.getAttributeValue(false).convertFromUtf8();
     875     2217982 :         } else if (attrNsId == ParseManager::NAMESPACE_OOR &&
     876     1108991 :                    attrLn.equals("node-type"))
     877             :         {
     878           0 :             hasNodeType = true;
     879           0 :             nodeType = reader.getAttributeValue(false).convertFromUtf8();
     880     2217982 :         } else if (attrNsId == ParseManager::NAMESPACE_OOR &&
     881     1108991 :                    attrLn.equals("op"))
     882             :         {
     883     1102103 :             op = parseOperation(reader.getAttributeValue(true));
     884       13776 :         } else if (attrNsId == ParseManager::NAMESPACE_OOR &&
     885        6888 :                    attrLn.equals("finalized"))
     886             :         {
     887         672 :             finalized = xmldata::parseBoolean(reader.getAttributeValue(true));
     888       12432 :         } else if (attrNsId == ParseManager::NAMESPACE_OOR &&
     889        6216 :                    attrLn.equals("mandatory"))
     890             :         {
     891        5712 :             mandatory = xmldata::parseBoolean(reader.getAttributeValue(true));
     892             :         }
     893     2226164 :     }
     894     1117173 :     if (!hasName) {
     895             :         throw css::uno::RuntimeException(
     896           0 :             "no node name attribute in " + reader.getUrl(),
     897           0 :             css::uno::Reference< css::uno::XInterface >());
     898             :     }
     899     1117173 :     if (trackPath_) {
     900         117 :         path_.push_back(name);
     901         117 :         if (partial_ != 0 && partial_->contains(path_) == Partial::CONTAINS_NOT)
     902             :         {
     903           0 :             state_.push(State::Ignore(true));
     904           0 :             return;
     905             :         }
     906             :     }
     907             :     OUString templateName(
     908             :         xmldata::parseTemplateReference(
     909     2234346 :             component, hasNodeType, nodeType, &set->getDefaultTemplateName()));
     910     1117173 :     if (!set->isValidTemplate(templateName)) {
     911             :         throw css::uno::RuntimeException(
     912           0 :             ("set member node " + name + " references invalid template " +
     913           0 :              templateName + " in " + reader.getUrl()),
     914           0 :             css::uno::Reference< css::uno::XInterface >());
     915             :     }
     916             :     rtl::Reference< Node > tmpl(
     917     2234346 :         data_.getTemplate(valueParser_.getLayer(), templateName));
     918     1117173 :     if (!tmpl.is()) {
     919             :         throw css::uno::RuntimeException(
     920           0 :             ("set member node " + name + " references undefined template " +
     921           0 :              templateName + " in " + reader.getUrl()),
     922           0 :             css::uno::Reference< css::uno::XInterface >());
     923             :     }
     924     1117173 :     int finalizedLayer = finalized ? valueParser_.getLayer() : Data::NO_LAYER;
     925     1117173 :     int mandatoryLayer = mandatory ? valueParser_.getLayer() : Data::NO_LAYER;
     926     1117173 :     NodeMap & members = set->getMembers();
     927     1117173 :     NodeMap::iterator i(members.find(name));
     928     1117173 :     if (i != members.end()) {
     929       27035 :         finalizedLayer = std::min(finalizedLayer, i->second->getFinalized());
     930       27035 :         i->second->setFinalized(finalizedLayer);
     931       27035 :         mandatoryLayer = std::min(mandatoryLayer, i->second->getMandatory());
     932       27035 :         i->second->setMandatory(mandatoryLayer);
     933       27035 :         if (i->second->getLayer() > valueParser_.getLayer()) {
     934           0 :             state_.push(State::Ignore(true));
     935           0 :             return;
     936             :         }
     937             :     }
     938     1117173 :     if (finalizedLayer < valueParser_.getLayer()) {
     939           0 :         state_.push(State::Ignore(true));
     940           0 :         return;
     941             :     }
     942     1117173 :     switch (op) {
     943             :     case OPERATION_MODIFY:
     944       15070 :         if (i == members.end()) {
     945             :             SAL_WARN(
     946             :                 "configmgr",
     947             :                 "ignoring modify of unknown set member node \"" << name
     948             :                     << "\" in \"" << reader.getUrl() << '"');
     949           0 :             state_.push(State::Ignore(true));
     950             :         } else {
     951       15070 :             state_.push(State::Modify(i->second));
     952             :         }
     953       15070 :         break;
     954             :     case OPERATION_REPLACE:
     955             :         {
     956     1091650 :             rtl::Reference< Node > member(tmpl->clone(true));
     957     1091650 :             member->setLayer(valueParser_.getLayer());
     958     1091650 :             member->setFinalized(finalizedLayer);
     959     1091650 :             member->setMandatory(mandatoryLayer);
     960     1091650 :             state_.push(State::Insert(member, name));
     961     1091650 :             recordModification(i == members.end());
     962             :         }
     963     1091650 :         break;
     964             :     case OPERATION_FUSE:
     965       10453 :         if (i == members.end()) {
     966       10453 :             rtl::Reference< Node > member(tmpl->clone(true));
     967       10453 :             member->setLayer(valueParser_.getLayer());
     968       10453 :             member->setFinalized(finalizedLayer);
     969       10453 :             member->setMandatory(mandatoryLayer);
     970       10453 :             state_.push(State::Insert(member, name));
     971       10453 :             recordModification(true);
     972             :         } else {
     973           0 :             state_.push(State::Modify(i->second));
     974             :         }
     975       10453 :         break;
     976             :     case OPERATION_REMOVE:
     977             :         {
     978             :             // Ignore removal of unknown members and members made mandatory in
     979             :             // this or a lower layer; forget about user-layer removals that no
     980             :             // longer remove anything (so that paired additions/removals in the
     981             :             // user layer do not grow registrymodifications.xcu unbounded):
     982           0 :             bool known = i != members.end();
     983           0 :             if (known &&
     984           0 :                 (mandatoryLayer == Data::NO_LAYER ||
     985           0 :                  mandatoryLayer > valueParser_.getLayer()))
     986             :             {
     987           0 :                 members.erase(i);
     988             :             }
     989           0 :             state_.push(State::Ignore(true));
     990           0 :             if (known) {
     991           0 :                 recordModification(false);
     992             :             }
     993           0 :             break;
     994             :         }
     995     1117173 :     }
     996             : }
     997             : 
     998     3222982 : void XcuParser::recordModification(bool addition) {
     999     3222982 :     if (broadcastModifications_ != 0) {
    1000           0 :         broadcastModifications_->add(path_);
    1001             :     }
    1002     3222982 :     if (addition && additions_ != 0) {
    1003           0 :         additions_->push_back(path_);
    1004             :     }
    1005     3222982 :     if (recordModifications_) {
    1006        2462 :         data_.modifications.add(path_);
    1007             :     }
    1008     3222982 : }
    1009             : 
    1010             : }
    1011             : 
    1012             : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Generated by: LCOV version 1.10