@@ -624,8 +624,15 @@ struct json_object* json_tokener_parse_ex(struct json_tokener *tok, | |||||
} | } | ||||
break; | break; | ||||
case json_tokener_state_array_after_sep: | |||||
case json_tokener_state_array: | case json_tokener_state_array: | ||||
if(c == ']') { | 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; | saved_state = json_tokener_state_finish; | ||||
state = json_tokener_state_eatws; | state = json_tokener_state_eatws; | ||||
} else { | } else { | ||||
@@ -651,7 +658,7 @@ struct json_object* json_tokener_parse_ex(struct json_tokener *tok, | |||||
saved_state = json_tokener_state_finish; | saved_state = json_tokener_state_finish; | ||||
state = json_tokener_state_eatws; | state = json_tokener_state_eatws; | ||||
} else if(c == ',') { | } else if(c == ',') { | ||||
saved_state = json_tokener_state_array; | |||||
saved_state = json_tokener_state_array_after_sep; | |||||
state = json_tokener_state_eatws; | state = json_tokener_state_eatws; | ||||
} else { | } else { | ||||
tok->err = json_tokener_error_parse_array; | tok->err = json_tokener_error_parse_array; | ||||
@@ -660,7 +667,14 @@ struct json_object* json_tokener_parse_ex(struct json_tokener *tok, | |||||
break; | break; | ||||
case json_tokener_state_object_field_start: | case json_tokener_state_object_field_start: | ||||
case json_tokener_state_object_field_start_after_sep: | |||||
if(c == '}') { | 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; | saved_state = json_tokener_state_finish; | ||||
state = json_tokener_state_eatws; | state = json_tokener_state_eatws; | ||||
} else if (c == '"' || c == '\'') { | } 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; | saved_state = json_tokener_state_finish; | ||||
state = json_tokener_state_eatws; | state = json_tokener_state_eatws; | ||||
} else if(c == ',') { | } 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; | state = json_tokener_state_eatws; | ||||
} else { | } else { | ||||
tok->err = json_tokener_error_parse_object_value_sep; | 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); | json_tokener_errors[tok->err], tok->char_offset); | ||||
return NULL; | 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_field_end, | ||||
json_tokener_state_object_value, | json_tokener_state_object_value, | ||||
json_tokener_state_object_value_add, | 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 | struct json_tokener_srec | ||||
@@ -80,8 +82,21 @@ struct json_tokener | |||||
unsigned int ucs_char; | unsigned int ucs_char; | ||||
char quote_char; | char quote_char; | ||||
struct json_tokener_srec *stack; | 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(), | * Given an error previously returned by json_tokener_get_error(), | ||||
* return a human readable description of the 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(const char *str); | ||||
extern struct json_object* json_tokener_parse_verbose(const char *str, enum json_tokener_error *error); | 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 | * 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; | * 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, -1, json_tokener_success, 0 }, | ||||
{ "[1,2,,3,]", -1, 5, json_tokener_error_parse_unexpected, 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 }, | { NULL, -1, -1, json_tokener_success, 0 }, | ||||
}; | }; | ||||
@@ -215,6 +218,12 @@ static void test_incremental_parse() | |||||
struct incremental_step *step = &incremental_steps[ii]; | struct incremental_step *step = &incremental_steps[ii]; | ||||
int length = step->length; | int length = step->length; | ||||
int expected_char_offset = step->char_offset; | 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) | if (length == -1) | ||||
length = strlen(step->string_to_parse); | length = strlen(step->string_to_parse); | ||||
if (expected_char_offset == -1) | if (expected_char_offset == -1) | ||||
@@ -264,7 +273,7 @@ static void test_incremental_parse() | |||||
if (new_obj) | if (new_obj) | ||||
json_object_put(new_obj); | json_object_put(new_obj); | ||||
if (step->reset_tokener) | |||||
if (step->reset_tokener & 1) | |||||
json_tokener_reset(tok); | json_tokener_reset(tok); | ||||
if (this_step_ok) | 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] , 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,] , 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 | 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 | |||||
================================== | ================================== |