diff --git a/Foundation/include/Poco/Platform_WIN32.h b/Foundation/include/Poco/Platform_WIN32.h index ab9727f4a..9ad64d259 100644 --- a/Foundation/include/Poco/Platform_WIN32.h +++ b/Foundation/include/Poco/Platform_WIN32.h @@ -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 diff --git a/JSON/include/Poco/JSON/Parser.h b/JSON/include/Poco/JSON/Parser.h index e59961b63..ca93fc690 100644 --- a/JSON/include/Poco/JSON/Parser.h +++ b/JSON/include/Poco/JSON/Parser.h @@ -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 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 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 diff --git a/JSON/include/Poco/JSON/PrintHandler.h b/JSON/include/Poco/JSON/PrintHandler.h index 6e3fc1cde..f696ccc0e 100644 --- a/JSON/include/Poco/JSON/PrintHandler.h +++ b/JSON/include/Poco/JSON/PrintHandler.h @@ -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; }; diff --git a/JSON/src/Parser.cpp b/JSON/src/Parser.cpp index cb05b8213..9c02b8bcd 100644 --- a/JSON/src/Parser.cpp +++ b/JSON/src/Parser.cpp @@ -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::max() - || value < std::numeric_limits::min() ) + if (value > std::numeric_limits::max() + || value < std::numeric_limits::min() ) { _pHandler->value(value); } diff --git a/JSON/src/PrintHandler.cpp b/JSON/src/PrintHandler.cpp index 2487d16ae..17d0858ce 100644 --- a/JSON/src/PrintHandler.cpp +++ b/JSON/src/PrintHandler.cpp @@ -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 diff --git a/JSON/testsuite/src/JSONTest.cpp b/JSON/testsuite/src/JSONTest.cpp index e9e7f8a78..525750123 100644 --- a/JSON/testsuite/src/JSONTest.cpp +++ b/JSON/testsuite/src/JSONTest.cpp @@ -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