mirror of
				https://github.com/eledio-devices/thirdparty-ArduinoJson.git
				synced 2025-10-31 00:32:37 +01:00 
			
		
		
		
	Renamed function RawJson() to serialized()
				
					
				
			This commit is contained in:
		
							
								
								
									
										18
									
								
								CHANGELOG.md
									
									
									
									
									
								
							
							
						
						
									
										18
									
								
								CHANGELOG.md
									
									
									
									
									
								
							| @@ -6,11 +6,29 @@ HEAD | ||||
|  | ||||
| * Disabled lazy number deserialization (issue #772) | ||||
| * Improved float serialization when `-fsingle-precision-constant` is used | ||||
| * Renamed function `RawJson()` to `serialized()` | ||||
| * `serializeMsgPack()` now supports values marked with `serialized()` | ||||
|  | ||||
| > ### BREAKING CHANGES | ||||
| > | ||||
| > #### Non quoted strings | ||||
| > | ||||
| > Non quoted strings are now forbidden in values, but they are still allowed in keys. | ||||
| > For example, `{key:"value"}` is accepted, but `{key:value}` is not. | ||||
| > | ||||
| > #### Preformatted values | ||||
| > | ||||
| > Old code: | ||||
| > | ||||
| > ```c++ | ||||
| > object["values"] = RawJson("[1,2,3,4]"); | ||||
| > ``` | ||||
| >  | ||||
| > New code: | ||||
| >  | ||||
| > ```c++ | ||||
| > object["values"] = serialized("[1,2,3,4]"); | ||||
| > ``` | ||||
|  | ||||
| v6.1.0-beta | ||||
| ----------- | ||||
|   | ||||
| @@ -37,8 +37,9 @@ void setup() { | ||||
|   // JsonBuffer. | ||||
|   obj["sensor"] = F("gps"); | ||||
|  | ||||
|   // It works with RawJson too: | ||||
|   obj["sensor"] = RawJson(F("\"gps\"")); | ||||
|   // It works with serialized() too: | ||||
|   obj["sensor"] = serialized(F("\"gps\"")); | ||||
|   obj["sensor"] = serialized(F("\xA3gps"), 3); | ||||
|  | ||||
|   // You can compare the content of a JsonVariant to a Flash String | ||||
|   if (obj["sensor"] == F("gps")) { | ||||
|   | ||||
| @@ -41,8 +41,8 @@ void setup() { | ||||
|   // WARNING: the content of the String will be duplicated in the JsonBuffer. | ||||
|   obj["sensor"] = sensor; | ||||
|  | ||||
|   // It works with RawJson too: | ||||
|   obj["sensor"] = RawJson(sensor); | ||||
|   // It works with serialized() too: | ||||
|   obj["sensor"] = serialized(sensor); | ||||
|  | ||||
|   // You can also concatenate strings | ||||
|   // WARNING: the content of the String will be duplicated in the JsonBuffer. | ||||
|   | ||||
| @@ -18,9 +18,13 @@ struct JsonObjectData; | ||||
| union JsonVariantContent { | ||||
|   JsonFloat asFloat;         // used for double and float | ||||
|   JsonUInt asInteger;        // used for bool, char, short, int and longs | ||||
|   const char* asString;      // asString can be null | ||||
|   JsonArrayData* asArray;    // asArray cannot be null | ||||
|   JsonObjectData* asObject;  // asObject cannot be null | ||||
|   const char* asString;      // asString can be null | ||||
|   struct { | ||||
|     const char* data; | ||||
|     size_t size; | ||||
|   } asRaw; | ||||
| }; | ||||
| }  // namespace Internals | ||||
| }  // namespace ArduinoJson | ||||
|   | ||||
| @@ -7,7 +7,7 @@ | ||||
| #include "../JsonVariant.hpp" | ||||
| #include "../Memory/JsonBuffer.hpp" | ||||
| #include "../Polyfills/type_traits.hpp" | ||||
| #include "../Strings/StringTraits.hpp" | ||||
| #include "../Strings/StringTypes.hpp" | ||||
|  | ||||
| namespace ArduinoJson { | ||||
| namespace Internals { | ||||
| @@ -21,30 +21,31 @@ struct ValueSaver { | ||||
|   } | ||||
| }; | ||||
|  | ||||
| template <typename Source> | ||||
| // We duplicate all strings except const char* | ||||
| template <typename TString> | ||||
| struct ValueSaver< | ||||
|     Source, typename enable_if<StringTraits<Source>::should_duplicate>::type> { | ||||
|     TString, typename enable_if<IsString<TString>::value && | ||||
|                                 !is_same<const char*, TString>::value>::type> { | ||||
|   template <typename Destination> | ||||
|   static bool save(JsonBuffer* buffer, Destination& dest, Source source) { | ||||
|     if (!StringTraits<Source>::is_null(source)) { | ||||
|       typename StringTraits<Source>::duplicate_t dup = | ||||
|           StringTraits<Source>::duplicate(source, buffer); | ||||
|       if (!dup) return false; | ||||
|       dest = dup; | ||||
|     } else { | ||||
|       dest = reinterpret_cast<const char*>(0); | ||||
|     } | ||||
|   static bool save(JsonBuffer* buffer, Destination& dest, TString source) { | ||||
|     const char* dup = makeString(source).save(buffer); | ||||
|     if (!dup) return false; | ||||
|     dest = dup; | ||||
|     return true; | ||||
|   } | ||||
| }; | ||||
|  | ||||
| // const char*, const signed char*, const unsigned char* | ||||
| template <typename Char> | ||||
| // We duplicate all SerializedValue<T> except SerializedValue<const char*> | ||||
| template <typename TString> | ||||
| struct ValueSaver< | ||||
|     Char*, typename enable_if<!StringTraits<Char*>::should_duplicate>::type> { | ||||
|     const SerializedValue<TString>&, | ||||
|     typename enable_if<!is_same<const char*, TString>::value>::type> { | ||||
|   template <typename Destination> | ||||
|   static bool save(JsonBuffer*, Destination& dest, Char* source) { | ||||
|     dest = reinterpret_cast<const char*>(source); | ||||
|   static bool save(JsonBuffer* buffer, Destination& dest, | ||||
|                    const SerializedValue<TString>& source) { | ||||
|     const char* dup = makeString(source.data(), source.size()).save(buffer); | ||||
|     if (!dup) return false; | ||||
|     dest = SerializedValue<const char*>(dup, source.size()); | ||||
|     return true; | ||||
|   } | ||||
| }; | ||||
|   | ||||
| @@ -19,19 +19,22 @@ class IndentedPrint { | ||||
|     isNewLine = true; | ||||
|   } | ||||
|  | ||||
|   size_t print(char c) { | ||||
|   size_t write(uint8_t c) { | ||||
|     size_t n = 0; | ||||
|     if (isNewLine) n += writeTabs(); | ||||
|     n += sink->print(c); | ||||
|     n += sink->write(c); | ||||
|     isNewLine = c == '\n'; | ||||
|     return n; | ||||
|   } | ||||
|  | ||||
|   size_t print(const char *s) { | ||||
|   size_t write(const uint8_t *s, size_t n) { | ||||
|     // TODO: optimize | ||||
|     size_t n = 0; | ||||
|     while (*s) n += print(*s++); | ||||
|     return n; | ||||
|     size_t bytesWritten = 0; | ||||
|     while (n > 0) { | ||||
|       bytesWritten += write(*s++); | ||||
|       n--; | ||||
|     } | ||||
|     return bytesWritten; | ||||
|   } | ||||
|  | ||||
|   // Adds one level of indentation | ||||
| @@ -57,7 +60,7 @@ class IndentedPrint { | ||||
|  | ||||
|   size_t writeTabs() { | ||||
|     size_t n = 0; | ||||
|     for (int i = 0; i < level * tabSize; i++) n += sink->print(' '); | ||||
|     for (int i = 0; i < level * tabSize; i++) n += sink->write(' '); | ||||
|     return n; | ||||
|   } | ||||
|  | ||||
|   | ||||
| @@ -11,10 +11,10 @@ | ||||
| namespace ArduinoJson { | ||||
| namespace Internals { | ||||
|  | ||||
| template <typename TPrint> | ||||
| template <typename TWriter> | ||||
| class JsonSerializer { | ||||
|  public: | ||||
|   JsonSerializer(TPrint &destination) : _writer(destination) {} | ||||
|   JsonSerializer(TWriter &writer) : _writer(writer) {} | ||||
|  | ||||
|   void acceptFloat(JsonFloat value) { | ||||
|     _writer.writeFloat(value); | ||||
| @@ -58,8 +58,9 @@ class JsonSerializer { | ||||
|     _writer.writeString(value); | ||||
|   } | ||||
|  | ||||
|   void acceptRawJson(const char *value) { | ||||
|     _writer.writeRaw(value); | ||||
|   void acceptRawJson(const char *data, size_t n) { | ||||
|     // TODO | ||||
|     for (size_t i = 0; i < n; i++) _writer.writeRaw(data[i]); | ||||
|   } | ||||
|  | ||||
|   void acceptNegativeInteger(JsonUInt value) { | ||||
| @@ -84,7 +85,7 @@ class JsonSerializer { | ||||
|   } | ||||
|  | ||||
|  private: | ||||
|   JsonWriter<TPrint> _writer; | ||||
|   JsonWriter<TWriter> _writer; | ||||
| }; | ||||
|  | ||||
| }  // namespace Internals | ||||
|   | ||||
| @@ -5,6 +5,7 @@ | ||||
| #pragma once | ||||
|  | ||||
| #include <stdint.h> | ||||
| #include <string.h>  // for strlen | ||||
| #include "../Data/JsonInteger.hpp" | ||||
| #include "../Numbers/FloatParts.hpp" | ||||
| #include "../Polyfills/attributes.hpp" | ||||
| @@ -13,12 +14,12 @@ | ||||
| namespace ArduinoJson { | ||||
| namespace Internals { | ||||
|  | ||||
| template <typename Print> | ||||
| template <typename TWriter> | ||||
| class JsonWriter { | ||||
|  public: | ||||
|   explicit JsonWriter(Print &sink) : _sink(sink), _length(0) {} | ||||
|   explicit JsonWriter(TWriter &writer) : _writer(writer), _length(0) {} | ||||
|  | ||||
|   // Returns the number of bytes sent to the Print implementation. | ||||
|   // Returns the number of bytes sent to the TWriter implementation. | ||||
|   size_t bytesWritten() const { | ||||
|     return _length; | ||||
|   } | ||||
| @@ -45,7 +46,10 @@ class JsonWriter { | ||||
|   } | ||||
|  | ||||
|   void writeBoolean(bool value) { | ||||
|     writeRaw(value ? "true" : "false"); | ||||
|     if (value) | ||||
|       writeRaw("true"); | ||||
|     else | ||||
|       writeRaw("false"); | ||||
|   } | ||||
|  | ||||
|   void writeString(const char *value) { | ||||
| @@ -98,45 +102,53 @@ class JsonWriter { | ||||
|   template <typename UInt> | ||||
|   void writeInteger(UInt value) { | ||||
|     char buffer[22]; | ||||
|     char *end = buffer + sizeof(buffer) - 1; | ||||
|     char *ptr = end; | ||||
|     char *end = buffer + sizeof(buffer); | ||||
|     char *begin = end; | ||||
|  | ||||
|     *ptr = 0; | ||||
|     // write the string in reverse order | ||||
|     do { | ||||
|       *--ptr = char(value % 10 + '0'); | ||||
|       *--begin = char(value % 10 + '0'); | ||||
|       value = UInt(value / 10); | ||||
|     } while (value); | ||||
|  | ||||
|     writeRaw(ptr); | ||||
|     // and dump it in the right order | ||||
|     writeRaw(begin, end); | ||||
|   } | ||||
|  | ||||
|   void writeDecimals(uint32_t value, int8_t width) { | ||||
|     // buffer should be big enough for all digits, the dot and the null | ||||
|     // terminator | ||||
|     // buffer should be big enough for all digits and the dot | ||||
|     char buffer[16]; | ||||
|     char *ptr = buffer + sizeof(buffer) - 1; | ||||
|     char *end = buffer + sizeof(buffer); | ||||
|     char *begin = end; | ||||
|  | ||||
|     // write the string in reverse order | ||||
|     *ptr = 0; | ||||
|     while (width--) { | ||||
|       *--ptr = char(value % 10 + '0'); | ||||
|       *--begin = char(value % 10 + '0'); | ||||
|       value /= 10; | ||||
|     } | ||||
|     *--ptr = '.'; | ||||
|     *--begin = '.'; | ||||
|  | ||||
|     // and dump it in the right order | ||||
|     writeRaw(ptr); | ||||
|     writeRaw(begin, end); | ||||
|   } | ||||
|  | ||||
|   void writeRaw(const char *s) { | ||||
|     _length += _sink.print(s); | ||||
|     _length += _writer.write(reinterpret_cast<const uint8_t *>(s), strlen(s)); | ||||
|   } | ||||
|   void writeRaw(const char *begin, const char *end) { | ||||
|     _length += _writer.write(reinterpret_cast<const uint8_t *>(begin), | ||||
|                              static_cast<size_t>(end - begin)); | ||||
|   } | ||||
|   template <size_t N> | ||||
|   void writeRaw(const char (&s)[N]) { | ||||
|     _length += _writer.write(reinterpret_cast<const uint8_t *>(s), N - 1); | ||||
|   } | ||||
|   void writeRaw(char c) { | ||||
|     _length += _sink.print(c); | ||||
|     _length += _writer.write(static_cast<uint8_t>(c)); | ||||
|   } | ||||
|  | ||||
|  protected: | ||||
|   Print &_sink; | ||||
|   TWriter &_writer; | ||||
|   size_t _length; | ||||
|  | ||||
|  private: | ||||
|   | ||||
| @@ -10,25 +10,28 @@ namespace ArduinoJson { | ||||
| namespace Internals { | ||||
|  | ||||
| // Converts a compact JSON string into an indented one. | ||||
| template <typename Print> | ||||
| template <typename TWriter> | ||||
| class Prettyfier { | ||||
|  public: | ||||
|   explicit Prettyfier(IndentedPrint<Print>& p) : _sink(p) { | ||||
|   explicit Prettyfier(IndentedPrint<TWriter>& p) : _sink(p) { | ||||
|     _previousChar = 0; | ||||
|     _inString = false; | ||||
|   } | ||||
|  | ||||
|   size_t print(char c) { | ||||
|     size_t n = _inString ? handleStringChar(c) : handleMarkupChar(c); | ||||
|     _previousChar = c; | ||||
|   size_t write(uint8_t c) { | ||||
|     size_t n = _inString ? handleStringChar(c) : handleMarkupChar(char(c)); | ||||
|     _previousChar = char(c); | ||||
|     return n; | ||||
|   } | ||||
|  | ||||
|   size_t print(const char* s) { | ||||
|   size_t write(const uint8_t* s, size_t n) { | ||||
|     // TODO: optimize | ||||
|     size_t n = 0; | ||||
|     while (*s) n += print(*s++); | ||||
|     return n; | ||||
|     size_t bytesWritten = 0; | ||||
|     while (n > 0) { | ||||
|       bytesWritten += write(*s++); | ||||
|       n--; | ||||
|     } | ||||
|     return bytesWritten; | ||||
|   } | ||||
|  | ||||
|  private: | ||||
| @@ -38,12 +41,12 @@ class Prettyfier { | ||||
|     return _previousChar == '{' || _previousChar == '['; | ||||
|   } | ||||
|  | ||||
|   size_t handleStringChar(char c) { | ||||
|   size_t handleStringChar(uint8_t c) { | ||||
|     bool isQuote = c == '"' && _previousChar != '\\'; | ||||
|  | ||||
|     if (isQuote) _inString = false; | ||||
|  | ||||
|     return _sink.print(c); | ||||
|     return _sink.write(c); | ||||
|   } | ||||
|  | ||||
|   size_t handleMarkupChar(char c) { | ||||
| @@ -73,26 +76,26 @@ class Prettyfier { | ||||
|   size_t writeBlockClose(char c) { | ||||
|     size_t n = 0; | ||||
|     n += unindentIfNeeded(); | ||||
|     n += _sink.print(c); | ||||
|     n += write(c); | ||||
|     return n; | ||||
|   } | ||||
|  | ||||
|   size_t writeBlockOpen(char c) { | ||||
|     size_t n = 0; | ||||
|     n += indentIfNeeded(); | ||||
|     n += _sink.print(c); | ||||
|     n += write(c); | ||||
|     return n; | ||||
|   } | ||||
|  | ||||
|   size_t writeColon() { | ||||
|     size_t n = 0; | ||||
|     n += _sink.print(": "); | ||||
|     n += write(": "); | ||||
|     return n; | ||||
|   } | ||||
|  | ||||
|   size_t writeComma() { | ||||
|     size_t n = 0; | ||||
|     n += _sink.print(",\r\n"); | ||||
|     n += write(",\r\n"); | ||||
|     return n; | ||||
|   } | ||||
|  | ||||
| @@ -100,14 +103,14 @@ class Prettyfier { | ||||
|     _inString = true; | ||||
|     size_t n = 0; | ||||
|     n += indentIfNeeded(); | ||||
|     n += _sink.print('"'); | ||||
|     n += write('"'); | ||||
|     return n; | ||||
|   } | ||||
|  | ||||
|   size_t writeNormalChar(char c) { | ||||
|     size_t n = 0; | ||||
|     n += indentIfNeeded(); | ||||
|     n += _sink.print(c); | ||||
|     n += write(c); | ||||
|     return n; | ||||
|   } | ||||
|  | ||||
| @@ -115,19 +118,28 @@ class Prettyfier { | ||||
|     if (!inEmptyBlock()) return 0; | ||||
|  | ||||
|     _sink.indent(); | ||||
|     return _sink.print("\r\n"); | ||||
|     return write("\r\n"); | ||||
|   } | ||||
|  | ||||
|   size_t unindentIfNeeded() { | ||||
|     if (inEmptyBlock()) return 0; | ||||
|  | ||||
|     _sink.unindent(); | ||||
|     return _sink.print("\r\n"); | ||||
|     return write("\r\n"); | ||||
|   } | ||||
|  | ||||
|   size_t write(char c) { | ||||
|     return _sink.write(static_cast<uint8_t>(c)); | ||||
|   } | ||||
|  | ||||
|   template <size_t N> | ||||
|   size_t write(const char (&s)[N]) { | ||||
|     return _sink.write(reinterpret_cast<const uint8_t*>(s), N - 1); | ||||
|   } | ||||
|  | ||||
|   char _previousChar; | ||||
|   IndentedPrint<Print>& _sink; | ||||
|   IndentedPrint<TWriter>& _sink; | ||||
|   bool _inString; | ||||
| }; | ||||
| } | ||||
| } | ||||
| }  // namespace Internals | ||||
| }  // namespace ArduinoJson | ||||
|   | ||||
| @@ -29,7 +29,7 @@ class JsonArray { | ||||
|   // Adds the specified value at the end of the array. | ||||
|   // | ||||
|   // bool add(TValue); | ||||
|   // TValue = bool, long, int, short, float, double, RawJson, JsonVariant, | ||||
|   // TValue = bool, long, int, short, float, double, serialized, JsonVariant, | ||||
|   //          std::string, String, JsonArrayData, JsonObject | ||||
|   template <typename T> | ||||
|   bool add(const T& value) { | ||||
| @@ -154,7 +154,7 @@ class JsonArray { | ||||
|   // Sets the value at specified index. | ||||
|   // | ||||
|   // bool add(size_t index, const TValue&); | ||||
|   // TValue = bool, long, int, short, float, double, RawJson, JsonVariant, | ||||
|   // TValue = bool, long, int, short, float, double, serialized, JsonVariant, | ||||
|   //          std::string, String, JsonArrayData, JsonObject | ||||
|   template <typename T> | ||||
|   bool set(size_t index, const T& value) { | ||||
|   | ||||
| @@ -9,7 +9,6 @@ | ||||
| #include "JsonVariant.hpp" | ||||
| #include "Memory/JsonBufferAllocated.hpp" | ||||
| #include "Polyfills/type_traits.hpp" | ||||
| #include "Strings/StringTraits.hpp" | ||||
|  | ||||
| // Returns the size (in bytes) of an array with n elements. | ||||
| // Can be very handy to determine the size of a StaticJsonBuffer. | ||||
|   | ||||
| @@ -27,7 +27,7 @@ class JsonArraySubscript : public JsonVariantBase<JsonArraySubscript> { | ||||
|   // Replaces the value | ||||
|   // | ||||
|   // operator=(const TValue&) | ||||
|   // TValue = bool, long, int, short, float, double, RawJson, JsonVariant, | ||||
|   // TValue = bool, long, int, short, float, double, serialized, JsonVariant, | ||||
|   //          std::string, String, JsonArray, JsonObject | ||||
|   template <typename T> | ||||
|   FORCE_INLINE JsonArraySubscript& operator=(const T& src) { | ||||
| @@ -60,7 +60,7 @@ class JsonArraySubscript : public JsonVariantBase<JsonArraySubscript> { | ||||
|   // Replaces the value | ||||
|   // | ||||
|   // bool set(const TValue&) | ||||
|   // TValue = bool, long, int, short, float, double, RawJson, JsonVariant, | ||||
|   // TValue = bool, long, int, short, float, double, serialized, JsonVariant, | ||||
|   //          std::string, String, JsonArray, JsonObject | ||||
|   template <typename TValue> | ||||
|   FORCE_INLINE bool set(const TValue& value) { | ||||
|   | ||||
| @@ -188,7 +188,7 @@ class JsonObject { | ||||
|   // | ||||
|   // bool set(TKey, TValue); | ||||
|   // TKey = const std::string&, const String& | ||||
|   // TValue = bool, long, int, short, float, double, RawJson, JsonVariant, | ||||
|   // TValue = bool, long, int, short, float, double, serialized, JsonVariant, | ||||
|   //          std::string, String, JsonArray, JsonObject | ||||
|   template <typename TValue, typename TString> | ||||
|   bool set(const TString& key, const TValue& value) { | ||||
| @@ -205,7 +205,7 @@ class JsonObject { | ||||
|   // | ||||
|   // bool set(TKey, const TValue&); | ||||
|   // TKey = char*, const char*, const FlashStringHelper* | ||||
|   // TValue = bool, long, int, short, float, double, RawJson, JsonVariant, | ||||
|   // TValue = bool, long, int, short, float, double, serialized, JsonVariant, | ||||
|   //          std::string, String, JsonArray, JsonObject | ||||
|   template <typename TValue, typename TString> | ||||
|   bool set(TString* key, const TValue& value) { | ||||
| @@ -254,7 +254,7 @@ class JsonObject { | ||||
|   iterator findKey(TStringRef key) { | ||||
|     iterator it; | ||||
|     for (it = begin(); it != end(); ++it) { | ||||
|       if (Internals::StringTraits<TStringRef>::equals(key, it->key)) break; | ||||
|       if (Internals::makeString(key).equals(it->key)) break; | ||||
|     } | ||||
|     return it; | ||||
|   } | ||||
| @@ -288,7 +288,7 @@ class JsonObject { | ||||
|     if (!_data) return false; | ||||
|  | ||||
|     // ignore null key | ||||
|     if (Internals::StringTraits<TStringRef>::is_null(key)) return false; | ||||
|     if (Internals::makeString(key).is_null()) return false; | ||||
|  | ||||
|     // search a matching key | ||||
|     iterator it = findKey<TStringRef>(key); | ||||
|   | ||||
| @@ -9,7 +9,6 @@ | ||||
| #include "JsonPair.hpp" | ||||
| #include "Memory/JsonBufferAllocated.hpp" | ||||
| #include "Polyfills/type_traits.hpp" | ||||
| #include "Strings/StringTraits.hpp" | ||||
|  | ||||
| // Returns the size (in bytes) of an object with n elements. | ||||
| // Can be very handy to determine the size of a StaticJsonBuffer. | ||||
|   | ||||
| @@ -67,7 +67,8 @@ class JsonObjectSubscript | ||||
|   // Sets the specified value. | ||||
|   // | ||||
|   // bool set(const TValue&); | ||||
|   // TValue = bool, char, long, int, short, float, double, RawJson, JsonVariant, | ||||
|   // TValue = bool, char, long, int, short, float, double, serialized, | ||||
|   // JsonVariant, | ||||
|   //          std::string, String, JsonArray, JsonObject | ||||
|   template <typename TValue> | ||||
|   FORCE_INLINE typename enable_if<!is_array<TValue>::value, bool>::type set( | ||||
| @@ -94,7 +95,7 @@ class JsonObjectSubscript | ||||
|  | ||||
| template <typename TImpl> | ||||
| template <typename TString> | ||||
| inline typename enable_if<StringTraits<TString>::has_equals, | ||||
| inline typename enable_if<IsString<TString>::value, | ||||
|                           const JsonObjectSubscript<const TString &> >::type | ||||
|     JsonVariantSubscripts<TImpl>::operator[](const TString &key) const { | ||||
|   return impl()->template as<JsonObject>()[key]; | ||||
| @@ -102,7 +103,7 @@ inline typename enable_if<StringTraits<TString>::has_equals, | ||||
|  | ||||
| template <typename TImpl> | ||||
| template <typename TString> | ||||
| inline typename enable_if<StringTraits<TString>::has_equals, | ||||
| inline typename enable_if<IsString<TString>::value, | ||||
|                           JsonObjectSubscript<const TString &> >::type | ||||
|     JsonVariantSubscripts<TImpl>::operator[](const TString &key) { | ||||
|   return impl()->template as<JsonObject>()[key]; | ||||
| @@ -110,7 +111,7 @@ inline typename enable_if<StringTraits<TString>::has_equals, | ||||
|  | ||||
| template <typename TImpl> | ||||
| template <typename TString> | ||||
| inline typename enable_if<StringTraits<const TString *>::has_equals, | ||||
| inline typename enable_if<IsString<const TString *>::value, | ||||
|                           JsonObjectSubscript<const TString *> >::type | ||||
|     JsonVariantSubscripts<TImpl>::operator[](const TString *key) { | ||||
|   return impl()->template as<JsonObject>()[key]; | ||||
| @@ -118,7 +119,7 @@ inline typename enable_if<StringTraits<const TString *>::has_equals, | ||||
|  | ||||
| template <typename TImpl> | ||||
| template <typename TString> | ||||
| inline typename enable_if<StringTraits<TString *>::has_equals, | ||||
| inline typename enable_if<IsString<TString *>::value, | ||||
|                           const JsonObjectSubscript<const TString *> >::type | ||||
|     JsonVariantSubscripts<TImpl>::operator[](const TString *key) const { | ||||
|   return impl()->template as<JsonObject>()[key]; | ||||
|   | ||||
| @@ -12,7 +12,8 @@ | ||||
| #include "Data/JsonVariantType.hpp" | ||||
| #include "JsonVariantBase.hpp" | ||||
| #include "Polyfills/type_traits.hpp" | ||||
| #include "RawJson.hpp" | ||||
| #include "Serialization/DynamicStringWriter.hpp" | ||||
| #include "SerializedValue.hpp" | ||||
|  | ||||
| namespace ArduinoJson { | ||||
|  | ||||
| @@ -99,9 +100,10 @@ class JsonVariant : public Internals::JsonVariantBase<JsonVariant> { | ||||
|   } | ||||
|  | ||||
|   // Create a JsonVariant containing an unparsed string | ||||
|   JsonVariant(Internals::RawJsonString<const char *> value) { | ||||
|   JsonVariant(Internals::SerializedValue<const char *> value) { | ||||
|     _type = Internals::JSON_UNPARSED; | ||||
|     _content.asString = value; | ||||
|     _content.asRaw.data = value.data(); | ||||
|     _content.asRaw.size = value.size(); | ||||
|   } | ||||
|  | ||||
|   JsonVariant(JsonArray array); | ||||
| @@ -153,7 +155,7 @@ class JsonVariant : public Internals::JsonVariantBase<JsonVariant> { | ||||
|   // std::string as<std::string>() const; | ||||
|   // String as<String>() const; | ||||
|   template <typename T> | ||||
|   typename Internals::enable_if<Internals::StringTraits<T>::has_append, T>::type | ||||
|   typename Internals::enable_if<Internals::IsWriteableString<T>::value, T>::type | ||||
|   as() const { | ||||
|     const char *cstr = variantAsString(); | ||||
|     if (cstr) return T(cstr); | ||||
| @@ -276,7 +278,7 @@ class JsonVariant : public Internals::JsonVariantBase<JsonVariant> { | ||||
|         return visitor.acceptString(_content.asString); | ||||
|  | ||||
|       case JSON_UNPARSED: | ||||
|         return visitor.acceptRawJson(_content.asString); | ||||
|         return visitor.acceptRawJson(_content.asRaw.data, _content.asRaw.size); | ||||
|  | ||||
|       case JSON_NEGATIVE_INTEGER: | ||||
|         return visitor.acceptNegativeInteger(_content.asInteger); | ||||
| @@ -310,9 +312,7 @@ class JsonVariant : public Internals::JsonVariantBase<JsonVariant> { | ||||
|     return _type == Internals::JSON_OBJECT; | ||||
|   } | ||||
|   bool variantIsString() const { | ||||
|     return _type == Internals::JSON_STRING || | ||||
|            (_type == Internals::JSON_UNPARSED && _content.asString && | ||||
|             !strcmp("null", _content.asString)); | ||||
|     return _type == Internals::JSON_STRING; | ||||
|   } | ||||
|  | ||||
|   // The current type of the variant | ||||
|   | ||||
| @@ -6,7 +6,7 @@ | ||||
|  | ||||
| #include "Data/IsVariant.hpp" | ||||
| #include "Polyfills/type_traits.hpp" | ||||
| #include "Strings/StringTraits.hpp" | ||||
| #include "Strings/StringTypes.hpp" | ||||
|  | ||||
| namespace ArduinoJson { | ||||
| class JsonArray; | ||||
| @@ -104,16 +104,14 @@ class JsonVariantComparisons { | ||||
|   } | ||||
|  | ||||
|   template <typename TString> | ||||
|   typename enable_if<StringTraits<TString>::has_equals, bool>::type equals( | ||||
|   typename enable_if<IsString<TString>::value, bool>::type equals( | ||||
|       const TString &comparand) const { | ||||
|     const char *value = as<const char *>(); | ||||
|     return StringTraits<TString>::equals(comparand, value); | ||||
|     return makeString(comparand).equals(as<const char *>()); | ||||
|   } | ||||
|  | ||||
|   template <typename TComparand> | ||||
|   typename enable_if<!IsVariant<TComparand>::value && | ||||
|                          !StringTraits<TComparand>::has_equals, | ||||
|                      bool>::type | ||||
|   typename enable_if< | ||||
|       !IsVariant<TComparand>::value && !IsString<TComparand>::value, bool>::type | ||||
|   equals(const TComparand &comparand) const { | ||||
|     return as<TComparand>() == comparand; | ||||
|   } | ||||
| @@ -132,8 +130,7 @@ class JsonVariantComparisons { | ||||
|     if (is<JsonObject>() && right.template is<JsonObject>()) | ||||
|       return as<JsonObject>() == right.template as<JsonObject>(); | ||||
|     if (is<char *>() && right.template is<char *>()) | ||||
|       return StringTraits<const char *>::equals(as<char *>(), | ||||
|                                                 right.template as<char *>()); | ||||
|       return makeString(as<char *>()).equals(right.template as<char *>()); | ||||
|  | ||||
|     return false; | ||||
|   } | ||||
|   | ||||
| @@ -68,6 +68,7 @@ inline T JsonVariant::variantAsInteger() const { | ||||
|   using namespace Internals; | ||||
|   switch (_type) { | ||||
|     case JSON_UNDEFINED: | ||||
|     case JSON_UNPARSED: | ||||
|       return 0; | ||||
|     case JSON_POSITIVE_INTEGER: | ||||
|     case JSON_BOOLEAN: | ||||
| @@ -75,7 +76,6 @@ inline T JsonVariant::variantAsInteger() const { | ||||
|     case JSON_NEGATIVE_INTEGER: | ||||
|       return T(~_content.asInteger + 1); | ||||
|     case JSON_STRING: | ||||
|     case JSON_UNPARSED: | ||||
|       return parseInteger<T>(_content.asString); | ||||
|     default: | ||||
|       return T(_content.asFloat); | ||||
| @@ -84,11 +84,7 @@ inline T JsonVariant::variantAsInteger() const { | ||||
|  | ||||
| inline const char *JsonVariant::variantAsString() const { | ||||
|   using namespace Internals; | ||||
|   if (_type == JSON_UNPARSED && _content.asString && | ||||
|       !strcmp("null", _content.asString)) | ||||
|     return NULL; | ||||
|   if (_type == JSON_STRING || _type == JSON_UNPARSED) return _content.asString; | ||||
|   return NULL; | ||||
|   return _type == JSON_STRING ? _content.asString : NULL; | ||||
| } | ||||
|  | ||||
| template <typename T> | ||||
| @@ -96,6 +92,7 @@ inline T JsonVariant::variantAsFloat() const { | ||||
|   using namespace Internals; | ||||
|   switch (_type) { | ||||
|     case JSON_UNDEFINED: | ||||
|     case JSON_UNPARSED: | ||||
|       return 0; | ||||
|     case JSON_POSITIVE_INTEGER: | ||||
|     case JSON_BOOLEAN: | ||||
| @@ -103,7 +100,6 @@ inline T JsonVariant::variantAsFloat() const { | ||||
|     case JSON_NEGATIVE_INTEGER: | ||||
|       return -static_cast<T>(_content.asInteger); | ||||
|     case JSON_STRING: | ||||
|     case JSON_UNPARSED: | ||||
|       return parseFloat<T>(_content.asString); | ||||
|     default: | ||||
|       return static_cast<T>(_content.asFloat); | ||||
| @@ -112,27 +108,20 @@ inline T JsonVariant::variantAsFloat() const { | ||||
|  | ||||
| inline bool JsonVariant::variantIsBoolean() const { | ||||
|   using namespace Internals; | ||||
|   if (_type == JSON_BOOLEAN) return true; | ||||
|  | ||||
|   if (_type != JSON_UNPARSED || _content.asString == NULL) return false; | ||||
|  | ||||
|   return !strcmp(_content.asString, "true") || | ||||
|          !strcmp(_content.asString, "false"); | ||||
|   return _type == JSON_BOOLEAN; | ||||
| } | ||||
|  | ||||
| inline bool JsonVariant::variantIsInteger() const { | ||||
|   using namespace Internals; | ||||
|  | ||||
|   return _type == JSON_POSITIVE_INTEGER || _type == JSON_NEGATIVE_INTEGER || | ||||
|          (_type == JSON_UNPARSED && isInteger(_content.asString)); | ||||
|   return _type == JSON_POSITIVE_INTEGER || _type == JSON_NEGATIVE_INTEGER; | ||||
| } | ||||
|  | ||||
| inline bool JsonVariant::variantIsFloat() const { | ||||
|   using namespace Internals; | ||||
|  | ||||
|   return _type == JSON_FLOAT || _type == JSON_POSITIVE_INTEGER || | ||||
|          _type == JSON_NEGATIVE_INTEGER || | ||||
|          (_type == JSON_UNPARSED && isFloat(_content.asString)); | ||||
|          _type == JSON_NEGATIVE_INTEGER; | ||||
| } | ||||
|  | ||||
| }  // namespace ArduinoJson | ||||
|   | ||||
| @@ -7,7 +7,7 @@ | ||||
| #include "Data/JsonVariantAs.hpp" | ||||
| #include "Polyfills/attributes.hpp" | ||||
| #include "Polyfills/type_traits.hpp" | ||||
| #include "Strings/StringTraits.hpp" | ||||
| #include "Strings/StringTypes.hpp" | ||||
|  | ||||
| namespace ArduinoJson { | ||||
| class JsonArray; | ||||
| @@ -43,21 +43,21 @@ class JsonVariantSubscripts { | ||||
|   // TKey = const std::string&, const String& | ||||
|   template <typename TString> | ||||
|   FORCE_INLINE | ||||
|       typename enable_if<StringTraits<TString>::has_equals, | ||||
|       typename enable_if<IsString<TString>::value, | ||||
|                          const JsonObjectSubscript<const TString &> >::type | ||||
|       operator[](const TString &key) const; | ||||
|   // | ||||
|   // const JsonObjectSubscript operator[](TKey) const; | ||||
|   // TKey = const std::string&, const String& | ||||
|   template <typename TString> | ||||
|   FORCE_INLINE typename enable_if<StringTraits<TString>::has_equals, | ||||
|   FORCE_INLINE typename enable_if<IsString<TString>::value, | ||||
|                                   JsonObjectSubscript<const TString &> >::type | ||||
|   operator[](const TString &key); | ||||
|   // | ||||
|   // JsonObjectSubscript operator[](TKey); | ||||
|   // TKey = const char*, const char[N], const FlashStringHelper* | ||||
|   template <typename TString> | ||||
|   FORCE_INLINE typename enable_if<StringTraits<const TString *>::has_equals, | ||||
|   FORCE_INLINE typename enable_if<IsString<const TString *>::value, | ||||
|                                   JsonObjectSubscript<const TString *> >::type | ||||
|   operator[](const TString *key); | ||||
|   // | ||||
| @@ -65,7 +65,7 @@ class JsonVariantSubscripts { | ||||
|   // TKey = const char*, const char[N], const FlashStringHelper* | ||||
|   template <typename TString> | ||||
|   FORCE_INLINE | ||||
|       typename enable_if<StringTraits<TString *>::has_equals, | ||||
|       typename enable_if<IsString<TString *>::value, | ||||
|                          const JsonObjectSubscript<const TString *> >::type | ||||
|       operator[](const TString *key) const; | ||||
|  | ||||
|   | ||||
| @@ -13,10 +13,10 @@ | ||||
| namespace ArduinoJson { | ||||
| namespace Internals { | ||||
|  | ||||
| template <typename TPrint> | ||||
| template <typename TWriter> | ||||
| class MsgPackSerializer { | ||||
|  public: | ||||
|   MsgPackSerializer(TPrint& output) : _output(&output), _bytesWritten(0) {} | ||||
|   MsgPackSerializer(TWriter& writer) : _writer(&writer), _bytesWritten(0) {} | ||||
|  | ||||
|   template <typename T> | ||||
|   typename enable_if<sizeof(T) == 4>::type acceptFloat(T value32) { | ||||
| @@ -91,7 +91,9 @@ class MsgPackSerializer { | ||||
|     writeBytes(reinterpret_cast<const uint8_t*>(value), n); | ||||
|   } | ||||
|  | ||||
|   void acceptRawJson(const char* /*value*/) {} | ||||
|   void acceptRawJson(const char* data, size_t size) { | ||||
|     writeBytes(reinterpret_cast<const uint8_t*>(data), size); | ||||
|   } | ||||
|  | ||||
|   void acceptNegativeInteger(JsonUInt value) { | ||||
|     JsonUInt negated = JsonUInt(~value + 1); | ||||
| @@ -150,12 +152,11 @@ class MsgPackSerializer { | ||||
|  | ||||
|  private: | ||||
|   void writeByte(uint8_t c) { | ||||
|     _output->print(char(c)); | ||||
|     _bytesWritten++; | ||||
|     _bytesWritten += _writer->write(c); | ||||
|   } | ||||
|  | ||||
|   void writeBytes(const uint8_t* c, size_t n) { | ||||
|     for (; n > 0; --n, ++c) writeByte(*c); | ||||
|   void writeBytes(const uint8_t* p, size_t n) { | ||||
|     _bytesWritten += _writer->write(p, n); | ||||
|   } | ||||
|  | ||||
|   template <typename T> | ||||
| @@ -164,7 +165,7 @@ class MsgPackSerializer { | ||||
|     writeBytes(reinterpret_cast<uint8_t*>(&value), sizeof(value)); | ||||
|   } | ||||
|  | ||||
|   TPrint* _output; | ||||
|   TWriter* _writer; | ||||
|   size_t _bytesWritten; | ||||
| }; | ||||
| }  // namespace Internals | ||||
|   | ||||
| @@ -1,46 +0,0 @@ | ||||
| // ArduinoJson - arduinojson.org | ||||
| // Copyright Benoit Blanchon 2014-2018 | ||||
| // MIT License | ||||
|  | ||||
| #pragma once | ||||
|  | ||||
| namespace ArduinoJson { | ||||
|  | ||||
| namespace Internals { | ||||
| // A special type of data that can be used to insert pregenerated JSON portions. | ||||
| template <typename T> | ||||
| class RawJsonString { | ||||
|  public: | ||||
|   explicit RawJsonString(T str) : _str(str) {} | ||||
|   operator T() const { | ||||
|     return _str; | ||||
|   } | ||||
|  | ||||
|  private: | ||||
|   T _str; | ||||
| }; | ||||
|  | ||||
| template <typename String> | ||||
| struct StringTraits<RawJsonString<String>, void> { | ||||
|   static bool is_null(RawJsonString<String> source) { | ||||
|     return StringTraits<String>::is_null(static_cast<String>(source)); | ||||
|   } | ||||
|  | ||||
|   typedef RawJsonString<const char*> duplicate_t; | ||||
|  | ||||
|   template <typename Buffer> | ||||
|   static duplicate_t duplicate(RawJsonString<String> source, Buffer* buffer) { | ||||
|     return duplicate_t(StringTraits<String>::duplicate(source, buffer)); | ||||
|   } | ||||
|  | ||||
|   static const bool has_append = false; | ||||
|   static const bool has_equals = false; | ||||
|   static const bool should_duplicate = StringTraits<String>::should_duplicate; | ||||
| }; | ||||
| } | ||||
|  | ||||
| template <typename T> | ||||
| inline Internals::RawJsonString<T> RawJson(T str) { | ||||
|   return Internals::RawJsonString<T>(str); | ||||
| } | ||||
| } | ||||
| @@ -7,14 +7,14 @@ | ||||
| namespace ArduinoJson { | ||||
| namespace Internals { | ||||
| 
 | ||||
| class DummyPrint { | ||||
| class DummyWriter { | ||||
|  public: | ||||
|   size_t print(char) { | ||||
|   size_t write(uint8_t) { | ||||
|     return 1; | ||||
|   } | ||||
| 
 | ||||
|   size_t print(const char* s) { | ||||
|     return strlen(s); | ||||
|   size_t write(const uint8_t*, size_t n) { | ||||
|     return n; | ||||
|   } | ||||
| }; | ||||
| }  // namespace Internals
 | ||||
| @@ -1,35 +0,0 @@ | ||||
| // ArduinoJson - arduinojson.org | ||||
| // Copyright Benoit Blanchon 2014-2018 | ||||
| // MIT License | ||||
|  | ||||
| #pragma once | ||||
|  | ||||
| #include "../Strings/StringTraits.hpp" | ||||
|  | ||||
| namespace ArduinoJson { | ||||
| namespace Internals { | ||||
|  | ||||
| // A Print implementation that allows to write in a String | ||||
| template <typename TString> | ||||
| class DynamicStringBuilder { | ||||
|  public: | ||||
|   DynamicStringBuilder(TString &str) : _str(str) {} | ||||
|  | ||||
|   size_t print(char c) { | ||||
|     StringTraits<TString>::append(_str, c); | ||||
|     return 1; | ||||
|   } | ||||
|  | ||||
|   size_t print(const char *s) { | ||||
|     size_t initialLen = _str.length(); | ||||
|     StringTraits<TString>::append(_str, s); | ||||
|     return _str.length() - initialLen; | ||||
|   } | ||||
|  | ||||
|  private: | ||||
|   DynamicStringBuilder &operator=(const DynamicStringBuilder &); | ||||
|  | ||||
|   TString &_str; | ||||
| }; | ||||
| }  // namespace Internals | ||||
| }  // namespace ArduinoJson | ||||
							
								
								
									
										81
									
								
								src/ArduinoJson/Serialization/DynamicStringWriter.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										81
									
								
								src/ArduinoJson/Serialization/DynamicStringWriter.hpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,81 @@ | ||||
| // ArduinoJson - arduinojson.org | ||||
| // Copyright Benoit Blanchon 2014-2018 | ||||
| // MIT License | ||||
|  | ||||
| #pragma once | ||||
|  | ||||
| #include "../Polyfills/type_traits.hpp" | ||||
|  | ||||
| #if ARDUINOJSON_ENABLE_ARDUINO_STRING | ||||
| #include <WString.h> | ||||
| #endif | ||||
|  | ||||
| #if ARDUINOJSON_ENABLE_STD_STRING | ||||
| #include <string> | ||||
| #endif | ||||
|  | ||||
| namespace ArduinoJson { | ||||
| namespace Internals { | ||||
|  | ||||
| template <typename> | ||||
| struct IsWriteableString : false_type {}; | ||||
|  | ||||
| // A Print implementation that allows to write in a String | ||||
| template <typename TString> | ||||
| class DynamicStringWriter {}; | ||||
|  | ||||
| #if ARDUINOJSON_ENABLE_ARDUINO_STRING | ||||
| template <> | ||||
| struct IsWriteableString<String> : true_type {}; | ||||
|  | ||||
| template <> | ||||
| class DynamicStringWriter<String> { | ||||
|  public: | ||||
|   DynamicStringWriter(String &str) : _str(&str) {} | ||||
|  | ||||
|   size_t write(uint8_t c) { | ||||
|     _str->operator+=(static_cast<char>(c)); | ||||
|     return 1; | ||||
|   } | ||||
|  | ||||
|   size_t write(const uint8_t *s, size_t n) { | ||||
|     // CAUTION: Arduino String doesn't have append() | ||||
|     // and old version doesn't have size() either | ||||
|     _str->reserve(_str->length() + n); | ||||
|     while (n > 0) { | ||||
|       _str->operator+=(static_cast<char>(*s++)); | ||||
|       n--; | ||||
|     } | ||||
|     return n; | ||||
|   } | ||||
|  | ||||
|  private: | ||||
|   String *_str; | ||||
| }; | ||||
| #endif | ||||
|  | ||||
| #if ARDUINOJSON_ENABLE_STD_STRING | ||||
| template <> | ||||
| struct IsWriteableString<std::string> : true_type {}; | ||||
|  | ||||
| template <> | ||||
| class DynamicStringWriter<std::string> { | ||||
|  public: | ||||
|   DynamicStringWriter(std::string &str) : _str(&str) {} | ||||
|  | ||||
|   size_t write(uint8_t c) { | ||||
|     _str->operator+=(static_cast<char>(c)); | ||||
|     return 1; | ||||
|   } | ||||
|  | ||||
|   size_t write(const uint8_t *s, size_t n) { | ||||
|     _str->append(reinterpret_cast<const char *>(s), n); | ||||
|     return n; | ||||
|   } | ||||
|  | ||||
|  private: | ||||
|   std::string *_str; | ||||
| }; | ||||
| #endif | ||||
| }  // namespace Internals | ||||
| }  // namespace ArduinoJson | ||||
| @@ -8,22 +8,25 @@ namespace ArduinoJson { | ||||
| namespace Internals { | ||||
| 
 | ||||
| // A Print implementation that allows to write in a char[]
 | ||||
| class StaticStringBuilder { | ||||
| class StaticStringWriter { | ||||
|  public: | ||||
|   StaticStringBuilder(char *buf, size_t size) : end(buf + size - 1), p(buf) { | ||||
|   StaticStringWriter(char *buf, size_t size) : end(buf + size - 1), p(buf) { | ||||
|     *p = '\0'; | ||||
|   } | ||||
| 
 | ||||
|   size_t print(char c) { | ||||
|   size_t write(uint8_t c) { | ||||
|     if (p >= end) return 0; | ||||
|     *p++ = c; | ||||
|     *p++ = static_cast<char>(c); | ||||
|     *p = '\0'; | ||||
|     return 1; | ||||
|   } | ||||
| 
 | ||||
|   size_t print(const char *s) { | ||||
|   size_t write(const uint8_t *s, size_t n) { | ||||
|     char *begin = p; | ||||
|     while (p < end && *s) *p++ = *s++; | ||||
|     while (p < end && n > 0) { | ||||
|       *p++ = static_cast<char>(*s++); | ||||
|       n--; | ||||
|     } | ||||
|     *p = '\0'; | ||||
|     return size_t(p - begin); | ||||
|   } | ||||
| @@ -13,27 +13,28 @@ | ||||
| namespace ArduinoJson { | ||||
| namespace Internals { | ||||
| 
 | ||||
| class StreamPrintAdapter { | ||||
| class StreamWriter { | ||||
|  public: | ||||
|   explicit StreamPrintAdapter(std::ostream& os) : _os(os) {} | ||||
|   explicit StreamWriter(std::ostream& os) : _os(os) {} | ||||
| 
 | ||||
|   size_t print(char c) { | ||||
|   size_t write(uint8_t c) { | ||||
|     _os << c; | ||||
|     return 1; | ||||
|   } | ||||
| 
 | ||||
|   size_t print(const char* s) { | ||||
|     _os << s; | ||||
|     return strlen(s); | ||||
|   size_t write(const uint8_t* s, size_t n) { | ||||
|     _os.write(reinterpret_cast<const char*>(s), | ||||
|               static_cast<std::streamsize>(n)); | ||||
|     return n; | ||||
|   } | ||||
| 
 | ||||
|  private: | ||||
|   // cannot be assigned
 | ||||
|   StreamPrintAdapter& operator=(const StreamPrintAdapter&); | ||||
|   StreamWriter& operator=(const StreamWriter&); | ||||
| 
 | ||||
|   std::ostream& _os; | ||||
| }; | ||||
| } | ||||
| } | ||||
| }  // namespace Internals
 | ||||
| }  // namespace ArduinoJson
 | ||||
| 
 | ||||
| #endif  // ARDUINOJSON_ENABLE_STD_STREAM
 | ||||
| @@ -4,15 +4,15 @@ | ||||
|  | ||||
| #pragma once | ||||
|  | ||||
| #include "./DummyPrint.hpp" | ||||
| #include "./DummyWriter.hpp" | ||||
|  | ||||
| namespace ArduinoJson { | ||||
| namespace Internals { | ||||
|  | ||||
| template <template <typename> class TSerializer, typename TSource> | ||||
| size_t measure(const TSource &source) { | ||||
|   DummyPrint dp; | ||||
|   TSerializer<DummyPrint> serializer(dp); | ||||
|   DummyWriter dp; | ||||
|   TSerializer<DummyWriter> serializer(dp); | ||||
|   source.visit(serializer); | ||||
|   return serializer.bytesWritten(); | ||||
| } | ||||
|   | ||||
| @@ -4,11 +4,11 @@ | ||||
|  | ||||
| #pragma once | ||||
|  | ||||
| #include "./DynamicStringBuilder.hpp" | ||||
| #include "./StaticStringBuilder.hpp" | ||||
| #include "./DynamicStringWriter.hpp" | ||||
| #include "./StaticStringWriter.hpp" | ||||
|  | ||||
| #if ARDUINOJSON_ENABLE_STD_STREAM | ||||
| #include "./StreamPrintAdapter.hpp" | ||||
| #include "./StreamWriter.hpp" | ||||
| #endif | ||||
|  | ||||
| namespace ArduinoJson { | ||||
| @@ -16,7 +16,7 @@ namespace Internals { | ||||
|  | ||||
| template <template <typename> class TSerializer, typename TSource, | ||||
|           typename TPrint> | ||||
| typename enable_if<!StringTraits<TPrint>::has_append, size_t>::type serialize( | ||||
| typename enable_if<!IsWriteableString<TPrint>::value, size_t>::type serialize( | ||||
|     const TSource &source, TPrint &destination) { | ||||
|   TSerializer<TPrint> serializer(destination); | ||||
|   source.visit(serializer); | ||||
| @@ -26,29 +26,29 @@ typename enable_if<!StringTraits<TPrint>::has_append, size_t>::type serialize( | ||||
| #if ARDUINOJSON_ENABLE_STD_STREAM | ||||
| template <template <typename> class TSerializer, typename TSource> | ||||
| size_t serialize(const TSource &source, std::ostream &os) { | ||||
|   StreamPrintAdapter adapter(os); | ||||
|   return serialize<TSerializer>(source, adapter); | ||||
|   StreamWriter writer(os); | ||||
|   return serialize<TSerializer>(source, writer); | ||||
| } | ||||
| #endif | ||||
|  | ||||
| template <template <typename> class TSerializer, typename TSource> | ||||
| size_t serialize(const TSource &source, char *buffer, size_t bufferSize) { | ||||
|   StaticStringBuilder sb(buffer, bufferSize); | ||||
|   return serialize<TSerializer>(source, sb); | ||||
|   StaticStringWriter writer(buffer, bufferSize); | ||||
|   return serialize<TSerializer>(source, writer); | ||||
| } | ||||
|  | ||||
| template <template <typename> class TSerializer, typename TSource, size_t N> | ||||
| size_t serialize(const TSource &source, char (&buffer)[N]) { | ||||
|   StaticStringBuilder sb(buffer, N); | ||||
|   return serialize<TSerializer>(source, sb); | ||||
|   StaticStringWriter writer(buffer, N); | ||||
|   return serialize<TSerializer>(source, writer); | ||||
| } | ||||
|  | ||||
| template <template <typename> class TSerializer, typename TSource, | ||||
|           typename TString> | ||||
| typename enable_if<StringTraits<TString>::has_append, size_t>::type serialize( | ||||
| typename enable_if<IsWriteableString<TString>::value, size_t>::type serialize( | ||||
|     const TSource &source, TString &str) { | ||||
|   DynamicStringBuilder<TString> sb(str); | ||||
|   return serialize<TSerializer>(source, sb); | ||||
|   DynamicStringWriter<TString> writer(str); | ||||
|   return serialize<TSerializer>(source, writer); | ||||
| } | ||||
|  | ||||
| }  // namespace Internals | ||||
|   | ||||
							
								
								
									
										70
									
								
								src/ArduinoJson/SerializedValue.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										70
									
								
								src/ArduinoJson/SerializedValue.hpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,70 @@ | ||||
| // ArduinoJson - arduinojson.org | ||||
| // Copyright Benoit Blanchon 2014-2018 | ||||
| // MIT License | ||||
|  | ||||
| #pragma once | ||||
|  | ||||
| #include "Strings/StringTypes.hpp" | ||||
|  | ||||
| namespace ArduinoJson { | ||||
|  | ||||
| namespace Internals { | ||||
| // A special type of data that can be used to insert pregenerated JSON portions. | ||||
| template <typename T> | ||||
| class SerializedValue { | ||||
|  public: | ||||
|   explicit SerializedValue(T str) : _str(str) {} | ||||
|   operator T() const { | ||||
|     return _str; | ||||
|   } | ||||
|  | ||||
|   const char* data() const { | ||||
|     return _str.c_str(); | ||||
|   } | ||||
|  | ||||
|   size_t size() const { | ||||
|     // CAUTION: the old Arduino String doesn't have size() | ||||
|     return _str.length(); | ||||
|   } | ||||
|  | ||||
|  private: | ||||
|   T _str; | ||||
| }; | ||||
|  | ||||
| template <typename TChar> | ||||
| class SerializedValue<TChar*> { | ||||
|  public: | ||||
|   explicit SerializedValue(TChar* p, size_t n) : _data(p), _size(n) {} | ||||
|   operator TChar*() const { | ||||
|     return _data; | ||||
|   } | ||||
|  | ||||
|   TChar* data() const { | ||||
|     return _data; | ||||
|   } | ||||
|  | ||||
|   size_t size() const { | ||||
|     return _size; | ||||
|   } | ||||
|  | ||||
|  private: | ||||
|   TChar* _data; | ||||
|   size_t _size; | ||||
| }; | ||||
| }  // namespace Internals | ||||
|  | ||||
| template <typename T> | ||||
| inline Internals::SerializedValue<T> serialized(T str) { | ||||
|   return Internals::SerializedValue<T>(str); | ||||
| } | ||||
|  | ||||
| template <typename TChar> | ||||
| inline Internals::SerializedValue<TChar*> serialized(TChar* p) { | ||||
|   return Internals::SerializedValue<TChar*>(p, Internals::makeString(p).size()); | ||||
| } | ||||
|  | ||||
| template <typename TChar> | ||||
| inline Internals::SerializedValue<TChar*> serialized(TChar* p, size_t n) { | ||||
|   return Internals::SerializedValue<TChar*>(p, n); | ||||
| } | ||||
| }  // namespace ArduinoJson | ||||
							
								
								
									
										60
									
								
								src/ArduinoJson/Strings/ArduinoString.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										60
									
								
								src/ArduinoJson/Strings/ArduinoString.hpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,60 @@ | ||||
| // ArduinoJson - arduinojson.org | ||||
| // Copyright Benoit Blanchon 2014-2018 | ||||
| // MIT License | ||||
|  | ||||
| #pragma once | ||||
|  | ||||
| #include <WString.h> | ||||
|  | ||||
| namespace ArduinoJson { | ||||
| namespace Internals { | ||||
|  | ||||
| class ArduinoString { | ||||
|  public: | ||||
|   ArduinoString(const ::String& str) : _str(&str) {} | ||||
|  | ||||
|   template <typename Buffer> | ||||
|   const char* save(Buffer* buffer) const { | ||||
|     if (!_str->c_str()) return NULL;  // <- Arduino string can return NULL | ||||
|     size_t n = _str->length() + 1; | ||||
|     void* dup = buffer->alloc(n); | ||||
|     if (dup != NULL) memcpy(dup, _str->c_str(), n); | ||||
|     return static_cast<const char*>(dup); | ||||
|   } | ||||
|  | ||||
|   bool is_null() const { | ||||
|     // Arduino's String::c_str() can return NULL | ||||
|     return _str->c_str(); | ||||
|   } | ||||
|  | ||||
|   bool equals(const char* expected) const { | ||||
|     // Arduino's String::c_str() can return NULL | ||||
|     const char* actual = _str->c_str(); | ||||
|     if (!actual || !expected) return actual == expected; | ||||
|     return 0 == strcmp(actual, expected); | ||||
|   } | ||||
|  | ||||
|   const char* data() const { | ||||
|     return _str->c_str(); | ||||
|   } | ||||
|  | ||||
|   size_t size() const { | ||||
|     return _str->length(); | ||||
|   } | ||||
|  | ||||
|  private: | ||||
|   const ::String* _str; | ||||
| }; | ||||
|  | ||||
| template <> | ||||
| struct IsString< ::String> : true_type {}; | ||||
|  | ||||
| template <> | ||||
| struct IsString< ::StringSumHelper> : true_type {}; | ||||
|  | ||||
| inline ArduinoString makeString(const ::String& str) { | ||||
|   return ArduinoString(str); | ||||
| } | ||||
|  | ||||
| }  // namespace Internals | ||||
| }  // namespace ArduinoJson | ||||
| @@ -1,44 +0,0 @@ | ||||
| // ArduinoJson - arduinojson.org | ||||
| // Copyright Benoit Blanchon 2014-2018 | ||||
| // MIT License | ||||
|  | ||||
| #pragma once | ||||
|  | ||||
| namespace ArduinoJson { | ||||
| namespace Internals { | ||||
|  | ||||
| template <typename TChar> | ||||
| struct CharPointerTraits { | ||||
|   static bool equals(const TChar* str, const char* expected) { | ||||
|     const char* actual = reinterpret_cast<const char*>(str); | ||||
|     if (!actual || !expected) return actual == expected; | ||||
|     return strcmp(actual, expected) == 0; | ||||
|   } | ||||
|  | ||||
|   static bool is_null(const TChar* str) { | ||||
|     return !str; | ||||
|   } | ||||
|  | ||||
|   typedef const char* duplicate_t; | ||||
|  | ||||
|   template <typename Buffer> | ||||
|   static duplicate_t duplicate(const TChar* str, Buffer* buffer) { | ||||
|     if (!str) return NULL; | ||||
|     size_t size = strlen(reinterpret_cast<const char*>(str)) + 1; | ||||
|     void* dup = buffer->alloc(size); | ||||
|     if (dup != NULL) memcpy(dup, str, size); | ||||
|     return static_cast<duplicate_t>(dup); | ||||
|   } | ||||
|  | ||||
|   static const bool has_append = false; | ||||
|   static const bool has_equals = true; | ||||
|   static const bool should_duplicate = !is_const<TChar>::value; | ||||
| }; | ||||
|  | ||||
| // char*, unsigned char*, signed char* | ||||
| // const char*, const unsigned char*, const signed char* | ||||
| template <typename TChar> | ||||
| struct StringTraits<TChar*, typename enable_if<sizeof(TChar) == 1>::type> | ||||
|     : CharPointerTraits<TChar> {}; | ||||
| }  // namespace Internals | ||||
| }  // namespace ArduinoJson | ||||
							
								
								
									
										47
									
								
								src/ArduinoJson/Strings/FixedSizeFlashString.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										47
									
								
								src/ArduinoJson/Strings/FixedSizeFlashString.hpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,47 @@ | ||||
| // ArduinoJson - arduinojson.org | ||||
| // Copyright Benoit Blanchon 2014-2018 | ||||
| // MIT License | ||||
|  | ||||
| #pragma once | ||||
|  | ||||
| namespace ArduinoJson { | ||||
| namespace Internals { | ||||
|  | ||||
| class FixedSizeFlashString { | ||||
|  public: | ||||
|   FixedSizeFlashString(const __FlashStringHelper* str, size_t sz) | ||||
|       : _str(str), _size(sz) {} | ||||
|  | ||||
|   bool equals(const char* expected) const { | ||||
|     const char* actual = reinterpret_cast<const char*>(_str); | ||||
|     if (!actual || !expected) return actual == expected; | ||||
|     return strcmp_P(actual, expected) == 0; | ||||
|   } | ||||
|  | ||||
|   bool is_null() const { | ||||
|     return !_str; | ||||
|   } | ||||
|  | ||||
|   template <typename Buffer> | ||||
|   const char* save(Buffer* buffer) const { | ||||
|     if (!_str) return NULL; | ||||
|     void* dup = buffer->alloc(_size); | ||||
|     if (dup != NULL) memcpy_P(dup, (const char*)_str, _size); | ||||
|     return static_cast<const char*>(dup); | ||||
|   } | ||||
|  | ||||
|   size_t size() const { | ||||
|     return strlen_P(reinterpret_cast<const char*>(_str)); | ||||
|   } | ||||
|  | ||||
|  private: | ||||
|   const __FlashStringHelper* _str; | ||||
|   size_t _size; | ||||
| }; | ||||
|  | ||||
| inline FixedSizeFlashString makeString(const __FlashStringHelper* str, | ||||
|                                        size_t sz) { | ||||
|   return FixedSizeFlashString(str, sz); | ||||
| } | ||||
| }  // namespace Internals | ||||
| }  // namespace ArduinoJson | ||||
							
								
								
									
										48
									
								
								src/ArduinoJson/Strings/FixedSizeRamString.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										48
									
								
								src/ArduinoJson/Strings/FixedSizeRamString.hpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,48 @@ | ||||
| // ArduinoJson - arduinojson.org | ||||
| // Copyright Benoit Blanchon 2014-2018 | ||||
| // MIT License | ||||
|  | ||||
| #pragma once | ||||
|  | ||||
| namespace ArduinoJson { | ||||
| namespace Internals { | ||||
|  | ||||
| class FixedSizeRamString { | ||||
|  public: | ||||
|   FixedSizeRamString(const char* str, size_t n) : _str(str), _size(n) {} | ||||
|  | ||||
|   bool equals(const char* expected) const { | ||||
|     const char* actual = reinterpret_cast<const char*>(_str); | ||||
|     if (!actual || !expected) return actual == expected; | ||||
|     return strcmp(actual, expected) == 0; | ||||
|   } | ||||
|  | ||||
|   bool is_null() const { | ||||
|     return !_str; | ||||
|   } | ||||
|  | ||||
|   template <typename Buffer> | ||||
|   const char* save(Buffer* buffer) const { | ||||
|     if (!_str) return NULL; | ||||
|     void* dup = buffer->alloc(_size); | ||||
|     if (!dup) return NULL; | ||||
|     memcpy(dup, _str, _size); | ||||
|     return static_cast<const char*>(dup); | ||||
|   } | ||||
|  | ||||
|   size_t size() const { | ||||
|     return strlen(reinterpret_cast<const char*>(_str)); | ||||
|   } | ||||
|  | ||||
|  private: | ||||
|   const char* _str; | ||||
|   size_t _size; | ||||
| }; | ||||
|  | ||||
| template <typename TChar> | ||||
| inline FixedSizeRamString makeString(const TChar* str, size_t size) { | ||||
|   return FixedSizeRamString(reinterpret_cast<const char*>(str), size); | ||||
| } | ||||
|  | ||||
| }  // namespace Internals | ||||
| }  // namespace ArduinoJson | ||||
| @@ -1,41 +0,0 @@ | ||||
| // ArduinoJson - arduinojson.org | ||||
| // Copyright Benoit Blanchon 2014-2018 | ||||
| // MIT License | ||||
|  | ||||
| #pragma once | ||||
|  | ||||
| #if ARDUINOJSON_ENABLE_PROGMEM | ||||
|  | ||||
| namespace ArduinoJson { | ||||
| namespace Internals { | ||||
| template <> | ||||
| struct StringTraits<const __FlashStringHelper*, void> { | ||||
|   static bool equals(const __FlashStringHelper* str, const char* expected) { | ||||
|     const char* actual = reinterpret_cast<const char*>(str); | ||||
|     if (!actual || !expected) return actual == expected; | ||||
|     return strcmp_P(expected, actual) == 0; | ||||
|   } | ||||
|  | ||||
|   static bool is_null(const __FlashStringHelper* str) { | ||||
|     return !str; | ||||
|   } | ||||
|  | ||||
|   typedef const char* duplicate_t; | ||||
|  | ||||
|   template <typename Buffer> | ||||
|   static duplicate_t duplicate(const __FlashStringHelper* str, Buffer* buffer) { | ||||
|     if (!str) return NULL; | ||||
|     size_t size = strlen_P((const char*)str) + 1; | ||||
|     void* dup = buffer->alloc(size); | ||||
|     if (dup != NULL) memcpy_P(dup, (const char*)str, size); | ||||
|     return static_cast<duplicate_t>(dup); | ||||
|   } | ||||
|  | ||||
|   static const bool has_append = false; | ||||
|   static const bool has_equals = true; | ||||
|   static const bool should_duplicate = true; | ||||
| }; | ||||
| }  // namespace Internals | ||||
| }  // namespace ArduinoJson | ||||
|  | ||||
| #endif | ||||
| @@ -1,73 +0,0 @@ | ||||
| // ArduinoJson - arduinojson.org | ||||
| // Copyright Benoit Blanchon 2014-2018 | ||||
| // MIT License | ||||
|  | ||||
| #pragma once | ||||
|  | ||||
| #if ARDUINOJSON_ENABLE_STD_STRING || ARDUINOJSON_ENABLE_ARDUINO_STRING | ||||
|  | ||||
| #if ARDUINOJSON_ENABLE_ARDUINO_STRING | ||||
| #include <WString.h> | ||||
| #endif | ||||
|  | ||||
| #if ARDUINOJSON_ENABLE_STD_STRING | ||||
| #include <string> | ||||
| #endif | ||||
|  | ||||
| namespace ArduinoJson { | ||||
| namespace Internals { | ||||
|  | ||||
| template <typename TString> | ||||
| struct StdStringTraits { | ||||
|   typedef const char* duplicate_t; | ||||
|  | ||||
|   template <typename Buffer> | ||||
|   static duplicate_t duplicate(const TString& str, Buffer* buffer) { | ||||
|     if (!str.c_str()) return NULL;  // <- Arduino string can return NULL | ||||
|     size_t size = str.length() + 1; | ||||
|     void* dup = buffer->alloc(size); | ||||
|     if (dup != NULL) memcpy(dup, str.c_str(), size); | ||||
|     return static_cast<duplicate_t>(dup); | ||||
|   } | ||||
|  | ||||
|   static bool is_null(const TString& str) { | ||||
|     // Arduino's String::c_str() can return NULL | ||||
|     return !str.c_str(); | ||||
|   } | ||||
|  | ||||
|   static bool equals(const TString& str, const char* expected) { | ||||
|     // Arduino's String::c_str() can return NULL | ||||
|     const char* actual = str.c_str(); | ||||
|     if (!actual || !expected) return actual == expected; | ||||
|     return 0 == strcmp(actual, expected); | ||||
|   } | ||||
|  | ||||
|   static void append(TString& str, char c) { | ||||
|     str += c; | ||||
|   } | ||||
|  | ||||
|   static void append(TString& str, const char* s) { | ||||
|     str += s; | ||||
|   } | ||||
|  | ||||
|   static const bool has_append = true; | ||||
|   static const bool has_equals = true; | ||||
|   static const bool should_duplicate = true; | ||||
| }; | ||||
|  | ||||
| #if ARDUINOJSON_ENABLE_ARDUINO_STRING | ||||
| template <> | ||||
| struct StringTraits<String, void> : StdStringTraits<String> {}; | ||||
| template <> | ||||
| struct StringTraits<StringSumHelper, void> : StdStringTraits<StringSumHelper> { | ||||
| }; | ||||
| #endif | ||||
|  | ||||
| #if ARDUINOJSON_ENABLE_STD_STRING | ||||
| template <> | ||||
| struct StringTraits<std::string, void> : StdStringTraits<std::string> {}; | ||||
| #endif | ||||
| }  // namespace Internals | ||||
| }  // namespace ArduinoJson | ||||
|  | ||||
| #endif | ||||
							
								
								
									
										52
									
								
								src/ArduinoJson/Strings/StlString.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										52
									
								
								src/ArduinoJson/Strings/StlString.hpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,52 @@ | ||||
| // ArduinoJson - arduinojson.org | ||||
| // Copyright Benoit Blanchon 2014-2018 | ||||
| // MIT License | ||||
|  | ||||
| #pragma once | ||||
|  | ||||
| #include <string> | ||||
|  | ||||
| namespace ArduinoJson { | ||||
| namespace Internals { | ||||
|  | ||||
| class StlString { | ||||
|  public: | ||||
|   StlString(const std::string& str) : _str(&str) {} | ||||
|  | ||||
|   template <typename Buffer> | ||||
|   const char* save(Buffer* buffer) const { | ||||
|     size_t n = _str->length() + 1; | ||||
|     void* dup = buffer->alloc(n); | ||||
|     if (dup != NULL) memcpy(dup, _str->c_str(), n); | ||||
|     return static_cast<const char*>(dup); | ||||
|   } | ||||
|  | ||||
|   bool is_null() const { | ||||
|     return false; | ||||
|   } | ||||
|  | ||||
|   bool equals(const char* expected) const { | ||||
|     return *_str == expected; | ||||
|   } | ||||
|  | ||||
|   const char* data() const { | ||||
|     return _str->data(); | ||||
|   } | ||||
|  | ||||
|   size_t size() const { | ||||
|     return _str->size(); | ||||
|   } | ||||
|  | ||||
|  private: | ||||
|   const std::string* _str; | ||||
| }; | ||||
|  | ||||
| template <> | ||||
| struct IsString<std::string> : true_type {}; | ||||
|  | ||||
| inline StlString makeString(const std::string& str) { | ||||
|   return StlString(str); | ||||
| } | ||||
|  | ||||
| }  // namespace Internals | ||||
| }  // namespace ArduinoJson | ||||
| @@ -1,30 +0,0 @@ | ||||
| // ArduinoJson - arduinojson.org | ||||
| // Copyright Benoit Blanchon 2014-2018 | ||||
| // MIT License | ||||
|  | ||||
| #pragma once | ||||
|  | ||||
| #include <string.h> | ||||
| #include "../Configuration.hpp" | ||||
| #include "../Polyfills/type_traits.hpp" | ||||
|  | ||||
| namespace ArduinoJson { | ||||
| namespace Internals { | ||||
|  | ||||
| template <typename TString, typename Enable = void> | ||||
| struct StringTraits { | ||||
|   static const bool has_append = false; | ||||
|   static const bool has_equals = false; | ||||
| }; | ||||
|  | ||||
| template <typename TString> | ||||
| struct StringTraits<const TString, void> : StringTraits<TString> {}; | ||||
|  | ||||
| template <typename TString> | ||||
| struct StringTraits<TString&, void> : StringTraits<TString> {}; | ||||
| }  // namespace Internals | ||||
| }  // namespace ArduinoJson | ||||
|  | ||||
| #include "CharPointer.hpp" | ||||
| #include "FlashString.hpp" | ||||
| #include "StdString.hpp" | ||||
							
								
								
									
										36
									
								
								src/ArduinoJson/Strings/StringTypes.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										36
									
								
								src/ArduinoJson/Strings/StringTypes.hpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,36 @@ | ||||
| // ArduinoJson - arduinojson.org | ||||
| // Copyright Benoit Blanchon 2014-2018 | ||||
| // MIT License | ||||
|  | ||||
| #pragma once | ||||
|  | ||||
| #include "../Polyfills/type_traits.hpp" | ||||
|  | ||||
| namespace ArduinoJson { | ||||
| namespace Internals { | ||||
| template <typename> | ||||
| struct IsString : false_type {}; | ||||
|  | ||||
| template <typename T> | ||||
| struct IsString<const T> : IsString<T> {}; | ||||
|  | ||||
| template <typename T> | ||||
| struct IsString<T&> : IsString<T> {}; | ||||
| }  // namespace Internals | ||||
| }  // namespace ArduinoJson | ||||
|  | ||||
| #include "FixedSizeRamString.hpp" | ||||
| #include "ZeroTerminatedRamString.hpp" | ||||
|  | ||||
| #if ARDUINOJSON_ENABLE_STD_STRING | ||||
| #include "StlString.hpp" | ||||
| #endif | ||||
|  | ||||
| #if ARDUINOJSON_ENABLE_ARDUINO_STRING | ||||
| #include "ArduinoString.hpp" | ||||
| #endif | ||||
|  | ||||
| #if ARDUINOJSON_ENABLE_PROGMEM | ||||
| #include "FixedSizeFlashString.hpp" | ||||
| #include "ZeroTerminatedFlashString.hpp" | ||||
| #endif | ||||
							
								
								
									
										48
									
								
								src/ArduinoJson/Strings/ZeroTerminatedFlashString.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										48
									
								
								src/ArduinoJson/Strings/ZeroTerminatedFlashString.hpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,48 @@ | ||||
| // ArduinoJson - arduinojson.org | ||||
| // Copyright Benoit Blanchon 2014-2018 | ||||
| // MIT License | ||||
|  | ||||
| #pragma once | ||||
|  | ||||
| namespace ArduinoJson { | ||||
| namespace Internals { | ||||
|  | ||||
| class ZeroTerminatedFlashString { | ||||
|  public: | ||||
|   ZeroTerminatedFlashString(const __FlashStringHelper* str) : _str(str) {} | ||||
|  | ||||
|   bool equals(const char* expected) const { | ||||
|     const char* actual = reinterpret_cast<const char*>(_str); | ||||
|     if (!actual || !expected) return actual == expected; | ||||
|     return strcmp_P(actual, expected) == 0; | ||||
|   } | ||||
|  | ||||
|   bool is_null() const { | ||||
|     return !_str; | ||||
|   } | ||||
|  | ||||
|   template <typename Buffer> | ||||
|   const char* save(Buffer* buffer) const { | ||||
|     if (!_str) return NULL; | ||||
|     size_t n = size() + 1;  // copy the terminator | ||||
|     void* dup = buffer->alloc(n); | ||||
|     if (dup != NULL) memcpy_P(dup, (const char*)_str, n); | ||||
|     return static_cast<const char*>(dup); | ||||
|   } | ||||
|  | ||||
|   size_t size() const { | ||||
|     return strlen_P(reinterpret_cast<const char*>(_str)); | ||||
|   } | ||||
|  | ||||
|  private: | ||||
|   const __FlashStringHelper* _str; | ||||
| }; | ||||
|  | ||||
| inline ZeroTerminatedFlashString makeString(const __FlashStringHelper* str) { | ||||
|   return ZeroTerminatedFlashString(str); | ||||
| } | ||||
|  | ||||
| template <> | ||||
| struct IsString<const __FlashStringHelper*> : true_type {}; | ||||
| }  // namespace Internals | ||||
| }  // namespace ArduinoJson | ||||
							
								
								
									
										53
									
								
								src/ArduinoJson/Strings/ZeroTerminatedRamString.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										53
									
								
								src/ArduinoJson/Strings/ZeroTerminatedRamString.hpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,53 @@ | ||||
| // ArduinoJson - arduinojson.org | ||||
| // Copyright Benoit Blanchon 2014-2018 | ||||
| // MIT License | ||||
|  | ||||
| #pragma once | ||||
|  | ||||
| namespace ArduinoJson { | ||||
| namespace Internals { | ||||
|  | ||||
| class ZeroTerminatedRamString { | ||||
|  public: | ||||
|   ZeroTerminatedRamString(const char* str) : _str(str) {} | ||||
|  | ||||
|   bool equals(const char* expected) const { | ||||
|     const char* actual = reinterpret_cast<const char*>(_str); | ||||
|     if (!actual || !expected) return actual == expected; | ||||
|     return strcmp(actual, expected) == 0; | ||||
|   } | ||||
|  | ||||
|   bool is_null() const { | ||||
|     return !_str; | ||||
|   } | ||||
|  | ||||
|   template <typename Buffer> | ||||
|   const char* save(Buffer* buffer) const { | ||||
|     if (!_str) return NULL; | ||||
|     size_t n = size() + 1; | ||||
|     void* dup = buffer->alloc(n); | ||||
|     if (!dup) return NULL; | ||||
|     memcpy(dup, _str, n); | ||||
|     return static_cast<const char*>(dup); | ||||
|   } | ||||
|  | ||||
|   size_t size() const { | ||||
|     return strlen(reinterpret_cast<const char*>(_str)); | ||||
|   } | ||||
|  | ||||
|  private: | ||||
|   const char* _str; | ||||
| }; | ||||
|  | ||||
| template <typename TChar> | ||||
| inline ZeroTerminatedRamString makeString(const TChar* str) { | ||||
|   return ZeroTerminatedRamString(reinterpret_cast<const char*>(str)); | ||||
| } | ||||
|  | ||||
| template <typename TChar> | ||||
| struct IsString<TChar*> { | ||||
|   static const bool value = sizeof(TChar) == 1; | ||||
| }; | ||||
|  | ||||
| }  // namespace Internals | ||||
| }  // namespace ArduinoJson | ||||
| @@ -4,16 +4,17 @@ | ||||
|  | ||||
| add_executable(JsonArrayTests  | ||||
| 	add.cpp | ||||
| 	basics.cpp | ||||
| 	copyFrom.cpp | ||||
| 	copyTo.cpp | ||||
| 	invalid.cpp | ||||
| 	createNested.cpp | ||||
| 	isNull.cpp | ||||
| 	iterator.cpp | ||||
| 	remove.cpp | ||||
| 	set.cpp | ||||
| 	size.cpp | ||||
| 	std_string.cpp | ||||
| 	subscript.cpp | ||||
| 	undefined.cpp | ||||
| ) | ||||
|  | ||||
| target_link_libraries(JsonArrayTests catch) | ||||
|   | ||||
| @@ -100,14 +100,26 @@ TEST_CASE("JsonArray::add()") { | ||||
|     REQUIRE(expectedSize == doc.memoryUsage()); | ||||
|   } | ||||
|  | ||||
|   SECTION("should not duplicate RawJson(const char*)") { | ||||
|     _array.add(RawJson("{}")); | ||||
|   SECTION("should not duplicate serialized(const char*)") { | ||||
|     _array.add(serialized("{}")); | ||||
|     const size_t expectedSize = JSON_ARRAY_SIZE(1); | ||||
|     REQUIRE(expectedSize == doc.memoryUsage()); | ||||
|   } | ||||
|  | ||||
|   SECTION("should duplicate RawJson(char*)") { | ||||
|     _array.add(RawJson(const_cast<char*>("{}"))); | ||||
|   SECTION("should duplicate serialized(char*)") { | ||||
|     _array.add(serialized(const_cast<char*>("{}"))); | ||||
|     const size_t expectedSize = JSON_ARRAY_SIZE(1) + 2; | ||||
|     REQUIRE(expectedSize == doc.memoryUsage()); | ||||
|   } | ||||
|  | ||||
|   SECTION("should duplicate serialized(std::string)") { | ||||
|     _array.add(serialized(std::string("{}"))); | ||||
|     const size_t expectedSize = JSON_ARRAY_SIZE(1) + 2; | ||||
|     REQUIRE(expectedSize == doc.memoryUsage()); | ||||
|   } | ||||
|  | ||||
|   SECTION("should duplicate serialized(std::string)") { | ||||
|     _array.add(serialized(std::string("\0XX", 3))); | ||||
|     const size_t expectedSize = JSON_ARRAY_SIZE(1) + 3; | ||||
|     REQUIRE(expectedSize == doc.memoryUsage()); | ||||
|   } | ||||
|   | ||||
| @@ -9,14 +9,6 @@ TEST_CASE("JsonArray basics") { | ||||
|   DynamicJsonDocument doc; | ||||
|   JsonArray array = doc.to<JsonArray>(); | ||||
| 
 | ||||
|   SECTION("isNull()") { | ||||
|     REQUIRE(array.isNull() == false); | ||||
|   } | ||||
| 
 | ||||
|   SECTION("InitialSizeIsZero") { | ||||
|     REQUIRE(0U == array.size()); | ||||
|   } | ||||
| 
 | ||||
|   SECTION("CreateNestedArray") { | ||||
|     JsonArray arr = array.createNestedArray(); | ||||
|     REQUIRE(arr == array[0].as<JsonArray>()); | ||||
							
								
								
									
										25
									
								
								test/JsonArray/isNull.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										25
									
								
								test/JsonArray/isNull.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,25 @@ | ||||
| // ArduinoJson - arduinojson.org | ||||
| // Copyright Benoit Blanchon 2014-2018 | ||||
| // MIT License | ||||
|  | ||||
| #include <ArduinoJson.h> | ||||
| #include <catch.hpp> | ||||
|  | ||||
| TEST_CASE("JsonArray::isNull()") { | ||||
|   SECTION("returns true for undefined JsonArray") { | ||||
|     JsonArray array; | ||||
|     REQUIRE(array.isNull() == true); | ||||
|   } | ||||
|  | ||||
|   SECTION("returns false when allocation succeeds") { | ||||
|     StaticJsonDocument<JSON_ARRAY_SIZE(0)> doc; | ||||
|     JsonArray array = doc.to<JsonArray>(); | ||||
|     REQUIRE(array.isNull() == false); | ||||
|   } | ||||
|  | ||||
|   SECTION("returns true when allocation fails") { | ||||
|     StaticJsonDocument<1> doc; | ||||
|     JsonArray array = doc.to<JsonArray>(); | ||||
|     REQUIRE(array.isNull() == true); | ||||
|   } | ||||
| } | ||||
| @@ -7,29 +7,33 @@ | ||||
|  | ||||
| TEST_CASE("JsonArray::size()") { | ||||
|   DynamicJsonDocument doc; | ||||
|   JsonArray _array = doc.to<JsonArray>(); | ||||
|   JsonArray array = doc.to<JsonArray>(); | ||||
|  | ||||
|   SECTION("InitialSizeIsZero") { | ||||
|     REQUIRE(0U == array.size()); | ||||
|   } | ||||
|  | ||||
|   SECTION("increases after add()") { | ||||
|     _array.add("hello"); | ||||
|     REQUIRE(1U == _array.size()); | ||||
|     array.add("hello"); | ||||
|     REQUIRE(1U == array.size()); | ||||
|  | ||||
|     _array.add("world"); | ||||
|     REQUIRE(2U == _array.size()); | ||||
|     array.add("world"); | ||||
|     REQUIRE(2U == array.size()); | ||||
|   } | ||||
|  | ||||
|   SECTION("remains the same after set()") { | ||||
|     _array.add("hello"); | ||||
|     REQUIRE(1U == _array.size()); | ||||
|     array.add("hello"); | ||||
|     REQUIRE(1U == array.size()); | ||||
|  | ||||
|     _array.set(0, "hello"); | ||||
|     REQUIRE(1U == _array.size()); | ||||
|     array.set(0, "hello"); | ||||
|     REQUIRE(1U == array.size()); | ||||
|   } | ||||
|  | ||||
|   SECTION("remains the same after assigment") { | ||||
|     _array.add("hello"); | ||||
|     REQUIRE(1U == _array.size()); | ||||
|     array.add("hello"); | ||||
|     REQUIRE(1U == array.size()); | ||||
|  | ||||
|     _array[0] = "hello"; | ||||
|     REQUIRE(1U == _array.size()); | ||||
|     array[0] = "hello"; | ||||
|     REQUIRE(1U == array.size()); | ||||
|   } | ||||
| } | ||||
|   | ||||
| @@ -3,10 +3,10 @@ | ||||
| # MIT License | ||||
|  | ||||
| add_executable(JsonObjectTests  | ||||
| 	basics.cpp | ||||
| 	containsKey.cpp | ||||
| 	get.cpp | ||||
| 	invalid.cpp | ||||
| 	isNull.cpp | ||||
| 	iterator.cpp | ||||
| 	remove.cpp | ||||
| 	set.cpp | ||||
|   | ||||
| @@ -1,15 +0,0 @@ | ||||
| // ArduinoJson - arduinojson.org | ||||
| // Copyright Benoit Blanchon 2014-2018 | ||||
| // MIT License | ||||
|  | ||||
| #include <ArduinoJson.h> | ||||
| #include <catch.hpp> | ||||
|  | ||||
| TEST_CASE("JsonObject basics") { | ||||
|   DynamicJsonDocument doc; | ||||
|   JsonObject obj = doc.to<JsonObject>(); | ||||
|  | ||||
|   SECTION("isNull()") { | ||||
|     REQUIRE(obj.isNull() == false); | ||||
|   } | ||||
| } | ||||
							
								
								
									
										25
									
								
								test/JsonObject/isNull.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										25
									
								
								test/JsonObject/isNull.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,25 @@ | ||||
| // ArduinoJson - arduinojson.org | ||||
| // Copyright Benoit Blanchon 2014-2018 | ||||
| // MIT License | ||||
|  | ||||
| #include <ArduinoJson.h> | ||||
| #include <catch.hpp> | ||||
|  | ||||
| TEST_CASE("JsonObject::isNull()") { | ||||
|   SECTION("returns true for undefined JsonObject") { | ||||
|     JsonObject array; | ||||
|     REQUIRE(array.isNull() == true); | ||||
|   } | ||||
|  | ||||
|   SECTION("returns false when allocation succeeds") { | ||||
|     StaticJsonDocument<JSON_OBJECT_SIZE(0)> doc; | ||||
|     JsonObject array = doc.to<JsonObject>(); | ||||
|     REQUIRE(array.isNull() == false); | ||||
|   } | ||||
|  | ||||
|   SECTION("returns true when allocation fails") { | ||||
|     StaticJsonDocument<1> doc; | ||||
|     JsonObject array = doc.to<JsonObject>(); | ||||
|     REQUIRE(array.isNull() == true); | ||||
|   } | ||||
| } | ||||
| @@ -67,15 +67,15 @@ TEST_CASE("serializeJson(JsonArray)") { | ||||
|     check(array, "[1,2]"); | ||||
|   } | ||||
|  | ||||
|   SECTION("RawJson(const char*)") { | ||||
|     array.add(RawJson("{\"key\":\"value\"}")); | ||||
|   SECTION("serialized(const char*)") { | ||||
|     array.add(serialized("{\"key\":\"value\"}")); | ||||
|  | ||||
|     check(array, "[{\"key\":\"value\"}]"); | ||||
|   } | ||||
|  | ||||
|   SECTION("RawJson(char*)") { | ||||
|   SECTION("serialized(char*)") { | ||||
|     char tmp[] = "{\"key\":\"value\"}"; | ||||
|     array.add(RawJson(tmp)); | ||||
|     array.add(serialized(tmp)); | ||||
|  | ||||
|     check(array, "[{\"key\":\"value\"}]"); | ||||
|   } | ||||
|   | ||||
| @@ -68,9 +68,9 @@ TEST_CASE("serializeJson(JsonObject)") { | ||||
|     check(obj, "{\"a\":1,\"b\":2}"); | ||||
|   } | ||||
|  | ||||
|   SECTION("RawJson") { | ||||
|     obj["a"] = RawJson("[1,2]"); | ||||
|     obj.set("b", RawJson("[4,5]")); | ||||
|   SECTION("serialized(const char*)") { | ||||
|     obj["a"] = serialized("[1,2]"); | ||||
|     obj.set("b", serialized("[4,5]")); | ||||
|     check(obj, "{\"a\":[1,2],\"b\":[4,5]}"); | ||||
|   } | ||||
|  | ||||
|   | ||||
| @@ -95,21 +95,4 @@ TEST_CASE("JsonVariant::is()") { | ||||
|   SECTION("string") { | ||||
|     checkIsString("42"); | ||||
|   } | ||||
|  | ||||
|   SECTION("unparsed bool") { | ||||
|     checkIsBool(RawJson("true")); | ||||
|     checkIsBool(RawJson("false")); | ||||
|   } | ||||
|  | ||||
|   SECTION("unparsed int") { | ||||
|     checkIsInteger(RawJson("42")); | ||||
|   } | ||||
|  | ||||
|   SECTION("unparsed float") { | ||||
|     checkIsFloat(RawJson("4.2e-10")); | ||||
|   } | ||||
|  | ||||
|   SECTION("unparsed null") { | ||||
|     checkIsString(RawJson("null")); | ||||
|   } | ||||
| } | ||||
|   | ||||
| @@ -7,15 +7,15 @@ | ||||
| #include <string> | ||||
|  | ||||
| #include <ArduinoJson/Json/JsonWriter.hpp> | ||||
| #include <ArduinoJson/Serialization/DynamicStringBuilder.hpp> | ||||
| #include <ArduinoJson/Serialization/DynamicStringWriter.hpp> | ||||
|  | ||||
| using namespace ArduinoJson::Internals; | ||||
|  | ||||
| template <typename TFloat> | ||||
| void check(TFloat input, const std::string& expected) { | ||||
|   std::string output; | ||||
|   DynamicStringBuilder<std::string> sb(output); | ||||
|   JsonWriter<DynamicStringBuilder<std::string> > writer(sb); | ||||
|   DynamicStringWriter<std::string> sb(output); | ||||
|   JsonWriter<DynamicStringWriter<std::string> > writer(sb); | ||||
|   writer.writeFloat(input); | ||||
|   REQUIRE(writer.bytesWritten() == output.size()); | ||||
|   CHECK(expected == output); | ||||
|   | ||||
| @@ -5,14 +5,14 @@ | ||||
| #include <catch.hpp> | ||||
|  | ||||
| #include <ArduinoJson/Json/JsonWriter.hpp> | ||||
| #include <ArduinoJson/Serialization/StaticStringBuilder.hpp> | ||||
| #include <ArduinoJson/Serialization/StaticStringWriter.hpp> | ||||
|  | ||||
| using namespace ArduinoJson::Internals; | ||||
|  | ||||
| void check(const char* input, std::string expected) { | ||||
|   char output[1024]; | ||||
|   StaticStringBuilder sb(output, sizeof(output)); | ||||
|   JsonWriter<StaticStringBuilder> writer(sb); | ||||
|   StaticStringWriter sb(output, sizeof(output)); | ||||
|   JsonWriter<StaticStringWriter> writer(sb); | ||||
|   writer.writeString(input); | ||||
|   REQUIRE(expected == output); | ||||
|   REQUIRE(writer.bytesWritten() == expected.size()); | ||||
|   | ||||
| @@ -4,8 +4,7 @@ | ||||
|  | ||||
| add_executable(MiscTests | ||||
| 	FloatParts.cpp | ||||
| 	StringBuilder.cpp | ||||
| 	StringTraits.cpp | ||||
| 	StringWriter.cpp | ||||
| 	TypeTraits.cpp | ||||
| 	unsigned_char.cpp | ||||
| 	version.cpp | ||||
|   | ||||
| @@ -1,22 +0,0 @@ | ||||
| // ArduinoJson - arduinojson.org | ||||
| // Copyright Benoit Blanchon 2014-2018 | ||||
| // MIT License | ||||
|  | ||||
| #include <ArduinoJson.h> | ||||
| #include <catch.hpp> | ||||
|  | ||||
| using namespace ArduinoJson::Internals; | ||||
|  | ||||
| template <typename String> | ||||
| bool should_duplicate() { | ||||
|   return StringTraits<String>::should_duplicate; | ||||
| } | ||||
|  | ||||
| TEST_CASE("StringTraits") { | ||||
|   SECTION("should_duplicate") { | ||||
|     REQUIRE(false == should_duplicate<const char*>()); | ||||
|     REQUIRE(true == should_duplicate<char*>()); | ||||
|     REQUIRE(true == should_duplicate<RawJsonString<char*> >()); | ||||
|     REQUIRE(false == should_duplicate<RawJsonString<const char*> >()); | ||||
|   } | ||||
| } | ||||
| @@ -7,44 +7,49 @@ | ||||
| 
 | ||||
| using namespace ArduinoJson::Internals; | ||||
| 
 | ||||
| template <typename StringBuilder, typename String> | ||||
| void common_tests(StringBuilder& sb, const String& output) { | ||||
| template <typename StringWriter> | ||||
| static size_t print(StringWriter& sb, const char* s) { | ||||
|   return sb.write(reinterpret_cast<const uint8_t*>(s), strlen(s)); | ||||
| } | ||||
| 
 | ||||
| template <typename StringWriter, typename String> | ||||
| void common_tests(StringWriter& sb, const String& output) { | ||||
|   SECTION("InitialState") { | ||||
|     REQUIRE(std::string("") == output); | ||||
|   } | ||||
| 
 | ||||
|   SECTION("EmptyString") { | ||||
|     REQUIRE(0 == sb.print("")); | ||||
|     REQUIRE(0 == print(sb, "")); | ||||
|     REQUIRE(std::string("") == output); | ||||
|   } | ||||
| 
 | ||||
|   SECTION("OneString") { | ||||
|     REQUIRE(4 == sb.print("ABCD")); | ||||
|     REQUIRE(4 == print(sb, "ABCD")); | ||||
|     REQUIRE(std::string("ABCD") == output); | ||||
|   } | ||||
| 
 | ||||
|   SECTION("TwoStrings") { | ||||
|     REQUIRE(4 == sb.print("ABCD")); | ||||
|     REQUIRE(4 == sb.print("EFGH")); | ||||
|     REQUIRE(4 == print(sb, "ABCD")); | ||||
|     REQUIRE(4 == print(sb, "EFGH")); | ||||
|     REQUIRE(std::string("ABCDEFGH") == output); | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| TEST_CASE("StaticStringBuilder") { | ||||
| TEST_CASE("StaticStringWriter") { | ||||
|   char output[20]; | ||||
|   StaticStringBuilder sb(output, sizeof(output)); | ||||
|   StaticStringWriter sb(output, sizeof(output)); | ||||
| 
 | ||||
|   common_tests(sb, static_cast<const char*>(output)); | ||||
| 
 | ||||
|   SECTION("OverCapacity") { | ||||
|     REQUIRE(19 == sb.print("ABCDEFGHIJKLMNOPQRSTUVWXYZ")); | ||||
|     REQUIRE(0 == sb.print("ABC")); | ||||
|     REQUIRE(19 == print(sb, "ABCDEFGHIJKLMNOPQRSTUVWXYZ")); | ||||
|     REQUIRE(0 == print(sb, "ABC")); | ||||
|     REQUIRE(std::string("ABCDEFGHIJKLMNOPQRS") == output); | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| TEST_CASE("DynamicStringBuilder") { | ||||
| TEST_CASE("DynamicStringWriter") { | ||||
|   std::string output; | ||||
|   DynamicStringBuilder<std::string> sb(output); | ||||
|   DynamicStringWriter<std::string> sb(output); | ||||
|   common_tests(sb, output); | ||||
| } | ||||
| @@ -70,4 +70,14 @@ TEST_CASE("serialize MsgPack object") { | ||||
|   // | ||||
|   //   check(object, expected); | ||||
|   // } | ||||
|  | ||||
|   SECTION("serialized(const char*)") { | ||||
|     object["hello"] = serialized("\xDB\x00\x01\x00\x00", 5); | ||||
|     check(object, "\x81\xA5hello\xDB\x00\x01\x00\x00"); | ||||
|   } | ||||
|  | ||||
|   SECTION("serialized(std::string)") { | ||||
|     object["hello"] = serialized(std::string("\xDB\x00\x01\x00\x00", 5)); | ||||
|     check(object, "\x81\xA5hello\xDB\x00\x01\x00\x00"); | ||||
|   } | ||||
| } | ||||
|   | ||||
| @@ -126,4 +126,9 @@ TEST_CASE("serialize MsgPack value") { | ||||
|     std::string shortest(65536, '?'); | ||||
|     check(shortest.c_str(), std::string("\xDB\x00\x01\x00\x00", 5) + shortest); | ||||
|   } | ||||
|  | ||||
|   SECTION("serialized(const char*)") { | ||||
|     check(serialized("\xDA\xFF\xFF"), "\xDA\xFF\xFF"); | ||||
|     check(serialized("\xDB\x00\x01\x00\x00", 5), "\xDB\x00\x01\x00\x00"); | ||||
|   } | ||||
| } | ||||
|   | ||||
		Reference in New Issue
	
	Block a user