ardupilot/libraries/SITL/picojson.h
Andrew Tridgell 7a4483b091 SITL: new XPlane backend
this makes use of DRefs to greatly improve XPlane support. It only
supports XPlane 11 and later

The key change is the use of a JSON file to map ArduPilot output
channels to DataRefs, and map raw joystick inputs to RC inputs

this gets rid of the awful throttle hack handling, and allows for
control of a much wider range of aircraft
2023-01-31 11:22:08 +11:00

1204 lines
34 KiB
C++

/*
picojson.h cloned from:
https://github.com/kazuho/picojson
*/
/*
* 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.
*/
// load a json file, actual return type is picojson::value
void *load_json(const char *filename);
/*
use picojson to load optional frame files
*/
#define PICOJSON_NOEXCEPT
#ifndef PICOJSON_ASSERT
#define PICOJSON_ASSERT(e) \
do { \
if (!(e)) \
::printf(#e "\n"); \
} while (0)
#endif
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wfloat-equal"
#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>
#else
extern "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
#ifndef PICOJSON_NOEXCEPT
#if PICOJSON_USE_RVALUE_REFERENCE
#define PICOJSON_NOEXCEPT noexcept
#else
#define PICOJSON_NOEXCEPT throw()
#endif
#endif
// experimental support for int64_t (see README.mkdn for detail)
#ifdef PICOJSON_USE_INT64
#define __STDC_FORMAT_MACROS
#include <cerrno>
#if __cplusplus >= 201103L
#include <cinttypes>
#else
extern "C" {
#include <inttypes.h>
}
#endif
#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_LOCALE
extern "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
#pragma warning(disable : 4706) // assignment within conditional expression
#else
#define SNPRINTF snprintf
#endif
namespace 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) PICOJSON_NOEXCEPT;
value &operator=(value &&x) PICOJSON_NOEXCEPT;
#endif
void swap(value &x) PICOJSON_NOEXCEPT;
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_INT64
inline value::value(int64_t i) : type_(int64_type), u_() {
u_.int64_ = i;
}
#endif
inline value::value(double n) : type_(number_type), u_() {
#ifndef PICOJSON_NOEXCEPT
if (
#ifdef _MSC_VER
!_finite(n)
#elif __cplusplus >= 201103L
std::isnan(n) || std::isinf(n)
#else
isnan(n) || isinf(n)
#endif
) {
throw std::overflow_error("");
}
#endif
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_REFERENCE
inline 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));
}
#endif
inline 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_REFERENCE
inline value::value(value &&x) PICOJSON_NOEXCEPT : type_(null_type), u_() {
swap(x);
}
inline value &value::operator=(value &&x) PICOJSON_NOEXCEPT {
swap(x);
return *this;
}
#endif
inline void value::swap(value &x) PICOJSON_NOEXCEPT {
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_INT64
IS(int64_t, int64)
#endif
IS(std::string, string)
IS(array, array)
IS(object, object)
#undef IS
template <> 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_INT64
GET(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_)
#else
GET(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_INT64
SET(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
#endif
inline 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 below
template <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_REFERENCE
namespace std {
template <> inline void swap(picojson::value &x, picojson::value &y) {
x.swap(y);
}
}
#endif
inline 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
#pragma GCC diagnostic pop