Line data Source code
1 : /****************************************************************************/
2 : // Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo
3 : // Copyright (C) 2002-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 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/sax2/XMLReaderFactory.hpp>
27 : #include <xercesc/framework/XMLGrammarPoolImpl.hpp>
28 : #include <utils/common/FileHelpers.h>
29 : #include <utils/common/MsgHandler.h>
30 : #include <utils/common/StringUtils.h>
31 : #include "SUMOSAXHandler.h"
32 : #include "SUMOSAXReader.h"
33 : #include "XMLSubSys.h"
34 :
35 : using XERCES_CPP_NAMESPACE::SAX2XMLReader;
36 : using XERCES_CPP_NAMESPACE::XMLPlatformUtils;
37 : using XERCES_CPP_NAMESPACE::XMLReaderFactory;
38 :
39 :
40 : // ===========================================================================
41 : // static member variables
42 : // ===========================================================================
43 : std::vector<SUMOSAXReader*> XMLSubSys::myReaders;
44 : int XMLSubSys::myNextFreeReader;
45 : std::string XMLSubSys::myValidationScheme = "local";
46 : std::string XMLSubSys::myNetValidationScheme = "local";
47 : std::string XMLSubSys::myRouteValidationScheme = "local";
48 : XERCES_CPP_NAMESPACE::XMLGrammarPool* XMLSubSys::myGrammarPool = nullptr;
49 : bool XMLSubSys::myNeedsValidationWarning = true;
50 :
51 :
52 : // ===========================================================================
53 : // method definitions
54 : // ===========================================================================
55 : void
56 57889 : XMLSubSys::init() {
57 : try {
58 57889 : XMLPlatformUtils::Initialize();
59 57889 : myNextFreeReader = 0;
60 0 : } catch (const XERCES_CPP_NAMESPACE::XMLException& e) {
61 0 : throw ProcessError("Error during XML-initialization:\n " + StringUtils::transcode(e.getMessage()));
62 0 : }
63 57889 : }
64 :
65 :
66 : std::string
67 165933 : XMLSubSys::warnLocalScheme(const std::string& newScheme, const bool haveSUMO_HOME) {
68 165933 : if (newScheme != "never" && newScheme != "auto" && newScheme != "always" && newScheme != "local") {
69 0 : throw ProcessError("Unknown xml validation scheme + '" + newScheme + "'.");
70 : }
71 165933 : if (!haveSUMO_HOME && newScheme == "local") {
72 32 : if (myNeedsValidationWarning) {
73 16 : WRITE_WARNING(TL("Environment variable SUMO_HOME is not set properly, disabling XML validation. Set 'auto' or 'always' for web lookups."));
74 16 : myNeedsValidationWarning = false;
75 : }
76 32 : return "never";
77 : }
78 : return newScheme;
79 : }
80 :
81 :
82 : void
83 55311 : XMLSubSys::setValidation(const std::string& validationScheme, const std::string& netValidationScheme, const std::string& routeValidationScheme) {
84 55311 : const char* sumoPath = std::getenv("SUMO_HOME");
85 165901 : const bool haveSUMO_HOME = sumoPath != nullptr && FileHelpers::isReadable(sumoPath + std::string("/data/xsd/net_file.xsd"));
86 55311 : myValidationScheme = warnLocalScheme(validationScheme, haveSUMO_HOME);
87 55311 : myNetValidationScheme = warnLocalScheme(netValidationScheme, haveSUMO_HOME);
88 55311 : myRouteValidationScheme = warnLocalScheme(routeValidationScheme, haveSUMO_HOME);
89 55311 : if (myGrammarPool == nullptr &&
90 35609 : (myValidationScheme != "never" ||
91 35609 : myNetValidationScheme != "never" ||
92 : myRouteValidationScheme != "never")) {
93 19690 : if (!haveSUMO_HOME) {
94 32 : if (myNeedsValidationWarning) {
95 32 : WRITE_WARNING(TL("Environment variable SUMO_HOME is not set properly, XML validation will fail or use slow website lookups."));
96 32 : myNeedsValidationWarning = false;
97 : }
98 32 : return;
99 : }
100 19658 : myGrammarPool = new XERCES_CPP_NAMESPACE::XMLGrammarPoolImpl(XMLPlatformUtils::fgMemoryManager);
101 19658 : SAX2XMLReader* parser(XMLReaderFactory::createXMLReader(XMLPlatformUtils::fgMemoryManager, myGrammarPool));
102 : #if _XERCES_VERSION >= 30100
103 19658 : parser->setFeature(XERCES_CPP_NAMESPACE::XMLUni::fgXercesHandleMultipleImports, true);
104 : #endif
105 58974 : for (const char* const& filetype : {
106 : "additional", "routes", "net"
107 78632 : }) {
108 58974 : const std::string file = sumoPath + std::string("/data/xsd/") + filetype + "_file.xsd";
109 58974 : if (!parser->loadGrammar(file.c_str(), XERCES_CPP_NAMESPACE::Grammar::SchemaGrammarType, true)) {
110 0 : WRITE_WARNINGF(TL("Cannot read local schema '%'."), file);
111 : }
112 : }
113 19658 : delete parser;
114 : }
115 : }
116 :
117 :
118 : void
119 58128 : XMLSubSys::close() {
120 113016 : for (std::vector<SUMOSAXReader*>::iterator i = myReaders.begin(); i != myReaders.end(); ++i) {
121 54888 : delete *i;
122 : }
123 : myReaders.clear();
124 58128 : delete myGrammarPool;
125 58128 : myGrammarPool = nullptr;
126 58128 : XMLPlatformUtils::Terminate();
127 58128 : StringUtils::resetTranscoder();
128 58128 : }
129 :
130 :
131 : SUMOSAXReader*
132 44737 : XMLSubSys::getSAXReader(SUMOSAXHandler& handler, const bool isNet, const bool isRoute) {
133 44737 : std::string validationScheme = isNet ? myNetValidationScheme : myValidationScheme;
134 44737 : if (isRoute) {
135 : validationScheme = myRouteValidationScheme;
136 : }
137 89474 : return new SUMOSAXReader(handler, validationScheme, myGrammarPool);
138 : }
139 :
140 :
141 : void
142 9006 : XMLSubSys::setHandler(GenericSAXHandler& handler) {
143 9006 : myReaders[myNextFreeReader - 1]->setHandler(handler);
144 9006 : }
145 :
146 :
147 : bool
148 143213 : XMLSubSys::runParser(GenericSAXHandler& handler, const std::string& file,
149 : const bool isNet, const bool isRoute, const bool isExternal, const bool catchExceptions) {
150 143213 : MsgHandler::getErrorInstance()->clear();
151 143213 : std::string errorMsg = "";
152 : try {
153 143213 : std::string validationScheme = isNet ? myNetValidationScheme : myValidationScheme;
154 143213 : if (isRoute) {
155 : validationScheme = myRouteValidationScheme;
156 : }
157 143213 : if (isExternal && validationScheme == "local") {
158 3 : WRITE_MESSAGEF(TL("Disabling XML validation for external file '%'. Use 'auto' or 'always' to enable."), file);
159 : validationScheme = "never";
160 : }
161 143213 : if (myNextFreeReader == (int)myReaders.size()) {
162 54898 : myReaders.push_back(new SUMOSAXReader(handler, validationScheme, myGrammarPool));
163 : } else {
164 177544 : myReaders[myNextFreeReader]->setValidation(validationScheme);
165 88315 : myReaders[myNextFreeReader]->setHandler(handler);
166 : }
167 143213 : myNextFreeReader++;
168 143213 : std::string prevFile = handler.getFileName();
169 143213 : handler.setFileName(file);
170 287340 : myReaders[myNextFreeReader - 1]->parse(file);
171 142299 : handler.setFileName(prevFile);
172 142299 : myNextFreeReader--;
173 914 : } catch (const ProcessError& e) {
174 914 : if (catchExceptions) {
175 1828 : errorMsg = std::string(e.what()) != std::string("") ? e.what() : TL("Process Error");
176 : } else {
177 0 : throw;
178 : }
179 914 : } catch (const std::runtime_error& re) {
180 0 : errorMsg = TLF("Runtime error: % while parsing '%'", re.what(), file);
181 0 : } catch (const std::exception& ex) {
182 0 : errorMsg = TLF("Error occurred: % while parsing '%'", ex.what(), file);
183 0 : } catch (const XERCES_CPP_NAMESPACE::SAXException& e) {
184 0 : errorMsg = TLF("SAX error occurred while parsing '%':\n %", file, StringUtils::transcode(e.getMessage()));
185 0 : } catch (...) {
186 0 : errorMsg = TLF("Unspecified error occurred while parsing '%'", file);
187 0 : }
188 143213 : if (errorMsg != "") {
189 914 : if (catchExceptions) {
190 2742 : WRITE_ERROR(errorMsg);
191 : } else {
192 0 : throw ProcessError(errorMsg);
193 : }
194 : }
195 143213 : return !MsgHandler::getErrorInstance()->wasInformed();
196 : }
197 :
198 :
199 : /****************************************************************************/
|