Something went wrong. Try again.
A fork of https://github.com/crosspoint-reader/crosspoint-reader
Something went wrong. Try again.
5.7 kB · 249 lines
C++
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250#include "StreamingJsonParser.h"
#include <cstring>
StreamingJsonParser::StreamingJsonParser(const JsonCallbacks& callbacks) : cb(callbacks) { reset(); }
void StreamingJsonParser::reset() { tokenLen = 0; state = State::SCANNING; expectingValue = false; escaped = false; tokenOverflow = false; error = false; nestingDepth = 0; literalLen = 0; literalPos = 0;}
void StreamingJsonParser::feed(const char* data, size_t len) { for (size_t i = 0; i < len && !error; ++i) { char c = data[i]; switch (state) { case State::SCANNING: handleScanning(c); break; case State::IN_STRING_KEY: case State::IN_STRING_VALUE: handleStringChar(c); break; case State::IN_NUMBER: handleNumber(c); break; case State::IN_LITERAL: handleLiteral(c); break; case State::SKIP_STRING: handleSkipString(c); break; } }}
void StreamingJsonParser::handleScanning(char c) { switch (c) { case '"': tokenLen = 0; tokenOverflow = false; if (expectingValue || inArray()) { state = State::IN_STRING_VALUE; } else { state = State::IN_STRING_KEY; } break; case '{': if (nestingDepth < MAX_NESTING) { nestingStack[nestingDepth++] = Container::OBJECT; } else { error = true; return; } if (cb.onObjectStart) cb.onObjectStart(cb.ctx); expectingValue = false; break; case '}': if (cb.onObjectEnd) cb.onObjectEnd(cb.ctx); if (nestingDepth > 0) --nestingDepth; expectingValue = false; break; case '[': if (nestingDepth < MAX_NESTING) { nestingStack[nestingDepth++] = Container::ARRAY; } else { error = true; return; } if (cb.onArrayStart) cb.onArrayStart(cb.ctx); expectingValue = false; break; case ']': if (cb.onArrayEnd) cb.onArrayEnd(cb.ctx); if (nestingDepth > 0) --nestingDepth; expectingValue = false; break; case ':': expectingValue = true; break; case ',': expectingValue = false; break; case 't': if (expectingValue || inArray()) { memcpy(literalExpected, "true", 4); literalLen = 4; literalPos = 1; state = State::IN_LITERAL; } break; case 'f': if (expectingValue || inArray()) { memcpy(literalExpected, "false", 5); literalLen = 5; literalPos = 1; state = State::IN_LITERAL; } break; case 'n': if (expectingValue || inArray()) { memcpy(literalExpected, "null", 4); literalLen = 4; literalPos = 1; state = State::IN_LITERAL; } break; default: if ((expectingValue || inArray()) && (c == '-' || (c >= '0' && c <= '9'))) { tokenLen = 0; tokenOverflow = false; appendToken(c); state = State::IN_NUMBER; } break; }}
void StreamingJsonParser::handleStringChar(char c) { if (escaped) { escaped = false; switch (c) { case '"': case '\\': case '/': appendToken(c); break; case 'b': appendToken('\b'); break; case 'f': appendToken('\f'); break; case 'n': appendToken('\n'); break; case 'r': appendToken('\r'); break; case 't': appendToken('\t'); break; case 'u': // Pass \uXXXX through as literal characters -- we don't decode // Unicode escapes since our use case only needs ASCII field matching. appendToken('\\'); appendToken('u'); break; default: appendToken('\\'); appendToken(c); break; } return; }
if (c == '\\') { escaped = true; return; }
if (c == '"') { emitToken(); return; }
appendToken(c);}
void StreamingJsonParser::handleNumber(char c) { if ((c >= '0' && c <= '9') || c == '.' || c == '-' || c == '+' || c == 'e' || c == 'E') { appendToken(c); return; }
if (!tokenOverflow && cb.onNumber) { tokenBuf[tokenLen] = '\0'; cb.onNumber(cb.ctx, tokenBuf, tokenLen); } state = State::SCANNING; expectingValue = false;
handleScanning(c);}
void StreamingJsonParser::handleLiteral(char c) { if (c == literalExpected[literalPos]) { ++literalPos; if (literalPos == literalLen) { if (literalExpected[0] == 't') { if (cb.onBool) cb.onBool(cb.ctx, true); } else if (literalExpected[0] == 'f') { if (cb.onBool) cb.onBool(cb.ctx, false); } else { if (cb.onNull) cb.onNull(cb.ctx); } state = State::SCANNING; expectingValue = false; } } else { error = true; }}
void StreamingJsonParser::handleSkipString(char c) { if (escaped) { escaped = false; return; } if (c == '\\') { escaped = true; return; } if (c == '"') { state = State::SCANNING; expectingValue = false; }}
void StreamingJsonParser::appendToken(char c) { if (tokenLen < TOKEN_BUF_SIZE - 1) { tokenBuf[tokenLen++] = c; } else { tokenOverflow = true; }}
void StreamingJsonParser::emitToken() { if (state == State::IN_STRING_KEY) { if (!tokenOverflow && cb.onKey) { tokenBuf[tokenLen] = '\0'; cb.onKey(cb.ctx, tokenBuf, tokenLen); } state = State::SCANNING; } else { if (!tokenOverflow && cb.onString) { tokenBuf[tokenLen] = '\0'; cb.onString(cb.ctx, tokenBuf, tokenLen); } state = State::SCANNING; expectingValue = false; }}