Skip to content

Commit

Permalink
Parse JSON number manually. (#1401)
Browse files Browse the repository at this point in the history
  • Loading branch information
Barenboim authored Oct 24, 2023
1 parent cfee907 commit 2d59873
Showing 1 changed file with 104 additions and 10 deletions.
114 changes: 104 additions & 10 deletions src/util/json_parser.c
Original file line number Diff line number Diff line change
Expand Up @@ -270,30 +270,124 @@ static int __parse_json_string(const char *cursor, const char **end,
return 0;
}

static double __evaluate_json_number(const char *integer,
const char *fraction,
int exp)
{
long long mant = 0;
int figures = 0;
double num;
int sign;

sign = (*integer == '-');
if (sign)
integer++;

if (*integer != '0')
{
figures++;
mant = *integer - '0';
while (isdigit(*++integer))
{
if (figures < 18)
{
figures++;
mant *= 10;
mant += *integer - '0';
}
else
exp++;
}
}
else
{
while (*fraction == '0')
{
exp--;
fraction++;
}
}

while (isdigit(*fraction) && figures < 18)
{
figures++;
mant *= 10;
mant += *fraction - '0';

exp--;
fraction++;
}

num = mant;
if (exp != 0 && figures != 0)
{
if (exp > 0)
num *= pow(10, exp);
else
num /= pow(10, -exp);
}

return sign ? -num : num;
}

static int __parse_json_number(const char *cursor, const char **end,
double *num)
{
const char *p = cursor;
const char *integer = cursor;
const char *fraction = "";
int exp = 0;
int sign;

if (*p == '-')
p++;
if (*cursor == '-')
cursor++;

if (!isdigit(*p))
if (!isdigit(*cursor))
return -2;

if (*p == '0' && (isdigit(p[1]) || p[1] == 'X' || p[1] == 'x'))
if (*cursor == '0' && isdigit(cursor[1]))
return -2;

while (isdigit(*++p))
while (isdigit(*++cursor))
;

if (*p == '.' && !isdigit(*(p + 1)))
return -2;
if (*cursor == '.')
{
fraction = ++cursor;
if (!isdigit(*cursor))
return -2;

while (isdigit(*++cursor))
;
}

if (*cursor == 'E' || *cursor == 'e')
{
sign = (*++cursor == '-');
if (sign || *cursor == '+')
cursor++;

if (!isdigit(*cursor))
return -2;

*num = strtod(cursor, (char **)end);
if (*end == cursor)
exp = *cursor - '0';
while (isdigit(*++cursor))
{
if (exp < 2000000)
{
exp *= 10;
exp += *cursor - '0';
}
}

if (sign)
exp = -exp;
}

if (cursor - integer > 1000000)
return -2;

*num = __evaluate_json_number(integer, fraction, exp);
*end = cursor;
return 0;
}

Expand Down

0 comments on commit 2d59873

Please sign in to comment.