mirror of
https://gitlab.isc.org/isc-projects/kea
synced 2025-08-30 13:37:55 +00:00
[5582] Fixed handling of unicode escapes
This commit is contained in:
@@ -357,6 +357,7 @@ strFromStringstream(std::istream& in, const std::string& file,
|
|||||||
while (c != EOF && c != '"') {
|
while (c != EOF && c != '"') {
|
||||||
if (c == '\\') {
|
if (c == '\\') {
|
||||||
// see the spec for allowed escape characters
|
// see the spec for allowed escape characters
|
||||||
|
int d;
|
||||||
switch (in.peek()) {
|
switch (in.peek()) {
|
||||||
case '"':
|
case '"':
|
||||||
c = '"';
|
c = '"';
|
||||||
@@ -382,6 +383,48 @@ strFromStringstream(std::istream& in, const std::string& file,
|
|||||||
case 't':
|
case 't':
|
||||||
c = '\t';
|
c = '\t';
|
||||||
break;
|
break;
|
||||||
|
case 'u':
|
||||||
|
// skip first 0
|
||||||
|
in.ignore();
|
||||||
|
++pos;
|
||||||
|
c = in.peek();
|
||||||
|
if (c != '0') {
|
||||||
|
throwJSONError("Unsupported unicode escape", file, line, pos);
|
||||||
|
}
|
||||||
|
// skip second 0
|
||||||
|
in.ignore();
|
||||||
|
++pos;
|
||||||
|
c = in.peek();
|
||||||
|
if (c != '0') {
|
||||||
|
throwJSONError("Unsupported unicode escape", file, line, pos - 2);
|
||||||
|
}
|
||||||
|
// get first digit
|
||||||
|
in.ignore();
|
||||||
|
++pos;
|
||||||
|
d = in.peek();
|
||||||
|
if ((d >= '0') && (d <= '9')) {
|
||||||
|
c = (d - '0') << 4;
|
||||||
|
} else if ((d >= 'A') && (d <= 'F')) {
|
||||||
|
c = (d - 'A' + 10) << 4;
|
||||||
|
} else if ((d >= 'a') && (d <= 'f')) {
|
||||||
|
c = (d - 'a' + 10) << 4;
|
||||||
|
} else {
|
||||||
|
throwJSONError("Not hexadecimal in unicode escape", file, line, pos - 3);
|
||||||
|
}
|
||||||
|
// get second digit
|
||||||
|
in.ignore();
|
||||||
|
++pos;
|
||||||
|
d = in.peek();
|
||||||
|
if ((d >= '0') && (d <= '9')) {
|
||||||
|
c |= d - '0';
|
||||||
|
} else if ((d >= 'A') && (d <= 'F')) {
|
||||||
|
c |= d - 'A' + 10;
|
||||||
|
} else if ((d >= 'a') && (d <= 'f')) {
|
||||||
|
c |= d - 'a' + 10;
|
||||||
|
} else {
|
||||||
|
throwJSONError("Not hexadecimal in unicode escape", file, line, pos - 4);
|
||||||
|
}
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
throwJSONError("Bad escape", file, line, pos);
|
throwJSONError("Bad escape", file, line, pos);
|
||||||
}
|
}
|
||||||
@@ -797,7 +840,7 @@ StringElement::toJSON(std::ostream& ss) const {
|
|||||||
ss << '\\' << 't';
|
ss << '\\' << 't';
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
if ((c >= 0) && (c < 0x20)) {
|
if (((c >= 0) && (c < 0x20)) || (c < 0) || (c >= 0x7f)) {
|
||||||
std::ostringstream esc;
|
std::ostringstream esc;
|
||||||
esc << "\\u"
|
esc << "\\u"
|
||||||
<< hex
|
<< hex
|
||||||
|
@@ -100,7 +100,7 @@ TEST(Element, from_and_to_json) {
|
|||||||
// We should confirm that our string handling is 8-bit clean.
|
// We should confirm that our string handling is 8-bit clean.
|
||||||
// At one point we were using char-length data and comparing to EOF,
|
// At one point we were using char-length data and comparing to EOF,
|
||||||
// which means that character '\xFF' would not parse properly.
|
// which means that character '\xFF' would not parse properly.
|
||||||
sv.push_back("\"\xFF\"");
|
sv.push_back("\"\\u00ff\"");
|
||||||
|
|
||||||
BOOST_FOREACH(const std::string& s, sv) {
|
BOOST_FOREACH(const std::string& s, sv) {
|
||||||
// Test two types of fromJSON(): with string and istream.
|
// Test two types of fromJSON(): with string and istream.
|
||||||
@@ -150,7 +150,12 @@ TEST(Element, from_and_to_json) {
|
|||||||
// String not delimited correctly
|
// String not delimited correctly
|
||||||
sv.push_back("\"hello");
|
sv.push_back("\"hello");
|
||||||
sv.push_back("hello\"");
|
sv.push_back("hello\"");
|
||||||
|
// Bad unicode
|
||||||
|
sv.push_back("\"\\u123\"");
|
||||||
|
sv.push_back("\"\\u1234\"");
|
||||||
|
sv.push_back("\"\\u0123\"");
|
||||||
|
sv.push_back("\"\\u00ag\"");
|
||||||
|
sv.push_back("\"\\u00BH\"");
|
||||||
|
|
||||||
BOOST_FOREACH(std::string s, sv) {
|
BOOST_FOREACH(std::string s, sv) {
|
||||||
EXPECT_THROW(el = Element::fromJSON(s), isc::data::JSONError);
|
EXPECT_THROW(el = Element::fromJSON(s), isc::data::JSONError);
|
||||||
@@ -550,11 +555,21 @@ TEST(Element, escape) {
|
|||||||
escapeHelper("foo\nbar", "\"foo\\nbar\"");
|
escapeHelper("foo\nbar", "\"foo\\nbar\"");
|
||||||
escapeHelper("foo\rbar", "\"foo\\rbar\"");
|
escapeHelper("foo\rbar", "\"foo\\rbar\"");
|
||||||
escapeHelper("foo\tbar", "\"foo\\tbar\"");
|
escapeHelper("foo\tbar", "\"foo\\tbar\"");
|
||||||
|
escapeHelper("foo\u001fbar", "\"foo\\u001fbar\"");
|
||||||
// Bad escapes
|
// Bad escapes
|
||||||
EXPECT_THROW(Element::fromJSON("\\a"), JSONError);
|
EXPECT_THROW(Element::fromJSON("\\a"), JSONError);
|
||||||
EXPECT_THROW(Element::fromJSON("\\"), JSONError);
|
EXPECT_THROW(Element::fromJSON("\\"), JSONError);
|
||||||
// Can't have escaped quotes outside strings
|
// Can't have escaped quotes outside strings
|
||||||
EXPECT_THROW(Element::fromJSON("\\\"\\\""), JSONError);
|
EXPECT_THROW(Element::fromJSON("\\\"\\\""), JSONError);
|
||||||
|
// Unicode use lower u and 4 hexa, only 00 prefix is supported
|
||||||
|
EXPECT_THROW(Element::fromJSON("\\U0020"), JSONError);
|
||||||
|
EXPECT_THROW(Element::fromJSON("\\u002"), JSONError);
|
||||||
|
EXPECT_THROW(Element::fromJSON("\\u0123"), JSONError);
|
||||||
|
EXPECT_THROW(Element::fromJSON("\\u1023"), JSONError);
|
||||||
|
EXPECT_THROW(Element::fromJSON("\\u00ag"), JSONError);
|
||||||
|
EXPECT_THROW(Element::fromJSON("\\u00ga"), JSONError);
|
||||||
|
EXPECT_THROW(Element::fromJSON("\\u00BH"), JSONError);
|
||||||
|
EXPECT_THROW(Element::fromJSON("\\u00HB"), JSONError);
|
||||||
// Inside strings is OK
|
// Inside strings is OK
|
||||||
EXPECT_NO_THROW(Element::fromJSON("\"\\\"\\\"\""));
|
EXPECT_NO_THROW(Element::fromJSON("\"\\\"\\\"\""));
|
||||||
// A whitespace test
|
// A whitespace test
|
||||||
@@ -565,6 +580,19 @@ TEST(Element, escape) {
|
|||||||
// Control characters
|
// Control characters
|
||||||
StringElement bell("foo\abar");
|
StringElement bell("foo\abar");
|
||||||
EXPECT_EQ("\"foo\\u0007bar\"", bell.str());
|
EXPECT_EQ("\"foo\\u0007bar\"", bell.str());
|
||||||
|
// 8 bit escape
|
||||||
|
StringElement ab("foo\253bar");
|
||||||
|
EXPECT_EQ("\"foo\\u00abbar\"", ab.str());
|
||||||
|
ASSERT_NO_THROW(Element::fromJSON("\"foo\\u00abbar\""));
|
||||||
|
EXPECT_TRUE(ab.equals(*Element::fromJSON("\"foo\\u00abbar\"")));
|
||||||
|
ASSERT_NO_THROW(Element::fromJSON("\"foo\\u00ABbar\""));
|
||||||
|
EXPECT_TRUE(ab.equals(*Element::fromJSON("\"foo\\u00ABbar\"")));
|
||||||
|
StringElement f1("foo\361bar");
|
||||||
|
EXPECT_EQ("\"foo\\u00f1bar\"", f1.str());
|
||||||
|
ASSERT_NO_THROW(Element::fromJSON("\"foo\\u00f1bar\""));
|
||||||
|
EXPECT_TRUE(f1.equals(*Element::fromJSON("\"foo\\u00f1bar\"")));
|
||||||
|
ASSERT_NO_THROW(Element::fromJSON("\"foo\\u00F1bar\""));
|
||||||
|
EXPECT_TRUE(f1.equals(*Element::fromJSON("\"foo\\u00F1bar\"")));
|
||||||
}
|
}
|
||||||
|
|
||||||
// This test verifies that strings are copied.
|
// This test verifies that strings are copied.
|
||||||
|
Reference in New Issue
Block a user