root/lang/cplusplus/picojson/trunk/picojson.h @ 34239

Revision 34239, 17.1 kB (checked in by kazuho, 4 years ago)

switch to iter-based impl.

Line 
1/* Copyright 2009 Cybozu Labs, Inc.
2 *
3 * Redistribution and use in source and binary forms, with or without
4 * modification, are permitted provided that the following conditions are met:
5 *
6 * 1. Redistributions of source code must retain the above copyright notice,
7 *    this list of conditions and the following disclaimer.
8 * 2. Redistributions in binary form must reproduce the above copyright notice,
9 *    this list of conditions and the following disclaimer in the documentation
10 *    and/or other materials provided with the distribution.
11 *
12 * THIS SOFTWARE IS PROVIDED BY CYBOZU LABS, INC. ``AS IS'' AND ANY EXPRESS OR
13 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
14 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
15 * EVENT SHALL CYBOZU LABS, INC. OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
16 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
17 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
18 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
19 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
20 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
21 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
22 *
23 * The views and conclusions contained in the software and documentation are
24 * those of the authors and should not be interpreted as representing official
25 * policies, either expressed or implied, of Cybozu Labs, Inc.
26 *
27 */
28#ifndef picojson_h
29#define picojson_h
30
31#include <cassert>
32#include <cstdlib>
33#include <cstring>
34#include <iostream>
35#include <iterator>
36#include <map>
37#include <string>
38#include <vector>
39
40namespace picojson {
41 
42  enum {
43    undefined_type,
44    null_type,
45    boolean_type,
46    number_type,
47    string_type,
48    array_type,
49    object_type
50  };
51 
52  struct undefined {};
53 
54  struct null {};
55 
56  class value {
57  public:
58    typedef std::vector<value> array;
59    typedef std::map<std::string, value> object;
60  protected:
61    int type_;
62    union {
63      bool boolean_;
64      double number_;
65      std::string* string_;
66      array* array_;
67      object* object_;
68    };
69  public:
70    value(int type = undefined_type);
71    ~value();
72    value(const value& x);
73    value& operator=(const value& x);
74    template <typename T> bool is() const;
75    template <typename T> const T& get() const;
76    template <typename T> T& get();
77    operator bool() const;
78    const value& get(size_t idx) const;
79    const value& get(const std::string& key) const;
80    std::string to_str() const;
81    template <typename Iter> void serialize(Iter os) const;
82    std::string serialize() const;
83  };
84 
85  typedef value::array array;
86  typedef value::object object;
87 
88  inline value::value(int type) : type_(type) {
89    switch (type) {
90#define INIT(p, v) case p##type: p = v; break
91      INIT(boolean_, false);
92      INIT(number_, 0.0);
93      INIT(string_, new std::string());
94      INIT(array_, new array());
95      INIT(object_, new object());
96#undef INIT
97    default: break;
98    }
99  }
100 
101  inline value::~value() {
102    switch (type_) {
103#define DEINIT(p) case p##type: delete p; break
104      DEINIT(string_);
105      DEINIT(array_);
106      DEINIT(object_);
107#undef DEINIT
108    default: break;
109    }
110  }
111 
112  inline value::value(const value& x) : type_(x.type_) {
113    switch (type_) {
114#define INIT(p, v) case p##type: p = v; break
115      INIT(boolean_, x.boolean_);
116      INIT(number_, x.number_);
117      INIT(string_, new std::string(*x.string_));
118      INIT(array_, new array(*x.array_));
119      INIT(object_, new object(*x.object_));
120#undef INIT
121    default: break;
122    }
123  }
124 
125  inline value& value::operator=(const value& x) {
126    if (this != &x) {
127      this->~value();
128      new (this) value(x);
129    }
130    return *this;
131  }
132 
133#define IS(ctype, jtype)                             \
134  template <> inline bool value::is<ctype>() const { \
135    return type_ == jtype##_type;                    \
136  }
137  IS(undefined, undefined)
138  IS(null, null)
139  IS(bool, boolean)
140  IS(int, number)
141  IS(double, number)
142  IS(std::string, string)
143  IS(array, array)
144  IS(object, object)
145#undef IS
146 
147#define GET(ctype, var)                                       \
148  template <> inline const ctype& value::get<ctype>() const { \
149    return var;                                               \
150  }                                                           \
151  template <> inline ctype& value::get<ctype>() {             \
152    return var;                                               \
153  }
154  GET(bool, boolean_)
155  GET(double, number_)
156  GET(std::string, *string_)
157  GET(array, *array_)
158  GET(object, *object_)
159#undef GET
160 
161  inline value::operator bool() const {
162    switch (type_) {
163    case undefined_type:
164    case null_type:
165      return false;
166    case boolean_type:
167      return boolean_;
168    case number_type:
169      return number_;
170    case string_type:
171      return ! string_->empty();
172    default:
173      return true;
174    }
175  }
176 
177  inline const value& value::get(size_t idx) const {
178    static value s_undefined(undefined_type);
179    assert(is<array>());
180    return idx < array_->size() ? (*array_)[idx] : s_undefined;
181  }
182
183  inline const value& value::get(const std::string& key) const {
184    static value s_undefined(undefined_type);
185    assert(is<object>());
186    object::const_iterator i = object_->find(key);
187    return i != object_->end() ? i->second : s_undefined;
188  }
189 
190  inline std::string value::to_str() const {
191    switch (type_) {
192    case undefined_type: return "undefined";
193    case null_type:      return "null";
194    case boolean_type:   return boolean_ ? "true" : "false";
195    case number_type:    {
196      char buf[256];
197#ifdef _MSC_VER
198      _snprintf_s(buf, sizeof(buf), "%f", number_);
199#else
200      snprintf(buf, sizeof(buf), "%f", number_);
201#endif
202      return buf;
203    }
204    case string_type:    return *string_;
205    case array_type:     return "array";
206    case object_type:    return "object";
207    default:             assert(0);
208#ifdef _MSC_VER
209      __assume(0);
210#endif
211    }
212  }
213 
214  template <typename Iter> void copy(const std::string& s, Iter oi) {
215    std::copy(s.begin(), s.end(), oi);
216  }
217 
218  template <typename Iter> void serialize_str(const std::string& s, Iter oi) {
219    *oi++ = '"';
220    for (std::string::const_iterator i = s.begin(); i != s.end(); ++i) {
221      switch (*i) {
222#define MAP(val, sym) case val: copy(sym, oi); break
223        MAP('"', "\\\"");
224        MAP('\\', "\\\\");
225        MAP('/', "\\/");
226        MAP('\b', "\\b");
227        MAP('\f', "\\f");
228        MAP('\n', "\\n");
229        MAP('\r', "\\r");
230        MAP('\t', "\\t");
231#undef MAP
232      default:
233        if ((unsigned char)*i <= 0x20 || *i == 0x7f) {
234          char buf[7];
235          sprintf(buf, "\\u%04x", *i & 0xff);
236          copy(buf, buf + 6, oi);
237          } else {
238          *oi++ = *i;
239        }
240        break;
241      }
242    }
243    *oi++ = '"';
244  }
245 
246  template <typename Iter> void value::serialize(Iter oi) const {
247    switch (type_) {
248    case string_type:
249      serialize_str(*string_, oi);
250      break;
251    case array_type: {
252      *oi++ = '[';
253      for (array::const_iterator i = array_->begin(); i != array_->end(); ++i) {
254        if (i != array_->begin()) {
255          *oi++ = ',';
256        }
257        i->serialize(oi);
258      }
259      *oi++ = ']';
260      break;
261    }
262    case object_type: {
263      *oi++ = '{';
264      for (object::const_iterator i = object_->begin();
265           i != object_->end();
266           ++i) {
267        if (i != object_->begin()) {
268          *oi++ = ',';
269        }
270        serialize_str(i->first, oi);
271        *oi++ = ':';
272        i->second.serialize(oi);
273      }
274      *oi++ = '}';
275      break;
276    }
277    default:
278      copy(to_str(), oi);
279      break;
280    }
281  }
282 
283  inline std::string value::serialize() const {
284    std::string s;
285    serialize(std::back_inserter(s));
286    return s;
287  }
288 
289  template <typename Iter> class input {
290  protected:
291    Iter cur_, end_;
292    int last_ch_;
293    bool ungot_;
294    int line_;
295  public:
296    input(const Iter& first, const Iter& last) : cur_(first), end_(last), last_ch_(-1), ungot_(false), line_(1) {}
297    bool eof() const { return cur_ == end_ && ! ungot_; }
298    int getc() {
299      if (ungot_) {
300        ungot_ = false;
301        return last_ch_;
302      }
303      if (cur_ == end_) {
304        return -1;
305      }
306      if (last_ch_ == '\n') {
307        line_++;
308      }
309      last_ch_ = *cur_++ & 0xff;
310      return last_ch_;
311    }
312    void ungetc() {
313      if (last_ch_ != -1) {
314        assert(! ungot_);
315        ungot_ = true;
316      }
317    }
318    Iter cur() const { return cur_; }
319    int line() const { return line_; }
320    void skip_ws() {
321      while (! eof()) {
322        if (! isspace(getc())) {
323          ungetc();
324          break;
325        }
326      }
327    }
328    enum {
329      error,
330      negative,
331      positive
332    };
333    int match(const std::string& pattern) {
334      skip_ws();
335      std::string::const_iterator pi(pattern.begin());
336      for (; pi != pattern.end(); ++pi) {
337        if (eof()) {
338          break;
339        } else if (getc() != *pi) {
340          ungetc();
341          break;
342        }
343      }
344      if (pi == pattern.end()) {
345        return positive;
346      } else if (pi == pattern.begin()) {
347        return negative;
348      } else {
349        return error;
350      }
351    }
352  };
353 
354  template<typename Iter> static int _parse_quadhex(input<Iter> &in) {
355    int uni_ch = 0, hex;
356    for (int i = 0; i < 4; i++) {
357      if ((hex = in.getc()) == -1) {
358        return -1;
359      }
360      if ('0' <= hex && hex <= '9') {
361        hex -= '0';
362      } else if ('A' <= hex && hex <= 'F') {
363        hex -= 'A' - 0xa;
364      } else if ('a' <= hex && hex <= 'f') {
365        hex -= 'a' - 0xa;
366      } else {
367        return -1;
368      }
369      uni_ch = uni_ch * 16 + hex;
370    }
371    return uni_ch;
372  }
373 
374  template<typename Iter> static bool _parse_codepoint(std::string& out, input<Iter>& in) {
375    int uni_ch;
376    if ((uni_ch = _parse_quadhex(in)) == -1) {
377      return false;
378    }
379    if (0xd800 <= uni_ch && uni_ch <= 0xdfff) {
380      if (0xdc00 <= uni_ch) {
381        // a second 16-bit of a surrogate pair appeared
382        return false;
383      }
384      // first 16-bit of surrogate pair, get the next one
385      if (in.getc() != '\\' || in.getc() != 'u') {
386        return false;
387      }
388      int second = _parse_quadhex(in);
389      if (! (0xdc00 <= second && second <= 0xdfff)) {
390        return false;
391      }
392      uni_ch = ((uni_ch - 0xd800) << 10) | ((second - 0xdc00) & 0x3ff);
393      uni_ch += 0x10000;
394    }
395    if (uni_ch < 0x80) {
396      out.push_back(uni_ch);
397    } else {
398      if (uni_ch < 0x800) {
399        out.push_back(0xc0 | (uni_ch >> 6));
400      } else {
401        if (uni_ch < 0x10000) {
402          out.push_back(0xe0 | (uni_ch >> 12));
403        } else {
404          out.push_back(0xf0 | (uni_ch >> 18));
405          out.push_back(0x80 | ((uni_ch >> 12) & 0x3f));
406        }
407        out.push_back(0x80 | ((uni_ch >> 6) & 0x3f));
408      }
409      out.push_back(0x80 | (uni_ch & 0x3f));
410    }
411    return true;
412  }
413 
414  template<typename Iter> static bool _parse_string(value& out, input<Iter>& in) {
415    // gcc 4.1 cannot compile if the below two lines are merged into one :-(
416    out = value(string_type);
417    std::string& s = out.get<std::string>();
418    while (! in.eof()) {
419      int ch = in.getc();
420      if (ch == '"') {
421        return true;
422      } else if (ch == '\\') {
423        if ((ch = in.getc()) == -1) {
424          return false;
425        }
426        switch (ch) {
427#define MAP(sym, val) case sym: s.push_back(val); break
428          MAP('"', '\"');
429          MAP('\\', '\\');
430          MAP('/', '/');
431          MAP('b', '\b');
432          MAP('f', '\f');
433          MAP('n', '\n');
434          MAP('r', '\r');
435          MAP('t', '\t');
436#undef MAP
437        case 'u':
438          if (! _parse_codepoint(s, in)) {
439            return false;
440          }
441          break;
442        default:
443          return false;
444        }
445      } else {
446        s.push_back(ch);
447      }
448    }
449    return false;
450  }
451 
452  template <typename Iter> static bool _parse_array(value& out, input<Iter>& in) {
453    out = value(array_type);
454    array& a = out.get<array>();
455    if (in.match("]") == input<Iter>::positive) {
456      return true;
457    }
458    do {
459      a.push_back(value());
460      if (! _parse(a.back(), in)) {
461        return false;
462      }
463    } while (in.match(",") == input<Iter>::positive);
464    return in.match("]") == input<Iter>::positive;
465  }
466 
467  template <typename Iter> static bool _parse_object(value& out, input<Iter>& in) {
468    out = value(object_type);
469    object& o = out.get<object>();
470    if (in.match("}") == input<Iter>::positive) {
471      return true;
472    }
473    do {
474      value key, val;
475      if (in.match("\"") == input<Iter>::positive
476          && _parse_string(key, in)
477          && in.match(":") == input<Iter>::positive
478          && _parse(val, in)) {
479        o[key.to_str()] = val;
480      } else {
481        return false;
482      }
483    } while (in.match(",") == input<Iter>::positive);
484    return in.match("}") == input<Iter>::positive;
485  }
486 
487  template <typename Iter> static bool _parse_number(value& out, input<Iter>& in) {
488    out = value(number_type);
489    std::string num_str;
490    while (! in.eof()) {
491      int ch = in.getc();
492      if ('0' <= ch && ch <= '9' || ch == '+' || ch == '-' || ch == '.'
493          || ch == 'e' || ch == 'E') {
494        num_str.push_back(ch);
495      } else {
496        in.ungetc();
497        break;
498      }
499    }
500    char* endp;
501    out.get<double>() = strtod(num_str.c_str(), &endp);
502    return endp == num_str.c_str() + num_str.size();
503  }
504 
505  template <typename Iter> static bool _parse(value& out, input<Iter>& in) {
506    int ret = input<Iter>::negative;
507#define IS(p)                                           \
508    (ret == input<Iter>::negative                       \
509     && (ret = in.match(p)) == input<Iter>::positive)
510    if (IS("undefined")) {
511      out = value(undefined_type);
512    } else if (IS("null")) {
513      out = value(null_type);
514    } else if (IS("false")) {
515      out = value(boolean_type);
516    } else if (IS("true")) {
517      out = value(boolean_type);
518      out.get<bool>() = true;
519    } else if (IS("\"")) {
520      return _parse_string(out, in);
521    } else if (IS("[")) {
522      return _parse_array(out, in);
523    } else if (IS("{")) {
524      return _parse_object(out, in);
525    } else {
526      int ch = in.getc();
527      if (ch != -1) {
528        in.ungetc();
529        if ('0' <= ch && ch <= '9' || ch == '-') {
530          return _parse_number(out, in);
531        }
532      }
533    }
534#undef IS
535    return ret == input<Iter>::positive;
536  }
537 
538  template <typename Iter> static std::string parse(value& out, Iter& pos, const Iter& last) {
539    // setup
540    input<Iter> in(pos, last);
541    std::string err;
542    // do
543    if (! _parse(out, in)) {
544      char buf[64];
545      sprintf(buf, "syntax error at line %d near: ", in.line());
546      err = buf;
547      while (! in.eof()) {
548        int ch = in.getc();
549        if (ch == '\n') {
550          break;
551        }
552        err += ch;
553      }
554    }
555    pos = in.cur();
556    return err;
557  }
558 
559  inline static std::string parse(value& out, std::istream& is) {
560    std::istreambuf_iterator<char> ii(is.rdbuf());
561    return parse(out, ii, std::istreambuf_iterator<char>());
562  }
563 
564}
565
566#endif
567#ifdef TEST_PICOJSON
568
569using namespace std;
570 
571static void plan(int num)
572{
573  printf("1..%d\n", num);
574}
575
576static void ok(bool b, const char* name = "")
577{
578  static int n = 1;
579  printf("%s %d - %s\n", b ? "ok" : "ng", n++, name);
580}
581
582template <typename T> void is(const T& x, const T& y, const char* name = "")
583{
584  if (x == y) {
585    ok(true, name);
586  } else {
587    ok(false, name);
588  }
589}
590
591int main(void)
592{
593  plan(54);
594 
595#define TEST(in, type, cmp, serialize_test) {                           \
596    picojson::value v;                                                  \
597    const char* s = in;                                                 \
598    string err = picojson::parse(v, s, s + strlen(s));                  \
599    ok(err.empty(), in " no error");                                    \
600    ok(v.is<type>(), in " check type");                                 \
601    is(v.get<type>(), cmp, in " correct output");                       \
602    is(*s, '\0', in " read to eof");                                    \
603    if (serialize_test) {                                               \
604      is(v.serialize(), string(in), in " serialize");                   \
605    }                                                                   \
606  }
607  TEST("false", bool, false, true);
608  TEST("true", bool, true, true);
609  TEST("90.5", double, 90.5, false);
610  TEST("\"hello\"", string, string("hello"), true);
611  TEST("\"\\\"\\\\\\/\\b\\f\\n\\r\\t\"", string, string("\"\\/\b\f\n\r\t"),
612       true);
613  TEST("\"\\u0061\\u30af\\u30ea\\u30b9\"", string,
614       string("a\xe3\x82\xaf\xe3\x83\xaa\xe3\x82\xb9"), false);
615  TEST("\"\\ud840\\udc0b\"", string, string("\xf0\xa0\x80\x8b"), false);
616#undef TEST
617
618#define TEST(type, expr) {                                             \
619    picojson::value v;                                                 \
620    const char *s = expr;                                              \
621    string err = picojson::parse(v, s, s + strlen(s));                 \
622    ok(err.empty(), "empty " #type " no error");                       \
623    ok(v.is<picojson::type>(), "empty " #type " check type");          \
624    ok(v.get<picojson::type>().empty(), "check " #type " array size"); \
625  }
626  TEST(array, "[]");
627  TEST(object, "{}");
628#undef TEST
629 
630  {
631    picojson::value v;
632    const char *s = "[1,true,\"hello\"]";
633    string err = picojson::parse(v, s, s + strlen(s));
634    ok(err.empty(), "array no error");
635    ok(v.is<picojson::array>(), "array check type");
636    is(v.get<picojson::array>().size(), size_t(3), "check array size");
637    ok(v.get(0).is<double>(), "check array[0] type");
638    is(v.get(0).get<double>(), 1.0, "check array[0] value");
639    ok(v.get(1).is<bool>(), "check array[1] type");
640    ok(v.get(1).get<bool>(), "check array[1] value");
641    ok(v.get(2).is<string>(), "check array[2] type");
642    is(v.get(2).get<string>(), string("hello"), "check array[2] value");
643  }
644 
645  {
646    picojson::value v;
647    const char *s = "{ \"a\": true }";
648    string err = picojson::parse(v, s, s + strlen(s));
649    ok(err.empty(), "object no error");
650    ok(v.is<picojson::object>(), "object check type");
651    is(v.get<picojson::object>().size(), size_t(1), "check object size");
652    ok(v.get("a").is<bool>(), "check property exists");
653    is(v.get("a").get<bool>(), true,
654       "check property value");
655    is(v.serialize(), string("{\"a\":true}"), "serialize object");
656  }
657 
658  {
659    picojson::value v;
660    const char *s = "falsoooo";
661    string err = picojson::parse(v, s, s + strlen(s));
662    is(err, string("syntax error at line 1 near: oooo"), "error message");
663  }
664 
665  return 0;
666}
667
668#endif
Note: See TracBrowser for help on using the browser.