blob: 36876455b5691876de1289a4596fd17bf4e2dc49 [file] [log] [blame]
Bram Moolenaar520e1e42016-01-23 19:46:28 +01001/* vi:set ts=8 sts=4 sw=4:
2 *
3 * VIM - Vi IMproved by Bram Moolenaar
4 *
5 * Do ":help uganda" in Vim to read copying and usage conditions.
6 * Do ":help credits" in Vim to see a list of people who contributed.
7 * See README.txt for an overview of the Vim source code.
8 */
9
10/*
11 * json.c: Encoding and decoding JSON.
12 *
Bram Moolenaar009d84a2016-01-28 14:12:00 +010013 * Follows this standard: https://tools.ietf.org/html/rfc7159.html
Bram Moolenaar520e1e42016-01-23 19:46:28 +010014 */
15
16#include "vim.h"
17
18#if defined(FEAT_EVAL) || defined(PROTO)
Bram Moolenaarf1b6ac72016-02-23 21:26:43 +010019
Bram Moolenaar595e64e2016-02-07 19:19:53 +010020static int json_encode_item(garray_T *gap, typval_T *val, int copyID, int options);
21static int json_decode_item(js_read_T *reader, typval_T *res, int options);
Bram Moolenaar520e1e42016-01-23 19:46:28 +010022
23/*
24 * Encode "val" into a JSON format string.
Bram Moolenaar55fab432016-02-07 16:53:13 +010025 * The result is in allocated memory.
26 * The result is empty when encoding fails.
Bram Moolenaar595e64e2016-02-07 19:19:53 +010027 * "options" can be JSON_JS or zero;
Bram Moolenaar520e1e42016-01-23 19:46:28 +010028 */
29 char_u *
Bram Moolenaar595e64e2016-02-07 19:19:53 +010030json_encode(typval_T *val, int options)
Bram Moolenaar520e1e42016-01-23 19:46:28 +010031{
32 garray_T ga;
33
34 /* Store bytes in the growarray. */
35 ga_init2(&ga, 1, 4000);
Bram Moolenaar595e64e2016-02-07 19:19:53 +010036 if (json_encode_item(&ga, val, get_copyID(), options) == FAIL)
Bram Moolenaar55fab432016-02-07 16:53:13 +010037 {
38 vim_free(ga.ga_data);
39 return vim_strsave((char_u *)"");
40 }
Bram Moolenaar520e1e42016-01-23 19:46:28 +010041 return ga.ga_data;
42}
43
Bram Moolenaarfb1f6262016-01-31 20:24:32 +010044/*
Bram Moolenaar55fab432016-02-07 16:53:13 +010045 * Encode ["nr", "val"] into a JSON format string in allocated memory.
Bram Moolenaar595e64e2016-02-07 19:19:53 +010046 * "options" can be JSON_JS or zero;
Bram Moolenaarfb1f6262016-01-31 20:24:32 +010047 * Returns NULL when out of memory.
48 */
49 char_u *
Bram Moolenaar595e64e2016-02-07 19:19:53 +010050json_encode_nr_expr(int nr, typval_T *val, int options)
Bram Moolenaarfb1f6262016-01-31 20:24:32 +010051{
52 typval_T listtv;
53 typval_T nrtv;
54 char_u *text;
55
56 nrtv.v_type = VAR_NUMBER;
57 nrtv.vval.v_number = nr;
58 if (rettv_list_alloc(&listtv) == FAIL)
59 return NULL;
60 if (list_append_tv(listtv.vval.v_list, &nrtv) == FAIL
61 || list_append_tv(listtv.vval.v_list, val) == FAIL)
62 {
63 list_unref(listtv.vval.v_list);
64 return NULL;
65 }
66
Bram Moolenaar595e64e2016-02-07 19:19:53 +010067 text = json_encode(&listtv, options);
Bram Moolenaarfb1f6262016-01-31 20:24:32 +010068 list_unref(listtv.vval.v_list);
69 return text;
70}
71
Bram Moolenaar520e1e42016-01-23 19:46:28 +010072 static void
73write_string(garray_T *gap, char_u *str)
74{
75 char_u *res = str;
76 char_u numbuf[NUMBUFLEN];
77
78 if (res == NULL)
79 ga_concat(gap, (char_u *)"null");
80 else
81 {
Bram Moolenaarb6ff8112016-02-27 18:41:27 +010082#if defined(FEAT_MBYTE) && defined(USE_ICONV)
83 vimconv_T conv;
84 char_u *converted = NULL;
85
Bram Moolenaarf97ddbe2016-02-27 21:13:38 +010086 if (!enc_utf8)
87 {
88 conv.vc_type = CONV_NONE;
89 convert_setup(&conv, p_enc, (char_u*)"utf-8");
90 if (conv.vc_type != CONV_NONE)
91 converted = res = string_convert(&conv, res, NULL);
92 convert_setup(&conv, NULL, NULL);
93 }
Bram Moolenaarb6ff8112016-02-27 18:41:27 +010094#endif
Bram Moolenaar520e1e42016-01-23 19:46:28 +010095 ga_append(gap, '"');
96 while (*res != NUL)
97 {
Bram Moolenaarb6ff8112016-02-27 18:41:27 +010098 int c;
99#ifdef FEAT_MBYTE
100 /* always use utf-8 encoding, ignore 'encoding' */
101 c = utf_ptr2char(res);
102#else
103 c = (int)*(p);
104#endif
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100105
106 switch (c)
107 {
108 case 0x08:
109 ga_append(gap, '\\'); ga_append(gap, 'b'); break;
110 case 0x09:
111 ga_append(gap, '\\'); ga_append(gap, 't'); break;
112 case 0x0a:
113 ga_append(gap, '\\'); ga_append(gap, 'n'); break;
114 case 0x0c:
115 ga_append(gap, '\\'); ga_append(gap, 'f'); break;
116 case 0x0d:
117 ga_append(gap, '\\'); ga_append(gap, 'r'); break;
118 case 0x22: /* " */
119 case 0x5c: /* \ */
120 ga_append(gap, '\\');
121 ga_append(gap, c);
122 break;
123 default:
124 if (c >= 0x20)
125 {
Bram Moolenaarfa06a512016-01-28 22:46:58 +0100126#ifdef FEAT_MBYTE
Bram Moolenaarb6ff8112016-02-27 18:41:27 +0100127 numbuf[utf_char2bytes(c, numbuf)] = NUL;
Bram Moolenaarfa06a512016-01-28 22:46:58 +0100128#else
129 numbuf[0] = c;
130 numbuf[1] = NUL;
131#endif
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100132 ga_concat(gap, numbuf);
133 }
134 else
135 {
136 vim_snprintf((char *)numbuf, NUMBUFLEN,
137 "\\u%04lx", (long)c);
138 ga_concat(gap, numbuf);
139 }
140 }
Bram Moolenaarb6ff8112016-02-27 18:41:27 +0100141#ifdef FEAT_MBYTE
142 res += utf_ptr2len(res);
143#else
144 ++p;
145#endif
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100146 }
147 ga_append(gap, '"');
Bram Moolenaarb6ff8112016-02-27 18:41:27 +0100148#if defined(FEAT_MBYTE) && defined(USE_ICONV)
149 vim_free(converted);
150#endif
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100151 }
152}
153
Bram Moolenaarfcaaae62016-01-24 16:49:11 +0100154/*
Bram Moolenaar595e64e2016-02-07 19:19:53 +0100155 * Return TRUE if "key" can be used without quotes.
156 * That is when it starts with a letter and only contains letters, digits and
157 * underscore.
158 */
159 static int
160is_simple_key(char_u *key)
161{
162 char_u *p;
163
164 if (!ASCII_ISALPHA(*key))
165 return FALSE;
166 for (p = key + 1; *p != NUL; ++p)
167 if (!ASCII_ISALPHA(*p) && *p != '_' && !vim_isdigit(*p))
168 return FALSE;
169 return TRUE;
170}
171
172/*
Bram Moolenaarfcaaae62016-01-24 16:49:11 +0100173 * Encode "val" into "gap".
174 * Return FAIL or OK.
175 */
176 static int
Bram Moolenaar595e64e2016-02-07 19:19:53 +0100177json_encode_item(garray_T *gap, typval_T *val, int copyID, int options)
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100178{
179 char_u numbuf[NUMBUFLEN];
180 char_u *res;
181 list_T *l;
182 dict_T *d;
183
184 switch (val->v_type)
185 {
186 case VAR_SPECIAL:
Bram Moolenaarfcaaae62016-01-24 16:49:11 +0100187 switch (val->vval.v_number)
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100188 {
189 case VVAL_FALSE: ga_concat(gap, (char_u *)"false"); break;
190 case VVAL_TRUE: ga_concat(gap, (char_u *)"true"); break;
Bram Moolenaar595e64e2016-02-07 19:19:53 +0100191 case VVAL_NONE: if ((options & JSON_JS) != 0
192 && (options & JSON_NO_NONE) == 0)
193 /* empty item */
194 break;
195 /* FALLTHROUGH */
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100196 case VVAL_NULL: ga_concat(gap, (char_u *)"null"); break;
197 }
198 break;
199
200 case VAR_NUMBER:
201 vim_snprintf((char *)numbuf, NUMBUFLEN, "%ld",
202 (long)val->vval.v_number);
203 ga_concat(gap, numbuf);
204 break;
205
206 case VAR_STRING:
207 res = val->vval.v_string;
208 write_string(gap, res);
209 break;
210
211 case VAR_FUNC:
Bram Moolenaar55fab432016-02-07 16:53:13 +0100212 case VAR_JOB:
Bram Moolenaar77073442016-02-13 23:23:53 +0100213 case VAR_CHANNEL:
Bram Moolenaar4f8b8fa2016-02-06 18:42:07 +0100214 /* no JSON equivalent TODO: better error */
Bram Moolenaarfcaaae62016-01-24 16:49:11 +0100215 EMSG(_(e_invarg));
216 return FAIL;
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100217
218 case VAR_LIST:
219 l = val->vval.v_list;
220 if (l == NULL)
221 ga_concat(gap, (char_u *)"null");
222 else
223 {
224 if (l->lv_copyID == copyID)
225 ga_concat(gap, (char_u *)"[]");
226 else
227 {
228 listitem_T *li;
229
230 l->lv_copyID = copyID;
231 ga_append(gap, '[');
232 for (li = l->lv_first; li != NULL && !got_int; )
233 {
Bram Moolenaar595e64e2016-02-07 19:19:53 +0100234 if (json_encode_item(gap, &li->li_tv, copyID,
235 options & JSON_JS) == FAIL)
Bram Moolenaarfcaaae62016-01-24 16:49:11 +0100236 return FAIL;
Bram Moolenaar595e64e2016-02-07 19:19:53 +0100237 if ((options & JSON_JS)
238 && li->li_next == NULL
239 && li->li_tv.v_type == VAR_SPECIAL
240 && li->li_tv.vval.v_number == VVAL_NONE)
241 /* add an extra comma if the last item is v:none */
242 ga_append(gap, ',');
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100243 li = li->li_next;
244 if (li != NULL)
245 ga_append(gap, ',');
246 }
247 ga_append(gap, ']');
Bram Moolenaarfcaaae62016-01-24 16:49:11 +0100248 l->lv_copyID = 0;
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100249 }
250 }
251 break;
252
253 case VAR_DICT:
254 d = val->vval.v_dict;
255 if (d == NULL)
256 ga_concat(gap, (char_u *)"null");
257 else
258 {
259 if (d->dv_copyID == copyID)
260 ga_concat(gap, (char_u *)"{}");
261 else
262 {
263 int first = TRUE;
264 int todo = (int)d->dv_hashtab.ht_used;
265 hashitem_T *hi;
266
267 d->dv_copyID = copyID;
268 ga_append(gap, '{');
269
270 for (hi = d->dv_hashtab.ht_array; todo > 0 && !got_int;
271 ++hi)
272 if (!HASHITEM_EMPTY(hi))
273 {
274 --todo;
275 if (first)
276 first = FALSE;
277 else
278 ga_append(gap, ',');
Bram Moolenaar595e64e2016-02-07 19:19:53 +0100279 if ((options & JSON_JS)
280 && is_simple_key(hi->hi_key))
281 ga_concat(gap, hi->hi_key);
282 else
283 write_string(gap, hi->hi_key);
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100284 ga_append(gap, ':');
Bram Moolenaarfcaaae62016-01-24 16:49:11 +0100285 if (json_encode_item(gap, &dict_lookup(hi)->di_tv,
Bram Moolenaar595e64e2016-02-07 19:19:53 +0100286 copyID, options | JSON_NO_NONE) == FAIL)
Bram Moolenaarfcaaae62016-01-24 16:49:11 +0100287 return FAIL;
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100288 }
289 ga_append(gap, '}');
Bram Moolenaarfcaaae62016-01-24 16:49:11 +0100290 d->dv_copyID = 0;
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100291 }
292 }
293 break;
294
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100295 case VAR_FLOAT:
Bram Moolenaar55fab432016-02-07 16:53:13 +0100296#ifdef FEAT_FLOAT
Bram Moolenaarf1b6ac72016-02-23 21:26:43 +0100297# if defined(HAVE_MATH_H)
Bram Moolenaar7ce686c2016-02-27 16:33:22 +0100298 if (isnan(val->vval.v_float))
Bram Moolenaarf1b6ac72016-02-23 21:26:43 +0100299 ga_concat(gap, (char_u *)"NaN");
Bram Moolenaar7ce686c2016-02-27 16:33:22 +0100300 else if (isinf(val->vval.v_float))
Bram Moolenaarf1b6ac72016-02-23 21:26:43 +0100301 ga_concat(gap, (char_u *)"Infinity");
Bram Moolenaarf1b6ac72016-02-23 21:26:43 +0100302 else
303# endif
304 {
305 vim_snprintf((char *)numbuf, NUMBUFLEN, "%g",
306 val->vval.v_float);
307 ga_concat(gap, numbuf);
308 }
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100309 break;
310#endif
Bram Moolenaar55fab432016-02-07 16:53:13 +0100311 case VAR_UNKNOWN:
Bram Moolenaarc6b14f02016-02-20 15:26:42 +0100312 EMSG2(_(e_intern2), "json_encode_item()");
Bram Moolenaar55fab432016-02-07 16:53:13 +0100313 return FAIL;
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100314 }
Bram Moolenaarfcaaae62016-01-24 16:49:11 +0100315 return OK;
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100316}
317
318/*
Bram Moolenaar56ead342016-02-02 18:20:08 +0100319 * When "reader" has less than NUMBUFLEN bytes available, call the fill
320 * callback to get more.
321 */
322 static void
323fill_numbuflen(js_read_T *reader)
324{
325 if (reader->js_fill != NULL && (int)(reader->js_end - reader->js_buf)
326 - reader->js_used < NUMBUFLEN)
327 {
328 if (reader->js_fill(reader))
329 reader->js_end = reader->js_buf + STRLEN(reader->js_buf);
330 }
331}
332
333/*
Bram Moolenaar595e64e2016-02-07 19:19:53 +0100334 * Skip white space in "reader". All characters <= space are considered white
335 * space.
Bram Moolenaar56ead342016-02-02 18:20:08 +0100336 * Also tops up readahead when needed.
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100337 */
338 static void
339json_skip_white(js_read_T *reader)
340{
341 int c;
342
Bram Moolenaar56ead342016-02-02 18:20:08 +0100343 for (;;)
344 {
345 c = reader->js_buf[reader->js_used];
346 if (reader->js_fill != NULL && c == NUL)
347 {
348 if (reader->js_fill(reader))
349 reader->js_end = reader->js_buf + STRLEN(reader->js_buf);
350 continue;
351 }
Bram Moolenaar595e64e2016-02-07 19:19:53 +0100352 if (c == NUL || c > ' ')
Bram Moolenaar56ead342016-02-02 18:20:08 +0100353 break;
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100354 ++reader->js_used;
Bram Moolenaar56ead342016-02-02 18:20:08 +0100355 }
356 fill_numbuflen(reader);
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100357}
358
Bram Moolenaar56ead342016-02-02 18:20:08 +0100359 static int
Bram Moolenaar595e64e2016-02-07 19:19:53 +0100360json_decode_array(js_read_T *reader, typval_T *res, int options)
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100361{
362 char_u *p;
363 typval_T item;
364 listitem_T *li;
Bram Moolenaar56ead342016-02-02 18:20:08 +0100365 int ret;
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100366
Bram Moolenaar56ead342016-02-02 18:20:08 +0100367 if (res != NULL && rettv_list_alloc(res) == FAIL)
368 {
369 res->v_type = VAR_SPECIAL;
370 res->vval.v_number = VVAL_NONE;
371 return FAIL;
372 }
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100373 ++reader->js_used; /* consume the '[' */
374
375 while (TRUE)
376 {
377 json_skip_white(reader);
378 p = reader->js_buf + reader->js_used;
379 if (*p == NUL)
Bram Moolenaar56ead342016-02-02 18:20:08 +0100380 return MAYBE;
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100381 if (*p == ']')
382 {
383 ++reader->js_used; /* consume the ']' */
Bram Moolenaar56ead342016-02-02 18:20:08 +0100384 break;
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100385 }
386
Bram Moolenaar595e64e2016-02-07 19:19:53 +0100387 ret = json_decode_item(reader, res == NULL ? NULL : &item, options);
Bram Moolenaar56ead342016-02-02 18:20:08 +0100388 if (ret != OK)
389 return ret;
390 if (res != NULL)
391 {
392 li = listitem_alloc();
393 if (li == NULL)
394 {
395 clear_tv(&item);
396 return FAIL;
397 }
398 li->li_tv = item;
399 list_append(res->vval.v_list, li);
400 }
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100401
402 json_skip_white(reader);
403 p = reader->js_buf + reader->js_used;
404 if (*p == ',')
405 ++reader->js_used;
406 else if (*p != ']')
Bram Moolenaar56ead342016-02-02 18:20:08 +0100407 {
408 if (*p == NUL)
409 return MAYBE;
410 return FAIL;
411 }
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100412 }
Bram Moolenaar56ead342016-02-02 18:20:08 +0100413 return OK;
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100414}
415
Bram Moolenaar56ead342016-02-02 18:20:08 +0100416 static int
Bram Moolenaar595e64e2016-02-07 19:19:53 +0100417json_decode_object(js_read_T *reader, typval_T *res, int options)
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100418{
419 char_u *p;
420 typval_T tvkey;
421 typval_T item;
422 dictitem_T *di;
423 char_u buf[NUMBUFLEN];
Bram Moolenaarfbf9c6b2016-02-02 19:43:57 +0100424 char_u *key = NULL;
Bram Moolenaar56ead342016-02-02 18:20:08 +0100425 int ret;
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100426
Bram Moolenaar56ead342016-02-02 18:20:08 +0100427 if (res != NULL && rettv_dict_alloc(res) == FAIL)
428 {
429 res->v_type = VAR_SPECIAL;
430 res->vval.v_number = VVAL_NONE;
431 return FAIL;
432 }
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100433 ++reader->js_used; /* consume the '{' */
434
435 while (TRUE)
436 {
437 json_skip_white(reader);
438 p = reader->js_buf + reader->js_used;
439 if (*p == NUL)
Bram Moolenaar56ead342016-02-02 18:20:08 +0100440 return MAYBE;
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100441 if (*p == '}')
442 {
443 ++reader->js_used; /* consume the '}' */
Bram Moolenaar56ead342016-02-02 18:20:08 +0100444 break;
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100445 }
446
Bram Moolenaar595e64e2016-02-07 19:19:53 +0100447 if ((options & JSON_JS) && reader->js_buf[reader->js_used] != '"')
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100448 {
Bram Moolenaar595e64e2016-02-07 19:19:53 +0100449 /* accept a key that is not in quotes */
450 key = p = reader->js_buf + reader->js_used;
451 while (*p != NUL && *p != ':' && *p > ' ')
452 ++p;
453 tvkey.v_type = VAR_STRING;
454 tvkey.vval.v_string = vim_strnsave(key, (int)(p - key));
455 reader->js_used += (int)(p - key);
456 key = tvkey.vval.v_string;
457 }
458 else
459 {
460 ret = json_decode_item(reader, res == NULL ? NULL : &tvkey,
461 options);
462 if (ret != OK)
463 return ret;
464 if (res != NULL)
Bram Moolenaar56ead342016-02-02 18:20:08 +0100465 {
Bram Moolenaar595e64e2016-02-07 19:19:53 +0100466 key = get_tv_string_buf_chk(&tvkey, buf);
467 if (key == NULL || *key == NUL)
468 {
469 clear_tv(&tvkey);
470 return FAIL;
471 }
Bram Moolenaar56ead342016-02-02 18:20:08 +0100472 }
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100473 }
474
475 json_skip_white(reader);
476 p = reader->js_buf + reader->js_used;
477 if (*p != ':')
478 {
Bram Moolenaar56ead342016-02-02 18:20:08 +0100479 if (res != NULL)
480 clear_tv(&tvkey);
481 if (*p == NUL)
482 return MAYBE;
483 return FAIL;
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100484 }
485 ++reader->js_used;
486 json_skip_white(reader);
487
Bram Moolenaar595e64e2016-02-07 19:19:53 +0100488 ret = json_decode_item(reader, res == NULL ? NULL : &item, options);
Bram Moolenaar56ead342016-02-02 18:20:08 +0100489 if (ret != OK)
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100490 {
Bram Moolenaar56ead342016-02-02 18:20:08 +0100491 if (res != NULL)
492 clear_tv(&tvkey);
493 return ret;
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100494 }
Bram Moolenaar56ead342016-02-02 18:20:08 +0100495
496 if (res != NULL)
497 {
498 di = dictitem_alloc(key);
499 clear_tv(&tvkey);
500 if (di == NULL)
501 {
502 clear_tv(&item);
503 return FAIL;
504 }
505 di->di_tv = item;
506 if (dict_add(res->vval.v_dict, di) == FAIL)
507 {
508 dictitem_free(di);
509 return FAIL;
510 }
511 }
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100512
513 json_skip_white(reader);
514 p = reader->js_buf + reader->js_used;
515 if (*p == ',')
516 ++reader->js_used;
517 else if (*p != '}')
Bram Moolenaar56ead342016-02-02 18:20:08 +0100518 {
519 if (*p == NUL)
520 return MAYBE;
521 return FAIL;
522 }
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100523 }
Bram Moolenaar56ead342016-02-02 18:20:08 +0100524 return OK;
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100525}
526
Bram Moolenaar56ead342016-02-02 18:20:08 +0100527 static int
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100528json_decode_string(js_read_T *reader, typval_T *res)
529{
530 garray_T ga;
531 int len;
Bram Moolenaar56ead342016-02-02 18:20:08 +0100532 char_u *p;
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100533 int c;
534 long nr;
535 char_u buf[NUMBUFLEN];
Bram Moolenaarb6ff8112016-02-27 18:41:27 +0100536#if defined(FEAT_MBYTE) && defined(USE_ICONV)
537 vimconv_T conv;
538 char_u *converted = NULL;
539#endif
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100540
Bram Moolenaar56ead342016-02-02 18:20:08 +0100541 if (res != NULL)
542 ga_init2(&ga, 1, 200);
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100543
Bram Moolenaar56ead342016-02-02 18:20:08 +0100544 p = reader->js_buf + reader->js_used + 1; /* skip over " */
Bram Moolenaarb6ff8112016-02-27 18:41:27 +0100545#if defined(FEAT_MBYTE) && defined(USE_ICONV)
Bram Moolenaarf97ddbe2016-02-27 21:13:38 +0100546 if (!enc_utf8)
547 {
548 conv.vc_type = CONV_NONE;
549 convert_setup(&conv, (char_u*)"utf-8", p_enc);
550 if (conv.vc_type != CONV_NONE)
551 converted = p = string_convert(&conv, p, NULL);
552 convert_setup(&conv, NULL, NULL);
553 }
Bram Moolenaarb6ff8112016-02-27 18:41:27 +0100554#endif
Bram Moolenaar56ead342016-02-02 18:20:08 +0100555 while (*p != '"')
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100556 {
Bram Moolenaar56ead342016-02-02 18:20:08 +0100557 if (*p == NUL || p[1] == NUL
558#ifdef FEAT_MBYTE
559 || utf_ptr2len(p) < utf_byte2len(*p)
560#endif
561 )
562 {
563 if (reader->js_fill == NULL)
564 break;
565 len = (int)(reader->js_end - p);
566 reader->js_used = (int)(p - reader->js_buf);
567 if (!reader->js_fill(reader))
568 break; /* didn't get more */
569 p = reader->js_buf + reader->js_used;
570 reader->js_end = reader->js_buf + STRLEN(reader->js_buf);
571 continue;
572 }
573
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100574 if (*p == '\\')
575 {
576 c = -1;
577 switch (p[1])
578 {
Bram Moolenaar56ead342016-02-02 18:20:08 +0100579 case '\\': c = '\\'; break;
580 case '"': c = '"'; break;
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100581 case 'b': c = BS; break;
582 case 't': c = TAB; break;
583 case 'n': c = NL; break;
584 case 'f': c = FF; break;
585 case 'r': c = CAR; break;
586 case 'u':
Bram Moolenaar56ead342016-02-02 18:20:08 +0100587 if (reader->js_fill != NULL
588 && (int)(reader->js_end - p) < NUMBUFLEN)
589 {
590 reader->js_used = (int)(p - reader->js_buf);
591 if (reader->js_fill(reader))
592 {
593 p = reader->js_buf + reader->js_used;
594 reader->js_end = reader->js_buf
595 + STRLEN(reader->js_buf);
596 }
597 }
Bram Moolenaarb6ff8112016-02-27 18:41:27 +0100598 nr = 0;
599 len = 0;
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100600 vim_str2nr(p + 2, NULL, &len,
601 STR2NR_HEX + STR2NR_FORCE, &nr, NULL, 4);
602 p += len + 2;
Bram Moolenaarb6ff8112016-02-27 18:41:27 +0100603 if (0xd800 <= nr && nr <= 0xdfff
604 && (int)(reader->js_end - p) >= 6
605 && *p == '\\' && *(p+1) == 'u')
606 {
607 long nr2 = 0;
608
609 /* decode surrogate pair: \ud812\u3456 */
610 len = 0;
611 vim_str2nr(p + 2, NULL, &len,
612 STR2NR_HEX + STR2NR_FORCE, &nr2, NULL, 4);
613 if (0xdc00 <= nr2 && nr2 <= 0xdfff)
614 {
615 p += len + 2;
616 nr = (((nr - 0xd800) << 10) |
617 ((nr2 - 0xdc00) & 0x3ff)) + 0x10000;
618 }
619 }
Bram Moolenaar56ead342016-02-02 18:20:08 +0100620 if (res != NULL)
621 {
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100622#ifdef FEAT_MBYTE
Bram Moolenaarb6ff8112016-02-27 18:41:27 +0100623 buf[utf_char2bytes((int)nr, buf)] = NUL;
Bram Moolenaar56ead342016-02-02 18:20:08 +0100624 ga_concat(&ga, buf);
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100625#else
Bram Moolenaar56ead342016-02-02 18:20:08 +0100626 ga_append(&ga, nr);
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100627#endif
Bram Moolenaar56ead342016-02-02 18:20:08 +0100628 }
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100629 break;
Bram Moolenaar56ead342016-02-02 18:20:08 +0100630 default:
631 /* not a special char, skip over \ */
632 ++p;
633 continue;
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100634 }
635 if (c > 0)
636 {
637 p += 2;
Bram Moolenaar56ead342016-02-02 18:20:08 +0100638 if (res != NULL)
639 ga_append(&ga, c);
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100640 }
641 }
642 else
643 {
Bram Moolenaarb6ff8112016-02-27 18:41:27 +0100644#ifdef FEAT_MBYTE
645 len = utf_ptr2len(p);
646#else
647 len = 1;
648#endif
Bram Moolenaar56ead342016-02-02 18:20:08 +0100649 if (res != NULL)
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100650 {
Bram Moolenaar56ead342016-02-02 18:20:08 +0100651 if (ga_grow(&ga, len) == FAIL)
652 {
653 ga_clear(&ga);
Bram Moolenaarb6ff8112016-02-27 18:41:27 +0100654#if defined(FEAT_MBYTE) && defined(USE_ICONV)
655 vim_free(converted);
656#endif
Bram Moolenaar56ead342016-02-02 18:20:08 +0100657 return FAIL;
658 }
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100659 mch_memmove((char *)ga.ga_data + ga.ga_len, p, (size_t)len);
660 ga.ga_len += len;
661 }
662 p += len;
663 }
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100664 }
Bram Moolenaarb6ff8112016-02-27 18:41:27 +0100665#if defined(FEAT_MBYTE) && defined(USE_ICONV)
666 vim_free(converted);
667#endif
Bram Moolenaar56ead342016-02-02 18:20:08 +0100668
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100669 reader->js_used = (int)(p - reader->js_buf);
670 if (*p == '"')
671 {
672 ++reader->js_used;
Bram Moolenaar56ead342016-02-02 18:20:08 +0100673 if (res != NULL)
674 {
675 res->v_type = VAR_STRING;
Bram Moolenaar4b6a6dc2016-02-04 22:49:49 +0100676 res->vval.v_string = ga.ga_data;
Bram Moolenaar56ead342016-02-02 18:20:08 +0100677 }
678 return OK;
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100679 }
Bram Moolenaar56ead342016-02-02 18:20:08 +0100680 if (res != NULL)
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100681 {
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100682 res->v_type = VAR_SPECIAL;
683 res->vval.v_number = VVAL_NONE;
Bram Moolenaar56ead342016-02-02 18:20:08 +0100684 ga_clear(&ga);
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100685 }
Bram Moolenaar56ead342016-02-02 18:20:08 +0100686 return MAYBE;
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100687}
688
689/*
Bram Moolenaar56ead342016-02-02 18:20:08 +0100690 * Decode one item and put it in "res". If "res" is NULL only advance.
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100691 * Must already have skipped white space.
Bram Moolenaar56ead342016-02-02 18:20:08 +0100692 *
693 * Return FAIL for a decoding error.
694 * Return MAYBE for an incomplete message.
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100695 */
Bram Moolenaar56ead342016-02-02 18:20:08 +0100696 static int
Bram Moolenaar595e64e2016-02-07 19:19:53 +0100697json_decode_item(js_read_T *reader, typval_T *res, int options)
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100698{
Bram Moolenaar56ead342016-02-02 18:20:08 +0100699 char_u *p;
700 int len;
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100701
Bram Moolenaar56ead342016-02-02 18:20:08 +0100702 fill_numbuflen(reader);
703 p = reader->js_buf + reader->js_used;
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100704 switch (*p)
705 {
706 case '[': /* array */
Bram Moolenaar595e64e2016-02-07 19:19:53 +0100707 return json_decode_array(reader, res, options);
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100708
709 case '{': /* object */
Bram Moolenaar595e64e2016-02-07 19:19:53 +0100710 return json_decode_object(reader, res, options);
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100711
712 case '"': /* string */
Bram Moolenaar56ead342016-02-02 18:20:08 +0100713 return json_decode_string(reader, res);
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100714
715 case ',': /* comma: empty item */
Bram Moolenaar595e64e2016-02-07 19:19:53 +0100716 if ((options & JSON_JS) == 0)
717 return FAIL;
718 /* FALLTHROUGH */
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100719 case NUL: /* empty */
Bram Moolenaar56ead342016-02-02 18:20:08 +0100720 if (res != NULL)
721 {
722 res->v_type = VAR_SPECIAL;
723 res->vval.v_number = VVAL_NONE;
724 }
725 return OK;
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100726
727 default:
728 if (VIM_ISDIGIT(*p) || *p == '-')
729 {
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100730 char_u *sp = p;
Bram Moolenaar56ead342016-02-02 18:20:08 +0100731
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100732#ifdef FEAT_FLOAT
733 if (*sp == '-')
Bram Moolenaar56ead342016-02-02 18:20:08 +0100734 {
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100735 ++sp;
Bram Moolenaar56ead342016-02-02 18:20:08 +0100736 if (*sp == NUL)
737 return MAYBE;
738 if (!VIM_ISDIGIT(*sp))
739 return FAIL;
740 }
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100741 sp = skipdigits(sp);
742 if (*sp == '.' || *sp == 'e' || *sp == 'E')
743 {
Bram Moolenaar56ead342016-02-02 18:20:08 +0100744 if (res == NULL)
745 {
746 float_T f;
747
748 len = string2float(p, &f);
749 }
750 else
751 {
752 res->v_type = VAR_FLOAT;
753 len = string2float(p, &res->vval.v_float);
754 }
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100755 }
756 else
757#endif
758 {
759 long nr;
760
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100761 vim_str2nr(reader->js_buf + reader->js_used,
762 NULL, &len, 0, /* what */
763 &nr, NULL, 0);
Bram Moolenaar56ead342016-02-02 18:20:08 +0100764 if (res != NULL)
765 {
766 res->v_type = VAR_NUMBER;
767 res->vval.v_number = nr;
768 }
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100769 }
770 reader->js_used += len;
Bram Moolenaar56ead342016-02-02 18:20:08 +0100771 return OK;
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100772 }
773 if (STRNICMP((char *)p, "false", 5) == 0)
774 {
775 reader->js_used += 5;
Bram Moolenaar56ead342016-02-02 18:20:08 +0100776 if (res != NULL)
777 {
778 res->v_type = VAR_SPECIAL;
779 res->vval.v_number = VVAL_FALSE;
780 }
781 return OK;
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100782 }
783 if (STRNICMP((char *)p, "true", 4) == 0)
784 {
785 reader->js_used += 4;
Bram Moolenaar56ead342016-02-02 18:20:08 +0100786 if (res != NULL)
787 {
788 res->v_type = VAR_SPECIAL;
789 res->vval.v_number = VVAL_TRUE;
790 }
791 return OK;
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100792 }
793 if (STRNICMP((char *)p, "null", 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_NULL;
800 }
801 return OK;
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100802 }
Bram Moolenaarf1b6ac72016-02-23 21:26:43 +0100803#ifdef FEAT_FLOAT
804 if (STRNICMP((char *)p, "NaN", 3) == 0)
805 {
806 reader->js_used += 3;
807 if (res != NULL)
808 {
809 res->v_type = VAR_FLOAT;
Bram Moolenaar3ea0f1a2016-02-23 22:07:32 +0100810 res->vval.v_float = NAN;
Bram Moolenaarf1b6ac72016-02-23 21:26:43 +0100811 }
812 return OK;
813 }
814 if (STRNICMP((char *)p, "Infinity", 8) == 0)
815 {
816 reader->js_used += 8;
817 if (res != NULL)
818 {
819 res->v_type = VAR_FLOAT;
Bram Moolenaar3ea0f1a2016-02-23 22:07:32 +0100820 res->vval.v_float = INFINITY;
Bram Moolenaarf1b6ac72016-02-23 21:26:43 +0100821 }
822 return OK;
823 }
824#endif
Bram Moolenaar56ead342016-02-02 18:20:08 +0100825 /* check for truncated name */
826 len = (int)(reader->js_end - (reader->js_buf + reader->js_used));
Bram Moolenaarf1b6ac72016-02-23 21:26:43 +0100827 if (
828 (len < 5 && STRNICMP((char *)p, "false", len) == 0)
829#ifdef FEAT_FLOAT
830 || (len < 8 && STRNICMP((char *)p, "Infinity", len) == 0)
831 || (len < 3 && STRNICMP((char *)p, "NaN", len) == 0)
832#endif
Bram Moolenaar56ead342016-02-02 18:20:08 +0100833 || (len < 4 && (STRNICMP((char *)p, "true", len) == 0
834 || STRNICMP((char *)p, "null", len) == 0)))
835 return MAYBE;
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100836 break;
837 }
838
Bram Moolenaar56ead342016-02-02 18:20:08 +0100839 if (res != NUL)
840 {
841 res->v_type = VAR_SPECIAL;
842 res->vval.v_number = VVAL_NONE;
843 }
844 return FAIL;
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100845}
846
847/*
848 * Decode the JSON from "reader" and store the result in "res".
Bram Moolenaar595e64e2016-02-07 19:19:53 +0100849 * "options" can be JSON_JS or zero;
Bram Moolenaar56ead342016-02-02 18:20:08 +0100850 * Return FAIL if not the whole message was consumed.
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100851 */
Bram Moolenaar19d2f152016-02-01 21:38:19 +0100852 int
Bram Moolenaar595e64e2016-02-07 19:19:53 +0100853json_decode_all(js_read_T *reader, typval_T *res, int options)
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100854{
Bram Moolenaar56ead342016-02-02 18:20:08 +0100855 int ret;
856
Bram Moolenaar595e64e2016-02-07 19:19:53 +0100857 /* We find the end once, to avoid calling strlen() many times. */
Bram Moolenaar56ead342016-02-02 18:20:08 +0100858 reader->js_end = reader->js_buf + STRLEN(reader->js_buf);
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100859 json_skip_white(reader);
Bram Moolenaar595e64e2016-02-07 19:19:53 +0100860 ret = json_decode_item(reader, res, options);
Bram Moolenaar56ead342016-02-02 18:20:08 +0100861 if (ret != OK)
862 return FAIL;
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100863 json_skip_white(reader);
864 if (reader->js_buf[reader->js_used] != NUL)
Bram Moolenaar19d2f152016-02-01 21:38:19 +0100865 return FAIL;
866 return OK;
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100867}
Bram Moolenaar56ead342016-02-02 18:20:08 +0100868
869/*
870 * Decode the JSON from "reader" and store the result in "res".
Bram Moolenaar595e64e2016-02-07 19:19:53 +0100871 * "options" can be JSON_JS or zero;
Bram Moolenaar56ead342016-02-02 18:20:08 +0100872 * Return FAIL if the message has a decoding error or the message is
873 * truncated. Consumes the message anyway.
874 */
875 int
Bram Moolenaar595e64e2016-02-07 19:19:53 +0100876json_decode(js_read_T *reader, typval_T *res, int options)
Bram Moolenaar56ead342016-02-02 18:20:08 +0100877{
878 int ret;
879
Bram Moolenaar595e64e2016-02-07 19:19:53 +0100880 /* We find the end once, to avoid calling strlen() many times. */
Bram Moolenaar56ead342016-02-02 18:20:08 +0100881 reader->js_end = reader->js_buf + STRLEN(reader->js_buf);
882 json_skip_white(reader);
Bram Moolenaar595e64e2016-02-07 19:19:53 +0100883 ret = json_decode_item(reader, res, options);
Bram Moolenaar56ead342016-02-02 18:20:08 +0100884 json_skip_white(reader);
885
886 return ret == OK ? OK : FAIL;
887}
888
889/*
890 * Decode the JSON from "reader" to find the end of the message.
Bram Moolenaar595e64e2016-02-07 19:19:53 +0100891 * "options" can be JSON_JS or zero;
Bram Moolenaar56ead342016-02-02 18:20:08 +0100892 * Return FAIL if the message has a decoding error.
893 * Return MAYBE if the message is truncated, need to read more.
894 * This only works reliable if the message contains an object, array or
895 * string. A number might be trucated without knowing.
896 * Does not advance the reader.
897 */
898 int
Bram Moolenaar595e64e2016-02-07 19:19:53 +0100899json_find_end(js_read_T *reader, int options)
Bram Moolenaar56ead342016-02-02 18:20:08 +0100900{
901 int used_save = reader->js_used;
902 int ret;
903
Bram Moolenaar595e64e2016-02-07 19:19:53 +0100904 /* We find the end once, to avoid calling strlen() many times. */
Bram Moolenaar56ead342016-02-02 18:20:08 +0100905 reader->js_end = reader->js_buf + STRLEN(reader->js_buf);
906 json_skip_white(reader);
Bram Moolenaar595e64e2016-02-07 19:19:53 +0100907 ret = json_decode_item(reader, NULL, options);
Bram Moolenaar56ead342016-02-02 18:20:08 +0100908 reader->js_used = used_save;
909 return ret;
910}
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100911#endif