Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
eclipse
GitHub Repository: eclipse/sumo
Path: blob/main/src/utils/xml/SUMOSAXReader.cpp
169678 views
1
/****************************************************************************/
2
// Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo
3
// Copyright (C) 2012-2025 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
SUMOSAXReader::SUMOSAXReader(GenericSAXHandler& handler, const std::string& validationScheme, XERCES_CPP_NAMESPACE::XMLGrammarPool* grammarPool) :
51
myHandler(nullptr),
52
myValidationScheme(validationScheme),
53
myGrammarPool(grammarPool),
54
myXMLReader(nullptr),
55
myIStream(nullptr),
56
myInputStream(nullptr),
57
mySchemaResolver(true, false),
58
myLocalResolver(false, false),
59
myNoOpResolver(false, true),
60
myNextSection(-1, nullptr) {
61
setHandler(handler);
62
}
63
64
65
SUMOSAXReader::~SUMOSAXReader() {
66
delete myXMLReader;
67
delete myNextSection.second;
68
}
69
70
71
void
72
SUMOSAXReader::setHandler(GenericSAXHandler& handler) {
73
myHandler = &handler;
74
if (myXMLReader != nullptr) {
75
myXMLReader->setContentHandler(&handler);
76
myXMLReader->setErrorHandler(&handler);
77
}
78
}
79
80
81
void
82
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
if (myXMLReader != nullptr && validationScheme != myValidationScheme) {
87
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
if (validationScheme == "never") {
92
myXMLReader->setEntityResolver(&myNoOpResolver);
93
myXMLReader->setProperty(XMLUni::fgXercesScannerName, (void*)XMLUni::fgWFXMLScanner);
94
} else {
95
myXMLReader->setEntityResolver(validationScheme == "local" ? &myLocalResolver : &mySchemaResolver);
96
myXMLReader->setProperty(XMLUni::fgXercesScannerName, (void*)XMLUni::fgIGXMLScanner);
97
myXMLReader->setFeature(XMLUni::fgXercesSchema, true);
98
myXMLReader->setFeature(XMLUni::fgSAX2CoreValidation, true);
99
myXMLReader->setFeature(XMLUni::fgXercesDynamic, validationScheme == "local" || validationScheme == "auto");
100
myXMLReader->setFeature(XMLUni::fgXercesUseCachedGrammarInParse, myValidationScheme == "always");
101
}
102
}
103
myValidationScheme = validationScheme;
104
}
105
106
107
void
108
SUMOSAXReader::parse(std::string systemID) {
109
if (!FileHelpers::isReadable(systemID)) {
110
throw IOError(TLF("Cannot read file '%'!", systemID));
111
}
112
if (FileHelpers::isDirectory(systemID)) {
113
throw IOError(TLF("File '%' is a directory!", systemID));
114
}
115
ensureSAXReader();
116
#ifdef HAVE_ZLIB
117
zstr::ifstream istream(StringUtils::transcodeToLocal(systemID).c_str(), std::fstream::in | std::fstream::binary);
118
myXMLReader->parse(IStreamInputSource(istream)); // NOSONAR
119
#else
120
myXMLReader->parse(StringUtils::transcodeToLocal(systemID).c_str()); // NOSONAR
121
#endif
122
}
123
124
125
void
126
SUMOSAXReader::parseString(std::string content) {
127
ensureSAXReader();
128
XERCES_CPP_NAMESPACE::MemBufInputSource memBufIS((const XMLByte*)content.c_str(), content.size(), "registrySettings");
129
myXMLReader->parse(memBufIS); // NOSONAR
130
}
131
132
133
bool
134
SUMOSAXReader::parseFirst(std::string systemID) {
135
if (!FileHelpers::isReadable(systemID)) {
136
throw IOError(TLF("Cannot read file '%'!", systemID));
137
}
138
if (FileHelpers::isDirectory(systemID)) {
139
throw IOError(TLF("File '%' is a directory!", systemID));
140
}
141
ensureSAXReader();
142
myToken = XERCES_CPP_NAMESPACE::XMLPScanToken();
143
#ifdef HAVE_ZLIB
144
myIStream = std::unique_ptr<zstr::ifstream>(new zstr::ifstream(StringUtils::transcodeToLocal(systemID).c_str(), std::fstream::in | std::fstream::binary));
145
myInputStream = std::unique_ptr<IStreamInputSource>(new IStreamInputSource(*myIStream));
146
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
SUMOSAXReader::parseNext() {
155
if (myXMLReader == nullptr) {
156
throw ProcessError(TL("The XML-parser was not initialized."));
157
}
158
return myXMLReader->parseNext(myToken);
159
}
160
161
162
bool
163
SUMOSAXReader::parseSection(SumoXMLTag element) {
164
if (myXMLReader == nullptr) {
165
throw ProcessError(TL("The XML-parser was not initialized."));
166
}
167
bool started = false;
168
if (myNextSection.first != -1) {
169
started = myNextSection.first == element;
170
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
WRITE_WARNINGF("Expected different XML section '%', some content may be missing.", toString(element));
174
}
175
myHandler->myStartElement(myNextSection.first, *myNextSection.second);
176
delete myNextSection.second;
177
myNextSection.first = -1;
178
myNextSection.second = nullptr;
179
}
180
myHandler->setSection(element, started);
181
while (!myHandler->sectionFinished()) {
182
if (!myXMLReader->parseNext(myToken)) {
183
return false;
184
}
185
}
186
myNextSection = myHandler->retrieveNextSectionStart();
187
return true;
188
}
189
190
191
void
192
SUMOSAXReader::ensureSAXReader() {
193
if (myXMLReader == nullptr) {
194
myXMLReader = XERCES_CPP_NAMESPACE::XMLReaderFactory::createXMLReader(XERCES_CPP_NAMESPACE::XMLPlatformUtils::fgMemoryManager, myGrammarPool);
195
if (myXMLReader == nullptr) {
196
throw ProcessError(TL("The XML-parser could not be build."));
197
}
198
setValidation();
199
myXMLReader->setContentHandler(myHandler);
200
myXMLReader->setErrorHandler(myHandler);
201
}
202
}
203
204
205
SUMOSAXReader::LocalSchemaResolver::LocalSchemaResolver(const bool haveFallback, const bool noOp) :
206
myHaveFallback(haveFallback),
207
myNoOp(noOp) {
208
}
209
210
211
XERCES_CPP_NAMESPACE::InputSource*
212
SUMOSAXReader::LocalSchemaResolver::resolveEntity(const XMLCh* const /* publicId */, const XMLCh* const systemId) {
213
if (myNoOp) {
214
return new XERCES_CPP_NAMESPACE::MemBufInputSource((const XMLByte*)"", 0, "");
215
}
216
const std::string url = StringUtils::transcode(systemId);
217
const std::string::size_type pos = url.find("/xsd/");
218
if (pos != std::string::npos) {
219
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
if (sumoPath != nullptr) {
222
const std::string file = sumoPath + std::string("/data") + url.substr(pos);
223
if (FileHelpers::isReadable(file)) {
224
XMLCh* t = XERCES_CPP_NAMESPACE::XMLString::transcode(file.c_str());
225
XERCES_CPP_NAMESPACE::InputSource* const result = new XERCES_CPP_NAMESPACE::LocalFileInputSource(t);
226
XERCES_CPP_NAMESPACE::XMLString::release(&t);
227
return result;
228
} else {
229
WRITE_WARNING("Cannot read local schema '" + file + (myHaveFallback ? "', will try website lookup." : "', XML validation will fail."));
230
}
231
}
232
}
233
if (myHaveFallback || (!StringUtils::startsWith(url, "http:") && !StringUtils::startsWith(url, "https:") && !StringUtils::startsWith(url, "ftp:"))) {
234
return nullptr;
235
}
236
return new XERCES_CPP_NAMESPACE::MemBufInputSource((const XMLByte*)"", 0, "");
237
}
238
239
240
/****************************************************************************/
241
242