diff --git a/include/ArduinoJson/Internals/EscapedString.h b/include/ArduinoJson/Internals/EscapedString.h index ea099141..311f7398 100644 --- a/include/ArduinoJson/Internals/EscapedString.h +++ b/include/ArduinoJson/Internals/EscapedString.h @@ -15,6 +15,8 @@ namespace ArduinoJson { public: static size_t printTo(const char*, Print*); + + static char* extractFrom(char* input, char** end); }; } } \ No newline at end of file diff --git a/src/Internals/EscapedString.cpp b/src/Internals/EscapedString.cpp index ad150385..0d3692e4 100644 --- a/src/Internals/EscapedString.cpp +++ b/src/Internals/EscapedString.cpp @@ -42,4 +42,47 @@ size_t EscapedString::printTo(const char* s, Print* p) } return n + p->write('\"'); +} + +static char unescapeChar(char c) +{ + // Optimized for code size on a 8-bit AVR + + const char* p = "b\bf\fn\nr\rt\t"; + + while (true) + { + if (p[0] == 0) return c; + if (p[0] == c) return p[1]; + p += 2; + } +} + +char* EscapedString::extractFrom(char* input, char** end) +{ + char* start = input + 1; // skip quote + char* readPtr = start; + char* writePtr = start; + char c; + + do + { + c = *readPtr++; + + if (c == '\"') + break; + + if (c == '\\') + { + c = unescapeChar(*readPtr++); + } + + *writePtr++ = c; + } while (c != 0); + + *writePtr = 0; + + *end = readPtr; + + return start; } \ No newline at end of file diff --git a/src/Internals/JsonParser.cpp b/src/Internals/JsonParser.cpp index 04e360c7..7953955b 100644 --- a/src/Internals/JsonParser.cpp +++ b/src/Internals/JsonParser.cpp @@ -1,8 +1,13 @@ #include "ArduinoJson/Internals/JsonParser.h" -#include "ArduinoJson/JsonBuffer.h" + #include // for strtol, strtod #include +#include "ArduinoJson/JsonBuffer.h" +#include "ArduinoJson/Internals/EscapedString.h" + +using namespace ArduinoJson::Internals; + bool JsonParser::isArrayStart() { return *_ptr == '['; @@ -179,12 +184,6 @@ JsonNode* JsonParser::parseNull() JsonNode* JsonParser::parseString() { - const char* s = ++_ptr; - - while (*_ptr != '\"') - _ptr++; - *_ptr = 0; - _ptr++; - + const char* s = EscapedString::extractFrom(_ptr, &_ptr); return _buffer->createStringNode(s); } diff --git a/test/JsonParser_String_Tests.cpp b/test/JsonParser_String_Tests.cpp index 834a4525..81000d3e 100644 --- a/test/JsonParser_String_Tests.cpp +++ b/test/JsonParser_String_Tests.cpp @@ -21,6 +21,13 @@ protected: const char* _result; }; + +TEST_F(JsonParser_String_Tests, EmptyString) +{ + whenInputIs("\"\""); + outputMustBe(""); +} + TEST_F(JsonParser_String_Tests, SimpleString) { whenInputIs("\"hello world\""); @@ -39,8 +46,14 @@ TEST_F(JsonParser_String_Tests, SquareBraquets) outputMustBe("[hello,world]"); } -TEST_F(JsonParser_String_Tests, EscapedQuote) +TEST_F(JsonParser_String_Tests, EscapedDoubleQuote) { whenInputIs("\"hello \\\"world\\\"\""); outputMustBe("hello \"world\""); +} + +TEST_F(JsonParser_String_Tests, EscapedSingleQuote) +{ + whenInputIs("\"hello \\\'world\\\'\""); + outputMustBe("hello 'world'"); } \ No newline at end of file