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-06-15 15:46:12 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        54735 : XMLSubSys::init() {
      62              :     try {
      63        54735 :         XMLPlatformUtils::Initialize();
      64        54735 :         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        54735 : }
      69              : 
      70              : 
      71              : std::string
      72       155280 : XMLSubSys::warnLocalScheme(const std::string& newScheme, const bool haveSUMO_HOME) {
      73       155280 :     if (newScheme != "never" && newScheme != "auto" && newScheme != "always" && newScheme != "local") {
      74            0 :         throw ProcessError("Unknown xml validation scheme + '" + newScheme + "'.");
      75              :     }
      76       155280 :     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        51760 : XMLSubSys::setValidation(const std::string& validationScheme, const std::string& netValidationScheme, const std::string& routeValidationScheme) {
      89        51760 :     const char* sumoPath = std::getenv("SUMO_HOME");
      90       155248 :     const bool haveSUMO_HOME = sumoPath != nullptr && FileHelpers::isReadable(sumoPath + std::string("/data/xsd/net_file.xsd"));
      91        51760 :     myValidationScheme = warnLocalScheme(validationScheme, haveSUMO_HOME);
      92        51760 :     myNetValidationScheme = warnLocalScheme(netValidationScheme, haveSUMO_HOME);
      93        51760 :     myRouteValidationScheme = warnLocalScheme(routeValidationScheme, haveSUMO_HOME);
      94        51760 :     if (myGrammarPool == nullptr &&
      95        33081 :             (myValidationScheme != "never" ||
      96        33081 :              myNetValidationScheme != "never" ||
      97              :              myRouteValidationScheme != "never")) {
      98        18667 :         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        18635 :         myGrammarPool = new XERCES_CPP_NAMESPACE::XMLGrammarPoolImpl(XMLPlatformUtils::fgMemoryManager);
     106        18635 :         SAX2XMLReader* parser(XMLReaderFactory::createXMLReader(XMLPlatformUtils::fgMemoryManager, myGrammarPool));
     107              : #if _XERCES_VERSION >= 30100
     108        18635 :         parser->setFeature(XERCES_CPP_NAMESPACE::XMLUni::fgXercesHandleMultipleImports, true);
     109              : #endif
     110        55905 :         for (const char* const& filetype : {
     111              :                     "additional", "routes", "net"
     112        74540 :                 }) {
     113        55905 :             const std::string file = sumoPath + std::string("/data/xsd/") + filetype + "_file.xsd";
     114        55905 :             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        18635 :         delete parser;
     119              :     }
     120              : }
     121              : 
     122              : 
     123              : void
     124        55091 : XMLSubSys::close() {
     125       104687 :     for (std::vector<SUMOSAXReader*>::iterator i = myReaders.begin(); i != myReaders.end(); ++i) {
     126        49596 :         delete *i;
     127              :     }
     128              :     myReaders.clear();
     129        55091 :     delete myGrammarPool;
     130        55091 :     myGrammarPool = nullptr;
     131        55091 :     XMLPlatformUtils::Terminate();
     132        55091 :     myLCPTranscoder = nullptr;
     133        55091 : }
     134              : 
     135              : 
     136              : SUMOSAXReader*
     137        39369 : XMLSubSys::getSAXReader(SUMOSAXHandler& handler, const bool isNet, const bool isRoute) {
     138        39369 :     std::string validationScheme = isNet ? myNetValidationScheme : myValidationScheme;
     139        39369 :     if (isRoute) {
     140              :         validationScheme = myRouteValidationScheme;
     141              :     }
     142        78738 :     return new SUMOSAXReader(handler, validationScheme, myGrammarPool);
     143              : }
     144              : 
     145              : 
     146              : void
     147        10542 : XMLSubSys::setHandler(GenericSAXHandler& handler) {
     148        10542 :     myReaders[myNextFreeReader - 1]->setHandler(handler);
     149        10542 : }
     150              : 
     151              : 
     152              : bool
     153       147637 : XMLSubSys::runParser(GenericSAXHandler& handler, const std::string& file,
     154              :                      const bool isNet, const bool isRoute, const bool isExternal, const bool catchExceptions) {
     155       147637 :     MsgHandler::getErrorInstance()->clear();
     156       147637 :     std::string errorMsg = "";
     157              :     try {
     158       147637 :         std::string validationScheme = isNet ? myNetValidationScheme : myValidationScheme;
     159       147637 :         if (isRoute) {
     160              :             validationScheme = myRouteValidationScheme;
     161              :         }
     162       147637 :         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       147637 :         if (myNextFreeReader == (int)myReaders.size()) {
     167        49625 :             myReaders.push_back(new SUMOSAXReader(handler, validationScheme, myGrammarPool));
     168              :         } else {
     169       196956 :             myReaders[myNextFreeReader]->setValidation(validationScheme);
     170        98012 :             myReaders[myNextFreeReader]->setHandler(handler);
     171              :         }
     172       147637 :         myNextFreeReader++;
     173       147637 :         std::string prevFile = handler.getFileName();
     174       147637 :         handler.setFileName(file);
     175       296206 :         myReaders[myNextFreeReader - 1]->parse(file);
     176       146705 :         handler.setFileName(prevFile);
     177       146705 :         myNextFreeReader--;
     178          932 :     } catch (const ProcessError& e) {
     179          932 :         if (catchExceptions) {
     180         1856 :             errorMsg = std::string(e.what()) != std::string("") ? e.what() : TL("Process Error");
     181              :         } else {
     182            4 :             throw;
     183              :         }
     184          932 :     } 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       147633 :     if (errorMsg != "") {
     194          928 :         if (catchExceptions) {
     195         2788 :             WRITE_ERROR(errorMsg);
     196              :         } else {
     197            0 :             throw ProcessError(errorMsg);
     198              :         }
     199              :     }
     200       147633 :     return !MsgHandler::getErrorInstance()->wasInformed();
     201              : }
     202              : 
     203              : 
     204              : std::string
     205    103131252 : XMLSubSys::transcode(const XMLCh* const data, int length) {
     206    103131252 :     if (data == 0) {
     207            0 :         throw EmptyData();
     208              :     }
     209    103131252 :     if (length < 0) {
     210    102991825 :         length = (int)XERCES_CPP_NAMESPACE::XMLString::stringLen(data);
     211              :     }
     212    103131252 :     if (length == 0) {
     213       355179 :         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    102776073 :         XERCES_CPP_NAMESPACE::TranscodeToStr utf8(data, "UTF-8");
     223    102776073 :         return reinterpret_cast<const char*>(utf8.str());
     224    102776073 :     } catch (XERCES_CPP_NAMESPACE::TranscodingException&) {
     225            0 :         return "?";
     226            0 :     }
     227              : #endif
     228              : }
     229              : 
     230              : 
     231              : std::string
     232       855541 : XMLSubSys::transcodeFromLocal(const std::string& localString) {
     233              : #if _XERCES_VERSION > 30100
     234              :     try {
     235       855541 :         if (myLCPTranscoder == nullptr) {
     236        53587 :             myLCPTranscoder = XERCES_CPP_NAMESPACE::XMLPlatformUtils::fgTransService->makeNewLCPTranscoder(XERCES_CPP_NAMESPACE::XMLPlatformUtils::fgMemoryManager);
     237              :         }
     238       855541 :         if (myLCPTranscoder != nullptr) {
     239       855541 :             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       929591 : XMLSubSys::transcodeToLocal(const std::string& utf8String) {
     249              : #if _XERCES_VERSION > 30100
     250              :     try {
     251       929591 :         if (myLCPTranscoder == nullptr) {
     252         1146 :             myLCPTranscoder = XERCES_CPP_NAMESPACE::XMLPlatformUtils::fgTransService->makeNewLCPTranscoder(XERCES_CPP_NAMESPACE::XMLPlatformUtils::fgMemoryManager);
     253              :         }
     254       929591 :         if (myLCPTranscoder != nullptr) {
     255       929591 :             XERCES_CPP_NAMESPACE::TranscodeFromStr utf8(reinterpret_cast<const XMLByte*>(utf8String.c_str()), utf8String.size(), "UTF-8");
     256       929591 :             return myLCPTranscoder->transcode(utf8.str());
     257       929591 :         }
     258            0 :     } catch (XERCES_CPP_NAMESPACE::TranscodingException&) {}
     259              : #endif
     260              :     return utf8String;
     261              : }
     262              : 
     263              : 
     264              : /****************************************************************************/
        

Generated by: LCOV version 2.0-1