diff --git a/upb/json_decode.c b/upb/json_decode.c index 4071fc3d95..556541ccff 100644 --- a/upb/json_decode.c +++ b/upb/json_decode.c @@ -631,7 +631,8 @@ static const char* jsondec_buftouint64(jsondec* d, const char* ptr, } static const char* jsondec_buftoint64(jsondec* d, const char* ptr, - const char* end, int64_t* val) { + const char* end, int64_t* val, + bool* is_neg) { bool neg = false; uint64_t u64; @@ -646,6 +647,9 @@ static const char* jsondec_buftoint64(jsondec* d, const char* ptr, } *val = neg ? -u64 : u64; + if (is_neg) { + *is_neg = neg; + } return ptr; } @@ -661,7 +665,7 @@ static uint64_t jsondec_strtouint64(jsondec* d, upb_StringView str) { static int64_t jsondec_strtoint64(jsondec* d, upb_StringView str) { const char* end = str.data + str.size; int64_t ret; - if (jsondec_buftoint64(d, str.data, end, &ret) != end) { + if (jsondec_buftoint64(d, str.data, end, &ret, NULL) != end) { jsondec_err(d, "Non-number characters in quoted integer"); } return ret; @@ -1130,9 +1134,10 @@ static void jsondec_duration(jsondec* d, upb_Message* msg, const char* ptr = str.data; const char* end = ptr + str.size; const int64_t max = (uint64_t)3652500 * 86400; + bool neg = false; /* "3.000000001s", "3s", etc. */ - ptr = jsondec_buftoint64(d, ptr, end, &seconds.int64_val); + ptr = jsondec_buftoint64(d, ptr, end, &seconds.int64_val, &neg); nanos.int32_val = jsondec_nanos(d, &ptr, end); if (end - ptr != 1 || *ptr != 's') { @@ -1143,7 +1148,7 @@ static void jsondec_duration(jsondec* d, upb_Message* msg, jsondec_err(d, "Duration out of range"); } - if (seconds.int64_val < 0) { + if (neg) { nanos.int32_val = -nanos.int32_val; } diff --git a/upb/json_encode.c b/upb/json_encode.c index 7836b47b1b..468b7f897c 100644 --- a/upb/json_encode.c +++ b/upb/json_encode.c @@ -188,17 +188,27 @@ static void jsonenc_duration(jsonenc* e, const upb_Message* msg, const upb_FieldDef* nanos_f = upb_MessageDef_FindFieldByNumber(m, 2); int64_t seconds = upb_Message_Get(msg, seconds_f).int64_val; int32_t nanos = upb_Message_Get(msg, nanos_f).int32_val; + bool negative = false; if (seconds > 315576000000 || seconds < -315576000000 || - (seconds < 0) != (nanos < 0)) { + (seconds != 0 && nanos != 0 && (seconds < 0) != (nanos < 0))) { jsonenc_err(e, "bad duration"); } + if (seconds < 0) { + negative = true; + seconds = -seconds; + } if (nanos < 0) { + negative = true; nanos = -nanos; } - jsonenc_printf(e, "\"%" PRId64, seconds); + jsonenc_putstr(e, "\""); + if (negative) { + jsonenc_putstr(e, "-"); + } + jsonenc_printf(e, "%" PRId64, seconds); jsonenc_nanos(e, nanos); jsonenc_putstr(e, "s\""); }