blob: da585e306db90dbcec7d6501fd44dc17862bbeb6 [file] [log] [blame]
Bram Moolenaar520e1e42016-01-23 19:46:28 +01001/* vi:set ts=8 sts=4 sw=4:
2 *
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 */
15
16#include "vim.h"
17
18#if defined(FEAT_EVAL) || defined(PROTO)
Bram Moolenaarf1b6ac72016-02-23 21:26:43 +010019
Bram Moolenaar3ea0f1a2016-02-23 22:07:32 +010020#if defined(FEAT_FLOAT)
21# include <float.h>
22# if defined(HAVE_MATH_H)
23 /* for isnan() and isinf() */
24# include <math.h>
25# endif
26# if defined(WIN32) && !defined(isnan)
27# define isnan(x) _isnan(x)
28# define isinf(x) (!_finite(x) && !_isnan(x))
29# endif
Bram Moolenaar7ce686c2016-02-27 16:33:22 +010030# if !defined(INFINITY) && defined(DBL_MAX)
Bram Moolenaar3ea0f1a2016-02-23 22:07:32 +010031# define INFINITY (DBL_MAX+DBL_MAX)
Bram Moolenaar7ce686c2016-02-27 16:33:22 +010032# endif
33# if !defined(NAN) && defined(INFINITY)
Bram Moolenaar3ea0f1a2016-02-23 22:07:32 +010034# define NAN (INFINITY-INFINITY)
35# endif
Bram Moolenaarf1b6ac72016-02-23 21:26:43 +010036#endif
37
Bram Moolenaar595e64e2016-02-07 19:19:53 +010038static int json_encode_item(garray_T *gap, typval_T *val, int copyID, int options);
39static int json_decode_item(js_read_T *reader, typval_T *res, int options);
Bram Moolenaar520e1e42016-01-23 19:46:28 +010040
41/*
42 * Encode "val" into a JSON format string.
Bram Moolenaar55fab432016-02-07 16:53:13 +010043 * The result is in allocated memory.
44 * The result is empty when encoding fails.
Bram Moolenaar595e64e2016-02-07 19:19:53 +010045 * "options" can be JSON_JS or zero;
Bram Moolenaar520e1e42016-01-23 19:46:28 +010046 */
47 char_u *
Bram Moolenaar595e64e2016-02-07 19:19:53 +010048json_encode(typval_T *val, int options)
Bram Moolenaar520e1e42016-01-23 19:46:28 +010049{
50 garray_T ga;
51
52 /* Store bytes in the growarray. */
53 ga_init2(&ga, 1, 4000);
Bram Moolenaar595e64e2016-02-07 19:19:53 +010054 if (json_encode_item(&ga, val, get_copyID(), options) == FAIL)
Bram Moolenaar55fab432016-02-07 16:53:13 +010055 {
56 vim_free(ga.ga_data);
57 return vim_strsave((char_u *)"");
58 }
Bram Moolenaar520e1e42016-01-23 19:46:28 +010059 return ga.ga_data;
60}
61
Bram Moolenaarfb1f6262016-01-31 20:24:32 +010062/*
Bram Moolenaar55fab432016-02-07 16:53:13 +010063 * Encode ["nr", "val"] into a JSON format string in allocated memory.
Bram Moolenaar595e64e2016-02-07 19:19:53 +010064 * "options" can be JSON_JS or zero;
Bram Moolenaarfb1f6262016-01-31 20:24:32 +010065 * Returns NULL when out of memory.
66 */
67 char_u *
Bram Moolenaar595e64e2016-02-07 19:19:53 +010068json_encode_nr_expr(int nr, typval_T *val, int options)
Bram Moolenaarfb1f6262016-01-31 20:24:32 +010069{
70 typval_T listtv;
71 typval_T nrtv;
72 char_u *text;
73
74 nrtv.v_type = VAR_NUMBER;
75 nrtv.vval.v_number = nr;
76 if (rettv_list_alloc(&listtv) == FAIL)
77 return NULL;
78 if (list_append_tv(listtv.vval.v_list, &nrtv) == FAIL
79 || list_append_tv(listtv.vval.v_list, val) == FAIL)
80 {
81 list_unref(listtv.vval.v_list);
82 return NULL;
83 }
84
Bram Moolenaar595e64e2016-02-07 19:19:53 +010085 text = json_encode(&listtv, options);
Bram Moolenaarfb1f6262016-01-31 20:24:32 +010086 list_unref(listtv.vval.v_list);
87 return text;
88}
89
Bram Moolenaar520e1e42016-01-23 19:46:28 +010090 static void
91write_string(garray_T *gap, char_u *str)
92{
93 char_u *res = str;
94 char_u numbuf[NUMBUFLEN];
95
96 if (res == NULL)
97 ga_concat(gap, (char_u *)"null");
98 else
99 {
Bram Moolenaarb6ff8112016-02-27 18:41:27 +0100100#if defined(FEAT_MBYTE) && defined(USE_ICONV)
101 vimconv_T conv;
102 char_u *converted = NULL;
103
104 convert_setup(&conv, p_enc, (char_u*)"utf-8");
105 if (conv.vc_type != CONV_NONE)
106 converted = res = string_convert(&conv, res, NULL);
107 convert_setup(&conv, NULL, NULL);
108#endif
109
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100110 ga_append(gap, '"');
111 while (*res != NUL)
112 {
Bram Moolenaarb6ff8112016-02-27 18:41:27 +0100113 int c;
114#ifdef FEAT_MBYTE
115 /* always use utf-8 encoding, ignore 'encoding' */
116 c = utf_ptr2char(res);
117#else
118 c = (int)*(p);
119#endif
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100120
121 switch (c)
122 {
123 case 0x08:
124 ga_append(gap, '\\'); ga_append(gap, 'b'); break;
125 case 0x09:
126 ga_append(gap, '\\'); ga_append(gap, 't'); break;
127 case 0x0a:
128 ga_append(gap, '\\'); ga_append(gap, 'n'); break;
129 case 0x0c:
130 ga_append(gap, '\\'); ga_append(gap, 'f'); break;
131 case 0x0d:
132 ga_append(gap, '\\'); ga_append(gap, 'r'); break;
133 case 0x22: /* " */
134 case 0x5c: /* \ */
135 ga_append(gap, '\\');
136 ga_append(gap, c);
137 break;
138 default:
139 if (c >= 0x20)
140 {
Bram Moolenaarfa06a512016-01-28 22:46:58 +0100141#ifdef FEAT_MBYTE
Bram Moolenaarb6ff8112016-02-27 18:41:27 +0100142 numbuf[utf_char2bytes(c, numbuf)] = NUL;
Bram Moolenaarfa06a512016-01-28 22:46:58 +0100143#else
144 numbuf[0] = c;
145 numbuf[1] = NUL;
146#endif
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100147 ga_concat(gap, numbuf);
148 }
149 else
150 {
151 vim_snprintf((char *)numbuf, NUMBUFLEN,
152 "\\u%04lx", (long)c);
153 ga_concat(gap, numbuf);
154 }
155 }
Bram Moolenaarb6ff8112016-02-27 18:41:27 +0100156#ifdef FEAT_MBYTE
157 res += utf_ptr2len(res);
158#else
159 ++p;
160#endif
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100161 }
162 ga_append(gap, '"');
Bram Moolenaarb6ff8112016-02-27 18:41:27 +0100163#if defined(FEAT_MBYTE) && defined(USE_ICONV)
164 vim_free(converted);
165#endif
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100166 }
167}
168
Bram Moolenaarfcaaae62016-01-24 16:49:11 +0100169/*
Bram Moolenaar595e64e2016-02-07 19:19:53 +0100170 * Return TRUE if "key" can be used without quotes.
171 * That is when it starts with a letter and only contains letters, digits and
172 * underscore.
173 */
174 static int
175is_simple_key(char_u *key)
176{
177 char_u *p;
178
179 if (!ASCII_ISALPHA(*key))
180 return FALSE;
181 for (p = key + 1; *p != NUL; ++p)
182 if (!ASCII_ISALPHA(*p) && *p != '_' && !vim_isdigit(*p))
183 return FALSE;
184 return TRUE;
185}
186
187/*
Bram Moolenaarfcaaae62016-01-24 16:49:11 +0100188 * Encode "val" into "gap".
189 * Return FAIL or OK.
190 */
191 static int
Bram Moolenaar595e64e2016-02-07 19:19:53 +0100192json_encode_item(garray_T *gap, typval_T *val, int copyID, int options)
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100193{
194 char_u numbuf[NUMBUFLEN];
195 char_u *res;
196 list_T *l;
197 dict_T *d;
198
199 switch (val->v_type)
200 {
201 case VAR_SPECIAL:
Bram Moolenaarfcaaae62016-01-24 16:49:11 +0100202 switch (val->vval.v_number)
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100203 {
204 case VVAL_FALSE: ga_concat(gap, (char_u *)"false"); break;
205 case VVAL_TRUE: ga_concat(gap, (char_u *)"true"); break;
Bram Moolenaar595e64e2016-02-07 19:19:53 +0100206 case VVAL_NONE: if ((options & JSON_JS) != 0
207 && (options & JSON_NO_NONE) == 0)
208 /* empty item */
209 break;
210 /* FALLTHROUGH */
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100211 case VVAL_NULL: ga_concat(gap, (char_u *)"null"); break;
212 }
213 break;
214
215 case VAR_NUMBER:
216 vim_snprintf((char *)numbuf, NUMBUFLEN, "%ld",
217 (long)val->vval.v_number);
218 ga_concat(gap, numbuf);
219 break;
220
221 case VAR_STRING:
222 res = val->vval.v_string;
223 write_string(gap, res);
224 break;
225
226 case VAR_FUNC:
Bram Moolenaar55fab432016-02-07 16:53:13 +0100227 case VAR_JOB:
Bram Moolenaar77073442016-02-13 23:23:53 +0100228 case VAR_CHANNEL:
Bram Moolenaar4f8b8fa2016-02-06 18:42:07 +0100229 /* no JSON equivalent TODO: better error */
Bram Moolenaarfcaaae62016-01-24 16:49:11 +0100230 EMSG(_(e_invarg));
231 return FAIL;
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100232
233 case VAR_LIST:
234 l = val->vval.v_list;
235 if (l == NULL)
236 ga_concat(gap, (char_u *)"null");
237 else
238 {
239 if (l->lv_copyID == copyID)
240 ga_concat(gap, (char_u *)"[]");
241 else
242 {
243 listitem_T *li;
244
245 l->lv_copyID = copyID;
246 ga_append(gap, '[');
247 for (li = l->lv_first; li != NULL && !got_int; )
248 {
Bram Moolenaar595e64e2016-02-07 19:19:53 +0100249 if (json_encode_item(gap, &li->li_tv, copyID,
250 options & JSON_JS) == FAIL)
Bram Moolenaarfcaaae62016-01-24 16:49:11 +0100251 return FAIL;
Bram Moolenaar595e64e2016-02-07 19:19:53 +0100252 if ((options & JSON_JS)
253 && li->li_next == NULL
254 && li->li_tv.v_type == VAR_SPECIAL
255 && li->li_tv.vval.v_number == VVAL_NONE)
256 /* add an extra comma if the last item is v:none */
257 ga_append(gap, ',');
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100258 li = li->li_next;
259 if (li != NULL)
260 ga_append(gap, ',');
261 }
262 ga_append(gap, ']');
Bram Moolenaarfcaaae62016-01-24 16:49:11 +0100263 l->lv_copyID = 0;
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100264 }
265 }
266 break;
267
268 case VAR_DICT:
269 d = val->vval.v_dict;
270 if (d == NULL)
271 ga_concat(gap, (char_u *)"null");
272 else
273 {
274 if (d->dv_copyID == copyID)
275 ga_concat(gap, (char_u *)"{}");
276 else
277 {
278 int first = TRUE;
279 int todo = (int)d->dv_hashtab.ht_used;
280 hashitem_T *hi;
281
282 d->dv_copyID = copyID;
283 ga_append(gap, '{');
284
285 for (hi = d->dv_hashtab.ht_array; todo > 0 && !got_int;
286 ++hi)
287 if (!HASHITEM_EMPTY(hi))
288 {
289 --todo;
290 if (first)
291 first = FALSE;
292 else
293 ga_append(gap, ',');
Bram Moolenaar595e64e2016-02-07 19:19:53 +0100294 if ((options & JSON_JS)
295 && is_simple_key(hi->hi_key))
296 ga_concat(gap, hi->hi_key);
297 else
298 write_string(gap, hi->hi_key);
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100299 ga_append(gap, ':');
Bram Moolenaarfcaaae62016-01-24 16:49:11 +0100300 if (json_encode_item(gap, &dict_lookup(hi)->di_tv,
Bram Moolenaar595e64e2016-02-07 19:19:53 +0100301 copyID, options | JSON_NO_NONE) == FAIL)
Bram Moolenaarfcaaae62016-01-24 16:49:11 +0100302 return FAIL;
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100303 }
304 ga_append(gap, '}');
Bram Moolenaarfcaaae62016-01-24 16:49:11 +0100305 d->dv_copyID = 0;
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100306 }
307 }
308 break;
309
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100310 case VAR_FLOAT:
Bram Moolenaar55fab432016-02-07 16:53:13 +0100311#ifdef FEAT_FLOAT
Bram Moolenaarf1b6ac72016-02-23 21:26:43 +0100312# if defined(HAVE_MATH_H)
Bram Moolenaar7ce686c2016-02-27 16:33:22 +0100313 if (isnan(val->vval.v_float))
Bram Moolenaarf1b6ac72016-02-23 21:26:43 +0100314 ga_concat(gap, (char_u *)"NaN");
Bram Moolenaar7ce686c2016-02-27 16:33:22 +0100315 else if (isinf(val->vval.v_float))
Bram Moolenaarf1b6ac72016-02-23 21:26:43 +0100316 ga_concat(gap, (char_u *)"Infinity");
Bram Moolenaarf1b6ac72016-02-23 21:26:43 +0100317 else
318# endif
319 {
320 vim_snprintf((char *)numbuf, NUMBUFLEN, "%g",
321 val->vval.v_float);
322 ga_concat(gap, numbuf);
323 }
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100324 break;
325#endif
Bram Moolenaar55fab432016-02-07 16:53:13 +0100326 case VAR_UNKNOWN:
Bram Moolenaarc6b14f02016-02-20 15:26:42 +0100327 EMSG2(_(e_intern2), "json_encode_item()");
Bram Moolenaar55fab432016-02-07 16:53:13 +0100328 return FAIL;
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100329 }
Bram Moolenaarfcaaae62016-01-24 16:49:11 +0100330 return OK;
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100331}
332
333/*
Bram Moolenaar56ead342016-02-02 18:20:08 +0100334 * When "reader" has less than NUMBUFLEN bytes available, call the fill
335 * callback to get more.
336 */
337 static void
338fill_numbuflen(js_read_T *reader)
339{
340 if (reader->js_fill != NULL && (int)(reader->js_end - reader->js_buf)
341 - reader->js_used < NUMBUFLEN)
342 {
343 if (reader->js_fill(reader))
344 reader->js_end = reader->js_buf + STRLEN(reader->js_buf);
345 }
346}
347
348/*
Bram Moolenaar595e64e2016-02-07 19:19:53 +0100349 * Skip white space in "reader". All characters <= space are considered white
350 * space.
Bram Moolenaar56ead342016-02-02 18:20:08 +0100351 * Also tops up readahead when needed.
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100352 */
353 static void
354json_skip_white(js_read_T *reader)
355{
356 int c;
357
Bram Moolenaar56ead342016-02-02 18:20:08 +0100358 for (;;)
359 {
360 c = reader->js_buf[reader->js_used];
361 if (reader->js_fill != NULL && c == NUL)
362 {
363 if (reader->js_fill(reader))
364 reader->js_end = reader->js_buf + STRLEN(reader->js_buf);
365 continue;
366 }
Bram Moolenaar595e64e2016-02-07 19:19:53 +0100367 if (c == NUL || c > ' ')
Bram Moolenaar56ead342016-02-02 18:20:08 +0100368 break;
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100369 ++reader->js_used;
Bram Moolenaar56ead342016-02-02 18:20:08 +0100370 }
371 fill_numbuflen(reader);
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100372}
373
Bram Moolenaar56ead342016-02-02 18:20:08 +0100374 static int
Bram Moolenaar595e64e2016-02-07 19:19:53 +0100375json_decode_array(js_read_T *reader, typval_T *res, int options)
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100376{
377 char_u *p;
378 typval_T item;
379 listitem_T *li;
Bram Moolenaar56ead342016-02-02 18:20:08 +0100380 int ret;
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100381
Bram Moolenaar56ead342016-02-02 18:20:08 +0100382 if (res != NULL && rettv_list_alloc(res) == FAIL)
383 {
384 res->v_type = VAR_SPECIAL;
385 res->vval.v_number = VVAL_NONE;
386 return FAIL;
387 }
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100388 ++reader->js_used; /* consume the '[' */
389
390 while (TRUE)
391 {
392 json_skip_white(reader);
393 p = reader->js_buf + reader->js_used;
394 if (*p == NUL)
Bram Moolenaar56ead342016-02-02 18:20:08 +0100395 return MAYBE;
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100396 if (*p == ']')
397 {
398 ++reader->js_used; /* consume the ']' */
Bram Moolenaar56ead342016-02-02 18:20:08 +0100399 break;
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100400 }
401
Bram Moolenaar595e64e2016-02-07 19:19:53 +0100402 ret = json_decode_item(reader, res == NULL ? NULL : &item, options);
Bram Moolenaar56ead342016-02-02 18:20:08 +0100403 if (ret != OK)
404 return ret;
405 if (res != NULL)
406 {
407 li = listitem_alloc();
408 if (li == NULL)
409 {
410 clear_tv(&item);
411 return FAIL;
412 }
413 li->li_tv = item;
414 list_append(res->vval.v_list, li);
415 }
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100416
417 json_skip_white(reader);
418 p = reader->js_buf + reader->js_used;
419 if (*p == ',')
420 ++reader->js_used;
421 else if (*p != ']')
Bram Moolenaar56ead342016-02-02 18:20:08 +0100422 {
423 if (*p == NUL)
424 return MAYBE;
425 return FAIL;
426 }
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100427 }
Bram Moolenaar56ead342016-02-02 18:20:08 +0100428 return OK;
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100429}
430
Bram Moolenaar56ead342016-02-02 18:20:08 +0100431 static int
Bram Moolenaar595e64e2016-02-07 19:19:53 +0100432json_decode_object(js_read_T *reader, typval_T *res, int options)
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100433{
434 char_u *p;
435 typval_T tvkey;
436 typval_T item;
437 dictitem_T *di;
438 char_u buf[NUMBUFLEN];
Bram Moolenaarfbf9c6b2016-02-02 19:43:57 +0100439 char_u *key = NULL;
Bram Moolenaar56ead342016-02-02 18:20:08 +0100440 int ret;
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100441
Bram Moolenaar56ead342016-02-02 18:20:08 +0100442 if (res != NULL && rettv_dict_alloc(res) == FAIL)
443 {
444 res->v_type = VAR_SPECIAL;
445 res->vval.v_number = VVAL_NONE;
446 return FAIL;
447 }
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100448 ++reader->js_used; /* consume the '{' */
449
450 while (TRUE)
451 {
452 json_skip_white(reader);
453 p = reader->js_buf + reader->js_used;
454 if (*p == NUL)
Bram Moolenaar56ead342016-02-02 18:20:08 +0100455 return MAYBE;
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100456 if (*p == '}')
457 {
458 ++reader->js_used; /* consume the '}' */
Bram Moolenaar56ead342016-02-02 18:20:08 +0100459 break;
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100460 }
461
Bram Moolenaar595e64e2016-02-07 19:19:53 +0100462 if ((options & JSON_JS) && reader->js_buf[reader->js_used] != '"')
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100463 {
Bram Moolenaar595e64e2016-02-07 19:19:53 +0100464 /* accept a key that is not in quotes */
465 key = p = reader->js_buf + reader->js_used;
466 while (*p != NUL && *p != ':' && *p > ' ')
467 ++p;
468 tvkey.v_type = VAR_STRING;
469 tvkey.vval.v_string = vim_strnsave(key, (int)(p - key));
470 reader->js_used += (int)(p - key);
471 key = tvkey.vval.v_string;
472 }
473 else
474 {
475 ret = json_decode_item(reader, res == NULL ? NULL : &tvkey,
476 options);
477 if (ret != OK)
478 return ret;
479 if (res != NULL)
Bram Moolenaar56ead342016-02-02 18:20:08 +0100480 {
Bram Moolenaar595e64e2016-02-07 19:19:53 +0100481 key = get_tv_string_buf_chk(&tvkey, buf);
482 if (key == NULL || *key == NUL)
483 {
484 clear_tv(&tvkey);
485 return FAIL;
486 }
Bram Moolenaar56ead342016-02-02 18:20:08 +0100487 }
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100488 }
489
490 json_skip_white(reader);
491 p = reader->js_buf + reader->js_used;
492 if (*p != ':')
493 {
Bram Moolenaar56ead342016-02-02 18:20:08 +0100494 if (res != NULL)
495 clear_tv(&tvkey);
496 if (*p == NUL)
497 return MAYBE;
498 return FAIL;
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100499 }
500 ++reader->js_used;
501 json_skip_white(reader);
502
Bram Moolenaar595e64e2016-02-07 19:19:53 +0100503 ret = json_decode_item(reader, res == NULL ? NULL : &item, options);
Bram Moolenaar56ead342016-02-02 18:20:08 +0100504 if (ret != OK)
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100505 {
Bram Moolenaar56ead342016-02-02 18:20:08 +0100506 if (res != NULL)
507 clear_tv(&tvkey);
508 return ret;
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100509 }
Bram Moolenaar56ead342016-02-02 18:20:08 +0100510
511 if (res != NULL)
512 {
513 di = dictitem_alloc(key);
514 clear_tv(&tvkey);
515 if (di == NULL)
516 {
517 clear_tv(&item);
518 return FAIL;
519 }
520 di->di_tv = item;
521 if (dict_add(res->vval.v_dict, di) == FAIL)
522 {
523 dictitem_free(di);
524 return FAIL;
525 }
526 }
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100527
528 json_skip_white(reader);
529 p = reader->js_buf + reader->js_used;
530 if (*p == ',')
531 ++reader->js_used;
532 else if (*p != '}')
Bram Moolenaar56ead342016-02-02 18:20:08 +0100533 {
534 if (*p == NUL)
535 return MAYBE;
536 return FAIL;
537 }
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100538 }
Bram Moolenaar56ead342016-02-02 18:20:08 +0100539 return OK;
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100540}
541
Bram Moolenaar56ead342016-02-02 18:20:08 +0100542 static int
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100543json_decode_string(js_read_T *reader, typval_T *res)
544{
545 garray_T ga;
546 int len;
Bram Moolenaar56ead342016-02-02 18:20:08 +0100547 char_u *p;
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100548 int c;
549 long nr;
550 char_u buf[NUMBUFLEN];
Bram Moolenaarb6ff8112016-02-27 18:41:27 +0100551#if defined(FEAT_MBYTE) && defined(USE_ICONV)
552 vimconv_T conv;
553 char_u *converted = NULL;
554#endif
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100555
Bram Moolenaar56ead342016-02-02 18:20:08 +0100556 if (res != NULL)
557 ga_init2(&ga, 1, 200);
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100558
Bram Moolenaar56ead342016-02-02 18:20:08 +0100559 p = reader->js_buf + reader->js_used + 1; /* skip over " */
Bram Moolenaarb6ff8112016-02-27 18:41:27 +0100560#if defined(FEAT_MBYTE) && defined(USE_ICONV)
561 convert_setup(&conv, (char_u*)"utf-8", p_enc);
562 if (conv.vc_type != CONV_NONE)
563 converted = p = string_convert(&conv, p, NULL);
564 convert_setup(&conv, NULL, NULL);
565#endif
Bram Moolenaar56ead342016-02-02 18:20:08 +0100566 while (*p != '"')
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100567 {
Bram Moolenaar56ead342016-02-02 18:20:08 +0100568 if (*p == NUL || p[1] == NUL
569#ifdef FEAT_MBYTE
570 || utf_ptr2len(p) < utf_byte2len(*p)
571#endif
572 )
573 {
574 if (reader->js_fill == NULL)
575 break;
576 len = (int)(reader->js_end - p);
577 reader->js_used = (int)(p - reader->js_buf);
578 if (!reader->js_fill(reader))
579 break; /* didn't get more */
580 p = reader->js_buf + reader->js_used;
581 reader->js_end = reader->js_buf + STRLEN(reader->js_buf);
582 continue;
583 }
584
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100585 if (*p == '\\')
586 {
587 c = -1;
588 switch (p[1])
589 {
Bram Moolenaar56ead342016-02-02 18:20:08 +0100590 case '\\': c = '\\'; break;
591 case '"': c = '"'; break;
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100592 case 'b': c = BS; break;
593 case 't': c = TAB; break;
594 case 'n': c = NL; break;
595 case 'f': c = FF; break;
596 case 'r': c = CAR; break;
597 case 'u':
Bram Moolenaar56ead342016-02-02 18:20:08 +0100598 if (reader->js_fill != NULL
599 && (int)(reader->js_end - p) < NUMBUFLEN)
600 {
601 reader->js_used = (int)(p - reader->js_buf);
602 if (reader->js_fill(reader))
603 {
604 p = reader->js_buf + reader->js_used;
605 reader->js_end = reader->js_buf
606 + STRLEN(reader->js_buf);
607 }
608 }
Bram Moolenaarb6ff8112016-02-27 18:41:27 +0100609 nr = 0;
610 len = 0;
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100611 vim_str2nr(p + 2, NULL, &len,
612 STR2NR_HEX + STR2NR_FORCE, &nr, NULL, 4);
613 p += len + 2;
Bram Moolenaarb6ff8112016-02-27 18:41:27 +0100614 if (0xd800 <= nr && nr <= 0xdfff
615 && (int)(reader->js_end - p) >= 6
616 && *p == '\\' && *(p+1) == 'u')
617 {
618 long nr2 = 0;
619
620 /* decode surrogate pair: \ud812\u3456 */
621 len = 0;
622 vim_str2nr(p + 2, NULL, &len,
623 STR2NR_HEX + STR2NR_FORCE, &nr2, NULL, 4);
624 if (0xdc00 <= nr2 && nr2 <= 0xdfff)
625 {
626 p += len + 2;
627 nr = (((nr - 0xd800) << 10) |
628 ((nr2 - 0xdc00) & 0x3ff)) + 0x10000;
629 }
630 }
Bram Moolenaar56ead342016-02-02 18:20:08 +0100631 if (res != NULL)
632 {
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100633#ifdef FEAT_MBYTE
Bram Moolenaarb6ff8112016-02-27 18:41:27 +0100634 buf[utf_char2bytes((int)nr, buf)] = NUL;
Bram Moolenaar56ead342016-02-02 18:20:08 +0100635 ga_concat(&ga, buf);
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100636#else
Bram Moolenaar56ead342016-02-02 18:20:08 +0100637 ga_append(&ga, nr);
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100638#endif
Bram Moolenaar56ead342016-02-02 18:20:08 +0100639 }
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100640 break;
Bram Moolenaar56ead342016-02-02 18:20:08 +0100641 default:
642 /* not a special char, skip over \ */
643 ++p;
644 continue;
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100645 }
646 if (c > 0)
647 {
648 p += 2;
Bram Moolenaar56ead342016-02-02 18:20:08 +0100649 if (res != NULL)
650 ga_append(&ga, c);
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100651 }
652 }
653 else
654 {
Bram Moolenaarb6ff8112016-02-27 18:41:27 +0100655#ifdef FEAT_MBYTE
656 len = utf_ptr2len(p);
657#else
658 len = 1;
659#endif
Bram Moolenaar56ead342016-02-02 18:20:08 +0100660 if (res != NULL)
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100661 {
Bram Moolenaar56ead342016-02-02 18:20:08 +0100662 if (ga_grow(&ga, len) == FAIL)
663 {
664 ga_clear(&ga);
Bram Moolenaarb6ff8112016-02-27 18:41:27 +0100665#if defined(FEAT_MBYTE) && defined(USE_ICONV)
666 vim_free(converted);
667#endif
Bram Moolenaar56ead342016-02-02 18:20:08 +0100668 return FAIL;
669 }
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100670 mch_memmove((char *)ga.ga_data + ga.ga_len, p, (size_t)len);
671 ga.ga_len += len;
672 }
673 p += len;
674 }
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100675 }
Bram Moolenaarb6ff8112016-02-27 18:41:27 +0100676#if defined(FEAT_MBYTE) && defined(USE_ICONV)
677 vim_free(converted);
678#endif
Bram Moolenaar56ead342016-02-02 18:20:08 +0100679
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100680 reader->js_used = (int)(p - reader->js_buf);
681 if (*p == '"')
682 {
683 ++reader->js_used;
Bram Moolenaar56ead342016-02-02 18:20:08 +0100684 if (res != NULL)
685 {
686 res->v_type = VAR_STRING;
Bram Moolenaar4b6a6dc2016-02-04 22:49:49 +0100687 res->vval.v_string = ga.ga_data;
Bram Moolenaar56ead342016-02-02 18:20:08 +0100688 }
689 return OK;
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100690 }
Bram Moolenaar56ead342016-02-02 18:20:08 +0100691 if (res != NULL)
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100692 {
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100693 res->v_type = VAR_SPECIAL;
694 res->vval.v_number = VVAL_NONE;
Bram Moolenaar56ead342016-02-02 18:20:08 +0100695 ga_clear(&ga);
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100696 }
Bram Moolenaar56ead342016-02-02 18:20:08 +0100697 return MAYBE;
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100698}
699
700/*
Bram Moolenaar56ead342016-02-02 18:20:08 +0100701 * Decode one item and put it in "res". If "res" is NULL only advance.
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100702 * Must already have skipped white space.
Bram Moolenaar56ead342016-02-02 18:20:08 +0100703 *
704 * Return FAIL for a decoding error.
705 * Return MAYBE for an incomplete message.
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100706 */
Bram Moolenaar56ead342016-02-02 18:20:08 +0100707 static int
Bram Moolenaar595e64e2016-02-07 19:19:53 +0100708json_decode_item(js_read_T *reader, typval_T *res, int options)
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100709{
Bram Moolenaar56ead342016-02-02 18:20:08 +0100710 char_u *p;
711 int len;
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100712
Bram Moolenaar56ead342016-02-02 18:20:08 +0100713 fill_numbuflen(reader);
714 p = reader->js_buf + reader->js_used;
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100715 switch (*p)
716 {
717 case '[': /* array */
Bram Moolenaar595e64e2016-02-07 19:19:53 +0100718 return json_decode_array(reader, res, options);
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100719
720 case '{': /* object */
Bram Moolenaar595e64e2016-02-07 19:19:53 +0100721 return json_decode_object(reader, res, options);
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100722
723 case '"': /* string */
Bram Moolenaar56ead342016-02-02 18:20:08 +0100724 return json_decode_string(reader, res);
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100725
726 case ',': /* comma: empty item */
Bram Moolenaar595e64e2016-02-07 19:19:53 +0100727 if ((options & JSON_JS) == 0)
728 return FAIL;
729 /* FALLTHROUGH */
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100730 case NUL: /* empty */
Bram Moolenaar56ead342016-02-02 18:20:08 +0100731 if (res != NULL)
732 {
733 res->v_type = VAR_SPECIAL;
734 res->vval.v_number = VVAL_NONE;
735 }
736 return OK;
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100737
738 default:
739 if (VIM_ISDIGIT(*p) || *p == '-')
740 {
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100741 char_u *sp = p;
Bram Moolenaar56ead342016-02-02 18:20:08 +0100742
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100743#ifdef FEAT_FLOAT
744 if (*sp == '-')
Bram Moolenaar56ead342016-02-02 18:20:08 +0100745 {
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100746 ++sp;
Bram Moolenaar56ead342016-02-02 18:20:08 +0100747 if (*sp == NUL)
748 return MAYBE;
749 if (!VIM_ISDIGIT(*sp))
750 return FAIL;
751 }
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100752 sp = skipdigits(sp);
753 if (*sp == '.' || *sp == 'e' || *sp == 'E')
754 {
Bram Moolenaar56ead342016-02-02 18:20:08 +0100755 if (res == NULL)
756 {
757 float_T f;
758
759 len = string2float(p, &f);
760 }
761 else
762 {
763 res->v_type = VAR_FLOAT;
764 len = string2float(p, &res->vval.v_float);
765 }
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100766 }
767 else
768#endif
769 {
770 long nr;
771
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100772 vim_str2nr(reader->js_buf + reader->js_used,
773 NULL, &len, 0, /* what */
774 &nr, NULL, 0);
Bram Moolenaar56ead342016-02-02 18:20:08 +0100775 if (res != NULL)
776 {
777 res->v_type = VAR_NUMBER;
778 res->vval.v_number = nr;
779 }
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100780 }
781 reader->js_used += len;
Bram Moolenaar56ead342016-02-02 18:20:08 +0100782 return OK;
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100783 }
784 if (STRNICMP((char *)p, "false", 5) == 0)
785 {
786 reader->js_used += 5;
Bram Moolenaar56ead342016-02-02 18:20:08 +0100787 if (res != NULL)
788 {
789 res->v_type = VAR_SPECIAL;
790 res->vval.v_number = VVAL_FALSE;
791 }
792 return OK;
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100793 }
794 if (STRNICMP((char *)p, "true", 4) == 0)
795 {
796 reader->js_used += 4;
Bram Moolenaar56ead342016-02-02 18:20:08 +0100797 if (res != NULL)
798 {
799 res->v_type = VAR_SPECIAL;
800 res->vval.v_number = VVAL_TRUE;
801 }
802 return OK;
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100803 }
804 if (STRNICMP((char *)p, "null", 4) == 0)
805 {
806 reader->js_used += 4;
Bram Moolenaar56ead342016-02-02 18:20:08 +0100807 if (res != NULL)
808 {
809 res->v_type = VAR_SPECIAL;
810 res->vval.v_number = VVAL_NULL;
811 }
812 return OK;
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100813 }
Bram Moolenaarf1b6ac72016-02-23 21:26:43 +0100814#ifdef FEAT_FLOAT
815 if (STRNICMP((char *)p, "NaN", 3) == 0)
816 {
817 reader->js_used += 3;
818 if (res != NULL)
819 {
820 res->v_type = VAR_FLOAT;
Bram Moolenaar3ea0f1a2016-02-23 22:07:32 +0100821 res->vval.v_float = NAN;
Bram Moolenaarf1b6ac72016-02-23 21:26:43 +0100822 }
823 return OK;
824 }
825 if (STRNICMP((char *)p, "Infinity", 8) == 0)
826 {
827 reader->js_used += 8;
828 if (res != NULL)
829 {
830 res->v_type = VAR_FLOAT;
Bram Moolenaar3ea0f1a2016-02-23 22:07:32 +0100831 res->vval.v_float = INFINITY;
Bram Moolenaarf1b6ac72016-02-23 21:26:43 +0100832 }
833 return OK;
834 }
835#endif
Bram Moolenaar56ead342016-02-02 18:20:08 +0100836 /* check for truncated name */
837 len = (int)(reader->js_end - (reader->js_buf + reader->js_used));
Bram Moolenaarf1b6ac72016-02-23 21:26:43 +0100838 if (
839 (len < 5 && STRNICMP((char *)p, "false", len) == 0)
840#ifdef FEAT_FLOAT
841 || (len < 8 && STRNICMP((char *)p, "Infinity", len) == 0)
842 || (len < 3 && STRNICMP((char *)p, "NaN", len) == 0)
843#endif
Bram Moolenaar56ead342016-02-02 18:20:08 +0100844 || (len < 4 && (STRNICMP((char *)p, "true", len) == 0
845 || STRNICMP((char *)p, "null", len) == 0)))
846 return MAYBE;
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100847 break;
848 }
849
Bram Moolenaar56ead342016-02-02 18:20:08 +0100850 if (res != NUL)
851 {
852 res->v_type = VAR_SPECIAL;
853 res->vval.v_number = VVAL_NONE;
854 }
855 return FAIL;
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100856}
857
858/*
859 * Decode the JSON from "reader" and store the result in "res".
Bram Moolenaar595e64e2016-02-07 19:19:53 +0100860 * "options" can be JSON_JS or zero;
Bram Moolenaar56ead342016-02-02 18:20:08 +0100861 * Return FAIL if not the whole message was consumed.
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100862 */
Bram Moolenaar19d2f152016-02-01 21:38:19 +0100863 int
Bram Moolenaar595e64e2016-02-07 19:19:53 +0100864json_decode_all(js_read_T *reader, typval_T *res, int options)
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100865{
Bram Moolenaar56ead342016-02-02 18:20:08 +0100866 int ret;
867
Bram Moolenaar595e64e2016-02-07 19:19:53 +0100868 /* We find the end once, to avoid calling strlen() many times. */
Bram Moolenaar56ead342016-02-02 18:20:08 +0100869 reader->js_end = reader->js_buf + STRLEN(reader->js_buf);
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100870 json_skip_white(reader);
Bram Moolenaar595e64e2016-02-07 19:19:53 +0100871 ret = json_decode_item(reader, res, options);
Bram Moolenaar56ead342016-02-02 18:20:08 +0100872 if (ret != OK)
873 return FAIL;
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100874 json_skip_white(reader);
875 if (reader->js_buf[reader->js_used] != NUL)
Bram Moolenaar19d2f152016-02-01 21:38:19 +0100876 return FAIL;
877 return OK;
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100878}
Bram Moolenaar56ead342016-02-02 18:20:08 +0100879
880/*
881 * Decode the JSON from "reader" and store the result in "res".
Bram Moolenaar595e64e2016-02-07 19:19:53 +0100882 * "options" can be JSON_JS or zero;
Bram Moolenaar56ead342016-02-02 18:20:08 +0100883 * Return FAIL if the message has a decoding error or the message is
884 * truncated. Consumes the message anyway.
885 */
886 int
Bram Moolenaar595e64e2016-02-07 19:19:53 +0100887json_decode(js_read_T *reader, typval_T *res, int options)
Bram Moolenaar56ead342016-02-02 18:20:08 +0100888{
889 int ret;
890
Bram Moolenaar595e64e2016-02-07 19:19:53 +0100891 /* We find the end once, to avoid calling strlen() many times. */
Bram Moolenaar56ead342016-02-02 18:20:08 +0100892 reader->js_end = reader->js_buf + STRLEN(reader->js_buf);
893 json_skip_white(reader);
Bram Moolenaar595e64e2016-02-07 19:19:53 +0100894 ret = json_decode_item(reader, res, options);
Bram Moolenaar56ead342016-02-02 18:20:08 +0100895 json_skip_white(reader);
896
897 return ret == OK ? OK : FAIL;
898}
899
900/*
901 * Decode the JSON from "reader" to find the end of the message.
Bram Moolenaar595e64e2016-02-07 19:19:53 +0100902 * "options" can be JSON_JS or zero;
Bram Moolenaar56ead342016-02-02 18:20:08 +0100903 * Return FAIL if the message has a decoding error.
904 * Return MAYBE if the message is truncated, need to read more.
905 * This only works reliable if the message contains an object, array or
906 * string. A number might be trucated without knowing.
907 * Does not advance the reader.
908 */
909 int
Bram Moolenaar595e64e2016-02-07 19:19:53 +0100910json_find_end(js_read_T *reader, int options)
Bram Moolenaar56ead342016-02-02 18:20:08 +0100911{
912 int used_save = reader->js_used;
913 int ret;
914
Bram Moolenaar595e64e2016-02-07 19:19:53 +0100915 /* We find the end once, to avoid calling strlen() many times. */
Bram Moolenaar56ead342016-02-02 18:20:08 +0100916 reader->js_end = reader->js_buf + STRLEN(reader->js_buf);
917 json_skip_white(reader);
Bram Moolenaar595e64e2016-02-07 19:19:53 +0100918 ret = json_decode_item(reader, NULL, options);
Bram Moolenaar56ead342016-02-02 18:20:08 +0100919 reader->js_used = used_save;
920 return ret;
921}
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100922#endif