Merge pull request #21 from Teemperor/fixed_escaped_chars

Implemented the JSON spec for string parsing for everything but the \uXXXX escaping - see issue #12.
This commit is contained in:
Niels 2015-01-09 20:32:08 +01:00
commit 69195e070f
2 changed files with 75 additions and 15 deletions

View file

@ -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;
}
}

View file

@ -1618,10 +1618,44 @@ 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"));
// escaping senseless stuff
CHECK_THROWS_AS(json::parse("\"\\z\""), std::invalid_argument);
CHECK_THROWS_AS(json::parse("\"\\ \""), std::invalid_argument);
CHECK_THROWS_AS(json::parse("\"\\9\""), std::invalid_argument);
// quotes must be closed
CHECK_THROWS_AS(json::parse("\""), std::invalid_argument);