mirror of
https://github.com/bblanchon/ArduinoJson.git
synced 2025-07-23 07:17:30 +02:00
Added custom implementation of strtod()
(issue #453)
This commit is contained in:
2
.github/ISSUE_TEMPLATE.md
vendored
2
.github/ISSUE_TEMPLATE.md
vendored
@ -3,7 +3,7 @@ Thanks for using ArduinoJson :-)
|
|||||||
|
|
||||||
Before opening an issue, please make sure you've read these:
|
Before opening an issue, please make sure you've read these:
|
||||||
https://bblanchon.github.io/ArduinoJson/faq/
|
https://bblanchon.github.io/ArduinoJson/faq/
|
||||||
https://github.com/bblanchon/ArduinoJson/wiki/Avoiding-pitfalls
|
https://bblanchon.github.io/ArduinoJson/doc/pitfalls/
|
||||||
|
|
||||||
Next, make sure you provide all the relevant information: platform, code snippet, and error messages.
|
Next, make sure you provide all the relevant information: platform, code snippet, and error messages.
|
||||||
|
|
||||||
|
@ -1,6 +1,11 @@
|
|||||||
ArduinoJson: change log
|
ArduinoJson: change log
|
||||||
=======================
|
=======================
|
||||||
|
|
||||||
|
HEAD
|
||||||
|
----
|
||||||
|
|
||||||
|
* Added custom implementation of `strtod()` (issue #453)
|
||||||
|
|
||||||
v5.8.3
|
v5.8.3
|
||||||
------
|
------
|
||||||
|
|
||||||
|
@ -7,7 +7,7 @@ all: \
|
|||||||
$(OUT)/json_fuzzer_seed_corpus.zip \
|
$(OUT)/json_fuzzer_seed_corpus.zip \
|
||||||
$(OUT)/json_fuzzer.options
|
$(OUT)/json_fuzzer.options
|
||||||
|
|
||||||
$(OUT)/json_fuzzer: fuzzer.cpp
|
$(OUT)/json_fuzzer: fuzzer.cpp $(shell find ../include -type f)
|
||||||
$(CXX) $(CXXFLAGS) $< -o$@ $(LIB_FUZZING_ENGINE)
|
$(CXX) $(CXXFLAGS) $< -o$@ $(LIB_FUZZING_ENGINE)
|
||||||
|
|
||||||
$(OUT)/json_fuzzer_seed_corpus.zip: seed_corpus/*
|
$(OUT)/json_fuzzer_seed_corpus.zip: seed_corpus/*
|
||||||
|
@ -14,5 +14,11 @@
|
|||||||
12.34e+56,
|
12.34e+56,
|
||||||
12.34E56,
|
12.34E56,
|
||||||
12.34E-56,
|
12.34E-56,
|
||||||
12.34E+56
|
12.34E+56,
|
||||||
|
NaN,
|
||||||
|
-NaN,
|
||||||
|
+NaN,
|
||||||
|
Infinity,
|
||||||
|
+Infinity,
|
||||||
|
-Infinity
|
||||||
]
|
]
|
@ -1,66 +0,0 @@
|
|||||||
// Copyright Benoit Blanchon 2014-2017
|
|
||||||
// MIT License
|
|
||||||
//
|
|
||||||
// Arduino JSON library
|
|
||||||
// https://github.com/bblanchon/ArduinoJson
|
|
||||||
// If you like this project, please add a star!
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <stdlib.h>
|
|
||||||
|
|
||||||
namespace ArduinoJson {
|
|
||||||
namespace Internals {
|
|
||||||
template <typename TFloat>
|
|
||||||
TFloat parse(const char *);
|
|
||||||
|
|
||||||
template <>
|
|
||||||
inline float parse<float>(const char *s) {
|
|
||||||
return static_cast<float>(strtod(s, NULL));
|
|
||||||
}
|
|
||||||
|
|
||||||
template <>
|
|
||||||
inline double parse<double>(const char *s) {
|
|
||||||
return strtod(s, NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
template <>
|
|
||||||
inline long parse<long>(const char *s) {
|
|
||||||
return strtol(s, NULL, 10);
|
|
||||||
}
|
|
||||||
|
|
||||||
template <>
|
|
||||||
inline unsigned long parse<unsigned long>(const char *s) {
|
|
||||||
return strtoul(s, NULL, 10);
|
|
||||||
}
|
|
||||||
|
|
||||||
template <>
|
|
||||||
inline int parse<int>(const char *s) {
|
|
||||||
return atoi(s);
|
|
||||||
}
|
|
||||||
|
|
||||||
#if ARDUINOJSON_USE_LONG_LONG
|
|
||||||
template <>
|
|
||||||
inline long long parse<long long>(const char *s) {
|
|
||||||
return strtoll(s, NULL, 10);
|
|
||||||
}
|
|
||||||
|
|
||||||
template <>
|
|
||||||
inline unsigned long long parse<unsigned long long>(const char *s) {
|
|
||||||
return strtoull(s, NULL, 10);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if ARDUINOJSON_USE_INT64
|
|
||||||
template <>
|
|
||||||
inline __int64 parse<__int64>(const char *s) {
|
|
||||||
return _strtoi64(s, NULL, 10);
|
|
||||||
}
|
|
||||||
|
|
||||||
template <>
|
|
||||||
inline unsigned __int64 parse<unsigned __int64>(const char *s) {
|
|
||||||
return _strtoui64(s, NULL, 10);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
}
|
|
@ -8,10 +8,12 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "Configuration.hpp"
|
#include "Configuration.hpp"
|
||||||
#include "Data/Parse.hpp"
|
|
||||||
#include "JsonArray.hpp"
|
#include "JsonArray.hpp"
|
||||||
#include "JsonObject.hpp"
|
#include "JsonObject.hpp"
|
||||||
#include "JsonVariant.hpp"
|
#include "JsonVariant.hpp"
|
||||||
|
#include "Polyfills/isFloat.hpp"
|
||||||
|
#include "Polyfills/parseFloat.hpp"
|
||||||
|
#include "Polyfills/parseInteger.hpp"
|
||||||
|
|
||||||
#include <errno.h> // for errno
|
#include <errno.h> // for errno
|
||||||
#include <stdlib.h> // for strtol, strtod
|
#include <stdlib.h> // for strtol, strtod
|
||||||
@ -56,14 +58,14 @@ inline Internals::JsonInteger JsonVariant::variantAsInteger() const {
|
|||||||
case JSON_BOOLEAN:
|
case JSON_BOOLEAN:
|
||||||
return _content.asInteger;
|
return _content.asInteger;
|
||||||
case JSON_NEGATIVE_INTEGER:
|
case JSON_NEGATIVE_INTEGER:
|
||||||
return -static_cast<Internals::JsonInteger>(_content.asInteger);
|
return -static_cast<JsonInteger>(_content.asInteger);
|
||||||
case JSON_STRING:
|
case JSON_STRING:
|
||||||
case JSON_UNPARSED:
|
case JSON_UNPARSED:
|
||||||
if (!_content.asString) return 0;
|
if (!_content.asString) return 0;
|
||||||
if (!strcmp("true", _content.asString)) return 1;
|
if (!strcmp("true", _content.asString)) return 1;
|
||||||
return parse<Internals::JsonInteger>(_content.asString);
|
return Polyfills::parseInteger<JsonInteger>(_content.asString);
|
||||||
default:
|
default:
|
||||||
return static_cast<Internals::JsonInteger>(_content.asFloat);
|
return static_cast<JsonInteger>(_content.asFloat);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -80,9 +82,9 @@ inline Internals::JsonUInt JsonVariant::asUnsignedInteger() const {
|
|||||||
case JSON_UNPARSED:
|
case JSON_UNPARSED:
|
||||||
if (!_content.asString) return 0;
|
if (!_content.asString) return 0;
|
||||||
if (!strcmp("true", _content.asString)) return 1;
|
if (!strcmp("true", _content.asString)) return 1;
|
||||||
return parse<Internals::JsonUInt>(_content.asString);
|
return Polyfills::parseInteger<JsonUInt>(_content.asString);
|
||||||
default:
|
default:
|
||||||
return static_cast<Internals::JsonUInt>(_content.asFloat);
|
return static_cast<JsonUInt>(_content.asFloat);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -107,7 +109,9 @@ inline Internals::JsonFloat JsonVariant::variantAsFloat() const {
|
|||||||
return -static_cast<JsonFloat>(_content.asInteger);
|
return -static_cast<JsonFloat>(_content.asInteger);
|
||||||
case JSON_STRING:
|
case JSON_STRING:
|
||||||
case JSON_UNPARSED:
|
case JSON_UNPARSED:
|
||||||
return _content.asString ? parse<JsonFloat>(_content.asString) : 0;
|
return _content.asString
|
||||||
|
? Polyfills::parseFloat<JsonFloat>(_content.asString)
|
||||||
|
: 0;
|
||||||
default:
|
default:
|
||||||
return _content.asFloat;
|
return _content.asFloat;
|
||||||
}
|
}
|
||||||
@ -143,11 +147,7 @@ inline bool JsonVariant::isFloat() const {
|
|||||||
|
|
||||||
if (_type != JSON_UNPARSED || _content.asString == NULL) return false;
|
if (_type != JSON_UNPARSED || _content.asString == NULL) return false;
|
||||||
|
|
||||||
char *end;
|
return Polyfills::isFloat(_content.asString);
|
||||||
errno = 0;
|
|
||||||
strtod(_content.asString, &end);
|
|
||||||
|
|
||||||
return *end == '\0' && errno == 0 && !is<long>();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#if ARDUINOJSON_ENABLE_STD_STREAM
|
#if ARDUINOJSON_ENABLE_STD_STREAM
|
||||||
|
21
include/ArduinoJson/Polyfills/ctype.hpp
Normal file
21
include/ArduinoJson/Polyfills/ctype.hpp
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
// Copyright Benoit Blanchon 2014-2017
|
||||||
|
// MIT License
|
||||||
|
//
|
||||||
|
// Arduino JSON library
|
||||||
|
// https://github.com/bblanchon/ArduinoJson
|
||||||
|
// If you like this project, please add a star!
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
namespace ArduinoJson {
|
||||||
|
namespace Polyfills {
|
||||||
|
|
||||||
|
inline bool isdigit(char c) {
|
||||||
|
return '0' <= c && c <= '9';
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool issign(char c) {
|
||||||
|
return '-' == c || c == '+';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
40
include/ArduinoJson/Polyfills/isFloat.hpp
Normal file
40
include/ArduinoJson/Polyfills/isFloat.hpp
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
// Copyright Benoit Blanchon 2014-2017
|
||||||
|
// MIT License
|
||||||
|
//
|
||||||
|
// Arduino JSON library
|
||||||
|
// https://github.com/bblanchon/ArduinoJson
|
||||||
|
// If you like this project, please add a star!
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "./ctype.hpp"
|
||||||
|
#include "./math.hpp"
|
||||||
|
|
||||||
|
namespace ArduinoJson {
|
||||||
|
namespace Polyfills {
|
||||||
|
|
||||||
|
inline bool isFloat(const char* s) {
|
||||||
|
if (!strcmp(s, "NaN")) return true;
|
||||||
|
if (issign(*s)) s++;
|
||||||
|
if (!strcmp(s, "Infinity")) return true;
|
||||||
|
|
||||||
|
while (isdigit(*s)) s++;
|
||||||
|
|
||||||
|
bool has_dot = *s == '.';
|
||||||
|
if (has_dot) {
|
||||||
|
s++;
|
||||||
|
while (isdigit(*s)) s++;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool has_exponent = *s == 'e' || *s == 'E';
|
||||||
|
if (has_exponent) {
|
||||||
|
s++;
|
||||||
|
if (issign(*s)) s++;
|
||||||
|
if (!isdigit(*s)) return false;
|
||||||
|
while (isdigit(*s)) s++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (has_dot || has_exponent) && *s == '\0';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -7,10 +7,11 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
// If Visual Studo <= 2012
|
// If Visual Studo
|
||||||
#if defined(_MSC_VER) && _MSC_VER <= 1700
|
#if defined(_MSC_VER)
|
||||||
|
|
||||||
#include <float.h>
|
#include <float.h>
|
||||||
|
#include <limits>
|
||||||
|
|
||||||
namespace ArduinoJson {
|
namespace ArduinoJson {
|
||||||
namespace Polyfills {
|
namespace Polyfills {
|
||||||
@ -23,6 +24,16 @@ template <typename T>
|
|||||||
bool isInfinity(T x) {
|
bool isInfinity(T x) {
|
||||||
return !_finite(x);
|
return !_finite(x);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
T nan() {
|
||||||
|
return std::numeric_limits<T>::quiet_NaN();
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
T inf() {
|
||||||
|
return std::numeric_limits<T>::infinity();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -101,6 +112,16 @@ inline bool isInfinity<float>(float x) {
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
T nan() {
|
||||||
|
return static_cast<T>(NAN);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
T inf() {
|
||||||
|
return static_cast<T>(INFINITY);
|
||||||
|
}
|
||||||
|
|
||||||
#if defined(__GNUC__)
|
#if defined(__GNUC__)
|
||||||
#if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)
|
#if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)
|
||||||
#pragma GCC diagnostic pop
|
#pragma GCC diagnostic pop
|
||||||
|
87
include/ArduinoJson/Polyfills/parseFloat.hpp
Normal file
87
include/ArduinoJson/Polyfills/parseFloat.hpp
Normal file
@ -0,0 +1,87 @@
|
|||||||
|
// Copyright Benoit Blanchon 2014-2017
|
||||||
|
// MIT License
|
||||||
|
//
|
||||||
|
// Arduino JSON library
|
||||||
|
// https://github.com/bblanchon/ArduinoJson
|
||||||
|
// If you like this project, please add a star!
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "../TypeTraits/FloatTraits.hpp"
|
||||||
|
#include "./ctype.hpp"
|
||||||
|
#include "./math.hpp"
|
||||||
|
|
||||||
|
namespace ArduinoJson {
|
||||||
|
namespace Polyfills {
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
inline T parseFloat(const char* s) {
|
||||||
|
typedef TypeTraits::FloatTraits<T> traits;
|
||||||
|
typedef typename traits::mantissa_type mantissa_t;
|
||||||
|
typedef typename traits::exponent_type exponent_t;
|
||||||
|
|
||||||
|
bool negative_result = false;
|
||||||
|
switch (*s) {
|
||||||
|
case '-':
|
||||||
|
negative_result = true;
|
||||||
|
case '+':
|
||||||
|
s++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (*s == 'n' || *s == 'N') return traits::nan();
|
||||||
|
if (*s == 'i' || *s == 'I')
|
||||||
|
return negative_result ? -traits::inf() : traits::inf();
|
||||||
|
|
||||||
|
mantissa_t mantissa = 0;
|
||||||
|
exponent_t exponent_offset = 0;
|
||||||
|
|
||||||
|
while (isdigit(*s)) {
|
||||||
|
if (mantissa < traits::mantissa_max / 10)
|
||||||
|
mantissa = mantissa * 10 + (*s - '0');
|
||||||
|
else
|
||||||
|
exponent_offset++;
|
||||||
|
s++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (*s == '.') {
|
||||||
|
s++;
|
||||||
|
while (isdigit(*s)) {
|
||||||
|
if (mantissa < traits::mantissa_max / 10) {
|
||||||
|
mantissa = mantissa * 10 + (*s - '0');
|
||||||
|
exponent_offset--;
|
||||||
|
}
|
||||||
|
s++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int exponent = 0;
|
||||||
|
if (*s == 'e' || *s == 'E') {
|
||||||
|
s++;
|
||||||
|
bool negative_exponent = false;
|
||||||
|
if (*s == '-') {
|
||||||
|
negative_exponent = true;
|
||||||
|
s++;
|
||||||
|
} else if (*s == '+') {
|
||||||
|
s++;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (isdigit(*s)) {
|
||||||
|
exponent = exponent * 10 + (*s - '0');
|
||||||
|
if (exponent + exponent_offset > traits::exponent_max) {
|
||||||
|
if (negative_exponent)
|
||||||
|
return negative_result ? -0.0f : 0.0f;
|
||||||
|
else
|
||||||
|
return negative_result ? -traits::inf() : traits::inf();
|
||||||
|
}
|
||||||
|
s++;
|
||||||
|
}
|
||||||
|
if (negative_exponent) exponent = -exponent;
|
||||||
|
}
|
||||||
|
exponent += exponent_offset;
|
||||||
|
|
||||||
|
T result = traits::make_float(static_cast<T>(mantissa), exponent);
|
||||||
|
|
||||||
|
return negative_result ? -result : result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
56
include/ArduinoJson/Polyfills/parseInteger.hpp
Normal file
56
include/ArduinoJson/Polyfills/parseInteger.hpp
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
// Copyright Benoit Blanchon 2014-2017
|
||||||
|
// MIT License
|
||||||
|
//
|
||||||
|
// Arduino JSON library
|
||||||
|
// https://github.com/bblanchon/ArduinoJson
|
||||||
|
// If you like this project, please add a star!
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
namespace ArduinoJson {
|
||||||
|
namespace Polyfills {
|
||||||
|
template <typename T>
|
||||||
|
T parseInteger(const char *s);
|
||||||
|
|
||||||
|
template <>
|
||||||
|
inline long parseInteger<long>(const char *s) {
|
||||||
|
return ::strtol(s, NULL, 10);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <>
|
||||||
|
inline unsigned long parseInteger<unsigned long>(const char *s) {
|
||||||
|
return ::strtoul(s, NULL, 10);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <>
|
||||||
|
inline int parseInteger<int>(const char *s) {
|
||||||
|
return ::atoi(s);
|
||||||
|
}
|
||||||
|
|
||||||
|
#if ARDUINOJSON_USE_LONG_LONG
|
||||||
|
template <>
|
||||||
|
inline long long parseInteger<long long>(const char *s) {
|
||||||
|
return ::strtoll(s, NULL, 10);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <>
|
||||||
|
inline unsigned long long parseInteger<unsigned long long>(const char *s) {
|
||||||
|
return ::strtoull(s, NULL, 10);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if ARDUINOJSON_USE_INT64
|
||||||
|
template <>
|
||||||
|
inline __int64 parseInteger<__int64>(const char *s) {
|
||||||
|
return ::_strtoi64(s, NULL, 10);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <>
|
||||||
|
inline unsigned __int64 parseInteger<unsigned __int64>(const char *s) {
|
||||||
|
return ::_strtoui64(s, NULL, 10);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
83
include/ArduinoJson/TypeTraits/FloatTraits.hpp
Normal file
83
include/ArduinoJson/TypeTraits/FloatTraits.hpp
Normal file
@ -0,0 +1,83 @@
|
|||||||
|
// Copyright Benoit Blanchon 2014-2017
|
||||||
|
// MIT License
|
||||||
|
//
|
||||||
|
// Arduino JSON library
|
||||||
|
// https://github.com/bblanchon/ArduinoJson
|
||||||
|
// If you like this project, please add a star!
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include "../Polyfills/math.hpp"
|
||||||
|
|
||||||
|
namespace ArduinoJson {
|
||||||
|
namespace TypeTraits {
|
||||||
|
|
||||||
|
template <typename T, size_t = sizeof(T)>
|
||||||
|
struct FloatTraits {};
|
||||||
|
|
||||||
|
#ifndef ARDUINO_ARCH_AVR // double is 32 bits, so 1e64 gives a warning
|
||||||
|
template <typename T>
|
||||||
|
struct FloatTraits<T, 8 /*64bits*/> {
|
||||||
|
typedef int64_t mantissa_type;
|
||||||
|
static const short mantissa_bits = 52;
|
||||||
|
static const mantissa_type mantissa_max =
|
||||||
|
(static_cast<mantissa_type>(1) << mantissa_bits) - 1;
|
||||||
|
|
||||||
|
typedef int16_t exponent_type;
|
||||||
|
static const exponent_type exponent_max = 308;
|
||||||
|
|
||||||
|
template <typename TExponent>
|
||||||
|
static T make_float(T m, TExponent e) {
|
||||||
|
if (e >= 0)
|
||||||
|
return m * (e & 1 ? 1e1 : 1) * (e & 2 ? 1e2 : 1) * (e & 4 ? 1e4 : 1) *
|
||||||
|
(e & 8 ? 1e8 : 1) * (e & 16 ? 1e16 : 1) * (e & 32 ? 1e32 : 1) *
|
||||||
|
(e & 64 ? 1e64 : 1) * (e & 128 ? 1e128 : 1) *
|
||||||
|
(e & 256 ? 1e256 : 1);
|
||||||
|
e = -e;
|
||||||
|
return m * (e & 1 ? 1e-1 : 1) * (e & 2 ? 1e-2 : 1) * (e & 4 ? 1e-4 : 1) *
|
||||||
|
(e & 8 ? 1e-8 : 1) * (e & 16 ? 1e-16 : 1) * (e & 32 ? 1e-32 : 1) *
|
||||||
|
(e & 64 ? 1e-64 : 1) * (e & 128 ? 1e-128 : 1) *
|
||||||
|
(e & 256 ? 1e-256 : 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
static T nan() {
|
||||||
|
return Polyfills::nan<T>();
|
||||||
|
}
|
||||||
|
|
||||||
|
static T inf() {
|
||||||
|
return Polyfills::inf<T>();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
#endif
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
struct FloatTraits<T, 4 /*32bits*/> {
|
||||||
|
typedef int32_t mantissa_type;
|
||||||
|
static const short mantissa_bits = 23;
|
||||||
|
static const mantissa_type mantissa_max =
|
||||||
|
(static_cast<mantissa_type>(1) << mantissa_bits) - 1;
|
||||||
|
|
||||||
|
typedef int8_t exponent_type;
|
||||||
|
static const exponent_type exponent_max = 38;
|
||||||
|
|
||||||
|
template <typename TExponent>
|
||||||
|
static T make_float(T m, TExponent e) {
|
||||||
|
if (e > 0)
|
||||||
|
return m * (e & 1 ? 1e1f : 1) * (e & 2 ? 1e2f : 1) * (e & 4 ? 1e4f : 1) *
|
||||||
|
(e & 8 ? 1e8f : 1) * (e & 16 ? 1e16f : 1) * (e & 32 ? 1e32f : 1);
|
||||||
|
e = -e;
|
||||||
|
return m * (e & 1 ? 1e-1f : 1) * (e & 2 ? 1e-2f : 1) * (e & 4 ? 1e-4f : 1) *
|
||||||
|
(e & 8 ? 1e-8f : 1) * (e & 16 ? 1e-16f : 1) * (e & 32 ? 1e-32f : 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
static T nan() {
|
||||||
|
return Polyfills::nan<T>();
|
||||||
|
}
|
||||||
|
|
||||||
|
static T inf() {
|
||||||
|
return Polyfills::inf<T>();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
1
scripts/oss-fuzz/Vagrantfile
vendored
1
scripts/oss-fuzz/Vagrantfile
vendored
@ -26,6 +26,7 @@ Vagrant.configure(2) do |config|
|
|||||||
echo "export PROJECT_NAME='arduinojson'" >> $HOME/.profile
|
echo "export PROJECT_NAME='arduinojson'" >> $HOME/.profile
|
||||||
echo "export CC='clang'" >> $HOME/.profile
|
echo "export CC='clang'" >> $HOME/.profile
|
||||||
echo "export CXX='clang++'" >> $HOME/.profile
|
echo "export CXX='clang++'" >> $HOME/.profile
|
||||||
|
echo "export LD_LIBRARY_PATH=/usr/lib/x86_64-linux-gnu/" >> $HOME/.profile
|
||||||
|
|
||||||
echo "Run /host/ArduinoJson/fuzzing/fuzz.sh" | sudo tee /etc/motd
|
echo "Run /host/ArduinoJson/fuzzing/fuzz.sh" | sudo tee /etc/motd
|
||||||
SHELL
|
SHELL
|
||||||
|
81
test/Polyfills_IsFloat_Tests.cpp
Normal file
81
test/Polyfills_IsFloat_Tests.cpp
Normal file
@ -0,0 +1,81 @@
|
|||||||
|
// Copyright Benoit Blanchon 2014-2017
|
||||||
|
// MIT License
|
||||||
|
//
|
||||||
|
// Arduino JSON library
|
||||||
|
// https://github.com/bblanchon/ArduinoJson
|
||||||
|
// If you like this project, please add a star!
|
||||||
|
|
||||||
|
#include <gtest/gtest.h>
|
||||||
|
#include <ArduinoJson/Polyfills/isFloat.hpp>
|
||||||
|
|
||||||
|
using namespace ArduinoJson::Polyfills;
|
||||||
|
|
||||||
|
struct Polyfills_IsFloat_Tests : testing::Test {
|
||||||
|
void check(bool expected, const char* input) {
|
||||||
|
bool actual = isFloat(input);
|
||||||
|
EXPECT_EQ(expected, actual) << input;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
#define TEST_(X) TEST_F(Polyfills_IsFloat_Tests, X)
|
||||||
|
|
||||||
|
TEST_(NoExponent) {
|
||||||
|
check(true, "3.14");
|
||||||
|
check(true, "-3.14");
|
||||||
|
check(true, "+3.14");
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_(IntegralPartMissing) {
|
||||||
|
check(true, ".14");
|
||||||
|
check(true, "-.14");
|
||||||
|
check(true, "+.14");
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_(FractionalPartMissing) {
|
||||||
|
check(true, "3.");
|
||||||
|
check(true, "-3.e14");
|
||||||
|
check(true, "+3.e-14");
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_(NoDot) {
|
||||||
|
check(true, "3e14");
|
||||||
|
check(true, "3e-14");
|
||||||
|
check(true, "3e+14");
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_(Integer) {
|
||||||
|
check(false, "14");
|
||||||
|
check(false, "-14");
|
||||||
|
check(false, "+14");
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_(ExponentMissing) {
|
||||||
|
check(false, "3.14e");
|
||||||
|
check(false, "3.14e-");
|
||||||
|
check(false, "3.14e+");
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_(JustASign) {
|
||||||
|
check(false, "-");
|
||||||
|
check(false, "+");
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_(Empty) {
|
||||||
|
check(false, "");
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_(NaN) {
|
||||||
|
check(true, "NaN");
|
||||||
|
check(false, "n");
|
||||||
|
check(false, "N");
|
||||||
|
check(false, "nan");
|
||||||
|
check(false, "-NaN");
|
||||||
|
check(false, "+NaN");
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_(Infinity) {
|
||||||
|
check(true, "Infinity");
|
||||||
|
check(true, "+Infinity");
|
||||||
|
check(true, "-Infinity");
|
||||||
|
check(false, "infinity");
|
||||||
|
check(false, "Inf");
|
||||||
|
}
|
175
test/Polyfills_ParseFloat_Tests.cpp
Normal file
175
test/Polyfills_ParseFloat_Tests.cpp
Normal file
@ -0,0 +1,175 @@
|
|||||||
|
// Copyright Benoit Blanchon 2014-2017
|
||||||
|
// MIT License
|
||||||
|
//
|
||||||
|
// Arduino JSON library
|
||||||
|
// https://github.com/bblanchon/ArduinoJson
|
||||||
|
// If you like this project, please add a star!
|
||||||
|
|
||||||
|
#include <gtest/gtest.h>
|
||||||
|
#include <ArduinoJson/Polyfills/parseFloat.hpp>
|
||||||
|
|
||||||
|
using namespace ArduinoJson::Polyfills;
|
||||||
|
|
||||||
|
struct Polyfills_ParseFloat_Float_Tests : testing::Test {
|
||||||
|
void check(const char* input, float expected) {
|
||||||
|
float actual = parseFloat<float>(input);
|
||||||
|
EXPECT_FLOAT_EQ(expected, actual) << input;
|
||||||
|
}
|
||||||
|
|
||||||
|
void checkNaN(const char* input) {
|
||||||
|
float result = parseFloat<float>(input);
|
||||||
|
EXPECT_TRUE(result != result) << input;
|
||||||
|
}
|
||||||
|
|
||||||
|
void checkInf(const char* input, bool negative) {
|
||||||
|
float x = parseFloat<float>(input);
|
||||||
|
if (negative)
|
||||||
|
EXPECT_TRUE(x < 0) << input;
|
||||||
|
else
|
||||||
|
EXPECT_TRUE(x > 0) << input;
|
||||||
|
EXPECT_TRUE(x == x && x * 2 == x) << input;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
#define TEST_FLOAT(X) TEST_F(Polyfills_ParseFloat_Float_Tests, X)
|
||||||
|
|
||||||
|
struct Polyfills_ParseFloat_Double_Tests : testing::Test {
|
||||||
|
void check(const char* input, double expected) {
|
||||||
|
double actual = parseFloat<double>(input);
|
||||||
|
EXPECT_DOUBLE_EQ(expected, actual) << input;
|
||||||
|
}
|
||||||
|
|
||||||
|
void checkNaN(const char* input) {
|
||||||
|
double result = parseFloat<double>(input);
|
||||||
|
EXPECT_TRUE(result != result) << input;
|
||||||
|
}
|
||||||
|
|
||||||
|
void checkInf(const char* input, bool negative) {
|
||||||
|
double x = parseFloat<double>(input);
|
||||||
|
if (negative)
|
||||||
|
EXPECT_TRUE(x < 0) << input;
|
||||||
|
else
|
||||||
|
EXPECT_TRUE(x > 0) << input;
|
||||||
|
EXPECT_TRUE(x == x && x * 2 == x) << input;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
#define TEST_DOUBLE(X) TEST_F(Polyfills_ParseFloat_Double_Tests, X)
|
||||||
|
|
||||||
|
TEST_DOUBLE(Short_NoExponent) {
|
||||||
|
check("3.14", 3.14);
|
||||||
|
check("-3.14", -3.14);
|
||||||
|
check("+3.14", +3.14);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_FLOAT(Float_Short_NoExponent) {
|
||||||
|
check("3.14", 3.14f);
|
||||||
|
check("-3.14", -3.14f);
|
||||||
|
check("+3.14", +3.14f);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_DOUBLE(Short_NoDot) {
|
||||||
|
check("1E+308", 1E+308);
|
||||||
|
check("-1E+308", -1E+308);
|
||||||
|
check("+1E-308", +1E-308);
|
||||||
|
check("+1e+308", +1e+308);
|
||||||
|
check("-1e-308", -1e-308);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_FLOAT(Short_NoDot) {
|
||||||
|
check("1E+38", 1E+38f);
|
||||||
|
check("-1E+38", -1E+38f);
|
||||||
|
check("+1E-38", +1E-38f);
|
||||||
|
check("+1e+38", +1e+38f);
|
||||||
|
check("-1e-38", -1e-38f);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_FLOAT(Max) {
|
||||||
|
check("340.2823e+36", 3.402823e+38f);
|
||||||
|
check("34.02823e+37", 3.402823e+38f);
|
||||||
|
check("3.402823e+38", 3.402823e+38f);
|
||||||
|
check("0.3402823e+39", 3.402823e+38f);
|
||||||
|
check("00.3402823e+40", 3.402823e+38f);
|
||||||
|
check("000.3402823e+41", 3.402823e+38f);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_DOUBLE(Max) {
|
||||||
|
check(".017976931348623147e+310", 1.7976931348623147e+308);
|
||||||
|
check(".17976931348623147e+309", 1.7976931348623147e+308);
|
||||||
|
check("1.7976931348623147e+308", 1.7976931348623147e+308);
|
||||||
|
check("17.976931348623147e+307", 1.7976931348623147e+308);
|
||||||
|
check("179.76931348623147e+306", 1.7976931348623147e+308);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_DOUBLE(Min) {
|
||||||
|
check(".022250738585072014e-306", 2.2250738585072014e-308);
|
||||||
|
check(".22250738585072014e-307", 2.2250738585072014e-308);
|
||||||
|
check("2.2250738585072014e-308", 2.2250738585072014e-308);
|
||||||
|
check("22.250738585072014e-309", 2.2250738585072014e-308);
|
||||||
|
check("222.50738585072014e-310", 2.2250738585072014e-308);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_DOUBLE(VeryLong) {
|
||||||
|
check("0.00000000000000000000000000000001", 1e-32);
|
||||||
|
check("100000000000000000000000000000000.0", 1e+32);
|
||||||
|
check("100000000000000000000000000000000.00000000000000000000000000000",
|
||||||
|
1e+32);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_FLOAT(VeryLong) {
|
||||||
|
check("0.00000000000000000000000000000001", 1e-32f);
|
||||||
|
check("100000000000000000000000000000000.0", 1e+32f);
|
||||||
|
check("100000000000000000000000000000000.00000000000000000000000000000",
|
||||||
|
1e+32f);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_DOUBLE(MantissaTooLongToFit) {
|
||||||
|
check("0.179769313486231571111111111111", 0.17976931348623157);
|
||||||
|
check("17976931348623157.11111111111111", 17976931348623157.0);
|
||||||
|
check("1797693.134862315711111111111111", 1797693.1348623157);
|
||||||
|
|
||||||
|
check("-0.179769313486231571111111111111", -0.17976931348623157);
|
||||||
|
check("-17976931348623157.11111111111111", -17976931348623157.0);
|
||||||
|
check("-1797693.134862315711111111111111", -1797693.1348623157);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_FLOAT(MantissaTooLongToFit) {
|
||||||
|
check("0.340282346638528861111111111111", 0.34028234663852886f);
|
||||||
|
check("34028234663852886.11111111111111", 34028234663852886.0f);
|
||||||
|
check("34028234.66385288611111111111111", 34028234.663852886f);
|
||||||
|
|
||||||
|
check("-0.340282346638528861111111111111", -0.34028234663852886f);
|
||||||
|
check("-34028234663852886.11111111111111", -34028234663852886.0f);
|
||||||
|
check("-34028234.66385288611111111111111", -34028234.663852886f);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_DOUBLE(ExponentTooBig) {
|
||||||
|
checkInf("1e309", false);
|
||||||
|
checkInf("-1e309", true);
|
||||||
|
checkInf("1e65535", false);
|
||||||
|
check("1e-65535", 0.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_FLOAT(ExponentTooBig) {
|
||||||
|
checkInf("1e39", false);
|
||||||
|
checkInf("-1e39", true);
|
||||||
|
checkInf("1e255", false);
|
||||||
|
check("1e-255", 0.0f);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_DOUBLE(NaN) {
|
||||||
|
checkNaN("NaN");
|
||||||
|
checkNaN("nan");
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_FLOAT(NaN) {
|
||||||
|
checkNaN("NaN");
|
||||||
|
checkNaN("nan");
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_FLOAT(Infinity) {
|
||||||
|
checkInf("Infinity", false);
|
||||||
|
checkInf("+Infinity", false);
|
||||||
|
checkInf("-Infinity", true);
|
||||||
|
checkInf("inf", false);
|
||||||
|
checkInf("+inf", false);
|
||||||
|
checkInf("-inf", true);
|
||||||
|
}
|
Reference in New Issue
Block a user