diff --git a/Data/Data_x64_vs120.vcxproj b/Data/Data_x64_vs120.vcxproj index 7116bf5b2..e841d6760 100644 --- a/Data/Data_x64_vs120.vcxproj +++ b/Data/Data_x64_vs120.vcxproj @@ -1,4 +1,4 @@ - + @@ -32,7 +32,7 @@ Data Win32Proj - + StaticLibrary MultiByte @@ -63,27 +63,27 @@ MultiByte v120 - - + + - + - + - + - + - + - + - + <_ProjectFileVersion>12.0.30501.0 PocoData64d @@ -132,7 +132,7 @@ true true true - + Level3 ProgramDatabase Default @@ -164,9 +164,9 @@ true true true - + Level3 - + Default /bigobj %(AdditionalOptions) @@ -195,7 +195,7 @@ true true true - + ..\lib64\PocoDatamtd.pdb Level3 ProgramDatabase @@ -221,9 +221,9 @@ true true true - + Level3 - + Default /bigobj %(AdditionalOptions) @@ -244,7 +244,7 @@ true true true - + ..\lib64\PocoDatamdd.pdb Level3 ProgramDatabase @@ -270,9 +270,9 @@ true true true - + Level3 - + Default /bigobj %(AdditionalOptions) @@ -281,93 +281,95 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - + + + \ No newline at end of file diff --git a/Data/Data_x64_vs120.vcxproj.filters b/Data/Data_x64_vs120.vcxproj.filters index 1d9a874c5..07ae67f45 100644 --- a/Data/Data_x64_vs120.vcxproj.filters +++ b/Data/Data_x64_vs120.vcxproj.filters @@ -177,6 +177,9 @@ Logging\Header Files + + DataCore\Header Files + @@ -284,5 +287,8 @@ Logging\Source Files + + DataCore\Source Files + \ No newline at end of file diff --git a/Data/include/Poco/Data/JSONFormatter.h b/Data/include/Poco/Data/JSONFormatter.h new file mode 100644 index 000000000..94df33835 --- /dev/null +++ b/Data/include/Poco/Data/JSONFormatter.h @@ -0,0 +1,62 @@ +// +// JSONFormatter.h +// +// $Id: //poco/Main/Data/include/Poco/Data/JSONFormatter.h#9 $ +// +// Library: Data +// Package: DataCore +// Module: JSONFormatter +// +// Definition of the JSONFormatter class. +// +// Copyright (c) 2006, Applied Informatics Software Engineering GmbH. +// and Contributors. +// +// SPDX-License-Identifier: BSL-1.0 +// + + +#ifndef Data_JSONFormatter_INCLUDED +#define Data_JSONFormatter_INCLUDED + + +#include "Poco/Data/RowFormatter.h" + + +namespace Poco { +namespace Data { + + +class Data_API JSONFormatter: public Poco::Data::RowFormatter + /// Class for JSON formatting of data rows. +{ +public: + JSONFormatter(); + /// Creates a new JSONFormatter. + + ~JSONFormatter(); + /// Destroy the JSONFormatter. + + std::string& formatNames(const NameVecPtr pNames, std::string& formattedNames); + std::string& formatValues(const ValueVec& vals, std::string& formattedValues); + +private: + NameVecPtr _pNames; + int _rowCounter; +}; + + +// +// inlines +// +inline std::string& JSONFormatter::formatNames(const NameVecPtr pNames, std::string& formattedNames) +{ + // names are used in formatValues + if (pNames && !_pNames) _pNames = pNames; + return formattedNames = ""; +} + +} } // namespace Poco::Data + + +#endif // Data_JSONFormatter_INCLUDED diff --git a/Data/src/JSONFormatter.cpp b/Data/src/JSONFormatter.cpp new file mode 100644 index 000000000..a58bd6653 --- /dev/null +++ b/Data/src/JSONFormatter.cpp @@ -0,0 +1,84 @@ +// +// JSONFormatter.cpp +// +// $Id: //poco/Main/Data/src/JSONFormatter.cpp#1 $ +// +// Library: Data +// Package: DataCore +// Module: JSONFormatter +// +// Copyright (c) 2006, Applied Informatics Software Engineering GmbH. +// and Contributors. +// +// SPDX-License-Identifier: BSL-1.0 +// + + +#include "Poco/Data/JSONFormatter.h" +#include "Poco/String.h" +#include "Poco/JSONString.h" +#include "Poco/Format.h" + + +using Poco::trimInPlace; +using Poco::format; +using Poco::toJSON; + + +namespace Poco { +namespace Data { + + + JSONFormatter::JSONFormatter() : _rowCounter(0) + { + } + + + JSONFormatter::~JSONFormatter() + { + } + + + std::string& JSONFormatter::formatValues(const ValueVec& vals, std::string& formattedValues) + { + std::ostringstream str; + + str << "{\"count\":" << getTotalRowCount() << ",\"rows\":[{"; + + std::string pref = str.str(); + if (prefix() != pref) setPrefix(pref); + else + { + str.str(""); + str << ",{"; + } + + if (postfix().empty()) setPostfix("]}"); + + ValueVec::const_iterator it = vals.begin(); + ValueVec::const_iterator end = vals.end(); + NameVec::iterator nIt = _pNames->begin(); + NameVec::iterator nEnd = _pNames->end(); + for (; it != end && nIt != nEnd; ++nIt) + { + if (!it->isEmpty()) + { + if (it->isString()) + str << '"' << *nIt << "\":" << + toJSON(trimInPlace(it->convert())); + else + str << '"' << *nIt << "\":" << it->convert(); + } + else + str << '"' << *nIt << "\":null"; + + if (++it != end) str << ','; + } + + str << '}'; + ++_rowCounter; + return formattedValues = str.str(); + } + + +} }// namespace Poco::Data diff --git a/Foundation/Foundation_x64_vs120.vcxproj b/Foundation/Foundation_x64_vs120.vcxproj index 0f156a27f..a5c679210 100644 --- a/Foundation/Foundation_x64_vs120.vcxproj +++ b/Foundation/Foundation_x64_vs120.vcxproj @@ -392,6 +392,7 @@ true true + @@ -1055,6 +1056,7 @@ + diff --git a/Foundation/Foundation_x64_vs120.vcxproj.filters b/Foundation/Foundation_x64_vs120.vcxproj.filters index ac61a22ca..de071f668 100644 --- a/Foundation/Foundation_x64_vs120.vcxproj.filters +++ b/Foundation/Foundation_x64_vs120.vcxproj.filters @@ -930,6 +930,9 @@ Text\Source Files + + Core\Source Files + @@ -1907,6 +1910,9 @@ Crypt\Header Files + + Core\Header Files + diff --git a/Foundation/include/Poco/JSONString.h b/Foundation/include/Poco/JSONString.h new file mode 100644 index 000000000..f762725f5 --- /dev/null +++ b/Foundation/include/Poco/JSONString.h @@ -0,0 +1,48 @@ +// +// JSONString.h +// +// $Id: //poco/1.4/Foundation/include/Poco/JSONString.h#1 $ +// +// Library: Foundation +// Package: Core +// Module: String +// +// JSONString utility functions. +// +// Copyright (c) 2004-2006, Applied Informatics Software Engineering GmbH. +// and Contributors. +// +// SPDX-License-Identifier: BSL-1.0 +// + + +#ifndef Foundation_JSONString_INCLUDED +#define Foundation_JSONString_INCLUDED + + +#include "Poco/Foundation.h" + + +namespace Poco { + + +std::string Foundation_API toJSON(char c); + /// Utility function for escaping JSON characters. + + +void Foundation_API toJSON(const std::string& value, std::ostream& out, bool wrap = true); + /// Formats string value into the suplied output stream by + /// escaping control characters. + /// If wrap is true, the resulting string is enclosed in double quotes + + +std::string Foundation_API toJSON(const std::string& value, bool wrap = true); + /// Formats string value by escaping control characters. + /// If wrap is true, the resulting string is enclosed in double quotes + /// Returns formatted string. + + +} // namespace Poco + + +#endif // Foundation_JSONString_INCLUDED diff --git a/Foundation/src/JSONString.cpp b/Foundation/src/JSONString.cpp new file mode 100644 index 000000000..5b118a5ae --- /dev/null +++ b/Foundation/src/JSONString.cpp @@ -0,0 +1,66 @@ +// +// String.h +// +// $Id: //poco/1.4/Foundation/src/String.cpp#1 $ +// +// Library: Foundation +// Package: Core +// Module: String +// +// Copyright (c) 2004-2006, Applied Informatics Software Engineering GmbH. +// and Contributors. +// +// SPDX-License-Identifier: BSL-1.0 +// + + +#include "Poco/JSONString.h" + + +namespace Poco { + + +std::string toJSON(char c) +{ + switch (c) + { + case '\\': return "\\\\"; + case '"': return "\\\""; + case '/': return "\\/"; + case '\b': return "\\b"; + case '\f': return "\\f"; + case '\n': return "\\n"; + case '\r': return "\\r"; + case '\t': return "\\t"; + default: return std::string(1, c); + } +} + + +void toJSON(const std::string& value, std::ostream& out, bool wrap) +{ + if (wrap) out << '"'; + for (std::string::const_iterator it = value.begin(), + end = value.end(); it != end; ++it) + { + out << toJSON(*it); + } + if (wrap) out << '"'; +} + + +std::string toJSON(const std::string& value, bool wrap) +{ + std::string ret; + if (wrap) ret.append(1, '"'); + for (std::string::const_iterator it = value.begin(), + end = value.end(); it != end; ++it) + { + ret.append(toJSON(*it)); + } + if (wrap) ret.append(1, '"'); + return ret; +} + + +} // namespace Poco diff --git a/Foundation/src/VarHolder.cpp b/Foundation/src/VarHolder.cpp index 8dde3e52e..e49511f4b 100644 --- a/Foundation/src/VarHolder.cpp +++ b/Foundation/src/VarHolder.cpp @@ -16,6 +16,7 @@ #include "Poco/Dynamic/VarHolder.h" #include "Poco/Dynamic/Var.h" +#include "Poco/JSONString.h" namespace Poco { @@ -41,33 +42,7 @@ void escape(std::string& target, const std::string& source) std::string::const_iterator end(source.end()); for (; it != end; ++it) { - switch (*it) - { - case '"': - target += "\\\""; - break; - case '\\': - target += "\\\\"; - break; - case '\b': - target += "\\b"; - break; - case '\f': - target += "\\f"; - break; - case '\n': - target += "\\n"; - break; - case '\r': - target += "\\r"; - break; - case '\t': - target += "\\t"; - break; - default: - target += *it; - break; - } + target.append(Poco::toJSON(*it)); } } diff --git a/Foundation/testsuite/src/HMACEngineTest.cpp b/Foundation/testsuite/src/HMACEngineTest.cpp index eb19286dd..2b21e1e6d 100644 --- a/Foundation/testsuite/src/HMACEngineTest.cpp +++ b/Foundation/testsuite/src/HMACEngineTest.cpp @@ -50,8 +50,8 @@ void HMACEngineTest::testHMAC() digest = DigestEngine::digestToHex(hmac2.digest()); assert (digest == "750c783e6ab0b503eaa86e310a5db738"); - key = std::string(16, 0xaa); - data = std::string(50, 0xdd); + key = std::string(16, char(0xaa)); + data = std::string(50, char(0xdd)); HMACEngine hmac3(key); hmac3.update(data); digest = DigestEngine::digestToHex(hmac3.digest()); diff --git a/Foundation/testsuite/src/StringTest.cpp b/Foundation/testsuite/src/StringTest.cpp index a317c5413..7e7cc5932 100644 --- a/Foundation/testsuite/src/StringTest.cpp +++ b/Foundation/testsuite/src/StringTest.cpp @@ -14,11 +14,13 @@ #include "CppUnit/TestCaller.h" #include "CppUnit/TestSuite.h" #include "Poco/String.h" +#include "Poco/JSONString.h" #include "Poco/Format.h" #include "Poco/MemoryStream.h" #include "Poco/Stopwatch.h" #include "Poco/Exception.h" #include +#include #include #include #include @@ -55,6 +57,7 @@ using Poco::doubleToStr; using Poco::thousandSeparator; using Poco::decimalSeparator; using Poco::format; +using Poco::toJSON; using Poco::CILess; using Poco::MemoryInputStream; using Poco::Stopwatch; @@ -1081,6 +1084,56 @@ void StringTest::benchmarkFloatToStr() } +void StringTest::testJSONString() +{ + assert (toJSON('\\') == "\\\\"); + assert (toJSON('"') == "\\\""); + assert (toJSON('/') == "\\/"); + assert (toJSON('\b') == "\\b"); + assert (toJSON('\f') == "\\f"); + assert (toJSON('\n') == "\\n"); + assert (toJSON('\r') == "\\r"); + assert (toJSON('\t') == "\\t"); + assert (toJSON('a') == "a"); + + // ??? on MSVC, the assert macro expansion + // fails to compile when this string is inline ??? + std::string str = "\"foo\\\\\""; + assert (toJSON("foo\\") == str); + + assert (toJSON("bar/") == "\"bar\\/\""); + assert (toJSON("baz") == "\"baz\""); + assert (toJSON("q\"uote\"d") == "\"q\\\"uote\\\"d\""); + assert (toJSON("bs\b") == "\"bs\\b\""); + assert (toJSON("nl\n") == "\"nl\\n\""); + assert (toJSON("tb\t") == "\"tb\\t\""); + + std::ostringstream ostr; + toJSON("foo\\", ostr); + assert(ostr.str() == str); + ostr.str(""); + + toJSON("foo\\", ostr); + assert(toJSON("bar/") == "\"bar\\/\""); + ostr.str(""); + toJSON("baz", ostr); + assert(ostr.str() == "\"baz\""); + ostr.str(""); + toJSON("q\"uote\"d", ostr); + assert(ostr.str() == "\"q\\\"uote\\\"d\""); + ostr.str(""); + toJSON("bs\b", ostr); + assert(ostr.str() == "\"bs\\b\""); + ostr.str(""); + toJSON("nl\n", ostr); + assert(ostr.str() == "\"nl\\n\""); + ostr.str(""); + toJSON("tb\t", ostr); + assert(ostr.str() == "\"tb\\t\""); + ostr.str(""); +} + + void StringTest::setUp() { } @@ -1121,6 +1174,7 @@ CppUnit::Test* StringTest::suite() CppUnit_addTest(pSuite, StringTest, testIntToString); CppUnit_addTest(pSuite, StringTest, testFloatToString); //CppUnit_addTest(pSuite, StringTest, benchmarkFloatToStr); + CppUnit_addTest(pSuite, StringTest, testJSONString); return pSuite; } diff --git a/Foundation/testsuite/src/StringTest.h b/Foundation/testsuite/src/StringTest.h index 58f4c9591..f24fea056 100644 --- a/Foundation/testsuite/src/StringTest.h +++ b/Foundation/testsuite/src/StringTest.h @@ -57,6 +57,8 @@ public: void testFloatToString(); void benchmarkFloatToStr(); + void testJSONString(); + void setUp(); void tearDown(); diff --git a/JSON/src/Stringifier.cpp b/JSON/src/Stringifier.cpp index 21be0a3fc..af240c395 100644 --- a/JSON/src/Stringifier.cpp +++ b/JSON/src/Stringifier.cpp @@ -17,6 +17,7 @@ #include "Poco/JSON/Stringifier.h" #include "Poco/JSON/Array.h" #include "Poco/JSON/Object.h" +#include "Poco/JSONString.h" #include @@ -69,24 +70,7 @@ void Stringifier::stringify(const Var& any, std::ostream& out, unsigned int inde void Stringifier::formatString(const std::string& value, std::ostream& out) { - out << '"'; - for (std::string::const_iterator it = value.begin(), - end = value.end(); it != end; ++it) - { - switch (*it) - { - case '\\': out << "\\\\"; break; - case '"': out << "\\\""; break; - case '/': out << "\\/"; break; - case '\b': out << "\\b"; break; - case '\f': out << "\\f"; break; - case '\n': out << "\\n"; break; - case '\r': out << "\\r"; break; - case '\t': out << "\\t"; break; - default: out << *it; break; - } - } - out << '"'; + Poco::toJSON(value, out); }