mirror of
https://github.com/json-c/json-c.git
synced 2026-04-05 05:19:07 +08:00
Fix incremental parsing of invalid numbers with exponents, such as "0e+-" and "12.3E12E12", while still allowing "0e+" in non-strict mode.
Deprecate the json_parse_double() function from json_util.h
This commit is contained in:
@@ -97,6 +97,8 @@ static const char *json_tokener_errors[] = {
|
||||
*/
|
||||
static json_bool json_tokener_validate_utf8(const char c, unsigned int *nBytes);
|
||||
|
||||
static int json_tokener_parse_double(const char *buf, int len, double *retval);
|
||||
|
||||
const char *json_tokener_error_desc(enum json_tokener_error jerr)
|
||||
{
|
||||
int jerr_int = (int)jerr;
|
||||
@@ -837,6 +839,25 @@ struct json_object *json_tokener_parse_ex(struct json_tokener *tok, const char *
|
||||
int case_len = 0;
|
||||
int is_exponent = 0;
|
||||
int negativesign_next_possible_location = 1;
|
||||
if (printbuf_length(tok->pb) > 0)
|
||||
{
|
||||
/* We don't save all state from the previous incremental parse
|
||||
so we need to re-generate it based on the saved string so far.
|
||||
*/
|
||||
char *e_loc = strchr(tok->pb->buf, 'e');
|
||||
if (!e_loc)
|
||||
e_loc = strchr(tok->pb->buf, 'E');
|
||||
if (e_loc)
|
||||
{
|
||||
char *last_saved_char =
|
||||
&tok->pb->buf[printbuf_length(tok->pb) - 1];
|
||||
is_exponent = 1;
|
||||
/* If the "e" isn't at the end, we can't start with a '-' */
|
||||
if (e_loc != last_saved_char)
|
||||
negativesign_next_possible_location = -1;
|
||||
// else leave it set to 1, i.e. start of the new input
|
||||
}
|
||||
}
|
||||
while (c && strchr(json_number_chars, c))
|
||||
{
|
||||
++case_len;
|
||||
@@ -847,8 +868,9 @@ struct json_object *json_tokener_parse_ex(struct json_tokener *tok, const char *
|
||||
* protected from input starting with '.' or
|
||||
* e/E.
|
||||
*/
|
||||
if (c == '.')
|
||||
switch (c)
|
||||
{
|
||||
case '.':
|
||||
if (tok->is_double != 0)
|
||||
{
|
||||
/* '.' can only be found once, and out of the exponent part.
|
||||
@@ -859,9 +881,9 @@ struct json_object *json_tokener_parse_ex(struct json_tokener *tok, const char *
|
||||
goto out;
|
||||
}
|
||||
tok->is_double = 1;
|
||||
}
|
||||
if (c == 'e' || c == 'E')
|
||||
{
|
||||
break;
|
||||
case 'e': /* FALLTHRU */
|
||||
case 'E':
|
||||
if (is_exponent != 0)
|
||||
{
|
||||
/* only one exponent possible */
|
||||
@@ -872,15 +894,19 @@ struct json_object *json_tokener_parse_ex(struct json_tokener *tok, const char *
|
||||
tok->is_double = 1;
|
||||
/* the exponent part can begin with a negative sign */
|
||||
negativesign_next_possible_location = case_len + 1;
|
||||
}
|
||||
if (c == '-' && case_len != negativesign_next_possible_location)
|
||||
{
|
||||
/* If the negative sign is not where expected (ie
|
||||
* start of input or start of exponent part), the
|
||||
* input is invalid.
|
||||
*/
|
||||
tok->err = json_tokener_error_parse_number;
|
||||
goto out;
|
||||
break;
|
||||
case '-':
|
||||
if (case_len != negativesign_next_possible_location)
|
||||
{
|
||||
/* If the negative sign is not where expected (ie
|
||||
* start of input or start of exponent part), the
|
||||
* input is invalid.
|
||||
*/
|
||||
tok->err = json_tokener_error_parse_number;
|
||||
goto out;
|
||||
}
|
||||
break;
|
||||
default: break;
|
||||
}
|
||||
|
||||
if (!ADVANCE_CHAR(str, tok) || !PEEK_CHAR(c, tok))
|
||||
@@ -899,6 +925,22 @@ struct json_object *json_tokener_parse_ex(struct json_tokener *tok, const char *
|
||||
tok->st_pos = 0;
|
||||
goto redo_char;
|
||||
}
|
||||
if (tok->is_double && !(tok->flags & JSON_TOKENER_STRICT))
|
||||
{
|
||||
/* Trim some chars off the end, to allow things
|
||||
like "123e+" to parse ok. */
|
||||
while (printbuf_length(tok->pb) > 1)
|
||||
{
|
||||
char last_char = tok->pb->buf[printbuf_length(tok->pb) - 1];
|
||||
if (last_char != 'e' && last_char != 'E' &&
|
||||
last_char != '-' && last_char != '+')
|
||||
{
|
||||
break;
|
||||
}
|
||||
tok->pb->buf[printbuf_length(tok->pb) - 1] = '\0';
|
||||
printbuf_length(tok->pb)--;
|
||||
}
|
||||
}
|
||||
}
|
||||
{
|
||||
int64_t num64;
|
||||
@@ -935,7 +977,8 @@ struct json_object *json_tokener_parse_ex(struct json_tokener *tok, const char *
|
||||
}
|
||||
}
|
||||
else if (tok->is_double &&
|
||||
json_parse_double(tok->pb->buf, &numd) == 0)
|
||||
json_tokener_parse_double(
|
||||
tok->pb->buf, printbuf_length(tok->pb), &numd) == 0)
|
||||
{
|
||||
current = json_object_new_double_s(numd, tok->pb->buf);
|
||||
if (current == NULL)
|
||||
@@ -1204,3 +1247,12 @@ size_t json_tokener_get_parse_end(struct json_tokener *tok)
|
||||
assert(tok->char_offset >= 0); /* Drop this line when char_offset becomes a size_t */
|
||||
return (size_t)tok->char_offset;
|
||||
}
|
||||
|
||||
static int json_tokener_parse_double(const char *buf, int len, double *retval)
|
||||
{
|
||||
char *end;
|
||||
*retval = strtod(buf, &end);
|
||||
if (buf + len == end)
|
||||
return 0; // It worked
|
||||
return 1;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user