Merge pull request #86 from haberman/json-numbers

Some fixes to make JSON properly recognize numbers in quotes.
pull/13171/head
Joshua Haberman 8 years ago committed by GitHub
commit e38098cbfc
  1. 288
      upb/json/parser.c
  2. 215
      upb/json/parser.rl
  3. 19
      upb/json/printer.c

@ -21,8 +21,9 @@
** - handling of keys/escape-sequences/etc that span input buffers.
*/
#include <assert.h>
#include <errno.h>
#include <float.h>
#include <math.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
@ -608,103 +609,160 @@ static void start_number(upb_json_parser *p, const char *ptr) {
capture_begin(p, ptr);
}
static bool parse_number(upb_json_parser *p);
static bool parse_number(upb_json_parser *p, bool is_quoted);
static bool end_number(upb_json_parser *p, const char *ptr) {
if (!capture_end(p, ptr)) {
return false;
}
return parse_number(p);
return parse_number(p, false);
}
static bool parse_number(upb_json_parser *p) {
size_t len;
const char *buf;
const char *myend;
/* |buf| is NULL-terminated. |buf| itself will never include quotes;
* |is_quoted| tells us whether this text originally appeared inside quotes. */
static bool parse_number_from_buffer(upb_json_parser *p, const char *buf,
bool is_quoted) {
size_t len = strlen(buf);
const char *bufend = buf + len;
char *end;
upb_fieldtype_t type = upb_fielddef_type(p->top->f);
double val;
double dummy;
double inf = 1.0 / 0.0; /* C89 does not have an INFINITY macro. */
/* strtol() and friends unfortunately do not support specifying the length of
* the input string, so we need to force a copy into a NULL-terminated buffer. */
if (!multipart_text(p, "\0", 1, false)) {
errno = 0;
if (len == 0 || buf[0] == ' ') {
return false;
}
buf = accumulate_getptr(p, &len);
myend = buf + len - 1; /* One for NULL. */
/* XXX: We are using strtol to parse integers, but this is wrong as even
* integers can be represented as 1e6 (for example), which strtol can't
* handle correctly.
*
* XXX: Also, we can't handle large integers properly because strto[u]ll
* isn't in C89.
*
* XXX: Also, we don't properly check floats for overflow, since strtof
* isn't in C89. */
switch (upb_fielddef_type(p->top->f)) {
/* For integer types, first try parsing with integer-specific routines.
* If these succeed, they will be more accurate for int64/uint64 than
* strtod().
*/
switch (type) {
case UPB_TYPE_ENUM:
case UPB_TYPE_INT32: {
long val = strtol(p->accumulated, &end, 0);
if (val > INT32_MAX || val < INT32_MIN || errno == ERANGE || end != myend)
goto err;
else
long val = strtol(buf, &end, 0);
if (errno == ERANGE || end != bufend) {
break;
} else if (val > INT32_MAX || val < INT32_MIN) {
return false;
} else {
upb_sink_putint32(&p->top->sink, parser_getsel(p), val);
break;
}
case UPB_TYPE_INT64: {
long long val = strtol(p->accumulated, &end, 0);
if (val > INT64_MAX || val < INT64_MIN || errno == ERANGE || end != myend)
goto err;
else
upb_sink_putint64(&p->top->sink, parser_getsel(p), val);
break;
return true;
}
}
case UPB_TYPE_UINT32: {
unsigned long val = strtoul(p->accumulated, &end, 0);
if (val > UINT32_MAX || errno == ERANGE || end != myend)
goto err;
else
unsigned long val = strtoul(buf, &end, 0);
if (end != bufend) {
break;
} else if (val > UINT32_MAX || errno == ERANGE) {
return false;
} else {
upb_sink_putuint32(&p->top->sink, parser_getsel(p), val);
break;
return true;
}
}
/* XXX: We can't handle [u]int64 properly on 32-bit machines because
* strto[u]ll isn't in C89. */
case UPB_TYPE_INT64: {
long val = strtol(buf, &end, 0);
if (errno == ERANGE || end != bufend) {
break;
} else {
upb_sink_putint64(&p->top->sink, parser_getsel(p), val);
return true;
}
}
case UPB_TYPE_UINT64: {
unsigned long long val = strtoul(p->accumulated, &end, 0);
if (val > UINT64_MAX || errno == ERANGE || end != myend)
goto err;
else
unsigned long val = strtoul(p->accumulated, &end, 0);
if (end != bufend) {
break;
} else if (errno == ERANGE) {
return false;
} else {
upb_sink_putuint64(&p->top->sink, parser_getsel(p), val);
break;
return true;
}
}
case UPB_TYPE_DOUBLE: {
double val = strtod(p->accumulated, &end);
if (errno == ERANGE || end != myend)
goto err;
else
upb_sink_putdouble(&p->top->sink, parser_getsel(p), val);
default:
break;
}
if (type != UPB_TYPE_DOUBLE && type != UPB_TYPE_FLOAT && is_quoted) {
/* Quoted numbers for integer types are not allowed to be in double form. */
return false;
}
if (len == strlen("Infinity") && strcmp(buf, "Infinity") == 0) {
/* C89 does not have an INFINITY macro. */
val = inf;
} else if (len == strlen("-Infinity") && strcmp(buf, "-Infinity") == 0) {
val = -inf;
} else {
val = strtod(buf, &end);
if (errno == ERANGE || end != bufend) {
return false;
}
case UPB_TYPE_FLOAT: {
float val = strtod(p->accumulated, &end);
if (errno == ERANGE || end != myend)
goto err;
else
upb_sink_putfloat(&p->top->sink, parser_getsel(p), val);
break;
}
switch (type) {
#define CASE(capitaltype, smalltype, ctype, min, max) \
case UPB_TYPE_ ## capitaltype: { \
if (modf(val, &dummy) != 0 || val > max || val < min) { \
return false; \
} else { \
upb_sink_put ## smalltype(&p->top->sink, parser_getsel(p), \
(ctype)val); \
return true; \
} \
break; \
}
case UPB_TYPE_ENUM:
CASE(INT32, int32, int32_t, INT32_MIN, INT32_MAX);
CASE(INT64, int64, int64_t, INT64_MIN, INT64_MAX);
CASE(UINT32, uint32, uint32_t, 0, UINT32_MAX);
CASE(UINT64, uint64, uint64_t, 0, UINT64_MAX);
#undef CASE
case UPB_TYPE_DOUBLE:
upb_sink_putdouble(&p->top->sink, parser_getsel(p), val);
return true;
case UPB_TYPE_FLOAT:
if ((val > FLT_MAX || val < -FLT_MAX) && val != inf && val != -inf) {
return false;
} else {
upb_sink_putfloat(&p->top->sink, parser_getsel(p), val);
return true;
}
default:
UPB_ASSERT(false);
return false;
}
}
multipart_end(p);
static bool parse_number(upb_json_parser *p, bool is_quoted) {
size_t len;
const char *buf;
return true;
/* strtol() and friends unfortunately do not support specifying the length of
* the input string, so we need to force a copy into a NULL-terminated buffer. */
if (!multipart_text(p, "\0", 1, false)) {
return false;
}
err:
upb_status_seterrf(&p->status, "error parsing number: %s", buf);
upb_env_reporterror(p->env, &p->status);
multipart_end(p);
return false;
buf = accumulate_getptr(p, &len);
if (parse_number_from_buffer(p, buf, is_quoted)) {
multipart_end(p);
return true;
} else {
upb_status_seterrf(&p->status, "error parsing number: %s", buf);
upb_env_reporterror(p->env, &p->status);
multipart_end(p);
return false;
}
}
static bool parser_putbool(upb_json_parser *p, bool val) {
@ -757,17 +815,16 @@ static bool start_stringval(upb_json_parser *p) {
multipart_startaccum(p);
return true;
}
} else if (upb_fielddef_type(p->top->f) == UPB_TYPE_ENUM) {
/* No need to push a frame -- symbolic enum names in quotes remain in the
* current parser frame.
*
* Enum string values must accumulate so we can look up the value in a table
* once it is complete. */
} else if (upb_fielddef_type(p->top->f) != UPB_TYPE_BOOL &&
upb_fielddef_type(p->top->f) != UPB_TYPE_MESSAGE) {
/* No need to push a frame -- numeric values in quotes remain in the
* current parser frame. These values must accmulate so we can convert
* them all at once at the end. */
multipart_startaccum(p);
return true;
} else {
upb_status_seterrf(&p->status,
"String specified for non-string/non-enum field: %s",
"String specified for bool or submessage field: %s",
upb_fielddef_name(p->top->f));
upb_env_reporterror(p->env, &p->status);
return false;
@ -814,6 +871,15 @@ static bool end_stringval(upb_json_parser *p) {
break;
}
case UPB_TYPE_INT32:
case UPB_TYPE_INT64:
case UPB_TYPE_UINT32:
case UPB_TYPE_UINT64:
case UPB_TYPE_DOUBLE:
case UPB_TYPE_FLOAT:
ok = parse_number(p, true);
break;
default:
UPB_ASSERT(false);
upb_status_seterrmsg(&p->status, "Internal error in JSON decoder");
@ -857,7 +923,7 @@ static bool parse_mapentry_key(upb_json_parser *p) {
case UPB_TYPE_UINT32:
case UPB_TYPE_UINT64:
/* Invoke end_number. The accum buffer has the number's text already. */
if (!parse_number(p)) {
if (!parse_number(p, true)) {
return false;
}
break;
@ -1148,11 +1214,11 @@ static void end_object(upb_json_parser *p) {
* final state once, when the closing '"' is seen. */
#line 1244 "upb/json/parser.rl"
#line 1310 "upb/json/parser.rl"
#line 1156 "upb/json/parser.c"
#line 1222 "upb/json/parser.c"
static const char _json_actions[] = {
0, 1, 0, 1, 2, 1, 3, 1,
5, 1, 6, 1, 7, 1, 8, 1,
@ -1301,7 +1367,7 @@ static const int json_en_value_machine = 27;
static const int json_en_main = 1;
#line 1247 "upb/json/parser.rl"
#line 1313 "upb/json/parser.rl"
size_t parse(void *closure, const void *hd, const char *buf, size_t size,
const upb_bufhandle *handle) {
@ -1323,7 +1389,7 @@ size_t parse(void *closure, const void *hd, const char *buf, size_t size,
capture_resume(parser, buf);
#line 1327 "upb/json/parser.c"
#line 1393 "upb/json/parser.c"
{
int _klen;
unsigned int _trans;
@ -1398,118 +1464,118 @@ _match:
switch ( *_acts++ )
{
case 0:
#line 1159 "upb/json/parser.rl"
#line 1225 "upb/json/parser.rl"
{ p--; {cs = stack[--top]; goto _again;} }
break;
case 1:
#line 1160 "upb/json/parser.rl"
#line 1226 "upb/json/parser.rl"
{ p--; {stack[top++] = cs; cs = 10; goto _again;} }
break;
case 2:
#line 1164 "upb/json/parser.rl"
#line 1230 "upb/json/parser.rl"
{ start_text(parser, p); }
break;
case 3:
#line 1165 "upb/json/parser.rl"
#line 1231 "upb/json/parser.rl"
{ CHECK_RETURN_TOP(end_text(parser, p)); }
break;
case 4:
#line 1171 "upb/json/parser.rl"
#line 1237 "upb/json/parser.rl"
{ start_hex(parser); }
break;
case 5:
#line 1172 "upb/json/parser.rl"
#line 1238 "upb/json/parser.rl"
{ hexdigit(parser, p); }
break;
case 6:
#line 1173 "upb/json/parser.rl"
#line 1239 "upb/json/parser.rl"
{ CHECK_RETURN_TOP(end_hex(parser)); }
break;
case 7:
#line 1179 "upb/json/parser.rl"
#line 1245 "upb/json/parser.rl"
{ CHECK_RETURN_TOP(escape(parser, p)); }
break;
case 8:
#line 1185 "upb/json/parser.rl"
#line 1251 "upb/json/parser.rl"
{ p--; {cs = stack[--top]; goto _again;} }
break;
case 9:
#line 1188 "upb/json/parser.rl"
#line 1254 "upb/json/parser.rl"
{ {stack[top++] = cs; cs = 19; goto _again;} }
break;
case 10:
#line 1190 "upb/json/parser.rl"
#line 1256 "upb/json/parser.rl"
{ p--; {stack[top++] = cs; cs = 27; goto _again;} }
break;
case 11:
#line 1195 "upb/json/parser.rl"
#line 1261 "upb/json/parser.rl"
{ start_member(parser); }
break;
case 12:
#line 1196 "upb/json/parser.rl"
#line 1262 "upb/json/parser.rl"
{ CHECK_RETURN_TOP(end_membername(parser)); }
break;
case 13:
#line 1199 "upb/json/parser.rl"
#line 1265 "upb/json/parser.rl"
{ end_member(parser); }
break;
case 14:
#line 1205 "upb/json/parser.rl"
#line 1271 "upb/json/parser.rl"
{ start_object(parser); }
break;
case 15:
#line 1208 "upb/json/parser.rl"
#line 1274 "upb/json/parser.rl"
{ end_object(parser); }
break;
case 16:
#line 1214 "upb/json/parser.rl"
#line 1280 "upb/json/parser.rl"
{ CHECK_RETURN_TOP(start_array(parser)); }
break;
case 17:
#line 1218 "upb/json/parser.rl"
#line 1284 "upb/json/parser.rl"
{ end_array(parser); }
break;
case 18:
#line 1223 "upb/json/parser.rl"
#line 1289 "upb/json/parser.rl"
{ start_number(parser, p); }
break;
case 19:
#line 1224 "upb/json/parser.rl"
#line 1290 "upb/json/parser.rl"
{ CHECK_RETURN_TOP(end_number(parser, p)); }
break;
case 20:
#line 1226 "upb/json/parser.rl"
#line 1292 "upb/json/parser.rl"
{ CHECK_RETURN_TOP(start_stringval(parser)); }
break;
case 21:
#line 1227 "upb/json/parser.rl"
#line 1293 "upb/json/parser.rl"
{ CHECK_RETURN_TOP(end_stringval(parser)); }
break;
case 22:
#line 1229 "upb/json/parser.rl"
#line 1295 "upb/json/parser.rl"
{ CHECK_RETURN_TOP(parser_putbool(parser, true)); }
break;
case 23:
#line 1231 "upb/json/parser.rl"
#line 1297 "upb/json/parser.rl"
{ CHECK_RETURN_TOP(parser_putbool(parser, false)); }
break;
case 24:
#line 1233 "upb/json/parser.rl"
#line 1299 "upb/json/parser.rl"
{ /* null value */ }
break;
case 25:
#line 1235 "upb/json/parser.rl"
#line 1301 "upb/json/parser.rl"
{ CHECK_RETURN_TOP(start_subobject(parser)); }
break;
case 26:
#line 1236 "upb/json/parser.rl"
#line 1302 "upb/json/parser.rl"
{ end_subobject(parser); }
break;
case 27:
#line 1241 "upb/json/parser.rl"
#line 1307 "upb/json/parser.rl"
{ p--; {cs = stack[--top]; goto _again;} }
break;
#line 1513 "upb/json/parser.c"
#line 1579 "upb/json/parser.c"
}
}
@ -1522,7 +1588,7 @@ _again:
_out: {}
}
#line 1268 "upb/json/parser.rl"
#line 1334 "upb/json/parser.rl"
if (p != pe) {
upb_status_seterrf(&parser->status, "Parse error at '%.*s'\n", pe - p, p);
@ -1563,13 +1629,13 @@ static void json_parser_reset(upb_json_parser *p) {
/* Emit Ragel initialization of the parser. */
#line 1567 "upb/json/parser.c"
#line 1633 "upb/json/parser.c"
{
cs = json_start;
top = 0;
}
#line 1308 "upb/json/parser.rl"
#line 1374 "upb/json/parser.rl"
p->current_state = cs;
p->parser_top = top;
accumulate_clear(p);

@ -20,6 +20,8 @@
*/
#include <errno.h>
#include <float.h>
#include <math.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
@ -605,103 +607,160 @@ static void start_number(upb_json_parser *p, const char *ptr) {
capture_begin(p, ptr);
}
static bool parse_number(upb_json_parser *p);
static bool parse_number(upb_json_parser *p, bool is_quoted);
static bool end_number(upb_json_parser *p, const char *ptr) {
if (!capture_end(p, ptr)) {
return false;
}
return parse_number(p);
return parse_number(p, false);
}
static bool parse_number(upb_json_parser *p) {
size_t len;
const char *buf;
const char *myend;
/* |buf| is NULL-terminated. |buf| itself will never include quotes;
* |is_quoted| tells us whether this text originally appeared inside quotes. */
static bool parse_number_from_buffer(upb_json_parser *p, const char *buf,
bool is_quoted) {
size_t len = strlen(buf);
const char *bufend = buf + len;
char *end;
upb_fieldtype_t type = upb_fielddef_type(p->top->f);
double val;
double dummy;
double inf = 1.0 / 0.0; /* C89 does not have an INFINITY macro. */
/* strtol() and friends unfortunately do not support specifying the length of
* the input string, so we need to force a copy into a NULL-terminated buffer. */
if (!multipart_text(p, "\0", 1, false)) {
errno = 0;
if (len == 0 || buf[0] == ' ') {
return false;
}
buf = accumulate_getptr(p, &len);
myend = buf + len - 1; /* One for NULL. */
/* XXX: We are using strtol to parse integers, but this is wrong as even
* integers can be represented as 1e6 (for example), which strtol can't
* handle correctly.
*
* XXX: Also, we can't handle large integers properly because strto[u]ll
* isn't in C89.
*
* XXX: Also, we don't properly check floats for overflow, since strtof
* isn't in C89. */
switch (upb_fielddef_type(p->top->f)) {
/* For integer types, first try parsing with integer-specific routines.
* If these succeed, they will be more accurate for int64/uint64 than
* strtod().
*/
switch (type) {
case UPB_TYPE_ENUM:
case UPB_TYPE_INT32: {
long val = strtol(p->accumulated, &end, 0);
if (val > INT32_MAX || val < INT32_MIN || errno == ERANGE || end != myend)
goto err;
else
long val = strtol(buf, &end, 0);
if (errno == ERANGE || end != bufend) {
break;
} else if (val > INT32_MAX || val < INT32_MIN) {
return false;
} else {
upb_sink_putint32(&p->top->sink, parser_getsel(p), val);
break;
}
case UPB_TYPE_INT64: {
long long val = strtol(p->accumulated, &end, 0);
if (val > INT64_MAX || val < INT64_MIN || errno == ERANGE || end != myend)
goto err;
else
upb_sink_putint64(&p->top->sink, parser_getsel(p), val);
break;
return true;
}
}
case UPB_TYPE_UINT32: {
unsigned long val = strtoul(p->accumulated, &end, 0);
if (val > UINT32_MAX || errno == ERANGE || end != myend)
goto err;
else
unsigned long val = strtoul(buf, &end, 0);
if (end != bufend) {
break;
} else if (val > UINT32_MAX || errno == ERANGE) {
return false;
} else {
upb_sink_putuint32(&p->top->sink, parser_getsel(p), val);
break;
return true;
}
}
/* XXX: We can't handle [u]int64 properly on 32-bit machines because
* strto[u]ll isn't in C89. */
case UPB_TYPE_INT64: {
long val = strtol(buf, &end, 0);
if (errno == ERANGE || end != bufend) {
break;
} else {
upb_sink_putint64(&p->top->sink, parser_getsel(p), val);
return true;
}
}
case UPB_TYPE_UINT64: {
unsigned long long val = strtoul(p->accumulated, &end, 0);
if (val > UINT64_MAX || errno == ERANGE || end != myend)
goto err;
else
unsigned long val = strtoul(p->accumulated, &end, 0);
if (end != bufend) {
break;
} else if (errno == ERANGE) {
return false;
} else {
upb_sink_putuint64(&p->top->sink, parser_getsel(p), val);
break;
return true;
}
}
case UPB_TYPE_DOUBLE: {
double val = strtod(p->accumulated, &end);
if (errno == ERANGE || end != myend)
goto err;
else
upb_sink_putdouble(&p->top->sink, parser_getsel(p), val);
default:
break;
}
if (type != UPB_TYPE_DOUBLE && type != UPB_TYPE_FLOAT && is_quoted) {
/* Quoted numbers for integer types are not allowed to be in double form. */
return false;
}
if (len == strlen("Infinity") && strcmp(buf, "Infinity") == 0) {
/* C89 does not have an INFINITY macro. */
val = inf;
} else if (len == strlen("-Infinity") && strcmp(buf, "-Infinity") == 0) {
val = -inf;
} else {
val = strtod(buf, &end);
if (errno == ERANGE || end != bufend) {
return false;
}
case UPB_TYPE_FLOAT: {
float val = strtod(p->accumulated, &end);
if (errno == ERANGE || end != myend)
goto err;
else
upb_sink_putfloat(&p->top->sink, parser_getsel(p), val);
break;
}
switch (type) {
#define CASE(capitaltype, smalltype, ctype, min, max) \
case UPB_TYPE_ ## capitaltype: { \
if (modf(val, &dummy) != 0 || val > max || val < min) { \
return false; \
} else { \
upb_sink_put ## smalltype(&p->top->sink, parser_getsel(p), \
(ctype)val); \
return true; \
} \
break; \
}
case UPB_TYPE_ENUM:
CASE(INT32, int32, int32_t, INT32_MIN, INT32_MAX);
CASE(INT64, int64, int64_t, INT64_MIN, INT64_MAX);
CASE(UINT32, uint32, uint32_t, 0, UINT32_MAX);
CASE(UINT64, uint64, uint64_t, 0, UINT64_MAX);
#undef CASE
case UPB_TYPE_DOUBLE:
upb_sink_putdouble(&p->top->sink, parser_getsel(p), val);
return true;
case UPB_TYPE_FLOAT:
if ((val > FLT_MAX || val < -FLT_MAX) && val != inf && val != -inf) {
return false;
} else {
upb_sink_putfloat(&p->top->sink, parser_getsel(p), val);
return true;
}
default:
UPB_ASSERT(false);
return false;
}
}
multipart_end(p);
static bool parse_number(upb_json_parser *p, bool is_quoted) {
size_t len;
const char *buf;
return true;
/* strtol() and friends unfortunately do not support specifying the length of
* the input string, so we need to force a copy into a NULL-terminated buffer. */
if (!multipart_text(p, "\0", 1, false)) {
return false;
}
err:
upb_status_seterrf(&p->status, "error parsing number: %s", buf);
upb_env_reporterror(p->env, &p->status);
multipart_end(p);
return false;
buf = accumulate_getptr(p, &len);
if (parse_number_from_buffer(p, buf, is_quoted)) {
multipart_end(p);
return true;
} else {
upb_status_seterrf(&p->status, "error parsing number: %s", buf);
upb_env_reporterror(p->env, &p->status);
multipart_end(p);
return false;
}
}
static bool parser_putbool(upb_json_parser *p, bool val) {
@ -754,17 +813,16 @@ static bool start_stringval(upb_json_parser *p) {
multipart_startaccum(p);
return true;
}
} else if (upb_fielddef_type(p->top->f) == UPB_TYPE_ENUM) {
/* No need to push a frame -- symbolic enum names in quotes remain in the
* current parser frame.
*
* Enum string values must accumulate so we can look up the value in a table
* once it is complete. */
} else if (upb_fielddef_type(p->top->f) != UPB_TYPE_BOOL &&
upb_fielddef_type(p->top->f) != UPB_TYPE_MESSAGE) {
/* No need to push a frame -- numeric values in quotes remain in the
* current parser frame. These values must accmulate so we can convert
* them all at once at the end. */
multipart_startaccum(p);
return true;
} else {
upb_status_seterrf(&p->status,
"String specified for non-string/non-enum field: %s",
"String specified for bool or submessage field: %s",
upb_fielddef_name(p->top->f));
upb_env_reporterror(p->env, &p->status);
return false;
@ -811,6 +869,15 @@ static bool end_stringval(upb_json_parser *p) {
break;
}
case UPB_TYPE_INT32:
case UPB_TYPE_INT64:
case UPB_TYPE_UINT32:
case UPB_TYPE_UINT64:
case UPB_TYPE_DOUBLE:
case UPB_TYPE_FLOAT:
ok = parse_number(p, true);
break;
default:
UPB_ASSERT(false);
upb_status_seterrmsg(&p->status, "Internal error in JSON decoder");
@ -854,7 +921,7 @@ static bool parse_mapentry_key(upb_json_parser *p) {
case UPB_TYPE_UINT32:
case UPB_TYPE_UINT64:
/* Invoke end_number. The accum buffer has the number's text already. */
if (!parse_number(p)) {
if (!parse_number(p, true)) {
return false;
}
break;

@ -154,10 +154,23 @@ static void putstring(upb_json_printer *p, const char *buf, unsigned int len) {
* Right now we use %.8g and %.17g for float/double, respectively, to match
* proto2::util::JsonFormat's defaults. May want to change this later. */
const char neginf[] = "\"-Infinity\"";
const char inf[] = "\"Infinity\"";
static size_t fmt_double(double val, char* buf, size_t length) {
size_t n = _upb_snprintf(buf, length, "%.17g", val);
CHKLENGTH(n > 0 && n < length);
return n;
if (val == (1.0 / 0.0)) {
CHKLENGTH(length >= strlen(inf));
strcpy(buf, inf);
return strlen(inf);
} else if (val == (-1.0 / 0.0)) {
CHKLENGTH(length >= strlen(neginf));
strcpy(buf, neginf);
return strlen(neginf);
} else {
size_t n = _upb_snprintf(buf, length, "%.17g", val);
CHKLENGTH(n > 0 && n < length);
return n;
}
}
static size_t fmt_float(float val, char* buf, size_t length) {

Loading…
Cancel
Save