LCOV - code coverage report
Current view: top level - configmgr/source - xcuparser.cxx (source / functions) Hit Total Coverage
Test: commit 10e77ab3ff6f4314137acd6e2702a6e5c1ce1fae Lines: 376 540 69.6 %
Date: 2014-11-03 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       76935 : 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       76935 :     additions_(additions), recordModifications_(layer == Data::NO_LAYER),
      63             :     trackPath_(
      64       76935 :         partial_ != 0 || broadcastModifications_ != 0 || additions_ != 0 ||
      65      230805 :         recordModifications_)
      66       76935 : {}
      67             : 
      68      153870 : XcuParser::~XcuParser() {}
      69             : 
      70    40538935 : xmlreader::XmlReader::Text XcuParser::getTextMode() {
      71    40538935 :     return valueParser_.getTextMode();
      72             : }
      73             : 
      74    17073906 : bool XcuParser::startElement(
      75             :     xmlreader::XmlReader & reader, int nsId, xmlreader::Span const & name,
      76             :     std::set< OUString > const * existingDependencies)
      77             : {
      78    17073906 :     if (valueParser_.startElement(reader, nsId, name, existingDependencies)) {
      79       49210 :         return true;
      80             :     }
      81    17024696 :     if (state_.empty()) {
      82      153734 :         if (nsId == ParseManager::NAMESPACE_OOR &&
      83       76867 :             name.equals("component-data"))
      84             :         {
      85       76769 :             handleComponentData(reader);
      86          98 :         } else if (nsId == ParseManager::NAMESPACE_OOR && name.equals("items"))
      87             :         {
      88          98 :             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    16947829 :     } else if (state_.top().ignore) {
      95           0 :         state_.push(State::Ignore(false));
      96    16947829 :     } else if (!state_.top().node.is()) {
      97        4892 :         if (nsId == xmlreader::XmlReader::NAMESPACE_NONE && name.equals("item"))
      98             :         {
      99        4892 :             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    16942937 :         switch (state_.top().node->kind()) {
     107             :         case Node::KIND_PROPERTY:
     108     8992114 :             if (nsId == xmlreader::XmlReader::NAMESPACE_NONE &&
     109     4496057 :                 name.equals("value"))
     110             :             {
     111             :                 handlePropValue(
     112             :                     reader,
     113     4496057 :                     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     4496057 :             break;
     120             :         case Node::KIND_LOCALIZED_PROPERTY:
     121     4660208 :             if (nsId == xmlreader::XmlReader::NAMESPACE_NONE &&
     122     2330104 :                 name.equals("value"))
     123             :             {
     124             :                 handleLocpropValue(
     125             :                     reader,
     126             :                     static_cast< LocalizedPropertyNode * >(
     127     2330104 :                         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     2330104 :             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    15129778 :             if (nsId == xmlreader::XmlReader::NAMESPACE_NONE &&
     140     7564889 :                 name.equals("prop"))
     141             :             {
     142             :                 handleGroupProp(
     143             :                     reader,
     144     7295122 :                     static_cast< GroupNode * >(state_.top().node.get()));
     145      539534 :             } else if (nsId == xmlreader::XmlReader::NAMESPACE_NONE &&
     146      269767 :                        name.equals("node"))
     147             :             {
     148      269767 :                 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     7564889 :             break;
     155             :         case Node::KIND_SET:
     156     5103774 :             if (nsId == xmlreader::XmlReader::NAMESPACE_NONE &&
     157     2551887 :                 name.equals("node"))
     158             :             {
     159             :                 handleSetNode(
     160     2551887 :                     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     2551887 :             break;
     175             :         case Node::KIND_ROOT:
     176             :             assert(false); // this cannot happen
     177           0 :             break;
     178             :         }
     179             :     }
     180    17024696 :     return true;
     181             : }
     182             : 
     183    17073906 : void XcuParser::endElement(xmlreader::XmlReader const &) {
     184    17073906 :     if (valueParser_.endElement()) {
     185    23941750 :         return;
     186             :     }
     187             :     assert(!state_.empty());
     188    10206062 :     bool pop = state_.top().pop;
     189    10206062 :     rtl::Reference< Node > insert;
     190    20412124 :     OUString name;
     191    10206062 :     if (state_.top().insert) {
     192     2620443 :         insert = state_.top().node;
     193             :         assert(insert.is());
     194     2620443 :         name = state_.top().name;
     195             :     }
     196    10206062 :     state_.pop();
     197    10206062 :     if (insert.is()) {
     198             :         assert(!state_.empty() && state_.top().node.is());
     199     2620443 :         state_.top().node->getMembers()[name] = insert;
     200             :     }
     201    10206062 :     if (pop && !path_.empty()) {
     202       10830 :         path_.pop_back();
     203             :             // </item> will pop less than <item> pushed, but that is harmless,
     204             :             // as the next <item> will reset path_
     205    10206062 :     }
     206             : }
     207             : 
     208     6467794 : void XcuParser::characters(xmlreader::Span const & text) {
     209     6467794 :     valueParser_.characters(text);
     210     6467794 : }
     211             : 
     212     2624076 : XcuParser::Operation XcuParser::parseOperation(xmlreader::Span const & text) {
     213             :     assert(text.is());
     214     2624076 :     if (text.equals("modify")) {
     215           0 :         return OPERATION_MODIFY;
     216             :     }
     217     2624076 :     if (text.equals("replace")) {
     218     2594601 :         return OPERATION_REPLACE;
     219             :     }
     220       29475 :     if (text.equals("fuse")) {
     221       29475 :         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       76769 : void XcuParser::handleComponentData(xmlreader::XmlReader & reader) {
     231       76769 :     OStringBuffer buf;
     232       76769 :     buf.append('.');
     233       76769 :     bool hasPackage = false;
     234       76769 :     bool hasName = false;
     235       76769 :     Operation op = OPERATION_MODIFY;
     236       76769 :     bool finalized = false;
     237             :     for (;;) {
     238             :         int attrNsId;
     239      230307 :         xmlreader::Span attrLn;
     240      230307 :         if (!reader.nextAttribute(&attrNsId, &attrLn)) {
     241       76769 :             break;
     242             :         }
     243      153538 :         if (attrNsId == ParseManager::NAMESPACE_OOR && attrLn.equals("package"))
     244             :         {
     245       76769 :             if (hasPackage) {
     246             :                 throw css::uno::RuntimeException(
     247           0 :                     "multiple component-update package attributes in " +
     248           0 :                     reader.getUrl());
     249             :             }
     250       76769 :             hasPackage = true;
     251       76769 :             xmlreader::Span s(reader.getAttributeValue(false));
     252       76769 :             buf.insert(0, s.begin, s.length);
     253      153538 :         } else if (attrNsId == ParseManager::NAMESPACE_OOR &&
     254       76769 :                    attrLn.equals("name"))
     255             :         {
     256       76769 :             if (hasName) {
     257             :                 throw css::uno::RuntimeException(
     258           0 :                     "multiple component-update name attributes in " +
     259           0 :                     reader.getUrl());
     260             :             }
     261       76769 :             hasName = true;
     262       76769 :             xmlreader::Span s(reader.getAttributeValue(false));
     263       76769 :             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      153538 :     }
     274       76769 :     if (!hasPackage) {
     275             :         throw css::uno::RuntimeException(
     276           0 :             "no component-data package attribute in " + reader.getUrl());
     277             :     }
     278       76769 :     if (!hasName) {
     279             :         throw css::uno::RuntimeException(
     280           0 :             "no component-data name attribute in " + reader.getUrl());
     281             :     }
     282      153538 :     componentName_ = xmlreader::Span(buf.getStr(), buf.getLength()).
     283       76769 :         convertFromUtf8();
     284       76769 :     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       76769 :         data_.getComponents().findNode(valueParser_.getLayer(),
     295      230307 :                                        componentName_));
     296       76769 :     if (!node.is()) {
     297             :         SAL_WARN(
     298             :             "configmgr",
     299             :             "unknown component \"" << componentName_ << "\" in \""
     300             :                 << reader.getUrl() << '"');
     301           0 :         state_.push(State::Ignore(true));
     302           0 :         return;
     303             :     }
     304       76769 :     switch (op) {
     305             :     case OPERATION_MODIFY:
     306             :     case OPERATION_FUSE:
     307       76769 :         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       76769 :         node->getFinalized());
     315       76769 :     node->setFinalized(finalizedLayer);
     316       76769 :     if (finalizedLayer < valueParser_.getLayer()) {
     317           0 :         state_.push(State::Ignore(true));
     318           0 :         return;
     319             :     }
     320      153538 :     state_.push(State::Modify(node));
     321             : }
     322             : 
     323        4892 : void XcuParser::handleItem(xmlreader::XmlReader & reader) {
     324        4892 :     xmlreader::Span attrPath;
     325             :     for (;;) {
     326             :         int attrNsId;
     327        9784 :         xmlreader::Span attrLn;
     328        9784 :         if (!reader.nextAttribute(&attrNsId, &attrLn)) {
     329        4892 :             break;
     330             :         }
     331        4892 :         if (attrNsId == ParseManager::NAMESPACE_OOR && attrLn.equals("path")) {
     332        4892 :             attrPath = reader.getAttributeValue(false);
     333             :         }
     334        4892 :     }
     335        4892 :     if (!attrPath.is()) {
     336             :         throw css::uno::RuntimeException(
     337           0 :             "missing path attribute in " + reader.getUrl());
     338             :     }
     339        4892 :     OUString path(attrPath.convertFromUtf8());
     340             :     int finalizedLayer;
     341             :     rtl::Reference< Node > node(
     342             :         data_.resolvePathRepresentation(
     343        9784 :             path, 0, &path_, &finalizedLayer));
     344        4892 :     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        4892 :     componentName_ = path_.front();
     353        4892 :     if (trackPath_) {
     354        4892 :         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        4892 :     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          50 :             node.get())->getStaticType();
     374          50 :         break;
     375             :     default:
     376        4842 :         break;
     377             :     }
     378        4892 :     if (finalizedLayer < valueParser_.getLayer()) {
     379           0 :         state_.push(State::Ignore(true));
     380           0 :         return;
     381             :     }
     382        9784 :     state_.push(State::Modify(node));
     383             : }
     384             : 
     385     4496057 : void XcuParser::handlePropValue(
     386             :     xmlreader::XmlReader & reader, PropertyNode * prop)
     387             :  {
     388     4496057 :     bool nil = false;
     389     4496057 :     OString separator;
     390     8992114 :     OUString external;
     391             :     for (;;) {
     392             :         int attrNsId;
     393     4547018 :         xmlreader::Span attrLn;
     394     4547018 :         if (!reader.nextAttribute(&attrNsId, &attrLn)) {
     395     4496057 :             break;
     396             :         }
     397       50961 :         if (attrNsId == ParseManager::NAMESPACE_XSI && attrLn.equals("nil")) {
     398         288 :             nil = xmldata::parseBoolean(reader.getAttributeValue(true));
     399       97917 :         } else if (attrNsId == ParseManager::NAMESPACE_OOR &&
     400       47244 :                    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       97917 :         } else if (attrNsId == ParseManager::NAMESPACE_OOR &&
     410       47244 :                    attrLn.equals("separator"))
     411             :         {
     412       40005 :             xmlreader::Span s(reader.getAttributeValue(false));
     413       40005 :             if (s.length == 0) {
     414             :                 throw css::uno::RuntimeException(
     415           0 :                     "bad oor:separator attribute in " + reader.getUrl());
     416             :             }
     417       40005 :             separator = OString(s.begin, s.length);
     418       17907 :         } else if (attrNsId == ParseManager::NAMESPACE_OOR &&
     419        7239 :                    attrLn.equals("external"))
     420             :         {
     421        7239 :             external = reader.getAttributeValue(true).convertFromUtf8();
     422        7239 :             if (external.isEmpty()) {
     423             :                 throw css::uno::RuntimeException(
     424           0 :                     "bad oor:external attribute value in " + reader.getUrl());
     425             :             }
     426             :         }
     427       50961 :     }
     428     4496057 :     if (nil) {
     429         288 :         if (!prop->isNillable()) {
     430             :             throw css::uno::RuntimeException(
     431           0 :                 "xsi:nil attribute for non-nillable prop in " + reader.getUrl());
     432             :         }
     433         288 :         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         288 :         prop->setValue(valueParser_.getLayer(), css::uno::Any());
     439         288 :         state_.push(State::Ignore(false));
     440     4495769 :     } else if (external.isEmpty()) {
     441     4488530 :         valueParser_.separator_ = separator;
     442     4488530 :         valueParser_.start(prop);
     443             :     } else {
     444        7239 :         prop->setExternal(valueParser_.getLayer(), external);
     445        7239 :         state_.push(State::Ignore(false));
     446     4496057 :     }
     447     4496057 : }
     448             : 
     449     2330104 : void XcuParser::handleLocpropValue(
     450             :     xmlreader::XmlReader & reader, LocalizedPropertyNode * locprop)
     451             : {
     452     2330104 :     OUString name;
     453     2330104 :     bool nil = false;
     454     4660208 :     OString separator;
     455     2330104 :     Operation op = OPERATION_FUSE;
     456             :     for (;;) {
     457             :         int attrNsId;
     458     4516190 :         xmlreader::Span attrLn;
     459     4516190 :         if (!reader.nextAttribute(&attrNsId, &attrLn)) {
     460     2330104 :             break;
     461             :         }
     462     4370648 :         if (attrNsId == xmlreader::XmlReader::NAMESPACE_XML &&
     463     2184562 :             attrLn.equals("lang"))
     464             :         {
     465     2184562 :             name = reader.getAttributeValue(false).convertFromUtf8();
     466        1524 :         } else if (attrNsId == ParseManager::NAMESPACE_XSI &&
     467           0 :                    attrLn.equals("nil"))
     468             :         {
     469           0 :             nil = xmldata::parseBoolean(reader.getAttributeValue(true));
     470        3048 :         } else if (attrNsId == ParseManager::NAMESPACE_OOR &&
     471        1524 :                    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        3048 :         } else if (attrNsId == ParseManager::NAMESPACE_OOR &&
     481        1524 :                    attrLn.equals("separator"))
     482             :         {
     483        1524 :             xmlreader::Span s(reader.getAttributeValue(false));
     484        1524 :             if (s.length == 0) {
     485             :                 throw css::uno::RuntimeException(
     486           0 :                     "bad oor:separator attribute in " + reader.getUrl());
     487             :             }
     488        1524 :             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     2186086 :     }
     495     2330104 :     if (trackPath_) {
     496          50 :         path_.push_back(name);
     497          50 :         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     2330104 :     NodeMap & members = locprop->getMembers();
     505     2330104 :     NodeMap::iterator i(members.find(name));
     506     2330104 :     if (i != members.end() && i->second->getLayer() > valueParser_.getLayer()) {
     507           0 :         state_.push(State::Ignore(true));
     508           0 :         return;
     509             :     }
     510     2330104 :     if (nil && !locprop->isNillable()) {
     511             :         throw css::uno::RuntimeException(
     512           0 :             "xsi:nil attribute for non-nillable prop in " + reader.getUrl());
     513             :     }
     514     2330104 :     switch (op) {
     515             :     case OPERATION_FUSE:
     516             :         {
     517     2330104 :             bool pop = false;
     518     2330104 :             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     2330104 :                 valueParser_.separator_ = separator;
     530     2330104 :                 valueParser_.start(locprop, name);
     531     2330104 :                 pop = true;
     532             :             }
     533     2330104 :             if (trackPath_) {
     534          50 :                 recordModification(false);
     535          50 :                 if (pop) {
     536          50 :                     path_.pop_back();
     537             :                 }
     538             :             }
     539             :         }
     540     2330104 :         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     2330104 :     }
     554             : }
     555             : 
     556     7295122 : void XcuParser::handleGroupProp(
     557             :     xmlreader::XmlReader & reader, GroupNode * group)
     558             : {
     559     7295122 :     bool hasName = false;
     560     7295122 :     OUString name;
     561     7295122 :     Type type = TYPE_ERROR;
     562     7295122 :     Operation op = OPERATION_MODIFY;
     563     7295122 :     bool finalized = false;
     564             :     for (;;) {
     565             :         int attrNsId;
     566    17157324 :         xmlreader::Span attrLn;
     567    17157324 :         if (!reader.nextAttribute(&attrNsId, &attrLn)) {
     568     7295122 :             break;
     569             :         }
     570     9862202 :         if (attrNsId == ParseManager::NAMESPACE_OOR && attrLn.equals("name")) {
     571     7295122 :             hasName = true;
     572     7295122 :             name = reader.getAttributeValue(false).convertFromUtf8();
     573     5134160 :         } else if (attrNsId == ParseManager::NAMESPACE_OOR &&
     574     2567080 :                    attrLn.equals("type"))
     575             :         {
     576     2423024 :             type = xmldata::parseType(reader, reader.getAttributeValue(true));
     577      288112 :         } else if (attrNsId == ParseManager::NAMESPACE_OOR &&
     578      144056 :                    attrLn.equals("op"))
     579             :         {
     580      104813 :             op = parseOperation(reader.getAttributeValue(true));
     581       78486 :         } else if (attrNsId == ParseManager::NAMESPACE_OOR &&
     582       39243 :                    attrLn.equals("finalized"))
     583             :         {
     584       39243 :             finalized = xmldata::parseBoolean(reader.getAttributeValue(true));
     585             :         }
     586     9862202 :     }
     587     7295122 :     if (!hasName) {
     588             :         throw css::uno::RuntimeException(
     589           0 :             "no prop name attribute in " + reader.getUrl());
     590             :     }
     591     7295122 :     if (trackPath_) {
     592        5372 :         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        5372 :         if (partial_ != 0 &&
     596           0 :             partial_->contains(path_) != Partial::CONTAINS_NODE)
     597             :         {
     598           0 :             state_.push(State::Ignore(true));
     599     7295122 :             return;
     600             :         }
     601             :     }
     602     7295122 :     NodeMap & members = group->getMembers();
     603     7295122 :     NodeMap::iterator i(members.find(name));
     604     7295122 :     if (i == members.end()) {
     605      101561 :         handleUnknownGroupProp(reader, group, name, type, op, finalized);
     606             :     } else {
     607     7193561 :         switch (i->second->kind()) {
     608             :         case Node::KIND_PROPERTY:
     609     4825788 :             handlePlainGroupProp(reader, group, i, name, type, op, finalized);
     610     4825788 :             break;
     611             :         case Node::KIND_LOCALIZED_PROPERTY:
     612             :             handleLocalizedGroupProp(
     613             :                 reader,
     614     2367773 :                 static_cast< LocalizedPropertyNode * >(i->second.get()), name,
     615     4735546 :                 type, op, finalized);
     616     2367773 :             break;
     617             :         default:
     618             :             throw css::uno::RuntimeException(
     619           0 :                 "inappropriate prop " + name + " in " + reader.getUrl());
     620             :         }
     621     7295122 :     }
     622             : }
     623             : 
     624      101561 : void XcuParser::handleUnknownGroupProp(
     625             :     xmlreader::XmlReader const & reader, GroupNode * group,
     626             :     OUString const & name, Type type, Operation operation, bool finalized)
     627             : {
     628      101561 :     switch (operation) {
     629             :     case OPERATION_REPLACE:
     630             :     case OPERATION_FUSE:
     631      101561 :         if (group->isExtensible()) {
     632      101561 :             if (type == TYPE_ERROR) {
     633             :                 throw css::uno::RuntimeException(
     634           0 :                     "missing type attribute for prop " + name + " in " +
     635           0 :                     reader.getUrl());
     636             :             }
     637      101561 :             valueParser_.type_ = type;
     638             :             rtl::Reference< Node > prop(
     639             :                 new PropertyNode(
     640      101561 :                     valueParser_.getLayer(), TYPE_ANY, true, css::uno::Any(),
     641      101561 :                     true));
     642      101561 :             if (finalized) {
     643           0 :                 prop->setFinalized(valueParser_.getLayer());
     644             :             }
     645      101561 :             state_.push(State::Insert(prop, name));
     646      101561 :             recordModification(false);
     647      101561 :             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      101561 : }
     659             : 
     660     4825788 : 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     4825788 :         propertyIndex->second.get());
     667     4825788 :     if (property->getLayer() > valueParser_.getLayer()) {
     668           0 :         state_.push(State::Ignore(true));
     669           0 :         return;
     670             :     }
     671             :     int finalizedLayer = std::min(
     672       39243 :         finalized ? valueParser_.getLayer() : Data::NO_LAYER,
     673     4865031 :         property->getFinalized());
     674     4825788 :     property->setFinalized(finalizedLayer);
     675     4825788 :     if (finalizedLayer < valueParser_.getLayer()) {
     676           0 :         state_.push(State::Ignore(true));
     677           0 :         return;
     678             :     }
     679     5958882 :     if (type != TYPE_ERROR && property->getStaticType() != TYPE_ANY &&
     680     1133094 :         type != property->getStaticType())
     681             :     {
     682             :         throw css::uno::RuntimeException(
     683           0 :             "invalid type for prop " + name + " in " + reader.getUrl());
     684             :     }
     685     4825788 :     valueParser_.type_ = type == TYPE_ERROR ? property->getStaticType() : type;
     686     4825788 :     switch (operation) {
     687             :     case OPERATION_MODIFY:
     688             :     case OPERATION_REPLACE:
     689             :     case OPERATION_FUSE:
     690     4825788 :         state_.push(State::Modify(property));
     691     4825788 :         recordModification(false);
     692     4825788 :         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     2367773 : void XcuParser::handleLocalizedGroupProp(
     707             :     xmlreader::XmlReader const & reader, LocalizedPropertyNode * property,
     708             :     OUString const & name, Type type, Operation operation, bool finalized)
     709             : {
     710     2367773 :     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     2367773 :         property->getFinalized());
     717     2367773 :     property->setFinalized(finalizedLayer);
     718     2367773 :     if (finalizedLayer < valueParser_.getLayer()) {
     719           0 :         state_.push(State::Ignore(true));
     720           0 :         return;
     721             :     }
     722     3524870 :     if (type != TYPE_ERROR && property->getStaticType() != TYPE_ANY &&
     723     1157097 :         type != property->getStaticType())
     724             :     {
     725             :         throw css::uno::RuntimeException(
     726           0 :             "invalid type for prop " + name + " in " + reader.getUrl());
     727             :     }
     728     2367773 :     valueParser_.type_ = type == TYPE_ERROR ? property->getStaticType() : type;
     729     2367773 :     switch (operation) {
     730             :     case OPERATION_MODIFY:
     731             :     case OPERATION_FUSE:
     732     2367773 :         state_.push(State::Modify(property));
     733     2367773 :         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      269767 : void XcuParser::handleGroupNode(
     753             :     xmlreader::XmlReader & reader, rtl::Reference< Node > const & group)
     754             : {
     755      269767 :     bool hasName = false;
     756      269767 :     OUString name;
     757      269767 :     Operation op = OPERATION_MODIFY;
     758      269767 :     bool finalized = false;
     759             :     for (;;) {
     760             :         int attrNsId;
     761      542582 :         xmlreader::Span attrLn;
     762      542582 :         if (!reader.nextAttribute(&attrNsId, &attrLn)) {
     763      269767 :             break;
     764             :         }
     765      272815 :         if (attrNsId == ParseManager::NAMESPACE_OOR && attrLn.equals("name")) {
     766      269767 :             hasName = true;
     767      269767 :             name = reader.getAttributeValue(false).convertFromUtf8();
     768        6096 :         } else if (attrNsId == ParseManager::NAMESPACE_OOR &&
     769        3048 :                    attrLn.equals("op"))
     770             :         {
     771         381 :             op = parseOperation(reader.getAttributeValue(true));
     772        5334 :         } else if (attrNsId == ParseManager::NAMESPACE_OOR &&
     773        2667 :                    attrLn.equals("finalized"))
     774             :         {
     775        1905 :             finalized = xmldata::parseBoolean(reader.getAttributeValue(true));
     776             :         }
     777      272815 :     }
     778      269767 :     if (!hasName) {
     779             :         throw css::uno::RuntimeException(
     780           0 :             "no node name attribute in " + reader.getUrl());
     781             :     }
     782      269767 :     if (trackPath_) {
     783         196 :         path_.push_back(name);
     784         196 :         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      539534 :         group->getMembers().findNode(valueParser_.getLayer(), name));
     792      269767 :     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      269767 :     Node::Kind kind = child->kind();
     800      269767 :     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      269767 :     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        1905 :         finalized ? valueParser_.getLayer() : Data::NO_LAYER,
     811      271672 :         child->getFinalized());
     812      269767 :     child->setFinalized(finalizedLayer);
     813      269767 :     if (finalizedLayer < valueParser_.getLayer()) {
     814           0 :         state_.push(State::Ignore(true));
     815           0 :         return;
     816             :     }
     817      539534 :     state_.push(State::Modify(child));
     818             : }
     819             : 
     820     2551887 : void XcuParser::handleSetNode(xmlreader::XmlReader & reader, SetNode * set) {
     821     2551887 :     bool hasName = false;
     822     2551887 :     OUString name;
     823     5103774 :     OUString component(componentName_);
     824     2551887 :     bool hasNodeType = false;
     825     5103774 :     OUString nodeType;
     826     2551887 :     Operation op = OPERATION_MODIFY;
     827     2551887 :     bool finalized = false;
     828     2551887 :     bool mandatory = false;
     829             :     for (;;) {
     830             :         int attrNsId;
     831     7638277 :         xmlreader::Span attrLn;
     832     7638277 :         if (!reader.nextAttribute(&attrNsId, &attrLn)) {
     833     2551887 :             break;
     834             :         }
     835     5086390 :         if (attrNsId == ParseManager::NAMESPACE_OOR && attrLn.equals("name")) {
     836     2551887 :             hasName = true;
     837     2551887 :             name = reader.getAttributeValue(false).convertFromUtf8();
     838     5069006 :         } else if (attrNsId == ParseManager::NAMESPACE_OOR &&
     839     2534503 :                    attrLn.equals("component"))
     840             :         {
     841           0 :             component = reader.getAttributeValue(false).convertFromUtf8();
     842     5069006 :         } else if (attrNsId == ParseManager::NAMESPACE_OOR &&
     843     2534503 :                    attrLn.equals("node-type"))
     844             :         {
     845           0 :             hasNodeType = true;
     846           0 :             nodeType = reader.getAttributeValue(false).convertFromUtf8();
     847     5069006 :         } else if (attrNsId == ParseManager::NAMESPACE_OOR &&
     848     2534503 :                    attrLn.equals("op"))
     849             :         {
     850     2518882 :             op = parseOperation(reader.getAttributeValue(true));
     851       31242 :         } else if (attrNsId == ParseManager::NAMESPACE_OOR &&
     852       15621 :                    attrLn.equals("finalized"))
     853             :         {
     854        1524 :             finalized = xmldata::parseBoolean(reader.getAttributeValue(true));
     855       28194 :         } else if (attrNsId == ParseManager::NAMESPACE_OOR &&
     856       14097 :                    attrLn.equals("mandatory"))
     857             :         {
     858       12954 :             mandatory = xmldata::parseBoolean(reader.getAttributeValue(true));
     859             :         }
     860     5086390 :     }
     861     2551887 :     if (!hasName) {
     862             :         throw css::uno::RuntimeException(
     863           0 :             "no node name attribute in " + reader.getUrl());
     864             :     }
     865     2551887 :     if (trackPath_) {
     866         272 :         path_.push_back(name);
     867         272 :         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     5103774 :             component, hasNodeType, nodeType, &set->getDefaultTemplateName()));
     876     2551887 :     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     5103774 :         data_.getTemplate(valueParser_.getLayer(), templateName));
     883     2551887 :     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     2551887 :     int finalizedLayer = finalized ? valueParser_.getLayer() : Data::NO_LAYER;
     889     2551887 :     int mandatoryLayer = mandatory ? valueParser_.getLayer() : Data::NO_LAYER;
     890     2551887 :     NodeMap & members = set->getMembers();
     891     2551887 :     NodeMap::iterator i(members.find(name));
     892     2551887 :     if (i != members.end()) {
     893       60156 :         finalizedLayer = std::min(finalizedLayer, i->second->getFinalized());
     894       60156 :         i->second->setFinalized(finalizedLayer);
     895       60156 :         mandatoryLayer = std::min(mandatoryLayer, i->second->getMandatory());
     896       60156 :         i->second->setMandatory(mandatoryLayer);
     897       60156 :         if (i->second->getLayer() > valueParser_.getLayer()) {
     898           0 :             state_.push(State::Ignore(true));
     899           0 :             return;
     900             :         }
     901             :     }
     902     2551887 :     if (finalizedLayer < valueParser_.getLayer()) {
     903           0 :         state_.push(State::Ignore(true));
     904           0 :         return;
     905             :     }
     906     2551887 :     switch (op) {
     907             :     case OPERATION_MODIFY:
     908       33005 :         if (i == members.end()) {
     909             :             SAL_WARN(
     910             :                 "configmgr",
     911             :                 "ignoring modify of unknown set member node \"" << name
     912             :                     << "\" in \"" << reader.getUrl() << '"');
     913           0 :             state_.push(State::Ignore(true));
     914             :         } else {
     915       33005 :             state_.push(State::Modify(i->second));
     916             :         }
     917       33005 :         break;
     918             :     case OPERATION_REPLACE:
     919             :         {
     920     2495160 :             rtl::Reference< Node > member(tmpl->clone(true));
     921     2495160 :             member->setLayer(valueParser_.getLayer());
     922     2495160 :             member->setFinalized(finalizedLayer);
     923     2495160 :             member->setMandatory(mandatoryLayer);
     924     2495160 :             state_.push(State::Insert(member, name));
     925     2495160 :             recordModification(i == members.end());
     926             :         }
     927     2495160 :         break;
     928             :     case OPERATION_FUSE:
     929       23722 :         if (i == members.end()) {
     930       23722 :             rtl::Reference< Node > member(tmpl->clone(true));
     931       23722 :             member->setLayer(valueParser_.getLayer());
     932       23722 :             member->setFinalized(finalizedLayer);
     933       23722 :             member->setMandatory(mandatoryLayer);
     934       23722 :             state_.push(State::Insert(member, name));
     935       23722 :             recordModification(true);
     936             :         } else {
     937           0 :             state_.push(State::Modify(i->second));
     938             :         }
     939       23722 :         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     2551887 :     }
     960             : }
     961             : 
     962     7446281 : void XcuParser::recordModification(bool addition) {
     963     7446281 :     if (broadcastModifications_ != 0) {
     964           0 :         broadcastModifications_->add(path_);
     965             :     }
     966     7446281 :     if (addition && additions_ != 0) {
     967           0 :         additions_->push_back(path_);
     968             :     }
     969     7446281 :     if (recordModifications_) {
     970        5694 :         data_.modifications.add(path_);
     971             :     }
     972     7446281 : }
     973             : 
     974             : }
     975             : 
     976             : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Generated by: LCOV version 1.10