1 // -*- mode: c++; c-basic-offset: 4; -*-
2
3 // Author: Hong Jiang <hong@hjiang.net>
4 // Contributors:
5 // Sean Middleditch <sean@middleditch.us>
6 // rlyeh <https://github.com/r-lyeh>
7
8 #pragma once
9
10 #include <cstddef>
11 #include <cassert>
12 #include <iostream>
13 #include <map>
14 #include <vector>
15 #include <string>
16 #include <sstream>
17
18 // jsonxx versioning: major.minor-extra where
19 // major = { number }
20 // minor = { number }
21 // extra = { 'a':alpha, 'b':beta, 'rc': release candidate, 'r': release, 's':stable }
22 #define JSONXX_MAJOR "0"
23 #define JSONXX_MINOR "22"
24 #define JSONXX_EXTRA "a"
25 #define JSONXX_VERSION JSONXX_MAJOR "." JSONXX_MINOR "-" JSONXX_EXTRA
26 #define JSONXX_XML_TAG "<!-- generated by jsonxx " JSONXX_VERSION " -->"
27
28 #if __cplusplus > 199711L
29 #define JSONXX_COMPILER_HAS_CXX11 1
30 #elif defined(_MSC_VER) && _MSC_VER > 1700
31 #define JSONXX_COMPILER_HAS_CXX11 1
32 #else
33 #define JSONXX_COMPILER_HAS_CXX11 0
34 #endif
35
36 #ifdef _MSC_VER
37 // disable the C4127 warning if using VC, see http://stackoverflow.com/a/12042515
38 #define JSONXX_ASSERT(...) \
39 do { \
40 __pragma(warning(push)) __pragma(warning(disable:4127)) \
41 if( jsonxx::Assertions ) \
42 __pragma(warning(pop)) \
43 jsonxx::assertion(__FILE__,__LINE__,#__VA_ARGS__,bool(__VA_ARGS__)); \
44 __pragma(warning(push)) __pragma(warning(disable:4127)) \
45 } while(0) \
46 __pragma(warning(pop))
47 #else
48 #define JSONXX_ASSERT(...) do { if( jsonxx::Assertions ) \
49 jsonxx::assertion(__FILE__,__LINE__,#__VA_ARGS__,bool(__VA_ARGS__)); } while(0)
50 #endif
51
52 namespace jsonxx {
53
54 // FIXME(hjiang): Those should really be dynamic.
55 // Settings
56 enum Settings {
57 // constants
58 Enabled = true,
59 Disabled = false,
60 Permissive = true,
61 Strict = false,
62 // values
63 Parser = Permissive, // permissive or strict parsing
64 UnquotedKeys = Disabled, // support of unquoted keys
65 Assertions = Enabled // enabled or disabled assertions (these asserts work both in DEBUG and RELEASE builds)
66 };
67
68 #ifdef _MSC_VER
69 #pragma warning(push)
70 #pragma warning(disable:4127)
71 #endif
parser_is_strict()72 inline bool parser_is_strict() { return Parser == Strict; }
parser_is_permissive()73 inline bool parser_is_permissive() { return Parser == Permissive; }
unquoted_keys_are_enabled()74 inline bool unquoted_keys_are_enabled() { return UnquotedKeys == Enabled; }
75 #ifdef _MSC_VER
76 #pragma warning(pop)
77 #endif
78
79 // Constants for .write() and .xml() methods
80 enum Format {
81 JSON = 0, // JSON output
82 JSONx = 1, // XML output, JSONx format. see http://goo.gl/I3cxs
83 JXML = 2, // XML output, JXML format. see https://github.com/r-lyeh/JXML
84 JXMLex = 3, // XML output, JXMLex format. see https://github.com/r-lyeh/JXMLex
85 TaggedXML = 4 // XML output, tagged XML format. see https://github.com/hjiang/jsonxx/issues/12
86 };
87
88 // Types
89 typedef long double Number;
90 typedef bool Boolean;
91 typedef std::string String;
92 struct Null {};
93 class Value;
94 class Object;
95 class Array;
96
97 // Identity meta-function
98 template <typename T>
99 struct identity {
100 typedef T type;
101 };
102
103 // Tools
104 bool validate( const std::string &input );
105 bool validate( std::istream &input );
106 std::string reformat( const std::string &input );
107 std::string reformat( std::istream &input );
108 std::string xml( const std::string &input, unsigned format = JSONx );
109 std::string xml( std::istream &input, unsigned format = JSONx );
110
111 // Detail
112 void assertion( const char *file, int line, const char *expression, bool result );
113
114 // A JSON Object
115 class Object {
116 public:
117 Object();
118 ~Object();
119
120 template <typename T>
121 bool has(const std::string& key) const;
122
123 // Always call has<>() first. If the key doesn't exist, consider
124 // the behavior undefined.
125 template <typename T>
126 T& get(const std::string& key);
127 template <typename T>
128 const T& get(const std::string& key) const;
129
130 template <typename T>
131 const T& get(const std::string& key, const typename identity<T>::type& default_value) const;
132
133 size_t size() const;
134 bool empty() const;
135
136 const std::map<std::string, Value*>& kv_map() const;
137 std::string json() const;
138 std::string xml( unsigned format = JSONx, const std::string &header = std::string(), const std::string &attrib = std::string() ) const;
139 std::string write( unsigned format ) const;
140
141 void reset();
142 bool parse(std::istream &input);
143 bool parse(const std::string &input);
144 typedef std::map<std::string, Value*> container;
145 void import( const Object &other );
146 void import( const std::string &key, const Value &value );
147 Object &operator<<(const Value &value);
148 Object &operator<<(const Object &value);
149 Object &operator=(const Object &value);
150 Object(const Object &other);
151 Object(const std::string &key, const Value &value);
152 template<size_t N>
Object(const char (& key)[N],const Value & value)153 Object(const char (&key)[N], const Value &value) {
154 import(key,value);
155 }
156 template<typename T>
157 Object &operator<<(const T &value);
158
159 protected:
160 static bool parse(std::istream& input, Object& object);
161 container value_map_;
162 std::string odd;
163 };
164
165 class Array {
166 public:
167 Array();
168 ~Array();
169
170 size_t size() const;
171 bool empty() const;
172
173 template <typename T>
174 bool has(unsigned int i) const;
175
176 template <typename T>
177 T& get(unsigned int i);
178 template <typename T>
179 const T& get(unsigned int i) const;
180
181 template <typename T>
182 const T& get(unsigned int i, const typename identity<T>::type& default_value) const;
183
values()184 const std::vector<Value*>& values() const {
185 return values_;
186 }
187 std::string json() const;
188 std::string xml( unsigned format = JSONx, const std::string &header = std::string(), const std::string &attrib = std::string() ) const;
189
write(unsigned format)190 std::string write( unsigned format ) const { return format == JSON ? json() : xml(format); }
191 void reset();
192 bool parse(std::istream &input);
193 bool parse(const std::string &input);
194 typedef std::vector<Value*> container;
195 void append(const Array &other);
append(const Value & value)196 void append(const Value &value) { import(value); }
197 void import(const Array &other);
198 void import(const Value &value);
199 Array &operator<<(const Array &other);
200 Array &operator<<(const Value &value);
201 Array &operator=(const Array &other);
202 Array &operator=(const Value &value);
203 Array(const Array &other);
204 Array(const Value &value);
205 protected:
206 static bool parse(std::istream& input, Array& array);
207 container values_;
208 };
209
210 // A value could be a number, an array, a string, an object, a
211 // boolean, or null
212 class Value {
213 public:
214
215 Value();
~Value()216 ~Value() { reset(); }
217 void reset();
218
219 template<typename T>
import(const T &)220 void import( const T & ) {
221 reset();
222 type_ = INVALID_;
223 // debug
224 // std::cout << "[WARN] No support for " << typeid(t).name() << std::endl;
225 }
import(const bool & b)226 void import( const bool &b ) {
227 reset();
228 type_ = BOOL_;
229 bool_value_ = b;
230 }
231 #define $number(TYPE) \
232 void import( const TYPE &n ) { \
233 reset(); \
234 type_ = NUMBER_; \
235 number_value_ = static_cast<long double>(n); \
236 }
237 $number( char )
$number(int)238 $number( int )
239 $number( long )
240 $number( long long )
241 $number( unsigned char )
242 $number( unsigned int )
243 $number( unsigned long )
244 $number( unsigned long long )
245 $number( float )
246 $number( double )
247 $number( long double )
248 #undef $number
249 #if JSONXX_COMPILER_HAS_CXX11 > 0
250 void import( const std::nullptr_t & ) {
251 reset();
252 type_ = NULL_;
253 }
254 #endif
import(const Null &)255 void import( const Null & ) {
256 reset();
257 type_ = NULL_;
258 }
import(const String & s)259 void import( const String &s ) {
260 reset();
261 type_ = STRING_;
262 *( string_value_ = new String() ) = s;
263 }
import(const Array & a)264 void import( const Array &a ) {
265 reset();
266 type_ = ARRAY_;
267 *( array_value_ = new Array() ) = a;
268 }
import(const Object & o)269 void import( const Object &o ) {
270 reset();
271 type_ = OBJECT_;
272 *( object_value_ = new Object() ) = o;
273 }
import(const Value & other)274 void import( const Value &other ) {
275 if (this != &other)
276 switch (other.type_) {
277 case NULL_:
278 import( Null() );
279 break;
280 case BOOL_:
281 import( other.bool_value_ );
282 break;
283 case NUMBER_:
284 import( other.number_value_ );
285 break;
286 case STRING_:
287 import( *other.string_value_ );
288 break;
289 case ARRAY_:
290 import( *other.array_value_ );
291 break;
292 case OBJECT_:
293 import( *other.object_value_ );
294 break;
295 case INVALID_:
296 type_ = INVALID_;
297 break;
298 default:
299 JSONXX_ASSERT( !"not implemented" );
300 }
301 }
302 template<typename T>
303 Value &operator <<( const T &t ) {
304 import(t);
305 return *this;
306 }
307 template<typename T>
308 Value &operator =( const T &t ) {
309 reset();
310 import(t);
311 return *this;
312 }
313 Value(const Value &other);
314 template<typename T>
Value(const T & t)315 Value( const T&t ) : type_(INVALID_) { import(t); }
316 template<size_t N>
Value(const char (& t)[N])317 Value( const char (&t)[N] ) : type_(INVALID_) { import( std::string(t) ); }
318
319 bool parse(std::istream &input);
320 bool parse(const std::string &input);
321
322 template<typename T>
323 bool is() const;
324 template<typename T>
325 T& get();
326 template<typename T>
327 const T& get() const;
328
329 bool empty() const;
330
331 public:
332 enum {
333 NUMBER_,
334 STRING_,
335 BOOL_,
336 NULL_,
337 ARRAY_,
338 OBJECT_,
339 INVALID_
340 } type_;
341 union {
342 Number number_value_;
343 String* string_value_;
344 Boolean bool_value_;
345 Array* array_value_;
346 Object* object_value_;
347 };
348
349 protected:
350 static bool parse(std::istream& input, Value& value);
351 };
352
353 template <typename T>
has(unsigned int i)354 bool Array::has(unsigned int i) const {
355 if (i >= size()) {
356 return false;
357 } else {
358 Value* v = values_.at(i);
359 return v->is<T>();
360 }
361 }
362
363 template <typename T>
get(unsigned int i)364 T& Array::get(unsigned int i) {
365 JSONXX_ASSERT(i < size());
366 Value* v = values_.at(i);
367 return v->get<T>();
368 }
369
370 template <typename T>
get(unsigned int i)371 const T& Array::get(unsigned int i) const {
372 JSONXX_ASSERT(i < size());
373 const Value* v = values_.at(i);
374 return v->get<T>();
375 }
376
377 template <typename T>
get(unsigned int i,const typename identity<T>::type & default_value)378 const T& Array::get(unsigned int i, const typename identity<T>::type& default_value) const {
379 if(has<T>(i)) {
380 const Value* v = values_.at(i);
381 return v->get<T>();
382 } else {
383 return default_value;
384 }
385 }
386
387 template <typename T>
has(const std::string & key)388 bool Object::has(const std::string& key) const {
389 container::const_iterator it(value_map_.find(key));
390 return it != value_map_.end() && it->second->is<T>();
391 }
392
393 template <typename T>
get(const std::string & key)394 T& Object::get(const std::string& key) {
395 JSONXX_ASSERT(has<T>(key));
396 return value_map_.find(key)->second->get<T>();
397 }
398
399 template <typename T>
get(const std::string & key)400 const T& Object::get(const std::string& key) const {
401 JSONXX_ASSERT(has<T>(key));
402 return value_map_.find(key)->second->get<T>();
403 }
404
405 template <typename T>
get(const std::string & key,const typename identity<T>::type & default_value)406 const T& Object::get(const std::string& key, const typename identity<T>::type& default_value) const {
407 if (has<T>(key)) {
408 return value_map_.find(key)->second->get<T>();
409 } else {
410 return default_value;
411 }
412 }
413
414 template<>
415 inline bool Value::is<Value>() const {
416 return true;
417 }
418
419 template<>
420 inline bool Value::is<Null>() const {
421 return type_ == NULL_;
422 }
423
424 template<>
425 inline bool Value::is<Boolean>() const {
426 return type_ == BOOL_;
427 }
428
429 template<>
430 inline bool Value::is<String>() const {
431 return type_ == STRING_;
432 }
433
434 template<>
435 inline bool Value::is<Number>() const {
436 return type_ == NUMBER_;
437 }
438
439 template<>
440 inline bool Value::is<Array>() const {
441 return type_ == ARRAY_;
442 }
443
444 template<>
445 inline bool Value::is<Object>() const {
446 return type_ == OBJECT_;
447 }
448
449 template<>
450 inline Value& Value::get<Value>() {
451 return *this;
452 }
453
454 template<>
455 inline const Value& Value::get<Value>() const {
456 return *this;
457 }
458
459 template<>
460 inline bool& Value::get<Boolean>() {
461 JSONXX_ASSERT(is<Boolean>());
462 return bool_value_;
463 }
464
465 template<>
466 inline std::string& Value::get<String>() {
467 JSONXX_ASSERT(is<String>());
468 return *string_value_;
469 }
470
471 template<>
472 inline Number& Value::get<Number>() {
473 JSONXX_ASSERT(is<Number>());
474 return number_value_;
475 }
476
477 template<>
478 inline Array& Value::get<Array>() {
479 JSONXX_ASSERT(is<Array>());
480 return *array_value_;
481 }
482
483 template<>
484 inline Object& Value::get<Object>() {
485 JSONXX_ASSERT(is<Object>());
486 return *object_value_;
487 }
488
489 template<>
490 inline const Boolean& Value::get<Boolean>() const {
491 JSONXX_ASSERT(is<Boolean>());
492 return bool_value_;
493 }
494
495 template<>
496 inline const String& Value::get<String>() const {
497 JSONXX_ASSERT(is<String>());
498 return *string_value_;
499 }
500
501 template<>
502 inline const Number& Value::get<Number>() const {
503 JSONXX_ASSERT(is<Number>());
504 return number_value_;
505 }
506
507 template<>
508 inline const Array& Value::get<Array>() const {
509 JSONXX_ASSERT(is<Array>());
510 return *array_value_;
511 }
512
513 template<>
514 inline const Object& Value::get<Object>() const {
515 JSONXX_ASSERT(is<Object>());
516 return *object_value_;
517 }
518
519 template<typename T>
520 inline Object &Object::operator<<(const T &value) {
521 return *this << Value(value), *this;
522 }
523
524 } // namespace jsonxx
525
526 std::ostream& operator<<(std::ostream& stream, const jsonxx::Value& v);
527 std::ostream& operator<<(std::ostream& stream, const jsonxx::Object& v);
528 std::ostream& operator<<(std::ostream& stream, const jsonxx::Array& v);
529