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 <miloyip@gmail.com>
This commit is contained in:
xpahos 2020-02-13 04:53:15 +03:00 committed by GitHub
parent 418331e99f
commit a895ce150f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 32 additions and 1 deletions

View File

@ -119,6 +119,7 @@ Parse flags | Meaning
`kParseNumbersAsStringsFlag` | Parse numerical type values as strings. `kParseNumbersAsStringsFlag` | Parse numerical type values as strings.
`kParseTrailingCommasFlag` | Allow trailing commas at the end of objects and arrays (relaxed JSON syntax). `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). `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. 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.

View File

@ -119,6 +119,7 @@ GenericDocument& GenericDocument::Parse(const Ch* str);
`kParseNumbersAsStringsFlag` | 把数字类型解析成字符串。 `kParseNumbersAsStringsFlag` | 把数字类型解析成字符串。
`kParseTrailingCommasFlag` | 容许在对象和数组结束前含有逗号(放宽的 JSON 语法)。 `kParseTrailingCommasFlag` | 容许在对象和数组结束前含有逗号(放宽的 JSON 语法)。
`kParseNanAndInfFlag` | 容许 `NaN``Inf``Infinity``-Inf``-Infinity` 作为 `double` 值(放宽的 JSON 语法)。 `kParseNanAndInfFlag` | 容许 `NaN``Inf``Infinity``-Inf``-Infinity` 作为 `double` 值(放宽的 JSON 语法)。
`kParseEscapedApostropheFlag` | 容许字符串中转义单引号 `\'` (放宽的 JSON 语法)。
由于使用了非类型模板参数而不是函数参数C++ 编译器能为个别组合生成代码,以改善性能及减少代码尺寸(当只用单种特化)。缺点是需要在编译期决定标志。 由于使用了非类型模板参数而不是函数参数C++ 编译器能为个别组合生成代码,以改善性能及减少代码尺寸(当只用单种特化)。缺点是需要在编译期决定标志。

View File

@ -154,6 +154,7 @@ enum ParseFlag {
kParseNumbersAsStringsFlag = 64, //!< Parse all numbers (ints/doubles) as strings. kParseNumbersAsStringsFlag = 64, //!< Parse all numbers (ints/doubles) as strings.
kParseTrailingCommasFlag = 128, //!< Allow trailing commas at the end of objects and arrays. kParseTrailingCommasFlag = 128, //!< Allow trailing commas at the end of objects and arrays.
kParseNanAndInfFlag = 256, //!< Allow parsing NaN, Inf, Infinity, -Inf and -Infinity as doubles. 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 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 //!@cond RAPIDJSON_HIDDEN_FROM_DOXYGEN
#define Z16 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 #define Z16 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
static const char escape[256] = { 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, 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,'\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, 0, 0,'\r', 0,'\t', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
@ -1014,6 +1015,10 @@ private:
is.Take(); is.Take();
os.Put(static_cast<typename TEncoding::Ch>(escape[static_cast<unsigned char>(e)])); os.Put(static_cast<typename TEncoding::Ch>(escape[static_cast<unsigned char>(e)]));
} }
else if ((parseFlags & kParseEscapedApostropheFlag) && RAPIDJSON_LIKELY(e == '\'')) { // Allow escaped apostrophe
is.Take();
os.Put('\'');
}
else if (RAPIDJSON_LIKELY(e == 'u')) { // Unicode else if (RAPIDJSON_LIKELY(e == 'u')) { // Unicode
is.Take(); is.Take();
unsigned codepoint = ParseHex4(is, escapeOffset); unsigned codepoint = ParseHex4(is, escapeOffset);

View File

@ -2198,4 +2198,28 @@ TEST(Reader, ParseNanAndInfinity) {
#undef TEST_NAN_INF #undef TEST_NAN_INF
} }
TEST(Reader, EscapedApostrophe) {
const char json[] = " { \"foo\": \"bar\\'buzz\" } ";
BaseReaderHandler<> h;
{
StringStream s(json);
Reader reader;
ParseResult r = reader.Parse<kParseNoFlags>(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<kParseEscapedApostropheFlag>(s, h);
EXPECT_FALSE(reader.HasParseError());
EXPECT_EQ(kParseErrorNone, r.Code());
EXPECT_EQ(0u, r.Offset());
}
}
RAPIDJSON_DIAG_POP RAPIDJSON_DIAG_POP