| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160 | /* * Copyright 2009-2010 Cybozu Labs, Inc. * Copyright 2011-2014 Kazuho Oku * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, *    this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright notice, *    this list of conditions and the following disclaimer in the documentation *    and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */#ifndef picojson_h#define picojson_h#include <algorithm>#include <cstdio>#include <cstdlib>#include <cstring>#include <cstddef>#include <iostream>#include <iterator>#include <limits>#include <map>#include <stdexcept>#include <string>#include <vector>#include <utility>// for isnan/isinf#if __cplusplus >= 201103L#include <cmath>#elseextern "C" {#ifdef _MSC_VER#include <float.h>#elif defined(__INTEL_COMPILER)#include <mathimf.h>#else#include <math.h>#endif}#endif#ifndef PICOJSON_USE_RVALUE_REFERENCE#if (defined(__cpp_rvalue_references) && __cpp_rvalue_references >= 200610) || (defined(_MSC_VER) && _MSC_VER >= 1600)#define PICOJSON_USE_RVALUE_REFERENCE 1#else#define PICOJSON_USE_RVALUE_REFERENCE 0#endif#endif // PICOJSON_USE_RVALUE_REFERENCE// experimental support for int64_t (see README.mkdn for detail)#ifdef PICOJSON_USE_INT64#define __STDC_FORMAT_MACROS#include <errno.h>#include <inttypes.h>#endif// to disable the use of localeconv(3), set PICOJSON_USE_LOCALE to 0#ifndef PICOJSON_USE_LOCALE#define PICOJSON_USE_LOCALE 1#endif#if PICOJSON_USE_LOCALEextern "C" {#include <locale.h>}#endif#ifndef PICOJSON_ASSERT#define PICOJSON_ASSERT(e)                                                                                                         \  do {                                                                                                                             \    if (!(e))                                                                                                                      \      throw std::runtime_error(#e);                                                                                                \  } while (0)#endif#ifdef _MSC_VER#define SNPRINTF _snprintf_s#pragma warning(push)#pragma warning(disable : 4244) // conversion from int to char#pragma warning(disable : 4127) // conditional expression is constant#pragma warning(disable : 4702) // unreachable code#else#define SNPRINTF snprintf#endifnamespace picojson {enum {  null_type,  boolean_type,  number_type,  string_type,  array_type,  object_type#ifdef PICOJSON_USE_INT64  ,  int64_type#endif};enum { INDENT_WIDTH = 2 };struct null {};class value {public:  typedef std::vector<value> array;  typedef std::map<std::string, value> object;  union _storage {    bool boolean_;    double number_;#ifdef PICOJSON_USE_INT64    int64_t int64_;#endif    std::string *string_;    array *array_;    object *object_;  };protected:  int type_;  _storage u_;public:  value();  value(int type, bool);  explicit value(bool b);#ifdef PICOJSON_USE_INT64  explicit value(int64_t i);#endif  explicit value(double n);  explicit value(const std::string &s);  explicit value(const array &a);  explicit value(const object &o);#if PICOJSON_USE_RVALUE_REFERENCE  explicit value(std::string &&s);  explicit value(array &&a);  explicit value(object &&o);#endif  explicit value(const char *s);  value(const char *s, size_t len);  ~value();  value(const value &x);  value &operator=(const value &x);#if PICOJSON_USE_RVALUE_REFERENCE  value(value &&x) throw();  value &operator=(value &&x) throw();#endif  void swap(value &x) throw();  template <typename T> bool is() const;  template <typename T> const T &get() const;  template <typename T> T &get();  template <typename T> void set(const T &);#if PICOJSON_USE_RVALUE_REFERENCE  template <typename T> void set(T &&);#endif  bool evaluate_as_boolean() const;  const value &get(const size_t idx) const;  const value &get(const std::string &key) const;  value &get(const size_t idx);  value &get(const std::string &key);  bool contains(const size_t idx) const;  bool contains(const std::string &key) const;  std::string to_str() const;  template <typename Iter> void serialize(Iter os, bool prettify = false) const;  std::string serialize(bool prettify = false) const;private:  template <typename T> value(const T *); // intentionally defined to block implicit conversion of pointer to bool  template <typename Iter> static void _indent(Iter os, int indent);  template <typename Iter> void _serialize(Iter os, int indent) const;  std::string _serialize(int indent) const;  void clear();};typedef value::array array;typedef value::object object;inline value::value() : type_(null_type), u_() {}inline value::value(int type, bool) : type_(type), u_() {  switch (type) {#define INIT(p, v)                                                                                                                 \  case p##type:                                                                                                                    \    u_.p = v;                                                                                                                      \    break    INIT(boolean_, false);    INIT(number_, 0.0);#ifdef PICOJSON_USE_INT64    INIT(int64_, 0);#endif    INIT(string_, new std::string());    INIT(array_, new array());    INIT(object_, new object());#undef INIT  default:    break;  }}inline value::value(bool b) : type_(boolean_type), u_() {  u_.boolean_ = b;}#ifdef PICOJSON_USE_INT64inline value::value(int64_t i) : type_(int64_type), u_() {  u_.int64_ = i;}#endifinline value::value(double n) : type_(number_type), u_() {  if (#ifdef _MSC_VER      !_finite(n)#elif __cplusplus >= 201103L || !(defined(isnan) && defined(isinf))      std::isnan(n) || std::isinf(n)#else      isnan(n) || isinf(n)#endif          ) {    throw std::overflow_error("");  }  u_.number_ = n;}inline value::value(const std::string &s) : type_(string_type), u_() {  u_.string_ = new std::string(s);}inline value::value(const array &a) : type_(array_type), u_() {  u_.array_ = new array(a);}inline value::value(const object &o) : type_(object_type), u_() {  u_.object_ = new object(o);}#if PICOJSON_USE_RVALUE_REFERENCEinline value::value(std::string &&s) : type_(string_type), u_() {  u_.string_ = new std::string(std::move(s));}inline value::value(array &&a) : type_(array_type), u_() {  u_.array_ = new array(std::move(a));}inline value::value(object &&o) : type_(object_type), u_() {  u_.object_ = new object(std::move(o));}#endifinline value::value(const char *s) : type_(string_type), u_() {  u_.string_ = new std::string(s);}inline value::value(const char *s, size_t len) : type_(string_type), u_() {  u_.string_ = new std::string(s, len);}inline void value::clear() {  switch (type_) {#define DEINIT(p)                                                                                                                  \  case p##type:                                                                                                                    \    delete u_.p;                                                                                                                   \    break    DEINIT(string_);    DEINIT(array_);    DEINIT(object_);#undef DEINIT  default:    break;  }}inline value::~value() {  clear();}inline value::value(const value &x) : type_(x.type_), u_() {  switch (type_) {#define INIT(p, v)                                                                                                                 \  case p##type:                                                                                                                    \    u_.p = v;                                                                                                                      \    break    INIT(string_, new std::string(*x.u_.string_));    INIT(array_, new array(*x.u_.array_));    INIT(object_, new object(*x.u_.object_));#undef INIT  default:    u_ = x.u_;    break;  }}inline value &value::operator=(const value &x) {  if (this != &x) {    value t(x);    swap(t);  }  return *this;}#if PICOJSON_USE_RVALUE_REFERENCEinline value::value(value &&x) throw() : type_(null_type), u_() {  swap(x);}inline value &value::operator=(value &&x) throw() {  swap(x);  return *this;}#endifinline void value::swap(value &x) throw() {  std::swap(type_, x.type_);  std::swap(u_, x.u_);}#define IS(ctype, jtype)                                                                                                           \  template <> inline bool value::is<ctype>() const {                                                                               \    return type_ == jtype##_type;                                                                                                  \  }IS(null, null)IS(bool, boolean)#ifdef PICOJSON_USE_INT64IS(int64_t, int64)#endifIS(std::string, string)IS(array, array)IS(object, object)#undef IStemplate <> inline bool value::is<double>() const {  return type_ == number_type#ifdef PICOJSON_USE_INT64         || type_ == int64_type#endif      ;}#define GET(ctype, var)                                                                                                            \  template <> inline const ctype &value::get<ctype>() const {                                                                      \    PICOJSON_ASSERT("type mismatch! call is<type>() before get<type>()" && is<ctype>());                                           \    return var;                                                                                                                    \  }                                                                                                                                \  template <> inline ctype &value::get<ctype>() {                                                                                  \    PICOJSON_ASSERT("type mismatch! call is<type>() before get<type>()" && is<ctype>());                                           \    return var;                                                                                                                    \  }GET(bool, u_.boolean_)GET(std::string, *u_.string_)GET(array, *u_.array_)GET(object, *u_.object_)#ifdef PICOJSON_USE_INT64GET(double,    (type_ == int64_type && (const_cast<value *>(this)->type_ = number_type, const_cast<value *>(this)->u_.number_ = u_.int64_),     u_.number_))GET(int64_t, u_.int64_)#elseGET(double, u_.number_)#endif#undef GET#define SET(ctype, jtype, setter)                                                                                                  \  template <> inline void value::set<ctype>(const ctype &_val) {                                                                   \    clear();                                                                                                                       \    type_ = jtype##_type;                                                                                                          \    setter                                                                                                                         \  }SET(bool, boolean, u_.boolean_ = _val;)SET(std::string, string, u_.string_ = new std::string(_val);)SET(array, array, u_.array_ = new array(_val);)SET(object, object, u_.object_ = new object(_val);)SET(double, number, u_.number_ = _val;)#ifdef PICOJSON_USE_INT64SET(int64_t, int64, u_.int64_ = _val;)#endif#undef SET#if PICOJSON_USE_RVALUE_REFERENCE#define MOVESET(ctype, jtype, setter)                                                                                              \  template <> inline void value::set<ctype>(ctype && _val) {                                                                       \    clear();                                                                                                                       \    type_ = jtype##_type;                                                                                                          \    setter                                                                                                                         \  }MOVESET(std::string, string, u_.string_ = new std::string(std::move(_val));)MOVESET(array, array, u_.array_ = new array(std::move(_val));)MOVESET(object, object, u_.object_ = new object(std::move(_val));)#undef MOVESET#endifinline bool value::evaluate_as_boolean() const {  switch (type_) {  case null_type:    return false;  case boolean_type:    return u_.boolean_;  case number_type:    return u_.number_ != 0;#ifdef PICOJSON_USE_INT64  case int64_type:    return u_.int64_ != 0;#endif  case string_type:    return !u_.string_->empty();  default:    return true;  }}inline const value &value::get(const size_t idx) const {  static value s_null;  PICOJSON_ASSERT(is<array>());  return idx < u_.array_->size() ? (*u_.array_)[idx] : s_null;}inline value &value::get(const size_t idx) {  static value s_null;  PICOJSON_ASSERT(is<array>());  return idx < u_.array_->size() ? (*u_.array_)[idx] : s_null;}inline const value &value::get(const std::string &key) const {  static value s_null;  PICOJSON_ASSERT(is<object>());  object::const_iterator i = u_.object_->find(key);  return i != u_.object_->end() ? i->second : s_null;}inline value &value::get(const std::string &key) {  static value s_null;  PICOJSON_ASSERT(is<object>());  object::iterator i = u_.object_->find(key);  return i != u_.object_->end() ? i->second : s_null;}inline bool value::contains(const size_t idx) const {  PICOJSON_ASSERT(is<array>());  return idx < u_.array_->size();}inline bool value::contains(const std::string &key) const {  PICOJSON_ASSERT(is<object>());  object::const_iterator i = u_.object_->find(key);  return i != u_.object_->end();}inline std::string value::to_str() const {  switch (type_) {  case null_type:    return "null";  case boolean_type:    return u_.boolean_ ? "true" : "false";#ifdef PICOJSON_USE_INT64  case int64_type: {    char buf[sizeof("-9223372036854775808")];    SNPRINTF(buf, sizeof(buf), "%" PRId64, u_.int64_);    return buf;  }#endif  case number_type: {    char buf[256];    double tmp;    SNPRINTF(buf, sizeof(buf), fabs(u_.number_) < (1ULL << 53) && modf(u_.number_, &tmp) == 0 ? "%.f" : "%.17g", u_.number_);#if PICOJSON_USE_LOCALE    char *decimal_point = localeconv()->decimal_point;    if (strcmp(decimal_point, ".") != 0) {      size_t decimal_point_len = strlen(decimal_point);      for (char *p = buf; *p != '\0'; ++p) {        if (strncmp(p, decimal_point, decimal_point_len) == 0) {          return std::string(buf, p) + "." + (p + decimal_point_len);        }      }    }#endif    return buf;  }  case string_type:    return *u_.string_;  case array_type:    return "array";  case object_type:    return "object";  default:    PICOJSON_ASSERT(0);#ifdef _MSC_VER    __assume(0);#endif  }  return std::string();}template <typename Iter> void copy(const std::string &s, Iter oi) {  std::copy(s.begin(), s.end(), oi);}template <typename Iter> struct serialize_str_char {  Iter oi;  void operator()(char c) {    switch (c) {#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");#undef MAP    default:      if (static_cast<unsigned char>(c) < 0x20 || c == 0x7f) {        char buf[7];        SNPRINTF(buf, sizeof(buf), "\\u%04x", c & 0xff);        copy(buf, buf + 6, oi);      } else {        *oi++ = c;      }      break;    }  }};template <typename Iter> void serialize_str(const std::string &s, Iter oi) {  *oi++ = '"';  serialize_str_char<Iter> process_char = {oi};  std::for_each(s.begin(), s.end(), process_char);  *oi++ = '"';}template <typename Iter> void value::serialize(Iter oi, bool prettify) const {  return _serialize(oi, prettify ? 0 : -1);}inline std::string value::serialize(bool prettify) const {  return _serialize(prettify ? 0 : -1);}template <typename Iter> void value::_indent(Iter oi, int indent) {  *oi++ = '\n';  for (int i = 0; i < indent * INDENT_WIDTH; ++i) {    *oi++ = ' ';  }}template <typename Iter> void value::_serialize(Iter oi, int indent) const {  switch (type_) {  case string_type:    serialize_str(*u_.string_, oi);    break;  case array_type: {    *oi++ = '[';    if (indent != -1) {      ++indent;    }    for (array::const_iterator i = u_.array_->begin(); i != u_.array_->end(); ++i) {      if (i != u_.array_->begin()) {        *oi++ = ',';      }      if (indent != -1) {        _indent(oi, indent);      }      i->_serialize(oi, indent);    }    if (indent != -1) {      --indent;      if (!u_.array_->empty()) {        _indent(oi, indent);      }    }    *oi++ = ']';    break;  }  case object_type: {    *oi++ = '{';    if (indent != -1) {      ++indent;    }    for (object::const_iterator i = u_.object_->begin(); i != u_.object_->end(); ++i) {      if (i != u_.object_->begin()) {        *oi++ = ',';      }      if (indent != -1) {        _indent(oi, indent);      }      serialize_str(i->first, oi);      *oi++ = ':';      if (indent != -1) {        *oi++ = ' ';      }      i->second._serialize(oi, indent);    }    if (indent != -1) {      --indent;      if (!u_.object_->empty()) {        _indent(oi, indent);      }    }    *oi++ = '}';    break;  }  default:    copy(to_str(), oi);    break;  }  if (indent == 0) {    *oi++ = '\n';  }}inline std::string value::_serialize(int indent) const {  std::string s;  _serialize(std::back_inserter(s), indent);  return s;}template <typename Iter> class input {protected:  Iter cur_, end_;  bool consumed_;  int line_;public:  input(const Iter &first, const Iter &last) : cur_(first), end_(last), consumed_(false), line_(1) {  }  int getc() {    if (consumed_) {      if (*cur_ == '\n') {        ++line_;      }      ++cur_;    }    if (cur_ == end_) {      consumed_ = false;      return -1;    }    consumed_ = true;    return *cur_ & 0xff;  }  void ungetc() {    consumed_ = false;  }  Iter cur() const {    if (consumed_) {      input<Iter> *self = const_cast<input<Iter> *>(this);      self->consumed_ = false;      ++self->cur_;    }    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;      }    }  }  bool expect(const int expected) {    skip_ws();    if (getc() != expected) {      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;      }    }    return true;  }};template <typename Iter> inline int _parse_quadhex(input<Iter> &in) {  int uni_ch = 0, hex;  for (int i = 0; i < 4; i++) {    if ((hex = in.getc()) == -1) {      return -1;    }    if ('0' <= hex && hex <= '9') {      hex -= '0';    } else if ('A' <= hex && hex <= 'F') {      hex -= 'A' - 0xa;    } else if ('a' <= hex && hex <= 'f') {      hex -= 'a' - 0xa;    } else {      in.ungetc();      return -1;    }    uni_ch = uni_ch * 16 + hex;  }  return uni_ch;}template <typename String, typename Iter> inline bool _parse_codepoint(String &out, input<Iter> &in) {  int uni_ch;  if ((uni_ch = _parse_quadhex(in)) == -1) {    return false;  }  if (0xd800 <= uni_ch && uni_ch <= 0xdfff) {    if (0xdc00 <= uni_ch) {      // 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;    }    int second = _parse_quadhex(in);    if (!(0xdc00 <= second && second <= 0xdfff)) {      return false;    }    uni_ch = ((uni_ch - 0xd800) << 10) | ((second - 0xdc00) & 0x3ff);    uni_ch += 0x10000;  }  if (uni_ch < 0x80) {    out.push_back(static_cast<char>(uni_ch));  } else {    if (uni_ch < 0x800) {      out.push_back(static_cast<char>(0xc0 | (uni_ch >> 6)));    } else {      if (uni_ch < 0x10000) {        out.push_back(static_cast<char>(0xe0 | (uni_ch >> 12)));      } else {        out.push_back(static_cast<char>(0xf0 | (uni_ch >> 18)));        out.push_back(static_cast<char>(0x80 | ((uni_ch >> 12) & 0x3f)));      }      out.push_back(static_cast<char>(0x80 | ((uni_ch >> 6) & 0x3f)));    }    out.push_back(static_cast<char>(0x80 | (uni_ch & 0x3f)));  }  return true;}template <typename String, typename Iter> inline bool _parse_string(String &out, input<Iter> &in) {  while (1) {    int ch = in.getc();    if (ch < ' ') {      in.ungetc();      return false;    } else if (ch == '"') {      return true;    } else if (ch == '\\') {      if ((ch = in.getc()) == -1) {        return false;      }      switch (ch) {#define MAP(sym, val)                                                                                                              \  case sym:                                                                                                                        \    out.push_back(val);                                                                                                            \    break        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(out, in)) {          return false;        }        break;      default:        return false;      }    } else {      out.push_back(static_cast<char>(ch));    }  }  return false;}template <typename Context, typename Iter> inline bool _parse_array(Context &ctx, input<Iter> &in) {  if (!ctx.parse_array_start()) {    return false;  }  size_t idx = 0;  if (in.expect(']')) {    return ctx.parse_array_stop(idx);  }  do {    if (!ctx.parse_array_item(in, idx)) {      return false;    }    idx++;  } while (in.expect(','));  return in.expect(']') && ctx.parse_array_stop(idx);}template <typename Context, typename Iter> inline bool _parse_object(Context &ctx, input<Iter> &in) {  if (!ctx.parse_object_start()) {    return false;  }  if (in.expect('}')) {    return true;  }  do {    std::string key;    if (!in.expect('"') || !_parse_string(key, in) || !in.expect(':')) {      return false;    }    if (!ctx.parse_object_item(in, key)) {      return false;    }  } while (in.expect(','));  return in.expect('}');}template <typename Iter> inline std::string _parse_number(input<Iter> &in) {  std::string num_str;  while (1) {    int ch = in.getc();    if (('0' <= ch && ch <= '9') || ch == '+' || ch == '-' || ch == 'e' || ch == 'E') {      num_str.push_back(static_cast<char>(ch));    } else if (ch == '.') {#if PICOJSON_USE_LOCALE      num_str += localeconv()->decimal_point;#else      num_str.push_back('.');#endif    } else {      in.ungetc();      break;    }  }  return num_str;}template <typename Context, typename Iter> inline bool _parse(Context &ctx, input<Iter> &in) {  in.skip_ws();  int ch = in.getc();  switch (ch) {#define IS(ch, text, op)                                                                                                           \  case ch:                                                                                                                         \    if (in.match(text) && op) {                                                                                                    \      return true;                                                                                                                 \    } else {                                                                                                                       \      return false;                                                                                                                \    }    IS('n', "ull", ctx.set_null());    IS('f', "alse", ctx.set_bool(false));    IS('t', "rue", ctx.set_bool(true));#undef IS  case '"':    return ctx.parse_string(in);  case '[':    return _parse_array(ctx, in);  case '{':    return _parse_object(ctx, in);  default:    if (('0' <= ch && ch <= '9') || ch == '-') {      double f;      char *endp;      in.ungetc();      std::string num_str(_parse_number(in));      if (num_str.empty()) {        return false;      }#ifdef PICOJSON_USE_INT64      {        errno = 0;        intmax_t ival = strtoimax(num_str.c_str(), &endp, 10);        if (errno == 0 && std::numeric_limits<int64_t>::min() <= ival && ival <= std::numeric_limits<int64_t>::max() &&            endp == num_str.c_str() + num_str.size()) {          ctx.set_int64(ival);          return true;        }      }#endif      f = strtod(num_str.c_str(), &endp);      if (endp == num_str.c_str() + num_str.size()) {        ctx.set_number(f);        return true;      }      return false;    }    break;  }  in.ungetc();  return false;}class deny_parse_context {public:  bool set_null() {    return false;  }  bool set_bool(bool) {    return false;  }#ifdef PICOJSON_USE_INT64  bool set_int64(int64_t) {    return false;  }#endif  bool set_number(double) {    return false;  }  template <typename Iter> bool parse_string(input<Iter> &) {    return false;  }  bool parse_array_start() {    return false;  }  template <typename Iter> bool parse_array_item(input<Iter> &, size_t) {    return false;  }  bool parse_array_stop(size_t) {    return false;  }  bool parse_object_start() {    return false;  }  template <typename Iter> bool parse_object_item(input<Iter> &, const std::string &) {    return false;  }};class default_parse_context {protected:  value *out_;public:  default_parse_context(value *out) : out_(out) {  }  bool set_null() {    *out_ = value();    return true;  }  bool set_bool(bool b) {    *out_ = value(b);    return true;  }#ifdef PICOJSON_USE_INT64  bool set_int64(int64_t i) {    *out_ = value(i);    return true;  }#endif  bool set_number(double f) {    *out_ = value(f);    return true;  }  template <typename Iter> bool parse_string(input<Iter> &in) {    *out_ = value(string_type, false);    return _parse_string(out_->get<std::string>(), in);  }  bool parse_array_start() {    *out_ = value(array_type, false);    return true;  }  template <typename Iter> bool parse_array_item(input<Iter> &in, size_t) {    array &a = out_->get<array>();    a.push_back(value());    default_parse_context ctx(&a.back());    return _parse(ctx, in);  }  bool parse_array_stop(size_t) {    return true;  }  bool parse_object_start() {    *out_ = value(object_type, false);    return true;  }  template <typename Iter> bool parse_object_item(input<Iter> &in, const std::string &key) {    object &o = out_->get<object>();    default_parse_context ctx(&o[key]);    return _parse(ctx, in);  }private:  default_parse_context(const default_parse_context &);  default_parse_context &operator=(const default_parse_context &);};class null_parse_context {public:  struct dummy_str {    void push_back(int) {    }  };public:  null_parse_context() {  }  bool set_null() {    return true;  }  bool set_bool(bool) {    return true;  }#ifdef PICOJSON_USE_INT64  bool set_int64(int64_t) {    return true;  }#endif  bool set_number(double) {    return true;  }  template <typename Iter> bool parse_string(input<Iter> &in) {    dummy_str s;    return _parse_string(s, in);  }  bool parse_array_start() {    return true;  }  template <typename Iter> bool parse_array_item(input<Iter> &in, size_t) {    return _parse(*this, in);  }  bool parse_array_stop(size_t) {    return true;  }  bool parse_object_start() {    return true;  }  template <typename Iter> bool parse_object_item(input<Iter> &in, const std::string &) {    return _parse(*this, in);  }private:  null_parse_context(const null_parse_context &);  null_parse_context &operator=(const null_parse_context &);};// obsolete, use the version belowtemplate <typename Iter> inline std::string parse(value &out, Iter &pos, const Iter &last) {  std::string err;  pos = parse(out, pos, last, &err);  return err;}template <typename Context, typename Iter> inline Iter _parse(Context &ctx, const Iter &first, const Iter &last, std::string *err) {  input<Iter> in(first, last);  if (!_parse(ctx, in) && err != NULL) {    char buf[64];    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(static_cast<char>(ch));      }    }  }  return in.cur();}template <typename Iter> inline Iter parse(value &out, const Iter &first, const Iter &last, std::string *err) {  default_parse_context ctx(&out);  return _parse(ctx, first, last, err);}inline std::string parse(value &out, const std::string &s) {  std::string err;  parse(out, s.begin(), s.end(), &err);  return err;}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);  return err;}template <typename T> struct last_error_t { static std::string s; };template <typename T> std::string last_error_t<T>::s;inline void set_last_error(const std::string &s) {  last_error_t<bool>::s = s;}inline const std::string &get_last_error() {  return last_error_t<bool>::s;}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>())                                                                                                                \  return y.is<type>() && x.get<type>() == y.get<type>()  PICOJSON_CMP(bool);  PICOJSON_CMP(double);  PICOJSON_CMP(std::string);  PICOJSON_CMP(array);  PICOJSON_CMP(object);#undef PICOJSON_CMP  PICOJSON_ASSERT(0);#ifdef _MSC_VER  __assume(0);#endif  return false;}inline bool operator!=(const value &x, const value &y) {  return !(x == y);}}#if !PICOJSON_USE_RVALUE_REFERENCEnamespace std {template <> inline void swap(picojson::value &x, picojson::value &y) {  x.swap(y);}}#endifinline std::istream &operator>>(std::istream &is, picojson::value &x) {  picojson::set_last_error(std::string());  const std::string err(picojson::parse(x, is));  if (!err.empty()) {    picojson::set_last_error(err);    is.setstate(std::ios::failbit);  }  return is;}inline std::ostream &operator<<(std::ostream &os, const picojson::value &x) {  x.serialize(std::ostream_iterator<char>(os));  return os;}#ifdef _MSC_VER#pragma warning(pop)#endif#endif
 |