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