blob: d8ccfe8fbee16749cf09331e84506e5af0ba273e [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
23/*
24 * Encode "val" into a JSON format string.
Bram Moolenaarf1f07922016-08-26 17:58:53 +020025 * The result is added to "gap"
26 * Returns FAIL on failure and makes gap->ga_data empty.
27 */
28 static int
29json_encode_gap(garray_T *gap, typval_T *val, int options)
30{
31 if (json_encode_item(gap, val, get_copyID(), options) == FAIL)
32 {
33 ga_clear(gap);
34 gap->ga_data = vim_strsave((char_u *)"");
35 return FAIL;
36 }
37 return OK;
38}
39
40/*
41 * Encode "val" into a JSON format string.
Bram Moolenaar55fab432016-02-07 16:53:13 +010042 * The result is in allocated memory.
43 * The result is empty when encoding fails.
Bram Moolenaarf1f07922016-08-26 17:58:53 +020044 * "options" can contain JSON_JS, JSON_NO_NONE and JSON_NL.
Bram Moolenaar520e1e42016-01-23 19:46:28 +010045 */
46 char_u *
Bram Moolenaar595e64e2016-02-07 19:19:53 +010047json_encode(typval_T *val, int options)
Bram Moolenaar520e1e42016-01-23 19:46:28 +010048{
49 garray_T ga;
50
51 /* Store bytes in the growarray. */
52 ga_init2(&ga, 1, 4000);
Bram Moolenaarf1f07922016-08-26 17:58:53 +020053 json_encode_gap(&ga, val, options);
Bram Moolenaar520e1e42016-01-23 19:46:28 +010054 return ga.ga_data;
55}
56
Bram Moolenaarfb1f6262016-01-31 20:24:32 +010057/*
Bram Moolenaar55fab432016-02-07 16:53:13 +010058 * Encode ["nr", "val"] into a JSON format string in allocated memory.
Bram Moolenaarf1f07922016-08-26 17:58:53 +020059 * "options" can contain JSON_JS, JSON_NO_NONE and JSON_NL.
Bram Moolenaarfb1f6262016-01-31 20:24:32 +010060 * Returns NULL when out of memory.
61 */
62 char_u *
Bram Moolenaar595e64e2016-02-07 19:19:53 +010063json_encode_nr_expr(int nr, typval_T *val, int options)
Bram Moolenaarfb1f6262016-01-31 20:24:32 +010064{
65 typval_T listtv;
66 typval_T nrtv;
Bram Moolenaarf1f07922016-08-26 17:58:53 +020067 garray_T ga;
Bram Moolenaarfb1f6262016-01-31 20:24:32 +010068
69 nrtv.v_type = VAR_NUMBER;
70 nrtv.vval.v_number = nr;
71 if (rettv_list_alloc(&listtv) == FAIL)
72 return NULL;
73 if (list_append_tv(listtv.vval.v_list, &nrtv) == FAIL
74 || list_append_tv(listtv.vval.v_list, val) == FAIL)
75 {
76 list_unref(listtv.vval.v_list);
77 return NULL;
78 }
79
Bram Moolenaarf1f07922016-08-26 17:58:53 +020080 ga_init2(&ga, 1, 4000);
81 if (json_encode_gap(&ga, &listtv, options) == OK && (options & JSON_NL))
82 ga_append(&ga, '\n');
Bram Moolenaarfb1f6262016-01-31 20:24:32 +010083 list_unref(listtv.vval.v_list);
Bram Moolenaarf1f07922016-08-26 17:58:53 +020084 return ga.ga_data;
Bram Moolenaarfb1f6262016-01-31 20:24:32 +010085}
86
Bram Moolenaar520e1e42016-01-23 19:46:28 +010087 static void
88write_string(garray_T *gap, char_u *str)
89{
90 char_u *res = str;
91 char_u numbuf[NUMBUFLEN];
92
93 if (res == NULL)
Bram Moolenaarb29d3282017-12-15 21:25:01 +010094 ga_concat(gap, (char_u *)"\"\"");
Bram Moolenaar520e1e42016-01-23 19:46:28 +010095 else
96 {
Bram Moolenaarb6ff8112016-02-27 18:41:27 +010097#if defined(FEAT_MBYTE) && defined(USE_ICONV)
98 vimconv_T conv;
99 char_u *converted = NULL;
100
Bram Moolenaarf97ddbe2016-02-27 21:13:38 +0100101 if (!enc_utf8)
102 {
Bram Moolenaarb3628722016-02-28 14:56:39 +0100103 /* Convert the text from 'encoding' to utf-8, the JSON string is
104 * always utf-8. */
Bram Moolenaarf97ddbe2016-02-27 21:13:38 +0100105 conv.vc_type = CONV_NONE;
106 convert_setup(&conv, p_enc, (char_u*)"utf-8");
107 if (conv.vc_type != CONV_NONE)
108 converted = res = string_convert(&conv, res, NULL);
109 convert_setup(&conv, NULL, NULL);
110 }
Bram Moolenaarb6ff8112016-02-27 18:41:27 +0100111#endif
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100112 ga_append(gap, '"');
113 while (*res != NUL)
114 {
Bram Moolenaarb6ff8112016-02-27 18:41:27 +0100115 int c;
116#ifdef FEAT_MBYTE
117 /* always use utf-8 encoding, ignore 'encoding' */
118 c = utf_ptr2char(res);
119#else
Bram Moolenaar0f526f52016-02-27 22:59:41 +0100120 c = *res;
Bram Moolenaarb6ff8112016-02-27 18:41:27 +0100121#endif
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100122
123 switch (c)
124 {
125 case 0x08:
126 ga_append(gap, '\\'); ga_append(gap, 'b'); break;
127 case 0x09:
128 ga_append(gap, '\\'); ga_append(gap, 't'); break;
129 case 0x0a:
130 ga_append(gap, '\\'); ga_append(gap, 'n'); break;
131 case 0x0c:
132 ga_append(gap, '\\'); ga_append(gap, 'f'); break;
133 case 0x0d:
134 ga_append(gap, '\\'); ga_append(gap, 'r'); break;
135 case 0x22: /* " */
136 case 0x5c: /* \ */
137 ga_append(gap, '\\');
138 ga_append(gap, c);
139 break;
140 default:
141 if (c >= 0x20)
142 {
Bram Moolenaarfa06a512016-01-28 22:46:58 +0100143#ifdef FEAT_MBYTE
Bram Moolenaarb6ff8112016-02-27 18:41:27 +0100144 numbuf[utf_char2bytes(c, numbuf)] = NUL;
Bram Moolenaarfa06a512016-01-28 22:46:58 +0100145#else
146 numbuf[0] = c;
147 numbuf[1] = NUL;
148#endif
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100149 ga_concat(gap, numbuf);
150 }
151 else
152 {
153 vim_snprintf((char *)numbuf, NUMBUFLEN,
154 "\\u%04lx", (long)c);
155 ga_concat(gap, numbuf);
156 }
157 }
Bram Moolenaarb6ff8112016-02-27 18:41:27 +0100158#ifdef FEAT_MBYTE
159 res += utf_ptr2len(res);
160#else
Bram Moolenaar0f526f52016-02-27 22:59:41 +0100161 ++res;
Bram Moolenaarb6ff8112016-02-27 18:41:27 +0100162#endif
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100163 }
164 ga_append(gap, '"');
Bram Moolenaarb6ff8112016-02-27 18:41:27 +0100165#if defined(FEAT_MBYTE) && defined(USE_ICONV)
166 vim_free(converted);
167#endif
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100168 }
169}
170
Bram Moolenaarfcaaae62016-01-24 16:49:11 +0100171/*
Bram Moolenaar595e64e2016-02-07 19:19:53 +0100172 * Return TRUE if "key" can be used without quotes.
173 * That is when it starts with a letter and only contains letters, digits and
174 * underscore.
175 */
176 static int
177is_simple_key(char_u *key)
178{
179 char_u *p;
180
181 if (!ASCII_ISALPHA(*key))
182 return FALSE;
183 for (p = key + 1; *p != NUL; ++p)
184 if (!ASCII_ISALPHA(*p) && *p != '_' && !vim_isdigit(*p))
185 return FALSE;
186 return TRUE;
187}
188
189/*
Bram Moolenaarfcaaae62016-01-24 16:49:11 +0100190 * Encode "val" into "gap".
191 * Return FAIL or OK.
192 */
193 static int
Bram Moolenaar595e64e2016-02-07 19:19:53 +0100194json_encode_item(garray_T *gap, typval_T *val, int copyID, int options)
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100195{
196 char_u numbuf[NUMBUFLEN];
197 char_u *res;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +0100198 blob_T *b;
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100199 list_T *l;
200 dict_T *d;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +0100201 int i;
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100202
203 switch (val->v_type)
204 {
205 case VAR_SPECIAL:
Bram Moolenaarfcaaae62016-01-24 16:49:11 +0100206 switch (val->vval.v_number)
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100207 {
208 case VVAL_FALSE: ga_concat(gap, (char_u *)"false"); break;
209 case VVAL_TRUE: ga_concat(gap, (char_u *)"true"); break;
Bram Moolenaar595e64e2016-02-07 19:19:53 +0100210 case VVAL_NONE: if ((options & JSON_JS) != 0
211 && (options & JSON_NO_NONE) == 0)
212 /* empty item */
213 break;
214 /* FALLTHROUGH */
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100215 case VVAL_NULL: ga_concat(gap, (char_u *)"null"); break;
216 }
217 break;
218
219 case VAR_NUMBER:
Bram Moolenaar22fcfad2016-07-01 18:17:26 +0200220 vim_snprintf((char *)numbuf, NUMBUFLEN, "%lld",
Bram Moolenaarea391762018-04-08 13:07:22 +0200221 (long long)val->vval.v_number);
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100222 ga_concat(gap, numbuf);
223 break;
224
225 case VAR_STRING:
226 res = val->vval.v_string;
227 write_string(gap, res);
228 break;
229
230 case VAR_FUNC:
Bram Moolenaar1735bc92016-03-14 23:05:14 +0100231 case VAR_PARTIAL:
Bram Moolenaar55fab432016-02-07 16:53:13 +0100232 case VAR_JOB:
Bram Moolenaar77073442016-02-13 23:23:53 +0100233 case VAR_CHANNEL:
Bram Moolenaar4f8b8fa2016-02-06 18:42:07 +0100234 /* no JSON equivalent TODO: better error */
Bram Moolenaarfcaaae62016-01-24 16:49:11 +0100235 EMSG(_(e_invarg));
236 return FAIL;
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100237
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +0100238 case VAR_BLOB:
239 b = val->vval.v_blob;
240 if (b == NULL || b->bv_ga.ga_len == 0)
241 ga_concat(gap, (char_u *)"[]");
242 else
243 {
244 ga_append(gap, '[');
245 for (i = 0; i < b->bv_ga.ga_len; i++)
246 {
247 if (i > 0)
248 ga_concat(gap, (char_u *)",");
249 vim_snprintf((char *)numbuf, NUMBUFLEN, "%d",
250 (int)blob_get(b, i));
251 ga_concat(gap, numbuf);
252 }
253 ga_append(gap, ']');
254 }
255 break;
256
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100257 case VAR_LIST:
258 l = val->vval.v_list;
259 if (l == NULL)
Bram Moolenaarb29d3282017-12-15 21:25:01 +0100260 ga_concat(gap, (char_u *)"[]");
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100261 else
262 {
263 if (l->lv_copyID == copyID)
264 ga_concat(gap, (char_u *)"[]");
265 else
266 {
267 listitem_T *li;
268
269 l->lv_copyID = copyID;
270 ga_append(gap, '[');
271 for (li = l->lv_first; li != NULL && !got_int; )
272 {
Bram Moolenaar595e64e2016-02-07 19:19:53 +0100273 if (json_encode_item(gap, &li->li_tv, copyID,
274 options & JSON_JS) == FAIL)
Bram Moolenaarfcaaae62016-01-24 16:49:11 +0100275 return FAIL;
Bram Moolenaar595e64e2016-02-07 19:19:53 +0100276 if ((options & JSON_JS)
277 && li->li_next == NULL
278 && li->li_tv.v_type == VAR_SPECIAL
279 && li->li_tv.vval.v_number == VVAL_NONE)
280 /* add an extra comma if the last item is v:none */
281 ga_append(gap, ',');
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100282 li = li->li_next;
283 if (li != NULL)
284 ga_append(gap, ',');
285 }
286 ga_append(gap, ']');
Bram Moolenaarfcaaae62016-01-24 16:49:11 +0100287 l->lv_copyID = 0;
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100288 }
289 }
290 break;
291
292 case VAR_DICT:
293 d = val->vval.v_dict;
294 if (d == NULL)
Bram Moolenaarb29d3282017-12-15 21:25:01 +0100295 ga_concat(gap, (char_u *)"{}");
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100296 else
297 {
298 if (d->dv_copyID == copyID)
299 ga_concat(gap, (char_u *)"{}");
300 else
301 {
302 int first = TRUE;
303 int todo = (int)d->dv_hashtab.ht_used;
304 hashitem_T *hi;
305
306 d->dv_copyID = copyID;
307 ga_append(gap, '{');
308
309 for (hi = d->dv_hashtab.ht_array; todo > 0 && !got_int;
310 ++hi)
311 if (!HASHITEM_EMPTY(hi))
312 {
313 --todo;
314 if (first)
315 first = FALSE;
316 else
317 ga_append(gap, ',');
Bram Moolenaar595e64e2016-02-07 19:19:53 +0100318 if ((options & JSON_JS)
319 && is_simple_key(hi->hi_key))
320 ga_concat(gap, hi->hi_key);
321 else
322 write_string(gap, hi->hi_key);
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100323 ga_append(gap, ':');
Bram Moolenaarfcaaae62016-01-24 16:49:11 +0100324 if (json_encode_item(gap, &dict_lookup(hi)->di_tv,
Bram Moolenaar595e64e2016-02-07 19:19:53 +0100325 copyID, options | JSON_NO_NONE) == FAIL)
Bram Moolenaarfcaaae62016-01-24 16:49:11 +0100326 return FAIL;
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100327 }
328 ga_append(gap, '}');
Bram Moolenaarfcaaae62016-01-24 16:49:11 +0100329 d->dv_copyID = 0;
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100330 }
331 }
332 break;
333
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100334 case VAR_FLOAT:
Bram Moolenaar55fab432016-02-07 16:53:13 +0100335#ifdef FEAT_FLOAT
Bram Moolenaarf1b6ac72016-02-23 21:26:43 +0100336# if defined(HAVE_MATH_H)
Bram Moolenaar7ce686c2016-02-27 16:33:22 +0100337 if (isnan(val->vval.v_float))
Bram Moolenaarf1b6ac72016-02-23 21:26:43 +0100338 ga_concat(gap, (char_u *)"NaN");
Bram Moolenaar7ce686c2016-02-27 16:33:22 +0100339 else if (isinf(val->vval.v_float))
Bram Moolenaar5f6b3792019-01-12 14:24:27 +0100340 {
341 if (val->vval.v_float < 0.0)
342 ga_concat(gap, (char_u *)"-Infinity");
343 else
344 ga_concat(gap, (char_u *)"Infinity");
345 }
Bram Moolenaarf1b6ac72016-02-23 21:26:43 +0100346 else
347# endif
348 {
349 vim_snprintf((char *)numbuf, NUMBUFLEN, "%g",
350 val->vval.v_float);
351 ga_concat(gap, numbuf);
352 }
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100353 break;
354#endif
Bram Moolenaar55fab432016-02-07 16:53:13 +0100355 case VAR_UNKNOWN:
Bram Moolenaar95f09602016-11-10 20:01:45 +0100356 internal_error("json_encode_item()");
Bram Moolenaar55fab432016-02-07 16:53:13 +0100357 return FAIL;
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100358 }
Bram Moolenaarfcaaae62016-01-24 16:49:11 +0100359 return OK;
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100360}
361
362/*
Bram Moolenaar56ead342016-02-02 18:20:08 +0100363 * When "reader" has less than NUMBUFLEN bytes available, call the fill
364 * callback to get more.
365 */
366 static void
367fill_numbuflen(js_read_T *reader)
368{
369 if (reader->js_fill != NULL && (int)(reader->js_end - reader->js_buf)
370 - reader->js_used < NUMBUFLEN)
371 {
372 if (reader->js_fill(reader))
373 reader->js_end = reader->js_buf + STRLEN(reader->js_buf);
374 }
375}
376
377/*
Bram Moolenaar595e64e2016-02-07 19:19:53 +0100378 * Skip white space in "reader". All characters <= space are considered white
379 * space.
Bram Moolenaar56ead342016-02-02 18:20:08 +0100380 * Also tops up readahead when needed.
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100381 */
382 static void
383json_skip_white(js_read_T *reader)
384{
385 int c;
386
Bram Moolenaar56ead342016-02-02 18:20:08 +0100387 for (;;)
388 {
389 c = reader->js_buf[reader->js_used];
390 if (reader->js_fill != NULL && c == NUL)
391 {
392 if (reader->js_fill(reader))
Bram Moolenaar46c00a62016-03-28 14:11:42 +0200393 {
Bram Moolenaar56ead342016-02-02 18:20:08 +0100394 reader->js_end = reader->js_buf + STRLEN(reader->js_buf);
Bram Moolenaar46c00a62016-03-28 14:11:42 +0200395 continue;
396 }
Bram Moolenaar56ead342016-02-02 18:20:08 +0100397 }
Bram Moolenaar595e64e2016-02-07 19:19:53 +0100398 if (c == NUL || c > ' ')
Bram Moolenaar56ead342016-02-02 18:20:08 +0100399 break;
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100400 ++reader->js_used;
Bram Moolenaar56ead342016-02-02 18:20:08 +0100401 }
402 fill_numbuflen(reader);
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100403}
404
Bram Moolenaar56ead342016-02-02 18:20:08 +0100405 static int
Bram Moolenaaree142ad2017-01-11 21:50:08 +0100406json_decode_string(js_read_T *reader, typval_T *res, int quote)
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100407{
408 garray_T ga;
409 int len;
Bram Moolenaar56ead342016-02-02 18:20:08 +0100410 char_u *p;
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100411 int c;
Bram Moolenaar22fcfad2016-07-01 18:17:26 +0200412 varnumber_T nr;
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100413
Bram Moolenaar56ead342016-02-02 18:20:08 +0100414 if (res != NULL)
415 ga_init2(&ga, 1, 200);
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100416
Bram Moolenaaree142ad2017-01-11 21:50:08 +0100417 p = reader->js_buf + reader->js_used + 1; /* skip over " or ' */
418 while (*p != quote)
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100419 {
Bram Moolenaarb3628722016-02-28 14:56:39 +0100420 /* The JSON is always expected to be utf-8, thus use utf functions
421 * here. The string is converted below if needed. */
Bram Moolenaar56ead342016-02-02 18:20:08 +0100422 if (*p == NUL || p[1] == NUL
423#ifdef FEAT_MBYTE
424 || utf_ptr2len(p) < utf_byte2len(*p)
425#endif
426 )
427 {
Bram Moolenaarb3628722016-02-28 14:56:39 +0100428 /* Not enough bytes to make a character or end of the string. Get
429 * more if possible. */
Bram Moolenaar56ead342016-02-02 18:20:08 +0100430 if (reader->js_fill == NULL)
431 break;
432 len = (int)(reader->js_end - p);
433 reader->js_used = (int)(p - reader->js_buf);
434 if (!reader->js_fill(reader))
435 break; /* didn't get more */
436 p = reader->js_buf + reader->js_used;
437 reader->js_end = reader->js_buf + STRLEN(reader->js_buf);
438 continue;
439 }
440
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100441 if (*p == '\\')
442 {
443 c = -1;
444 switch (p[1])
445 {
Bram Moolenaar56ead342016-02-02 18:20:08 +0100446 case '\\': c = '\\'; break;
447 case '"': c = '"'; break;
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100448 case 'b': c = BS; break;
449 case 't': c = TAB; break;
450 case 'n': c = NL; break;
451 case 'f': c = FF; break;
452 case 'r': c = CAR; break;
453 case 'u':
Bram Moolenaar56ead342016-02-02 18:20:08 +0100454 if (reader->js_fill != NULL
455 && (int)(reader->js_end - p) < NUMBUFLEN)
456 {
457 reader->js_used = (int)(p - reader->js_buf);
458 if (reader->js_fill(reader))
459 {
460 p = reader->js_buf + reader->js_used;
461 reader->js_end = reader->js_buf
462 + STRLEN(reader->js_buf);
463 }
464 }
Bram Moolenaarb6ff8112016-02-27 18:41:27 +0100465 nr = 0;
466 len = 0;
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100467 vim_str2nr(p + 2, NULL, &len,
468 STR2NR_HEX + STR2NR_FORCE, &nr, NULL, 4);
469 p += len + 2;
Bram Moolenaarb6ff8112016-02-27 18:41:27 +0100470 if (0xd800 <= nr && nr <= 0xdfff
471 && (int)(reader->js_end - p) >= 6
472 && *p == '\\' && *(p+1) == 'u')
473 {
Bram Moolenaar22fcfad2016-07-01 18:17:26 +0200474 varnumber_T nr2 = 0;
Bram Moolenaarb6ff8112016-02-27 18:41:27 +0100475
476 /* decode surrogate pair: \ud812\u3456 */
477 len = 0;
478 vim_str2nr(p + 2, NULL, &len,
479 STR2NR_HEX + STR2NR_FORCE, &nr2, NULL, 4);
480 if (0xdc00 <= nr2 && nr2 <= 0xdfff)
481 {
482 p += len + 2;
483 nr = (((nr - 0xd800) << 10) |
484 ((nr2 - 0xdc00) & 0x3ff)) + 0x10000;
485 }
486 }
Bram Moolenaar56ead342016-02-02 18:20:08 +0100487 if (res != NULL)
488 {
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100489#ifdef FEAT_MBYTE
Bram Moolenaardc633cf2016-04-23 14:33:19 +0200490 char_u buf[NUMBUFLEN];
Bram Moolenaarb6ff8112016-02-27 18:41:27 +0100491 buf[utf_char2bytes((int)nr, buf)] = NUL;
Bram Moolenaar56ead342016-02-02 18:20:08 +0100492 ga_concat(&ga, buf);
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100493#else
Bram Moolenaar22fcfad2016-07-01 18:17:26 +0200494 ga_append(&ga, (int)nr);
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100495#endif
Bram Moolenaar56ead342016-02-02 18:20:08 +0100496 }
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100497 break;
Bram Moolenaar56ead342016-02-02 18:20:08 +0100498 default:
499 /* not a special char, skip over \ */
500 ++p;
501 continue;
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100502 }
503 if (c > 0)
504 {
505 p += 2;
Bram Moolenaar56ead342016-02-02 18:20:08 +0100506 if (res != NULL)
507 ga_append(&ga, c);
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100508 }
509 }
510 else
511 {
Bram Moolenaarb6ff8112016-02-27 18:41:27 +0100512#ifdef FEAT_MBYTE
513 len = utf_ptr2len(p);
514#else
515 len = 1;
516#endif
Bram Moolenaar56ead342016-02-02 18:20:08 +0100517 if (res != NULL)
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100518 {
Bram Moolenaar56ead342016-02-02 18:20:08 +0100519 if (ga_grow(&ga, len) == FAIL)
520 {
521 ga_clear(&ga);
522 return FAIL;
523 }
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100524 mch_memmove((char *)ga.ga_data + ga.ga_len, p, (size_t)len);
525 ga.ga_len += len;
526 }
527 p += len;
528 }
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100529 }
Bram Moolenaar56ead342016-02-02 18:20:08 +0100530
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100531 reader->js_used = (int)(p - reader->js_buf);
Bram Moolenaaree142ad2017-01-11 21:50:08 +0100532 if (*p == quote)
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100533 {
534 ++reader->js_used;
Bram Moolenaar56ead342016-02-02 18:20:08 +0100535 if (res != NULL)
536 {
Bram Moolenaar80e78842016-02-28 15:21:13 +0100537 ga_append(&ga, NUL);
Bram Moolenaar56ead342016-02-02 18:20:08 +0100538 res->v_type = VAR_STRING;
Bram Moolenaarb3628722016-02-28 14:56:39 +0100539#if defined(FEAT_MBYTE) && defined(USE_ICONV)
540 if (!enc_utf8)
541 {
542 vimconv_T conv;
543
544 /* Convert the utf-8 string to 'encoding'. */
545 conv.vc_type = CONV_NONE;
546 convert_setup(&conv, (char_u*)"utf-8", p_enc);
547 if (conv.vc_type != CONV_NONE)
548 {
549 res->vval.v_string =
550 string_convert(&conv, ga.ga_data, NULL);
551 vim_free(ga.ga_data);
552 }
553 convert_setup(&conv, NULL, NULL);
554 }
555 else
556#endif
557 res->vval.v_string = ga.ga_data;
Bram Moolenaar56ead342016-02-02 18:20:08 +0100558 }
559 return OK;
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100560 }
Bram Moolenaar56ead342016-02-02 18:20:08 +0100561 if (res != NULL)
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100562 {
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100563 res->v_type = VAR_SPECIAL;
564 res->vval.v_number = VVAL_NONE;
Bram Moolenaar56ead342016-02-02 18:20:08 +0100565 ga_clear(&ga);
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100566 }
Bram Moolenaar56ead342016-02-02 18:20:08 +0100567 return MAYBE;
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100568}
569
Bram Moolenaar8b2f1952017-01-10 19:44:18 +0100570typedef enum {
571 JSON_ARRAY, /* parsing items in an array */
572 JSON_OBJECT_KEY, /* parsing key of an object */
573 JSON_OBJECT /* parsing item in an object, after the key */
574} json_decode_T;
575
576typedef struct {
577 json_decode_T jd_type;
578 typval_T jd_tv; /* the list or dict */
579 typval_T jd_key_tv;
580 char_u *jd_key;
581} json_dec_item_T;
582
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100583/*
Bram Moolenaar56ead342016-02-02 18:20:08 +0100584 * Decode one item and put it in "res". If "res" is NULL only advance.
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100585 * Must already have skipped white space.
Bram Moolenaar56ead342016-02-02 18:20:08 +0100586 *
Bram Moolenaar03c60c12017-01-10 15:15:37 +0100587 * Return FAIL for a decoding error (and give an error).
Bram Moolenaar56ead342016-02-02 18:20:08 +0100588 * Return MAYBE for an incomplete message.
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100589 */
Bram Moolenaar56ead342016-02-02 18:20:08 +0100590 static int
Bram Moolenaar595e64e2016-02-07 19:19:53 +0100591json_decode_item(js_read_T *reader, typval_T *res, int options)
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100592{
Bram Moolenaar56ead342016-02-02 18:20:08 +0100593 char_u *p;
594 int len;
Bram Moolenaar8b2f1952017-01-10 19:44:18 +0100595 int retval;
596 garray_T stack;
597 typval_T item;
598 typval_T *cur_item;
599 json_dec_item_T *top_item;
600 char_u key_buf[NUMBUFLEN];
601
602 ga_init2(&stack, sizeof(json_dec_item_T), 100);
603 cur_item = res;
604 init_tv(&item);
Bram Moolenaare32abbe2017-01-10 22:57:34 +0100605 if (res != NULL)
606 init_tv(res);
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100607
Bram Moolenaar56ead342016-02-02 18:20:08 +0100608 fill_numbuflen(reader);
609 p = reader->js_buf + reader->js_used;
Bram Moolenaar8b2f1952017-01-10 19:44:18 +0100610 for (;;)
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100611 {
Bram Moolenaar8b2f1952017-01-10 19:44:18 +0100612 top_item = NULL;
613 if (stack.ga_len > 0)
614 {
615 top_item = ((json_dec_item_T *)stack.ga_data) + stack.ga_len - 1;
616 json_skip_white(reader);
617 p = reader->js_buf + reader->js_used;
618 if (*p == NUL)
Bram Moolenaar03c60c12017-01-10 15:15:37 +0100619 {
Bram Moolenaar8b2f1952017-01-10 19:44:18 +0100620 retval = MAYBE;
621 if (top_item->jd_type == JSON_OBJECT)
622 /* did get the key, clear it */
623 clear_tv(&top_item->jd_key_tv);
624 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 Moolenaar8b2f1952017-01-10 19:44:18 +0100629 /* Check for end of object or array. */
630 if (*p == (top_item->jd_type == JSON_ARRAY ? ']' : '}'))
Bram Moolenaar56ead342016-02-02 18:20:08 +0100631 {
Bram Moolenaar8b2f1952017-01-10 19:44:18 +0100632 ++reader->js_used; /* consume the ']' or '}' */
633 --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
655 /* accept an object key that is not in quotes */
656 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;
662 cur_item->vval.v_string = vim_strnsave(key, (int)(p - key));
663 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 {
671 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
690 ++reader->js_used; /* consume the '[' */
691 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
702 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
721 ++reader->js_used; /* consume the '{' */
722 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
733 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 {
742 EMSG(_(e_invarg));
743 retval = FAIL;
744 }
Bram Moolenaar8b2f1952017-01-10 19:44:18 +0100745 break;
746
747 case ',': /* comma: empty item */
748 if ((options & JSON_JS) == 0)
Bram Moolenaar03c60c12017-01-10 15:15:37 +0100749 {
750 EMSG(_(e_invarg));
Bram Moolenaar8b2f1952017-01-10 19:44:18 +0100751 retval = FAIL;
752 break;
Bram Moolenaar03c60c12017-01-10 15:15:37 +0100753 }
Bram Moolenaar8b2f1952017-01-10 19:44:18 +0100754 /* FALLTHROUGH */
755 case NUL: /* empty */
756 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 Moolenaar5f6b3792019-01-12 14:24:27 +0100765 if (VIM_ISDIGIT(*p) || (*p == '-' && VIM_ISDIGIT(p[1])))
Bram Moolenaar8b2f1952017-01-10 19:44:18 +0100766 {
767#ifdef FEAT_FLOAT
768 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 {
780 EMSG(_(e_invarg));
781 retval = FAIL;
782 break;
783 }
784 }
785 sp = skipdigits(sp);
786 if (*sp == '.' || *sp == 'e' || *sp == 'E')
787 {
788 if (cur_item == NULL)
789 {
790 float_T f;
791
792 len = string2float(p, &f);
793 }
794 else
795 {
796 cur_item->v_type = VAR_FLOAT;
797 len = string2float(p, &cur_item->vval.v_float);
798 }
799 }
800 else
801#endif
802 {
803 varnumber_T nr;
804
805 vim_str2nr(reader->js_buf + reader->js_used,
806 NULL, &len, 0, /* what */
807 &nr, NULL, 0);
808 if (cur_item != NULL)
809 {
810 cur_item->v_type = VAR_NUMBER;
811 cur_item->vval.v_number = nr;
812 }
813 }
814 reader->js_used += len;
815 retval = OK;
816 break;
817 }
818 if (STRNICMP((char *)p, "false", 5) == 0)
819 {
820 reader->js_used += 5;
821 if (cur_item != NULL)
822 {
823 cur_item->v_type = VAR_SPECIAL;
824 cur_item->vval.v_number = VVAL_FALSE;
825 }
826 retval = OK;
827 break;
828 }
829 if (STRNICMP((char *)p, "true", 4) == 0)
830 {
831 reader->js_used += 4;
832 if (cur_item != NULL)
833 {
834 cur_item->v_type = VAR_SPECIAL;
835 cur_item->vval.v_number = VVAL_TRUE;
836 }
837 retval = OK;
838 break;
839 }
840 if (STRNICMP((char *)p, "null", 4) == 0)
841 {
842 reader->js_used += 4;
843 if (cur_item != NULL)
844 {
845 cur_item->v_type = VAR_SPECIAL;
846 cur_item->vval.v_number = VVAL_NULL;
847 }
848 retval = OK;
849 break;
850 }
851#ifdef FEAT_FLOAT
852 if (STRNICMP((char *)p, "NaN", 3) == 0)
853 {
854 reader->js_used += 3;
855 if (cur_item != NULL)
856 {
857 cur_item->v_type = VAR_FLOAT;
858 cur_item->vval.v_float = NAN;
859 }
860 retval = OK;
861 break;
862 }
Bram Moolenaar5f6b3792019-01-12 14:24:27 +0100863 if (STRNICMP((char *)p, "-Infinity", 9) == 0)
864 {
865 reader->js_used += 9;
866 if (cur_item != NULL)
867 {
868 cur_item->v_type = VAR_FLOAT;
869 cur_item->vval.v_float = -INFINITY;
870 }
871 retval = OK;
872 break;
873 }
Bram Moolenaar8b2f1952017-01-10 19:44:18 +0100874 if (STRNICMP((char *)p, "Infinity", 8) == 0)
875 {
876 reader->js_used += 8;
877 if (cur_item != NULL)
878 {
879 cur_item->v_type = VAR_FLOAT;
880 cur_item->vval.v_float = INFINITY;
881 }
882 retval = OK;
883 break;
884 }
885#endif
886 /* check for truncated name */
887 len = (int)(reader->js_end - (reader->js_buf + reader->js_used));
888 if (
889 (len < 5 && STRNICMP((char *)p, "false", len) == 0)
890#ifdef FEAT_FLOAT
Bram Moolenaar5f6b3792019-01-12 14:24:27 +0100891 || (len < 9 && STRNICMP((char *)p, "-Infinity", len) == 0)
Bram Moolenaar8b2f1952017-01-10 19:44:18 +0100892 || (len < 8 && STRNICMP((char *)p, "Infinity", len) == 0)
893 || (len < 3 && STRNICMP((char *)p, "NaN", len) == 0)
894#endif
895 || (len < 4 && (STRNICMP((char *)p, "true", len) == 0
896 || STRNICMP((char *)p, "null", len) == 0)))
897
898 retval = MAYBE;
899 else
900 retval = FAIL;
901 break;
902 }
903
904 /* We are finished when retval is FAIL or MAYBE and when at the
905 * toplevel. */
906 if (retval == FAIL)
907 break;
908 if (retval == MAYBE || stack.ga_len == 0)
909 goto theend;
910
911 if (top_item != NULL && top_item->jd_type == JSON_OBJECT_KEY
912 && cur_item != NULL)
913 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +0100914 top_item->jd_key = tv_get_string_buf_chk(cur_item, key_buf);
Bram Moolenaar059b7482017-02-05 16:34:43 +0100915 if (top_item->jd_key == NULL)
Bram Moolenaar8b2f1952017-01-10 19:44:18 +0100916 {
917 clear_tv(cur_item);
918 EMSG(_(e_invarg));
919 retval = FAIL;
920 goto theend;
921 }
922 }
923 }
924
925item_end:
926 top_item = ((json_dec_item_T *)stack.ga_data) + stack.ga_len - 1;
927 switch (top_item->jd_type)
928 {
929 case JSON_ARRAY:
930 if (res != NULL)
931 {
932 listitem_T *li = listitem_alloc();
933
934 if (li == NULL)
935 {
936 clear_tv(cur_item);
937 retval = FAIL;
938 goto theend;
939 }
940 li->li_tv = *cur_item;
941 list_append(top_item->jd_tv.vval.v_list, li);
942 }
943 if (cur_item != NULL)
944 cur_item = &item;
945
946 json_skip_white(reader);
947 p = reader->js_buf + reader->js_used;
948 if (*p == ',')
949 ++reader->js_used;
950 else if (*p != ']')
951 {
952 if (*p == NUL)
953 retval = MAYBE;
Bram Moolenaar56ead342016-02-02 18:20:08 +0100954 else
955 {
Bram Moolenaar8b2f1952017-01-10 19:44:18 +0100956 EMSG(_(e_invarg));
957 retval = FAIL;
Bram Moolenaar56ead342016-02-02 18:20:08 +0100958 }
Bram Moolenaar8b2f1952017-01-10 19:44:18 +0100959 goto theend;
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100960 }
Bram Moolenaar8b2f1952017-01-10 19:44:18 +0100961 break;
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100962
Bram Moolenaar8b2f1952017-01-10 19:44:18 +0100963 case JSON_OBJECT_KEY:
964 json_skip_white(reader);
965 p = reader->js_buf + reader->js_used;
966 if (*p != ':')
967 {
968 if (cur_item != NULL)
969 clear_tv(cur_item);
970 if (*p == NUL)
971 retval = MAYBE;
972 else
Bram Moolenaar56ead342016-02-02 18:20:08 +0100973 {
Bram Moolenaar8b2f1952017-01-10 19:44:18 +0100974 EMSG(_(e_invarg));
975 retval = FAIL;
976 }
977 goto theend;
978 }
979 ++reader->js_used;
980 json_skip_white(reader);
981 top_item->jd_type = JSON_OBJECT;
982 if (cur_item != NULL)
983 cur_item = &item;
984 break;
985
986 case JSON_OBJECT:
987 if (cur_item != NULL
988 && dict_find(top_item->jd_tv.vval.v_dict,
989 top_item->jd_key, -1) != NULL)
990 {
Bram Moolenaar83381f72017-01-14 14:36:08 +0100991 EMSG2(_("E938: Duplicate key in JSON: \"%s\""),
Bram Moolenaar8b2f1952017-01-10 19:44:18 +0100992 top_item->jd_key);
993 clear_tv(&top_item->jd_key_tv);
994 clear_tv(cur_item);
995 retval = FAIL;
996 goto theend;
997 }
998
999 if (cur_item != NULL)
1000 {
1001 dictitem_T *di = dictitem_alloc(top_item->jd_key);
1002
1003 clear_tv(&top_item->jd_key_tv);
1004 if (di == NULL)
1005 {
1006 clear_tv(cur_item);
1007 retval = FAIL;
1008 goto theend;
1009 }
1010 di->di_tv = *cur_item;
1011 di->di_tv.v_lock = 0;
1012 if (dict_add(top_item->jd_tv.vval.v_dict, di) == FAIL)
1013 {
1014 dictitem_free(di);
1015 retval = FAIL;
1016 goto theend;
Bram Moolenaar56ead342016-02-02 18:20:08 +01001017 }
Bram Moolenaar520e1e42016-01-23 19:46:28 +01001018 }
Bram Moolenaar8b2f1952017-01-10 19:44:18 +01001019
1020 json_skip_white(reader);
1021 p = reader->js_buf + reader->js_used;
1022 if (*p == ',')
1023 ++reader->js_used;
1024 else if (*p != '}')
Bram Moolenaar56ead342016-02-02 18:20:08 +01001025 {
Bram Moolenaar8b2f1952017-01-10 19:44:18 +01001026 if (*p == NUL)
1027 retval = MAYBE;
1028 else
1029 {
1030 EMSG(_(e_invarg));
1031 retval = FAIL;
1032 }
1033 goto theend;
Bram Moolenaar56ead342016-02-02 18:20:08 +01001034 }
Bram Moolenaar8b2f1952017-01-10 19:44:18 +01001035 top_item->jd_type = JSON_OBJECT_KEY;
1036 if (cur_item != NULL)
1037 cur_item = &top_item->jd_key_tv;
1038 break;
1039 }
Bram Moolenaar520e1e42016-01-23 19:46:28 +01001040 }
1041
Bram Moolenaar8b2f1952017-01-10 19:44:18 +01001042 /* Get here when parsing failed. */
Bram Moolenaar7756e742016-10-21 20:35:37 +02001043 if (res != NULL)
Bram Moolenaar56ead342016-02-02 18:20:08 +01001044 {
Bram Moolenaar8b2f1952017-01-10 19:44:18 +01001045 clear_tv(res);
Bram Moolenaar56ead342016-02-02 18:20:08 +01001046 res->v_type = VAR_SPECIAL;
1047 res->vval.v_number = VVAL_NONE;
1048 }
Bram Moolenaar03c60c12017-01-10 15:15:37 +01001049 EMSG(_(e_invarg));
Bram Moolenaar8b2f1952017-01-10 19:44:18 +01001050
1051theend:
1052 ga_clear(&stack);
Bram Moolenaar8b2f1952017-01-10 19:44:18 +01001053 return retval;
Bram Moolenaar520e1e42016-01-23 19:46:28 +01001054}
1055
1056/*
1057 * Decode the JSON from "reader" and store the result in "res".
Bram Moolenaar595e64e2016-02-07 19:19:53 +01001058 * "options" can be JSON_JS or zero;
Bram Moolenaar56ead342016-02-02 18:20:08 +01001059 * Return FAIL if not the whole message was consumed.
Bram Moolenaar520e1e42016-01-23 19:46:28 +01001060 */
Bram Moolenaar19d2f152016-02-01 21:38:19 +01001061 int
Bram Moolenaar595e64e2016-02-07 19:19:53 +01001062json_decode_all(js_read_T *reader, typval_T *res, int options)
Bram Moolenaar520e1e42016-01-23 19:46:28 +01001063{
Bram Moolenaar56ead342016-02-02 18:20:08 +01001064 int ret;
1065
Bram Moolenaar595e64e2016-02-07 19:19:53 +01001066 /* We find the end once, to avoid calling strlen() many times. */
Bram Moolenaar56ead342016-02-02 18:20:08 +01001067 reader->js_end = reader->js_buf + STRLEN(reader->js_buf);
Bram Moolenaar520e1e42016-01-23 19:46:28 +01001068 json_skip_white(reader);
Bram Moolenaar595e64e2016-02-07 19:19:53 +01001069 ret = json_decode_item(reader, res, options);
Bram Moolenaar56ead342016-02-02 18:20:08 +01001070 if (ret != OK)
Bram Moolenaar03c60c12017-01-10 15:15:37 +01001071 {
1072 if (ret == MAYBE)
1073 EMSG(_(e_invarg));
Bram Moolenaar56ead342016-02-02 18:20:08 +01001074 return FAIL;
Bram Moolenaar03c60c12017-01-10 15:15:37 +01001075 }
Bram Moolenaar520e1e42016-01-23 19:46:28 +01001076 json_skip_white(reader);
1077 if (reader->js_buf[reader->js_used] != NUL)
Bram Moolenaar03c60c12017-01-10 15:15:37 +01001078 {
1079 EMSG(_(e_trailing));
Bram Moolenaar19d2f152016-02-01 21:38:19 +01001080 return FAIL;
Bram Moolenaar03c60c12017-01-10 15:15:37 +01001081 }
Bram Moolenaar19d2f152016-02-01 21:38:19 +01001082 return OK;
Bram Moolenaar520e1e42016-01-23 19:46:28 +01001083}
Bram Moolenaar56ead342016-02-02 18:20:08 +01001084
1085/*
1086 * Decode the JSON from "reader" and store the result in "res".
Bram Moolenaar595e64e2016-02-07 19:19:53 +01001087 * "options" can be JSON_JS or zero;
Bram Moolenaarba61ac02016-03-20 16:40:37 +01001088 * Return FAIL for a decoding error.
1089 * Return MAYBE for an incomplete message.
1090 * Consumes the message anyway.
Bram Moolenaar56ead342016-02-02 18:20:08 +01001091 */
1092 int
Bram Moolenaar595e64e2016-02-07 19:19:53 +01001093json_decode(js_read_T *reader, typval_T *res, int options)
Bram Moolenaar56ead342016-02-02 18:20:08 +01001094{
1095 int ret;
1096
Bram Moolenaar595e64e2016-02-07 19:19:53 +01001097 /* We find the end once, to avoid calling strlen() many times. */
Bram Moolenaar56ead342016-02-02 18:20:08 +01001098 reader->js_end = reader->js_buf + STRLEN(reader->js_buf);
1099 json_skip_white(reader);
Bram Moolenaar595e64e2016-02-07 19:19:53 +01001100 ret = json_decode_item(reader, res, options);
Bram Moolenaar56ead342016-02-02 18:20:08 +01001101 json_skip_white(reader);
1102
Bram Moolenaarba61ac02016-03-20 16:40:37 +01001103 return ret;
Bram Moolenaar56ead342016-02-02 18:20:08 +01001104}
1105
1106/*
1107 * Decode the JSON from "reader" to find the end of the message.
Bram Moolenaare2c60372017-01-22 15:56:26 +01001108 * "options" can be JSON_JS or zero.
1109 * This is only used for testing.
Bram Moolenaar56ead342016-02-02 18:20:08 +01001110 * Return FAIL if the message has a decoding error.
1111 * Return MAYBE if the message is truncated, need to read more.
1112 * This only works reliable if the message contains an object, array or
Bram Moolenaar5f6b3792019-01-12 14:24:27 +01001113 * string. A number might be truncated without knowing.
Bram Moolenaar56ead342016-02-02 18:20:08 +01001114 * Does not advance the reader.
1115 */
1116 int
Bram Moolenaar595e64e2016-02-07 19:19:53 +01001117json_find_end(js_read_T *reader, int options)
Bram Moolenaar56ead342016-02-02 18:20:08 +01001118{
1119 int used_save = reader->js_used;
1120 int ret;
1121
Bram Moolenaar595e64e2016-02-07 19:19:53 +01001122 /* We find the end once, to avoid calling strlen() many times. */
Bram Moolenaar56ead342016-02-02 18:20:08 +01001123 reader->js_end = reader->js_buf + STRLEN(reader->js_buf);
1124 json_skip_white(reader);
Bram Moolenaar595e64e2016-02-07 19:19:53 +01001125 ret = json_decode_item(reader, NULL, options);
Bram Moolenaar56ead342016-02-02 18:20:08 +01001126 reader->js_used = used_save;
1127 return ret;
1128}
Bram Moolenaar520e1e42016-01-23 19:46:28 +01001129#endif