JSON library for parser and serializer picojson is a header-file-only, JSON parser serializer in C++. The original source code is available at https://github.com/kazuho/picojson You can parse a JSON string using something like <<code>> picojson::value v; const char *json = "{\"string\": \"it works\", \"number\": 3.14}"; string err = picojson::parse(v, json, json + strlen(json)); printf("--> res %s\r\n", err.c_str()); printf("string =%s\r\n" , v.get("string").get<string>()); printf("number =%f\r\n" , v.get("number").get<double>()); <</code>> or serialize using something like <<code>> picojson::object v; v["aa"] = picojson::value(string("tt")); v["bb"] = picojson::value(double(1)); string str = picojson::value(v).serialize(); printf("result =%s\r\n" , str.c_str()); <</code>> Note: it seems that there are some memory? issues with "complex" structures. So always test your json with the lib before using it within your application.
Dependents: PicoJSONSample SenseClientSample net-o-meter AV_MQTT ... more
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 Thu Jul 14 2022 08:34:50 by 1.7.2