DeviceAtlas C++ Api documentation
json.h
1 /*
2  * Basic JSON parse
3  */
4 
5 #ifndef MTLD_JSON_H
6 #define MTLD_JSON_H
7 #include <string>
8 #include <iostream>
9 #include <vector>
10 #include <mtld/exception.h>
11 #include <mtld/common.h>
12 #include <stdlib.h>
13 
14 namespace Mobi { namespace Mtld { namespace JSON {
15 
16 // Identifies type of JSON construct
17 enum Type {
18  Array,
19  Object,
20  Number,
21  String
22 };
23 
24 // pretty-printer for JSON data.
25 std::ostream &operator<< (std::ostream &, const Type &);
26 
27 class FormatError : public Exception {};
28 
29 // Basic parser.
30 class Parser {
31  std::istream &f; // data stream to parse
32  unsigned char peek(); // peek at next character
33  unsigned char read(); // consume next character.
34 public:
35  Parser(std::istream &f_) : f(f_) {}
36 
37  // Parse one primitive item from the stream
38  void parseString(std::string &);
39  template <typename I> void parseInt(I &); // templatise for different integer types.
40  void parseFloat(double &);
41 
42  void skipAny(); // skips over the next field, irrespective of type.
43 
44  /*
45  * parse an object calling back into
46  * Context::parseField(this, fieldname) for each constituent object.
47  */
48 
49  template <typename Context> void parseObject(Context &ctx);
50 
51  /*
52  * parse an array calling back into
53  * Context::parseElement(this, index) for each constituent object.
54  */
55  template <typename Context> void parseArray(Context &ctx);
56 
57  // Peek at the type of the next object in the stream
58  Type peekType();
59 
60  // consume whitespace, and return a peek at the next character.
61  unsigned char startNextToken();
62  ~Parser() {}
63 };
64 
65 template <typename N>
66 void
67 Parser::parseInt(N &in)
68 {
69  int sign = 1;
70  char c = startNextToken();
71  if (c == '-') {
72  read();
73  c = peek();
74  sign = -1;
75  } else if (!isdigit(c)) {
76  throw FormatError();
77  }
78  for (in = 0; isdigit(c); c = peek()) {
79  read();
80  in *= 10;
81  in += c - '0';
82  };
83  in *= sign;
84 }
85 
86 template <typename Context>
87 void
88 Parser::parseArray(Context &ctx)
89 {
90  int c = startNextToken();
91  if (c != '[')
92  throw FormatError();
93  read();
94  if ((c = startNextToken()) == ']')
95  return; // empty array
96 
97  for (size_t i = 0;; i++) {
98  startNextToken();
99  ctx.parseElement(this, i);
100 
101  c = startNextToken();
102  read();
103  switch (c) {
104  case ']':
105  return;
106  case ',':
107  break;
108  default:
109  throw FormatError();
110  }
111  }
112 }
113 
114 template <typename Context>
115 void
116 Parser::parseObject(Context &ctx)
117 {
118  // An object is a list of pairs.
119  int c = startNextToken();
120  if (c != '{')
121  throw FormatError();
122  read();
123  for (;;) {
124  std::string fieldName;
125  switch (startNextToken()) {
126  case '"': // Name of next field.
127  parseString(fieldName);
128  c = startNextToken();
129  read();
130  if (c != ':')
131  throw FormatError();
132  ctx.parseField(this, fieldName);
133  break;
134 
135  case '}': // End of this object
136  read();
137  return;
138 
139  case ',': // Separator to next field
140  read();
141  break;
142 
143  default:
144  throw FormatError();
145  }
146  }
147 }
148 
149 // For parsing simple vector types:
150 // VectorArrayParser<std::string, parseStringF> would be a candidate argument for the parseArray template.
151 
152 template <typename VT, typename Func>
154  std::vector<VT> &values;
155  Func f;
156  public:
157  void parseElement(Parser *j, size_t idx) {
158  if (values.size() <= idx)
159  values.resize(idx + 1);
160  f(j, values[idx]);
161  }
162  VectorArrayParser(std::vector<VT> &values_, Func f_ = Func()) : values(values_), f(f_) {}
163 };
164 
165 // This is a special case parser for objects where the keys are indexes into an array.
166 // This can me more compact than an array where most of the elements take a default value
167 
168 template <typename VT, typename Func>
170  std::vector<VT> &values;
171  Func f;
172 public:
173  void parseField(Parser *j, std::string field) {
174  const char *p = field.c_str();
175  unsigned long idx = 0;
176  try {
177  idx = Mobi::Mtld::Da::ValueChecker::atou<unsigned long>(p);
178  if (values.size() <= idx)
179  values.resize(idx + 1);
180  f(j, values[idx]);
181  } catch (Exception &e) {
182  e << " (parse json field)";
183  throw e;
184  }
185  }
186  SparseArrayParser(std::vector<VT> &values_, Func f_ = Func()) : values(values_), f(f_) {}
187 };
188 
189 struct parseStringF {
190  void operator () (Parser *j, std::string &s) { j->parseString(s); }
191 };
192 
193 template <typename IntegerType = int> struct parseIntF {
194  void operator () (Parser *j, IntegerType &i) { j->parseInt(i); }
195 };
196 
197 template <typename Object, typename ObjectParser> struct parseObjectF {
198  void operator () (JSON::Parser *j, Object &o) {
199  ObjectParser p(o);
200  j->parseObject(p);
201  }
202 };
203 
204 
205 }}}
206 #endif
Definition: json.h:193
Definition: json.h:197
Definition: exception.h:16
Definition: json.h:27
Definition: json.h:189
Definition: json.h:30
Definition: binary.h:13