New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

json11 fixes from upstream via pdns #135

Merged
merged 1 commit into from May 4, 2017
Jump to file or symbol
Failed to load files and symbols.
+157 −36
Diff settings

Always

Just for now

json11 fixes from upstream via pdns

  • Loading branch information...
neilcook committed May 4, 2017
commit 9e4d9bd48663e849be13e2cb5fcf64f917aec608
View
@@ -21,10 +21,11 @@
#include "json11.hpp"
#include <cassert>
#include <cmath>
#include <cstdlib>
#include <cstdio>
#include <limits>
#include <string.h>
#include <string>
namespace json11 {
@@ -37,18 +38,31 @@ using std::make_shared;
using std::initializer_list;
using std::move;
/* Helper for representing null - just a do-nothing struct, plus comparison
* operators so the helpers in JsonValue work. We can't use nullptr_t because
* it may not be orderable.
*/
struct NullStruct {
bool operator==(NullStruct) const { return true; }
bool operator<(NullStruct) const { return false; }
};
/* * * * * * * * * * * * * * * * * * * *
* Serialization
*/
static void dump(std::nullptr_t, string &out) {
static void dump(NullStruct, string &out) {
out += "null";
}
static void dump(double value, string &out) {
char buf[32];
snprintf(buf, sizeof buf, "%.17g", value);
out += buf;
if (std::isfinite(value)) {
char buf[32];
snprintf(buf, sizeof buf, "%.17g", value);
out += buf;
} else {
out += "null";
}
}
static void dump(int value, string &out) {
@@ -204,9 +218,9 @@ class JsonObject final : public Value<Json::OBJECT, Json::object> {
explicit JsonObject(Json::object &&value) : Value(move(value)) {}
};
class JsonNull final : public Value<Json::NUL, std::nullptr_t> {
class JsonNull final : public Value<Json::NUL, NullStruct> {
public:
JsonNull() : Value(nullptr) {}
JsonNull() : Value({}) {}
};
/* * * * * * * * * * * * * * * * * * * *
@@ -222,12 +236,12 @@ struct Statics {
Statics() {}
};
const Statics & statics() {
static const Statics & statics() {
static const Statics s {};
return s;
}
const Json & static_null() {
static const Json & static_null() {
// This has to be separate, not in Statics, because Json() accesses statics().null.
static const Json json_null;
return json_null;
@@ -322,18 +336,20 @@ static inline bool in_range(long x, long lower, long upper) {
return (x >= lower && x <= upper);
}
namespace {
/* JsonParser
*
* Object that tracks all state of an in-progress parse.
*/
struct JsonParser {
struct JsonParser final {
/* State
*/
const string &str;
size_t i;
string &err;
bool failed;
const JsonParse strategy;
/* fail(msg, err_ret = Json())
*
@@ -360,15 +376,76 @@ struct JsonParser {
i++;
}
/* consume_comment()
*
* Advance comments (c-style inline and multiline).
*/
bool consume_comment() {
bool comment_found = false;
if (str[i] == '/') {
i++;
if (i == str.size())
return fail("unexpected end of input inside comment", false);
if (str[i] == '/') { // inline comment
i++;
if (i == str.size())
return fail("unexpected end of input inside inline comment", false);
// advance until next line
while (str[i] != '\n') {
i++;
if (i == str.size())
return fail("unexpected end of input inside inline comment", false);
}
comment_found = true;
}
else if (str[i] == '*') { // multiline comment
i++;
if (i > str.size()-2)
return fail("unexpected end of input inside multi-line comment", false);
// advance until closing tokens
while (!(str[i] == '*' && str[i+1] == '/')) {
i++;
if (i > str.size()-2)
return fail(
"unexpected end of input inside multi-line comment", false);
}
i += 2;
if (i == str.size())
return fail(
"unexpected end of input inside multi-line comment", false);
comment_found = true;
}
else
return fail("malformed comment", false);
}
return comment_found;
}
/* consume_garbage()
*
* Advance until the current character is non-whitespace and non-comment.
*/
void consume_garbage() {
consume_whitespace();
if(strategy == JsonParse::COMMENTS) {
bool comment_found = false;
do {
comment_found = consume_comment();
consume_whitespace();
}
while(comment_found);
}
}
/* get_next_token()
*
* Return the next non-whitespace character. If the end of the input is reached,
* flag an error and return 0.
*/
char get_next_token() {
consume_whitespace();
consume_garbage();
if (i == str.size())
return fail("unexpected end of input", 0);
return fail("unexpected end of input", (char)0);
return str[i++];
}
@@ -382,19 +459,19 @@ struct JsonParser {
return;
if (pt < 0x80) {
out += pt;
out += static_cast<char>(pt);
} else if (pt < 0x800) {
out += (pt >> 6) | 0xC0;
out += (pt & 0x3F) | 0x80;
out += static_cast<char>((pt >> 6) | 0xC0);
out += static_cast<char>((pt & 0x3F) | 0x80);
} else if (pt < 0x10000) {
out += (pt >> 12) | 0xE0;
out += ((pt >> 6) & 0x3F) | 0x80;
out += (pt & 0x3F) | 0x80;
out += static_cast<char>((pt >> 12) | 0xE0);
out += static_cast<char>(((pt >> 6) & 0x3F) | 0x80);
out += static_cast<char>((pt & 0x3F) | 0x80);
} else {
out += (pt >> 18) | 0xF0;
out += ((pt >> 12) & 0x3F) | 0x80;
out += ((pt >> 6) & 0x3F) | 0x80;
out += (pt & 0x3F) | 0x80;
out += static_cast<char>((pt >> 18) | 0xF0);
out += static_cast<char>(((pt >> 12) & 0x3F) | 0x80);
out += static_cast<char>(((pt >> 6) & 0x3F) | 0x80);
out += static_cast<char>((pt & 0x3F) | 0x80);
}
}
@@ -436,7 +513,13 @@ struct JsonParser {
if (ch == 'u') {
// Extract 4-byte escape sequence
string esc = str.substr(i, 4);
for (int j = 0; j < 4; j++) {
// Explicitly check length of the substring. The following loop
// relies on std::string returning the terminating NUL when
// accessing str[length]. Checking here reduces brittleness.
if (esc.length() < 4) {
return fail("bad \\u escape: " + esc, "");
}
for (size_t j = 0; j < 4; j++) {
if (!in_range(esc[j], 'a', 'f') && !in_range(esc[j], 'A', 'F')
&& !in_range(esc[j], '0', '9'))
return fail("bad \\u escape: " + esc, "");
@@ -537,7 +620,7 @@ struct JsonParser {
i++;
}
return std::atof(str.c_str() + start_pos);
return std::strtod(str.c_str() + start_pos, nullptr);
}
/* expect(str, res)
@@ -646,28 +729,34 @@ struct JsonParser {
return fail("expected value, got " + esc(ch));
}
};
}//namespace {
Json Json::parse(const string &in, string &err) {
JsonParser parser { in, 0, err, false };
Json Json::parse(const string &in, string &err, JsonParse strategy) {
JsonParser parser { in, 0, err, false, strategy };
Json result = parser.parse_json(0);
// Check for any trailing garbage
parser.consume_whitespace();
parser.consume_garbage();
if (parser.i != in.size())
return parser.fail("unexpected trailing " + esc(in[parser.i]));
return result;
}
// Documented in json11.hpp
vector<Json> Json::parse_multi(const string &in, string &err) {
JsonParser parser { in, 0, err, false };
vector<Json> Json::parse_multi(const string &in,
std::string::size_type &parser_stop_pos,
string &err,
JsonParse strategy) {
JsonParser parser { in, 0, err, false, strategy };
parser_stop_pos = 0;
vector<Json> json_vec;
while (parser.i != in.size() && !parser.failed) {
json_vec.push_back(parser.parse_json(0));
// Check for another object
parser.consume_whitespace();
parser.consume_garbage();
if (!parser.failed)
parser_stop_pos = parser.i;
}
return json_vec;
}
View
@@ -16,7 +16,7 @@
* A note on numbers - JSON specifies the syntax of number formatting but not its semantics,
* so some JSON implementations distinguish between integers and floating-point numbers, while
* some don't. In json11, we choose the latter. Because some JSON implementations (namely
* Javascript itself) treat all numbers as the same type, distinguishing the two leads
* JavaScript itself) treat all numbers as the same type, distinguishing the two leads
* to JSON that will be *silently* changed by a round-trip through those implementations.
* Dangerous! To avoid that risk, json11 stores all numbers as double internally, but also
* provides integer helpers.
@@ -56,8 +56,24 @@
#include <memory>
#include <initializer_list>
#ifdef _MSC_VER
#if _MSC_VER <= 1800 // VS 2013
#ifndef noexcept
#define noexcept throw()
#endif
#ifndef snprintf
#define snprintf _snprintf_s
#endif
#endif
#endif
namespace json11 {
enum JsonParse {
STANDARD, COMMENTS
};
class JsonValue;
class Json final {
@@ -145,17 +161,33 @@ class Json final {
}
// Parse. If parse fails, return Json() and assign an error message to err.
static Json parse(const std::string & in, std::string & err);
static Json parse(const char * in, std::string & err) {
static Json parse(const std::string & in,
std::string & err,
JsonParse strategy = JsonParse::STANDARD);
static Json parse(const char * in,
std::string & err,
JsonParse strategy = JsonParse::STANDARD) {
if (in) {
return parse(std::string(in), err);
return parse(std::string(in), err, strategy);
} else {
err = "null input";
return nullptr;
}
}
// Parse multiple objects, concatenated or separated by whitespace
static std::vector<Json> parse_multi(const std::string & in, std::string & err);
static std::vector<Json> parse_multi(
const std::string & in,
std::string::size_type & parser_stop_pos,
std::string & err,
JsonParse strategy = JsonParse::STANDARD);
static inline std::vector<Json> parse_multi(
const std::string & in,
std::string & err,
JsonParse strategy = JsonParse::STANDARD) {
std::string::size_type parser_stop_pos;
return parse_multi(in, parser_stop_pos, err, strategy);
}
bool operator== (const Json &rhs) const;
bool operator< (const Json &rhs) const;
ProTip! Use n and p to navigate between commits in a pull request.