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; }
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; }
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; }
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; }
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; }
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; }