The R Project SVN R-packages

Rev

Blame | Last modification | View Log | Download | RSS feed

#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<ch>(vt, po)
    template<json_char ch>
    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<json_char> 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