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