Joshua Haberman | e59d2c8 | 2021-04-05 10:47:53 -0700 | [diff] [blame] | 1 | /* |
Joshua Haberman | 823eb09 | 2021-04-05 12:26:41 -0700 | [diff] [blame] | 2 | * Copyright (c) 2009-2021, Google LLC |
Joshua Haberman | e59d2c8 | 2021-04-05 10:47:53 -0700 | [diff] [blame] | 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 | * |
Joshua Haberman | 1c955f3 | 2022-01-12 07:19:28 -0800 | [diff] [blame] | 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 |
Joshua Haberman | e59d2c8 | 2021-04-05 10:47:53 -0700 | [diff] [blame] | 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 | */ |
Joshua Haberman | 60d0966 | 2020-02-10 09:44:07 -0800 | [diff] [blame] | 27 | |
Joshua Haberman | 6e9db7d | 2020-02-15 19:31:51 -0800 | [diff] [blame] | 28 | #include "upb/json_encode.h" |
Joshua Haberman | 60d0966 | 2020-02-10 09:44:07 -0800 | [diff] [blame] | 29 | |
| 30 | #include <ctype.h> |
| 31 | #include <float.h> |
| 32 | #include <inttypes.h> |
Joshua Haberman | 8f3ee80 | 2020-10-28 16:23:20 -0700 | [diff] [blame] | 33 | #include <math.h> |
| 34 | #include <setjmp.h> |
Joshua Haberman | 60d0966 | 2020-02-10 09:44:07 -0800 | [diff] [blame] | 35 | #include <stdarg.h> |
| 36 | #include <stdio.h> |
| 37 | #include <string.h> |
| 38 | |
Joshua Haberman | 6e9db7d | 2020-02-15 19:31:51 -0800 | [diff] [blame] | 39 | #include "upb/decode.h" |
Joshua Haberman | a60e9a3 | 2022-05-13 17:32:17 -0700 | [diff] [blame] | 40 | #include "upb/internal/vsnprintf_compat.h" |
Joshua Haberman | 60d0966 | 2020-02-10 09:44:07 -0800 | [diff] [blame] | 41 | #include "upb/reflection.h" |
Joshua Haberman | bc7b5dc | 2022-01-17 13:32:37 -0800 | [diff] [blame] | 42 | #include "upb/upb_internal.h" |
Joshua Haberman | 60d0966 | 2020-02-10 09:44:07 -0800 | [diff] [blame] | 43 | |
Joshua Haberman | 8f3ee80 | 2020-10-28 16:23:20 -0700 | [diff] [blame] | 44 | /* Must be last. */ |
Joshua Haberman | 6e9db7d | 2020-02-15 19:31:51 -0800 | [diff] [blame] | 45 | #include "upb/port_def.inc" |
| 46 | |
Joshua Haberman | 60d0966 | 2020-02-10 09:44:07 -0800 | [diff] [blame] | 47 | typedef struct { |
| 48 | char *buf, *ptr, *end; |
| 49 | size_t overflow; |
| 50 | int indent_depth; |
| 51 | int options; |
Joshua Haberman | 1c955f3 | 2022-01-12 07:19:28 -0800 | [diff] [blame] | 52 | const upb_DefPool* ext_pool; |
Joshua Haberman | 6e9db7d | 2020-02-15 19:31:51 -0800 | [diff] [blame] | 53 | jmp_buf err; |
Joshua Haberman | 1c955f3 | 2022-01-12 07:19:28 -0800 | [diff] [blame] | 54 | upb_Status* status; |
| 55 | upb_Arena* arena; |
Joshua Haberman | 60d0966 | 2020-02-10 09:44:07 -0800 | [diff] [blame] | 56 | } jsonenc; |
| 57 | |
Joshua Haberman | 499c2cc | 2022-01-12 09:09:59 -0800 | [diff] [blame] | 58 | static void jsonenc_msg(jsonenc* e, const upb_Message* msg, |
Joshua Haberman | 1c955f3 | 2022-01-12 07:19:28 -0800 | [diff] [blame] | 59 | const upb_MessageDef* m); |
| 60 | static void jsonenc_scalar(jsonenc* e, upb_MessageValue val, |
| 61 | const upb_FieldDef* f); |
Joshua Haberman | 499c2cc | 2022-01-12 09:09:59 -0800 | [diff] [blame] | 62 | static void jsonenc_msgfield(jsonenc* e, const upb_Message* msg, |
Joshua Haberman | 1c955f3 | 2022-01-12 07:19:28 -0800 | [diff] [blame] | 63 | const upb_MessageDef* m); |
Joshua Haberman | 499c2cc | 2022-01-12 09:09:59 -0800 | [diff] [blame] | 64 | static void jsonenc_msgfields(jsonenc* e, const upb_Message* msg, |
Joshua Haberman | 1c955f3 | 2022-01-12 07:19:28 -0800 | [diff] [blame] | 65 | const upb_MessageDef* m, bool first); |
Joshua Haberman | 499c2cc | 2022-01-12 09:09:59 -0800 | [diff] [blame] | 66 | static void jsonenc_value(jsonenc* e, const upb_Message* msg, |
Joshua Haberman | 1c955f3 | 2022-01-12 07:19:28 -0800 | [diff] [blame] | 67 | const upb_MessageDef* m); |
Joshua Haberman | 6e9db7d | 2020-02-15 19:31:51 -0800 | [diff] [blame] | 68 | |
Joshua Haberman | 1c955f3 | 2022-01-12 07:19:28 -0800 | [diff] [blame] | 69 | UPB_NORETURN static void jsonenc_err(jsonenc* e, const char* msg) { |
| 70 | upb_Status_SetErrorMessage(e->status, msg); |
Joshua Haberman | 6e9db7d | 2020-02-15 19:31:51 -0800 | [diff] [blame] | 71 | longjmp(e->err, 1); |
| 72 | } |
Joshua Haberman | 60d0966 | 2020-02-10 09:44:07 -0800 | [diff] [blame] | 73 | |
Joshua Haberman | c7787cb | 2021-01-10 09:17:52 -0800 | [diff] [blame] | 74 | UPB_PRINTF(2, 3) |
Joshua Haberman | 1c955f3 | 2022-01-12 07:19:28 -0800 | [diff] [blame] | 75 | UPB_NORETURN static void jsonenc_errf(jsonenc* e, const char* fmt, ...) { |
Joshua Haberman | 81c2aa7 | 2020-06-11 12:42:17 -0700 | [diff] [blame] | 76 | va_list argp; |
| 77 | va_start(argp, fmt); |
Joshua Haberman | 1c955f3 | 2022-01-12 07:19:28 -0800 | [diff] [blame] | 78 | upb_Status_VSetErrorFormat(e->status, fmt, argp); |
Joshua Haberman | 81c2aa7 | 2020-06-11 12:42:17 -0700 | [diff] [blame] | 79 | va_end(argp); |
| 80 | longjmp(e->err, 1); |
| 81 | } |
| 82 | |
Joshua Haberman | 1c955f3 | 2022-01-12 07:19:28 -0800 | [diff] [blame] | 83 | static upb_Arena* jsonenc_arena(jsonenc* e) { |
Joshua Haberman | a292261 | 2020-02-24 13:57:57 -0800 | [diff] [blame] | 84 | /* Create lazily, since it's only needed for Any */ |
| 85 | if (!e->arena) { |
Joshua Haberman | 1c955f3 | 2022-01-12 07:19:28 -0800 | [diff] [blame] | 86 | e->arena = upb_Arena_New(); |
Joshua Haberman | a292261 | 2020-02-24 13:57:57 -0800 | [diff] [blame] | 87 | } |
| 88 | return e->arena; |
| 89 | } |
| 90 | |
Joshua Haberman | 1c955f3 | 2022-01-12 07:19:28 -0800 | [diff] [blame] | 91 | static void jsonenc_putbytes(jsonenc* e, const void* data, size_t len) { |
Joshua Haberman | 60d0966 | 2020-02-10 09:44:07 -0800 | [diff] [blame] | 92 | 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 Haberman | 63ad3db | 2021-03-09 11:21:03 -0800 | [diff] [blame] | 97 | if (have) { |
| 98 | memcpy(e->ptr, data, have); |
| 99 | e->ptr += have; |
| 100 | } |
Joshua Haberman | 60d0966 | 2020-02-10 09:44:07 -0800 | [diff] [blame] | 101 | e->overflow += (len - have); |
| 102 | } |
| 103 | } |
| 104 | |
Joshua Haberman | 1c955f3 | 2022-01-12 07:19:28 -0800 | [diff] [blame] | 105 | static void jsonenc_putstr(jsonenc* e, const char* str) { |
Joshua Haberman | 60d0966 | 2020-02-10 09:44:07 -0800 | [diff] [blame] | 106 | jsonenc_putbytes(e, str, strlen(str)); |
| 107 | } |
| 108 | |
Joshua Haberman | c7787cb | 2021-01-10 09:17:52 -0800 | [diff] [blame] | 109 | UPB_PRINTF(2, 3) |
Joshua Haberman | 1c955f3 | 2022-01-12 07:19:28 -0800 | [diff] [blame] | 110 | static void jsonenc_printf(jsonenc* e, const char* fmt, ...) { |
Joshua Haberman | 60d0966 | 2020-02-10 09:44:07 -0800 | [diff] [blame] | 111 | size_t n; |
| 112 | size_t have = e->end - e->ptr; |
| 113 | va_list args; |
| 114 | |
| 115 | va_start(args, fmt); |
Joshua Haberman | a60e9a3 | 2022-05-13 17:32:17 -0700 | [diff] [blame] | 116 | n = _upb_vsnprintf(e->ptr, have, fmt, args); |
Joshua Haberman | 60d0966 | 2020-02-10 09:44:07 -0800 | [diff] [blame] | 117 | va_end(args); |
| 118 | |
| 119 | if (UPB_LIKELY(have > n)) { |
| 120 | e->ptr += n; |
| 121 | } else { |
Joshua Haberman | 8370818 | 2021-03-09 14:44:35 -0800 | [diff] [blame] | 122 | e->ptr = UPB_PTRADD(e->ptr, have); |
Joshua Haberman | 60d0966 | 2020-02-10 09:44:07 -0800 | [diff] [blame] | 123 | e->overflow += (n - have); |
| 124 | } |
| 125 | } |
| 126 | |
Joshua Haberman | 1c955f3 | 2022-01-12 07:19:28 -0800 | [diff] [blame] | 127 | static void jsonenc_nanos(jsonenc* e, int32_t nanos) { |
Joshua Haberman | a292261 | 2020-02-24 13:57:57 -0800 | [diff] [blame] | 128 | int digits = 9; |
Joshua Haberman | 60d0966 | 2020-02-10 09:44:07 -0800 | [diff] [blame] | 129 | |
| 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 Haberman | a292261 | 2020-02-24 13:57:57 -0800 | [diff] [blame] | 135 | while (nanos % 1000 == 0) { |
| 136 | nanos /= 1000; |
| 137 | digits -= 3; |
Joshua Haberman | 60d0966 | 2020-02-10 09:44:07 -0800 | [diff] [blame] | 138 | } |
Joshua Haberman | a292261 | 2020-02-24 13:57:57 -0800 | [diff] [blame] | 139 | |
Joshua Haberman | c7787cb | 2021-01-10 09:17:52 -0800 | [diff] [blame] | 140 | jsonenc_printf(e, ".%.*" PRId32, digits, nanos); |
Joshua Haberman | 60d0966 | 2020-02-10 09:44:07 -0800 | [diff] [blame] | 141 | } |
| 142 | |
Joshua Haberman | 499c2cc | 2022-01-12 09:09:59 -0800 | [diff] [blame] | 143 | static void jsonenc_timestamp(jsonenc* e, const upb_Message* msg, |
Joshua Haberman | 1c955f3 | 2022-01-12 07:19:28 -0800 | [diff] [blame] | 144 | const upb_MessageDef* m) { |
Joshua Haberman | c56fe27 | 2022-02-22 20:32:56 -0800 | [diff] [blame] | 145 | const upb_FieldDef* seconds_f = upb_MessageDef_FindFieldByNumber(m, 1); |
| 146 | const upb_FieldDef* nanos_f = upb_MessageDef_FindFieldByNumber(m, 2); |
Joshua Haberman | 1c955f3 | 2022-01-12 07:19:28 -0800 | [diff] [blame] | 147 | int64_t seconds = upb_Message_Get(msg, seconds_f).int64_val; |
| 148 | int32_t nanos = upb_Message_Get(msg, nanos_f).int32_val; |
Joshua Haberman | 6e9db7d | 2020-02-15 19:31:51 -0800 | [diff] [blame] | 149 | int L, N, I, J, K, hour, min, sec; |
Joshua Haberman | 60d0966 | 2020-02-10 09:44:07 -0800 | [diff] [blame] | 150 | |
| 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 Haberman | be7dfeb | 2022-02-05 19:55:17 -0800 | [diff] [blame] | 165 | seconds += 62135596800; // Ensure seconds is positive. |
Bernardo Bruning | 4a3a7d9 | 2022-01-26 22:15:23 -0300 | [diff] [blame] | 166 | L = (int)(seconds / 86400) - 719162 + 68569 + 2440588; |
Joshua Haberman | 60d0966 | 2020-02-10 09:44:07 -0800 | [diff] [blame] | 167 | 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 Bruning | 6475a96 | 2022-01-25 17:02:17 -0300 | [diff] [blame] | 177 | sec = seconds % 60; |
| 178 | min = (seconds / 60) % 60; |
| 179 | hour = (seconds / 3600) % 24; |
Joshua Haberman | 60d0966 | 2020-02-10 09:44:07 -0800 | [diff] [blame] | 180 | |
Joshua Haberman | 6e9db7d | 2020-02-15 19:31:51 -0800 | [diff] [blame] | 181 | jsonenc_printf(e, "\"%04d-%02d-%02dT%02d:%02d:%02d", I, J, K, hour, min, sec); |
| 182 | jsonenc_nanos(e, nanos); |
Joshua Haberman | 60d0966 | 2020-02-10 09:44:07 -0800 | [diff] [blame] | 183 | jsonenc_putstr(e, "Z\""); |
| 184 | } |
| 185 | |
Joshua Haberman | 499c2cc | 2022-01-12 09:09:59 -0800 | [diff] [blame] | 186 | static void jsonenc_duration(jsonenc* e, const upb_Message* msg, |
Joshua Haberman | 1c955f3 | 2022-01-12 07:19:28 -0800 | [diff] [blame] | 187 | const upb_MessageDef* m) { |
Joshua Haberman | c56fe27 | 2022-02-22 20:32:56 -0800 | [diff] [blame] | 188 | const upb_FieldDef* seconds_f = upb_MessageDef_FindFieldByNumber(m, 1); |
| 189 | const upb_FieldDef* nanos_f = upb_MessageDef_FindFieldByNumber(m, 2); |
Joshua Haberman | 1c955f3 | 2022-01-12 07:19:28 -0800 | [diff] [blame] | 190 | int64_t seconds = upb_Message_Get(msg, seconds_f).int64_val; |
| 191 | int32_t nanos = upb_Message_Get(msg, nanos_f).int32_val; |
Joshua Haberman | 60d0966 | 2020-02-10 09:44:07 -0800 | [diff] [blame] | 192 | |
| 193 | if (seconds > 315576000000 || seconds < -315576000000 || |
| 194 | (seconds < 0) != (nanos < 0)) { |
| 195 | jsonenc_err(e, "bad duration"); |
| 196 | } |
| 197 | |
Joshua Haberman | a292261 | 2020-02-24 13:57:57 -0800 | [diff] [blame] | 198 | if (nanos < 0) { |
| 199 | nanos = -nanos; |
| 200 | } |
| 201 | |
Joshua Haberman | 60d0966 | 2020-02-10 09:44:07 -0800 | [diff] [blame] | 202 | jsonenc_printf(e, "\"%" PRId64, seconds); |
| 203 | jsonenc_nanos(e, nanos); |
| 204 | jsonenc_putstr(e, "s\""); |
| 205 | } |
| 206 | |
Joshua Haberman | 1c955f3 | 2022-01-12 07:19:28 -0800 | [diff] [blame] | 207 | static void jsonenc_enum(int32_t val, const upb_FieldDef* f, jsonenc* e) { |
| 208 | const upb_EnumDef* e_def = upb_FieldDef_EnumSubDef(f); |
Joshua Haberman | 60d0966 | 2020-02-10 09:44:07 -0800 | [diff] [blame] | 209 | |
Joshua Haberman | 1c955f3 | 2022-01-12 07:19:28 -0800 | [diff] [blame] | 210 | if (strcmp(upb_EnumDef_FullName(e_def), "google.protobuf.NullValue") == 0) { |
Joshua Haberman | 0a3a94a | 2020-10-12 15:31:13 -0700 | [diff] [blame] | 211 | jsonenc_putstr(e, "null"); |
Joshua Haberman | 60d0966 | 2020-02-10 09:44:07 -0800 | [diff] [blame] | 212 | } else { |
Protobuf Team Bot | 6e1aa9f | 2022-06-08 11:17:20 -0700 | [diff] [blame] | 213 | const upb_EnumValueDef* ev = |
| 214 | (e->options & upb_JsonEncode_FormatEnumsAsIntegers) |
| 215 | ? NULL |
| 216 | : upb_EnumDef_FindValueByNumber(e_def, val); |
Joshua Haberman | 0a3a94a | 2020-10-12 15:31:13 -0700 | [diff] [blame] | 217 | |
Joshua Haberman | 5c28ab6 | 2021-08-27 17:12:54 -0700 | [diff] [blame] | 218 | if (ev) { |
Joshua Haberman | 1c955f3 | 2022-01-12 07:19:28 -0800 | [diff] [blame] | 219 | jsonenc_printf(e, "\"%s\"", upb_EnumValueDef_Name(ev)); |
Joshua Haberman | 0a3a94a | 2020-10-12 15:31:13 -0700 | [diff] [blame] | 220 | } else { |
| 221 | jsonenc_printf(e, "%" PRId32, val); |
| 222 | } |
Joshua Haberman | 60d0966 | 2020-02-10 09:44:07 -0800 | [diff] [blame] | 223 | } |
| 224 | } |
| 225 | |
Joshua Haberman | 1c955f3 | 2022-01-12 07:19:28 -0800 | [diff] [blame] | 226 | static void jsonenc_bytes(jsonenc* e, upb_StringView str) { |
Joshua Haberman | 60d0966 | 2020-02-10 09:44:07 -0800 | [diff] [blame] | 227 | /* This is the regular base64, not the "web-safe" version. */ |
| 228 | static const char base64[] = |
| 229 | "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; |
Joshua Haberman | 1c955f3 | 2022-01-12 07:19:28 -0800 | [diff] [blame] | 230 | const unsigned char* ptr = (unsigned char*)str.data; |
| 231 | const unsigned char* end = UPB_PTRADD(ptr, str.size); |
Joshua Haberman | 60d0966 | 2020-02-10 09:44:07 -0800 | [diff] [blame] | 232 | char buf[4]; |
| 233 | |
Joshua Haberman | 6e9db7d | 2020-02-15 19:31:51 -0800 | [diff] [blame] | 234 | jsonenc_putstr(e, "\""); |
Joshua Haberman | 60d0966 | 2020-02-10 09:44:07 -0800 | [diff] [blame] | 235 | |
| 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 Haberman | 6e9db7d | 2020-02-15 19:31:51 -0800 | [diff] [blame] | 241 | jsonenc_putbytes(e, buf, 4); |
Joshua Haberman | 60d0966 | 2020-02-10 09:44:07 -0800 | [diff] [blame] | 242 | ptr += 3; |
| 243 | } |
| 244 | |
| 245 | switch (end - ptr) { |
| 246 | case 2: |
Joshua Haberman | 6e9db7d | 2020-02-15 19:31:51 -0800 | [diff] [blame] | 247 | 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 Haberman | 60d0966 | 2020-02-10 09:44:07 -0800 | [diff] [blame] | 250 | buf[3] = '='; |
Joshua Haberman | 6e9db7d | 2020-02-15 19:31:51 -0800 | [diff] [blame] | 251 | jsonenc_putbytes(e, buf, 4); |
Joshua Haberman | 60d0966 | 2020-02-10 09:44:07 -0800 | [diff] [blame] | 252 | break; |
| 253 | case 1: |
Joshua Haberman | 6e9db7d | 2020-02-15 19:31:51 -0800 | [diff] [blame] | 254 | buf[0] = base64[ptr[0] >> 2]; |
| 255 | buf[1] = base64[((ptr[0] & 0x3) << 4)]; |
Joshua Haberman | 60d0966 | 2020-02-10 09:44:07 -0800 | [diff] [blame] | 256 | buf[2] = '='; |
| 257 | buf[3] = '='; |
Joshua Haberman | 6e9db7d | 2020-02-15 19:31:51 -0800 | [diff] [blame] | 258 | jsonenc_putbytes(e, buf, 4); |
Joshua Haberman | 60d0966 | 2020-02-10 09:44:07 -0800 | [diff] [blame] | 259 | break; |
| 260 | } |
| 261 | |
Joshua Haberman | 6e9db7d | 2020-02-15 19:31:51 -0800 | [diff] [blame] | 262 | jsonenc_putstr(e, "\""); |
Joshua Haberman | 60d0966 | 2020-02-10 09:44:07 -0800 | [diff] [blame] | 263 | } |
| 264 | |
Joshua Haberman | 1c955f3 | 2022-01-12 07:19:28 -0800 | [diff] [blame] | 265 | static void jsonenc_stringbody(jsonenc* e, upb_StringView str) { |
| 266 | const char* ptr = str.data; |
| 267 | const char* end = UPB_PTRADD(ptr, str.size); |
Joshua Haberman | 60d0966 | 2020-02-10 09:44:07 -0800 | [diff] [blame] | 268 | |
| 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 Haberman | a292261 | 2020-02-24 13:57:57 -0800 | [diff] [blame] | 284 | jsonenc_putstr(e, "\\f"); |
Joshua Haberman | 60d0966 | 2020-02-10 09:44:07 -0800 | [diff] [blame] | 285 | break; |
| 286 | case '\b': |
Joshua Haberman | a292261 | 2020-02-24 13:57:57 -0800 | [diff] [blame] | 287 | jsonenc_putstr(e, "\\b"); |
Joshua Haberman | 60d0966 | 2020-02-10 09:44:07 -0800 | [diff] [blame] | 288 | 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 Haberman | 6e9db7d | 2020-02-15 19:31:51 -0800 | [diff] [blame] | 298 | jsonenc_putbytes(e, ptr, 1); |
Joshua Haberman | 60d0966 | 2020-02-10 09:44:07 -0800 | [diff] [blame] | 299 | } |
| 300 | break; |
| 301 | } |
| 302 | ptr++; |
| 303 | } |
Joshua Haberman | 6e9db7d | 2020-02-15 19:31:51 -0800 | [diff] [blame] | 304 | } |
Joshua Haberman | 60d0966 | 2020-02-10 09:44:07 -0800 | [diff] [blame] | 305 | |
Joshua Haberman | 1c955f3 | 2022-01-12 07:19:28 -0800 | [diff] [blame] | 306 | static void jsonenc_string(jsonenc* e, upb_StringView str) { |
Joshua Haberman | 6e9db7d | 2020-02-15 19:31:51 -0800 | [diff] [blame] | 307 | jsonenc_putstr(e, "\""); |
| 308 | jsonenc_stringbody(e, str); |
Joshua Haberman | 60d0966 | 2020-02-10 09:44:07 -0800 | [diff] [blame] | 309 | jsonenc_putstr(e, "\""); |
| 310 | } |
| 311 | |
Joshua Haberman | bc7b5dc | 2022-01-17 13:32:37 -0800 | [diff] [blame] | 312 | static bool upb_JsonEncode_HandleSpecialDoubles(jsonenc* e, double val) { |
Joshua Haberman | 8f3ee80 | 2020-10-28 16:23:20 -0700 | [diff] [blame] | 313 | if (val == INFINITY) { |
Joshua Haberman | 6e9db7d | 2020-02-15 19:31:51 -0800 | [diff] [blame] | 314 | jsonenc_putstr(e, "\"Infinity\""); |
Joshua Haberman | 8f3ee80 | 2020-10-28 16:23:20 -0700 | [diff] [blame] | 315 | } else if (val == -INFINITY) { |
Joshua Haberman | 6e9db7d | 2020-02-15 19:31:51 -0800 | [diff] [blame] | 316 | jsonenc_putstr(e, "\"-Infinity\""); |
Joshua Haberman | 384cf15 | 2020-02-15 22:07:24 -0800 | [diff] [blame] | 317 | } else if (val != val) { |
| 318 | jsonenc_putstr(e, "\"NaN\""); |
Joshua Haberman | 6e9db7d | 2020-02-15 19:31:51 -0800 | [diff] [blame] | 319 | } else { |
Joshua Haberman | bc7b5dc | 2022-01-17 13:32:37 -0800 | [diff] [blame] | 320 | return false; |
Joshua Haberman | 60d0966 | 2020-02-10 09:44:07 -0800 | [diff] [blame] | 321 | } |
Joshua Haberman | bc7b5dc | 2022-01-17 13:32:37 -0800 | [diff] [blame] | 322 | return true; |
| 323 | } |
| 324 | |
| 325 | static 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 | |
| 332 | static 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 Haberman | 60d0966 | 2020-02-10 09:44:07 -0800 | [diff] [blame] | 337 | } |
| 338 | |
Joshua Haberman | 499c2cc | 2022-01-12 09:09:59 -0800 | [diff] [blame] | 339 | static void jsonenc_wrapper(jsonenc* e, const upb_Message* msg, |
Joshua Haberman | 1c955f3 | 2022-01-12 07:19:28 -0800 | [diff] [blame] | 340 | const upb_MessageDef* m) { |
Joshua Haberman | c56fe27 | 2022-02-22 20:32:56 -0800 | [diff] [blame] | 341 | const upb_FieldDef* val_f = upb_MessageDef_FindFieldByNumber(m, 1); |
Joshua Haberman | 1c955f3 | 2022-01-12 07:19:28 -0800 | [diff] [blame] | 342 | upb_MessageValue val = upb_Message_Get(msg, val_f); |
Joshua Haberman | 6e9db7d | 2020-02-15 19:31:51 -0800 | [diff] [blame] | 343 | jsonenc_scalar(e, val, val_f); |
Joshua Haberman | 60d0966 | 2020-02-10 09:44:07 -0800 | [diff] [blame] | 344 | } |
| 345 | |
Joshua Haberman | 1c955f3 | 2022-01-12 07:19:28 -0800 | [diff] [blame] | 346 | static const upb_MessageDef* jsonenc_getanymsg(jsonenc* e, |
| 347 | upb_StringView type_url) { |
Joshua Haberman | 384cf15 | 2020-02-15 22:07:24 -0800 | [diff] [blame] | 348 | /* Find last '/', if any. */ |
Joshua Haberman | 1c955f3 | 2022-01-12 07:19:28 -0800 | [diff] [blame] | 349 | const char* end = type_url.data + type_url.size; |
| 350 | const char* ptr = end; |
| 351 | const upb_MessageDef* ret; |
Joshua Haberman | 384cf15 | 2020-02-15 22:07:24 -0800 | [diff] [blame] | 352 | |
Joshua Haberman | 81c2aa7 | 2020-06-11 12:42:17 -0700 | [diff] [blame] | 353 | 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 Haberman | 384cf15 | 2020-02-15 22:07:24 -0800 | [diff] [blame] | 358 | |
| 359 | while (true) { |
| 360 | if (--ptr == type_url.data) { |
| 361 | /* Type URL must contain at least one '/', with host before. */ |
Joshua Haberman | a292261 | 2020-02-24 13:57:57 -0800 | [diff] [blame] | 362 | goto badurl; |
Joshua Haberman | 384cf15 | 2020-02-15 22:07:24 -0800 | [diff] [blame] | 363 | } |
| 364 | if (*ptr == '/') { |
| 365 | ptr++; |
| 366 | break; |
| 367 | } |
| 368 | } |
| 369 | |
Joshua Haberman | 1c955f3 | 2022-01-12 07:19:28 -0800 | [diff] [blame] | 370 | ret = upb_DefPool_FindMessageByNameWithSize(e->ext_pool, ptr, end - ptr); |
Joshua Haberman | a292261 | 2020-02-24 13:57:57 -0800 | [diff] [blame] | 371 | |
| 372 | if (!ret) { |
Joshua Haberman | efe11c6 | 2020-06-11 13:01:51 -0700 | [diff] [blame] | 373 | jsonenc_errf(e, "Couldn't find Any type: %.*s", (int)(end - ptr), ptr); |
Joshua Haberman | a292261 | 2020-02-24 13:57:57 -0800 | [diff] [blame] | 374 | } |
| 375 | |
| 376 | return ret; |
| 377 | |
| 378 | badurl: |
Joshua Haberman | 1c955f3 | 2022-01-12 07:19:28 -0800 | [diff] [blame] | 379 | jsonenc_errf(e, "Bad type URL: " UPB_STRINGVIEW_FORMAT, |
| 380 | UPB_STRINGVIEW_ARGS(type_url)); |
Joshua Haberman | 384cf15 | 2020-02-15 22:07:24 -0800 | [diff] [blame] | 381 | } |
| 382 | |
Joshua Haberman | 499c2cc | 2022-01-12 09:09:59 -0800 | [diff] [blame] | 383 | static void jsonenc_any(jsonenc* e, const upb_Message* msg, |
Joshua Haberman | 1c955f3 | 2022-01-12 07:19:28 -0800 | [diff] [blame] | 384 | const upb_MessageDef* m) { |
Joshua Haberman | c56fe27 | 2022-02-22 20:32:56 -0800 | [diff] [blame] | 385 | const upb_FieldDef* type_url_f = upb_MessageDef_FindFieldByNumber(m, 1); |
| 386 | const upb_FieldDef* value_f = upb_MessageDef_FindFieldByNumber(m, 2); |
Joshua Haberman | 1c955f3 | 2022-01-12 07:19:28 -0800 | [diff] [blame] | 387 | 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 Haberman | 499c2cc | 2022-01-12 09:09:59 -0800 | [diff] [blame] | 392 | upb_Message* any = upb_Message_New(any_m, arena); |
Joshua Haberman | 60d0966 | 2020-02-10 09:44:07 -0800 | [diff] [blame] | 393 | |
Joshua Haberman | 72af9dc | 2022-01-12 10:04:02 -0800 | [diff] [blame] | 394 | if (upb_Decode(value.data, value.size, any, any_layout, NULL, 0, arena) != |
Joshua Haberman | 58c1dbc | 2021-10-13 23:03:47 -0700 | [diff] [blame] | 395 | kUpb_DecodeStatus_Ok) { |
Joshua Haberman | 6e9db7d | 2020-02-15 19:31:51 -0800 | [diff] [blame] | 396 | jsonenc_err(e, "Error decoding message in Any"); |
Joshua Haberman | 60d0966 | 2020-02-10 09:44:07 -0800 | [diff] [blame] | 397 | } |
| 398 | |
Joshua Haberman | 543a0ce | 2020-05-26 22:30:50 -0700 | [diff] [blame] | 399 | jsonenc_putstr(e, "{\"@type\":"); |
Joshua Haberman | 60d0966 | 2020-02-10 09:44:07 -0800 | [diff] [blame] | 400 | jsonenc_string(e, type_url); |
Joshua Haberman | 60d0966 | 2020-02-10 09:44:07 -0800 | [diff] [blame] | 401 | |
Joshua Haberman | 1c955f3 | 2022-01-12 07:19:28 -0800 | [diff] [blame] | 402 | if (upb_MessageDef_WellKnownType(any_m) == kUpb_WellKnown_Unspecified) { |
Joshua Haberman | 543a0ce | 2020-05-26 22:30:50 -0700 | [diff] [blame] | 403 | /* Regular messages: {"@type": "...","foo": 1, "bar": 2} */ |
Joshua Haberman | e58f7a0 | 2021-02-17 17:18:55 -0800 | [diff] [blame] | 404 | jsonenc_msgfields(e, any, any_m, false); |
Joshua Haberman | 60d0966 | 2020-02-10 09:44:07 -0800 | [diff] [blame] | 405 | } else { |
Joshua Haberman | 543a0ce | 2020-05-26 22:30:50 -0700 | [diff] [blame] | 406 | /* Well-known type: {"@type": "...","value": <well-known encoding>} */ |
Joshua Haberman | e58f7a0 | 2021-02-17 17:18:55 -0800 | [diff] [blame] | 407 | jsonenc_putstr(e, ",\"value\":"); |
Joshua Haberman | 60d0966 | 2020-02-10 09:44:07 -0800 | [diff] [blame] | 408 | jsonenc_msgfield(e, any, any_m); |
| 409 | } |
| 410 | |
| 411 | jsonenc_putstr(e, "}"); |
| 412 | } |
| 413 | |
Joshua Haberman | 1c955f3 | 2022-01-12 07:19:28 -0800 | [diff] [blame] | 414 | static void jsonenc_putsep(jsonenc* e, const char* str, bool* first) { |
Joshua Haberman | 60d0966 | 2020-02-10 09:44:07 -0800 | [diff] [blame] | 415 | if (*first) { |
| 416 | *first = false; |
| 417 | } else { |
Joshua Haberman | 384cf15 | 2020-02-15 22:07:24 -0800 | [diff] [blame] | 418 | jsonenc_putstr(e, str); |
Joshua Haberman | 60d0966 | 2020-02-10 09:44:07 -0800 | [diff] [blame] | 419 | } |
| 420 | } |
| 421 | |
Joshua Haberman | 1c955f3 | 2022-01-12 07:19:28 -0800 | [diff] [blame] | 422 | static void jsonenc_fieldpath(jsonenc* e, upb_StringView path) { |
| 423 | const char* ptr = path.data; |
| 424 | const char* end = ptr + path.size; |
Joshua Haberman | 384cf15 | 2020-02-15 22:07:24 -0800 | [diff] [blame] | 425 | |
| 426 | while (ptr < end) { |
| 427 | char ch = *ptr; |
Joshua Haberman | 23a5af3 | 2020-02-25 19:13:27 -0800 | [diff] [blame] | 428 | |
Joshua Haberman | 384cf15 | 2020-02-15 22:07:24 -0800 | [diff] [blame] | 429 | 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 Haberman | 23a5af3 | 2020-02-25 19:13:27 -0800 | [diff] [blame] | 435 | ch = *++ptr - 32; |
Joshua Haberman | 384cf15 | 2020-02-15 22:07:24 -0800 | [diff] [blame] | 436 | } |
Joshua Haberman | 23a5af3 | 2020-02-25 19:13:27 -0800 | [diff] [blame] | 437 | |
| 438 | jsonenc_putbytes(e, &ch, 1); |
Joshua Haberman | 384cf15 | 2020-02-15 22:07:24 -0800 | [diff] [blame] | 439 | ptr++; |
| 440 | } |
| 441 | } |
| 442 | |
Joshua Haberman | 499c2cc | 2022-01-12 09:09:59 -0800 | [diff] [blame] | 443 | static void jsonenc_fieldmask(jsonenc* e, const upb_Message* msg, |
Joshua Haberman | 1c955f3 | 2022-01-12 07:19:28 -0800 | [diff] [blame] | 444 | const upb_MessageDef* m) { |
Joshua Haberman | c56fe27 | 2022-02-22 20:32:56 -0800 | [diff] [blame] | 445 | const upb_FieldDef* paths_f = upb_MessageDef_FindFieldByNumber(m, 1); |
Joshua Haberman | 1c955f3 | 2022-01-12 07:19:28 -0800 | [diff] [blame] | 446 | const upb_Array* paths = upb_Message_Get(msg, paths_f).array_val; |
Joshua Haberman | 384cf15 | 2020-02-15 22:07:24 -0800 | [diff] [blame] | 447 | bool first = true; |
| 448 | size_t i, n = 0; |
| 449 | |
Joshua Haberman | 1c955f3 | 2022-01-12 07:19:28 -0800 | [diff] [blame] | 450 | if (paths) n = upb_Array_Size(paths); |
Joshua Haberman | 384cf15 | 2020-02-15 22:07:24 -0800 | [diff] [blame] | 451 | |
| 452 | jsonenc_putstr(e, "\""); |
| 453 | |
| 454 | for (i = 0; i < n; i++) { |
| 455 | jsonenc_putsep(e, ",", &first); |
Joshua Haberman | 1c955f3 | 2022-01-12 07:19:28 -0800 | [diff] [blame] | 456 | jsonenc_fieldpath(e, upb_Array_Get(paths, i).str_val); |
Joshua Haberman | 384cf15 | 2020-02-15 22:07:24 -0800 | [diff] [blame] | 457 | } |
| 458 | |
| 459 | jsonenc_putstr(e, "\""); |
| 460 | } |
| 461 | |
Joshua Haberman | 499c2cc | 2022-01-12 09:09:59 -0800 | [diff] [blame] | 462 | static void jsonenc_struct(jsonenc* e, const upb_Message* msg, |
Joshua Haberman | 1c955f3 | 2022-01-12 07:19:28 -0800 | [diff] [blame] | 463 | const upb_MessageDef* m) { |
Joshua Haberman | c56fe27 | 2022-02-22 20:32:56 -0800 | [diff] [blame] | 464 | const upb_FieldDef* fields_f = upb_MessageDef_FindFieldByNumber(m, 1); |
Joshua Haberman | 1c955f3 | 2022-01-12 07:19:28 -0800 | [diff] [blame] | 465 | const upb_Map* fields = upb_Message_Get(msg, fields_f).map_val; |
| 466 | const upb_MessageDef* entry_m = upb_FieldDef_MessageSubDef(fields_f); |
Joshua Haberman | c56fe27 | 2022-02-22 20:32:56 -0800 | [diff] [blame] | 467 | const upb_FieldDef* value_f = upb_MessageDef_FindFieldByNumber(entry_m, 2); |
Joshua Haberman | 1c955f3 | 2022-01-12 07:19:28 -0800 | [diff] [blame] | 468 | size_t iter = kUpb_Map_Begin; |
Joshua Haberman | 60d0966 | 2020-02-10 09:44:07 -0800 | [diff] [blame] | 469 | bool first = true; |
| 470 | |
| 471 | jsonenc_putstr(e, "{"); |
| 472 | |
Joshua Haberman | 543a0ce | 2020-05-26 22:30:50 -0700 | [diff] [blame] | 473 | if (fields) { |
Joshua Haberman | 1c955f3 | 2022-01-12 07:19:28 -0800 | [diff] [blame] | 474 | 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 Haberman | 60d0966 | 2020-02-10 09:44:07 -0800 | [diff] [blame] | 477 | |
Joshua Haberman | 543a0ce | 2020-05-26 22:30:50 -0700 | [diff] [blame] | 478 | jsonenc_putsep(e, ",", &first); |
| 479 | jsonenc_string(e, key.str_val); |
| 480 | jsonenc_putstr(e, ":"); |
Joshua Haberman | 1c955f3 | 2022-01-12 07:19:28 -0800 | [diff] [blame] | 481 | jsonenc_value(e, val.msg_val, upb_FieldDef_MessageSubDef(value_f)); |
Joshua Haberman | 543a0ce | 2020-05-26 22:30:50 -0700 | [diff] [blame] | 482 | } |
Joshua Haberman | 60d0966 | 2020-02-10 09:44:07 -0800 | [diff] [blame] | 483 | } |
| 484 | |
| 485 | jsonenc_putstr(e, "}"); |
| 486 | } |
| 487 | |
Joshua Haberman | 499c2cc | 2022-01-12 09:09:59 -0800 | [diff] [blame] | 488 | static void jsonenc_listvalue(jsonenc* e, const upb_Message* msg, |
Joshua Haberman | 1c955f3 | 2022-01-12 07:19:28 -0800 | [diff] [blame] | 489 | const upb_MessageDef* m) { |
Joshua Haberman | c56fe27 | 2022-02-22 20:32:56 -0800 | [diff] [blame] | 490 | const upb_FieldDef* values_f = upb_MessageDef_FindFieldByNumber(m, 1); |
Joshua Haberman | 1c955f3 | 2022-01-12 07:19:28 -0800 | [diff] [blame] | 491 | const upb_MessageDef* values_m = upb_FieldDef_MessageSubDef(values_f); |
| 492 | const upb_Array* values = upb_Message_Get(msg, values_f).array_val; |
Joshua Haberman | 6e9db7d | 2020-02-15 19:31:51 -0800 | [diff] [blame] | 493 | size_t i; |
Joshua Haberman | 60d0966 | 2020-02-10 09:44:07 -0800 | [diff] [blame] | 494 | bool first = true; |
| 495 | |
| 496 | jsonenc_putstr(e, "["); |
| 497 | |
Joshua Haberman | 543a0ce | 2020-05-26 22:30:50 -0700 | [diff] [blame] | 498 | if (values) { |
Joshua Haberman | 1c955f3 | 2022-01-12 07:19:28 -0800 | [diff] [blame] | 499 | const size_t size = upb_Array_Size(values); |
Joshua Haberman | 543a0ce | 2020-05-26 22:30:50 -0700 | [diff] [blame] | 500 | for (i = 0; i < size; i++) { |
Joshua Haberman | 1c955f3 | 2022-01-12 07:19:28 -0800 | [diff] [blame] | 501 | upb_MessageValue elem = upb_Array_Get(values, i); |
Joshua Haberman | 60d0966 | 2020-02-10 09:44:07 -0800 | [diff] [blame] | 502 | |
Joshua Haberman | 543a0ce | 2020-05-26 22:30:50 -0700 | [diff] [blame] | 503 | jsonenc_putsep(e, ",", &first); |
| 504 | jsonenc_value(e, elem.msg_val, values_m); |
| 505 | } |
Joshua Haberman | 60d0966 | 2020-02-10 09:44:07 -0800 | [diff] [blame] | 506 | } |
| 507 | |
| 508 | jsonenc_putstr(e, "]"); |
| 509 | } |
| 510 | |
Joshua Haberman | 499c2cc | 2022-01-12 09:09:59 -0800 | [diff] [blame] | 511 | static void jsonenc_value(jsonenc* e, const upb_Message* msg, |
Joshua Haberman | 1c955f3 | 2022-01-12 07:19:28 -0800 | [diff] [blame] | 512 | const upb_MessageDef* m) { |
Joshua Haberman | 60d0966 | 2020-02-10 09:44:07 -0800 | [diff] [blame] | 513 | /* TODO(haberman): do we want a reflection method to get oneof case? */ |
Joshua Haberman | 1c955f3 | 2022-01-12 07:19:28 -0800 | [diff] [blame] | 514 | size_t iter = kUpb_Message_Begin; |
| 515 | const upb_FieldDef* f; |
| 516 | upb_MessageValue val; |
Joshua Haberman | 60d0966 | 2020-02-10 09:44:07 -0800 | [diff] [blame] | 517 | |
Joshua Haberman | 1c955f3 | 2022-01-12 07:19:28 -0800 | [diff] [blame] | 518 | if (!upb_Message_Next(msg, m, NULL, &f, &val, &iter)) { |
Joshua Haberman | 60d0966 | 2020-02-10 09:44:07 -0800 | [diff] [blame] | 519 | jsonenc_err(e, "No value set in Value proto"); |
| 520 | } |
| 521 | |
Joshua Haberman | 1c955f3 | 2022-01-12 07:19:28 -0800 | [diff] [blame] | 522 | switch (upb_FieldDef_Number(f)) { |
Joshua Haberman | 60d0966 | 2020-02-10 09:44:07 -0800 | [diff] [blame] | 523 | case 1: |
Joshua Haberman | 6e9db7d | 2020-02-15 19:31:51 -0800 | [diff] [blame] | 524 | jsonenc_putstr(e, "null"); |
Joshua Haberman | 60d0966 | 2020-02-10 09:44:07 -0800 | [diff] [blame] | 525 | break; |
| 526 | case 2: |
Joshua Haberman | bc7b5dc | 2022-01-17 13:32:37 -0800 | [diff] [blame] | 527 | upb_JsonEncode_Double(e, val.double_val); |
Joshua Haberman | 60d0966 | 2020-02-10 09:44:07 -0800 | [diff] [blame] | 528 | 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 Haberman | 1c955f3 | 2022-01-12 07:19:28 -0800 | [diff] [blame] | 536 | jsonenc_struct(e, val.msg_val, upb_FieldDef_MessageSubDef(f)); |
Joshua Haberman | 60d0966 | 2020-02-10 09:44:07 -0800 | [diff] [blame] | 537 | break; |
| 538 | case 6: |
Joshua Haberman | 1c955f3 | 2022-01-12 07:19:28 -0800 | [diff] [blame] | 539 | jsonenc_listvalue(e, val.msg_val, upb_FieldDef_MessageSubDef(f)); |
Joshua Haberman | 60d0966 | 2020-02-10 09:44:07 -0800 | [diff] [blame] | 540 | break; |
| 541 | } |
| 542 | } |
| 543 | |
Joshua Haberman | 499c2cc | 2022-01-12 09:09:59 -0800 | [diff] [blame] | 544 | static void jsonenc_msgfield(jsonenc* e, const upb_Message* msg, |
Joshua Haberman | 1c955f3 | 2022-01-12 07:19:28 -0800 | [diff] [blame] | 545 | const upb_MessageDef* m) { |
| 546 | switch (upb_MessageDef_WellKnownType(m)) { |
| 547 | case kUpb_WellKnown_Unspecified: |
Joshua Haberman | 6e9db7d | 2020-02-15 19:31:51 -0800 | [diff] [blame] | 548 | jsonenc_msg(e, msg, m); |
Joshua Haberman | 60d0966 | 2020-02-10 09:44:07 -0800 | [diff] [blame] | 549 | break; |
Joshua Haberman | 1c955f3 | 2022-01-12 07:19:28 -0800 | [diff] [blame] | 550 | case kUpb_WellKnown_Any: |
Joshua Haberman | 60d0966 | 2020-02-10 09:44:07 -0800 | [diff] [blame] | 551 | jsonenc_any(e, msg, m); |
| 552 | break; |
Joshua Haberman | 1c955f3 | 2022-01-12 07:19:28 -0800 | [diff] [blame] | 553 | case kUpb_WellKnown_FieldMask: |
Joshua Haberman | 384cf15 | 2020-02-15 22:07:24 -0800 | [diff] [blame] | 554 | jsonenc_fieldmask(e, msg, m); |
| 555 | break; |
Joshua Haberman | 1c955f3 | 2022-01-12 07:19:28 -0800 | [diff] [blame] | 556 | case kUpb_WellKnown_Duration: |
Joshua Haberman | 60d0966 | 2020-02-10 09:44:07 -0800 | [diff] [blame] | 557 | jsonenc_duration(e, msg, m); |
| 558 | break; |
Joshua Haberman | 1c955f3 | 2022-01-12 07:19:28 -0800 | [diff] [blame] | 559 | case kUpb_WellKnown_Timestamp: |
Joshua Haberman | 60d0966 | 2020-02-10 09:44:07 -0800 | [diff] [blame] | 560 | jsonenc_timestamp(e, msg, m); |
| 561 | break; |
Joshua Haberman | 1c955f3 | 2022-01-12 07:19:28 -0800 | [diff] [blame] | 562 | 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 Haberman | 60d0966 | 2020-02-10 09:44:07 -0800 | [diff] [blame] | 571 | jsonenc_wrapper(e, msg, m); |
| 572 | break; |
Joshua Haberman | 1c955f3 | 2022-01-12 07:19:28 -0800 | [diff] [blame] | 573 | case kUpb_WellKnown_Value: |
Joshua Haberman | 60d0966 | 2020-02-10 09:44:07 -0800 | [diff] [blame] | 574 | jsonenc_value(e, msg, m); |
| 575 | break; |
Joshua Haberman | 1c955f3 | 2022-01-12 07:19:28 -0800 | [diff] [blame] | 576 | case kUpb_WellKnown_ListValue: |
Joshua Haberman | 60d0966 | 2020-02-10 09:44:07 -0800 | [diff] [blame] | 577 | jsonenc_listvalue(e, msg, m); |
| 578 | break; |
Joshua Haberman | 1c955f3 | 2022-01-12 07:19:28 -0800 | [diff] [blame] | 579 | case kUpb_WellKnown_Struct: |
Joshua Haberman | a292261 | 2020-02-24 13:57:57 -0800 | [diff] [blame] | 580 | jsonenc_struct(e, msg, m); |
Joshua Haberman | 60d0966 | 2020-02-10 09:44:07 -0800 | [diff] [blame] | 581 | break; |
| 582 | } |
| 583 | } |
| 584 | |
Joshua Haberman | 1c955f3 | 2022-01-12 07:19:28 -0800 | [diff] [blame] | 585 | static 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 Haberman | 60d0966 | 2020-02-10 09:44:07 -0800 | [diff] [blame] | 589 | jsonenc_putstr(e, val.bool_val ? "true" : "false"); |
| 590 | break; |
Joshua Haberman | 1c955f3 | 2022-01-12 07:19:28 -0800 | [diff] [blame] | 591 | case kUpb_CType_Float: |
Joshua Haberman | bc7b5dc | 2022-01-17 13:32:37 -0800 | [diff] [blame] | 592 | upb_JsonEncode_Float(e, val.float_val); |
Joshua Haberman | 60d0966 | 2020-02-10 09:44:07 -0800 | [diff] [blame] | 593 | break; |
Joshua Haberman | 1c955f3 | 2022-01-12 07:19:28 -0800 | [diff] [blame] | 594 | case kUpb_CType_Double: |
Joshua Haberman | bc7b5dc | 2022-01-17 13:32:37 -0800 | [diff] [blame] | 595 | upb_JsonEncode_Double(e, val.double_val); |
Joshua Haberman | 60d0966 | 2020-02-10 09:44:07 -0800 | [diff] [blame] | 596 | break; |
Joshua Haberman | 1c955f3 | 2022-01-12 07:19:28 -0800 | [diff] [blame] | 597 | case kUpb_CType_Int32: |
Joshua Haberman | 60d0966 | 2020-02-10 09:44:07 -0800 | [diff] [blame] | 598 | jsonenc_printf(e, "%" PRId32, val.int32_val); |
| 599 | break; |
Joshua Haberman | 1c955f3 | 2022-01-12 07:19:28 -0800 | [diff] [blame] | 600 | case kUpb_CType_UInt32: |
Joshua Haberman | 60d0966 | 2020-02-10 09:44:07 -0800 | [diff] [blame] | 601 | jsonenc_printf(e, "%" PRIu32, val.uint32_val); |
| 602 | break; |
Joshua Haberman | 1c955f3 | 2022-01-12 07:19:28 -0800 | [diff] [blame] | 603 | case kUpb_CType_Int64: |
Joshua Haberman | 60d0966 | 2020-02-10 09:44:07 -0800 | [diff] [blame] | 604 | jsonenc_printf(e, "\"%" PRId64 "\"", val.int64_val); |
| 605 | break; |
Joshua Haberman | 1c955f3 | 2022-01-12 07:19:28 -0800 | [diff] [blame] | 606 | case kUpb_CType_UInt64: |
Joshua Haberman | 60d0966 | 2020-02-10 09:44:07 -0800 | [diff] [blame] | 607 | jsonenc_printf(e, "\"%" PRIu64 "\"", val.uint64_val); |
| 608 | break; |
Joshua Haberman | 1c955f3 | 2022-01-12 07:19:28 -0800 | [diff] [blame] | 609 | case kUpb_CType_String: |
Joshua Haberman | 60d0966 | 2020-02-10 09:44:07 -0800 | [diff] [blame] | 610 | jsonenc_string(e, val.str_val); |
| 611 | break; |
Joshua Haberman | 1c955f3 | 2022-01-12 07:19:28 -0800 | [diff] [blame] | 612 | case kUpb_CType_Bytes: |
Joshua Haberman | 60d0966 | 2020-02-10 09:44:07 -0800 | [diff] [blame] | 613 | jsonenc_bytes(e, val.str_val); |
| 614 | break; |
Joshua Haberman | 1c955f3 | 2022-01-12 07:19:28 -0800 | [diff] [blame] | 615 | case kUpb_CType_Enum: |
Joshua Haberman | 60d0966 | 2020-02-10 09:44:07 -0800 | [diff] [blame] | 616 | jsonenc_enum(val.int32_val, f, e); |
| 617 | break; |
Joshua Haberman | 1c955f3 | 2022-01-12 07:19:28 -0800 | [diff] [blame] | 618 | case kUpb_CType_Message: |
| 619 | jsonenc_msgfield(e, val.msg_val, upb_FieldDef_MessageSubDef(f)); |
Joshua Haberman | 60d0966 | 2020-02-10 09:44:07 -0800 | [diff] [blame] | 620 | break; |
| 621 | } |
| 622 | } |
| 623 | |
Joshua Haberman | 1c955f3 | 2022-01-12 07:19:28 -0800 | [diff] [blame] | 624 | static void jsonenc_mapkey(jsonenc* e, upb_MessageValue val, |
| 625 | const upb_FieldDef* f) { |
Joshua Haberman | 6e9db7d | 2020-02-15 19:31:51 -0800 | [diff] [blame] | 626 | jsonenc_putstr(e, "\""); |
Joshua Haberman | 60d0966 | 2020-02-10 09:44:07 -0800 | [diff] [blame] | 627 | |
Joshua Haberman | 1c955f3 | 2022-01-12 07:19:28 -0800 | [diff] [blame] | 628 | switch (upb_FieldDef_CType(f)) { |
| 629 | case kUpb_CType_Bool: |
Joshua Haberman | 60d0966 | 2020-02-10 09:44:07 -0800 | [diff] [blame] | 630 | jsonenc_putstr(e, val.bool_val ? "true" : "false"); |
| 631 | break; |
Joshua Haberman | 1c955f3 | 2022-01-12 07:19:28 -0800 | [diff] [blame] | 632 | case kUpb_CType_Int32: |
Joshua Haberman | 60d0966 | 2020-02-10 09:44:07 -0800 | [diff] [blame] | 633 | jsonenc_printf(e, "%" PRId32, val.int32_val); |
| 634 | break; |
Joshua Haberman | 1c955f3 | 2022-01-12 07:19:28 -0800 | [diff] [blame] | 635 | case kUpb_CType_UInt32: |
Joshua Haberman | 60d0966 | 2020-02-10 09:44:07 -0800 | [diff] [blame] | 636 | jsonenc_printf(e, "%" PRIu32, val.uint32_val); |
| 637 | break; |
Joshua Haberman | 1c955f3 | 2022-01-12 07:19:28 -0800 | [diff] [blame] | 638 | case kUpb_CType_Int64: |
Joshua Haberman | 60d0966 | 2020-02-10 09:44:07 -0800 | [diff] [blame] | 639 | jsonenc_printf(e, "%" PRId64, val.int64_val); |
| 640 | break; |
Joshua Haberman | 1c955f3 | 2022-01-12 07:19:28 -0800 | [diff] [blame] | 641 | case kUpb_CType_UInt64: |
Joshua Haberman | 60d0966 | 2020-02-10 09:44:07 -0800 | [diff] [blame] | 642 | jsonenc_printf(e, "%" PRIu64, val.uint64_val); |
| 643 | break; |
Joshua Haberman | 1c955f3 | 2022-01-12 07:19:28 -0800 | [diff] [blame] | 644 | case kUpb_CType_String: |
Joshua Haberman | 6e9db7d | 2020-02-15 19:31:51 -0800 | [diff] [blame] | 645 | jsonenc_stringbody(e, val.str_val); |
Joshua Haberman | a292261 | 2020-02-24 13:57:57 -0800 | [diff] [blame] | 646 | break; |
Joshua Haberman | 6e9db7d | 2020-02-15 19:31:51 -0800 | [diff] [blame] | 647 | default: |
| 648 | UPB_UNREACHABLE(); |
Joshua Haberman | 60d0966 | 2020-02-10 09:44:07 -0800 | [diff] [blame] | 649 | } |
| 650 | |
Joshua Haberman | 543a0ce | 2020-05-26 22:30:50 -0700 | [diff] [blame] | 651 | jsonenc_putstr(e, "\":"); |
Joshua Haberman | 60d0966 | 2020-02-10 09:44:07 -0800 | [diff] [blame] | 652 | } |
| 653 | |
Joshua Haberman | 1c955f3 | 2022-01-12 07:19:28 -0800 | [diff] [blame] | 654 | static void jsonenc_array(jsonenc* e, const upb_Array* arr, |
| 655 | const upb_FieldDef* f) { |
Joshua Haberman | 60d0966 | 2020-02-10 09:44:07 -0800 | [diff] [blame] | 656 | size_t i; |
Joshua Haberman | 1c955f3 | 2022-01-12 07:19:28 -0800 | [diff] [blame] | 657 | size_t size = arr ? upb_Array_Size(arr) : 0; |
Joshua Haberman | 60d0966 | 2020-02-10 09:44:07 -0800 | [diff] [blame] | 658 | bool first = true; |
| 659 | |
Joshua Haberman | 6e9db7d | 2020-02-15 19:31:51 -0800 | [diff] [blame] | 660 | jsonenc_putstr(e, "["); |
Joshua Haberman | 60d0966 | 2020-02-10 09:44:07 -0800 | [diff] [blame] | 661 | |
| 662 | for (i = 0; i < size; i++) { |
Joshua Haberman | 543a0ce | 2020-05-26 22:30:50 -0700 | [diff] [blame] | 663 | jsonenc_putsep(e, ",", &first); |
Joshua Haberman | 1c955f3 | 2022-01-12 07:19:28 -0800 | [diff] [blame] | 664 | jsonenc_scalar(e, upb_Array_Get(arr, i), f); |
Joshua Haberman | 60d0966 | 2020-02-10 09:44:07 -0800 | [diff] [blame] | 665 | } |
| 666 | |
Joshua Haberman | 6e9db7d | 2020-02-15 19:31:51 -0800 | [diff] [blame] | 667 | jsonenc_putstr(e, "]"); |
Joshua Haberman | 60d0966 | 2020-02-10 09:44:07 -0800 | [diff] [blame] | 668 | } |
| 669 | |
Joshua Haberman | 1c955f3 | 2022-01-12 07:19:28 -0800 | [diff] [blame] | 670 | static void jsonenc_map(jsonenc* e, const upb_Map* map, const upb_FieldDef* f) { |
| 671 | const upb_MessageDef* entry = upb_FieldDef_MessageSubDef(f); |
Joshua Haberman | c56fe27 | 2022-02-22 20:32:56 -0800 | [diff] [blame] | 672 | const upb_FieldDef* key_f = upb_MessageDef_FindFieldByNumber(entry, 1); |
| 673 | const upb_FieldDef* val_f = upb_MessageDef_FindFieldByNumber(entry, 2); |
Joshua Haberman | 1c955f3 | 2022-01-12 07:19:28 -0800 | [diff] [blame] | 674 | size_t iter = kUpb_Map_Begin; |
Joshua Haberman | 60d0966 | 2020-02-10 09:44:07 -0800 | [diff] [blame] | 675 | bool first = true; |
| 676 | |
Joshua Haberman | 6e9db7d | 2020-02-15 19:31:51 -0800 | [diff] [blame] | 677 | jsonenc_putstr(e, "{"); |
Joshua Haberman | 60d0966 | 2020-02-10 09:44:07 -0800 | [diff] [blame] | 678 | |
Joshua Haberman | 6b35760 | 2020-12-08 16:58:30 -0800 | [diff] [blame] | 679 | if (map) { |
Joshua Haberman | 1c955f3 | 2022-01-12 07:19:28 -0800 | [diff] [blame] | 680 | while (upb_MapIterator_Next(map, &iter)) { |
Joshua Haberman | 6b35760 | 2020-12-08 16:58:30 -0800 | [diff] [blame] | 681 | jsonenc_putsep(e, ",", &first); |
Joshua Haberman | 1c955f3 | 2022-01-12 07:19:28 -0800 | [diff] [blame] | 682 | jsonenc_mapkey(e, upb_MapIterator_Key(map, iter), key_f); |
| 683 | jsonenc_scalar(e, upb_MapIterator_Value(map, iter), val_f); |
Joshua Haberman | 6b35760 | 2020-12-08 16:58:30 -0800 | [diff] [blame] | 684 | } |
Joshua Haberman | 60d0966 | 2020-02-10 09:44:07 -0800 | [diff] [blame] | 685 | } |
| 686 | |
Joshua Haberman | 6e9db7d | 2020-02-15 19:31:51 -0800 | [diff] [blame] | 687 | jsonenc_putstr(e, "}"); |
Joshua Haberman | 60d0966 | 2020-02-10 09:44:07 -0800 | [diff] [blame] | 688 | } |
| 689 | |
Joshua Haberman | 1c955f3 | 2022-01-12 07:19:28 -0800 | [diff] [blame] | 690 | static void jsonenc_fieldval(jsonenc* e, const upb_FieldDef* f, |
| 691 | upb_MessageValue val, bool* first) { |
| 692 | const char* name; |
Joshua Haberman | 60d0966 | 2020-02-10 09:44:07 -0800 | [diff] [blame] | 693 | |
Joshua Haberman | 543a0ce | 2020-05-26 22:30:50 -0700 | [diff] [blame] | 694 | jsonenc_putsep(e, ",", first); |
Joshua Haberman | ce012b7 | 2021-10-01 16:34:42 -0700 | [diff] [blame] | 695 | |
Joshua Haberman | 1c955f3 | 2022-01-12 07:19:28 -0800 | [diff] [blame] | 696 | if (upb_FieldDef_IsExtension(f)) { |
Joshua Haberman | 6f89034 | 2021-10-03 15:18:38 -0700 | [diff] [blame] | 697 | // 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 Haberman | 1c955f3 | 2022-01-12 07:19:28 -0800 | [diff] [blame] | 700 | jsonenc_printf(e, "\"[%s]\":", upb_FieldDef_FullName(f)); |
Joshua Haberman | ce012b7 | 2021-10-01 16:34:42 -0700 | [diff] [blame] | 701 | } else { |
Joshua Haberman | 1c955f3 | 2022-01-12 07:19:28 -0800 | [diff] [blame] | 702 | if (e->options & upb_JsonEncode_UseProtoNames) { |
| 703 | name = upb_FieldDef_Name(f); |
Joshua Haberman | ce012b7 | 2021-10-01 16:34:42 -0700 | [diff] [blame] | 704 | } else { |
Joshua Haberman | 1c955f3 | 2022-01-12 07:19:28 -0800 | [diff] [blame] | 705 | name = upb_FieldDef_JsonName(f); |
Joshua Haberman | ce012b7 | 2021-10-01 16:34:42 -0700 | [diff] [blame] | 706 | } |
| 707 | jsonenc_printf(e, "\"%s\":", name); |
| 708 | } |
Joshua Haberman | 60d0966 | 2020-02-10 09:44:07 -0800 | [diff] [blame] | 709 | |
Joshua Haberman | 1c955f3 | 2022-01-12 07:19:28 -0800 | [diff] [blame] | 710 | if (upb_FieldDef_IsMap(f)) { |
Joshua Haberman | 60d0966 | 2020-02-10 09:44:07 -0800 | [diff] [blame] | 711 | jsonenc_map(e, val.map_val, f); |
Joshua Haberman | 1c955f3 | 2022-01-12 07:19:28 -0800 | [diff] [blame] | 712 | } else if (upb_FieldDef_IsRepeated(f)) { |
Joshua Haberman | 60d0966 | 2020-02-10 09:44:07 -0800 | [diff] [blame] | 713 | jsonenc_array(e, val.array_val, f); |
| 714 | } else { |
Joshua Haberman | 6e9db7d | 2020-02-15 19:31:51 -0800 | [diff] [blame] | 715 | jsonenc_scalar(e, val, f); |
Joshua Haberman | 60d0966 | 2020-02-10 09:44:07 -0800 | [diff] [blame] | 716 | } |
| 717 | } |
| 718 | |
Joshua Haberman | 499c2cc | 2022-01-12 09:09:59 -0800 | [diff] [blame] | 719 | static void jsonenc_msgfields(jsonenc* e, const upb_Message* msg, |
Joshua Haberman | 1c955f3 | 2022-01-12 07:19:28 -0800 | [diff] [blame] | 720 | const upb_MessageDef* m, bool first) { |
| 721 | upb_MessageValue val; |
| 722 | const upb_FieldDef* f; |
Joshua Haberman | 60d0966 | 2020-02-10 09:44:07 -0800 | [diff] [blame] | 723 | |
Joshua Haberman | 1c955f3 | 2022-01-12 07:19:28 -0800 | [diff] [blame] | 724 | if (e->options & upb_JsonEncode_EmitDefaults) { |
Joshua Haberman | 60d0966 | 2020-02-10 09:44:07 -0800 | [diff] [blame] | 725 | /* Iterate over all fields. */ |
Joshua Haberman | 5aa5b77 | 2020-10-11 13:37:57 -0700 | [diff] [blame] | 726 | int i = 0; |
Joshua Haberman | 1c955f3 | 2022-01-12 07:19:28 -0800 | [diff] [blame] | 727 | int n = upb_MessageDef_FieldCount(m); |
Joshua Haberman | 5aa5b77 | 2020-10-11 13:37:57 -0700 | [diff] [blame] | 728 | for (i = 0; i < n; i++) { |
Joshua Haberman | 1c955f3 | 2022-01-12 07:19:28 -0800 | [diff] [blame] | 729 | 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 Haberman | 6b35760 | 2020-12-08 16:58:30 -0800 | [diff] [blame] | 732 | } |
Joshua Haberman | 60d0966 | 2020-02-10 09:44:07 -0800 | [diff] [blame] | 733 | } |
| 734 | } else { |
| 735 | /* Iterate over non-empty fields. */ |
Joshua Haberman | 1c955f3 | 2022-01-12 07:19:28 -0800 | [diff] [blame] | 736 | size_t iter = kUpb_Message_Begin; |
| 737 | while (upb_Message_Next(msg, m, e->ext_pool, &f, &val, &iter)) { |
Joshua Haberman | 60d0966 | 2020-02-10 09:44:07 -0800 | [diff] [blame] | 738 | jsonenc_fieldval(e, f, val, &first); |
| 739 | } |
| 740 | } |
Joshua Haberman | a292261 | 2020-02-24 13:57:57 -0800 | [diff] [blame] | 741 | } |
Joshua Haberman | 60d0966 | 2020-02-10 09:44:07 -0800 | [diff] [blame] | 742 | |
Joshua Haberman | 499c2cc | 2022-01-12 09:09:59 -0800 | [diff] [blame] | 743 | static void jsonenc_msg(jsonenc* e, const upb_Message* msg, |
Joshua Haberman | 1c955f3 | 2022-01-12 07:19:28 -0800 | [diff] [blame] | 744 | const upb_MessageDef* m) { |
Joshua Haberman | a292261 | 2020-02-24 13:57:57 -0800 | [diff] [blame] | 745 | jsonenc_putstr(e, "{"); |
Joshua Haberman | e58f7a0 | 2021-02-17 17:18:55 -0800 | [diff] [blame] | 746 | jsonenc_msgfields(e, msg, m, true); |
Joshua Haberman | 6e9db7d | 2020-02-15 19:31:51 -0800 | [diff] [blame] | 747 | jsonenc_putstr(e, "}"); |
Joshua Haberman | 60d0966 | 2020-02-10 09:44:07 -0800 | [diff] [blame] | 748 | } |
| 749 | |
Joshua Haberman | 1c955f3 | 2022-01-12 07:19:28 -0800 | [diff] [blame] | 750 | static size_t jsonenc_nullz(jsonenc* e, size_t size) { |
Joshua Haberman | 60d0966 | 2020-02-10 09:44:07 -0800 | [diff] [blame] | 751 | 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 Haberman | 499c2cc | 2022-01-12 09:09:59 -0800 | [diff] [blame] | 761 | size_t upb_JsonEncode(const upb_Message* msg, const upb_MessageDef* m, |
Joshua Haberman | 1c955f3 | 2022-01-12 07:19:28 -0800 | [diff] [blame] | 762 | const upb_DefPool* ext_pool, int options, char* buf, |
| 763 | size_t size, upb_Status* status) { |
Joshua Haberman | 60d0966 | 2020-02-10 09:44:07 -0800 | [diff] [blame] | 764 | jsonenc e; |
| 765 | |
| 766 | e.buf = buf; |
| 767 | e.ptr = buf; |
Joshua Haberman | 8370818 | 2021-03-09 14:44:35 -0800 | [diff] [blame] | 768 | e.end = UPB_PTRADD(buf, size); |
Joshua Haberman | 60d0966 | 2020-02-10 09:44:07 -0800 | [diff] [blame] | 769 | e.overflow = 0; |
| 770 | e.options = options; |
| 771 | e.ext_pool = ext_pool; |
Joshua Haberman | 6e9db7d | 2020-02-15 19:31:51 -0800 | [diff] [blame] | 772 | e.status = status; |
Joshua Haberman | a292261 | 2020-02-24 13:57:57 -0800 | [diff] [blame] | 773 | e.arena = NULL; |
Joshua Haberman | 6e9db7d | 2020-02-15 19:31:51 -0800 | [diff] [blame] | 774 | |
| 775 | if (setjmp(e.err)) return -1; |
Joshua Haberman | 60d0966 | 2020-02-10 09:44:07 -0800 | [diff] [blame] | 776 | |
Joshua Haberman | 543a0ce | 2020-05-26 22:30:50 -0700 | [diff] [blame] | 777 | jsonenc_msgfield(&e, msg, m); |
Joshua Haberman | 1c955f3 | 2022-01-12 07:19:28 -0800 | [diff] [blame] | 778 | if (e.arena) upb_Arena_Free(e.arena); |
Joshua Haberman | 60d0966 | 2020-02-10 09:44:07 -0800 | [diff] [blame] | 779 | return jsonenc_nullz(&e, size); |
| 780 | } |