mirror of
https://github.com/pocoproject/poco.git
synced 2025-01-19 00:46:03 +01:00
parent
4a7ab78686
commit
bd81aec779
@ -24,15 +24,67 @@
|
||||
namespace Poco {
|
||||
|
||||
|
||||
void Foundation_API toJSON(const std::string& value, std::ostream& out, bool wrap = true);
|
||||
enum JSONOptions
|
||||
{
|
||||
JSON_PRESERVE_KEY_ORDER = 1,
|
||||
/// Applies to JSON::Object. If specified, the Object will
|
||||
/// preserve the items insertion order. Otherwise, items
|
||||
/// will be sorted by keys.
|
||||
///
|
||||
/// Has no effect on toJSON() function.
|
||||
|
||||
JSON_ESCAPE_UNICODE = 2,
|
||||
/// If specified, when the object is stringified, all
|
||||
/// unicode characters will be escaped in the resulting
|
||||
/// string.
|
||||
|
||||
JSON_WRAP_STRINGS = 4
|
||||
/// If specified, the object will preserve the items
|
||||
/// insertion order. Otherwise, items will be sorted
|
||||
/// by keys.
|
||||
};
|
||||
|
||||
|
||||
//@ deprecated
|
||||
void Foundation_API toJSON(const std::string& value, std::ostream& out, bool wrap = true);
|
||||
/// Formats string value into the supplied output stream by
|
||||
/// escaping control and ALL Unicode characters.
|
||||
/// If wrap is true, the resulting string is enclosed in double quotes.
|
||||
///
|
||||
/// This function is deprecated, please use
|
||||
///
|
||||
/// void Poco::toJSON(const std::string&, std::ostream&, int)
|
||||
|
||||
|
||||
//@ deprecated
|
||||
std::string Foundation_API toJSON(const std::string& value, bool wrap = true);
|
||||
/// Formats string value by escaping control and ALL Unicode characters.
|
||||
/// If wrap is true, the resulting string is enclosed in double quotes
|
||||
///
|
||||
/// Returns formatted string.
|
||||
///
|
||||
/// This function is deprecated, please use
|
||||
///
|
||||
/// std::string Poco::toJSON(const std::string&, int)
|
||||
|
||||
|
||||
void Foundation_API toJSON(const std::string& value, std::ostream& out, int options);
|
||||
/// Formats string value into the supplied output stream by
|
||||
/// escaping control characters.
|
||||
/// If wrap is true, the resulting string is enclosed in double quotes
|
||||
/// If JSON_WRAP_STRINGS is in options, the resulting strings is enclosed in double quotes
|
||||
/// If JSON_ESCAPE_UNICODE is in options, all unicode characters will be escaped, otherwise
|
||||
/// only the compulsory ones.
|
||||
|
||||
std::string Foundation_API toJSON(const std::string& value, bool wrap = true);
|
||||
|
||||
std::string Foundation_API toJSON(const std::string& value, int options);
|
||||
/// Formats string value by escaping control characters.
|
||||
/// If wrap is true, the resulting string is enclosed in double quotes
|
||||
/// If JSON_WRAP_STRINGS is in options, the resulting string is enclosed in double quotes
|
||||
/// If JSON_ESCAPE_UNICODE is in options, all unicode characters will be escaped, otherwise
|
||||
/// only the compulsory ones.
|
||||
///
|
||||
/// Returns formatted string.
|
||||
/// If escapeAllUnicode is true, all unicode characters will be escaped, otherwise only the compulsory ones.
|
||||
|
||||
|
||||
|
||||
} // namespace Poco
|
||||
|
@ -15,24 +15,90 @@
|
||||
#include "Poco/UTF8String.h"
|
||||
#include <ostream>
|
||||
|
||||
|
||||
namespace {
|
||||
|
||||
|
||||
template<typename T, typename S>
|
||||
struct WriteFunc
|
||||
{
|
||||
typedef T& (T::*Type)(const char* s, S n);
|
||||
};
|
||||
|
||||
|
||||
|
||||
template<typename T, typename S>
|
||||
void writeString(const std::string &value, T& obj, typename WriteFunc<T, S>::Type write, int options)
|
||||
{
|
||||
bool wrap = ((options & Poco::JSON_WRAP_STRINGS) != 0);
|
||||
bool escapeAllUnicode = ((options & Poco::JSON_ESCAPE_UNICODE) != 0);
|
||||
|
||||
if (value.size() == 0)
|
||||
{
|
||||
if (wrap) (obj.*write)("\"\"", 2);
|
||||
return;
|
||||
}
|
||||
|
||||
if (wrap) (obj.*write)("\"", 1);
|
||||
if (escapeAllUnicode)
|
||||
{
|
||||
std::string str = Poco::UTF8::escape(value.begin(), value.end());
|
||||
(obj.*write)(str.c_str(), str.size());
|
||||
}
|
||||
else
|
||||
{
|
||||
for (std::string::const_iterator it = value.begin(), end = value.end(); it != end; ++it)
|
||||
{
|
||||
// Forward slash isn't strictly required by JSON spec, but some parsers expect it
|
||||
if ((*it >= 0 && *it <= 31) || (*it == '"') || (*it == '\\') || (*it == '/'))
|
||||
{
|
||||
std::string str = Poco::UTF8::escape(it, it + 1);
|
||||
(obj.*write)(str.c_str(), str.size());
|
||||
}
|
||||
else (obj.*write)(&(*it), 1);
|
||||
}
|
||||
}
|
||||
if (wrap) (obj.*write)("\"", 1);
|
||||
};
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
namespace Poco {
|
||||
|
||||
void toJSON(const std::string& value, std::ostream& out, bool wrap)
|
||||
{
|
||||
if (wrap) out << '"';
|
||||
out << UTF8::escape(value.begin(), value.end());
|
||||
if (wrap) out << '"';
|
||||
}
|
||||
|
||||
void toJSON(const std::string& value, std::ostream& out, bool wrap)
|
||||
{
|
||||
int options = (wrap ? Poco::JSON_WRAP_STRINGS : 0);
|
||||
writeString<std::ostream,
|
||||
std::streamsize>(value, out, &std::ostream::write, options);
|
||||
}
|
||||
|
||||
|
||||
std::string toJSON(const std::string& value, bool wrap)
|
||||
{
|
||||
std::string ret;
|
||||
if (wrap) ret.append(1, '"');
|
||||
ret.append(UTF8::escape(value.begin(), value.end()));
|
||||
if (wrap) ret.append(1, '"');
|
||||
return ret;
|
||||
}
|
||||
std::string toJSON(const std::string& value, bool wrap)
|
||||
{
|
||||
int options = (wrap ? Poco::JSON_WRAP_STRINGS : 0);
|
||||
std::string ret;
|
||||
writeString<std::string,
|
||||
std::string::size_type>(value, ret, &std::string::append, options);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
void toJSON(const std::string& value, std::ostream& out, int options)
|
||||
{
|
||||
writeString<std::ostream, std::streamsize>(value, out, &std::ostream::write, options);
|
||||
}
|
||||
|
||||
|
||||
std::string toJSON(const std::string& value, int options)
|
||||
{
|
||||
std::string ret;
|
||||
writeString<std::string,
|
||||
std::string::size_type>(value, ret, &std::string::append, options);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
} // namespace Poco
|
||||
|
@ -14,7 +14,7 @@
|
||||
|
||||
#include "Poco/Dynamic/VarHolder.h"
|
||||
#include "Poco/Dynamic/Var.h"
|
||||
#include "Poco/UTF8String.h"
|
||||
#include "Poco/JSONString.h"
|
||||
|
||||
|
||||
namespace Poco {
|
||||
@ -36,7 +36,7 @@ namespace Impl {
|
||||
|
||||
void escape(std::string& target, const std::string& source)
|
||||
{
|
||||
target = UTF8::escape(source.begin(), source.end());
|
||||
target = toJSON(source);
|
||||
}
|
||||
|
||||
|
||||
@ -53,11 +53,9 @@ bool isJSONString(const Var& any)
|
||||
|
||||
void appendJSONString(std::string& val, const Var& any)
|
||||
{
|
||||
std::string json(val);
|
||||
val.append(1, '"');
|
||||
std::string json;
|
||||
escape(json, any.convert<std::string>());
|
||||
val.append(json);
|
||||
val.append(1, '"');
|
||||
}
|
||||
|
||||
|
||||
|
@ -16,6 +16,7 @@
|
||||
#include "Poco/MemoryStream.h"
|
||||
#include "Poco/Stopwatch.h"
|
||||
#include "Poco/Exception.h"
|
||||
#include "Poco/JSONString.h"
|
||||
#include <iostream>
|
||||
#include <iomanip>
|
||||
#include <cstdio>
|
||||
@ -57,6 +58,7 @@ using Poco::CILess;
|
||||
using Poco::MemoryInputStream;
|
||||
using Poco::Stopwatch;
|
||||
using Poco::RangeException;
|
||||
using Poco::toJSON;
|
||||
|
||||
|
||||
StringTest::StringTest(const std::string& name): CppUnit::TestCase(name)
|
||||
@ -1078,6 +1080,68 @@ void StringTest::benchmarkFloatToStr()
|
||||
}
|
||||
|
||||
|
||||
void StringTest::testJSONString()
|
||||
{
|
||||
assert (toJSON("\\", false) == "\\\\");
|
||||
assert (toJSON("\"", false) == "\\\"");
|
||||
assert (toJSON("/", false) == "\\/");
|
||||
assert (toJSON("\a", false) == "\\a");
|
||||
assert (toJSON("\b", false) == "\\b");
|
||||
assert (toJSON("\f", false) == "\\f");
|
||||
assert (toJSON("\n", false) == "\\n");
|
||||
assert (toJSON("\r", false) == "\\r");
|
||||
assert (toJSON("\t", false) == "\\t");
|
||||
assert (toJSON("\v", false) == "\\v");
|
||||
assert (toJSON("a", false) == "a");
|
||||
assert (toJSON("\xD0\x82", false) == "\xD0\x82");
|
||||
assert (toJSON("\xD0\x82", false, true) == "\\u0402");
|
||||
|
||||
// ??? 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\"");
|
||||
assert (toJSON("\xD0\x82", true) == "\"\xD0\x82\"");
|
||||
assert (toJSON("\xD0\x82", true, true) == "\"\\u0402\"");
|
||||
|
||||
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("");
|
||||
toJSON("\xD0\x82", ostr);
|
||||
assert(ostr.str() == "\"\xD0\x82\"");
|
||||
ostr.str("");
|
||||
toJSON("\xD0\x82", ostr, true, true);
|
||||
assert(ostr.str() == "\"\\u0402\"");
|
||||
ostr.str("");
|
||||
}
|
||||
|
||||
|
||||
void StringTest::setUp()
|
||||
{
|
||||
}
|
||||
@ -1118,6 +1182,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;
|
||||
}
|
||||
|
@ -55,6 +55,8 @@ public:
|
||||
void testFloatToString();
|
||||
void benchmarkFloatToStr();
|
||||
|
||||
void testJSONString();
|
||||
|
||||
void setUp();
|
||||
void tearDown();
|
||||
|
||||
|
@ -63,8 +63,11 @@ public:
|
||||
typedef std::vector<Dynamic::Var>::const_iterator ConstIterator;
|
||||
typedef SharedPtr<Array> Ptr;
|
||||
|
||||
Array();
|
||||
Array(bool escapeUnicode = false);
|
||||
/// Creates an empty Array.
|
||||
///
|
||||
/// If escapeUnicode is true, when the object is stringified, all unicode
|
||||
/// characters will be escaped in the resulting string.
|
||||
|
||||
Array(const Array& copy);
|
||||
/// Creates an Array by copying another one.
|
||||
@ -85,6 +88,12 @@ public:
|
||||
virtual ~Array();
|
||||
/// Destroys the Array.
|
||||
|
||||
void setEscapeUnicode(bool escape = true);
|
||||
/// Sets the flag for escaping unicode.
|
||||
|
||||
bool getEscapeUnicode() const;
|
||||
/// Returns the flag for escaping unicode.
|
||||
|
||||
ValueVec::const_iterator begin() const;
|
||||
/// Returns the begin iterator for values.
|
||||
|
||||
@ -192,12 +201,30 @@ private:
|
||||
ValueVec _values;
|
||||
mutable ArrayPtr _pArray;
|
||||
mutable bool _modified;
|
||||
// Note:
|
||||
// The reason we have this flag here (rather than as argument to stringify())
|
||||
// is because Array can be returned stringified from a Dynamic::Var:toString(),
|
||||
// so it must know whether to escape unicode or not.
|
||||
bool _escapeUnicode;
|
||||
};
|
||||
|
||||
|
||||
//
|
||||
// inlines
|
||||
//
|
||||
|
||||
inline void Array::setEscapeUnicode(bool escape)
|
||||
{
|
||||
_escapeUnicode = true;
|
||||
}
|
||||
|
||||
|
||||
inline bool Array::getEscapeUnicode() const
|
||||
{
|
||||
return _escapeUnicode;
|
||||
}
|
||||
|
||||
|
||||
inline Array::ValueVec::const_iterator Array::begin() const
|
||||
{
|
||||
return _values.begin();
|
||||
|
@ -37,8 +37,13 @@ namespace JSON {
|
||||
|
||||
|
||||
class JSON_API Object
|
||||
<<<<<<< HEAD
|
||||
/// Represents a JSON object. Object provides a representation
|
||||
/// based on shared pointers and optimized for performance. It is possible to
|
||||
=======
|
||||
/// Represents a JSON object. Object provides a representation based on
|
||||
/// shared pointers and optimized for performance. It is possible to
|
||||
>>>>>>> df5968ce1... Json unicode escape && preserveOrder keys sync (#2145)
|
||||
/// convert Object to DynamicStruct. Conversion requires copying and therefore
|
||||
/// has performance penalty; the benefit is in improved syntax, eg:
|
||||
///
|
||||
@ -56,7 +61,7 @@ class JSON_API Object
|
||||
/// // copy/convert to Poco::DynamicStruct
|
||||
/// Poco::DynamicStruct ds = *object;
|
||||
/// val = ds["test"]["property"]; // val holds "value"
|
||||
/// ----
|
||||
///
|
||||
{
|
||||
public:
|
||||
typedef SharedPtr<Object> Ptr;
|
||||
@ -64,12 +69,36 @@ public:
|
||||
typedef ValueMap::value_type ValueType;
|
||||
typedef ValueMap::iterator Iterator;
|
||||
typedef ValueMap::const_iterator ConstIterator;
|
||||
typedef std::vector<std::string> NameList;
|
||||
|
||||
explicit Object(bool preserveInsertionOrder = false);
|
||||
enum Options
|
||||
{
|
||||
JSON_PRESERVE_KEY_ORDER = 1,
|
||||
/// If specified, the object will preserve the items
|
||||
/// insertion order. Otherwise, items will be sorted
|
||||
/// by keys.
|
||||
|
||||
JSON_ESCAPE_UNICODE = 2
|
||||
/// If specified, when the object is stringified, all
|
||||
/// unicode characters will be escaped in the resulting
|
||||
/// string.
|
||||
};
|
||||
|
||||
explicit Object(int options = 0);
|
||||
/// Creates an empty Object.
|
||||
///
|
||||
<<<<<<< HEAD
|
||||
/// If preserveInsertionOrder, object will preserve the items insertion
|
||||
/// order. Otherwise, items will be sorted by keys.
|
||||
=======
|
||||
/// If JSON_PRESERVE_KEY_ORDER is specified, the object will
|
||||
/// preserve the items insertion order. Otherwise, items will be
|
||||
/// sorted by keys.
|
||||
///
|
||||
/// If JSON_ESCAPE_UNICODE is specified, when the object is
|
||||
/// stringified, all unicode characters will be escaped in the
|
||||
/// resulting string.
|
||||
>>>>>>> df5968ce1... Json unicode escape && preserveOrder keys sync (#2145)
|
||||
|
||||
Object(const Object& copy);
|
||||
/// Creates an Object by copying another one.
|
||||
@ -93,25 +122,33 @@ public:
|
||||
Object &operator =(const Object &other);
|
||||
// Assignment operator
|
||||
|
||||
<<<<<<< HEAD
|
||||
Iterator begin()
|
||||
{
|
||||
return _values.begin();
|
||||
}
|
||||
=======
|
||||
Object &operator =(Object &&other);
|
||||
// Move asignment operator
|
||||
|
||||
ConstIterator begin() const
|
||||
{
|
||||
return _values.begin();
|
||||
}
|
||||
void setEscapeUnicode(bool escape = true);
|
||||
/// Sets the flag for escaping unicode.
|
||||
>>>>>>> df5968ce1... Json unicode escape && preserveOrder keys sync (#2145)
|
||||
|
||||
Iterator end()
|
||||
{
|
||||
return _values.end();
|
||||
}
|
||||
bool getEscapeUnicode() const;
|
||||
/// Returns the flag for escaping unicode.
|
||||
|
||||
ConstIterator end() const
|
||||
{
|
||||
return _values.end();
|
||||
}
|
||||
Iterator begin();
|
||||
/// Returns begin iterator for values.
|
||||
|
||||
ConstIterator begin() const;
|
||||
/// Returns const begin iterator for values.
|
||||
|
||||
Iterator end();
|
||||
/// Returns end iterator for values.
|
||||
|
||||
ConstIterator end() const;
|
||||
/// Returns const end iterator for values.
|
||||
|
||||
Dynamic::Var get(const std::string& key) const;
|
||||
/// Retrieves a property. An empty value is
|
||||
@ -155,7 +192,10 @@ public:
|
||||
return value.convert<T>();
|
||||
}
|
||||
|
||||
void getNames(std::vector<std::string>& names) const;
|
||||
void getNames(NameList& names) const;
|
||||
/// Fills the supplied vector with all property names.
|
||||
|
||||
NameList getNames() const;
|
||||
/// Returns all property names.
|
||||
|
||||
bool has(const std::string& key) const;
|
||||
@ -225,7 +265,11 @@ public:
|
||||
/// Insertion order preservation property is left intact.
|
||||
|
||||
private:
|
||||
typedef std::deque<ValueMap::const_iterator> KeyList;
|
||||
typedef Poco::DynamicStruct::Ptr StructPtr;
|
||||
|
||||
void resetDynStruct() const;
|
||||
void syncKeys(const KeyList& keys);
|
||||
|
||||
template <typename C>
|
||||
void doStringify(const C& container, std::ostream& out, unsigned int indent, unsigned int step) const
|
||||
@ -233,17 +277,17 @@ private:
|
||||
out << '{';
|
||||
|
||||
if (indent > 0) out << std::endl;
|
||||
|
||||
|
||||
typename C::const_iterator it = container.begin();
|
||||
typename C::const_iterator end = container.end();
|
||||
for (; it != end;)
|
||||
{
|
||||
for (unsigned int i = 0; i < indent; i++) out << ' ';
|
||||
|
||||
Stringifier::stringify(getKey(it), out);
|
||||
Stringifier::stringify(getKey(it), out, indent, step, _escapeUnicode);
|
||||
out << ((indent > 0) ? " : " : ":");
|
||||
|
||||
Stringifier::stringify(getValue(it), out, indent + step, step);
|
||||
Stringifier::stringify(getValue(it), out, indent + step, step, _escapeUnicode);
|
||||
|
||||
if (++it != container.end()) out << ',';
|
||||
|
||||
@ -257,17 +301,19 @@ private:
|
||||
out << '}';
|
||||
}
|
||||
|
||||
typedef std::deque<const std::string*> KeyPtrList;
|
||||
typedef Poco::DynamicStruct::Ptr StructPtr;
|
||||
|
||||
const std::string& getKey(ValueMap::const_iterator& it) const;
|
||||
const Dynamic::Var& getValue(ValueMap::const_iterator& it) const;
|
||||
const std::string& getKey(KeyPtrList::const_iterator& it) const;
|
||||
const Dynamic::Var& getValue(KeyPtrList::const_iterator& it) const;
|
||||
const std::string& getKey(KeyList::const_iterator& it) const;
|
||||
const Dynamic::Var& getValue(KeyList::const_iterator& it) const;
|
||||
|
||||
ValueMap _values;
|
||||
KeyPtrList _keys;
|
||||
KeyList _keys;
|
||||
bool _preserveInsOrder;
|
||||
// Note:
|
||||
// The reason for this flag (rather than as argument to stringify()) is
|
||||
// because Object can be returned stringified from Dynamic::Var::toString(),
|
||||
// so it must know whether to escape unicode or not.
|
||||
bool _escapeUnicode;
|
||||
mutable StructPtr _pStruct;
|
||||
mutable bool _modified;
|
||||
};
|
||||
@ -276,6 +322,43 @@ private:
|
||||
//
|
||||
// inlines
|
||||
//
|
||||
|
||||
inline void Object::setEscapeUnicode(bool escape)
|
||||
{
|
||||
_escapeUnicode = true;
|
||||
}
|
||||
|
||||
|
||||
inline bool Object::getEscapeUnicode() const
|
||||
{
|
||||
return _escapeUnicode;
|
||||
}
|
||||
|
||||
|
||||
inline Object::Iterator Object::begin()
|
||||
{
|
||||
return _values.begin();
|
||||
}
|
||||
|
||||
|
||||
inline Object::ConstIterator Object::begin() const
|
||||
{
|
||||
return _values.begin();
|
||||
}
|
||||
|
||||
|
||||
inline Object::Iterator Object::end()
|
||||
{
|
||||
return _values.end();
|
||||
}
|
||||
|
||||
|
||||
inline Object::ConstIterator Object::end() const
|
||||
{
|
||||
return _values.end();
|
||||
}
|
||||
|
||||
|
||||
inline bool Object::has(const std::string& key) const
|
||||
{
|
||||
ValueMap::const_iterator it = _values.find(key);
|
||||
@ -329,11 +412,11 @@ inline void Object::remove(const std::string& key)
|
||||
_values.erase(key);
|
||||
if (_preserveInsOrder)
|
||||
{
|
||||
KeyPtrList::iterator it = _keys.begin();
|
||||
KeyPtrList::iterator end = _keys.end();
|
||||
KeyList::iterator it = _keys.begin();
|
||||
KeyList::iterator end = _keys.end();
|
||||
for (; it != end; ++it)
|
||||
{
|
||||
if (key == **it)
|
||||
if (key == (*it)->first)
|
||||
{
|
||||
_keys.erase(it);
|
||||
break;
|
||||
@ -356,9 +439,9 @@ inline const Dynamic::Var& Object::getValue(ValueMap::const_iterator& it) const
|
||||
}
|
||||
|
||||
|
||||
inline const Dynamic::Var& Object::getValue(KeyPtrList::const_iterator& it) const
|
||||
inline const Dynamic::Var& Object::getValue(KeyList::const_iterator& it) const
|
||||
{
|
||||
ValueMap::const_iterator itv = _values.find(**it);
|
||||
ValueMap::const_iterator itv = _values.find((*it)->first);
|
||||
if (itv != _values.end())
|
||||
return itv->second;
|
||||
else
|
||||
|
@ -31,26 +31,29 @@ class JSON_API Stringifier
|
||||
/// Helper class for creating a string from a JSON object or array.
|
||||
{
|
||||
public:
|
||||
static void condense(const Dynamic::Var& any, std::ostream& out);
|
||||
static void condense(const Dynamic::Var& any, std::ostream& out, bool escapeUnicode = false);
|
||||
/// Writes a condensed string representation of the value to the output stream while preserving the insertion order.
|
||||
///
|
||||
/// This is just a "shortcut" to stringify(any, out) with name indicating the function effect.
|
||||
|
||||
static void stringify(const Dynamic::Var& any, std::ostream& out, unsigned int indent = 0, int step = -1);
|
||||
static void stringify(const Dynamic::Var& any, std::ostream& out, unsigned int indent = 0, int step = -1, bool escapeUnicode = false);
|
||||
/// Writes a string representation of the value to the output stream.
|
||||
///
|
||||
/// When indent is 0, the string will be created as small as possible.
|
||||
/// When preserveInsertionOrder is true, the original string object members order will be preserved;
|
||||
/// otherwise, object members are sorted by their names.
|
||||
/// Indentation is increased/decreased using number of spaces defined in step.
|
||||
/// The default value -1 for step indicates that step will be equal to the
|
||||
/// indent size.
|
||||
/// If escapeUnicode is true, all unicode characers will be escaped in the
|
||||
/// resulting string.
|
||||
|
||||
static void formatString(const std::string& value, std::ostream& out);
|
||||
static void formatString(const std::string& value, std::ostream& out, bool escapeUnicode = false);
|
||||
/// Formats the JSON string and streams it into ostream.
|
||||
};
|
||||
|
||||
|
||||
inline void Stringifier::condense(const Dynamic::Var& any, std::ostream& out)
|
||||
inline void Stringifier::condense(const Dynamic::Var& any, std::ostream& out, bool escapeUnicode)
|
||||
{
|
||||
stringify(any, out, 0, -1);
|
||||
stringify(any, out, 0, -1, escapeUnicode);
|
||||
}
|
||||
|
||||
|
||||
|
@ -24,7 +24,8 @@ namespace Poco {
|
||||
namespace JSON {
|
||||
|
||||
|
||||
Array::Array(): _modified(false)
|
||||
Array::Array(bool escapeUnicode): _modified(false),
|
||||
_escapeUnicode(escapeUnicode)
|
||||
{
|
||||
}
|
||||
|
||||
@ -162,7 +163,7 @@ void Array::stringify(std::ostream& out, unsigned int indent, int step) const
|
||||
{
|
||||
for (int i = 0; i < indent; i++) out << ' ';
|
||||
|
||||
Stringifier::stringify(*it, out, indent + step, step);
|
||||
Stringifier::stringify(*it, out, indent + step, step, _escapeUnicode);
|
||||
|
||||
if (++it != _values.end())
|
||||
{
|
||||
@ -175,8 +176,7 @@ void Array::stringify(std::ostream& out, unsigned int indent, int step) const
|
||||
|
||||
if (indent >= step) indent -= step;
|
||||
|
||||
for (int i = 0; i < indent; i++)
|
||||
out << ' ';
|
||||
for (int i = 0; i < indent; i++) out << ' ';
|
||||
|
||||
out << "]";
|
||||
}
|
||||
|
@ -24,28 +24,22 @@ namespace Poco {
|
||||
namespace JSON {
|
||||
|
||||
|
||||
Object::Object(bool preserveInsOrder):
|
||||
_preserveInsOrder(preserveInsOrder),
|
||||
|
||||
Object::Object(int options):
|
||||
_preserveInsOrder(options & JSON_PRESERVE_KEY_ORDER),
|
||||
_escapeUnicode(options & JSON_ESCAPE_UNICODE),
|
||||
_modified(false)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
Object::Object(const Object& copy) : _values(copy._values),
|
||||
_preserveInsOrder(copy._preserveInsOrder),
|
||||
_pStruct(!copy._modified ? copy._pStruct : 0),
|
||||
_modified(copy._modified)
|
||||
Object::Object(const Object& other) : _values(other._values),
|
||||
_preserveInsOrder(other._preserveInsOrder),
|
||||
_escapeUnicode(other._escapeUnicode),
|
||||
_pStruct(!other._modified ? other._pStruct : 0),
|
||||
_modified(other._modified)
|
||||
{
|
||||
if (_preserveInsOrder)
|
||||
{
|
||||
// need to update pointers in _keys to point to copied _values
|
||||
for (KeyPtrList::const_iterator it = copy._keys.begin(); it != copy._keys.end(); ++it)
|
||||
{
|
||||
ValueMap::const_iterator itv = _values.find(**it);
|
||||
poco_assert (itv != _values.end());
|
||||
_keys.push_back(&itv->first);
|
||||
}
|
||||
}
|
||||
syncKeys(other._keys);
|
||||
}
|
||||
|
||||
|
||||
@ -56,9 +50,11 @@ Object::Object(Object&& other) :
|
||||
_values(std::move(other._values)),
|
||||
_keys(std::move(other._keys)),
|
||||
_preserveInsOrder(other._preserveInsOrder),
|
||||
_escapeUnicode(other._escapeUnicode),
|
||||
_pStruct(!other._modified ? other._pStruct : 0),
|
||||
_modified(other._modified)
|
||||
{
|
||||
other.clear();
|
||||
}
|
||||
|
||||
|
||||
@ -66,9 +62,15 @@ Object &Object::operator= (Object &&other)
|
||||
{
|
||||
if (&other != this)
|
||||
{
|
||||
<<<<<<< HEAD
|
||||
_values = std::move(other._values);
|
||||
_keys = std::move(other._keys);
|
||||
=======
|
||||
_values = other._values;
|
||||
>>>>>>> df5968ce1... Json unicode escape && preserveOrder keys sync (#2145)
|
||||
_preserveInsOrder = other._preserveInsOrder;
|
||||
syncKeys(other._keys);
|
||||
_escapeUnicode = other._escapeUnicode;
|
||||
_pStruct = !other._modified ? other._pStruct : 0;
|
||||
_modified = other._modified;
|
||||
}
|
||||
@ -91,13 +93,30 @@ Object &Object::operator= (const Object &other)
|
||||
_values = other._values;
|
||||
_keys = other._keys;
|
||||
_preserveInsOrder = other._preserveInsOrder;
|
||||
_escapeUnicode = other._escapeUnicode;
|
||||
_pStruct = !other._modified ? other._pStruct : 0;
|
||||
_modified = other._modified;
|
||||
other.clear();
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
void Object::syncKeys(const KeyList& keys)
|
||||
{
|
||||
if(_preserveInsOrder)
|
||||
{
|
||||
// update iterators in _keys to point to copied _values
|
||||
for(KeyList::const_iterator it = keys.begin(); it != keys.end(); ++it)
|
||||
{
|
||||
ValueMap::const_iterator itv = _values.find((*it)->first);
|
||||
poco_assert (itv != _values.end());
|
||||
_keys.push_back(itv);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Var Object::get(const std::string& key) const
|
||||
{
|
||||
ValueMap::const_iterator it = _values.find(key);
|
||||
@ -134,13 +153,31 @@ Object::Ptr Object::getObject(const std::string& key) const
|
||||
}
|
||||
|
||||
|
||||
void Object::getNames(std::vector<std::string>& names) const
|
||||
void Object::getNames(NameList& names) const
|
||||
{
|
||||
names.clear();
|
||||
for (ValueMap::const_iterator it = _values.begin(); it != _values.end(); ++it)
|
||||
if (_preserveInsOrder)
|
||||
{
|
||||
names.push_back(it->first);
|
||||
for(KeyList::const_iterator it = _keys.begin(); it != _keys.end(); ++it)
|
||||
{
|
||||
names.push_back((*it)->first);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for(ValueMap::const_iterator it = _values.begin(); it != _values.end(); ++it)
|
||||
{
|
||||
names.push_back(it->first);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Object::NameList Object::getNames() const
|
||||
{
|
||||
NameList names;
|
||||
getNames(names);
|
||||
return names;
|
||||
}
|
||||
|
||||
|
||||
@ -155,16 +192,16 @@ void Object::stringify(std::ostream& out, unsigned int indent, int step) const
|
||||
}
|
||||
|
||||
|
||||
const std::string& Object::getKey(KeyPtrList::const_iterator& iter) const
|
||||
const std::string& Object::getKey(KeyList::const_iterator& iter) const
|
||||
{
|
||||
ValueMap::const_iterator it = _values.begin();
|
||||
ValueMap::const_iterator end = _values.end();
|
||||
for (; it != end; ++it)
|
||||
{
|
||||
if (it->first == **iter) return it->first;
|
||||
if (it == *iter) return it->first;
|
||||
}
|
||||
|
||||
throw NotFoundException(**iter);
|
||||
throw NotFoundException((*iter)->first);
|
||||
}
|
||||
|
||||
|
||||
@ -174,13 +211,13 @@ void Object::set(const std::string& key, const Dynamic::Var& value)
|
||||
if (!ret.second) ret.first->second = value;
|
||||
if (_preserveInsOrder)
|
||||
{
|
||||
KeyPtrList::iterator it = _keys.begin();
|
||||
KeyPtrList::iterator end = _keys.end();
|
||||
KeyList::iterator it = _keys.begin();
|
||||
KeyList::iterator end = _keys.end();
|
||||
for (; it != end; ++it)
|
||||
{
|
||||
if (key == **it) return;
|
||||
if (key == (*it)->first) return;
|
||||
}
|
||||
_keys.push_back(&ret.first->first);
|
||||
_keys.push_back(ret.first);
|
||||
}
|
||||
_modified = true;
|
||||
}
|
||||
|
@ -26,28 +26,32 @@ namespace Poco {
|
||||
namespace JSON {
|
||||
|
||||
|
||||
void Stringifier::stringify(const Var& any, std::ostream& out, unsigned int indent, int step)
|
||||
void Stringifier::stringify(const Var& any, std::ostream& out, unsigned int indent, int step, bool escapeUnicode)
|
||||
{
|
||||
if (step == -1) step = indent;
|
||||
|
||||
if (any.type() == typeid(Object))
|
||||
{
|
||||
const Object& o = any.extract<Object>();
|
||||
Object& o = const_cast<Object&>(any.extract<Object>());
|
||||
o.setEscapeUnicode(escapeUnicode);
|
||||
o.stringify(out, indent == 0 ? 0 : indent, step);
|
||||
}
|
||||
else if (any.type() == typeid(Array))
|
||||
{
|
||||
const Array& a = any.extract<Array>();
|
||||
Array& a = const_cast<Array&>(any.extract<Array>());
|
||||
a.setEscapeUnicode(escapeUnicode);
|
||||
a.stringify(out, indent == 0 ? 0 : indent, step);
|
||||
}
|
||||
else if (any.type() == typeid(Object::Ptr))
|
||||
{
|
||||
const Object::Ptr& o = any.extract<Object::Ptr>();
|
||||
Object::Ptr& o = const_cast<Object::Ptr&>(any.extract<Object::Ptr>());
|
||||
o->setEscapeUnicode(escapeUnicode);
|
||||
o->stringify(out, indent == 0 ? 0 : indent, step);
|
||||
}
|
||||
else if (any.type() == typeid(Array::Ptr))
|
||||
{
|
||||
const Array::Ptr& a = any.extract<Array::Ptr>();
|
||||
Array::Ptr& a = const_cast<Array::Ptr&>(any.extract<Array::Ptr>());
|
||||
a->setEscapeUnicode(escapeUnicode);
|
||||
a->stringify(out, indent == 0 ? 0 : indent, step);
|
||||
}
|
||||
else if (any.isEmpty())
|
||||
@ -57,13 +61,13 @@ void Stringifier::stringify(const Var& any, std::ostream& out, unsigned int inde
|
||||
else if (any.isNumeric() || any.isBoolean())
|
||||
{
|
||||
std::string value = any.convert<std::string>();
|
||||
if (any.type() == typeid(char)) formatString(value, out);
|
||||
if (any.type() == typeid(char)) formatString(value, out, escapeUnicode);
|
||||
else out << value;
|
||||
}
|
||||
else if (any.isString() || any.isDateTime() || any.isDate() || any.isTime())
|
||||
{
|
||||
std::string value = any.convert<std::string>();
|
||||
formatString(value, out);
|
||||
formatString(value, out, escapeUnicode);
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -72,9 +76,9 @@ void Stringifier::stringify(const Var& any, std::ostream& out, unsigned int inde
|
||||
}
|
||||
|
||||
|
||||
void Stringifier::formatString(const std::string& value, std::ostream& out)
|
||||
void Stringifier::formatString(const std::string& value, std::ostream& out, bool escapeUnicode)
|
||||
{
|
||||
Poco::toJSON(value, out);
|
||||
Poco::toJSON(value, out, true, escapeUnicode);
|
||||
}
|
||||
|
||||
|
||||
|
@ -481,6 +481,13 @@ void JSONTest::testComplexObject()
|
||||
Object::Ptr object = result.extract<Object::Ptr>();
|
||||
assert(object->size() > 0);
|
||||
|
||||
Object::NameList names = object->getNames();
|
||||
assert (names.size() == 4);
|
||||
assert (names[0] == "id");
|
||||
assert (names[1] == "jsonrpc");
|
||||
assert (names[2] == "result");
|
||||
assert (names[3] == "total");
|
||||
|
||||
DynamicStruct ds = *object;
|
||||
assert (ds.size() > 0);
|
||||
assert (ds["id"] == 1);
|
||||
@ -1374,7 +1381,7 @@ void JSONTest::testStringify()
|
||||
|
||||
std::string str1 = "\r";
|
||||
std::string str2 = "\n";
|
||||
Poco::JSON::Object obj1, obj2;
|
||||
Object obj1, obj2;
|
||||
obj1.set("payload", str1);
|
||||
obj2.set("payload", str2);
|
||||
std::ostringstream oss1, oss2;
|
||||
@ -1526,13 +1533,19 @@ void JSONTest::testStringify()
|
||||
|
||||
void JSONTest::testStringifyPreserveOrder()
|
||||
{
|
||||
Object presObj(true);
|
||||
Object presObj(Object::JSON_PRESERVE_KEY_ORDER);
|
||||
presObj.set("foo", 0);
|
||||
presObj.set("bar", 0);
|
||||
presObj.set("baz", 0);
|
||||
std::stringstream ss;
|
||||
presObj.stringify(ss);
|
||||
assert(ss.str() == "{\"foo\":0,\"bar\":0,\"baz\":0}");
|
||||
Object::NameList nl = presObj.getNames();
|
||||
assert (nl.size() == 3);
|
||||
assert (nl[0] == "foo");
|
||||
assert (nl[1] == "bar");
|
||||
assert (nl[2] == "baz");
|
||||
|
||||
ss.str("");
|
||||
Stringifier::stringify(presObj, ss);
|
||||
assert(ss.str() == "{\"foo\":0,\"bar\":0,\"baz\":0}");
|
||||
@ -1918,7 +1931,8 @@ void JSONTest::testEscape0()
|
||||
assert(ss.str().compare("{\"name\":\"B\\u0000b\"}") == 0);
|
||||
}
|
||||
|
||||
void JSONTest::testEscapeUnicode()
|
||||
|
||||
void JSONTest::testNonEscapeUnicode()
|
||||
{
|
||||
Poco::JSON::Object::Ptr json = new Poco::JSON::Object();
|
||||
std::string chinese("{ \"name\" : \"\\u4e2d\" }");
|
||||
@ -1931,16 +1945,43 @@ void JSONTest::testEscapeUnicode()
|
||||
|
||||
std::stringstream ss;
|
||||
object->stringify(ss);
|
||||
|
||||
assert(ss.str().compare("{\"name\":\"\\u4E2D\"}") == 0);
|
||||
assert(ss.str().compare("{\"name\":\"\xE4\xB8\xAD\"}") == 0);
|
||||
|
||||
const unsigned char utf8Chars[] = {'{', '"', 'n', 'a', 'm', 'e', '"', ':',
|
||||
'"', 'g', 195, 188, 'n', 't', 'e', 'r', '"', '}', 0};
|
||||
'"', 'g', 0xC3, 0xBC, 'n', 't', 'e', 'r', '"', '}', 0};
|
||||
std::string utf8Text((const char*) utf8Chars);
|
||||
parser.reset();
|
||||
result = parser.parse(utf8Text);
|
||||
object = result.extract<Object::Ptr>();
|
||||
ss.str(""); object->stringify(ss);
|
||||
assert (ss.str() == "{\"name\":\"g\xC3\xBCnter\"}");
|
||||
}
|
||||
|
||||
|
||||
void JSONTest::testEscapeUnicode()
|
||||
{
|
||||
Poco::JSON::Object::Ptr json = new Poco::JSON::Object();
|
||||
std::string chinese("{ \"name\" : \"\\u4e2d\" }");
|
||||
Poco::JSON::Parser parser(new Poco::JSON::ParseHandler());
|
||||
Var result = parser.parse(chinese);
|
||||
|
||||
assert(result.type() == typeid(Object::Ptr));
|
||||
|
||||
Object::Ptr object = result.extract<Object::Ptr>();
|
||||
object->setEscapeUnicode(true);
|
||||
|
||||
std::stringstream ss;
|
||||
object->stringify(ss, 0, -1);
|
||||
assert(ss.str().compare("{\"name\":\"\\u4E2D\"}") == 0);
|
||||
|
||||
const unsigned char utf8Chars[] = {'{', '"', 'n', 'a', 'm', 'e', '"', ':',
|
||||
'"', 'g', 0xC3, 0xBC, 'n', 't', 'e', 'r', '"', '}', 0};
|
||||
std::string utf8Text((const char*) utf8Chars);
|
||||
parser.reset();
|
||||
result = parser.parse(utf8Text);
|
||||
object = result.extract<Object::Ptr>();
|
||||
object->setEscapeUnicode(true);
|
||||
ss.str(""); object->stringify(ss, 0, -1);
|
||||
assert (ss.str() == "{\"name\":\"g\\u00FCnter\"}");
|
||||
}
|
||||
|
||||
@ -1974,6 +2015,125 @@ std::string JSONTest::getTestFilesPath(const std::string& type)
|
||||
}
|
||||
|
||||
|
||||
void JSONTest::testCopy()
|
||||
{
|
||||
Object obj1(Object::JSON_PRESERVE_KEY_ORDER);
|
||||
obj1.set("foo", 0);
|
||||
obj1.set("bar", 0);
|
||||
obj1.set("baz", 0);
|
||||
|
||||
Object::NameList nl = obj1.getNames();
|
||||
assert (nl.size() == 3);
|
||||
assert (nl[0] == "foo");
|
||||
assert (nl[1] == "bar");
|
||||
assert (nl[2] == "baz");
|
||||
|
||||
Object obj2;
|
||||
obj2 = obj1;
|
||||
nl = obj2.getNames();
|
||||
assert (nl.size() == 3);
|
||||
assert (nl[0] == "foo");
|
||||
assert (nl[1] == "bar");
|
||||
assert (nl[2] == "baz");
|
||||
|
||||
Object obj3;
|
||||
obj3.set("foo", 0);
|
||||
obj3.set("bar", 0);
|
||||
obj3.set("baz", 0);
|
||||
nl = obj3.getNames();
|
||||
assert (nl.size() == 3);
|
||||
assert (nl[0] == "bar");
|
||||
assert (nl[1] == "baz");
|
||||
assert (nl[2] == "foo");
|
||||
|
||||
Object obj4;
|
||||
obj4 = obj3;
|
||||
nl = obj4.getNames();
|
||||
assert (nl.size() == 3);
|
||||
assert (nl[0] == "bar");
|
||||
assert (nl[1] == "baz");
|
||||
assert (nl[2] == "foo");
|
||||
|
||||
obj4 = obj1;
|
||||
nl = obj4.getNames();
|
||||
assert (nl.size() == 3);
|
||||
assert (nl[0] == "foo");
|
||||
assert (nl[1] == "bar");
|
||||
assert (nl[2] == "baz");
|
||||
|
||||
Object obj5(obj1);
|
||||
nl = obj5.getNames();
|
||||
assert (nl.size() == 3);
|
||||
assert (nl[0] == "foo");
|
||||
assert (nl[1] == "bar");
|
||||
assert (nl[2] == "baz");
|
||||
}
|
||||
|
||||
|
||||
void JSONTest::testMove()
|
||||
{
|
||||
Object obj1(Object::JSON_PRESERVE_KEY_ORDER);
|
||||
obj1.set("foo", 0);
|
||||
obj1.set("bar", 0);
|
||||
obj1.set("baz", 0);
|
||||
|
||||
Object::NameList nl = obj1.getNames();
|
||||
assert (nl.size() == 3);
|
||||
assert (nl[0] == "foo");
|
||||
assert (nl[1] == "bar");
|
||||
assert (nl[2] == "baz");
|
||||
|
||||
Object obj2;
|
||||
obj2 = std::move(obj1);
|
||||
assert (obj1.getNames().size() == 0);
|
||||
|
||||
nl = obj2.getNames();
|
||||
assert (nl.size() == 3);
|
||||
assert (nl[0] == "foo");
|
||||
assert (nl[1] == "bar");
|
||||
assert (nl[2] == "baz");
|
||||
|
||||
Object obj3;
|
||||
obj3.set("foo", 0);
|
||||
obj3.set("bar", 0);
|
||||
obj3.set("baz", 0);
|
||||
nl = obj3.getNames();
|
||||
assert (nl.size() == 3);
|
||||
assert (nl[0] == "bar");
|
||||
assert (nl[1] == "baz");
|
||||
assert (nl[2] == "foo");
|
||||
|
||||
Object obj4;
|
||||
obj4 = std::move(obj3);
|
||||
assert (obj3.getNames().size() == 0);
|
||||
|
||||
nl = obj4.getNames();
|
||||
assert (nl.size() == 3);
|
||||
assert (nl[0] == "bar");
|
||||
assert (nl[1] == "baz");
|
||||
assert (nl[2] == "foo");
|
||||
|
||||
Object obj5(Object::JSON_PRESERVE_KEY_ORDER);
|
||||
obj5.set("foo", 0);
|
||||
obj5.set("bar", 0);
|
||||
obj5.set("baz", 0);
|
||||
nl = obj5.getNames();
|
||||
assert (nl.size() == 3);
|
||||
assert (nl[0] == "foo");
|
||||
assert (nl[1] == "bar");
|
||||
assert (nl[2] == "baz");
|
||||
|
||||
obj4 = std::move(obj5);
|
||||
assert (obj5.getNames().size() == 0);
|
||||
|
||||
nl = obj4.getNames();
|
||||
assert (nl.size() == 3);
|
||||
assert (nl[0] == "foo");
|
||||
assert (nl[1] == "bar");
|
||||
assert (nl[2] == "baz");
|
||||
}
|
||||
|
||||
|
||||
CppUnit::Test* JSONTest::suite()
|
||||
{
|
||||
CppUnit::TestSuite* pSuite = new CppUnit::TestSuite("JSONTest");
|
||||
@ -2020,7 +2180,10 @@ CppUnit::Test* JSONTest::suite()
|
||||
CppUnit_addTest(pSuite, JSONTest, testUnicode);
|
||||
CppUnit_addTest(pSuite, JSONTest, testSmallBuffer);
|
||||
CppUnit_addTest(pSuite, JSONTest, testEscape0);
|
||||
CppUnit_addTest(pSuite, JSONTest, testNonEscapeUnicode);
|
||||
CppUnit_addTest(pSuite, JSONTest, testEscapeUnicode);
|
||||
CppUnit_addTest(pSuite, JSONTest, testCopy);
|
||||
CppUnit_addTest(pSuite, JSONTest, testMove);
|
||||
|
||||
return pSuite;
|
||||
}
|
||||
|
@ -72,12 +72,16 @@ public:
|
||||
void testValidJanssonFiles();
|
||||
void testInvalidJanssonFiles();
|
||||
void testTemplate();
|
||||
void testItunes();
|
||||
void testUnicode();
|
||||
void testInvalidUnicodeJanssonFiles();
|
||||
void testSmallBuffer();
|
||||
void testEscape0();
|
||||
void testNonEscapeUnicode();
|
||||
void testEscapeUnicode();
|
||||
|
||||
void testCopy();
|
||||
void testMove();
|
||||
|
||||
void setUp();
|
||||
void tearDown();
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user