Beispiel #1
0
static int parse_parse_buffer(JSON_parser jc)
{
int ok;
    if (jc->callback) {
        JSON_value value, *arg = NULL;
        
        if (jc->type != JSON_T_NONE) {
            assert(
                jc->type == JSON_T_NULL ||
                jc->type == JSON_T_FALSE ||
                jc->type == JSON_T_TRUE ||
                jc->type == JSON_T_FLOAT ||
                jc->type == JSON_T_INTEGER ||
                jc->type == JSON_T_STRING);
        
            switch(jc->type) {
                case JSON_T_FLOAT:
                    arg = &value;
                    if (jc->handle_floats_manually) {
                        value.vu.str.value = jc->parse_buffer;
                        value.vu.str.length = jc->parse_buffer_count;
                    } else { 
                        sscanf(jc->parse_buffer, DoubleScanFormat, &value.vu.float_value);
                    }
                    break;
                case JSON_T_INTEGER: {
                    double tmp;
                    arg = &value;
                    ok = sscanf(jc->parse_buffer, "%lf", &tmp);
	            if(tmp > MAX_INT || tmp < - MAX_INT) {
                       jc->type = JSON_T_FLOAT;
	               value.vu.float_value = tmp;
	            } else
	               value.vu.integer_value = tmp;
                    break;
                }
                case JSON_T_STRING:
                    arg = &value;
                    value.vu.str.value = jc->parse_buffer;
                    value.vu.str.length = jc->parse_buffer_count;
                    break;
            }
            
            if (!(*jc->callback)(jc->ctx, jc->type, arg)) {
                return false;
            }
        }
    }
    
    parse_buffer_clear(jc);
    
    return true;
}
Beispiel #2
0
static int parse_parse_buffer(JSON_parser jc)
{
    if (jc->callback) {
        JSON_value value, *arg = NULL;
        
        if (jc->type != JSON_T_NONE) {
            assert(
                jc->type == JSON_T_NULL ||
                jc->type == JSON_T_FALSE ||
                jc->type == JSON_T_TRUE ||
                jc->type == JSON_T_FLOAT ||
                jc->type == JSON_T_INTEGER ||
                jc->type == JSON_T_STRING);
        
            switch(jc->type) {
                case JSON_T_FLOAT:
                    arg = &value;
                    if (jc->handle_floats_manually) {
                        value.vu.str.value = jc->parse_buffer;
                        value.vu.str.length = jc->parse_buffer_count;
                    } else { 
                        sscanf(jc->parse_buffer, "%Lf", &value.vu.float_value);
                    }
                    break;
                case JSON_T_INTEGER:
                    arg = &value;
                    sscanf(jc->parse_buffer, JSON_PARSER_INTEGER_SSCANF_TOKEN, &value.vu.integer_value);
                    break;
                case JSON_T_STRING:
                    arg = &value;
                    value.vu.str.value = jc->parse_buffer;
                    value.vu.str.length = jc->parse_buffer_count;
                    break;
            }
            
            if (!(*jc->callback)(jc->ctx, jc->type, arg)) {
                return false;
            }
        }
    }
    
    parse_buffer_clear(jc);
    
    return true;
}
Beispiel #3
0
static int parse_parse_buffer( us_json_parser_t jc )
{
    if ( jc->callback )
    {
        us_json_value_t value, *arg = NULL;
        if ( jc->type != US_JSON_T_NONE )
        {
            us_json_assert_is_non_container_type( jc );
            switch ( jc->type )
            {
            case US_JSON_T_FLOAT:
                arg = &value;
                if ( jc->handle_floats_manually )
                {
                    value.vu.str.value = jc->parse_buffer;
                    value.vu.str.length = jc->parse_buffer_count;
                }
                else
                {
                    /* not checking with end pointer b/c there may be trailing ws */
                    value.vu.float_value = strtod( jc->parse_buffer, NULL );
                }
                break;
            case US_JSON_T_INTEGER:
                arg = &value;
                sscanf( jc->parse_buffer, US_JSON_PARSER_INTEGER_SSCANF_TOKEN, &value.vu.integer_value );
                break;
            case US_JSON_T_STRING:
                arg = &value;
                value.vu.str.value = jc->parse_buffer;
                value.vu.str.length = jc->parse_buffer_count;
                break;
            }
            if ( !( *jc->callback )( jc->ctx, jc->type, arg ) )
            {
                return false;
            }
        }
    }
    parse_buffer_clear( jc );
    return true;
}
Beispiel #4
0
int
JSON_parser_char(JSON_parser jc, int next_char)
{
/*
    After calling new_JSON_parser, call this function for each character (or
    partial character) in your JSON text. It can accept UTF-8, UTF-16, or
    UTF-32. It returns true if things are looking ok so far. If it rejects the
    text, it returns false.
*/
    int next_class, next_state;
    
/*
    Determine the character's class.
*/
    if (next_char < 0) {
        return false;
    }
    if (next_char >= 128) {
        next_class = C_ETC;
    } else {
        next_class = ascii_class[next_char];
        if (next_class <= __) {
            return false;
        }
    }
    
    if (jc->escaped) {
        jc->escaped = 0;
        /* remove the backslash */
        parse_buffer_pop_back_char(jc);
        switch(next_char) {
        case 'b':
            parse_buffer_push_back_char(jc, '\b');
            break;
        case 'f':
            parse_buffer_push_back_char(jc, '\f');
            break;
        case 'n':
            parse_buffer_push_back_char(jc, '\n');
            break;
        case 'r':
            parse_buffer_push_back_char(jc, '\r');
            break;
        case 't':
            parse_buffer_push_back_char(jc, '\t');
            break;
        case '"':
            parse_buffer_push_back_char(jc, '"');
            break;
        case '\\':
            parse_buffer_push_back_char(jc, '\\');
            break;
        case '/':
            parse_buffer_push_back_char(jc, '/');
            break;
        case 'u':
            parse_buffer_push_back_char(jc, '\\');
            parse_buffer_push_back_char(jc, 'u');
            break;
        default:
            return false;
        }
    } else if (!jc->comment) { 
        if (jc->type != JSON_T_NONE || !(next_class == C_SPACE || next_class == C_WHITE) /* non-white-space */) {
            parse_buffer_push_back_char(jc, (char)next_char);
        }
    }
    
    
    
/*
    Get the next state from the state transition table.
*/
    next_state = state_transition_table[jc->state][next_class];
    if (next_state >= 0) {
/*
    Change the state.
*/
        jc->state = next_state;
    } else {
/*
    Or perform one of the actions.
*/
        switch (next_state) {
/* Unicode character */        
        case UC:
            if(!decode_unicode_char(jc)) {
/* we disabled Unicode, so this always returns false */
                return false;
            }
            break;
/* escaped char */
        case EX:
            jc->escaped = 1;
            jc->state = ES;
            break;
/* integer detected by minus */
        case MX:
            jc->type = JSON_T_INTEGER;
            jc->state = MI;
            break;  
/* integer detected by zero */            
        case ZX:
            jc->type = JSON_T_INTEGER;
            jc->state = ZE;
            break;  
/* integer detected by 1-9 */            
        case IX:
            jc->type = JSON_T_INTEGER;
            jc->state = IT;
            break;  
            
/* floating point number detected by exponent*/
        case DE:
            assert(jc->type != JSON_T_FALSE);
            assert(jc->type != JSON_T_TRUE);
            assert(jc->type != JSON_T_NULL);
            assert(jc->type != JSON_T_STRING);
            jc->type = JSON_T_FLOAT;
            jc->state = E1;
            break;   
        
/* floating point number detected by fraction */
        case DF:
            assert(jc->type != JSON_T_FALSE);
            assert(jc->type != JSON_T_TRUE);
            assert(jc->type != JSON_T_NULL);
            assert(jc->type != JSON_T_STRING);
            jc->type = JSON_T_FLOAT;
            jc->state = FX;
            break;   
/* string begin " */
        case SB:
            parse_buffer_clear(jc);
            assert(jc->type == JSON_T_NONE);
            jc->type = JSON_T_STRING;
            jc->state = ST;
            break;        
        
/* n */
        case NU:
            assert(jc->type == JSON_T_NONE);
            jc->type = JSON_T_NULL;
            jc->state = N1;
            break;        
/* f */
        case FA:
            assert(jc->type == JSON_T_NONE);
            jc->type = JSON_T_FALSE;
            jc->state = F1;
            break;        
/* t */
        case TR:
            assert(jc->type == JSON_T_NONE);
            jc->type = JSON_T_TRUE;
            jc->state = T1;
            break;        
        
/* closing comment */
        case CE:
            jc->comment = 0;
            assert(jc->parse_buffer_count == 0);
            assert(jc->type == JSON_T_NONE);
            jc->state = jc->before_comment_state;
            break;        
        
/* opening comment  */
        case CB:
            if (!jc->allow_comments) {
                return false;
            }
            parse_buffer_pop_back_char(jc);
            if (!parse_parse_buffer(jc)) {
                return false;
            }
            assert(jc->parse_buffer_count == 0);
            assert(jc->type != JSON_T_STRING);
            switch (jc->stack[jc->top]) {
            case MODE_ARRAY:
            case MODE_OBJECT:   
                switch(jc->state) {
                case VA:
                case AR:
                    jc->before_comment_state = jc->state;
                    break;
                default:
                    jc->before_comment_state = OK;
                    break;
                }
                break;
            default:
                jc->before_comment_state = jc->state;
                break;
            }
            jc->type = JSON_T_NONE;
            jc->state = C1;
            jc->comment = 1;
            break;
/* empty } */
        case -9:        
            parse_buffer_clear(jc);
            if (jc->callback && !(*jc->callback)(jc->ctx, JSON_T_OBJECT_END, NULL)) {
                return false;
            }
            if (!pop(jc, MODE_KEY)) {
                return false;
            }
            jc->state = OK;
            break;

/* } */ case -8:
            parse_buffer_pop_back_char(jc);
            if (!parse_parse_buffer(jc)) {
                return false;
            }
            if (jc->callback && !(*jc->callback)(jc->ctx, JSON_T_OBJECT_END, NULL)) {
                return false;
            }
            if (!pop(jc, MODE_OBJECT)) {
                return false;
            }
            jc->type = JSON_T_NONE;
            jc->state = OK;
            break;

/* ] */ case -7:
            parse_buffer_pop_back_char(jc);
            if (!parse_parse_buffer(jc)) {
                return false;
            }
            if (jc->callback && !(*jc->callback)(jc->ctx, JSON_T_ARRAY_END, NULL)) {
                return false;
            }
            if (!pop(jc, MODE_ARRAY)) {
                return false;
            }
            
            jc->type = JSON_T_NONE;
            jc->state = OK;
            break;

/* { */ case -6:
            parse_buffer_pop_back_char(jc);
            if (jc->callback && !(*jc->callback)(jc->ctx, JSON_T_OBJECT_BEGIN, NULL)) {
                return false;
            }
            if (!push(jc, MODE_KEY)) {
                return false;
            }
            assert(jc->type == JSON_T_NONE);
            jc->state = OB;
            break;

/* [ */ case -5:
            parse_buffer_pop_back_char(jc);
            if (jc->callback && !(*jc->callback)(jc->ctx, JSON_T_ARRAY_BEGIN, NULL)) {
                return false;
            }
            if (!push(jc, MODE_ARRAY)) {
                return false;
            }
            assert(jc->type == JSON_T_NONE);
            jc->state = AR;
            break;

/* string end " */ case -4:
            parse_buffer_pop_back_char(jc);
            switch (jc->stack[jc->top]) {
            case MODE_KEY:
                assert(jc->type == JSON_T_STRING);
                jc->type = JSON_T_NONE;
                jc->state = CO;
                
                if (jc->callback) {
                    JSON_value value;
                    value.vu.str.value = jc->parse_buffer;
                    value.vu.str.length = jc->parse_buffer_count;
                    if (!(*jc->callback)(jc->ctx, JSON_T_KEY, &value)) {
                        return false;
                    }
                }
                parse_buffer_clear(jc);
                break;
            case MODE_ARRAY:
            case MODE_OBJECT:
                assert(jc->type == JSON_T_STRING);
                if (!parse_parse_buffer(jc)) {
                    return false;
                }
                jc->type = JSON_T_NONE;
                jc->state = OK;
                break;
            default:
                return false;
            }
            break;

/* , */ case -3:
            parse_buffer_pop_back_char(jc);
            if (!parse_parse_buffer(jc)) {
                return false;
            }
            switch (jc->stack[jc->top]) {
            case MODE_OBJECT:
/*
    A comma causes a flip from object mode to key mode.
*/
                if (!pop(jc, MODE_OBJECT) || !push(jc, MODE_KEY)) {
                    return false;
                }
                assert(jc->type != JSON_T_STRING);
                jc->type = JSON_T_NONE;
                jc->state = KE;
                break;
            case MODE_ARRAY:
                assert(jc->type != JSON_T_STRING);
                jc->type = JSON_T_NONE;
                jc->state = VA;
                break;
            default:
                return false;
            }
            break;

/* : */ case -2:
/*
    A colon causes a flip from key mode to object mode.
*/
            parse_buffer_pop_back_char(jc);
            if (!pop(jc, MODE_KEY) || !push(jc, MODE_OBJECT)) {
                return false;
            }
            assert(jc->type == JSON_T_NONE);
            jc->state = VA;
            break;
/*
    Bad action.
*/
        default:
            return false;
        }
    }
    return true;
}
Beispiel #5
0
JSON_parser
new_JSON_parser(JSON_config* config)
{
/*
    new_JSON_parser starts the checking process by constructing a JSON_parser
    object. It takes a depth parameter that restricts the level of maximum
    nesting.

    To continue the process, call JSON_parser_char for each character in the
    JSON text, and then call JSON_parser_done to obtain the final result.
    These functions are fully reentrant.
*/

    int depth = 0;
    JSON_config default_config;
    
    JSON_parser jc = malloc(sizeof(struct JSON_parser_struct));
    
    memset(jc, 0, sizeof(*jc));
    
    
    /* initialize configuration */
    init_JSON_config(&default_config);
    
    /* set to default configuration if none was provided */
    if (config == NULL) {
        config = &default_config;
    }

    depth = config->depth;
    
    /* We need to be able to push at least one object */
    if (depth == 0) {
        depth = 1;
    }
    
    jc->state = GO;
    jc->top = -1;
    
    /* Do we want non-bound stack? */
    if (depth > 0) {
        jc->stack_capacity = depth;
        jc->depth = depth;
        if (depth <= COUNTOF(jc->static_stack)) {
            jc->stack = &jc->static_stack[0];
        } else {
            jc->stack = (signed char*)malloc(jc->stack_capacity * sizeof(jc->static_stack[0]));
        }
    } else {
        jc->stack_capacity = COUNTOF(jc->static_stack);
        jc->depth = -1;
        jc->stack = &jc->static_stack[0];
    }
    
    /* set parser to start */
    push(jc, MODE_DONE);
    
    /* set up the parse buffer */
    jc->parse_buffer = &jc->static_parse_buffer[0];
    jc->parse_buffer_capacity = COUNTOF(jc->static_parse_buffer);
    parse_buffer_clear(jc);
    
    /* set up callback, comment & float handling */
    jc->callback = config->callback;
    jc->ctx = config->callback_ctx;
    jc->allow_comments = config->allow_comments != 0;
    jc->handle_floats_manually = config->handle_floats_manually != 0;
    return jc;
}
Beispiel #6
0
int us_json_parser_char( us_json_parser_t jc, int next_char )
{
    /*
      After calling new_json_parser, call this function for each character (or
      partial character) in your JSON text. It can accept UTF-8, UTF-16, or
      UTF-32. It returns true if things are looking ok so far. If it rejects the
      text, it returns false.
    */
    int next_class, next_state;
    /*
      Determine the character's class.
    */
    if ( next_char < 0 )
    {
        return false;
    }
    if ( next_char >= 128 )
    {
        next_class = C_ETC;
    }
    else
    {
        next_class = ascii_class[next_char];
        if ( next_class <= __ )
        {
            return false;
        }
    }
    us_json_add_char_to_parse_buffer( jc, next_char, next_class );
    /*
      Get the next state from the state transition table.
    */
    next_state = state_transition_table[jc->state][next_class];
    if ( next_state >= 0 )
    {
        /*
          Change the state.
        */
        jc->state = next_state;
    }
    else
    {
        /*
          Or perform one of the actions.
        */
        switch ( next_state )
        {
        /* Unicode character */
        case UC:
            if ( !us_utf_decode_unicode_char( jc ) )
            {
                return false;
            }
            /* check if we need to read a second UTF-16 char */
            if ( jc->utf16_high_surrogate )
            {
                jc->state = D1;
            }
            else
            {
                jc->state = ST;
            }
            break;
        /* escaped char */
        case EX:
            jc->escaped = 1;
            jc->state = ES;
            break;
        /* integer detected by minus */
        case MX:
            jc->type = US_JSON_T_INTEGER;
            jc->state = MI;
            break;
        /* integer detected by zero */
        case ZX:
            jc->type = US_JSON_T_INTEGER;
            jc->state = ZE;
            break;
        /* integer detected by 1-9 */
        case IX:
            jc->type = US_JSON_T_INTEGER;
            jc->state = IT;
            break;
        /* floating point number detected by exponent*/
        case DE:
            us_json_assert_type_isnt_string_null_or_bool( jc );
            jc->type = US_JSON_T_FLOAT;
            jc->state = E1;
            break;
        /* floating point number detected by fraction */
        case DF:
            us_json_assert_type_isnt_string_null_or_bool( jc );
            if ( !jc->handle_floats_manually )
            {
                /*
                  Some versions of strtod (which underlies sscanf) don't support converting
                  C-locale formated floating point values.
                */
                assert( jc->parse_buffer[jc->parse_buffer_count - 1] == '.' );
                jc->parse_buffer[jc->parse_buffer_count - 1] = jc->decimal_point;
            }
            jc->type = US_JSON_T_FLOAT;
            jc->state = FX;
            break;
        /* string begin " */
        case SB:
            parse_buffer_clear( jc );
            assert( jc->type == US_JSON_T_NONE );
            jc->type = US_JSON_T_STRING;
            jc->state = ST;
            break;
        /* n */
        case NU:
            assert( jc->type == US_JSON_T_NONE );
            jc->type = US_JSON_T_NULL;
            jc->state = N1;
            break;
        /* f */
        case FA:
            assert( jc->type == US_JSON_T_NONE );
            jc->type = US_JSON_T_FALSE;
            jc->state = F1;
            break;
        /* t */
        case TR:
            assert( jc->type == US_JSON_T_NONE );
            jc->type = US_JSON_T_TRUE;
            jc->state = T1;
            break;
        /* closing comment */
        case CE:
            jc->comment = 0;
            assert( jc->parse_buffer_count == 0 );
            assert( jc->type == US_JSON_T_NONE );
            jc->state = jc->before_comment_state;
            break;
        /* opening comment  */
        case CB:
            if ( !jc->allow_comments )
            {
                return false;
            }
            parse_buffer_pop_back_char( jc );
            if ( !parse_parse_buffer( jc ) )
            {
                return false;
            }
            assert( jc->parse_buffer_count == 0 );
            assert( jc->type != US_JSON_T_STRING );
            switch ( jc->stack[jc->top] )
            {
            case MODE_ARRAY:
            case MODE_OBJECT:
                switch ( jc->state )
                {
                case VA:
                case AR:
                    jc->before_comment_state = jc->state;
                    break;
                default:
                    jc->before_comment_state = OK;
                    break;
                }
                break;
            default:
                jc->before_comment_state = jc->state;
                break;
            }
            jc->type = US_JSON_T_NONE;
            jc->state = C1;
            jc->comment = 1;
            break;
        /* empty closing curly brace */
        case -9:
            parse_buffer_clear( jc );
            if ( jc->callback && !( *jc->callback )( jc->ctx, US_JSON_T_OBJECT_END, NULL ) )
            {
                return false;
            }
            if ( !pop( jc, MODE_KEY ) )
            {
                return false;
            }
            jc->state = OK;
            break;
        /* closing curly brace */
        case -8:
            parse_buffer_pop_back_char( jc );
            if ( !parse_parse_buffer( jc ) )
            {
                return false;
            }
            if ( jc->callback && !( *jc->callback )( jc->ctx, US_JSON_T_OBJECT_END, NULL ) )
            {
                return false;
            }
            if ( !pop( jc, MODE_OBJECT ) )
            {
                return false;
            }
            jc->type = US_JSON_T_NONE;
            jc->state = OK;
            break;
        /* closing square bracket */
        case -7:
            parse_buffer_pop_back_char( jc );
            if ( !parse_parse_buffer( jc ) )
            {
                return false;
            }
            if ( jc->callback && !( *jc->callback )( jc->ctx, US_JSON_T_ARRAY_END, NULL ) )
            {
                return false;
            }
            if ( !pop( jc, MODE_ARRAY ) )
            {
                return false;
            }
            jc->type = US_JSON_T_NONE;
            jc->state = OK;
            break;
        /* open curly brace */
        case -6:
            parse_buffer_pop_back_char( jc );
            if ( jc->callback && !( *jc->callback )( jc->ctx, US_JSON_T_OBJECT_BEGIN, NULL ) )
            {
                return false;
            }
            if ( !push( jc, MODE_KEY ) )
            {
                return false;
            }
            assert( jc->type == US_JSON_T_NONE );
            jc->state = OB;
            break;
        /* open square bracket */
        case -5:
            parse_buffer_pop_back_char( jc );
            if ( jc->callback && !( *jc->callback )( jc->ctx, US_JSON_T_ARRAY_BEGIN, NULL ) )
            {
                return false;
            }
            if ( !push( jc, MODE_ARRAY ) )
            {
                return false;
            }
            assert( jc->type == US_JSON_T_NONE );
            jc->state = AR;
            break;
        /* string end " */
        case -4:
            parse_buffer_pop_back_char( jc );
            switch ( jc->stack[jc->top] )
            {
            case MODE_KEY:
                assert( jc->type == US_JSON_T_STRING );
                jc->type = US_JSON_T_NONE;
                jc->state = CO;
                if ( jc->callback )
                {
                    us_json_value_t value;
                    value.vu.str.value = jc->parse_buffer;
                    value.vu.str.length = jc->parse_buffer_count;
                    if ( !( *jc->callback )( jc->ctx, US_JSON_T_KEY, &value ) )
                    {
                        return false;
                    }
                }
                parse_buffer_clear( jc );
                break;
            case MODE_ARRAY:
            case MODE_OBJECT:
                assert( jc->type == US_JSON_T_STRING );
                if ( !parse_parse_buffer( jc ) )
                {
                    return false;
                }
                jc->type = US_JSON_T_NONE;
                jc->state = OK;
                break;
            default:
                return false;
            }
            break;
        /* , */
        case -3:
            parse_buffer_pop_back_char( jc );
            if ( !parse_parse_buffer( jc ) )
            {
                return false;
            }
            switch ( jc->stack[jc->top] )
            {
            case MODE_OBJECT:
                /*
                  A comma causes a flip from object mode to key mode.
                */
                if ( !pop( jc, MODE_OBJECT ) || !push( jc, MODE_KEY ) )
                {
                    return false;
                }
                assert( jc->type != US_JSON_T_STRING );
                jc->type = US_JSON_T_NONE;
                jc->state = KE;
                break;
            case MODE_ARRAY:
                assert( jc->type != US_JSON_T_STRING );
                jc->type = US_JSON_T_NONE;
                jc->state = VA;
                break;
            default:
                return false;
            }
            break;
        /* : */
        case -2:
            /*
              A colon causes a flip from key mode to object mode.
            */
            parse_buffer_pop_back_char( jc );
            if ( !pop( jc, MODE_KEY ) || !push( jc, MODE_OBJECT ) )
            {
                return false;
            }
            assert( jc->type == US_JSON_T_NONE );
            jc->state = VA;
            break;
        /*
          Bad action.
        */
        default:
            return false;
        }
    }
    return true;
}