1 /* This is a (butchered) derivative of picojson, incorporated into the
2 * Pangolin Project (http://github.com/stevenlovegrove/Pangolin)
3 *
4 * Modifications Copyright (c) 2014 Steven Lovegrove,
5 * Original licence applies (below), https://github.com/kazuho/picojson
6 */
7
8 /*
9 * Copyright 2009-2010 Cybozu Labs, Inc.
10 * Copyright 2011-2014 Kazuho Oku
11 * All rights reserved.
12 *
13 * Redistribution and use in source and binary forms, with or without
14 * modification, are permitted provided that the following conditions are met:
15 *
16 * 1. Redistributions of source code must retain the above copyright notice,
17 * this list of conditions and the following disclaimer.
18 *
19 * 2. Redistributions in binary form must reproduce the above copyright notice,
20 * this list of conditions and the following disclaimer in the documentation
21 * and/or other materials provided with the distribution.
22 *
23 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
24 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
27 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
28 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
29 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
30 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
31 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
32 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
33 * POSSIBILITY OF SUCH DAMAGE.
34 */
35 #ifndef picojson_h
36 #define picojson_h
37
38 #include <algorithm>
39 #include <cstdio>
40 #include <cstdlib>
41 #include <cstring>
42 #include <iostream>
43 #include <iterator>
44 #include <limits>
45 #include <map>
46 #include <stdexcept>
47 #include <string>
48 #include <vector>
49
50 #include <pangolin/compat/type_traits.h>
51
52 // Enable INT64 support
53 #define PICOJSON_USE_INT64
54
55 // for isnan/isinf
56 #if __cplusplus>=201103L
57 # include <cmath>
58 #else
59 extern "C" {
60 # ifdef _MSC_VER
61 # include <float.h>
62 # elif defined(__INTEL_COMPILER)
63 # include <mathimf.h>
64 # else
65 # include <math.h>
66 # endif
67 }
68 #endif
69
70 // experimental support for int64_t (see README.mkdn for detail)
71 #ifdef PICOJSON_USE_INT64
72 # ifndef __STDC_FORMAT_MACROS
73 # define __STDC_FORMAT_MACROS
74 # endif
75 # include <errno.h>
76 # include <inttypes.h>
77 #endif // PICOJSON_USE_INT64
78
79 // to disable the use of localeconv(3), set PICOJSON_USE_LOCALE to 0
80 #ifndef PICOJSON_USE_LOCALE
81 # define PICOJSON_USE_LOCALE 1
82 #endif // PICOJSON_USE_LOCALE
83
84 #if PICOJSON_USE_LOCALE
85 extern "C" {
86 # include <locale.h>
87 }
88 #endif // PICOJSON_USE_LOCALE
89
90 #ifndef PICOJSON_ASSERT
91 # define PICOJSON_ASSERT(e) do { if (! (e)) throw std::runtime_error(#e); } while (0)
92 #endif
93
94 #ifdef _MSC_VER
95 #define SNPRINTF _snprintf_s
96 #pragma warning(push)
97 #pragma warning(disable : 4244) // conversion from int to char
98 #else
99 #define SNPRINTF snprintf
100 #endif
101
102 #ifdef _MSC_VER
103 #define PICOJSON_FALSE_TEMPLATE_TYPE nullptr
104 #else
105 #define PICOJSON_FALSE_TEMPLATE_TYPE ((void*)0)
106 #endif
107
108 namespace picojson {
109
110 enum {
111 null_type,
112 boolean_type,
113 number_type,
114 string_type,
115 array_type,
116 object_type
117 #ifdef PICOJSON_USE_INT64
118 , int64_type
119 #endif
120 };
121
122 enum {
123 INDENT_WIDTH = 2
124 };
125
126 struct null {};
127
128 class value {
129 public:
130 typedef std::vector<value> array;
131 typedef std::map<std::string, value> object;
132
133 union _storage {
134 bool boolean_;
135 double number_;
136 #ifdef PICOJSON_USE_INT64
137 int64_t int64_;
138 #endif
139 std::string* string_;
140 array* array_;
141 object* object_;
142 };
143 protected:
144 int type_;
145 _storage u_;
146 public:
147
148
149 /////////////////////////////
150 // Constructors / Destructor
151 /////////////////////////////
152
153 ~value();
154 value();
155 value(int type, bool);
156
157 /////////////////////////////
158 // Implicit type constructors
159 /////////////////////////////
160
value(bool b)161 value(bool b) : type_(boolean_type) {
162 u_.boolean_ = b;
163 }
164
165 #ifdef PICOJSON_USE_INT64
value(short v)166 value(short v) : type_(int64_type) {
167 u_.int64_ = static_cast<int64_t>(v);
168 }
value(unsigned short v)169 value(unsigned short v) : type_(int64_type) {
170 u_.int64_ = static_cast<int64_t>(v);
171 }
value(int v)172 value(int v) : type_(int64_type) {
173 u_.int64_ = static_cast<int64_t>(v);
174 }
value(unsigned int v)175 value(unsigned int v) : type_(int64_type) {
176 u_.int64_ = static_cast<int64_t>(v);
177 }
value(long v)178 value(long v) : type_(int64_type) {
179 u_.int64_ = static_cast<int64_t>(v);
180 }
value(unsigned long v)181 value(unsigned long v) : type_(int64_type) {
182 u_.int64_ = static_cast<int64_t>(v);
183 }
value(long long v)184 value(long long v) : type_(int64_type) {
185 u_.int64_ = static_cast<int64_t>(v);
186 }
value(unsigned long long v)187 value(unsigned long long v) : type_(int64_type) {
188 u_.int64_ = static_cast<int64_t>(v);
189 }
190 #endif
191
value(float n)192 value(float n) : type_(number_type) {
193 if (
194 #ifdef _MSC_VER
195 ! _finite(n)
196 #elif __cplusplus>=201103L || !(defined(isnan) && defined(isinf))
197 std::isnan(n) || std::isinf(n)
198 #else
199 isnan(n) || isinf(n)
200 #endif
201 ) {
202 throw std::overflow_error("");
203 }
204 u_.number_ = static_cast<double>(n);
205 }
206
value(double n)207 value(double n) : type_(number_type) {
208 if (
209 #ifdef _MSC_VER
210 ! _finite(n)
211 #elif __cplusplus>=201103L || !(defined(isnan) && defined(isinf))
212 std::isnan(n) || std::isinf(n)
213 #else
214 isnan(n) || isinf(n)
215 #endif
216 ) {
217 throw std::overflow_error("");
218 }
219 u_.number_ = n;
220 }
221
222 value(const array& a);
223 value(const object& o);
224
225 value(const std::string& s);
226 value(const char* s);
227 value(const char* s, size_t len);
228
229 value(const value& x);
230 value& operator=(const value& x);
231
232 /////////////////////////////
233 // Query / get type
234 /////////////////////////////
235
236 void swap(value& x);
237 template <typename T> bool is() const;
238 template <typename T> const T& get() const;
239 template <typename T> T& get();
240 bool evaluate_as_boolean() const;
241 size_t size() const;
242
243 /////////////////////////////
244 // Usage as array
245 /////////////////////////////
246
247 value& operator[](size_t idx);
248 const value& operator[](size_t idx) const;
249 bool contains(size_t idx) const;
250 value& push_back(const value& = value() );
251
252 /////////////////////////////
253 // Usage as object
254 /////////////////////////////
255
256 value& operator[](const std::string& key);
257 const value& operator[](const std::string& key) const;
258 bool contains(const std::string& key) const;
259
260 template <typename T>
261 T get_value(const std::string& key, T default_value) const;
262
263 /////////////////////////////
264 // Serialization
265 /////////////////////////////
266
267 std::string to_str() const;
268 template <typename Iter> void serialize(Iter os, bool prettify = false) const;
269 std::string serialize(bool prettify = false) const;
270 private:
271 template <typename T> value(const T*); // intentionally defined to block implicit conversion of pointer to bool
272 template <typename Iter> static void _indent(Iter os, int indent);
273 template <typename Iter> void _serialize(Iter os, int indent) const;
274 std::string _serialize(int indent) const;
275 };
276
277 typedef value::array array;
278 typedef value::object object;
279
value()280 inline value::value() : type_(null_type), u_({false}) {}
281
value(int type,bool)282 inline value::value(int type, bool) : type_(type) {
283 switch (type) {
284 #define INIT(p, v) case p##type: u_.p = v; break
285 INIT(boolean_, false);
286 INIT(number_, 0.0);
287 #ifdef PICOJSON_USE_INT64
288 INIT(int64_, 0);
289 #endif
290 INIT(string_, new std::string());
291 INIT(array_, new array());
292 INIT(object_, new object());
293 #undef INIT
294 default: break;
295 }
296 }
297
value(const std::string & s)298 inline value::value(const std::string& s) : type_(string_type) {
299 u_.string_ = new std::string(s);
300 }
301
value(const array & a)302 inline value::value(const array& a) : type_(array_type) {
303 u_.array_ = new array(a);
304 }
305
value(const object & o)306 inline value::value(const object& o) : type_(object_type) {
307 u_.object_ = new object(o);
308 }
309
value(const char * s)310 inline value::value(const char* s) : type_(string_type) {
311 u_.string_ = new std::string(s);
312 }
313
value(const char * s,size_t len)314 inline value::value(const char* s, size_t len) : type_(string_type) {
315 u_.string_ = new std::string(s, len);
316 }
317
~value()318 inline value::~value() {
319 switch (type_) {
320 #define DEINIT(p) case p##type: delete u_.p; break
321 DEINIT(string_);
322 DEINIT(array_);
323 DEINIT(object_);
324 #undef DEINIT
325 default: break;
326 }
327 }
328
value(const value & x)329 inline value::value(const value& x) : type_(x.type_) {
330 switch (type_) {
331 #define INIT(p, v) case p##type: u_.p = v; break
332 INIT(string_, new std::string(*x.u_.string_));
333 INIT(array_, new array(*x.u_.array_));
334 INIT(object_, new object(*x.u_.object_));
335 #undef INIT
336 default:
337 u_ = x.u_;
338 break;
339 }
340 }
341
342 inline value& value::operator=(const value& x) {
343 if (this != &x) {
344 this->~value();
345 new (this) value(x);
346 }
347 return *this;
348 }
349
swap(value & x)350 inline void value::swap(value& x) {
351 std::swap(type_, x.type_);
352 std::swap(u_, x.u_);
353 }
354
355 #define IS(ctype, jtype) \
356 template <> inline bool value::is<ctype>() const { \
357 return type_ == jtype##_type; \
358 }
IS(null,null)359 IS(null, null)
360 IS(bool, boolean)
361 #ifdef PICOJSON_USE_INT64
362 IS(int64_t, int64)
363 #endif
364 IS(std::string, string)
365 IS(array, array)
366 IS(object, object)
367 #undef IS
368 template <> inline bool value::is<double>() const {
369 return type_ == number_type
370 #ifdef PICOJSON_USE_INT64
371 || type_ == int64_type
372 #endif
373 ;
374 }
375
376 #define GET(ctype, var) \
377 template <> inline const ctype& value::get<ctype>() const { \
378 PICOJSON_ASSERT("type mismatch! call is<type>() before get<type>()" \
379 && is<ctype>()); \
380 return var; \
381 } \
382 template <> inline ctype& value::get<ctype>() { \
383 PICOJSON_ASSERT("type mismatch! call is<type>() before get<type>()" \
384 && is<ctype>()); \
385 return var; \
386 }
387 GET(bool, u_.boolean_)
388 GET(std::string, *u_.string_)
389 GET(array, *u_.array_)
390 GET(object, *u_.object_)
391 #ifdef PICOJSON_USE_INT64
392 GET(double, (type_ == int64_type && (const_cast<value*>(this)->type_ = number_type, const_cast<value*>(this)->u_.number_ = u_.int64_), u_.number_))
393 GET(int64_t, u_.int64_)
394 #else
395 GET(double, u_.number_)
396 #endif
397 #undef GET
398
evaluate_as_boolean()399 inline bool value::evaluate_as_boolean() const {
400 switch (type_) {
401 case null_type:
402 return false;
403 case boolean_type:
404 return u_.boolean_;
405 case number_type:
406 return u_.number_ != 0;
407 case string_type:
408 return ! u_.string_->empty();
409 default:
410 return true;
411 }
412 }
413
size()414 inline size_t value::size() const
415 {
416 PICOJSON_ASSERT("Type mismatch! Not array." && is<array>());
417 return u_.array_->size();
418 }
419
420 inline const value& value::operator[](size_t idx) const {
421 PICOJSON_ASSERT("Type mismatch! Not array." && is<array>());
422 PICOJSON_ASSERT("Out of bounds." && idx < u_.array_->size() );
423 return (*u_.array_)[idx];
424 }
425
426 inline value& value::operator[](size_t idx) {
427 if( type_ == null_type ) {
428 // instantiate as array
429 type_ = array_type;
430 u_.array_ = new array();
431 }
432
433 PICOJSON_ASSERT("Type mismatch! Not array." && is<array>());
434 PICOJSON_ASSERT("Out of bounds." && idx < u_.array_->size() );
435 return (*u_.array_)[idx];
436 }
437
contains(size_t idx)438 inline bool value::contains(size_t idx) const {
439 if( type_ == array_type) {
440 return idx < u_.array_->size();
441 }else{
442 return false;
443 }
444 }
445
push_back(const value & val)446 inline value& value::push_back(const value& val)
447 {
448 if( type_ == null_type ) {
449 // instantiate as array
450 type_ = array_type;
451 u_.array_ = new array();
452 }
453 PICOJSON_ASSERT("Type mismatch! Not array." && is<array>());
454 u_.array_->push_back( val );
455 return u_.array_->back();
456 }
457
458 inline const value& value::operator[](const std::string& key) const {
459 PICOJSON_ASSERT("Type mismatch! Not object." && is<object>() );
460 object::const_iterator i = u_.object_->find(key);
461 PICOJSON_ASSERT("Key not found." && i != u_.object_->end() );
462 return i->second;
463 }
464
465 inline value& value::operator[](const std::string& key) {
466 if( type_ == null_type ) {
467 // instantiate as object
468 type_ = object_type;
469 u_.object_ = new object();
470 }
471 PICOJSON_ASSERT("Type mismatch! Not object." && is<object>());
472 return u_.object_->operator [](key);
473 }
474
contains(const std::string & key)475 inline bool value::contains(const std::string& key) const {
476 if( type_ == object_type) {
477 object::const_iterator i = u_.object_->find(key);
478 return i != u_.object_->end();
479 }else{
480 return false;
481 }
482 }
483
484 template <typename T>
get_value(const std::string & key,T default_value)485 inline T value::get_value(const std::string& key, T default_value) const {
486 if(contains(key)) {
487 return (*this)[key].get<T>();
488 }else{
489 return default_value;
490 }
491 }
492
to_str()493 inline std::string value::to_str() const {
494 switch (type_) {
495 case null_type: return "null";
496 case boolean_type: return u_.boolean_ ? "true" : "false";
497 #ifdef PICOJSON_USE_INT64
498 case int64_type: {
499 char buf[sizeof("-9223372036854775808")];
500 SNPRINTF(buf, sizeof(buf), "%" PRId64, u_.int64_);
501 return buf;
502 }
503 #endif
504 case number_type: {
505 char buf[256];
506 double tmp;
507 SNPRINTF(buf, sizeof(buf), fabs(u_.number_) < (1ULL << 53) && modf(u_.number_, &tmp) == 0 ? "%.f" : "%.17g", u_.number_);
508 #if PICOJSON_USE_LOCALE
509 char *decimal_point = localeconv()->decimal_point;
510 if (strcmp(decimal_point, ".") != 0) {
511 size_t decimal_point_len = strlen(decimal_point);
512 for (char *p = buf; *p != '\0'; ++p) {
513 if (strncmp(p, decimal_point, decimal_point_len) == 0) {
514 return std::string(buf, p) + "." + (p + decimal_point_len);
515 }
516 }
517 }
518 #endif
519 return buf;
520 }
521 case string_type: return *u_.string_;
522 case array_type: return "array";
523 case object_type: return "object";
524 default: PICOJSON_ASSERT("value::to_str() assert failed." && 0);
525 #ifdef _MSC_VER
526 __assume(0);
527 #endif
528 }
529 }
530
copy(const std::string & s,Iter oi)531 template <typename Iter> void copy(const std::string& s, Iter oi) {
532 std::copy(s.begin(), s.end(), oi);
533 }
534
serialize_str(const std::string & s,Iter oi)535 template <typename Iter> void serialize_str(const std::string& s, Iter oi) {
536 *oi++ = '"';
537 for (std::string::const_iterator i = s.begin(); i != s.end(); ++i) {
538 switch (*i) {
539 #define MAP(val, sym) case val: copy(sym, oi); break
540 MAP('"', "\\\"");
541 MAP('\\', "\\\\");
542 MAP('/', "\\/");
543 MAP('\b', "\\b");
544 MAP('\f', "\\f");
545 MAP('\n', "\\n");
546 MAP('\r', "\\r");
547 MAP('\t', "\\t");
548 #undef MAP
549 default:
550 if (static_cast<unsigned char>(*i) < 0x20 || *i == 0x7f) {
551 char buf[7];
552 SNPRINTF(buf, sizeof(buf), "\\u%04x", *i & 0xff);
553 copy(buf, buf + 6, oi);
554 } else {
555 *oi++ = *i;
556 }
557 break;
558 }
559 }
560 *oi++ = '"';
561 }
562
serialize(Iter oi,bool prettify)563 template <typename Iter> void value::serialize(Iter oi, bool prettify) const {
564 return _serialize(oi, prettify ? 0 : -1);
565 }
566
serialize(bool prettify)567 inline std::string value::serialize(bool prettify) const {
568 return _serialize(prettify ? 0 : -1);
569 }
570
_indent(Iter oi,int indent)571 template <typename Iter> void value::_indent(Iter oi, int indent) {
572 *oi++ = '\n';
573 for (int i = 0; i < indent * INDENT_WIDTH; ++i) {
574 *oi++ = ' ';
575 }
576 }
577
_serialize(Iter oi,int indent)578 template <typename Iter> void value::_serialize(Iter oi, int indent) const {
579 switch (type_) {
580 case string_type:
581 serialize_str(*u_.string_, oi);
582 break;
583 case array_type: {
584 *oi++ = '[';
585 if (indent != -1) {
586 ++indent;
587 }
588 for (array::const_iterator i = u_.array_->begin();
589 i != u_.array_->end();
590 ++i) {
591 if (i != u_.array_->begin()) {
592 *oi++ = ',';
593 }
594 if (indent != -1) {
595 _indent(oi, indent);
596 }
597 i->_serialize(oi, indent);
598 }
599 if (indent != -1) {
600 --indent;
601 if (! u_.array_->empty()) {
602 _indent(oi, indent);
603 }
604 }
605 *oi++ = ']';
606 break;
607 }
608 case object_type: {
609 *oi++ = '{';
610 if (indent != -1) {
611 ++indent;
612 }
613 for (object::const_iterator i = u_.object_->begin();
614 i != u_.object_->end();
615 ++i) {
616 if (i != u_.object_->begin()) {
617 *oi++ = ',';
618 }
619 if (indent != -1) {
620 _indent(oi, indent);
621 }
622 serialize_str(i->first, oi);
623 *oi++ = ':';
624 if (indent != -1) {
625 *oi++ = ' ';
626 }
627 i->second._serialize(oi, indent);
628 }
629 if (indent != -1) {
630 --indent;
631 if (! u_.object_->empty()) {
632 _indent(oi, indent);
633 }
634 }
635 *oi++ = '}';
636 break;
637 }
638 default:
639 copy(to_str(), oi);
640 break;
641 }
642 if (indent == 0) {
643 *oi++ = '\n';
644 }
645 }
646
_serialize(int indent)647 inline std::string value::_serialize(int indent) const {
648 std::string s;
649 _serialize(std::back_inserter(s), indent);
650 return s;
651 }
652
653 template <typename Iter> class input {
654 protected:
655 Iter cur_, end_;
656 int last_ch_;
657 bool ungot_;
658 int line_;
659 public:
input(const Iter & first,const Iter & last)660 input(const Iter& first, const Iter& last) : cur_(first), end_(last), last_ch_(-1), ungot_(false), line_(1) {}
getc()661 int getc() {
662 if (ungot_) {
663 ungot_ = false;
664 return last_ch_;
665 }
666 if (cur_ == end_) {
667 last_ch_ = -1;
668 return -1;
669 }
670 if (last_ch_ == '\n') {
671 line_++;
672 }
673 last_ch_ = *cur_ & 0xff;
674 ++cur_;
675 return last_ch_;
676 }
ungetc()677 void ungetc() {
678 if (last_ch_ != -1) {
679 PICOJSON_ASSERT(! ungot_);
680 ungot_ = true;
681 }
682 }
cur()683 Iter cur() const { return cur_; }
line()684 int line() const { return line_; }
skip_ws()685 void skip_ws() {
686 while (1) {
687 int ch = getc();
688 if (! (ch == ' ' || ch == '\t' || ch == '\n' || ch == '\r')) {
689 ungetc();
690 break;
691 }
692 }
693 }
expect(int expect)694 bool expect(int expect) {
695 skip_ws();
696 if (getc() != expect) {
697 ungetc();
698 return false;
699 }
700 return true;
701 }
match(const std::string & pattern)702 bool match(const std::string& pattern) {
703 for (std::string::const_iterator pi(pattern.begin());
704 pi != pattern.end();
705 ++pi) {
706 if (getc() != *pi) {
707 ungetc();
708 return false;
709 }
710 }
711 return true;
712 }
713 };
714
_parse_quadhex(input<Iter> & in)715 template<typename Iter> inline int _parse_quadhex(input<Iter> &in) {
716 int uni_ch = 0, hex;
717 for (int i = 0; i < 4; i++) {
718 if ((hex = in.getc()) == -1) {
719 return -1;
720 }
721 if ('0' <= hex && hex <= '9') {
722 hex -= '0';
723 } else if ('A' <= hex && hex <= 'F') {
724 hex -= 'A' - 0xa;
725 } else if ('a' <= hex && hex <= 'f') {
726 hex -= 'a' - 0xa;
727 } else {
728 in.ungetc();
729 return -1;
730 }
731 uni_ch = uni_ch * 16 + hex;
732 }
733 return uni_ch;
734 }
735
_parse_codepoint(String & out,input<Iter> & in)736 template<typename String, typename Iter> inline bool _parse_codepoint(String& out, input<Iter>& in) {
737 int uni_ch;
738 if ((uni_ch = _parse_quadhex(in)) == -1) {
739 return false;
740 }
741 if (0xd800 <= uni_ch && uni_ch <= 0xdfff) {
742 if (0xdc00 <= uni_ch) {
743 // a second 16-bit of a surrogate pair appeared
744 return false;
745 }
746 // first 16-bit of surrogate pair, get the next one
747 if (in.getc() != '\\' || in.getc() != 'u') {
748 in.ungetc();
749 return false;
750 }
751 int second = _parse_quadhex(in);
752 if (! (0xdc00 <= second && second <= 0xdfff)) {
753 return false;
754 }
755 uni_ch = ((uni_ch - 0xd800) << 10) | ((second - 0xdc00) & 0x3ff);
756 uni_ch += 0x10000;
757 }
758 if (uni_ch < 0x80) {
759 out.push_back(uni_ch);
760 } else {
761 if (uni_ch < 0x800) {
762 out.push_back(0xc0 | (uni_ch >> 6));
763 } else {
764 if (uni_ch < 0x10000) {
765 out.push_back(0xe0 | (uni_ch >> 12));
766 } else {
767 out.push_back(0xf0 | (uni_ch >> 18));
768 out.push_back(0x80 | ((uni_ch >> 12) & 0x3f));
769 }
770 out.push_back(0x80 | ((uni_ch >> 6) & 0x3f));
771 }
772 out.push_back(0x80 | (uni_ch & 0x3f));
773 }
774 return true;
775 }
776
777 template<typename String, typename Iter> inline bool _parse_string(String& out, input<Iter>& in, int delim='"') {
778 while (1) {
779 int ch = in.getc();
780 if (ch < ' ') {
781 in.ungetc();
782 return false;
783 } else if (ch == delim) {
784 return true;
785 } else if (ch == '\\') {
786 if ((ch = in.getc()) == -1) {
787 return false;
788 }
789 switch (ch) {
790 #define MAP(sym, val) case sym: out.push_back(val); break
791 MAP('"', '\"');
792 MAP('\\', '\\');
793 MAP('/', '/');
794 MAP('b', '\b');
795 MAP('f', '\f');
796 MAP('n', '\n');
797 MAP('r', '\r');
798 MAP('t', '\t');
799 #undef MAP
800 case 'u':
801 if (! _parse_codepoint(out, in)) {
802 return false;
803 }
804 break;
805 default:
806 return false;
807 }
808 } else {
809 out.push_back(ch);
810 }
811 }
812 }
813
_parse_array(Context & ctx,input<Iter> & in)814 template <typename Context, typename Iter> inline bool _parse_array(Context& ctx, input<Iter>& in) {
815 if (! ctx.parse_array_start()) {
816 return false;
817 }
818 size_t idx = 0;
819 if (in.expect(']')) {
820 return ctx.parse_array_stop(idx);
821 }
822 do {
823 if (! ctx.parse_array_item(in, idx)) {
824 return false;
825 }
826 idx++;
827 } while (in.expect(','));
828 return in.expect(']') && ctx.parse_array_stop(idx);
829 }
830
_parse_object(Context & ctx,input<Iter> & in)831 template <typename Context, typename Iter> inline bool _parse_object(Context& ctx, input<Iter>& in) {
832 if (! ctx.parse_object_start()) {
833 return false;
834 }
835 if (in.expect('}')) {
836 return true;
837 }
838 do {
839 std::string key;
840 // Support " and ' delimited strings
841 if( in.expect('"') ) {
842 if( !_parse_string(key, in, '"') )
843 return false;
844 }else if (!in.expect('\'') || !_parse_string(key, in,'\'') ) {
845 return false;
846 }
847 if (!in.expect(':') || !ctx.parse_object_item(in, key)) {
848 return false;
849 }
850 } while (in.expect(','));
851 return in.expect('}');
852 }
853
_parse_number(input<Iter> & in)854 template <typename Iter> inline std::string _parse_number(input<Iter>& in) {
855 std::string num_str;
856 while (1) {
857 int ch = in.getc();
858 if (('0' <= ch && ch <= '9') || ch == '+' || ch == '-'
859 || ch == 'e' || ch == 'E') {
860 num_str.push_back(ch);
861 } else if (ch == '.') {
862 #if PICOJSON_USE_LOCALE
863 num_str += localeconv()->decimal_point;
864 #else
865 num_str.push_back('.');
866 #endif
867 } else {
868 in.ungetc();
869 break;
870 }
871 }
872 return num_str;
873 }
874
_parse(Context & ctx,input<Iter> & in)875 template <typename Context, typename Iter> inline bool _parse(Context& ctx, input<Iter>& in) {
876 in.skip_ws();
877 int ch = in.getc();
878 switch (ch) {
879 #define IS(ch, text, op) case ch: \
880 if (in.match(text) && op) { \
881 return true; \
882 } else { \
883 return false; \
884 }
885 IS('n', "ull", ctx.set_null());
886 IS('f', "alse", ctx.set_bool(false));
887 IS('t', "rue", ctx.set_bool(true));
888 #undef IS
889 case '"':
890 return ctx.parse_string(in);
891 case '[':
892 return _parse_array(ctx, in);
893 case '{':
894 return _parse_object(ctx, in);
895 default:
896 if (('0' <= ch && ch <= '9') || ch == '-') {
897 double f;
898 char *endp;
899 in.ungetc();
900 std::string num_str = _parse_number(in);
901 if (num_str.empty()) {
902 return false;
903 }
904 #ifdef PICOJSON_USE_INT64
905 {
906 errno = 0;
907 intmax_t ival = strtoimax(num_str.c_str(), &endp, 10);
908 if (errno == 0
909 && std::numeric_limits<int64_t>::min() <= ival
910 && ival <= std::numeric_limits<int64_t>::max()
911 && endp == num_str.c_str() + num_str.size()) {
912 ctx.set_int64(ival);
913 return true;
914 }
915 }
916 #endif
917 f = strtod(num_str.c_str(), &endp);
918 if (endp == num_str.c_str() + num_str.size()) {
919 ctx.set_number(f);
920 return true;
921 }
922 return false;
923 }
924 break;
925 }
926 in.ungetc();
927 return false;
928 }
929
930 class deny_parse_context {
931 public:
set_null()932 bool set_null() { return false; }
set_bool(bool)933 bool set_bool(bool) { return false; }
934 #ifdef PICOJSON_USE_INT64
set_int64(int64_t)935 bool set_int64(int64_t) { return false; }
936 #endif
set_number(double)937 bool set_number(double) { return false; }
parse_string(input<Iter> &)938 template <typename Iter> bool parse_string(input<Iter>&) { return false; }
parse_array_start()939 bool parse_array_start() { return false; }
parse_array_item(input<Iter> &,size_t)940 template <typename Iter> bool parse_array_item(input<Iter>&, size_t) {
941 return false;
942 }
parse_array_stop(size_t)943 bool parse_array_stop(size_t) { return false; }
parse_object_start()944 bool parse_object_start() { return false; }
parse_object_item(input<Iter> &,const std::string &)945 template <typename Iter> bool parse_object_item(input<Iter>&, const std::string&) {
946 return false;
947 }
948 };
949
950 class default_parse_context {
951 protected:
952 value* out_;
953 public:
default_parse_context(value * out)954 default_parse_context(value* out) : out_(out) {}
set_null()955 bool set_null() {
956 *out_ = value();
957 return true;
958 }
set_bool(bool b)959 bool set_bool(bool b) {
960 *out_ = value(b);
961 return true;
962 }
963 #ifdef PICOJSON_USE_INT64
set_int64(int64_t i)964 bool set_int64(int64_t i) {
965 *out_ = value(i);
966 return true;
967 }
968 #endif
set_number(double f)969 bool set_number(double f) {
970 *out_ = value(f);
971 return true;
972 }
parse_string(input<Iter> & in)973 template<typename Iter> bool parse_string(input<Iter>& in) {
974 *out_ = value(string_type, false);
975 return _parse_string(out_->get<std::string>(), in);
976 }
parse_array_start()977 bool parse_array_start() {
978 *out_ = value(array_type, false);
979 return true;
980 }
parse_array_item(input<Iter> & in,size_t)981 template <typename Iter> bool parse_array_item(input<Iter>& in, size_t) {
982 array& a = out_->get<array>();
983 a.push_back(value());
984 default_parse_context ctx(&a.back());
985 return _parse(ctx, in);
986 }
parse_array_stop(size_t)987 bool parse_array_stop(size_t) { return true; }
parse_object_start()988 bool parse_object_start() {
989 *out_ = value(object_type, false);
990 return true;
991 }
parse_object_item(input<Iter> & in,const std::string & key)992 template <typename Iter> bool parse_object_item(input<Iter>& in, const std::string& key) {
993 object& o = out_->get<object>();
994 default_parse_context ctx(&o[key]);
995 return _parse(ctx, in);
996 }
997 private:
998 default_parse_context(const default_parse_context&);
999 default_parse_context& operator=(const default_parse_context&);
1000 };
1001
1002 class null_parse_context {
1003 public:
1004 struct dummy_str {
push_backdummy_str1005 void push_back(int) {}
1006 };
1007 public:
null_parse_context()1008 null_parse_context() {}
set_null()1009 bool set_null() { return true; }
set_bool(bool)1010 bool set_bool(bool) { return true; }
1011 #ifdef PICOJSON_USE_INT64
set_int64(int64_t)1012 bool set_int64(int64_t) { return true; }
1013 #endif
set_number(double)1014 bool set_number(double) { return true; }
parse_string(input<Iter> & in)1015 template <typename Iter> bool parse_string(input<Iter>& in) {
1016 dummy_str s;
1017 return _parse_string(s, in);
1018 }
parse_array_start()1019 bool parse_array_start() { return true; }
parse_array_item(input<Iter> & in,size_t)1020 template <typename Iter> bool parse_array_item(input<Iter>& in, size_t) {
1021 return _parse(*this, in);
1022 }
parse_array_stop(size_t)1023 bool parse_array_stop(size_t) { return true; }
parse_object_start()1024 bool parse_object_start() { return true; }
parse_object_item(input<Iter> & in,const std::string &)1025 template <typename Iter> bool parse_object_item(input<Iter>& in, const std::string&) {
1026 return _parse(*this, in);
1027 }
1028 private:
1029 null_parse_context(const null_parse_context&);
1030 null_parse_context& operator=(const null_parse_context&);
1031 };
1032
1033 // obsolete, use the version below
parse(value & out,Iter & pos,const Iter & last)1034 template <typename Iter> inline std::string parse(value& out, Iter& pos, const Iter& last) {
1035 std::string err;
1036 pos = parse(out, pos, last, &err);
1037 return err;
1038 }
1039
_parse(Context & ctx,const Iter & first,const Iter & last,std::string * err)1040 template <typename Context, typename Iter> inline Iter _parse(Context& ctx, const Iter& first, const Iter& last, std::string* err) {
1041 input<Iter> in(first, last);
1042 if (! _parse(ctx, in) && err != NULL) {
1043 char buf[64];
1044 SNPRINTF(buf, sizeof(buf), "syntax error at line %d near: ", in.line());
1045 *err = buf;
1046 while (1) {
1047 int ch = in.getc();
1048 if (ch == -1 || ch == '\n') {
1049 break;
1050 } else if (ch >= ' ') {
1051 err->push_back(ch);
1052 }
1053 }
1054 }
1055 return in.cur();
1056 }
1057
parse(value & out,const Iter & first,const Iter & last,std::string * err)1058 template <typename Iter> inline Iter parse(value& out, const Iter& first, const Iter& last, std::string* err) {
1059 default_parse_context ctx(&out);
1060 return _parse(ctx, first, last, err);
1061 }
1062
parse(value & out,const std::string & s)1063 inline std::string parse(value &out, const std::string &s) {
1064 std::string err;
1065 parse(out, s.begin(), s.end(), &err);
1066 return err;
1067 }
1068
parse(value & out,std::istream & is)1069 inline std::string parse(value& out, std::istream& is) {
1070 std::string err;
1071 parse(out, std::istreambuf_iterator<char>(is.rdbuf()),
1072 std::istreambuf_iterator<char>(), &err);
1073 return err;
1074 }
1075
1076 template <typename T> struct last_error_t {
1077 static std::string s;
1078 };
1079 template <typename T> std::string last_error_t<T>::s;
1080
set_last_error(const std::string & s)1081 inline void set_last_error(const std::string& s) {
1082 last_error_t<bool>::s = s;
1083 }
1084
get_last_error()1085 inline const std::string& get_last_error() {
1086 return last_error_t<bool>::s;
1087 }
1088
1089 inline bool operator==(const value& x, const value& y) {
1090 if (x.is<null>())
1091 return y.is<null>();
1092 #define PICOJSON_CMP(type) \
1093 if (x.is<type>()) \
1094 return y.is<type>() && x.get<type>() == y.get<type>()
1095 PICOJSON_CMP(bool);
1096 PICOJSON_CMP(double);
1097 PICOJSON_CMP(std::string);
1098 PICOJSON_CMP(array);
1099 PICOJSON_CMP(object);
1100 #undef PICOJSON_CMP
1101 PICOJSON_ASSERT(0);
1102 #ifdef _MSC_VER
1103 __assume(0);
1104 #endif
1105 }
1106
1107 inline bool operator!=(const value& x, const value& y) {
1108 return ! (x == y);
1109 }
1110
1111 } // namespace json
1112
1113 inline std::istream& operator>>(std::istream& is, picojson::value& x)
1114 {
1115 picojson::set_last_error(std::string());
1116 std::string err = picojson::parse(x, is);
1117 if (! err.empty()) {
1118 picojson::set_last_error(err);
1119 is.setstate(std::ios::failbit);
1120 }
1121 return is;
1122 }
1123
1124 inline std::ostream& operator<<(std::ostream& os, const picojson::value& x)
1125 {
1126 x.serialize(std::ostream_iterator<char>(os));
1127 return os;
1128 }
1129 #ifdef _MSC_VER
1130 #pragma warning(pop)
1131 #endif // _MSC_VER
1132
1133 #endif // picojson_h
1134
1135
1136
1137
1138 #ifdef TEST_PICOJSON
1139
1140 #ifdef _MSC_VER
1141 #pragma warning(disable : 4127) // conditional expression is constant
1142 #endif // _MSC_VER
1143
1144 using namespace std;
1145
1146 static bool success = true;
1147 static int test_num = 0;
1148
1149 static void ok(bool b, const char* name = "")
1150 {
1151 if (! b)
1152 success = false;
1153 printf("%s %d - %s\n", b ? "ok" : "ng", ++test_num, name);
1154 }
1155
done_testing()1156 static void done_testing()
1157 {
1158 printf("1..%d\n", test_num);
1159 }
1160
1161 template <typename T> void is(const T& x, const T& y, const char* name = "")
1162 {
1163 if (x == y) {
1164 ok(true, name);
1165 } else {
1166 ok(false, name);
1167 }
1168 }
1169
1170 #include <algorithm>
1171 #include <sstream>
1172 #include <float.h>
1173 #include <limits.h>
1174
main(void)1175 int main(void)
1176 {
1177 #if PICOJSON_USE_LOCALE
1178 setlocale(LC_ALL, "");
1179 #endif // PICOJSON_USE_LOCALE
1180
1181 // constructors
1182 #define TEST(expr, expected) \
1183 is(picojson::value expr .serialize(), string(expected), "picojson::value" #expr)
1184
1185 TEST( (true), "true");
1186 TEST( (false), "false");
1187 TEST( (42.0), "42");
1188 TEST( (string("hello")), "\"hello\"");
1189 TEST( ("hello"), "\"hello\"");
1190 TEST( ("hello", 4), "\"hell\"");
1191
1192 {
1193 double a = 1;
1194 for (int i = 0; i < 1024; i++) {
1195 picojson::value vi(a);
1196 std::stringstream ss;
1197 ss << vi;
1198 picojson::value vo;
1199 ss >> vo;
1200 double b = vo.get<double>();
1201 if ((i < 53 && a != b) || fabs(a - b) / b > 1e-8) {
1202 printf("ng i=%d a=%.18e b=%.18e\n", i, a, b);
1203 }
1204 a *= 2;
1205 }
1206 }
1207
1208 #undef TEST
1209
1210 #define TEST(in, type, cmp, serialize_test) { \
1211 picojson::value v; \
1212 const char* s = in; \
1213 string err = picojson::parse(v, s, s + strlen(s)); \
1214 ok(err.empty(), in " no error"); \
1215 ok(v.is<type>(), in " check type"); \
1216 is<type>(v.get<type>(), cmp, in " correct output"); \
1217 is(*s, '\0', in " read to eof"); \
1218 if (serialize_test) { \
1219 is(v.serialize(), string(in), in " serialize"); \
1220 } \
1221 }
1222 TEST("false", bool, false, true);
1223 TEST("true", bool, true, true);
1224 TEST("90.5", double, 90.5, false);
1225 TEST("1.7976931348623157e+308", double, DBL_MAX, false);
1226 TEST("\"hello\"", string, string("hello"), true);
1227 TEST("\"\\\"\\\\\\/\\b\\f\\n\\r\\t\"", string, string("\"\\/\b\f\n\r\t"),
1228 true);
1229 TEST("\"\\u0061\\u30af\\u30ea\\u30b9\"", string,
1230 string("a\xe3\x82\xaf\xe3\x83\xaa\xe3\x82\xb9"), false);
1231 TEST("\"\\ud840\\udc0b\"", string, string("\xf0\xa0\x80\x8b"), false);
1232 #ifdef PICOJSON_USE_INT64
1233 TEST("0", int64_t, 0, true);
1234 TEST("-9223372036854775808", int64_t, std::numeric_limits<int64_t>::min(), true);
1235 TEST("9223372036854775807", int64_t, std::numeric_limits<int64_t>::max(), true);
1236 #endif // PICOJSON_USE_INT64
1237
1238 #undef TEST
1239
1240 #define TEST(type, expr) { \
1241 picojson::value v; \
1242 const char *s = expr; \
1243 string err = picojson::parse(v, s, s + strlen(s)); \
1244 ok(err.empty(), "empty " #type " no error"); \
1245 ok(v.is<picojson::type>(), "empty " #type " check type"); \
1246 ok(v.get<picojson::type>().empty(), "check " #type " array size"); \
1247 }
1248 TEST(array, "[]");
1249 TEST(object, "{}");
1250 #undef TEST
1251
1252 {
1253 picojson::value v;
1254 const char *s = "[1,true,\"hello\"]";
1255 string err = picojson::parse(v, s, s + strlen(s));
1256 ok(err.empty(), "array no error");
1257 ok(v.is<picojson::array>(), "array check type");
1258 is(v.get<picojson::array>().size(), size_t(3), "check array size");
1259 ok(v.contains(0), "check contains array[0]");
1260 ok(v.get(0).is<double>(), "check array[0] type");
1261 is(v.get(0).get<double>(), 1.0, "check array[0] value");
1262 ok(v.contains(1), "check contains array[1]");
1263 ok(v.get(1).is<bool>(), "check array[1] type");
1264 ok(v.get(1).get<bool>(), "check array[1] value");
1265 ok(v.contains(2), "check contains array[2]");
1266 ok(v.get(2).is<string>(), "check array[2] type");
1267 is(v.get(2).get<string>(), string("hello"), "check array[2] value");
1268 ok(!v.contains(3), "check not contains array[3]");
1269 }
1270
1271 {
1272 picojson::value v;
1273 const char *s = "{ \"a\": true }";
1274 string err = picojson::parse(v, s, s + strlen(s));
1275 ok(err.empty(), "object no error");
1276 ok(v.is<picojson::object>(), "object check type");
1277 is(v.get<picojson::object>().size(), size_t(1), "check object size");
1278 ok(v.contains("a"), "check contains property");
1279 ok(v.get("a").is<bool>(), "check bool property exists");
1280 is(v.get("a").get<bool>(), true, "check bool property value");
1281 is(v.serialize(), string("{\"a\":true}"), "serialize object");
1282 ok(!v.contains("z"), "check not contains property");
1283 }
1284
1285 #define TEST(json, msg) do { \
1286 picojson::value v; \
1287 const char *s = json; \
1288 string err = picojson::parse(v, s, s + strlen(s)); \
1289 is(err, string("syntax error at line " msg), msg); \
1290 } while (0)
1291 TEST("falsoa", "1 near: oa");
1292 TEST("{]", "1 near: ]");
1293 TEST("\n\bbell", "2 near: bell");
1294 TEST("\"abc\nd\"", "1 near: ");
1295 #undef TEST
1296
1297 {
1298 picojson::value v1, v2;
1299 const char *s;
1300 string err;
1301 s = "{ \"b\": true, \"a\": [1,2,\"three\"], \"d\": 2 }";
1302 err = picojson::parse(v1, s, s + strlen(s));
1303 s = "{ \"d\": 2.0, \"b\": true, \"a\": [1,2,\"three\"] }";
1304 err = picojson::parse(v2, s, s + strlen(s));
1305 ok((v1 == v2), "check == operator in deep comparison");
1306 }
1307
1308 {
1309 picojson::value v1, v2;
1310 const char *s;
1311 string err;
1312 s = "{ \"b\": true, \"a\": [1,2,\"three\"], \"d\": 2 }";
1313 err = picojson::parse(v1, s, s + strlen(s));
1314 s = "{ \"d\": 2.0, \"a\": [1,\"three\"], \"b\": true }";
1315 err = picojson::parse(v2, s, s + strlen(s));
1316 ok((v1 != v2), "check != operator for array in deep comparison");
1317 }
1318
1319 {
1320 picojson::value v1, v2;
1321 const char *s;
1322 string err;
1323 s = "{ \"b\": true, \"a\": [1,2,\"three\"], \"d\": 2 }";
1324 err = picojson::parse(v1, s, s + strlen(s));
1325 s = "{ \"d\": 2.0, \"a\": [1,2,\"three\"], \"b\": false }";
1326 err = picojson::parse(v2, s, s + strlen(s));
1327 ok((v1 != v2), "check != operator for object in deep comparison");
1328 }
1329
1330 {
1331 picojson::value v1, v2;
1332 const char *s;
1333 string err;
1334 s = "{ \"b\": true, \"a\": [1,2,\"three\"], \"d\": 2 }";
1335 err = picojson::parse(v1, s, s + strlen(s));
1336 picojson::object& o = v1.get<picojson::object>();
1337 o.erase("b");
1338 picojson::array& a = o["a"].get<picojson::array>();
1339 picojson::array::iterator i;
1340 i = std::remove(a.begin(), a.end(), picojson::value(std::string("three")));
1341 a.erase(i, a.end());
1342 s = "{ \"a\": [1,2], \"d\": 2 }";
1343 err = picojson::parse(v2, s, s + strlen(s));
1344 ok((v1 == v2), "check erase()");
1345 }
1346
1347 ok(picojson::value(3.0).serialize() == "3",
1348 "integral number should be serialized as a integer");
1349
1350 {
1351 const char* s = "{ \"a\": [1,2], \"d\": 2 }";
1352 picojson::null_parse_context ctx;
1353 string err;
1354 picojson::_parse(ctx, s, s + strlen(s), &err);
1355 ok(err.empty(), "null_parse_context");
1356 }
1357
1358 {
1359 picojson::value v;
1360 const char *s = "{ \"a\": 1, \"b\": [ 2, { \"b1\": \"abc\" } ], \"c\": {}, \"d\": [] }";
1361 string err;
1362 err = picojson::parse(v, s, s + strlen(s));
1363 ok(err.empty(), "parse test data for prettifying output");
1364 ok(v.serialize() == "{\"a\":1,\"b\":[2,{\"b1\":\"abc\"}],\"c\":{},\"d\":[]}", "non-prettifying output");
1365 ok(v.serialize(true) == "{\n \"a\": 1,\n \"b\": [\n 2,\n {\n \"b1\": \"abc\"\n }\n ],\n \"c\": {},\n \"d\": []\n}\n", "prettifying output");
1366 }
1367
1368 try {
1369 picojson::value v(std::numeric_limits<double>::quiet_NaN());
1370 ok(false, "should not accept NaN");
1371 } catch (std::overflow_error e) {
1372 ok(true, "should not accept NaN");
1373 }
1374
1375 try {
1376 picojson::value v(std::numeric_limits<double>::infinity());
1377 ok(false, "should not accept infinity");
1378 } catch (std::overflow_error e) {
1379 ok(true, "should not accept infinity");
1380 }
1381
1382 try {
1383 picojson::value v(123.);
1384 ok(! v.is<bool>(), "is<wrong_type>() should return false");
1385 v.get<bool>();
1386 ok(false, "get<wrong_type>() should raise an error");
1387 } catch (std::runtime_error e) {
1388 ok(true, "get<wrong_type>() should raise an error");
1389 }
1390
1391 #ifdef PICOJSON_USE_INT64
1392 {
1393 picojson::value v1((int64_t)123);
1394 ok(v1.is<int64_t>(), "is int64_t");
1395 ok(v1.is<double>(), "is double as well");
1396 ok(v1.serialize() == "123", "serialize the value");
1397 ok(v1.get<int64_t>() == 123, "value is correct as int64_t");
1398 ok(v1.get<double>(), "value is correct as double");
1399
1400 ok(! v1.is<int64_t>(), "is no more int64_type once get<double>() is called");
1401 ok(v1.is<double>(), "and is still a double");
1402
1403 const char *s = "-9223372036854775809";
1404 ok(picojson::parse(v1, s, s + strlen(s)).empty(), "parse underflowing int64_t");
1405 ok(! v1.is<int64_t>(), "underflowing int is not int64_t");
1406 ok(v1.is<double>(), "underflowing int is double");
1407 ok(v1.get<double>() + 9.22337203685478e+18 < 65536, "double value is somewhat correct");
1408 }
1409 #endif // PICOJSON_USE_INT64
1410
1411 done_testing();
1412
1413 return success ? 0 : 1;
1414 }
1415
1416 #endif // TEST_PICOJSON
1417