while (c != EOF && c != '"') {
if (c == '\\') {
// see the spec for allowed escape characters
+ int d;
switch (in.peek()) {
case '"':
c = '"';
case 't':
c = '\t';
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:
throwJSONError("Bad escape", file, line, pos);
}
ss << '\\' << 't';
break;
default:
- if ((c >= 0) && (c < 0x20)) {
+ if (((c >= 0) && (c < 0x20)) || (c < 0) || (c >= 0x7f)) {
std::ostringstream esc;
esc << "\\u"
<< hex
// We should confirm that our string handling is 8-bit clean.
// At one point we were using char-length data and comparing to EOF,
// which means that character '\xFF' would not parse properly.
- sv.push_back("\"\xFF\"");
+ sv.push_back("\"\\u00ff\"");
BOOST_FOREACH(const std::string& s, sv) {
// Test two types of fromJSON(): with string and istream.
// String not delimited correctly
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) {
EXPECT_THROW(el = Element::fromJSON(s), isc::data::JSONError);
escapeHelper("foo\nbar", "\"foo\\nbar\"");
escapeHelper("foo\rbar", "\"foo\\rbar\"");
escapeHelper("foo\tbar", "\"foo\\tbar\"");
+ escapeHelper("foo\u001fbar", "\"foo\\u001fbar\"");
// Bad escapes
EXPECT_THROW(Element::fromJSON("\\a"), JSONError);
EXPECT_THROW(Element::fromJSON("\\"), JSONError);
// Can't have escaped quotes outside strings
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
EXPECT_NO_THROW(Element::fromJSON("\"\\\"\\\"\""));
// A whitespace test
// Control characters
StringElement bell("foo\abar");
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.