Line data Source code
1 : /****************************************************************************/
2 : // Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo
3 : // Copyright (C) 2007-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 SUMOSAXAttributes.cpp
15 : /// @author Daniel Krajzewicz
16 : /// @author Jakob Erdmann
17 : /// @author Michael Behrisch
18 : /// @date Fri, 30 Mar 2007
19 : ///
20 : // Encapsulated SAX-Attributes
21 : /****************************************************************************/
22 : #include <config.h>
23 :
24 : #include <string>
25 : #include <iostream>
26 : #include <sstream>
27 : #include <utils/common/MsgHandler.h>
28 : #include <utils/common/RGBColor.h>
29 : #include <utils/common/StringTokenizer.h>
30 : #include <utils/common/StringUtils.h>
31 : #include <utils/geom/Boundary.h>
32 : #include <utils/geom/PositionVector.h>
33 : #include "SUMOSAXAttributes.h"
34 :
35 :
36 : // ===========================================================================
37 : // static members
38 : // ===========================================================================
39 : const std::string SUMOSAXAttributes::ENCODING = " encoding=\"UTF-8\"";
40 :
41 :
42 : // ===========================================================================
43 : // method definitions
44 : // ===========================================================================
45 16623670 : SUMOSAXAttributes::SUMOSAXAttributes(const std::string& objectType):
46 16623670 : myObjectType(objectType) {}
47 :
48 :
49 : const std::string invalid_return<std::string>::value = "";
50 : template<>
51 34219244 : std::string SUMOSAXAttributes::fromString(const std::string& value) const {
52 34219244 : if (value == "") {
53 682 : throw EmptyData();
54 : }
55 34218562 : return value;
56 : }
57 :
58 :
59 : SUMOTime
60 632227 : SUMOSAXAttributes::getSUMOTimeReporting(int attr, const char* objectid,
61 : bool& ok, bool report) const {
62 : try {
63 632227 : bool isPresent = true;
64 632227 : const std::string& val = getString(attr, &isPresent);
65 632227 : if (!isPresent) {
66 14 : if (report) {
67 52 : emitUngivenError(getName(attr), objectid);
68 : }
69 14 : ok = false;
70 14 : return -1;
71 : }
72 632213 : return string2time(val);
73 24 : } catch (EmptyData&) {
74 12 : if (report) {
75 24 : emitEmptyError(getName(attr), objectid);
76 : }
77 24 : } catch (ProcessError&) {
78 12 : if (report) {
79 24 : emitFormatError(getName(attr), "is not a valid time value", objectid);
80 : }
81 12 : }
82 24 : ok = false;
83 24 : return -1;
84 : }
85 :
86 :
87 : SUMOTime
88 557 : SUMOSAXAttributes::getPeriod(const char* objectid, bool& ok, bool report) const {
89 : int attr = SUMO_ATTR_PERIOD;
90 : try {
91 557 : bool isPresent = true;
92 557 : const std::string& val = getString(attr, &isPresent);
93 557 : if (!isPresent) {
94 : // try 'freq' as alias for 'period'
95 : attr = SUMO_ATTR_FREQUENCY;
96 532 : isPresent = true;
97 532 : const std::string& valFreq = getString(attr, &isPresent);
98 532 : if (!isPresent) {
99 532 : if (report) {
100 0 : emitUngivenError(getName(SUMO_ATTR_PERIOD), objectid);
101 : }
102 532 : ok = false;
103 532 : return -1;
104 : }
105 0 : return string2time(valFreq);
106 : }
107 25 : return string2time(val);
108 0 : } catch (EmptyData&) {
109 0 : if (report) {
110 0 : emitEmptyError(getName(attr), objectid);
111 : }
112 0 : } catch (ProcessError&) {
113 0 : if (report) {
114 0 : emitFormatError(getName(attr), "is not a valid time value", objectid);
115 : }
116 0 : }
117 0 : ok = false;
118 0 : return -1;
119 : }
120 :
121 :
122 : SUMOTime
123 5341459 : SUMOSAXAttributes::getOptSUMOTimeReporting(int attr, const char* objectid,
124 : bool& ok, SUMOTime defaultValue, bool report) const {
125 : try {
126 5341459 : bool isPresent = true;
127 5341459 : const std::string& val = getString(attr, &isPresent);
128 5341459 : if (!isPresent) {
129 : return defaultValue;
130 : }
131 82057 : return string2time(val);
132 36 : } catch (EmptyData&) {
133 0 : if (report) {
134 0 : emitEmptyError(getName(attr), objectid);
135 : }
136 36 : } catch (ProcessError&) {
137 36 : if (report) {
138 72 : emitFormatError(getName(attr), "is not a valid time value", objectid);
139 : }
140 36 : }
141 36 : ok = false;
142 36 : return -1;
143 : }
144 :
145 :
146 : SUMOTime
147 117860 : SUMOSAXAttributes::getOptOffsetReporting(int attr, const char* objectid,
148 : bool& ok, SUMOTime defaultValue, bool report) const {
149 : try {
150 117860 : bool isPresent = true;
151 117860 : const std::string& val = getString(attr, &isPresent);
152 117860 : if (!isPresent) {
153 : return defaultValue;
154 : }
155 117726 : if (val == "begin") {
156 : return SUMOTime_MAX;
157 : } else {
158 117722 : return string2time(val);
159 : }
160 0 : } catch (EmptyData&) {
161 0 : if (report) {
162 0 : emitEmptyError(getName(attr), objectid);
163 : }
164 0 : } catch (ProcessError&) {
165 0 : if (report) {
166 0 : emitFormatError(getName(attr), "is not a valid time value", objectid);
167 : }
168 0 : }
169 0 : ok = false;
170 0 : return -1;
171 : }
172 :
173 :
174 : SUMOTime
175 53529 : SUMOSAXAttributes::getOptPeriod(const char* objectid, bool& ok, SUMOTime defaultValue, bool report) const {
176 : int attr = SUMO_ATTR_PERIOD;
177 : try {
178 53529 : bool isPresent = true;
179 53529 : const std::string& val = getString(attr, &isPresent);
180 53529 : if (!isPresent) {
181 : // try 'freq' as alias for 'period'
182 : attr = SUMO_ATTR_FREQUENCY;
183 28746 : isPresent = true;
184 28746 : const std::string& valFreq = getString(attr, &isPresent);
185 28746 : if (!isPresent) {
186 : return defaultValue;
187 : }
188 8111 : return string2time(valFreq);
189 : }
190 24783 : return string2time(val);
191 40 : } catch (EmptyData&) {
192 20 : if (report) {
193 40 : emitEmptyError(getName(attr), objectid);
194 : }
195 40 : } catch (ProcessError&) {
196 20 : if (report) {
197 40 : emitFormatError(getName(attr), "is not a valid time value", objectid);
198 : }
199 20 : }
200 40 : ok = false;
201 40 : return -1;
202 : }
203 :
204 :
205 : void
206 299 : SUMOSAXAttributes::emitUngivenError(const std::string& attrname, const char* objectid) const {
207 299 : std::ostringstream oss;
208 299 : oss << "Attribute '" << attrname << "' is missing in definition of ";
209 299 : if (objectid == nullptr || objectid[0] == 0) {
210 : oss << "a " << myObjectType;
211 : } else {
212 166 : oss << myObjectType << " '" << objectid << "'";
213 : }
214 299 : oss << ".";
215 299 : WRITE_ERROR(oss.str());
216 299 : }
217 :
218 :
219 : void
220 549 : SUMOSAXAttributes::emitEmptyError(const std::string& attrname, const char* objectid) const {
221 549 : std::ostringstream oss;
222 549 : oss << "Attribute '" << attrname << "' in definition of ";
223 549 : if (objectid == nullptr || objectid[0] == 0) {
224 : oss << "a " << myObjectType;
225 : } else {
226 392 : oss << myObjectType << " '" << objectid << "'";
227 : }
228 549 : oss << " is empty.";
229 549 : WRITE_ERROR(oss.str());
230 549 : }
231 :
232 :
233 : void
234 302 : SUMOSAXAttributes::emitFormatError(const std::string& attrname, const std::string& type, const char* objectid) const {
235 302 : std::ostringstream oss;
236 302 : oss << "Attribute '" << attrname << "' in definition of ";
237 302 : if (objectid == nullptr || objectid[0] == 0) {
238 : oss << "a " << myObjectType;
239 : } else {
240 282 : oss << myObjectType << " '" << objectid << "'";
241 : }
242 302 : oss << " " << type << ".";
243 302 : WRITE_ERROR(oss.str());
244 302 : }
245 :
246 :
247 : const int invalid_return<int>::value = -1;
248 : template<>
249 12014598 : int SUMOSAXAttributes::fromString(const std::string& value) const {
250 12014598 : return StringUtils::toInt(value);
251 : }
252 :
253 :
254 : const long long int invalid_return<long long int>::value = -1;
255 : template<>
256 1032132 : long long int SUMOSAXAttributes::fromString(const std::string& value) const {
257 1032132 : return StringUtils::toLong(value);
258 : }
259 :
260 :
261 : const double invalid_return<double>::value = -1;
262 : template<>
263 8710148 : double SUMOSAXAttributes::fromString(const std::string& value) const {
264 8710148 : return StringUtils::toDouble(value);
265 : }
266 :
267 :
268 : const bool invalid_return<bool>::value = false;
269 : template<>
270 910552 : bool SUMOSAXAttributes::fromString(const std::string& value) const {
271 910552 : return StringUtils::toBool(value);
272 : }
273 :
274 :
275 : const RGBColor invalid_return<RGBColor>::value = RGBColor();
276 : template<>
277 71312 : RGBColor SUMOSAXAttributes::fromString(const std::string& value) const {
278 142616 : return RGBColor::parseColor(value);
279 : }
280 :
281 :
282 : const Position invalid_return<Position>::value = Position();
283 : template<>
284 1326 : Position SUMOSAXAttributes::fromString(const std::string& value) const {
285 1326 : StringTokenizer st(value);
286 : // check StringTokenizer
287 1326 : while (st.hasNext()) {
288 : // obtain position
289 2652 : StringTokenizer pos(st.next(), ",");
290 : // check that position has X-Y or X-Y-Z
291 1326 : if ((pos.size() != 2) && (pos.size() != 3)) {
292 0 : throw FormatException("is not a valid position");
293 : }
294 : // obtain x and y
295 1326 : double x = StringUtils::toDouble(pos.next());
296 1326 : double y = StringUtils::toDouble(pos.next());
297 : // check if return a X-Y or a X-Y-Z Position
298 1326 : if (pos.size() == 2) {
299 : return Position(x, y);
300 : } else {
301 : // obtain z
302 0 : double z = StringUtils::toDouble(pos.next());
303 : return Position(x, y, z);
304 : }
305 1326 : }
306 : // empty positions aren't allowed
307 0 : throw FormatException("is not a valid position");
308 1326 : }
309 :
310 :
311 : const PositionVector invalid_return<PositionVector>::value = PositionVector();
312 : template<>
313 3029422 : PositionVector SUMOSAXAttributes::fromString(const std::string& value) const {
314 3029422 : StringTokenizer st(value);
315 3029422 : PositionVector shape;
316 14663626 : while (st.hasNext()) {
317 23268624 : StringTokenizer pos(st.next(), ",");
318 11634312 : if (pos.size() != 2 && pos.size() != 3) {
319 84 : throw FormatException("is not a valid list of positions");
320 : }
321 11634270 : double x = StringUtils::toDouble(pos.next());
322 11634226 : double y = StringUtils::toDouble(pos.next());
323 11634204 : if (pos.size() == 2) {
324 11603045 : shape.push_back(Position(x, y));
325 : } else {
326 31159 : double z = StringUtils::toDouble(pos.next());
327 31159 : shape.push_back(Position(x, y, z));
328 : }
329 11634312 : }
330 3029314 : return shape;
331 3029530 : }
332 :
333 :
334 : const Boundary invalid_return<Boundary>::value = Boundary();
335 : template<>
336 94326 : Boundary SUMOSAXAttributes::fromString(const std::string& value) const {
337 282978 : StringTokenizer st(value, ",");
338 94326 : if (st.size() != 4) {
339 0 : throw FormatException("is not a valid boundary");
340 : }
341 94326 : const double xmin = StringUtils::toDouble(st.next());
342 94326 : const double ymin = StringUtils::toDouble(st.next());
343 94326 : const double xmax = StringUtils::toDouble(st.next());
344 94326 : const double ymax = StringUtils::toDouble(st.next());
345 188652 : return Boundary(xmin, ymin, xmax, ymax);
346 94326 : }
347 :
348 :
349 : const SumoXMLEdgeFunc invalid_return<SumoXMLEdgeFunc>::value = SumoXMLEdgeFunc::NORMAL;
350 : template<>
351 1325577 : SumoXMLEdgeFunc SUMOSAXAttributes::fromString(const std::string& value) const {
352 : if (SUMOXMLDefinitions::EdgeFunctions.hasString(value)) {
353 1325567 : return SUMOXMLDefinitions::EdgeFunctions.get(value);
354 : }
355 20 : throw FormatException("is not a valid edge function");
356 : }
357 :
358 :
359 : const SumoXMLNodeType invalid_return<SumoXMLNodeType>::value = SumoXMLNodeType::UNKNOWN;
360 : template<>
361 678478 : SumoXMLNodeType SUMOSAXAttributes::fromString(const std::string& value) const {
362 : if (SUMOXMLDefinitions::NodeTypes.hasString(value)) {
363 678448 : return SUMOXMLDefinitions::NodeTypes.get(value);
364 : }
365 60 : throw FormatException("is not a valid node type");
366 : }
367 :
368 :
369 : const RightOfWay invalid_return<RightOfWay>::value = RightOfWay::DEFAULT;
370 : template<>
371 4 : RightOfWay SUMOSAXAttributes::fromString(const std::string& value) const {
372 : if (SUMOXMLDefinitions::RightOfWayValues.hasString(value)) {
373 4 : return SUMOXMLDefinitions::RightOfWayValues.get(value);
374 : }
375 0 : throw FormatException("is not a valid right of way value");
376 : }
377 :
378 :
379 : const FringeType invalid_return<FringeType>::value = FringeType::DEFAULT;
380 : template<>
381 264 : FringeType SUMOSAXAttributes::fromString(const std::string& value) const {
382 : if (SUMOXMLDefinitions::FringeTypeValues.hasString(value)) {
383 264 : return SUMOXMLDefinitions::FringeTypeValues.get(value);
384 : }
385 0 : throw FormatException("is not a valid fringe type");
386 : }
387 :
388 :
389 : const RoundaboutType invalid_return<RoundaboutType>::value = RoundaboutType::DEFAULT;
390 : template<>
391 1 : RoundaboutType SUMOSAXAttributes::fromString(const std::string& value) const {
392 : if (SUMOXMLDefinitions::RoundaboutTypeValues.hasString(value)) {
393 1 : return SUMOXMLDefinitions::RoundaboutTypeValues.get(value);
394 : }
395 0 : throw FormatException("is not a valid roundabout type");
396 : }
397 :
398 :
399 : const ParkingType invalid_return<ParkingType>::value = ParkingType::ONROAD;
400 : template<>
401 914 : ParkingType SUMOSAXAttributes::fromString(const std::string& value) const {
402 914 : if (value == toString(ParkingType::OPPORTUNISTIC)) {
403 : return ParkingType::OPPORTUNISTIC;
404 : } else {
405 914 : return StringUtils::toBool(value) ? ParkingType::OFFROAD : ParkingType::ONROAD;
406 : }
407 : }
408 :
409 :
410 : const std::vector<std::string> invalid_return<std::vector<std::string> >::value = std::vector<std::string>();
411 : template<>
412 12241 : std::vector<std::string> SUMOSAXAttributes::fromString(const std::string& value) const {
413 24482 : const std::vector<std::string>& ret = StringTokenizer(value).getVector();
414 12241 : if (ret.empty()) {
415 364 : throw EmptyData();
416 : }
417 23754 : return ret;
418 12241 : }
419 :
420 :
421 : const std::vector<int> invalid_return<std::vector<int> >::value = std::vector<int>();
422 : template<>
423 419 : std::vector<int> SUMOSAXAttributes::fromString(const std::string& value) const {
424 838 : const std::vector<std::string>& tmp = StringTokenizer(value).getVector();
425 419 : if (tmp.empty()) {
426 0 : throw EmptyData();
427 : }
428 : std::vector<int> ret;
429 1060 : for (const std::string& s : tmp) {
430 641 : ret.push_back(StringUtils::toInt(s));
431 : }
432 419 : return ret;
433 419 : }
434 :
435 :
436 : const std::vector<double> invalid_return<std::vector<double> >::value = std::vector<double>();
437 : template<>
438 1322 : std::vector<double> SUMOSAXAttributes::fromString(const std::string& value) const {
439 2644 : const std::vector<std::string>& tmp = StringTokenizer(value).getVector();
440 1322 : if (tmp.empty()) {
441 0 : throw EmptyData();
442 : }
443 : std::vector<double> ret;
444 142254 : for (const std::string& s : tmp) {
445 140932 : ret.push_back(StringUtils::toDouble(s));
446 : }
447 1322 : return ret;
448 1322 : }
449 :
450 : /****************************************************************************/
|