blob: 31bac26d5fe41cf3cbb44af6062ff55f392ac310 [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 Moolenaar4f8b8fa2016-02-06 18:42:07 +0100186 /* no JSON equivalent TODO: better error */
Bram Moolenaarfcaaae62016-01-24 16:49:11 +0100187 EMSG(_(e_invarg));
188 return FAIL;
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100189
190 case VAR_LIST:
191 l = val->vval.v_list;
192 if (l == NULL)
193 ga_concat(gap, (char_u *)"null");
194 else
195 {
196 if (l->lv_copyID == copyID)
197 ga_concat(gap, (char_u *)"[]");
198 else
199 {
200 listitem_T *li;
201
202 l->lv_copyID = copyID;
203 ga_append(gap, '[');
204 for (li = l->lv_first; li != NULL && !got_int; )
205 {
Bram Moolenaar595e64e2016-02-07 19:19:53 +0100206 if (json_encode_item(gap, &li->li_tv, copyID,
207 options & JSON_JS) == FAIL)
Bram Moolenaarfcaaae62016-01-24 16:49:11 +0100208 return FAIL;
Bram Moolenaar595e64e2016-02-07 19:19:53 +0100209 if ((options & JSON_JS)
210 && li->li_next == NULL
211 && li->li_tv.v_type == VAR_SPECIAL
212 && li->li_tv.vval.v_number == VVAL_NONE)
213 /* add an extra comma if the last item is v:none */
214 ga_append(gap, ',');
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100215 li = li->li_next;
216 if (li != NULL)
217 ga_append(gap, ',');
218 }
219 ga_append(gap, ']');
Bram Moolenaarfcaaae62016-01-24 16:49:11 +0100220 l->lv_copyID = 0;
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100221 }
222 }
223 break;
224
225 case VAR_DICT:
226 d = val->vval.v_dict;
227 if (d == NULL)
228 ga_concat(gap, (char_u *)"null");
229 else
230 {
231 if (d->dv_copyID == copyID)
232 ga_concat(gap, (char_u *)"{}");
233 else
234 {
235 int first = TRUE;
236 int todo = (int)d->dv_hashtab.ht_used;
237 hashitem_T *hi;
238
239 d->dv_copyID = copyID;
240 ga_append(gap, '{');
241
242 for (hi = d->dv_hashtab.ht_array; todo > 0 && !got_int;
243 ++hi)
244 if (!HASHITEM_EMPTY(hi))
245 {
246 --todo;
247 if (first)
248 first = FALSE;
249 else
250 ga_append(gap, ',');
Bram Moolenaar595e64e2016-02-07 19:19:53 +0100251 if ((options & JSON_JS)
252 && is_simple_key(hi->hi_key))
253 ga_concat(gap, hi->hi_key);
254 else
255 write_string(gap, hi->hi_key);
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100256 ga_append(gap, ':');
Bram Moolenaarfcaaae62016-01-24 16:49:11 +0100257 if (json_encode_item(gap, &dict_lookup(hi)->di_tv,
Bram Moolenaar595e64e2016-02-07 19:19:53 +0100258 copyID, options | JSON_NO_NONE) == FAIL)
Bram Moolenaarfcaaae62016-01-24 16:49:11 +0100259 return FAIL;
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100260 }
261 ga_append(gap, '}');
Bram Moolenaarfcaaae62016-01-24 16:49:11 +0100262 d->dv_copyID = 0;
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100263 }
264 }
265 break;
266
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100267 case VAR_FLOAT:
Bram Moolenaar55fab432016-02-07 16:53:13 +0100268#ifdef FEAT_FLOAT
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100269 vim_snprintf((char *)numbuf, NUMBUFLEN, "%g", val->vval.v_float);
270 ga_concat(gap, numbuf);
271 break;
272#endif
Bram Moolenaar55fab432016-02-07 16:53:13 +0100273 case VAR_UNKNOWN:
274 EMSG2(_(e_intern2), "json_encode_item()"); break;
275 return FAIL;
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100276 }
Bram Moolenaarfcaaae62016-01-24 16:49:11 +0100277 return OK;
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100278}
279
280/*
Bram Moolenaar56ead342016-02-02 18:20:08 +0100281 * When "reader" has less than NUMBUFLEN bytes available, call the fill
282 * callback to get more.
283 */
284 static void
285fill_numbuflen(js_read_T *reader)
286{
287 if (reader->js_fill != NULL && (int)(reader->js_end - reader->js_buf)
288 - reader->js_used < NUMBUFLEN)
289 {
290 if (reader->js_fill(reader))
291 reader->js_end = reader->js_buf + STRLEN(reader->js_buf);
292 }
293}
294
295/*
Bram Moolenaar595e64e2016-02-07 19:19:53 +0100296 * Skip white space in "reader". All characters <= space are considered white
297 * space.
Bram Moolenaar56ead342016-02-02 18:20:08 +0100298 * Also tops up readahead when needed.
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100299 */
300 static void
301json_skip_white(js_read_T *reader)
302{
303 int c;
304
Bram Moolenaar56ead342016-02-02 18:20:08 +0100305 for (;;)
306 {
307 c = reader->js_buf[reader->js_used];
308 if (reader->js_fill != NULL && c == NUL)
309 {
310 if (reader->js_fill(reader))
311 reader->js_end = reader->js_buf + STRLEN(reader->js_buf);
312 continue;
313 }
Bram Moolenaar595e64e2016-02-07 19:19:53 +0100314 if (c == NUL || c > ' ')
Bram Moolenaar56ead342016-02-02 18:20:08 +0100315 break;
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100316 ++reader->js_used;
Bram Moolenaar56ead342016-02-02 18:20:08 +0100317 }
318 fill_numbuflen(reader);
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100319}
320
Bram Moolenaar56ead342016-02-02 18:20:08 +0100321 static int
Bram Moolenaar595e64e2016-02-07 19:19:53 +0100322json_decode_array(js_read_T *reader, typval_T *res, int options)
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100323{
324 char_u *p;
325 typval_T item;
326 listitem_T *li;
Bram Moolenaar56ead342016-02-02 18:20:08 +0100327 int ret;
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100328
Bram Moolenaar56ead342016-02-02 18:20:08 +0100329 if (res != NULL && rettv_list_alloc(res) == FAIL)
330 {
331 res->v_type = VAR_SPECIAL;
332 res->vval.v_number = VVAL_NONE;
333 return FAIL;
334 }
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100335 ++reader->js_used; /* consume the '[' */
336
337 while (TRUE)
338 {
339 json_skip_white(reader);
340 p = reader->js_buf + reader->js_used;
341 if (*p == NUL)
Bram Moolenaar56ead342016-02-02 18:20:08 +0100342 return MAYBE;
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100343 if (*p == ']')
344 {
345 ++reader->js_used; /* consume the ']' */
Bram Moolenaar56ead342016-02-02 18:20:08 +0100346 break;
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100347 }
348
Bram Moolenaar595e64e2016-02-07 19:19:53 +0100349 ret = json_decode_item(reader, res == NULL ? NULL : &item, options);
Bram Moolenaar56ead342016-02-02 18:20:08 +0100350 if (ret != OK)
351 return ret;
352 if (res != NULL)
353 {
354 li = listitem_alloc();
355 if (li == NULL)
356 {
357 clear_tv(&item);
358 return FAIL;
359 }
360 li->li_tv = item;
361 list_append(res->vval.v_list, li);
362 }
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100363
364 json_skip_white(reader);
365 p = reader->js_buf + reader->js_used;
366 if (*p == ',')
367 ++reader->js_used;
368 else if (*p != ']')
Bram Moolenaar56ead342016-02-02 18:20:08 +0100369 {
370 if (*p == NUL)
371 return MAYBE;
372 return FAIL;
373 }
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100374 }
Bram Moolenaar56ead342016-02-02 18:20:08 +0100375 return OK;
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100376}
377
Bram Moolenaar56ead342016-02-02 18:20:08 +0100378 static int
Bram Moolenaar595e64e2016-02-07 19:19:53 +0100379json_decode_object(js_read_T *reader, typval_T *res, int options)
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100380{
381 char_u *p;
382 typval_T tvkey;
383 typval_T item;
384 dictitem_T *di;
385 char_u buf[NUMBUFLEN];
Bram Moolenaarfbf9c6b2016-02-02 19:43:57 +0100386 char_u *key = NULL;
Bram Moolenaar56ead342016-02-02 18:20:08 +0100387 int ret;
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100388
Bram Moolenaar56ead342016-02-02 18:20:08 +0100389 if (res != NULL && rettv_dict_alloc(res) == FAIL)
390 {
391 res->v_type = VAR_SPECIAL;
392 res->vval.v_number = VVAL_NONE;
393 return FAIL;
394 }
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100395 ++reader->js_used; /* consume the '{' */
396
397 while (TRUE)
398 {
399 json_skip_white(reader);
400 p = reader->js_buf + reader->js_used;
401 if (*p == NUL)
Bram Moolenaar56ead342016-02-02 18:20:08 +0100402 return MAYBE;
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100403 if (*p == '}')
404 {
405 ++reader->js_used; /* consume the '}' */
Bram Moolenaar56ead342016-02-02 18:20:08 +0100406 break;
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100407 }
408
Bram Moolenaar595e64e2016-02-07 19:19:53 +0100409 if ((options & JSON_JS) && reader->js_buf[reader->js_used] != '"')
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100410 {
Bram Moolenaar595e64e2016-02-07 19:19:53 +0100411 /* accept a key that is not in quotes */
412 key = p = reader->js_buf + reader->js_used;
413 while (*p != NUL && *p != ':' && *p > ' ')
414 ++p;
415 tvkey.v_type = VAR_STRING;
416 tvkey.vval.v_string = vim_strnsave(key, (int)(p - key));
417 reader->js_used += (int)(p - key);
418 key = tvkey.vval.v_string;
419 }
420 else
421 {
422 ret = json_decode_item(reader, res == NULL ? NULL : &tvkey,
423 options);
424 if (ret != OK)
425 return ret;
426 if (res != NULL)
Bram Moolenaar56ead342016-02-02 18:20:08 +0100427 {
Bram Moolenaar595e64e2016-02-07 19:19:53 +0100428 key = get_tv_string_buf_chk(&tvkey, buf);
429 if (key == NULL || *key == NUL)
430 {
431 clear_tv(&tvkey);
432 return FAIL;
433 }
Bram Moolenaar56ead342016-02-02 18:20:08 +0100434 }
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100435 }
436
437 json_skip_white(reader);
438 p = reader->js_buf + reader->js_used;
439 if (*p != ':')
440 {
Bram Moolenaar56ead342016-02-02 18:20:08 +0100441 if (res != NULL)
442 clear_tv(&tvkey);
443 if (*p == NUL)
444 return MAYBE;
445 return FAIL;
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100446 }
447 ++reader->js_used;
448 json_skip_white(reader);
449
Bram Moolenaar595e64e2016-02-07 19:19:53 +0100450 ret = json_decode_item(reader, res == NULL ? NULL : &item, options);
Bram Moolenaar56ead342016-02-02 18:20:08 +0100451 if (ret != OK)
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100452 {
Bram Moolenaar56ead342016-02-02 18:20:08 +0100453 if (res != NULL)
454 clear_tv(&tvkey);
455 return ret;
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100456 }
Bram Moolenaar56ead342016-02-02 18:20:08 +0100457
458 if (res != NULL)
459 {
460 di = dictitem_alloc(key);
461 clear_tv(&tvkey);
462 if (di == NULL)
463 {
464 clear_tv(&item);
465 return FAIL;
466 }
467 di->di_tv = item;
468 if (dict_add(res->vval.v_dict, di) == FAIL)
469 {
470 dictitem_free(di);
471 return FAIL;
472 }
473 }
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100474
475 json_skip_white(reader);
476 p = reader->js_buf + reader->js_used;
477 if (*p == ',')
478 ++reader->js_used;
479 else if (*p != '}')
Bram Moolenaar56ead342016-02-02 18:20:08 +0100480 {
481 if (*p == NUL)
482 return MAYBE;
483 return FAIL;
484 }
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100485 }
Bram Moolenaar56ead342016-02-02 18:20:08 +0100486 return OK;
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100487}
488
Bram Moolenaar56ead342016-02-02 18:20:08 +0100489 static int
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100490json_decode_string(js_read_T *reader, typval_T *res)
491{
492 garray_T ga;
493 int len;
Bram Moolenaar56ead342016-02-02 18:20:08 +0100494 char_u *p;
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100495 int c;
496 long nr;
497 char_u buf[NUMBUFLEN];
498
Bram Moolenaar56ead342016-02-02 18:20:08 +0100499 if (res != NULL)
500 ga_init2(&ga, 1, 200);
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100501
Bram Moolenaar56ead342016-02-02 18:20:08 +0100502 p = reader->js_buf + reader->js_used + 1; /* skip over " */
503 while (*p != '"')
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100504 {
Bram Moolenaar56ead342016-02-02 18:20:08 +0100505 if (*p == NUL || p[1] == NUL
506#ifdef FEAT_MBYTE
507 || utf_ptr2len(p) < utf_byte2len(*p)
508#endif
509 )
510 {
511 if (reader->js_fill == NULL)
512 break;
513 len = (int)(reader->js_end - p);
514 reader->js_used = (int)(p - reader->js_buf);
515 if (!reader->js_fill(reader))
516 break; /* didn't get more */
517 p = reader->js_buf + reader->js_used;
518 reader->js_end = reader->js_buf + STRLEN(reader->js_buf);
519 continue;
520 }
521
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100522 if (*p == '\\')
523 {
524 c = -1;
525 switch (p[1])
526 {
Bram Moolenaar56ead342016-02-02 18:20:08 +0100527 case '\\': c = '\\'; break;
528 case '"': c = '"'; break;
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100529 case 'b': c = BS; break;
530 case 't': c = TAB; break;
531 case 'n': c = NL; break;
532 case 'f': c = FF; break;
533 case 'r': c = CAR; break;
534 case 'u':
Bram Moolenaar56ead342016-02-02 18:20:08 +0100535 if (reader->js_fill != NULL
536 && (int)(reader->js_end - p) < NUMBUFLEN)
537 {
538 reader->js_used = (int)(p - reader->js_buf);
539 if (reader->js_fill(reader))
540 {
541 p = reader->js_buf + reader->js_used;
542 reader->js_end = reader->js_buf
543 + STRLEN(reader->js_buf);
544 }
545 }
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100546 vim_str2nr(p + 2, NULL, &len,
547 STR2NR_HEX + STR2NR_FORCE, &nr, NULL, 4);
548 p += len + 2;
Bram Moolenaar56ead342016-02-02 18:20:08 +0100549 if (res != NULL)
550 {
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100551#ifdef FEAT_MBYTE
Bram Moolenaar56ead342016-02-02 18:20:08 +0100552 buf[(*mb_char2bytes)((int)nr, buf)] = NUL;
553 ga_concat(&ga, buf);
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100554#else
Bram Moolenaar56ead342016-02-02 18:20:08 +0100555 ga_append(&ga, nr);
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100556#endif
Bram Moolenaar56ead342016-02-02 18:20:08 +0100557 }
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100558 break;
Bram Moolenaar56ead342016-02-02 18:20:08 +0100559 default:
560 /* not a special char, skip over \ */
561 ++p;
562 continue;
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100563 }
564 if (c > 0)
565 {
566 p += 2;
Bram Moolenaar56ead342016-02-02 18:20:08 +0100567 if (res != NULL)
568 ga_append(&ga, c);
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100569 }
570 }
571 else
572 {
573 len = MB_PTR2LEN(p);
Bram Moolenaar56ead342016-02-02 18:20:08 +0100574 if (res != NULL)
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100575 {
Bram Moolenaar56ead342016-02-02 18:20:08 +0100576 if (ga_grow(&ga, len) == FAIL)
577 {
578 ga_clear(&ga);
579 return FAIL;
580 }
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100581 mch_memmove((char *)ga.ga_data + ga.ga_len, p, (size_t)len);
582 ga.ga_len += len;
583 }
584 p += len;
585 }
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100586 }
Bram Moolenaar56ead342016-02-02 18:20:08 +0100587
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100588 reader->js_used = (int)(p - reader->js_buf);
589 if (*p == '"')
590 {
591 ++reader->js_used;
Bram Moolenaar56ead342016-02-02 18:20:08 +0100592 if (res != NULL)
593 {
594 res->v_type = VAR_STRING;
Bram Moolenaar4b6a6dc2016-02-04 22:49:49 +0100595 res->vval.v_string = ga.ga_data;
Bram Moolenaar56ead342016-02-02 18:20:08 +0100596 }
597 return OK;
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100598 }
Bram Moolenaar56ead342016-02-02 18:20:08 +0100599 if (res != NULL)
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100600 {
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100601 res->v_type = VAR_SPECIAL;
602 res->vval.v_number = VVAL_NONE;
Bram Moolenaar56ead342016-02-02 18:20:08 +0100603 ga_clear(&ga);
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100604 }
Bram Moolenaar56ead342016-02-02 18:20:08 +0100605 return MAYBE;
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100606}
607
608/*
Bram Moolenaar56ead342016-02-02 18:20:08 +0100609 * Decode one item and put it in "res". If "res" is NULL only advance.
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100610 * Must already have skipped white space.
Bram Moolenaar56ead342016-02-02 18:20:08 +0100611 *
612 * Return FAIL for a decoding error.
613 * Return MAYBE for an incomplete message.
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100614 */
Bram Moolenaar56ead342016-02-02 18:20:08 +0100615 static int
Bram Moolenaar595e64e2016-02-07 19:19:53 +0100616json_decode_item(js_read_T *reader, typval_T *res, int options)
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100617{
Bram Moolenaar56ead342016-02-02 18:20:08 +0100618 char_u *p;
619 int len;
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100620
Bram Moolenaar56ead342016-02-02 18:20:08 +0100621 fill_numbuflen(reader);
622 p = reader->js_buf + reader->js_used;
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100623 switch (*p)
624 {
625 case '[': /* array */
Bram Moolenaar595e64e2016-02-07 19:19:53 +0100626 return json_decode_array(reader, res, options);
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100627
628 case '{': /* object */
Bram Moolenaar595e64e2016-02-07 19:19:53 +0100629 return json_decode_object(reader, res, options);
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100630
631 case '"': /* string */
Bram Moolenaar56ead342016-02-02 18:20:08 +0100632 return json_decode_string(reader, res);
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100633
634 case ',': /* comma: empty item */
Bram Moolenaar595e64e2016-02-07 19:19:53 +0100635 if ((options & JSON_JS) == 0)
636 return FAIL;
637 /* FALLTHROUGH */
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100638 case NUL: /* empty */
Bram Moolenaar56ead342016-02-02 18:20:08 +0100639 if (res != NULL)
640 {
641 res->v_type = VAR_SPECIAL;
642 res->vval.v_number = VVAL_NONE;
643 }
644 return OK;
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100645
646 default:
647 if (VIM_ISDIGIT(*p) || *p == '-')
648 {
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100649 char_u *sp = p;
Bram Moolenaar56ead342016-02-02 18:20:08 +0100650
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100651#ifdef FEAT_FLOAT
652 if (*sp == '-')
Bram Moolenaar56ead342016-02-02 18:20:08 +0100653 {
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100654 ++sp;
Bram Moolenaar56ead342016-02-02 18:20:08 +0100655 if (*sp == NUL)
656 return MAYBE;
657 if (!VIM_ISDIGIT(*sp))
658 return FAIL;
659 }
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100660 sp = skipdigits(sp);
661 if (*sp == '.' || *sp == 'e' || *sp == 'E')
662 {
Bram Moolenaar56ead342016-02-02 18:20:08 +0100663 if (res == NULL)
664 {
665 float_T f;
666
667 len = string2float(p, &f);
668 }
669 else
670 {
671 res->v_type = VAR_FLOAT;
672 len = string2float(p, &res->vval.v_float);
673 }
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100674 }
675 else
676#endif
677 {
678 long nr;
679
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100680 vim_str2nr(reader->js_buf + reader->js_used,
681 NULL, &len, 0, /* what */
682 &nr, NULL, 0);
Bram Moolenaar56ead342016-02-02 18:20:08 +0100683 if (res != NULL)
684 {
685 res->v_type = VAR_NUMBER;
686 res->vval.v_number = nr;
687 }
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100688 }
689 reader->js_used += len;
Bram Moolenaar56ead342016-02-02 18:20:08 +0100690 return OK;
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100691 }
692 if (STRNICMP((char *)p, "false", 5) == 0)
693 {
694 reader->js_used += 5;
Bram Moolenaar56ead342016-02-02 18:20:08 +0100695 if (res != NULL)
696 {
697 res->v_type = VAR_SPECIAL;
698 res->vval.v_number = VVAL_FALSE;
699 }
700 return OK;
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100701 }
702 if (STRNICMP((char *)p, "true", 4) == 0)
703 {
704 reader->js_used += 4;
Bram Moolenaar56ead342016-02-02 18:20:08 +0100705 if (res != NULL)
706 {
707 res->v_type = VAR_SPECIAL;
708 res->vval.v_number = VVAL_TRUE;
709 }
710 return OK;
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100711 }
712 if (STRNICMP((char *)p, "null", 4) == 0)
713 {
714 reader->js_used += 4;
Bram Moolenaar56ead342016-02-02 18:20:08 +0100715 if (res != NULL)
716 {
717 res->v_type = VAR_SPECIAL;
718 res->vval.v_number = VVAL_NULL;
719 }
720 return OK;
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100721 }
Bram Moolenaar56ead342016-02-02 18:20:08 +0100722 /* check for truncated name */
723 len = (int)(reader->js_end - (reader->js_buf + reader->js_used));
724 if ((len < 5 && STRNICMP((char *)p, "false", len) == 0)
725 || (len < 4 && (STRNICMP((char *)p, "true", len) == 0
726 || STRNICMP((char *)p, "null", len) == 0)))
727 return MAYBE;
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100728 break;
729 }
730
Bram Moolenaar56ead342016-02-02 18:20:08 +0100731 if (res != NUL)
732 {
733 res->v_type = VAR_SPECIAL;
734 res->vval.v_number = VVAL_NONE;
735 }
736 return FAIL;
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100737}
738
739/*
740 * Decode the JSON from "reader" and store the result in "res".
Bram Moolenaar595e64e2016-02-07 19:19:53 +0100741 * "options" can be JSON_JS or zero;
Bram Moolenaar56ead342016-02-02 18:20:08 +0100742 * Return FAIL if not the whole message was consumed.
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100743 */
Bram Moolenaar19d2f152016-02-01 21:38:19 +0100744 int
Bram Moolenaar595e64e2016-02-07 19:19:53 +0100745json_decode_all(js_read_T *reader, typval_T *res, int options)
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100746{
Bram Moolenaar56ead342016-02-02 18:20:08 +0100747 int ret;
748
Bram Moolenaar595e64e2016-02-07 19:19:53 +0100749 /* We find the end once, to avoid calling strlen() many times. */
Bram Moolenaar56ead342016-02-02 18:20:08 +0100750 reader->js_end = reader->js_buf + STRLEN(reader->js_buf);
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100751 json_skip_white(reader);
Bram Moolenaar595e64e2016-02-07 19:19:53 +0100752 ret = json_decode_item(reader, res, options);
Bram Moolenaar56ead342016-02-02 18:20:08 +0100753 if (ret != OK)
754 return FAIL;
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100755 json_skip_white(reader);
756 if (reader->js_buf[reader->js_used] != NUL)
Bram Moolenaar19d2f152016-02-01 21:38:19 +0100757 return FAIL;
758 return OK;
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100759}
Bram Moolenaar56ead342016-02-02 18:20:08 +0100760
761/*
762 * Decode the JSON from "reader" and store the result in "res".
Bram Moolenaar595e64e2016-02-07 19:19:53 +0100763 * "options" can be JSON_JS or zero;
Bram Moolenaar56ead342016-02-02 18:20:08 +0100764 * Return FAIL if the message has a decoding error or the message is
765 * truncated. Consumes the message anyway.
766 */
767 int
Bram Moolenaar595e64e2016-02-07 19:19:53 +0100768json_decode(js_read_T *reader, typval_T *res, int options)
Bram Moolenaar56ead342016-02-02 18:20:08 +0100769{
770 int ret;
771
Bram Moolenaar595e64e2016-02-07 19:19:53 +0100772 /* We find the end once, to avoid calling strlen() many times. */
Bram Moolenaar56ead342016-02-02 18:20:08 +0100773 reader->js_end = reader->js_buf + STRLEN(reader->js_buf);
774 json_skip_white(reader);
Bram Moolenaar595e64e2016-02-07 19:19:53 +0100775 ret = json_decode_item(reader, res, options);
Bram Moolenaar56ead342016-02-02 18:20:08 +0100776 json_skip_white(reader);
777
778 return ret == OK ? OK : FAIL;
779}
780
781/*
782 * Decode the JSON from "reader" to find the end of the message.
Bram Moolenaar595e64e2016-02-07 19:19:53 +0100783 * "options" can be JSON_JS or zero;
Bram Moolenaar56ead342016-02-02 18:20:08 +0100784 * Return FAIL if the message has a decoding error.
785 * Return MAYBE if the message is truncated, need to read more.
786 * This only works reliable if the message contains an object, array or
787 * string. A number might be trucated without knowing.
788 * Does not advance the reader.
789 */
790 int
Bram Moolenaar595e64e2016-02-07 19:19:53 +0100791json_find_end(js_read_T *reader, int options)
Bram Moolenaar56ead342016-02-02 18:20:08 +0100792{
793 int used_save = reader->js_used;
794 int ret;
795
Bram Moolenaar595e64e2016-02-07 19:19:53 +0100796 /* We find the end once, to avoid calling strlen() many times. */
Bram Moolenaar56ead342016-02-02 18:20:08 +0100797 reader->js_end = reader->js_buf + STRLEN(reader->js_buf);
798 json_skip_white(reader);
Bram Moolenaar595e64e2016-02-07 19:19:53 +0100799 ret = json_decode_item(reader, NULL, options);
Bram Moolenaar56ead342016-02-02 18:20:08 +0100800 reader->js_used = used_save;
801 return ret;
802}
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100803#endif