Skip to content

Commit

Permalink
Merge pull request #18 from Teemperor/fix_quote_escaping
Browse files Browse the repository at this point in the history
Fixed escaped quotes (issue #17)
  • Loading branch information
nlohmann committed Jan 9, 2015
2 parents 4647401 + 4a39bfb commit 661a44d
Show file tree
Hide file tree
Showing 2 changed files with 38 additions and 25 deletions.
62 changes: 37 additions & 25 deletions src/json.cc
Original file line number Diff line number Diff line change
Expand Up @@ -2042,34 +2042,46 @@ Parses a string after opening quotes (\p ") where read.
*/
std::string json::parser::parseString()
{
// get position of closing quotes
auto quotepos_ = buffer_.find_first_of("\"", pos_);

// if the closing quotes are escaped (character before the quotes is a
// backslash), we continue looking for the final quotes
while (quotepos_ != std::string::npos and buffer_[quotepos_ - 1] == '\\')
{
quotepos_ = buffer_.find_first_of("\"", quotepos_ + 1);
}
// 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;

// iterate with pos_ over the whole string
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) {

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

// check if closing quotes were found
if (quotepos_ == std::string::npos)
{
error("expected '\"'");
// remember if we have an even amount of backslashes before the current character
if (currentChar == '\\') {
// jump between even/uneven for each backslash we encounter
evenAmountOfBackslashes = !evenAmountOfBackslashes;
} else {
// zero backslashes are also an even number, so as soon as we encounter a non-backslash
// the chain of backslashes breaks and we start again from zero
evenAmountOfBackslashes = true;
}
}

// store the coordinates of the string for the later return value
const auto stringBegin = pos_;
const auto stringLength = quotepos_ - pos_;

// set buffer position to the position behind (+1) the closing quote
pos_ = quotepos_ + 1;

// read next character
next();

// return the string value
return buffer_.substr(stringBegin, stringLength);
// we iterated over the whole string without finding a unescaped quote
// so the given string is malformed
error("expected '\"'");
}

/*!
Expand Down
1 change: 1 addition & 0 deletions test/json_unit.cc
Original file line number Diff line number Diff line change
Expand Up @@ -1621,6 +1621,7 @@ TEST_CASE("Parser")
// escape characters
CHECK_THROWS_AS(json::parse("\"\\\""), std::invalid_argument);
CHECK_NOTHROW(json::parse("\"\\\"\""));
CHECK_NOTHROW(json::parse("\"\\\\\""));

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

0 comments on commit 661a44d

Please sign in to comment.