blob: 81c0501a4e6ed663428d23692153a76f92bd5ea3 [file] [log] [blame]
Joshua Habermane59d2c82021-04-05 10:47:53 -07001/*
Joshua Haberman823eb092021-04-05 12:26:41 -07002 * Copyright (c) 2009-2021, Google LLC
Joshua Habermane59d2c82021-04-05 10:47:53 -07003 * 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 *
Joshua Haberman1c955f32022-01-12 07:19:28 -080016 * 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
Joshua Habermane59d2c82021-04-05 10:47:53 -070021 * (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 */
Joshua Haberman60d09662020-02-10 09:44:07 -080027
Joshua Haberman6e9db7d2020-02-15 19:31:51 -080028#include "upb/json_encode.h"
Joshua Haberman60d09662020-02-10 09:44:07 -080029
30#include <ctype.h>
31#include <float.h>
32#include <inttypes.h>
Joshua Haberman8f3ee802020-10-28 16:23:20 -070033#include <math.h>
34#include <setjmp.h>
Joshua Haberman60d09662020-02-10 09:44:07 -080035#include <stdarg.h>
36#include <stdio.h>
37#include <string.h>
38
Joshua Haberman6e9db7d2020-02-15 19:31:51 -080039#include "upb/decode.h"
Joshua Habermana60e9a32022-05-13 17:32:17 -070040#include "upb/internal/vsnprintf_compat.h"
Joshua Haberman60d09662020-02-10 09:44:07 -080041#include "upb/reflection.h"
Joshua Habermanbc7b5dc2022-01-17 13:32:37 -080042#include "upb/upb_internal.h"
Joshua Haberman60d09662020-02-10 09:44:07 -080043
Joshua Haberman8f3ee802020-10-28 16:23:20 -070044/* Must be last. */
Joshua Haberman6e9db7d2020-02-15 19:31:51 -080045#include "upb/port_def.inc"
46
Joshua Haberman60d09662020-02-10 09:44:07 -080047typedef struct {
48 char *buf, *ptr, *end;
49 size_t overflow;
50 int indent_depth;
51 int options;
Joshua Haberman1c955f32022-01-12 07:19:28 -080052 const upb_DefPool* ext_pool;
Joshua Haberman6e9db7d2020-02-15 19:31:51 -080053 jmp_buf err;
Joshua Haberman1c955f32022-01-12 07:19:28 -080054 upb_Status* status;
55 upb_Arena* arena;
Joshua Haberman60d09662020-02-10 09:44:07 -080056} jsonenc;
57
Joshua Haberman499c2cc2022-01-12 09:09:59 -080058static void jsonenc_msg(jsonenc* e, const upb_Message* msg,
Joshua Haberman1c955f32022-01-12 07:19:28 -080059 const upb_MessageDef* m);
60static void jsonenc_scalar(jsonenc* e, upb_MessageValue val,
61 const upb_FieldDef* f);
Joshua Haberman499c2cc2022-01-12 09:09:59 -080062static void jsonenc_msgfield(jsonenc* e, const upb_Message* msg,
Joshua Haberman1c955f32022-01-12 07:19:28 -080063 const upb_MessageDef* m);
Joshua Haberman499c2cc2022-01-12 09:09:59 -080064static void jsonenc_msgfields(jsonenc* e, const upb_Message* msg,
Joshua Haberman1c955f32022-01-12 07:19:28 -080065 const upb_MessageDef* m, bool first);
Joshua Haberman499c2cc2022-01-12 09:09:59 -080066static void jsonenc_value(jsonenc* e, const upb_Message* msg,
Joshua Haberman1c955f32022-01-12 07:19:28 -080067 const upb_MessageDef* m);
Joshua Haberman6e9db7d2020-02-15 19:31:51 -080068
Joshua Haberman1c955f32022-01-12 07:19:28 -080069UPB_NORETURN static void jsonenc_err(jsonenc* e, const char* msg) {
70 upb_Status_SetErrorMessage(e->status, msg);
Joshua Haberman6e9db7d2020-02-15 19:31:51 -080071 longjmp(e->err, 1);
72}
Joshua Haberman60d09662020-02-10 09:44:07 -080073
Joshua Habermanc7787cb2021-01-10 09:17:52 -080074UPB_PRINTF(2, 3)
Joshua Haberman1c955f32022-01-12 07:19:28 -080075UPB_NORETURN static void jsonenc_errf(jsonenc* e, const char* fmt, ...) {
Joshua Haberman81c2aa72020-06-11 12:42:17 -070076 va_list argp;
77 va_start(argp, fmt);
Joshua Haberman1c955f32022-01-12 07:19:28 -080078 upb_Status_VSetErrorFormat(e->status, fmt, argp);
Joshua Haberman81c2aa72020-06-11 12:42:17 -070079 va_end(argp);
80 longjmp(e->err, 1);
81}
82
Joshua Haberman1c955f32022-01-12 07:19:28 -080083static upb_Arena* jsonenc_arena(jsonenc* e) {
Joshua Habermana2922612020-02-24 13:57:57 -080084 /* Create lazily, since it's only needed for Any */
85 if (!e->arena) {
Joshua Haberman1c955f32022-01-12 07:19:28 -080086 e->arena = upb_Arena_New();
Joshua Habermana2922612020-02-24 13:57:57 -080087 }
88 return e->arena;
89}
90
Joshua Haberman1c955f32022-01-12 07:19:28 -080091static void jsonenc_putbytes(jsonenc* e, const void* data, size_t len) {
Joshua Haberman60d09662020-02-10 09:44:07 -080092 size_t have = e->end - e->ptr;
93 if (UPB_LIKELY(have >= len)) {
94 memcpy(e->ptr, data, len);
95 e->ptr += len;
96 } else {
Joshua Haberman63ad3db2021-03-09 11:21:03 -080097 if (have) {
98 memcpy(e->ptr, data, have);
99 e->ptr += have;
100 }
Joshua Haberman60d09662020-02-10 09:44:07 -0800101 e->overflow += (len - have);
102 }
103}
104
Joshua Haberman1c955f32022-01-12 07:19:28 -0800105static void jsonenc_putstr(jsonenc* e, const char* str) {
Joshua Haberman60d09662020-02-10 09:44:07 -0800106 jsonenc_putbytes(e, str, strlen(str));
107}
108
Joshua Habermanc7787cb2021-01-10 09:17:52 -0800109UPB_PRINTF(2, 3)
Joshua Haberman1c955f32022-01-12 07:19:28 -0800110static void jsonenc_printf(jsonenc* e, const char* fmt, ...) {
Joshua Haberman60d09662020-02-10 09:44:07 -0800111 size_t n;
112 size_t have = e->end - e->ptr;
113 va_list args;
114
115 va_start(args, fmt);
Joshua Habermana60e9a32022-05-13 17:32:17 -0700116 n = _upb_vsnprintf(e->ptr, have, fmt, args);
Joshua Haberman60d09662020-02-10 09:44:07 -0800117 va_end(args);
118
119 if (UPB_LIKELY(have > n)) {
120 e->ptr += n;
121 } else {
Joshua Haberman83708182021-03-09 14:44:35 -0800122 e->ptr = UPB_PTRADD(e->ptr, have);
Joshua Haberman60d09662020-02-10 09:44:07 -0800123 e->overflow += (n - have);
124 }
125}
126
Joshua Haberman1c955f32022-01-12 07:19:28 -0800127static void jsonenc_nanos(jsonenc* e, int32_t nanos) {
Joshua Habermana2922612020-02-24 13:57:57 -0800128 int digits = 9;
Joshua Haberman60d09662020-02-10 09:44:07 -0800129
130 if (nanos == 0) return;
131 if (nanos < 0 || nanos >= 1000000000) {
132 jsonenc_err(e, "error formatting timestamp as JSON: invalid nanos");
133 }
134
Joshua Habermana2922612020-02-24 13:57:57 -0800135 while (nanos % 1000 == 0) {
136 nanos /= 1000;
137 digits -= 3;
Joshua Haberman60d09662020-02-10 09:44:07 -0800138 }
Joshua Habermana2922612020-02-24 13:57:57 -0800139
Joshua Habermanc7787cb2021-01-10 09:17:52 -0800140 jsonenc_printf(e, ".%.*" PRId32, digits, nanos);
Joshua Haberman60d09662020-02-10 09:44:07 -0800141}
142
Joshua Haberman499c2cc2022-01-12 09:09:59 -0800143static void jsonenc_timestamp(jsonenc* e, const upb_Message* msg,
Joshua Haberman1c955f32022-01-12 07:19:28 -0800144 const upb_MessageDef* m) {
Joshua Habermanc56fe272022-02-22 20:32:56 -0800145 const upb_FieldDef* seconds_f = upb_MessageDef_FindFieldByNumber(m, 1);
146 const upb_FieldDef* nanos_f = upb_MessageDef_FindFieldByNumber(m, 2);
Joshua Haberman1c955f32022-01-12 07:19:28 -0800147 int64_t seconds = upb_Message_Get(msg, seconds_f).int64_val;
148 int32_t nanos = upb_Message_Get(msg, nanos_f).int32_val;
Joshua Haberman6e9db7d2020-02-15 19:31:51 -0800149 int L, N, I, J, K, hour, min, sec;
Joshua Haberman60d09662020-02-10 09:44:07 -0800150
151 if (seconds < -62135596800) {
152 jsonenc_err(e,
153 "error formatting timestamp as JSON: minimum acceptable value "
154 "is 0001-01-01T00:00:00Z");
155 } else if (seconds > 253402300799) {
156 jsonenc_err(e,
157 "error formatting timestamp as JSON: maximum acceptable value "
158 "is 9999-12-31T23:59:59Z");
159 }
160
161 /* Julian Day -> Y/M/D, Algorithm from:
162 * Fliegel, H. F., and Van Flandern, T. C., "A Machine Algorithm for
163 * Processing Calendar Dates," Communications of the Association of
164 * Computing Machines, vol. 11 (1968), p. 657. */
Joshua Habermanbe7dfeb2022-02-05 19:55:17 -0800165 seconds += 62135596800; // Ensure seconds is positive.
Bernardo Bruning4a3a7d92022-01-26 22:15:23 -0300166 L = (int)(seconds / 86400) - 719162 + 68569 + 2440588;
Joshua Haberman60d09662020-02-10 09:44:07 -0800167 N = 4 * L / 146097;
168 L = L - (146097 * N + 3) / 4;
169 I = 4000 * (L + 1) / 1461001;
170 L = L - 1461 * I / 4 + 31;
171 J = 80 * L / 2447;
172 K = L - 2447 * J / 80;
173 L = J / 11;
174 J = J + 2 - 12 * L;
175 I = 100 * (N - 49) + I + L;
176
Bernardo Bruning6475a962022-01-25 17:02:17 -0300177 sec = seconds % 60;
178 min = (seconds / 60) % 60;
179 hour = (seconds / 3600) % 24;
Joshua Haberman60d09662020-02-10 09:44:07 -0800180
Joshua Haberman6e9db7d2020-02-15 19:31:51 -0800181 jsonenc_printf(e, "\"%04d-%02d-%02dT%02d:%02d:%02d", I, J, K, hour, min, sec);
182 jsonenc_nanos(e, nanos);
Joshua Haberman60d09662020-02-10 09:44:07 -0800183 jsonenc_putstr(e, "Z\"");
184}
185
Joshua Haberman499c2cc2022-01-12 09:09:59 -0800186static void jsonenc_duration(jsonenc* e, const upb_Message* msg,
Joshua Haberman1c955f32022-01-12 07:19:28 -0800187 const upb_MessageDef* m) {
Joshua Habermanc56fe272022-02-22 20:32:56 -0800188 const upb_FieldDef* seconds_f = upb_MessageDef_FindFieldByNumber(m, 1);
189 const upb_FieldDef* nanos_f = upb_MessageDef_FindFieldByNumber(m, 2);
Joshua Haberman1c955f32022-01-12 07:19:28 -0800190 int64_t seconds = upb_Message_Get(msg, seconds_f).int64_val;
191 int32_t nanos = upb_Message_Get(msg, nanos_f).int32_val;
Joshua Haberman60d09662020-02-10 09:44:07 -0800192
193 if (seconds > 315576000000 || seconds < -315576000000 ||
194 (seconds < 0) != (nanos < 0)) {
195 jsonenc_err(e, "bad duration");
196 }
197
Joshua Habermana2922612020-02-24 13:57:57 -0800198 if (nanos < 0) {
199 nanos = -nanos;
200 }
201
Joshua Haberman60d09662020-02-10 09:44:07 -0800202 jsonenc_printf(e, "\"%" PRId64, seconds);
203 jsonenc_nanos(e, nanos);
204 jsonenc_putstr(e, "s\"");
205}
206
Joshua Haberman1c955f32022-01-12 07:19:28 -0800207static void jsonenc_enum(int32_t val, const upb_FieldDef* f, jsonenc* e) {
208 const upb_EnumDef* e_def = upb_FieldDef_EnumSubDef(f);
Joshua Haberman60d09662020-02-10 09:44:07 -0800209
Joshua Haberman1c955f32022-01-12 07:19:28 -0800210 if (strcmp(upb_EnumDef_FullName(e_def), "google.protobuf.NullValue") == 0) {
Joshua Haberman0a3a94a2020-10-12 15:31:13 -0700211 jsonenc_putstr(e, "null");
Joshua Haberman60d09662020-02-10 09:44:07 -0800212 } else {
Protobuf Team Bot6e1aa9f2022-06-08 11:17:20 -0700213 const upb_EnumValueDef* ev =
214 (e->options & upb_JsonEncode_FormatEnumsAsIntegers)
215 ? NULL
216 : upb_EnumDef_FindValueByNumber(e_def, val);
Joshua Haberman0a3a94a2020-10-12 15:31:13 -0700217
Joshua Haberman5c28ab62021-08-27 17:12:54 -0700218 if (ev) {
Joshua Haberman1c955f32022-01-12 07:19:28 -0800219 jsonenc_printf(e, "\"%s\"", upb_EnumValueDef_Name(ev));
Joshua Haberman0a3a94a2020-10-12 15:31:13 -0700220 } else {
221 jsonenc_printf(e, "%" PRId32, val);
222 }
Joshua Haberman60d09662020-02-10 09:44:07 -0800223 }
224}
225
Joshua Haberman1c955f32022-01-12 07:19:28 -0800226static void jsonenc_bytes(jsonenc* e, upb_StringView str) {
Joshua Haberman60d09662020-02-10 09:44:07 -0800227 /* This is the regular base64, not the "web-safe" version. */
228 static const char base64[] =
229 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
Joshua Haberman1c955f32022-01-12 07:19:28 -0800230 const unsigned char* ptr = (unsigned char*)str.data;
231 const unsigned char* end = UPB_PTRADD(ptr, str.size);
Joshua Haberman60d09662020-02-10 09:44:07 -0800232 char buf[4];
233
Joshua Haberman6e9db7d2020-02-15 19:31:51 -0800234 jsonenc_putstr(e, "\"");
Joshua Haberman60d09662020-02-10 09:44:07 -0800235
236 while (end - ptr >= 3) {
237 buf[0] = base64[ptr[0] >> 2];
238 buf[1] = base64[((ptr[0] & 0x3) << 4) | (ptr[1] >> 4)];
239 buf[2] = base64[((ptr[1] & 0xf) << 2) | (ptr[2] >> 6)];
240 buf[3] = base64[ptr[2] & 0x3f];
Joshua Haberman6e9db7d2020-02-15 19:31:51 -0800241 jsonenc_putbytes(e, buf, 4);
Joshua Haberman60d09662020-02-10 09:44:07 -0800242 ptr += 3;
243 }
244
245 switch (end - ptr) {
246 case 2:
Joshua Haberman6e9db7d2020-02-15 19:31:51 -0800247 buf[0] = base64[ptr[0] >> 2];
248 buf[1] = base64[((ptr[0] & 0x3) << 4) | (ptr[1] >> 4)];
249 buf[2] = base64[(ptr[1] & 0xf) << 2];
Joshua Haberman60d09662020-02-10 09:44:07 -0800250 buf[3] = '=';
Joshua Haberman6e9db7d2020-02-15 19:31:51 -0800251 jsonenc_putbytes(e, buf, 4);
Joshua Haberman60d09662020-02-10 09:44:07 -0800252 break;
253 case 1:
Joshua Haberman6e9db7d2020-02-15 19:31:51 -0800254 buf[0] = base64[ptr[0] >> 2];
255 buf[1] = base64[((ptr[0] & 0x3) << 4)];
Joshua Haberman60d09662020-02-10 09:44:07 -0800256 buf[2] = '=';
257 buf[3] = '=';
Joshua Haberman6e9db7d2020-02-15 19:31:51 -0800258 jsonenc_putbytes(e, buf, 4);
Joshua Haberman60d09662020-02-10 09:44:07 -0800259 break;
260 }
261
Joshua Haberman6e9db7d2020-02-15 19:31:51 -0800262 jsonenc_putstr(e, "\"");
Joshua Haberman60d09662020-02-10 09:44:07 -0800263}
264
Joshua Haberman1c955f32022-01-12 07:19:28 -0800265static void jsonenc_stringbody(jsonenc* e, upb_StringView str) {
266 const char* ptr = str.data;
267 const char* end = UPB_PTRADD(ptr, str.size);
Joshua Haberman60d09662020-02-10 09:44:07 -0800268
269 while (ptr < end) {
270 switch (*ptr) {
271 case '\n':
272 jsonenc_putstr(e, "\\n");
273 break;
274 case '\r':
275 jsonenc_putstr(e, "\\r");
276 break;
277 case '\t':
278 jsonenc_putstr(e, "\\t");
279 break;
280 case '\"':
281 jsonenc_putstr(e, "\\\"");
282 break;
283 case '\f':
Joshua Habermana2922612020-02-24 13:57:57 -0800284 jsonenc_putstr(e, "\\f");
Joshua Haberman60d09662020-02-10 09:44:07 -0800285 break;
286 case '\b':
Joshua Habermana2922612020-02-24 13:57:57 -0800287 jsonenc_putstr(e, "\\b");
Joshua Haberman60d09662020-02-10 09:44:07 -0800288 break;
289 case '\\':
290 jsonenc_putstr(e, "\\\\");
291 break;
292 default:
293 if ((uint8_t)*ptr < 0x20) {
294 jsonenc_printf(e, "\\u%04x", (int)(uint8_t)*ptr);
295 } else {
296 /* This could be a non-ASCII byte. We rely on the string being valid
297 * UTF-8. */
Joshua Haberman6e9db7d2020-02-15 19:31:51 -0800298 jsonenc_putbytes(e, ptr, 1);
Joshua Haberman60d09662020-02-10 09:44:07 -0800299 }
300 break;
301 }
302 ptr++;
303 }
Joshua Haberman6e9db7d2020-02-15 19:31:51 -0800304}
Joshua Haberman60d09662020-02-10 09:44:07 -0800305
Joshua Haberman1c955f32022-01-12 07:19:28 -0800306static void jsonenc_string(jsonenc* e, upb_StringView str) {
Joshua Haberman6e9db7d2020-02-15 19:31:51 -0800307 jsonenc_putstr(e, "\"");
308 jsonenc_stringbody(e, str);
Joshua Haberman60d09662020-02-10 09:44:07 -0800309 jsonenc_putstr(e, "\"");
310}
311
Joshua Habermanbc7b5dc2022-01-17 13:32:37 -0800312static bool upb_JsonEncode_HandleSpecialDoubles(jsonenc* e, double val) {
Joshua Haberman8f3ee802020-10-28 16:23:20 -0700313 if (val == INFINITY) {
Joshua Haberman6e9db7d2020-02-15 19:31:51 -0800314 jsonenc_putstr(e, "\"Infinity\"");
Joshua Haberman8f3ee802020-10-28 16:23:20 -0700315 } else if (val == -INFINITY) {
Joshua Haberman6e9db7d2020-02-15 19:31:51 -0800316 jsonenc_putstr(e, "\"-Infinity\"");
Joshua Haberman384cf152020-02-15 22:07:24 -0800317 } else if (val != val) {
318 jsonenc_putstr(e, "\"NaN\"");
Joshua Haberman6e9db7d2020-02-15 19:31:51 -0800319 } else {
Joshua Habermanbc7b5dc2022-01-17 13:32:37 -0800320 return false;
Joshua Haberman60d09662020-02-10 09:44:07 -0800321 }
Joshua Habermanbc7b5dc2022-01-17 13:32:37 -0800322 return true;
323}
324
325static void upb_JsonEncode_Double(jsonenc* e, double val) {
326 if (upb_JsonEncode_HandleSpecialDoubles(e, val)) return;
327 char buf[32];
328 _upb_EncodeRoundTripDouble(val, buf, sizeof(buf));
329 jsonenc_putstr(e, buf);
330}
331
332static void upb_JsonEncode_Float(jsonenc* e, float val) {
333 if (upb_JsonEncode_HandleSpecialDoubles(e, val)) return;
334 char buf[32];
335 _upb_EncodeRoundTripFloat(val, buf, sizeof(buf));
336 jsonenc_putstr(e, buf);
Joshua Haberman60d09662020-02-10 09:44:07 -0800337}
338
Joshua Haberman499c2cc2022-01-12 09:09:59 -0800339static void jsonenc_wrapper(jsonenc* e, const upb_Message* msg,
Joshua Haberman1c955f32022-01-12 07:19:28 -0800340 const upb_MessageDef* m) {
Joshua Habermanc56fe272022-02-22 20:32:56 -0800341 const upb_FieldDef* val_f = upb_MessageDef_FindFieldByNumber(m, 1);
Joshua Haberman1c955f32022-01-12 07:19:28 -0800342 upb_MessageValue val = upb_Message_Get(msg, val_f);
Joshua Haberman6e9db7d2020-02-15 19:31:51 -0800343 jsonenc_scalar(e, val, val_f);
Joshua Haberman60d09662020-02-10 09:44:07 -0800344}
345
Joshua Haberman1c955f32022-01-12 07:19:28 -0800346static const upb_MessageDef* jsonenc_getanymsg(jsonenc* e,
347 upb_StringView type_url) {
Joshua Haberman384cf152020-02-15 22:07:24 -0800348 /* Find last '/', if any. */
Joshua Haberman1c955f32022-01-12 07:19:28 -0800349 const char* end = type_url.data + type_url.size;
350 const char* ptr = end;
351 const upb_MessageDef* ret;
Joshua Haberman384cf152020-02-15 22:07:24 -0800352
Joshua Haberman81c2aa72020-06-11 12:42:17 -0700353 if (!e->ext_pool) {
354 jsonenc_err(e, "Tried to encode Any, but no symtab was provided");
355 }
356
357 if (type_url.size == 0) goto badurl;
Joshua Haberman384cf152020-02-15 22:07:24 -0800358
359 while (true) {
360 if (--ptr == type_url.data) {
361 /* Type URL must contain at least one '/', with host before. */
Joshua Habermana2922612020-02-24 13:57:57 -0800362 goto badurl;
Joshua Haberman384cf152020-02-15 22:07:24 -0800363 }
364 if (*ptr == '/') {
365 ptr++;
366 break;
367 }
368 }
369
Joshua Haberman1c955f32022-01-12 07:19:28 -0800370 ret = upb_DefPool_FindMessageByNameWithSize(e->ext_pool, ptr, end - ptr);
Joshua Habermana2922612020-02-24 13:57:57 -0800371
372 if (!ret) {
Joshua Habermanefe11c62020-06-11 13:01:51 -0700373 jsonenc_errf(e, "Couldn't find Any type: %.*s", (int)(end - ptr), ptr);
Joshua Habermana2922612020-02-24 13:57:57 -0800374 }
375
376 return ret;
377
378badurl:
Joshua Haberman1c955f32022-01-12 07:19:28 -0800379 jsonenc_errf(e, "Bad type URL: " UPB_STRINGVIEW_FORMAT,
380 UPB_STRINGVIEW_ARGS(type_url));
Joshua Haberman384cf152020-02-15 22:07:24 -0800381}
382
Joshua Haberman499c2cc2022-01-12 09:09:59 -0800383static void jsonenc_any(jsonenc* e, const upb_Message* msg,
Joshua Haberman1c955f32022-01-12 07:19:28 -0800384 const upb_MessageDef* m) {
Joshua Habermanc56fe272022-02-22 20:32:56 -0800385 const upb_FieldDef* type_url_f = upb_MessageDef_FindFieldByNumber(m, 1);
386 const upb_FieldDef* value_f = upb_MessageDef_FindFieldByNumber(m, 2);
Joshua Haberman1c955f32022-01-12 07:19:28 -0800387 upb_StringView type_url = upb_Message_Get(msg, type_url_f).str_val;
388 upb_StringView value = upb_Message_Get(msg, value_f).str_val;
389 const upb_MessageDef* any_m = jsonenc_getanymsg(e, type_url);
390 const upb_MiniTable* any_layout = upb_MessageDef_MiniTable(any_m);
391 upb_Arena* arena = jsonenc_arena(e);
Joshua Haberman499c2cc2022-01-12 09:09:59 -0800392 upb_Message* any = upb_Message_New(any_m, arena);
Joshua Haberman60d09662020-02-10 09:44:07 -0800393
Joshua Haberman72af9dc2022-01-12 10:04:02 -0800394 if (upb_Decode(value.data, value.size, any, any_layout, NULL, 0, arena) !=
Joshua Haberman58c1dbc2021-10-13 23:03:47 -0700395 kUpb_DecodeStatus_Ok) {
Joshua Haberman6e9db7d2020-02-15 19:31:51 -0800396 jsonenc_err(e, "Error decoding message in Any");
Joshua Haberman60d09662020-02-10 09:44:07 -0800397 }
398
Joshua Haberman543a0ce2020-05-26 22:30:50 -0700399 jsonenc_putstr(e, "{\"@type\":");
Joshua Haberman60d09662020-02-10 09:44:07 -0800400 jsonenc_string(e, type_url);
Joshua Haberman60d09662020-02-10 09:44:07 -0800401
Joshua Haberman1c955f32022-01-12 07:19:28 -0800402 if (upb_MessageDef_WellKnownType(any_m) == kUpb_WellKnown_Unspecified) {
Joshua Haberman543a0ce2020-05-26 22:30:50 -0700403 /* Regular messages: {"@type": "...","foo": 1, "bar": 2} */
Joshua Habermane58f7a02021-02-17 17:18:55 -0800404 jsonenc_msgfields(e, any, any_m, false);
Joshua Haberman60d09662020-02-10 09:44:07 -0800405 } else {
Joshua Haberman543a0ce2020-05-26 22:30:50 -0700406 /* Well-known type: {"@type": "...","value": <well-known encoding>} */
Joshua Habermane58f7a02021-02-17 17:18:55 -0800407 jsonenc_putstr(e, ",\"value\":");
Joshua Haberman60d09662020-02-10 09:44:07 -0800408 jsonenc_msgfield(e, any, any_m);
409 }
410
411 jsonenc_putstr(e, "}");
412}
413
Joshua Haberman1c955f32022-01-12 07:19:28 -0800414static void jsonenc_putsep(jsonenc* e, const char* str, bool* first) {
Joshua Haberman60d09662020-02-10 09:44:07 -0800415 if (*first) {
416 *first = false;
417 } else {
Joshua Haberman384cf152020-02-15 22:07:24 -0800418 jsonenc_putstr(e, str);
Joshua Haberman60d09662020-02-10 09:44:07 -0800419 }
420}
421
Joshua Haberman1c955f32022-01-12 07:19:28 -0800422static void jsonenc_fieldpath(jsonenc* e, upb_StringView path) {
423 const char* ptr = path.data;
424 const char* end = ptr + path.size;
Joshua Haberman384cf152020-02-15 22:07:24 -0800425
426 while (ptr < end) {
427 char ch = *ptr;
Joshua Haberman23a5af32020-02-25 19:13:27 -0800428
Joshua Haberman384cf152020-02-15 22:07:24 -0800429 if (ch >= 'A' && ch <= 'Z') {
430 jsonenc_err(e, "Field mask element may not have upper-case letter.");
431 } else if (ch == '_') {
432 if (ptr == end - 1 || *(ptr + 1) < 'a' || *(ptr + 1) > 'z') {
433 jsonenc_err(e, "Underscore must be followed by a lowercase letter.");
434 }
Joshua Haberman23a5af32020-02-25 19:13:27 -0800435 ch = *++ptr - 32;
Joshua Haberman384cf152020-02-15 22:07:24 -0800436 }
Joshua Haberman23a5af32020-02-25 19:13:27 -0800437
438 jsonenc_putbytes(e, &ch, 1);
Joshua Haberman384cf152020-02-15 22:07:24 -0800439 ptr++;
440 }
441}
442
Joshua Haberman499c2cc2022-01-12 09:09:59 -0800443static void jsonenc_fieldmask(jsonenc* e, const upb_Message* msg,
Joshua Haberman1c955f32022-01-12 07:19:28 -0800444 const upb_MessageDef* m) {
Joshua Habermanc56fe272022-02-22 20:32:56 -0800445 const upb_FieldDef* paths_f = upb_MessageDef_FindFieldByNumber(m, 1);
Joshua Haberman1c955f32022-01-12 07:19:28 -0800446 const upb_Array* paths = upb_Message_Get(msg, paths_f).array_val;
Joshua Haberman384cf152020-02-15 22:07:24 -0800447 bool first = true;
448 size_t i, n = 0;
449
Joshua Haberman1c955f32022-01-12 07:19:28 -0800450 if (paths) n = upb_Array_Size(paths);
Joshua Haberman384cf152020-02-15 22:07:24 -0800451
452 jsonenc_putstr(e, "\"");
453
454 for (i = 0; i < n; i++) {
455 jsonenc_putsep(e, ",", &first);
Joshua Haberman1c955f32022-01-12 07:19:28 -0800456 jsonenc_fieldpath(e, upb_Array_Get(paths, i).str_val);
Joshua Haberman384cf152020-02-15 22:07:24 -0800457 }
458
459 jsonenc_putstr(e, "\"");
460}
461
Joshua Haberman499c2cc2022-01-12 09:09:59 -0800462static void jsonenc_struct(jsonenc* e, const upb_Message* msg,
Joshua Haberman1c955f32022-01-12 07:19:28 -0800463 const upb_MessageDef* m) {
Joshua Habermanc56fe272022-02-22 20:32:56 -0800464 const upb_FieldDef* fields_f = upb_MessageDef_FindFieldByNumber(m, 1);
Joshua Haberman1c955f32022-01-12 07:19:28 -0800465 const upb_Map* fields = upb_Message_Get(msg, fields_f).map_val;
466 const upb_MessageDef* entry_m = upb_FieldDef_MessageSubDef(fields_f);
Joshua Habermanc56fe272022-02-22 20:32:56 -0800467 const upb_FieldDef* value_f = upb_MessageDef_FindFieldByNumber(entry_m, 2);
Joshua Haberman1c955f32022-01-12 07:19:28 -0800468 size_t iter = kUpb_Map_Begin;
Joshua Haberman60d09662020-02-10 09:44:07 -0800469 bool first = true;
470
471 jsonenc_putstr(e, "{");
472
Joshua Haberman543a0ce2020-05-26 22:30:50 -0700473 if (fields) {
Joshua Haberman1c955f32022-01-12 07:19:28 -0800474 while (upb_MapIterator_Next(fields, &iter)) {
475 upb_MessageValue key = upb_MapIterator_Key(fields, iter);
476 upb_MessageValue val = upb_MapIterator_Value(fields, iter);
Joshua Haberman60d09662020-02-10 09:44:07 -0800477
Joshua Haberman543a0ce2020-05-26 22:30:50 -0700478 jsonenc_putsep(e, ",", &first);
479 jsonenc_string(e, key.str_val);
480 jsonenc_putstr(e, ":");
Joshua Haberman1c955f32022-01-12 07:19:28 -0800481 jsonenc_value(e, val.msg_val, upb_FieldDef_MessageSubDef(value_f));
Joshua Haberman543a0ce2020-05-26 22:30:50 -0700482 }
Joshua Haberman60d09662020-02-10 09:44:07 -0800483 }
484
485 jsonenc_putstr(e, "}");
486}
487
Joshua Haberman499c2cc2022-01-12 09:09:59 -0800488static void jsonenc_listvalue(jsonenc* e, const upb_Message* msg,
Joshua Haberman1c955f32022-01-12 07:19:28 -0800489 const upb_MessageDef* m) {
Joshua Habermanc56fe272022-02-22 20:32:56 -0800490 const upb_FieldDef* values_f = upb_MessageDef_FindFieldByNumber(m, 1);
Joshua Haberman1c955f32022-01-12 07:19:28 -0800491 const upb_MessageDef* values_m = upb_FieldDef_MessageSubDef(values_f);
492 const upb_Array* values = upb_Message_Get(msg, values_f).array_val;
Joshua Haberman6e9db7d2020-02-15 19:31:51 -0800493 size_t i;
Joshua Haberman60d09662020-02-10 09:44:07 -0800494 bool first = true;
495
496 jsonenc_putstr(e, "[");
497
Joshua Haberman543a0ce2020-05-26 22:30:50 -0700498 if (values) {
Joshua Haberman1c955f32022-01-12 07:19:28 -0800499 const size_t size = upb_Array_Size(values);
Joshua Haberman543a0ce2020-05-26 22:30:50 -0700500 for (i = 0; i < size; i++) {
Joshua Haberman1c955f32022-01-12 07:19:28 -0800501 upb_MessageValue elem = upb_Array_Get(values, i);
Joshua Haberman60d09662020-02-10 09:44:07 -0800502
Joshua Haberman543a0ce2020-05-26 22:30:50 -0700503 jsonenc_putsep(e, ",", &first);
504 jsonenc_value(e, elem.msg_val, values_m);
505 }
Joshua Haberman60d09662020-02-10 09:44:07 -0800506 }
507
508 jsonenc_putstr(e, "]");
509}
510
Joshua Haberman499c2cc2022-01-12 09:09:59 -0800511static void jsonenc_value(jsonenc* e, const upb_Message* msg,
Joshua Haberman1c955f32022-01-12 07:19:28 -0800512 const upb_MessageDef* m) {
Joshua Haberman60d09662020-02-10 09:44:07 -0800513 /* TODO(haberman): do we want a reflection method to get oneof case? */
Joshua Haberman1c955f32022-01-12 07:19:28 -0800514 size_t iter = kUpb_Message_Begin;
515 const upb_FieldDef* f;
516 upb_MessageValue val;
Joshua Haberman60d09662020-02-10 09:44:07 -0800517
Joshua Haberman1c955f32022-01-12 07:19:28 -0800518 if (!upb_Message_Next(msg, m, NULL, &f, &val, &iter)) {
Joshua Haberman60d09662020-02-10 09:44:07 -0800519 jsonenc_err(e, "No value set in Value proto");
520 }
521
Joshua Haberman1c955f32022-01-12 07:19:28 -0800522 switch (upb_FieldDef_Number(f)) {
Joshua Haberman60d09662020-02-10 09:44:07 -0800523 case 1:
Joshua Haberman6e9db7d2020-02-15 19:31:51 -0800524 jsonenc_putstr(e, "null");
Joshua Haberman60d09662020-02-10 09:44:07 -0800525 break;
526 case 2:
Joshua Habermanbc7b5dc2022-01-17 13:32:37 -0800527 upb_JsonEncode_Double(e, val.double_val);
Joshua Haberman60d09662020-02-10 09:44:07 -0800528 break;
529 case 3:
530 jsonenc_string(e, val.str_val);
531 break;
532 case 4:
533 jsonenc_putstr(e, val.bool_val ? "true" : "false");
534 break;
535 case 5:
Joshua Haberman1c955f32022-01-12 07:19:28 -0800536 jsonenc_struct(e, val.msg_val, upb_FieldDef_MessageSubDef(f));
Joshua Haberman60d09662020-02-10 09:44:07 -0800537 break;
538 case 6:
Joshua Haberman1c955f32022-01-12 07:19:28 -0800539 jsonenc_listvalue(e, val.msg_val, upb_FieldDef_MessageSubDef(f));
Joshua Haberman60d09662020-02-10 09:44:07 -0800540 break;
541 }
542}
543
Joshua Haberman499c2cc2022-01-12 09:09:59 -0800544static void jsonenc_msgfield(jsonenc* e, const upb_Message* msg,
Joshua Haberman1c955f32022-01-12 07:19:28 -0800545 const upb_MessageDef* m) {
546 switch (upb_MessageDef_WellKnownType(m)) {
547 case kUpb_WellKnown_Unspecified:
Joshua Haberman6e9db7d2020-02-15 19:31:51 -0800548 jsonenc_msg(e, msg, m);
Joshua Haberman60d09662020-02-10 09:44:07 -0800549 break;
Joshua Haberman1c955f32022-01-12 07:19:28 -0800550 case kUpb_WellKnown_Any:
Joshua Haberman60d09662020-02-10 09:44:07 -0800551 jsonenc_any(e, msg, m);
552 break;
Joshua Haberman1c955f32022-01-12 07:19:28 -0800553 case kUpb_WellKnown_FieldMask:
Joshua Haberman384cf152020-02-15 22:07:24 -0800554 jsonenc_fieldmask(e, msg, m);
555 break;
Joshua Haberman1c955f32022-01-12 07:19:28 -0800556 case kUpb_WellKnown_Duration:
Joshua Haberman60d09662020-02-10 09:44:07 -0800557 jsonenc_duration(e, msg, m);
558 break;
Joshua Haberman1c955f32022-01-12 07:19:28 -0800559 case kUpb_WellKnown_Timestamp:
Joshua Haberman60d09662020-02-10 09:44:07 -0800560 jsonenc_timestamp(e, msg, m);
561 break;
Joshua Haberman1c955f32022-01-12 07:19:28 -0800562 case kUpb_WellKnown_DoubleValue:
563 case kUpb_WellKnown_FloatValue:
564 case kUpb_WellKnown_Int64Value:
565 case kUpb_WellKnown_UInt64Value:
566 case kUpb_WellKnown_Int32Value:
567 case kUpb_WellKnown_UInt32Value:
568 case kUpb_WellKnown_StringValue:
569 case kUpb_WellKnown_BytesValue:
570 case kUpb_WellKnown_BoolValue:
Joshua Haberman60d09662020-02-10 09:44:07 -0800571 jsonenc_wrapper(e, msg, m);
572 break;
Joshua Haberman1c955f32022-01-12 07:19:28 -0800573 case kUpb_WellKnown_Value:
Joshua Haberman60d09662020-02-10 09:44:07 -0800574 jsonenc_value(e, msg, m);
575 break;
Joshua Haberman1c955f32022-01-12 07:19:28 -0800576 case kUpb_WellKnown_ListValue:
Joshua Haberman60d09662020-02-10 09:44:07 -0800577 jsonenc_listvalue(e, msg, m);
578 break;
Joshua Haberman1c955f32022-01-12 07:19:28 -0800579 case kUpb_WellKnown_Struct:
Joshua Habermana2922612020-02-24 13:57:57 -0800580 jsonenc_struct(e, msg, m);
Joshua Haberman60d09662020-02-10 09:44:07 -0800581 break;
582 }
583}
584
Joshua Haberman1c955f32022-01-12 07:19:28 -0800585static void jsonenc_scalar(jsonenc* e, upb_MessageValue val,
586 const upb_FieldDef* f) {
587 switch (upb_FieldDef_CType(f)) {
588 case kUpb_CType_Bool:
Joshua Haberman60d09662020-02-10 09:44:07 -0800589 jsonenc_putstr(e, val.bool_val ? "true" : "false");
590 break;
Joshua Haberman1c955f32022-01-12 07:19:28 -0800591 case kUpb_CType_Float:
Joshua Habermanbc7b5dc2022-01-17 13:32:37 -0800592 upb_JsonEncode_Float(e, val.float_val);
Joshua Haberman60d09662020-02-10 09:44:07 -0800593 break;
Joshua Haberman1c955f32022-01-12 07:19:28 -0800594 case kUpb_CType_Double:
Joshua Habermanbc7b5dc2022-01-17 13:32:37 -0800595 upb_JsonEncode_Double(e, val.double_val);
Joshua Haberman60d09662020-02-10 09:44:07 -0800596 break;
Joshua Haberman1c955f32022-01-12 07:19:28 -0800597 case kUpb_CType_Int32:
Joshua Haberman60d09662020-02-10 09:44:07 -0800598 jsonenc_printf(e, "%" PRId32, val.int32_val);
599 break;
Joshua Haberman1c955f32022-01-12 07:19:28 -0800600 case kUpb_CType_UInt32:
Joshua Haberman60d09662020-02-10 09:44:07 -0800601 jsonenc_printf(e, "%" PRIu32, val.uint32_val);
602 break;
Joshua Haberman1c955f32022-01-12 07:19:28 -0800603 case kUpb_CType_Int64:
Joshua Haberman60d09662020-02-10 09:44:07 -0800604 jsonenc_printf(e, "\"%" PRId64 "\"", val.int64_val);
605 break;
Joshua Haberman1c955f32022-01-12 07:19:28 -0800606 case kUpb_CType_UInt64:
Joshua Haberman60d09662020-02-10 09:44:07 -0800607 jsonenc_printf(e, "\"%" PRIu64 "\"", val.uint64_val);
608 break;
Joshua Haberman1c955f32022-01-12 07:19:28 -0800609 case kUpb_CType_String:
Joshua Haberman60d09662020-02-10 09:44:07 -0800610 jsonenc_string(e, val.str_val);
611 break;
Joshua Haberman1c955f32022-01-12 07:19:28 -0800612 case kUpb_CType_Bytes:
Joshua Haberman60d09662020-02-10 09:44:07 -0800613 jsonenc_bytes(e, val.str_val);
614 break;
Joshua Haberman1c955f32022-01-12 07:19:28 -0800615 case kUpb_CType_Enum:
Joshua Haberman60d09662020-02-10 09:44:07 -0800616 jsonenc_enum(val.int32_val, f, e);
617 break;
Joshua Haberman1c955f32022-01-12 07:19:28 -0800618 case kUpb_CType_Message:
619 jsonenc_msgfield(e, val.msg_val, upb_FieldDef_MessageSubDef(f));
Joshua Haberman60d09662020-02-10 09:44:07 -0800620 break;
621 }
622}
623
Joshua Haberman1c955f32022-01-12 07:19:28 -0800624static void jsonenc_mapkey(jsonenc* e, upb_MessageValue val,
625 const upb_FieldDef* f) {
Joshua Haberman6e9db7d2020-02-15 19:31:51 -0800626 jsonenc_putstr(e, "\"");
Joshua Haberman60d09662020-02-10 09:44:07 -0800627
Joshua Haberman1c955f32022-01-12 07:19:28 -0800628 switch (upb_FieldDef_CType(f)) {
629 case kUpb_CType_Bool:
Joshua Haberman60d09662020-02-10 09:44:07 -0800630 jsonenc_putstr(e, val.bool_val ? "true" : "false");
631 break;
Joshua Haberman1c955f32022-01-12 07:19:28 -0800632 case kUpb_CType_Int32:
Joshua Haberman60d09662020-02-10 09:44:07 -0800633 jsonenc_printf(e, "%" PRId32, val.int32_val);
634 break;
Joshua Haberman1c955f32022-01-12 07:19:28 -0800635 case kUpb_CType_UInt32:
Joshua Haberman60d09662020-02-10 09:44:07 -0800636 jsonenc_printf(e, "%" PRIu32, val.uint32_val);
637 break;
Joshua Haberman1c955f32022-01-12 07:19:28 -0800638 case kUpb_CType_Int64:
Joshua Haberman60d09662020-02-10 09:44:07 -0800639 jsonenc_printf(e, "%" PRId64, val.int64_val);
640 break;
Joshua Haberman1c955f32022-01-12 07:19:28 -0800641 case kUpb_CType_UInt64:
Joshua Haberman60d09662020-02-10 09:44:07 -0800642 jsonenc_printf(e, "%" PRIu64, val.uint64_val);
643 break;
Joshua Haberman1c955f32022-01-12 07:19:28 -0800644 case kUpb_CType_String:
Joshua Haberman6e9db7d2020-02-15 19:31:51 -0800645 jsonenc_stringbody(e, val.str_val);
Joshua Habermana2922612020-02-24 13:57:57 -0800646 break;
Joshua Haberman6e9db7d2020-02-15 19:31:51 -0800647 default:
648 UPB_UNREACHABLE();
Joshua Haberman60d09662020-02-10 09:44:07 -0800649 }
650
Joshua Haberman543a0ce2020-05-26 22:30:50 -0700651 jsonenc_putstr(e, "\":");
Joshua Haberman60d09662020-02-10 09:44:07 -0800652}
653
Joshua Haberman1c955f32022-01-12 07:19:28 -0800654static void jsonenc_array(jsonenc* e, const upb_Array* arr,
655 const upb_FieldDef* f) {
Joshua Haberman60d09662020-02-10 09:44:07 -0800656 size_t i;
Joshua Haberman1c955f32022-01-12 07:19:28 -0800657 size_t size = arr ? upb_Array_Size(arr) : 0;
Joshua Haberman60d09662020-02-10 09:44:07 -0800658 bool first = true;
659
Joshua Haberman6e9db7d2020-02-15 19:31:51 -0800660 jsonenc_putstr(e, "[");
Joshua Haberman60d09662020-02-10 09:44:07 -0800661
662 for (i = 0; i < size; i++) {
Joshua Haberman543a0ce2020-05-26 22:30:50 -0700663 jsonenc_putsep(e, ",", &first);
Joshua Haberman1c955f32022-01-12 07:19:28 -0800664 jsonenc_scalar(e, upb_Array_Get(arr, i), f);
Joshua Haberman60d09662020-02-10 09:44:07 -0800665 }
666
Joshua Haberman6e9db7d2020-02-15 19:31:51 -0800667 jsonenc_putstr(e, "]");
Joshua Haberman60d09662020-02-10 09:44:07 -0800668}
669
Joshua Haberman1c955f32022-01-12 07:19:28 -0800670static void jsonenc_map(jsonenc* e, const upb_Map* map, const upb_FieldDef* f) {
671 const upb_MessageDef* entry = upb_FieldDef_MessageSubDef(f);
Joshua Habermanc56fe272022-02-22 20:32:56 -0800672 const upb_FieldDef* key_f = upb_MessageDef_FindFieldByNumber(entry, 1);
673 const upb_FieldDef* val_f = upb_MessageDef_FindFieldByNumber(entry, 2);
Joshua Haberman1c955f32022-01-12 07:19:28 -0800674 size_t iter = kUpb_Map_Begin;
Joshua Haberman60d09662020-02-10 09:44:07 -0800675 bool first = true;
676
Joshua Haberman6e9db7d2020-02-15 19:31:51 -0800677 jsonenc_putstr(e, "{");
Joshua Haberman60d09662020-02-10 09:44:07 -0800678
Joshua Haberman6b357602020-12-08 16:58:30 -0800679 if (map) {
Joshua Haberman1c955f32022-01-12 07:19:28 -0800680 while (upb_MapIterator_Next(map, &iter)) {
Joshua Haberman6b357602020-12-08 16:58:30 -0800681 jsonenc_putsep(e, ",", &first);
Joshua Haberman1c955f32022-01-12 07:19:28 -0800682 jsonenc_mapkey(e, upb_MapIterator_Key(map, iter), key_f);
683 jsonenc_scalar(e, upb_MapIterator_Value(map, iter), val_f);
Joshua Haberman6b357602020-12-08 16:58:30 -0800684 }
Joshua Haberman60d09662020-02-10 09:44:07 -0800685 }
686
Joshua Haberman6e9db7d2020-02-15 19:31:51 -0800687 jsonenc_putstr(e, "}");
Joshua Haberman60d09662020-02-10 09:44:07 -0800688}
689
Joshua Haberman1c955f32022-01-12 07:19:28 -0800690static void jsonenc_fieldval(jsonenc* e, const upb_FieldDef* f,
691 upb_MessageValue val, bool* first) {
692 const char* name;
Joshua Haberman60d09662020-02-10 09:44:07 -0800693
Joshua Haberman543a0ce2020-05-26 22:30:50 -0700694 jsonenc_putsep(e, ",", first);
Joshua Habermance012b72021-10-01 16:34:42 -0700695
Joshua Haberman1c955f32022-01-12 07:19:28 -0800696 if (upb_FieldDef_IsExtension(f)) {
Joshua Haberman6f890342021-10-03 15:18:38 -0700697 // TODO: For MessageSet, I would have expected this to print the message
698 // name here, but Python doesn't appear to do this. We should do more
699 // research here about what various implementations do.
Joshua Haberman1c955f32022-01-12 07:19:28 -0800700 jsonenc_printf(e, "\"[%s]\":", upb_FieldDef_FullName(f));
Joshua Habermance012b72021-10-01 16:34:42 -0700701 } else {
Joshua Haberman1c955f32022-01-12 07:19:28 -0800702 if (e->options & upb_JsonEncode_UseProtoNames) {
703 name = upb_FieldDef_Name(f);
Joshua Habermance012b72021-10-01 16:34:42 -0700704 } else {
Joshua Haberman1c955f32022-01-12 07:19:28 -0800705 name = upb_FieldDef_JsonName(f);
Joshua Habermance012b72021-10-01 16:34:42 -0700706 }
707 jsonenc_printf(e, "\"%s\":", name);
708 }
Joshua Haberman60d09662020-02-10 09:44:07 -0800709
Joshua Haberman1c955f32022-01-12 07:19:28 -0800710 if (upb_FieldDef_IsMap(f)) {
Joshua Haberman60d09662020-02-10 09:44:07 -0800711 jsonenc_map(e, val.map_val, f);
Joshua Haberman1c955f32022-01-12 07:19:28 -0800712 } else if (upb_FieldDef_IsRepeated(f)) {
Joshua Haberman60d09662020-02-10 09:44:07 -0800713 jsonenc_array(e, val.array_val, f);
714 } else {
Joshua Haberman6e9db7d2020-02-15 19:31:51 -0800715 jsonenc_scalar(e, val, f);
Joshua Haberman60d09662020-02-10 09:44:07 -0800716 }
717}
718
Joshua Haberman499c2cc2022-01-12 09:09:59 -0800719static void jsonenc_msgfields(jsonenc* e, const upb_Message* msg,
Joshua Haberman1c955f32022-01-12 07:19:28 -0800720 const upb_MessageDef* m, bool first) {
721 upb_MessageValue val;
722 const upb_FieldDef* f;
Joshua Haberman60d09662020-02-10 09:44:07 -0800723
Joshua Haberman1c955f32022-01-12 07:19:28 -0800724 if (e->options & upb_JsonEncode_EmitDefaults) {
Joshua Haberman60d09662020-02-10 09:44:07 -0800725 /* Iterate over all fields. */
Joshua Haberman5aa5b772020-10-11 13:37:57 -0700726 int i = 0;
Joshua Haberman1c955f32022-01-12 07:19:28 -0800727 int n = upb_MessageDef_FieldCount(m);
Joshua Haberman5aa5b772020-10-11 13:37:57 -0700728 for (i = 0; i < n; i++) {
Joshua Haberman1c955f32022-01-12 07:19:28 -0800729 f = upb_MessageDef_Field(m, i);
730 if (!upb_FieldDef_HasPresence(f) || upb_Message_Has(msg, f)) {
731 jsonenc_fieldval(e, f, upb_Message_Get(msg, f), &first);
Joshua Haberman6b357602020-12-08 16:58:30 -0800732 }
Joshua Haberman60d09662020-02-10 09:44:07 -0800733 }
734 } else {
735 /* Iterate over non-empty fields. */
Joshua Haberman1c955f32022-01-12 07:19:28 -0800736 size_t iter = kUpb_Message_Begin;
737 while (upb_Message_Next(msg, m, e->ext_pool, &f, &val, &iter)) {
Joshua Haberman60d09662020-02-10 09:44:07 -0800738 jsonenc_fieldval(e, f, val, &first);
739 }
740 }
Joshua Habermana2922612020-02-24 13:57:57 -0800741}
Joshua Haberman60d09662020-02-10 09:44:07 -0800742
Joshua Haberman499c2cc2022-01-12 09:09:59 -0800743static void jsonenc_msg(jsonenc* e, const upb_Message* msg,
Joshua Haberman1c955f32022-01-12 07:19:28 -0800744 const upb_MessageDef* m) {
Joshua Habermana2922612020-02-24 13:57:57 -0800745 jsonenc_putstr(e, "{");
Joshua Habermane58f7a02021-02-17 17:18:55 -0800746 jsonenc_msgfields(e, msg, m, true);
Joshua Haberman6e9db7d2020-02-15 19:31:51 -0800747 jsonenc_putstr(e, "}");
Joshua Haberman60d09662020-02-10 09:44:07 -0800748}
749
Joshua Haberman1c955f32022-01-12 07:19:28 -0800750static size_t jsonenc_nullz(jsonenc* e, size_t size) {
Joshua Haberman60d09662020-02-10 09:44:07 -0800751 size_t ret = e->ptr - e->buf + e->overflow;
752
753 if (size > 0) {
754 if (e->ptr == e->end) e->ptr--;
755 *e->ptr = '\0';
756 }
757
758 return ret;
759}
760
Joshua Haberman499c2cc2022-01-12 09:09:59 -0800761size_t upb_JsonEncode(const upb_Message* msg, const upb_MessageDef* m,
Joshua Haberman1c955f32022-01-12 07:19:28 -0800762 const upb_DefPool* ext_pool, int options, char* buf,
763 size_t size, upb_Status* status) {
Joshua Haberman60d09662020-02-10 09:44:07 -0800764 jsonenc e;
765
766 e.buf = buf;
767 e.ptr = buf;
Joshua Haberman83708182021-03-09 14:44:35 -0800768 e.end = UPB_PTRADD(buf, size);
Joshua Haberman60d09662020-02-10 09:44:07 -0800769 e.overflow = 0;
770 e.options = options;
771 e.ext_pool = ext_pool;
Joshua Haberman6e9db7d2020-02-15 19:31:51 -0800772 e.status = status;
Joshua Habermana2922612020-02-24 13:57:57 -0800773 e.arena = NULL;
Joshua Haberman6e9db7d2020-02-15 19:31:51 -0800774
775 if (setjmp(e.err)) return -1;
Joshua Haberman60d09662020-02-10 09:44:07 -0800776
Joshua Haberman543a0ce2020-05-26 22:30:50 -0700777 jsonenc_msgfield(&e, msg, m);
Joshua Haberman1c955f32022-01-12 07:19:28 -0800778 if (e.arena) upb_Arena_Free(e.arena);
Joshua Haberman60d09662020-02-10 09:44:07 -0800779 return jsonenc_nullz(&e, size);
780}