LCOV - code coverage report
Current view: top level - externals/picojson - picojson.h (source / functions) Hit Total Coverage
Test: lcov.info Lines: 216 320 67.5 %
Date: 2024-04-28 12:00:40 Functions: 50 78 64.1 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*
       2             :  * Copyright 2009-2010 Cybozu Labs, Inc.
       3             :  * Copyright 2011-2014 Kazuho Oku
       4             :  * All rights reserved.
       5             :  *
       6             :  * Redistribution and use in source and binary forms, with or without
       7             :  * modification, are permitted provided that the following conditions are met:
       8             :  *
       9             :  * 1. Redistributions of source code must retain the above copyright notice,
      10             :  *    this list of conditions and the following disclaimer.
      11             :  *
      12             :  * 2. Redistributions in binary form must reproduce the above copyright notice,
      13             :  *    this list of conditions and the following disclaimer in the documentation
      14             :  *    and/or other materials provided with the distribution.
      15             :  *
      16             :  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
      17             :  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
      18             :  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
      19             :  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
      20             :  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
      21             :  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
      22             :  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
      23             :  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
      24             :  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
      25             :  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
      26             :  * POSSIBILITY OF SUCH DAMAGE.
      27             :  */
      28             : #ifndef picojson_h
      29             : #define picojson_h
      30             : 
      31             : #include <algorithm>
      32             : #include <cstdio>
      33             : #include <cstdlib>
      34             : #include <cstring>
      35             : #include <cstddef>
      36             : #include <iostream>
      37             : #include <iterator>
      38             : #include <limits>
      39             : #include <map>
      40             : #include <stdexcept>
      41             : #include <string>
      42             : #include <vector>
      43             : #include <utility>
      44             : 
      45             : // for isnan/isinf
      46             : #if __cplusplus >= 201103L
      47             : #include <cmath>
      48             : #else
      49             : extern "C" {
      50             : #ifdef _MSC_VER
      51             : #include <float.h>
      52             : #elif defined(__INTEL_COMPILER)
      53             : #include <mathimf.h>
      54             : #else
      55             : #include <math.h>
      56             : #endif
      57             : }
      58             : #endif
      59             : 
      60             : #ifndef PICOJSON_USE_RVALUE_REFERENCE
      61             : #if (defined(__cpp_rvalue_references) && __cpp_rvalue_references >= 200610) || (defined(_MSC_VER) && _MSC_VER >= 1600)
      62             : #define PICOJSON_USE_RVALUE_REFERENCE 1
      63             : #else
      64             : #define PICOJSON_USE_RVALUE_REFERENCE 0
      65             : #endif
      66             : #endif // PICOJSON_USE_RVALUE_REFERENCE
      67             : 
      68             : #ifndef PICOJSON_NOEXCEPT
      69             : #if PICOJSON_USE_RVALUE_REFERENCE
      70             : #define PICOJSON_NOEXCEPT noexcept
      71             : #else
      72             : #define PICOJSON_NOEXCEPT throw()
      73             : #endif
      74             : #endif
      75             : 
      76             : // experimental support for int64_t (see README.mkdn for detail)
      77             : #ifdef PICOJSON_USE_INT64
      78             : #define __STDC_FORMAT_MACROS
      79             : #include <cerrno>
      80             : #if __cplusplus >= 201103L
      81             : #include <cinttypes>
      82             : #else
      83             : extern "C" {
      84             : #include <inttypes.h>
      85             : }
      86             : #endif
      87             : #endif
      88             : 
      89             : // to disable the use of localeconv(3), set PICOJSON_USE_LOCALE to 0
      90             : #ifndef PICOJSON_USE_LOCALE
      91             : #define PICOJSON_USE_LOCALE 1
      92             : #endif
      93             : #if PICOJSON_USE_LOCALE
      94             : extern "C" {
      95             : #include <locale.h>
      96             : }
      97             : #endif
      98             : 
      99             : #ifndef PICOJSON_ASSERT
     100             : #define PICOJSON_ASSERT(e)                                                                                                         \
     101             :   do {                                                                                                                             \
     102             :     if (!(e))                                                                                                                      \
     103             :       throw std::runtime_error(#e);                                                                                                \
     104             :   } while (0)
     105             : #endif
     106             : 
     107             : #ifdef _MSC_VER
     108             : #define SNPRINTF _snprintf_s
     109             : #pragma warning(push)
     110             : #pragma warning(disable : 4244) // conversion from int to char
     111             : #pragma warning(disable : 4127) // conditional expression is constant
     112             : #pragma warning(disable : 4702) // unreachable code
     113             : #pragma warning(disable : 4706) // assignment within conditional expression
     114             : #else
     115             : #define SNPRINTF snprintf
     116             : #endif
     117             : 
     118             : namespace picojson {
     119             : 
     120             : enum {
     121             :   null_type,
     122             :   boolean_type,
     123             :   number_type,
     124             :   string_type,
     125             :   array_type,
     126             :   object_type
     127             : #ifdef PICOJSON_USE_INT64
     128             :   ,
     129             :   int64_type
     130             : #endif
     131             : };
     132             : 
     133             : enum { INDENT_WIDTH = 2, DEFAULT_MAX_DEPTHS = 100 };
     134             : 
     135             : struct null {};
     136             : 
     137             : class value {
     138             : public:
     139             :   typedef std::vector<value> array;
     140             :   typedef std::map<std::string, value> object;
     141             :   union _storage {
     142             :     bool boolean_;
     143             :     double number_;
     144             : #ifdef PICOJSON_USE_INT64
     145             :     int64_t int64_;
     146             : #endif
     147             :     std::string *string_;
     148             :     array *array_;
     149             :     object *object_;
     150             :   };
     151             : 
     152             : protected:
     153             :   int type_;
     154             :   _storage u_;
     155             : 
     156             : public:
     157             :   value();
     158             :   value(int type, bool);
     159             :   explicit value(bool b);
     160             : #ifdef PICOJSON_USE_INT64
     161             :   explicit value(int64_t i);
     162             : #endif
     163             :   explicit value(double n);
     164             :   explicit value(const std::string &s);
     165             :   explicit value(const array &a);
     166             :   explicit value(const object &o);
     167             : #if PICOJSON_USE_RVALUE_REFERENCE
     168             :   explicit value(std::string &&s);
     169             :   explicit value(array &&a);
     170             :   explicit value(object &&o);
     171             : #endif
     172             :   explicit value(const char *s);
     173             :   value(const char *s, size_t len);
     174             :   ~value();
     175             :   value(const value &x);
     176             :   value &operator=(const value &x);
     177             : #if PICOJSON_USE_RVALUE_REFERENCE
     178             :   value(value &&x) PICOJSON_NOEXCEPT;
     179             :   value &operator=(value &&x) PICOJSON_NOEXCEPT;
     180             : #endif
     181             :   void swap(value &x) PICOJSON_NOEXCEPT;
     182             :   template <typename T> bool is() const;
     183             :   template <typename T> const T &get() const;
     184             :   template <typename T> T &get();
     185             :   template <typename T> void set(const T &);
     186             : #if PICOJSON_USE_RVALUE_REFERENCE
     187             :   template <typename T> void set(T &&);
     188             : #endif
     189             :   bool evaluate_as_boolean() const;
     190             :   const value &get(const size_t idx) const;
     191             :   const value &get(const std::string &key) const;
     192             :   value &get(const size_t idx);
     193             :   value &get(const std::string &key);
     194             : 
     195             :   bool contains(const size_t idx) const;
     196             :   bool contains(const std::string &key) const;
     197             :   std::string to_str() const;
     198             :   template <typename Iter> void serialize(Iter os, bool prettify = false) const;
     199             :   std::string serialize(bool prettify = false) const;
     200             : 
     201             : private:
     202             :   template <typename T> value(const T *); // intentionally defined to block implicit conversion of pointer to bool
     203             :   template <typename Iter> static void _indent(Iter os, int indent);
     204             :   template <typename Iter> void _serialize(Iter os, int indent) const;
     205             :   std::string _serialize(int indent) const;
     206             :   void clear();
     207             : };
     208             : 
     209             : typedef value::array array;
     210             : typedef value::object object;
     211             : 
     212         134 : inline value::value() : type_(null_type), u_() {
     213         134 : }
     214             : 
     215         126 : inline value::value(int type, bool) : type_(type), u_() {
     216         126 :   switch (type) {
     217             : #define INIT(p, v)                                                                                                                 \
     218             :   case p##type:                                                                                                                    \
     219             :     u_.p = v;                                                                                                                      \
     220             :     break
     221           0 :     INIT(boolean_, false);
     222           0 :     INIT(number_, 0.0);
     223             : #ifdef PICOJSON_USE_INT64
     224           0 :     INIT(int64_, 0);
     225             : #endif
     226          62 :     INIT(string_, new std::string());
     227          24 :     INIT(array_, new array());
     228          40 :     INIT(object_, new object());
     229             : #undef INIT
     230           0 :   default:
     231           0 :     break;
     232             :   }
     233         126 : }
     234             : 
     235           2 : inline value::value(bool b) : type_(boolean_type), u_() {
     236           2 :   u_.boolean_ = b;
     237           2 : }
     238             : 
     239             : #ifdef PICOJSON_USE_INT64
     240           6 : inline value::value(int64_t i) : type_(int64_type), u_() {
     241           6 :   u_.int64_ = i;
     242           6 : }
     243             : #endif
     244             : 
     245           0 : inline value::value(double n) : type_(number_type), u_() {
     246           0 :   if (
     247             : #ifdef _MSC_VER
     248             :       !_finite(n)
     249             : #elif __cplusplus >= 201103L
     250           0 :       std::isnan(n) || std::isinf(n)
     251             : #else
     252             :       isnan(n) || isinf(n)
     253             : #endif
     254             :           ) {
     255           0 :     throw std::overflow_error("");
     256             :   }
     257           0 :   u_.number_ = n;
     258           0 : }
     259             : 
     260             : inline value::value(const std::string &s) : type_(string_type), u_() {
     261             :   u_.string_ = new std::string(s);
     262             : }
     263             : 
     264             : inline value::value(const array &a) : type_(array_type), u_() {
     265             :   u_.array_ = new array(a);
     266             : }
     267             : 
     268             : inline value::value(const object &o) : type_(object_type), u_() {
     269             :   u_.object_ = new object(o);
     270             : }
     271             : 
     272             : #if PICOJSON_USE_RVALUE_REFERENCE
     273             : inline value::value(std::string &&s) : type_(string_type), u_() {
     274             :   u_.string_ = new std::string(std::move(s));
     275             : }
     276             : 
     277             : inline value::value(array &&a) : type_(array_type), u_() {
     278             :   u_.array_ = new array(std::move(a));
     279             : }
     280             : 
     281             : inline value::value(object &&o) : type_(object_type), u_() {
     282             :   u_.object_ = new object(std::move(o));
     283             : }
     284             : #endif
     285             : 
     286             : inline value::value(const char *s) : type_(string_type), u_() {
     287             :   u_.string_ = new std::string(s);
     288             : }
     289             : 
     290             : inline value::value(const char *s, size_t len) : type_(string_type), u_() {
     291             :   u_.string_ = new std::string(s, len);
     292             : }
     293             : 
     294         372 : inline void value::clear() {
     295         372 :   switch (type_) {
     296             : #define DEINIT(p)                                                                                                                  \
     297             :   case p##type:                                                                                                                    \
     298             :     delete u_.p;                                                                                                                   \
     299             :     break
     300         115 :     DEINIT(string_);
     301          28 :     DEINIT(array_);
     302          40 :     DEINIT(object_);
     303             : #undef DEINIT
     304         189 :   default:
     305         189 :     break;
     306             :   }
     307         372 : }
     308             : 
     309         744 : inline value::~value() {
     310         372 :   clear();
     311         372 : }
     312             : 
     313          57 : inline value::value(const value &x) : type_(x.type_), u_() {
     314          57 :   switch (type_) {
     315             : #define INIT(p, v)                                                                                                                 \
     316             :   case p##type:                                                                                                                    \
     317             :     u_.p = v;                                                                                                                      \
     318             :     break
     319          53 :     INIT(string_, new std::string(*x.u_.string_));
     320           4 :     INIT(array_, new array(*x.u_.array_));
     321           0 :     INIT(object_, new object(*x.u_.object_));
     322             : #undef INIT
     323           0 :   default:
     324           0 :     u_ = x.u_;
     325           0 :     break;
     326             :   }
     327          57 : }
     328             : 
     329             : inline value &value::operator=(const value &x) {
     330             :   if (this != &x) {
     331             :     value t(x);
     332             :     swap(t);
     333             :   }
     334             :   return *this;
     335             : }
     336             : 
     337             : #if PICOJSON_USE_RVALUE_REFERENCE
     338          47 : inline value::value(value &&x) PICOJSON_NOEXCEPT : type_(null_type), u_() {
     339          47 :   swap(x);
     340          47 : }
     341         134 : inline value &value::operator=(value &&x) PICOJSON_NOEXCEPT {
     342         134 :   swap(x);
     343         134 :   return *this;
     344             : }
     345             : #endif
     346         181 : inline void value::swap(value &x) PICOJSON_NOEXCEPT {
     347         181 :   std::swap(type_, x.type_);
     348         181 :   std::swap(u_, x.u_);
     349         181 : }
     350             : 
     351             : #define IS(ctype, jtype)                                                                                                           \
     352             :   template <> inline bool value::is<ctype>() const {                                                                               \
     353             :     return type_ == jtype##_type;                                                                                                  \
     354             :   }
     355             : IS(null, null)
     356           3 : IS(bool, boolean)
     357             : #ifdef PICOJSON_USE_INT64
     358           0 : IS(int64_t, int64)
     359             : #endif
     360         171 : IS(std::string, string)
     361          82 : IS(array, array)
     362         100 : IS(object, object)
     363             : #undef IS
     364             : template <> inline bool value::is<double>() const {
     365             :   return type_ == number_type
     366             : #ifdef PICOJSON_USE_INT64
     367             :          || type_ == int64_type
     368             : #endif
     369             :       ;
     370             : }
     371             : 
     372             : #define GET(ctype, var)                                                                                                            \
     373             :   template <> inline const ctype &value::get<ctype>() const {                                                                      \
     374             :     PICOJSON_ASSERT("type mismatch! call is<type>() before get<type>()" && is<ctype>());                                           \
     375             :     return var;                                                                                                                    \
     376             :   }                                                                                                                                \
     377             :   template <> inline ctype &value::get<ctype>() {                                                                                  \
     378             :     PICOJSON_ASSERT("type mismatch! call is<type>() before get<type>()" && is<ctype>());                                           \
     379             :     return var;                                                                                                                    \
     380             :   }
     381           1 : GET(bool, u_.boolean_)
     382         122 : GET(std::string, *u_.string_)
     383          56 : GET(array, *u_.array_)
     384         100 : GET(object, *u_.object_)
     385             : #ifdef PICOJSON_USE_INT64
     386             : GET(double,
     387             :     (type_ == int64_type && (const_cast<value *>(this)->type_ = number_type, (const_cast<value *>(this)->u_.number_ = u_.int64_)),
     388             :      u_.number_))
     389           0 : GET(int64_t, u_.int64_)
     390             : #else
     391             : GET(double, u_.number_)
     392             : #endif
     393             : #undef GET
     394             : 
     395             : #define SET(ctype, jtype, setter)                                                                                                  \
     396             :   template <> inline void value::set<ctype>(const ctype &_val) {                                                                   \
     397             :     clear();                                                                                                                       \
     398             :     type_ = jtype##_type;                                                                                                          \
     399             :     setter                                                                                                                         \
     400             :   }
     401             : SET(bool, boolean, u_.boolean_ = _val;)
     402             : SET(std::string, string, u_.string_ = new std::string(_val);)
     403             : SET(array, array, u_.array_ = new array(_val);)
     404             : SET(object, object, u_.object_ = new object(_val);)
     405             : SET(double, number, u_.number_ = _val;)
     406             : #ifdef PICOJSON_USE_INT64
     407             : SET(int64_t, int64, u_.int64_ = _val;)
     408             : #endif
     409             : #undef SET
     410             : 
     411             : #if PICOJSON_USE_RVALUE_REFERENCE
     412             : #define MOVESET(ctype, jtype, setter)                                                                                              \
     413             :   template <> inline void value::set<ctype>(ctype && _val) {                                                                       \
     414             :     clear();                                                                                                                       \
     415             :     type_ = jtype##_type;                                                                                                          \
     416             :     setter                                                                                                                         \
     417             :   }
     418             : MOVESET(std::string, string, u_.string_ = new std::string(std::move(_val));)
     419             : MOVESET(array, array, u_.array_ = new array(std::move(_val));)
     420             : MOVESET(object, object, u_.object_ = new object(std::move(_val));)
     421             : #undef MOVESET
     422             : #endif
     423             : 
     424             : inline bool value::evaluate_as_boolean() const {
     425             :   switch (type_) {
     426             :   case null_type:
     427             :     return false;
     428             :   case boolean_type:
     429             :     return u_.boolean_;
     430             :   case number_type:
     431             :     return u_.number_ != 0;
     432             : #ifdef PICOJSON_USE_INT64
     433             :   case int64_type:
     434             :     return u_.int64_ != 0;
     435             : #endif
     436             :   case string_type:
     437             :     return !u_.string_->empty();
     438             :   default:
     439             :     return true;
     440             :   }
     441             : }
     442             : 
     443             : inline const value &value::get(const size_t idx) const {
     444             :   static value s_null;
     445             :   PICOJSON_ASSERT(is<array>());
     446             :   return idx < u_.array_->size() ? (*u_.array_)[idx] : s_null;
     447             : }
     448             : 
     449             : inline value &value::get(const size_t idx) {
     450             :   static value s_null;
     451             :   PICOJSON_ASSERT(is<array>());
     452             :   return idx < u_.array_->size() ? (*u_.array_)[idx] : s_null;
     453             : }
     454             : 
     455             : inline const value &value::get(const std::string &key) const {
     456             :   static value s_null;
     457             :   PICOJSON_ASSERT(is<object>());
     458             :   object::const_iterator i = u_.object_->find(key);
     459             :   return i != u_.object_->end() ? i->second : s_null;
     460             : }
     461             : 
     462             : inline value &value::get(const std::string &key) {
     463             :   static value s_null;
     464             :   PICOJSON_ASSERT(is<object>());
     465             :   object::iterator i = u_.object_->find(key);
     466             :   return i != u_.object_->end() ? i->second : s_null;
     467             : }
     468             : 
     469             : inline bool value::contains(const size_t idx) const {
     470             :   PICOJSON_ASSERT(is<array>());
     471             :   return idx < u_.array_->size();
     472             : }
     473             : 
     474             : inline bool value::contains(const std::string &key) const {
     475             :   PICOJSON_ASSERT(is<object>());
     476             :   object::const_iterator i = u_.object_->find(key);
     477             :   return i != u_.object_->end();
     478             : }
     479             : 
     480             : inline std::string value::to_str() const {
     481             :   switch (type_) {
     482             :   case null_type:
     483             :     return "null";
     484             :   case boolean_type:
     485             :     return u_.boolean_ ? "true" : "false";
     486             : #ifdef PICOJSON_USE_INT64
     487             :   case int64_type: {
     488             :     char buf[sizeof("-9223372036854775808")];
     489             :     SNPRINTF(buf, sizeof(buf), "%" PRId64, u_.int64_);
     490             :     return buf;
     491             :   }
     492             : #endif
     493             :   case number_type: {
     494             :     char buf[256];
     495             :     double tmp;
     496             :     SNPRINTF(buf, sizeof(buf), fabs(u_.number_) < (1ULL << 53) && modf(u_.number_, &tmp) == 0 ? "%.f" : "%.17g", u_.number_);
     497             : #if PICOJSON_USE_LOCALE
     498             :     char *decimal_point = localeconv()->decimal_point;
     499             :     if (strcmp(decimal_point, ".") != 0) {
     500             :       size_t decimal_point_len = strlen(decimal_point);
     501             :       for (char *p = buf; *p != '\0'; ++p) {
     502             :         if (strncmp(p, decimal_point, decimal_point_len) == 0) {
     503             :           return std::string(buf, p) + "." + (p + decimal_point_len);
     504             :         }
     505             :       }
     506             :     }
     507             : #endif
     508             :     return buf;
     509             :   }
     510             :   case string_type:
     511             :     return *u_.string_;
     512             :   case array_type:
     513             :     return "array";
     514             :   case object_type:
     515             :     return "object";
     516             :   default:
     517             :     PICOJSON_ASSERT(0);
     518             : #ifdef _MSC_VER
     519             :     __assume(0);
     520             : #endif
     521             :   }
     522             :   return std::string();
     523             : }
     524             : 
     525             : template <typename Iter> void copy(const std::string &s, Iter oi) {
     526             :   std::copy(s.begin(), s.end(), oi);
     527             : }
     528             : 
     529             : template <typename Iter> struct serialize_str_char {
     530             :   Iter oi;
     531             :   void operator()(char c) {
     532             :     switch (c) {
     533             : #define MAP(val, sym)                                                                                                              \
     534             :   case val:                                                                                                                        \
     535             :     copy(sym, oi);                                                                                                                 \
     536             :     break
     537             :       MAP('"', "\\\"");
     538             :       MAP('\\', "\\\\");
     539             :       MAP('/', "\\/");
     540             :       MAP('\b', "\\b");
     541             :       MAP('\f', "\\f");
     542             :       MAP('\n', "\\n");
     543             :       MAP('\r', "\\r");
     544             :       MAP('\t', "\\t");
     545             : #undef MAP
     546             :     default:
     547             :       if (static_cast<unsigned char>(c) < 0x20 || c == 0x7f) {
     548             :         char buf[7];
     549             :         SNPRINTF(buf, sizeof(buf), "\\u%04x", c & 0xff);
     550             :         copy(buf, buf + 6, oi);
     551             :       } else {
     552             :         *oi++ = c;
     553             :       }
     554             :       break;
     555             :     }
     556             :   }
     557             : };
     558             : 
     559             : template <typename Iter> void serialize_str(const std::string &s, Iter oi) {
     560             :   *oi++ = '"';
     561             :   serialize_str_char<Iter> process_char = {oi};
     562             :   std::for_each(s.begin(), s.end(), process_char);
     563             :   *oi++ = '"';
     564             : }
     565             : 
     566             : template <typename Iter> void value::serialize(Iter oi, bool prettify) const {
     567             :   return _serialize(oi, prettify ? 0 : -1);
     568             : }
     569             : 
     570             : inline std::string value::serialize(bool prettify) const {
     571             :   return _serialize(prettify ? 0 : -1);
     572             : }
     573             : 
     574             : template <typename Iter> void value::_indent(Iter oi, int indent) {
     575             :   *oi++ = '\n';
     576             :   for (int i = 0; i < indent * INDENT_WIDTH; ++i) {
     577             :     *oi++ = ' ';
     578             :   }
     579             : }
     580             : 
     581             : template <typename Iter> void value::_serialize(Iter oi, int indent) const {
     582             :   switch (type_) {
     583             :   case string_type:
     584             :     serialize_str(*u_.string_, oi);
     585             :     break;
     586             :   case array_type: {
     587             :     *oi++ = '[';
     588             :     if (indent != -1) {
     589             :       ++indent;
     590             :     }
     591             :     for (array::const_iterator i = u_.array_->begin(); i != u_.array_->end(); ++i) {
     592             :       if (i != u_.array_->begin()) {
     593             :         *oi++ = ',';
     594             :       }
     595             :       if (indent != -1) {
     596             :         _indent(oi, indent);
     597             :       }
     598             :       i->_serialize(oi, indent);
     599             :     }
     600             :     if (indent != -1) {
     601             :       --indent;
     602             :       if (!u_.array_->empty()) {
     603             :         _indent(oi, indent);
     604             :       }
     605             :     }
     606             :     *oi++ = ']';
     607             :     break;
     608             :   }
     609             :   case object_type: {
     610             :     *oi++ = '{';
     611             :     if (indent != -1) {
     612             :       ++indent;
     613             :     }
     614             :     for (object::const_iterator i = u_.object_->begin(); i != u_.object_->end(); ++i) {
     615             :       if (i != u_.object_->begin()) {
     616             :         *oi++ = ',';
     617             :       }
     618             :       if (indent != -1) {
     619             :         _indent(oi, indent);
     620             :       }
     621             :       serialize_str(i->first, oi);
     622             :       *oi++ = ':';
     623             :       if (indent != -1) {
     624             :         *oi++ = ' ';
     625             :       }
     626             :       i->second._serialize(oi, indent);
     627             :     }
     628             :     if (indent != -1) {
     629             :       --indent;
     630             :       if (!u_.object_->empty()) {
     631             :         _indent(oi, indent);
     632             :       }
     633             :     }
     634             :     *oi++ = '}';
     635             :     break;
     636             :   }
     637             :   default:
     638             :     copy(to_str(), oi);
     639             :     break;
     640             :   }
     641             :   if (indent == 0) {
     642             :     *oi++ = '\n';
     643             :   }
     644             : }
     645             : 
     646             : inline std::string value::_serialize(int indent) const {
     647             :   std::string s;
     648             :   _serialize(std::back_inserter(s), indent);
     649             :   return s;
     650             : }
     651             : 
     652             : template <typename Iter> class input {
     653             : protected:
     654             :   Iter cur_, end_;
     655             :   bool consumed_;
     656             :   int line_;
     657             : 
     658             : public:
     659          38 :   input(const Iter &first, const Iter &last) : cur_(first), end_(last), consumed_(false), line_(1) {
     660          38 :   }
     661        6507 :   int getc() {
     662        6507 :     if (consumed_) {
     663        5855 :       if (*cur_ == '\n') {
     664          72 :         ++line_;
     665             :       }
     666        5855 :       ++cur_;
     667             :     }
     668        6507 :     if (cur_ == end_) {
     669          20 :       consumed_ = false;
     670          20 :       return -1;
     671             :     }
     672        6487 :     consumed_ = true;
     673        6487 :     return *cur_ & 0xff;
     674             :   }
     675         614 :   void ungetc() {
     676         614 :     consumed_ = false;
     677         614 :   }
     678          38 :   Iter cur() const {
     679          38 :     if (consumed_) {
     680          34 :       input<Iter> *self = const_cast<input<Iter> *>(this);
     681          34 :       self->consumed_ = false;
     682          34 :       ++self->cur_;
     683             :     }
     684          38 :     return cur_;
     685             :   }
     686           4 :   int line() const {
     687           4 :     return line_;
     688             :   }
     689        1972 :   void skip_ws() {
     690        1490 :     while (1) {
     691        1972 :       int ch = getc();
     692        1972 :       if (!(ch == ' ' || ch == '\t' || ch == '\n' || ch == '\r')) {
     693         482 :         ungetc();
     694         482 :         break;
     695             :       }
     696             :     }
     697         482 :   }
     698         348 :   bool expect(const int expected) {
     699         348 :     skip_ws();
     700         348 :     if (getc() != expected) {
     701         120 :       ungetc();
     702         120 :       return false;
     703             :     }
     704         228 :     return true;
     705             :   }
     706           2 :   bool match(const std::string &pattern) {
     707           9 :     for (std::string::const_iterator pi(pattern.begin()); pi != pattern.end(); ++pi) {
     708           7 :       if (getc() != *pi) {
     709           0 :         ungetc();
     710           0 :         return false;
     711             :       }
     712             :     }
     713           2 :     return true;
     714             :   }
     715             : };
     716             : 
     717           0 : template <typename Iter> inline int _parse_quadhex(input<Iter> &in) {
     718           0 :   int uni_ch = 0, hex;
     719           0 :   for (int i = 0; i < 4; i++) {
     720           0 :     if ((hex = in.getc()) == -1) {
     721           0 :       return -1;
     722             :     }
     723           0 :     if ('0' <= hex && hex <= '9') {
     724           0 :       hex -= '0';
     725           0 :     } else if ('A' <= hex && hex <= 'F') {
     726           0 :       hex -= 'A' - 0xa;
     727           0 :     } else if ('a' <= hex && hex <= 'f') {
     728           0 :       hex -= 'a' - 0xa;
     729             :     } else {
     730           0 :       in.ungetc();
     731           0 :       return -1;
     732             :     }
     733           0 :     uni_ch = uni_ch * 16 + hex;
     734             :   }
     735           0 :   return uni_ch;
     736             : }
     737             : 
     738           0 : template <typename String, typename Iter> inline bool _parse_codepoint(String &out, input<Iter> &in) {
     739             :   int uni_ch;
     740           0 :   if ((uni_ch = _parse_quadhex(in)) == -1) {
     741           0 :     return false;
     742             :   }
     743           0 :   if (0xd800 <= uni_ch && uni_ch <= 0xdfff) {
     744           0 :     if (0xdc00 <= uni_ch) {
     745             :       // a second 16-bit of a surrogate pair appeared
     746           0 :       return false;
     747             :     }
     748             :     // first 16-bit of surrogate pair, get the next one
     749           0 :     if (in.getc() != '\\' || in.getc() != 'u') {
     750           0 :       in.ungetc();
     751           0 :       return false;
     752             :     }
     753           0 :     int second = _parse_quadhex(in);
     754           0 :     if (!(0xdc00 <= second && second <= 0xdfff)) {
     755           0 :       return false;
     756             :     }
     757           0 :     uni_ch = ((uni_ch - 0xd800) << 10) | ((second - 0xdc00) & 0x3ff);
     758           0 :     uni_ch += 0x10000;
     759             :   }
     760           0 :   if (uni_ch < 0x80) {
     761           0 :     out.push_back(static_cast<char>(uni_ch));
     762             :   } else {
     763           0 :     if (uni_ch < 0x800) {
     764           0 :       out.push_back(static_cast<char>(0xc0 | (uni_ch >> 6)));
     765             :     } else {
     766           0 :       if (uni_ch < 0x10000) {
     767           0 :         out.push_back(static_cast<char>(0xe0 | (uni_ch >> 12)));
     768             :       } else {
     769           0 :         out.push_back(static_cast<char>(0xf0 | (uni_ch >> 18)));
     770           0 :         out.push_back(static_cast<char>(0x80 | ((uni_ch >> 12) & 0x3f)));
     771             :       }
     772           0 :       out.push_back(static_cast<char>(0x80 | ((uni_ch >> 6) & 0x3f)));
     773             :     }
     774           0 :     out.push_back(static_cast<char>(0x80 | (uni_ch & 0x3f)));
     775             :   }
     776           0 :   return true;
     777             : }
     778             : 
     779        3799 : template <typename String, typename Iter> inline bool _parse_string(String &out, input<Iter> &in) {
     780        3673 :   while (1) {
     781        3799 :     int ch = in.getc();
     782        3799 :     if (ch < ' ') {
     783           0 :       in.ungetc();
     784           0 :       return false;
     785        3799 :     } else if (ch == '"') {
     786         126 :       return true;
     787        3673 :     } else if (ch == '\\') {
     788         231 :       if ((ch = in.getc()) == -1) {
     789           0 :         return false;
     790             :       }
     791         231 :       switch (ch) {
     792             : #define MAP(sym, val)                                                                                                              \
     793             :   case sym:                                                                                                                        \
     794             :     out.push_back(val);                                                                                                            \
     795             :     break
     796          18 :         MAP('"', '\"');
     797         213 :         MAP('\\', '\\');
     798           0 :         MAP('/', '/');
     799           0 :         MAP('b', '\b');
     800           0 :         MAP('f', '\f');
     801           0 :         MAP('n', '\n');
     802           0 :         MAP('r', '\r');
     803           0 :         MAP('t', '\t');
     804             : #undef MAP
     805           0 :       case 'u':
     806           0 :         if (!_parse_codepoint(out, in)) {
     807           0 :           return false;
     808             :         }
     809           0 :         break;
     810           0 :       default:
     811           0 :         return false;
     812             :       }
     813             :     } else {
     814        3442 :       out.push_back(static_cast<char>(ch));
     815             :     }
     816             :   }
     817             :   return false;
     818             : }
     819             : 
     820          24 : template <typename Context, typename Iter> inline bool _parse_array(Context &ctx, input<Iter> &in) {
     821          24 :   if (!ctx.parse_array_start()) {
     822           0 :     return false;
     823             :   }
     824          24 :   size_t idx = 0;
     825          24 :   if (in.expect(']')) {
     826           2 :     return ctx.parse_array_stop(idx);
     827             :   }
     828          10 :   do {
     829          32 :     if (!ctx.parse_array_item(in, idx)) {
     830           0 :       return false;
     831             :     }
     832          32 :     idx++;
     833          32 :   } while (in.expect(','));
     834          22 :   return in.expect(']') && ctx.parse_array_stop(idx);
     835             : }
     836             : 
     837          40 : template <typename Context, typename Iter> inline bool _parse_object(Context &ctx, input<Iter> &in) {
     838          40 :   if (!ctx.parse_object_start()) {
     839           0 :     return false;
     840             :   }
     841          40 :   if (in.expect('}')) {
     842           2 :     return ctx.parse_object_stop();
     843             :   }
     844          30 :   do {
     845          68 :     std::string key;
     846          68 :     if (!in.expect('"') || !_parse_string(key, in) || !in.expect(':')) {
     847           4 :       return false;
     848             :     }
     849          64 :     if (!ctx.parse_object_item(in, key)) {
     850           0 :       return false;
     851             :     }
     852          64 :   } while (in.expect(','));
     853          34 :   return in.expect('}') && ctx.parse_object_stop();
     854             : }
     855             : 
     856           6 : template <typename Iter> inline std::string _parse_number(input<Iter> &in) {
     857           6 :   std::string num_str;
     858           6 :   while (1) {
     859          12 :     int ch = in.getc();
     860          12 :     if (('0' <= ch && ch <= '9') || ch == '+' || ch == '-' || ch == 'e' || ch == 'E') {
     861           6 :       num_str.push_back(static_cast<char>(ch));
     862           6 :     } else if (ch == '.') {
     863             : #if PICOJSON_USE_LOCALE
     864           0 :       num_str += localeconv()->decimal_point;
     865             : #else
     866             :       num_str.push_back('.');
     867             : #endif
     868             :     } else {
     869           6 :       in.ungetc();
     870           6 :       break;
     871             :     }
     872             :   }
     873           6 :   return num_str;
     874             : }
     875             : 
     876         134 : template <typename Context, typename Iter> inline bool _parse(Context &ctx, input<Iter> &in) {
     877         134 :   in.skip_ws();
     878         134 :   int ch = in.getc();
     879         134 :   switch (ch) {
     880             : #define IS(ch, text, op)                                                                                                           \
     881             :   case ch:                                                                                                                         \
     882             :     if (in.match(text) && op) {                                                                                                    \
     883             :       return true;                                                                                                                 \
     884             :     } else {                                                                                                                       \
     885             :       return false;                                                                                                                \
     886             :     }
     887           0 :     IS('n', "ull", ctx.set_null());
     888           2 :     IS('f', "alse", ctx.set_bool(false));
     889           2 :     IS('t', "rue", ctx.set_bool(true));
     890             : #undef IS
     891          62 :   case '"':
     892          62 :     return ctx.parse_string(in);
     893          24 :   case '[':
     894          24 :     return _parse_array(ctx, in);
     895          40 :   case '{':
     896          40 :     return _parse_object(ctx, in);
     897           6 :   default:
     898           6 :     if (('0' <= ch && ch <= '9') || ch == '-') {
     899             :       double f;
     900             :       char *endp;
     901           6 :       in.ungetc();
     902          12 :       std::string num_str(_parse_number(in));
     903           6 :       if (num_str.empty()) {
     904           0 :         return false;
     905             :       }
     906             : #ifdef PICOJSON_USE_INT64
     907             :       {
     908           6 :         errno = 0;
     909           6 :         intmax_t ival = strtoimax(num_str.c_str(), &endp, 10);
     910          12 :         if (errno == 0 && std::numeric_limits<int64_t>::min() <= ival && ival <= std::numeric_limits<int64_t>::max() &&
     911           6 :             endp == num_str.c_str() + num_str.size()) {
     912           6 :           ctx.set_int64(ival);
     913           6 :           return true;
     914             :         }
     915             :       }
     916             : #endif
     917           0 :       f = strtod(num_str.c_str(), &endp);
     918           0 :       if (endp == num_str.c_str() + num_str.size()) {
     919           0 :         ctx.set_number(f);
     920           0 :         return true;
     921             :       }
     922           0 :       return false;
     923             :     }
     924           0 :     break;
     925             :   }
     926           0 :   in.ungetc();
     927           0 :   return false;
     928             : }
     929             : 
     930             : class deny_parse_context {
     931             : public:
     932             :   bool set_null() {
     933             :     return false;
     934             :   }
     935             :   bool set_bool(bool) {
     936             :     return false;
     937             :   }
     938             : #ifdef PICOJSON_USE_INT64
     939             :   bool set_int64(int64_t) {
     940             :     return false;
     941             :   }
     942             : #endif
     943             :   bool set_number(double) {
     944             :     return false;
     945             :   }
     946             :   template <typename Iter> bool parse_string(input<Iter> &) {
     947             :     return false;
     948             :   }
     949             :   bool parse_array_start() {
     950             :     return false;
     951             :   }
     952             :   template <typename Iter> bool parse_array_item(input<Iter> &, size_t) {
     953             :     return false;
     954             :   }
     955             :   bool parse_array_stop(size_t) {
     956             :     return false;
     957             :   }
     958             :   bool parse_object_start() {
     959             :     return false;
     960             :   }
     961             :   template <typename Iter> bool parse_object_item(input<Iter> &, const std::string &) {
     962             :     return false;
     963             :   }
     964             : };
     965             : 
     966             : class default_parse_context {
     967             : protected:
     968             :   value *out_;
     969             :   size_t depths_;
     970             : 
     971             : public:
     972         134 :   default_parse_context(value *out, size_t depths = DEFAULT_MAX_DEPTHS) : out_(out), depths_(depths) {
     973         134 :   }
     974           0 :   bool set_null() {
     975           0 :     *out_ = value();
     976           0 :     return true;
     977             :   }
     978           2 :   bool set_bool(bool b) {
     979           2 :     *out_ = value(b);
     980           2 :     return true;
     981             :   }
     982             : #ifdef PICOJSON_USE_INT64
     983           6 :   bool set_int64(int64_t i) {
     984           6 :     *out_ = value(i);
     985           6 :     return true;
     986             :   }
     987             : #endif
     988           0 :   bool set_number(double f) {
     989           0 :     *out_ = value(f);
     990           0 :     return true;
     991             :   }
     992          62 :   template <typename Iter> bool parse_string(input<Iter> &in) {
     993          62 :     *out_ = value(string_type, false);
     994          62 :     return _parse_string(out_->get<std::string>(), in);
     995             :   }
     996          24 :   bool parse_array_start() {
     997          24 :     if (depths_ == 0)
     998           0 :       return false;
     999          24 :     --depths_;
    1000          24 :     *out_ = value(array_type, false);
    1001          24 :     return true;
    1002             :   }
    1003          32 :   template <typename Iter> bool parse_array_item(input<Iter> &in, size_t) {
    1004          32 :     array &a = out_->get<array>();
    1005          32 :     a.push_back(value());
    1006          32 :     default_parse_context ctx(&a.back(), depths_);
    1007          64 :     return _parse(ctx, in);
    1008             :   }
    1009          24 :   bool parse_array_stop(size_t) {
    1010          24 :     ++depths_;
    1011          24 :     return true;
    1012             :   }
    1013          40 :   bool parse_object_start() {
    1014          40 :     if (depths_ == 0)
    1015           0 :       return false;
    1016          40 :     *out_ = value(object_type, false);
    1017          40 :     return true;
    1018             :   }
    1019          64 :   template <typename Iter> bool parse_object_item(input<Iter> &in, const std::string &key) {
    1020          64 :     object &o = out_->get<object>();
    1021          64 :     default_parse_context ctx(&o[key], depths_);
    1022         128 :     return _parse(ctx, in);
    1023             :   }
    1024          36 :   bool parse_object_stop() {
    1025          36 :     ++depths_;
    1026          36 :     return true;
    1027             :   }
    1028             : 
    1029             : private:
    1030             :   default_parse_context(const default_parse_context &);
    1031             :   default_parse_context &operator=(const default_parse_context &);
    1032             : };
    1033             : 
    1034             : class null_parse_context {
    1035             : protected:
    1036             :   size_t depths_;
    1037             : 
    1038             : public:
    1039             :   struct dummy_str {
    1040             :     void push_back(int) {
    1041             :     }
    1042             :   };
    1043             : 
    1044             : public:
    1045             :   null_parse_context(size_t depths = DEFAULT_MAX_DEPTHS) : depths_(depths) {
    1046             :   }
    1047             :   bool set_null() {
    1048             :     return true;
    1049             :   }
    1050             :   bool set_bool(bool) {
    1051             :     return true;
    1052             :   }
    1053             : #ifdef PICOJSON_USE_INT64
    1054             :   bool set_int64(int64_t) {
    1055             :     return true;
    1056             :   }
    1057             : #endif
    1058             :   bool set_number(double) {
    1059             :     return true;
    1060             :   }
    1061             :   template <typename Iter> bool parse_string(input<Iter> &in) {
    1062             :     dummy_str s;
    1063             :     return _parse_string(s, in);
    1064             :   }
    1065             :   bool parse_array_start() {
    1066             :     if (depths_ == 0)
    1067             :       return false;
    1068             :     --depths_;
    1069             :     return true;
    1070             :   }
    1071             :   template <typename Iter> bool parse_array_item(input<Iter> &in, size_t) {
    1072             :     return _parse(*this, in);
    1073             :   }
    1074             :   bool parse_array_stop(size_t) {
    1075             :     ++depths_;
    1076             :     return true;
    1077             :   }
    1078             :   bool parse_object_start() {
    1079             :     if (depths_ == 0)
    1080             :       return false;
    1081             :     --depths_;
    1082             :     return true;
    1083             :   }
    1084             :   template <typename Iter> bool parse_object_item(input<Iter> &in, const std::string &) {
    1085             :     ++depths_;
    1086             :     return _parse(*this, in);
    1087             :   }
    1088             :   bool parse_object_stop() {
    1089             :     return true;
    1090             :   }
    1091             : 
    1092             : private:
    1093             :   null_parse_context(const null_parse_context &);
    1094             :   null_parse_context &operator=(const null_parse_context &);
    1095             : };
    1096             : 
    1097             : // obsolete, use the version below
    1098             : template <typename Iter> inline std::string parse(value &out, Iter &pos, const Iter &last) {
    1099             :   std::string err;
    1100             :   pos = parse(out, pos, last, &err);
    1101             :   return err;
    1102             : }
    1103             : 
    1104          38 : template <typename Context, typename Iter> inline Iter _parse(Context &ctx, const Iter &first, const Iter &last, std::string *err) {
    1105          38 :   input<Iter> in(first, last);
    1106          38 :   if (!_parse(ctx, in) && err != NULL) {
    1107             :     char buf[64];
    1108           4 :     SNPRINTF(buf, sizeof(buf), "syntax error at line %d near: ", in.line());
    1109           4 :     *err = buf;
    1110           0 :     while (1) {
    1111           4 :       int ch = in.getc();
    1112           4 :       if (ch == -1 || ch == '\n') {
    1113             :         break;
    1114           0 :       } else if (ch >= ' ') {
    1115           0 :         err->push_back(static_cast<char>(ch));
    1116             :       }
    1117             :     }
    1118             :   }
    1119          76 :   return in.cur();
    1120             : }
    1121             : 
    1122          38 : template <typename Iter> inline Iter parse(value &out, const Iter &first, const Iter &last, std::string *err) {
    1123          38 :   default_parse_context ctx(&out);
    1124          76 :   return _parse(ctx, first, last, err);
    1125             : }
    1126             : 
    1127           0 : inline std::string parse(value &out, const std::string &s) {
    1128           0 :   std::string err;
    1129           0 :   parse(out, s.begin(), s.end(), &err);
    1130           0 :   return err;
    1131             : }
    1132             : 
    1133          38 : inline std::string parse(value &out, std::istream &is) {
    1134          38 :   std::string err;
    1135          38 :   parse(out, std::istreambuf_iterator<char>(is.rdbuf()), std::istreambuf_iterator<char>(), &err);
    1136          38 :   return err;
    1137             : }
    1138             : 
    1139             : template <typename T> struct last_error_t { static std::string s; };
    1140             : template <typename T> std::string last_error_t<T>::s;
    1141             : 
    1142          42 : inline void set_last_error(const std::string &s) {
    1143          42 :   last_error_t<bool>::s = s;
    1144          42 : }
    1145             : 
    1146          25 : inline const std::string &get_last_error() {
    1147          25 :   return last_error_t<bool>::s;
    1148             : }
    1149             : 
    1150             : inline bool operator==(const value &x, const value &y) {
    1151             :   if (x.is<null>())
    1152             :     return y.is<null>();
    1153             : #define PICOJSON_CMP(type)                                                                                                         \
    1154             :   if (x.is<type>())                                                                                                                \
    1155             :   return y.is<type>() && x.get<type>() == y.get<type>()
    1156             :   PICOJSON_CMP(bool);
    1157             :   PICOJSON_CMP(double);
    1158             :   PICOJSON_CMP(std::string);
    1159             :   PICOJSON_CMP(array);
    1160             :   PICOJSON_CMP(object);
    1161             : #undef PICOJSON_CMP
    1162             :   PICOJSON_ASSERT(0);
    1163             : #ifdef _MSC_VER
    1164             :   __assume(0);
    1165             : #endif
    1166             :   return false;
    1167             : }
    1168             : 
    1169             : inline bool operator!=(const value &x, const value &y) {
    1170             :   return !(x == y);
    1171             : }
    1172             : }
    1173             : 
    1174             : #if !PICOJSON_USE_RVALUE_REFERENCE
    1175             : namespace std {
    1176             : template <> inline void swap(picojson::value &x, picojson::value &y) {
    1177             :   x.swap(y);
    1178             : }
    1179             : }
    1180             : #endif
    1181             : 
    1182          38 : inline std::istream &operator>>(std::istream &is, picojson::value &x) {
    1183          38 :   picojson::set_last_error(std::string());
    1184          38 :   const std::string err(picojson::parse(x, is));
    1185          38 :   if (!err.empty()) {
    1186           4 :     picojson::set_last_error(err);
    1187           4 :     is.setstate(std::ios::failbit);
    1188             :   }
    1189          76 :   return is;
    1190             : }
    1191             : 
    1192             : inline std::ostream &operator<<(std::ostream &os, const picojson::value &x) {
    1193             :   x.serialize(std::ostream_iterator<char>(os));
    1194             :   return os;
    1195             : }
    1196             : #ifdef _MSC_VER
    1197             : #pragma warning(pop)
    1198             : #endif
    1199             : 
    1200             : #endif

Generated by: LCOV version 1.14