dynamic parseNumber(Input& in) {
bool const negative = (*in == '-');
- if (negative) {
- if (in.consume("-Infinity")) {
+ if (negative && in.consume("-Infinity")) {
+ if (in.getOpts().parse_numbers_as_strings) {
+ return "-Infinity";
+ } else {
return -std::numeric_limits<double>::infinity();
}
}
constexpr const char* minInt = "9223372036854775808";
constexpr auto maxIntLen = __builtin_strlen(maxInt);
+
+ if (*in != '.' && !wasE && in.getOpts().parse_numbers_as_strings) {
+ return integral;
+ }
+
if (*in != '.' && !wasE) {
if (LIKELY(!in.getOpts().double_fallback || integral.size() < maxIntLen) ||
(integral.size() == maxIntLen &&
end = expPart.end();
}
auto fullNum = range(integral.begin(), end);
-
+ if (in.getOpts().parse_numbers_as_strings) {
+ return fullNum;
+ }
auto val = to<double>(fullNum);
return val;
}
in.consume("true") ? true :
in.consume("false") ? false :
in.consume("null") ? nullptr :
- in.consume("Infinity") ? std::numeric_limits<double>::infinity() :
- in.consume("NaN") ? std::numeric_limits<double>::quiet_NaN() :
+ in.consume("Infinity") ?
+ (in.getOpts().parse_numbers_as_strings ? (dynamic)"Infinity" :
+ (dynamic)std::numeric_limits<double>::infinity()) :
+ in.consume("NaN") ?
+ (in.getOpts().parse_numbers_as_strings ? (dynamic)"NaN" :
+ (dynamic)std::numeric_limits<double>::quiet_NaN()) :
in.error("expected json value");
}
, double_mode(double_conversion::DoubleToStringConverter::SHORTEST)
, double_num_digits(0) // ignored when mode is SHORTEST
, double_fallback(false)
+ , parse_numbers_as_strings(false)
{}
// If true, keys in an object can be non-strings. (In strict
// Fallback to double when a value that looks like integer is too big to
// fit in an int64_t. Can result in loss a of precision.
bool double_fallback;
+
+ // Do not parse numbers. Instead, store them as strings and leave the
+ // conversion up to the user.
+ bool parse_numbers_as_strings;
};
/*
opts).items().begin()->second.asDouble());
}
+TEST(Json, ParseNumbersAsStrings) {
+ folly::json::serialization_opts opts;
+ opts.parse_numbers_as_strings = true;
+ auto parse = [&](folly::fbstring number) {
+ return parseJson(number, opts).asString();
+ };
+
+ EXPECT_EQ("0", parse("0"));
+ EXPECT_EQ("1234", parse("1234"));
+ EXPECT_EQ("3.00", parse("3.00"));
+ EXPECT_EQ("3.14", parse("3.14"));
+ EXPECT_EQ("0.1234", parse("0.1234"));
+ EXPECT_EQ("0.0", parse("0.0"));
+ EXPECT_EQ("46845131213548676854213265486468451312135486768542132",
+ parse("46845131213548676854213265486468451312135486768542132"));
+ EXPECT_EQ("-468451312135486768542132654864684513121354867685.5e4",
+ parse("-468451312135486768542132654864684513121354867685.5e4"));
+ EXPECT_EQ("6.62607004e-34", parse("6.62607004e-34"));
+ EXPECT_EQ("6.62607004E+34", parse("6.62607004E+34"));
+ EXPECT_EQ("Infinity", parse("Infinity"));
+ EXPECT_EQ("-Infinity", parse("-Infinity"));
+ EXPECT_EQ("NaN", parse("NaN"));
+
+ EXPECT_THROW(parse("ThisIsWrong"), std::runtime_error);
+ EXPECT_THROW(parse("34-2"), std::runtime_error);
+ EXPECT_THROW(parse(""), std::runtime_error);
+ EXPECT_THROW(parse("-"), std::runtime_error);
+ EXPECT_THROW(parse("34-e2"), std::runtime_error);
+ EXPECT_THROW(parse("34e2.4"), std::runtime_error);
+ EXPECT_THROW(parse("infinity"), std::runtime_error);
+ EXPECT_THROW(parse("nan"), std::runtime_error);
+}
+
TEST(Json, SortKeys) {
folly::json::serialization_opts opts_on, opts_off;
opts_on.sort_keys = true;