blob: dba003eae78a1e18fb9fe809b0bb5b6f122b55b1 [file] [log] [blame]
Bram Moolenaaredf3f972016-08-29 22:49:24 +02001/* vi:set ts=8 sts=4 sw=4 noet:
Bram Moolenaar520e1e42016-01-23 19:46:28 +01002 *
3 * VIM - Vi IMproved by Bram Moolenaar
4 *
5 * Do ":help uganda" in Vim to read copying and usage conditions.
6 * Do ":help credits" in Vim to see a list of people who contributed.
7 * See README.txt for an overview of the Vim source code.
8 */
9
10/*
11 * json.c: Encoding and decoding JSON.
12 *
Bram Moolenaar009d84a2016-01-28 14:12:00 +010013 * Follows this standard: https://tools.ietf.org/html/rfc7159.html
Bram Moolenaar520e1e42016-01-23 19:46:28 +010014 */
Bram Moolenaarfefecb02016-02-27 21:27:20 +010015#define USING_FLOAT_STUFF
Bram Moolenaar520e1e42016-01-23 19:46:28 +010016
17#include "vim.h"
18
19#if defined(FEAT_EVAL) || defined(PROTO)
Bram Moolenaarf1b6ac72016-02-23 21:26:43 +010020
Bram Moolenaar595e64e2016-02-07 19:19:53 +010021static int json_encode_item(garray_T *gap, typval_T *val, int copyID, int options);
Bram Moolenaar520e1e42016-01-23 19:46:28 +010022
Bram Moolenaara09195f2020-05-19 22:38:59 +020023static char e_json_error[] = N_("E491: json decode error at '%s'");
24
Bram Moolenaar520e1e42016-01-23 19:46:28 +010025/*
26 * Encode "val" into a JSON format string.
Bram Moolenaarf1f07922016-08-26 17:58:53 +020027 * The result is added to "gap"
28 * Returns FAIL on failure and makes gap->ga_data empty.
29 */
30 static int
31json_encode_gap(garray_T *gap, typval_T *val, int options)
32{
33 if (json_encode_item(gap, val, get_copyID(), options) == FAIL)
34 {
35 ga_clear(gap);
36 gap->ga_data = vim_strsave((char_u *)"");
37 return FAIL;
38 }
39 return OK;
40}
41
42/*
43 * Encode "val" into a JSON format string.
Bram Moolenaar55fab432016-02-07 16:53:13 +010044 * The result is in allocated memory.
45 * The result is empty when encoding fails.
Bram Moolenaarf1f07922016-08-26 17:58:53 +020046 * "options" can contain JSON_JS, JSON_NO_NONE and JSON_NL.
Bram Moolenaar520e1e42016-01-23 19:46:28 +010047 */
48 char_u *
Bram Moolenaar595e64e2016-02-07 19:19:53 +010049json_encode(typval_T *val, int options)
Bram Moolenaar520e1e42016-01-23 19:46:28 +010050{
51 garray_T ga;
52
Bram Moolenaar4ba37b52019-12-04 21:57:43 +010053 // Store bytes in the growarray.
Bram Moolenaar520e1e42016-01-23 19:46:28 +010054 ga_init2(&ga, 1, 4000);
Bram Moolenaarf1f07922016-08-26 17:58:53 +020055 json_encode_gap(&ga, val, options);
Bram Moolenaar04af1962019-04-12 21:19:04 +020056 ga_append(&ga, NUL);
Bram Moolenaar520e1e42016-01-23 19:46:28 +010057 return ga.ga_data;
58}
59
Bram Moolenaar113e1072019-01-20 15:30:40 +010060#if defined(FEAT_JOB_CHANNEL) || defined(PROTO)
Bram Moolenaarfb1f6262016-01-31 20:24:32 +010061/*
Bram Moolenaar55fab432016-02-07 16:53:13 +010062 * Encode ["nr", "val"] into a JSON format string in allocated memory.
Bram Moolenaarf1f07922016-08-26 17:58:53 +020063 * "options" can contain JSON_JS, JSON_NO_NONE and JSON_NL.
Bram Moolenaarfb1f6262016-01-31 20:24:32 +010064 * Returns NULL when out of memory.
65 */
66 char_u *
Bram Moolenaar595e64e2016-02-07 19:19:53 +010067json_encode_nr_expr(int nr, typval_T *val, int options)
Bram Moolenaarfb1f6262016-01-31 20:24:32 +010068{
69 typval_T listtv;
70 typval_T nrtv;
Bram Moolenaarf1f07922016-08-26 17:58:53 +020071 garray_T ga;
Bram Moolenaarfb1f6262016-01-31 20:24:32 +010072
73 nrtv.v_type = VAR_NUMBER;
74 nrtv.vval.v_number = nr;
75 if (rettv_list_alloc(&listtv) == FAIL)
76 return NULL;
77 if (list_append_tv(listtv.vval.v_list, &nrtv) == FAIL
78 || list_append_tv(listtv.vval.v_list, val) == FAIL)
79 {
80 list_unref(listtv.vval.v_list);
81 return NULL;
82 }
83
Bram Moolenaarf1f07922016-08-26 17:58:53 +020084 ga_init2(&ga, 1, 4000);
85 if (json_encode_gap(&ga, &listtv, options) == OK && (options & JSON_NL))
86 ga_append(&ga, '\n');
Bram Moolenaarfb1f6262016-01-31 20:24:32 +010087 list_unref(listtv.vval.v_list);
Bram Moolenaar04af1962019-04-12 21:19:04 +020088 ga_append(&ga, NUL);
Bram Moolenaarf1f07922016-08-26 17:58:53 +020089 return ga.ga_data;
Bram Moolenaarfb1f6262016-01-31 20:24:32 +010090}
Bram Moolenaar113e1072019-01-20 15:30:40 +010091#endif
Bram Moolenaarfb1f6262016-01-31 20:24:32 +010092
Bram Moolenaar520e1e42016-01-23 19:46:28 +010093 static void
94write_string(garray_T *gap, char_u *str)
95{
96 char_u *res = str;
97 char_u numbuf[NUMBUFLEN];
98
99 if (res == NULL)
Bram Moolenaarb29d3282017-12-15 21:25:01 +0100100 ga_concat(gap, (char_u *)"\"\"");
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100101 else
102 {
Bram Moolenaarfc3abf42019-01-24 15:54:21 +0100103#if defined(USE_ICONV)
Bram Moolenaarb6ff8112016-02-27 18:41:27 +0100104 vimconv_T conv;
105 char_u *converted = NULL;
106
Bram Moolenaarf97ddbe2016-02-27 21:13:38 +0100107 if (!enc_utf8)
108 {
Bram Moolenaar4ba37b52019-12-04 21:57:43 +0100109 // Convert the text from 'encoding' to utf-8, the JSON string is
110 // always utf-8.
Bram Moolenaarf97ddbe2016-02-27 21:13:38 +0100111 conv.vc_type = CONV_NONE;
112 convert_setup(&conv, p_enc, (char_u*)"utf-8");
113 if (conv.vc_type != CONV_NONE)
114 converted = res = string_convert(&conv, res, NULL);
115 convert_setup(&conv, NULL, NULL);
116 }
Bram Moolenaarb6ff8112016-02-27 18:41:27 +0100117#endif
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100118 ga_append(gap, '"');
119 while (*res != NUL)
120 {
Bram Moolenaarb6ff8112016-02-27 18:41:27 +0100121 int c;
Bram Moolenaar4ba37b52019-12-04 21:57:43 +0100122 // always use utf-8 encoding, ignore 'encoding'
Bram Moolenaarb6ff8112016-02-27 18:41:27 +0100123 c = utf_ptr2char(res);
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100124
125 switch (c)
126 {
127 case 0x08:
128 ga_append(gap, '\\'); ga_append(gap, 'b'); break;
129 case 0x09:
130 ga_append(gap, '\\'); ga_append(gap, 't'); break;
131 case 0x0a:
132 ga_append(gap, '\\'); ga_append(gap, 'n'); break;
133 case 0x0c:
134 ga_append(gap, '\\'); ga_append(gap, 'f'); break;
135 case 0x0d:
136 ga_append(gap, '\\'); ga_append(gap, 'r'); break;
Bram Moolenaar4ba37b52019-12-04 21:57:43 +0100137 case 0x22: // "
138 case 0x5c: // backslash
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100139 ga_append(gap, '\\');
140 ga_append(gap, c);
141 break;
142 default:
143 if (c >= 0x20)
144 {
Bram Moolenaarb6ff8112016-02-27 18:41:27 +0100145 numbuf[utf_char2bytes(c, numbuf)] = NUL;
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100146 ga_concat(gap, numbuf);
147 }
148 else
149 {
150 vim_snprintf((char *)numbuf, NUMBUFLEN,
151 "\\u%04lx", (long)c);
152 ga_concat(gap, numbuf);
153 }
154 }
Bram Moolenaarb6ff8112016-02-27 18:41:27 +0100155 res += utf_ptr2len(res);
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100156 }
157 ga_append(gap, '"');
Bram Moolenaarfc3abf42019-01-24 15:54:21 +0100158#if defined(USE_ICONV)
Bram Moolenaarb6ff8112016-02-27 18:41:27 +0100159 vim_free(converted);
160#endif
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100161 }
162}
163
Bram Moolenaarfcaaae62016-01-24 16:49:11 +0100164/*
Bram Moolenaar595e64e2016-02-07 19:19:53 +0100165 * Return TRUE if "key" can be used without quotes.
166 * That is when it starts with a letter and only contains letters, digits and
167 * underscore.
168 */
169 static int
170is_simple_key(char_u *key)
171{
172 char_u *p;
173
174 if (!ASCII_ISALPHA(*key))
175 return FALSE;
176 for (p = key + 1; *p != NUL; ++p)
177 if (!ASCII_ISALPHA(*p) && *p != '_' && !vim_isdigit(*p))
178 return FALSE;
179 return TRUE;
180}
181
182/*
Bram Moolenaarfcaaae62016-01-24 16:49:11 +0100183 * Encode "val" into "gap".
184 * Return FAIL or OK.
185 */
186 static int
Bram Moolenaar595e64e2016-02-07 19:19:53 +0100187json_encode_item(garray_T *gap, typval_T *val, int copyID, int options)
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100188{
189 char_u numbuf[NUMBUFLEN];
190 char_u *res;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +0100191 blob_T *b;
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100192 list_T *l;
193 dict_T *d;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +0100194 int i;
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100195
196 switch (val->v_type)
197 {
Bram Moolenaar9b4a15d2020-01-11 16:05:23 +0100198 case VAR_BOOL:
Bram Moolenaarc593bec2020-02-25 21:26:49 +0100199 switch ((long)val->vval.v_number)
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100200 {
201 case VVAL_FALSE: ga_concat(gap, (char_u *)"false"); break;
202 case VVAL_TRUE: ga_concat(gap, (char_u *)"true"); break;
Bram Moolenaar9b4a15d2020-01-11 16:05:23 +0100203 }
204 break;
205
206 case VAR_SPECIAL:
Bram Moolenaarc593bec2020-02-25 21:26:49 +0100207 switch ((long)val->vval.v_number)
Bram Moolenaar9b4a15d2020-01-11 16:05:23 +0100208 {
Bram Moolenaar595e64e2016-02-07 19:19:53 +0100209 case VVAL_NONE: if ((options & JSON_JS) != 0
210 && (options & JSON_NO_NONE) == 0)
Bram Moolenaar4ba37b52019-12-04 21:57:43 +0100211 // empty item
Bram Moolenaar595e64e2016-02-07 19:19:53 +0100212 break;
Bram Moolenaar4ba37b52019-12-04 21:57:43 +0100213 // FALLTHROUGH
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100214 case VVAL_NULL: ga_concat(gap, (char_u *)"null"); break;
215 }
216 break;
217
218 case VAR_NUMBER:
Bram Moolenaar22fcfad2016-07-01 18:17:26 +0200219 vim_snprintf((char *)numbuf, NUMBUFLEN, "%lld",
Bram Moolenaarf9706e92020-02-22 14:27:04 +0100220 (varnumber_T)val->vval.v_number);
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100221 ga_concat(gap, numbuf);
222 break;
223
224 case VAR_STRING:
225 res = val->vval.v_string;
226 write_string(gap, res);
227 break;
228
229 case VAR_FUNC:
Bram Moolenaar1735bc92016-03-14 23:05:14 +0100230 case VAR_PARTIAL:
Bram Moolenaar55fab432016-02-07 16:53:13 +0100231 case VAR_JOB:
Bram Moolenaar77073442016-02-13 23:23:53 +0100232 case VAR_CHANNEL:
Bram Moolenaara8530892021-02-08 21:53:09 +0100233 semsg(_(e_cannot_json_encode_str), vartype_name(val->v_type));
Bram Moolenaarfcaaae62016-01-24 16:49:11 +0100234 return FAIL;
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100235
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +0100236 case VAR_BLOB:
237 b = val->vval.v_blob;
238 if (b == NULL || b->bv_ga.ga_len == 0)
239 ga_concat(gap, (char_u *)"[]");
240 else
241 {
242 ga_append(gap, '[');
243 for (i = 0; i < b->bv_ga.ga_len; i++)
244 {
245 if (i > 0)
246 ga_concat(gap, (char_u *)",");
247 vim_snprintf((char *)numbuf, NUMBUFLEN, "%d",
248 (int)blob_get(b, i));
249 ga_concat(gap, numbuf);
250 }
251 ga_append(gap, ']');
252 }
253 break;
254
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100255 case VAR_LIST:
256 l = val->vval.v_list;
257 if (l == NULL)
Bram Moolenaarb29d3282017-12-15 21:25:01 +0100258 ga_concat(gap, (char_u *)"[]");
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100259 else
260 {
261 if (l->lv_copyID == copyID)
262 ga_concat(gap, (char_u *)"[]");
263 else
264 {
265 listitem_T *li;
266
267 l->lv_copyID = copyID;
268 ga_append(gap, '[');
Bram Moolenaar7e9f3512020-05-13 22:44:22 +0200269 CHECK_LIST_MATERIALIZE(l);
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100270 for (li = l->lv_first; li != NULL && !got_int; )
271 {
Bram Moolenaar595e64e2016-02-07 19:19:53 +0100272 if (json_encode_item(gap, &li->li_tv, copyID,
273 options & JSON_JS) == FAIL)
Bram Moolenaarfcaaae62016-01-24 16:49:11 +0100274 return FAIL;
Bram Moolenaar595e64e2016-02-07 19:19:53 +0100275 if ((options & JSON_JS)
276 && li->li_next == NULL
277 && li->li_tv.v_type == VAR_SPECIAL
278 && li->li_tv.vval.v_number == VVAL_NONE)
Bram Moolenaar4ba37b52019-12-04 21:57:43 +0100279 // add an extra comma if the last item is v:none
Bram Moolenaar595e64e2016-02-07 19:19:53 +0100280 ga_append(gap, ',');
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100281 li = li->li_next;
282 if (li != NULL)
283 ga_append(gap, ',');
284 }
285 ga_append(gap, ']');
Bram Moolenaarfcaaae62016-01-24 16:49:11 +0100286 l->lv_copyID = 0;
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100287 }
288 }
289 break;
290
291 case VAR_DICT:
292 d = val->vval.v_dict;
293 if (d == NULL)
Bram Moolenaarb29d3282017-12-15 21:25:01 +0100294 ga_concat(gap, (char_u *)"{}");
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100295 else
296 {
297 if (d->dv_copyID == copyID)
298 ga_concat(gap, (char_u *)"{}");
299 else
300 {
301 int first = TRUE;
302 int todo = (int)d->dv_hashtab.ht_used;
303 hashitem_T *hi;
304
305 d->dv_copyID = copyID;
306 ga_append(gap, '{');
307
308 for (hi = d->dv_hashtab.ht_array; todo > 0 && !got_int;
309 ++hi)
310 if (!HASHITEM_EMPTY(hi))
311 {
312 --todo;
313 if (first)
314 first = FALSE;
315 else
316 ga_append(gap, ',');
Bram Moolenaar595e64e2016-02-07 19:19:53 +0100317 if ((options & JSON_JS)
318 && is_simple_key(hi->hi_key))
319 ga_concat(gap, hi->hi_key);
320 else
321 write_string(gap, hi->hi_key);
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100322 ga_append(gap, ':');
Bram Moolenaarfcaaae62016-01-24 16:49:11 +0100323 if (json_encode_item(gap, &dict_lookup(hi)->di_tv,
Bram Moolenaar595e64e2016-02-07 19:19:53 +0100324 copyID, options | JSON_NO_NONE) == FAIL)
Bram Moolenaarfcaaae62016-01-24 16:49:11 +0100325 return FAIL;
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100326 }
327 ga_append(gap, '}');
Bram Moolenaarfcaaae62016-01-24 16:49:11 +0100328 d->dv_copyID = 0;
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100329 }
330 }
331 break;
332
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100333 case VAR_FLOAT:
Bram Moolenaar55fab432016-02-07 16:53:13 +0100334#ifdef FEAT_FLOAT
Bram Moolenaarf1b6ac72016-02-23 21:26:43 +0100335# if defined(HAVE_MATH_H)
Bram Moolenaar7ce686c2016-02-27 16:33:22 +0100336 if (isnan(val->vval.v_float))
Bram Moolenaarf1b6ac72016-02-23 21:26:43 +0100337 ga_concat(gap, (char_u *)"NaN");
Bram Moolenaar7ce686c2016-02-27 16:33:22 +0100338 else if (isinf(val->vval.v_float))
Bram Moolenaar5f6b3792019-01-12 14:24:27 +0100339 {
340 if (val->vval.v_float < 0.0)
341 ga_concat(gap, (char_u *)"-Infinity");
342 else
343 ga_concat(gap, (char_u *)"Infinity");
344 }
Bram Moolenaarf1b6ac72016-02-23 21:26:43 +0100345 else
346# endif
347 {
348 vim_snprintf((char *)numbuf, NUMBUFLEN, "%g",
349 val->vval.v_float);
350 ga_concat(gap, numbuf);
351 }
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100352 break;
353#endif
Bram Moolenaar55fab432016-02-07 16:53:13 +0100354 case VAR_UNKNOWN:
Bram Moolenaar4c683752020-04-05 21:38:23 +0200355 case VAR_ANY:
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100356 case VAR_VOID:
Bram Moolenaardd589232020-02-29 17:38:12 +0100357 internal_error_no_abort("json_encode_item()");
Bram Moolenaar55fab432016-02-07 16:53:13 +0100358 return FAIL;
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100359 }
Bram Moolenaarfcaaae62016-01-24 16:49:11 +0100360 return OK;
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100361}
362
363/*
Bram Moolenaar56ead342016-02-02 18:20:08 +0100364 * When "reader" has less than NUMBUFLEN bytes available, call the fill
365 * callback to get more.
366 */
367 static void
368fill_numbuflen(js_read_T *reader)
369{
370 if (reader->js_fill != NULL && (int)(reader->js_end - reader->js_buf)
371 - reader->js_used < NUMBUFLEN)
372 {
373 if (reader->js_fill(reader))
374 reader->js_end = reader->js_buf + STRLEN(reader->js_buf);
375 }
376}
377
378/*
Bram Moolenaar595e64e2016-02-07 19:19:53 +0100379 * Skip white space in "reader". All characters <= space are considered white
380 * space.
Bram Moolenaar56ead342016-02-02 18:20:08 +0100381 * Also tops up readahead when needed.
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100382 */
383 static void
384json_skip_white(js_read_T *reader)
385{
386 int c;
387
Bram Moolenaar56ead342016-02-02 18:20:08 +0100388 for (;;)
389 {
390 c = reader->js_buf[reader->js_used];
391 if (reader->js_fill != NULL && c == NUL)
392 {
393 if (reader->js_fill(reader))
Bram Moolenaar46c00a62016-03-28 14:11:42 +0200394 {
Bram Moolenaar56ead342016-02-02 18:20:08 +0100395 reader->js_end = reader->js_buf + STRLEN(reader->js_buf);
Bram Moolenaar46c00a62016-03-28 14:11:42 +0200396 continue;
397 }
Bram Moolenaar56ead342016-02-02 18:20:08 +0100398 }
Bram Moolenaar595e64e2016-02-07 19:19:53 +0100399 if (c == NUL || c > ' ')
Bram Moolenaar56ead342016-02-02 18:20:08 +0100400 break;
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100401 ++reader->js_used;
Bram Moolenaar56ead342016-02-02 18:20:08 +0100402 }
403 fill_numbuflen(reader);
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100404}
405
Bram Moolenaar56ead342016-02-02 18:20:08 +0100406 static int
Bram Moolenaaree142ad2017-01-11 21:50:08 +0100407json_decode_string(js_read_T *reader, typval_T *res, int quote)
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100408{
409 garray_T ga;
410 int len;
Bram Moolenaar56ead342016-02-02 18:20:08 +0100411 char_u *p;
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100412 int c;
Bram Moolenaar22fcfad2016-07-01 18:17:26 +0200413 varnumber_T nr;
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100414
Bram Moolenaar56ead342016-02-02 18:20:08 +0100415 if (res != NULL)
416 ga_init2(&ga, 1, 200);
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100417
Bram Moolenaar4ba37b52019-12-04 21:57:43 +0100418 p = reader->js_buf + reader->js_used + 1; // skip over " or '
Bram Moolenaaree142ad2017-01-11 21:50:08 +0100419 while (*p != quote)
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100420 {
Bram Moolenaar4ba37b52019-12-04 21:57:43 +0100421 // The JSON is always expected to be utf-8, thus use utf functions
422 // here. The string is converted below if needed.
Bram Moolenaarfc3abf42019-01-24 15:54:21 +0100423 if (*p == NUL || p[1] == NUL || utf_ptr2len(p) < utf_byte2len(*p))
Bram Moolenaar56ead342016-02-02 18:20:08 +0100424 {
Bram Moolenaar4ba37b52019-12-04 21:57:43 +0100425 // Not enough bytes to make a character or end of the string. Get
426 // more if possible.
Bram Moolenaar56ead342016-02-02 18:20:08 +0100427 if (reader->js_fill == NULL)
428 break;
429 len = (int)(reader->js_end - p);
430 reader->js_used = (int)(p - reader->js_buf);
431 if (!reader->js_fill(reader))
Bram Moolenaar4ba37b52019-12-04 21:57:43 +0100432 break; // didn't get more
Bram Moolenaar56ead342016-02-02 18:20:08 +0100433 p = reader->js_buf + reader->js_used;
434 reader->js_end = reader->js_buf + STRLEN(reader->js_buf);
435 continue;
436 }
437
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100438 if (*p == '\\')
439 {
440 c = -1;
441 switch (p[1])
442 {
Bram Moolenaar56ead342016-02-02 18:20:08 +0100443 case '\\': c = '\\'; break;
444 case '"': c = '"'; break;
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100445 case 'b': c = BS; break;
446 case 't': c = TAB; break;
447 case 'n': c = NL; break;
448 case 'f': c = FF; break;
449 case 'r': c = CAR; break;
450 case 'u':
Bram Moolenaar56ead342016-02-02 18:20:08 +0100451 if (reader->js_fill != NULL
452 && (int)(reader->js_end - p) < NUMBUFLEN)
453 {
454 reader->js_used = (int)(p - reader->js_buf);
455 if (reader->js_fill(reader))
456 {
457 p = reader->js_buf + reader->js_used;
458 reader->js_end = reader->js_buf
459 + STRLEN(reader->js_buf);
460 }
461 }
Bram Moolenaarb6ff8112016-02-27 18:41:27 +0100462 nr = 0;
463 len = 0;
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100464 vim_str2nr(p + 2, NULL, &len,
Bram Moolenaar16e9b852019-05-19 19:59:35 +0200465 STR2NR_HEX + STR2NR_FORCE, &nr, NULL, 4, TRUE);
466 if (len == 0)
467 {
Bram Moolenaarb4368372019-05-27 20:01:41 +0200468 if (res != NULL)
469 ga_clear(&ga);
Bram Moolenaar16e9b852019-05-19 19:59:35 +0200470 return FAIL;
471 }
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100472 p += len + 2;
Bram Moolenaarb6ff8112016-02-27 18:41:27 +0100473 if (0xd800 <= nr && nr <= 0xdfff
474 && (int)(reader->js_end - p) >= 6
475 && *p == '\\' && *(p+1) == 'u')
476 {
Bram Moolenaar22fcfad2016-07-01 18:17:26 +0200477 varnumber_T nr2 = 0;
Bram Moolenaarb6ff8112016-02-27 18:41:27 +0100478
Bram Moolenaar4ba37b52019-12-04 21:57:43 +0100479 // decode surrogate pair: \ud812\u3456
Bram Moolenaarb6ff8112016-02-27 18:41:27 +0100480 len = 0;
481 vim_str2nr(p + 2, NULL, &len,
Bram Moolenaar16e9b852019-05-19 19:59:35 +0200482 STR2NR_HEX + STR2NR_FORCE, &nr2, NULL, 4, TRUE);
483 if (len == 0)
484 {
Bram Moolenaarb4368372019-05-27 20:01:41 +0200485 if (res != NULL)
486 ga_clear(&ga);
Bram Moolenaar16e9b852019-05-19 19:59:35 +0200487 return FAIL;
488 }
Bram Moolenaarb6ff8112016-02-27 18:41:27 +0100489 if (0xdc00 <= nr2 && nr2 <= 0xdfff)
490 {
491 p += len + 2;
492 nr = (((nr - 0xd800) << 10) |
493 ((nr2 - 0xdc00) & 0x3ff)) + 0x10000;
494 }
495 }
Bram Moolenaar56ead342016-02-02 18:20:08 +0100496 if (res != NULL)
497 {
Bram Moolenaardc633cf2016-04-23 14:33:19 +0200498 char_u buf[NUMBUFLEN];
Bram Moolenaarb4368372019-05-27 20:01:41 +0200499
Bram Moolenaarb6ff8112016-02-27 18:41:27 +0100500 buf[utf_char2bytes((int)nr, buf)] = NUL;
Bram Moolenaar56ead342016-02-02 18:20:08 +0100501 ga_concat(&ga, buf);
Bram Moolenaar56ead342016-02-02 18:20:08 +0100502 }
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100503 break;
Bram Moolenaar56ead342016-02-02 18:20:08 +0100504 default:
Bram Moolenaar4ba37b52019-12-04 21:57:43 +0100505 // not a special char, skip over backslash
Bram Moolenaar56ead342016-02-02 18:20:08 +0100506 ++p;
507 continue;
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100508 }
509 if (c > 0)
510 {
511 p += 2;
Bram Moolenaar56ead342016-02-02 18:20:08 +0100512 if (res != NULL)
513 ga_append(&ga, c);
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100514 }
515 }
516 else
517 {
Bram Moolenaarb6ff8112016-02-27 18:41:27 +0100518 len = utf_ptr2len(p);
Bram Moolenaar56ead342016-02-02 18:20:08 +0100519 if (res != NULL)
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100520 {
Bram Moolenaar56ead342016-02-02 18:20:08 +0100521 if (ga_grow(&ga, len) == FAIL)
522 {
523 ga_clear(&ga);
524 return FAIL;
525 }
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100526 mch_memmove((char *)ga.ga_data + ga.ga_len, p, (size_t)len);
527 ga.ga_len += len;
528 }
529 p += len;
530 }
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100531 }
Bram Moolenaar56ead342016-02-02 18:20:08 +0100532
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100533 reader->js_used = (int)(p - reader->js_buf);
Bram Moolenaaree142ad2017-01-11 21:50:08 +0100534 if (*p == quote)
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100535 {
536 ++reader->js_used;
Bram Moolenaar56ead342016-02-02 18:20:08 +0100537 if (res != NULL)
538 {
Bram Moolenaar80e78842016-02-28 15:21:13 +0100539 ga_append(&ga, NUL);
Bram Moolenaar56ead342016-02-02 18:20:08 +0100540 res->v_type = VAR_STRING;
Bram Moolenaarfc3abf42019-01-24 15:54:21 +0100541#if defined(USE_ICONV)
Bram Moolenaarb3628722016-02-28 14:56:39 +0100542 if (!enc_utf8)
543 {
544 vimconv_T conv;
545
Bram Moolenaar4ba37b52019-12-04 21:57:43 +0100546 // Convert the utf-8 string to 'encoding'.
Bram Moolenaarb3628722016-02-28 14:56:39 +0100547 conv.vc_type = CONV_NONE;
548 convert_setup(&conv, (char_u*)"utf-8", p_enc);
549 if (conv.vc_type != CONV_NONE)
550 {
551 res->vval.v_string =
552 string_convert(&conv, ga.ga_data, NULL);
553 vim_free(ga.ga_data);
554 }
555 convert_setup(&conv, NULL, NULL);
556 }
557 else
558#endif
559 res->vval.v_string = ga.ga_data;
Bram Moolenaar56ead342016-02-02 18:20:08 +0100560 }
561 return OK;
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100562 }
Bram Moolenaar56ead342016-02-02 18:20:08 +0100563 if (res != NULL)
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100564 {
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100565 res->v_type = VAR_SPECIAL;
566 res->vval.v_number = VVAL_NONE;
Bram Moolenaar56ead342016-02-02 18:20:08 +0100567 ga_clear(&ga);
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100568 }
Bram Moolenaar56ead342016-02-02 18:20:08 +0100569 return MAYBE;
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100570}
571
Bram Moolenaar8b2f1952017-01-10 19:44:18 +0100572typedef enum {
Bram Moolenaar4ba37b52019-12-04 21:57:43 +0100573 JSON_ARRAY, // parsing items in an array
574 JSON_OBJECT_KEY, // parsing key of an object
575 JSON_OBJECT // parsing item in an object, after the key
Bram Moolenaar8b2f1952017-01-10 19:44:18 +0100576} json_decode_T;
577
578typedef struct {
579 json_decode_T jd_type;
Bram Moolenaar4ba37b52019-12-04 21:57:43 +0100580 typval_T jd_tv; // the list or dict
Bram Moolenaar8b2f1952017-01-10 19:44:18 +0100581 typval_T jd_key_tv;
582 char_u *jd_key;
583} json_dec_item_T;
584
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100585/*
Bram Moolenaar56ead342016-02-02 18:20:08 +0100586 * Decode one item and put it in "res". If "res" is NULL only advance.
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100587 * Must already have skipped white space.
Bram Moolenaar56ead342016-02-02 18:20:08 +0100588 *
Bram Moolenaar03c60c12017-01-10 15:15:37 +0100589 * Return FAIL for a decoding error (and give an error).
Bram Moolenaar56ead342016-02-02 18:20:08 +0100590 * Return MAYBE for an incomplete message.
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100591 */
Bram Moolenaar56ead342016-02-02 18:20:08 +0100592 static int
Bram Moolenaar595e64e2016-02-07 19:19:53 +0100593json_decode_item(js_read_T *reader, typval_T *res, int options)
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100594{
Bram Moolenaar56ead342016-02-02 18:20:08 +0100595 char_u *p;
Bram Moolenaar6d3a7212020-07-12 14:34:00 +0200596 int i;
Bram Moolenaar56ead342016-02-02 18:20:08 +0100597 int len;
Bram Moolenaar8b2f1952017-01-10 19:44:18 +0100598 int retval;
599 garray_T stack;
600 typval_T item;
601 typval_T *cur_item;
602 json_dec_item_T *top_item;
603 char_u key_buf[NUMBUFLEN];
604
605 ga_init2(&stack, sizeof(json_dec_item_T), 100);
606 cur_item = res;
607 init_tv(&item);
Bram Moolenaare32abbe2017-01-10 22:57:34 +0100608 if (res != NULL)
609 init_tv(res);
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100610
Bram Moolenaar56ead342016-02-02 18:20:08 +0100611 fill_numbuflen(reader);
612 p = reader->js_buf + reader->js_used;
Bram Moolenaar8b2f1952017-01-10 19:44:18 +0100613 for (;;)
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100614 {
Bram Moolenaar8b2f1952017-01-10 19:44:18 +0100615 top_item = NULL;
616 if (stack.ga_len > 0)
617 {
618 top_item = ((json_dec_item_T *)stack.ga_data) + stack.ga_len - 1;
619 json_skip_white(reader);
620 p = reader->js_buf + reader->js_used;
621 if (*p == NUL)
Bram Moolenaar03c60c12017-01-10 15:15:37 +0100622 {
Bram Moolenaar8b2f1952017-01-10 19:44:18 +0100623 retval = MAYBE;
Bram Moolenaar8b2f1952017-01-10 19:44:18 +0100624 goto theend;
Bram Moolenaar03c60c12017-01-10 15:15:37 +0100625 }
Bram Moolenaar8b2f1952017-01-10 19:44:18 +0100626 if (top_item->jd_type == JSON_OBJECT_KEY
627 || top_item->jd_type == JSON_ARRAY)
Bram Moolenaar56ead342016-02-02 18:20:08 +0100628 {
Bram Moolenaar4ba37b52019-12-04 21:57:43 +0100629 // Check for end of object or array.
Bram Moolenaar8b2f1952017-01-10 19:44:18 +0100630 if (*p == (top_item->jd_type == JSON_ARRAY ? ']' : '}'))
Bram Moolenaar56ead342016-02-02 18:20:08 +0100631 {
Bram Moolenaar4ba37b52019-12-04 21:57:43 +0100632 ++reader->js_used; // consume the ']' or '}'
Bram Moolenaar8b2f1952017-01-10 19:44:18 +0100633 --stack.ga_len;
634 if (stack.ga_len == 0)
635 {
636 retval = OK;
637 goto theend;
638 }
639 if (cur_item != NULL)
640 cur_item = &top_item->jd_tv;
641 goto item_end;
642 }
643 }
644 }
645
646 if (top_item != NULL && top_item->jd_type == JSON_OBJECT_KEY
647 && (options & JSON_JS)
Bram Moolenaaree142ad2017-01-11 21:50:08 +0100648 && reader->js_buf[reader->js_used] != '"'
Bram Moolenaar625f0c12018-03-13 13:10:41 +0100649 && reader->js_buf[reader->js_used] != '\''
650 && reader->js_buf[reader->js_used] != '['
651 && reader->js_buf[reader->js_used] != '{')
Bram Moolenaar8b2f1952017-01-10 19:44:18 +0100652 {
653 char_u *key;
654
Bram Moolenaar4ba37b52019-12-04 21:57:43 +0100655 // accept an object key that is not in quotes
Bram Moolenaar8b2f1952017-01-10 19:44:18 +0100656 key = p = reader->js_buf + reader->js_used;
657 while (*p != NUL && *p != ':' && *p > ' ')
658 ++p;
Bram Moolenaare2c60372017-01-22 15:56:26 +0100659 if (cur_item != NULL)
660 {
661 cur_item->v_type = VAR_STRING;
Bram Moolenaar71ccd032020-06-12 22:59:11 +0200662 cur_item->vval.v_string = vim_strnsave(key, p - key);
Bram Moolenaare2c60372017-01-22 15:56:26 +0100663 top_item->jd_key = cur_item->vval.v_string;
664 }
Bram Moolenaar8b2f1952017-01-10 19:44:18 +0100665 reader->js_used += (int)(p - key);
Bram Moolenaar8b2f1952017-01-10 19:44:18 +0100666 }
667 else
668 {
669 switch (*p)
670 {
Bram Moolenaar4ba37b52019-12-04 21:57:43 +0100671 case '[': // start of array
Bram Moolenaar625f0c12018-03-13 13:10:41 +0100672 if (top_item && top_item->jd_type == JSON_OBJECT_KEY)
673 {
674 retval = FAIL;
675 break;
676 }
Bram Moolenaar8b2f1952017-01-10 19:44:18 +0100677 if (ga_grow(&stack, 1) == FAIL)
678 {
679 retval = FAIL;
680 break;
681 }
682 if (cur_item != NULL && rettv_list_alloc(cur_item) == FAIL)
683 {
684 cur_item->v_type = VAR_SPECIAL;
685 cur_item->vval.v_number = VVAL_NONE;
686 retval = FAIL;
687 break;
688 }
689
Bram Moolenaar4ba37b52019-12-04 21:57:43 +0100690 ++reader->js_used; // consume the '['
Bram Moolenaar8b2f1952017-01-10 19:44:18 +0100691 top_item = ((json_dec_item_T *)stack.ga_data)
692 + stack.ga_len;
693 top_item->jd_type = JSON_ARRAY;
694 ++stack.ga_len;
695 if (cur_item != NULL)
696 {
697 top_item->jd_tv = *cur_item;
698 cur_item = &item;
699 }
700 continue;
701
Bram Moolenaar4ba37b52019-12-04 21:57:43 +0100702 case '{': // start of object
Bram Moolenaar625f0c12018-03-13 13:10:41 +0100703 if (top_item && top_item->jd_type == JSON_OBJECT_KEY)
704 {
705 retval = FAIL;
706 break;
707 }
Bram Moolenaar8b2f1952017-01-10 19:44:18 +0100708 if (ga_grow(&stack, 1) == FAIL)
709 {
710 retval = FAIL;
711 break;
712 }
713 if (cur_item != NULL && rettv_dict_alloc(cur_item) == FAIL)
714 {
715 cur_item->v_type = VAR_SPECIAL;
716 cur_item->vval.v_number = VVAL_NONE;
717 retval = FAIL;
718 break;
719 }
720
Bram Moolenaar4ba37b52019-12-04 21:57:43 +0100721 ++reader->js_used; // consume the '{'
Bram Moolenaar8b2f1952017-01-10 19:44:18 +0100722 top_item = ((json_dec_item_T *)stack.ga_data)
723 + stack.ga_len;
724 top_item->jd_type = JSON_OBJECT_KEY;
725 ++stack.ga_len;
726 if (cur_item != NULL)
727 {
728 top_item->jd_tv = *cur_item;
729 cur_item = &top_item->jd_key_tv;
730 }
731 continue;
732
Bram Moolenaar4ba37b52019-12-04 21:57:43 +0100733 case '"': // string
Bram Moolenaaree142ad2017-01-11 21:50:08 +0100734 retval = json_decode_string(reader, cur_item, *p);
735 break;
736
737 case '\'':
738 if (options & JSON_JS)
739 retval = json_decode_string(reader, cur_item, *p);
740 else
741 {
Bram Moolenaara09195f2020-05-19 22:38:59 +0200742 semsg(_(e_json_error), p);
Bram Moolenaaree142ad2017-01-11 21:50:08 +0100743 retval = FAIL;
744 }
Bram Moolenaar8b2f1952017-01-10 19:44:18 +0100745 break;
746
Bram Moolenaar4ba37b52019-12-04 21:57:43 +0100747 case ',': // comma: empty item
Bram Moolenaar8b2f1952017-01-10 19:44:18 +0100748 if ((options & JSON_JS) == 0)
Bram Moolenaar03c60c12017-01-10 15:15:37 +0100749 {
Bram Moolenaara09195f2020-05-19 22:38:59 +0200750 semsg(_(e_json_error), p);
Bram Moolenaar8b2f1952017-01-10 19:44:18 +0100751 retval = FAIL;
752 break;
Bram Moolenaar03c60c12017-01-10 15:15:37 +0100753 }
Bram Moolenaar4ba37b52019-12-04 21:57:43 +0100754 // FALLTHROUGH
755 case NUL: // empty
Bram Moolenaar8b2f1952017-01-10 19:44:18 +0100756 if (cur_item != NULL)
Bram Moolenaar56ead342016-02-02 18:20:08 +0100757 {
Bram Moolenaar8b2f1952017-01-10 19:44:18 +0100758 cur_item->v_type = VAR_SPECIAL;
759 cur_item->vval.v_number = VVAL_NONE;
Bram Moolenaar56ead342016-02-02 18:20:08 +0100760 }
Bram Moolenaar8b2f1952017-01-10 19:44:18 +0100761 retval = OK;
762 break;
763
764 default:
Bram Moolenaara5d59532020-01-26 21:42:03 +0100765 if (VIM_ISDIGIT(*p) || (*p == '-'
766 && (VIM_ISDIGIT(p[1]) || p[1] == NUL)))
Bram Moolenaar8b2f1952017-01-10 19:44:18 +0100767 {
Bram Moolenaar8b2f1952017-01-10 19:44:18 +0100768 char_u *sp = p;
769
770 if (*sp == '-')
771 {
772 ++sp;
773 if (*sp == NUL)
774 {
775 retval = MAYBE;
776 break;
777 }
778 if (!VIM_ISDIGIT(*sp))
779 {
Bram Moolenaara09195f2020-05-19 22:38:59 +0200780 semsg(_(e_json_error), p);
Bram Moolenaar8b2f1952017-01-10 19:44:18 +0100781 retval = FAIL;
782 break;
783 }
784 }
785 sp = skipdigits(sp);
Bram Moolenaara5d59532020-01-26 21:42:03 +0100786#ifdef FEAT_FLOAT
Bram Moolenaar8b2f1952017-01-10 19:44:18 +0100787 if (*sp == '.' || *sp == 'e' || *sp == 'E')
788 {
789 if (cur_item == NULL)
790 {
791 float_T f;
792
793 len = string2float(p, &f);
794 }
795 else
796 {
797 cur_item->v_type = VAR_FLOAT;
798 len = string2float(p, &cur_item->vval.v_float);
799 }
800 }
801 else
802#endif
803 {
804 varnumber_T nr;
805
806 vim_str2nr(reader->js_buf + reader->js_used,
Bram Moolenaar4ba37b52019-12-04 21:57:43 +0100807 NULL, &len, 0, // what
Bram Moolenaar16e9b852019-05-19 19:59:35 +0200808 &nr, NULL, 0, TRUE);
809 if (len == 0)
810 {
Bram Moolenaara09195f2020-05-19 22:38:59 +0200811 semsg(_(e_json_error), p);
Bram Moolenaar16e9b852019-05-19 19:59:35 +0200812 retval = FAIL;
813 goto theend;
814 }
Bram Moolenaar8b2f1952017-01-10 19:44:18 +0100815 if (cur_item != NULL)
816 {
817 cur_item->v_type = VAR_NUMBER;
818 cur_item->vval.v_number = nr;
819 }
820 }
821 reader->js_used += len;
822 retval = OK;
823 break;
824 }
825 if (STRNICMP((char *)p, "false", 5) == 0)
826 {
827 reader->js_used += 5;
828 if (cur_item != NULL)
829 {
Bram Moolenaar9b4a15d2020-01-11 16:05:23 +0100830 cur_item->v_type = VAR_BOOL;
Bram Moolenaar8b2f1952017-01-10 19:44:18 +0100831 cur_item->vval.v_number = VVAL_FALSE;
832 }
833 retval = OK;
834 break;
835 }
836 if (STRNICMP((char *)p, "true", 4) == 0)
837 {
838 reader->js_used += 4;
839 if (cur_item != NULL)
840 {
Bram Moolenaar9b4a15d2020-01-11 16:05:23 +0100841 cur_item->v_type = VAR_BOOL;
Bram Moolenaar8b2f1952017-01-10 19:44:18 +0100842 cur_item->vval.v_number = VVAL_TRUE;
843 }
844 retval = OK;
845 break;
846 }
847 if (STRNICMP((char *)p, "null", 4) == 0)
848 {
849 reader->js_used += 4;
850 if (cur_item != NULL)
851 {
852 cur_item->v_type = VAR_SPECIAL;
853 cur_item->vval.v_number = VVAL_NULL;
854 }
855 retval = OK;
856 break;
857 }
858#ifdef FEAT_FLOAT
859 if (STRNICMP((char *)p, "NaN", 3) == 0)
860 {
861 reader->js_used += 3;
862 if (cur_item != NULL)
863 {
864 cur_item->v_type = VAR_FLOAT;
865 cur_item->vval.v_float = NAN;
866 }
867 retval = OK;
868 break;
869 }
Bram Moolenaar5f6b3792019-01-12 14:24:27 +0100870 if (STRNICMP((char *)p, "-Infinity", 9) == 0)
871 {
872 reader->js_used += 9;
873 if (cur_item != NULL)
874 {
875 cur_item->v_type = VAR_FLOAT;
876 cur_item->vval.v_float = -INFINITY;
877 }
878 retval = OK;
879 break;
880 }
Bram Moolenaar8b2f1952017-01-10 19:44:18 +0100881 if (STRNICMP((char *)p, "Infinity", 8) == 0)
882 {
883 reader->js_used += 8;
884 if (cur_item != NULL)
885 {
886 cur_item->v_type = VAR_FLOAT;
887 cur_item->vval.v_float = INFINITY;
888 }
889 retval = OK;
890 break;
891 }
892#endif
Bram Moolenaar4ba37b52019-12-04 21:57:43 +0100893 // check for truncated name
Bram Moolenaara5d59532020-01-26 21:42:03 +0100894 len = (int)(reader->js_end
895 - (reader->js_buf + reader->js_used));
Bram Moolenaar8b2f1952017-01-10 19:44:18 +0100896 if (
897 (len < 5 && STRNICMP((char *)p, "false", len) == 0)
898#ifdef FEAT_FLOAT
Bram Moolenaar5f6b3792019-01-12 14:24:27 +0100899 || (len < 9 && STRNICMP((char *)p, "-Infinity", len) == 0)
Bram Moolenaar8b2f1952017-01-10 19:44:18 +0100900 || (len < 8 && STRNICMP((char *)p, "Infinity", len) == 0)
901 || (len < 3 && STRNICMP((char *)p, "NaN", len) == 0)
902#endif
903 || (len < 4 && (STRNICMP((char *)p, "true", len) == 0
904 || STRNICMP((char *)p, "null", len) == 0)))
905
906 retval = MAYBE;
907 else
908 retval = FAIL;
909 break;
910 }
911
Bram Moolenaar4ba37b52019-12-04 21:57:43 +0100912 // We are finished when retval is FAIL or MAYBE and when at the
913 // toplevel.
Bram Moolenaar8b2f1952017-01-10 19:44:18 +0100914 if (retval == FAIL)
915 break;
916 if (retval == MAYBE || stack.ga_len == 0)
917 goto theend;
918
919 if (top_item != NULL && top_item->jd_type == JSON_OBJECT_KEY
920 && cur_item != NULL)
921 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +0100922 top_item->jd_key = tv_get_string_buf_chk(cur_item, key_buf);
Bram Moolenaar059b7482017-02-05 16:34:43 +0100923 if (top_item->jd_key == NULL)
Bram Moolenaar8b2f1952017-01-10 19:44:18 +0100924 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +0100925 emsg(_(e_invarg));
Bram Moolenaar8b2f1952017-01-10 19:44:18 +0100926 retval = FAIL;
927 goto theend;
928 }
929 }
930 }
931
932item_end:
933 top_item = ((json_dec_item_T *)stack.ga_data) + stack.ga_len - 1;
934 switch (top_item->jd_type)
935 {
936 case JSON_ARRAY:
937 if (res != NULL)
938 {
939 listitem_T *li = listitem_alloc();
940
941 if (li == NULL)
942 {
943 clear_tv(cur_item);
944 retval = FAIL;
945 goto theend;
946 }
947 li->li_tv = *cur_item;
948 list_append(top_item->jd_tv.vval.v_list, li);
949 }
950 if (cur_item != NULL)
951 cur_item = &item;
952
953 json_skip_white(reader);
954 p = reader->js_buf + reader->js_used;
955 if (*p == ',')
956 ++reader->js_used;
957 else if (*p != ']')
958 {
959 if (*p == NUL)
960 retval = MAYBE;
Bram Moolenaar56ead342016-02-02 18:20:08 +0100961 else
962 {
Bram Moolenaara09195f2020-05-19 22:38:59 +0200963 semsg(_(e_json_error), p);
Bram Moolenaar8b2f1952017-01-10 19:44:18 +0100964 retval = FAIL;
Bram Moolenaar56ead342016-02-02 18:20:08 +0100965 }
Bram Moolenaar8b2f1952017-01-10 19:44:18 +0100966 goto theend;
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100967 }
Bram Moolenaar8b2f1952017-01-10 19:44:18 +0100968 break;
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100969
Bram Moolenaar8b2f1952017-01-10 19:44:18 +0100970 case JSON_OBJECT_KEY:
971 json_skip_white(reader);
972 p = reader->js_buf + reader->js_used;
973 if (*p != ':')
974 {
975 if (cur_item != NULL)
976 clear_tv(cur_item);
977 if (*p == NUL)
978 retval = MAYBE;
979 else
Bram Moolenaar56ead342016-02-02 18:20:08 +0100980 {
Bram Moolenaara09195f2020-05-19 22:38:59 +0200981 semsg(_(e_json_error), p);
Bram Moolenaar8b2f1952017-01-10 19:44:18 +0100982 retval = FAIL;
983 }
984 goto theend;
985 }
986 ++reader->js_used;
987 json_skip_white(reader);
988 top_item->jd_type = JSON_OBJECT;
989 if (cur_item != NULL)
990 cur_item = &item;
991 break;
992
993 case JSON_OBJECT:
994 if (cur_item != NULL
995 && dict_find(top_item->jd_tv.vval.v_dict,
996 top_item->jd_key, -1) != NULL)
997 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +0100998 semsg(_("E938: Duplicate key in JSON: \"%s\""),
Bram Moolenaar8b2f1952017-01-10 19:44:18 +0100999 top_item->jd_key);
Bram Moolenaar8b2f1952017-01-10 19:44:18 +01001000 clear_tv(cur_item);
1001 retval = FAIL;
1002 goto theend;
1003 }
1004
1005 if (cur_item != NULL)
1006 {
1007 dictitem_T *di = dictitem_alloc(top_item->jd_key);
1008
1009 clear_tv(&top_item->jd_key_tv);
1010 if (di == NULL)
1011 {
1012 clear_tv(cur_item);
1013 retval = FAIL;
1014 goto theend;
1015 }
1016 di->di_tv = *cur_item;
1017 di->di_tv.v_lock = 0;
1018 if (dict_add(top_item->jd_tv.vval.v_dict, di) == FAIL)
1019 {
1020 dictitem_free(di);
1021 retval = FAIL;
1022 goto theend;
Bram Moolenaar56ead342016-02-02 18:20:08 +01001023 }
Bram Moolenaar520e1e42016-01-23 19:46:28 +01001024 }
Bram Moolenaar8b2f1952017-01-10 19:44:18 +01001025
1026 json_skip_white(reader);
1027 p = reader->js_buf + reader->js_used;
1028 if (*p == ',')
1029 ++reader->js_used;
1030 else if (*p != '}')
Bram Moolenaar56ead342016-02-02 18:20:08 +01001031 {
Bram Moolenaar8b2f1952017-01-10 19:44:18 +01001032 if (*p == NUL)
1033 retval = MAYBE;
1034 else
1035 {
Bram Moolenaara09195f2020-05-19 22:38:59 +02001036 semsg(_(e_json_error), p);
Bram Moolenaar8b2f1952017-01-10 19:44:18 +01001037 retval = FAIL;
1038 }
1039 goto theend;
Bram Moolenaar56ead342016-02-02 18:20:08 +01001040 }
Bram Moolenaar8b2f1952017-01-10 19:44:18 +01001041 top_item->jd_type = JSON_OBJECT_KEY;
1042 if (cur_item != NULL)
1043 cur_item = &top_item->jd_key_tv;
1044 break;
1045 }
Bram Moolenaar520e1e42016-01-23 19:46:28 +01001046 }
1047
Bram Moolenaar4ba37b52019-12-04 21:57:43 +01001048 // Get here when parsing failed.
Bram Moolenaar7756e742016-10-21 20:35:37 +02001049 if (res != NULL)
Bram Moolenaar56ead342016-02-02 18:20:08 +01001050 {
Bram Moolenaar8b2f1952017-01-10 19:44:18 +01001051 clear_tv(res);
Bram Moolenaar56ead342016-02-02 18:20:08 +01001052 res->v_type = VAR_SPECIAL;
1053 res->vval.v_number = VVAL_NONE;
1054 }
Bram Moolenaara09195f2020-05-19 22:38:59 +02001055 semsg(_(e_json_error), p);
Bram Moolenaar8b2f1952017-01-10 19:44:18 +01001056
1057theend:
Bram Moolenaar6d3a7212020-07-12 14:34:00 +02001058 for (i = 0; i < stack.ga_len; i++)
1059 clear_tv(&(((json_dec_item_T *)stack.ga_data) + i)->jd_key_tv);
Bram Moolenaar8b2f1952017-01-10 19:44:18 +01001060 ga_clear(&stack);
Bram Moolenaar6d3a7212020-07-12 14:34:00 +02001061
Bram Moolenaar8b2f1952017-01-10 19:44:18 +01001062 return retval;
Bram Moolenaar520e1e42016-01-23 19:46:28 +01001063}
1064
1065/*
1066 * Decode the JSON from "reader" and store the result in "res".
Bram Moolenaar595e64e2016-02-07 19:19:53 +01001067 * "options" can be JSON_JS or zero;
Bram Moolenaar56ead342016-02-02 18:20:08 +01001068 * Return FAIL if not the whole message was consumed.
Bram Moolenaar520e1e42016-01-23 19:46:28 +01001069 */
Bram Moolenaar5843f5f2019-08-20 20:13:45 +02001070 static int
Bram Moolenaar595e64e2016-02-07 19:19:53 +01001071json_decode_all(js_read_T *reader, typval_T *res, int options)
Bram Moolenaar520e1e42016-01-23 19:46:28 +01001072{
Bram Moolenaar56ead342016-02-02 18:20:08 +01001073 int ret;
1074
Bram Moolenaar4ba37b52019-12-04 21:57:43 +01001075 // We find the end once, to avoid calling strlen() many times.
Bram Moolenaar56ead342016-02-02 18:20:08 +01001076 reader->js_end = reader->js_buf + STRLEN(reader->js_buf);
Bram Moolenaar520e1e42016-01-23 19:46:28 +01001077 json_skip_white(reader);
Bram Moolenaar595e64e2016-02-07 19:19:53 +01001078 ret = json_decode_item(reader, res, options);
Bram Moolenaar56ead342016-02-02 18:20:08 +01001079 if (ret != OK)
Bram Moolenaar03c60c12017-01-10 15:15:37 +01001080 {
1081 if (ret == MAYBE)
Bram Moolenaara09195f2020-05-19 22:38:59 +02001082 semsg(_(e_json_error), reader->js_buf);
Bram Moolenaar56ead342016-02-02 18:20:08 +01001083 return FAIL;
Bram Moolenaar03c60c12017-01-10 15:15:37 +01001084 }
Bram Moolenaar520e1e42016-01-23 19:46:28 +01001085 json_skip_white(reader);
1086 if (reader->js_buf[reader->js_used] != NUL)
Bram Moolenaar03c60c12017-01-10 15:15:37 +01001087 {
Bram Moolenaar2d06bfd2020-07-23 17:16:18 +02001088 semsg(_(e_trailing_arg), reader->js_buf + reader->js_used);
Bram Moolenaar19d2f152016-02-01 21:38:19 +01001089 return FAIL;
Bram Moolenaar03c60c12017-01-10 15:15:37 +01001090 }
Bram Moolenaar19d2f152016-02-01 21:38:19 +01001091 return OK;
Bram Moolenaar520e1e42016-01-23 19:46:28 +01001092}
Bram Moolenaar56ead342016-02-02 18:20:08 +01001093
Bram Moolenaar113e1072019-01-20 15:30:40 +01001094#if defined(FEAT_JOB_CHANNEL) || defined(PROTO)
Bram Moolenaar56ead342016-02-02 18:20:08 +01001095/*
1096 * Decode the JSON from "reader" and store the result in "res".
Bram Moolenaar595e64e2016-02-07 19:19:53 +01001097 * "options" can be JSON_JS or zero;
Bram Moolenaarba61ac02016-03-20 16:40:37 +01001098 * Return FAIL for a decoding error.
1099 * Return MAYBE for an incomplete message.
1100 * Consumes the message anyway.
Bram Moolenaar56ead342016-02-02 18:20:08 +01001101 */
1102 int
Bram Moolenaar595e64e2016-02-07 19:19:53 +01001103json_decode(js_read_T *reader, typval_T *res, int options)
Bram Moolenaar56ead342016-02-02 18:20:08 +01001104{
1105 int ret;
1106
Bram Moolenaar4ba37b52019-12-04 21:57:43 +01001107 // We find the end once, to avoid calling strlen() many times.
Bram Moolenaar56ead342016-02-02 18:20:08 +01001108 reader->js_end = reader->js_buf + STRLEN(reader->js_buf);
1109 json_skip_white(reader);
Bram Moolenaar595e64e2016-02-07 19:19:53 +01001110 ret = json_decode_item(reader, res, options);
Bram Moolenaar56ead342016-02-02 18:20:08 +01001111 json_skip_white(reader);
1112
Bram Moolenaarba61ac02016-03-20 16:40:37 +01001113 return ret;
Bram Moolenaar56ead342016-02-02 18:20:08 +01001114}
Bram Moolenaar113e1072019-01-20 15:30:40 +01001115#endif
Bram Moolenaar56ead342016-02-02 18:20:08 +01001116
1117/*
1118 * Decode the JSON from "reader" to find the end of the message.
Bram Moolenaare2c60372017-01-22 15:56:26 +01001119 * "options" can be JSON_JS or zero.
1120 * This is only used for testing.
Bram Moolenaar56ead342016-02-02 18:20:08 +01001121 * Return FAIL if the message has a decoding error.
1122 * Return MAYBE if the message is truncated, need to read more.
1123 * This only works reliable if the message contains an object, array or
Bram Moolenaar5f6b3792019-01-12 14:24:27 +01001124 * string. A number might be truncated without knowing.
Bram Moolenaar56ead342016-02-02 18:20:08 +01001125 * Does not advance the reader.
1126 */
1127 int
Bram Moolenaar595e64e2016-02-07 19:19:53 +01001128json_find_end(js_read_T *reader, int options)
Bram Moolenaar56ead342016-02-02 18:20:08 +01001129{
1130 int used_save = reader->js_used;
1131 int ret;
1132
Bram Moolenaar4ba37b52019-12-04 21:57:43 +01001133 // We find the end once, to avoid calling strlen() many times.
Bram Moolenaar56ead342016-02-02 18:20:08 +01001134 reader->js_end = reader->js_buf + STRLEN(reader->js_buf);
1135 json_skip_white(reader);
Bram Moolenaar595e64e2016-02-07 19:19:53 +01001136 ret = json_decode_item(reader, NULL, options);
Bram Moolenaar56ead342016-02-02 18:20:08 +01001137 reader->js_used = used_save;
1138 return ret;
1139}
Bram Moolenaar29b7d7a2019-07-22 23:03:57 +02001140
1141/*
1142 * "js_decode()" function
1143 */
1144 void
1145f_js_decode(typval_T *argvars, typval_T *rettv)
1146{
1147 js_read_T reader;
1148
1149 reader.js_buf = tv_get_string(&argvars[0]);
1150 reader.js_fill = NULL;
1151 reader.js_used = 0;
1152 if (json_decode_all(&reader, rettv, JSON_JS) != OK)
1153 emsg(_(e_invarg));
1154}
1155
1156/*
1157 * "js_encode()" function
1158 */
1159 void
1160f_js_encode(typval_T *argvars, typval_T *rettv)
1161{
1162 rettv->v_type = VAR_STRING;
1163 rettv->vval.v_string = json_encode(&argvars[0], JSON_JS);
1164}
1165
1166/*
1167 * "json_decode()" function
1168 */
1169 void
1170f_json_decode(typval_T *argvars, typval_T *rettv)
1171{
1172 js_read_T reader;
1173
1174 reader.js_buf = tv_get_string(&argvars[0]);
1175 reader.js_fill = NULL;
1176 reader.js_used = 0;
1177 json_decode_all(&reader, rettv, 0);
1178}
1179
1180/*
1181 * "json_encode()" function
1182 */
1183 void
1184f_json_encode(typval_T *argvars, typval_T *rettv)
1185{
1186 rettv->v_type = VAR_STRING;
1187 rettv->vval.v_string = json_encode(&argvars[0], 0);
1188}
Bram Moolenaarc61a48d2019-07-22 23:16:33 +02001189#endif