mirror of
				https://github.com/eledio-devices/thirdparty-ArduinoJson.git
				synced 2025-10-31 16:14:11 +01:00 
			
		
		
		
	Added support of non standard JSON input (issue #44)
This commit is contained in:
		
							
								
								
									
										1
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										1
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							| @@ -3,3 +3,4 @@ | |||||||
| /build | /build | ||||||
| /bin | /bin | ||||||
| /lib | /lib | ||||||
|  | /sftp-config.json | ||||||
|   | |||||||
| @@ -4,9 +4,7 @@ compiler: | |||||||
|   - clang |   - clang | ||||||
| before_install: | before_install: | ||||||
|   - sudo pip install cpp-coveralls |   - sudo pip install cpp-coveralls | ||||||
| before_script: |  | ||||||
|   - cmake -DCOVERAGE=true . |  | ||||||
| script: | script: | ||||||
|   - make && make test |   - cmake -DCOVERAGE=true . && make && make test | ||||||
| after_success: | after_success: | ||||||
|   - coveralls --exclude test --exclude third-party --gcov-options '\-lp' |     - if [ "$CC" = "gcc" ]; then coveralls --exclude third-party --gcov-options '\-lp'; fi | ||||||
|   | |||||||
							
								
								
									
										10
									
								
								CHANGELOG.md
									
									
									
									
									
								
							
							
						
						
									
										10
									
								
								CHANGELOG.md
									
									
									
									
									
								
							| @@ -5,6 +5,7 @@ v5.0 (currently in beta) | |||||||
| ---- | ---- | ||||||
|  |  | ||||||
| * Added support of `String` class (issue #55, #56, #70, #77) | * Added support of `String` class (issue #55, #56, #70, #77) | ||||||
|  | * Added support of non standard JSON input (issue #44) | ||||||
| * Redesigned `JsonVariant` to leverage converting constructors instead of assignment operators | * Redesigned `JsonVariant` to leverage converting constructors instead of assignment operators | ||||||
| * Switched to new the library layout (requires Arduino 1.0.6 or above) | * Switched to new the library layout (requires Arduino 1.0.6 or above) | ||||||
|  |  | ||||||
| @@ -20,6 +21,15 @@ The `String` class is **bad** because it uses dynamic memory allocation. | |||||||
| Compared to static allocation, it compiles to a bigger, slower program, and is less predictable. | Compared to static allocation, it compiles to a bigger, slower program, and is less predictable. | ||||||
| You certainly don't want that in an embedded environment! | You certainly don't want that in an embedded environment! | ||||||
|  |  | ||||||
|  | v4.5 | ||||||
|  | ---- | ||||||
|  |  | ||||||
|  | * Fixed buffer overflow when input contains a backslash followed by a terminator (issue #81) | ||||||
|  |  | ||||||
|  | **Upgrading is recommended** since previous versions contain a potential security risk. | ||||||
|  |  | ||||||
|  | Special thanks to [Giancarlo Canales Barreto](https://github.com/gcanalesb) for finding this nasty bug. | ||||||
|  |  | ||||||
| v4.4 | v4.4 | ||||||
| ---- | ---- | ||||||
|  |  | ||||||
|   | |||||||
| @@ -12,8 +12,7 @@ if(MSVC) | |||||||
| endif() | endif() | ||||||
|  |  | ||||||
| if(${COVERAGE}) | if(${COVERAGE}) | ||||||
| 	set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -coverage") | 	set(CMAKE_CXX_FLAGS "-g -O0 -fprofile-arcs -ftest-coverage") | ||||||
| 	set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -coverage") |  | ||||||
| endif() | endif() | ||||||
|  |  | ||||||
| add_subdirectory(src) | add_subdirectory(src) | ||||||
|   | |||||||
							
								
								
									
										39
									
								
								include/ArduinoJson/Internals/Encoding.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										39
									
								
								include/ArduinoJson/Internals/Encoding.hpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,39 @@ | |||||||
|  | // Copyright Benoit Blanchon 2014-2015 | ||||||
|  | // MIT License | ||||||
|  | // | ||||||
|  | // Arduino JSON library | ||||||
|  | // https://github.com/bblanchon/ArduinoJson | ||||||
|  |  | ||||||
|  | #pragma once | ||||||
|  |  | ||||||
|  | #include "../Arduino/Print.hpp" | ||||||
|  |  | ||||||
|  | namespace ArduinoJson { | ||||||
|  | namespace Internals { | ||||||
|  |  | ||||||
|  | class Encoding { | ||||||
|  |  public: | ||||||
|  |   // Optimized for code size on a 8-bit AVR | ||||||
|  |   static char escapeChar(char c) { | ||||||
|  |     const char *p = _escapeTable; | ||||||
|  |     while (p[0] && p[1] != c) { | ||||||
|  |       p += 2; | ||||||
|  |     } | ||||||
|  |     return p[0]; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   // Optimized for code size on a 8-bit AVR | ||||||
|  |   static char unescapeChar(char c) { | ||||||
|  |     const char *p = _escapeTable + 4; | ||||||
|  |     for (;;) { | ||||||
|  |       if (p[0] == '\0') return c; | ||||||
|  |       if (p[0] == c) return p[1]; | ||||||
|  |       p += 2; | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |  | ||||||
|  | private: | ||||||
|  | 	static const char _escapeTable[]; | ||||||
|  | }; | ||||||
|  | } | ||||||
|  | } | ||||||
| @@ -18,7 +18,10 @@ namespace Internals { | |||||||
| class JsonParser { | class JsonParser { | ||||||
|  public: |  public: | ||||||
|   JsonParser(JsonBuffer *buffer, char *json, uint8_t nestingLimit) |   JsonParser(JsonBuffer *buffer, char *json, uint8_t nestingLimit) | ||||||
|       : _buffer(buffer), _ptr(json), _nestingLimit(nestingLimit) {} |       : _buffer(buffer), | ||||||
|  |         _readPtr(json), | ||||||
|  |         _writePtr(json), | ||||||
|  |         _nestingLimit(nestingLimit) {} | ||||||
|  |  | ||||||
|   JsonArray &parseArray(); |   JsonArray &parseArray(); | ||||||
|   JsonObject &parseObject(); |   JsonObject &parseObject(); | ||||||
| @@ -26,12 +29,10 @@ class JsonParser { | |||||||
|  private: |  private: | ||||||
|   bool skip(char charToSkip); |   bool skip(char charToSkip); | ||||||
|   bool skip(const char *wordToSkip); |   bool skip(const char *wordToSkip); | ||||||
|   void skipSpaces(); |  | ||||||
|  |  | ||||||
|   bool parseAnythingTo(JsonVariant *destination); |  | ||||||
|   FORCE_INLINE bool parseAnythingToUnsafe(JsonVariant *destination); |  | ||||||
|  |  | ||||||
|   const char *parseString(); |   const char *parseString(); | ||||||
|  |   bool parseAnythingTo(JsonVariant *destination); | ||||||
|  |   FORCE_INLINE bool parseAnythingToUnsafe(JsonVariant *destination); | ||||||
|  |  | ||||||
|   inline bool parseArrayTo(JsonVariant *destination); |   inline bool parseArrayTo(JsonVariant *destination); | ||||||
|   inline bool parseBooleanTo(JsonVariant *destination); |   inline bool parseBooleanTo(JsonVariant *destination); | ||||||
| @@ -41,7 +42,8 @@ class JsonParser { | |||||||
|   inline bool parseStringTo(JsonVariant *destination); |   inline bool parseStringTo(JsonVariant *destination); | ||||||
|  |  | ||||||
|   JsonBuffer *_buffer; |   JsonBuffer *_buffer; | ||||||
|   char *_ptr; |   const char *_readPtr; | ||||||
|  |   char *_writePtr; | ||||||
|   uint8_t _nestingLimit; |   uint8_t _nestingLimit; | ||||||
| }; | }; | ||||||
| } | } | ||||||
|   | |||||||
| @@ -12,6 +12,10 @@ | |||||||
| #include "Prettyfier.hpp" | #include "Prettyfier.hpp" | ||||||
| #include "StringBuilder.hpp" | #include "StringBuilder.hpp" | ||||||
|  |  | ||||||
|  | #ifdef ARDUINOJSON_ENABLE_STD_STREAM | ||||||
|  | #include "StreamPrintAdapter.hpp" | ||||||
|  | #endif | ||||||
|  |  | ||||||
| namespace ArduinoJson { | namespace ArduinoJson { | ||||||
| namespace Internals { | namespace Internals { | ||||||
|  |  | ||||||
| @@ -28,6 +32,14 @@ class JsonPrintable { | |||||||
|     return writer.bytesWritten(); |     return writer.bytesWritten(); | ||||||
|   } |   } | ||||||
|  |  | ||||||
|  | #ifdef ARDUINOJSON_ENABLE_STD_STREAM | ||||||
|  |   std::ostream& printTo(std::ostream &os) const { | ||||||
|  |     StreamPrintAdapter adapter(os); | ||||||
|  |     printTo(adapter); | ||||||
|  |     return os; | ||||||
|  |   } | ||||||
|  | #endif  | ||||||
|  |  | ||||||
|   size_t printTo(char *buffer, size_t bufferSize) const { |   size_t printTo(char *buffer, size_t bufferSize) const { | ||||||
|     StringBuilder sb(buffer, bufferSize); |     StringBuilder sb(buffer, bufferSize); | ||||||
|     return printTo(sb); |     return printTo(sb); | ||||||
| @@ -61,5 +73,13 @@ class JsonPrintable { | |||||||
|  private: |  private: | ||||||
|   const T &downcast() const { return *static_cast<const T *>(this); } |   const T &downcast() const { return *static_cast<const T *>(this); } | ||||||
| }; | }; | ||||||
|  |  | ||||||
|  | #ifdef ARDUINOJSON_ENABLE_STD_STREAM | ||||||
|  | template<typename T> | ||||||
|  | inline std::ostream& operator<<(std::ostream& os, const JsonPrintable<T>& v) { | ||||||
|  |   return v.printTo(os); | ||||||
|  | } | ||||||
|  | #endif | ||||||
|  |  | ||||||
| } | } | ||||||
| } | } | ||||||
|   | |||||||
| @@ -7,7 +7,7 @@ | |||||||
| #pragma once | #pragma once | ||||||
|  |  | ||||||
| #include "../Arduino/Print.hpp" | #include "../Arduino/Print.hpp" | ||||||
| #include "QuotedString.hpp" | #include "Encoding.hpp" | ||||||
|  |  | ||||||
| namespace ArduinoJson { | namespace ArduinoJson { | ||||||
| namespace Internals { | namespace Internals { | ||||||
| @@ -26,7 +26,7 @@ class JsonWriter { | |||||||
|   // Returns the number of bytes sent to the Print implementation. |   // Returns the number of bytes sent to the Print implementation. | ||||||
|   // This is very handy for implementations of printTo() that must return the |   // This is very handy for implementations of printTo() that must return the | ||||||
|   // number of bytes written. |   // number of bytes written. | ||||||
|   size_t bytesWritten() { return _length; } |   size_t bytesWritten() const { return _length; } | ||||||
|  |  | ||||||
|   void beginArray() { write('['); } |   void beginArray() { write('['); } | ||||||
|   void endArray() { write(']'); } |   void endArray() { write(']'); } | ||||||
| @@ -37,15 +37,32 @@ class JsonWriter { | |||||||
|   void writeColon() { write(':'); } |   void writeColon() { write(':'); } | ||||||
|   void writeComma() { write(','); } |   void writeComma() { write(','); } | ||||||
|  |  | ||||||
|  |   void writeBoolean(bool value) { | ||||||
|  |     write(value ? "true" : "false"); | ||||||
|  |   } | ||||||
|  |    | ||||||
|   void writeString(const char *value) { |   void writeString(const char *value) { | ||||||
|     _length += QuotedString::printTo(value, _sink); |     if (!value) { | ||||||
|  |       write("null"); | ||||||
|  |     } else { | ||||||
|  |       write('\"'); | ||||||
|  |       while (*value) writeChar(*value++); | ||||||
|  |       write('\"'); | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   void writeChar(char c) { | ||||||
|  |     char specialChar = Encoding::escapeChar(c); | ||||||
|  |     if (specialChar) { | ||||||
|  |       write('\\'); | ||||||
|  |       write(specialChar); | ||||||
|  |     } else { | ||||||
|  |       write(c); | ||||||
|  |     } | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   void writeLong(long value) { _length += _sink.print(value); } |   void writeLong(long value) { _length += _sink.print(value); } | ||||||
|  |  | ||||||
|   void writeBoolean(bool value) { |  | ||||||
|     _length += _sink.print(value ? "true" : "false"); |  | ||||||
|   } |  | ||||||
|   void writeDouble(double value, uint8_t decimals) { |   void writeDouble(double value, uint8_t decimals) { | ||||||
|     _length += _sink.print(value, decimals); |     _length += _sink.print(value, decimals); | ||||||
|   } |   } | ||||||
|   | |||||||
| @@ -1,29 +0,0 @@ | |||||||
| // Copyright Benoit Blanchon 2014-2015 |  | ||||||
| // MIT License |  | ||||||
| // |  | ||||||
| // Arduino JSON library |  | ||||||
| // https://github.com/bblanchon/ArduinoJson |  | ||||||
|  |  | ||||||
| #pragma once |  | ||||||
|  |  | ||||||
| #include "../Arduino/Print.hpp" |  | ||||||
|  |  | ||||||
| namespace ArduinoJson { |  | ||||||
| namespace Internals { |  | ||||||
|  |  | ||||||
| // An helper class to print and extract doubly-quoted strings |  | ||||||
| class QuotedString { |  | ||||||
|  public: |  | ||||||
|   // Writes a doubly-quote string to a Print implementation. |  | ||||||
|   // It adds the double quotes (") at the beginning and the end of the string. |  | ||||||
|   // It escapes the special characters as required by the JSON specifications. |  | ||||||
|   static size_t printTo(const char *, Print &); |  | ||||||
|  |  | ||||||
|   // Reads a doubly-quoted string from a buffer. |  | ||||||
|   // It removes the double quotes ("). |  | ||||||
|   // It unescapes the special character as required by the JSON specification, |  | ||||||
|   // with the exception of the Unicode characters (\u0000). |  | ||||||
|   static char *extractFrom(char *input, char **end); |  | ||||||
| }; |  | ||||||
| } |  | ||||||
| } |  | ||||||
							
								
								
									
										34
									
								
								include/ArduinoJson/Internals/StreamPrintAdapter.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										34
									
								
								include/ArduinoJson/Internals/StreamPrintAdapter.hpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,34 @@ | |||||||
|  | // Copyright Benoit Blanchon 2014-2015 | ||||||
|  | // MIT License | ||||||
|  | // | ||||||
|  | // Arduino JSON library | ||||||
|  | // https://github.com/bblanchon/ArduinoJson | ||||||
|  |  | ||||||
|  | #pragma once | ||||||
|  |  | ||||||
|  | #ifdef ARDUINOJSON_ENABLE_STD_STREAM | ||||||
|  |  | ||||||
|  | #include "../Arduino/Print.hpp" | ||||||
|  |  | ||||||
|  | namespace ArduinoJson { | ||||||
|  | namespace Internals { | ||||||
|  |  | ||||||
|  | class StreamPrintAdapter : public Print { | ||||||
|  |  public: | ||||||
|  |   explicit StreamPrintAdapter(std::ostream& os) : _os(os) {} | ||||||
|  |  | ||||||
|  |   virtual size_t write(uint8_t c) { | ||||||
|  |     _os << static_cast<char>(c); | ||||||
|  |     return 1; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |  private: | ||||||
|  |   // cannot be assigned | ||||||
|  |   StreamPrintAdapter& operator=(const StreamPrintAdapter&); | ||||||
|  |  | ||||||
|  |   std::ostream& _os; | ||||||
|  | }; | ||||||
|  | } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | #endif // ARDUINOJSON_ENABLE_STD_STREAM | ||||||
| @@ -40,8 +40,19 @@ class JsonArraySubscript : public JsonVariantBase<JsonArraySubscript> { | |||||||
|     return _array.is<T>(_index); |     return _array.is<T>(_index); | ||||||
|   } |   } | ||||||
|  |  | ||||||
|  |   void writeTo(Internals::JsonWriter &writer) const { | ||||||
|  |     _array.get(_index).writeTo(writer); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  private: |  private: | ||||||
|   JsonArray& _array; |   JsonArray& _array; | ||||||
|   const size_t _index; |   const size_t _index; | ||||||
| }; | }; | ||||||
|  |  | ||||||
|  | #ifdef ARDUINOJSON_ENABLE_STD_STREAM | ||||||
|  | inline std::ostream& operator<<(std::ostream& os, const JsonArraySubscript& source) { | ||||||
|  |   return source.printTo(os); | ||||||
| } | } | ||||||
|  | #endif | ||||||
|  |  | ||||||
|  | } // namespace ArduinoJson | ||||||
|   | |||||||
| @@ -41,8 +41,18 @@ class JsonObjectSubscript : public JsonVariantBase<JsonObjectSubscript> { | |||||||
|     return _object.is<T>(_key); |     return _object.is<T>(_key); | ||||||
|   } |   } | ||||||
|  |  | ||||||
|  |   void writeTo(Internals::JsonWriter &writer) const { | ||||||
|  |     _object.get(_key).writeTo(writer); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  private: |  private: | ||||||
|   JsonObject& _object; |   JsonObject& _object; | ||||||
|   JsonObjectKey _key; |   JsonObjectKey _key; | ||||||
| }; | }; | ||||||
|  |  | ||||||
|  | #ifdef ARDUINOJSON_ENABLE_STD_STREAM | ||||||
|  | inline std::ostream& operator<<(std::ostream& os, const JsonObjectSubscript& source) { | ||||||
|  |   return source.printTo(os); | ||||||
|  | } | ||||||
|  | #endif | ||||||
| } | } | ||||||
|   | |||||||
| @@ -28,8 +28,7 @@ class JsonObject; | |||||||
| // - a char, short, int or a long (signed or unsigned) | // - a char, short, int or a long (signed or unsigned) | ||||||
| // - a string (const char*) | // - a string (const char*) | ||||||
| // - a reference to a JsonArray or JsonObject | // - a reference to a JsonArray or JsonObject | ||||||
| class JsonVariant : public Internals::JsonPrintable<JsonVariant>, | class JsonVariant : public JsonVariantBase<JsonVariant> { | ||||||
|                     public JsonVariantBase<JsonVariant> { |  | ||||||
|  public: |  public: | ||||||
|   // Creates an uninitialized JsonVariant |   // Creates an uninitialized JsonVariant | ||||||
|   FORCE_INLINE JsonVariant() : _type(Internals::JSON_UNDEFINED) {} |   FORCE_INLINE JsonVariant() : _type(Internals::JSON_UNDEFINED) {} | ||||||
|   | |||||||
| @@ -186,4 +186,11 @@ template <> | |||||||
| inline bool JsonVariant::is<unsigned short>() const { | inline bool JsonVariant::is<unsigned short>() const { | ||||||
|   return _type == Internals::JSON_LONG; |   return _type == Internals::JSON_LONG; | ||||||
| } | } | ||||||
|  |  | ||||||
|  | #ifdef ARDUINOJSON_ENABLE_STD_STREAM | ||||||
|  | inline std::ostream& operator<<(std::ostream& os, const JsonVariant& source) { | ||||||
|  |   return source.printTo(os); | ||||||
| } | } | ||||||
|  | #endif | ||||||
|  |  | ||||||
|  | } // namespace ArduinoJson | ||||||
|   | |||||||
| @@ -16,7 +16,7 @@ class JsonArraySubscript; | |||||||
| class JsonObjectSubscript; | class JsonObjectSubscript; | ||||||
|  |  | ||||||
| template <typename TImpl> | template <typename TImpl> | ||||||
| class JsonVariantBase { | class JsonVariantBase : public Internals::JsonPrintable<TImpl> { | ||||||
|  public: |  public: | ||||||
|   // Gets the variant as a boolean value. |   // Gets the variant as a boolean value. | ||||||
|   // Returns false if the variant is not a boolean value. |   // Returns false if the variant is not a boolean value. | ||||||
| @@ -79,6 +79,9 @@ class JsonVariantBase { | |||||||
|   FORCE_INLINE const JsonObjectSubscript operator[](const char *key) const; |   FORCE_INLINE const JsonObjectSubscript operator[](const char *key) const; | ||||||
|   FORCE_INLINE const JsonObjectSubscript operator[](const String &key) const; |   FORCE_INLINE const JsonObjectSubscript operator[](const String &key) const; | ||||||
|  |  | ||||||
|  |   // Serialize the variant to a JsonWriter | ||||||
|  |   void writeTo(Internals::JsonWriter &writer) const; | ||||||
|  |  | ||||||
|  private: |  private: | ||||||
|   const TImpl *impl() const { return static_cast<const TImpl *>(this); } |   const TImpl *impl() const { return static_cast<const TImpl *>(this); } | ||||||
| }; | }; | ||||||
|   | |||||||
							
								
								
									
										12
									
								
								src/Internals/Encoding.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								src/Internals/Encoding.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,12 @@ | |||||||
|  | // Copyright Benoit Blanchon 2014-2015 | ||||||
|  | // MIT License | ||||||
|  | // | ||||||
|  | // Arduino JSON library | ||||||
|  | // https://github.com/bblanchon/ArduinoJson | ||||||
|  |  | ||||||
|  | #include "../../include/ArduinoJson/Internals/Encoding.hpp" | ||||||
|  |  | ||||||
|  | // How to escape special chars: | ||||||
|  | // _escapeTable[2*i+1] => the special char | ||||||
|  | // _escapeTable[2*i] => the char to use instead | ||||||
|  | const char ArduinoJson::Internals::Encoding::_escapeTable[] = "\"\"\\\\b\bf\fn\nr\rt\t"; | ||||||
| @@ -9,7 +9,7 @@ | |||||||
| #include <stdlib.h>  // for strtol, strtod | #include <stdlib.h>  // for strtol, strtod | ||||||
| #include <ctype.h> | #include <ctype.h> | ||||||
|  |  | ||||||
| #include "../../include/ArduinoJson/Internals/QuotedString.hpp" | #include "../../include/ArduinoJson/Internals/Encoding.hpp" | ||||||
| #include "../../include/ArduinoJson/JsonArray.hpp" | #include "../../include/ArduinoJson/JsonArray.hpp" | ||||||
| #include "../../include/ArduinoJson/JsonBuffer.hpp" | #include "../../include/ArduinoJson/JsonBuffer.hpp" | ||||||
| #include "../../include/ArduinoJson/JsonObject.hpp" | #include "../../include/ArduinoJson/JsonObject.hpp" | ||||||
| @@ -17,25 +17,28 @@ | |||||||
| using namespace ArduinoJson; | using namespace ArduinoJson; | ||||||
| using namespace ArduinoJson::Internals; | using namespace ArduinoJson::Internals; | ||||||
|  |  | ||||||
| void JsonParser::skipSpaces() { | static const char *skipSpaces(const char *ptr) { | ||||||
|   while (isspace(*_ptr)) _ptr++; |   while (isspace(*ptr)) ptr++; | ||||||
|  |   return ptr; | ||||||
| } | } | ||||||
|  |  | ||||||
| bool JsonParser::skip(char charToSkip) { | bool JsonParser::skip(char charToSkip) { | ||||||
|   skipSpaces(); |   register const char *ptr = skipSpaces(_readPtr); | ||||||
|   if (*_ptr != charToSkip) return false; |   if (*ptr != charToSkip) return false; | ||||||
|   _ptr++; |   ptr++; | ||||||
|   skipSpaces(); |   _readPtr = skipSpaces(ptr); | ||||||
|   return true; |   return true; | ||||||
| } | } | ||||||
|  |  | ||||||
| bool JsonParser::skip(const char *wordToSkip) { | bool JsonParser::skip(const char *wordToSkip) { | ||||||
|   const char *charToSkip = wordToSkip; |   register const char *ptr = _readPtr; | ||||||
|   while (*charToSkip && *_ptr == *charToSkip) { |   while (*wordToSkip && *ptr == *wordToSkip) { | ||||||
|     charToSkip++; |     wordToSkip++; | ||||||
|     _ptr++; |     ptr++; | ||||||
|   } |   } | ||||||
|   return *charToSkip == '\0'; |   if (*wordToSkip != '\0') return false; | ||||||
|  |   _readPtr = ptr; | ||||||
|  |   return true; | ||||||
| } | } | ||||||
|  |  | ||||||
| bool JsonParser::parseAnythingTo(JsonVariant *destination) { | bool JsonParser::parseAnythingTo(JsonVariant *destination) { | ||||||
| @@ -47,9 +50,9 @@ bool JsonParser::parseAnythingTo(JsonVariant *destination) { | |||||||
| } | } | ||||||
|  |  | ||||||
| inline bool JsonParser::parseAnythingToUnsafe(JsonVariant *destination) { | inline bool JsonParser::parseAnythingToUnsafe(JsonVariant *destination) { | ||||||
|   skipSpaces(); |   _readPtr = skipSpaces(_readPtr); | ||||||
|  |  | ||||||
|   switch (*_ptr) { |   switch (*_readPtr) { | ||||||
|     case '[': |     case '[': | ||||||
|       return parseArrayTo(destination); |       return parseArrayTo(destination); | ||||||
|  |  | ||||||
| @@ -181,7 +184,7 @@ bool JsonParser::parseBooleanTo(JsonVariant *destination) { | |||||||
|  |  | ||||||
| bool JsonParser::parseNumberTo(JsonVariant *destination) { | bool JsonParser::parseNumberTo(JsonVariant *destination) { | ||||||
|   char *endOfLong; |   char *endOfLong; | ||||||
|   long longValue = strtol(_ptr, &endOfLong, 10); |   long longValue = strtol(_readPtr, &endOfLong, 10); | ||||||
|   char stopChar = *endOfLong; |   char stopChar = *endOfLong; | ||||||
|  |  | ||||||
|   // Could it be a floating point value? |   // Could it be a floating point value? | ||||||
| @@ -189,14 +192,14 @@ bool JsonParser::parseNumberTo(JsonVariant *destination) { | |||||||
|  |  | ||||||
|   if (couldBeFloat) { |   if (couldBeFloat) { | ||||||
|     // Yes => parse it as a double |     // Yes => parse it as a double | ||||||
|     double doubleValue = strtod(_ptr, &_ptr); |     double doubleValue = strtod(_readPtr, const_cast<char **>(&_readPtr)); | ||||||
|     // Count the decimal digits |     // Count the decimal digits | ||||||
|     uint8_t decimals = static_cast<uint8_t>(_ptr - endOfLong - 1); |     uint8_t decimals = static_cast<uint8_t>(_readPtr - endOfLong - 1); | ||||||
|     // Set the variant as a double |     // Set the variant as a double | ||||||
|     *destination = JsonVariant(doubleValue, decimals); |     *destination = JsonVariant(doubleValue, decimals); | ||||||
|   } else { |   } else { | ||||||
|     // No => set the variant as a long |     // No => set the variant as a long | ||||||
|     _ptr = endOfLong; |     _readPtr = endOfLong; | ||||||
|     *destination = longValue; |     *destination = longValue; | ||||||
|   } |   } | ||||||
|   return true; |   return true; | ||||||
| @@ -209,8 +212,53 @@ bool JsonParser::parseNullTo(JsonVariant *destination) { | |||||||
|   return true; |   return true; | ||||||
| } | } | ||||||
|  |  | ||||||
|  | static bool isStopChar(char c) { | ||||||
|  |   return c == '\0' || c == ':' || c == '}' || c == ']' || c == ','; | ||||||
|  | } | ||||||
|  |  | ||||||
| const char *JsonParser::parseString() { | const char *JsonParser::parseString() { | ||||||
|   return QuotedString::extractFrom(_ptr, &_ptr); |   const char *readPtr = _readPtr; | ||||||
|  |   char *writePtr = _writePtr; | ||||||
|  |  | ||||||
|  |   char c = *readPtr; | ||||||
|  |  | ||||||
|  |   if (c == '\'' || c == '\"') { | ||||||
|  |     char stopChar = c; | ||||||
|  |     for (;;) { | ||||||
|  |       c = *++readPtr; | ||||||
|  |       if (c == '\0') break; | ||||||
|  |  | ||||||
|  |       if (c == stopChar) { | ||||||
|  |         readPtr++; | ||||||
|  |         break; | ||||||
|  |       } | ||||||
|  |  | ||||||
|  |       if (c == '\\') { | ||||||
|  |         // replace char | ||||||
|  |         c = Encoding::unescapeChar(*++readPtr); | ||||||
|  |         if (c == '\0') break; | ||||||
|  |       } | ||||||
|  |  | ||||||
|  |       *writePtr++ = c; | ||||||
|  |     } | ||||||
|  |   } else { | ||||||
|  |     for (;;) { | ||||||
|  |       if (isStopChar(c)) break; | ||||||
|  |       *writePtr++ = c; | ||||||
|  |       c = *++readPtr; | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |   // end the string here | ||||||
|  |   *writePtr++ = '\0'; | ||||||
|  |  | ||||||
|  |   const char *startPtr = _writePtr; | ||||||
|  |  | ||||||
|  |   // update end ptr | ||||||
|  |   _readPtr = readPtr; | ||||||
|  |   _writePtr = writePtr; | ||||||
|  |  | ||||||
|  |   // return pointer to unquoted string | ||||||
|  |   return startPtr; | ||||||
| } | } | ||||||
|  |  | ||||||
| bool JsonParser::parseStringTo(JsonVariant *destination) { | bool JsonParser::parseStringTo(JsonVariant *destination) { | ||||||
|   | |||||||
| @@ -1,103 +0,0 @@ | |||||||
| // Copyright Benoit Blanchon 2014-2015 |  | ||||||
| // MIT License |  | ||||||
| // |  | ||||||
| // Arduino JSON library |  | ||||||
| // https://github.com/bblanchon/ArduinoJson |  | ||||||
|  |  | ||||||
| #include "../../include/ArduinoJson/Internals/QuotedString.hpp" |  | ||||||
|  |  | ||||||
| using namespace ArduinoJson::Internals; |  | ||||||
|  |  | ||||||
| // How to escape special chars: |  | ||||||
| // specialChars[2*i+1] => the special char |  | ||||||
| // specialChars[2*i] => the char to use instead |  | ||||||
| static const char specialChars[] = "\"\"\\\\b\bf\fn\nr\rt\t"; |  | ||||||
|  |  | ||||||
| static inline char getSpecialChar(char c) { |  | ||||||
|   // Optimized for code size on a 8-bit AVR |  | ||||||
|  |  | ||||||
|   const char *p = specialChars; |  | ||||||
|  |  | ||||||
|   while (p[0] && p[1] != c) { |  | ||||||
|     p += 2; |  | ||||||
|   } |  | ||||||
|  |  | ||||||
|   return p[0]; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| static inline size_t printCharTo(char c, Print &p) { |  | ||||||
|   char specialChar = getSpecialChar(c); |  | ||||||
|  |  | ||||||
|   return specialChar ? p.write('\\') + p.write(specialChar) : p.write(c); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| size_t QuotedString::printTo(const char *s, Print &p) { |  | ||||||
|   if (!s) return p.print("null"); |  | ||||||
|  |  | ||||||
|   size_t n = p.write('\"'); |  | ||||||
|  |  | ||||||
|   while (*s) { |  | ||||||
|     n += printCharTo(*s++, p); |  | ||||||
|   } |  | ||||||
|  |  | ||||||
|   return n + p.write('\"'); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| static char unescapeChar(char c) { |  | ||||||
|   // Optimized for code size on a 8-bit AVR |  | ||||||
|  |  | ||||||
|   const char *p = specialChars + 4; |  | ||||||
|  |  | ||||||
|   for (;;) { |  | ||||||
|     if (p[0] == '\0') return c; |  | ||||||
|     if (p[0] == c) return p[1]; |  | ||||||
|     p += 2; |  | ||||||
|   } |  | ||||||
| } |  | ||||||
|  |  | ||||||
| static inline bool isQuote(char c) { return c == '\"' || c == '\''; } |  | ||||||
|  |  | ||||||
| char *QuotedString::extractFrom(char *input, char **endPtr) { |  | ||||||
|   char firstChar = *input; |  | ||||||
|  |  | ||||||
|   if (!isQuote(firstChar)) { |  | ||||||
|     // must start with a quote |  | ||||||
|     return NULL; |  | ||||||
|   } |  | ||||||
|  |  | ||||||
|   char stopChar = firstChar;  // closing quote is the same as opening quote |  | ||||||
|  |  | ||||||
|   char *startPtr = input + 1;  // skip the quote |  | ||||||
|   char *readPtr = startPtr; |  | ||||||
|   char *writePtr = startPtr; |  | ||||||
|   char c; |  | ||||||
|  |  | ||||||
|   for (;;) { |  | ||||||
|     c = *readPtr++; |  | ||||||
|  |  | ||||||
|     if (c == '\0') { |  | ||||||
|       // premature ending |  | ||||||
|       return NULL; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     if (c == stopChar) { |  | ||||||
|       // closing quote |  | ||||||
|       break; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     if (c == '\\') { |  | ||||||
|       // replace char |  | ||||||
|       c = unescapeChar(*readPtr++); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     *writePtr++ = c; |  | ||||||
|   } |  | ||||||
|  |  | ||||||
|   // end the string here |  | ||||||
|   *writePtr = '\0'; |  | ||||||
|  |  | ||||||
|   // update end ptr |  | ||||||
|   *endPtr = readPtr; |  | ||||||
|  |  | ||||||
|   return startPtr; |  | ||||||
| } |  | ||||||
| @@ -5,8 +5,8 @@ | |||||||
| // https://github.com/bblanchon/ArduinoJson | // https://github.com/bblanchon/ArduinoJson | ||||||
|  |  | ||||||
| #include <gtest/gtest.h> | #include <gtest/gtest.h> | ||||||
|  | #define ARDUINOJSON_ENABLE_STD_STREAM | ||||||
| #include <ArduinoJson.h> | #include <ArduinoJson.h> | ||||||
| #include "Printers.hpp" |  | ||||||
|  |  | ||||||
| class GbathreeBug : public testing::Test { | class GbathreeBug : public testing::Test { | ||||||
|  public: |  public: | ||||||
|   | |||||||
| @@ -5,8 +5,8 @@ | |||||||
| // https://github.com/bblanchon/ArduinoJson | // https://github.com/bblanchon/ArduinoJson | ||||||
|  |  | ||||||
| #include <gtest/gtest.h> | #include <gtest/gtest.h> | ||||||
|  | #define ARDUINOJSON_ENABLE_STD_STREAM | ||||||
| #include <ArduinoJson.h> | #include <ArduinoJson.h> | ||||||
| #include "Printers.hpp" |  | ||||||
|  |  | ||||||
| class JsonObject_Iterator_Test : public testing::Test { | class JsonObject_Iterator_Test : public testing::Test { | ||||||
|  public: |  public: | ||||||
|   | |||||||
| @@ -9,14 +9,19 @@ | |||||||
|  |  | ||||||
| class JsonParser_Array_Tests : public testing::Test { | class JsonParser_Array_Tests : public testing::Test { | ||||||
|  protected: |  protected: | ||||||
|   void whenInputIs(const char *json) { |   void whenInputIs(const char *json) { strcpy(_jsonString, json); } | ||||||
|     strcpy(_jsonString, json); |  | ||||||
|     _array = &_jsonBuffer.parseArray(_jsonString); |   void whenInputIs(const char *json, size_t len) { | ||||||
|  |     memcpy(_jsonString, json, len); | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   void parseMustSucceed() { EXPECT_TRUE(_array->success()); } |   void parseMustSucceed() { | ||||||
|  |     _array = &_jsonBuffer.parseArray(_jsonString); | ||||||
|  |     EXPECT_TRUE(_array->success()); | ||||||
|  |   } | ||||||
|  |  | ||||||
|   void parseMustFail() { |   void parseMustFail() { | ||||||
|  |     _array = &_jsonBuffer.parseArray(_jsonString); | ||||||
|     EXPECT_FALSE(_array->success()); |     EXPECT_FALSE(_array->success()); | ||||||
|     EXPECT_EQ(0, _array->size()); |     EXPECT_EQ(0, _array->size()); | ||||||
|   } |   } | ||||||
| @@ -154,6 +159,11 @@ TEST_F(JsonParser_Array_Tests, IncompleteFalse) { | |||||||
|   parseMustFail(); |   parseMustFail(); | ||||||
| } | } | ||||||
|  |  | ||||||
|  | TEST_F(JsonParser_Array_Tests, MixedTrueFalse) { | ||||||
|  |   whenInputIs("[trufalse]"); | ||||||
|  |   parseMustFail(); | ||||||
|  | } | ||||||
|  |  | ||||||
| TEST_F(JsonParser_Array_Tests, TwoStrings) { | TEST_F(JsonParser_Array_Tests, TwoStrings) { | ||||||
|   whenInputIs("[\"hello\",\"world\"]"); |   whenInputIs("[\"hello\",\"world\"]"); | ||||||
|  |  | ||||||
| @@ -162,3 +172,55 @@ TEST_F(JsonParser_Array_Tests, TwoStrings) { | |||||||
|   firstElementMustBe("hello"); |   firstElementMustBe("hello"); | ||||||
|   secondElementMustBe("world"); |   secondElementMustBe("world"); | ||||||
| } | } | ||||||
|  |  | ||||||
|  | TEST_F(JsonParser_Array_Tests, EmptyStringsDoubleQuotes) { | ||||||
|  |   whenInputIs("[\"\",\"\"]"); | ||||||
|  |  | ||||||
|  |   parseMustSucceed(); | ||||||
|  |   sizeMustBe(2); | ||||||
|  |   firstElementMustBe(""); | ||||||
|  |   secondElementMustBe(""); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | TEST_F(JsonParser_Array_Tests, EmptyStringSingleQuotes) { | ||||||
|  |   whenInputIs("[\'\',\'\']"); | ||||||
|  |  | ||||||
|  |   parseMustSucceed(); | ||||||
|  |   sizeMustBe(2); | ||||||
|  |   firstElementMustBe(""); | ||||||
|  |   secondElementMustBe(""); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | TEST_F(JsonParser_Array_Tests, EmptyStringNoQuotes) { | ||||||
|  |   whenInputIs("[,]"); | ||||||
|  |  | ||||||
|  |   parseMustSucceed(); | ||||||
|  |   sizeMustBe(2); | ||||||
|  |   firstElementMustBe(""); | ||||||
|  |   secondElementMustBe(""); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | TEST_F(JsonParser_Array_Tests, ClosingDoubleQuoteMissing) { | ||||||
|  |   whenInputIs("[\"]"); | ||||||
|  |  | ||||||
|  |   parseMustFail(); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | TEST_F(JsonParser_Array_Tests, ClosingSignleQuoteMissing) { | ||||||
|  |   whenInputIs("[\']"); | ||||||
|  |  | ||||||
|  |   parseMustFail(); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | TEST_F(JsonParser_Array_Tests, StringWithEscapedChars) { | ||||||
|  |   whenInputIs("[\"1\\\"2\\\\3\\/4\\b5\\f6\\n7\\r8\\t9\"]"); | ||||||
|  |  | ||||||
|  |   parseMustSucceed(); | ||||||
|  |   sizeMustBe(1); | ||||||
|  |   firstElementMustBe("1\"2\\3/4\b5\f6\n7\r8\t9"); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | TEST_F(JsonParser_Array_Tests, StringWithUnterminatedEscapeSequence) { | ||||||
|  |   whenInputIs("\"\\\0\"", 4); | ||||||
|  |   parseMustFail(); | ||||||
|  | } | ||||||
|   | |||||||
| @@ -75,6 +75,13 @@ TEST_F(JsonParser_Object_Test, OneStringSingleQuotes) { | |||||||
|   keyMustHaveValue("key", "value"); |   keyMustHaveValue("key", "value"); | ||||||
| } | } | ||||||
|  |  | ||||||
|  | TEST_F(JsonParser_Object_Test, OneStringNoQuotes) { | ||||||
|  |   whenInputIs("{key:value}"); | ||||||
|  |   parseMustSucceed(); | ||||||
|  |   sizeMustBe(1); | ||||||
|  |   keyMustHaveValue("key", "value"); | ||||||
|  | } | ||||||
|  |  | ||||||
| TEST_F(JsonParser_Object_Test, OneStringSpaceBeforeKey) { | TEST_F(JsonParser_Object_Test, OneStringSpaceBeforeKey) { | ||||||
|   whenInputIs("{ \"key\":\"value\"}"); |   whenInputIs("{ \"key\":\"value\"}"); | ||||||
|   parseMustSucceed(); |   parseMustSucceed(); | ||||||
|   | |||||||
| @@ -5,8 +5,8 @@ | |||||||
| // https://github.com/bblanchon/ArduinoJson | // https://github.com/bblanchon/ArduinoJson | ||||||
|  |  | ||||||
| #include <gtest/gtest.h> | #include <gtest/gtest.h> | ||||||
|  | #define ARDUINOJSON_ENABLE_STD_STREAM | ||||||
| #include <ArduinoJson/JsonVariant.hpp> | #include <ArduinoJson/JsonVariant.hpp> | ||||||
| #include "Printers.hpp" |  | ||||||
|  |  | ||||||
| using namespace ArduinoJson; | using namespace ArduinoJson; | ||||||
|  |  | ||||||
|   | |||||||
| @@ -5,8 +5,8 @@ | |||||||
| // https://github.com/bblanchon/ArduinoJson | // https://github.com/bblanchon/ArduinoJson | ||||||
|  |  | ||||||
| #include <gtest/gtest.h> | #include <gtest/gtest.h> | ||||||
|  | #define ARDUINOJSON_ENABLE_STD_STREAM | ||||||
| #include <ArduinoJson.h> | #include <ArduinoJson.h> | ||||||
| #include "Printers.hpp" |  | ||||||
|  |  | ||||||
| class JsonVariant_Undefined_Tests : public ::testing::Test { | class JsonVariant_Undefined_Tests : public ::testing::Test { | ||||||
|  protected: |  protected: | ||||||
|   | |||||||
| @@ -6,16 +6,18 @@ | |||||||
| 
 | 
 | ||||||
| #include <gtest/gtest.h> | #include <gtest/gtest.h> | ||||||
| 
 | 
 | ||||||
| #include <ArduinoJson/Internals/QuotedString.hpp> | #include <ArduinoJson/Internals/JsonWriter.hpp> | ||||||
| #include <ArduinoJson/Internals/StringBuilder.hpp> | #include <ArduinoJson/Internals/StringBuilder.hpp> | ||||||
| 
 | 
 | ||||||
| using namespace ArduinoJson::Internals; | using namespace ArduinoJson::Internals; | ||||||
| 
 | 
 | ||||||
| class QuotedString_PrintTo_Tests : public testing::Test { | class JsonWriter_WriteString_Tests : public testing::Test { | ||||||
|  protected: |  protected: | ||||||
|   void whenInputIs(const char *input) { |   void whenInputIs(const char *input) { | ||||||
|     StringBuilder sb(buffer, sizeof(buffer)); |     StringBuilder sb(buffer, sizeof(buffer)); | ||||||
|     returnValue = QuotedString::printTo(input, sb); |     JsonWriter writer(sb); | ||||||
|  |     writer.writeString(input); | ||||||
|  |     returnValue = writer.bytesWritten(); | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   void outputMustBe(const char *expected) { |   void outputMustBe(const char *expected) { | ||||||
| @@ -28,52 +30,52 @@ class QuotedString_PrintTo_Tests : public testing::Test { | |||||||
|   size_t returnValue; |   size_t returnValue; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| TEST_F(QuotedString_PrintTo_Tests, Null) { | TEST_F(JsonWriter_WriteString_Tests, Null) { | ||||||
|   whenInputIs(0); |   whenInputIs(0); | ||||||
|   outputMustBe("null"); |   outputMustBe("null"); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| TEST_F(QuotedString_PrintTo_Tests, EmptyString) { | TEST_F(JsonWriter_WriteString_Tests, EmptyString) { | ||||||
|   whenInputIs(""); |   whenInputIs(""); | ||||||
|   outputMustBe("\"\""); |   outputMustBe("\"\""); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| TEST_F(QuotedString_PrintTo_Tests, QuotationMark) { | TEST_F(JsonWriter_WriteString_Tests, QuotationMark) { | ||||||
|   whenInputIs("\""); |   whenInputIs("\""); | ||||||
|   outputMustBe("\"\\\"\""); |   outputMustBe("\"\\\"\""); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| TEST_F(QuotedString_PrintTo_Tests, ReverseSolidus) { | TEST_F(JsonWriter_WriteString_Tests, ReverseSolidus) { | ||||||
|   whenInputIs("\\"); |   whenInputIs("\\"); | ||||||
|   outputMustBe("\"\\\\\""); |   outputMustBe("\"\\\\\""); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| TEST_F(QuotedString_PrintTo_Tests, Solidus) { | TEST_F(JsonWriter_WriteString_Tests, Solidus) { | ||||||
|   whenInputIs("/"); |   whenInputIs("/"); | ||||||
|   outputMustBe("\"/\"");  // but the JSON format allows \/
 |   outputMustBe("\"/\"");  // but the JSON format allows \/
 | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| TEST_F(QuotedString_PrintTo_Tests, Backspace) { | TEST_F(JsonWriter_WriteString_Tests, Backspace) { | ||||||
|   whenInputIs("\b"); |   whenInputIs("\b"); | ||||||
|   outputMustBe("\"\\b\""); |   outputMustBe("\"\\b\""); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| TEST_F(QuotedString_PrintTo_Tests, Formfeed) { | TEST_F(JsonWriter_WriteString_Tests, Formfeed) { | ||||||
|   whenInputIs("\f"); |   whenInputIs("\f"); | ||||||
|   outputMustBe("\"\\f\""); |   outputMustBe("\"\\f\""); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| TEST_F(QuotedString_PrintTo_Tests, Newline) { | TEST_F(JsonWriter_WriteString_Tests, Newline) { | ||||||
|   whenInputIs("\n"); |   whenInputIs("\n"); | ||||||
|   outputMustBe("\"\\n\""); |   outputMustBe("\"\\n\""); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| TEST_F(QuotedString_PrintTo_Tests, CarriageReturn) { | TEST_F(JsonWriter_WriteString_Tests, CarriageReturn) { | ||||||
|   whenInputIs("\r"); |   whenInputIs("\r"); | ||||||
|   outputMustBe("\"\\r\""); |   outputMustBe("\"\\r\""); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| TEST_F(QuotedString_PrintTo_Tests, HorizontalTab) { | TEST_F(JsonWriter_WriteString_Tests, HorizontalTab) { | ||||||
|   whenInputIs("\t"); |   whenInputIs("\t"); | ||||||
|   outputMustBe("\"\\t\""); |   outputMustBe("\"\\t\""); | ||||||
| } | } | ||||||
| @@ -1,50 +0,0 @@ | |||||||
| // Copyright Benoit Blanchon 2014-2015 |  | ||||||
| // MIT License |  | ||||||
| // |  | ||||||
| // Arduino JSON library |  | ||||||
| // https://github.com/bblanchon/ArduinoJson |  | ||||||
|  |  | ||||||
| #include "Printers.hpp" |  | ||||||
| #include <ArduinoJson/JsonArray.hpp> |  | ||||||
|  |  | ||||||
| class StreamPrintAdapter : public Print { |  | ||||||
|  public: |  | ||||||
|   explicit StreamPrintAdapter(std::ostream& os) : _os(os) {} |  | ||||||
|  |  | ||||||
|   virtual size_t write(uint8_t c) { |  | ||||||
|     _os << static_cast<char>(c); |  | ||||||
|     return 1; |  | ||||||
|   } |  | ||||||
|  |  | ||||||
|  private: |  | ||||||
|   // cannot be assigned |  | ||||||
|   StreamPrintAdapter& operator=(const StreamPrintAdapter&); |  | ||||||
|  |  | ||||||
|   std::ostream& _os; |  | ||||||
| }; |  | ||||||
|  |  | ||||||
| std::ostream& ArduinoJson::operator<<(std::ostream& os, |  | ||||||
|                                       const ArduinoJson::JsonVariant& v) { |  | ||||||
|   StreamPrintAdapter adapter(os); |  | ||||||
|   v.printTo(adapter); |  | ||||||
|   return os; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| std::ostream& ArduinoJson::operator<<(std::ostream& os, |  | ||||||
|                                       const ArduinoJson::JsonArray& v) { |  | ||||||
|   StreamPrintAdapter adapter(os); |  | ||||||
|   v.printTo(adapter); |  | ||||||
|   return os; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| std::ostream& ArduinoJson::operator<<( |  | ||||||
|     std::ostream& os, const ArduinoJson::JsonObjectSubscript& v) { |  | ||||||
|   JsonVariant value = v; |  | ||||||
|   return os << value; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| std::ostream& ArduinoJson::operator<<( |  | ||||||
|     std::ostream& os, const ArduinoJson::JsonArraySubscript& v) { |  | ||||||
|   JsonVariant value = v; |  | ||||||
|   return os << value; |  | ||||||
| } |  | ||||||
| @@ -1,17 +0,0 @@ | |||||||
| // Copyright Benoit Blanchon 2014-2015 |  | ||||||
| // MIT License |  | ||||||
| // |  | ||||||
| // Arduino JSON library |  | ||||||
| // https://github.com/bblanchon/ArduinoJson |  | ||||||
|  |  | ||||||
| #pragma once |  | ||||||
|  |  | ||||||
| #include <ArduinoJson.h> |  | ||||||
| #include <ostream> |  | ||||||
|  |  | ||||||
| namespace ArduinoJson { |  | ||||||
| std::ostream& operator<<(std::ostream& os, const JsonVariant& v); |  | ||||||
| std::ostream& operator<<(std::ostream& os, const JsonArray& v); |  | ||||||
| std::ostream& operator<<(std::ostream& os, const JsonObjectSubscript& v); |  | ||||||
| std::ostream& operator<<(std::ostream& os, const JsonArraySubscript& v); |  | ||||||
| } |  | ||||||
| @@ -1,136 +0,0 @@ | |||||||
| // Copyright Benoit Blanchon 2014-2015 |  | ||||||
| // MIT License |  | ||||||
| // |  | ||||||
| // Arduino JSON library |  | ||||||
| // https://github.com/bblanchon/ArduinoJson |  | ||||||
|  |  | ||||||
| #include <gtest/gtest.h> |  | ||||||
| #include <ArduinoJson/Internals/QuotedString.hpp> |  | ||||||
|  |  | ||||||
| using namespace ArduinoJson::Internals; |  | ||||||
|  |  | ||||||
| class QuotedString_ExtractFrom_Tests : public testing::Test { |  | ||||||
|  protected: |  | ||||||
|   void whenInputIs(const char *json) { |  | ||||||
|     strcpy(_jsonString, json); |  | ||||||
|     _result = QuotedString::extractFrom(_jsonString, &_trailing); |  | ||||||
|   } |  | ||||||
|  |  | ||||||
|   void resultMustBe(const char *expected) { EXPECT_STREQ(expected, _result); } |  | ||||||
|  |  | ||||||
|   void trailingMustBe(const char *expected) { |  | ||||||
|     EXPECT_STREQ(expected, _trailing); |  | ||||||
|   } |  | ||||||
|  |  | ||||||
|  private: |  | ||||||
|   char _jsonString[256]; |  | ||||||
|   char *_result; |  | ||||||
|   char *_trailing; |  | ||||||
| }; |  | ||||||
|  |  | ||||||
| TEST_F(QuotedString_ExtractFrom_Tests, EmptyDoubleQuotedString) { |  | ||||||
|   whenInputIs("\"\""); |  | ||||||
|  |  | ||||||
|   resultMustBe(""); |  | ||||||
|   trailingMustBe(""); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| TEST_F(QuotedString_ExtractFrom_Tests, NoQuotes) { |  | ||||||
|   whenInputIs("hello world"); |  | ||||||
|  |  | ||||||
|   resultMustBe(0); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| TEST_F(QuotedString_ExtractFrom_Tests, MissingClosingQuote) { |  | ||||||
|   whenInputIs("\"hello world"); |  | ||||||
|  |  | ||||||
|   resultMustBe(0); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| TEST_F(QuotedString_ExtractFrom_Tests, EmptySingleQuotedString) { |  | ||||||
|   whenInputIs("''"); |  | ||||||
|  |  | ||||||
|   resultMustBe(""); |  | ||||||
|   trailingMustBe(""); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| TEST_F(QuotedString_ExtractFrom_Tests, SimpleDoubleQuotedString) { |  | ||||||
|   whenInputIs("\"hello world\""); |  | ||||||
|  |  | ||||||
|   resultMustBe("hello world"); |  | ||||||
|   trailingMustBe(""); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| TEST_F(QuotedString_ExtractFrom_Tests, DoubleQuotedStringWithTrailing) { |  | ||||||
|   whenInputIs("\"hello\" world"); |  | ||||||
|  |  | ||||||
|   resultMustBe("hello"); |  | ||||||
|   trailingMustBe(" world"); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| TEST_F(QuotedString_ExtractFrom_Tests, SingleQuotedStringWithTrailing) { |  | ||||||
|   whenInputIs("'hello' world"); |  | ||||||
|  |  | ||||||
|   resultMustBe("hello"); |  | ||||||
|   trailingMustBe(" world"); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| TEST_F(QuotedString_ExtractFrom_Tests, CurlyBraces) { |  | ||||||
|   whenInputIs("\"{hello:world}\""); |  | ||||||
|   resultMustBe("{hello:world}"); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| TEST_F(QuotedString_ExtractFrom_Tests, SquareBraquets) { |  | ||||||
|   whenInputIs("\"[hello,world]\""); |  | ||||||
|   resultMustBe("[hello,world]"); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| TEST_F(QuotedString_ExtractFrom_Tests, EscapedDoubleQuote) { |  | ||||||
|   whenInputIs("\"hello \\\"world\\\"\""); |  | ||||||
|   resultMustBe("hello \"world\""); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| TEST_F(QuotedString_ExtractFrom_Tests, EscapedSingleQuote) { |  | ||||||
|   whenInputIs("\"hello \\\'world\\\'\""); |  | ||||||
|   resultMustBe("hello 'world'"); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| TEST_F(QuotedString_ExtractFrom_Tests, EscapedSolidus) { |  | ||||||
|   whenInputIs("\"hello \\/world\\/\""); |  | ||||||
|   resultMustBe("hello /world/"); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| TEST_F(QuotedString_ExtractFrom_Tests, EscapedReverseSolidus) { |  | ||||||
|   whenInputIs("\"hello \\\\world\\\\\""); |  | ||||||
|   resultMustBe("hello \\world\\"); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| TEST_F(QuotedString_ExtractFrom_Tests, EscapedBackspace) { |  | ||||||
|   whenInputIs("\"hello \\bworld\\b\""); |  | ||||||
|   resultMustBe("hello \bworld\b"); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| TEST_F(QuotedString_ExtractFrom_Tests, EscapedFormfeed) { |  | ||||||
|   whenInputIs("\"hello \\fworld\\f\""); |  | ||||||
|   resultMustBe("hello \fworld\f"); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| TEST_F(QuotedString_ExtractFrom_Tests, EscapedNewline) { |  | ||||||
|   whenInputIs("\"hello \\nworld\\n\""); |  | ||||||
|   resultMustBe("hello \nworld\n"); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| TEST_F(QuotedString_ExtractFrom_Tests, EscapedCarriageReturn) { |  | ||||||
|   whenInputIs("\"hello \\rworld\\r\""); |  | ||||||
|   resultMustBe("hello \rworld\r"); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| TEST_F(QuotedString_ExtractFrom_Tests, EscapedTab) { |  | ||||||
|   whenInputIs("\"hello \\tworld\\t\""); |  | ||||||
|   resultMustBe("hello \tworld\t"); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| TEST_F(QuotedString_ExtractFrom_Tests, AllEscapedCharsTogether) { |  | ||||||
|   whenInputIs("\"1\\\"2\\\\3\\/4\\b5\\f6\\n7\\r8\\t9\""); |  | ||||||
|   resultMustBe("1\"2\\3/4\b5\f6\n7\r8\t9"); |  | ||||||
| } |  | ||||||
							
								
								
									
										62
									
								
								test/StdStream.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										62
									
								
								test/StdStream.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,62 @@ | |||||||
|  | // Copyright Benoit Blanchon 2014-2015 | ||||||
|  | // MIT License | ||||||
|  | // | ||||||
|  | // Arduino JSON library | ||||||
|  | // https://github.com/bblanchon/ArduinoJson | ||||||
|  |  | ||||||
|  | #include <sstream> | ||||||
|  | #include <gtest/gtest.h> | ||||||
|  | #define ARDUINOJSON_ENABLE_STD_STREAM | ||||||
|  | #include <ArduinoJson.h> | ||||||
|  |  | ||||||
|  | TEST(StdStream, JsonVariantFalse) {  | ||||||
|  |   std::ostringstream os; | ||||||
|  |   JsonVariant variant = false; | ||||||
|  |   os << variant; | ||||||
|  |   ASSERT_EQ("false", os.str()); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | TEST(StdStream, JsonVariantString) {  | ||||||
|  |   std::ostringstream os; | ||||||
|  |   JsonVariant variant = "coucou"; | ||||||
|  |   os << variant; | ||||||
|  |   ASSERT_EQ("\"coucou\"", os.str()); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | TEST(StdStream, JsonObject) {  | ||||||
|  |   std::ostringstream os; | ||||||
|  |   DynamicJsonBuffer jsonBuffer; | ||||||
|  |   JsonObject& object = jsonBuffer.createObject(); | ||||||
|  |   object["key"] = "value"; | ||||||
|  |   os << object; | ||||||
|  |   ASSERT_EQ("{\"key\":\"value\"}", os.str()); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | TEST(StdStream, JsonObjectSubscript) {  | ||||||
|  |   std::ostringstream os; | ||||||
|  |   DynamicJsonBuffer jsonBuffer; | ||||||
|  |   JsonObject& object = jsonBuffer.createObject(); | ||||||
|  |   object["key"] = "value"; | ||||||
|  |   os << object["key"]; | ||||||
|  |   ASSERT_EQ("\"value\"", os.str()); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | TEST(StdStream, JsonArray) {  | ||||||
|  |   std::ostringstream os; | ||||||
|  |   DynamicJsonBuffer jsonBuffer; | ||||||
|  |   JsonArray& array = jsonBuffer.createArray(); | ||||||
|  |   array.add("value"); | ||||||
|  |   os << array; | ||||||
|  |   ASSERT_EQ("[\"value\"]", os.str()); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | TEST(StdStream, JsonArraySubscript) {  | ||||||
|  |   std::ostringstream os; | ||||||
|  |   DynamicJsonBuffer jsonBuffer; | ||||||
|  |   JsonArray& array = jsonBuffer.createArray(); | ||||||
|  |   array.add("value"); | ||||||
|  |   os << array[0]; | ||||||
|  |   ASSERT_EQ("\"value\"", os.str()); | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
		Reference in New Issue
	
	Block a user