blob: 6eadd2e83e17acfb8ed04618210dc6308c829b87 [file] [log] [blame]
Bram Moolenaar520e1e42016-01-23 19:46:28 +01001/* vi:set ts=8 sts=4 sw=4:
2 *
3 * VIM - Vi IMproved by Bram Moolenaar
4 *
5 * Do ":help uganda" in Vim to read copying and usage conditions.
6 * Do ":help credits" in Vim to see a list of people who contributed.
7 * See README.txt for an overview of the Vim source code.
8 */
9
10/*
11 * json.c: Encoding and decoding JSON.
12 *
Bram Moolenaar009d84a2016-01-28 14:12:00 +010013 * Follows this standard: https://tools.ietf.org/html/rfc7159.html
Bram Moolenaar520e1e42016-01-23 19:46:28 +010014 */
15
16#include "vim.h"
17
18#if defined(FEAT_EVAL) || defined(PROTO)
Bram Moolenaarf1b6ac72016-02-23 21:26:43 +010019
20#if defined(FEAT_FLOAT) && defined(HAVE_MATH_H)
21 /* for isnan() and isinf() */
22# include <math.h>
23#endif
24
Bram Moolenaar595e64e2016-02-07 19:19:53 +010025static int json_encode_item(garray_T *gap, typval_T *val, int copyID, int options);
26static int json_decode_item(js_read_T *reader, typval_T *res, int options);
Bram Moolenaar520e1e42016-01-23 19:46:28 +010027
28/*
29 * Encode "val" into a JSON format string.
Bram Moolenaar55fab432016-02-07 16:53:13 +010030 * The result is in allocated memory.
31 * The result is empty when encoding fails.
Bram Moolenaar595e64e2016-02-07 19:19:53 +010032 * "options" can be JSON_JS or zero;
Bram Moolenaar520e1e42016-01-23 19:46:28 +010033 */
34 char_u *
Bram Moolenaar595e64e2016-02-07 19:19:53 +010035json_encode(typval_T *val, int options)
Bram Moolenaar520e1e42016-01-23 19:46:28 +010036{
37 garray_T ga;
38
39 /* Store bytes in the growarray. */
40 ga_init2(&ga, 1, 4000);
Bram Moolenaar595e64e2016-02-07 19:19:53 +010041 if (json_encode_item(&ga, val, get_copyID(), options) == FAIL)
Bram Moolenaar55fab432016-02-07 16:53:13 +010042 {
43 vim_free(ga.ga_data);
44 return vim_strsave((char_u *)"");
45 }
Bram Moolenaar520e1e42016-01-23 19:46:28 +010046 return ga.ga_data;
47}
48
Bram Moolenaarfb1f6262016-01-31 20:24:32 +010049/*
Bram Moolenaar55fab432016-02-07 16:53:13 +010050 * Encode ["nr", "val"] into a JSON format string in allocated memory.
Bram Moolenaar595e64e2016-02-07 19:19:53 +010051 * "options" can be JSON_JS or zero;
Bram Moolenaarfb1f6262016-01-31 20:24:32 +010052 * Returns NULL when out of memory.
53 */
54 char_u *
Bram Moolenaar595e64e2016-02-07 19:19:53 +010055json_encode_nr_expr(int nr, typval_T *val, int options)
Bram Moolenaarfb1f6262016-01-31 20:24:32 +010056{
57 typval_T listtv;
58 typval_T nrtv;
59 char_u *text;
60
61 nrtv.v_type = VAR_NUMBER;
62 nrtv.vval.v_number = nr;
63 if (rettv_list_alloc(&listtv) == FAIL)
64 return NULL;
65 if (list_append_tv(listtv.vval.v_list, &nrtv) == FAIL
66 || list_append_tv(listtv.vval.v_list, val) == FAIL)
67 {
68 list_unref(listtv.vval.v_list);
69 return NULL;
70 }
71
Bram Moolenaar595e64e2016-02-07 19:19:53 +010072 text = json_encode(&listtv, options);
Bram Moolenaarfb1f6262016-01-31 20:24:32 +010073 list_unref(listtv.vval.v_list);
74 return text;
75}
76
Bram Moolenaar520e1e42016-01-23 19:46:28 +010077 static void
78write_string(garray_T *gap, char_u *str)
79{
80 char_u *res = str;
81 char_u numbuf[NUMBUFLEN];
82
83 if (res == NULL)
84 ga_concat(gap, (char_u *)"null");
85 else
86 {
87 ga_append(gap, '"');
88 while (*res != NUL)
89 {
90 int c = PTR2CHAR(res);
91
92 switch (c)
93 {
94 case 0x08:
95 ga_append(gap, '\\'); ga_append(gap, 'b'); break;
96 case 0x09:
97 ga_append(gap, '\\'); ga_append(gap, 't'); break;
98 case 0x0a:
99 ga_append(gap, '\\'); ga_append(gap, 'n'); break;
100 case 0x0c:
101 ga_append(gap, '\\'); ga_append(gap, 'f'); break;
102 case 0x0d:
103 ga_append(gap, '\\'); ga_append(gap, 'r'); break;
104 case 0x22: /* " */
105 case 0x5c: /* \ */
106 ga_append(gap, '\\');
107 ga_append(gap, c);
108 break;
109 default:
110 if (c >= 0x20)
111 {
Bram Moolenaarfa06a512016-01-28 22:46:58 +0100112#ifdef FEAT_MBYTE
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100113 numbuf[mb_char2bytes(c, numbuf)] = NUL;
Bram Moolenaarfa06a512016-01-28 22:46:58 +0100114#else
115 numbuf[0] = c;
116 numbuf[1] = NUL;
117#endif
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100118 ga_concat(gap, numbuf);
119 }
120 else
121 {
122 vim_snprintf((char *)numbuf, NUMBUFLEN,
123 "\\u%04lx", (long)c);
124 ga_concat(gap, numbuf);
125 }
126 }
127 mb_cptr_adv(res);
128 }
129 ga_append(gap, '"');
130 }
131}
132
Bram Moolenaarfcaaae62016-01-24 16:49:11 +0100133/*
Bram Moolenaar595e64e2016-02-07 19:19:53 +0100134 * Return TRUE if "key" can be used without quotes.
135 * That is when it starts with a letter and only contains letters, digits and
136 * underscore.
137 */
138 static int
139is_simple_key(char_u *key)
140{
141 char_u *p;
142
143 if (!ASCII_ISALPHA(*key))
144 return FALSE;
145 for (p = key + 1; *p != NUL; ++p)
146 if (!ASCII_ISALPHA(*p) && *p != '_' && !vim_isdigit(*p))
147 return FALSE;
148 return TRUE;
149}
150
151/*
Bram Moolenaarfcaaae62016-01-24 16:49:11 +0100152 * Encode "val" into "gap".
153 * Return FAIL or OK.
154 */
155 static int
Bram Moolenaar595e64e2016-02-07 19:19:53 +0100156json_encode_item(garray_T *gap, typval_T *val, int copyID, int options)
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100157{
158 char_u numbuf[NUMBUFLEN];
159 char_u *res;
160 list_T *l;
161 dict_T *d;
162
163 switch (val->v_type)
164 {
165 case VAR_SPECIAL:
Bram Moolenaarfcaaae62016-01-24 16:49:11 +0100166 switch (val->vval.v_number)
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100167 {
168 case VVAL_FALSE: ga_concat(gap, (char_u *)"false"); break;
169 case VVAL_TRUE: ga_concat(gap, (char_u *)"true"); break;
Bram Moolenaar595e64e2016-02-07 19:19:53 +0100170 case VVAL_NONE: if ((options & JSON_JS) != 0
171 && (options & JSON_NO_NONE) == 0)
172 /* empty item */
173 break;
174 /* FALLTHROUGH */
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100175 case VVAL_NULL: ga_concat(gap, (char_u *)"null"); break;
176 }
177 break;
178
179 case VAR_NUMBER:
180 vim_snprintf((char *)numbuf, NUMBUFLEN, "%ld",
181 (long)val->vval.v_number);
182 ga_concat(gap, numbuf);
183 break;
184
185 case VAR_STRING:
186 res = val->vval.v_string;
187 write_string(gap, res);
188 break;
189
190 case VAR_FUNC:
Bram Moolenaar55fab432016-02-07 16:53:13 +0100191 case VAR_JOB:
Bram Moolenaar77073442016-02-13 23:23:53 +0100192 case VAR_CHANNEL:
Bram Moolenaar4f8b8fa2016-02-06 18:42:07 +0100193 /* no JSON equivalent TODO: better error */
Bram Moolenaarfcaaae62016-01-24 16:49:11 +0100194 EMSG(_(e_invarg));
195 return FAIL;
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100196
197 case VAR_LIST:
198 l = val->vval.v_list;
199 if (l == NULL)
200 ga_concat(gap, (char_u *)"null");
201 else
202 {
203 if (l->lv_copyID == copyID)
204 ga_concat(gap, (char_u *)"[]");
205 else
206 {
207 listitem_T *li;
208
209 l->lv_copyID = copyID;
210 ga_append(gap, '[');
211 for (li = l->lv_first; li != NULL && !got_int; )
212 {
Bram Moolenaar595e64e2016-02-07 19:19:53 +0100213 if (json_encode_item(gap, &li->li_tv, copyID,
214 options & JSON_JS) == FAIL)
Bram Moolenaarfcaaae62016-01-24 16:49:11 +0100215 return FAIL;
Bram Moolenaar595e64e2016-02-07 19:19:53 +0100216 if ((options & JSON_JS)
217 && li->li_next == NULL
218 && li->li_tv.v_type == VAR_SPECIAL
219 && li->li_tv.vval.v_number == VVAL_NONE)
220 /* add an extra comma if the last item is v:none */
221 ga_append(gap, ',');
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100222 li = li->li_next;
223 if (li != NULL)
224 ga_append(gap, ',');
225 }
226 ga_append(gap, ']');
Bram Moolenaarfcaaae62016-01-24 16:49:11 +0100227 l->lv_copyID = 0;
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100228 }
229 }
230 break;
231
232 case VAR_DICT:
233 d = val->vval.v_dict;
234 if (d == NULL)
235 ga_concat(gap, (char_u *)"null");
236 else
237 {
238 if (d->dv_copyID == copyID)
239 ga_concat(gap, (char_u *)"{}");
240 else
241 {
242 int first = TRUE;
243 int todo = (int)d->dv_hashtab.ht_used;
244 hashitem_T *hi;
245
246 d->dv_copyID = copyID;
247 ga_append(gap, '{');
248
249 for (hi = d->dv_hashtab.ht_array; todo > 0 && !got_int;
250 ++hi)
251 if (!HASHITEM_EMPTY(hi))
252 {
253 --todo;
254 if (first)
255 first = FALSE;
256 else
257 ga_append(gap, ',');
Bram Moolenaar595e64e2016-02-07 19:19:53 +0100258 if ((options & JSON_JS)
259 && is_simple_key(hi->hi_key))
260 ga_concat(gap, hi->hi_key);
261 else
262 write_string(gap, hi->hi_key);
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100263 ga_append(gap, ':');
Bram Moolenaarfcaaae62016-01-24 16:49:11 +0100264 if (json_encode_item(gap, &dict_lookup(hi)->di_tv,
Bram Moolenaar595e64e2016-02-07 19:19:53 +0100265 copyID, options | JSON_NO_NONE) == FAIL)
Bram Moolenaarfcaaae62016-01-24 16:49:11 +0100266 return FAIL;
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100267 }
268 ga_append(gap, '}');
Bram Moolenaarfcaaae62016-01-24 16:49:11 +0100269 d->dv_copyID = 0;
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100270 }
271 }
272 break;
273
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100274 case VAR_FLOAT:
Bram Moolenaar55fab432016-02-07 16:53:13 +0100275#ifdef FEAT_FLOAT
Bram Moolenaarf1b6ac72016-02-23 21:26:43 +0100276# if defined(HAVE_MATH_H)
277 if ((options & JSON_JS) && isnan(val->vval.v_float))
278 ga_concat(gap, (char_u *)"NaN");
279 else if ((options & JSON_JS) && isinf(val->vval.v_float))
280 ga_concat(gap, (char_u *)"Infinity");
281 else if (isnan(val->vval.v_float) || isinf(val->vval.v_float))
282 ga_concat(gap, (char_u *)"null");
283 else
284# endif
285 {
286 vim_snprintf((char *)numbuf, NUMBUFLEN, "%g",
287 val->vval.v_float);
288 ga_concat(gap, numbuf);
289 }
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100290 break;
291#endif
Bram Moolenaar55fab432016-02-07 16:53:13 +0100292 case VAR_UNKNOWN:
Bram Moolenaarc6b14f02016-02-20 15:26:42 +0100293 EMSG2(_(e_intern2), "json_encode_item()");
Bram Moolenaar55fab432016-02-07 16:53:13 +0100294 return FAIL;
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100295 }
Bram Moolenaarfcaaae62016-01-24 16:49:11 +0100296 return OK;
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100297}
298
299/*
Bram Moolenaar56ead342016-02-02 18:20:08 +0100300 * When "reader" has less than NUMBUFLEN bytes available, call the fill
301 * callback to get more.
302 */
303 static void
304fill_numbuflen(js_read_T *reader)
305{
306 if (reader->js_fill != NULL && (int)(reader->js_end - reader->js_buf)
307 - reader->js_used < NUMBUFLEN)
308 {
309 if (reader->js_fill(reader))
310 reader->js_end = reader->js_buf + STRLEN(reader->js_buf);
311 }
312}
313
314/*
Bram Moolenaar595e64e2016-02-07 19:19:53 +0100315 * Skip white space in "reader". All characters <= space are considered white
316 * space.
Bram Moolenaar56ead342016-02-02 18:20:08 +0100317 * Also tops up readahead when needed.
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100318 */
319 static void
320json_skip_white(js_read_T *reader)
321{
322 int c;
323
Bram Moolenaar56ead342016-02-02 18:20:08 +0100324 for (;;)
325 {
326 c = reader->js_buf[reader->js_used];
327 if (reader->js_fill != NULL && c == NUL)
328 {
329 if (reader->js_fill(reader))
330 reader->js_end = reader->js_buf + STRLEN(reader->js_buf);
331 continue;
332 }
Bram Moolenaar595e64e2016-02-07 19:19:53 +0100333 if (c == NUL || c > ' ')
Bram Moolenaar56ead342016-02-02 18:20:08 +0100334 break;
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100335 ++reader->js_used;
Bram Moolenaar56ead342016-02-02 18:20:08 +0100336 }
337 fill_numbuflen(reader);
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100338}
339
Bram Moolenaar56ead342016-02-02 18:20:08 +0100340 static int
Bram Moolenaar595e64e2016-02-07 19:19:53 +0100341json_decode_array(js_read_T *reader, typval_T *res, int options)
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100342{
343 char_u *p;
344 typval_T item;
345 listitem_T *li;
Bram Moolenaar56ead342016-02-02 18:20:08 +0100346 int ret;
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100347
Bram Moolenaar56ead342016-02-02 18:20:08 +0100348 if (res != NULL && rettv_list_alloc(res) == FAIL)
349 {
350 res->v_type = VAR_SPECIAL;
351 res->vval.v_number = VVAL_NONE;
352 return FAIL;
353 }
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100354 ++reader->js_used; /* consume the '[' */
355
356 while (TRUE)
357 {
358 json_skip_white(reader);
359 p = reader->js_buf + reader->js_used;
360 if (*p == NUL)
Bram Moolenaar56ead342016-02-02 18:20:08 +0100361 return MAYBE;
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100362 if (*p == ']')
363 {
364 ++reader->js_used; /* consume the ']' */
Bram Moolenaar56ead342016-02-02 18:20:08 +0100365 break;
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100366 }
367
Bram Moolenaar595e64e2016-02-07 19:19:53 +0100368 ret = json_decode_item(reader, res == NULL ? NULL : &item, options);
Bram Moolenaar56ead342016-02-02 18:20:08 +0100369 if (ret != OK)
370 return ret;
371 if (res != NULL)
372 {
373 li = listitem_alloc();
374 if (li == NULL)
375 {
376 clear_tv(&item);
377 return FAIL;
378 }
379 li->li_tv = item;
380 list_append(res->vval.v_list, li);
381 }
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100382
383 json_skip_white(reader);
384 p = reader->js_buf + reader->js_used;
385 if (*p == ',')
386 ++reader->js_used;
387 else if (*p != ']')
Bram Moolenaar56ead342016-02-02 18:20:08 +0100388 {
389 if (*p == NUL)
390 return MAYBE;
391 return FAIL;
392 }
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100393 }
Bram Moolenaar56ead342016-02-02 18:20:08 +0100394 return OK;
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100395}
396
Bram Moolenaar56ead342016-02-02 18:20:08 +0100397 static int
Bram Moolenaar595e64e2016-02-07 19:19:53 +0100398json_decode_object(js_read_T *reader, typval_T *res, int options)
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100399{
400 char_u *p;
401 typval_T tvkey;
402 typval_T item;
403 dictitem_T *di;
404 char_u buf[NUMBUFLEN];
Bram Moolenaarfbf9c6b2016-02-02 19:43:57 +0100405 char_u *key = NULL;
Bram Moolenaar56ead342016-02-02 18:20:08 +0100406 int ret;
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100407
Bram Moolenaar56ead342016-02-02 18:20:08 +0100408 if (res != NULL && rettv_dict_alloc(res) == FAIL)
409 {
410 res->v_type = VAR_SPECIAL;
411 res->vval.v_number = VVAL_NONE;
412 return FAIL;
413 }
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100414 ++reader->js_used; /* consume the '{' */
415
416 while (TRUE)
417 {
418 json_skip_white(reader);
419 p = reader->js_buf + reader->js_used;
420 if (*p == NUL)
Bram Moolenaar56ead342016-02-02 18:20:08 +0100421 return MAYBE;
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100422 if (*p == '}')
423 {
424 ++reader->js_used; /* consume the '}' */
Bram Moolenaar56ead342016-02-02 18:20:08 +0100425 break;
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100426 }
427
Bram Moolenaar595e64e2016-02-07 19:19:53 +0100428 if ((options & JSON_JS) && reader->js_buf[reader->js_used] != '"')
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100429 {
Bram Moolenaar595e64e2016-02-07 19:19:53 +0100430 /* accept a key that is not in quotes */
431 key = p = reader->js_buf + reader->js_used;
432 while (*p != NUL && *p != ':' && *p > ' ')
433 ++p;
434 tvkey.v_type = VAR_STRING;
435 tvkey.vval.v_string = vim_strnsave(key, (int)(p - key));
436 reader->js_used += (int)(p - key);
437 key = tvkey.vval.v_string;
438 }
439 else
440 {
441 ret = json_decode_item(reader, res == NULL ? NULL : &tvkey,
442 options);
443 if (ret != OK)
444 return ret;
445 if (res != NULL)
Bram Moolenaar56ead342016-02-02 18:20:08 +0100446 {
Bram Moolenaar595e64e2016-02-07 19:19:53 +0100447 key = get_tv_string_buf_chk(&tvkey, buf);
448 if (key == NULL || *key == NUL)
449 {
450 clear_tv(&tvkey);
451 return FAIL;
452 }
Bram Moolenaar56ead342016-02-02 18:20:08 +0100453 }
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100454 }
455
456 json_skip_white(reader);
457 p = reader->js_buf + reader->js_used;
458 if (*p != ':')
459 {
Bram Moolenaar56ead342016-02-02 18:20:08 +0100460 if (res != NULL)
461 clear_tv(&tvkey);
462 if (*p == NUL)
463 return MAYBE;
464 return FAIL;
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100465 }
466 ++reader->js_used;
467 json_skip_white(reader);
468
Bram Moolenaar595e64e2016-02-07 19:19:53 +0100469 ret = json_decode_item(reader, res == NULL ? NULL : &item, options);
Bram Moolenaar56ead342016-02-02 18:20:08 +0100470 if (ret != OK)
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100471 {
Bram Moolenaar56ead342016-02-02 18:20:08 +0100472 if (res != NULL)
473 clear_tv(&tvkey);
474 return ret;
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100475 }
Bram Moolenaar56ead342016-02-02 18:20:08 +0100476
477 if (res != NULL)
478 {
479 di = dictitem_alloc(key);
480 clear_tv(&tvkey);
481 if (di == NULL)
482 {
483 clear_tv(&item);
484 return FAIL;
485 }
486 di->di_tv = item;
487 if (dict_add(res->vval.v_dict, di) == FAIL)
488 {
489 dictitem_free(di);
490 return FAIL;
491 }
492 }
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100493
494 json_skip_white(reader);
495 p = reader->js_buf + reader->js_used;
496 if (*p == ',')
497 ++reader->js_used;
498 else if (*p != '}')
Bram Moolenaar56ead342016-02-02 18:20:08 +0100499 {
500 if (*p == NUL)
501 return MAYBE;
502 return FAIL;
503 }
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100504 }
Bram Moolenaar56ead342016-02-02 18:20:08 +0100505 return OK;
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100506}
507
Bram Moolenaar56ead342016-02-02 18:20:08 +0100508 static int
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100509json_decode_string(js_read_T *reader, typval_T *res)
510{
511 garray_T ga;
512 int len;
Bram Moolenaar56ead342016-02-02 18:20:08 +0100513 char_u *p;
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100514 int c;
515 long nr;
516 char_u buf[NUMBUFLEN];
517
Bram Moolenaar56ead342016-02-02 18:20:08 +0100518 if (res != NULL)
519 ga_init2(&ga, 1, 200);
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100520
Bram Moolenaar56ead342016-02-02 18:20:08 +0100521 p = reader->js_buf + reader->js_used + 1; /* skip over " */
522 while (*p != '"')
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100523 {
Bram Moolenaar56ead342016-02-02 18:20:08 +0100524 if (*p == NUL || p[1] == NUL
525#ifdef FEAT_MBYTE
526 || utf_ptr2len(p) < utf_byte2len(*p)
527#endif
528 )
529 {
530 if (reader->js_fill == NULL)
531 break;
532 len = (int)(reader->js_end - p);
533 reader->js_used = (int)(p - reader->js_buf);
534 if (!reader->js_fill(reader))
535 break; /* didn't get more */
536 p = reader->js_buf + reader->js_used;
537 reader->js_end = reader->js_buf + STRLEN(reader->js_buf);
538 continue;
539 }
540
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100541 if (*p == '\\')
542 {
543 c = -1;
544 switch (p[1])
545 {
Bram Moolenaar56ead342016-02-02 18:20:08 +0100546 case '\\': c = '\\'; break;
547 case '"': c = '"'; break;
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100548 case 'b': c = BS; break;
549 case 't': c = TAB; break;
550 case 'n': c = NL; break;
551 case 'f': c = FF; break;
552 case 'r': c = CAR; break;
553 case 'u':
Bram Moolenaar56ead342016-02-02 18:20:08 +0100554 if (reader->js_fill != NULL
555 && (int)(reader->js_end - p) < NUMBUFLEN)
556 {
557 reader->js_used = (int)(p - reader->js_buf);
558 if (reader->js_fill(reader))
559 {
560 p = reader->js_buf + reader->js_used;
561 reader->js_end = reader->js_buf
562 + STRLEN(reader->js_buf);
563 }
564 }
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100565 vim_str2nr(p + 2, NULL, &len,
566 STR2NR_HEX + STR2NR_FORCE, &nr, NULL, 4);
567 p += len + 2;
Bram Moolenaar56ead342016-02-02 18:20:08 +0100568 if (res != NULL)
569 {
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100570#ifdef FEAT_MBYTE
Bram Moolenaar56ead342016-02-02 18:20:08 +0100571 buf[(*mb_char2bytes)((int)nr, buf)] = NUL;
572 ga_concat(&ga, buf);
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100573#else
Bram Moolenaar56ead342016-02-02 18:20:08 +0100574 ga_append(&ga, nr);
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100575#endif
Bram Moolenaar56ead342016-02-02 18:20:08 +0100576 }
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100577 break;
Bram Moolenaar56ead342016-02-02 18:20:08 +0100578 default:
579 /* not a special char, skip over \ */
580 ++p;
581 continue;
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100582 }
583 if (c > 0)
584 {
585 p += 2;
Bram Moolenaar56ead342016-02-02 18:20:08 +0100586 if (res != NULL)
587 ga_append(&ga, c);
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100588 }
589 }
590 else
591 {
592 len = MB_PTR2LEN(p);
Bram Moolenaar56ead342016-02-02 18:20:08 +0100593 if (res != NULL)
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100594 {
Bram Moolenaar56ead342016-02-02 18:20:08 +0100595 if (ga_grow(&ga, len) == FAIL)
596 {
597 ga_clear(&ga);
598 return FAIL;
599 }
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100600 mch_memmove((char *)ga.ga_data + ga.ga_len, p, (size_t)len);
601 ga.ga_len += len;
602 }
603 p += len;
604 }
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100605 }
Bram Moolenaar56ead342016-02-02 18:20:08 +0100606
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100607 reader->js_used = (int)(p - reader->js_buf);
608 if (*p == '"')
609 {
610 ++reader->js_used;
Bram Moolenaar56ead342016-02-02 18:20:08 +0100611 if (res != NULL)
612 {
613 res->v_type = VAR_STRING;
Bram Moolenaar4b6a6dc2016-02-04 22:49:49 +0100614 res->vval.v_string = ga.ga_data;
Bram Moolenaar56ead342016-02-02 18:20:08 +0100615 }
616 return OK;
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100617 }
Bram Moolenaar56ead342016-02-02 18:20:08 +0100618 if (res != NULL)
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100619 {
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100620 res->v_type = VAR_SPECIAL;
621 res->vval.v_number = VVAL_NONE;
Bram Moolenaar56ead342016-02-02 18:20:08 +0100622 ga_clear(&ga);
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100623 }
Bram Moolenaar56ead342016-02-02 18:20:08 +0100624 return MAYBE;
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100625}
626
627/*
Bram Moolenaar56ead342016-02-02 18:20:08 +0100628 * Decode one item and put it in "res". If "res" is NULL only advance.
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100629 * Must already have skipped white space.
Bram Moolenaar56ead342016-02-02 18:20:08 +0100630 *
631 * Return FAIL for a decoding error.
632 * Return MAYBE for an incomplete message.
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100633 */
Bram Moolenaar56ead342016-02-02 18:20:08 +0100634 static int
Bram Moolenaar595e64e2016-02-07 19:19:53 +0100635json_decode_item(js_read_T *reader, typval_T *res, int options)
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100636{
Bram Moolenaar56ead342016-02-02 18:20:08 +0100637 char_u *p;
638 int len;
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100639
Bram Moolenaar56ead342016-02-02 18:20:08 +0100640 fill_numbuflen(reader);
641 p = reader->js_buf + reader->js_used;
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100642 switch (*p)
643 {
644 case '[': /* array */
Bram Moolenaar595e64e2016-02-07 19:19:53 +0100645 return json_decode_array(reader, res, options);
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100646
647 case '{': /* object */
Bram Moolenaar595e64e2016-02-07 19:19:53 +0100648 return json_decode_object(reader, res, options);
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100649
650 case '"': /* string */
Bram Moolenaar56ead342016-02-02 18:20:08 +0100651 return json_decode_string(reader, res);
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100652
653 case ',': /* comma: empty item */
Bram Moolenaar595e64e2016-02-07 19:19:53 +0100654 if ((options & JSON_JS) == 0)
655 return FAIL;
656 /* FALLTHROUGH */
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100657 case NUL: /* empty */
Bram Moolenaar56ead342016-02-02 18:20:08 +0100658 if (res != NULL)
659 {
660 res->v_type = VAR_SPECIAL;
661 res->vval.v_number = VVAL_NONE;
662 }
663 return OK;
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100664
665 default:
666 if (VIM_ISDIGIT(*p) || *p == '-')
667 {
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100668 char_u *sp = p;
Bram Moolenaar56ead342016-02-02 18:20:08 +0100669
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100670#ifdef FEAT_FLOAT
671 if (*sp == '-')
Bram Moolenaar56ead342016-02-02 18:20:08 +0100672 {
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100673 ++sp;
Bram Moolenaar56ead342016-02-02 18:20:08 +0100674 if (*sp == NUL)
675 return MAYBE;
676 if (!VIM_ISDIGIT(*sp))
677 return FAIL;
678 }
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100679 sp = skipdigits(sp);
680 if (*sp == '.' || *sp == 'e' || *sp == 'E')
681 {
Bram Moolenaar56ead342016-02-02 18:20:08 +0100682 if (res == NULL)
683 {
684 float_T f;
685
686 len = string2float(p, &f);
687 }
688 else
689 {
690 res->v_type = VAR_FLOAT;
691 len = string2float(p, &res->vval.v_float);
692 }
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100693 }
694 else
695#endif
696 {
697 long nr;
698
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100699 vim_str2nr(reader->js_buf + reader->js_used,
700 NULL, &len, 0, /* what */
701 &nr, NULL, 0);
Bram Moolenaar56ead342016-02-02 18:20:08 +0100702 if (res != NULL)
703 {
704 res->v_type = VAR_NUMBER;
705 res->vval.v_number = nr;
706 }
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100707 }
708 reader->js_used += len;
Bram Moolenaar56ead342016-02-02 18:20:08 +0100709 return OK;
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100710 }
711 if (STRNICMP((char *)p, "false", 5) == 0)
712 {
713 reader->js_used += 5;
Bram Moolenaar56ead342016-02-02 18:20:08 +0100714 if (res != NULL)
715 {
716 res->v_type = VAR_SPECIAL;
717 res->vval.v_number = VVAL_FALSE;
718 }
719 return OK;
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100720 }
721 if (STRNICMP((char *)p, "true", 4) == 0)
722 {
723 reader->js_used += 4;
Bram Moolenaar56ead342016-02-02 18:20:08 +0100724 if (res != NULL)
725 {
726 res->v_type = VAR_SPECIAL;
727 res->vval.v_number = VVAL_TRUE;
728 }
729 return OK;
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100730 }
731 if (STRNICMP((char *)p, "null", 4) == 0)
732 {
733 reader->js_used += 4;
Bram Moolenaar56ead342016-02-02 18:20:08 +0100734 if (res != NULL)
735 {
736 res->v_type = VAR_SPECIAL;
737 res->vval.v_number = VVAL_NULL;
738 }
739 return OK;
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100740 }
Bram Moolenaarf1b6ac72016-02-23 21:26:43 +0100741#ifdef FEAT_FLOAT
742 if (STRNICMP((char *)p, "NaN", 3) == 0)
743 {
744 reader->js_used += 3;
745 if (res != NULL)
746 {
747 res->v_type = VAR_FLOAT;
748 res->vval.v_float = 0.0 / 0.0;
749 }
750 return OK;
751 }
752 if (STRNICMP((char *)p, "Infinity", 8) == 0)
753 {
754 reader->js_used += 8;
755 if (res != NULL)
756 {
757 res->v_type = VAR_FLOAT;
758 res->vval.v_float = 1.0 / 0.0;
759 }
760 return OK;
761 }
762#endif
Bram Moolenaar56ead342016-02-02 18:20:08 +0100763 /* check for truncated name */
764 len = (int)(reader->js_end - (reader->js_buf + reader->js_used));
Bram Moolenaarf1b6ac72016-02-23 21:26:43 +0100765 if (
766 (len < 5 && STRNICMP((char *)p, "false", len) == 0)
767#ifdef FEAT_FLOAT
768 || (len < 8 && STRNICMP((char *)p, "Infinity", len) == 0)
769 || (len < 3 && STRNICMP((char *)p, "NaN", len) == 0)
770#endif
Bram Moolenaar56ead342016-02-02 18:20:08 +0100771 || (len < 4 && (STRNICMP((char *)p, "true", len) == 0
772 || STRNICMP((char *)p, "null", len) == 0)))
773 return MAYBE;
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100774 break;
775 }
776
Bram Moolenaar56ead342016-02-02 18:20:08 +0100777 if (res != NUL)
778 {
779 res->v_type = VAR_SPECIAL;
780 res->vval.v_number = VVAL_NONE;
781 }
782 return FAIL;
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100783}
784
785/*
786 * Decode the JSON from "reader" and store the result in "res".
Bram Moolenaar595e64e2016-02-07 19:19:53 +0100787 * "options" can be JSON_JS or zero;
Bram Moolenaar56ead342016-02-02 18:20:08 +0100788 * Return FAIL if not the whole message was consumed.
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100789 */
Bram Moolenaar19d2f152016-02-01 21:38:19 +0100790 int
Bram Moolenaar595e64e2016-02-07 19:19:53 +0100791json_decode_all(js_read_T *reader, typval_T *res, int options)
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100792{
Bram Moolenaar56ead342016-02-02 18:20:08 +0100793 int ret;
794
Bram Moolenaar595e64e2016-02-07 19:19:53 +0100795 /* We find the end once, to avoid calling strlen() many times. */
Bram Moolenaar56ead342016-02-02 18:20:08 +0100796 reader->js_end = reader->js_buf + STRLEN(reader->js_buf);
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100797 json_skip_white(reader);
Bram Moolenaar595e64e2016-02-07 19:19:53 +0100798 ret = json_decode_item(reader, res, options);
Bram Moolenaar56ead342016-02-02 18:20:08 +0100799 if (ret != OK)
800 return FAIL;
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100801 json_skip_white(reader);
802 if (reader->js_buf[reader->js_used] != NUL)
Bram Moolenaar19d2f152016-02-01 21:38:19 +0100803 return FAIL;
804 return OK;
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100805}
Bram Moolenaar56ead342016-02-02 18:20:08 +0100806
807/*
808 * Decode the JSON from "reader" and store the result in "res".
Bram Moolenaar595e64e2016-02-07 19:19:53 +0100809 * "options" can be JSON_JS or zero;
Bram Moolenaar56ead342016-02-02 18:20:08 +0100810 * Return FAIL if the message has a decoding error or the message is
811 * truncated. Consumes the message anyway.
812 */
813 int
Bram Moolenaar595e64e2016-02-07 19:19:53 +0100814json_decode(js_read_T *reader, typval_T *res, int options)
Bram Moolenaar56ead342016-02-02 18:20:08 +0100815{
816 int ret;
817
Bram Moolenaar595e64e2016-02-07 19:19:53 +0100818 /* We find the end once, to avoid calling strlen() many times. */
Bram Moolenaar56ead342016-02-02 18:20:08 +0100819 reader->js_end = reader->js_buf + STRLEN(reader->js_buf);
820 json_skip_white(reader);
Bram Moolenaar595e64e2016-02-07 19:19:53 +0100821 ret = json_decode_item(reader, res, options);
Bram Moolenaar56ead342016-02-02 18:20:08 +0100822 json_skip_white(reader);
823
824 return ret == OK ? OK : FAIL;
825}
826
827/*
828 * Decode the JSON from "reader" to find the end of the message.
Bram Moolenaar595e64e2016-02-07 19:19:53 +0100829 * "options" can be JSON_JS or zero;
Bram Moolenaar56ead342016-02-02 18:20:08 +0100830 * Return FAIL if the message has a decoding error.
831 * Return MAYBE if the message is truncated, need to read more.
832 * This only works reliable if the message contains an object, array or
833 * string. A number might be trucated without knowing.
834 * Does not advance the reader.
835 */
836 int
Bram Moolenaar595e64e2016-02-07 19:19:53 +0100837json_find_end(js_read_T *reader, int options)
Bram Moolenaar56ead342016-02-02 18:20:08 +0100838{
839 int used_save = reader->js_used;
840 int ret;
841
Bram Moolenaar595e64e2016-02-07 19:19:53 +0100842 /* We find the end once, to avoid calling strlen() many times. */
Bram Moolenaar56ead342016-02-02 18:20:08 +0100843 reader->js_end = reader->js_buf + STRLEN(reader->js_buf);
844 json_skip_white(reader);
Bram Moolenaar595e64e2016-02-07 19:19:53 +0100845 ret = json_decode_item(reader, NULL, options);
Bram Moolenaar56ead342016-02-02 18:20:08 +0100846 reader->js_used = used_save;
847 return ret;
848}
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100849#endif