1 /*
2 * Copyright (c) 2009-2021, Google LLC
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of Google LLC nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED. IN NO EVENT SHALL Google LLC BE LIABLE FOR ANY DIRECT,
20 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28 #include "upb/json/encode.h"
29
30 #include <ctype.h>
31 #include <float.h>
32 #include <inttypes.h>
33 #include <math.h>
34 #include <stdarg.h>
35 #include <string.h>
36
37 #include "upb/collections/map.h"
38 #include "upb/lex/round_trip.h"
39 #include "upb/port/vsnprintf_compat.h"
40 #include "upb/reflection/message.h"
41 #include "upb/wire/decode.h"
42
43 // Must be last.
44 #include "upb/port/def.inc"
45
46 typedef struct {
47 char *buf, *ptr, *end;
48 size_t overflow;
49 int indent_depth;
50 int options;
51 const upb_DefPool* ext_pool;
52 jmp_buf err;
53 upb_Status* status;
54 upb_Arena* arena;
55 } jsonenc;
56
57 static void jsonenc_msg(jsonenc* e, const upb_Message* msg,
58 const upb_MessageDef* m);
59 static void jsonenc_scalar(jsonenc* e, upb_MessageValue val,
60 const upb_FieldDef* f);
61 static void jsonenc_msgfield(jsonenc* e, const upb_Message* msg,
62 const upb_MessageDef* m);
63 static void jsonenc_msgfields(jsonenc* e, const upb_Message* msg,
64 const upb_MessageDef* m, bool first);
65 static void jsonenc_value(jsonenc* e, const upb_Message* msg,
66 const upb_MessageDef* m);
67
jsonenc_err(jsonenc * e,const char * msg)68 UPB_NORETURN static void jsonenc_err(jsonenc* e, const char* msg) {
69 upb_Status_SetErrorMessage(e->status, msg);
70 longjmp(e->err, 1);
71 }
72
73 UPB_PRINTF(2, 3)
jsonenc_errf(jsonenc * e,const char * fmt,...)74 UPB_NORETURN static void jsonenc_errf(jsonenc* e, const char* fmt, ...) {
75 va_list argp;
76 va_start(argp, fmt);
77 upb_Status_VSetErrorFormat(e->status, fmt, argp);
78 va_end(argp);
79 longjmp(e->err, 1);
80 }
81
jsonenc_arena(jsonenc * e)82 static upb_Arena* jsonenc_arena(jsonenc* e) {
83 /* Create lazily, since it's only needed for Any */
84 if (!e->arena) {
85 e->arena = upb_Arena_New();
86 }
87 return e->arena;
88 }
89
jsonenc_putbytes(jsonenc * e,const void * data,size_t len)90 static void jsonenc_putbytes(jsonenc* e, const void* data, size_t len) {
91 size_t have = e->end - e->ptr;
92 if (UPB_LIKELY(have >= len)) {
93 memcpy(e->ptr, data, len);
94 e->ptr += len;
95 } else {
96 if (have) {
97 memcpy(e->ptr, data, have);
98 e->ptr += have;
99 }
100 e->overflow += (len - have);
101 }
102 }
103
jsonenc_putstr(jsonenc * e,const char * str)104 static void jsonenc_putstr(jsonenc* e, const char* str) {
105 jsonenc_putbytes(e, str, strlen(str));
106 }
107
108 UPB_PRINTF(2, 3)
jsonenc_printf(jsonenc * e,const char * fmt,...)109 static void jsonenc_printf(jsonenc* e, const char* fmt, ...) {
110 size_t n;
111 size_t have = e->end - e->ptr;
112 va_list args;
113
114 va_start(args, fmt);
115 n = _upb_vsnprintf(e->ptr, have, fmt, args);
116 va_end(args);
117
118 if (UPB_LIKELY(have > n)) {
119 e->ptr += n;
120 } else {
121 e->ptr = UPB_PTRADD(e->ptr, have);
122 e->overflow += (n - have);
123 }
124 }
125
jsonenc_nanos(jsonenc * e,int32_t nanos)126 static void jsonenc_nanos(jsonenc* e, int32_t nanos) {
127 int digits = 9;
128
129 if (nanos == 0) return;
130 if (nanos < 0 || nanos >= 1000000000) {
131 jsonenc_err(e, "error formatting timestamp as JSON: invalid nanos");
132 }
133
134 while (nanos % 1000 == 0) {
135 nanos /= 1000;
136 digits -= 3;
137 }
138
139 jsonenc_printf(e, ".%.*" PRId32, digits, nanos);
140 }
141
jsonenc_timestamp(jsonenc * e,const upb_Message * msg,const upb_MessageDef * m)142 static void jsonenc_timestamp(jsonenc* e, const upb_Message* msg,
143 const upb_MessageDef* m) {
144 const upb_FieldDef* seconds_f = upb_MessageDef_FindFieldByNumber(m, 1);
145 const upb_FieldDef* nanos_f = upb_MessageDef_FindFieldByNumber(m, 2);
146 int64_t seconds = upb_Message_GetFieldByDef(msg, seconds_f).int64_val;
147 int32_t nanos = upb_Message_GetFieldByDef(msg, nanos_f).int32_val;
148 int L, N, I, J, K, hour, min, sec;
149
150 if (seconds < -62135596800) {
151 jsonenc_err(e,
152 "error formatting timestamp as JSON: minimum acceptable value "
153 "is 0001-01-01T00:00:00Z");
154 } else if (seconds > 253402300799) {
155 jsonenc_err(e,
156 "error formatting timestamp as JSON: maximum acceptable value "
157 "is 9999-12-31T23:59:59Z");
158 }
159
160 /* Julian Day -> Y/M/D, Algorithm from:
161 * Fliegel, H. F., and Van Flandern, T. C., "A Machine Algorithm for
162 * Processing Calendar Dates," Communications of the Association of
163 * Computing Machines, vol. 11 (1968), p. 657. */
164 seconds += 62135596800; // Ensure seconds is positive.
165 L = (int)(seconds / 86400) - 719162 + 68569 + 2440588;
166 N = 4 * L / 146097;
167 L = L - (146097 * N + 3) / 4;
168 I = 4000 * (L + 1) / 1461001;
169 L = L - 1461 * I / 4 + 31;
170 J = 80 * L / 2447;
171 K = L - 2447 * J / 80;
172 L = J / 11;
173 J = J + 2 - 12 * L;
174 I = 100 * (N - 49) + I + L;
175
176 sec = seconds % 60;
177 min = (seconds / 60) % 60;
178 hour = (seconds / 3600) % 24;
179
180 jsonenc_printf(e, "\"%04d-%02d-%02dT%02d:%02d:%02d", I, J, K, hour, min, sec);
181 jsonenc_nanos(e, nanos);
182 jsonenc_putstr(e, "Z\"");
183 }
184
jsonenc_duration(jsonenc * e,const upb_Message * msg,const upb_MessageDef * m)185 static void jsonenc_duration(jsonenc* e, const upb_Message* msg,
186 const upb_MessageDef* m) {
187 const upb_FieldDef* seconds_f = upb_MessageDef_FindFieldByNumber(m, 1);
188 const upb_FieldDef* nanos_f = upb_MessageDef_FindFieldByNumber(m, 2);
189 int64_t seconds = upb_Message_GetFieldByDef(msg, seconds_f).int64_val;
190 int32_t nanos = upb_Message_GetFieldByDef(msg, nanos_f).int32_val;
191 bool negative = false;
192
193 if (seconds > 315576000000 || seconds < -315576000000 ||
194 (seconds != 0 && nanos != 0 && (seconds < 0) != (nanos < 0))) {
195 jsonenc_err(e, "bad duration");
196 }
197
198 if (seconds < 0) {
199 negative = true;
200 seconds = -seconds;
201 }
202 if (nanos < 0) {
203 negative = true;
204 nanos = -nanos;
205 }
206
207 jsonenc_putstr(e, "\"");
208 if (negative) {
209 jsonenc_putstr(e, "-");
210 }
211 jsonenc_printf(e, "%" PRId64, seconds);
212 jsonenc_nanos(e, nanos);
213 jsonenc_putstr(e, "s\"");
214 }
215
jsonenc_enum(int32_t val,const upb_FieldDef * f,jsonenc * e)216 static void jsonenc_enum(int32_t val, const upb_FieldDef* f, jsonenc* e) {
217 const upb_EnumDef* e_def = upb_FieldDef_EnumSubDef(f);
218
219 if (strcmp(upb_EnumDef_FullName(e_def), "google.protobuf.NullValue") == 0) {
220 jsonenc_putstr(e, "null");
221 } else {
222 const upb_EnumValueDef* ev =
223 (e->options & upb_JsonEncode_FormatEnumsAsIntegers)
224 ? NULL
225 : upb_EnumDef_FindValueByNumber(e_def, val);
226
227 if (ev) {
228 jsonenc_printf(e, "\"%s\"", upb_EnumValueDef_Name(ev));
229 } else {
230 jsonenc_printf(e, "%" PRId32, val);
231 }
232 }
233 }
234
jsonenc_bytes(jsonenc * e,upb_StringView str)235 static void jsonenc_bytes(jsonenc* e, upb_StringView str) {
236 /* This is the regular base64, not the "web-safe" version. */
237 static const char base64[] =
238 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
239 const unsigned char* ptr = (unsigned char*)str.data;
240 const unsigned char* end = UPB_PTRADD(ptr, str.size);
241 char buf[4];
242
243 jsonenc_putstr(e, "\"");
244
245 while (end - ptr >= 3) {
246 buf[0] = base64[ptr[0] >> 2];
247 buf[1] = base64[((ptr[0] & 0x3) << 4) | (ptr[1] >> 4)];
248 buf[2] = base64[((ptr[1] & 0xf) << 2) | (ptr[2] >> 6)];
249 buf[3] = base64[ptr[2] & 0x3f];
250 jsonenc_putbytes(e, buf, 4);
251 ptr += 3;
252 }
253
254 switch (end - ptr) {
255 case 2:
256 buf[0] = base64[ptr[0] >> 2];
257 buf[1] = base64[((ptr[0] & 0x3) << 4) | (ptr[1] >> 4)];
258 buf[2] = base64[(ptr[1] & 0xf) << 2];
259 buf[3] = '=';
260 jsonenc_putbytes(e, buf, 4);
261 break;
262 case 1:
263 buf[0] = base64[ptr[0] >> 2];
264 buf[1] = base64[((ptr[0] & 0x3) << 4)];
265 buf[2] = '=';
266 buf[3] = '=';
267 jsonenc_putbytes(e, buf, 4);
268 break;
269 }
270
271 jsonenc_putstr(e, "\"");
272 }
273
jsonenc_stringbody(jsonenc * e,upb_StringView str)274 static void jsonenc_stringbody(jsonenc* e, upb_StringView str) {
275 const char* ptr = str.data;
276 const char* end = UPB_PTRADD(ptr, str.size);
277
278 while (ptr < end) {
279 switch (*ptr) {
280 case '\n':
281 jsonenc_putstr(e, "\\n");
282 break;
283 case '\r':
284 jsonenc_putstr(e, "\\r");
285 break;
286 case '\t':
287 jsonenc_putstr(e, "\\t");
288 break;
289 case '\"':
290 jsonenc_putstr(e, "\\\"");
291 break;
292 case '\f':
293 jsonenc_putstr(e, "\\f");
294 break;
295 case '\b':
296 jsonenc_putstr(e, "\\b");
297 break;
298 case '\\':
299 jsonenc_putstr(e, "\\\\");
300 break;
301 default:
302 if ((uint8_t)*ptr < 0x20) {
303 jsonenc_printf(e, "\\u%04x", (int)(uint8_t)*ptr);
304 } else {
305 /* This could be a non-ASCII byte. We rely on the string being valid
306 * UTF-8. */
307 jsonenc_putbytes(e, ptr, 1);
308 }
309 break;
310 }
311 ptr++;
312 }
313 }
314
jsonenc_string(jsonenc * e,upb_StringView str)315 static void jsonenc_string(jsonenc* e, upb_StringView str) {
316 jsonenc_putstr(e, "\"");
317 jsonenc_stringbody(e, str);
318 jsonenc_putstr(e, "\"");
319 }
320
upb_JsonEncode_HandleSpecialDoubles(jsonenc * e,double val)321 static bool upb_JsonEncode_HandleSpecialDoubles(jsonenc* e, double val) {
322 if (val == INFINITY) {
323 jsonenc_putstr(e, "\"Infinity\"");
324 } else if (val == -INFINITY) {
325 jsonenc_putstr(e, "\"-Infinity\"");
326 } else if (val != val) {
327 jsonenc_putstr(e, "\"NaN\"");
328 } else {
329 return false;
330 }
331 return true;
332 }
333
upb_JsonEncode_Double(jsonenc * e,double val)334 static void upb_JsonEncode_Double(jsonenc* e, double val) {
335 if (upb_JsonEncode_HandleSpecialDoubles(e, val)) return;
336 char buf[32];
337 _upb_EncodeRoundTripDouble(val, buf, sizeof(buf));
338 jsonenc_putstr(e, buf);
339 }
340
upb_JsonEncode_Float(jsonenc * e,float val)341 static void upb_JsonEncode_Float(jsonenc* e, float val) {
342 if (upb_JsonEncode_HandleSpecialDoubles(e, val)) return;
343 char buf[32];
344 _upb_EncodeRoundTripFloat(val, buf, sizeof(buf));
345 jsonenc_putstr(e, buf);
346 }
347
jsonenc_wrapper(jsonenc * e,const upb_Message * msg,const upb_MessageDef * m)348 static void jsonenc_wrapper(jsonenc* e, const upb_Message* msg,
349 const upb_MessageDef* m) {
350 const upb_FieldDef* val_f = upb_MessageDef_FindFieldByNumber(m, 1);
351 upb_MessageValue val = upb_Message_GetFieldByDef(msg, val_f);
352 jsonenc_scalar(e, val, val_f);
353 }
354
jsonenc_getanymsg(jsonenc * e,upb_StringView type_url)355 static const upb_MessageDef* jsonenc_getanymsg(jsonenc* e,
356 upb_StringView type_url) {
357 /* Find last '/', if any. */
358 const char* end = type_url.data + type_url.size;
359 const char* ptr = end;
360 const upb_MessageDef* ret;
361
362 if (!e->ext_pool) {
363 jsonenc_err(e, "Tried to encode Any, but no symtab was provided");
364 }
365
366 if (type_url.size == 0) goto badurl;
367
368 while (true) {
369 if (--ptr == type_url.data) {
370 /* Type URL must contain at least one '/', with host before. */
371 goto badurl;
372 }
373 if (*ptr == '/') {
374 ptr++;
375 break;
376 }
377 }
378
379 ret = upb_DefPool_FindMessageByNameWithSize(e->ext_pool, ptr, end - ptr);
380
381 if (!ret) {
382 jsonenc_errf(e, "Couldn't find Any type: %.*s", (int)(end - ptr), ptr);
383 }
384
385 return ret;
386
387 badurl:
388 jsonenc_errf(e, "Bad type URL: " UPB_STRINGVIEW_FORMAT,
389 UPB_STRINGVIEW_ARGS(type_url));
390 }
391
jsonenc_any(jsonenc * e,const upb_Message * msg,const upb_MessageDef * m)392 static void jsonenc_any(jsonenc* e, const upb_Message* msg,
393 const upb_MessageDef* m) {
394 const upb_FieldDef* type_url_f = upb_MessageDef_FindFieldByNumber(m, 1);
395 const upb_FieldDef* value_f = upb_MessageDef_FindFieldByNumber(m, 2);
396 upb_StringView type_url = upb_Message_GetFieldByDef(msg, type_url_f).str_val;
397 upb_StringView value = upb_Message_GetFieldByDef(msg, value_f).str_val;
398 const upb_MessageDef* any_m = jsonenc_getanymsg(e, type_url);
399 const upb_MiniTable* any_layout = upb_MessageDef_MiniTable(any_m);
400 upb_Arena* arena = jsonenc_arena(e);
401 upb_Message* any = upb_Message_New(any_layout, arena);
402
403 if (upb_Decode(value.data, value.size, any, any_layout, NULL, 0, arena) !=
404 kUpb_DecodeStatus_Ok) {
405 jsonenc_err(e, "Error decoding message in Any");
406 }
407
408 jsonenc_putstr(e, "{\"@type\":");
409 jsonenc_string(e, type_url);
410
411 if (upb_MessageDef_WellKnownType(any_m) == kUpb_WellKnown_Unspecified) {
412 /* Regular messages: {"@type": "...","foo": 1, "bar": 2} */
413 jsonenc_msgfields(e, any, any_m, false);
414 } else {
415 /* Well-known type: {"@type": "...","value": <well-known encoding>} */
416 jsonenc_putstr(e, ",\"value\":");
417 jsonenc_msgfield(e, any, any_m);
418 }
419
420 jsonenc_putstr(e, "}");
421 }
422
jsonenc_putsep(jsonenc * e,const char * str,bool * first)423 static void jsonenc_putsep(jsonenc* e, const char* str, bool* first) {
424 if (*first) {
425 *first = false;
426 } else {
427 jsonenc_putstr(e, str);
428 }
429 }
430
jsonenc_fieldpath(jsonenc * e,upb_StringView path)431 static void jsonenc_fieldpath(jsonenc* e, upb_StringView path) {
432 const char* ptr = path.data;
433 const char* end = ptr + path.size;
434
435 while (ptr < end) {
436 char ch = *ptr;
437
438 if (ch >= 'A' && ch <= 'Z') {
439 jsonenc_err(e, "Field mask element may not have upper-case letter.");
440 } else if (ch == '_') {
441 if (ptr == end - 1 || *(ptr + 1) < 'a' || *(ptr + 1) > 'z') {
442 jsonenc_err(e, "Underscore must be followed by a lowercase letter.");
443 }
444 ch = *++ptr - 32;
445 }
446
447 jsonenc_putbytes(e, &ch, 1);
448 ptr++;
449 }
450 }
451
jsonenc_fieldmask(jsonenc * e,const upb_Message * msg,const upb_MessageDef * m)452 static void jsonenc_fieldmask(jsonenc* e, const upb_Message* msg,
453 const upb_MessageDef* m) {
454 const upb_FieldDef* paths_f = upb_MessageDef_FindFieldByNumber(m, 1);
455 const upb_Array* paths = upb_Message_GetFieldByDef(msg, paths_f).array_val;
456 bool first = true;
457 size_t i, n = 0;
458
459 if (paths) n = upb_Array_Size(paths);
460
461 jsonenc_putstr(e, "\"");
462
463 for (i = 0; i < n; i++) {
464 jsonenc_putsep(e, ",", &first);
465 jsonenc_fieldpath(e, upb_Array_Get(paths, i).str_val);
466 }
467
468 jsonenc_putstr(e, "\"");
469 }
470
jsonenc_struct(jsonenc * e,const upb_Message * msg,const upb_MessageDef * m)471 static void jsonenc_struct(jsonenc* e, const upb_Message* msg,
472 const upb_MessageDef* m) {
473 jsonenc_putstr(e, "{");
474
475 const upb_FieldDef* fields_f = upb_MessageDef_FindFieldByNumber(m, 1);
476 const upb_Map* fields = upb_Message_GetFieldByDef(msg, fields_f).map_val;
477
478 if (fields) {
479 const upb_MessageDef* entry_m = upb_FieldDef_MessageSubDef(fields_f);
480 const upb_FieldDef* value_f = upb_MessageDef_FindFieldByNumber(entry_m, 2);
481
482 size_t iter = kUpb_Map_Begin;
483 bool first = true;
484
485 upb_MessageValue key, val;
486 while (upb_Map_Next(fields, &key, &val, &iter)) {
487 jsonenc_putsep(e, ",", &first);
488 jsonenc_string(e, key.str_val);
489 jsonenc_putstr(e, ":");
490 jsonenc_value(e, val.msg_val, upb_FieldDef_MessageSubDef(value_f));
491 }
492 }
493
494 jsonenc_putstr(e, "}");
495 }
496
jsonenc_listvalue(jsonenc * e,const upb_Message * msg,const upb_MessageDef * m)497 static void jsonenc_listvalue(jsonenc* e, const upb_Message* msg,
498 const upb_MessageDef* m) {
499 const upb_FieldDef* values_f = upb_MessageDef_FindFieldByNumber(m, 1);
500 const upb_MessageDef* values_m = upb_FieldDef_MessageSubDef(values_f);
501 const upb_Array* values = upb_Message_GetFieldByDef(msg, values_f).array_val;
502 size_t i;
503 bool first = true;
504
505 jsonenc_putstr(e, "[");
506
507 if (values) {
508 const size_t size = upb_Array_Size(values);
509 for (i = 0; i < size; i++) {
510 upb_MessageValue elem = upb_Array_Get(values, i);
511
512 jsonenc_putsep(e, ",", &first);
513 jsonenc_value(e, elem.msg_val, values_m);
514 }
515 }
516
517 jsonenc_putstr(e, "]");
518 }
519
jsonenc_value(jsonenc * e,const upb_Message * msg,const upb_MessageDef * m)520 static void jsonenc_value(jsonenc* e, const upb_Message* msg,
521 const upb_MessageDef* m) {
522 /* TODO(haberman): do we want a reflection method to get oneof case? */
523 size_t iter = kUpb_Message_Begin;
524 const upb_FieldDef* f;
525 upb_MessageValue val;
526
527 if (!upb_Message_Next(msg, m, NULL, &f, &val, &iter)) {
528 jsonenc_err(e, "No value set in Value proto");
529 }
530
531 switch (upb_FieldDef_Number(f)) {
532 case 1:
533 jsonenc_putstr(e, "null");
534 break;
535 case 2:
536 if (upb_JsonEncode_HandleSpecialDoubles(e, val.double_val)) {
537 jsonenc_err(
538 e,
539 "google.protobuf.Value cannot encode double values for "
540 "infinity or nan, because they would be parsed as a string");
541 }
542 upb_JsonEncode_Double(e, val.double_val);
543 break;
544 case 3:
545 jsonenc_string(e, val.str_val);
546 break;
547 case 4:
548 jsonenc_putstr(e, val.bool_val ? "true" : "false");
549 break;
550 case 5:
551 jsonenc_struct(e, val.msg_val, upb_FieldDef_MessageSubDef(f));
552 break;
553 case 6:
554 jsonenc_listvalue(e, val.msg_val, upb_FieldDef_MessageSubDef(f));
555 break;
556 }
557 }
558
jsonenc_msgfield(jsonenc * e,const upb_Message * msg,const upb_MessageDef * m)559 static void jsonenc_msgfield(jsonenc* e, const upb_Message* msg,
560 const upb_MessageDef* m) {
561 switch (upb_MessageDef_WellKnownType(m)) {
562 case kUpb_WellKnown_Unspecified:
563 jsonenc_msg(e, msg, m);
564 break;
565 case kUpb_WellKnown_Any:
566 jsonenc_any(e, msg, m);
567 break;
568 case kUpb_WellKnown_FieldMask:
569 jsonenc_fieldmask(e, msg, m);
570 break;
571 case kUpb_WellKnown_Duration:
572 jsonenc_duration(e, msg, m);
573 break;
574 case kUpb_WellKnown_Timestamp:
575 jsonenc_timestamp(e, msg, m);
576 break;
577 case kUpb_WellKnown_DoubleValue:
578 case kUpb_WellKnown_FloatValue:
579 case kUpb_WellKnown_Int64Value:
580 case kUpb_WellKnown_UInt64Value:
581 case kUpb_WellKnown_Int32Value:
582 case kUpb_WellKnown_UInt32Value:
583 case kUpb_WellKnown_StringValue:
584 case kUpb_WellKnown_BytesValue:
585 case kUpb_WellKnown_BoolValue:
586 jsonenc_wrapper(e, msg, m);
587 break;
588 case kUpb_WellKnown_Value:
589 jsonenc_value(e, msg, m);
590 break;
591 case kUpb_WellKnown_ListValue:
592 jsonenc_listvalue(e, msg, m);
593 break;
594 case kUpb_WellKnown_Struct:
595 jsonenc_struct(e, msg, m);
596 break;
597 }
598 }
599
jsonenc_scalar(jsonenc * e,upb_MessageValue val,const upb_FieldDef * f)600 static void jsonenc_scalar(jsonenc* e, upb_MessageValue val,
601 const upb_FieldDef* f) {
602 switch (upb_FieldDef_CType(f)) {
603 case kUpb_CType_Bool:
604 jsonenc_putstr(e, val.bool_val ? "true" : "false");
605 break;
606 case kUpb_CType_Float:
607 upb_JsonEncode_Float(e, val.float_val);
608 break;
609 case kUpb_CType_Double:
610 upb_JsonEncode_Double(e, val.double_val);
611 break;
612 case kUpb_CType_Int32:
613 jsonenc_printf(e, "%" PRId32, val.int32_val);
614 break;
615 case kUpb_CType_UInt32:
616 jsonenc_printf(e, "%" PRIu32, val.uint32_val);
617 break;
618 case kUpb_CType_Int64:
619 jsonenc_printf(e, "\"%" PRId64 "\"", val.int64_val);
620 break;
621 case kUpb_CType_UInt64:
622 jsonenc_printf(e, "\"%" PRIu64 "\"", val.uint64_val);
623 break;
624 case kUpb_CType_String:
625 jsonenc_string(e, val.str_val);
626 break;
627 case kUpb_CType_Bytes:
628 jsonenc_bytes(e, val.str_val);
629 break;
630 case kUpb_CType_Enum:
631 jsonenc_enum(val.int32_val, f, e);
632 break;
633 case kUpb_CType_Message:
634 jsonenc_msgfield(e, val.msg_val, upb_FieldDef_MessageSubDef(f));
635 break;
636 }
637 }
638
jsonenc_mapkey(jsonenc * e,upb_MessageValue val,const upb_FieldDef * f)639 static void jsonenc_mapkey(jsonenc* e, upb_MessageValue val,
640 const upb_FieldDef* f) {
641 jsonenc_putstr(e, "\"");
642
643 switch (upb_FieldDef_CType(f)) {
644 case kUpb_CType_Bool:
645 jsonenc_putstr(e, val.bool_val ? "true" : "false");
646 break;
647 case kUpb_CType_Int32:
648 jsonenc_printf(e, "%" PRId32, val.int32_val);
649 break;
650 case kUpb_CType_UInt32:
651 jsonenc_printf(e, "%" PRIu32, val.uint32_val);
652 break;
653 case kUpb_CType_Int64:
654 jsonenc_printf(e, "%" PRId64, val.int64_val);
655 break;
656 case kUpb_CType_UInt64:
657 jsonenc_printf(e, "%" PRIu64, val.uint64_val);
658 break;
659 case kUpb_CType_String:
660 jsonenc_stringbody(e, val.str_val);
661 break;
662 default:
663 UPB_UNREACHABLE();
664 }
665
666 jsonenc_putstr(e, "\":");
667 }
668
jsonenc_array(jsonenc * e,const upb_Array * arr,const upb_FieldDef * f)669 static void jsonenc_array(jsonenc* e, const upb_Array* arr,
670 const upb_FieldDef* f) {
671 size_t i;
672 size_t size = arr ? upb_Array_Size(arr) : 0;
673 bool first = true;
674
675 jsonenc_putstr(e, "[");
676
677 for (i = 0; i < size; i++) {
678 jsonenc_putsep(e, ",", &first);
679 jsonenc_scalar(e, upb_Array_Get(arr, i), f);
680 }
681
682 jsonenc_putstr(e, "]");
683 }
684
jsonenc_map(jsonenc * e,const upb_Map * map,const upb_FieldDef * f)685 static void jsonenc_map(jsonenc* e, const upb_Map* map, const upb_FieldDef* f) {
686 jsonenc_putstr(e, "{");
687
688 const upb_MessageDef* entry = upb_FieldDef_MessageSubDef(f);
689 const upb_FieldDef* key_f = upb_MessageDef_FindFieldByNumber(entry, 1);
690 const upb_FieldDef* val_f = upb_MessageDef_FindFieldByNumber(entry, 2);
691
692 if (map) {
693 size_t iter = kUpb_Map_Begin;
694 bool first = true;
695
696 upb_MessageValue key, val;
697 while (upb_Map_Next(map, &key, &val, &iter)) {
698 jsonenc_putsep(e, ",", &first);
699 jsonenc_mapkey(e, key, key_f);
700 jsonenc_scalar(e, val, val_f);
701 }
702 }
703
704 jsonenc_putstr(e, "}");
705 }
706
jsonenc_fieldval(jsonenc * e,const upb_FieldDef * f,upb_MessageValue val,bool * first)707 static void jsonenc_fieldval(jsonenc* e, const upb_FieldDef* f,
708 upb_MessageValue val, bool* first) {
709 const char* name;
710
711 jsonenc_putsep(e, ",", first);
712
713 if (upb_FieldDef_IsExtension(f)) {
714 // TODO: For MessageSet, I would have expected this to print the message
715 // name here, but Python doesn't appear to do this. We should do more
716 // research here about what various implementations do.
717 jsonenc_printf(e, "\"[%s]\":", upb_FieldDef_FullName(f));
718 } else {
719 if (e->options & upb_JsonEncode_UseProtoNames) {
720 name = upb_FieldDef_Name(f);
721 } else {
722 name = upb_FieldDef_JsonName(f);
723 }
724 jsonenc_printf(e, "\"%s\":", name);
725 }
726
727 if (upb_FieldDef_IsMap(f)) {
728 jsonenc_map(e, val.map_val, f);
729 } else if (upb_FieldDef_IsRepeated(f)) {
730 jsonenc_array(e, val.array_val, f);
731 } else {
732 jsonenc_scalar(e, val, f);
733 }
734 }
735
jsonenc_msgfields(jsonenc * e,const upb_Message * msg,const upb_MessageDef * m,bool first)736 static void jsonenc_msgfields(jsonenc* e, const upb_Message* msg,
737 const upb_MessageDef* m, bool first) {
738 upb_MessageValue val;
739 const upb_FieldDef* f;
740
741 if (e->options & upb_JsonEncode_EmitDefaults) {
742 /* Iterate over all fields. */
743 int i = 0;
744 int n = upb_MessageDef_FieldCount(m);
745 for (i = 0; i < n; i++) {
746 f = upb_MessageDef_Field(m, i);
747 if (!upb_FieldDef_HasPresence(f) || upb_Message_HasFieldByDef(msg, f)) {
748 jsonenc_fieldval(e, f, upb_Message_GetFieldByDef(msg, f), &first);
749 }
750 }
751 } else {
752 /* Iterate over non-empty fields. */
753 size_t iter = kUpb_Message_Begin;
754 while (upb_Message_Next(msg, m, e->ext_pool, &f, &val, &iter)) {
755 jsonenc_fieldval(e, f, val, &first);
756 }
757 }
758 }
759
jsonenc_msg(jsonenc * e,const upb_Message * msg,const upb_MessageDef * m)760 static void jsonenc_msg(jsonenc* e, const upb_Message* msg,
761 const upb_MessageDef* m) {
762 jsonenc_putstr(e, "{");
763 jsonenc_msgfields(e, msg, m, true);
764 jsonenc_putstr(e, "}");
765 }
766
jsonenc_nullz(jsonenc * e,size_t size)767 static size_t jsonenc_nullz(jsonenc* e, size_t size) {
768 size_t ret = e->ptr - e->buf + e->overflow;
769
770 if (size > 0) {
771 if (e->ptr == e->end) e->ptr--;
772 *e->ptr = '\0';
773 }
774
775 return ret;
776 }
777
upb_JsonEncoder_Encode(jsonenc * const e,const upb_Message * const msg,const upb_MessageDef * const m,const size_t size)778 static size_t upb_JsonEncoder_Encode(jsonenc* const e,
779 const upb_Message* const msg,
780 const upb_MessageDef* const m,
781 const size_t size) {
782 if (UPB_SETJMP(e->err) != 0) return -1;
783
784 jsonenc_msgfield(e, msg, m);
785 if (e->arena) upb_Arena_Free(e->arena);
786 return jsonenc_nullz(e, size);
787 }
788
upb_JsonEncode(const upb_Message * msg,const upb_MessageDef * m,const upb_DefPool * ext_pool,int options,char * buf,size_t size,upb_Status * status)789 size_t upb_JsonEncode(const upb_Message* msg, const upb_MessageDef* m,
790 const upb_DefPool* ext_pool, int options, char* buf,
791 size_t size, upb_Status* status) {
792 jsonenc e;
793
794 e.buf = buf;
795 e.ptr = buf;
796 e.end = UPB_PTRADD(buf, size);
797 e.overflow = 0;
798 e.options = options;
799 e.ext_pool = ext_pool;
800 e.status = status;
801 e.arena = NULL;
802
803 return upb_JsonEncoder_Encode(&e, msg, m, size);
804 }
805