LCOV - code coverage report
Current view: top level - src/utils/xml - SUMOSAXReader.cpp (source / functions) Coverage Total Hit
Test: lcov.info Lines: 88.6 % 105 93
Test Date: 2024-12-21 15:45:41 Functions: 91.7 % 12 11

            Line data    Source code
       1              : /****************************************************************************/
       2              : // Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo
       3              : // Copyright (C) 2012-2024 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    SUMOSAXReader.cpp
      15              : /// @author  Daniel Krajzewicz
      16              : /// @author  Jakob Erdmann
      17              : /// @author  Michael Behrisch
      18              : /// @date    Nov 2012
      19              : ///
      20              : // SAX-reader encapsulation
      21              : /****************************************************************************/
      22              : #include <config.h>
      23              : 
      24              : #include <string>
      25              : #include <memory>
      26              : #include <iostream>
      27              : #include <xercesc/sax2/XMLReaderFactory.hpp>
      28              : #include <xercesc/framework/LocalFileInputSource.hpp>
      29              : #include <xercesc/framework/MemBufInputSource.hpp>
      30              : 
      31              : #include <utils/common/FileHelpers.h>
      32              : #include <utils/common/MsgHandler.h>
      33              : #include <utils/common/ToString.h>
      34              : #include <utils/common/StringUtils.h>
      35              : #include "GenericSAXHandler.h"
      36              : #ifdef HAVE_ZLIB
      37              : #include <foreign/zstr/zstr.hpp>
      38              : #endif
      39              : #include "IStreamInputSource.h"
      40              : #include "SUMOSAXReader.h"
      41              : 
      42              : using XERCES_CPP_NAMESPACE::SAX2XMLReader;
      43              : using XERCES_CPP_NAMESPACE::XMLUni;
      44              : 
      45              : 
      46              : // ===========================================================================
      47              : // method definitions
      48              : // ===========================================================================
      49              : 
      50       100695 : SUMOSAXReader::SUMOSAXReader(GenericSAXHandler& handler, const std::string& validationScheme, XERCES_CPP_NAMESPACE::XMLGrammarPool* grammarPool) :
      51       100695 :     myHandler(nullptr),
      52       100695 :     myValidationScheme(validationScheme),
      53       100695 :     myGrammarPool(grammarPool),
      54       100695 :     myXMLReader(nullptr),
      55              :     myIStream(nullptr),
      56              :     myInputStream(nullptr),
      57       100695 :     mySchemaResolver(true, false),
      58       100695 :     myLocalResolver(false, false),
      59       100695 :     myNoOpResolver(false, true),
      60              :     myNextSection(-1, nullptr) {
      61       100695 :     setHandler(handler);
      62       100695 : }
      63              : 
      64              : 
      65        97724 : SUMOSAXReader::~SUMOSAXReader() {
      66        97724 :     delete myXMLReader;
      67        97724 :     delete myNextSection.second;
      68       195448 : }
      69              : 
      70              : 
      71              : void
      72       214846 : SUMOSAXReader::setHandler(GenericSAXHandler& handler) {
      73       214846 :     myHandler = &handler;
      74       214846 :     if (myXMLReader != nullptr) {
      75       114151 :         myXMLReader->setContentHandler(&handler);
      76       114151 :         myXMLReader->setErrorHandler(&handler);
      77              :     }
      78       214846 : }
      79              : 
      80              : 
      81              : void
      82       205202 : SUMOSAXReader::setValidation(std::string validationScheme) {
      83              :     // The settings ensure that by default (validationScheme "local" or "never") no network access occurs
      84              :     // this is achieved by either resolving no entities at all (myNoOpResolver) or resolving only
      85              :     // to local files (myLocalResolver). Thus we can safely disable the Sonar warnings in the parse methods below.
      86       205202 :     if (myXMLReader != nullptr && validationScheme != myValidationScheme) {
      87       117862 :         if (validationScheme == "") {
      88              :             validationScheme = myValidationScheme;
      89              :         }
      90              :         // see here https://svn.apache.org/repos/asf/xerces/c/trunk/samples/src/SAX2Count/SAX2Count.cpp for the way to set features
      91       117862 :         if (validationScheme == "never") {
      92        82239 :             myXMLReader->setEntityResolver(&myNoOpResolver);
      93        82239 :             myXMLReader->setProperty(XMLUni::fgXercesScannerName, (void*)XMLUni::fgWFXMLScanner);
      94              :         } else {
      95        35623 :             myXMLReader->setEntityResolver(validationScheme == "local" ? &myLocalResolver : &mySchemaResolver);
      96        35623 :             myXMLReader->setProperty(XMLUni::fgXercesScannerName, (void*)XMLUni::fgIGXMLScanner);
      97        35623 :             myXMLReader->setFeature(XMLUni::fgXercesSchema, true);
      98        35623 :             myXMLReader->setFeature(XMLUni::fgSAX2CoreValidation, true);
      99        35623 :             myXMLReader->setFeature(XMLUni::fgXercesDynamic, validationScheme == "local" || validationScheme == "auto");
     100        35623 :             myXMLReader->setFeature(XMLUni::fgXercesUseCachedGrammarInParse, myValidationScheme == "always");
     101              :         }
     102              :     }
     103       205202 :     myValidationScheme = validationScheme;
     104       205202 : }
     105              : 
     106              : 
     107              : void
     108       159972 : SUMOSAXReader::parse(std::string systemID) {
     109       319944 :     if (!FileHelpers::isReadable(systemID)) {
     110            0 :         throw IOError(TLF("Cannot read file '%'!", systemID));
     111              :     }
     112       319944 :     if (FileHelpers::isDirectory(systemID)) {
     113            0 :         throw IOError(TLF("File '%' is a directory!", systemID));
     114              :     }
     115       159972 :     ensureSAXReader();
     116              : #ifdef HAVE_ZLIB
     117       159972 :     zstr::ifstream istream(StringUtils::transcodeToLocal(systemID).c_str(), std::fstream::in | std::fstream::binary);
     118       159972 :     myXMLReader->parse(IStreamInputSource(istream));  // NOSONAR
     119              : #else
     120              :     myXMLReader->parse(StringUtils::transcodeToLocal(systemID).c_str());  // NOSONAR
     121              : #endif
     122       159972 : }
     123              : 
     124              : 
     125              : void
     126            0 : SUMOSAXReader::parseString(std::string content) {
     127            0 :     ensureSAXReader();
     128            0 :     XERCES_CPP_NAMESPACE::MemBufInputSource memBufIS((const XMLByte*)content.c_str(), content.size(), "registrySettings");
     129            0 :     myXMLReader->parse(memBufIS);  // NOSONAR
     130            0 : }
     131              : 
     132              : 
     133              : bool
     134        45243 : SUMOSAXReader::parseFirst(std::string systemID) {
     135        90486 :     if (!FileHelpers::isReadable(systemID)) {
     136           39 :         throw IOError(TLF("Cannot read file '%'!", systemID));
     137              :     }
     138        90460 :     if (FileHelpers::isDirectory(systemID)) {
     139            0 :         throw IOError(TLF("File '%' is a directory!", systemID));
     140              :     }
     141        45230 :     ensureSAXReader();
     142        45230 :     myToken = XERCES_CPP_NAMESPACE::XMLPScanToken();
     143              : #ifdef HAVE_ZLIB
     144        45230 :     myIStream = std::unique_ptr<zstr::ifstream>(new zstr::ifstream(StringUtils::transcodeToLocal(systemID).c_str(), std::fstream::in | std::fstream::binary));
     145        45230 :     myInputStream = std::unique_ptr<IStreamInputSource>(new IStreamInputSource(*myIStream));
     146        45230 :     return myXMLReader->parseFirst(*myInputStream, myToken);  // NOSONAR
     147              : #else
     148              :     return myXMLReader->parseFirst(StringUtils::transcodeToLocal(systemID).c_str(), myToken);  // NOSONAR
     149              : #endif
     150              : }
     151              : 
     152              : 
     153              : bool
     154      3033964 : SUMOSAXReader::parseNext() {
     155      3033964 :     if (myXMLReader == nullptr) {
     156            0 :         throw ProcessError(TL("The XML-parser was not initialized."));
     157              :     }
     158      3033964 :     return myXMLReader->parseNext(myToken);
     159              : }
     160              : 
     161              : 
     162              : bool
     163          461 : SUMOSAXReader::parseSection(SumoXMLTag element) {
     164          461 :     if (myXMLReader == nullptr) {
     165            0 :         throw ProcessError(TL("The XML-parser was not initialized."));
     166              :     }
     167              :     bool started = false;
     168          461 :     if (myNextSection.first != -1) {
     169          287 :         started = myNextSection.first == element;
     170          287 :         if (!started) {
     171              :             // This enforces that the next parsed section starts right after the last one.
     172              :             // If we want to skip sections we need to change this.
     173            2 :             WRITE_WARNINGF("Expected different XML section '%', some content may be missing.", toString(element));
     174              :         }
     175          287 :         myHandler->myStartElement(myNextSection.first, *myNextSection.second);
     176          287 :         delete myNextSection.second;
     177          287 :         myNextSection.first = -1;
     178          287 :         myNextSection.second = nullptr;
     179              :     }
     180          461 :     myHandler->setSection(element, started);
     181      3494793 :     while (!myHandler->sectionFinished()) {
     182      3494505 :         if (!myXMLReader->parseNext(myToken)) {
     183              :             return false;
     184              :         }
     185              :     }
     186              :     myNextSection = myHandler->retrieveNextSectionStart();
     187          288 :     return true;
     188              : }
     189              : 
     190              : 
     191              : void
     192       205202 : SUMOSAXReader::ensureSAXReader() {
     193       205202 :     if (myXMLReader == nullptr) {
     194       100666 :         myXMLReader = XERCES_CPP_NAMESPACE::XMLReaderFactory::createXMLReader(XERCES_CPP_NAMESPACE::XMLPlatformUtils::fgMemoryManager, myGrammarPool);
     195       100666 :         if (myXMLReader == nullptr) {
     196            0 :             throw ProcessError(TL("The XML-parser could not be build."));
     197              :         }
     198       100666 :         setValidation();
     199       100666 :         myXMLReader->setContentHandler(myHandler);
     200       100666 :         myXMLReader->setErrorHandler(myHandler);
     201              :     }
     202       205202 : }
     203              : 
     204              : 
     205       302085 : SUMOSAXReader::LocalSchemaResolver::LocalSchemaResolver(const bool haveFallback, const bool noOp) :
     206       302085 :     myHaveFallback(haveFallback),
     207       302085 :     myNoOp(noOp) {
     208       302085 : }
     209              : 
     210              : 
     211              : XERCES_CPP_NAMESPACE::InputSource*
     212       225843 : SUMOSAXReader::LocalSchemaResolver::resolveEntity(const XMLCh* const /* publicId */, const XMLCh* const systemId) {
     213       225843 :     if (myNoOp) {
     214            0 :         return new XERCES_CPP_NAMESPACE::MemBufInputSource((const XMLByte*)"", 0, "");
     215              :     }
     216       225843 :     const std::string url = StringUtils::transcode(systemId);
     217              :     const std::string::size_type pos = url.find("/xsd/");
     218       225843 :     if (pos != std::string::npos) {
     219        52201 :         const char* sumoPath = std::getenv("SUMO_HOME");
     220              :         // no need for a warning if SUMO_HOME is not set, global preparsing should have done it.
     221        52201 :         if (sumoPath != nullptr) {
     222       156579 :             const std::string file = sumoPath + std::string("/data") + url.substr(pos);
     223       104386 :             if (FileHelpers::isReadable(file)) {
     224        52164 :                 XMLCh* t = XERCES_CPP_NAMESPACE::XMLString::transcode(file.c_str());
     225        52164 :                 XERCES_CPP_NAMESPACE::InputSource* const result = new XERCES_CPP_NAMESPACE::LocalFileInputSource(t);
     226        52164 :                 XERCES_CPP_NAMESPACE::XMLString::release(&t);
     227              :                 return result;
     228              :             } else {
     229           89 :                 WRITE_WARNING("Cannot read local schema '" + file + (myHaveFallback ? "', will try website lookup." : "', XML validation will fail."));
     230              :             }
     231              :         }
     232              :     }
     233       862509 :     if (myHaveFallback || (!StringUtils::startsWith(url, "http:") && !StringUtils::startsWith(url, "https:") && !StringUtils::startsWith(url, "ftp:"))) {
     234              :         return nullptr;
     235              :     }
     236            2 :     return new XERCES_CPP_NAMESPACE::MemBufInputSource((const XMLByte*)"", 0, "");
     237              : }
     238              : 
     239              : 
     240              : /****************************************************************************/
        

Generated by: LCOV version 2.0-1