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 
13 namespace 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
Atlas::Bridge
Definition: Bridge.h:36
Atlas
Definition: Bridge.h:20