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 : /****************************************************************************/
|