LCOV - code coverage report
Current view: top level - src/utils/xml - SUMOSAXReader.cpp (source / functions) Hit Total Coverage
Test: lcov.info Lines: 91 103 88.3 %
Date: 2024-05-05 15:31:14 Functions: 11 12 91.7 %

          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       72584 : SUMOSAXReader::SUMOSAXReader(GenericSAXHandler& handler, const std::string& validationScheme, XERCES_CPP_NAMESPACE::XMLGrammarPool* grammarPool) :
      51       72584 :     myHandler(nullptr),
      52       72584 :     myValidationScheme(validationScheme),
      53       72584 :     myGrammarPool(grammarPool),
      54       72584 :     myXMLReader(nullptr),
      55             :     myIStream(nullptr),
      56             :     myInputStream(nullptr),
      57       72584 :     mySchemaResolver(true, false),
      58       72584 :     myLocalResolver(false, false),
      59       72584 :     myNoOpResolver(false, true),
      60             :     myNextSection(-1, nullptr) {
      61       72584 :     setHandler(handler);
      62       72584 : }
      63             : 
      64             : 
      65       72121 : SUMOSAXReader::~SUMOSAXReader() {
      66       72121 :     delete myXMLReader;
      67       72121 :     delete myNextSection.second;
      68       72121 : }
      69             : 
      70             : 
      71             : void
      72      142832 : SUMOSAXReader::setHandler(GenericSAXHandler& handler) {
      73      142832 :     myHandler = &handler;
      74      142832 :     if (myXMLReader != nullptr) {
      75       70248 :         myXMLReader->setContentHandler(&handler);
      76       70248 :         myXMLReader->setErrorHandler(&handler);
      77             :     }
      78      142832 : }
      79             : 
      80             : 
      81             : void
      82      134696 : 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      134696 :     if (myXMLReader != nullptr && validationScheme != myValidationScheme) {
      87       82271 :         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       82271 :         if (validationScheme == "never") {
      92       61773 :             myXMLReader->setEntityResolver(&myNoOpResolver);
      93       61773 :             myXMLReader->setProperty(XMLUni::fgXercesScannerName, (void*)XMLUni::fgWFXMLScanner);
      94             :         } else {
      95       20498 :             myXMLReader->setEntityResolver(validationScheme == "local" ? &myLocalResolver : &mySchemaResolver);
      96       20498 :             myXMLReader->setProperty(XMLUni::fgXercesScannerName, (void*)XMLUni::fgIGXMLScanner);
      97       20498 :             myXMLReader->setFeature(XMLUni::fgXercesSchema, true);
      98       20498 :             myXMLReader->setFeature(XMLUni::fgSAX2CoreValidation, true);
      99       23406 :             myXMLReader->setFeature(XMLUni::fgXercesDynamic, validationScheme == "local" || validationScheme == "auto");
     100       20498 :             myXMLReader->setFeature(XMLUni::fgXercesUseCachedGrammarInParse, myValidationScheme == "always");
     101             :         }
     102             :     }
     103      134696 :     myValidationScheme = validationScheme;
     104      134696 : }
     105             : 
     106             : 
     107             : void
     108      105223 : SUMOSAXReader::parse(std::string systemID) {
     109      210446 :     if (!FileHelpers::isReadable(systemID)) {
     110           0 :         throw IOError(TLF("Cannot read file '%'!", systemID));
     111             :     }
     112      210446 :     if (FileHelpers::isDirectory(systemID)) {
     113           0 :         throw IOError(TLF("File '%' is a directory!", systemID));
     114             :     }
     115      105223 :     ensureSAXReader();
     116             : #ifdef HAVE_ZLIB
     117      210446 :     zstr::ifstream istream(StringUtils::transcodeToLocal(systemID).c_str(), std::fstream::in | std::fstream::binary);
     118      105223 :     myXMLReader->parse(IStreamInputSource(istream));  // NOSONAR
     119             : #else
     120             :     myXMLReader->parse(StringUtils::transcodeToLocal(systemID).c_str());  // NOSONAR
     121             : #endif
     122      105223 : }
     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       29487 : SUMOSAXReader::parseFirst(std::string systemID) {
     135       58974 :     if (!FileHelpers::isReadable(systemID)) {
     136          56 :         throw IOError(TLF("Cannot read file '%'!", systemID));
     137             :     }
     138       58946 :     if (FileHelpers::isDirectory(systemID)) {
     139           0 :         throw IOError(TLF("File '%' is a directory!", systemID));
     140             :     }
     141       29473 :     ensureSAXReader();
     142       29473 :     myToken = XERCES_CPP_NAMESPACE::XMLPScanToken();
     143             : #ifdef HAVE_ZLIB
     144       83486 :     myIStream = std::unique_ptr<zstr::ifstream>(new zstr::ifstream(StringUtils::transcodeToLocal(systemID).c_str(), std::fstream::in | std::fstream::binary));
     145       29473 :     myInputStream = std::unique_ptr<IStreamInputSource>(new IStreamInputSource(*myIStream));
     146       29473 :     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     4302705 : SUMOSAXReader::parseNext() {
     155     4302705 :     if (myXMLReader == nullptr) {
     156           0 :         throw ProcessError(TL("The XML-parser was not initialized."));
     157             :     }
     158     4302705 :     return myXMLReader->parseNext(myToken);
     159             : }
     160             : 
     161             : 
     162             : bool
     163         474 : SUMOSAXReader::parseSection(int element) {
     164         474 :     if (myXMLReader == nullptr) {
     165           0 :         throw ProcessError(TL("The XML-parser was not initialized."));
     166             :     }
     167             :     bool started = false;
     168         474 :     if (myNextSection.first != -1) {
     169         296 :         started = myNextSection.first == element;
     170         296 :         myHandler->myStartElement(myNextSection.first, *myNextSection.second);
     171         296 :         delete myNextSection.second;
     172         296 :         myNextSection.first = -1;
     173         296 :         myNextSection.second = nullptr;
     174             :     }
     175         474 :     myHandler->setSection(element, started);
     176     5207156 :     while (!myHandler->sectionFinished()) {
     177     5206859 :         if (!myXMLReader->parseNext(myToken)) {
     178             :             return false;
     179             :         }
     180             :     }
     181             :     myNextSection = myHandler->retrieveNextSectionStart();
     182         297 :     return true;
     183             : }
     184             : 
     185             : 
     186             : void
     187      134696 : SUMOSAXReader::ensureSAXReader() {
     188      134696 :     if (myXMLReader == nullptr) {
     189       72554 :         myXMLReader = XERCES_CPP_NAMESPACE::XMLReaderFactory::createXMLReader(XERCES_CPP_NAMESPACE::XMLPlatformUtils::fgMemoryManager, myGrammarPool);
     190       72554 :         if (myXMLReader == nullptr) {
     191           0 :             throw ProcessError(TL("The XML-parser could not be build."));
     192             :         }
     193       72554 :         setValidation();
     194       72554 :         myXMLReader->setContentHandler(myHandler);
     195       72554 :         myXMLReader->setErrorHandler(myHandler);
     196             :     }
     197      134696 : }
     198             : 
     199             : 
     200      217752 : SUMOSAXReader::LocalSchemaResolver::LocalSchemaResolver(const bool haveFallback, const bool noOp) :
     201      217752 :     myHaveFallback(haveFallback),
     202      217752 :     myNoOp(noOp) {
     203      217752 : }
     204             : 
     205             : 
     206             : XERCES_CPP_NAMESPACE::InputSource*
     207       98650 : SUMOSAXReader::LocalSchemaResolver::resolveEntity(const XMLCh* const /* publicId */, const XMLCh* const systemId) {
     208       98650 :     if (myNoOp) {
     209           0 :         return new XERCES_CPP_NAMESPACE::MemBufInputSource((const XMLByte*)"", 0, "");
     210             :     }
     211       98650 :     const std::string url = StringUtils::transcode(systemId);
     212             :     const std::string::size_type pos = url.find("/xsd/");
     213       98650 :     if (pos != std::string::npos) {
     214       23792 :         const char* sumoPath = std::getenv("SUMO_HOME");
     215             :         // no need for a warning if SUMO_HOME is not set, global preparsing should have done it.
     216       23792 :         if (sumoPath != nullptr) {
     217       71296 :             const std::string file = sumoPath + std::string("/data") + url.substr(pos);
     218       47552 :             if (FileHelpers::isReadable(file)) {
     219       23719 :                 XMLCh* t = XERCES_CPP_NAMESPACE::XMLString::transcode(file.c_str());
     220       23719 :                 XERCES_CPP_NAMESPACE::InputSource* const result = new XERCES_CPP_NAMESPACE::LocalFileInputSource(t);
     221       23719 :                 XERCES_CPP_NAMESPACE::XMLString::release(&t);
     222             :                 return result;
     223             :             } else {
     224         118 :                 WRITE_WARNING("Cannot read local schema '" + file + (myHaveFallback ? "', will try website lookup." : "', XML validation will fail."));
     225             :             }
     226             :         }
     227             :     }
     228      362919 :     if (myHaveFallback || (!StringUtils::startsWith(url, "http:") && !StringUtils::startsWith(url, "https:") && !StringUtils::startsWith(url, "ftp:"))) {
     229             :         return nullptr;
     230             :     }
     231           4 :     return new XERCES_CPP_NAMESPACE::MemBufInputSource((const XMLByte*)"", 0, "");
     232             : }
     233             : 
     234             : /****************************************************************************/

Generated by: LCOV version 1.14