1 /*
2 * Copyright 2009-2010 Cybozu Labs, Inc.
3 * Copyright 2011-2014 Kazuho Oku
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions are met:
8 *
9 * 1. Redistributions of source code must retain the above copyright notice,
10 * this list of conditions and the following disclaimer.
11 *
12 * 2. Redistributions in binary form must reproduce the above copyright notice,
13 * this list of conditions and the following disclaimer in the documentation
14 * and/or other materials provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
20 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26 * POSSIBILITY OF SUCH DAMAGE.
27 */
28 #ifndef picojson_h
29 #define picojson_h
30
31 #include <algorithm>
32 #include <cstdio>
33 #include <cstdlib>
34 #include <cstring>
35 #include <iostream>
36 #include <iterator>
37 #include <limits>
38 #include <map>
39 #include <stdexcept>
40 #include <string>
41 #include <vector>
42
43 // for isnan/isinf
44 #if __cplusplus>=201103L
45 # include <cmath>
46 #else
47 extern "C" {
48 # ifdef _MSC_VER
49 # include <float.h>
50 # elif defined(__INTEL_COMPILER)
51 # include <mathimf.h>
52 # else
53 # include <math.h>
54 # endif
55 }
56 #endif
57
58 // experimental support for int64_t (see README.mkdn for detail)
59 #ifdef PICOJSON_USE_INT64
60 # define __STDC_FORMAT_MACROS
61 # include <errno.h>
62 # include <inttypes.h>
63 #endif
64
65 // to disable the use of localeconv(3), set PICOJSON_USE_LOCALE to 0
66 #ifndef PICOJSON_USE_LOCALE
67 # define PICOJSON_USE_LOCALE 1
68 #endif
69 #if PICOJSON_USE_LOCALE
70 extern "C" {
71 # include <locale.h>
72 }
73 #endif
74
75 #ifndef PICOJSON_ASSERT
76 # define PICOJSON_ASSERT(e) do { if (! (e)) throw std::runtime_error(#e); } while (0)
77 #endif
78
79 #ifdef _MSC_VER
80 #define SNPRINTF _snprintf_s
81 #pragma warning(push)
82 #pragma warning(disable : 4244) // conversion from int to char
83 #pragma warning(disable : 4127) // conditional expression is constant
84 #pragma warning(disable : 4702) // unreachable code
85 #else
86 #define SNPRINTF snprintf
87 #endif
88
89 namespace picojson
90 {
91
92 enum {
93 null_type,
94 boolean_type,
95 number_type,
96 string_type,
97 array_type,
98 object_type
99 #ifdef PICOJSON_USE_INT64
100 , int64_type
101 #endif
102 };
103
104 enum {
105 INDENT_WIDTH = 2
106 };
107
108 struct null {};
109
110 class value
111 {
112 public:
113 typedef std::vector<value> array;
114 typedef std::map<std::string, value> object;
115 union _storage {
116 bool boolean_;
117 double number_;
118 #ifdef PICOJSON_USE_INT64
119 int64_t int64_;
120 #endif
121 std::string* string_;
122 array* array_;
123 object* object_;
124 };
125 protected:
126 int type_;
127 _storage u_;
128 public:
129 value();
130 value(int type, bool);
131 explicit value(bool b);
132 #ifdef PICOJSON_USE_INT64
133 explicit value(int64_t i);
134 #endif
135 explicit value(double n);
136 explicit value(const std::string& s);
137 explicit value(const array& a);
138 explicit value(const object& o);
139 explicit value(const char* s);
140 value(const char* s, size_t len);
141 ~value();
142 value(const value& x);
143 value& operator=(const value& x);
144 void swap(value& x);
145 template <typename T> bool is() const;
146 template <typename T> const T& get() const;
147 template <typename T> T& get();
148 bool evaluate_as_boolean() const;
149 const value& get(size_t idx) const;
150 const value& get(const std::string& key) const;
151 value& get(size_t idx);
152 value& get(const std::string& key);
153
154 bool contains(size_t idx) const;
155 bool contains(const std::string& key) const;
156 std::string to_str() const;
157 template <typename Iter> void serialize(Iter os, bool prettify = false) const;
158 std::string serialize(bool prettify = false) const;
159 private:
160 template <typename T> value(const T*); // intentionally defined to block implicit conversion of pointer to bool
161 template <typename Iter> static void _indent(Iter os, int indent);
162 template <typename Iter> void _serialize(Iter os, int indent) const;
163 std::string _serialize(int indent) const;
164 };
165
166 typedef value::array array;
167 typedef value::object object;
168
value()169 inline value::value() : type_(null_type) {}
170
value(int type,bool)171 inline value::value(int type, bool) : type_(type)
172 {
173 switch (type) {
174 #define INIT(p, v) case p##type: u_.p = v; break
175 INIT(boolean_, false);
176 INIT(number_, 0.0);
177 #ifdef PICOJSON_USE_INT64
178 INIT(int64_, 0);
179 #endif
180 INIT(string_, new std::string());
181 INIT(array_, new array());
182 INIT(object_, new object());
183 #undef INIT
184 default:
185 break;
186 }
187 }
188
value(bool b)189 inline value::value(bool b) : type_(boolean_type)
190 {
191 u_.boolean_ = b;
192 }
193
194 #ifdef PICOJSON_USE_INT64
value(int64_t i)195 inline value::value(int64_t i) : type_(int64_type)
196 {
197 u_.int64_ = i;
198 }
199 #endif
200
value(double n)201 inline value::value(double n) : type_(number_type)
202 {
203 if (
204 #ifdef _MSC_VER
205 ! _finite(n)
206 #elif __cplusplus>=201103L || !(defined(isnan) && defined(isinf))
207 std::isnan(n) || std::isinf(n)
208 #else
209 isnan(n) || isinf(n)
210 #endif
211 ) {
212 throw std::overflow_error("");
213 }
214 u_.number_ = n;
215 }
216
value(const std::string & s)217 inline value::value(const std::string& s) : type_(string_type)
218 {
219 u_.string_ = new std::string(s);
220 }
221
value(const array & a)222 inline value::value(const array& a) : type_(array_type)
223 {
224 u_.array_ = new array(a);
225 }
226
value(const object & o)227 inline value::value(const object& o) : type_(object_type)
228 {
229 u_.object_ = new object(o);
230 }
231
value(const char * s)232 inline value::value(const char* s) : type_(string_type)
233 {
234 u_.string_ = new std::string(s);
235 }
236
value(const char * s,size_t len)237 inline value::value(const char* s, size_t len) : type_(string_type)
238 {
239 u_.string_ = new std::string(s, len);
240 }
241
~value()242 inline value::~value()
243 {
244 switch (type_) {
245 #define DEINIT(p) case p##type: delete u_.p; break
246 DEINIT(string_);
247 DEINIT(array_);
248 DEINIT(object_);
249 #undef DEINIT
250 default:
251 break;
252 }
253 }
254
value(const value & x)255 inline value::value(const value& x) : type_(x.type_)
256 {
257 switch (type_) {
258 #define INIT(p, v) case p##type: u_.p = v; break
259 INIT(string_, new std::string(*x.u_.string_));
260 INIT(array_, new array(*x.u_.array_));
261 INIT(object_, new object(*x.u_.object_));
262 #undef INIT
263 default:
264 u_ = x.u_;
265 break;
266 }
267 }
268
operator =(const value & x)269 inline value& value::operator=(const value& x)
270 {
271 if (this != &x) {
272 this->~value();
273 new (this) value(x);
274 }
275 return *this;
276 }
277
swap(value & x)278 inline void value::swap(value& x)
279 {
280 std::swap(type_, x.type_);
281 std::swap(u_, x.u_);
282 }
283
284 #define IS(ctype, jtype) \
285 template <> inline bool value::is<ctype>() const { \
286 return type_ == jtype##_type; \
287 }
IS(null,null)288 IS(null, null)
289 IS(bool, boolean)
290 #ifdef PICOJSON_USE_INT64
291 IS(int64_t, int64)
292 #endif
293 IS(std::string, string)
294 IS(array, array)
295 IS(object, object)
296 #undef IS
297 template <> inline bool value::is<double>() const
298 {
299 return type_ == number_type
300 #ifdef PICOJSON_USE_INT64
301 || type_ == int64_type
302 #endif
303 ;
304 }
305
306 #define GET(ctype, var) \
307 template <> inline const ctype& value::get<ctype>() const { \
308 PICOJSON_ASSERT("type mismatch! call is<type>() before get<type>()" \
309 && is<ctype>()); \
310 return var; \
311 } \
312 template <> inline ctype& value::get<ctype>() { \
313 PICOJSON_ASSERT("type mismatch! call is<type>() before get<type>()" \
314 && is<ctype>()); \
315 return var; \
316 }
317 GET(bool, u_.boolean_)
318 GET(std::string, *u_.string_)
319 GET(array, *u_.array_)
320 GET(object, *u_.object_)
321 #ifdef PICOJSON_USE_INT64
322 GET(double, (type_ == int64_type && (const_cast<value*>(this)->type_ = number_type, const_cast<value*>(this)->u_.number_ = u_.int64_), u_.number_))
323 GET(int64_t, u_.int64_)
324 #else
325 GET(double, u_.number_)
326 #endif
327 #undef GET
328
evaluate_as_boolean() const329 inline bool value::evaluate_as_boolean() const
330 {
331 switch (type_) {
332 case null_type:
333 return false;
334 case boolean_type:
335 return u_.boolean_;
336 case number_type:
337 return u_.number_ != 0;
338 case string_type:
339 return ! u_.string_->empty();
340 default:
341 return true;
342 }
343 }
344
get(size_t idx) const345 inline const value& value::get(size_t idx) const
346 {
347 static value s_null;
348 PICOJSON_ASSERT(is<array>());
349 return idx < u_.array_->size() ? (*u_.array_)[idx] : s_null;
350 }
351
get(size_t idx)352 inline value& value::get(size_t idx)
353 {
354 static value s_null;
355 PICOJSON_ASSERT(is<array>());
356 return idx < u_.array_->size() ? (*u_.array_)[idx] : s_null;
357 }
358
get(const std::string & key) const359 inline const value& value::get(const std::string& key) const
360 {
361 static value s_null;
362 PICOJSON_ASSERT(is<object>());
363 object::const_iterator i = u_.object_->find(key);
364 return i != u_.object_->end() ? i->second : s_null;
365 }
366
get(const std::string & key)367 inline value& value::get(const std::string& key)
368 {
369 static value s_null;
370 PICOJSON_ASSERT(is<object>());
371 object::iterator i = u_.object_->find(key);
372 return i != u_.object_->end() ? i->second : s_null;
373 }
374
contains(size_t idx) const375 inline bool value::contains(size_t idx) const
376 {
377 PICOJSON_ASSERT(is<array>());
378 return idx < u_.array_->size();
379 }
380
contains(const std::string & key) const381 inline bool value::contains(const std::string& key) const
382 {
383 PICOJSON_ASSERT(is<object>());
384 object::const_iterator i = u_.object_->find(key);
385 return i != u_.object_->end();
386 }
387
to_str() const388 inline std::string value::to_str() const
389 {
390 switch (type_) {
391 case null_type:
392 return "null";
393 case boolean_type:
394 return u_.boolean_ ? "true" : "false";
395 #ifdef PICOJSON_USE_INT64
396 case int64_type: {
397 char buf[sizeof("-9223372036854775808")];
398 SNPRINTF(buf, sizeof(buf), "%" PRId64, u_.int64_);
399 return buf;
400 }
401 #endif
402 case number_type: {
403 char buf[256];
404 double tmp;
405 SNPRINTF(buf, sizeof(buf), fabs(u_.number_) < (1ULL << 53) && modf(u_.number_, &tmp) == 0 ? "%.f" : "%.17g", u_.number_);
406 #if PICOJSON_USE_LOCALE
407 char *decimal_point = localeconv()->decimal_point;
408 if (strcmp(decimal_point, ".") != 0) {
409 size_t decimal_point_len = strlen(decimal_point);
410 for (char *p = buf; *p != '\0'; ++p) {
411 if (strncmp(p, decimal_point, decimal_point_len) == 0) {
412 return std::string(buf, p) + "." + (p + decimal_point_len);
413 }
414 }
415 }
416 #endif
417 return buf;
418 }
419 case string_type:
420 return *u_.string_;
421 case array_type:
422 return "array";
423 case object_type:
424 return "object";
425 default:
426 PICOJSON_ASSERT(0);
427 #ifdef _MSC_VER
428 __assume(0);
429 #endif
430 }
431 return std::string();
432 }
433
copy(const std::string & s,Iter oi)434 template <typename Iter> void copy(const std::string& s, Iter oi)
435 {
436 std::copy(s.begin(), s.end(), oi);
437 }
438
serialize_str(const std::string & s,Iter oi)439 template <typename Iter> void serialize_str(const std::string& s, Iter oi)
440 {
441 *oi++ = '"';
442 for (std::string::const_iterator i = s.begin(); i != s.end(); ++i) {
443 switch (*i) {
444 #define MAP(val, sym) case val: copy(sym, oi); break
445 MAP('"', "\\\"");
446 MAP('\\', "\\\\");
447 MAP('/', "\\/");
448 MAP('\b', "\\b");
449 MAP('\f', "\\f");
450 MAP('\n', "\\n");
451 MAP('\r', "\\r");
452 MAP('\t', "\\t");
453 #undef MAP
454 default:
455 if (static_cast<unsigned char>(*i) < 0x20 || *i == 0x7f) {
456 char buf[7];
457 SNPRINTF(buf, sizeof(buf), "\\u%04x", *i & 0xff);
458 copy(buf, buf + 6, oi);
459 } else {
460 *oi++ = *i;
461 }
462 break;
463 }
464 }
465 *oi++ = '"';
466 }
467
serialize(Iter oi,bool prettify) const468 template <typename Iter> void value::serialize(Iter oi, bool prettify) const
469 {
470 return _serialize(oi, prettify ? 0 : -1);
471 }
472
serialize(bool prettify) const473 inline std::string value::serialize(bool prettify) const
474 {
475 return _serialize(prettify ? 0 : -1);
476 }
477
_indent(Iter oi,int indent)478 template <typename Iter> void value::_indent(Iter oi, int indent)
479 {
480 *oi++ = '\n';
481 for (int i = 0; i < indent * INDENT_WIDTH; ++i) {
482 *oi++ = ' ';
483 }
484 }
485
_serialize(Iter oi,int indent) const486 template <typename Iter> void value::_serialize(Iter oi, int indent) const
487 {
488 switch (type_) {
489 case string_type:
490 serialize_str(*u_.string_, oi);
491 break;
492 case array_type: {
493 *oi++ = '[';
494 if (indent != -1) {
495 ++indent;
496 }
497 for (array::const_iterator i = u_.array_->begin();
498 i != u_.array_->end();
499 ++i) {
500 if (i != u_.array_->begin()) {
501 *oi++ = ',';
502 }
503 if (indent != -1) {
504 _indent(oi, indent);
505 }
506 i->_serialize(oi, indent);
507 }
508 if (indent != -1) {
509 --indent;
510 if (! u_.array_->empty()) {
511 _indent(oi, indent);
512 }
513 }
514 *oi++ = ']';
515 break;
516 }
517 case object_type: {
518 *oi++ = '{';
519 if (indent != -1) {
520 ++indent;
521 }
522 for (object::const_iterator i = u_.object_->begin();
523 i != u_.object_->end();
524 ++i) {
525 if (i != u_.object_->begin()) {
526 *oi++ = ',';
527 }
528 if (indent != -1) {
529 _indent(oi, indent);
530 }
531 serialize_str(i->first, oi);
532 *oi++ = ':';
533 if (indent != -1) {
534 *oi++ = ' ';
535 }
536 i->second._serialize(oi, indent);
537 }
538 if (indent != -1) {
539 --indent;
540 if (! u_.object_->empty()) {
541 _indent(oi, indent);
542 }
543 }
544 *oi++ = '}';
545 break;
546 }
547 default:
548 copy(to_str(), oi);
549 break;
550 }
551 if (indent == 0) {
552 *oi++ = '\n';
553 }
554 }
555
_serialize(int indent) const556 inline std::string value::_serialize(int indent) const
557 {
558 std::string s;
559 _serialize(std::back_inserter(s), indent);
560 return s;
561 }
562
563 template <typename Iter> class input
564 {
565 protected:
566 Iter cur_, end_;
567 int last_ch_;
568 bool ungot_;
569 int line_;
570 public:
input(const Iter & first,const Iter & last)571 input(const Iter& first, const Iter& last) : cur_(first), end_(last), last_ch_(-1), ungot_(false), line_(1) {}
getc()572 int getc()
573 {
574 if (ungot_) {
575 ungot_ = false;
576 return last_ch_;
577 }
578 if (cur_ == end_) {
579 last_ch_ = -1;
580 return -1;
581 }
582 if (last_ch_ == '\n') {
583 line_++;
584 }
585 last_ch_ = *cur_ & 0xff;
586 ++cur_;
587 return last_ch_;
588 }
ungetc()589 void ungetc()
590 {
591 if (last_ch_ != -1) {
592 PICOJSON_ASSERT(! ungot_);
593 ungot_ = true;
594 }
595 }
cur() const596 Iter cur() const
597 {
598 return cur_;
599 }
line() const600 int line() const
601 {
602 return line_;
603 }
skip_ws()604 void skip_ws()
605 {
606 while (1) {
607 int ch = getc();
608 if (! (ch == ' ' || ch == '\t' || ch == '\n' || ch == '\r')) {
609 ungetc();
610 break;
611 }
612 }
613 }
expect(int expect)614 bool expect(int expect)
615 {
616 skip_ws();
617 if (getc() != expect) {
618 ungetc();
619 return false;
620 }
621 return true;
622 }
match(const std::string & pattern)623 bool match(const std::string& pattern)
624 {
625 for (std::string::const_iterator pi(pattern.begin());
626 pi != pattern.end();
627 ++pi) {
628 if (getc() != *pi) {
629 ungetc();
630 return false;
631 }
632 }
633 return true;
634 }
635 };
636
_parse_quadhex(input<Iter> & in)637 template<typename Iter> inline int _parse_quadhex(input<Iter> &in)
638 {
639 int uni_ch = 0, hex;
640 for (int i = 0; i < 4; i++) {
641 if ((hex = in.getc()) == -1) {
642 return -1;
643 }
644 if ('0' <= hex && hex <= '9') {
645 hex -= '0';
646 } else if ('A' <= hex && hex <= 'F') {
647 hex -= 'A' - 0xa;
648 } else if ('a' <= hex && hex <= 'f') {
649 hex -= 'a' - 0xa;
650 } else {
651 in.ungetc();
652 return -1;
653 }
654 uni_ch = uni_ch * 16 + hex;
655 }
656 return uni_ch;
657 }
658
_parse_codepoint(String & out,input<Iter> & in)659 template<typename String, typename Iter> inline bool _parse_codepoint(String& out, input<Iter>& in)
660 {
661 int uni_ch;
662 if ((uni_ch = _parse_quadhex(in)) == -1) {
663 return false;
664 }
665 if (0xd800 <= uni_ch && uni_ch <= 0xdfff) {
666 if (0xdc00 <= uni_ch) {
667 // a second 16-bit of a surrogate pair appeared
668 return false;
669 }
670 // first 16-bit of surrogate pair, get the next one
671 if (in.getc() != '\\' || in.getc() != 'u') {
672 in.ungetc();
673 return false;
674 }
675 int second = _parse_quadhex(in);
676 if (! (0xdc00 <= second && second <= 0xdfff)) {
677 return false;
678 }
679 uni_ch = ((uni_ch - 0xd800) << 10) | ((second - 0xdc00) & 0x3ff);
680 uni_ch += 0x10000;
681 }
682 if (uni_ch < 0x80) {
683 out.push_back(uni_ch);
684 } else {
685 if (uni_ch < 0x800) {
686 out.push_back(0xc0 | (uni_ch >> 6));
687 } else {
688 if (uni_ch < 0x10000) {
689 out.push_back(0xe0 | (uni_ch >> 12));
690 } else {
691 out.push_back(0xf0 | (uni_ch >> 18));
692 out.push_back(0x80 | ((uni_ch >> 12) & 0x3f));
693 }
694 out.push_back(0x80 | ((uni_ch >> 6) & 0x3f));
695 }
696 out.push_back(0x80 | (uni_ch & 0x3f));
697 }
698 return true;
699 }
700
_parse_string(String & out,input<Iter> & in)701 template<typename String, typename Iter> inline bool _parse_string(String& out, input<Iter>& in)
702 {
703 while (1) {
704 int ch = in.getc();
705 if (ch < ' ') {
706 in.ungetc();
707 return false;
708 } else if (ch == '"') {
709 return true;
710 } else if (ch == '\\') {
711 if ((ch = in.getc()) == -1) {
712 return false;
713 }
714 switch (ch) {
715 #define MAP(sym, val) case sym: out.push_back(val); break
716 MAP('"', '\"');
717 MAP('\\', '\\');
718 MAP('/', '/');
719 MAP('b', '\b');
720 MAP('f', '\f');
721 MAP('n', '\n');
722 MAP('r', '\r');
723 MAP('t', '\t');
724 #undef MAP
725 case 'u':
726 if (! _parse_codepoint(out, in)) {
727 return false;
728 }
729 break;
730 default:
731 return false;
732 }
733 } else {
734 out.push_back(ch);
735 }
736 }
737 return false;
738 }
739
_parse_array(Context & ctx,input<Iter> & in)740 template <typename Context, typename Iter> inline bool _parse_array(Context& ctx, input<Iter>& in)
741 {
742 if (! ctx.parse_array_start()) {
743 return false;
744 }
745 size_t idx = 0;
746 if (in.expect(']')) {
747 return ctx.parse_array_stop(idx);
748 }
749 do {
750 if (! ctx.parse_array_item(in, idx)) {
751 return false;
752 }
753 idx++;
754 } while (in.expect(','));
755 return in.expect(']') && ctx.parse_array_stop(idx);
756 }
757
_parse_object(Context & ctx,input<Iter> & in)758 template <typename Context, typename Iter> inline bool _parse_object(Context& ctx, input<Iter>& in)
759 {
760 if (! ctx.parse_object_start()) {
761 return false;
762 }
763 if (in.expect('}')) {
764 return true;
765 }
766 do {
767 std::string key;
768 if (! in.expect('"')
769 || ! _parse_string(key, in)
770 || ! in.expect(':')) {
771 return false;
772 }
773 if (! ctx.parse_object_item(in, key)) {
774 return false;
775 }
776 } while (in.expect(','));
777 return in.expect('}');
778 }
779
_parse_number(input<Iter> & in)780 template <typename Iter> inline std::string _parse_number(input<Iter>& in)
781 {
782 std::string num_str;
783 while (1) {
784 int ch = in.getc();
785 if (('0' <= ch && ch <= '9') || ch == '+' || ch == '-'
786 || ch == 'e' || ch == 'E') {
787 num_str.push_back(ch);
788 } else if (ch == '.') {
789 #if PICOJSON_USE_LOCALE
790 num_str += localeconv()->decimal_point;
791 #else
792 num_str.push_back('.');
793 #endif
794 } else {
795 in.ungetc();
796 break;
797 }
798 }
799 return num_str;
800 }
801
_parse(Context & ctx,input<Iter> & in)802 template <typename Context, typename Iter> inline bool _parse(Context& ctx, input<Iter>& in)
803 {
804 in.skip_ws();
805 int ch = in.getc();
806 switch (ch) {
807 #define IS(ch, text, op) case ch: \
808 if (in.match(text) && op) { \
809 return true; \
810 } else { \
811 return false; \
812 }
813 IS('n', "ull", ctx.set_null());
814 IS('f', "alse", ctx.set_bool(false));
815 IS('t', "rue", ctx.set_bool(true));
816 #undef IS
817 case '"':
818 return ctx.parse_string(in);
819 case '[':
820 return _parse_array(ctx, in);
821 case '{':
822 return _parse_object(ctx, in);
823 default:
824 if (('0' <= ch && ch <= '9') || ch == '-') {
825 double f;
826 char *endp;
827 in.ungetc();
828 std::string num_str = _parse_number(in);
829 if (num_str.empty()) {
830 return false;
831 }
832 #ifdef PICOJSON_USE_INT64
833 {
834 errno = 0;
835 intmax_t ival = strtoimax(num_str.c_str(), &endp, 10);
836 if (errno == 0
837 && std::numeric_limits<int64_t>::min() <= ival
838 && ival <= std::numeric_limits<int64_t>::max()
839 && endp == num_str.c_str() + num_str.size()) {
840 ctx.set_int64(ival);
841 return true;
842 }
843 }
844 #endif
845 f = strtod(num_str.c_str(), &endp);
846 if (endp == num_str.c_str() + num_str.size()) {
847 ctx.set_number(f);
848 return true;
849 }
850 return false;
851 }
852 break;
853 }
854 in.ungetc();
855 return false;
856 }
857
858 class deny_parse_context
859 {
860 public:
set_null()861 bool set_null()
862 {
863 return false;
864 }
set_bool(bool)865 bool set_bool(bool)
866 {
867 return false;
868 }
869 #ifdef PICOJSON_USE_INT64
set_int64(int64_t)870 bool set_int64(int64_t)
871 {
872 return false;
873 }
874 #endif
set_number(double)875 bool set_number(double)
876 {
877 return false;
878 }
parse_string(input<Iter> &)879 template <typename Iter> bool parse_string(input<Iter>&)
880 {
881 return false;
882 }
parse_array_start()883 bool parse_array_start()
884 {
885 return false;
886 }
parse_array_item(input<Iter> &,size_t)887 template <typename Iter> bool parse_array_item(input<Iter>&, size_t)
888 {
889 return false;
890 }
parse_array_stop(size_t)891 bool parse_array_stop(size_t)
892 {
893 return false;
894 }
parse_object_start()895 bool parse_object_start()
896 {
897 return false;
898 }
parse_object_item(input<Iter> &,const std::string &)899 template <typename Iter> bool parse_object_item(input<Iter>&, const std::string&)
900 {
901 return false;
902 }
903 };
904
905 class default_parse_context
906 {
907 protected:
908 value* out_;
909 public:
default_parse_context(value * out)910 default_parse_context(value* out) : out_(out) {}
set_null()911 bool set_null()
912 {
913 *out_ = value();
914 return true;
915 }
set_bool(bool b)916 bool set_bool(bool b)
917 {
918 *out_ = value(b);
919 return true;
920 }
921 #ifdef PICOJSON_USE_INT64
set_int64(int64_t i)922 bool set_int64(int64_t i)
923 {
924 *out_ = value(i);
925 return true;
926 }
927 #endif
set_number(double f)928 bool set_number(double f)
929 {
930 *out_ = value(f);
931 return true;
932 }
parse_string(input<Iter> & in)933 template<typename Iter> bool parse_string(input<Iter>& in)
934 {
935 *out_ = value(string_type, false);
936 return _parse_string(out_->get<std::string>(), in);
937 }
parse_array_start()938 bool parse_array_start()
939 {
940 *out_ = value(array_type, false);
941 return true;
942 }
parse_array_item(input<Iter> & in,size_t)943 template <typename Iter> bool parse_array_item(input<Iter>& in, size_t)
944 {
945 array& a = out_->get<array>();
946 a.push_back(value());
947 default_parse_context ctx(&a.back());
948 return _parse(ctx, in);
949 }
parse_array_stop(size_t)950 bool parse_array_stop(size_t)
951 {
952 return true;
953 }
parse_object_start()954 bool parse_object_start()
955 {
956 *out_ = value(object_type, false);
957 return true;
958 }
parse_object_item(input<Iter> & in,const std::string & key)959 template <typename Iter> bool parse_object_item(input<Iter>& in, const std::string& key)
960 {
961 object& o = out_->get<object>();
962 default_parse_context ctx(&o[key]);
963 return _parse(ctx, in);
964 }
965 private:
966 default_parse_context(const default_parse_context&);
967 default_parse_context& operator=(const default_parse_context&);
968 };
969
970 class null_parse_context
971 {
972 public:
973 struct dummy_str {
push_backpicojson::null_parse_context::dummy_str974 void push_back(int) {}
975 };
976 public:
null_parse_context()977 null_parse_context() {}
set_null()978 bool set_null()
979 {
980 return true;
981 }
set_bool(bool)982 bool set_bool(bool)
983 {
984 return true;
985 }
986 #ifdef PICOJSON_USE_INT64
set_int64(int64_t)987 bool set_int64(int64_t)
988 {
989 return true;
990 }
991 #endif
set_number(double)992 bool set_number(double)
993 {
994 return true;
995 }
parse_string(input<Iter> & in)996 template <typename Iter> bool parse_string(input<Iter>& in)
997 {
998 dummy_str s;
999 return _parse_string(s, in);
1000 }
parse_array_start()1001 bool parse_array_start()
1002 {
1003 return true;
1004 }
parse_array_item(input<Iter> & in,size_t)1005 template <typename Iter> bool parse_array_item(input<Iter>& in, size_t)
1006 {
1007 return _parse(*this, in);
1008 }
parse_array_stop(size_t)1009 bool parse_array_stop(size_t)
1010 {
1011 return true;
1012 }
parse_object_start()1013 bool parse_object_start()
1014 {
1015 return true;
1016 }
parse_object_item(input<Iter> & in,const std::string &)1017 template <typename Iter> bool parse_object_item(input<Iter>& in, const std::string&)
1018 {
1019 return _parse(*this, in);
1020 }
1021 private:
1022 null_parse_context(const null_parse_context&);
1023 null_parse_context& operator=(const null_parse_context&);
1024 };
1025
1026 // obsolete, use the version below
parse(value & out,Iter & pos,const Iter & last)1027 template <typename Iter> inline std::string parse(value& out, Iter& pos, const Iter& last)
1028 {
1029 std::string err;
1030 pos = parse(out, pos, last, &err);
1031 return err;
1032 }
1033
_parse(Context & ctx,const Iter & first,const Iter & last,std::string * err)1034 template <typename Context, typename Iter> inline Iter _parse(Context& ctx, const Iter& first, const Iter& last, std::string* err)
1035 {
1036 input<Iter> in(first, last);
1037 if (! _parse(ctx, in) && err != NULL) {
1038 char buf[64];
1039 SNPRINTF(buf, sizeof(buf), "syntax error at line %d near: ", in.line());
1040 *err = buf;
1041 while (1) {
1042 int ch = in.getc();
1043 if (ch == -1 || ch == '\n') {
1044 break;
1045 } else if (ch >= ' ') {
1046 err->push_back(ch);
1047 }
1048 }
1049 }
1050 return in.cur();
1051 }
1052
parse(value & out,const Iter & first,const Iter & last,std::string * err)1053 template <typename Iter> inline Iter parse(value& out, const Iter& first, const Iter& last, std::string* err)
1054 {
1055 default_parse_context ctx(&out);
1056 return _parse(ctx, first, last, err);
1057 }
1058
parse(value & out,const std::string & s)1059 inline std::string parse(value& out, const std::string& s)
1060 {
1061 std::string err;
1062 parse(out, s.begin(), s.end(), &err);
1063 return err;
1064 }
1065
parse(value & out,std::istream & is)1066 inline std::string parse(value& out, std::istream& is)
1067 {
1068 std::string err;
1069 parse(out, std::istreambuf_iterator<char>(is.rdbuf()),
1070 std::istreambuf_iterator<char>(), &err);
1071 return err;
1072 }
1073
1074 template <typename T> struct last_error_t {
1075 static std::string s;
1076 };
1077 template <typename T> std::string last_error_t<T>::s;
1078
set_last_error(const std::string & s)1079 inline void set_last_error(const std::string& s)
1080 {
1081 last_error_t<bool>::s = s;
1082 }
1083
get_last_error()1084 inline const std::string& get_last_error()
1085 {
1086 return last_error_t<bool>::s;
1087 }
1088
operator ==(const value & x,const value & y)1089 inline bool operator==(const value& x, const value& y)
1090 {
1091 if (x.is<null>())
1092 return y.is<null>();
1093 #define PICOJSON_CMP(type) \
1094 if (x.is<type>()) \
1095 return y.is<type>() && x.get<type>() == y.get<type>()
1096 PICOJSON_CMP(bool);
1097 PICOJSON_CMP(double);
1098 PICOJSON_CMP(std::string);
1099 PICOJSON_CMP(array);
1100 PICOJSON_CMP(object);
1101 #undef PICOJSON_CMP
1102 PICOJSON_ASSERT(0);
1103 #ifdef _MSC_VER
1104 __assume(0);
1105 #endif
1106 return false;
1107 }
1108
operator !=(const value & x,const value & y)1109 inline bool operator!=(const value& x, const value& y)
1110 {
1111 return ! (x == y);
1112 }
1113 }
1114
1115 namespace std
1116 {
swap(picojson::value & x,picojson::value & y)1117 template<> inline void swap(picojson::value& x, picojson::value& y)
1118 {
1119 x.swap(y);
1120 }
1121 }
1122
operator >>(std::istream & is,picojson::value & x)1123 inline std::istream& operator>>(std::istream& is, picojson::value& x)
1124 {
1125 picojson::set_last_error(std::string());
1126 std::string err = picojson::parse(x, is);
1127 if (! err.empty()) {
1128 picojson::set_last_error(err);
1129 is.setstate(std::ios::failbit);
1130 }
1131 return is;
1132 }
1133
operator <<(std::ostream & os,const picojson::value & x)1134 inline std::ostream& operator<<(std::ostream& os, const picojson::value& x)
1135 {
1136 x.serialize(std::ostream_iterator<char>(os));
1137 return os;
1138 }
1139 #ifdef _MSC_VER
1140 #pragma warning(pop)
1141 #endif
1142
1143 #endif
1144