JSON fixes/refactoring

This commit is contained in:
Aleksandar Fabijanic 2013-05-20 23:36:58 -05:00
parent 9b6db2e75d
commit 41a07c15bf
6 changed files with 225 additions and 143 deletions

View File

@ -48,55 +48,55 @@
#if defined(_WIN32_WINNT_WIN8)
//Windows 8 _WIN32_WINNT_WIN8 (0x0602)
#ifdef _WIN32_WINNT
#undef _WIN32_WINNT
#undef _WIN32_WINNT
#endif
#define _WIN32_WINNT _WIN32_WINNT_WIN8
#elif defined(_WIN32_WINNT_WIN7)
//Windows 7 _WIN32_WINNT_WIN7 (0x0601)
#ifdef _WIN32_WINNT
#undef _WIN32_WINNT
#undef _WIN32_WINNT
#endif
#define _WIN32_WINNT _WIN32_WINNT_WIN7
#elif defined (_WIN32_WINNT_WS08)
//Windows Server 2008 _WIN32_WINNT_WS08 (0x0600)
#ifdef _WIN32_WINNT
#undef _WIN32_WINNT
#undef _WIN32_WINNT
#endif
#define _WIN32_WINNT _WIN32_WINNT_WS08
#elif defined (_WIN32_WINNT_VISTA)
//Windows Vista _WIN32_WINNT_VISTA (0x0600)
#ifdef _WIN32_WINNT
#undef _WIN32_WINNT
#undef _WIN32_WINNT
#endif
#define _WIN32_WINNT _WIN32_WINNT_VISTA
#elif defined (_WIN32_WINNT_LONGHORN)
//Windows Vista and server 2008 Development _WIN32_WINNT_LONGHORN (0x0600)
#ifdef _WIN32_WINNT
#undef _WIN32_WINNT
#undef _WIN32_WINNT
#endif
#define _WIN32_WINNT _WIN32_WINNT_LONGHORN
#elif defined (_WIN32_WINNT_WS03)
//Windows Server 2003 with SP1,
//Windows XP with SP2 _WIN32_WINNT_WS03 (0x0502)
#ifdef _WIN32_WINNT
#undef _WIN32_WINNT
#undef _WIN32_WINNT
#endif
#define _WIN32_WINNT _WIN32_WINNT_WS03
#elif defined (_WIN32_WINNT_WINXP)
//Windows Server 2003, Windows XP _WIN32_WINNT_WINXP (0x0501)
#ifdef _WIN32_WINNT
#undef _WIN32_WINNT
#undef _WIN32_WINNT
#endif
#define _WIN32_WINNT _WIN32_WINNT_WINXP
#elif defined (_WIN32_WINNT_WIN2K)
//Windows 2000 _WIN32_WINNT_WIN2K (0x0500)
#ifdef _WIN32_WINNT
#undef _WIN32_WINNT
#undef _WIN32_WINNT
#endif
#define _WIN32_WINNT _WIN32_WINNT_WIN2K
#elif defined (WINVER)
#ifdef _WIN32_WINNT
#undef _WIN32_WINNT
#undef _WIN32_WINNT
#endif
#define _WIN32_WINNT WINVER
#endif

View File

@ -53,64 +53,9 @@
namespace Poco {
namespace JSON {
class JSON_API CharacterFeeder
{
public:
virtual ~CharacterFeeder() {}
virtual bool nextChar(int& c) = 0;
};
class Source;
class JSON_API StreamCharacterFeeder : public CharacterFeeder
{
public:
StreamCharacterFeeder(std::istream& in) : _in(in) {}
virtual ~StreamCharacterFeeder() {}
bool nextChar(int& c);
private:
std::istream& _in;
};
inline bool StreamCharacterFeeder::nextChar(int& c)
{
if ( _in.good() )
{
c = _in.get();
return _in.good();
}
return false;
}
class JSON_API StringCharacterFeeder : public CharacterFeeder
{
public:
StringCharacterFeeder(std::string::const_iterator begin, std::string::const_iterator end) : _it(begin), _end(end)
{
}
virtual ~StringCharacterFeeder() {}
bool nextChar(int& c);
private:
std::string::const_iterator _it;
std::string::const_iterator _end;
};
inline bool StringCharacterFeeder::nextChar(int& c)
{
if ( _it == _end )
return false;
c = *_it++;
return true;
}
class JSON_API Parser
/// A class for passing JSON strings or streams.
@ -239,23 +184,39 @@ public:
JSON_T_VALUE_SEPARATOR,
JSON_T_MAX
};
static const std::size_t PARSE_BUFFER_SIZE = 3500;
static const std::size_t PARSER_STACK_SIZE = 128;
static const int UNLIMITED_DEPTH = -1;
static const int PARSE_BUFFER_SIZE = 3500;
static const int PARSER_STACK_SIZE = 128;
Parser(const Handler::Ptr& pHandler = new ParseHandler);
Parser(const Handler::Ptr& pHandler = new ParseHandler, std::size_t bufSize = PARSE_BUFFER_SIZE);
/// Constructor.
virtual ~Parser();
/// Destructor.
void reset();
/// Resets the parser.
void allowComments(bool sw);
/// Allow comments. By default this is false.
void setAllowComments(bool comments);
/// Allow comments. By default, comments are not allowed.
bool getAllowComments() const;
/// Returns true if comments are allowed, false otherwise.
/// By default, comments are not allowed.
void allowNullByte(bool sw);
/// Allow a null byte in strings. By default this is true.
void setAllowNullByte(bool nullByte);
/// Allow null byte in strings. By default, null byte is allowed.
bool getAllowNullByte() const;
/// Returns true if null byte is allowed, false otherwise.
/// By default, null bytes are allowed.
void setDepth(std::size_t depth);
/// Sets the allowed JSON depth.
std::size_t getDepth() const;
/// Returns the allowed JSON depth.
Dynamic::Var parse(const std::string& json);
/// Parses a string.
@ -273,12 +234,8 @@ public:
/// Returns the result of parsing;
private:
Handler::Ptr _pHandler;
typedef Poco::Buffer<char> BufType;
bool push(int mode);
/// Push a mode onto the _pStack. Return false if there is overflow.
@ -288,83 +245,95 @@ private:
void growBuffer();
void clearBuffer();
void parseBufferPushBackChar(char c);
void parseBufferPopBackChar();
void addCharToParseBuffer(int nextChar, int nextClass);
void addEscapedCharToParseBuffer(int nextChar);
int decodeUnicodeChar();
void assertNotStringNullBool();
void assertNonContainer();
void parseBuffer();
bool parseChar(int nextChar);
bool parseChar(int nextChar, Source& feeder);
/// Called for each character (or partial character) in JSON string.
/// It accepts UTF-8, UTF-16, or UTF-32. If it the character is accpeted,
/// It accepts UTF-8, UTF-16, or UTF-32. If it the character is accepted,
/// it returns true, otherwise false.
bool done();
static int utf8_check_first(char byte);
static const int _asciiClass[128];
/// This array maps the 128 ASCII characters into character classes.
/// The remaining Unicode characters should be mapped to C_ETC.
/// Non-whitespace control characters are errors.
static const int _stateTransitionTable[NR_STATES][NR_CLASSES];
static const int xx = -1;
signed char _state;
signed char _beforeCommentState;
JSONType _type;
signed char _escaped;
signed char _comment;
Handler::Ptr _pHandler;
signed char _state;
signed char _beforeCommentState;
JSONType _type;
signed char _escaped;
signed char _comment;
unsigned short _utf16HighSurrogate;
long _depth;
long _top;
BufType _stack;
BufType _parseBuffer;
size_t _parseBufferCount;
size_t _commentBeginOffset;
char _decimalPoint;
bool _allowNullByte;
bool _allowComments;
SharedPtr<CharacterFeeder> feeder;
int _depth;
int _top;
BufType _stack;
BufType _parseBuffer;
std::size_t _parseBufferCount;
char _decimalPoint;
bool _allowNullByte;
bool _allowComments;
};
inline void Parser::allowComments(bool sw)
inline void Parser::setAllowComments(bool sw)
{
_allowComments = sw;
}
inline void Parser::allowNullByte(bool sw)
inline bool Parser::getAllowComments() const
{
return _allowComments;
}
inline void Parser::setAllowNullByte(bool sw)
{
_allowNullByte = sw;
}
inline bool Parser::getAllowNullByte() const
{
return _allowNullByte;
}
inline void Parser::setDepth(std::size_t depth)
{
_depth = depth;
}
inline std::size_t Parser::getDepth() const
{
return _depth;
}
inline void Parser::setHandler(const Handler::Ptr& pHandler)
{
_pHandler = pHandler;
@ -385,7 +354,7 @@ inline Dynamic::Var Parser::result() const
inline bool Parser::done()
{
return _state == OK && pop(MODE_DONE);
return _state == OK && pop(MODE_DONE);
}
@ -414,6 +383,7 @@ inline void Parser::growBuffer()
_parseBuffer.resize(_parseBuffer.size() * 2, true);
}
}} // namespace Poco::JSON

View File

@ -125,11 +125,13 @@ private:
const char* endLine() const;
unsigned indent();
bool printFlat() const;
void arrayValue();
std::ostream& _out;
unsigned _indent;
std::string _tab;
bool _array;
bool _value;
};

View File

@ -129,7 +129,76 @@ const int Parser::_stateTransitionTable[NR_STATES][NR_CLASSES] = {
};
Parser::Parser(const Handler::Ptr& pHandler) :
// Source
class Source
{
public:
Source()
{
}
virtual ~Source()
{
}
virtual bool nextChar(int& c) = 0;
};
class StreamSource : public Source
{
public:
StreamSource(std::istream& in) : _in(in)
{
}
virtual ~StreamSource()
{
}
bool nextChar(int& c)
{
if ( _in.good() )
{
c = _in.get();
return _in.good();
}
return false;
}
private:
std::istream& _in;
};
class StringSource : public Source
{
public:
StringSource(std::string::const_iterator begin, std::string::const_iterator end) : _it(begin), _end(end)
{
}
virtual ~StringSource()
{
}
bool nextChar(int& c)
{
if ( _it == _end ) return false;
c = *_it++;
return true;
}
private:
std::string::const_iterator _it;
std::string::const_iterator _end;
};
// Parser
Parser::Parser(const Handler::Ptr& pHandler, std::size_t bufSize) :
_pHandler(pHandler),
_state(GO),
_beforeCommentState(0),
@ -137,38 +206,50 @@ Parser::Parser(const Handler::Ptr& pHandler) :
_escaped(0),
_comment(0),
_utf16HighSurrogate(0),
//_depth(config.parseDepth() ? config.parseDepth() : -1),
_depth(-1),
_depth(UNLIMITED_DEPTH),
_top(-1),
_stack(PARSER_STACK_SIZE),
_parseBuffer(PARSE_BUFFER_SIZE),
_parseBuffer(bufSize),
_parseBufferCount(0),
_commentBeginOffset(0),
_decimalPoint(0),
_decimalPoint('.'),
_allowNullByte(true),
_allowComments(false)
{
_stack.clear();
_parseBuffer.clear();
push(MODE_DONE);
_decimalPoint = *std::localeconv()->decimal_point;
clearBuffer();
}
Parser::~Parser()
{
}
void Parser::reset()
{
_state = GO;
_beforeCommentState = 0;
_type = JSON_T_NONE;
_escaped = 0;
_comment = 0;
_utf16HighSurrogate = 0;
_top = -1;
_parseBufferCount = 0;
_stack.clear();
_parseBuffer.clear();
push(MODE_DONE);
clearBuffer();
}
Dynamic::Var Parser::parse(const std::string& json)
{
feeder = new StringCharacterFeeder(json.begin(), json.end());
StringSource source(json.begin(), json.end());
int c = 0;
while(feeder->nextChar(c))
while(source.nextChar(c))
{
if (0 == parseChar(c)) throw SyntaxException("JSON syntax error");
if (0 == parseChar(c, source)) throw SyntaxException("JSON syntax error");
}
if (!done())
@ -180,12 +261,12 @@ Dynamic::Var Parser::parse(const std::string& json)
Dynamic::Var Parser::parse(std::istream& in)
{
feeder = new StreamCharacterFeeder(in);
StreamSource source(in);
int c = 0;
while(feeder->nextChar(c))
while(source.nextChar(c))
{
if (0 == parseChar(c)) throw JSONException("JSON syntax error");
if (0 == parseChar(c, source)) throw JSONException("JSON syntax error");
}
if (!done())
@ -222,6 +303,7 @@ bool Parser::pop(int mode)
return true;
}
void Parser::clearBuffer()
{
_parseBufferCount = 0;
@ -305,7 +387,7 @@ void Parser::addCharToParseBuffer(int nextChar, int nextClass)
}
bool Parser::parseChar(int nextChar)
bool Parser::parseChar(int nextChar, Source& source)
{
int nextClass, nextState;
@ -325,7 +407,7 @@ bool Parser::parseChar(int nextChar)
for(int i = 1; i < count; ++i)
{
int c = 0;
if ( !feeder->nextChar(c) ) throw JSONException("Invalid UTF8 character found");
if (!source.nextChar(c)) throw JSONException("Invalid UTF8 character found");
buffer[i] = c;
}
@ -702,8 +784,8 @@ void Parser::parseBuffer()
{
Int64 value = NumberParser::parse64(_parseBuffer.begin());
// if number is 32-bit, then handle as such
if ( value > std::numeric_limits<int>::max()
|| value < std::numeric_limits<int>::min() )
if (value > std::numeric_limits<int>::max()
|| value < std::numeric_limits<int>::min() )
{
_pHandler->value(value);
}

View File

@ -46,7 +46,8 @@ namespace JSON {
PrintHandler::PrintHandler(unsigned indent):
_out(std::cout),
_indent(indent),
_array(false)
_array(false),
_value(false)
{
}
@ -54,7 +55,8 @@ PrintHandler::PrintHandler(unsigned indent):
PrintHandler::PrintHandler(std::ostream& out, unsigned indent):
_out(out),
_indent(indent),
_array(false)
_array(false),
_value(false)
{
}
@ -107,6 +109,7 @@ void PrintHandler::startArray()
_out << '[' << endLine();
_tab.append(indent(), ' ');
_array = true;
_value = false;
}
@ -115,11 +118,17 @@ void PrintHandler::endArray()
_tab.erase(_tab.length() - indent());
_out << endLine() << _tab << ']';
_array = false;
_value = false;
}
void PrintHandler::key(const std::string& k)
{
if (_value)
{
comma();
_value = false;
}
_out << _tab << '"' << k << '"';
if (!printFlat()) _out << ' ';
_out << ':';
@ -129,60 +138,68 @@ void PrintHandler::key(const std::string& k)
void PrintHandler::null()
{
if (_array) _out << _tab;
arrayValue();
_out << "null";
_value = true;
}
void PrintHandler::value(int v)
{
if (_array) _out << _tab;
arrayValue();
_out << v;
_value = true;
}
void PrintHandler::value(unsigned v)
{
if (_array) _out << _tab;
arrayValue();
_out << v;
_value = true;
}
#if defined(POCO_HAVE_INT64)
void PrintHandler::value(Int64 v)
{
if (_array) _out << _tab;
arrayValue();
_out << v;
_value = true;
}
void PrintHandler::value(UInt64 v)
{
if (_array) _out << _tab;
arrayValue();
_out << v;
_value = true;
}
#endif
void PrintHandler::value(const std::string& value)
{
if (_array) _out << _tab;
arrayValue();
Stringifier::formatString(value, _out);
_value = true;
}
void PrintHandler::value(double d)
{
if (_array) _out << _tab;
arrayValue();
_out << d;
_value = true;
}
void PrintHandler::value(bool b)
{
if (_array) _out << _tab;
arrayValue();
_out << b;
_value = true;
}
@ -192,4 +209,12 @@ void PrintHandler::comma()
}
void PrintHandler::arrayValue()
{
if (_array)
{
if (_value) comma();
_out << _tab;
}
}
} } // namespace Poco::JSON

View File

@ -841,6 +841,7 @@ void JSONTest::testPrintHandler()
pHandler->setIndent(1);
ostr.str("");
parser.reset();
parser.parse(json);
assert (ostr.str() == "{\n"
" \"name\" : \"Homer\",\n"
@ -857,6 +858,7 @@ void JSONTest::testPrintHandler()
pHandler->setIndent(2);
ostr.str("");
parser.reset();
parser.parse(json);
assert (ostr.str() == "{\n"
" \"name\" : \"Homer\",\n"
@ -873,6 +875,7 @@ void JSONTest::testPrintHandler()
pHandler->setIndent(4);
ostr.str("");
parser.reset();
parser.parse(json);
assert (ostr.str() == "{\n"
" \"name\" : \"Homer\",\n"
@ -1193,7 +1196,7 @@ void JSONTest::testInvalidJanssonFiles()
std::cout << filePath.toString() << std::endl;
Parser parser;
parser.allowNullByte(false);
parser.setAllowNullByte(false);
Var result;
try
@ -1236,7 +1239,7 @@ void JSONTest::testInvalidUnicodeJanssonFiles()
std::cout << filePath.toString() << std::endl;
Parser parser;
parser.allowNullByte(false);
parser.setAllowNullByte(false);
Var result;
try