LCOV - code coverage report
Current view: top level - src/utils/handlers - TemplateHandler.cpp (source / functions) Coverage Total Hit
Test: lcov.info Lines: 0.0 % 121 0
Test Date: 2026-06-15 15:46:12 Functions: 0.0 % 10 0

            Line data    Source code
       1              : /****************************************************************************/
       2              : // Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo
       3              : // Copyright (C) 2001-2026 German Aerospace Center (DLR) and others.
       4              : // This program and the accompanying materials are made available under the
       5              : // terms of the Eclipse Public License 2.0 which is available at
       6              : // https://www.eclipse.org/legal/epl-2.0/
       7              : // This Source Code may also be made available under the following Secondary
       8              : // Licenses when the conditions for such availability set forth in the Eclipse
       9              : // Public License 2.0 are satisfied: GNU General Public License, version 2
      10              : // or later which is available at
      11              : // https://www.gnu.org/licenses/old-licenses/gpl-2.0-standalone.html
      12              : // SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-or-later
      13              : /****************************************************************************/
      14              : /// @file    TemplateHandler.cpp
      15              : /// @author  Pablo Alvarez Lopez
      16              : /// @date    Dec 2022
      17              : ///
      18              : // A SAX-Handler for loading templates
      19              : /****************************************************************************/
      20              : #include <config.h>
      21              : 
      22              : #include <algorithm>
      23              : #include <string>
      24              : #include <vector>
      25              : #include <xercesc/sax/HandlerBase.hpp>
      26              : #include <xercesc/sax/AttributeList.hpp>
      27              : #include <xercesc/sax/SAXParseException.hpp>
      28              : #include <xercesc/sax/SAXException.hpp>
      29              : #include <utils/common/StringUtils.h>
      30              : #include <utils/xml/XMLSubSys.h>
      31              : #include <utils/common/StringTokenizer.h>
      32              : #include <utils/common/UtilExceptions.h>
      33              : #include <utils/common/FileHelpers.h>
      34              : #include <utils/common/MsgHandler.h>
      35              : #include <utils/common/ToString.h>
      36              : #include <utils/options/OptionsCont.h>
      37              : #include <xercesc/parsers/SAXParser.hpp>
      38              : #include <xercesc/sax2/XMLReaderFactory.hpp>
      39              : #include <xercesc/framework/LocalFileInputSource.hpp>
      40              : #include <xercesc/framework/MemBufInputSource.hpp>
      41              : 
      42              : #include "TemplateHandler.h"
      43              : 
      44              : 
      45              : const std::string TemplateHandler::INVALID_INT_STR = toString(INVALID_INT);
      46              : const std::string TemplateHandler::INVALID_DOUBLE_STR = toString(INVALID_DOUBLE);
      47              : 
      48              : // ===========================================================================
      49              : // method definitions
      50              : // ===========================================================================
      51              : 
      52              : void
      53            0 : TemplateHandler::parseTemplate(OptionsCont& options, const std::string& templateString) {
      54              :     // build parser
      55            0 :     XERCES_CPP_NAMESPACE::SAXParser parser;
      56              :     // disable validation
      57            0 :     parser.setValidationScheme(XERCES_CPP_NAMESPACE::SAXParser::Val_Never);
      58            0 :     parser.setDisableDefaultEntityResolution(true);
      59              :     // build TemplateHandler
      60            0 :     TemplateHandler handler(options);
      61              :     // start parsing
      62              :     try {
      63            0 :         parser.setDocumentHandler(&handler);
      64            0 :         parser.setErrorHandler(&handler);
      65            0 :         XERCES_CPP_NAMESPACE::MemBufInputSource memBufIS((const XMLByte*)templateString.c_str(), templateString.size(), "template");
      66            0 :         parser.parse(memBufIS);
      67            0 :         if (handler.myError) {
      68            0 :             throw ProcessError(TLF("Could not load template '%'.", templateString));
      69              :         }
      70            0 :     } catch (const XERCES_CPP_NAMESPACE::XMLException& e) {
      71            0 :         throw ProcessError("Could not load template '" + templateString + "':\n " + XMLSubSys::transcode(e.getMessage()));
      72            0 :     }
      73              :     // mark al loaded options as default
      74            0 :     options.resetDefault();
      75            0 : }
      76              : 
      77            0 : TemplateHandler::TemplateHandler(OptionsCont& options) :
      78            0 :     myError(false),
      79            0 :     myOptions(options) {
      80            0 : }
      81              : 
      82              : 
      83            0 : TemplateHandler::~TemplateHandler() {}
      84              : 
      85              : 
      86              : void
      87            0 : TemplateHandler::startElement(const XMLCh* const name, XERCES_CPP_NAMESPACE::AttributeList& attributes) {
      88              :     // get current topic
      89            0 :     myOptionName = XMLSubSys::transcode(name);
      90            0 :     if (myLevel++ == 0) {
      91              :         // skip root elemnt
      92              :         return;
      93              :     }
      94              :     // check if this is a subtopic
      95            0 :     if (attributes.getLength() == 0) {
      96            0 :         mySubTopic = myOptionName;
      97            0 :         myOptions.addOptionSubTopic(mySubTopic);
      98              :     } else {
      99              :         // declare options parameters (by default all empty)
     100              :         std::string value;
     101              :         std::string synonymes;
     102              :         std::string type;
     103              :         std::string help;
     104              :         bool required = false;
     105              :         bool positional = false;
     106            0 :         std::string listSep = "";
     107              :         // iterate over attributes
     108            0 :         for (int i = 0; i < (int)attributes.getLength(); i++) {
     109            0 :             const std::string attributeName = XMLSubSys::transcode(attributes.getName(i));
     110            0 :             const std::string attributeValue = XMLSubSys::transcode(attributes.getValue(i));
     111              :             // check attribute name
     112            0 :             if (attributeName == "value") {
     113              :                 value = attributeValue;
     114            0 :             } else if (attributeName == "synonymes") {
     115              :                 synonymes = attributeValue;
     116            0 :             } else if (attributeName == "type") {
     117              :                 type = attributeValue;
     118            0 :             } else if (attributeName == "help") {
     119              :                 help = attributeValue;
     120            0 :             } else if (attributeName == "category") {
     121              :                 // tool templates have subtopic as attribute category
     122            0 :                 mySubTopic = attributeValue;
     123            0 :                 const auto& topics = myOptions.getSubTopics();
     124            0 :                 if (std::find(topics.begin(), topics.end(), attributeValue) == topics.end()) {
     125            0 :                     myOptions.addOptionSubTopic(attributeValue);
     126              :                 }
     127            0 :             } else if (attributeName == "required") {
     128            0 :                 required = StringUtils::toBool(attributeValue);
     129            0 :             } else if (attributeName == "positional") {
     130            0 :                 positional = StringUtils::toBool(attributeValue);
     131            0 :             } else if (attributeName == "listSeparator") {
     132              :                 listSep = attributeValue;
     133              :             }
     134              :         }
     135              :         // add option
     136            0 :         addOption(value, synonymes, type, help, required, positional, listSep);
     137              :     }
     138              : }
     139              : 
     140              : 
     141              : bool
     142            0 : TemplateHandler::addOption(std::string value, const std::string& synonymes, const std::string& type,
     143              :                            const std::string& help, bool required, bool positional, const std::string& listSep) const {
     144            0 :     if (myOptions.exists(myOptionName)) {
     145            0 :         WRITE_WARNING(myOptionName + " already exists");
     146            0 :         return false;
     147              :     } else {
     148              :         // declare option
     149              :         Option* option = nullptr;
     150              :         // handle "None" as empty
     151            0 :         if (value == "None") {
     152              :             value.clear();
     153              :         }
     154              :         // create register depending of type
     155            0 :         if ((type == "STR") || (type == "string")) {
     156            0 :             option = new Option_String(value);
     157            0 :         } else if ((type == "TIME") || (type == "time")) {
     158            0 :             option = new Option_String(value, "TIME");
     159            0 :         } else if ((type == "INT") || (type == "int")) {
     160            0 :             option = new Option_Integer(0);
     161            0 :             if (value.empty()) {
     162            0 :                 option->set(INVALID_INT_STR, "", true);
     163              :             } else {
     164            0 :                 option->set(value, value, true);
     165              :             }
     166            0 :         } else if ((type == "FLOAT") || (type == "float")) {
     167            0 :             option = new Option_Float(0);
     168            0 :             if (value.empty()) {
     169            0 :                 option->set(INVALID_DOUBLE_STR, "", true);
     170              :             } else {
     171            0 :                 option->set(value, value, true);
     172              :             }
     173            0 :         } else if ((type == "BOOL") || (type == "bool")) {
     174            0 :             option = new Option_Bool(false);
     175            0 :             if (value.empty()) {
     176            0 :                 option->set("false", "", true);
     177              :             } else {
     178            0 :                 option->set(value, value, true);
     179              :             }
     180            0 :         } else if (type == "INT[]") {
     181            0 :             option = new Option_IntVector();
     182            0 :         } else if (type == "STR[]") {
     183            0 :             option = new Option_StringVector();
     184            0 :         } else if ((type == "FILE") || (type == "file")) {
     185            0 :             option = new Option_FileName();
     186            0 :         } else if ((type == "NETWORK") || (type == "net_file")) {
     187            0 :             option = new Option_Network(value);
     188            0 :         } else if ((type == "ADDITIONAL") || (type == "additional_file")) {
     189            0 :             option = new Option_Additional(value);
     190            0 :         } else if ((type == "ROUTE") || (type == "route_file")) {
     191            0 :             option = new Option_Route(value);
     192            0 :         } else if ((type == "DATA") || (type == "data_file") || (type == "edgedata_file")) {
     193            0 :             option = new Option_Data(value);
     194            0 :         } else if ((type == "SUMOCONFIG") || (type == "sumoconfig_file")) {
     195            0 :             option = new Option_SumoConfig(value);
     196            0 :         } else if ((type == "EDGE") || (type == "edge")) {
     197            0 :             if (listSep.empty()) {
     198            0 :                 option = new Option_Edge(value);
     199              :             } else {
     200            0 :                 option = new Option_EdgeVector(value);
     201              :             }
     202            0 :         } else if (type.size() > 0) {
     203            0 :             WRITE_WARNING(type + " is an invalid type");
     204              :         }
     205              :         // check if option was created
     206              :         if (option) {
     207              :             // set value
     208            0 :             if (!option->isSet()) {
     209            0 :                 option->set(value, "", false);
     210              :             }
     211            0 :             myOptions.doRegister(myOptionName, option);
     212              :             // check if add synonyme
     213            0 :             if (synonymes.size() > 0) {
     214            0 :                 myOptions.addSynonyme(myOptionName, synonymes);
     215              :             }
     216              :             // check if add help
     217            0 :             if (help.size() > 0) {
     218            0 :                 myOptions.addDescription(myOptionName, mySubTopic, help);
     219              :             }
     220            0 :             myOptions.setFurtherAttributes(myOptionName, mySubTopic, required, positional, listSep);
     221            0 :             return true;
     222              :         } else {
     223            0 :             return false;
     224              :         }
     225              :     }
     226              : }
     227              : 
     228              : 
     229              : void
     230            0 : TemplateHandler::endElement(const XMLCh* const /*name*/) {
     231            0 :     myLevel--;
     232            0 :     if (myOptionName.length() == 0) {
     233              :         return;
     234              :     }
     235            0 :     myOptionName = "";
     236              : }
     237              : 
     238              : 
     239              : void
     240            0 : TemplateHandler::warning(const XERCES_CPP_NAMESPACE::SAXParseException& exception) {
     241            0 :     WRITE_WARNING(XMLSubSys::transcode(exception.getMessage()));
     242            0 :     WRITE_WARNING(" (At line/column " \
     243              :                   + toString(exception.getLineNumber() + 1) + '/' \
     244              :                   + toString(exception.getColumnNumber()) + ").");
     245            0 :     myError = true;
     246            0 : }
     247              : 
     248              : 
     249              : void
     250            0 : TemplateHandler::error(const XERCES_CPP_NAMESPACE::SAXParseException& exception) {
     251            0 :     WRITE_ERROR(XMLSubSys::transcode(exception.getMessage()));
     252            0 :     WRITE_ERROR(" (At line/column "
     253              :                 + toString(exception.getLineNumber() + 1) + '/'
     254              :                 + toString(exception.getColumnNumber()) + ").");
     255            0 :     myError = true;
     256            0 : }
     257              : 
     258              : 
     259              : void
     260            0 : TemplateHandler::fatalError(const XERCES_CPP_NAMESPACE::SAXParseException& exception) {
     261            0 :     WRITE_ERROR(XMLSubSys::transcode(exception.getMessage()));
     262            0 :     WRITE_ERROR(" (At line/column "
     263              :                 + toString(exception.getLineNumber() + 1) + '/'
     264              :                 + toString(exception.getColumnNumber()) + ").");
     265            0 :     myError = true;
     266            0 : }
     267              : 
     268              : /****************************************************************************/
        

Generated by: LCOV version 2.0-1