StRoot  1
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Groups Pages
picojson.h
1 /*
2  * Copyright 2009-2010 Cybozu Labs, Inc.
3  * Copyright 2011 Kazuho Oku
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are met:
7  *
8  * 1. Redistributions of source code must retain the above copyright notice,
9  * this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright notice,
11  * this list of conditions and the following disclaimer in the documentation
12  * and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY CYBOZU LABS, INC. ``AS IS'' AND ANY EXPRESS OR
15  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
16  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
17  * EVENT SHALL CYBOZU LABS, INC. OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
18  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
19  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
20  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
21  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
23  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24  *
25  * The views and conclusions contained in the software and documentation are
26  * those of the authors and should not be interpreted as representing official
27  * policies, either expressed or implied, of Cybozu Labs, Inc.
28  *
29  */
30 #ifndef picojson_h
31 #define picojson_h
32 
33 #include <cassert>
34 #include <cmath>
35 #include <cstdio>
36 #include <cstdlib>
37 #include <cstring>
38 #include <iostream>
39 #include <iterator>
40 #include <map>
41 #include <string>
42 #include <vector>
43 
44 #ifdef _MSC_VER
45  #define SNPRINTF _snprintf_s
46  #pragma warning(push)
47  #pragma warning(disable : 4244) // conversion from int to char
48 #else
49  #define SNPRINTF snprintf
50 #endif
51 
52 namespace picojson {
53 
54  enum {
55  null_type,
56  boolean_type,
57  number_type,
58  string_type,
59  array_type,
60  object_type
61  };
62 
63  struct null {};
64 
65  class value {
66  public:
67  typedef std::vector<value> array;
68  typedef std::map<std::string, value> object;
69  protected:
70  int type_;
71  union {
72  bool boolean_;
73  double number_;
74  std::string* string_;
75  array* array_;
76  object* object_;
77  };
78  public:
79  value();
80  value(int type, bool);
81  explicit value(bool b);
82  explicit value(double n);
83  explicit value(const std::string& s);
84  explicit value(const array& a);
85  explicit value(const object& o);
86  explicit value(const char* s);
87  value(const char* s, size_t len);
88  ~value();
89  value(const value& x);
90  value& operator=(const value& x);
91  template <typename T> bool is() const;
92  template <typename T> const T& get() const;
93  template <typename T> T& get();
94  bool evaluate_as_boolean() const;
95  const value& get(size_t idx) const;
96  const value& get(const std::string& key) const;
97  bool contains(size_t idx) const;
98  bool contains(const std::string& key) const;
99  std::string to_str() const;
100  template <typename Iter> void serialize(Iter os) const;
101  std::string serialize() const;
102  private:
103  template <typename T> value(const T*); // intentionally defined to block implicit conversion of pointer to bool
104  };
105 
106  typedef value::array array;
107  typedef value::object object;
108 
109  inline value::value() : type_(null_type) {}
110 
111  inline value::value(int type, bool) : type_(type) {
112  switch (type) {
113 #define INIT(p, v) case p##type: p = v; break
114  INIT(boolean_, false);
115  INIT(number_, 0.0);
116  INIT(string_, new std::string());
117  INIT(array_, new array());
118  INIT(object_, new object());
119 #undef INIT
120  default: break;
121  }
122  }
123 
124  inline value::value(bool b) : type_(boolean_type) {
125  boolean_ = b;
126  }
127 
128  inline value::value(double n) : type_(number_type) {
129  number_ = n;
130  }
131 
132  inline value::value(const std::string& s) : type_(string_type) {
133  string_ = new std::string(s);
134  }
135 
136  inline value::value(const array& a) : type_(array_type) {
137  array_ = new array(a);
138  }
139 
140  inline value::value(const object& o) : type_(object_type) {
141  object_ = new object(o);
142  }
143 
144  inline value::value(const char* s) : type_(string_type) {
145  string_ = new std::string(s);
146  }
147 
148  inline value::value(const char* s, size_t len) : type_(string_type) {
149  string_ = new std::string(s, len);
150  }
151 
152  inline value::~value() {
153  switch (type_) {
154 #define DEINIT(p) case p##type: delete p; break
155  DEINIT(string_);
156  DEINIT(array_);
157  DEINIT(object_);
158 #undef DEINIT
159  default: break;
160  }
161  }
162 
163  inline value::value(const value& x) : type_(x.type_) {
164  switch (type_) {
165 #define INIT(p, v) case p##type: p = v; break
166  INIT(boolean_, x.boolean_);
167  INIT(number_, x.number_);
168  INIT(string_, new std::string(*x.string_));
169  INIT(array_, new array(*x.array_));
170  INIT(object_, new object(*x.object_));
171 #undef INIT
172  default: break;
173  }
174  }
175 
176  inline value& value::operator=(const value& x) {
177  if (this != &x) {
178  this->~value();
179  new (this) value(x);
180  }
181  return *this;
182  }
183 
184 #define IS(ctype, jtype) \
185  template <> inline bool value::is<ctype>() const { \
186  return type_ == jtype##_type; \
187  }
188  IS(null, null)
189  IS(bool, boolean)
190  IS(int, number)
191  IS(double, number)
192  IS(std::string, string)
193  IS(array, array)
194  IS(object, object)
195 #undef IS
196 
197 #define GET(ctype, var) \
198  template <> inline const ctype& value::get<ctype>() const { \
199  assert("type mismatch! call vis<type>() before get<type>()" \
200  && is<ctype>()); \
201  return var; \
202  } \
203  template <> inline ctype& value::get<ctype>() { \
204  assert("type mismatch! call is<type>() before get<type>()" \
205  && is<ctype>()); \
206  return var; \
207  }
208  GET(bool, boolean_)
209  GET(double, number_)
210  GET(std::string, *string_)
211  GET(array, *array_)
212  GET(object, *object_)
213 #undef GET
214 
215  inline bool value::evaluate_as_boolean() const {
216  switch (type_) {
217  case null_type:
218  return false;
219  case boolean_type:
220  return boolean_;
221  case number_type:
222  return number_ != 0;
223  case string_type:
224  return ! string_->empty();
225  default:
226  return true;
227  }
228  }
229 
230  inline const value& value::get(size_t idx) const {
231  static value s_null;
232  assert(is<array>());
233  return idx < array_->size() ? (*array_)[idx] : s_null;
234  }
235 
236  inline const value& value::get(const std::string& key) const {
237  static value s_null;
238  assert(is<object>());
239  object::const_iterator i = object_->find(key);
240  return i != object_->end() ? i->second : s_null;
241  }
242 
243  inline bool value::contains(size_t idx) const {
244  assert(is<array>());
245  return idx < array_->size();
246  }
247 
248  inline bool value::contains(const std::string& key) const {
249  assert(is<object>());
250  object::const_iterator i = object_->find(key);
251  return i != object_->end();
252  }
253 
254  inline std::string value::to_str() const {
255  switch (type_) {
256  case null_type: return "null";
257  case boolean_type: return boolean_ ? "true" : "false";
258  case number_type: {
259  char buf[256];
260  double tmp;
261  SNPRINTF(buf, sizeof(buf), modf(number_, &tmp) == 0 ? "%.f" : "%f", number_);
262  return buf;
263  }
264  case string_type: return *string_;
265  case array_type: return "array";
266  case object_type: return "object";
267  default: assert(0);
268 #ifdef _MSC_VER
269  __assume(0);
270 #endif
271  }
272  }
273 
274  template <typename Iter> void copy(const std::string& s, Iter oi) {
275  std::copy(s.begin(), s.end(), oi);
276  }
277 
278  template <typename Iter> void serialize_str(const std::string& s, Iter oi) {
279  *oi++ = '"';
280  for (std::string::const_iterator i = s.begin(); i != s.end(); ++i) {
281  switch (*i) {
282 #define MAP(val, sym) case val: copy(sym, oi); break
283  MAP('"', "\\\"");
284  MAP('\\', "\\\\");
285  MAP('/', "\\/");
286  MAP('\b', "\\b");
287  MAP('\f', "\\f");
288  MAP('\n', "\\n");
289  MAP('\r', "\\r");
290  MAP('\t', "\\t");
291 #undef MAP
292  default:
293  if ((unsigned char)*i < 0x20 || *i == 0x7f) {
294  char buf[7];
295  SNPRINTF(buf, sizeof(buf), "\\u%04x", *i & 0xff);
296  copy(buf, buf + 6, oi);
297  } else {
298  *oi++ = *i;
299  }
300  break;
301  }
302  }
303  *oi++ = '"';
304  }
305 
306  template <typename Iter> void value::serialize(Iter oi) const {
307  switch (type_) {
308  case string_type:
309  serialize_str(*string_, oi);
310  break;
311  case array_type: {
312  *oi++ = '[';
313  for (array::const_iterator i = array_->begin(); i != array_->end(); ++i) {
314  if (i != array_->begin()) {
315  *oi++ = ',';
316  }
317  i->serialize(oi);
318  }
319  *oi++ = ']';
320  break;
321  }
322  case object_type: {
323  *oi++ = '{';
324  for (object::const_iterator i = object_->begin();
325  i != object_->end();
326  ++i) {
327  if (i != object_->begin()) {
328  *oi++ = ',';
329  }
330  serialize_str(i->first, oi);
331  *oi++ = ':';
332  i->second.serialize(oi);
333  }
334  *oi++ = '}';
335  break;
336  }
337  default:
338  copy(to_str(), oi);
339  break;
340  }
341  }
342 
343  inline std::string value::serialize() const {
344  std::string s;
345  serialize(std::back_inserter(s));
346  return s;
347  }
348 
349  template <typename Iter> class input {
350  protected:
351  Iter cur_, end_;
352  int last_ch_;
353  bool ungot_;
354  int line_;
355  public:
356  input(const Iter& first, const Iter& last) : cur_(first), end_(last), last_ch_(-1), ungot_(false), line_(1) {}
357  int getc() {
358  if (ungot_) {
359  ungot_ = false;
360  return last_ch_;
361  }
362  if (cur_ == end_) {
363  last_ch_ = -1;
364  return -1;
365  }
366  if (last_ch_ == '\n') {
367  line_++;
368  }
369  last_ch_ = *cur_++ & 0xff;
370  return last_ch_;
371  }
372  void ungetc() {
373  if (last_ch_ != -1) {
374  assert(! ungot_);
375  ungot_ = true;
376  }
377  }
378  Iter cur() const { return cur_; }
379  int line() const { return line_; }
380  void skip_ws() {
381  while (1) {
382  int ch = getc();
383  if (! (ch == ' ' || ch == '\t' || ch == '\n' || ch == '\r')) {
384  ungetc();
385  break;
386  }
387  }
388  }
389  int expect(int expect) {
390  skip_ws();
391  if (getc() != expect) {
392  ungetc();
393  return false;
394  }
395  return true;
396  }
397  bool match(const std::string& pattern) {
398  for (std::string::const_iterator pi(pattern.begin());
399  pi != pattern.end();
400  ++pi) {
401  if (getc() != *pi) {
402  ungetc();
403  return false;
404  }
405  }
406  return true;
407  }
408  };
409 
410  template<typename Iter> inline int _parse_quadhex(input<Iter> &in) {
411  int uni_ch = 0, hex;
412  for (int i = 0; i < 4; i++) {
413  if ((hex = in.getc()) == -1) {
414  return -1;
415  }
416  if ('0' <= hex && hex <= '9') {
417  hex -= '0';
418  } else if ('A' <= hex && hex <= 'F') {
419  hex -= 'A' - 0xa;
420  } else if ('a' <= hex && hex <= 'f') {
421  hex -= 'a' - 0xa;
422  } else {
423  in.ungetc();
424  return -1;
425  }
426  uni_ch = uni_ch * 16 + hex;
427  }
428  return uni_ch;
429  }
430 
431  template<typename String, typename Iter> inline bool _parse_codepoint(String& out, input<Iter>& in) {
432  int uni_ch;
433  if ((uni_ch = _parse_quadhex(in)) == -1) {
434  return false;
435  }
436  if (0xd800 <= uni_ch && uni_ch <= 0xdfff) {
437  if (0xdc00 <= uni_ch) {
438  // a second 16-bit of a surrogate pair appeared
439  return false;
440  }
441  // first 16-bit of surrogate pair, get the next one
442  if (in.getc() != '\\' || in.getc() != 'u') {
443  in.ungetc();
444  return false;
445  }
446  int second = _parse_quadhex(in);
447  if (! (0xdc00 <= second && second <= 0xdfff)) {
448  return false;
449  }
450  uni_ch = ((uni_ch - 0xd800) << 10) | ((second - 0xdc00) & 0x3ff);
451  uni_ch += 0x10000;
452  }
453  if (uni_ch < 0x80) {
454  out.push_back(uni_ch);
455  } else {
456  if (uni_ch < 0x800) {
457  out.push_back(0xc0 | (uni_ch >> 6));
458  } else {
459  if (uni_ch < 0x10000) {
460  out.push_back(0xe0 | (uni_ch >> 12));
461  } else {
462  out.push_back(0xf0 | (uni_ch >> 18));
463  out.push_back(0x80 | ((uni_ch >> 12) & 0x3f));
464  }
465  out.push_back(0x80 | ((uni_ch >> 6) & 0x3f));
466  }
467  out.push_back(0x80 | (uni_ch & 0x3f));
468  }
469  return true;
470  }
471 
472  template<typename String, typename Iter> inline bool _parse_string(String& out, input<Iter>& in) {
473  while (1) {
474  int ch = in.getc();
475  if (ch < ' ') {
476  in.ungetc();
477  return false;
478  } else if (ch == '"') {
479  return true;
480  } else if (ch == '\\') {
481  if ((ch = in.getc()) == -1) {
482  return false;
483  }
484  switch (ch) {
485 #define MAP(sym, val) case sym: out.push_back(val); break
486  MAP('"', '\"');
487  MAP('\\', '\\');
488  MAP('/', '/');
489  MAP('b', '\b');
490  MAP('f', '\f');
491  MAP('n', '\n');
492  MAP('r', '\r');
493  MAP('t', '\t');
494 #undef MAP
495  case 'u':
496  if (! _parse_codepoint(out, in)) {
497  return false;
498  }
499  break;
500  default:
501  return false;
502  }
503  } else {
504  out.push_back(ch);
505  }
506  }
507  return false;
508  }
509 
510  template <typename Context, typename Iter> inline bool _parse_array(Context& ctx, input<Iter>& in) {
511  if (! ctx.parse_array_start()) {
512  return false;
513  }
514  if (in.expect(']')) {
515  return true;
516  }
517  size_t idx = 0;
518  do {
519  if (! ctx.parse_array_item(in, idx)) {
520  return false;
521  }
522  idx++;
523  } while (in.expect(','));
524  return in.expect(']');
525  }
526 
527  template <typename Context, typename Iter> inline bool _parse_object(Context& ctx, input<Iter>& in) {
528  if (! ctx.parse_object_start()) {
529  return false;
530  }
531  if (in.expect('}')) {
532  return true;
533  }
534  do {
535  std::string key;
536  if (! in.expect('"')
537  || ! _parse_string(key, in)
538  || ! in.expect(':')) {
539  return false;
540  }
541  if (! ctx.parse_object_item(in, key)) {
542  return false;
543  }
544  } while (in.expect(','));
545  return in.expect('}');
546  }
547 
548  template <typename Iter> inline bool _parse_number(double& out, input<Iter>& in) {
549  std::string num_str;
550  while (1) {
551  int ch = in.getc();
552  if (('0' <= ch && ch <= '9') || ch == '+' || ch == '-' || ch == '.'
553  || ch == 'e' || ch == 'E') {
554  num_str.push_back(ch);
555  } else {
556  in.ungetc();
557  break;
558  }
559  }
560  char* endp;
561  out = strtod(num_str.c_str(), &endp);
562  return endp == num_str.c_str() + num_str.size();
563  }
564 
565  template <typename Context, typename Iter> inline bool _parse(Context& ctx, input<Iter>& in) {
566  in.skip_ws();
567  int ch = in.getc();
568  switch (ch) {
569 #define IS(ch, text, op) case ch: \
570  if (in.match(text) && op) { \
571  return true; \
572  } else { \
573  return false; \
574  }
575  IS('n', "ull", ctx.set_null());
576  IS('f', "alse", ctx.set_bool(false));
577  IS('t', "rue", ctx.set_bool(true));
578 #undef IS
579  case '"':
580  return ctx.parse_string(in);
581  case '[':
582  return _parse_array(ctx, in);
583  case '{':
584  return _parse_object(ctx, in);
585  default:
586  if (('0' <= ch && ch <= '9') || ch == '-') {
587  in.ungetc();
588  double f;
589  if (_parse_number(f, in)) {
590  ctx.set_number(f);
591  return true;
592  } else {
593  return false;
594  }
595  }
596  break;
597  }
598  in.ungetc();
599  return false;
600  }
601 
603  public:
604  bool set_null() { return false; }
605  bool set_bool(bool) { return false; }
606  bool set_number(double) { return false; }
607  template <typename Iter> bool parse_string(input<Iter>&) { return false; }
608  bool parse_array_start() { return false; }
609  template <typename Iter> bool parse_array_item(input<Iter>&, size_t) {
610  return false;
611  }
612  bool parse_object_start() { return false; }
613  template <typename Iter> bool parse_object_item(input<Iter>&, const std::string&) {
614  return false;
615  }
616  };
617 
619  protected:
620  value* out_;
621  public:
622  default_parse_context(value* out) : out_(out) {}
623  bool set_null() {
624  *out_ = value();
625  return true;
626  }
627  bool set_bool(bool b) {
628  *out_ = value(b);
629  return true;
630  }
631  bool set_number(double f) {
632  *out_ = value(f);
633  return true;
634  }
635  template<typename Iter> bool parse_string(input<Iter>& in) {
636  *out_ = value(string_type, false);
637  return _parse_string(out_->get<std::string>(), in);
638  }
639  bool parse_array_start() {
640  *out_ = value(array_type, false);
641  return true;
642  }
643  template <typename Iter> bool parse_array_item(input<Iter>& in, size_t) {
644  array& a = out_->get<array>();
645  a.push_back(value());
646  default_parse_context ctx(&a.back());
647  return _parse(ctx, in);
648  }
649  bool parse_object_start() {
650  *out_ = value(object_type, false);
651  return true;
652  }
653  template <typename Iter> bool parse_object_item(input<Iter>& in, const std::string& key) {
654  object& o = out_->get<object>();
655  default_parse_context ctx(&o[key]);
656  return _parse(ctx, in);
657  }
658  private:
660  default_parse_context& operator=(const default_parse_context&);
661  };
662 
664  public:
665  struct dummy_str {
666  void push_back(int) {}
667  };
668  public:
669  null_parse_context() {}
670  bool set_null() { return true; }
671  bool set_bool(bool) { return true; }
672  bool set_number(double) { return true; }
673  template <typename Iter> bool parse_string(input<Iter>& in) {
674  dummy_str s;
675  return _parse_string(s, in);
676  }
677  bool parse_array_start() { return true; }
678  template <typename Iter> bool parse_array_item(input<Iter>& in, size_t) {
679  return _parse(*this, in);
680  }
681  bool parse_object_start() { return true; }
682  template <typename Iter> bool parse_object_item(input<Iter>& in, const std::string&) {
683  return _parse(*this, in);
684  }
685  private:
686  null_parse_context(const null_parse_context&);
687  null_parse_context& operator=(const null_parse_context&);
688  };
689 
690  // obsolete, use the version below
691  template <typename Iter> inline std::string parse(value& out, Iter& pos, const Iter& last) {
692  std::string err;
693  pos = parse(out, pos, last, &err);
694  return err;
695  }
696 
697  template <typename Context, typename Iter> inline Iter _parse(Context& ctx, const Iter& first, const Iter& last, std::string* err) {
698  input<Iter> in(first, last);
699  if (! _parse(ctx, in) && err != NULL) {
700  char buf[64];
701  SNPRINTF(buf, sizeof(buf), "syntax error at line %d near: ", in.line());
702  *err = buf;
703  while (1) {
704  int ch = in.getc();
705  if (ch == -1 || ch == '\n') {
706  break;
707  } else if (ch >= ' ') {
708  err->push_back(ch);
709  }
710  }
711  }
712  return in.cur();
713  }
714 
715  template <typename Iter> inline Iter parse(value& out, const Iter& first, const Iter& last, std::string* err) {
716  default_parse_context ctx(&out);
717  return _parse(ctx, first, last, err);
718  }
719 
720  inline std::string parse(value& out, std::istream& is) {
721  std::string err;
722  parse(out, std::istreambuf_iterator<char>(is.rdbuf()),
723  std::istreambuf_iterator<char>(), &err);
724  return err;
725  }
726 
727  template <typename T> struct last_error_t {
728  static std::string s;
729  };
730  template <typename T> std::string last_error_t<T>::s;
731 
732  inline void set_last_error(const std::string& s) {
734  }
735 
736  inline const std::string& get_last_error() {
737  return last_error_t<bool>::s;
738  }
739 
740  inline bool operator==(const value& x, const value& y) {
741  if (x.is<null>())
742  return y.is<null>();
743 #define PICOJSON_CMP(type) \
744  if (x.is<type>()) \
745  return y.is<type>() && x.get<type>() == y.get<type>()
746  PICOJSON_CMP(bool);
747  PICOJSON_CMP(double);
748  PICOJSON_CMP(std::string);
749  PICOJSON_CMP(array);
750  PICOJSON_CMP(object);
751 #undef PICOJSON_CMP
752  assert(0);
753 #ifdef _MSC_VER
754  __assume(0);
755 #endif
756  return false;
757  }
758 
759  inline bool operator!=(const value& x, const value& y) {
760  return ! (x == y);
761  }
762 }
763 
764 inline std::istream& operator>>(std::istream& is, picojson::value& x)
765 {
766  picojson::set_last_error(std::string());
767  std::string err = picojson::parse(x, is);
768  if (! err.empty()) {
769  picojson::set_last_error(err);
770  is.setstate(std::ios::failbit);
771  }
772  return is;
773 }
774 
775 inline std::ostream& operator<<(std::ostream& os, const picojson::value& x)
776 {
777  x.serialize(std::ostream_iterator<char>(os));
778  return os;
779 }
780 #ifdef _MSC_VER
781  #pragma warning(pop)
782 #endif
783 
784 #endif
785 #ifdef TEST_PICOJSON
786 #ifdef _MSC_VER
787  #pragma warning(disable : 4127) // conditional expression is constant
788 #endif
789 
790 using namespace std;
791 
792 static void plan(int num)
793 {
794  printf("1..%d\n", num);
795 }
796 
797 static bool success = true;
798 
799 static void ok(bool b, const char* name = "")
800 {
801  static int n = 1;
802  if (! b)
803  success = false;
804  printf("%s %d - %s\n", b ? "ok" : "ng", n++, name);
805 }
806 
807 template <typename T> void is(const T& x, const T& y, const char* name = "")
808 {
809  if (x == y) {
810  ok(true, name);
811  } else {
812  ok(false, name);
813  }
814 }
815 
816 #include <algorithm>
817 
818 int main(void)
819 {
820  plan(75);
821 
822  // constructors
823 #define TEST(expr, expected) \
824  is(picojson::value expr .serialize(), string(expected), "picojson::value" #expr)
825 
826  TEST( (true), "true");
827  TEST( (false), "false");
828  TEST( (42.0), "42");
829  TEST( (string("hello")), "\"hello\"");
830  TEST( ("hello"), "\"hello\"");
831  TEST( ("hello", 4), "\"hell\"");
832 
833 #undef TEST
834 
835 #define TEST(in, type, cmp, serialize_test) { \
836  picojson::value v; \
837  const char* s = in; \
838  string err = picojson::parse(v, s, s + strlen(s)); \
839  ok(err.empty(), in " no error"); \
840  ok(v.is<type>(), in " check type"); \
841  is<type>(v.get<type>(), cmp, in " correct output"); \
842  is(*s, '\0', in " read to eof"); \
843  if (serialize_test) { \
844  is(v.serialize(), string(in), in " serialize"); \
845  } \
846  }
847  TEST("false", bool, false, true);
848  TEST("true", bool, true, true);
849  TEST("90.5", double, 90.5, false);
850  TEST("\"hello\"", string, string("hello"), true);
851  TEST("\"\\\"\\\\\\/\\b\\f\\n\\r\\t\"", string, string("\"\\/\b\f\n\r\t"),
852  true);
853  TEST("\"\\u0061\\u30af\\u30ea\\u30b9\"", string,
854  string("a\xe3\x82\xaf\xe3\x83\xaa\xe3\x82\xb9"), false);
855  TEST("\"\\ud840\\udc0b\"", string, string("\xf0\xa0\x80\x8b"), false);
856 #undef TEST
857 
858 #define TEST(type, expr) { \
859  picojson::value v; \
860  const char *s = expr; \
861  string err = picojson::parse(v, s, s + strlen(s)); \
862  ok(err.empty(), "empty " #type " no error"); \
863  ok(v.is<picojson::type>(), "empty " #type " check type"); \
864  ok(v.get<picojson::type>().empty(), "check " #type " array size"); \
865  }
866  TEST(array, "[]");
867  TEST(object, "{}");
868 #undef TEST
869 
870  {
871  picojson::value v;
872  const char *s = "[1,true,\"hello\"]";
873  string err = picojson::parse(v, s, s + strlen(s));
874  ok(err.empty(), "array no error");
875  ok(v.is<picojson::array>(), "array check type");
876  is(v.get<picojson::array>().size(), size_t(3), "check array size");
877  ok(v.contains(0), "check contains array[0]");
878  ok(v.get(0).is<double>(), "check array[0] type");
879  is(v.get(0).get<double>(), 1.0, "check array[0] value");
880  ok(v.contains(1), "check contains array[1]");
881  ok(v.get(1).is<bool>(), "check array[1] type");
882  ok(v.get(1).get<bool>(), "check array[1] value");
883  ok(v.contains(2), "check contains array[2]");
884  ok(v.get(2).is<string>(), "check array[2] type");
885  is(v.get(2).get<string>(), string("hello"), "check array[2] value");
886  ok(!v.contains(3), "check not contains array[3]");
887  }
888 
889  {
890  picojson::value v;
891  const char *s = "{ \"a\": true }";
892  string err = picojson::parse(v, s, s + strlen(s));
893  ok(err.empty(), "object no error");
894  ok(v.is<picojson::object>(), "object check type");
895  is(v.get<picojson::object>().size(), size_t(1), "check object size");
896  ok(v.contains("a"), "check contains property");
897  ok(v.get("a").is<bool>(), "check bool property exists");
898  is(v.get("a").get<bool>(), true, "check bool property value");
899  is(v.serialize(), string("{\"a\":true}"), "serialize object");
900  ok(!v.contains("z"), "check not contains property");
901  }
902 
903 #define TEST(json, msg) do { \
904  picojson::value v; \
905  const char *s = json; \
906  string err = picojson::parse(v, s, s + strlen(s)); \
907  is(err, string("syntax error at line " msg), msg); \
908  } while (0)
909  TEST("falsoa", "1 near: oa");
910  TEST("{]", "1 near: ]");
911  TEST("\n\bbell", "2 near: bell");
912  TEST("\"abc\nd\"", "1 near: ");
913 #undef TEST
914 
915  {
916  picojson::value v1, v2;
917  const char *s;
918  string err;
919  s = "{ \"b\": true, \"a\": [1,2,\"three\"], \"d\": 2 }";
920  err = picojson::parse(v1, s, s + strlen(s));
921  s = "{ \"d\": 2.0, \"b\": true, \"a\": [1,2,\"three\"] }";
922  err = picojson::parse(v2, s, s + strlen(s));
923  ok((v1 == v2), "check == operator in deep comparison");
924  }
925 
926  {
927  picojson::value v1, v2;
928  const char *s;
929  string err;
930  s = "{ \"b\": true, \"a\": [1,2,\"three\"], \"d\": 2 }";
931  err = picojson::parse(v1, s, s + strlen(s));
932  s = "{ \"d\": 2.0, \"a\": [1,\"three\"], \"b\": true }";
933  err = picojson::parse(v2, s, s + strlen(s));
934  ok((v1 != v2), "check != operator for array in deep comparison");
935  }
936 
937  {
938  picojson::value v1, v2;
939  const char *s;
940  string err;
941  s = "{ \"b\": true, \"a\": [1,2,\"three\"], \"d\": 2 }";
942  err = picojson::parse(v1, s, s + strlen(s));
943  s = "{ \"d\": 2.0, \"a\": [1,2,\"three\"], \"b\": false }";
944  err = picojson::parse(v2, s, s + strlen(s));
945  ok((v1 != v2), "check != operator for object in deep comparison");
946  }
947 
948  {
949  picojson::value v1, v2;
950  const char *s;
951  string err;
952  s = "{ \"b\": true, \"a\": [1,2,\"three\"], \"d\": 2 }";
953  err = picojson::parse(v1, s, s + strlen(s));
954  picojson::object& o = v1.get<picojson::object>();
955  o.erase("b");
956  picojson::array& a = o["a"].get<picojson::array>();
957  picojson::array::iterator i;
958  i = std::remove(a.begin(), a.end(), picojson::value(std::string("three")));
959  a.erase(i, a.end());
960  s = "{ \"a\": [1,2], \"d\": 2 }";
961  err = picojson::parse(v2, s, s + strlen(s));
962  ok((v1 == v2), "check erase()");
963  }
964 
965  ok(picojson::value(3.0).serialize() == "3",
966  "integral number should be serialized as a integer");
967 
968  {
969  const char* s = "{ \"a\": [1,2], \"d\": 2 }";
971  string err;
972  picojson::_parse(ctx, s, s + strlen(s), &err);
973  ok(err.empty(), "null_parse_context");
974  }
975 
976  return success ? 0 : 1;
977 }
978 
979 #endif