Eclipse SUMO - Simulation of Urban MObility
SUMOSAXReader.cpp
Go to the documentation of this file.
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 /****************************************************************************/
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 <memory>
28 #include <iostream>
29 #include <xercesc/sax2/XMLReaderFactory.hpp>
30 #include <xercesc/framework/LocalFileInputSource.hpp>
31 #include <xercesc/framework/MemBufInputSource.hpp>
32 
34 #include <utils/common/ToString.h>
39 #include "GenericSAXHandler.h"
40 #ifdef HAVE_ZLIB
41 #include <foreign/zstr/zstr.hpp>
42 #endif
43 #include "IStreamInputSource.h"
44 #include "SUMOSAXReader.h"
45 
46 
47 // ===========================================================================
48 // method definitions
49 // ===========================================================================
50 SUMOSAXReader::SUMOSAXReader(GenericSAXHandler& handler, const XERCES_CPP_NAMESPACE::SAX2XMLReader::ValSchemes validationScheme)
51  : myHandler(nullptr), myValidationScheme(validationScheme), myXMLReader(nullptr), myBinaryInput(nullptr), myIStream(nullptr), myInputStream(nullptr) {
52  setHandler(handler);
53 }
54 
55 
57  delete myXMLReader;
58  delete myBinaryInput;
59 }
60 
61 
62 void
64  myHandler = &handler;
66  if (myXMLReader != nullptr) {
67  myXMLReader->setContentHandler(&handler);
68  myXMLReader->setErrorHandler(&handler);
69  }
70 }
71 
72 
73 void
74 SUMOSAXReader::setValidation(const XERCES_CPP_NAMESPACE::SAX2XMLReader::ValSchemes validationScheme) {
75  if (myXMLReader != nullptr && validationScheme != myValidationScheme) {
76  if (validationScheme == XERCES_CPP_NAMESPACE::SAX2XMLReader::Val_Never) {
77  myXMLReader->setEntityResolver(nullptr);
78  myXMLReader->setProperty(XERCES_CPP_NAMESPACE::XMLUni::fgXercesScannerName, (void*)XERCES_CPP_NAMESPACE::XMLUni::fgWFXMLScanner);
79  } else {
80  myXMLReader->setEntityResolver(&mySchemaResolver);
81  myXMLReader->setProperty(XERCES_CPP_NAMESPACE::XMLUni::fgXercesScannerName, (void*)XERCES_CPP_NAMESPACE::XMLUni::fgIGXMLScanner);
82  myXMLReader->setFeature(XERCES_CPP_NAMESPACE::XMLUni::fgXercesSchema, true);
83  myXMLReader->setFeature(XERCES_CPP_NAMESPACE::XMLUni::fgSAX2CoreValidation, true);
84  myXMLReader->setFeature(XERCES_CPP_NAMESPACE::XMLUni::fgXercesDynamic, validationScheme == XERCES_CPP_NAMESPACE::SAX2XMLReader::Val_Auto);
85  }
86  }
87  myValidationScheme = validationScheme;
88 }
89 
90 
91 void
92 SUMOSAXReader::parse(std::string systemID) {
93  if (systemID.length() >= 4 && systemID.substr(systemID.length() - 4) == ".sbx") {
94  if (parseFirst(systemID)) {
95  while (parseNext());
96  }
97  } else {
98  if (myXMLReader == nullptr) {
100  }
101  if (!FileHelpers::isReadable(systemID)) {
102  throw ProcessError("Cannot read file '" + systemID + "'!");
103  }
104 #ifdef HAVE_ZLIB
105  zstr::ifstream istream(systemID.c_str(), std::fstream::in | std::fstream::binary);
106  myXMLReader->parse(IStreamInputSource(istream));
107 #else
108  myXMLReader->parse(systemID.c_str());
109 #endif
110  }
111 }
112 
113 
114 void
115 SUMOSAXReader::parseString(std::string content) {
116  if (myXMLReader == nullptr) {
118  }
119  XERCES_CPP_NAMESPACE::MemBufInputSource memBufIS((const XMLByte*)content.c_str(), content.size(), "registrySettings");
120  myXMLReader->parse(memBufIS);
121 }
122 
123 
124 bool
125 SUMOSAXReader::parseFirst(std::string systemID) {
126  if (systemID.length() >= 4 && systemID.substr(systemID.length() - 4) == ".sbx") {
127  myBinaryInput = new BinaryInputDevice(systemID, true, myValidationScheme == XERCES_CPP_NAMESPACE::SAX2XMLReader::Val_Always);
129  if (mySbxVersion < 1 || mySbxVersion > 2) {
130  throw ProcessError("Unknown sbx version");
131  }
132  std::string sumoVer;
133  *myBinaryInput >> sumoVer;
134  std::vector<std::string> elems;
135  *myBinaryInput >> elems;
136  // !!! check elems here
137  elems.clear();
138  *myBinaryInput >> elems;
139  // !!! check attrs here
140  elems.clear();
141  *myBinaryInput >> elems;
142  // !!! check node types here
143  elems.clear();
144  *myBinaryInput >> elems;
145  // !!! check edge types here
146  elems.clear();
147  *myBinaryInput >> elems;
148  // !!! check edges here
149  std::vector< std::vector<int> > followers;
150  *myBinaryInput >> followers;
151  // !!! check followers here
152  return parseNext();
153  } else {
154  if (!FileHelpers::isReadable(systemID)) {
155  throw ProcessError("Cannot read file '" + systemID + "'!");
156  }
157  if (myXMLReader == nullptr) {
159  }
160  myToken = XERCES_CPP_NAMESPACE::XMLPScanToken();
161 #ifdef HAVE_ZLIB
162  myIStream = std::unique_ptr<zstr::ifstream>(new zstr::ifstream(systemID.c_str(), std::fstream::in | std::fstream::binary));
163  myInputStream = std::unique_ptr<IStreamInputSource>(new IStreamInputSource(*myIStream));
164  return myXMLReader->parseFirst(*myInputStream, myToken);
165 #else
166  return myXMLReader->parseFirst(systemID.c_str(), myToken);
167 #endif
168  }
169 }
170 
171 
172 bool
174  if (myBinaryInput != nullptr) {
175  int next = myBinaryInput->peek();
176  switch (next) {
177  case EOF:
178  delete myBinaryInput;
179  myBinaryInput = nullptr;
180  return false;
182  int tag;
183  unsigned char tagByte;
184  *myBinaryInput >> tagByte;
185  tag = tagByte;
186  if (mySbxVersion > 1) {
188  *myBinaryInput >> tagByte;
189  tag += 256 * tagByte;
190  }
191  myXMLStack.push_back((SumoXMLTag)tag);
193  myHandler->myStartElement(tag, attrs);
194  break;
195  }
197  if (myXMLStack.empty()) {
198  throw ProcessError("Binary file is invalid, unexpected tag end.");
199  }
201  myXMLStack.pop_back();
202  myBinaryInput->read(mySbxVersion > 1 ? 1 : 2);
203  break;
204  }
205  default:
206  throw ProcessError("Binary file is invalid, expected tag start or tag end.");
207  }
208  return true;
209  } else {
210  if (myXMLReader == nullptr) {
211  throw ProcessError("The XML-parser was not initialized.");
212  }
213  return myXMLReader->parseNext(myToken);
214  }
215 }
216 
217 
218 XERCES_CPP_NAMESPACE::SAX2XMLReader*
220  XERCES_CPP_NAMESPACE::SAX2XMLReader* reader = XERCES_CPP_NAMESPACE::XMLReaderFactory::createXMLReader();
221  if (reader == nullptr) {
222  throw ProcessError("The XML-parser could not be build.");
223  }
224  // see here https://svn.apache.org/repos/asf/xerces/c/trunk/samples/src/SAX2Count/SAX2Count.cpp for the way to set features
225  if (myValidationScheme == XERCES_CPP_NAMESPACE::SAX2XMLReader::Val_Never) {
226  reader->setProperty(XERCES_CPP_NAMESPACE::XMLUni::fgXercesScannerName, (void*)XERCES_CPP_NAMESPACE::XMLUni::fgWFXMLScanner);
227  } else {
228  reader->setEntityResolver(&mySchemaResolver);
229  reader->setFeature(XERCES_CPP_NAMESPACE::XMLUni::fgXercesSchema, true);
230  reader->setFeature(XERCES_CPP_NAMESPACE::XMLUni::fgSAX2CoreValidation, true);
231  reader->setFeature(XERCES_CPP_NAMESPACE::XMLUni::fgXercesDynamic, myValidationScheme == XERCES_CPP_NAMESPACE::SAX2XMLReader::Val_Auto);
232  }
233  reader->setContentHandler(myHandler);
234  reader->setErrorHandler(myHandler);
235  return reader;
236 }
237 
238 
239 XERCES_CPP_NAMESPACE::InputSource*
240 SUMOSAXReader::LocalSchemaResolver::resolveEntity(const XMLCh* const /* publicId */, const XMLCh* const systemId) {
241  const std::string url = StringUtils::transcode(systemId);
242  const std::string::size_type pos = url.find("/xsd/");
243  if (pos != std::string::npos) {
245  const char* sumoPath = std::getenv("SUMO_HOME");
246  if (sumoPath == nullptr) {
247  WRITE_WARNING("Environment variable SUMO_HOME is not set, schema resolution will use slow website lookups.");
248  return nullptr;
249  }
250  const std::string file = sumoPath + std::string("/data") + url.substr(pos);
251  if (FileHelpers::isReadable(file)) {
252  XMLCh* t = XERCES_CPP_NAMESPACE::XMLString::transcode(file.c_str());
253  XERCES_CPP_NAMESPACE::InputSource* const result = new XERCES_CPP_NAMESPACE::LocalFileInputSource(t);
254  XERCES_CPP_NAMESPACE::XMLString::release(&t);
255  return result;
256  } else {
257  WRITE_WARNING("Cannot read local schema '" + file + "', will try website lookup.");
258  }
259  }
260  return nullptr;
261 }
262 
263 
264 void
266  myHandler = &handler;
267 }
268 
269 
270 /****************************************************************************/
std::vector< SumoXMLTag > myXMLStack
The stack of begun xml elements.
int peek()
Returns the next character to be read by an actual parse.
SumoXMLTag
Numbers representing SUMO-XML - element names.
SUMOSAXReader(GenericSAXHandler &handler, const XERCES_CPP_NAMESPACE::SAX2XMLReader::ValSchemes validationScheme)
Constructor.
static bool isReadable(std::string path)
Checks whether the given file is readable.
Definition: FileHelpers.cpp:49
void putback(char c)
Pushes a character back into the stream to be read by the next actual parse.
XERCES_CPP_NAMESPACE::SAX2XMLReader * getSAXReader()
Builds a reader.
void setValidation(const XERCES_CPP_NAMESPACE::SAX2XMLReader::ValSchemes validationScheme)
XERCES_CPP_NAMESPACE::XMLPScanToken myToken
void parseString(std::string content)
BinaryInputDevice * myBinaryInput
std::string transcode(const XMLCh *const qname)
#define WRITE_WARNING(msg)
Definition: MsgHandler.h:239
void setSchemaSeen(const bool schemaSeen=true)
Xerces InputSource reading from arbitrary std::istream.
static std::string transcode(const XMLCh *const data)
converts a 0-terminated XMLCh* array (usually UTF-16, stemming from Xerces) into std::string in UTF-8...
Definition: StringUtils.h:132
A handler which converts occuring elements and attributes into enums.
std::string toString(const T &t, std::streamsize accuracy=gPrecision)
Definition: ToString.h:48
void parse(std::string systemID)
std::unique_ptr< IStreamInputSource > myInputStream
void setHandler(GenericSAXHandler &handler)
XERCES_CPP_NAMESPACE::SAX2XMLReader::ValSchemes myValidationScheme
Information whether built reader/parser shall validate XML-documents against schemata.
bool parseFirst(std::string systemID)
virtual void myStartElement(int element, const SUMOSAXAttributes &attrs)
Callback method for an opening tag to implement by derived classes.
Encapsulated Xerces-SAX-attributes.
XERCES_CPP_NAMESPACE::SAX2XMLReader * myXMLReader
void setHandler(GenericSAXHandler &handler)
Sets the given handler as content and error handler for the reader.
LocalSchemaResolver mySchemaResolver
std::map< int, std::string > myPredefinedTagsMML
the map from ids to their string representation
XERCES_CPP_NAMESPACE::InputSource * resolveEntity(const XMLCh *const publicId, const XMLCh *const systemId)
~SUMOSAXReader()
Destructor.
Encapsulates binary reading operations on a file.
GenericSAXHandler * myHandler
std::string read(int numBytes)
Reads the defined number of bytes and returns them as a string.
std::unique_ptr< std::istream > myIStream
virtual void myEndElement(int element)
Callback method for a closing tag to implement by derived classes.