Skip to content

Commit

Permalink
Implemented the JSON spec for string parsing for everything but the \…
Browse files Browse the repository at this point in the history
…uXXXX escaping for unicode
  • Loading branch information
Teemperor committed Jan 9, 2015
1 parent 2443aa6 commit 7f4fcc5
Show file tree
Hide file tree
Showing 2 changed files with 70 additions and 15 deletions.
52 changes: 39 additions & 13 deletions src/json.cc
Original file line number Diff line number Diff line change
Expand Up @@ -2042,32 +2042,58 @@ Parses a string after opening quotes (\p ") where read.
*/
std::string json::parser::parseString()
{
// remember the position where the first character of the string was
const auto startPos = pos_;
// true if and only if the amount of backslashes before the current
// character is even
bool evenAmountOfBackslashes = true;

// the result of the parse process
std::string result;

// iterate with pos_ over the whole string
for (; pos_ < buffer_.size(); pos_++)
{
for (; pos_ < buffer_.size(); pos_++) {
char currentChar = buffer_[pos_];

// currentChar is a quote, so we might have found the end of the string
if (currentChar == '"')
{
// but only if the amount of backslashes before that quote is even
if (evenAmountOfBackslashes)
{
// uneven amount of backslashes means the user wants to escape something
if (!evenAmountOfBackslashes) {

// slash, backslash and quote are copied as is
if ( currentChar == '/'
|| currentChar == '\\'
|| currentChar == '"') {
result += currentChar;
} else {
// All other characters are replaced by their respective special character
if (currentChar == 't') {
result += '\t';
} else if (currentChar == 'b') {
result += '\b';
} else if (currentChar == 'f') {
result += '\f';
} else if (currentChar == 'n') {
result += '\n';
} else if (currentChar == 'r') {
result += '\r';
} else {
error("expected one of \\,/,b,f,n,r,t behind backslash.");
}
// TODO implement \uXXXX
}
} else {
if (currentChar == '"') {
// currentChar is a quote, so we found the end of the string


const auto stringLength = pos_ - startPos;
// set pos_ behind the trailing quote
pos_++;
// find next char to parse
next();

// return string inside the quotes
return buffer_.substr(startPos, stringLength);
// bring the result of the parsing process back to the caller
return result;
} else if (currentChar != '\\') {
// all non-backslash characters are added to the end of the result string.
// the only backslashes we want in the result are the ones that are escaped (which happens above).
result += currentChar;
}
}

Expand Down
33 changes: 31 additions & 2 deletions test/json_unit.cc
Original file line number Diff line number Diff line change
Expand Up @@ -1618,10 +1618,39 @@ TEST_CASE("Parser")
CHECK(json::parse("\"\"") == json(""));
CHECK(json::parse("\"foo\"") == json("foo"));

// escape characters
// escaping quotes
CHECK_THROWS_AS(json::parse("\"\\\""), std::invalid_argument);
CHECK_NOTHROW(json::parse("\"\\\"\""));
CHECK_NOTHROW(json::parse("\"\\\\\""));

// escaping backslashes
CHECK(json::parse("\"a\\\\z\"") == json("a\\z"));
CHECK(json::parse("\"\\\\\"") == json("\\"));
CHECK(json::parse("\"\\\\a\\\\\"") == json("\\a\\"));
CHECK(json::parse("\"\\\\\\\\\"") == json("\\\\"));

// escaping slash
CHECK(json::parse("\"a\\/z\"") == json("a/z"));
CHECK(json::parse("\"\\/\"") == json("/"));

// escaping tabs
CHECK(json::parse("\"a\\tz\"") == json("a\tz"));
CHECK(json::parse("\"\\t\"") == json("\t"));

// escaping formfeed
CHECK(json::parse("\"a\\fz\"") == json("a\fz"));
CHECK(json::parse("\"\\f\"") == json("\f"));

// escaping carriage return
CHECK(json::parse("\"a\\rz\"") == json("a\rz"));
CHECK(json::parse("\"\\r\"") == json("\r"));

// escaping backspace
CHECK(json::parse("\"a\\bz\"") == json("a\bz"));
CHECK(json::parse("\"\\b\"") == json("\b"));

// escaping newline
CHECK(json::parse("\"a\\nz\"") == json("a\nz"));
CHECK(json::parse("\"\\n\"") == json("\n"));

// quotes must be closed
CHECK_THROWS_AS(json::parse("\""), std::invalid_argument);
Expand Down

0 comments on commit 7f4fcc5

Please sign in to comment.