blob: aa168ec117f7a04fd2d3e0cc9188e5560dd4d49d [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 */
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);
22static int json_decode_item(js_read_T *reader, typval_T *res, int options);
Bram Moolenaar520e1e42016-01-23 19:46:28 +010023
24/*
25 * Encode "val" into a JSON format string.
Bram Moolenaar55fab432016-02-07 16:53:13 +010026 * The result is in allocated memory.
27 * The result is empty when encoding fails.
Bram Moolenaar595e64e2016-02-07 19:19:53 +010028 * "options" can be JSON_JS or zero;
Bram Moolenaar520e1e42016-01-23 19:46:28 +010029 */
30 char_u *
Bram Moolenaar595e64e2016-02-07 19:19:53 +010031json_encode(typval_T *val, int options)
Bram Moolenaar520e1e42016-01-23 19:46:28 +010032{
33 garray_T ga;
34
35 /* Store bytes in the growarray. */
36 ga_init2(&ga, 1, 4000);
Bram Moolenaar595e64e2016-02-07 19:19:53 +010037 if (json_encode_item(&ga, val, get_copyID(), options) == FAIL)
Bram Moolenaar55fab432016-02-07 16:53:13 +010038 {
39 vim_free(ga.ga_data);
40 return vim_strsave((char_u *)"");
41 }
Bram Moolenaar520e1e42016-01-23 19:46:28 +010042 return ga.ga_data;
43}
44
Bram Moolenaarfb1f6262016-01-31 20:24:32 +010045/*
Bram Moolenaar55fab432016-02-07 16:53:13 +010046 * Encode ["nr", "val"] into a JSON format string in allocated memory.
Bram Moolenaar595e64e2016-02-07 19:19:53 +010047 * "options" can be JSON_JS or zero;
Bram Moolenaarfb1f6262016-01-31 20:24:32 +010048 * Returns NULL when out of memory.
49 */
50 char_u *
Bram Moolenaar595e64e2016-02-07 19:19:53 +010051json_encode_nr_expr(int nr, typval_T *val, int options)
Bram Moolenaarfb1f6262016-01-31 20:24:32 +010052{
53 typval_T listtv;
54 typval_T nrtv;
55 char_u *text;
56
57 nrtv.v_type = VAR_NUMBER;
58 nrtv.vval.v_number = nr;
59 if (rettv_list_alloc(&listtv) == FAIL)
60 return NULL;
61 if (list_append_tv(listtv.vval.v_list, &nrtv) == FAIL
62 || list_append_tv(listtv.vval.v_list, val) == FAIL)
63 {
64 list_unref(listtv.vval.v_list);
65 return NULL;
66 }
67
Bram Moolenaar595e64e2016-02-07 19:19:53 +010068 text = json_encode(&listtv, options);
Bram Moolenaarfb1f6262016-01-31 20:24:32 +010069 list_unref(listtv.vval.v_list);
70 return text;
71}
72
Bram Moolenaar520e1e42016-01-23 19:46:28 +010073 static void
74write_string(garray_T *gap, char_u *str)
75{
76 char_u *res = str;
77 char_u numbuf[NUMBUFLEN];
78
79 if (res == NULL)
80 ga_concat(gap, (char_u *)"null");
81 else
82 {
Bram Moolenaarb6ff8112016-02-27 18:41:27 +010083#if defined(FEAT_MBYTE) && defined(USE_ICONV)
84 vimconv_T conv;
85 char_u *converted = NULL;
86
Bram Moolenaarf97ddbe2016-02-27 21:13:38 +010087 if (!enc_utf8)
88 {
Bram Moolenaarb3628722016-02-28 14:56:39 +010089 /* Convert the text from 'encoding' to utf-8, the JSON string is
90 * always utf-8. */
Bram Moolenaarf97ddbe2016-02-27 21:13:38 +010091 conv.vc_type = CONV_NONE;
92 convert_setup(&conv, p_enc, (char_u*)"utf-8");
93 if (conv.vc_type != CONV_NONE)
94 converted = res = string_convert(&conv, res, NULL);
95 convert_setup(&conv, NULL, NULL);
96 }
Bram Moolenaarb6ff8112016-02-27 18:41:27 +010097#endif
Bram Moolenaar520e1e42016-01-23 19:46:28 +010098 ga_append(gap, '"');
99 while (*res != NUL)
100 {
Bram Moolenaarb6ff8112016-02-27 18:41:27 +0100101 int c;
102#ifdef FEAT_MBYTE
103 /* always use utf-8 encoding, ignore 'encoding' */
104 c = utf_ptr2char(res);
105#else
Bram Moolenaar0f526f52016-02-27 22:59:41 +0100106 c = *res;
Bram Moolenaarb6ff8112016-02-27 18:41:27 +0100107#endif
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100108
109 switch (c)
110 {
111 case 0x08:
112 ga_append(gap, '\\'); ga_append(gap, 'b'); break;
113 case 0x09:
114 ga_append(gap, '\\'); ga_append(gap, 't'); break;
115 case 0x0a:
116 ga_append(gap, '\\'); ga_append(gap, 'n'); break;
117 case 0x0c:
118 ga_append(gap, '\\'); ga_append(gap, 'f'); break;
119 case 0x0d:
120 ga_append(gap, '\\'); ga_append(gap, 'r'); break;
121 case 0x22: /* " */
122 case 0x5c: /* \ */
123 ga_append(gap, '\\');
124 ga_append(gap, c);
125 break;
126 default:
127 if (c >= 0x20)
128 {
Bram Moolenaarfa06a512016-01-28 22:46:58 +0100129#ifdef FEAT_MBYTE
Bram Moolenaarb6ff8112016-02-27 18:41:27 +0100130 numbuf[utf_char2bytes(c, numbuf)] = NUL;
Bram Moolenaarfa06a512016-01-28 22:46:58 +0100131#else
132 numbuf[0] = c;
133 numbuf[1] = NUL;
134#endif
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100135 ga_concat(gap, numbuf);
136 }
137 else
138 {
139 vim_snprintf((char *)numbuf, NUMBUFLEN,
140 "\\u%04lx", (long)c);
141 ga_concat(gap, numbuf);
142 }
143 }
Bram Moolenaarb6ff8112016-02-27 18:41:27 +0100144#ifdef FEAT_MBYTE
145 res += utf_ptr2len(res);
146#else
Bram Moolenaar0f526f52016-02-27 22:59:41 +0100147 ++res;
Bram Moolenaarb6ff8112016-02-27 18:41:27 +0100148#endif
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100149 }
150 ga_append(gap, '"');
Bram Moolenaarb6ff8112016-02-27 18:41:27 +0100151#if defined(FEAT_MBYTE) && defined(USE_ICONV)
152 vim_free(converted);
153#endif
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100154 }
155}
156
Bram Moolenaarfcaaae62016-01-24 16:49:11 +0100157/*
Bram Moolenaar595e64e2016-02-07 19:19:53 +0100158 * Return TRUE if "key" can be used without quotes.
159 * That is when it starts with a letter and only contains letters, digits and
160 * underscore.
161 */
162 static int
163is_simple_key(char_u *key)
164{
165 char_u *p;
166
167 if (!ASCII_ISALPHA(*key))
168 return FALSE;
169 for (p = key + 1; *p != NUL; ++p)
170 if (!ASCII_ISALPHA(*p) && *p != '_' && !vim_isdigit(*p))
171 return FALSE;
172 return TRUE;
173}
174
175/*
Bram Moolenaarfcaaae62016-01-24 16:49:11 +0100176 * Encode "val" into "gap".
177 * Return FAIL or OK.
178 */
179 static int
Bram Moolenaar595e64e2016-02-07 19:19:53 +0100180json_encode_item(garray_T *gap, typval_T *val, int copyID, int options)
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100181{
182 char_u numbuf[NUMBUFLEN];
183 char_u *res;
184 list_T *l;
185 dict_T *d;
186
187 switch (val->v_type)
188 {
189 case VAR_SPECIAL:
Bram Moolenaarfcaaae62016-01-24 16:49:11 +0100190 switch (val->vval.v_number)
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100191 {
192 case VVAL_FALSE: ga_concat(gap, (char_u *)"false"); break;
193 case VVAL_TRUE: ga_concat(gap, (char_u *)"true"); break;
Bram Moolenaar595e64e2016-02-07 19:19:53 +0100194 case VVAL_NONE: if ((options & JSON_JS) != 0
195 && (options & JSON_NO_NONE) == 0)
196 /* empty item */
197 break;
198 /* FALLTHROUGH */
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100199 case VVAL_NULL: ga_concat(gap, (char_u *)"null"); break;
200 }
201 break;
202
203 case VAR_NUMBER:
204 vim_snprintf((char *)numbuf, NUMBUFLEN, "%ld",
205 (long)val->vval.v_number);
206 ga_concat(gap, numbuf);
207 break;
208
209 case VAR_STRING:
210 res = val->vval.v_string;
211 write_string(gap, res);
212 break;
213
214 case VAR_FUNC:
Bram Moolenaar1735bc92016-03-14 23:05:14 +0100215 case VAR_PARTIAL:
Bram Moolenaar55fab432016-02-07 16:53:13 +0100216 case VAR_JOB:
Bram Moolenaar77073442016-02-13 23:23:53 +0100217 case VAR_CHANNEL:
Bram Moolenaar4f8b8fa2016-02-06 18:42:07 +0100218 /* no JSON equivalent TODO: better error */
Bram Moolenaarfcaaae62016-01-24 16:49:11 +0100219 EMSG(_(e_invarg));
220 return FAIL;
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100221
222 case VAR_LIST:
223 l = val->vval.v_list;
224 if (l == NULL)
225 ga_concat(gap, (char_u *)"null");
226 else
227 {
228 if (l->lv_copyID == copyID)
229 ga_concat(gap, (char_u *)"[]");
230 else
231 {
232 listitem_T *li;
233
234 l->lv_copyID = copyID;
235 ga_append(gap, '[');
236 for (li = l->lv_first; li != NULL && !got_int; )
237 {
Bram Moolenaar595e64e2016-02-07 19:19:53 +0100238 if (json_encode_item(gap, &li->li_tv, copyID,
239 options & JSON_JS) == FAIL)
Bram Moolenaarfcaaae62016-01-24 16:49:11 +0100240 return FAIL;
Bram Moolenaar595e64e2016-02-07 19:19:53 +0100241 if ((options & JSON_JS)
242 && li->li_next == NULL
243 && li->li_tv.v_type == VAR_SPECIAL
244 && li->li_tv.vval.v_number == VVAL_NONE)
245 /* add an extra comma if the last item is v:none */
246 ga_append(gap, ',');
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100247 li = li->li_next;
248 if (li != NULL)
249 ga_append(gap, ',');
250 }
251 ga_append(gap, ']');
Bram Moolenaarfcaaae62016-01-24 16:49:11 +0100252 l->lv_copyID = 0;
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100253 }
254 }
255 break;
256
257 case VAR_DICT:
258 d = val->vval.v_dict;
259 if (d == NULL)
260 ga_concat(gap, (char_u *)"null");
261 else
262 {
263 if (d->dv_copyID == copyID)
264 ga_concat(gap, (char_u *)"{}");
265 else
266 {
267 int first = TRUE;
268 int todo = (int)d->dv_hashtab.ht_used;
269 hashitem_T *hi;
270
271 d->dv_copyID = copyID;
272 ga_append(gap, '{');
273
274 for (hi = d->dv_hashtab.ht_array; todo > 0 && !got_int;
275 ++hi)
276 if (!HASHITEM_EMPTY(hi))
277 {
278 --todo;
279 if (first)
280 first = FALSE;
281 else
282 ga_append(gap, ',');
Bram Moolenaar595e64e2016-02-07 19:19:53 +0100283 if ((options & JSON_JS)
284 && is_simple_key(hi->hi_key))
285 ga_concat(gap, hi->hi_key);
286 else
287 write_string(gap, hi->hi_key);
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100288 ga_append(gap, ':');
Bram Moolenaarfcaaae62016-01-24 16:49:11 +0100289 if (json_encode_item(gap, &dict_lookup(hi)->di_tv,
Bram Moolenaar595e64e2016-02-07 19:19:53 +0100290 copyID, options | JSON_NO_NONE) == FAIL)
Bram Moolenaarfcaaae62016-01-24 16:49:11 +0100291 return FAIL;
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100292 }
293 ga_append(gap, '}');
Bram Moolenaarfcaaae62016-01-24 16:49:11 +0100294 d->dv_copyID = 0;
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100295 }
296 }
297 break;
298
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100299 case VAR_FLOAT:
Bram Moolenaar55fab432016-02-07 16:53:13 +0100300#ifdef FEAT_FLOAT
Bram Moolenaarf1b6ac72016-02-23 21:26:43 +0100301# if defined(HAVE_MATH_H)
Bram Moolenaar7ce686c2016-02-27 16:33:22 +0100302 if (isnan(val->vval.v_float))
Bram Moolenaarf1b6ac72016-02-23 21:26:43 +0100303 ga_concat(gap, (char_u *)"NaN");
Bram Moolenaar7ce686c2016-02-27 16:33:22 +0100304 else if (isinf(val->vval.v_float))
Bram Moolenaarf1b6ac72016-02-23 21:26:43 +0100305 ga_concat(gap, (char_u *)"Infinity");
Bram Moolenaarf1b6ac72016-02-23 21:26:43 +0100306 else
307# endif
308 {
309 vim_snprintf((char *)numbuf, NUMBUFLEN, "%g",
310 val->vval.v_float);
311 ga_concat(gap, numbuf);
312 }
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100313 break;
314#endif
Bram Moolenaar55fab432016-02-07 16:53:13 +0100315 case VAR_UNKNOWN:
Bram Moolenaarc6b14f02016-02-20 15:26:42 +0100316 EMSG2(_(e_intern2), "json_encode_item()");
Bram Moolenaar55fab432016-02-07 16:53:13 +0100317 return FAIL;
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100318 }
Bram Moolenaarfcaaae62016-01-24 16:49:11 +0100319 return OK;
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100320}
321
322/*
Bram Moolenaar56ead342016-02-02 18:20:08 +0100323 * When "reader" has less than NUMBUFLEN bytes available, call the fill
324 * callback to get more.
325 */
326 static void
327fill_numbuflen(js_read_T *reader)
328{
329 if (reader->js_fill != NULL && (int)(reader->js_end - reader->js_buf)
330 - reader->js_used < NUMBUFLEN)
331 {
332 if (reader->js_fill(reader))
333 reader->js_end = reader->js_buf + STRLEN(reader->js_buf);
334 }
335}
336
337/*
Bram Moolenaar595e64e2016-02-07 19:19:53 +0100338 * Skip white space in "reader". All characters <= space are considered white
339 * space.
Bram Moolenaar56ead342016-02-02 18:20:08 +0100340 * Also tops up readahead when needed.
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100341 */
342 static void
343json_skip_white(js_read_T *reader)
344{
345 int c;
346
Bram Moolenaar56ead342016-02-02 18:20:08 +0100347 for (;;)
348 {
349 c = reader->js_buf[reader->js_used];
350 if (reader->js_fill != NULL && c == NUL)
351 {
352 if (reader->js_fill(reader))
Bram Moolenaar46c00a62016-03-28 14:11:42 +0200353 {
Bram Moolenaar56ead342016-02-02 18:20:08 +0100354 reader->js_end = reader->js_buf + STRLEN(reader->js_buf);
Bram Moolenaar46c00a62016-03-28 14:11:42 +0200355 continue;
356 }
Bram Moolenaar56ead342016-02-02 18:20:08 +0100357 }
Bram Moolenaar595e64e2016-02-07 19:19:53 +0100358 if (c == NUL || c > ' ')
Bram Moolenaar56ead342016-02-02 18:20:08 +0100359 break;
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100360 ++reader->js_used;
Bram Moolenaar56ead342016-02-02 18:20:08 +0100361 }
362 fill_numbuflen(reader);
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100363}
364
Bram Moolenaar56ead342016-02-02 18:20:08 +0100365 static int
Bram Moolenaar595e64e2016-02-07 19:19:53 +0100366json_decode_array(js_read_T *reader, typval_T *res, int options)
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100367{
368 char_u *p;
369 typval_T item;
370 listitem_T *li;
Bram Moolenaar56ead342016-02-02 18:20:08 +0100371 int ret;
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100372
Bram Moolenaar56ead342016-02-02 18:20:08 +0100373 if (res != NULL && rettv_list_alloc(res) == FAIL)
374 {
375 res->v_type = VAR_SPECIAL;
376 res->vval.v_number = VVAL_NONE;
377 return FAIL;
378 }
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100379 ++reader->js_used; /* consume the '[' */
380
381 while (TRUE)
382 {
383 json_skip_white(reader);
384 p = reader->js_buf + reader->js_used;
385 if (*p == NUL)
Bram Moolenaar56ead342016-02-02 18:20:08 +0100386 return MAYBE;
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100387 if (*p == ']')
388 {
389 ++reader->js_used; /* consume the ']' */
Bram Moolenaar56ead342016-02-02 18:20:08 +0100390 break;
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100391 }
392
Bram Moolenaar595e64e2016-02-07 19:19:53 +0100393 ret = json_decode_item(reader, res == NULL ? NULL : &item, options);
Bram Moolenaar56ead342016-02-02 18:20:08 +0100394 if (ret != OK)
395 return ret;
396 if (res != NULL)
397 {
398 li = listitem_alloc();
399 if (li == NULL)
400 {
401 clear_tv(&item);
402 return FAIL;
403 }
404 li->li_tv = item;
405 list_append(res->vval.v_list, li);
406 }
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100407
408 json_skip_white(reader);
409 p = reader->js_buf + reader->js_used;
410 if (*p == ',')
411 ++reader->js_used;
412 else if (*p != ']')
Bram Moolenaar56ead342016-02-02 18:20:08 +0100413 {
414 if (*p == NUL)
415 return MAYBE;
416 return FAIL;
417 }
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100418 }
Bram Moolenaar56ead342016-02-02 18:20:08 +0100419 return OK;
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100420}
421
Bram Moolenaar56ead342016-02-02 18:20:08 +0100422 static int
Bram Moolenaar595e64e2016-02-07 19:19:53 +0100423json_decode_object(js_read_T *reader, typval_T *res, int options)
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100424{
425 char_u *p;
426 typval_T tvkey;
427 typval_T item;
428 dictitem_T *di;
429 char_u buf[NUMBUFLEN];
Bram Moolenaarfbf9c6b2016-02-02 19:43:57 +0100430 char_u *key = NULL;
Bram Moolenaar56ead342016-02-02 18:20:08 +0100431 int ret;
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100432
Bram Moolenaar56ead342016-02-02 18:20:08 +0100433 if (res != NULL && rettv_dict_alloc(res) == FAIL)
434 {
435 res->v_type = VAR_SPECIAL;
436 res->vval.v_number = VVAL_NONE;
437 return FAIL;
438 }
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100439 ++reader->js_used; /* consume the '{' */
440
441 while (TRUE)
442 {
443 json_skip_white(reader);
444 p = reader->js_buf + reader->js_used;
445 if (*p == NUL)
Bram Moolenaar56ead342016-02-02 18:20:08 +0100446 return MAYBE;
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100447 if (*p == '}')
448 {
449 ++reader->js_used; /* consume the '}' */
Bram Moolenaar56ead342016-02-02 18:20:08 +0100450 break;
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100451 }
452
Bram Moolenaar595e64e2016-02-07 19:19:53 +0100453 if ((options & JSON_JS) && reader->js_buf[reader->js_used] != '"')
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100454 {
Bram Moolenaar595e64e2016-02-07 19:19:53 +0100455 /* accept a key that is not in quotes */
456 key = p = reader->js_buf + reader->js_used;
457 while (*p != NUL && *p != ':' && *p > ' ')
458 ++p;
459 tvkey.v_type = VAR_STRING;
460 tvkey.vval.v_string = vim_strnsave(key, (int)(p - key));
461 reader->js_used += (int)(p - key);
462 key = tvkey.vval.v_string;
463 }
464 else
465 {
466 ret = json_decode_item(reader, res == NULL ? NULL : &tvkey,
467 options);
468 if (ret != OK)
469 return ret;
470 if (res != NULL)
Bram Moolenaar56ead342016-02-02 18:20:08 +0100471 {
Bram Moolenaar595e64e2016-02-07 19:19:53 +0100472 key = get_tv_string_buf_chk(&tvkey, buf);
473 if (key == NULL || *key == NUL)
474 {
475 clear_tv(&tvkey);
476 return FAIL;
477 }
Bram Moolenaar56ead342016-02-02 18:20:08 +0100478 }
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100479 }
480
481 json_skip_white(reader);
482 p = reader->js_buf + reader->js_used;
483 if (*p != ':')
484 {
Bram Moolenaar56ead342016-02-02 18:20:08 +0100485 if (res != NULL)
486 clear_tv(&tvkey);
487 if (*p == NUL)
488 return MAYBE;
489 return FAIL;
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100490 }
491 ++reader->js_used;
492 json_skip_white(reader);
493
Bram Moolenaar595e64e2016-02-07 19:19:53 +0100494 ret = json_decode_item(reader, res == NULL ? NULL : &item, options);
Bram Moolenaar56ead342016-02-02 18:20:08 +0100495 if (ret != OK)
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100496 {
Bram Moolenaar56ead342016-02-02 18:20:08 +0100497 if (res != NULL)
498 clear_tv(&tvkey);
499 return ret;
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100500 }
Bram Moolenaar56ead342016-02-02 18:20:08 +0100501
502 if (res != NULL)
503 {
504 di = dictitem_alloc(key);
505 clear_tv(&tvkey);
506 if (di == NULL)
507 {
508 clear_tv(&item);
509 return FAIL;
510 }
511 di->di_tv = item;
Bram Moolenaar2588b5a2016-03-05 23:23:02 +0100512 di->di_tv.v_lock = 0;
Bram Moolenaar56ead342016-02-02 18:20:08 +0100513 if (dict_add(res->vval.v_dict, di) == FAIL)
514 {
515 dictitem_free(di);
516 return FAIL;
517 }
518 }
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100519
520 json_skip_white(reader);
521 p = reader->js_buf + reader->js_used;
522 if (*p == ',')
523 ++reader->js_used;
524 else if (*p != '}')
Bram Moolenaar56ead342016-02-02 18:20:08 +0100525 {
526 if (*p == NUL)
527 return MAYBE;
528 return FAIL;
529 }
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100530 }
Bram Moolenaar56ead342016-02-02 18:20:08 +0100531 return OK;
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100532}
533
Bram Moolenaar56ead342016-02-02 18:20:08 +0100534 static int
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100535json_decode_string(js_read_T *reader, typval_T *res)
536{
537 garray_T ga;
538 int len;
Bram Moolenaar56ead342016-02-02 18:20:08 +0100539 char_u *p;
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100540 int c;
541 long nr;
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100542
Bram Moolenaar56ead342016-02-02 18:20:08 +0100543 if (res != NULL)
544 ga_init2(&ga, 1, 200);
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100545
Bram Moolenaar56ead342016-02-02 18:20:08 +0100546 p = reader->js_buf + reader->js_used + 1; /* skip over " */
547 while (*p != '"')
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100548 {
Bram Moolenaarb3628722016-02-28 14:56:39 +0100549 /* The JSON is always expected to be utf-8, thus use utf functions
550 * here. The string is converted below if needed. */
Bram Moolenaar56ead342016-02-02 18:20:08 +0100551 if (*p == NUL || p[1] == NUL
552#ifdef FEAT_MBYTE
553 || utf_ptr2len(p) < utf_byte2len(*p)
554#endif
555 )
556 {
Bram Moolenaarb3628722016-02-28 14:56:39 +0100557 /* Not enough bytes to make a character or end of the string. Get
558 * more if possible. */
Bram Moolenaar56ead342016-02-02 18:20:08 +0100559 if (reader->js_fill == NULL)
560 break;
561 len = (int)(reader->js_end - p);
562 reader->js_used = (int)(p - reader->js_buf);
563 if (!reader->js_fill(reader))
564 break; /* didn't get more */
565 p = reader->js_buf + reader->js_used;
566 reader->js_end = reader->js_buf + STRLEN(reader->js_buf);
567 continue;
568 }
569
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100570 if (*p == '\\')
571 {
572 c = -1;
573 switch (p[1])
574 {
Bram Moolenaar56ead342016-02-02 18:20:08 +0100575 case '\\': c = '\\'; break;
576 case '"': c = '"'; break;
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100577 case 'b': c = BS; break;
578 case 't': c = TAB; break;
579 case 'n': c = NL; break;
580 case 'f': c = FF; break;
581 case 'r': c = CAR; break;
582 case 'u':
Bram Moolenaar56ead342016-02-02 18:20:08 +0100583 if (reader->js_fill != NULL
584 && (int)(reader->js_end - p) < NUMBUFLEN)
585 {
586 reader->js_used = (int)(p - reader->js_buf);
587 if (reader->js_fill(reader))
588 {
589 p = reader->js_buf + reader->js_used;
590 reader->js_end = reader->js_buf
591 + STRLEN(reader->js_buf);
592 }
593 }
Bram Moolenaarb6ff8112016-02-27 18:41:27 +0100594 nr = 0;
595 len = 0;
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100596 vim_str2nr(p + 2, NULL, &len,
597 STR2NR_HEX + STR2NR_FORCE, &nr, NULL, 4);
598 p += len + 2;
Bram Moolenaarb6ff8112016-02-27 18:41:27 +0100599 if (0xd800 <= nr && nr <= 0xdfff
600 && (int)(reader->js_end - p) >= 6
601 && *p == '\\' && *(p+1) == 'u')
602 {
603 long nr2 = 0;
604
605 /* decode surrogate pair: \ud812\u3456 */
606 len = 0;
607 vim_str2nr(p + 2, NULL, &len,
608 STR2NR_HEX + STR2NR_FORCE, &nr2, NULL, 4);
609 if (0xdc00 <= nr2 && nr2 <= 0xdfff)
610 {
611 p += len + 2;
612 nr = (((nr - 0xd800) << 10) |
613 ((nr2 - 0xdc00) & 0x3ff)) + 0x10000;
614 }
615 }
Bram Moolenaar56ead342016-02-02 18:20:08 +0100616 if (res != NULL)
617 {
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100618#ifdef FEAT_MBYTE
Bram Moolenaardc633cf2016-04-23 14:33:19 +0200619 char_u buf[NUMBUFLEN];
Bram Moolenaarb6ff8112016-02-27 18:41:27 +0100620 buf[utf_char2bytes((int)nr, buf)] = NUL;
Bram Moolenaar56ead342016-02-02 18:20:08 +0100621 ga_concat(&ga, buf);
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100622#else
Bram Moolenaar56ead342016-02-02 18:20:08 +0100623 ga_append(&ga, nr);
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100624#endif
Bram Moolenaar56ead342016-02-02 18:20:08 +0100625 }
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100626 break;
Bram Moolenaar56ead342016-02-02 18:20:08 +0100627 default:
628 /* not a special char, skip over \ */
629 ++p;
630 continue;
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100631 }
632 if (c > 0)
633 {
634 p += 2;
Bram Moolenaar56ead342016-02-02 18:20:08 +0100635 if (res != NULL)
636 ga_append(&ga, c);
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100637 }
638 }
639 else
640 {
Bram Moolenaarb6ff8112016-02-27 18:41:27 +0100641#ifdef FEAT_MBYTE
642 len = utf_ptr2len(p);
643#else
644 len = 1;
645#endif
Bram Moolenaar56ead342016-02-02 18:20:08 +0100646 if (res != NULL)
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100647 {
Bram Moolenaar56ead342016-02-02 18:20:08 +0100648 if (ga_grow(&ga, len) == FAIL)
649 {
650 ga_clear(&ga);
651 return FAIL;
652 }
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100653 mch_memmove((char *)ga.ga_data + ga.ga_len, p, (size_t)len);
654 ga.ga_len += len;
655 }
656 p += len;
657 }
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100658 }
Bram Moolenaar56ead342016-02-02 18:20:08 +0100659
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100660 reader->js_used = (int)(p - reader->js_buf);
661 if (*p == '"')
662 {
663 ++reader->js_used;
Bram Moolenaar56ead342016-02-02 18:20:08 +0100664 if (res != NULL)
665 {
Bram Moolenaar80e78842016-02-28 15:21:13 +0100666 ga_append(&ga, NUL);
Bram Moolenaar56ead342016-02-02 18:20:08 +0100667 res->v_type = VAR_STRING;
Bram Moolenaarb3628722016-02-28 14:56:39 +0100668#if defined(FEAT_MBYTE) && defined(USE_ICONV)
669 if (!enc_utf8)
670 {
671 vimconv_T conv;
672
673 /* Convert the utf-8 string to 'encoding'. */
674 conv.vc_type = CONV_NONE;
675 convert_setup(&conv, (char_u*)"utf-8", p_enc);
676 if (conv.vc_type != CONV_NONE)
677 {
678 res->vval.v_string =
679 string_convert(&conv, ga.ga_data, NULL);
680 vim_free(ga.ga_data);
681 }
682 convert_setup(&conv, NULL, NULL);
683 }
684 else
685#endif
686 res->vval.v_string = ga.ga_data;
Bram Moolenaar56ead342016-02-02 18:20:08 +0100687 }
688 return OK;
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100689 }
Bram Moolenaar56ead342016-02-02 18:20:08 +0100690 if (res != NULL)
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100691 {
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100692 res->v_type = VAR_SPECIAL;
693 res->vval.v_number = VVAL_NONE;
Bram Moolenaar56ead342016-02-02 18:20:08 +0100694 ga_clear(&ga);
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100695 }
Bram Moolenaar56ead342016-02-02 18:20:08 +0100696 return MAYBE;
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100697}
698
699/*
Bram Moolenaar56ead342016-02-02 18:20:08 +0100700 * Decode one item and put it in "res". If "res" is NULL only advance.
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100701 * Must already have skipped white space.
Bram Moolenaar56ead342016-02-02 18:20:08 +0100702 *
703 * Return FAIL for a decoding error.
704 * Return MAYBE for an incomplete message.
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100705 */
Bram Moolenaar56ead342016-02-02 18:20:08 +0100706 static int
Bram Moolenaar595e64e2016-02-07 19:19:53 +0100707json_decode_item(js_read_T *reader, typval_T *res, int options)
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100708{
Bram Moolenaar56ead342016-02-02 18:20:08 +0100709 char_u *p;
710 int len;
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100711
Bram Moolenaar56ead342016-02-02 18:20:08 +0100712 fill_numbuflen(reader);
713 p = reader->js_buf + reader->js_used;
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100714 switch (*p)
715 {
716 case '[': /* array */
Bram Moolenaar595e64e2016-02-07 19:19:53 +0100717 return json_decode_array(reader, res, options);
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100718
719 case '{': /* object */
Bram Moolenaar595e64e2016-02-07 19:19:53 +0100720 return json_decode_object(reader, res, options);
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100721
722 case '"': /* string */
Bram Moolenaar56ead342016-02-02 18:20:08 +0100723 return json_decode_string(reader, res);
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100724
725 case ',': /* comma: empty item */
Bram Moolenaar595e64e2016-02-07 19:19:53 +0100726 if ((options & JSON_JS) == 0)
727 return FAIL;
728 /* FALLTHROUGH */
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100729 case NUL: /* empty */
Bram Moolenaar56ead342016-02-02 18:20:08 +0100730 if (res != NULL)
731 {
732 res->v_type = VAR_SPECIAL;
733 res->vval.v_number = VVAL_NONE;
734 }
735 return OK;
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100736
737 default:
738 if (VIM_ISDIGIT(*p) || *p == '-')
739 {
Bram Moolenaar10b369f2016-02-29 23:12:49 +0100740#ifdef FEAT_FLOAT
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 if (*sp == '-')
Bram Moolenaar56ead342016-02-02 18:20:08 +0100744 {
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100745 ++sp;
Bram Moolenaar56ead342016-02-02 18:20:08 +0100746 if (*sp == NUL)
747 return MAYBE;
748 if (!VIM_ISDIGIT(*sp))
749 return FAIL;
750 }
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100751 sp = skipdigits(sp);
752 if (*sp == '.' || *sp == 'e' || *sp == 'E')
753 {
Bram Moolenaar56ead342016-02-02 18:20:08 +0100754 if (res == NULL)
755 {
756 float_T f;
757
758 len = string2float(p, &f);
759 }
760 else
761 {
762 res->v_type = VAR_FLOAT;
763 len = string2float(p, &res->vval.v_float);
764 }
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100765 }
766 else
767#endif
768 {
769 long nr;
770
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100771 vim_str2nr(reader->js_buf + reader->js_used,
772 NULL, &len, 0, /* what */
773 &nr, NULL, 0);
Bram Moolenaar56ead342016-02-02 18:20:08 +0100774 if (res != NULL)
775 {
776 res->v_type = VAR_NUMBER;
777 res->vval.v_number = nr;
778 }
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100779 }
780 reader->js_used += len;
Bram Moolenaar56ead342016-02-02 18:20:08 +0100781 return OK;
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100782 }
783 if (STRNICMP((char *)p, "false", 5) == 0)
784 {
785 reader->js_used += 5;
Bram Moolenaar56ead342016-02-02 18:20:08 +0100786 if (res != NULL)
787 {
788 res->v_type = VAR_SPECIAL;
789 res->vval.v_number = VVAL_FALSE;
790 }
791 return OK;
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100792 }
793 if (STRNICMP((char *)p, "true", 4) == 0)
794 {
795 reader->js_used += 4;
Bram Moolenaar56ead342016-02-02 18:20:08 +0100796 if (res != NULL)
797 {
798 res->v_type = VAR_SPECIAL;
799 res->vval.v_number = VVAL_TRUE;
800 }
801 return OK;
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100802 }
803 if (STRNICMP((char *)p, "null", 4) == 0)
804 {
805 reader->js_used += 4;
Bram Moolenaar56ead342016-02-02 18:20:08 +0100806 if (res != NULL)
807 {
808 res->v_type = VAR_SPECIAL;
809 res->vval.v_number = VVAL_NULL;
810 }
811 return OK;
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100812 }
Bram Moolenaarf1b6ac72016-02-23 21:26:43 +0100813#ifdef FEAT_FLOAT
814 if (STRNICMP((char *)p, "NaN", 3) == 0)
815 {
816 reader->js_used += 3;
817 if (res != NULL)
818 {
819 res->v_type = VAR_FLOAT;
Bram Moolenaar3ea0f1a2016-02-23 22:07:32 +0100820 res->vval.v_float = NAN;
Bram Moolenaarf1b6ac72016-02-23 21:26:43 +0100821 }
822 return OK;
823 }
824 if (STRNICMP((char *)p, "Infinity", 8) == 0)
825 {
826 reader->js_used += 8;
827 if (res != NULL)
828 {
829 res->v_type = VAR_FLOAT;
Bram Moolenaar3ea0f1a2016-02-23 22:07:32 +0100830 res->vval.v_float = INFINITY;
Bram Moolenaarf1b6ac72016-02-23 21:26:43 +0100831 }
832 return OK;
833 }
834#endif
Bram Moolenaar56ead342016-02-02 18:20:08 +0100835 /* check for truncated name */
836 len = (int)(reader->js_end - (reader->js_buf + reader->js_used));
Bram Moolenaarf1b6ac72016-02-23 21:26:43 +0100837 if (
838 (len < 5 && STRNICMP((char *)p, "false", len) == 0)
839#ifdef FEAT_FLOAT
840 || (len < 8 && STRNICMP((char *)p, "Infinity", len) == 0)
841 || (len < 3 && STRNICMP((char *)p, "NaN", len) == 0)
842#endif
Bram Moolenaar56ead342016-02-02 18:20:08 +0100843 || (len < 4 && (STRNICMP((char *)p, "true", len) == 0
844 || STRNICMP((char *)p, "null", len) == 0)))
845 return MAYBE;
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100846 break;
847 }
848
Bram Moolenaar56ead342016-02-02 18:20:08 +0100849 if (res != NUL)
850 {
851 res->v_type = VAR_SPECIAL;
852 res->vval.v_number = VVAL_NONE;
853 }
854 return FAIL;
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100855}
856
857/*
858 * Decode the JSON from "reader" and store the result in "res".
Bram Moolenaar595e64e2016-02-07 19:19:53 +0100859 * "options" can be JSON_JS or zero;
Bram Moolenaar56ead342016-02-02 18:20:08 +0100860 * Return FAIL if not the whole message was consumed.
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100861 */
Bram Moolenaar19d2f152016-02-01 21:38:19 +0100862 int
Bram Moolenaar595e64e2016-02-07 19:19:53 +0100863json_decode_all(js_read_T *reader, typval_T *res, int options)
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100864{
Bram Moolenaar56ead342016-02-02 18:20:08 +0100865 int ret;
866
Bram Moolenaar595e64e2016-02-07 19:19:53 +0100867 /* We find the end once, to avoid calling strlen() many times. */
Bram Moolenaar56ead342016-02-02 18:20:08 +0100868 reader->js_end = reader->js_buf + STRLEN(reader->js_buf);
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100869 json_skip_white(reader);
Bram Moolenaar595e64e2016-02-07 19:19:53 +0100870 ret = json_decode_item(reader, res, options);
Bram Moolenaar56ead342016-02-02 18:20:08 +0100871 if (ret != OK)
872 return FAIL;
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100873 json_skip_white(reader);
874 if (reader->js_buf[reader->js_used] != NUL)
Bram Moolenaar19d2f152016-02-01 21:38:19 +0100875 return FAIL;
876 return OK;
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100877}
Bram Moolenaar56ead342016-02-02 18:20:08 +0100878
879/*
880 * Decode the JSON from "reader" and store the result in "res".
Bram Moolenaar595e64e2016-02-07 19:19:53 +0100881 * "options" can be JSON_JS or zero;
Bram Moolenaarba61ac02016-03-20 16:40:37 +0100882 * Return FAIL for a decoding error.
883 * Return MAYBE for an incomplete message.
884 * Consumes the message anyway.
Bram Moolenaar56ead342016-02-02 18:20:08 +0100885 */
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
Bram Moolenaarba61ac02016-03-20 16:40:37 +0100897 return ret;
Bram Moolenaar56ead342016-02-02 18:20:08 +0100898}
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