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