diff --git a/.travis.yml b/.travis.yml index b6038505..dc7340ed 100644 --- a/.travis.yml +++ b/.travis.yml @@ -24,4 +24,4 @@ after_success: - make clean - make json_unit CXXFLAGS="-fprofile-arcs -ftest-coverage" - ./json_unit - - coveralls --exclude benchmark --exclude test --gcov-options '\-lp' --gcov 'gcov-4.8' + - coveralls --exclude benchmark --exclude test --exclude header_only --gcov-options '\-lp' --gcov 'gcov-4.8' diff --git a/header_only/json.h b/header_only/json.h index 2a35fddd..c8f5047c 100644 --- a/header_only/json.h +++ b/header_only/json.h @@ -165,7 +165,10 @@ class json /// dump the object (with pretty printer) std::string dump(const bool, const unsigned int, unsigned int = 0) const noexcept; - + /// replaced a character in a string with another string + void replaceChar(std::string& str, char c, const std::string& replacement) const; + /// escapes special characters to safely dump the string + std::string escapeString(const std::string&) const; public: /// explicit value conversion template @@ -935,7 +938,7 @@ std::string json::dump(const bool prettyPrint, const unsigned int indentStep, { case (value_type::string): { - return std::string("\"") + *value_.string + "\""; + return std::string("\"") + escapeString(*value_.string) + "\""; } case (value_type::boolean): @@ -1032,6 +1035,50 @@ std::string json::dump(const bool prettyPrint, const unsigned int indentStep, } } +/*! +Internal function to replace all occurrences of a character in a given string +with another string. + +\param str the string that contains tokens to replace +\param c the character that needs to be replaced +\param replacement the string that is the replacement for the character +*/ +void json::replaceChar(std::string& str, char c, const std::string& replacement) +const +{ + size_t start_pos = 0; + while ((start_pos = str.find(c, start_pos)) != std::string::npos) + { + str.replace(start_pos, 1, replacement); + start_pos += replacement.length(); + } +} + +/*! +Escapes all special characters in the given string according to ECMA-404. +Necessary as some characters such as quotes, backslashes and so on +can't be used as is when dumping a string value. + +\param str the string that should be escaped. + +\return a copy of the given string with all special characters escaped. +*/ +std::string json::escapeString(const std::string& str) const +{ + std::string result(str); + // we first need to escape the backslashes as all other methods will insert + // legitimate backslashes into the result. + replaceChar(result, '\\', "\\\\"); + // replace all other characters + replaceChar(result, '"', "\\\""); + replaceChar(result, '\n', "\\n"); + replaceChar(result, '\r', "\\r"); + replaceChar(result, '\f', "\\f"); + replaceChar(result, '\b', "\\b"); + replaceChar(result, '\t', "\\t"); + return result; +} + /*! Serialization function for JSON objects. The function tries to mimick Python's \p json.dumps() function, and currently supports its \p indent parameter. diff --git a/src/json.cc b/src/json.cc index 33cf0062..0eef1cc2 100644 --- a/src/json.cc +++ b/src/json.cc @@ -598,10 +598,11 @@ with another string. \param replacement the string that is the replacement for the character */ void json::replaceChar(std::string& str, char c, const std::string& replacement) - const +const { size_t start_pos = 0; - while((start_pos = str.find(c, start_pos)) != std::string::npos) { + while ((start_pos = str.find(c, start_pos)) != std::string::npos) + { str.replace(start_pos, 1, replacement); start_pos += replacement.length(); }