Просмотр исходного кода

Merge branch 'parse-escaped-chars'

Benoit Blanchon 11 лет назад
Родитель
Сommit
a1b6c2df75

+ 9 - 3
CHANGELOG.md

@@ -1,10 +1,16 @@
 Arduino JSON: change log
 ========================
 
+v3.4
+----
+
+* Fixed escaped char parsing (issue #16)
+  
+
 v3.3
 ----
 
-* Added indented output for the JSON generator, see example bellow.
+* Added indented output for the JSON generator (issue #11), see example bellow.
 * Added `IndentedPrint`, a decorator for `Print` to allow indented output
 
 Example:
@@ -23,7 +29,7 @@ v3.1
 
 * Calling `Generator::JsonObject::add()` twice with the same `key` now replaces the `value`
 * Added `Generator::JsonObject::operator[]`, see bellow the new API
-* Added `Generator::JsonObject::remove()`
+* Added `Generator::JsonObject::remove()` (issue #9)
 
 Old generator API:
 
@@ -44,7 +50,7 @@ v3.0
 
 * New parser API, see bellow
 * Renamed `JsonHashTable` into `JsonObject`
-* Added iterators for `JsonArray` and `JsonObject`
+* Added iterators for `JsonArray` and `JsonObject` (issue #4)
 
 Old parser API:
 

+ 44 - 0
JsonParser/JsonToken.cpp

@@ -7,6 +7,50 @@
 
 using namespace ArduinoJson::Parser;
 
+char* JsonToken::getText()
+{
+    char* s = json + token->start;
+    json[token->end] = 0;
+
+    unescapeString(s);
+
+    return s;
+}
+
+inline void JsonToken::unescapeString(char* s)
+{
+    char* readPtr = s;
+    char* writePtr = s;
+    char c;
+
+    do
+    {
+        c = *readPtr++;
+
+        if (c == '\\')
+        {
+            c = unescapeChar(*readPtr++);
+        }
+
+        *writePtr++ = c;
+
+    } while (c != 0);
+}
+
+inline char JsonToken::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;
+    }
+}
+
 JsonToken JsonToken::nextSibling() const
 {
     // start with current token

+ 4 - 5
JsonParser/JsonToken.h

@@ -29,11 +29,7 @@ namespace ArduinoJson
             }
 
             // Get content of the JSON token
-            char* getText()
-            {
-                json[token->end] = 0;
-                return json + token->start;
-            }
+            char* getText();
 
             // Get the number of children tokens
             int childrenCount()
@@ -95,6 +91,9 @@ namespace ArduinoJson
         private:
             char* json;
             jsmntok_t* token;
+            
+            static char unescapeChar(char c);
+            static void unescapeString(char* s);
         };
     }
 }

+ 19 - 25
JsonParserTests/JsonArrayTests.cpp

@@ -11,33 +11,27 @@ using namespace ArduinoJson::Parser;
 
 namespace ArduinoJsonParserTests
 {
-	TEST_CLASS(JsonArrayTests)
-	{
+    TEST_CLASS(JsonArrayTests)
+    {
         JsonArray array;
         char json[256];
         jsmntok_t tokens[32];
         JsonParserBase parser = JsonParserBase(tokens, 32);
 
-	public:
-		
-		TEST_METHOD(EmptyString)
-		{
-            whenInputIs("");
-            parseMustFail();             
-		}
-
-		TEST_METHOD(TooFewClosingBrackets)
-		{
+    public:
+        
+        TEST_METHOD(TooFewClosingBrackets)
+        {
             whenInputIs("[[]");
             parseMustFail();
-		}
+        }
 
-		TEST_METHOD(TooManyClosingBrackets)
-		{
+        TEST_METHOD(TooManyClosingBrackets)
+        {
             whenInputIs("[]]");
             parseMustFail();
-		}
-		
+        }
+        
         TEST_METHOD(EmptyArray)
         {
             whenInputIs("[]");
@@ -55,8 +49,8 @@ namespace ArduinoJsonParserTests
             itemMustNotExist(0);
         }
 
-		TEST_METHOD(TwoIntegers)
-		{
+        TEST_METHOD(TwoIntegers)
+        {
             setTokenCountTo(3);
 
             whenInputIs("[1,2]");
@@ -66,7 +60,7 @@ namespace ArduinoJsonParserTests
             itemMustBe(0, 1L);
             itemMustBe(1, 2L);
             itemMustNotExist(2);
-		}
+        }
 
         TEST_METHOD(TwoBooleans)
         {
@@ -94,8 +88,8 @@ namespace ArduinoJsonParserTests
             itemMustNotExist(2);
         }
 
-		TEST_METHOD(TwoDimensionsArray)
-		{
+        TEST_METHOD(TwoDimensionsArray)
+        {
             setTokenCountTo(7);
 
             whenInputIs("[[1,2],[3,4]]");
@@ -107,7 +101,7 @@ namespace ArduinoJsonParserTests
             itemMustBe(1, 0, 3L);
             itemMustBe(1, 1, 4L);
             itemMustNotExist(2);
-		}
+        }
 
         TEST_METHOD(ThreeDimensionsArray)
         {
@@ -127,7 +121,7 @@ namespace ArduinoJsonParserTests
             itemMustBe(1, 1, 1, 8L);
             itemMustNotExist(2);
         }        
-		
+        
     private:
 
         void setTokenCountTo(int n)
@@ -191,5 +185,5 @@ namespace ArduinoJsonParserTests
             Assert::AreEqual(0L, array.getLong(index));
             Assert::IsNull(array.getString(index));
         }
-	};
+    };
 }

+ 0 - 6
JsonParserTests/JsonObjectTests.cpp

@@ -23,12 +23,6 @@ namespace ArduinoJsonParserTests
 
     public:
 
-        TEST_METHOD(EmptyString)
-        {
-            whenInputIs("");
-            parseMustFail();
-        }
-
         TEST_METHOD(EmptyHashTable)
         {
             whenInputIs("{}");

+ 1 - 0
JsonParserTests/JsonParserTests.vcxproj

@@ -90,6 +90,7 @@
     <ClCompile Include="JsonArrayIteratorTests.cpp" />
     <ClCompile Include="JsonObjectTests.cpp" />
     <ClCompile Include="GbathreeBug.cpp" />
+    <ClCompile Include="JsonStringTests.cpp" />
   </ItemGroup>
   <ItemGroup>
     <ProjectReference Include="..\JsonParser\JsonParser.vcxproj">

+ 6 - 3
JsonParserTests/JsonParserTests.vcxproj.filters

@@ -15,9 +15,6 @@
     </Filter>
   </ItemGroup>
   <ItemGroup>
-    <ClCompile Include="JsonArrayTests.cpp">
-      <Filter>Source Files</Filter>
-    </ClCompile>
     <ClCompile Include="GbathreeBug.cpp">
       <Filter>Source Files</Filter>
     </ClCompile>
@@ -30,5 +27,11 @@
     <ClCompile Include="JsonObjectIteratorTests.cpp">
       <Filter>Source Files</Filter>
     </ClCompile>
+    <ClCompile Include="JsonArrayTests.cpp">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+    <ClCompile Include="JsonStringTests.cpp">
+      <Filter>Source Files</Filter>
+    </ClCompile>
   </ItemGroup>
 </Project>

+ 107 - 0
JsonParserTests/JsonStringTests.cpp

@@ -0,0 +1,107 @@
+/*
+* Arduino JSON library
+* Benoit Blanchon 2014 - MIT License
+*/
+
+#include "CppUnitTest.h"
+#include "JsonParser.h"
+
+using namespace Microsoft::VisualStudio::CppUnitTestFramework;
+using namespace ArduinoJson::Parser;
+
+namespace ArduinoJsonParserTests
+{
+    TEST_CLASS(JsonStringTests)
+    {
+        const char* actual;
+        char json[256];
+        JsonParser<32> parser;
+
+    public:
+
+        TEST_METHOD(EmptyString)
+        {
+            whenInputIs("");
+            outputMustBe(0);
+        }
+
+        TEST_METHOD(JustOneQuote)
+        {
+            whenInputIs("\"");
+            outputMustBe(0);
+        }
+
+        TEST_METHOD(SimpleString)
+        {
+            whenInputIs("\"Hi!\"");
+            outputMustBe("Hi!");
+        }
+
+        TEST_METHOD(EscapedQuote)
+        {
+            whenInputIs("\"12\\\"34\"");  // ie 12\"34
+            outputMustBe("12\"34");
+        }
+
+        TEST_METHOD(EscapedReverseSolidus)
+        {
+            whenInputIs("\"12\\\\34\""); // ie 12\\34
+            outputMustBe("12\\34");
+        }
+
+        TEST_METHOD(EscapedSolidus)
+        {
+            whenInputIs("\"12\\/34\"");
+            outputMustBe("12/34");
+        }
+
+        TEST_METHOD(EscapedBackspace)
+        {
+            whenInputIs("\"12\\b34\"");
+            outputMustBe("12\b34");
+        }
+
+        TEST_METHOD(EscapedFormfeed)
+        {
+            whenInputIs("\"12\\f34\"");
+            outputMustBe("12\f34");
+        }
+        
+        TEST_METHOD(EscapedNewline)
+        {
+            whenInputIs("\"12\\n34\""); 
+            outputMustBe("12\n34");
+        }
+
+        TEST_METHOD(EscapedCarriageReturn)
+        {
+            whenInputIs("\"12\\r34\"");
+            outputMustBe("12\r34");
+        }
+
+        TEST_METHOD(EscapedTab)
+        {
+            whenInputIs("\"12\\t34\"");
+            outputMustBe("12\t34");
+        }
+
+        TEST_METHOD(AllEscapedCharsTogether)
+        {
+            whenInputIs("\"1\\\"2\\\\3\\/4\\b5\\f6\\n7\\r8\\t9\"");
+            outputMustBe("1\"2\\3/4\b5\f6\n7\r8\t9");
+        }
+
+    private:       
+
+        void whenInputIs(const char* input)
+        {
+            strcpy(json, input);
+            actual = parser.parse(json);
+        }
+
+        void outputMustBe(const char* expected)
+        {
+            Assert::AreEqual(expected, actual);
+        }
+    };
+}

+ 5 - 5
README.md

@@ -10,8 +10,8 @@ It has been written with Arduino in mind, but it isn't linked to Arduino librari
 Features
 --------
 
-* JSON decoding: [more details here](/JsonParser/)
-* JSON encoding: [more details here](/JsonGenerator/)
+* JSON decoding: [see documentation here](/JsonParser/)
+* JSON encoding: [see documentation here](/JsonGenerator/)
 * Elegant API, very easy to use 
 * Fixed memory allocation (no malloc)
 * Small footprint
@@ -22,9 +22,9 @@ Feature comparison
 
 | Library      | Memory allocation | Nested objects | Parser size | Encoder size  |
 | ------------ | ----------------- | -------------- | ----------- | ------------- |
-| Arduino JSON | static            | yes            | 2642 Bytes  | 862 bytes     |
-| json-arduino | dynamic           | no             | 3348 (+27%) | not supported |
-| aJson        | dynamic           | yes            | 5088 (+93%) | 4678 (+540%)  |
+| Arduino JSON | static            | yes            | 2760 Bytes  | 862 bytes     |
+| json-arduino | dynamic           | no             | 3348 (+21%) | not supported |
+| aJson        | dynamic           | yes            | 5088 (+84%) | 4678 (+540%)  |
 
 "Parser size" was measured with a program parsing `{"sensor":"outdoor","value":25.6}`.
 For each library, I wrote a program that extracts a string and a float. I subtracted the size of a program doing the same without any JSON parsing involved. [Source files are here](https://gist.github.com/bblanchon/e8ba914a7109f3642c0f).