Integrate Poco::Web::JSON parser

This commit is contained in:
fbraem 2013-05-20 20:37:13 +02:00
parent 9ad116745b
commit 87d955ecde
3 changed files with 998 additions and 714 deletions

View File

@ -53,19 +53,211 @@
namespace Poco {
namespace JSON {
class JSON_API CharacterFeeder
{
public:
virtual ~CharacterFeeder() {}
virtual bool nextChar(int& c) = 0;
};
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.
{
public:
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 */
ES, /* 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_ARRAY_BEGIN,
JSON_T_ARRAY_END,
JSON_T_OBJECT_BEGIN,
JSON_T_OBJECT_END,
JSON_T_INTEGER,
JSON_T_FLOAT,
JSON_T_NULL,
JSON_T_TRUE,
JSON_T_FALSE,
JSON_T_STRING,
JSON_T_KEY,
JSON_T_VALUE_SEPARATOR,
JSON_T_MAX
};
static const int PARSE_BUFFER_SIZE = 3500;
static const int PARSER_STACK_SIZE = 128;
Parser(const Handler::Ptr& pHandler = new ParseHandler);
/// Constructor.
virtual ~Parser();
/// Destructor.
Dynamic::Var parse(const std::string& source);
void allowComments(bool sw);
/// Allow comments. By default this is false.
void allowNullByte(bool sw);
/// Allow a null byte in strings. By default this is true.
Dynamic::Var parse(const std::string& json);
/// Parses a string.
Dynamic::Var parse(std::istream& in);
@ -81,33 +273,95 @@ public:
/// Returns the result of parsing;
private:
const Token* nextToken();
/// Returns the next token.
void readObject();
/// Starts reading an object.
void readArray();
/// Starts reading an array.
bool readRow(bool firstCall = false);
/// Reads a property value pair. Returns true when a next row is expected.
void readValue(const Token* token);
/// Read a value from the token.
bool readElements(bool firstCall = false);
/// Read all elements of an array.
StreamTokenizer _tokenizer;
Handler::Ptr _pHandler;
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(int nextChar, int nextClass);
void addEscapedCharToParseBuffer(int nextChar);
int decodeUnicodeChar();
void assertNotStringNullBool();
void assertNonContainer();
void parseBuffer();
bool parseChar(int nextChar);
/// 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 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;
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;
};
inline Dynamic::Var Parser::parse(const std::string& source)
inline void Parser::allowComments(bool sw)
{
std::istringstream is(source);
return parse(is);
_allowComments = sw;
}
inline void Parser::allowNullByte(bool sw)
{
_allowNullByte = sw;
}
@ -129,6 +383,37 @@ inline Dynamic::Var Parser::result() const
}
inline bool Parser::done()
{
return _state == OK && pop(MODE_DONE);
}
inline void Parser::assertNotStringNullBool()
{
poco_assert(_type != JSON_T_FALSE &&
_type != JSON_T_TRUE &&
_type != JSON_T_NULL &&
_type != JSON_T_STRING);
}
inline void Parser::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 Parser::growBuffer()
{
_parseBuffer.resize(_parseBuffer.size() * 2, true);
}
}} // namespace Poco::JSON

File diff suppressed because it is too large Load Diff

View File

@ -1193,6 +1193,7 @@ void JSONTest::testInvalidJanssonFiles()
std::cout << filePath.toString() << std::endl;
Parser parser;
parser.allowNullByte(false);
Var result;
try
@ -1235,6 +1236,7 @@ void JSONTest::testInvalidUnicodeJanssonFiles()
std::cout << filePath.toString() << std::endl;
Parser parser;
parser.allowNullByte(false);
Var result;
try