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

Generated by: LCOV version 1.10