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
Fork of picojson by
Diff: picojson.h
- Revision:
- 1:2bb500b021e2
- Parent:
- 0:7bd1a48945f5
- Child:
- 2:fa0776ec0f86
diff -r 7bd1a48945f5 -r 2bb500b021e2 picojson.h --- a/picojson.h Wed Aug 31 14:48:57 2011 +0000 +++ b/picojson.h Tue Sep 06 16:49:40 2011 +0000 @@ -29,6 +29,7 @@ #define picojson_h #include <cassert> +#include <cmath> #include <cstdio> #include <cstdlib> #include <cstring> @@ -164,9 +165,9 @@ return *this; } -#define IS(ctype, jtype) \ +#define IS(ctype, jtype) \ template <> inline bool value::is<ctype>() const { \ - return type_ == jtype##_type; \ + return type_ == jtype##_type; \ } IS(null, null) IS(bool, boolean) @@ -177,12 +178,12 @@ IS(object, object) #undef IS -#define GET(ctype, var) \ +#define GET(ctype, var) \ template <> inline const ctype& value::get<ctype>() const { \ - return var; \ - } \ - template <> inline ctype& value::get<ctype>() { \ - return var; \ + return var; \ + } \ + template <> inline ctype& value::get<ctype>() { \ + return var; \ } GET(bool, boolean_) GET(double, number_) @@ -225,7 +226,8 @@ case boolean_type: return boolean_ ? "true" : "false"; case number_type: { char buf[256]; - SNPRINTF(buf, sizeof(buf), "%f", number_); + double tmp; + SNPRINTF(buf, sizeof(buf), modf(number_, &tmp) == 0 ? "%.f" : "%f", number_); return buf; } case string_type: return *string_; @@ -247,24 +249,24 @@ for (std::string::const_iterator i = s.begin(); i != s.end(); ++i) { switch (*i) { #define MAP(val, sym) case val: copy(sym, oi); break - MAP('"', "\\\""); - MAP('\\', "\\\\"); - MAP('/', "\\/"); - MAP('\b', "\\b"); - MAP('\f', "\\f"); - MAP('\n', "\\n"); - MAP('\r', "\\r"); - MAP('\t', "\\t"); + MAP('"', "\\\""); + MAP('\\', "\\\\"); + MAP('/', "\\/"); + MAP('\b', "\\b"); + MAP('\f', "\\f"); + MAP('\n', "\\n"); + MAP('\r', "\\r"); + MAP('\t', "\\t"); #undef MAP default: - if ((unsigned char)*i < 0x20 || *i == 0x7f) { - char buf[7]; - SNPRINTF(buf, sizeof(buf), "\\u%04x", *i & 0xff); - copy(buf, buf + 6, oi); - } else { - *oi++ = *i; - } - break; + if ((unsigned char)*i < 0x20 || *i == 0x7f) { + char buf[7]; + SNPRINTF(buf, sizeof(buf), "\\u%04x", *i & 0xff); + copy(buf, buf + 6, oi); + } else { + *oi++ = *i; + } + break; } } *oi++ = '"'; @@ -278,10 +280,10 @@ case array_type: { *oi++ = '['; for (array::const_iterator i = array_->begin(); i != array_->end(); ++i) { - if (i != array_->begin()) { - *oi++ = ','; - } - i->serialize(oi); + if (i != array_->begin()) { + *oi++ = ','; + } + i->serialize(oi); } *oi++ = ']'; break; @@ -289,14 +291,14 @@ case object_type: { *oi++ = '{'; for (object::const_iterator i = object_->begin(); - i != object_->end(); - ++i) { - if (i != object_->begin()) { - *oi++ = ','; - } - serialize_str(i->first, oi); - *oi++ = ':'; - i->second.serialize(oi); + i != object_->end(); + ++i) { + if (i != object_->begin()) { + *oi++ = ','; + } + serialize_str(i->first, oi); + *oi++ = ':'; + i->second.serialize(oi); } *oi++ = '}'; break; @@ -323,52 +325,52 @@ input(const Iter& first, const Iter& last) : cur_(first), end_(last), last_ch_(-1), ungot_(false), line_(1) {} int getc() { if (ungot_) { - ungot_ = false; - return last_ch_; + ungot_ = false; + return last_ch_; } if (cur_ == end_) { - last_ch_ = -1; - return -1; + last_ch_ = -1; + return -1; } if (last_ch_ == '\n') { - line_++; + line_++; } last_ch_ = *cur_++ & 0xff; return last_ch_; } void ungetc() { if (last_ch_ != -1) { - assert(! ungot_); - ungot_ = true; + assert(! ungot_); + ungot_ = true; } } Iter cur() const { return cur_; } int line() const { return line_; } void skip_ws() { while (1) { - int ch = getc(); - if (! (ch == ' ' || ch == '\t' || ch == '\n' || ch == '\r')) { - ungetc(); - break; - } + int ch = getc(); + if (! (ch == ' ' || ch == '\t' || ch == '\n' || ch == '\r')) { + ungetc(); + break; + } } } int expect(int expect) { skip_ws(); if (getc() != expect) { - ungetc(); - return false; + ungetc(); + return false; } return true; } bool match(const std::string& pattern) { for (std::string::const_iterator pi(pattern.begin()); - pi != pattern.end(); - ++pi) { - if (getc() != *pi) { - ungetc(); - return false; - } + pi != pattern.end(); + ++pi) { + if (getc() != *pi) { + ungetc(); + return false; + } } return true; } @@ -378,17 +380,17 @@ int uni_ch = 0, hex; for (int i = 0; i < 4; i++) { if ((hex = in.getc()) == -1) { - return -1; + return -1; } if ('0' <= hex && hex <= '9') { - hex -= '0'; + hex -= '0'; } else if ('A' <= hex && hex <= 'F') { - hex -= 'A' - 0xa; + hex -= 'A' - 0xa; } else if ('a' <= hex && hex <= 'f') { - hex -= 'a' - 0xa; + hex -= 'a' - 0xa; } else { - in.ungetc(); - return -1; + in.ungetc(); + return -1; } uni_ch = uni_ch * 16 + hex; } @@ -402,17 +404,17 @@ } if (0xd800 <= uni_ch && uni_ch <= 0xdfff) { if (0xdc00 <= uni_ch) { - // a second 16-bit of a surrogate pair appeared - return false; + // a second 16-bit of a surrogate pair appeared + return false; } // first 16-bit of surrogate pair, get the next one if (in.getc() != '\\' || in.getc() != 'u') { - in.ungetc(); - return false; + in.ungetc(); + return false; } int second = _parse_quadhex(in); if (! (0xdc00 <= second && second <= 0xdfff)) { - return false; + return false; } uni_ch = ((uni_ch - 0xd800) << 10) | ((second - 0xdc00) & 0x3ff); uni_ch += 0x10000; @@ -421,15 +423,15 @@ out.push_back(uni_ch); } else { if (uni_ch < 0x800) { - out.push_back(0xc0 | (uni_ch >> 6)); + out.push_back(0xc0 | (uni_ch >> 6)); } else { - if (uni_ch < 0x10000) { - out.push_back(0xe0 | (uni_ch >> 12)); - } else { - out.push_back(0xf0 | (uni_ch >> 18)); - out.push_back(0x80 | ((uni_ch >> 12) & 0x3f)); - } - out.push_back(0x80 | ((uni_ch >> 6) & 0x3f)); + if (uni_ch < 0x10000) { + out.push_back(0xe0 | (uni_ch >> 12)); + } else { + out.push_back(0xf0 | (uni_ch >> 18)); + out.push_back(0x80 | ((uni_ch >> 12) & 0x3f)); + } + out.push_back(0x80 | ((uni_ch >> 6) & 0x3f)); } out.push_back(0x80 | (uni_ch & 0x3f)); } @@ -443,35 +445,35 @@ while (1) { int ch = in.getc(); if (ch < ' ') { - in.ungetc(); - return false; + in.ungetc(); + return false; } else if (ch == '"') { - return true; + return true; } else if (ch == '\\') { - if ((ch = in.getc()) == -1) { - return false; - } - switch (ch) { + if ((ch = in.getc()) == -1) { + return false; + } + switch (ch) { #define MAP(sym, val) case sym: s.push_back(val); break - MAP('"', '\"'); - MAP('\\', '\\'); - MAP('/', '/'); - MAP('b', '\b'); - MAP('f', '\f'); - MAP('n', '\n'); - MAP('r', '\r'); - MAP('t', '\t'); + MAP('"', '\"'); + MAP('\\', '\\'); + MAP('/', '/'); + MAP('b', '\b'); + MAP('f', '\f'); + MAP('n', '\n'); + MAP('r', '\r'); + MAP('t', '\t'); #undef MAP - case 'u': - if (! _parse_codepoint(s, in)) { - return false; - } - break; - default: - return false; - } + case 'u': + if (! _parse_codepoint(s, in)) { + return false; + } + break; + default: + return false; + } } else { - s.push_back(ch); + s.push_back(ch); } } return false; @@ -486,7 +488,7 @@ do { a.push_back(value()); if (! _parse(a.back(), in)) { - return false; + return false; } } while (in.expect(',')); return in.expect(']'); @@ -501,12 +503,12 @@ do { value key, val; if (in.expect('"') - && _parse_string(key, in) - && in.expect(':') - && _parse(val, in)) { - o[key.to_str()] = val; + && _parse_string(key, in) + && in.expect(':') + && _parse(val, in)) { + o[key.to_str()] = val; } else { - return false; + return false; } } while (in.expect(',')); return in.expect('}'); @@ -517,11 +519,11 @@ while (1) { int ch = in.getc(); if (('0' <= ch && ch <= '9') || ch == '+' || ch == '-' || ch == '.' - || ch == 'e' || ch == 'E') { - num_str.push_back(ch); + || ch == 'e' || ch == 'E') { + num_str.push_back(ch); } else { - in.ungetc(); - break; + in.ungetc(); + break; } } char* endp; @@ -535,10 +537,10 @@ switch (ch) { #define IS(ch, text, val) case ch: \ if (in.match(text)) { \ - out = val; \ - return true; \ + out = val; \ + return true; \ } else { \ - return false; \ + return false; \ } IS('n', "ull", value()); IS('f', "alse", value(false)); @@ -552,8 +554,8 @@ return _parse_object(out, in); default: if (('0' <= ch && ch <= '9') || ch == '-') { - in.ungetc(); - return _parse_number(out, in); + in.ungetc(); + return _parse_number(out, in); } break; } @@ -575,12 +577,12 @@ SNPRINTF(buf, sizeof(buf), "syntax error at line %d near: ", in.line()); *err = buf; while (1) { - int ch = in.getc(); - if (ch == -1 || ch == '\n') { - break; - } else if (ch >= ' ') { - err->push_back(ch); - } + int ch = in.getc(); + if (ch == -1 || ch == '\n') { + break; + } else if (ch >= ' ') { + err->push_back(ch); + } } } return in.cur(); @@ -589,7 +591,7 @@ inline std::string parse(value& out, std::istream& is) { std::string err; parse(out, std::istreambuf_iterator<char>(is.rdbuf()), - std::istreambuf_iterator<char>(), &err); + std::istreambuf_iterator<char>(), &err); return err; } @@ -606,11 +608,11 @@ return last_error_t<bool>::s; } - bool operator==(const value& x, const value& y) { + inline bool operator==(const value& x, const value& y) { if (x.is<null>()) return y.is<null>(); -#define PICOJSON_CMP(type) \ - if (x.is<type>()) \ +#define PICOJSON_CMP(type) \ + if (x.is<type>()) \ return y.is<type>() && x.get<type>() == y.get<type>() PICOJSON_CMP(bool); PICOJSON_CMP(double); @@ -682,19 +684,19 @@ int main(void) { - plan(61); + plan(62); -#define TEST(in, type, cmp, serialize_test) { \ - picojson::value v; \ - const char* s = in; \ - string err = picojson::parse(v, s, s + strlen(s)); \ - ok(err.empty(), in " no error"); \ - ok(v.is<type>(), in " check type"); \ - is(v.get<type>(), cmp, in " correct output"); \ - is(*s, '\0', in " read to eof"); \ - if (serialize_test) { \ - is(v.serialize(), string(in), in " serialize"); \ - } \ +#define TEST(in, type, cmp, serialize_test) { \ + picojson::value v; \ + const char* s = in; \ + string err = picojson::parse(v, s, s + strlen(s)); \ + ok(err.empty(), in " no error"); \ + ok(v.is<type>(), in " check type"); \ + is(v.get<type>(), cmp, in " correct output"); \ + is(*s, '\0', in " read to eof"); \ + if (serialize_test) { \ + is(v.serialize(), string(in), in " serialize"); \ + } \ } TEST("false", bool, false, true); TEST("true", bool, true, true); @@ -707,12 +709,12 @@ TEST("\"\\ud840\\udc0b\"", string, string("\xf0\xa0\x80\x8b"), false); #undef TEST -#define TEST(type, expr) { \ - picojson::value v; \ - const char *s = expr; \ - string err = picojson::parse(v, s, s + strlen(s)); \ - ok(err.empty(), "empty " #type " no error"); \ - ok(v.is<picojson::type>(), "empty " #type " check type"); \ +#define TEST(type, expr) { \ + picojson::value v; \ + const char *s = expr; \ + string err = picojson::parse(v, s, s + strlen(s)); \ + ok(err.empty(), "empty " #type " no error"); \ + ok(v.is<picojson::type>(), "empty " #type " check type"); \ ok(v.get<picojson::type>().empty(), "check " #type " array size"); \ } TEST(array, "[]"); @@ -747,11 +749,11 @@ is(v.serialize(), string("{\"a\":true}"), "serialize object"); } -#define TEST(json, msg) do { \ - picojson::value v; \ - const char *s = json; \ - string err = picojson::parse(v, s, s + strlen(s)); \ - is(err, string("syntax error at line " msg), msg); \ +#define TEST(json, msg) do { \ + picojson::value v; \ + const char *s = json; \ + string err = picojson::parse(v, s, s + strlen(s)); \ + is(err, string("syntax error at line " msg), msg); \ } while (0) TEST("falsoa", "1 near: oa"); TEST("{]", "1 near: ]"); @@ -809,7 +811,10 @@ ok((v1 == v2), "check erase()"); } + ok(picojson::value(3.0).serialize() == "3", + "integral number should be serialized as a integer"); + return 0; } -#endif \ No newline at end of file +#endif