blob: 8d9a03b71da4254eadb3ee080ed2e91f0a0b353f [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 Moolenaar595e64e2016-02-07 19:19:53 +010019static int json_encode_item(garray_T *gap, typval_T *val, int copyID, int options);
20static int json_decode_item(js_read_T *reader, typval_T *res, int options);
Bram Moolenaar520e1e42016-01-23 19:46:28 +010021
22/*
23 * Encode "val" into a JSON format string.
Bram Moolenaar55fab432016-02-07 16:53:13 +010024 * The result is in allocated memory.
25 * The result is empty when encoding fails.
Bram Moolenaar595e64e2016-02-07 19:19:53 +010026 * "options" can be JSON_JS or zero;
Bram Moolenaar520e1e42016-01-23 19:46:28 +010027 */
28 char_u *
Bram Moolenaar595e64e2016-02-07 19:19:53 +010029json_encode(typval_T *val, int options)
Bram Moolenaar520e1e42016-01-23 19:46:28 +010030{
31 garray_T ga;
32
33 /* Store bytes in the growarray. */
34 ga_init2(&ga, 1, 4000);
Bram Moolenaar595e64e2016-02-07 19:19:53 +010035 if (json_encode_item(&ga, val, get_copyID(), options) == FAIL)
Bram Moolenaar55fab432016-02-07 16:53:13 +010036 {
37 vim_free(ga.ga_data);
38 return vim_strsave((char_u *)"");
39 }
Bram Moolenaar520e1e42016-01-23 19:46:28 +010040 return ga.ga_data;
41}
42
Bram Moolenaarfb1f6262016-01-31 20:24:32 +010043/*
Bram Moolenaar55fab432016-02-07 16:53:13 +010044 * Encode ["nr", "val"] into a JSON format string in allocated memory.
Bram Moolenaar595e64e2016-02-07 19:19:53 +010045 * "options" can be JSON_JS or zero;
Bram Moolenaarfb1f6262016-01-31 20:24:32 +010046 * Returns NULL when out of memory.
47 */
48 char_u *
Bram Moolenaar595e64e2016-02-07 19:19:53 +010049json_encode_nr_expr(int nr, typval_T *val, int options)
Bram Moolenaarfb1f6262016-01-31 20:24:32 +010050{
51 typval_T listtv;
52 typval_T nrtv;
53 char_u *text;
54
55 nrtv.v_type = VAR_NUMBER;
56 nrtv.vval.v_number = nr;
57 if (rettv_list_alloc(&listtv) == FAIL)
58 return NULL;
59 if (list_append_tv(listtv.vval.v_list, &nrtv) == FAIL
60 || list_append_tv(listtv.vval.v_list, val) == FAIL)
61 {
62 list_unref(listtv.vval.v_list);
63 return NULL;
64 }
65
Bram Moolenaar595e64e2016-02-07 19:19:53 +010066 text = json_encode(&listtv, options);
Bram Moolenaarfb1f6262016-01-31 20:24:32 +010067 list_unref(listtv.vval.v_list);
68 return text;
69}
70
Bram Moolenaar520e1e42016-01-23 19:46:28 +010071 static void
72write_string(garray_T *gap, char_u *str)
73{
74 char_u *res = str;
75 char_u numbuf[NUMBUFLEN];
76
77 if (res == NULL)
78 ga_concat(gap, (char_u *)"null");
79 else
80 {
81 ga_append(gap, '"');
82 while (*res != NUL)
83 {
84 int c = PTR2CHAR(res);
85
86 switch (c)
87 {
88 case 0x08:
89 ga_append(gap, '\\'); ga_append(gap, 'b'); break;
90 case 0x09:
91 ga_append(gap, '\\'); ga_append(gap, 't'); break;
92 case 0x0a:
93 ga_append(gap, '\\'); ga_append(gap, 'n'); break;
94 case 0x0c:
95 ga_append(gap, '\\'); ga_append(gap, 'f'); break;
96 case 0x0d:
97 ga_append(gap, '\\'); ga_append(gap, 'r'); break;
98 case 0x22: /* " */
99 case 0x5c: /* \ */
100 ga_append(gap, '\\');
101 ga_append(gap, c);
102 break;
103 default:
104 if (c >= 0x20)
105 {
Bram Moolenaarfa06a512016-01-28 22:46:58 +0100106#ifdef FEAT_MBYTE
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100107 numbuf[mb_char2bytes(c, numbuf)] = NUL;
Bram Moolenaarfa06a512016-01-28 22:46:58 +0100108#else
109 numbuf[0] = c;
110 numbuf[1] = NUL;
111#endif
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100112 ga_concat(gap, numbuf);
113 }
114 else
115 {
116 vim_snprintf((char *)numbuf, NUMBUFLEN,
117 "\\u%04lx", (long)c);
118 ga_concat(gap, numbuf);
119 }
120 }
121 mb_cptr_adv(res);
122 }
123 ga_append(gap, '"');
124 }
125}
126
Bram Moolenaarfcaaae62016-01-24 16:49:11 +0100127/*
Bram Moolenaar595e64e2016-02-07 19:19:53 +0100128 * Return TRUE if "key" can be used without quotes.
129 * That is when it starts with a letter and only contains letters, digits and
130 * underscore.
131 */
132 static int
133is_simple_key(char_u *key)
134{
135 char_u *p;
136
137 if (!ASCII_ISALPHA(*key))
138 return FALSE;
139 for (p = key + 1; *p != NUL; ++p)
140 if (!ASCII_ISALPHA(*p) && *p != '_' && !vim_isdigit(*p))
141 return FALSE;
142 return TRUE;
143}
144
145/*
Bram Moolenaarfcaaae62016-01-24 16:49:11 +0100146 * Encode "val" into "gap".
147 * Return FAIL or OK.
148 */
149 static int
Bram Moolenaar595e64e2016-02-07 19:19:53 +0100150json_encode_item(garray_T *gap, typval_T *val, int copyID, int options)
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100151{
152 char_u numbuf[NUMBUFLEN];
153 char_u *res;
154 list_T *l;
155 dict_T *d;
156
157 switch (val->v_type)
158 {
159 case VAR_SPECIAL:
Bram Moolenaarfcaaae62016-01-24 16:49:11 +0100160 switch (val->vval.v_number)
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100161 {
162 case VVAL_FALSE: ga_concat(gap, (char_u *)"false"); break;
163 case VVAL_TRUE: ga_concat(gap, (char_u *)"true"); break;
Bram Moolenaar595e64e2016-02-07 19:19:53 +0100164 case VVAL_NONE: if ((options & JSON_JS) != 0
165 && (options & JSON_NO_NONE) == 0)
166 /* empty item */
167 break;
168 /* FALLTHROUGH */
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100169 case VVAL_NULL: ga_concat(gap, (char_u *)"null"); break;
170 }
171 break;
172
173 case VAR_NUMBER:
174 vim_snprintf((char *)numbuf, NUMBUFLEN, "%ld",
175 (long)val->vval.v_number);
176 ga_concat(gap, numbuf);
177 break;
178
179 case VAR_STRING:
180 res = val->vval.v_string;
181 write_string(gap, res);
182 break;
183
184 case VAR_FUNC:
Bram Moolenaar55fab432016-02-07 16:53:13 +0100185 case VAR_JOB:
Bram Moolenaar77073442016-02-13 23:23:53 +0100186 case VAR_CHANNEL:
Bram Moolenaar4f8b8fa2016-02-06 18:42:07 +0100187 /* no JSON equivalent TODO: better error */
Bram Moolenaarfcaaae62016-01-24 16:49:11 +0100188 EMSG(_(e_invarg));
189 return FAIL;
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100190
191 case VAR_LIST:
192 l = val->vval.v_list;
193 if (l == NULL)
194 ga_concat(gap, (char_u *)"null");
195 else
196 {
197 if (l->lv_copyID == copyID)
198 ga_concat(gap, (char_u *)"[]");
199 else
200 {
201 listitem_T *li;
202
203 l->lv_copyID = copyID;
204 ga_append(gap, '[');
205 for (li = l->lv_first; li != NULL && !got_int; )
206 {
Bram Moolenaar595e64e2016-02-07 19:19:53 +0100207 if (json_encode_item(gap, &li->li_tv, copyID,
208 options & JSON_JS) == FAIL)
Bram Moolenaarfcaaae62016-01-24 16:49:11 +0100209 return FAIL;
Bram Moolenaar595e64e2016-02-07 19:19:53 +0100210 if ((options & JSON_JS)
211 && li->li_next == NULL
212 && li->li_tv.v_type == VAR_SPECIAL
213 && li->li_tv.vval.v_number == VVAL_NONE)
214 /* add an extra comma if the last item is v:none */
215 ga_append(gap, ',');
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100216 li = li->li_next;
217 if (li != NULL)
218 ga_append(gap, ',');
219 }
220 ga_append(gap, ']');
Bram Moolenaarfcaaae62016-01-24 16:49:11 +0100221 l->lv_copyID = 0;
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100222 }
223 }
224 break;
225
226 case VAR_DICT:
227 d = val->vval.v_dict;
228 if (d == NULL)
229 ga_concat(gap, (char_u *)"null");
230 else
231 {
232 if (d->dv_copyID == copyID)
233 ga_concat(gap, (char_u *)"{}");
234 else
235 {
236 int first = TRUE;
237 int todo = (int)d->dv_hashtab.ht_used;
238 hashitem_T *hi;
239
240 d->dv_copyID = copyID;
241 ga_append(gap, '{');
242
243 for (hi = d->dv_hashtab.ht_array; todo > 0 && !got_int;
244 ++hi)
245 if (!HASHITEM_EMPTY(hi))
246 {
247 --todo;
248 if (first)
249 first = FALSE;
250 else
251 ga_append(gap, ',');
Bram Moolenaar595e64e2016-02-07 19:19:53 +0100252 if ((options & JSON_JS)
253 && is_simple_key(hi->hi_key))
254 ga_concat(gap, hi->hi_key);
255 else
256 write_string(gap, hi->hi_key);
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100257 ga_append(gap, ':');
Bram Moolenaarfcaaae62016-01-24 16:49:11 +0100258 if (json_encode_item(gap, &dict_lookup(hi)->di_tv,
Bram Moolenaar595e64e2016-02-07 19:19:53 +0100259 copyID, options | JSON_NO_NONE) == FAIL)
Bram Moolenaarfcaaae62016-01-24 16:49:11 +0100260 return FAIL;
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100261 }
262 ga_append(gap, '}');
Bram Moolenaarfcaaae62016-01-24 16:49:11 +0100263 d->dv_copyID = 0;
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100264 }
265 }
266 break;
267
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100268 case VAR_FLOAT:
Bram Moolenaar55fab432016-02-07 16:53:13 +0100269#ifdef FEAT_FLOAT
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100270 vim_snprintf((char *)numbuf, NUMBUFLEN, "%g", val->vval.v_float);
271 ga_concat(gap, numbuf);
272 break;
273#endif
Bram Moolenaar55fab432016-02-07 16:53:13 +0100274 case VAR_UNKNOWN:
275 EMSG2(_(e_intern2), "json_encode_item()"); break;
276 return FAIL;
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100277 }
Bram Moolenaarfcaaae62016-01-24 16:49:11 +0100278 return OK;
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100279}
280
281/*
Bram Moolenaar56ead342016-02-02 18:20:08 +0100282 * When "reader" has less than NUMBUFLEN bytes available, call the fill
283 * callback to get more.
284 */
285 static void
286fill_numbuflen(js_read_T *reader)
287{
288 if (reader->js_fill != NULL && (int)(reader->js_end - reader->js_buf)
289 - reader->js_used < NUMBUFLEN)
290 {
291 if (reader->js_fill(reader))
292 reader->js_end = reader->js_buf + STRLEN(reader->js_buf);
293 }
294}
295
296/*
Bram Moolenaar595e64e2016-02-07 19:19:53 +0100297 * Skip white space in "reader". All characters <= space are considered white
298 * space.
Bram Moolenaar56ead342016-02-02 18:20:08 +0100299 * Also tops up readahead when needed.
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100300 */
301 static void
302json_skip_white(js_read_T *reader)
303{
304 int c;
305
Bram Moolenaar56ead342016-02-02 18:20:08 +0100306 for (;;)
307 {
308 c = reader->js_buf[reader->js_used];
309 if (reader->js_fill != NULL && c == NUL)
310 {
311 if (reader->js_fill(reader))
312 reader->js_end = reader->js_buf + STRLEN(reader->js_buf);
313 continue;
314 }
Bram Moolenaar595e64e2016-02-07 19:19:53 +0100315 if (c == NUL || c > ' ')
Bram Moolenaar56ead342016-02-02 18:20:08 +0100316 break;
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100317 ++reader->js_used;
Bram Moolenaar56ead342016-02-02 18:20:08 +0100318 }
319 fill_numbuflen(reader);
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100320}
321
Bram Moolenaar56ead342016-02-02 18:20:08 +0100322 static int
Bram Moolenaar595e64e2016-02-07 19:19:53 +0100323json_decode_array(js_read_T *reader, typval_T *res, int options)
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100324{
325 char_u *p;
326 typval_T item;
327 listitem_T *li;
Bram Moolenaar56ead342016-02-02 18:20:08 +0100328 int ret;
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100329
Bram Moolenaar56ead342016-02-02 18:20:08 +0100330 if (res != NULL && rettv_list_alloc(res) == FAIL)
331 {
332 res->v_type = VAR_SPECIAL;
333 res->vval.v_number = VVAL_NONE;
334 return FAIL;
335 }
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100336 ++reader->js_used; /* consume the '[' */
337
338 while (TRUE)
339 {
340 json_skip_white(reader);
341 p = reader->js_buf + reader->js_used;
342 if (*p == NUL)
Bram Moolenaar56ead342016-02-02 18:20:08 +0100343 return MAYBE;
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100344 if (*p == ']')
345 {
346 ++reader->js_used; /* consume the ']' */
Bram Moolenaar56ead342016-02-02 18:20:08 +0100347 break;
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100348 }
349
Bram Moolenaar595e64e2016-02-07 19:19:53 +0100350 ret = json_decode_item(reader, res == NULL ? NULL : &item, options);
Bram Moolenaar56ead342016-02-02 18:20:08 +0100351 if (ret != OK)
352 return ret;
353 if (res != NULL)
354 {
355 li = listitem_alloc();
356 if (li == NULL)
357 {
358 clear_tv(&item);
359 return FAIL;
360 }
361 li->li_tv = item;
362 list_append(res->vval.v_list, li);
363 }
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100364
365 json_skip_white(reader);
366 p = reader->js_buf + reader->js_used;
367 if (*p == ',')
368 ++reader->js_used;
369 else if (*p != ']')
Bram Moolenaar56ead342016-02-02 18:20:08 +0100370 {
371 if (*p == NUL)
372 return MAYBE;
373 return FAIL;
374 }
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100375 }
Bram Moolenaar56ead342016-02-02 18:20:08 +0100376 return OK;
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100377}
378
Bram Moolenaar56ead342016-02-02 18:20:08 +0100379 static int
Bram Moolenaar595e64e2016-02-07 19:19:53 +0100380json_decode_object(js_read_T *reader, typval_T *res, int options)
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100381{
382 char_u *p;
383 typval_T tvkey;
384 typval_T item;
385 dictitem_T *di;
386 char_u buf[NUMBUFLEN];
Bram Moolenaarfbf9c6b2016-02-02 19:43:57 +0100387 char_u *key = NULL;
Bram Moolenaar56ead342016-02-02 18:20:08 +0100388 int ret;
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100389
Bram Moolenaar56ead342016-02-02 18:20:08 +0100390 if (res != NULL && rettv_dict_alloc(res) == FAIL)
391 {
392 res->v_type = VAR_SPECIAL;
393 res->vval.v_number = VVAL_NONE;
394 return FAIL;
395 }
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100396 ++reader->js_used; /* consume the '{' */
397
398 while (TRUE)
399 {
400 json_skip_white(reader);
401 p = reader->js_buf + reader->js_used;
402 if (*p == NUL)
Bram Moolenaar56ead342016-02-02 18:20:08 +0100403 return MAYBE;
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100404 if (*p == '}')
405 {
406 ++reader->js_used; /* consume the '}' */
Bram Moolenaar56ead342016-02-02 18:20:08 +0100407 break;
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100408 }
409
Bram Moolenaar595e64e2016-02-07 19:19:53 +0100410 if ((options & JSON_JS) && reader->js_buf[reader->js_used] != '"')
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100411 {
Bram Moolenaar595e64e2016-02-07 19:19:53 +0100412 /* accept a key that is not in quotes */
413 key = p = reader->js_buf + reader->js_used;
414 while (*p != NUL && *p != ':' && *p > ' ')
415 ++p;
416 tvkey.v_type = VAR_STRING;
417 tvkey.vval.v_string = vim_strnsave(key, (int)(p - key));
418 reader->js_used += (int)(p - key);
419 key = tvkey.vval.v_string;
420 }
421 else
422 {
423 ret = json_decode_item(reader, res == NULL ? NULL : &tvkey,
424 options);
425 if (ret != OK)
426 return ret;
427 if (res != NULL)
Bram Moolenaar56ead342016-02-02 18:20:08 +0100428 {
Bram Moolenaar595e64e2016-02-07 19:19:53 +0100429 key = get_tv_string_buf_chk(&tvkey, buf);
430 if (key == NULL || *key == NUL)
431 {
432 clear_tv(&tvkey);
433 return FAIL;
434 }
Bram Moolenaar56ead342016-02-02 18:20:08 +0100435 }
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100436 }
437
438 json_skip_white(reader);
439 p = reader->js_buf + reader->js_used;
440 if (*p != ':')
441 {
Bram Moolenaar56ead342016-02-02 18:20:08 +0100442 if (res != NULL)
443 clear_tv(&tvkey);
444 if (*p == NUL)
445 return MAYBE;
446 return FAIL;
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100447 }
448 ++reader->js_used;
449 json_skip_white(reader);
450
Bram Moolenaar595e64e2016-02-07 19:19:53 +0100451 ret = json_decode_item(reader, res == NULL ? NULL : &item, options);
Bram Moolenaar56ead342016-02-02 18:20:08 +0100452 if (ret != OK)
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100453 {
Bram Moolenaar56ead342016-02-02 18:20:08 +0100454 if (res != NULL)
455 clear_tv(&tvkey);
456 return ret;
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100457 }
Bram Moolenaar56ead342016-02-02 18:20:08 +0100458
459 if (res != NULL)
460 {
461 di = dictitem_alloc(key);
462 clear_tv(&tvkey);
463 if (di == NULL)
464 {
465 clear_tv(&item);
466 return FAIL;
467 }
468 di->di_tv = item;
469 if (dict_add(res->vval.v_dict, di) == FAIL)
470 {
471 dictitem_free(di);
472 return FAIL;
473 }
474 }
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100475
476 json_skip_white(reader);
477 p = reader->js_buf + reader->js_used;
478 if (*p == ',')
479 ++reader->js_used;
480 else if (*p != '}')
Bram Moolenaar56ead342016-02-02 18:20:08 +0100481 {
482 if (*p == NUL)
483 return MAYBE;
484 return FAIL;
485 }
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100486 }
Bram Moolenaar56ead342016-02-02 18:20:08 +0100487 return OK;
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100488}
489
Bram Moolenaar56ead342016-02-02 18:20:08 +0100490 static int
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100491json_decode_string(js_read_T *reader, typval_T *res)
492{
493 garray_T ga;
494 int len;
Bram Moolenaar56ead342016-02-02 18:20:08 +0100495 char_u *p;
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100496 int c;
497 long nr;
498 char_u buf[NUMBUFLEN];
499
Bram Moolenaar56ead342016-02-02 18:20:08 +0100500 if (res != NULL)
501 ga_init2(&ga, 1, 200);
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100502
Bram Moolenaar56ead342016-02-02 18:20:08 +0100503 p = reader->js_buf + reader->js_used + 1; /* skip over " */
504 while (*p != '"')
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100505 {
Bram Moolenaar56ead342016-02-02 18:20:08 +0100506 if (*p == NUL || p[1] == NUL
507#ifdef FEAT_MBYTE
508 || utf_ptr2len(p) < utf_byte2len(*p)
509#endif
510 )
511 {
512 if (reader->js_fill == NULL)
513 break;
514 len = (int)(reader->js_end - p);
515 reader->js_used = (int)(p - reader->js_buf);
516 if (!reader->js_fill(reader))
517 break; /* didn't get more */
518 p = reader->js_buf + reader->js_used;
519 reader->js_end = reader->js_buf + STRLEN(reader->js_buf);
520 continue;
521 }
522
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100523 if (*p == '\\')
524 {
525 c = -1;
526 switch (p[1])
527 {
Bram Moolenaar56ead342016-02-02 18:20:08 +0100528 case '\\': c = '\\'; break;
529 case '"': c = '"'; break;
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100530 case 'b': c = BS; break;
531 case 't': c = TAB; break;
532 case 'n': c = NL; break;
533 case 'f': c = FF; break;
534 case 'r': c = CAR; break;
535 case 'u':
Bram Moolenaar56ead342016-02-02 18:20:08 +0100536 if (reader->js_fill != NULL
537 && (int)(reader->js_end - p) < NUMBUFLEN)
538 {
539 reader->js_used = (int)(p - reader->js_buf);
540 if (reader->js_fill(reader))
541 {
542 p = reader->js_buf + reader->js_used;
543 reader->js_end = reader->js_buf
544 + STRLEN(reader->js_buf);
545 }
546 }
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100547 vim_str2nr(p + 2, NULL, &len,
548 STR2NR_HEX + STR2NR_FORCE, &nr, NULL, 4);
549 p += len + 2;
Bram Moolenaar56ead342016-02-02 18:20:08 +0100550 if (res != NULL)
551 {
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100552#ifdef FEAT_MBYTE
Bram Moolenaar56ead342016-02-02 18:20:08 +0100553 buf[(*mb_char2bytes)((int)nr, buf)] = NUL;
554 ga_concat(&ga, buf);
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100555#else
Bram Moolenaar56ead342016-02-02 18:20:08 +0100556 ga_append(&ga, nr);
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100557#endif
Bram Moolenaar56ead342016-02-02 18:20:08 +0100558 }
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100559 break;
Bram Moolenaar56ead342016-02-02 18:20:08 +0100560 default:
561 /* not a special char, skip over \ */
562 ++p;
563 continue;
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100564 }
565 if (c > 0)
566 {
567 p += 2;
Bram Moolenaar56ead342016-02-02 18:20:08 +0100568 if (res != NULL)
569 ga_append(&ga, c);
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100570 }
571 }
572 else
573 {
574 len = MB_PTR2LEN(p);
Bram Moolenaar56ead342016-02-02 18:20:08 +0100575 if (res != NULL)
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100576 {
Bram Moolenaar56ead342016-02-02 18:20:08 +0100577 if (ga_grow(&ga, len) == FAIL)
578 {
579 ga_clear(&ga);
580 return FAIL;
581 }
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100582 mch_memmove((char *)ga.ga_data + ga.ga_len, p, (size_t)len);
583 ga.ga_len += len;
584 }
585 p += len;
586 }
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100587 }
Bram Moolenaar56ead342016-02-02 18:20:08 +0100588
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100589 reader->js_used = (int)(p - reader->js_buf);
590 if (*p == '"')
591 {
592 ++reader->js_used;
Bram Moolenaar56ead342016-02-02 18:20:08 +0100593 if (res != NULL)
594 {
595 res->v_type = VAR_STRING;
Bram Moolenaar4b6a6dc2016-02-04 22:49:49 +0100596 res->vval.v_string = ga.ga_data;
Bram Moolenaar56ead342016-02-02 18:20:08 +0100597 }
598 return OK;
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100599 }
Bram Moolenaar56ead342016-02-02 18:20:08 +0100600 if (res != NULL)
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100601 {
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100602 res->v_type = VAR_SPECIAL;
603 res->vval.v_number = VVAL_NONE;
Bram Moolenaar56ead342016-02-02 18:20:08 +0100604 ga_clear(&ga);
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100605 }
Bram Moolenaar56ead342016-02-02 18:20:08 +0100606 return MAYBE;
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100607}
608
609/*
Bram Moolenaar56ead342016-02-02 18:20:08 +0100610 * Decode one item and put it in "res". If "res" is NULL only advance.
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100611 * Must already have skipped white space.
Bram Moolenaar56ead342016-02-02 18:20:08 +0100612 *
613 * Return FAIL for a decoding error.
614 * Return MAYBE for an incomplete message.
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100615 */
Bram Moolenaar56ead342016-02-02 18:20:08 +0100616 static int
Bram Moolenaar595e64e2016-02-07 19:19:53 +0100617json_decode_item(js_read_T *reader, typval_T *res, int options)
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100618{
Bram Moolenaar56ead342016-02-02 18:20:08 +0100619 char_u *p;
620 int len;
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100621
Bram Moolenaar56ead342016-02-02 18:20:08 +0100622 fill_numbuflen(reader);
623 p = reader->js_buf + reader->js_used;
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100624 switch (*p)
625 {
626 case '[': /* array */
Bram Moolenaar595e64e2016-02-07 19:19:53 +0100627 return json_decode_array(reader, res, options);
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100628
629 case '{': /* object */
Bram Moolenaar595e64e2016-02-07 19:19:53 +0100630 return json_decode_object(reader, res, options);
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100631
632 case '"': /* string */
Bram Moolenaar56ead342016-02-02 18:20:08 +0100633 return json_decode_string(reader, res);
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100634
635 case ',': /* comma: empty item */
Bram Moolenaar595e64e2016-02-07 19:19:53 +0100636 if ((options & JSON_JS) == 0)
637 return FAIL;
638 /* FALLTHROUGH */
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100639 case NUL: /* empty */
Bram Moolenaar56ead342016-02-02 18:20:08 +0100640 if (res != NULL)
641 {
642 res->v_type = VAR_SPECIAL;
643 res->vval.v_number = VVAL_NONE;
644 }
645 return OK;
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100646
647 default:
648 if (VIM_ISDIGIT(*p) || *p == '-')
649 {
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100650 char_u *sp = p;
Bram Moolenaar56ead342016-02-02 18:20:08 +0100651
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100652#ifdef FEAT_FLOAT
653 if (*sp == '-')
Bram Moolenaar56ead342016-02-02 18:20:08 +0100654 {
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100655 ++sp;
Bram Moolenaar56ead342016-02-02 18:20:08 +0100656 if (*sp == NUL)
657 return MAYBE;
658 if (!VIM_ISDIGIT(*sp))
659 return FAIL;
660 }
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100661 sp = skipdigits(sp);
662 if (*sp == '.' || *sp == 'e' || *sp == 'E')
663 {
Bram Moolenaar56ead342016-02-02 18:20:08 +0100664 if (res == NULL)
665 {
666 float_T f;
667
668 len = string2float(p, &f);
669 }
670 else
671 {
672 res->v_type = VAR_FLOAT;
673 len = string2float(p, &res->vval.v_float);
674 }
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100675 }
676 else
677#endif
678 {
679 long nr;
680
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100681 vim_str2nr(reader->js_buf + reader->js_used,
682 NULL, &len, 0, /* what */
683 &nr, NULL, 0);
Bram Moolenaar56ead342016-02-02 18:20:08 +0100684 if (res != NULL)
685 {
686 res->v_type = VAR_NUMBER;
687 res->vval.v_number = nr;
688 }
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100689 }
690 reader->js_used += len;
Bram Moolenaar56ead342016-02-02 18:20:08 +0100691 return OK;
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100692 }
693 if (STRNICMP((char *)p, "false", 5) == 0)
694 {
695 reader->js_used += 5;
Bram Moolenaar56ead342016-02-02 18:20:08 +0100696 if (res != NULL)
697 {
698 res->v_type = VAR_SPECIAL;
699 res->vval.v_number = VVAL_FALSE;
700 }
701 return OK;
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100702 }
703 if (STRNICMP((char *)p, "true", 4) == 0)
704 {
705 reader->js_used += 4;
Bram Moolenaar56ead342016-02-02 18:20:08 +0100706 if (res != NULL)
707 {
708 res->v_type = VAR_SPECIAL;
709 res->vval.v_number = VVAL_TRUE;
710 }
711 return OK;
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100712 }
713 if (STRNICMP((char *)p, "null", 4) == 0)
714 {
715 reader->js_used += 4;
Bram Moolenaar56ead342016-02-02 18:20:08 +0100716 if (res != NULL)
717 {
718 res->v_type = VAR_SPECIAL;
719 res->vval.v_number = VVAL_NULL;
720 }
721 return OK;
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100722 }
Bram Moolenaar56ead342016-02-02 18:20:08 +0100723 /* check for truncated name */
724 len = (int)(reader->js_end - (reader->js_buf + reader->js_used));
725 if ((len < 5 && STRNICMP((char *)p, "false", len) == 0)
726 || (len < 4 && (STRNICMP((char *)p, "true", len) == 0
727 || STRNICMP((char *)p, "null", len) == 0)))
728 return MAYBE;
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100729 break;
730 }
731
Bram Moolenaar56ead342016-02-02 18:20:08 +0100732 if (res != NUL)
733 {
734 res->v_type = VAR_SPECIAL;
735 res->vval.v_number = VVAL_NONE;
736 }
737 return FAIL;
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100738}
739
740/*
741 * Decode the JSON from "reader" and store the result in "res".
Bram Moolenaar595e64e2016-02-07 19:19:53 +0100742 * "options" can be JSON_JS or zero;
Bram Moolenaar56ead342016-02-02 18:20:08 +0100743 * Return FAIL if not the whole message was consumed.
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100744 */
Bram Moolenaar19d2f152016-02-01 21:38:19 +0100745 int
Bram Moolenaar595e64e2016-02-07 19:19:53 +0100746json_decode_all(js_read_T *reader, typval_T *res, int options)
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100747{
Bram Moolenaar56ead342016-02-02 18:20:08 +0100748 int ret;
749
Bram Moolenaar595e64e2016-02-07 19:19:53 +0100750 /* We find the end once, to avoid calling strlen() many times. */
Bram Moolenaar56ead342016-02-02 18:20:08 +0100751 reader->js_end = reader->js_buf + STRLEN(reader->js_buf);
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100752 json_skip_white(reader);
Bram Moolenaar595e64e2016-02-07 19:19:53 +0100753 ret = json_decode_item(reader, res, options);
Bram Moolenaar56ead342016-02-02 18:20:08 +0100754 if (ret != OK)
755 return FAIL;
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100756 json_skip_white(reader);
757 if (reader->js_buf[reader->js_used] != NUL)
Bram Moolenaar19d2f152016-02-01 21:38:19 +0100758 return FAIL;
759 return OK;
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100760}
Bram Moolenaar56ead342016-02-02 18:20:08 +0100761
762/*
763 * Decode the JSON from "reader" and store the result in "res".
Bram Moolenaar595e64e2016-02-07 19:19:53 +0100764 * "options" can be JSON_JS or zero;
Bram Moolenaar56ead342016-02-02 18:20:08 +0100765 * Return FAIL if the message has a decoding error or the message is
766 * truncated. Consumes the message anyway.
767 */
768 int
Bram Moolenaar595e64e2016-02-07 19:19:53 +0100769json_decode(js_read_T *reader, typval_T *res, int options)
Bram Moolenaar56ead342016-02-02 18:20:08 +0100770{
771 int ret;
772
Bram Moolenaar595e64e2016-02-07 19:19:53 +0100773 /* We find the end once, to avoid calling strlen() many times. */
Bram Moolenaar56ead342016-02-02 18:20:08 +0100774 reader->js_end = reader->js_buf + STRLEN(reader->js_buf);
775 json_skip_white(reader);
Bram Moolenaar595e64e2016-02-07 19:19:53 +0100776 ret = json_decode_item(reader, res, options);
Bram Moolenaar56ead342016-02-02 18:20:08 +0100777 json_skip_white(reader);
778
779 return ret == OK ? OK : FAIL;
780}
781
782/*
783 * Decode the JSON from "reader" to find the end of the message.
Bram Moolenaar595e64e2016-02-07 19:19:53 +0100784 * "options" can be JSON_JS or zero;
Bram Moolenaar56ead342016-02-02 18:20:08 +0100785 * Return FAIL if the message has a decoding error.
786 * Return MAYBE if the message is truncated, need to read more.
787 * This only works reliable if the message contains an object, array or
788 * string. A number might be trucated without knowing.
789 * Does not advance the reader.
790 */
791 int
Bram Moolenaar595e64e2016-02-07 19:19:53 +0100792json_find_end(js_read_T *reader, int options)
Bram Moolenaar56ead342016-02-02 18:20:08 +0100793{
794 int used_save = reader->js_used;
795 int ret;
796
Bram Moolenaar595e64e2016-02-07 19:19:53 +0100797 /* We find the end once, to avoid calling strlen() many times. */
Bram Moolenaar56ead342016-02-02 18:20:08 +0100798 reader->js_end = reader->js_buf + STRLEN(reader->js_buf);
799 json_skip_white(reader);
Bram Moolenaar595e64e2016-02-07 19:19:53 +0100800 ret = json_decode_item(reader, NULL, options);
Bram Moolenaar56ead342016-02-02 18:20:08 +0100801 reader->js_used = used_save;
802 return ret;
803}
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100804#endif