Line data Source code
1 : /****************************************************************************/
2 : // Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo
3 : // Copyright (C) 2001-2024 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 ParBuffer.h
15 : /// @author Michele Segata
16 : /// @date Wed, 18 Apr 2012
17 : ///
18 : // Class for the string serialization and deserialization of parameters
19 : /****************************************************************************/
20 :
21 : #pragma once
22 : #include <config.h>
23 :
24 : #include <cstddef>
25 : #include <string>
26 : #include <sstream>
27 : #include <algorithm>
28 :
29 0 : class ParBuffer {
30 : public:
31 0 : ParBuffer() : SEP(':'), ESC('\\'), QUO('"'), was_empty(false) {}
32 0 : ParBuffer(std::string buf) : SEP(':'), ESC('\\'), QUO('"'),
33 0 : was_empty(false) {
34 0 : inBuffer = buf;
35 0 : }
36 :
37 0 : template<typename T> ParBuffer& operator <<(const T& v) {
38 0 : std::stringstream ss;
39 : std::string str_value;
40 0 : ss << v;
41 0 : str_value = escape(ss.str());
42 0 : if (outBuffer.str().length() == 0) {
43 0 : outBuffer << str_value;
44 : } else {
45 0 : outBuffer << SEP << str_value;
46 : }
47 0 : return *this;
48 0 : }
49 :
50 0 : size_t next_escape(std::string str, size_t pos) {
51 0 : size_t c_pos = str.find(SEP, pos);
52 0 : size_t e_pos = str.find(ESC, pos);
53 0 : if (c_pos == std::string::npos) {
54 : return e_pos;
55 : }
56 0 : if (e_pos == std::string::npos) {
57 : return c_pos;
58 : }
59 0 : return std::min(c_pos, e_pos);
60 : }
61 :
62 0 : std::string escape(std::string str) {
63 : size_t pos, last_pos = 0;
64 0 : std::stringstream escaping;
65 : std::string escaped;
66 0 : while ((pos = next_escape(str, last_pos)) != std::string::npos) {
67 0 : escaping << str.substr(last_pos, pos - last_pos);
68 0 : escaping << ESC << str.substr(pos, 1);
69 0 : last_pos = pos + 1;
70 : }
71 0 : if (last_pos != str.size()) {
72 0 : escaping << str.substr(last_pos);
73 : }
74 0 : escaped = escaping.str();
75 0 : if (escaped.empty() || (escaped.c_str()[0] == QUO && escaped.c_str()[escaped.length() - 1] == QUO)) {
76 0 : escaping.str("");
77 0 : escaping.clear();
78 0 : escaping << QUO << escaped << QUO;
79 0 : escaped = escaping.str();
80 : }
81 0 : return escaped;
82 0 : }
83 :
84 0 : std::string unescape(std::string str) {
85 : size_t pos, last_pos = 0;
86 0 : std::stringstream unescaped;
87 : std::string escaped;
88 0 : if (str.c_str()[0] == QUO && str.c_str()[str.length() - 1] == QUO) {
89 0 : str = str.substr(1, str.length() - 2);
90 : }
91 0 : while ((pos = str.find(ESC, last_pos)) != std::string::npos) {
92 0 : unescaped << str.substr(last_pos, pos - last_pos);
93 0 : unescaped << str.substr(pos + 1, 1);
94 0 : last_pos = pos + 2;
95 : }
96 0 : if (last_pos != str.size()) {
97 0 : unescaped << str.substr(last_pos);
98 : }
99 0 : return unescaped.str();
100 0 : }
101 :
102 0 : std::string next() {
103 0 : if (inBuffer.size() == 0) {
104 0 : return "";
105 : }
106 :
107 : size_t sep = std::string::npos;
108 : do {
109 0 : sep = inBuffer.find(SEP, sep + 1);
110 0 : } while (!(sep == std::string::npos || sep == 0 || inBuffer.c_str()[sep - 1] != ESC));
111 :
112 : std::string value;
113 0 : if (sep == std::string::npos) {
114 0 : value = unescape(inBuffer);
115 : inBuffer = "";
116 : } else {
117 0 : value = unescape(inBuffer.substr(0, sep));
118 0 : inBuffer = inBuffer.substr(sep + 1);
119 : }
120 0 : return value;
121 : }
122 :
123 0 : template <typename T> ParBuffer& operator>>(T& v) {
124 0 : std::string value = next();
125 0 : std::stringstream ss(value);
126 0 : ss >> v;
127 : // stringstream doesn't write to v if value is an empty string. the
128 : // only solution is letting the user know that the last parsed
129 : // portion was empty
130 0 : if (value == "") {
131 0 : was_empty = true;
132 : } else {
133 0 : was_empty = false;
134 : }
135 0 : return *this;
136 0 : }
137 :
138 : bool last_empty() {
139 0 : return was_empty;
140 : }
141 :
142 : void set(std::string buf) {
143 : inBuffer = buf;
144 : }
145 : void clear() {
146 : outBuffer.clear();
147 : }
148 : std::string str() const {
149 0 : return outBuffer.str();
150 : }
151 :
152 : private:
153 : const char SEP;
154 : const char ESC;
155 : const char QUO;
156 : std::stringstream outBuffer;
157 : std::string inBuffer;
158 : bool was_empty;
159 :
160 : };
|