| @@ -624,8 +624,15 @@ struct json_object* json_tokener_parse_ex(struct json_tokener *tok, | |||
| } | |||
| break; | |||
| case json_tokener_state_array_after_sep: | |||
| case json_tokener_state_array: | |||
| if(c == ']') { | |||
| if (state == json_tokener_state_array_after_sep && | |||
| (tok->flags & JSON_TOKENER_STRICT)) | |||
| { | |||
| tok->err = json_tokener_error_parse_unexpected; | |||
| goto out; | |||
| } | |||
| saved_state = json_tokener_state_finish; | |||
| state = json_tokener_state_eatws; | |||
| } else { | |||
| @@ -651,7 +658,7 @@ struct json_object* json_tokener_parse_ex(struct json_tokener *tok, | |||
| saved_state = json_tokener_state_finish; | |||
| state = json_tokener_state_eatws; | |||
| } else if(c == ',') { | |||
| saved_state = json_tokener_state_array; | |||
| saved_state = json_tokener_state_array_after_sep; | |||
| state = json_tokener_state_eatws; | |||
| } else { | |||
| tok->err = json_tokener_error_parse_array; | |||
| @@ -660,7 +667,14 @@ struct json_object* json_tokener_parse_ex(struct json_tokener *tok, | |||
| break; | |||
| case json_tokener_state_object_field_start: | |||
| case json_tokener_state_object_field_start_after_sep: | |||
| if(c == '}') { | |||
| if (state == json_tokener_state_object_field_start_after_sep && | |||
| (tok->flags & JSON_TOKENER_STRICT)) | |||
| { | |||
| tok->err = json_tokener_error_parse_unexpected; | |||
| goto out; | |||
| } | |||
| saved_state = json_tokener_state_finish; | |||
| state = json_tokener_state_eatws; | |||
| } else if (c == '"' || c == '\'') { | |||
| @@ -731,7 +745,7 @@ struct json_object* json_tokener_parse_ex(struct json_tokener *tok, | |||
| saved_state = json_tokener_state_finish; | |||
| state = json_tokener_state_eatws; | |||
| } else if(c == ',') { | |||
| saved_state = json_tokener_state_object_field_start; | |||
| saved_state = json_tokener_state_object_field_start_after_sep; | |||
| state = json_tokener_state_eatws; | |||
| } else { | |||
| tok->err = json_tokener_error_parse_object_value_sep; | |||
| @@ -771,3 +785,8 @@ struct json_object* json_tokener_parse_ex(struct json_tokener *tok, | |||
| json_tokener_errors[tok->err], tok->char_offset); | |||
| return NULL; | |||
| } | |||
| void json_tokener_set_flags(struct json_tokener *tok, int flags) | |||
| { | |||
| tok->flags = flags; | |||
| } | |||
| @@ -58,7 +58,9 @@ enum json_tokener_state { | |||
| json_tokener_state_object_field_end, | |||
| json_tokener_state_object_value, | |||
| json_tokener_state_object_value_add, | |||
| json_tokener_state_object_sep | |||
| json_tokener_state_object_sep, | |||
| json_tokener_state_array_after_sep, | |||
| json_tokener_state_object_field_start_after_sep | |||
| }; | |||
| struct json_tokener_srec | |||
| @@ -80,8 +82,21 @@ struct json_tokener | |||
| unsigned int ucs_char; | |||
| char quote_char; | |||
| struct json_tokener_srec *stack; | |||
| int flags; | |||
| }; | |||
| /** | |||
| * Be strict when parsing JSON input. Use caution with | |||
| * this flag as what is considered valid may become more | |||
| * restrictive from one release to the next, causing your | |||
| * code to fail on previously working input. | |||
| * | |||
| * This flag is not set by default. | |||
| * | |||
| * @see json_tokener_set_flags() | |||
| */ | |||
| #define JSON_TOKENER_STRICT 0x01 | |||
| /** | |||
| * Given an error previously returned by json_tokener_get_error(), | |||
| * return a human readable description of the error. | |||
| @@ -116,6 +131,11 @@ extern void json_tokener_reset(struct json_tokener *tok); | |||
| extern struct json_object* json_tokener_parse(const char *str); | |||
| extern struct json_object* json_tokener_parse_verbose(const char *str, enum json_tokener_error *error); | |||
| /** | |||
| * Set flags that control how parsing will be done. | |||
| */ | |||
| extern void json_tokener_set_flags(struct json_tokener *tok, int flags); | |||
| /** | |||
| * Parse a string and return a non-NULL json_object if a valid JSON value | |||
| * is found. The string does not need to be a JSON object or array; | |||
| @@ -183,6 +183,9 @@ struct incremental_step { | |||
| { "[1,2,3,]", -1, -1, json_tokener_success, 0 }, | |||
| { "[1,2,,3,]", -1, 5, json_tokener_error_parse_unexpected, 0 }, | |||
| { "[1,2,3,]", -1, 7, json_tokener_error_parse_unexpected, 3 }, | |||
| { "{\"a\":1,}", -1, 7, json_tokener_error_parse_unexpected, 3 }, | |||
| { NULL, -1, -1, json_tokener_success, 0 }, | |||
| }; | |||
| @@ -215,6 +218,12 @@ static void test_incremental_parse() | |||
| struct incremental_step *step = &incremental_steps[ii]; | |||
| int length = step->length; | |||
| int expected_char_offset = step->char_offset; | |||
| if (step->reset_tokener & 2) | |||
| json_tokener_set_flags(tok, JSON_TOKENER_STRICT); | |||
| else | |||
| json_tokener_set_flags(tok, 0); | |||
| if (length == -1) | |||
| length = strlen(step->string_to_parse); | |||
| if (expected_char_offset == -1) | |||
| @@ -264,7 +273,7 @@ static void test_incremental_parse() | |||
| if (new_obj) | |||
| json_object_put(new_obj); | |||
| if (step->reset_tokener) | |||
| if (step->reset_tokener & 1) | |||
| json_tokener_reset(tok); | |||
| if (this_step_ok) | |||
| @@ -51,5 +51,7 @@ json_tokener_parse_ex(tok, "\t" , 4) ... OK: got object of type [string | |||
| json_tokener_parse_ex(tok, [1,2,3] , 7) ... OK: got object of type [array]: [ 1, 2, 3 ] | |||
| json_tokener_parse_ex(tok, [1,2,3,] , 8) ... OK: got object of type [array]: [ 1, 2, 3 ] | |||
| json_tokener_parse_ex(tok, [1,2,,3,] , 9) ... OK: got correct error: unexpected character | |||
| End Incremental Tests OK=27 ERROR=0 | |||
| json_tokener_parse_ex(tok, [1,2,3,] , 8) ... OK: got correct error: unexpected character | |||
| json_tokener_parse_ex(tok, {"a":1,} , 8) ... OK: got correct error: unexpected character | |||
| End Incremental Tests OK=29 ERROR=0 | |||
| ================================== | |||