fixed #592: Incorrect format string in Poco::Dynamic::Struct

This commit is contained in:
Guenter Obiltschnig
2014-11-07 10:43:50 +01:00
parent 6c37d53b39
commit fa4989e0c7
5 changed files with 151 additions and 35 deletions

View File

@@ -542,6 +542,7 @@ private:
static Var parseObject(const std::string& val, std::string::size_type& pos); static Var parseObject(const std::string& val, std::string::size_type& pos);
static Var parseArray(const std::string& val, std::string::size_type& pos); static Var parseArray(const std::string& val, std::string::size_type& pos);
static std::string parseString(const std::string& val, std::string::size_type& pos); static std::string parseString(const std::string& val, std::string::size_type& pos);
static std::string parseJSONString(const std::string& val, std::string::size_type& pos);
static void skipWhiteSpace(const std::string& val, std::string::size_type& pos); static void skipWhiteSpace(const std::string& val, std::string::size_type& pos);
template <typename T> template <typename T>

View File

@@ -401,6 +401,8 @@ Var Var::parse(const std::string& val, std::string::size_type& pos)
return parseObject(val, pos); return parseObject(val, pos);
case '[': case '[':
return parseArray(val, pos); return parseArray(val, pos);
case '"':
return parseJSONString(val, pos);
default: default:
return parseString(val, pos); return parseString(val, pos);
} }
@@ -464,41 +466,79 @@ Var Var::parseArray(const std::string& val, std::string::size_type& pos)
std::string Var::parseString(const std::string& val, std::string::size_type& pos) std::string Var::parseString(const std::string& val, std::string::size_type& pos)
{ {
static const std::string STR_STOP("\"");
static const std::string OTHER_STOP("\n ,]}");
bool inString = false;
//skip optional ' "
if (val[pos] == '"') if (val[pos] == '"')
{ {
inString = true; return parseJSONString(val, pos);
++pos;
}
std::string::size_type stop = std::string::npos;
if (inString)
{
stop = val.find_first_of(STR_STOP, pos);
if (stop == std::string::npos)
throw DataFormatException("Unterminated string");
} }
else else
{ {
// we stop at space, ',', ']' or '}' or end of string std::string result;
stop = val.find_first_of(OTHER_STOP, pos); while (pos < val.size()
if (stop == std::string::npos) && !Poco::Ascii::isSpace(val[pos])
stop = val.size(); && val[pos] != ','
&& val[pos] != ']'
std::string::size_type safeCheck = val.find_first_of(STR_STOP, pos); && val[pos] != '}')
if (safeCheck != std::string::npos && safeCheck < stop) {
throw DataFormatException("Misplaced string termination char found"); result += val[pos++];
} }
return result;
}
}
// stop now points to the last char to be not included
std::string result = val.substr(pos, stop - pos); std::string Var::parseJSONString(const std::string& val, std::string::size_type& pos)
++stop; // point past '/" {
pos = stop; poco_assert_dbg (val[pos] == '"');
++pos;
std::string result;
bool done = false;
while (pos < val.size() && !done)
{
switch (val[pos])
{
case '"':
done = true;
++pos;
break;
case '\\':
if (pos < val.size())
{
++pos;
switch (val[pos])
{
case 'b':
result += '\b';
break;
case 'f':
result += '\f';
break;
case 'n':
result += '\n';
break;
case 'r':
result += '\r';
break;
case 't':
result += '\t';
break;
default:
result += val[pos];
break;
}
break;
}
else
{
result += val[pos];
}
++pos;
break;
default:
result += val[pos++];
break;
}
}
if (!done) throw Poco::DataFormatException("unterminated JSON string");
return result; return result;
} }

View File

@@ -35,6 +35,43 @@ VarHolder::~VarHolder()
namespace Impl { namespace Impl {
void escape(std::string& target, const std::string& source)
{
std::string::const_iterator it(source.begin());
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;
}
}
}
bool isJSONString(const Var& any) bool isJSONString(const Var& any)
{ {
return any.type() == typeid(std::string) || return any.type() == typeid(std::string) ||
@@ -48,9 +85,9 @@ bool isJSONString(const Var& any)
void appendJSONString(std::string& val, const Var& any) void appendJSONString(std::string& val, const Var& any)
{ {
val.append(1, '"'); val += '"';
val.append(any.convert<std::string>()); escape(val, any.convert<std::string>());
val.append(1, '"'); val += '"';
} }
@@ -62,13 +99,21 @@ void appendJSONKey(std::string& val, const Var& any)
void appendJSONValue(std::string& val, const Var& any) void appendJSONValue(std::string& val, const Var& any)
{ {
if (any.isEmpty()) val.append("null"); if (any.isEmpty())
{
val.append("null");
}
else else
{ {
bool isStr = isJSONString(any); bool isStr = isJSONString(any);
if (isStr) val.append(1, '"'); if (isStr)
{
appendJSONString(val, any.convert<std::string>());
}
else
{
val.append(any.convert<std::string>()); val.append(any.convert<std::string>());
if (isStr) val.append(1, '"'); }
} }
} }

View File

@@ -2089,6 +2089,20 @@ void VarTest::testArrayToString()
} }
void VarTest::testArrayToStringEscape()
{
std::string s1("\"quoted string\"");
Poco::Int8 s2(23);
std::vector<Var> s16;
s16.push_back(s1);
s16.push_back(s2);
Var a1(s16);
std::string res = a1.convert<std::string>();
std::string expected("[ \"\\\"quoted string\\\"\", 23 ]");
assert (res == expected);
}
void VarTest::testStructToString() void VarTest::testStructToString()
{ {
DynamicStruct aStruct; DynamicStruct aStruct;
@@ -2103,6 +2117,18 @@ void VarTest::testStructToString()
} }
void VarTest::testStructToStringEscape()
{
DynamicStruct aStruct;
aStruct["Value"] = "Value with \" and \n";
Var a1(aStruct);
std::string res = a1.convert<std::string>();
std::string expected = "{ \"Value\" : \"Value with \\\" and \\n\" }";
assert (res == expected);
assert (aStruct.toString() == res);
}
void VarTest::testArrayOfStructsToString() void VarTest::testArrayOfStructsToString()
{ {
std::vector<Var> s16; std::vector<Var> s16;
@@ -2592,7 +2618,9 @@ CppUnit::Test* VarTest::suite()
CppUnit_addTest(pSuite, VarTest, testDynamicStructString); CppUnit_addTest(pSuite, VarTest, testDynamicStructString);
CppUnit_addTest(pSuite, VarTest, testDynamicStructInt); CppUnit_addTest(pSuite, VarTest, testDynamicStructInt);
CppUnit_addTest(pSuite, VarTest, testArrayToString); CppUnit_addTest(pSuite, VarTest, testArrayToString);
CppUnit_addTest(pSuite, VarTest, testArrayToStringEscape);
CppUnit_addTest(pSuite, VarTest, testStructToString); CppUnit_addTest(pSuite, VarTest, testStructToString);
CppUnit_addTest(pSuite, VarTest, testStructToStringEscape);
CppUnit_addTest(pSuite, VarTest, testArrayOfStructsToString); CppUnit_addTest(pSuite, VarTest, testArrayOfStructsToString);
CppUnit_addTest(pSuite, VarTest, testStructWithArraysToString); CppUnit_addTest(pSuite, VarTest, testStructWithArraysToString);
CppUnit_addTest(pSuite, VarTest, testJSONDeserializeString); CppUnit_addTest(pSuite, VarTest, testJSONDeserializeString);

View File

@@ -59,7 +59,9 @@ public:
void testDynamicStructString(); void testDynamicStructString();
void testDynamicStructInt(); void testDynamicStructInt();
void testArrayToString(); void testArrayToString();
void testArrayToStringEscape();
void testStructToString(); void testStructToString();
void testStructToStringEscape();
void testArrayOfStructsToString(); void testArrayOfStructsToString();
void testStructWithArraysToString(); void testStructWithArraysToString();
void testJSONDeserializeString(); void testJSONDeserializeString();