From a895ce150fa2d73f4ee55f8657761a6b3e96236f Mon Sep 17 00:00:00 2001 From: xpahos Date: Thu, 13 Feb 2020 04:53:15 +0300 Subject: [PATCH] Allow escaped apostrophe in values (#1639) * Allow escaped apostrophe in values * Allow escaped apostrophe in values * Canonical flag name * Add translation for escaped apostrophe Co-authored-by: Milo Yip --- doc/dom.md | 1 + doc/dom.zh-cn.md | 1 + include/rapidjson/reader.h | 7 ++++++- test/unittest/readertest.cpp | 24 ++++++++++++++++++++++++ 4 files changed, 32 insertions(+), 1 deletion(-) diff --git a/doc/dom.md b/doc/dom.md index 0079b64..6992e77 100644 --- a/doc/dom.md +++ b/doc/dom.md @@ -119,6 +119,7 @@ Parse flags | Meaning `kParseNumbersAsStringsFlag` | Parse numerical type values as strings. `kParseTrailingCommasFlag` | Allow trailing commas at the end of objects and arrays (relaxed JSON syntax). `kParseNanAndInfFlag` | Allow parsing `NaN`, `Inf`, `Infinity`, `-Inf` and `-Infinity` as `double` values (relaxed JSON syntax). +`kParseEscapedApostropheFlag` | Allow escaped apostrophe `\'` in strings (relaxed JSON syntax). By using a non-type template parameter, instead of a function parameter, C++ compiler can generate code which is optimized for specified combinations, improving speed, and reducing code size (if only using a single specialization). The downside is the flags needed to be determined in compile-time. diff --git a/doc/dom.zh-cn.md b/doc/dom.zh-cn.md index 9743b7a..8fcd538 100644 --- a/doc/dom.zh-cn.md +++ b/doc/dom.zh-cn.md @@ -119,6 +119,7 @@ GenericDocument& GenericDocument::Parse(const Ch* str); `kParseNumbersAsStringsFlag` | 把数字类型解析成字符串。 `kParseTrailingCommasFlag` | 容许在对象和数组结束前含有逗号(放宽的 JSON 语法)。 `kParseNanAndInfFlag` | 容许 `NaN`、`Inf`、`Infinity`、`-Inf` 及 `-Infinity` 作为 `double` 值(放宽的 JSON 语法)。 +`kParseEscapedApostropheFlag` | 容许字符串中转义单引号 `\'` (放宽的 JSON 语法)。 由于使用了非类型模板参数,而不是函数参数,C++ 编译器能为个别组合生成代码,以改善性能及减少代码尺寸(当只用单种特化)。缺点是需要在编译期决定标志。 diff --git a/include/rapidjson/reader.h b/include/rapidjson/reader.h index 13d27c2..2d73b19 100644 --- a/include/rapidjson/reader.h +++ b/include/rapidjson/reader.h @@ -154,6 +154,7 @@ enum ParseFlag { kParseNumbersAsStringsFlag = 64, //!< Parse all numbers (ints/doubles) as strings. kParseTrailingCommasFlag = 128, //!< Allow trailing commas at the end of objects and arrays. kParseNanAndInfFlag = 256, //!< Allow parsing NaN, Inf, Infinity, -Inf and -Infinity as doubles. + kParseEscapedApostropheFlag = 512, //!< Allow escaped apostrophe in strings. kParseDefaultFlags = RAPIDJSON_PARSE_DEFAULT_FLAGS //!< Default parse flags. Can be customized by defining RAPIDJSON_PARSE_DEFAULT_FLAGS }; @@ -991,7 +992,7 @@ private: //!@cond RAPIDJSON_HIDDEN_FROM_DOXYGEN #define Z16 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 static const char escape[256] = { - Z16, Z16, 0, 0,'\"', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,'/', + Z16, Z16, 0, 0,'\"', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, '/', Z16, Z16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,'\\', 0, 0, 0, 0, 0,'\b', 0, 0, 0,'\f', 0, 0, 0, 0, 0, 0, 0,'\n', 0, 0, 0,'\r', 0,'\t', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, @@ -1014,6 +1015,10 @@ private: is.Take(); os.Put(static_cast(escape[static_cast(e)])); } + else if ((parseFlags & kParseEscapedApostropheFlag) && RAPIDJSON_LIKELY(e == '\'')) { // Allow escaped apostrophe + is.Take(); + os.Put('\''); + } else if (RAPIDJSON_LIKELY(e == 'u')) { // Unicode is.Take(); unsigned codepoint = ParseHex4(is, escapeOffset); diff --git a/test/unittest/readertest.cpp b/test/unittest/readertest.cpp index e3d5148..2795766 100644 --- a/test/unittest/readertest.cpp +++ b/test/unittest/readertest.cpp @@ -2198,4 +2198,28 @@ TEST(Reader, ParseNanAndInfinity) { #undef TEST_NAN_INF } +TEST(Reader, EscapedApostrophe) { + const char json[] = " { \"foo\": \"bar\\'buzz\" } "; + + BaseReaderHandler<> h; + + { + StringStream s(json); + Reader reader; + ParseResult r = reader.Parse(s, h); + EXPECT_TRUE(reader.HasParseError()); + EXPECT_EQ(kParseErrorStringEscapeInvalid, r.Code()); + EXPECT_EQ(14u, r.Offset()); + } + + { + StringStream s(json); + Reader reader; + ParseResult r = reader.Parse(s, h); + EXPECT_FALSE(reader.HasParseError()); + EXPECT_EQ(kParseErrorNone, r.Code()); + EXPECT_EQ(0u, r.Offset()); + } +} + RAPIDJSON_DIAG_POP