#include "JSONStream.h" #ifdef JSON_STREAM #include "JSONWorker.h" #include "JSONValidator.h" JSONStream::JSONStream(json_stream_callback_t call_p, json_stream_e_callback_t call_e, void * callbackIdentifier) json_nothrow : state(true), call(call_p), err_call(call_e), buffer(), callback_identifier(callbackIdentifier) { LIBJSON_CTOR; } JSONStream::JSONStream(const JSONStream & orig) json_nothrow : state(orig.state), call(orig.call), err_call(orig.err_call), buffer(orig.buffer), callback_identifier(orig.callback_identifier){ LIBJSON_COPY_CTOR; } JSONStream & JSONStream::operator =(const JSONStream & orig) json_nothrow { LIBJSON_ASSIGNMENT; err_call = orig.err_call; call = orig.call; state = orig.state; buffer = orig.buffer; callback_identifier = orig.callback_identifier; return *this; } #ifdef JSON_LIBRARY JSONStream & JSONStream::operator << (const json_char * str) json_nothrow { #else JSONStream & JSONStream::operator << (const json_string & str) json_nothrow { #endif if (state){ buffer += str; parse(); } return *this; } #define QUOTECASE_STREAM()\ case JSON_TEXT('\"'):\ while (*(++p) != JSON_TEXT('\"')){\ if (json_unlikely(*p == JSON_TEXT('\0'))) return json_string::npos;\ }\ break; #define NULLCASE_STREAM()\ case JSON_TEXT('\0'):\ return json_string::npos;\ #define BRACKET_STREAM(left, right)\ case left: {\ size_t brac = 1;\ while (brac){\ switch (*(++p)){\ case right:\ --brac;\ break;\ case left:\ ++brac;\ break;\ QUOTECASE_STREAM()\ NULLCASE_STREAM()\ }\ }\ break;}\ case right:\ return json_string::npos; #if (JSON_READ_PRIORITY == HIGH) && (!(defined(JSON_LESS_MEMORY))) #define STREAM_FIND_NEXT_RELEVANT(ch, vt, po) FindNextRelevant(vt, po) template size_t JSONStream::FindNextRelevant(const json_string & value_t, const size_t pos) json_nothrow { #else #define STREAM_FIND_NEXT_RELEVANT(ch, vt, po) FindNextRelevant(ch, vt, po) size_t JSONStream::FindNextRelevant(json_char ch, const json_string & value_t, const size_t pos) json_nothrow { #endif const json_char * start = value_t.c_str(); for (const json_char * p = start + pos; *p; ++p){ if (json_unlikely(*p == ch)) return p - start; switch (*p){ BRACKET_STREAM(JSON_TEXT('['), JSON_TEXT(']')) BRACKET_STREAM(JSON_TEXT('{'), JSON_TEXT('}')) QUOTECASE_STREAM() } }; return json_string::npos; } void JSONStream::parse(void) json_nothrow { #ifdef JSON_SECURITY_MAX_STREAM_OBJECTS size_t objects = 0; #endif for(;;){ size_t pos = buffer.find_first_of(JSON_TEXT("{[")); if (json_likely(pos != json_string::npos)){ size_t end = (buffer[pos] == JSON_TEXT('[')) ? STREAM_FIND_NEXT_RELEVANT(JSON_TEXT(']'), buffer, pos + 1) : STREAM_FIND_NEXT_RELEVANT(JSON_TEXT('}'), buffer, pos + 1); if (end != json_string::npos){ #ifdef JSON_SECURITY_MAX_STREAM_OBJECTS if (++objects > JSON_SECURITY_MAX_STREAM_OBJECTS){ JSON_FAIL(JSON_TEXT("Maximum number of json objects for a stream at once has been reached")); if (err_call) err_call(getIdentifier()); state = false; return; } #endif START_MEM_SCOPE JSONNode temp(JSONWorker::parse(buffer.substr(pos, end - pos + 1))); #ifndef JSON_LIBRARY call(temp, getIdentifier()); #else call(&temp, getIdentifier()); #endif END_MEM_SCOPE json_string::iterator beginning = buffer.begin(); buffer.erase(beginning, beginning + end); continue; //parse(); //parse the next object too } #ifdef JSON_SAFE else { //verify that what's in there is at least valid so far #ifndef JSON_VALIDATE #error In order to use safe mode and streams, JSON_VALIDATE needs to be defined #endif json_auto s; size_t len; s.set(JSONWorker::RemoveWhiteSpace(json_string(buffer.c_str() + pos), len, false)); if (!JSONValidator::isValidPartialRoot(s.ptr)){ if (err_call) err_call(getIdentifier()); state = false; } } #endif } break; } } #endif