1
0
mirror of https://github.com/VCMP-SqMod/SqMod.git synced 2025-08-01 21:51:48 +02:00

Update POCO to 1.11.0

This commit is contained in:
Sandu Liviu Catalin
2021-08-22 18:07:06 +03:00
parent 151077c799
commit 7a3d92d1d1
450 changed files with 25219 additions and 6528 deletions

View File

@@ -124,6 +124,9 @@ public:
std::size_t size() const;
/// Returns the size of the array.
bool empty() const;
/// Returns true if the array is empty, false otherwise.
bool isArray(unsigned int index) const;
/// Returns true when the element is an array.
@@ -241,6 +244,12 @@ inline std::size_t Array::size() const
}
inline bool Array::empty() const
{
return _values.empty();
}
inline bool Array::isArray(unsigned int index) const
{
Dynamic::Var value = get(index);

View File

@@ -267,7 +267,7 @@ private:
for (unsigned int i = 0; i < indent; i++) out << ' ';
Stringifier::stringify(getKey(it), out, indent, step, options);
out << ((indent > 0) ? " : " : ":");
out << ((indent > 0) ? ": " : ":");
Stringifier::stringify(getValue(it), out, indent + step, step, options);
@@ -443,7 +443,6 @@ inline std::size_t Object::size() const
inline void Object::remove(const std::string& key)
{
_values.erase(key);
if (_preserveInsOrder)
{
KeyList::iterator it = _keys.begin();
@@ -457,6 +456,7 @@ inline void Object::remove(const std::string& key)
}
}
}
_values.erase(key);
_modified = true;
}

View File

@@ -35,9 +35,9 @@ namespace JSON {
class JSON_API Parser: private ParserImpl
/// A parser for reading RFC 4627 compliant JSON from strings or streams.
///
///
/// Simple usage example:
///
///
/// std::string json = "{ \"name\" : \"Franky\", \"children\" : [ \"Jonas\", \"Ellen\" ] }";
/// Parser parser;
/// Var result = parser.parse(json);
@@ -54,18 +54,18 @@ class JSON_API Parser: private ParserImpl
/// containing a Poco::SharedPtr to an Object or Array instance.
///
/// Example:
///
///
/// std::string json = "{ \"name\" : \"Franky\", \"children\" : [ \"Jonas\", \"Ellen\" ] }";
/// Parser parser;
/// Var result = parser.parse(json);
/// Object::Ptr object = result.extract<Object::Ptr>();
/// std::string name = object.getValue<std::string>("name");
/// Array::Ptr children = object.getArray("children");
/// Object::Ptr pObject = result.extract<Object::Ptr>();
/// std::string name = pObject->getValue<std::string>("name");
/// Array::Ptr pChildren = pObject->getArray("children");
/// ----
{
public:
Parser(const Handler::Ptr& pHandler = new ParseHandler, std::size_t bufSize = JSON_PARSE_BUFFER_SIZE);
Parser(const Handler::Ptr& pHandler = new ParseHandler);
/// Creates JSON Parser, using the given Handler and buffer size.
virtual ~Parser();
@@ -76,16 +76,24 @@ public:
void setAllowComments(bool comments);
/// Allow or disallow comments. By default, comments are not allowed.
///
/// If set to true, comments will be filtered out of the input data
/// before passing the JSON on to the parser. This will impact performance,
/// especially when reading from a std::istream.
bool getAllowComments() const;
/// Returns true if comments are allowed, false otherwise.
///
/// By default, comments are not allowed.
void setAllowNullByte(bool nullByte);
/// Allow or disallow null byte in strings.
/// Allow or disallow null byte in strings.
///
/// By default, null byte is allowed.
/// By default, null byte is allowed (true).
///
/// If set to false, an additional check for "\u0000" will be performed
/// before passing the JSON on to the parser. This will impact performance,
/// especially when reading from a std::istream.
bool getAllowNullByte() const;
/// Returns true if null byte is allowed, false otherwise.
@@ -94,6 +102,10 @@ public:
void setDepth(std::size_t depth);
/// Sets the allowed JSON depth.
///
/// Default maximum depth is 128. Setting this value too high
/// may result in a stack overflow when parsing a (malicious)
/// JSON document.
std::size_t getDepth() const;
/// Returns the allowed JSON depth.

View File

@@ -38,11 +38,9 @@ namespace JSON {
class JSON_API ParserImpl
{
protected:
static const std::size_t JSON_PARSE_BUFFER_SIZE = 4096;
static const std::size_t JSON_PARSER_STACK_SIZE = 128;
static const int JSON_UNLIMITED_DEPTH = -1;
static const std::size_t JSON_DEFAULT_DEPTH = 128;
ParserImpl(const Handler::Ptr& pHandler = new ParseHandler, std::size_t bufSize = JSON_PARSE_BUFFER_SIZE);
ParserImpl(const Handler::Ptr& pHandler = new ParseHandler);
/// Creates JSON ParserImpl, using the given Handler and buffer size.
virtual ~ParserImpl();
@@ -101,12 +99,13 @@ private:
void handleObject();
void handle();
void handle(const std::string& json);
void handle(std::istream& json);
void stripComments(std::string& json);
bool checkError();
struct json_stream* _pJSON;
Handler::Ptr _pHandler;
int _depth;
std::size_t _depth;
char _decimalPoint;
bool _allowNullByte;
bool _allowComments;

View File

@@ -45,7 +45,7 @@ int main(int argc, char** argv)
else
{
std::cout << filePath.toString() << " doesn't exist!" << std::endl;
return 1;
return 1;
}
}
@@ -109,7 +109,7 @@ int main(int argc, char** argv)
std::cout << "-----------------------------------" << std::endl;
std::cout << std::endl;
}
catch(Poco::JSON::JSONException jsone)
catch(Poco::JSON::JSONException& jsone)
{
std::cout << jsone.message() << std::endl;
}

View File

@@ -138,10 +138,7 @@ void ParseHandler::setValue(const Var& value)
_key.clear();
}
}
else
{
throw JSONException("Attempt to set value on an empty stack");
}
else throw JSONException("Attempt to set value on an empty stack");
}

View File

@@ -29,8 +29,8 @@ namespace Poco {
namespace JSON {
Parser::Parser(const Handler::Ptr& pHandler, std::size_t bufSize):
ParserImpl(pHandler, bufSize)
Parser::Parser(const Handler::Ptr& pHandler):
ParserImpl(pHandler)
{
}

View File

@@ -34,10 +34,26 @@ namespace Poco {
namespace JSON {
ParserImpl::ParserImpl(const Handler::Ptr& pHandler, std::size_t bufSize):
extern "C"
{
static int istream_get(void* ptr)
{
std::streambuf* pBuf = reinterpret_cast<std::streambuf*>(ptr);
return pBuf->sbumpc();
}
static int istream_peek(void* ptr)
{
std::streambuf* pBuf = reinterpret_cast<std::streambuf*>(ptr);
return pBuf->sgetc();
}
}
ParserImpl::ParserImpl(const Handler::Ptr& pHandler):
_pJSON(new json_stream),
_pHandler(pHandler),
_depth(JSON_UNLIMITED_DEPTH),
_depth(JSON_DEFAULT_DEPTH),
_decimalPoint('.'),
_allowNullByte(true),
_allowComments(false)
@@ -68,12 +84,34 @@ void ParserImpl::handle(const std::string& json)
// json_open*() call, which calls internal init()
json_set_streaming(_pJSON, false);
/////////////////////////////////
handle(); checkError();
handle();
checkError();
if (JSON_DONE != json_next(_pJSON))
throw JSONException("Excess characters found after JSON end.");
json_close(_pJSON);
}
catch (std::exception&)
catch (...)
{
json_close(_pJSON);
throw;
}
}
void ParserImpl::handle(std::istream& json)
{
try
{
json_open_user(_pJSON, istream_get, istream_peek, json.rdbuf());
checkError();
json_set_streaming(_pJSON, false);
handle();
checkError();
if (JSON_DONE != json_next(_pJSON))
throw JSONException("Excess characters found after JSON end.");
json_close(_pJSON);
}
catch (...)
{
json_close(_pJSON);
throw;
@@ -89,17 +127,33 @@ Dynamic::Var ParserImpl::parseImpl(const std::string& json)
stripComments(str);
handle(str);
}
else handle(json);
else
{
handle(json);
}
return asVarImpl();
}
Dynamic::Var ParserImpl::parseImpl(std::istream& in)
Dynamic::Var ParserImpl::parseImpl(std::istream& json)
{
std::ostringstream os;
StreamCopier::copyStream(in, os);
return parseImpl(os.str());
if (_allowComments || !_allowNullByte)
{
std::string str;
Poco::StreamCopier::copyToString(json, str);
if (_allowComments)
{
stripComments(str);
}
handle(str);
}
else
{
handle(json);
}
return asVarImpl();
}
@@ -139,6 +193,9 @@ void ParserImpl::stripComments(std::string& json)
void ParserImpl::handleArray()
{
if (json_get_depth(_pJSON) > _depth)
throw JSONException("Maximum depth exceeded");
json_type tok = json_peek(_pJSON);
while (tok != JSON_ARRAY_END && checkError())
{
@@ -146,13 +203,19 @@ void ParserImpl::handleArray()
tok = json_peek(_pJSON);
}
if (tok == JSON_ARRAY_END) handle();
if (tok == JSON_ARRAY_END)
{
handle();
}
else throw JSONException("JSON array end not found");
}
void ParserImpl::handleObject()
{
if (json_get_depth(_pJSON) > _depth)
throw JSONException("Maximum depth exceeded");
json_type tok = json_peek(_pJSON);
while (tok != JSON_OBJECT_END && checkError())
{
@@ -162,7 +225,10 @@ void ParserImpl::handleObject()
tok = json_peek(_pJSON);
}
if (tok == JSON_OBJECT_END) handle();
if (tok == JSON_OBJECT_END)
{
handle();
}
else throw JSONException("JSON object end not found");
}
@@ -172,55 +238,58 @@ void ParserImpl::handle()
enum json_type type = json_next(_pJSON);
switch (type)
{
case JSON_DONE:
return;
case JSON_NULL:
_pHandler->null();
break;
case JSON_TRUE:
if (_pHandler) _pHandler->value(true);
break;
case JSON_FALSE:
if (_pHandler) _pHandler->value(false);
break;
case JSON_NUMBER:
case JSON_DONE:
return;
case JSON_NULL:
_pHandler->null();
break;
case JSON_TRUE:
if (_pHandler) _pHandler->value(true);
break;
case JSON_FALSE:
if (_pHandler) _pHandler->value(false);
break;
case JSON_NUMBER:
if (_pHandler)
{
if (_pHandler)
std::string str(json_get_string(_pJSON, NULL));
if (str.find(_decimalPoint) != str.npos || str.find('e') != str.npos || str.find('E') != str.npos)
{
std::string str(json_get_string(_pJSON, NULL));
if (str.find(_decimalPoint) != str.npos || str.find('e') != str.npos || str.find('E') != str.npos)
{
_pHandler->value(NumberParser::parseFloat(str));
}
else
{
Poco::Int64 val;
if (NumberParser::tryParse64(str, val))
_pHandler->value(val);
else
_pHandler->value(NumberParser::parseUnsigned64(str));
}
_pHandler->value(NumberParser::parseFloat(str));
}
else
{
Poco::Int64 val;
if (NumberParser::tryParse64(str, val))
_pHandler->value(val);
else
_pHandler->value(NumberParser::parseUnsigned64(str));
}
break;
}
case JSON_STRING:
if (_pHandler) _pHandler->value(std::string(json_get_string(_pJSON, NULL)));
break;
case JSON_OBJECT:
if (_pHandler) _pHandler->startObject();
handleObject();
break;
case JSON_OBJECT_END:
if (_pHandler) _pHandler->endObject();
return;
case JSON_ARRAY:
if (_pHandler) _pHandler->startArray();
handleArray();
break;
case JSON_ARRAY_END:
if (_pHandler) _pHandler->endArray();
return;
case JSON_ERROR:
break;
case JSON_STRING:
if (_pHandler)
{
std::size_t length = 0;
const char* val = json_get_string(_pJSON, &length);
_pHandler->value(std::string(val, length == 0 ? 0 : length - 1)); // Decrease the length by 1 because it also contains the terminating null character
}
break;
case JSON_OBJECT:
if (_pHandler) _pHandler->startObject();
handleObject();
break;
case JSON_OBJECT_END:
if (_pHandler) _pHandler->endObject();
return;
case JSON_ARRAY:
if (_pHandler) _pHandler->startArray();
handleArray();
break;
case JSON_ARRAY_END:
if (_pHandler) _pHandler->endArray();
return;
case JSON_ERROR:
{
const char* pErr = json_get_error(_pJSON);
std::string err(pErr ? pErr : "JSON parser error.");

View File

@@ -1,23 +1,28 @@
#define _POSIX_C_SOURCE 200112L
#ifndef _POSIX_C_SOURCE
# define _POSIX_C_SOURCE 200112L
#elif _POSIX_C_SOURCE < 200112L
# error incompatible _POSIX_C_SOURCE level
#endif
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <errno.h>
#include "pdjson.h"
#ifndef PDJSON_H
# include "pdjson.h"
#endif
#define JSON_FLAG_ERROR (1u << 0)
#define JSON_FLAG_STREAMING (1u << 1)
// patched for poco 1.8.x (VS 2008)
#if defined(_MSC_VER) && (_MSC_VER < 1900)
#define json_error(json, format, ...) \
if (!(json->flags & JSON_FLAG_ERROR)) { \
json->flags |= JSON_FLAG_ERROR; \
_snprintf_s(json->errmsg, sizeof(json->errmsg), _TRUNCATE,\
"error: %lu: " format, \
(unsigned long) json->lineno, \
_snprintf_s(json->errmsg, sizeof(json->errmsg), \
_TRUNCATE, \
format, \
__VA_ARGS__); \
} \
@@ -27,60 +32,44 @@
if (!(json->flags & JSON_FLAG_ERROR)) { \
json->flags |= JSON_FLAG_ERROR; \
snprintf(json->errmsg, sizeof(json->errmsg), \
"error: %lu: " format, \
(unsigned long) json->lineno, \
format, \
__VA_ARGS__); \
} \
#endif // _MSC_VER
#endif /* _MSC_VER */
#define STACK_INC 4
#if defined(_MSC_VER) || defined(__MINGW32__)
#define strerror_r(err, buf, len) strerror_s(buf, len, err)
/* See also PDJSON_STACK_MAX below. */
#ifndef PDJSON_STACK_INC
# define PDJSON_STACK_INC 4
#endif
/*
const char *json_typename[] = {
[JSON_ERROR] = "ERROR",
[JSON_DONE] = "DONE",
[JSON_OBJECT] = "OBJECT",
[JSON_OBJECT_END] = "OBJECT_END",
[JSON_ARRAY] = "ARRAY",
[JSON_ARRAY_END] = "ARRAY_END",
[JSON_STRING] = "STRING",
[JSON_NUMBER] = "NUMBER",
[JSON_TRUE] = "TRUE",
[JSON_FALSE] = "FALSE",
[JSON_NULL] = "NULL",
};
*/
struct json_stack {
enum json_type type;
long count;
};
static void json_error_s(json_stream *json, int err)
{
char errbuf[1024] = {0};
strerror_r(err, errbuf, sizeof(errbuf));
json_error(json, "%s", errbuf);
}
static enum json_type
push(json_stream *json, enum json_type type)
{
json->stack_top++;
#ifdef PDJSON_STACK_MAX
if (json->stack_top > PDJSON_STACK_MAX) {
json_error(json, "%s", "maximum depth of nesting reached");
return JSON_ERROR;
}
#endif
if (json->stack_top >= json->stack_size) {
struct json_stack *stack;
stack = (struct json_stack *) json->alloc.realloc(json->stack,
(json->stack_size + STACK_INC) * sizeof(*json->stack));
size_t size = (json->stack_size + PDJSON_STACK_INC) * sizeof(*json->stack);
stack = (struct json_stack *)json->alloc.realloc(json->stack, size);
if (stack == NULL) {
json_error_s(json, errno);
json_error(json, "%s", "out of memory");
return JSON_ERROR;
}
json->stack_size += STACK_INC;
json->stack_size += PDJSON_STACK_INC;
json->stack = stack;
}
@@ -94,7 +83,7 @@ static enum json_type
pop(json_stream *json, int c, enum json_type expected)
{
if (json->stack == NULL || json->stack[json->stack_top].type != expected) {
json_error(json, "unexpected byte, '%c'", c);
json_error(json, "unexpected byte '%c'", c);
return JSON_ERROR;
}
json->stack_top--;
@@ -135,7 +124,7 @@ static void init(json_stream *json)
json->flags = JSON_FLAG_STREAMING;
json->errmsg[0] = '\0';
json->ntokens = 0;
json->next = (enum json_type) 0;
json->next = (enum json_type)0;
json->stack = NULL;
json->stack_top = -1;
@@ -154,9 +143,13 @@ static void init(json_stream *json)
static enum json_type
is_match(json_stream *json, const char *pattern, enum json_type type)
{
for (const char *p = pattern; *p; p++)
if (*p != json->source.get(&json->source))
int c;
for (const char *p = pattern; *p; p++) {
if (*p != (c = json->source.get(&json->source))) {
json_error(json, "expected '%c' instead of byte '%c'", *p, c);
return JSON_ERROR;
}
}
return type;
}
@@ -164,9 +157,9 @@ static int pushchar(json_stream *json, int c)
{
if (json->data.string_fill == json->data.string_size) {
size_t size = json->data.string_size * 2;
char *buffer = (char*) json->alloc.realloc(json->data.string, size);
char *buffer = (char *)json->alloc.realloc(json->data.string, size);
if (buffer == NULL) {
json_error_s(json, errno);
json_error(json, "%s", "out of memory");
return -1;
} else {
json->data.string_size = size;
@@ -182,9 +175,9 @@ static int init_string(json_stream *json)
json->data.string_fill = 0;
if (json->data.string == NULL) {
json->data.string_size = 1024;
json->data.string = (char*) json->alloc.malloc(json->data.string_size);
json->data.string = (char *)json->alloc.malloc(json->data.string_size);
if (json->data.string == NULL) {
json_error_s(json, errno);
json_error(json, "%s", "out of memory");
return -1;
}
}
@@ -213,7 +206,7 @@ static int encode_utf8(json_stream *json, unsigned long c)
(pushchar(json, (c >> 6 & 0x3F) | 0x80) == 0) &&
(pushchar(json, (c >> 0 & 0x3F) | 0x80) == 0));
} else {
json_error(json, "can't encode UTF-8 for %06lx", c);
json_error(json, "unable to encode %06lx as UTF-8", c);
return -1;
}
}
@@ -259,10 +252,10 @@ read_unicode_cp(json_stream *json)
int hc;
if (c == EOF) {
json_error(json, "%s", "unterminated string literal in unicode");
json_error(json, "%s", "unterminated string literal in Unicode");
return -1;
} else if ((hc = hexchar(c)) == -1) {
json_error(json, "bad escape unicode byte, '%c'", c);
json_error(json, "invalid escape Unicode byte '%c'", c);
return -1;
}
@@ -290,20 +283,20 @@ static int read_unicode(json_stream *json)
int c = json->source.get(&json->source);
if (c == EOF) {
json_error(json, "%s", "unterminated string literal in unicode");
json_error(json, "%s", "unterminated string literal in Unicode");
return -1;
} else if (c != '\\') {
json_error(json, "invalid continuation for surrogate pair: '%c', "
json_error(json, "invalid continuation for surrogate pair '%c', "
"expected '\\'", c);
return -1;
}
c = json->source.get(&json->source);
if (c == EOF) {
json_error(json, "%s", "unterminated string literal in unicode");
json_error(json, "%s", "unterminated string literal in Unicode");
return -1;
} else if (c != 'u') {
json_error(json, "invalid continuation for surrogate pair: '%c', "
json_error(json, "invalid continuation for surrogate pair '%c', "
"expected 'u'", c);
return -1;
}
@@ -313,7 +306,7 @@ static int read_unicode(json_stream *json)
}
if (l < 0xdc00 || l > 0xdfff) {
json_error(json, "invalid surrogate pair continuation \\u%04lx out "
json_error(json, "surrogate pair continuation \\u%04lx out "
"of range (dc00-dfff)", l);
return -1;
}
@@ -327,7 +320,8 @@ static int read_unicode(json_stream *json)
return encode_utf8(json, cp);
}
int read_escaped(json_stream *json)
static int
read_escaped(json_stream *json)
{
int c = json->source.get(&json->source);
if (c == EOF) {
@@ -348,13 +342,13 @@ int read_escaped(json_stream *json)
case '"':
{
const char *codes = "\\bfnrt/\"";
char *p = (char*) strchr(codes, c);
const char *p = strchr(codes, c);
if (pushchar(json, "\\\b\f\n\r\t/\""[p - codes]) != 0)
return -1;
}
break;
default:
json_error(json, "bad escaped byte, '%c'", c);
json_error(json, "invalid escaped byte '%c'", c);
return -1;
}
}
@@ -425,8 +419,10 @@ is_legal_utf8(const unsigned char *bytes, int length)
// Everything else falls through when true.
case 4:
if ((a = (*--srcptr)) < 0x80 || a > 0xBF) return 0;
/* FALLTHRU */
case 3:
if ((a = (*--srcptr)) < 0x80 || a > 0xBF) return 0;
/* FALLTHRU */
case 2:
a = (*--srcptr);
switch (*bytes)
@@ -445,7 +441,9 @@ is_legal_utf8(const unsigned char *bytes, int length)
break;
default:
if (a < 0x80 || a > 0xBF) return 0;
break;
}
/* FALLTHRU */
case 1:
if (*bytes >= 0x80 && *bytes < 0xC2) return 0;
}
@@ -458,24 +456,25 @@ read_utf8(json_stream* json, int next_char)
int count = utf8_seq_length(next_char);
if (!count)
{
json_error(json, "%s", "Bad character.");
json_error(json, "%s", "invalid UTF-8 character");
return -1;
}
char buffer[4];
buffer[0] = next_char;
for (int i = 1; i < count; ++i)
int i;
for (i = 1; i < count; ++i)
{
buffer[i] = json->source.get(&json->source);;
}
if (!is_legal_utf8((unsigned char*) buffer, count))
{
json_error(json, "%s", "No legal UTF8 found");
json_error(json, "%s", "invalid UTF-8 text");
return -1;
}
for (int i = 0; i < count; ++i)
for (i = 0; i < count; ++i)
{
if (pushchar(json, buffer[i]) != 0)
return -1;
@@ -526,8 +525,9 @@ is_digit(int c)
static int
read_digits(json_stream *json)
{
int c;
unsigned nread = 0;
while (is_digit(json->source.peek(&json->source))) {
while (is_digit(c = json->source.peek(&json->source))) {
if (pushchar(json, json->source.get(&json->source)) != 0)
return -1;
@@ -535,6 +535,7 @@ read_digits(json_stream *json)
}
if (nread == 0) {
json_error(json, "expected digit instead of byte '%c'", c);
return -1;
}
@@ -551,7 +552,8 @@ read_number(json_stream *json, int c)
if (is_digit(c)) {
return read_number(json, c);
} else {
json_error(json, "unexpected byte, '%c'", c);
json_error(json, "unexpected byte '%c' in number", c);
return JSON_ERROR;
}
} else if (strchr("123456789", c) != NULL) {
c = json->source.peek(&json->source);
@@ -592,7 +594,7 @@ read_number(json_stream *json, int c)
if (read_digits(json) != 0)
return JSON_ERROR;
} else {
json_error(json, "unexpected byte in number, '%c'", c);
json_error(json, "unexpected byte '%c' in number", c);
return JSON_ERROR;
}
}
@@ -602,7 +604,7 @@ read_number(json_stream *json, int c)
return JSON_NUMBER;
}
static int
bool
json_isspace(int c)
{
switch (c) {
@@ -610,10 +612,10 @@ json_isspace(int c)
case 0x0a:
case 0x0d:
case 0x20:
return 1;
return true;
}
return 0;
return false;
}
/* Returns the next non-whitespace character in the stream. */
@@ -632,7 +634,7 @@ read_value(json_stream *json, int c)
json->ntokens++;
switch (c) {
case EOF:
json_error(json, "%s", "unexpected end of data");
json_error(json, "%s", "unexpected end of text");
return JSON_ERROR;
case '{':
return push(json, JSON_OBJECT);
@@ -661,15 +663,18 @@ read_value(json_stream *json, int c)
return JSON_ERROR;
return read_number(json, c);
default:
json_error(json, "unexpected byte, '%c'", c);
json_error(json, "unexpected byte '%c' in value", c);
return JSON_ERROR;
}
}
enum json_type json_peek(json_stream *json)
{
enum json_type next = json_next(json);
json->next = next;
enum json_type next;
if (json->next)
next = json->next;
else
next = json->next = json_next(json);
return next;
}
@@ -679,28 +684,41 @@ enum json_type json_next(json_stream *json)
return JSON_ERROR;
if (json->next != 0) {
enum json_type next = json->next;
json->next = (enum json_type) 0;
json->next = (enum json_type)0;
return next;
}
if (json->ntokens > 0 && json->stack_top == (size_t)-1) {
int c;
do {
c = json->source.peek(&json->source);
if (json_isspace(c)) {
c = json->source.get(&json->source);
/* In the streaming mode leave any trailing whitespaces in the stream.
* This allows the user to validate any desired separation between
* values (such as newlines) using json_source_get/peek() with any
* remaining whitespaces ignored as leading when we parse the next
* value. */
if (!(json->flags & JSON_FLAG_STREAMING)) {
int c;
do {
c = json->source.peek(&json->source);
if (json_isspace(c)) {
c = json->source.get(&json->source);
}
} while (json_isspace(c));
if (c != EOF) {
json_error(json, "expected end of text instead of byte '%c'", c);
return JSON_ERROR;
}
} while (json_isspace(c));
if (!(json->flags & JSON_FLAG_STREAMING) && c != EOF) {
return JSON_ERROR;
}
return JSON_DONE;
}
int c = next(json);
if (json->stack_top == (size_t)-1)
if (json->stack_top == (size_t)-1) {
if (c == EOF && (json->flags & JSON_FLAG_STREAMING))
return JSON_DONE;
return read_value(json, c);
}
if (json->stack[json->stack_top].type == JSON_ARRAY) {
if (json->stack[json->stack_top].count == 0) {
if (c == ']') {
@@ -714,7 +732,7 @@ enum json_type json_next(json_stream *json)
} else if (c == ']') {
return pop(json, c, JSON_ARRAY);
} else {
json_error(json, "unexpected byte, '%c'", c);
json_error(json, "unexpected byte '%c'", c);
return JSON_ERROR;
}
} else if (json->stack[json->stack_top].type == JSON_OBJECT) {
@@ -723,26 +741,28 @@ enum json_type json_next(json_stream *json)
return pop(json, c, JSON_OBJECT);
}
/* No property value pairs yet. */
/* No member name/value pairs yet. */
enum json_type value = read_value(json, c);
if (value != JSON_STRING) {
json_error(json, "%s", "expected property name or '}'");
if (value != JSON_ERROR)
json_error(json, "%s", "expected member name or '}'");
return JSON_ERROR;
} else {
json->stack[json->stack_top].count++;
return value;
}
} else if ((json->stack[json->stack_top].count % 2) == 0) {
/* Expecting comma followed by property name. */
/* Expecting comma followed by member name. */
if (c != ',' && c != '}') {
json_error(json, "%s", "expected ',' or '}'");
json_error(json, "%s", "expected ',' or '}' after member value");
return JSON_ERROR;
} else if (c == '}') {
return pop(json, c, JSON_OBJECT);
} else {
enum json_type value = read_value(json, next(json));
if (value != JSON_STRING) {
json_error(json, "%s", "expected property name");
if (value != JSON_ERROR)
json_error(json, "%s", "expected member name");
return JSON_ERROR;
} else {
json->stack[json->stack_top].count++;
@@ -752,7 +772,7 @@ enum json_type json_next(json_stream *json)
} else if ((json->stack[json->stack_top].count % 2) == 1) {
/* Expecting colon followed by value. */
if (c != ':') {
json_error(json, "%s", "expected ':' after property name");
json_error(json, "%s", "expected ':' after member name");
return JSON_ERROR;
} else {
json->stack[json->stack_top].count++;
@@ -772,6 +792,48 @@ void json_reset(json_stream *json)
json->errmsg[0] = '\0';
}
enum json_type json_skip(json_stream *json)
{
enum json_type type = json_next(json);
size_t cnt_arr = 0;
size_t cnt_obj = 0;
for (enum json_type skip = type; ; skip = json_next(json)) {
if (skip == JSON_ERROR || skip == JSON_DONE)
return skip;
if (skip == JSON_ARRAY) {
++cnt_arr;
} else if (skip == JSON_ARRAY_END && cnt_arr > 0) {
--cnt_arr;
} else if (skip == JSON_OBJECT) {
++cnt_obj;
} else if (skip == JSON_OBJECT_END && cnt_obj > 0) {
--cnt_obj;
}
if (!cnt_arr && !cnt_obj)
break;
}
return type;
}
enum json_type json_skip_until(json_stream *json, enum json_type type)
{
while (1) {
enum json_type skip = json_skip(json);
if (skip == JSON_ERROR || skip == JSON_DONE)
return skip;
if (skip == type)
break;
}
return type;
}
const char *json_get_string(json_stream *json, size_t *length)
{
if (length != NULL)
@@ -808,12 +870,45 @@ size_t json_get_depth(json_stream *json)
return json->stack_top + 1;
}
/* Return the current parsing context, that is, JSON_OBJECT if we are inside
an object, JSON_ARRAY if we are inside an array, and JSON_DONE if we are
not yet/anymore in either.
Additionally, for the first two cases, also return the number of parsing
events that have already been observed at this level with json_next/peek().
In particular, inside an object, an odd number would indicate that the just
observed JSON_STRING event is a member name.
*/
enum json_type json_get_context(json_stream *json, size_t *count)
{
if (json->stack_top == (size_t)-1)
return JSON_DONE;
if (count != NULL)
*count = json->stack[json->stack_top].count;
return json->stack[json->stack_top].type;
}
int json_source_get(json_stream *json)
{
int c = json->source.get(&json->source);
if (c == '\n')
json->lineno++;
return c;
}
int json_source_peek(json_stream *json)
{
return json->source.peek(&json->source);
}
void json_open_buffer(json_stream *json, const void *buffer, size_t size)
{
init(json);
json->source.get = buffer_get;
json->source.peek = buffer_peek;
json->source.source.buffer.buffer = (char*) buffer;
json->source.source.buffer.buffer = (const char *)buffer;
json->source.source.buffer.length = size;
}

View File

@@ -1,27 +1,25 @@
#ifndef PDJSON_H
#define PDJSON_H
#if defined(__cplusplus)
#ifndef PDJSON_SYMEXPORT
# define PDJSON_SYMEXPORT
#endif
#ifdef __cplusplus
extern "C" {
#endif // __cplusplus
#include <stdio.h>
#if !defined(__cplusplus) && !defined(_MSC_VER) // for poco 1.8.x we must compile as C++
#if defined(__STDC_VERSION__) || (__STDC_VERSION__ >= 199901L)
#else
#if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L)
#include <stdbool.h>
#else
#ifndef bool
#define bool int
#endif
#ifndef true
#define true 1
#endif
#ifndef false
#define false 0
#endif
#endif // __STDC_VERSION__
#endif
#endif /* bool */
#endif /* __STDC_VERSION__ */
#endif /* __cplusplus */
#include <stdio.h>
enum json_type {
JSON_ERROR = 1, JSON_DONE,
@@ -40,27 +38,33 @@ typedef int (*json_user_io) (void *user);
typedef struct json_stream json_stream;
typedef struct json_allocator json_allocator;
//extern const char *json_typename[];
PDJSON_SYMEXPORT void json_open_buffer(json_stream *json, const void *buffer, size_t size);
PDJSON_SYMEXPORT void json_open_string(json_stream *json, const char *string);
PDJSON_SYMEXPORT void json_open_stream(json_stream *json, FILE *stream);
PDJSON_SYMEXPORT void json_open_user(json_stream *json, json_user_io get, json_user_io peek, void *user);
PDJSON_SYMEXPORT void json_close(json_stream *json);
void json_open_buffer(json_stream *json, const void *buffer, size_t size);
void json_open_string(json_stream *json, const char *string);
void json_open_stream(json_stream *json, FILE *stream);
void json_open_user(json_stream *json, json_user_io get, json_user_io peek, void *user);
void json_close(json_stream *json);
PDJSON_SYMEXPORT void json_set_allocator(json_stream *json, json_allocator *a);
PDJSON_SYMEXPORT void json_set_streaming(json_stream *json, bool mode);
void json_set_allocator(json_stream *json, json_allocator *a);
void json_set_streaming(json_stream *json, bool strict);
PDJSON_SYMEXPORT enum json_type json_next(json_stream *json);
PDJSON_SYMEXPORT enum json_type json_peek(json_stream *json);
PDJSON_SYMEXPORT void json_reset(json_stream *json);
PDJSON_SYMEXPORT const char *json_get_string(json_stream *json, size_t *length);
PDJSON_SYMEXPORT double json_get_number(json_stream *json);
enum json_type json_next(json_stream *json);
enum json_type json_peek(json_stream *json);
void json_reset(json_stream *json);
const char *json_get_string(json_stream *json, size_t *length);
double json_get_number(json_stream *json);
PDJSON_SYMEXPORT enum json_type json_skip(json_stream *json);
PDJSON_SYMEXPORT enum json_type json_skip_until(json_stream *json, enum json_type type);
size_t json_get_lineno(json_stream *json);
size_t json_get_position(json_stream *json);
size_t json_get_depth(json_stream *json);
const char *json_get_error(json_stream *json);
PDJSON_SYMEXPORT size_t json_get_lineno(json_stream *json);
PDJSON_SYMEXPORT size_t json_get_position(json_stream *json);
PDJSON_SYMEXPORT size_t json_get_depth(json_stream *json);
PDJSON_SYMEXPORT enum json_type json_get_context(json_stream *json, size_t *count);
PDJSON_SYMEXPORT const char *json_get_error(json_stream *json);
PDJSON_SYMEXPORT int json_source_get(json_stream *json);
PDJSON_SYMEXPORT int json_source_peek(json_stream *json);
PDJSON_SYMEXPORT bool json_isspace(int c);
/* internal */
@@ -106,8 +110,8 @@ struct json_stream {
char errmsg[128];
};
#if defined(__cplusplus)
} // extern "C"
#endif // __cplusplus
#ifdef __cplusplus
} /* extern "C" */
#endif /* __cplusplus */
#endif

View File

@@ -791,9 +791,11 @@ void JSONTest::testEmptyArray()
Poco::JSON::Array::Ptr array = result.extract<Poco::JSON::Array::Ptr>();
assertTrue (array->size() == 0);
assertTrue (array->empty());
Poco::Dynamic::Array da = *array;
assertTrue (da.size() == 0);
assertTrue (da.empty());
}
@@ -817,10 +819,12 @@ void JSONTest::testNestedArray()
Poco::JSON::Array::Ptr array = result.extract<Poco::JSON::Array::Ptr>();
assertTrue (array->size() == 1);
assertTrue (!array->empty());
Poco::Dynamic::Array da = *array;
assertTrue (da.size() == 1);
assertTrue (da[0].size() == 1);
assertTrue (!da.empty());
assertTrue (da[0][0].size() == 1);
assertTrue (da[0][0][0].size() == 0);
}
@@ -1382,7 +1386,6 @@ void JSONTest::testStringify()
Poco::JSON::Stringifier::stringify(obj1, oss1);
Poco::JSON::Stringifier::stringify(obj2, oss2);
assertTrue (oss1.str() == "{\"payload\":\"\\r\"}");
std::cout << "\"" << oss1.str() << "\"" << std::endl;
assertTrue (oss2.str() == "{\"payload\":\"\\n\"}");
Object jObj(false);
@@ -1397,7 +1400,7 @@ void JSONTest::testStringify()
std::stringstream ss;
jObj.stringify(ss);
assertTrue (ss.str() == "{\"backspace\":\"bs\\b\",\"bar\\/\":0,\"baz\":0,\"foo\\\\\":0,"
assertTrue (ss.str() == "{\"backspace\":\"bs\\b\",\"bar/\":0,\"baz\":0,\"foo\\\\\":0,"
"\"newline\":\"nl\\n\",\"q\\\"uote\\\"d\":0,\"tab\":\"tb\\t\"}");
std::string json = "{ \"Simpsons\" : { \"husband\" : { \"name\" : \"Homer\" , \"age\" : 38 }, \"wife\" : { \"name\" : \"Marge\", \"age\" : 36 }, "
@@ -1448,24 +1451,24 @@ void JSONTest::testStringify()
ostr.str("");
Stringifier::stringify(result, ostr, 1);
str = "{\n"
" \"Simpsons\" : {\n"
" \"address\" : {\n"
" \"number\" : 742,\n"
" \"street\" : \"Evergreen Terrace\",\n"
" \"town\" : \"Springfield\"\n"
" \"Simpsons\": {\n"
" \"address\": {\n"
" \"number\": 742,\n"
" \"street\": \"Evergreen Terrace\",\n"
" \"town\": \"Springfield\"\n"
" },\n"
" \"children\" : [\n"
" \"children\": [\n"
" \"Bart\",\n"
" \"Lisa\",\n"
" \"Maggie\"\n"
" ],\n"
" \"husband\" : {\n"
" \"age\" : 38,\n"
" \"name\" : \"Homer\"\n"
" \"husband\": {\n"
" \"age\": 38,\n"
" \"name\": \"Homer\"\n"
" },\n"
" \"wife\" : {\n"
" \"age\" : 36,\n"
" \"name\" : \"Marge\"\n"
" \"wife\": {\n"
" \"age\": 36,\n"
" \"name\": \"Marge\"\n"
" }\n"
" }\n"
"}";
@@ -1474,24 +1477,24 @@ void JSONTest::testStringify()
ostr.str("");
Stringifier::stringify(result, ostr, 2);
str = "{\n"
" \"Simpsons\" : {\n"
" \"address\" : {\n"
" \"number\" : 742,\n"
" \"street\" : \"Evergreen Terrace\",\n"
" \"town\" : \"Springfield\"\n"
" \"Simpsons\": {\n"
" \"address\": {\n"
" \"number\": 742,\n"
" \"street\": \"Evergreen Terrace\",\n"
" \"town\": \"Springfield\"\n"
" },\n"
" \"children\" : [\n"
" \"children\": [\n"
" \"Bart\",\n"
" \"Lisa\",\n"
" \"Maggie\"\n"
" ],\n"
" \"husband\" : {\n"
" \"age\" : 38,\n"
" \"name\" : \"Homer\"\n"
" \"husband\": {\n"
" \"age\": 38,\n"
" \"name\": \"Homer\"\n"
" },\n"
" \"wife\" : {\n"
" \"age\" : 36,\n"
" \"name\" : \"Marge\"\n"
" \"wife\": {\n"
" \"age\": 36,\n"
" \"name\": \"Marge\"\n"
" }\n"
" }\n"
"}";
@@ -1500,24 +1503,24 @@ void JSONTest::testStringify()
ostr.str("");
Stringifier::stringify(result, ostr, 4);
str = "{\n"
" \"Simpsons\" : {\n"
" \"address\" : {\n"
" \"number\" : 742,\n"
" \"street\" : \"Evergreen Terrace\",\n"
" \"town\" : \"Springfield\"\n"
" \"Simpsons\": {\n"
" \"address\": {\n"
" \"number\": 742,\n"
" \"street\": \"Evergreen Terrace\",\n"
" \"town\": \"Springfield\"\n"
" },\n"
" \"children\" : [\n"
" \"children\": [\n"
" \"Bart\",\n"
" \"Lisa\",\n"
" \"Maggie\"\n"
" ],\n"
" \"husband\" : {\n"
" \"age\" : 38,\n"
" \"name\" : \"Homer\"\n"
" \"husband\": {\n"
" \"age\": 38,\n"
" \"name\": \"Homer\"\n"
" },\n"
" \"wife\" : {\n"
" \"age\" : 36,\n"
" \"name\" : \"Marge\"\n"
" \"wife\": {\n"
" \"age\": 36,\n"
" \"name\": \"Marge\"\n"
" }\n"
" }\n"
"}";
@@ -1590,24 +1593,24 @@ void JSONTest::testStringifyPreserveOrder()
ostr.str("");
Stringifier::stringify(result, ostr, 1);
assertTrue (ostr.str() == "{\n"
" \"Simpsons\" : {\n"
" \"husband\" : {\n"
" \"name\" : \"Homer\",\n"
" \"age\" : 38\n"
" \"Simpsons\": {\n"
" \"husband\": {\n"
" \"name\": \"Homer\",\n"
" \"age\": 38\n"
" },\n"
" \"wife\" : {\n"
" \"name\" : \"Marge\",\n"
" \"age\" : 36\n"
" \"wife\": {\n"
" \"name\": \"Marge\",\n"
" \"age\": 36\n"
" },\n"
" \"children\" : [\n"
" \"children\": [\n"
" \"Bart\",\n"
" \"Lisa\",\n"
" \"Maggie\"\n"
" ],\n"
" \"address\" : {\n"
" \"number\" : 742,\n"
" \"street\" : \"Evergreen Terrace\",\n"
" \"town\" : \"Springfield\"\n"
" \"address\": {\n"
" \"number\": 742,\n"
" \"street\": \"Evergreen Terrace\",\n"
" \"town\": \"Springfield\"\n"
" }\n"
" }\n"
"}");
@@ -1615,24 +1618,24 @@ void JSONTest::testStringifyPreserveOrder()
ostr.str("");
Stringifier::stringify(result, ostr, 2);
assertTrue (ostr.str() == "{\n"
" \"Simpsons\" : {\n"
" \"husband\" : {\n"
" \"name\" : \"Homer\",\n"
" \"age\" : 38\n"
" \"Simpsons\": {\n"
" \"husband\": {\n"
" \"name\": \"Homer\",\n"
" \"age\": 38\n"
" },\n"
" \"wife\" : {\n"
" \"name\" : \"Marge\",\n"
" \"age\" : 36\n"
" \"wife\": {\n"
" \"name\": \"Marge\",\n"
" \"age\": 36\n"
" },\n"
" \"children\" : [\n"
" \"children\": [\n"
" \"Bart\",\n"
" \"Lisa\",\n"
" \"Maggie\"\n"
" ],\n"
" \"address\" : {\n"
" \"number\" : 742,\n"
" \"street\" : \"Evergreen Terrace\",\n"
" \"town\" : \"Springfield\"\n"
" \"address\": {\n"
" \"number\": 742,\n"
" \"street\": \"Evergreen Terrace\",\n"
" \"town\": \"Springfield\"\n"
" }\n"
" }\n"
"}");
@@ -1640,33 +1643,33 @@ void JSONTest::testStringifyPreserveOrder()
ostr.str("");
Stringifier::stringify(result, ostr, 4);
assertTrue (ostr.str() == "{\n"
" \"Simpsons\" : {\n"
" \"husband\" : {\n"
" \"name\" : \"Homer\",\n"
" \"age\" : 38\n"
" \"Simpsons\": {\n"
" \"husband\": {\n"
" \"name\": \"Homer\",\n"
" \"age\": 38\n"
" },\n"
" \"wife\" : {\n"
" \"name\" : \"Marge\",\n"
" \"age\" : 36\n"
" \"wife\": {\n"
" \"name\": \"Marge\",\n"
" \"age\": 36\n"
" },\n"
" \"children\" : [\n"
" \"children\": [\n"
" \"Bart\",\n"
" \"Lisa\",\n"
" \"Maggie\"\n"
" ],\n"
" \"address\" : {\n"
" \"number\" : 742,\n"
" \"street\" : \"Evergreen Terrace\",\n"
" \"town\" : \"Springfield\"\n"
" \"address\": {\n"
" \"number\": 742,\n"
" \"street\": \"Evergreen Terrace\",\n"
" \"town\": \"Springfield\"\n"
" }\n"
" }\n"
"}");
Poco::DynamicStruct ds = *result.extract<Object::Ptr>();
assertTrue(ds.toString() == "{ \"Simpsons\" : { \"address\" : { \"number\" : 742, \"street\" : \"Evergreen Terrace\", \"town\" : \"Springfield\" }, "
"\"children\" : [ \"Bart\", \"Lisa\", \"Maggie\" ], "
"\"husband\" : { \"age\" : 38, \"name\" : \"Homer\" }, "
"\"wife\" : { \"age\" : 36, \"name\" : \"Marge\" } } }");
assertTrue(ds.toString() == "{ \"Simpsons\": { \"address\": { \"number\": 742, \"street\": \"Evergreen Terrace\", \"town\": \"Springfield\" }, "
"\"children\": [ \"Bart\", \"Lisa\", \"Maggie\" ], "
"\"husband\": { \"age\": 38, \"name\": \"Homer\" }, "
"\"wife\": { \"age\": 36, \"name\": \"Marge\" } } }");
assertTrue (ds["Simpsons"].isStruct());
assertFalse(ds["Simpsons"].isOrdered());
assertTrue (ds["Simpsons"]["husband"].isStruct());
@@ -1690,11 +1693,11 @@ void JSONTest::testStringifyPreserveOrder()
Poco::OrderedDynamicStruct ods = *result.extract<Object::Ptr>();
assertTrue(ods["Simpsons"].isStruct());
assertTrue(ods["Simpsons"].isOrdered());
assertTrue(ods.toString() == "{ \"Simpsons\" : { \"husband\" : { \"name\" : \"Homer\", \"age\" : 38 }, "
"\"wife\" : { \"name\" : \"Marge\", \"age\" : 36 }, "
"\"children\" : [ \"Bart\", \"Lisa\", \"Maggie\" ], "
"\"address\" : { \"number\" : 742, \"street\" : \"Evergreen Terrace\", "
"\"town\" : \"Springfield\" } } }");
assertTrue(ods.toString() == "{ \"Simpsons\": { \"husband\": { \"name\": \"Homer\", \"age\": 38 }, "
"\"wife\": { \"name\": \"Marge\", \"age\": 36 }, "
"\"children\": [ \"Bart\", \"Lisa\", \"Maggie\" ], "
"\"address\": { \"number\": 742, \"street\": \"Evergreen Terrace\", "
"\"town\": \"Springfield\" } } }");
}
@@ -1918,13 +1921,6 @@ void JSONTest::testUnicode()
}
void JSONTest::testSmallBuffer()
{
Poco::JSON::Parser parser(new Poco::JSON::ParseHandler(), 4);
std::string jsonStr = "{ \"x\" : \"123456789012345678901234567890123456789012345678901234567890\" }";
parser.parse(jsonStr);
}
void JSONTest::testEscape0()
{
Poco::JSON::Object::Ptr json = new Poco::JSON::Object();
@@ -1936,6 +1932,15 @@ void JSONTest::testEscape0()
json->stringify(ss);
assertTrue (ss.str().compare("{\"name\":\"B\\u0000b\"}") == 0);
// parse the JSON containing the escaped string
Poco::JSON::Parser parser(new Poco::JSON::ParseHandler());
Var result = parser.parse(ss.str());
assert(result.type() == typeid(Object::Ptr));
Object::Ptr object = result.extract<Object::Ptr>();
assert(object->get("name").extract<std::string>() == nullString);
}
@@ -2163,6 +2168,47 @@ void JSONTest::testMove()
assertTrue (nl[2] == "baz");
}
void JSONTest::testRemove()
{
Object obj1;
obj1.set("foo", 0);
obj1.set("bar", 0);
obj1.set("baz", 0);
Object::NameList nl = obj1.getNames();
assertTrue(nl.size() == 3);
assertTrue(nl[0] == "bar");
assertTrue(nl[1] == "baz");
assertTrue(nl[2] == "foo");
obj1.remove("baz");
nl = obj1.getNames();
assertTrue(nl.size() == 2);
assertTrue(nl[0] == "bar");
assertTrue(nl[1] == "foo");
Object obj2(Poco::JSON_PRESERVE_KEY_ORDER);
obj2.set("foo", 0);
obj2.set("bar", 0);
obj2.set("baz", 0);
nl = obj2.getNames();
assertTrue(nl.size() == 3);
assertTrue(nl[0] == "foo");
assertTrue(nl[1] == "bar");
assertTrue(nl[2] == "baz");
obj2.remove("bar");
nl = obj2.getNames();
assertTrue(nl.size() == 2);
assertTrue(nl[0] == "foo");
assertTrue(nl[1] == "baz");
}
CppUnit::Test* JSONTest::suite()
{
@@ -2208,12 +2254,12 @@ CppUnit::Test* JSONTest::suite()
CppUnit_addTest(pSuite, JSONTest, testInvalidUnicodeJanssonFiles);
CppUnit_addTest(pSuite, JSONTest, testTemplate);
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);
CppUnit_addTest(pSuite, JSONTest, testRemove);
return pSuite;
}

View File

@@ -74,13 +74,13 @@ public:
void testTemplate();
void testUnicode();
void testInvalidUnicodeJanssonFiles();
void testSmallBuffer();
void testEscape0();
void testNonEscapeUnicode();
void testEscapeUnicode();
void testCopy();
void testMove();
void testRemove();
void setUp();
void tearDown();