remove json.org parser code

This commit is contained in:
Alex Fabijanic
2017-09-25 11:46:23 -05:00
parent d805647476
commit b5b8d16e5d
3 changed files with 4 additions and 1199 deletions

View File

@@ -10,15 +10,9 @@ include $(POCO_BASE)/build/rules/global
INCLUDE += -I $(POCO_BASE)/JSON/include/Poco/JSON
POCO_JSON_PARSER := $(if $(POCO_JSON_PARSER),$(POCO_JSON_PARSER),PD_JSON_PARSER)
objects = Array Object Parser ParserImpl Handler \
Stringifier ParseHandler PrintHandler Query \
JSONException Template TemplateCache
ifeq ($(POCO_JSON_PARSER),PD_JSON_PARSER)
objects += pd_json
endif
JSONException Template TemplateCache pd_json
target = PocoJSON
target_version = $(LIBVERSION)

View File

@@ -28,23 +28,15 @@
#include "Poco/UTF8Encoding.h"
#include "Poco/Dynamic/Var.h"
#include <string>
//#define JSON_ORG_PARSER
#define PD_JSON_PARSER
#ifdef PD_JSON_PARSER
extern "C" {
#include "pd_json.h"
}
#endif
namespace Poco {
namespace JSON {
#ifdef PD_JSON_PARSER
class JSON_API ParserImpl
{
protected:
@@ -203,699 +195,6 @@ inline Dynamic::Var ParserImpl::asVarImpl() const
}
#elif defined(JSON_ORG_PARSER)
/*
Copyright (c) 2005 JSON.org
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
The Software shall be used for Good, not Evil.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
class JSON_API ParserImpl
{
protected:
typedef std::char_traits<char> CharTraits;
typedef CharTraits::int_type CharIntType;
enum Classes
{
C_SPACE, /* space */
C_WHITE, /* other whitespace */
C_LCURB, /* { */
C_RCURB, /* } */
C_LSQRB, /* [ */
C_RSQRB, /* ] */
C_COLON, /* : */
C_COMMA, /* , */
C_QUOTE, /* " */
C_BACKS, /* \ */
C_SLASH, /* / */
C_PLUS, /* + */
C_MINUS, /* - */
C_POINT, /* . */
C_ZERO , /* 0 */
C_DIGIT, /* 123456789 */
C_LOW_A, /* a */
C_LOW_B, /* b */
C_LOW_C, /* c */
C_LOW_D, /* d */
C_LOW_E, /* e */
C_LOW_F, /* f */
C_LOW_L, /* l */
C_LOW_N, /* n */
C_LOW_R, /* r */
C_LOW_S, /* s */
C_LOW_T, /* t */
C_LOW_U, /* u */
C_ABCDF, /* ABCDF */
C_E, /* E */
C_ETC, /* everything else */
C_STAR, /* * */
NR_CLASSES
};
enum States
/// State codes
{
GO, /* start */
OK, /* ok */
OB, /* object */
KE, /* key */
CO, /* colon */
VA, /* value */
AR, /* array */
ST, /* string */
EC, /* escape */
U1, /* u1 */
U2, /* u2 */
U3, /* u3 */
U4, /* u4 */
MI, /* minus */
ZE, /* zero */
IT, /* integer */
FR, /* fraction */
E1, /* e */
E2, /* ex */
E3, /* exp */
T1, /* tr */
T2, /* tru */
T3, /* true */
F1, /* fa */
F2, /* fal */
F3, /* fals */
F4, /* false */
N1, /* nu */
N2, /* nul */
N3, /* null */
C1, /* / */
C2, /* / * */
C3, /* * */
FX, /* *.* *eE* */
D1, /* second UTF-16 character decoding started by \ */
D2, /* second UTF-16 character proceeded by u */
NR_STATES
};
enum Modes
/// Modes that can be pushed on the _pStack.
{
MODE_ARRAY = 1,
MODE_DONE = 2,
MODE_KEY = 3,
MODE_OBJECT = 4
};
enum Actions
{
CB = -10, /* _comment begin */
CE = -11, /* _comment end */
FA = -12, /* 0 */
TR = -13, /* 0 */
NU = -14, /* null */
DE = -15, /* double detected by exponent e E */
DF = -16, /* double detected by fraction . */
SB = -17, /* string begin */
MX = -18, /* integer detected by minus */
ZX = -19, /* integer detected by zero */
IX = -20, /* integer detected by 1-9 */
EX = -21, /* next char is _escaped */
UC = -22 /* Unicode character read */
};
enum JSONType
{
JSON_T_NONE = 0,
JSON_T_INTEGER,
JSON_T_FLOAT,
JSON_T_NULL,
JSON_T_TRUE,
JSON_T_FALSE,
JSON_T_STRING,
JSON_T_MAX
};
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;
ParserImpl(const Handler::Ptr& pHandler = new ParseHandler, std::size_t bufSize = JSON_PARSE_BUFFER_SIZE);
/// Creates JSON ParserImpl, using the given Handler and buffer size.
virtual ~ParserImpl();
/// Destroys JSON ParserImpl.
void resetImpl();
/// Resets the parser.
void setAllowCommentsImpl(bool comments);
/// Allow or disallow comments. By default, comments are not allowed.
bool getAllowCommentsImpl() const;
/// Returns true if comments are allowed, false otherwise.
///
/// By default, comments are not allowed.
void setAllowNullByteImpl(bool nullByte);
/// Allow or disallow null byte in strings.
///
/// By default, null byte is allowed.
bool getAllowNullByteImpl() const;
/// Returns true if null byte is allowed, false otherwise.
///
/// By default, null bytes are allowed.
void setDepthImpl(std::size_t depth);
/// Sets the allowed JSON depth.
std::size_t getDepthImpl() const;
/// Returns the allowed JSON depth.
Dynamic::Var parseImpl(const std::string& json);
/// Parses JSON from a string.
Dynamic::Var parseImpl(std::istream& in);
/// Parses JSON from an input stream.
void setHandlerImpl(const Handler::Ptr& pHandler);
/// Set the Handler.
const Handler::Ptr& getHandlerImpl();
/// Returns the Handler.
Dynamic::Var asVarImpl() const;
/// Returns the result of parsing;
Dynamic::Var resultImpl() const;
/// Returns the result of parsing as Dynamic::Var;
private:
ParserImpl(const ParserImpl&);
ParserImpl& operator = (const ParserImpl&);
typedef Poco::Buffer<char> BufType;
bool push(int mode);
/// Push a mode onto the _pStack. Return false if there is overflow.
bool pop(int mode);
/// Pops the stack, assuring that the current mode matches the expectation.
/// Returns false if there is underflow or if the modes mismatch.
void growBuffer();
void clearBuffer();
void parseBufferPushBackChar(char c);
void parseBufferPopBackChar();
void addCharToParseBuffer(CharIntType nextChar, int nextClass);
void addEscapedCharToParseBuffer(CharIntType nextChar);
CharIntType decodeUnicodeChar();
void assertNotStringNullBool();
void assertNonContainer();
void parseBuffer();
template <typename IT>
class Source
{
public:
Source(const IT& it, const IT& end) : _it(it), _end(end)
{
}
~Source()
{
}
bool nextChar(CharIntType& c)
{
if (_it == _end) return false;
c = *_it;
++_it;
return true;
}
private:
IT _it;
IT _end;
};
template <typename S>
bool parseChar(CharIntType nextChar, S& source)
/// Called for each character (or partial character) in JSON string.
/// It accepts UTF-8, UTF-16, or UTF-32. If the character is accepted,
/// it returns true, otherwise false.
{
CharIntType nextClass, nextState;
unsigned char ch = static_cast<unsigned char>(CharTraits::to_char_type(nextChar));
// Determine the character's class.
if (!_allowNullByte && ch == 0) return false;
if (ch >= 0x80)
{
nextClass = C_ETC;
CharIntType count = utf8CheckFirst(nextChar);
if (!count)
{
throw Poco::JSON::JSONException("Bad character.");
}
char buffer[4];
buffer[0] = nextChar;
for (int i = 1; i < count; ++i)
{
int c = 0;
if (!source.nextChar(c)) throw Poco::JSON::JSONException("Invalid UTF8 sequence found");
buffer[i] = c;
}
if (!Poco::UTF8Encoding::isLegal((unsigned char*) buffer, count))
{
throw Poco::JSON::JSONException("No legal UTF8 found");
}
for (int i = 0; i < count; ++i)
{
parseBufferPushBackChar(buffer[i]);
}
return true;
}
else
{
nextClass = _asciiClass[nextChar];
if (nextClass <= xx) return false;
}
addCharToParseBuffer(nextChar, nextClass);
// Get the next _state from the _state transition table.
nextState = _stateTransitionTable[_state][nextClass];
if (nextState >= 0)
{
_state = nextState;
}
else
{
// Or perform one of the actions.
switch (nextState)
{
// Unicode character
case UC:
if (!decodeUnicodeChar()) return false;
// check if we need to read a second UTF-16 char
if (_utf16HighSurrogate) _state = D1;
else _state = ST;
break;
// _escaped char
case EX:
_escaped = 1;
_state = EC;
break;
// integer detected by minus
case MX:
_type = JSON_T_INTEGER;
_state = MI;
break;
// integer detected by zero
case ZX:
_type = JSON_T_INTEGER;
_state = ZE;
break;
// integer detected by 1-9
case IX:
_type = JSON_T_INTEGER;
_state = IT;
break;
// floating point number detected by exponent
case DE:
assertNotStringNullBool();
_type = JSON_T_FLOAT;
_state = E1;
break;
// floating point number detected by fraction
case DF:
assertNotStringNullBool();
_type = JSON_T_FLOAT;
_state = FX;
break;
// string begin "
case SB:
clearBuffer();
poco_assert(_type == JSON_T_NONE);
_type = JSON_T_STRING;
_state = ST;
break;
// n
case NU:
poco_assert(_type == JSON_T_NONE);
_type = JSON_T_NULL;
_state = N1;
break;
// f
case FA:
poco_assert(_type == JSON_T_NONE);
_type = JSON_T_FALSE;
_state = F1;
break;
// t
case TR:
poco_assert(_type == JSON_T_NONE);
_type = JSON_T_TRUE;
_state = T1;
break;
// closing comment
case CE:
_comment = 0;
poco_assert(_parseBuffer.size() == 0);
poco_assert(_type == JSON_T_NONE);
_state = _beforeCommentState;
break;
// opening comment
case CB:
if (!_allowComments) return false;
parseBufferPopBackChar();
parseBuffer();
poco_assert(_parseBuffer.size() == 0);
poco_assert(_type != JSON_T_STRING);
switch (_stack[_top])
{
case MODE_ARRAY:
case MODE_OBJECT:
switch (_state)
{
case VA:
case AR:
_beforeCommentState = _state;
break;
default:
_beforeCommentState = OK;
break;
}
break;
default:
_beforeCommentState = _state;
break;
}
_type = JSON_T_NONE;
_state = C1;
_comment = 1;
break;
// empty }
case -9:
{
clearBuffer();
if (_pHandler) _pHandler->endObject();
if (!pop(MODE_KEY)) return false;
_state = OK;
break;
}
// }
case -8:
{
parseBufferPopBackChar();
parseBuffer();
if (_pHandler) _pHandler->endObject();
if (!pop(MODE_OBJECT)) return false;
_type = JSON_T_NONE;
_state = OK;
break;
}
// ]
case -7:
{
parseBufferPopBackChar();
parseBuffer();
if (_pHandler) _pHandler->endArray();
if (!pop(MODE_ARRAY)) return false;
_type = JSON_T_NONE;
_state = OK;
break;
}
// {
case -6:
{
parseBufferPopBackChar();
if (_pHandler) _pHandler->startObject();
if (!push(MODE_KEY)) return false;
poco_assert(_type == JSON_T_NONE);
_state = OB;
break;
}
// [
case -5:
{
parseBufferPopBackChar();
if (_pHandler) _pHandler->startArray();
if (!push(MODE_ARRAY)) return false;
poco_assert(_type == JSON_T_NONE);
_state = AR;
break;
}
// string end "
case -4:
parseBufferPopBackChar();
switch (_stack[_top])
{
case MODE_KEY:
{
poco_assert(_type == JSON_T_STRING);
_type = JSON_T_NONE;
_state = CO;
if (_pHandler)
{
_pHandler->key(std::string(_parseBuffer.begin(), _parseBuffer.size()));
}
clearBuffer();
break;
}
case MODE_ARRAY:
case MODE_OBJECT:
poco_assert(_type == JSON_T_STRING);
parseBuffer();
_type = JSON_T_NONE;
_state = OK;
break;
default:
return false;
}
break;
// ,
case -3:
{
parseBufferPopBackChar();
parseBuffer();
switch (_stack[_top])
{
case MODE_OBJECT:
//A comma causes a flip from object mode to key mode.
if (!pop(MODE_OBJECT) || !push(MODE_KEY)) return false;
poco_assert(_type != JSON_T_STRING);
_type = JSON_T_NONE;
_state = KE;
break;
case MODE_ARRAY:
poco_assert(_type != JSON_T_STRING);
_type = JSON_T_NONE;
_state = VA;
break;
default:
return false;
}
break;
}
// :
case -2:
// A colon causes a flip from key mode to object mode.
parseBufferPopBackChar();
if (!pop(MODE_KEY) || !push(MODE_OBJECT)) return false;
poco_assert(_type == JSON_T_NONE);
_state = VA;
break;
//Bad action.
default:
return false;
}
}
return true;
}
bool done();
static CharIntType utf8CheckFirst(char byte);
bool isHighSurrogate(unsigned uc);
bool isLowSurrogate(unsigned uc);
unsigned decodeSurrogatePair(unsigned hi, unsigned lo);
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;
Handler::Ptr _pHandler;
signed char _state;
signed char _beforeCommentState;
JSONType _type;
signed char _escaped;
signed char _comment;
unsigned short _utf16HighSurrogate;
int _depth;
int _top;
BufType _stack;
BufType _parseBuffer;
char _decimalPoint;
bool _allowNullByte;
bool _allowComments;
};
//
// inlines
//
inline void ParserImpl::setAllowCommentsImpl(bool comments)
{
_allowComments = comments;
}
inline bool ParserImpl::getAllowCommentsImpl() const
{
return _allowComments;
}
inline void ParserImpl::setAllowNullByteImpl(bool nullByte)
{
_allowNullByte = nullByte;
}
inline bool ParserImpl::getAllowNullByteImpl() const
{
return _allowNullByte;
}
inline void ParserImpl::setDepthImpl(std::size_t depth)
{
_depth = static_cast<int>(depth);
}
inline std::size_t ParserImpl::getDepthImpl() const
{
return static_cast<int>(_depth);
}
inline void ParserImpl::setHandlerImpl(const Handler::Ptr& pHandler)
{
_pHandler = pHandler;
}
inline const Handler::Ptr& ParserImpl::getHandlerImpl()
{
return _pHandler;
}
inline Dynamic::Var ParserImpl::resultImpl() const
{
return asVarImpl();
}
inline Dynamic::Var ParserImpl::asVarImpl() const
{
if (_pHandler) return _pHandler->asVar();
return Dynamic::Var();
}
inline bool ParserImpl::done()
{
return _state == OK && pop(MODE_DONE);
}
inline void ParserImpl::assertNotStringNullBool()
{
poco_assert(_type != JSON_T_FALSE &&
_type != JSON_T_TRUE &&
_type != JSON_T_NULL &&
_type != JSON_T_STRING);
}
inline void ParserImpl::assertNonContainer()
{
poco_assert(_type == JSON_T_NULL ||
_type == JSON_T_FALSE ||
_type == JSON_T_TRUE ||
_type == JSON_T_FLOAT ||
_type == JSON_T_INTEGER ||
_type == JSON_T_STRING);
}
inline void ParserImpl::growBuffer()
{
_parseBuffer.setCapacity(_parseBuffer.size() * 2, true);
}
inline bool ParserImpl::isHighSurrogate(unsigned uc)
{
return (uc & 0xFC00) == 0xD800;
}
inline bool ParserImpl::isLowSurrogate(unsigned uc)
{
return (uc & 0xFC00) == 0xDC00;
}
inline unsigned ParserImpl::decodeSurrogatePair(unsigned hi, unsigned lo)
{
return ((hi & 0x3FF) << 10) + (lo & 0x3FF) + 0x10000;
}
#else
#error "No JSON parser defined."
#endif // JSON_ORG_PARSER
} } // namespace Poco::JSON

View File

@@ -32,9 +32,6 @@ namespace Poco {
namespace JSON {
#ifdef PD_JSON_PARSER
ParserImpl::ParserImpl(const Handler::Ptr& pHandler, std::size_t bufSize):
_pHandler(pHandler),
_depth(JSON_UNLIMITED_DEPTH),
@@ -229,489 +226,4 @@ void ParserImpl::handle()
}
#elif defined(JSON_ORG_PARSER)
static const unsigned char UTF8_LEAD_BITS[4] = { 0x00, 0xC0, 0xE0, 0xF0 };
const int ParserImpl::_asciiClass[] =
{
xx, xx, xx, xx, xx, xx, xx, xx,
xx, C_WHITE, C_WHITE, xx, xx, C_WHITE, xx, xx,
xx, xx, xx, xx, xx, xx, xx, xx,
xx, xx, xx, xx, xx, xx, xx, xx,
C_SPACE, C_ETC, C_QUOTE, C_ETC, C_ETC, C_ETC, C_ETC, C_ETC,
C_ETC, C_ETC, C_STAR, C_PLUS, C_COMMA, C_MINUS, C_POINT, C_SLASH,
C_ZERO, C_DIGIT, C_DIGIT, C_DIGIT, C_DIGIT, C_DIGIT, C_DIGIT, C_DIGIT,
C_DIGIT, C_DIGIT, C_COLON, C_ETC, C_ETC, C_ETC, C_ETC, C_ETC,
C_ETC, C_ABCDF, C_ABCDF, C_ABCDF, C_ABCDF, C_E, C_ABCDF, C_ETC,
C_ETC, C_ETC, C_ETC, C_ETC, C_ETC, C_ETC, C_ETC, C_ETC,
C_ETC, C_ETC, C_ETC, C_ETC, C_ETC, C_ETC, C_ETC, C_ETC,
C_ETC, C_ETC, C_ETC, C_LSQRB, C_BACKS, C_RSQRB, C_ETC, C_ETC,
C_ETC, C_LOW_A, C_LOW_B, C_LOW_C, C_LOW_D, C_LOW_E, C_LOW_F, C_ETC,
C_ETC, C_ETC, C_ETC, C_ETC, C_LOW_L, C_ETC, C_LOW_N, C_ETC,
C_ETC, C_ETC, C_LOW_R, C_LOW_S, C_LOW_T, C_LOW_U, C_ETC, C_ETC,
C_ETC, C_ETC, C_ETC, C_LCURB, C_ETC, C_RCURB, C_ETC, C_ETC
};
const int ParserImpl::_stateTransitionTable[NR_STATES][NR_CLASSES] =
{
/*
white 1-9 ABCDF etc
space | { } [ ] : , " \ / + - . 0 | a b c d e f l n r s t u | E | * */
/*start GO*/ {GO,GO,-6,xx,-5,xx,xx,xx,xx,xx,CB,xx,xx,xx,xx,xx,xx,xx,xx,xx,xx,xx,xx,xx,xx,xx,xx,xx,xx,xx,xx,xx},
/*ok OK*/ {OK,OK,xx,-8,xx,-7,xx,-3,xx,xx,CB,xx,xx,xx,xx,xx,xx,xx,xx,xx,xx,xx,xx,xx,xx,xx,xx,xx,xx,xx,xx,xx},
/*object OB*/ {OB,OB,xx,-9,xx,xx,xx,xx,SB,xx,CB,xx,xx,xx,xx,xx,xx,xx,xx,xx,xx,xx,xx,xx,xx,xx,xx,xx,xx,xx,xx,xx},
/*key KE*/ {KE,KE,xx,xx,xx,xx,xx,xx,SB,xx,CB,xx,xx,xx,xx,xx,xx,xx,xx,xx,xx,xx,xx,xx,xx,xx,xx,xx,xx,xx,xx,xx},
/*colon CO*/ {CO,CO,xx,xx,xx,xx,-2,xx,xx,xx,CB,xx,xx,xx,xx,xx,xx,xx,xx,xx,xx,xx,xx,xx,xx,xx,xx,xx,xx,xx,xx,xx},
/*value VA*/ {VA,VA,-6,xx,-5,xx,xx,xx,SB,xx,CB,xx,MX,xx,ZX,IX,xx,xx,xx,xx,xx,FA,xx,NU,xx,xx,TR,xx,xx,xx,xx,xx},
/*array AR*/ {AR,AR,-6,xx,-5,-7,xx,xx,SB,xx,CB,xx,MX,xx,ZX,IX,xx,xx,xx,xx,xx,FA,xx,NU,xx,xx,TR,xx,xx,xx,xx,xx},
/*string ST*/ {ST,xx,ST,ST,ST,ST,ST,ST,-4,EX,ST,ST,ST,ST,ST,ST,ST,ST,ST,ST,ST,ST,ST,ST,ST,ST,ST,ST,ST,ST,ST,ST},
/*escape EC*/ {xx,xx,xx,xx,xx,xx,xx,xx,ST,ST,ST,xx,xx,xx,xx,xx,xx,ST,xx,xx,xx,ST,xx,ST,ST,xx,ST,U1,xx,xx,xx,xx},
/*u1 U1*/ {xx,xx,xx,xx,xx,xx,xx,xx,xx,xx,xx,xx,xx,xx,U2,U2,U2,U2,U2,U2,U2,U2,xx,xx,xx,xx,xx,xx,U2,U2,xx,xx},
/*u2 U2*/ {xx,xx,xx,xx,xx,xx,xx,xx,xx,xx,xx,xx,xx,xx,U3,U3,U3,U3,U3,U3,U3,U3,xx,xx,xx,xx,xx,xx,U3,U3,xx,xx},
/*u3 U3*/ {xx,xx,xx,xx,xx,xx,xx,xx,xx,xx,xx,xx,xx,xx,U4,U4,U4,U4,U4,U4,U4,U4,xx,xx,xx,xx,xx,xx,U4,U4,xx,xx},
/*u4 U4*/ {xx,xx,xx,xx,xx,xx,xx,xx,xx,xx,xx,xx,xx,xx,UC,UC,UC,UC,UC,UC,UC,UC,xx,xx,xx,xx,xx,xx,UC,UC,xx,xx},
/*minus MI*/ {xx,xx,xx,xx,xx,xx,xx,xx,xx,xx,xx,xx,xx,xx,ZE,IT,xx,xx,xx,xx,xx,xx,xx,xx,xx,xx,xx,xx,xx,xx,xx,xx},
/*zero ZE*/ {OK,OK,xx,-8,xx,-7,xx,-3,xx,xx,CB,xx,xx,DF,xx,xx,xx,xx,xx,xx,xx,xx,xx,xx,xx,xx,xx,xx,xx,xx,xx,xx},
/*int IT*/ {OK,OK,xx,-8,xx,-7,xx,-3,xx,xx,CB,xx,xx,DF,IT,IT,xx,xx,xx,xx,DE,xx,xx,xx,xx,xx,xx,xx,xx,DE,xx,xx},
/*frac FR*/ {OK,OK,xx,-8,xx,-7,xx,-3,xx,xx,CB,xx,xx,xx,FR,FR,xx,xx,xx,xx,E1,xx,xx,xx,xx,xx,xx,xx,xx,E1,xx,xx},
/*e E1*/ {xx,xx,xx,xx,xx,xx,xx,xx,xx,xx,xx,E2,E2,xx,E3,E3,xx,xx,xx,xx,xx,xx,xx,xx,xx,xx,xx,xx,xx,xx,xx,xx},
/*ex E2*/ {xx,xx,xx,xx,xx,xx,xx,xx,xx,xx,xx,xx,xx,xx,E3,E3,xx,xx,xx,xx,xx,xx,xx,xx,xx,xx,xx,xx,xx,xx,xx,xx},
/*exp E3*/ {OK,OK,xx,-8,xx,-7,xx,-3,xx,xx,xx,xx,xx,xx,E3,E3,xx,xx,xx,xx,xx,xx,xx,xx,xx,xx,xx,xx,xx,xx,xx,xx},
/*tr T1*/ {xx,xx,xx,xx,xx,xx,xx,xx,xx,xx,xx,xx,xx,xx,xx,xx,xx,xx,xx,xx,xx,xx,xx,xx,T2,xx,xx,xx,xx,xx,xx,xx},
/*tru T2*/ {xx,xx,xx,xx,xx,xx,xx,xx,xx,xx,xx,xx,xx,xx,xx,xx,xx,xx,xx,xx,xx,xx,xx,xx,xx,xx,xx,T3,xx,xx,xx,xx},
/*1 T3*/ {xx,xx,xx,xx,xx,xx,xx,xx,xx,xx,CB,xx,xx,xx,xx,xx,xx,xx,xx,xx,OK,xx,xx,xx,xx,xx,xx,xx,xx,xx,xx,xx},
/*fa F1*/ {xx,xx,xx,xx,xx,xx,xx,xx,xx,xx,xx,xx,xx,xx,xx,xx,F2,xx,xx,xx,xx,xx,xx,xx,xx,xx,xx,xx,xx,xx,xx,xx},
/*fal F2*/ {xx,xx,xx,xx,xx,xx,xx,xx,xx,xx,xx,xx,xx,xx,xx,xx,xx,xx,xx,xx,xx,xx,F3,xx,xx,xx,xx,xx,xx,xx,xx,xx},
/*fals F3*/ {xx,xx,xx,xx,xx,xx,xx,xx,xx,xx,xx,xx,xx,xx,xx,xx,xx,xx,xx,xx,xx,xx,xx,xx,xx,F4,xx,xx,xx,xx,xx,xx},
/*0 F4*/ {xx,xx,xx,xx,xx,xx,xx,xx,xx,xx,CB,xx,xx,xx,xx,xx,xx,xx,xx,xx,OK,xx,xx,xx,xx,xx,xx,xx,xx,xx,xx,xx},
/*nu N1*/ {xx,xx,xx,xx,xx,xx,xx,xx,xx,xx,xx,xx,xx,xx,xx,xx,xx,xx,xx,xx,xx,xx,xx,xx,xx,xx,xx,N2,xx,xx,xx,xx},
/*nul N2*/ {xx,xx,xx,xx,xx,xx,xx,xx,xx,xx,xx,xx,xx,xx,xx,xx,xx,xx,xx,xx,xx,xx,N3,xx,xx,xx,xx,xx,xx,xx,xx,xx},
/*null N3*/ {xx,xx,xx,xx,xx,xx,xx,xx,xx,xx,CB,xx,xx,xx,xx,xx,xx,xx,xx,xx,xx,xx,OK,xx,xx,xx,xx,xx,xx,xx,xx,xx},
/*/ C1*/ {xx,xx,xx,xx,xx,xx,xx,xx,xx,xx,xx,xx,xx,xx,xx,xx,xx,xx,xx,xx,xx,xx,xx,xx,xx,xx,xx,xx,xx,xx,xx,C2},
/*/* C2*/ {C2,C2,C2,C2,C2,C2,C2,C2,C2,C2,C2,C2,C2,C2,C2,C2,C2,C2,C2,C2,C2,C2,C2,C2,C2,C2,C2,C2,C2,C2,C2,C3},
/** C3*/ {C2,C2,C2,C2,C2,C2,C2,C2,C2,C2,CE,C2,C2,C2,C2,C2,C2,C2,C2,C2,C2,C2,C2,C2,C2,C2,C2,C2,C2,C2,C2,C3},
/*_. FX*/ {OK,OK,xx,-8,xx,-7,xx,-3,xx,xx,xx,xx,xx,xx,FR,FR,xx,xx,xx,xx,E1,xx,xx,xx,xx,xx,xx,xx,xx,E1,xx,xx},
/*\ D1*/ {xx,xx,xx,xx,xx,xx,xx,xx,xx,D2,xx,xx,xx,xx,xx,xx,xx,xx,xx,xx,xx,xx,xx,xx,xx,xx,xx,xx,xx,xx,xx,xx},
/*\ D2*/ {xx,xx,xx,xx,xx,xx,xx,xx,xx,xx,xx,xx,xx,xx,xx,xx,xx,xx,xx,xx,xx,xx,xx,xx,xx,xx,xx,U1,xx,xx,xx,xx},
};
ParserImpl::ParserImpl(const Handler::Ptr& pHandler, std::size_t bufSize):
_pHandler(pHandler),
_state(GO),
_beforeCommentState(0),
_type(JSON_T_NONE),
_escaped(0),
_comment(0),
_utf16HighSurrogate(0),
_depth(JSON_UNLIMITED_DEPTH),
_top(-1),
_stack(JSON_PARSER_STACK_SIZE),
_parseBuffer(bufSize),
_decimalPoint('.'),
_allowNullByte(true),
_allowComments(false)
{
_parseBuffer.resize(0);
push(MODE_DONE);
}
ParserImpl::~ParserImpl()
{
}
void ParserImpl::resetImpl()
{
_state = GO;
_beforeCommentState = 0;
_type = JSON_T_NONE;
_escaped = 0;
_utf16HighSurrogate = 0;
_top = -1;
_stack.clear();
_parseBuffer.resize(0);
push(MODE_DONE);
if (_pHandler) _pHandler->reset();
}
Dynamic::Var ParserImpl::parseImpl(const std::string& json)
{
std::string::const_iterator it = json.begin();
std::string::const_iterator end = json.end();
Source<std::string::const_iterator> source(it, end);
int c = 0;
while (source.nextChar(c))
{
if (0 == parseChar(c, source))
throw SyntaxException("JSON syntax error");
}
if (!done())
throw JSONException("JSON syntax error");
return asVarImpl();
}
Dynamic::Var ParserImpl::parseImpl(std::istream& in)
{
std::istreambuf_iterator<char> it(in.rdbuf());
std::istreambuf_iterator<char> end;
Source<std::istreambuf_iterator<char> > source(it, end);
int c = 0;
while (source.nextChar(c))
{
if (0 == parseChar(c, source)) throw JSONException("JSON syntax error");
}
if (!done())
throw JSONException("JSON syntax error");
return asVarImpl();
}
bool ParserImpl::push(int mode)
{
_top += 1;
if (_depth < 0)
{
if (_top >= _stack.size())
_stack.resize(_stack.size() * 2, true);
}
else
{
if (_top >= _depth) return false;
}
_stack[_top] = mode;
return true;
}
bool ParserImpl::pop(int mode)
{
if (_top < 0 || _stack[_top] != mode)
return false;
_top -= 1;
return true;
}
void ParserImpl::clearBuffer()
{
_parseBuffer.resize(0);
}
void ParserImpl::parseBufferPopBackChar()
{
poco_assert(_parseBuffer.size() >= 1);
_parseBuffer.resize(_parseBuffer.size() - 1);
}
void ParserImpl::parseBufferPushBackChar(char c)
{
if (_parseBuffer.size() + 1 >= _parseBuffer.capacity())
_parseBuffer.setCapacity(_parseBuffer.capacity() * 2);
_parseBuffer.append(c);
}
void ParserImpl::addEscapedCharToParseBuffer(CharIntType nextChar)
{
_escaped = 0;
// remove the backslash
parseBufferPopBackChar();
switch (nextChar)
{
case 'b':
parseBufferPushBackChar('\b');
break;
case 'f':
parseBufferPushBackChar('\f');
break;
case 'n':
parseBufferPushBackChar('\n');
break;
case 'r':
parseBufferPushBackChar('\r');
break;
case 't':
parseBufferPushBackChar('\t');
break;
case '"':
parseBufferPushBackChar('"');
break;
case '\\':
parseBufferPushBackChar('\\');
break;
case '/':
parseBufferPushBackChar('/');
break;
case 'u':
parseBufferPushBackChar('\\');
parseBufferPushBackChar('u');
break;
default:
break;
}
}
void ParserImpl::addCharToParseBuffer(CharIntType nextChar, int nextClass)
{
if (_escaped)
{
addEscapedCharToParseBuffer(nextChar);
return;
}
else if (!_comment)
{
if ((_type != JSON_T_NONE) ||
!((nextClass == C_SPACE) || (nextClass == C_WHITE)))
{
parseBufferPushBackChar((char) nextChar);
}
}
}
ParserImpl::CharIntType ParserImpl::decodeUnicodeChar()
{
int i;
unsigned uc = 0;
char* p;
int trailBytes;
poco_assert(_parseBuffer.size() >= 6);
p = &_parseBuffer[_parseBuffer.size() - 4];
for (i = 12; i >= 0; i -= 4, ++p)
{
unsigned x = *p;
if (x >= 'a') x -= ('a' - 10);
else if (x >= 'A') x -= ('A' - 10);
else x &= ~0x30u;
poco_assert(x < 16);
uc |= x << i;
}
if (!_allowNullByte && uc == 0) return 0;
// clear UTF-16 char from buffer
_parseBuffer.resize(_parseBuffer.size() - 6);
if (_utf16HighSurrogate)
{
if (isLowSurrogate(uc))
{
uc = decodeSurrogatePair(_utf16HighSurrogate, uc);
trailBytes = 3;
_utf16HighSurrogate = 0;
}
else // high surrogate without a following low surrogate
{
return 0;
}
}
else
{
if (uc < 0x80)
{
trailBytes = 0;
}
else if (uc < 0x800)
{
trailBytes = 1;
}
else if (isHighSurrogate(uc))
{
// save the high surrogate and wait for the low surrogate
_utf16HighSurrogate = uc;
return 1;
}
else if (isLowSurrogate(uc))
{
// low surrogate without a preceding high surrogate
return 0;
}
else
{
trailBytes = 2;
}
}
_parseBuffer.append((char) ((uc >> (trailBytes * 6)) | UTF8_LEAD_BITS[trailBytes]));
for (i = trailBytes * 6 - 6; i >= 0; i -= 6)
{
_parseBuffer.append((char) (((uc >> i) & 0x3F) | 0x80));
}
return 1;
}
void ParserImpl::parseBuffer()
{
if (_pHandler)
{
int type = _type; // just to silence g++
if (type != JSON_T_NONE)
{
assertNonContainer();
switch (type)
{
case JSON_T_TRUE:
{
_pHandler->value(true);
break;
}
case JSON_T_FALSE:
{
_pHandler->value(false);
break;
}
case JSON_T_NULL:
{
_pHandler->null();
break;
}
case JSON_T_FLOAT:
{
// Float can't end with a dot
if (_parseBuffer[_parseBuffer.size() - 1] == '.') throw SyntaxException("JSON syntax error");
double float_value = NumberParser::parseFloat(std::string(_parseBuffer.begin(), _parseBuffer.size()));
_pHandler->value(float_value);
break;
}
case JSON_T_INTEGER:
{
#if defined(POCO_HAVE_INT64)
std::string numStr(_parseBuffer.begin(), _parseBuffer.size());
try
{
Poco::trimInPlace(numStr);
Int64 value = NumberParser::parse64(numStr);
// if number is 32-bit, then handle as such
if (value > std::numeric_limits<int>::max()
|| value < std::numeric_limits<int>::min())
{
_pHandler->value(value);
}
else
{
_pHandler->value(static_cast<int>(value));
}
}
// try to handle error as unsigned in case of overflow
catch (const SyntaxException&)
{
UInt64 value = NumberParser::parseUnsigned64(numStr);
// if number is 32-bit, then handle as such
if (value > std::numeric_limits<unsigned>::max())
{
_pHandler->value(value);
}
else
{
_pHandler->value(static_cast<unsigned>(value));
}
}
#else
try
{
int value = NumberParser::parse(numStr);
_pHandler->value(value);
}
// try to handle error as unsigned in case of overflow
catch (const SyntaxException&)
{
unsigned value = NumberParser::parseUnsigned(numStr);
_pHandler->value(value);
}
#endif
}
break;
case JSON_T_STRING:
{
_pHandler->value(std::string(_parseBuffer.begin(), _parseBuffer.size()));
break;
}
}
}
}
clearBuffer();
}
int ParserImpl::utf8CheckFirst(char byte)
{
unsigned char u = (unsigned char) byte;
if (u < 0x80)
return 1;
if (0x80 <= u && u <= 0xBF)
{
// second, third or fourth byte of a multi-byte
// sequence, i.e. a "continuation byte"
return 0;
}
else if (u == 0xC0 || u == 0xC1)
{
// overlong encoding of an ASCII byte
return 0;
}
else if (0xC2 <= u && u <= 0xDF)
{
// 2-byte sequence
return 2;
}
else if (0xE0 <= u && u <= 0xEF)
{
// 3-byte sequence
return 3;
}
else if (0xF0 <= u && u <= 0xF4)
{
// 4-byte sequence
return 4;
}
else
{
// u >= 0xF5
// Restricted (start of 4-, 5- or 6-byte sequence) or invalid UTF-8
return 0;
}
}
#endif // JSON_ORG_PARSER
} } // namespace Poco::JSON