Atlas 0.7.0
Networking protocol for the Worldforge system.
Packed.cpp
1// This file may be redistributed and modified only under the terms of
2// the GNU Lesser General Public License (See COPYING for details).
3// Copyright (C) 2000-2001 Stefanus Du Toit, Michael Day
4
5// $Id$
6
7#include <Atlas/Codecs/Packed.h>
8
9#include <iostream>
10
11#include <cstdlib>
12
13namespace Atlas {
14 namespace Codecs {
15
16 Packed::Packed(std::istream &in, std::ostream &out, Atlas::Bridge &b)
17 : m_istream(in), m_ostream(out), m_bridge(b) {
18 m_state.push(PARSE_NOTHING);
19 }
20
21 void Packed::parsingBegins(char next) {
22 m_state.push(PARSE_STREAM);
23 m_bridge.streamBegin();
24 parseStream(next);
25 }
26
27
28 void Packed::parseStream(char next) {
29 switch (next) {
30 case '[':
31 m_bridge.streamMessage();
32 m_state.push(PARSE_MAP);
33 break;
34
35 default:
36 // FIXME signal error here
37 // unexpected character
38 break;
39 }
40 }
41
42 void Packed::parseMap(char next) {
43 switch (next) {
44 case ']':
45 m_bridge.mapEnd();
46 m_state.pop();
47 break;
48
49 case '[':
50 m_state.push(PARSE_MAP);
51 m_state.push(PARSE_MAP_BEGIN);
52 m_state.push(PARSE_NAME);
53 break;
54
55 case '(':
56 m_state.push(PARSE_LIST);
57 m_state.push(PARSE_LIST_BEGIN);
58 m_state.push(PARSE_NAME);
59 break;
60
61 case '$':
62 m_state.push(PARSE_STRING);
63 m_state.push(PARSE_NAME);
64 break;
65
66 case '@':
67 m_state.push(PARSE_INT);
68 m_state.push(PARSE_NAME);
69 break;
70
71 case '#':
72 m_state.push(PARSE_FLOAT);
73 m_state.push(PARSE_NAME);
74 break;
75
76 default:
77 // FIXME signal error here
78 // unexpected character
79 break;
80 }
81 }
82
83 void Packed::parseList(char next) {
84 switch (next) {
85 case ')':
86 m_bridge.listEnd();
87 m_state.pop();
88 break;
89
90 case '[':
91 m_bridge.listMapItem();
92 m_state.push(PARSE_MAP);
93 break;
94
95 case '(':
96 m_bridge.listListItem();
97 m_state.push(PARSE_LIST);
98 break;
99
100 case '$':
101 m_state.push(PARSE_STRING);
102 break;
103
104 case '@':
105 m_state.push(PARSE_INT);
106 break;
107
108 case '#':
109 m_state.push(PARSE_FLOAT);
110 break;
111
112 default:
113 // FIXME signal error here
114 // unexpected character
115 break;
116 }
117 }
118
119 void Packed::parseMapBegin(char next) {
120 m_bridge.mapMapItem(hexDecode(std::move(m_name)));
121 m_istream.putback(next);
122 m_state.pop();
123 m_name.clear();
124 }
125
126 void Packed::parseListBegin(char next) {
127 m_bridge.mapListItem(hexDecode(std::move(m_name)));
128 m_istream.putback(next);
129 m_state.pop();
130 m_name.clear();
131 }
132
133 void Packed::parseInt(char next) {
134 switch (next) {
135 case '[':
136 case ']':
137 case '(':
138 case ')':
139 case '$':
140 case '@':
141 case '#':
142 m_istream.putback(next);
143 m_state.pop();
144 try {
145 if (m_state.top() == PARSE_MAP) {
146 if (m_data.empty()) {
147 m_bridge.mapNoneItem(hexDecode(std::move(m_name)));
148 } else {
149 m_bridge.mapIntItem(hexDecode(std::move(m_name)), std::stol(m_data));
150 }
151 m_name.clear();
152 } else if (m_state.top() == PARSE_LIST) {
153 if (m_data.empty()) {
154 m_bridge.listNoneItem();
155 } else {
156 m_bridge.listIntItem(std::stol(m_data));
157 }
158 } else {
159 // FIXME some kind of sanity checking assertion here
160 }
161 } catch (...) {
162 //Could not parse long; just ignore
163 if (m_state.top() == PARSE_MAP) {
164 m_name.clear();
165 }
166 }
167 m_data.clear();
168 break;
169
170 case '0':
171 case '1':
172 case '2':
173 case '3':
174 case '4':
175 case '5':
176 case '6':
177 case '7':
178 case '8':
179 case '9':
180 case '-':
181 case '+':
182 m_data += next;
183 break;
184
185 default:
186 // FIXME signal error here
187 // unexpected character
188 break;
189 }
190 }
191
192 void Packed::parseFloat(char next) {
193 switch (next) {
194 case '[':
195 case ']':
196 case '(':
197 case ')':
198 case '$':
199 case '@':
200 case '#':
201 m_istream.putback(next);
202 m_state.pop();
203 try {
204
205 if (m_state.top() == PARSE_MAP) {
206 m_bridge.mapFloatItem(hexDecode(std::move(m_name)), std::stod(m_data));
207 m_name.clear();
208 } else if (m_state.top() == PARSE_LIST) {
209 m_bridge.listFloatItem(std::stod(m_data));
210 } else {
211 // FIXME some kind of sanity checking assertion here
212 }
213 } catch (...) {
214 //Could not parse float; just ignore
215 if (m_state.top() == PARSE_MAP) {
216 m_name.clear();
217 }
218 }
219 m_data.clear();
220 break;
221
222 case '0':
223 case '1':
224 case '2':
225 case '3':
226 case '4':
227 case '5':
228 case '6':
229 case '7':
230 case '8':
231 case '9':
232 case '.':
233 case '-':
234 case '+':
235 case 'e':
236 case 'E':
237 m_data += next;
238 break;
239
240 default:
241 // FIXME signal error here
242 // unexpected character
243 break;
244 }
245 }
246
247 void Packed::parseString(char next) {
248 switch (next) {
249 case '[':
250 case ']':
251 case '(':
252 case ')':
253 case '$':
254 case '@':
255 case '#':
256 m_istream.putback(next);
257 m_state.pop();
258 if (m_state.top() == PARSE_MAP) {
259 m_bridge.mapStringItem(hexDecode(std::move(m_name)), hexDecode(std::move(m_data)));
260 m_name.clear();
261 } else if (m_state.top() == PARSE_LIST) {
262 m_bridge.listStringItem(hexDecode(std::move(m_data)));
263 } else {
264 // FIXME some kind of sanity checking assertion here
265 }
266 m_data.clear();
267 break;
268
269 case '=':
270 // FIXME signal error here
271 // unexpected character
272 break;
273
274 default:
275 m_data += next;
276 break;
277 }
278 }
279
280 void Packed::parseName(char next) {
281 switch (next) {
282 case '=':
283 m_state.pop();
284 break;
285
286 case '[':
287 case ']':
288 case '(':
289 case ')':
290 case '$':
291 case '@':
292 case '#':
293 // FIXME signal error here
294 // unexpected character
295 break;
296
297 default:
298 m_name += next;
299 break;
300 }
301 }
302
303 void Packed::poll() {
304 m_istream.peek();
305
306 std::streamsize count;
307
308 while ((count = m_istream.rdbuf()->in_avail()) > 0) {
309
310 for (std::streamsize i = 0; i < count; ++i) {
311
312 char next = m_istream.rdbuf()->sbumpc();
313
314 switch (m_state.top()) {
315 case PARSE_NOTHING:
316 parsingBegins(next);
317 break;
318 case PARSE_STREAM:
319 parseStream(next);
320 break;
321 case PARSE_MAP:
322 parseMap(next);
323 break;
324 case PARSE_LIST:
325 parseList(next);
326 break;
327 case PARSE_MAP_BEGIN:
328 parseMapBegin(next);
329 break;
330 case PARSE_LIST_BEGIN:
331 parseListBegin(next);
332 break;
333 case PARSE_INT:
334 parseInt(next);
335 break;
336 case PARSE_FLOAT:
337 parseFloat(next);
338 break;
339 case PARSE_STRING:
340 parseString(next);
341 break;
342 case PARSE_NAME:
343 parseName(next);
344 break;
345 }
346 }
347 }
348 }
349
350 void Packed::streamBegin() {
351 //Do nothing to denote that a stream begins.
352 }
353
354 void Packed::streamMessage() {
355 m_ostream << '[';
356 }
357
358 void Packed::streamEnd() {
359 //Do nothing to denote that a stream ends.
360 }
361
362 void Packed::mapMapItem(std::string name) {
363 m_ostream << '[' << hexEncode(std::move(name)) << '=';
364 }
365
366 void Packed::mapListItem(std::string name) {
367 m_ostream << '(' << hexEncode(std::move(name)) << '=';
368 }
369
370 void Packed::mapIntItem(std::string name, std::int64_t data) {
371 m_ostream << '@' << hexEncode(std::move(name)) << '=' << data;
372 }
373
374 void Packed::mapFloatItem(std::string name, double data) {
375 m_ostream << '#' << hexEncode(std::move(name)) << '=' << data;
376 }
377
378 void Packed::mapStringItem(std::string name, std::string data) {
379 m_ostream << '$' << hexEncode(std::move(name)) << '=' << hexEncode(std::move(data));
380 }
381
382 void Packed::mapNoneItem(std::string name) {
383 m_ostream << '@' << hexEncode(std::move(name)) << '='; //Use the same marker as for int, but without anything trailing it.
384 }
385
386 void Packed::mapEnd() {
387 m_ostream << ']';
388 }
389
390 void Packed::listMapItem() {
391 m_ostream << '[';
392 }
393
394 void Packed::listListItem() {
395 m_ostream << '(';
396 }
397
398 void Packed::listIntItem(std::int64_t data) {
399 m_ostream << '@' << data;
400 }
401
402 void Packed::listFloatItem(double data) {
403 m_ostream << '#' << data;
404 }
405
406 void Packed::listStringItem(std::string data) {
407 m_ostream << '$' << hexEncode(std::move(data));
408 }
409
410 void Packed::listNoneItem() {
411 m_ostream << '@'; //Use the same marker as for int, but without anything trailing it.
412 }
413
414
415 void Packed::listEnd() {
416 m_ostream << ')';
417 }
418
419 }
420} // namespace Atlas::Codecs
Definition: Bridge.h:20