1 /****************************************************************************/
2 // Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.org/sumo
3 // Copyright (C) 2012-2019 German Aerospace Center (DLR) and others.
4 // This program and the accompanying materials
5 // are made available under the terms of the Eclipse Public License v2.0
6 // which accompanies this distribution, and is available at
7 // http://www.eclipse.org/legal/epl-v20.html
8 // SPDX-License-Identifier: EPL-2.0
9 /****************************************************************************/
10 /// @file SUMOSAXReader.cpp
11 /// @author Daniel Krajzewicz
12 /// @author Jakob Erdmann
13 /// @author Michael Behrisch
14 /// @date Nov 2012
15 /// @version $Id$
16 ///
17 // SAX-reader encapsulation containing binary reader
18 /****************************************************************************/
19
20
21 // ===========================================================================
22 // included modules
23 // ===========================================================================
24 #include <config.h>
25
26 #include <string>
27 #include <iostream>
28 #include <xercesc/sax2/XMLReaderFactory.hpp>
29 #include <xercesc/framework/LocalFileInputSource.hpp>
30 #include <xercesc/framework/MemBufInputSource.hpp>
31
32 #include <utils/common/MsgHandler.h>
33 #include <utils/common/ToString.h>
34 #include <utils/common/StringUtils.h>
35 #include <utils/iodevices/BinaryFormatter.h>
36 #include <utils/iodevices/BinaryInputDevice.h>
37 #include "SUMOSAXAttributesImpl_Binary.h"
38 #include "GenericSAXHandler.h"
39 #include "SUMOSAXReader.h"
40
41
42 // ===========================================================================
43 // method definitions
44 // ===========================================================================
SUMOSAXReader(GenericSAXHandler & handler,const XERCES_CPP_NAMESPACE::SAX2XMLReader::ValSchemes validationScheme)45 SUMOSAXReader::SUMOSAXReader(GenericSAXHandler& handler, const XERCES_CPP_NAMESPACE::SAX2XMLReader::ValSchemes validationScheme)
46 : myHandler(nullptr), myValidationScheme(validationScheme), myXMLReader(nullptr), myBinaryInput(nullptr) {
47 setHandler(handler);
48 }
49
50
~SUMOSAXReader()51 SUMOSAXReader::~SUMOSAXReader() {
52 delete myXMLReader;
53 delete myBinaryInput;
54 }
55
56
57 void
setHandler(GenericSAXHandler & handler)58 SUMOSAXReader::setHandler(GenericSAXHandler& handler) {
59 myHandler = &handler;
60 mySchemaResolver.setHandler(handler);
61 if (myXMLReader != nullptr) {
62 myXMLReader->setContentHandler(&handler);
63 myXMLReader->setErrorHandler(&handler);
64 }
65 }
66
67
68 void
setValidation(const XERCES_CPP_NAMESPACE::SAX2XMLReader::ValSchemes validationScheme)69 SUMOSAXReader::setValidation(const XERCES_CPP_NAMESPACE::SAX2XMLReader::ValSchemes validationScheme) {
70 if (myXMLReader != nullptr && validationScheme != myValidationScheme) {
71 if (validationScheme == XERCES_CPP_NAMESPACE::SAX2XMLReader::Val_Never) {
72 myXMLReader->setEntityResolver(nullptr);
73 myXMLReader->setProperty(XERCES_CPP_NAMESPACE::XMLUni::fgXercesScannerName, (void*)XERCES_CPP_NAMESPACE::XMLUni::fgWFXMLScanner);
74 } else {
75 myXMLReader->setEntityResolver(&mySchemaResolver);
76 myXMLReader->setProperty(XERCES_CPP_NAMESPACE::XMLUni::fgXercesScannerName, (void*)XERCES_CPP_NAMESPACE::XMLUni::fgIGXMLScanner);
77 myXMLReader->setFeature(XERCES_CPP_NAMESPACE::XMLUni::fgXercesSchema, true);
78 myXMLReader->setFeature(XERCES_CPP_NAMESPACE::XMLUni::fgSAX2CoreValidation, true);
79 myXMLReader->setFeature(XERCES_CPP_NAMESPACE::XMLUni::fgXercesDynamic, validationScheme == XERCES_CPP_NAMESPACE::SAX2XMLReader::Val_Auto);
80 }
81 }
82 myValidationScheme = validationScheme;
83 }
84
85
86 void
parse(std::string systemID)87 SUMOSAXReader::parse(std::string systemID) {
88 if (systemID.length() >= 4 && systemID.substr(systemID.length() - 4) == ".sbx") {
89 if (parseFirst(systemID)) {
90 while (parseNext());
91 }
92 } else {
93 if (myXMLReader == nullptr) {
94 myXMLReader = getSAXReader();
95 }
96 myXMLReader->parse(systemID.c_str());
97 }
98 }
99
100
101 void
parseString(std::string content)102 SUMOSAXReader::parseString(std::string content) {
103 if (myXMLReader == nullptr) {
104 myXMLReader = getSAXReader();
105 }
106 XERCES_CPP_NAMESPACE::MemBufInputSource memBufIS((const XMLByte*)content.c_str(), content.size(), "registrySettings");
107 myXMLReader->parse(memBufIS);
108 }
109
110
111 bool
parseFirst(std::string systemID)112 SUMOSAXReader::parseFirst(std::string systemID) {
113 if (systemID.length() >= 4 && systemID.substr(systemID.length() - 4) == ".sbx") {
114 myBinaryInput = new BinaryInputDevice(systemID, true, myValidationScheme == XERCES_CPP_NAMESPACE::SAX2XMLReader::Val_Always);
115 *myBinaryInput >> mySbxVersion;
116 if (mySbxVersion < 1 || mySbxVersion > 2) {
117 throw ProcessError("Unknown sbx version");
118 }
119 std::string sumoVer;
120 *myBinaryInput >> sumoVer;
121 std::vector<std::string> elems;
122 *myBinaryInput >> elems;
123 // !!! check elems here
124 elems.clear();
125 *myBinaryInput >> elems;
126 // !!! check attrs here
127 elems.clear();
128 *myBinaryInput >> elems;
129 // !!! check node types here
130 elems.clear();
131 *myBinaryInput >> elems;
132 // !!! check edge types here
133 elems.clear();
134 *myBinaryInput >> elems;
135 // !!! check edges here
136 std::vector< std::vector<int> > followers;
137 *myBinaryInput >> followers;
138 // !!! check followers here
139 return parseNext();
140 } else {
141 if (myXMLReader == nullptr) {
142 myXMLReader = getSAXReader();
143 }
144 myToken = XERCES_CPP_NAMESPACE::XMLPScanToken();
145 return myXMLReader->parseFirst(systemID.c_str(), myToken);
146 }
147 }
148
149
150 bool
parseNext()151 SUMOSAXReader::parseNext() {
152 if (myBinaryInput != nullptr) {
153 int next = myBinaryInput->peek();
154 switch (next) {
155 case EOF:
156 delete myBinaryInput;
157 myBinaryInput = nullptr;
158 return false;
159 case BinaryFormatter::BF_XML_TAG_START: {
160 int tag;
161 unsigned char tagByte;
162 *myBinaryInput >> tagByte;
163 tag = tagByte;
164 if (mySbxVersion > 1) {
165 myBinaryInput->putback(BinaryFormatter::BF_BYTE);
166 *myBinaryInput >> tagByte;
167 tag += 256 * tagByte;
168 }
169 myXMLStack.push_back((SumoXMLTag)tag);
170 SUMOSAXAttributesImpl_Binary attrs(myHandler->myPredefinedTagsMML, toString((SumoXMLTag)tag), myBinaryInput, mySbxVersion);
171 myHandler->myStartElement(tag, attrs);
172 break;
173 }
174 case BinaryFormatter::BF_XML_TAG_END: {
175 if (myXMLStack.empty()) {
176 throw ProcessError("Binary file is invalid, unexpected tag end.");
177 }
178 myHandler->myEndElement(myXMLStack.back());
179 myXMLStack.pop_back();
180 myBinaryInput->read(mySbxVersion > 1 ? 1 : 2);
181 break;
182 }
183 default:
184 throw ProcessError("Binary file is invalid, expected tag start or tag end.");
185 }
186 return true;
187 } else {
188 if (myXMLReader == nullptr) {
189 throw ProcessError("The XML-parser was not initialized.");
190 }
191 return myXMLReader->parseNext(myToken);
192 }
193 }
194
195
196 XERCES_CPP_NAMESPACE::SAX2XMLReader*
getSAXReader()197 SUMOSAXReader::getSAXReader() {
198 XERCES_CPP_NAMESPACE::SAX2XMLReader* reader = XERCES_CPP_NAMESPACE::XMLReaderFactory::createXMLReader();
199 if (reader == nullptr) {
200 throw ProcessError("The XML-parser could not be build.");
201 }
202 // see here https://svn.apache.org/repos/asf/xerces/c/trunk/samples/src/SAX2Count/SAX2Count.cpp for the way to set features
203 if (myValidationScheme == XERCES_CPP_NAMESPACE::SAX2XMLReader::Val_Never) {
204 reader->setProperty(XERCES_CPP_NAMESPACE::XMLUni::fgXercesScannerName, (void*)XERCES_CPP_NAMESPACE::XMLUni::fgWFXMLScanner);
205 } else {
206 reader->setEntityResolver(&mySchemaResolver);
207 reader->setFeature(XERCES_CPP_NAMESPACE::XMLUni::fgXercesSchema, true);
208 reader->setFeature(XERCES_CPP_NAMESPACE::XMLUni::fgSAX2CoreValidation, true);
209 reader->setFeature(XERCES_CPP_NAMESPACE::XMLUni::fgXercesDynamic, myValidationScheme == XERCES_CPP_NAMESPACE::SAX2XMLReader::Val_Auto);
210 }
211 reader->setContentHandler(myHandler);
212 reader->setErrorHandler(myHandler);
213 return reader;
214 }
215
216
217 XERCES_CPP_NAMESPACE::InputSource*
resolveEntity(const XMLCh * const,const XMLCh * const systemId)218 SUMOSAXReader::LocalSchemaResolver::resolveEntity(const XMLCh* const /* publicId */, const XMLCh* const systemId) {
219 const std::string url = StringUtils::transcode(systemId);
220 const std::string::size_type pos = url.find("/xsd/");
221 if (pos != std::string::npos) {
222 myHandler->setSchemaSeen();
223 const char* sumoPath = std::getenv("SUMO_HOME");
224 if (sumoPath == nullptr) {
225 WRITE_WARNING("Environment variable SUMO_HOME is not set, schema resolution will use slow website lookups.");
226 return nullptr;
227 }
228 const std::string file = sumoPath + std::string("/data") + url.substr(pos);
229 if (FileHelpers::isReadable(file)) {
230 XMLCh* t = XERCES_CPP_NAMESPACE::XMLString::transcode(file.c_str());
231 XERCES_CPP_NAMESPACE::InputSource* const result = new XERCES_CPP_NAMESPACE::LocalFileInputSource(t);
232 XERCES_CPP_NAMESPACE::XMLString::release(&t);
233 return result;
234 } else {
235 WRITE_WARNING("Cannot read local schema '" + file + "', will try website lookup.");
236 }
237 }
238 return nullptr;
239 }
240
241
242 void
setHandler(GenericSAXHandler & handler)243 SUMOSAXReader::LocalSchemaResolver::setHandler(GenericSAXHandler& handler) {
244 myHandler = &handler;
245 }
246
247
248 /****************************************************************************/
249