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

Generated by: LCOV version 1.11