LCOV - code coverage report
Current view: top level - src/utils/xml - XMLSubSys.cpp (source / functions) Coverage Total Hit
Test: lcov.info Lines: 83.3 % 114 95
Test Date: 2026-07-05 15:55:58 Functions: 100.0 % 10 10

            Line data    Source code
       1              : /****************************************************************************/
       2              : // Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo
       3              : // Copyright (C) 2002-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    XMLSubSys.cpp
      15              : /// @author  Daniel Krajzewicz
      16              : /// @author  Jakob Erdmann
      17              : /// @author  Michael Behrisch
      18              : /// @date    Mon, 1 Jul 2002
      19              : ///
      20              : // Utility methods for initialising, closing and using the XML-subsystem
      21              : /****************************************************************************/
      22              : #include <config.h>
      23              : 
      24              : #include <cstdint>
      25              : #include <xercesc/util/PlatformUtils.hpp>
      26              : #include <xercesc/util/TransService.hpp>
      27              : #include <xercesc/util/TranscodingException.hpp>
      28              : #include <xercesc/util/XMLString.hpp>
      29              : #include <xercesc/sax2/XMLReaderFactory.hpp>
      30              : #include <xercesc/framework/XMLGrammarPoolImpl.hpp>
      31              : #include <utils/common/FileHelpers.h>
      32              : #include <utils/common/MsgHandler.h>
      33              : #include <utils/common/StringUtils.h>
      34              : #include <utils/common/UtilExceptions.h>
      35              : #include "SUMOSAXHandler.h"
      36              : #include "SUMOSAXReader.h"
      37              : #include "XMLSubSys.h"
      38              : 
      39              : using XERCES_CPP_NAMESPACE::SAX2XMLReader;
      40              : using XERCES_CPP_NAMESPACE::XMLPlatformUtils;
      41              : using XERCES_CPP_NAMESPACE::XMLReaderFactory;
      42              : 
      43              : 
      44              : // ===========================================================================
      45              : // static member variables
      46              : // ===========================================================================
      47              : std::vector<SUMOSAXReader*> XMLSubSys::myReaders;
      48              : int XMLSubSys::myNextFreeReader;
      49              : std::string XMLSubSys::myValidationScheme = "local";
      50              : std::string XMLSubSys::myNetValidationScheme = "local";
      51              : std::string XMLSubSys::myRouteValidationScheme = "local";
      52              : XERCES_CPP_NAMESPACE::XMLGrammarPool* XMLSubSys::myGrammarPool = nullptr;
      53              : bool XMLSubSys::myNeedsValidationWarning = true;
      54              : XERCES_CPP_NAMESPACE::XMLLCPTranscoder* XMLSubSys::myLCPTranscoder = nullptr;
      55              : 
      56              : 
      57              : // ===========================================================================
      58              : // method definitions
      59              : // ===========================================================================
      60              : void
      61        54984 : XMLSubSys::init() {
      62              :     try {
      63        54984 :         XMLPlatformUtils::Initialize();
      64        54984 :         myNextFreeReader = 0;
      65            0 :     } catch (const XERCES_CPP_NAMESPACE::XMLException& e) {
      66            0 :         throw ProcessError("Error during XML-initialization:\n " + XMLSubSys::transcode(e.getMessage()));
      67            0 :     }
      68        54984 : }
      69              : 
      70              : 
      71              : std::string
      72       156021 : XMLSubSys::warnLocalScheme(const std::string& newScheme, const bool haveSUMO_HOME) {
      73       156021 :     if (newScheme != "never" && newScheme != "auto" && newScheme != "always" && newScheme != "local") {
      74            0 :         throw ProcessError("Unknown xml validation scheme + '" + newScheme + "'.");
      75              :     }
      76       156021 :     if (!haveSUMO_HOME && newScheme == "local") {
      77           32 :         if (myNeedsValidationWarning) {
      78           16 :             WRITE_WARNING(TL("Environment variable SUMO_HOME is not set properly, disabling XML validation. Set 'auto' or 'always' for web lookups."));
      79           16 :             myNeedsValidationWarning = false;
      80              :         }
      81           32 :         return "never";
      82              :     }
      83              :     return newScheme;
      84              : }
      85              : 
      86              : 
      87              : void
      88        52007 : XMLSubSys::setValidation(const std::string& validationScheme, const std::string& netValidationScheme, const std::string& routeValidationScheme) {
      89        52007 :     const char* sumoPath = std::getenv("SUMO_HOME");
      90       155989 :     const bool haveSUMO_HOME = sumoPath != nullptr && FileHelpers::isReadable(sumoPath + std::string("/data/xsd/net_file.xsd"));
      91        52007 :     myValidationScheme = warnLocalScheme(validationScheme, haveSUMO_HOME);
      92        52007 :     myNetValidationScheme = warnLocalScheme(netValidationScheme, haveSUMO_HOME);
      93        52007 :     myRouteValidationScheme = warnLocalScheme(routeValidationScheme, haveSUMO_HOME);
      94        52007 :     if (myGrammarPool == nullptr &&
      95        33333 :             (myValidationScheme != "never" ||
      96        33333 :              myNetValidationScheme != "never" ||
      97              :              myRouteValidationScheme != "never")) {
      98        18662 :         if (!haveSUMO_HOME) {
      99           32 :             if (myNeedsValidationWarning) {
     100           32 :                 WRITE_WARNING(TL("Environment variable SUMO_HOME is not set properly, XML validation will fail or use slow website lookups."));
     101           32 :                 myNeedsValidationWarning = false;
     102              :             }
     103           32 :             return;
     104              :         }
     105        18630 :         myGrammarPool = new XERCES_CPP_NAMESPACE::XMLGrammarPoolImpl(XMLPlatformUtils::fgMemoryManager);
     106        18630 :         SAX2XMLReader* parser(XMLReaderFactory::createXMLReader(XMLPlatformUtils::fgMemoryManager, myGrammarPool));
     107              : #if _XERCES_VERSION >= 30100
     108        18630 :         parser->setFeature(XERCES_CPP_NAMESPACE::XMLUni::fgXercesHandleMultipleImports, true);
     109              : #endif
     110        55890 :         for (const char* const& filetype : {
     111              :                     "additional", "routes", "net"
     112        74520 :                 }) {
     113        55890 :             const std::string file = sumoPath + std::string("/data/xsd/") + filetype + "_file.xsd";
     114        55890 :             if (!parser->loadGrammar(file.c_str(), XERCES_CPP_NAMESPACE::Grammar::SchemaGrammarType, true)) {
     115            0 :                 WRITE_WARNINGF(TL("Cannot read local schema '%'."), file);
     116              :             }
     117              :         }
     118        18630 :         delete parser;
     119              :     }
     120              : }
     121              : 
     122              : 
     123              : void
     124        55339 : XMLSubSys::close() {
     125       105185 :     for (std::vector<SUMOSAXReader*>::iterator i = myReaders.begin(); i != myReaders.end(); ++i) {
     126        49846 :         delete *i;
     127              :     }
     128              :     myReaders.clear();
     129        55339 :     delete myGrammarPool;
     130        55339 :     myGrammarPool = nullptr;
     131        55339 :     XMLPlatformUtils::Terminate();
     132        55339 :     myLCPTranscoder = nullptr;
     133        55339 : }
     134              : 
     135              : 
     136              : SUMOSAXReader*
     137        39592 : XMLSubSys::getSAXReader(SUMOSAXHandler& handler, const bool isNet, const bool isRoute) {
     138        39592 :     std::string validationScheme = isNet ? myNetValidationScheme : myValidationScheme;
     139        39592 :     if (isRoute) {
     140              :         validationScheme = myRouteValidationScheme;
     141              :     }
     142        79184 :     return new SUMOSAXReader(handler, validationScheme, myGrammarPool);
     143              : }
     144              : 
     145              : 
     146              : void
     147        10758 : XMLSubSys::setHandler(GenericSAXHandler& handler) {
     148        10758 :     myReaders[myNextFreeReader - 1]->setHandler(handler);
     149        10758 : }
     150              : 
     151              : 
     152              : bool
     153       148684 : XMLSubSys::runParser(GenericSAXHandler& handler, const std::string& file,
     154              :                      const bool isNet, const bool isRoute, const bool isExternal, const bool catchExceptions) {
     155       148684 :     MsgHandler::getErrorInstance()->clear();
     156       148684 :     std::string errorMsg = "";
     157              :     try {
     158       148684 :         std::string validationScheme = isNet ? myNetValidationScheme : myValidationScheme;
     159       148684 :         if (isRoute) {
     160              :             validationScheme = myRouteValidationScheme;
     161              :         }
     162       148684 :         if (isExternal && validationScheme == "local") {
     163            3 :             WRITE_MESSAGEF(TL("Disabling XML validation for external file '%'. Use 'auto' or 'always' to enable."), file);
     164              :             validationScheme = "never";
     165              :         }
     166       148684 :         if (myNextFreeReader == (int)myReaders.size()) {
     167        49876 :             myReaders.push_back(new SUMOSAXReader(handler, validationScheme, myGrammarPool));
     168              :         } else {
     169       198549 :             myReaders[myNextFreeReader]->setValidation(validationScheme);
     170        98808 :             myReaders[myNextFreeReader]->setHandler(handler);
     171              :         }
     172       148684 :         myNextFreeReader++;
     173       148684 :         std::string prevFile = handler.getFileName();
     174       148684 :         handler.setFileName(file);
     175       298301 :         myReaders[myNextFreeReader - 1]->parse(file);
     176       147751 :         handler.setFileName(prevFile);
     177       147751 :         myNextFreeReader--;
     178          933 :     } catch (const ProcessError& e) {
     179          933 :         if (catchExceptions) {
     180         1858 :             errorMsg = std::string(e.what()) != std::string("") ? e.what() : TL("Process Error");
     181              :         } else {
     182            4 :             throw;
     183              :         }
     184          933 :     } catch (const std::runtime_error& re) {
     185            0 :         errorMsg = TLF("Runtime error: % while parsing '%'", re.what(), file);
     186            0 :     } catch (const std::exception& ex) {
     187            0 :         errorMsg = TLF("Error occurred: % while parsing '%'", ex.what(), file);
     188            0 :     } catch (const XERCES_CPP_NAMESPACE::SAXException& e) {
     189            0 :         errorMsg = TLF("SAX error occurred while parsing '%':\n %", file, XMLSubSys::transcode(e.getMessage()));
     190            0 :     } catch (...) {
     191            0 :         errorMsg = TLF("Unspecified error occurred while parsing '%'", file);
     192            0 :     }
     193       148680 :     if (errorMsg != "") {
     194          929 :         if (catchExceptions) {
     195         2791 :             WRITE_ERROR(errorMsg);
     196              :         } else {
     197            0 :             throw ProcessError(errorMsg);
     198              :         }
     199              :     }
     200       148680 :     return !MsgHandler::getErrorInstance()->wasInformed();
     201              : }
     202              : 
     203              : 
     204              : std::string
     205    103673625 : XMLSubSys::transcode(const XMLCh* const data, int length) {
     206    103673625 :     if (data == 0) {
     207            0 :         throw EmptyData();
     208              :     }
     209    103673625 :     if (length < 0) {
     210    103534193 :         length = (int)XERCES_CPP_NAMESPACE::XMLString::stringLen(data);
     211              :     }
     212    103673625 :     if (length == 0) {
     213       355378 :         return "";
     214              :     }
     215              : #if _XERCES_VERSION < 30100
     216              :     char* t = XERCES_CPP_NAMESPACE::XMLString::transcode(data);
     217              :     std::string result(t);
     218              :     XERCES_CPP_NAMESPACE::XMLString::release(&t);
     219              :     return result;
     220              : #else
     221              :     try {
     222    103318247 :         XERCES_CPP_NAMESPACE::TranscodeToStr utf8(data, "UTF-8");
     223    103318247 :         return reinterpret_cast<const char*>(utf8.str());
     224    103318247 :     } catch (XERCES_CPP_NAMESPACE::TranscodingException&) {
     225            0 :         return "?";
     226            0 :     }
     227              : #endif
     228              : }
     229              : 
     230              : 
     231              : std::string
     232       873441 : XMLSubSys::transcodeFromLocal(const std::string& localString) {
     233              : #if _XERCES_VERSION > 30100
     234              :     try {
     235       873441 :         if (myLCPTranscoder == nullptr) {
     236        53839 :             myLCPTranscoder = XERCES_CPP_NAMESPACE::XMLPlatformUtils::fgTransService->makeNewLCPTranscoder(XERCES_CPP_NAMESPACE::XMLPlatformUtils::fgMemoryManager);
     237              :         }
     238       873441 :         if (myLCPTranscoder != nullptr) {
     239       873441 :             return transcode(myLCPTranscoder->transcode(localString.c_str()));
     240              :         }
     241            0 :     } catch (XERCES_CPP_NAMESPACE::TranscodingException&) {}
     242              : #endif
     243              :     return localString;
     244              : }
     245              : 
     246              : 
     247              : std::string
     248       935097 : XMLSubSys::transcodeToLocal(const std::string& utf8String) {
     249              : #if _XERCES_VERSION > 30100
     250              :     try {
     251       935097 :         if (myLCPTranscoder == nullptr) {
     252         1143 :             myLCPTranscoder = XERCES_CPP_NAMESPACE::XMLPlatformUtils::fgTransService->makeNewLCPTranscoder(XERCES_CPP_NAMESPACE::XMLPlatformUtils::fgMemoryManager);
     253              :         }
     254       935097 :         if (myLCPTranscoder != nullptr) {
     255       935097 :             XERCES_CPP_NAMESPACE::TranscodeFromStr utf8(reinterpret_cast<const XMLByte*>(utf8String.c_str()), utf8String.size(), "UTF-8");
     256       935097 :             return myLCPTranscoder->transcode(utf8.str());
     257       935097 :         }
     258            0 :     } catch (XERCES_CPP_NAMESPACE::TranscodingException&) {}
     259              : #endif
     260              :     return utf8String;
     261              : }
     262              : 
     263              : 
     264              : /****************************************************************************/
        

Generated by: LCOV version 2.0-1