mirror of
https://github.com/pocoproject/poco.git
synced 2025-01-29 21:30:04 +01:00
fixed #592: Incorrect format string in Poco::Dynamic::Struct
This commit is contained in:
parent
6c37d53b39
commit
fa4989e0c7
@ -542,6 +542,7 @@ private:
|
||||
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 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);
|
||||
|
||||
template <typename T>
|
||||
|
@ -401,6 +401,8 @@ Var Var::parse(const std::string& val, std::string::size_type& pos)
|
||||
return parseObject(val, pos);
|
||||
case '[':
|
||||
return parseArray(val, pos);
|
||||
case '"':
|
||||
return parseJSONString(val, pos);
|
||||
default:
|
||||
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)
|
||||
{
|
||||
static const std::string STR_STOP("\"");
|
||||
static const std::string OTHER_STOP("\n ,]}");
|
||||
|
||||
bool inString = false;
|
||||
//skip optional ' "
|
||||
if (val[pos] == '"')
|
||||
{
|
||||
inString = true;
|
||||
++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");
|
||||
return parseJSONString(val, pos);
|
||||
}
|
||||
else
|
||||
{
|
||||
// we stop at space, ',', ']' or '}' or end of string
|
||||
stop = val.find_first_of(OTHER_STOP, pos);
|
||||
if (stop == std::string::npos)
|
||||
stop = val.size();
|
||||
|
||||
std::string::size_type safeCheck = val.find_first_of(STR_STOP, pos);
|
||||
if (safeCheck != std::string::npos && safeCheck < stop)
|
||||
throw DataFormatException("Misplaced string termination char found");
|
||||
|
||||
std::string result;
|
||||
while (pos < val.size()
|
||||
&& !Poco::Ascii::isSpace(val[pos])
|
||||
&& val[pos] != ','
|
||||
&& val[pos] != ']'
|
||||
&& val[pos] != '}')
|
||||
{
|
||||
result += val[pos++];
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
// stop now points to the last char to be not included
|
||||
std::string result = val.substr(pos, stop - pos);
|
||||
++stop; // point past '/"
|
||||
pos = stop;
|
||||
|
||||
std::string Var::parseJSONString(const std::string& val, std::string::size_type& pos)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -35,6 +35,43 @@ VarHolder::~VarHolder()
|
||||
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)
|
||||
{
|
||||
return any.type() == typeid(std::string) ||
|
||||
@ -48,9 +85,9 @@ bool isJSONString(const Var& any)
|
||||
|
||||
void appendJSONString(std::string& val, const Var& any)
|
||||
{
|
||||
val.append(1, '"');
|
||||
val.append(any.convert<std::string>());
|
||||
val.append(1, '"');
|
||||
val += '"';
|
||||
escape(val, any.convert<std::string>());
|
||||
val += '"';
|
||||
}
|
||||
|
||||
|
||||
@ -62,13 +99,21 @@ void appendJSONKey(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
|
||||
{
|
||||
bool isStr = isJSONString(any);
|
||||
if (isStr) val.append(1, '"');
|
||||
val.append(any.convert<std::string>());
|
||||
if (isStr) val.append(1, '"');
|
||||
if (isStr)
|
||||
{
|
||||
appendJSONString(val, any.convert<std::string>());
|
||||
}
|
||||
else
|
||||
{
|
||||
val.append(any.convert<std::string>());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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()
|
||||
{
|
||||
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()
|
||||
{
|
||||
std::vector<Var> s16;
|
||||
@ -2592,7 +2618,9 @@ CppUnit::Test* VarTest::suite()
|
||||
CppUnit_addTest(pSuite, VarTest, testDynamicStructString);
|
||||
CppUnit_addTest(pSuite, VarTest, testDynamicStructInt);
|
||||
CppUnit_addTest(pSuite, VarTest, testArrayToString);
|
||||
CppUnit_addTest(pSuite, VarTest, testArrayToStringEscape);
|
||||
CppUnit_addTest(pSuite, VarTest, testStructToString);
|
||||
CppUnit_addTest(pSuite, VarTest, testStructToStringEscape);
|
||||
CppUnit_addTest(pSuite, VarTest, testArrayOfStructsToString);
|
||||
CppUnit_addTest(pSuite, VarTest, testStructWithArraysToString);
|
||||
CppUnit_addTest(pSuite, VarTest, testJSONDeserializeString);
|
||||
|
@ -59,7 +59,9 @@ public:
|
||||
void testDynamicStructString();
|
||||
void testDynamicStructInt();
|
||||
void testArrayToString();
|
||||
void testArrayToStringEscape();
|
||||
void testStructToString();
|
||||
void testStructToStringEscape();
|
||||
void testArrayOfStructsToString();
|
||||
void testStructWithArraysToString();
|
||||
void testJSONDeserializeString();
|
||||
|
Loading…
x
Reference in New Issue
Block a user