Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
picojson.h
00001 /* Copyright 2009 Cybozu Labs, Inc. 00002 * 00003 * Redistribution and use in source and binary forms, with or without 00004 * modification, are permitted provided that the following conditions are met: 00005 * 00006 * 1. Redistributions of source code must retain the above copyright notice, 00007 * this list of conditions and the following disclaimer. 00008 * 2. Redistributions in binary form must reproduce the above copyright notice, 00009 * this list of conditions and the following disclaimer in the documentation 00010 * and/or other materials provided with the distribution. 00011 * 00012 * THIS SOFTWARE IS PROVIDED BY CYBOZU LABS, INC. ``AS IS'' AND ANY EXPRESS OR 00013 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 00014 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO 00015 * EVENT SHALL CYBOZU LABS, INC. OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, 00016 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 00017 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 00018 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 00019 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 00020 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 00021 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 00022 * 00023 * The views and conclusions contained in the software and documentation are 00024 * those of the authors and should not be interpreted as representing official 00025 * policies, either expressed or implied, of Cybozu Labs, Inc. 00026 * 00027 */ 00028 #ifndef picojson_h 00029 #define picojson_h 00030 00031 #include <cassert> 00032 #include <cmath> 00033 #include <cstdio> 00034 #include <cstdlib> 00035 #include <cstring> 00036 #include <iostream> 00037 #include <iterator> 00038 #include <map> 00039 #include <string> 00040 #include <vector> 00041 00042 #ifdef _MSC_VER 00043 #define SNPRINTF _snprintf_s 00044 #pragma warning(push) 00045 #pragma warning(disable : 4244) // conversion from int to char 00046 #else 00047 #define SNPRINTF snprintf 00048 #endif 00049 00050 namespace picojson { 00051 00052 enum { 00053 null_type, 00054 boolean_type, 00055 number_type, 00056 string_type, 00057 array_type, 00058 object_type 00059 }; 00060 00061 struct null {}; 00062 00063 class value { 00064 public: 00065 typedef std::vector<value> array; 00066 typedef std::map<std::string, value> object; 00067 protected: 00068 int type_; 00069 union { 00070 bool boolean_; 00071 double number_; 00072 std::string* string_; 00073 array* array_; 00074 object* object_; 00075 }; 00076 public: 00077 value(); 00078 value(int type, bool); 00079 explicit value(bool b); 00080 explicit value(double n); 00081 explicit value(const std::string& s); 00082 explicit value(const array& a); 00083 explicit value(const object& o); 00084 ~value(); 00085 value(const value& x); 00086 value& operator=(const value& x); 00087 template <typename T> bool is() const; 00088 template <typename T> const T& get() const; 00089 template <typename T> T& get(); 00090 operator bool() const; 00091 const value& get(size_t idx) const; 00092 const value& get(const std::string& key) const; 00093 std::string to_str() const; 00094 template <typename Iter> void serialize(Iter os) const; 00095 std::string serialize() const; 00096 }; 00097 00098 typedef value::array array; 00099 typedef value::object object; 00100 00101 inline value::value() : type_(null_type) {} 00102 00103 inline value::value(int type, bool) : type_(type) { 00104 switch (type) { 00105 #define INIT(p, v) case p##type: p = v; break 00106 INIT(boolean_, false); 00107 INIT(number_, 0.0); 00108 INIT(string_, new std::string()); 00109 INIT(array_, new array()); 00110 INIT(object_, new object()); 00111 #undef INIT 00112 default: break; 00113 } 00114 } 00115 00116 inline value::value(bool b) : type_(boolean_type) { 00117 boolean_ = b; 00118 } 00119 00120 inline value::value(double n) : type_(number_type) { 00121 number_ = n; 00122 } 00123 00124 inline value::value(const std::string& s) : type_(string_type) { 00125 string_ = new std::string(s); 00126 } 00127 00128 inline value::value(const array& a) : type_(array_type) { 00129 array_ = new array(a); 00130 } 00131 00132 inline value::value(const object& o) : type_(object_type) { 00133 object_ = new object(o); 00134 } 00135 00136 inline value::~value() { 00137 switch (type_) { 00138 #define DEINIT(p) case p##type: delete p; break 00139 DEINIT(string_); 00140 DEINIT(array_); 00141 DEINIT(object_); 00142 #undef DEINIT 00143 default: break; 00144 } 00145 } 00146 00147 inline value::value(const value& x) : type_(x.type_) { 00148 switch (type_) { 00149 #define INIT(p, v) case p##type: p = v; break 00150 INIT(boolean_, x.boolean_); 00151 INIT(number_, x.number_); 00152 INIT(string_, new std::string(*x.string_)); 00153 INIT(array_, new array(*x.array_)); 00154 INIT(object_, new object(*x.object_)); 00155 #undef INIT 00156 default: break; 00157 } 00158 } 00159 00160 inline value& value::operator=(const value& x) { 00161 if (this != &x) { 00162 this->~value(); 00163 new (this) value(x); 00164 } 00165 return *this; 00166 } 00167 00168 #define IS(ctype, jtype) \ 00169 template <> inline bool value::is<ctype>() const { \ 00170 return type_ == jtype##_type; \ 00171 } 00172 IS(null, null) 00173 IS(bool, boolean) 00174 IS(int, number) 00175 IS(double, number) 00176 IS(std::string, string) 00177 IS(array, array) 00178 IS(object, object) 00179 #undef IS 00180 00181 #define GET(ctype, var) \ 00182 template <> inline const ctype& value::get<ctype>() const { \ 00183 return var; \ 00184 } \ 00185 template <> inline ctype& value::get<ctype>() { \ 00186 return var; \ 00187 } 00188 GET(bool, boolean_) 00189 GET(double, number_) 00190 GET(std::string, *string_) 00191 GET(array, *array_) 00192 GET(object, *object_) 00193 #undef GET 00194 00195 inline value::operator bool() const { 00196 switch (type_) { 00197 case null_type: 00198 return false; 00199 case boolean_type: 00200 return boolean_; 00201 case number_type: 00202 return number_ != 0; 00203 case string_type: 00204 return ! string_->empty(); 00205 default: 00206 return true; 00207 } 00208 } 00209 00210 inline const value& value::get(size_t idx) const { 00211 static value s_null; 00212 assert(is<array>()); 00213 return idx < array_->size() ? (*array_)[idx] : s_null; 00214 } 00215 00216 inline const value& value::get(const std::string& key) const { 00217 static value s_null; 00218 assert(is<object>()); 00219 object::const_iterator i = object_->find(key); 00220 return i != object_->end() ? i->second : s_null; 00221 } 00222 00223 inline std::string value::to_str() const { 00224 switch (type_) { 00225 case null_type: return "null"; 00226 case boolean_type: return boolean_ ? "true" : "false"; 00227 case number_type: { 00228 char buf[256]; 00229 double tmp; 00230 SNPRINTF(buf, sizeof(buf), modf(number_, &tmp) == 0 ? "%.f" : "%f", number_); 00231 return buf; 00232 } 00233 case string_type: return *string_; 00234 case array_type: return "array"; 00235 case object_type: return "object"; 00236 default: assert(0); 00237 #ifdef _MSC_VER 00238 __assume(0); 00239 #endif 00240 } 00241 } 00242 00243 template <typename Iter> void copy(const std::string& s, Iter oi) { 00244 std::copy(s.begin(), s.end(), oi); 00245 } 00246 00247 template <typename Iter> void serialize_str(const std::string& s, Iter oi) { 00248 *oi++ = '"'; 00249 for (std::string::const_iterator i = s.begin(); i != s.end(); ++i) { 00250 switch (*i) { 00251 #define MAP(val, sym) case val: copy(sym, oi); break 00252 MAP('"', "\\\""); 00253 MAP('\\', "\\\\"); 00254 MAP('/', "\\/"); 00255 MAP('\b', "\\b"); 00256 MAP('\f', "\\f"); 00257 MAP('\n', "\\n"); 00258 MAP('\r', "\\r"); 00259 MAP('\t', "\\t"); 00260 #undef MAP 00261 default: 00262 if ((unsigned char)*i < 0x20 || *i == 0x7f) { 00263 char buf[7]; 00264 SNPRINTF(buf, sizeof(buf), "\\u%04x", *i & 0xff); 00265 copy(buf, buf + 6, oi); 00266 } else { 00267 *oi++ = *i; 00268 } 00269 break; 00270 } 00271 } 00272 *oi++ = '"'; 00273 } 00274 00275 template <typename Iter> void value::serialize(Iter oi) const { 00276 switch (type_) { 00277 case string_type: 00278 serialize_str(*string_, oi); 00279 break; 00280 case array_type: { 00281 *oi++ = '['; 00282 for (array::const_iterator i = array_->begin(); i != array_->end(); ++i) { 00283 if (i != array_->begin()) { 00284 *oi++ = ','; 00285 } 00286 i->serialize(oi); 00287 } 00288 *oi++ = ']'; 00289 break; 00290 } 00291 case object_type: { 00292 *oi++ = '{'; 00293 for (object::const_iterator i = object_->begin(); 00294 i != object_->end(); 00295 ++i) { 00296 if (i != object_->begin()) { 00297 *oi++ = ','; 00298 } 00299 serialize_str(i->first, oi); 00300 *oi++ = ':'; 00301 i->second.serialize(oi); 00302 } 00303 *oi++ = '}'; 00304 break; 00305 } 00306 default: 00307 copy(to_str(), oi); 00308 break; 00309 } 00310 } 00311 00312 inline std::string value::serialize() const { 00313 std::string s; 00314 serialize(std::back_inserter(s)); 00315 return s; 00316 } 00317 00318 template <typename Iter> class input { 00319 protected: 00320 Iter cur_, end_; 00321 int last_ch_; 00322 bool ungot_; 00323 int line_; 00324 public: 00325 input(const Iter& first, const Iter& last) : cur_(first), end_(last), last_ch_(-1), ungot_(false), line_(1) {} 00326 int getc() { 00327 if (ungot_) { 00328 ungot_ = false; 00329 return last_ch_; 00330 } 00331 if (cur_ == end_) { 00332 last_ch_ = -1; 00333 return -1; 00334 } 00335 if (last_ch_ == '\n') { 00336 line_++; 00337 } 00338 last_ch_ = *cur_++ & 0xff; 00339 return last_ch_; 00340 } 00341 void ungetc() { 00342 if (last_ch_ != -1) { 00343 assert(! ungot_); 00344 ungot_ = true; 00345 } 00346 } 00347 Iter cur() const { return cur_; } 00348 int line() const { return line_; } 00349 void skip_ws() { 00350 while (1) { 00351 int ch = getc(); 00352 if (! (ch == ' ' || ch == '\t' || ch == '\n' || ch == '\r')) { 00353 ungetc(); 00354 break; 00355 } 00356 } 00357 } 00358 int expect(int expect) { 00359 skip_ws(); 00360 if (getc() != expect) { 00361 ungetc(); 00362 return false; 00363 } 00364 return true; 00365 } 00366 bool match(const std::string& pattern) { 00367 for (std::string::const_iterator pi(pattern.begin()); 00368 pi != pattern.end(); 00369 ++pi) { 00370 if (getc() != *pi) { 00371 ungetc(); 00372 return false; 00373 } 00374 } 00375 return true; 00376 } 00377 }; 00378 00379 template<typename Iter> inline int _parse_quadhex(input<Iter> &in) { 00380 int uni_ch = 0, hex; 00381 for (int i = 0; i < 4; i++) { 00382 if ((hex = in.getc()) == -1) { 00383 return -1; 00384 } 00385 if ('0' <= hex && hex <= '9') { 00386 hex -= '0'; 00387 } else if ('A' <= hex && hex <= 'F') { 00388 hex -= 'A' - 0xa; 00389 } else if ('a' <= hex && hex <= 'f') { 00390 hex -= 'a' - 0xa; 00391 } else { 00392 in.ungetc(); 00393 return -1; 00394 } 00395 uni_ch = uni_ch * 16 + hex; 00396 } 00397 return uni_ch; 00398 } 00399 00400 template<typename Iter> inline bool _parse_codepoint(std::string& out, input<Iter>& in) { 00401 int uni_ch; 00402 if ((uni_ch = _parse_quadhex(in)) == -1) { 00403 return false; 00404 } 00405 if (0xd800 <= uni_ch && uni_ch <= 0xdfff) { 00406 if (0xdc00 <= uni_ch) { 00407 // a second 16-bit of a surrogate pair appeared 00408 return false; 00409 } 00410 // first 16-bit of surrogate pair, get the next one 00411 if (in.getc() != '\\' || in.getc() != 'u') { 00412 in.ungetc(); 00413 return false; 00414 } 00415 int second = _parse_quadhex(in); 00416 if (! (0xdc00 <= second && second <= 0xdfff)) { 00417 return false; 00418 } 00419 uni_ch = ((uni_ch - 0xd800) << 10) | ((second - 0xdc00) & 0x3ff); 00420 uni_ch += 0x10000; 00421 } 00422 if (uni_ch < 0x80) { 00423 out.push_back(uni_ch); 00424 } else { 00425 if (uni_ch < 0x800) { 00426 out.push_back(0xc0 | (uni_ch >> 6)); 00427 } else { 00428 if (uni_ch < 0x10000) { 00429 out.push_back(0xe0 | (uni_ch >> 12)); 00430 } else { 00431 out.push_back(0xf0 | (uni_ch >> 18)); 00432 out.push_back(0x80 | ((uni_ch >> 12) & 0x3f)); 00433 } 00434 out.push_back(0x80 | ((uni_ch >> 6) & 0x3f)); 00435 } 00436 out.push_back(0x80 | (uni_ch & 0x3f)); 00437 } 00438 return true; 00439 } 00440 00441 template<typename Iter> inline bool _parse_string(value& out, input<Iter>& in) { 00442 // gcc 4.1 cannot compile if the below two lines are merged into one :-( 00443 out = value(string_type, false); 00444 std::string& s = out.get<std::string>(); 00445 while (1) { 00446 int ch = in.getc(); 00447 if (ch < ' ') { 00448 in.ungetc(); 00449 return false; 00450 } else if (ch == '"') { 00451 return true; 00452 } else if (ch == '\\') { 00453 if ((ch = in.getc()) == -1) { 00454 return false; 00455 } 00456 switch (ch) { 00457 #define MAP(sym, val) case sym: s.push_back(val); break 00458 MAP('"', '\"'); 00459 MAP('\\', '\\'); 00460 MAP('/', '/'); 00461 MAP('b', '\b'); 00462 MAP('f', '\f'); 00463 MAP('n', '\n'); 00464 MAP('r', '\r'); 00465 MAP('t', '\t'); 00466 #undef MAP 00467 case 'u': 00468 if (! _parse_codepoint(s, in)) { 00469 return false; 00470 } 00471 break; 00472 default: 00473 return false; 00474 } 00475 } else { 00476 s.push_back(ch); 00477 } 00478 } 00479 return false; 00480 } 00481 00482 template <typename Iter> inline bool _parse_array(value& out, input<Iter>& in) { 00483 out = value(array_type, false); 00484 array& a = out.get<array>(); 00485 if (in.expect(']')) { 00486 return true; 00487 } 00488 do { 00489 a.push_back(value()); 00490 if (! _parse(a.back(), in)) { 00491 return false; 00492 } 00493 } while (in.expect(',')); 00494 return in.expect(']'); 00495 } 00496 00497 template <typename Iter> inline bool _parse_object(value& out, input<Iter>& in) { 00498 out = value(object_type, false); 00499 object& o = out.get<object>(); 00500 if (in.expect('}')) { 00501 return true; 00502 } 00503 do { 00504 value key, val; 00505 if (in.expect('"') 00506 && _parse_string(key, in) 00507 && in.expect(':') 00508 && _parse(val, in)) { 00509 o[key.to_str()] = val; 00510 } else { 00511 return false; 00512 } 00513 } while (in.expect(',')); 00514 return in.expect('}'); 00515 } 00516 00517 template <typename Iter> inline bool _parse_number(value& out, input<Iter>& in) { 00518 std::string num_str; 00519 while (1) { 00520 int ch = in.getc(); 00521 if (('0' <= ch && ch <= '9') || ch == '+' || ch == '-' || ch == '.' 00522 || ch == 'e' || ch == 'E') { 00523 num_str.push_back(ch); 00524 } else { 00525 in.ungetc(); 00526 break; 00527 } 00528 } 00529 char* endp; 00530 out = value(strtod(num_str.c_str(), &endp)); 00531 return endp == num_str.c_str() + num_str.size(); 00532 } 00533 00534 template <typename Iter> inline bool _parse(value& out, input<Iter>& in) { 00535 in.skip_ws(); 00536 int ch = in.getc(); 00537 switch (ch) { 00538 #define IS(ch, text, val) case ch: \ 00539 if (in.match(text)) { \ 00540 out = val; \ 00541 return true; \ 00542 } else { \ 00543 return false; \ 00544 } 00545 IS('n', "ull", value()); 00546 IS('f', "alse", value(false)); 00547 IS('t', "rue", value(true)); 00548 #undef IS 00549 case '"': 00550 return _parse_string(out, in); 00551 case '[': 00552 return _parse_array(out, in); 00553 case '{': 00554 return _parse_object(out, in); 00555 default: 00556 if (('0' <= ch && ch <= '9') || ch == '-') { 00557 in.ungetc(); 00558 return _parse_number(out, in); 00559 } 00560 break; 00561 } 00562 in.ungetc(); 00563 return false; 00564 } 00565 00566 // obsolete, use the version below 00567 template <typename Iter> inline std::string parse(value& out, Iter& pos, const Iter& last) { 00568 std::string err; 00569 pos = parse(out, pos, last, &err); 00570 return err; 00571 } 00572 00573 template <typename Iter> inline Iter parse(value& out, const Iter& first, const Iter& last, std::string* err) { 00574 input<Iter> in(first, last); 00575 if (! _parse(out, in) && err != NULL) { 00576 char buf[64]; 00577 SNPRINTF(buf, sizeof(buf), "syntax error at line %d near: ", in.line()); 00578 *err = buf; 00579 while (1) { 00580 int ch = in.getc(); 00581 if (ch == -1 || ch == '\n') { 00582 break; 00583 } else if (ch >= ' ') { 00584 err->push_back(ch); 00585 } 00586 } 00587 } 00588 return in.cur(); 00589 } 00590 00591 inline std::string parse(value& out, std::istream& is) { 00592 std::string err; 00593 parse(out, std::istreambuf_iterator<char>(is.rdbuf()), 00594 std::istreambuf_iterator<char>(), &err); 00595 return err; 00596 } 00597 00598 template <typename T> struct last_error_t { 00599 static std::string s; 00600 }; 00601 template <typename T> std::string last_error_t<T>::s; 00602 00603 inline void set_last_error(const std::string& s) { 00604 last_error_t<bool>::s = s; 00605 } 00606 00607 inline const std::string& get_last_error() { 00608 return last_error_t<bool>::s; 00609 } 00610 00611 inline bool operator==(const value& x, const value& y) { 00612 if (x.is<null>()) 00613 return y.is<null>(); 00614 #define PICOJSON_CMP(type) \ 00615 if (x.is<type>()) \ 00616 return y.is<type>() && x.get<type>() == y.get<type>() 00617 PICOJSON_CMP(bool); 00618 PICOJSON_CMP(double); 00619 PICOJSON_CMP(std::string); 00620 PICOJSON_CMP(array); 00621 PICOJSON_CMP(object); 00622 #undef PICOJSON_CMP 00623 assert(0); 00624 #ifdef _MSC_VER 00625 __assume(0); 00626 #endif 00627 return false; 00628 } 00629 00630 inline bool operator!=(const value& x, const value& y) { 00631 return ! (x == y); 00632 } 00633 } 00634 00635 inline std::istream& operator>>(std::istream& is, picojson::value& x) 00636 { 00637 picojson::set_last_error(std::string()); 00638 std::string err = picojson::parse(x, is); 00639 if (! err.empty()) { 00640 picojson::set_last_error(err); 00641 is.setstate(std::ios::failbit); 00642 } 00643 return is; 00644 } 00645 00646 inline std::ostream& operator<<(std::ostream& os, const picojson::value& x) 00647 { 00648 x.serialize(std::ostream_iterator<char>(os)); 00649 return os; 00650 } 00651 #ifdef _MSC_VER 00652 #pragma warning(pop) 00653 #endif 00654 00655 #endif 00656 #ifdef TEST_PICOJSON 00657 #ifdef _MSC_VER 00658 #pragma warning(disable : 4127) // conditional expression is constant 00659 #endif 00660 00661 using namespace std; 00662 00663 static void plan(int num) 00664 { 00665 printf("1..%d\n", num); 00666 } 00667 00668 static void ok(bool b, const char* name = "") 00669 { 00670 static int n = 1; 00671 printf("%s %d - %s\n", b ? "ok" : "ng", n++, name); 00672 } 00673 00674 template <typename T> void is(const T& x, const T& y, const char* name = "") 00675 { 00676 if (x == y) { 00677 ok(true, name); 00678 } else { 00679 ok(false, name); 00680 } 00681 } 00682 00683 #include <algorithm> 00684 00685 int main(void) 00686 { 00687 plan(62); 00688 00689 #define TEST(in, type, cmp, serialize_test) { \ 00690 picojson::value v; \ 00691 const char* s = in; \ 00692 string err = picojson::parse(v, s, s + strlen(s)); \ 00693 ok(err.empty(), in " no error"); \ 00694 ok(v.is<type>(), in " check type"); \ 00695 is(v.get<type>(), cmp, in " correct output"); \ 00696 is(*s, '\0', in " read to eof"); \ 00697 if (serialize_test) { \ 00698 is(v.serialize(), string(in), in " serialize"); \ 00699 } \ 00700 } 00701 TEST("false", bool, false, true); 00702 TEST("true", bool, true, true); 00703 TEST("90.5", double, 90.5, false); 00704 TEST("\"hello\"", string, string("hello"), true); 00705 TEST("\"\\\"\\\\\\/\\b\\f\\n\\r\\t\"", string, string("\"\\/\b\f\n\r\t"), 00706 true); 00707 TEST("\"\\u0061\\u30af\\u30ea\\u30b9\"", string, 00708 string("a\xe3\x82\xaf\xe3\x83\xaa\xe3\x82\xb9"), false); 00709 TEST("\"\\ud840\\udc0b\"", string, string("\xf0\xa0\x80\x8b"), false); 00710 #undef TEST 00711 00712 #define TEST(type, expr) { \ 00713 picojson::value v; \ 00714 const char *s = expr; \ 00715 string err = picojson::parse(v, s, s + strlen(s)); \ 00716 ok(err.empty(), "empty " #type " no error"); \ 00717 ok(v.is<picojson::type>(), "empty " #type " check type"); \ 00718 ok(v.get<picojson::type>().empty(), "check " #type " array size"); \ 00719 } 00720 TEST(array, "[]"); 00721 TEST(object, "{}"); 00722 #undef TEST 00723 00724 { 00725 picojson::value v; 00726 const char *s = "[1,true,\"hello\"]"; 00727 string err = picojson::parse(v, s, s + strlen(s)); 00728 ok(err.empty(), "array no error"); 00729 ok(v.is<picojson::array>(), "array check type"); 00730 is(v.get<picojson::array>().size(), size_t(3), "check array size"); 00731 ok(v.get(0).is<double>(), "check array[0] type"); 00732 is(v.get(0).get<double>(), 1.0, "check array[0] value"); 00733 ok(v.get(1).is<bool>(), "check array[1] type"); 00734 ok(v.get(1).get<bool>(), "check array[1] value"); 00735 ok(v.get(2).is<string>(), "check array[2] type"); 00736 is(v.get(2).get<string>(), string("hello"), "check array[2] value"); 00737 } 00738 00739 { 00740 picojson::value v; 00741 const char *s = "{ \"a\": true }"; 00742 string err = picojson::parse(v, s, s + strlen(s)); 00743 ok(err.empty(), "object no error"); 00744 ok(v.is<picojson::object>(), "object check type"); 00745 is(v.get<picojson::object>().size(), size_t(1), "check object size"); 00746 ok(v.get("a").is<bool>(), "check property exists"); 00747 is(v.get("a").get<bool>(), true, 00748 "check property value"); 00749 is(v.serialize(), string("{\"a\":true}"), "serialize object"); 00750 } 00751 00752 #define TEST(json, msg) do { \ 00753 picojson::value v; \ 00754 const char *s = json; \ 00755 string err = picojson::parse(v, s, s + strlen(s)); \ 00756 is(err, string("syntax error at line " msg), msg); \ 00757 } while (0) 00758 TEST("falsoa", "1 near: oa"); 00759 TEST("{]", "1 near: ]"); 00760 TEST("\n\bbell", "2 near: bell"); 00761 TEST("\"abc\nd\"", "1 near: "); 00762 #undef TEST 00763 00764 { 00765 picojson::value v1, v2; 00766 const char *s; 00767 string err; 00768 s = "{ \"b\": true, \"a\": [1,2,\"three\"], \"d\": 2 }"; 00769 err = picojson::parse(v1, s, s + strlen(s)); 00770 s = "{ \"d\": 2.0, \"b\": true, \"a\": [1,2,\"three\"] }"; 00771 err = picojson::parse(v2, s, s + strlen(s)); 00772 ok((v1 == v2), "check == operator in deep comparison"); 00773 } 00774 00775 { 00776 picojson::value v1, v2; 00777 const char *s; 00778 string err; 00779 s = "{ \"b\": true, \"a\": [1,2,\"three\"], \"d\": 2 }"; 00780 err = picojson::parse(v1, s, s + strlen(s)); 00781 s = "{ \"d\": 2.0, \"a\": [1,\"three\"], \"b\": true }"; 00782 err = picojson::parse(v2, s, s + strlen(s)); 00783 ok((v1 != v2), "check != operator for array in deep comparison"); 00784 } 00785 00786 { 00787 picojson::value v1, v2; 00788 const char *s; 00789 string err; 00790 s = "{ \"b\": true, \"a\": [1,2,\"three\"], \"d\": 2 }"; 00791 err = picojson::parse(v1, s, s + strlen(s)); 00792 s = "{ \"d\": 2.0, \"a\": [1,2,\"three\"], \"b\": false }"; 00793 err = picojson::parse(v2, s, s + strlen(s)); 00794 ok((v1 != v2), "check != operator for object in deep comparison"); 00795 } 00796 00797 { 00798 picojson::value v1, v2; 00799 const char *s; 00800 string err; 00801 s = "{ \"b\": true, \"a\": [1,2,\"three\"], \"d\": 2 }"; 00802 err = picojson::parse(v1, s, s + strlen(s)); 00803 picojson::object& o = v1.get<picojson::object>(); 00804 o.erase("b"); 00805 picojson::array& a = o["a"].get<picojson::array>(); 00806 picojson::array::iterator i; 00807 i = std::remove(a.begin(), a.end(), picojson::value(std::string("three"))); 00808 a.erase(i, a.end()); 00809 s = "{ \"a\": [1,2], \"d\": 2 }"; 00810 err = picojson::parse(v2, s, s + strlen(s)); 00811 ok((v1 == v2), "check erase()"); 00812 } 00813 00814 ok(picojson::value(3.0).serialize() == "3", 00815 "integral number should be serialized as a integer"); 00816 00817 return 0; 00818 } 00819 00820 #endif
Generated on Sun Jul 17 2022 16:37:42 by
1.7.2