mirror of
				https://github.com/eledio-devices/thirdparty-ArduinoJson.git
				synced 2025-10-31 16:14:11 +01: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