mirror of
https://github.com/pocoproject/poco.git
synced 2025-04-24 09:08:43 +02:00
Integrate Poco::Web::JSON parser
This commit is contained in:
parent
9ad116745b
commit
87d955ecde
@ -53,19 +53,211 @@
|
|||||||
namespace Poco {
|
namespace Poco {
|
||||||
namespace JSON {
|
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
|
class JSON_API Parser
|
||||||
/// A class for passing JSON strings or streams.
|
/// A class for passing JSON strings or streams.
|
||||||
{
|
{
|
||||||
public:
|
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);
|
Parser(const Handler::Ptr& pHandler = new ParseHandler);
|
||||||
/// Constructor.
|
/// Constructor.
|
||||||
|
|
||||||
virtual ~Parser();
|
virtual ~Parser();
|
||||||
/// Destructor.
|
/// 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.
|
/// Parses a string.
|
||||||
|
|
||||||
Dynamic::Var parse(std::istream& in);
|
Dynamic::Var parse(std::istream& in);
|
||||||
@ -81,33 +273,95 @@ public:
|
|||||||
/// Returns the result of parsing;
|
/// Returns the result of parsing;
|
||||||
|
|
||||||
private:
|
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;
|
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);
|
_allowComments = sw;
|
||||||
return parse(is);
|
}
|
||||||
|
|
||||||
|
|
||||||
|
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
|
}} // namespace Poco::JSON
|
||||||
|
|
||||||
|
|
||||||
|
1379
JSON/src/Parser.cpp
1379
JSON/src/Parser.cpp
File diff suppressed because it is too large
Load Diff
@ -1193,6 +1193,7 @@ void JSONTest::testInvalidJanssonFiles()
|
|||||||
std::cout << filePath.toString() << std::endl;
|
std::cout << filePath.toString() << std::endl;
|
||||||
|
|
||||||
Parser parser;
|
Parser parser;
|
||||||
|
parser.allowNullByte(false);
|
||||||
Var result;
|
Var result;
|
||||||
|
|
||||||
try
|
try
|
||||||
@ -1235,6 +1236,7 @@ void JSONTest::testInvalidUnicodeJanssonFiles()
|
|||||||
std::cout << filePath.toString() << std::endl;
|
std::cout << filePath.toString() << std::endl;
|
||||||
|
|
||||||
Parser parser;
|
Parser parser;
|
||||||
|
parser.allowNullByte(false);
|
||||||
Var result;
|
Var result;
|
||||||
|
|
||||||
try
|
try
|
||||||
|
Loading…
x
Reference in New Issue
Block a user