-
Notifications
You must be signed in to change notification settings - Fork 1
/
JSON.h
297 lines (244 loc) · 7.77 KB
/
JSON.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
/* $Id: JSON.h 1375 2014-04-16 12:17:54Z dpd $
*
* Copyright : (c) 2010 by Open Source Solutions Pty Ltd. All Rights Reserved
* Project :
* File : JSON
*
* Author : Denis Dowling
* Created : 9/12/2010
*
* Description : Methods to encode and later decode JavaScript Object Notation
* messages.
* Follows the syntax described at www.json.org
*/
#ifndef JSON_H
#define JSON_H
#include <string>
#include <map>
#include <vector>
#include <exception>
#include <boost/shared_ptr.hpp>
using boost::shared_ptr;
namespace JSON
{
// Need to forward declare these class as they all refer to each other
class Object;
typedef shared_ptr<Object> ObjectPtr;
class Array;
typedef shared_ptr<Array> ArrayPtr;
class Value;
typedef shared_ptr<Value> ValuePtr;
class Value
{
public:
virtual ~Value() {}
bool isString() const { return type == TypeString; }
virtual std::string getString() const;
// Return a JSON value as a string
std::string getAsString() const;
bool isNumber() const { return type == TypeNumber; }
virtual double getNumber() const;
// Return a JSON value as a number if possible otherwise returns 0
double getAsNumber() const;
bool isBoolean() const { return type == TypeBoolean; }
virtual bool getBoolean() const;
// Return a JSON value as a boolean if possible otherwise returns false
bool getAsBoolean() const;
bool isObject() const { return type == TypeObject; }
// To convert value to object use
// boost::dynamic_pointer_cast<JSON::Object>(v)
bool isArray() const { return type == TypeArray; }
// To convert value to array use
// boost::dynamic_pointer_cast<JSON::Array>(v)
bool isNull() const { return type == TypeNull; }
// Encode the Value into JSON format
virtual std::string encode() const;
virtual std::string encodePretty(int indent = 0) const;
protected:
enum Type { TypeString, TypeNumber, TypeBoolean,
TypeObject, TypeArray, TypeNull
};
Type type;
// Cannot construct directly
Value(Type type_) : type(type_) {}
private:
// Cannot copy this base class
Value(const Value &) {}
Value &operator=(const Value &) { return *this; }
};
class String
: public Value
{
public:
// Itentionally not explicit as want automatic type conversion
String(const std::string &str) : Value(TypeString), val(str) {}
String(const char *str) : Value(TypeString), val(str) {}
virtual ~String() {}
virtual std::string getString() const;
static std::string encode(const std::string &raw);
virtual std::string encode() const;
protected:
std::string val;
};
class Number
: public Value
{
public:
// Itentionally not explicit as want automatic type conversion
Number(double d) : Value(TypeNumber), val(d) {}
Number(long d) : Value(TypeNumber), val(d) {}
Number(unsigned long d) : Value(TypeNumber), val(d) {}
Number(int d) : Value(TypeNumber), val(d) {}
virtual ~Number() {}
virtual double getNumber() const;
static std::string encode(double d);
virtual std::string encode() const;
protected:
double val;
};
class Boolean
: public Value
{
public:
// Itentionally not explicit as want automatic type conversion
Boolean(bool b) : Value(TypeBoolean), val(b) {}
virtual ~Boolean() {}
virtual bool getBoolean() const;
virtual std::string encode() const;
protected:
bool val;
};
class Object
: public Value
{
public:
Object() : Value(TypeObject) {}
virtual ~Object() {}
void setProperty(const std::string &name, ValuePtr value);
// It is a little messy to repeat all of these but
// it works well
void setProperty(const std::string &name, const std::string &value);
void setProperty(const std::string &name, const char *value);
void setProperty(const std::string &name, double value);
void setProperty(const std::string &name, unsigned long value);
void setProperty(const std::string &name, long value);
void setProperty(const std::string &name, int value);
void setProperty(const std::string &name, bool value);
void setProperty(const std::string &name, ObjectPtr value);
void setProperty(const std::string &name, ArrayPtr value);
bool hasProperty(const std::string &name);
ValuePtr getProperty(const std::string &name) const;
bool getProperty(const std::string &name, std::string &value) const;
bool getProperty(const std::string &name, double &value) const;
bool getProperty(const std::string &name, unsigned long &value) const;
bool getProperty(const std::string &name, long &value) const;
bool getProperty(const std::string &name, int &value) const;
bool getProperty(const std::string &name, bool &value) const;
typedef std::map<std::string, ValuePtr> Properties;
Properties properties;
virtual std::string encode() const;
virtual std::string encodePretty(int indent = 0) const;
};
class Array
: public Value
{
public:
Array() : Value(TypeArray) {}
virtual ~Array() {}
void add(ValuePtr value);
// Helpers to do the type conversion
void add(const std::string &value);
void add(const char *value);
void add(double value);
void add(long value);
void add(int value);
void add(bool value);
void add(ObjectPtr value);
void add(ArrayPtr value);
size_t size() const;
typedef std::vector<ValuePtr> Elements;
Elements elements;
virtual std::string encode() const;
virtual std::string encodePretty(int indent = 0) const;
};
class Null
: public Value
{
public:
Null() : Value(TypeNull) {}
virtual ~Null() {}
virtual std::string encode() const;
};
class Exception : public std::exception
{
public:
Exception(const std::string &str);
virtual ~Exception() throw();
virtual const char *what() const throw();
protected:
std::string reason;
};
class ParserException : public Exception
{
public:
ParserException(const std::string &str, size_t line, size_t column);
};
// Support relaxing the strict JSON parsing syntax to allow some
// common Javascript features. This idea is copied from the Jackson
// JSON parser
enum ParserFeature {
ALLOW_COMMENTS = 1<<0,
ALLOW_UNQUOTED_FIELD_NAMES = 1<<1,
ALLOW_SINGLE_QUOTES = 1<<2,
ALLOW_TRAILING_COMMAS = 1<<3,
};
class Parser
{
public:
Parser(int features =
ALLOW_COMMENTS | ALLOW_UNQUOTED_FIELD_NAMES |
ALLOW_SINGLE_QUOTES | ALLOW_TRAILING_COMMAS);
ValuePtr parse(const std::string &str);
protected:
int features;
enum TokenType
{
TOK_OPEN_BRACE, // '{'
TOK_CLOSE_BRACE, // '}'
TOK_COMMA, // ','
TOK_COLON, // ':'
TOK_OPEN_BRACKET, // '['
TOK_CLOSE_BRACKET, // ']'
TOK_DOUBLE_QUOTE, // '"'
TOK_SINGLE_QUOTE, // '\''
TOK_NUMBER, // Number starts with any of "-0123456789". Can also contain any of these '.eE+'
TOK_WHITE_SPACE, // space (0x20), HT (0x09), LF (0x0a), CR (0x0d)
TOK_COMMENT, // '/' for ALLOW_COMMENT
TOK_IDENTIFIER, // '[a-zA-Z_]' for ALLOW_UNQUOTED_FIELD_NAMES
TOK_EOS, // Matched the end of the string
TOK_ERROR, // Any other characters
};
// Vector will be initialised to 256 entries to map from an ASCII
// character to a token type
static std::vector<TokenType> tokenType;
// Human readable strings for the token names
static std::vector<std::string> tokenName;
size_t pos;
size_t line;
size_t column;
std::string str;
char getChar();
void ungetChar();
TokenType getNextToken();
void getToken(TokenType match);
ValuePtr parseValue();
std::string parseString(TokenType start_token);
std::string parseIdentifier();
ValuePtr parseStringValue(TokenType start_token);
ValuePtr parseNumericValue();
ValuePtr parseObject();
ValuePtr parseArray();
void parseComment();
};
}
#endif