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