mirror of
				https://github.com/eledio-devices/thirdparty-ArduinoJson.git
				synced 2025-10-31 16:14:11 +01:00 
			
		
		
		
	Fix unsigned long printed as signed long (issue #170)
				
					
				
			This commit is contained in:
		| @@ -1,6 +1,11 @@ | ||||
| ArduinoJson: change log | ||||
| ======================= | ||||
|  | ||||
| HEAD | ||||
| ---- | ||||
|  | ||||
| * Fix `unsigned long` printed as `signed long` (issue #170) | ||||
|  | ||||
| v5.2.0 | ||||
| ------ | ||||
|  | ||||
|   | ||||
| @@ -56,22 +56,16 @@ class Print { | ||||
|     return print(tmp); | ||||
|   } | ||||
|  | ||||
|   size_t print(ArduinoJson::Internals::JsonInteger value) { | ||||
|     // see http://clc-wiki.net/wiki/K%26R2_solutions:Chapter_3:Exercise_4 | ||||
|   size_t print(ArduinoJson::Internals::JsonUInt value) { | ||||
|     char buffer[22]; | ||||
|  | ||||
|     size_t n = 0; | ||||
|     if (value < 0) { | ||||
|       value = -value; | ||||
|       n += write('-'); | ||||
|     } | ||||
|     uint8_t i = 0; | ||||
|     do { | ||||
|       ArduinoJson::Internals::JsonInteger digit = value % 10; | ||||
|       buffer[i++] = static_cast<char>(value % 10 + '0'); | ||||
|       value /= 10; | ||||
|       buffer[i++] = static_cast<char>(digit >= 0 ? '0' + digit : '0' - digit); | ||||
|     } while (value); | ||||
|  | ||||
|     size_t n = 0; | ||||
|     while (i > 0) { | ||||
|       n += write(buffer[--i]); | ||||
|     } | ||||
|   | ||||
| @@ -14,10 +14,13 @@ namespace Internals { | ||||
|  | ||||
| #if ARDUINOJSON_USE_LONG_LONG | ||||
| typedef long long JsonInteger; | ||||
| typedef unsigned long long JsonUInt; | ||||
| #elif ARDUINOJSON_USE_INT64 | ||||
| typedef __int64 JsonInteger; | ||||
| typedef unsigned _int64 JsonUInt; | ||||
| #else | ||||
| typedef long JsonInteger; | ||||
| typedef unsigned long JsonUInt; | ||||
| #endif | ||||
| } | ||||
| } | ||||
|   | ||||
| @@ -20,11 +20,11 @@ namespace Internals { | ||||
| // A union that defines the actual content of a JsonVariant. | ||||
| // The enum JsonVariantType determines which member is in use. | ||||
| union JsonVariantContent { | ||||
|   JsonFloat asFloat;      // used for double and float | ||||
|   JsonInteger asInteger;  // used for bool, char, short, int and longs | ||||
|   const char* asString;   // asString can be null | ||||
|   JsonArray* asArray;     // asArray cannot be null | ||||
|   JsonObject* asObject;   // asObject cannot be null | ||||
|   JsonFloat asFloat;     // used for double and float | ||||
|   JsonUInt asInteger;    // used for bool, char, short, int and longs | ||||
|   const char* asString;  // asString can be null | ||||
|   JsonArray* asArray;    // asArray cannot be null | ||||
|   JsonObject* asObject;  // asObject cannot be null | ||||
| }; | ||||
| } | ||||
| } | ||||
|   | ||||
| @@ -16,13 +16,15 @@ namespace Internals { | ||||
| // Enumerated type to know the current type of a JsonVariant. | ||||
| // The value determines which member of JsonVariantContent is used. | ||||
| enum JsonVariantType { | ||||
|   JSON_UNDEFINED,  // the JsonVariant has not been initialized | ||||
|   JSON_UNPARSED,   // the JsonVariant contains an unparsed string | ||||
|   JSON_STRING,     // the JsonVariant stores a const char* | ||||
|   JSON_BOOLEAN,    // the JsonVariant stores a bool | ||||
|   JSON_INTEGER,    // the JsonVariant stores an integer | ||||
|   JSON_ARRAY,      // the JsonVariant stores a pointer to a JsonArray | ||||
|   JSON_OBJECT,     // the JsonVariant stores a pointer to a JsonObject | ||||
|   JSON_UNDEFINED,         // JsonVariant has not been initialized | ||||
|   JSON_UNPARSED,          // JsonVariant contains an unparsed string | ||||
|   JSON_STRING,            // JsonVariant stores a const char* | ||||
|   JSON_BOOLEAN,           // JsonVariant stores a bool | ||||
|   JSON_POSITIVE_INTEGER,  // JsonVariant stores an unsigned long | ||||
|   JSON_NEGATIVE_INTEGER,  // JsonVariant stores an unsigned long that must be | ||||
|                           // negated | ||||
|   JSON_ARRAY,             // JsonVariant stores a pointer to a JsonArray | ||||
|   JSON_OBJECT,            // JsonVariant stores a pointer to a JsonObject | ||||
|  | ||||
|   // The following values are reserved for float values | ||||
|   // Multiple values are used for double, depending on the number of decimal | ||||
|   | ||||
| @@ -32,49 +32,47 @@ class JsonWriter { | ||||
|   // number of bytes written. | ||||
|   size_t bytesWritten() const { return _length; } | ||||
|  | ||||
|   void beginArray() { write('['); } | ||||
|   void endArray() { write(']'); } | ||||
|   void beginArray() { writeRaw('['); } | ||||
|   void endArray() { writeRaw(']'); } | ||||
|  | ||||
|   void beginObject() { write('{'); } | ||||
|   void endObject() { write('}'); } | ||||
|   void beginObject() { writeRaw('{'); } | ||||
|   void endObject() { writeRaw('}'); } | ||||
|  | ||||
|   void writeColon() { write(':'); } | ||||
|   void writeComma() { write(','); } | ||||
|   void writeColon() { writeRaw(':'); } | ||||
|   void writeComma() { writeRaw(','); } | ||||
|  | ||||
|   void writeBoolean(bool value) { write(value ? "true" : "false"); } | ||||
|   void writeBoolean(bool value) { writeRaw(value ? "true" : "false"); } | ||||
|  | ||||
|   void writeString(const char *value) { | ||||
|     if (!value) { | ||||
|       write("null"); | ||||
|       writeRaw("null"); | ||||
|     } else { | ||||
|       write('\"'); | ||||
|       writeRaw('\"'); | ||||
|       while (*value) writeChar(*value++); | ||||
|       write('\"'); | ||||
|       writeRaw('\"'); | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   void writeChar(char c) { | ||||
|     char specialChar = Encoding::escapeChar(c); | ||||
|     if (specialChar) { | ||||
|       write('\\'); | ||||
|       write(specialChar); | ||||
|       writeRaw('\\'); | ||||
|       writeRaw(specialChar); | ||||
|     } else { | ||||
|       write(c); | ||||
|       writeRaw(c); | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   void writeInteger(JsonInteger value) { _length += _sink.print(value); } | ||||
|   void writeInteger(JsonUInt value) { _length += _sink.print(value); } | ||||
|  | ||||
|   void writeFloat(JsonFloat value, uint8_t decimals) { | ||||
|     _length += _sink.print(value, decimals); | ||||
|   } | ||||
|  | ||||
|   void writeRaw(const char *s) { return write(s); } | ||||
|   void writeRaw(const char *s) { _length += _sink.print(s); } | ||||
|   void writeRaw(char c) { _length += _sink.write(c); } | ||||
|  | ||||
|  protected: | ||||
|   void write(char c) { _length += _sink.write(c); } | ||||
|   FORCE_INLINE void write(const char *s) { _length += _sink.print(s); } | ||||
|  | ||||
|   Print &_sink; | ||||
|   size_t _length; | ||||
|  | ||||
|   | ||||
| @@ -72,8 +72,13 @@ class JsonVariant : public JsonVariantBase<JsonVariant> { | ||||
|       typename TypeTraits::EnableIf<TypeTraits::IsIntegral<T>::value>::type * = | ||||
|           0) { | ||||
|     using namespace Internals; | ||||
|     _type = JSON_INTEGER; | ||||
|     _content.asInteger = static_cast<JsonInteger>(value); | ||||
|     if (value >= 0) { | ||||
|       _type = JSON_POSITIVE_INTEGER; | ||||
|       _content.asInteger = static_cast<JsonInteger>(value); | ||||
|     } else { | ||||
|       _type = JSON_NEGATIVE_INTEGER; | ||||
|       _content.asInteger = static_cast<JsonInteger>(-value); | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   // Create a JsonVariant containing a string. | ||||
|   | ||||
| @@ -47,19 +47,23 @@ inline T JsonVariant::invalid() { | ||||
| } | ||||
|  | ||||
| inline Internals::JsonInteger JsonVariant::asInteger() const { | ||||
|   if (_type == Internals::JSON_INTEGER || _type == Internals::JSON_BOOLEAN) | ||||
|     return _content.asInteger; | ||||
|  | ||||
|   if (_type >= Internals::JSON_FLOAT_0_DECIMALS) | ||||
|     return static_cast<Internals::JsonInteger>(_content.asFloat); | ||||
|  | ||||
|   if ((_type == Internals::JSON_STRING || _type == Internals::JSON_UNPARSED) && | ||||
|       _content.asString) { | ||||
|     if (!strcmp("true", _content.asString)) return 1; | ||||
|     return Internals::parse<Internals::JsonInteger>(_content.asString); | ||||
|   using namespace Internals; | ||||
|   switch (_type) { | ||||
|     case JSON_UNDEFINED: | ||||
|       return 0; | ||||
|     case JSON_POSITIVE_INTEGER: | ||||
|     case JSON_BOOLEAN: | ||||
|       return _content.asInteger; | ||||
|     case JSON_NEGATIVE_INTEGER: | ||||
|       return -_content.asInteger; | ||||
|     case JSON_STRING: | ||||
|     case JSON_UNPARSED: | ||||
|       if (!_content.asString) return 0; | ||||
|       if (!strcmp("true", _content.asString)) return 1; | ||||
|       return parse<Internals::JsonInteger>(_content.asString); | ||||
|     default: | ||||
|       return static_cast<Internals::JsonInteger>(_content.asFloat); | ||||
|   } | ||||
|  | ||||
|   return 0L; | ||||
| } | ||||
|  | ||||
| #if ARDUINOJSON_ENABLE_STD_STREAM | ||||
|   | ||||
| @@ -26,15 +26,20 @@ const char *JsonVariant::asString() const { | ||||
| } | ||||
|  | ||||
| JsonFloat JsonVariant::asFloat() const { | ||||
|   if (_type >= JSON_FLOAT_0_DECIMALS) return _content.asFloat; | ||||
|  | ||||
|   if (_type == JSON_INTEGER || _type == JSON_BOOLEAN) | ||||
|     return static_cast<JsonFloat>(_content.asInteger); | ||||
|  | ||||
|   if ((_type == JSON_STRING || _type == JSON_UNPARSED) && _content.asString) | ||||
|     return parse<JsonFloat>(_content.asString); | ||||
|  | ||||
|   return 0.0; | ||||
|   switch (_type) { | ||||
|     case JSON_UNDEFINED: | ||||
|       return 0; | ||||
|     case JSON_POSITIVE_INTEGER: | ||||
|     case JSON_BOOLEAN: | ||||
|       return static_cast<JsonFloat>(_content.asInteger); | ||||
|     case JSON_NEGATIVE_INTEGER: | ||||
|       return -static_cast<JsonFloat>(_content.asInteger); | ||||
|     case JSON_STRING: | ||||
|     case JSON_UNPARSED: | ||||
|       return _content.asString ? parse<JsonFloat>(_content.asString) : 0; | ||||
|     default: | ||||
|       return _content.asFloat; | ||||
|   } | ||||
| } | ||||
|  | ||||
| String JsonVariant::toString() const { | ||||
| @@ -57,7 +62,8 @@ bool JsonVariant::isBoolean() const { | ||||
| } | ||||
|  | ||||
| bool JsonVariant::isInteger() const { | ||||
|   if (_type == JSON_INTEGER) return true; | ||||
|   if (_type == JSON_POSITIVE_INTEGER || _type == JSON_NEGATIVE_INTEGER) | ||||
|     return true; | ||||
|  | ||||
|   if (_type != JSON_UNPARSED || _content.asString == NULL) return false; | ||||
|  | ||||
| @@ -81,27 +87,39 @@ bool JsonVariant::isFloat() const { | ||||
| } | ||||
|  | ||||
| void JsonVariant::writeTo(JsonWriter &writer) const { | ||||
|   if (_type == JSON_ARRAY) | ||||
|     _content.asArray->writeTo(writer); | ||||
|   switch (_type) { | ||||
|     case JSON_UNDEFINED: | ||||
|       return; | ||||
|  | ||||
|   else if (_type == JSON_OBJECT) | ||||
|     _content.asObject->writeTo(writer); | ||||
|     case JSON_ARRAY: | ||||
|       _content.asArray->writeTo(writer); | ||||
|       return; | ||||
|  | ||||
|   else if (_type == JSON_STRING) | ||||
|     writer.writeString(_content.asString); | ||||
|     case JSON_OBJECT: | ||||
|       _content.asObject->writeTo(writer); | ||||
|       return; | ||||
|  | ||||
|   else if (_type == JSON_UNPARSED) | ||||
|     writer.writeRaw(_content.asString); | ||||
|     case JSON_STRING: | ||||
|       writer.writeString(_content.asString); | ||||
|       return; | ||||
|  | ||||
|   else if (_type == JSON_INTEGER) | ||||
|     writer.writeInteger(_content.asInteger); | ||||
|     case JSON_UNPARSED: | ||||
|       writer.writeRaw(_content.asString); | ||||
|       return; | ||||
|  | ||||
|   else if (_type == JSON_BOOLEAN) | ||||
|     writer.writeBoolean(_content.asInteger != 0); | ||||
|     case JSON_NEGATIVE_INTEGER: | ||||
|       writer.writeRaw('-'); | ||||
|     case JSON_POSITIVE_INTEGER: | ||||
|       writer.writeInteger(_content.asInteger); | ||||
|       return; | ||||
|  | ||||
|   else if (_type >= JSON_FLOAT_0_DECIMALS) { | ||||
|     uint8_t decimals = static_cast<uint8_t>(_type - JSON_FLOAT_0_DECIMALS); | ||||
|     writer.writeFloat(_content.asFloat, decimals); | ||||
|     case JSON_BOOLEAN: | ||||
|       writer.writeBoolean(_content.asInteger != 0); | ||||
|       return; | ||||
|  | ||||
|     default: | ||||
|       uint8_t decimals = static_cast<uint8_t>(_type - JSON_FLOAT_0_DECIMALS); | ||||
|       writer.writeFloat(_content.asFloat, decimals); | ||||
|   } | ||||
| } | ||||
| } | ||||
|   | ||||
| @@ -125,6 +125,14 @@ TEST_F(JsonParser_Array_Tests, TwoDoubles) { | ||||
|   secondElementMustBe(1e2); | ||||
| } | ||||
|  | ||||
| TEST_F(JsonParser_Array_Tests, UnsignedLong) { | ||||
|   whenInputIs("[4294967295]"); | ||||
|  | ||||
|   parseMustSucceed(); | ||||
|   sizeMustBe(1); | ||||
|   firstElementMustBe(4294967295UL); | ||||
| } | ||||
|  | ||||
| TEST_F(JsonParser_Array_Tests, TwoBooleans) { | ||||
|   whenInputIs("[true,false]"); | ||||
|  | ||||
|   | ||||
| @@ -57,6 +57,11 @@ TEST_F(JsonVariant_PrintTo_Tests, Long) { | ||||
|   outputMustBe("42"); | ||||
| } | ||||
|  | ||||
| TEST_F(JsonVariant_PrintTo_Tests, UnsignedLong) { | ||||
|   variant = 4294967295UL; | ||||
|   outputMustBe("4294967295"); | ||||
| } | ||||
|  | ||||
| TEST_F(JsonVariant_PrintTo_Tests, Char) { | ||||
|   variant = '*'; | ||||
|   outputMustBe("42"); | ||||
| @@ -82,4 +87,9 @@ TEST_F(JsonVariant_PrintTo_Tests, PositiveInt64) { | ||||
|   variant = 9223372036854775807; | ||||
|   outputMustBe("9223372036854775807"); | ||||
| } | ||||
|  | ||||
| TEST_F(JsonVariant_PrintTo_Tests, UInt64) { | ||||
|   variant = 18446744073709551615; | ||||
|   outputMustBe("18446744073709551615"); | ||||
| } | ||||
| #endif | ||||
|   | ||||
		Reference in New Issue
	
	Block a user