blob: a704fd5eb520c40109bfccde356dfab906ff72ca [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
86 convert_setup(&conv, p_enc, (char_u*)"utf-8");
87 if (conv.vc_type != CONV_NONE)
88 converted = res = string_convert(&conv, res, NULL);
89 convert_setup(&conv, NULL, NULL);
90#endif
91
Bram Moolenaar520e1e42016-01-23 19:46:28 +010092 ga_append(gap, '"');
93 while (*res != NUL)
94 {
Bram Moolenaarb6ff8112016-02-27 18:41:27 +010095 int c;
96#ifdef FEAT_MBYTE
97 /* always use utf-8 encoding, ignore 'encoding' */
98 c = utf_ptr2char(res);
99#else
100 c = (int)*(p);
101#endif
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100102
103 switch (c)
104 {
105 case 0x08:
106 ga_append(gap, '\\'); ga_append(gap, 'b'); break;
107 case 0x09:
108 ga_append(gap, '\\'); ga_append(gap, 't'); break;
109 case 0x0a:
110 ga_append(gap, '\\'); ga_append(gap, 'n'); break;
111 case 0x0c:
112 ga_append(gap, '\\'); ga_append(gap, 'f'); break;
113 case 0x0d:
114 ga_append(gap, '\\'); ga_append(gap, 'r'); break;
115 case 0x22: /* " */
116 case 0x5c: /* \ */
117 ga_append(gap, '\\');
118 ga_append(gap, c);
119 break;
120 default:
121 if (c >= 0x20)
122 {
Bram Moolenaarfa06a512016-01-28 22:46:58 +0100123#ifdef FEAT_MBYTE
Bram Moolenaarb6ff8112016-02-27 18:41:27 +0100124 numbuf[utf_char2bytes(c, numbuf)] = NUL;
Bram Moolenaarfa06a512016-01-28 22:46:58 +0100125#else
126 numbuf[0] = c;
127 numbuf[1] = NUL;
128#endif
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100129 ga_concat(gap, numbuf);
130 }
131 else
132 {
133 vim_snprintf((char *)numbuf, NUMBUFLEN,
134 "\\u%04lx", (long)c);
135 ga_concat(gap, numbuf);
136 }
137 }
Bram Moolenaarb6ff8112016-02-27 18:41:27 +0100138#ifdef FEAT_MBYTE
139 res += utf_ptr2len(res);
140#else
141 ++p;
142#endif
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100143 }
144 ga_append(gap, '"');
Bram Moolenaarb6ff8112016-02-27 18:41:27 +0100145#if defined(FEAT_MBYTE) && defined(USE_ICONV)
146 vim_free(converted);
147#endif
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100148 }
149}
150
Bram Moolenaarfcaaae62016-01-24 16:49:11 +0100151/*
Bram Moolenaar595e64e2016-02-07 19:19:53 +0100152 * Return TRUE if "key" can be used without quotes.
153 * That is when it starts with a letter and only contains letters, digits and
154 * underscore.
155 */
156 static int
157is_simple_key(char_u *key)
158{
159 char_u *p;
160
161 if (!ASCII_ISALPHA(*key))
162 return FALSE;
163 for (p = key + 1; *p != NUL; ++p)
164 if (!ASCII_ISALPHA(*p) && *p != '_' && !vim_isdigit(*p))
165 return FALSE;
166 return TRUE;
167}
168
169/*
Bram Moolenaarfcaaae62016-01-24 16:49:11 +0100170 * Encode "val" into "gap".
171 * Return FAIL or OK.
172 */
173 static int
Bram Moolenaar595e64e2016-02-07 19:19:53 +0100174json_encode_item(garray_T *gap, typval_T *val, int copyID, int options)
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100175{
176 char_u numbuf[NUMBUFLEN];
177 char_u *res;
178 list_T *l;
179 dict_T *d;
180
181 switch (val->v_type)
182 {
183 case VAR_SPECIAL:
Bram Moolenaarfcaaae62016-01-24 16:49:11 +0100184 switch (val->vval.v_number)
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100185 {
186 case VVAL_FALSE: ga_concat(gap, (char_u *)"false"); break;
187 case VVAL_TRUE: ga_concat(gap, (char_u *)"true"); break;
Bram Moolenaar595e64e2016-02-07 19:19:53 +0100188 case VVAL_NONE: if ((options & JSON_JS) != 0
189 && (options & JSON_NO_NONE) == 0)
190 /* empty item */
191 break;
192 /* FALLTHROUGH */
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100193 case VVAL_NULL: ga_concat(gap, (char_u *)"null"); break;
194 }
195 break;
196
197 case VAR_NUMBER:
198 vim_snprintf((char *)numbuf, NUMBUFLEN, "%ld",
199 (long)val->vval.v_number);
200 ga_concat(gap, numbuf);
201 break;
202
203 case VAR_STRING:
204 res = val->vval.v_string;
205 write_string(gap, res);
206 break;
207
208 case VAR_FUNC:
Bram Moolenaar55fab432016-02-07 16:53:13 +0100209 case VAR_JOB:
Bram Moolenaar77073442016-02-13 23:23:53 +0100210 case VAR_CHANNEL:
Bram Moolenaar4f8b8fa2016-02-06 18:42:07 +0100211 /* no JSON equivalent TODO: better error */
Bram Moolenaarfcaaae62016-01-24 16:49:11 +0100212 EMSG(_(e_invarg));
213 return FAIL;
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100214
215 case VAR_LIST:
216 l = val->vval.v_list;
217 if (l == NULL)
218 ga_concat(gap, (char_u *)"null");
219 else
220 {
221 if (l->lv_copyID == copyID)
222 ga_concat(gap, (char_u *)"[]");
223 else
224 {
225 listitem_T *li;
226
227 l->lv_copyID = copyID;
228 ga_append(gap, '[');
229 for (li = l->lv_first; li != NULL && !got_int; )
230 {
Bram Moolenaar595e64e2016-02-07 19:19:53 +0100231 if (json_encode_item(gap, &li->li_tv, copyID,
232 options & JSON_JS) == FAIL)
Bram Moolenaarfcaaae62016-01-24 16:49:11 +0100233 return FAIL;
Bram Moolenaar595e64e2016-02-07 19:19:53 +0100234 if ((options & JSON_JS)
235 && li->li_next == NULL
236 && li->li_tv.v_type == VAR_SPECIAL
237 && li->li_tv.vval.v_number == VVAL_NONE)
238 /* add an extra comma if the last item is v:none */
239 ga_append(gap, ',');
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100240 li = li->li_next;
241 if (li != NULL)
242 ga_append(gap, ',');
243 }
244 ga_append(gap, ']');
Bram Moolenaarfcaaae62016-01-24 16:49:11 +0100245 l->lv_copyID = 0;
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100246 }
247 }
248 break;
249
250 case VAR_DICT:
251 d = val->vval.v_dict;
252 if (d == NULL)
253 ga_concat(gap, (char_u *)"null");
254 else
255 {
256 if (d->dv_copyID == copyID)
257 ga_concat(gap, (char_u *)"{}");
258 else
259 {
260 int first = TRUE;
261 int todo = (int)d->dv_hashtab.ht_used;
262 hashitem_T *hi;
263
264 d->dv_copyID = copyID;
265 ga_append(gap, '{');
266
267 for (hi = d->dv_hashtab.ht_array; todo > 0 && !got_int;
268 ++hi)
269 if (!HASHITEM_EMPTY(hi))
270 {
271 --todo;
272 if (first)
273 first = FALSE;
274 else
275 ga_append(gap, ',');
Bram Moolenaar595e64e2016-02-07 19:19:53 +0100276 if ((options & JSON_JS)
277 && is_simple_key(hi->hi_key))
278 ga_concat(gap, hi->hi_key);
279 else
280 write_string(gap, hi->hi_key);
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100281 ga_append(gap, ':');
Bram Moolenaarfcaaae62016-01-24 16:49:11 +0100282 if (json_encode_item(gap, &dict_lookup(hi)->di_tv,
Bram Moolenaar595e64e2016-02-07 19:19:53 +0100283 copyID, options | JSON_NO_NONE) == FAIL)
Bram Moolenaarfcaaae62016-01-24 16:49:11 +0100284 return FAIL;
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100285 }
286 ga_append(gap, '}');
Bram Moolenaarfcaaae62016-01-24 16:49:11 +0100287 d->dv_copyID = 0;
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100288 }
289 }
290 break;
291
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100292 case VAR_FLOAT:
Bram Moolenaar55fab432016-02-07 16:53:13 +0100293#ifdef FEAT_FLOAT
Bram Moolenaarf1b6ac72016-02-23 21:26:43 +0100294# if defined(HAVE_MATH_H)
Bram Moolenaar7ce686c2016-02-27 16:33:22 +0100295 if (isnan(val->vval.v_float))
Bram Moolenaarf1b6ac72016-02-23 21:26:43 +0100296 ga_concat(gap, (char_u *)"NaN");
Bram Moolenaar7ce686c2016-02-27 16:33:22 +0100297 else if (isinf(val->vval.v_float))
Bram Moolenaarf1b6ac72016-02-23 21:26:43 +0100298 ga_concat(gap, (char_u *)"Infinity");
Bram Moolenaarf1b6ac72016-02-23 21:26:43 +0100299 else
300# endif
301 {
302 vim_snprintf((char *)numbuf, NUMBUFLEN, "%g",
303 val->vval.v_float);
304 ga_concat(gap, numbuf);
305 }
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100306 break;
307#endif
Bram Moolenaar55fab432016-02-07 16:53:13 +0100308 case VAR_UNKNOWN:
Bram Moolenaarc6b14f02016-02-20 15:26:42 +0100309 EMSG2(_(e_intern2), "json_encode_item()");
Bram Moolenaar55fab432016-02-07 16:53:13 +0100310 return FAIL;
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100311 }
Bram Moolenaarfcaaae62016-01-24 16:49:11 +0100312 return OK;
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100313}
314
315/*
Bram Moolenaar56ead342016-02-02 18:20:08 +0100316 * When "reader" has less than NUMBUFLEN bytes available, call the fill
317 * callback to get more.
318 */
319 static void
320fill_numbuflen(js_read_T *reader)
321{
322 if (reader->js_fill != NULL && (int)(reader->js_end - reader->js_buf)
323 - reader->js_used < NUMBUFLEN)
324 {
325 if (reader->js_fill(reader))
326 reader->js_end = reader->js_buf + STRLEN(reader->js_buf);
327 }
328}
329
330/*
Bram Moolenaar595e64e2016-02-07 19:19:53 +0100331 * Skip white space in "reader". All characters <= space are considered white
332 * space.
Bram Moolenaar56ead342016-02-02 18:20:08 +0100333 * Also tops up readahead when needed.
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100334 */
335 static void
336json_skip_white(js_read_T *reader)
337{
338 int c;
339
Bram Moolenaar56ead342016-02-02 18:20:08 +0100340 for (;;)
341 {
342 c = reader->js_buf[reader->js_used];
343 if (reader->js_fill != NULL && c == NUL)
344 {
345 if (reader->js_fill(reader))
346 reader->js_end = reader->js_buf + STRLEN(reader->js_buf);
347 continue;
348 }
Bram Moolenaar595e64e2016-02-07 19:19:53 +0100349 if (c == NUL || c > ' ')
Bram Moolenaar56ead342016-02-02 18:20:08 +0100350 break;
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100351 ++reader->js_used;
Bram Moolenaar56ead342016-02-02 18:20:08 +0100352 }
353 fill_numbuflen(reader);
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100354}
355
Bram Moolenaar56ead342016-02-02 18:20:08 +0100356 static int
Bram Moolenaar595e64e2016-02-07 19:19:53 +0100357json_decode_array(js_read_T *reader, typval_T *res, int options)
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100358{
359 char_u *p;
360 typval_T item;
361 listitem_T *li;
Bram Moolenaar56ead342016-02-02 18:20:08 +0100362 int ret;
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100363
Bram Moolenaar56ead342016-02-02 18:20:08 +0100364 if (res != NULL && rettv_list_alloc(res) == FAIL)
365 {
366 res->v_type = VAR_SPECIAL;
367 res->vval.v_number = VVAL_NONE;
368 return FAIL;
369 }
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100370 ++reader->js_used; /* consume the '[' */
371
372 while (TRUE)
373 {
374 json_skip_white(reader);
375 p = reader->js_buf + reader->js_used;
376 if (*p == NUL)
Bram Moolenaar56ead342016-02-02 18:20:08 +0100377 return MAYBE;
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100378 if (*p == ']')
379 {
380 ++reader->js_used; /* consume the ']' */
Bram Moolenaar56ead342016-02-02 18:20:08 +0100381 break;
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100382 }
383
Bram Moolenaar595e64e2016-02-07 19:19:53 +0100384 ret = json_decode_item(reader, res == NULL ? NULL : &item, options);
Bram Moolenaar56ead342016-02-02 18:20:08 +0100385 if (ret != OK)
386 return ret;
387 if (res != NULL)
388 {
389 li = listitem_alloc();
390 if (li == NULL)
391 {
392 clear_tv(&item);
393 return FAIL;
394 }
395 li->li_tv = item;
396 list_append(res->vval.v_list, li);
397 }
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100398
399 json_skip_white(reader);
400 p = reader->js_buf + reader->js_used;
401 if (*p == ',')
402 ++reader->js_used;
403 else if (*p != ']')
Bram Moolenaar56ead342016-02-02 18:20:08 +0100404 {
405 if (*p == NUL)
406 return MAYBE;
407 return FAIL;
408 }
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100409 }
Bram Moolenaar56ead342016-02-02 18:20:08 +0100410 return OK;
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100411}
412
Bram Moolenaar56ead342016-02-02 18:20:08 +0100413 static int
Bram Moolenaar595e64e2016-02-07 19:19:53 +0100414json_decode_object(js_read_T *reader, typval_T *res, int options)
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100415{
416 char_u *p;
417 typval_T tvkey;
418 typval_T item;
419 dictitem_T *di;
420 char_u buf[NUMBUFLEN];
Bram Moolenaarfbf9c6b2016-02-02 19:43:57 +0100421 char_u *key = NULL;
Bram Moolenaar56ead342016-02-02 18:20:08 +0100422 int ret;
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100423
Bram Moolenaar56ead342016-02-02 18:20:08 +0100424 if (res != NULL && rettv_dict_alloc(res) == FAIL)
425 {
426 res->v_type = VAR_SPECIAL;
427 res->vval.v_number = VVAL_NONE;
428 return FAIL;
429 }
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100430 ++reader->js_used; /* consume the '{' */
431
432 while (TRUE)
433 {
434 json_skip_white(reader);
435 p = reader->js_buf + reader->js_used;
436 if (*p == NUL)
Bram Moolenaar56ead342016-02-02 18:20:08 +0100437 return MAYBE;
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100438 if (*p == '}')
439 {
440 ++reader->js_used; /* consume the '}' */
Bram Moolenaar56ead342016-02-02 18:20:08 +0100441 break;
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100442 }
443
Bram Moolenaar595e64e2016-02-07 19:19:53 +0100444 if ((options & JSON_JS) && reader->js_buf[reader->js_used] != '"')
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100445 {
Bram Moolenaar595e64e2016-02-07 19:19:53 +0100446 /* accept a key that is not in quotes */
447 key = p = reader->js_buf + reader->js_used;
448 while (*p != NUL && *p != ':' && *p > ' ')
449 ++p;
450 tvkey.v_type = VAR_STRING;
451 tvkey.vval.v_string = vim_strnsave(key, (int)(p - key));
452 reader->js_used += (int)(p - key);
453 key = tvkey.vval.v_string;
454 }
455 else
456 {
457 ret = json_decode_item(reader, res == NULL ? NULL : &tvkey,
458 options);
459 if (ret != OK)
460 return ret;
461 if (res != NULL)
Bram Moolenaar56ead342016-02-02 18:20:08 +0100462 {
Bram Moolenaar595e64e2016-02-07 19:19:53 +0100463 key = get_tv_string_buf_chk(&tvkey, buf);
464 if (key == NULL || *key == NUL)
465 {
466 clear_tv(&tvkey);
467 return FAIL;
468 }
Bram Moolenaar56ead342016-02-02 18:20:08 +0100469 }
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100470 }
471
472 json_skip_white(reader);
473 p = reader->js_buf + reader->js_used;
474 if (*p != ':')
475 {
Bram Moolenaar56ead342016-02-02 18:20:08 +0100476 if (res != NULL)
477 clear_tv(&tvkey);
478 if (*p == NUL)
479 return MAYBE;
480 return FAIL;
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100481 }
482 ++reader->js_used;
483 json_skip_white(reader);
484
Bram Moolenaar595e64e2016-02-07 19:19:53 +0100485 ret = json_decode_item(reader, res == NULL ? NULL : &item, options);
Bram Moolenaar56ead342016-02-02 18:20:08 +0100486 if (ret != OK)
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100487 {
Bram Moolenaar56ead342016-02-02 18:20:08 +0100488 if (res != NULL)
489 clear_tv(&tvkey);
490 return ret;
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100491 }
Bram Moolenaar56ead342016-02-02 18:20:08 +0100492
493 if (res != NULL)
494 {
495 di = dictitem_alloc(key);
496 clear_tv(&tvkey);
497 if (di == NULL)
498 {
499 clear_tv(&item);
500 return FAIL;
501 }
502 di->di_tv = item;
503 if (dict_add(res->vval.v_dict, di) == FAIL)
504 {
505 dictitem_free(di);
506 return FAIL;
507 }
508 }
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100509
510 json_skip_white(reader);
511 p = reader->js_buf + reader->js_used;
512 if (*p == ',')
513 ++reader->js_used;
514 else if (*p != '}')
Bram Moolenaar56ead342016-02-02 18:20:08 +0100515 {
516 if (*p == NUL)
517 return MAYBE;
518 return FAIL;
519 }
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100520 }
Bram Moolenaar56ead342016-02-02 18:20:08 +0100521 return OK;
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100522}
523
Bram Moolenaar56ead342016-02-02 18:20:08 +0100524 static int
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100525json_decode_string(js_read_T *reader, typval_T *res)
526{
527 garray_T ga;
528 int len;
Bram Moolenaar56ead342016-02-02 18:20:08 +0100529 char_u *p;
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100530 int c;
531 long nr;
532 char_u buf[NUMBUFLEN];
Bram Moolenaarb6ff8112016-02-27 18:41:27 +0100533#if defined(FEAT_MBYTE) && defined(USE_ICONV)
534 vimconv_T conv;
535 char_u *converted = NULL;
536#endif
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100537
Bram Moolenaar56ead342016-02-02 18:20:08 +0100538 if (res != NULL)
539 ga_init2(&ga, 1, 200);
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100540
Bram Moolenaar56ead342016-02-02 18:20:08 +0100541 p = reader->js_buf + reader->js_used + 1; /* skip over " */
Bram Moolenaarb6ff8112016-02-27 18:41:27 +0100542#if defined(FEAT_MBYTE) && defined(USE_ICONV)
543 convert_setup(&conv, (char_u*)"utf-8", p_enc);
544 if (conv.vc_type != CONV_NONE)
545 converted = p = string_convert(&conv, p, NULL);
546 convert_setup(&conv, NULL, NULL);
547#endif
Bram Moolenaar56ead342016-02-02 18:20:08 +0100548 while (*p != '"')
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100549 {
Bram Moolenaar56ead342016-02-02 18:20:08 +0100550 if (*p == NUL || p[1] == NUL
551#ifdef FEAT_MBYTE
552 || utf_ptr2len(p) < utf_byte2len(*p)
553#endif
554 )
555 {
556 if (reader->js_fill == NULL)
557 break;
558 len = (int)(reader->js_end - p);
559 reader->js_used = (int)(p - reader->js_buf);
560 if (!reader->js_fill(reader))
561 break; /* didn't get more */
562 p = reader->js_buf + reader->js_used;
563 reader->js_end = reader->js_buf + STRLEN(reader->js_buf);
564 continue;
565 }
566
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100567 if (*p == '\\')
568 {
569 c = -1;
570 switch (p[1])
571 {
Bram Moolenaar56ead342016-02-02 18:20:08 +0100572 case '\\': c = '\\'; break;
573 case '"': c = '"'; break;
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100574 case 'b': c = BS; break;
575 case 't': c = TAB; break;
576 case 'n': c = NL; break;
577 case 'f': c = FF; break;
578 case 'r': c = CAR; break;
579 case 'u':
Bram Moolenaar56ead342016-02-02 18:20:08 +0100580 if (reader->js_fill != NULL
581 && (int)(reader->js_end - p) < NUMBUFLEN)
582 {
583 reader->js_used = (int)(p - reader->js_buf);
584 if (reader->js_fill(reader))
585 {
586 p = reader->js_buf + reader->js_used;
587 reader->js_end = reader->js_buf
588 + STRLEN(reader->js_buf);
589 }
590 }
Bram Moolenaarb6ff8112016-02-27 18:41:27 +0100591 nr = 0;
592 len = 0;
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100593 vim_str2nr(p + 2, NULL, &len,
594 STR2NR_HEX + STR2NR_FORCE, &nr, NULL, 4);
595 p += len + 2;
Bram Moolenaarb6ff8112016-02-27 18:41:27 +0100596 if (0xd800 <= nr && nr <= 0xdfff
597 && (int)(reader->js_end - p) >= 6
598 && *p == '\\' && *(p+1) == 'u')
599 {
600 long nr2 = 0;
601
602 /* decode surrogate pair: \ud812\u3456 */
603 len = 0;
604 vim_str2nr(p + 2, NULL, &len,
605 STR2NR_HEX + STR2NR_FORCE, &nr2, NULL, 4);
606 if (0xdc00 <= nr2 && nr2 <= 0xdfff)
607 {
608 p += len + 2;
609 nr = (((nr - 0xd800) << 10) |
610 ((nr2 - 0xdc00) & 0x3ff)) + 0x10000;
611 }
612 }
Bram Moolenaar56ead342016-02-02 18:20:08 +0100613 if (res != NULL)
614 {
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100615#ifdef FEAT_MBYTE
Bram Moolenaarb6ff8112016-02-27 18:41:27 +0100616 buf[utf_char2bytes((int)nr, buf)] = NUL;
Bram Moolenaar56ead342016-02-02 18:20:08 +0100617 ga_concat(&ga, buf);
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100618#else
Bram Moolenaar56ead342016-02-02 18:20:08 +0100619 ga_append(&ga, nr);
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100620#endif
Bram Moolenaar56ead342016-02-02 18:20:08 +0100621 }
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100622 break;
Bram Moolenaar56ead342016-02-02 18:20:08 +0100623 default:
624 /* not a special char, skip over \ */
625 ++p;
626 continue;
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100627 }
628 if (c > 0)
629 {
630 p += 2;
Bram Moolenaar56ead342016-02-02 18:20:08 +0100631 if (res != NULL)
632 ga_append(&ga, c);
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100633 }
634 }
635 else
636 {
Bram Moolenaarb6ff8112016-02-27 18:41:27 +0100637#ifdef FEAT_MBYTE
638 len = utf_ptr2len(p);
639#else
640 len = 1;
641#endif
Bram Moolenaar56ead342016-02-02 18:20:08 +0100642 if (res != NULL)
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100643 {
Bram Moolenaar56ead342016-02-02 18:20:08 +0100644 if (ga_grow(&ga, len) == FAIL)
645 {
646 ga_clear(&ga);
Bram Moolenaarb6ff8112016-02-27 18:41:27 +0100647#if defined(FEAT_MBYTE) && defined(USE_ICONV)
648 vim_free(converted);
649#endif
Bram Moolenaar56ead342016-02-02 18:20:08 +0100650 return FAIL;
651 }
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100652 mch_memmove((char *)ga.ga_data + ga.ga_len, p, (size_t)len);
653 ga.ga_len += len;
654 }
655 p += len;
656 }
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100657 }
Bram Moolenaarb6ff8112016-02-27 18:41:27 +0100658#if defined(FEAT_MBYTE) && defined(USE_ICONV)
659 vim_free(converted);
660#endif
Bram Moolenaar56ead342016-02-02 18:20:08 +0100661
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100662 reader->js_used = (int)(p - reader->js_buf);
663 if (*p == '"')
664 {
665 ++reader->js_used;
Bram Moolenaar56ead342016-02-02 18:20:08 +0100666 if (res != NULL)
667 {
668 res->v_type = VAR_STRING;
Bram Moolenaar4b6a6dc2016-02-04 22:49:49 +0100669 res->vval.v_string = ga.ga_data;
Bram Moolenaar56ead342016-02-02 18:20:08 +0100670 }
671 return OK;
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100672 }
Bram Moolenaar56ead342016-02-02 18:20:08 +0100673 if (res != NULL)
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100674 {
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100675 res->v_type = VAR_SPECIAL;
676 res->vval.v_number = VVAL_NONE;
Bram Moolenaar56ead342016-02-02 18:20:08 +0100677 ga_clear(&ga);
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100678 }
Bram Moolenaar56ead342016-02-02 18:20:08 +0100679 return MAYBE;
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100680}
681
682/*
Bram Moolenaar56ead342016-02-02 18:20:08 +0100683 * Decode one item and put it in "res". If "res" is NULL only advance.
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100684 * Must already have skipped white space.
Bram Moolenaar56ead342016-02-02 18:20:08 +0100685 *
686 * Return FAIL for a decoding error.
687 * Return MAYBE for an incomplete message.
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100688 */
Bram Moolenaar56ead342016-02-02 18:20:08 +0100689 static int
Bram Moolenaar595e64e2016-02-07 19:19:53 +0100690json_decode_item(js_read_T *reader, typval_T *res, int options)
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100691{
Bram Moolenaar56ead342016-02-02 18:20:08 +0100692 char_u *p;
693 int len;
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100694
Bram Moolenaar56ead342016-02-02 18:20:08 +0100695 fill_numbuflen(reader);
696 p = reader->js_buf + reader->js_used;
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100697 switch (*p)
698 {
699 case '[': /* array */
Bram Moolenaar595e64e2016-02-07 19:19:53 +0100700 return json_decode_array(reader, res, options);
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100701
702 case '{': /* object */
Bram Moolenaar595e64e2016-02-07 19:19:53 +0100703 return json_decode_object(reader, res, options);
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100704
705 case '"': /* string */
Bram Moolenaar56ead342016-02-02 18:20:08 +0100706 return json_decode_string(reader, res);
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100707
708 case ',': /* comma: empty item */
Bram Moolenaar595e64e2016-02-07 19:19:53 +0100709 if ((options & JSON_JS) == 0)
710 return FAIL;
711 /* FALLTHROUGH */
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100712 case NUL: /* empty */
Bram Moolenaar56ead342016-02-02 18:20:08 +0100713 if (res != NULL)
714 {
715 res->v_type = VAR_SPECIAL;
716 res->vval.v_number = VVAL_NONE;
717 }
718 return OK;
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100719
720 default:
721 if (VIM_ISDIGIT(*p) || *p == '-')
722 {
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100723 char_u *sp = p;
Bram Moolenaar56ead342016-02-02 18:20:08 +0100724
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100725#ifdef FEAT_FLOAT
726 if (*sp == '-')
Bram Moolenaar56ead342016-02-02 18:20:08 +0100727 {
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100728 ++sp;
Bram Moolenaar56ead342016-02-02 18:20:08 +0100729 if (*sp == NUL)
730 return MAYBE;
731 if (!VIM_ISDIGIT(*sp))
732 return FAIL;
733 }
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100734 sp = skipdigits(sp);
735 if (*sp == '.' || *sp == 'e' || *sp == 'E')
736 {
Bram Moolenaar56ead342016-02-02 18:20:08 +0100737 if (res == NULL)
738 {
739 float_T f;
740
741 len = string2float(p, &f);
742 }
743 else
744 {
745 res->v_type = VAR_FLOAT;
746 len = string2float(p, &res->vval.v_float);
747 }
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100748 }
749 else
750#endif
751 {
752 long nr;
753
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100754 vim_str2nr(reader->js_buf + reader->js_used,
755 NULL, &len, 0, /* what */
756 &nr, NULL, 0);
Bram Moolenaar56ead342016-02-02 18:20:08 +0100757 if (res != NULL)
758 {
759 res->v_type = VAR_NUMBER;
760 res->vval.v_number = nr;
761 }
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100762 }
763 reader->js_used += len;
Bram Moolenaar56ead342016-02-02 18:20:08 +0100764 return OK;
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100765 }
766 if (STRNICMP((char *)p, "false", 5) == 0)
767 {
768 reader->js_used += 5;
Bram Moolenaar56ead342016-02-02 18:20:08 +0100769 if (res != NULL)
770 {
771 res->v_type = VAR_SPECIAL;
772 res->vval.v_number = VVAL_FALSE;
773 }
774 return OK;
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100775 }
776 if (STRNICMP((char *)p, "true", 4) == 0)
777 {
778 reader->js_used += 4;
Bram Moolenaar56ead342016-02-02 18:20:08 +0100779 if (res != NULL)
780 {
781 res->v_type = VAR_SPECIAL;
782 res->vval.v_number = VVAL_TRUE;
783 }
784 return OK;
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100785 }
786 if (STRNICMP((char *)p, "null", 4) == 0)
787 {
788 reader->js_used += 4;
Bram Moolenaar56ead342016-02-02 18:20:08 +0100789 if (res != NULL)
790 {
791 res->v_type = VAR_SPECIAL;
792 res->vval.v_number = VVAL_NULL;
793 }
794 return OK;
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100795 }
Bram Moolenaarf1b6ac72016-02-23 21:26:43 +0100796#ifdef FEAT_FLOAT
797 if (STRNICMP((char *)p, "NaN", 3) == 0)
798 {
799 reader->js_used += 3;
800 if (res != NULL)
801 {
802 res->v_type = VAR_FLOAT;
Bram Moolenaar3ea0f1a2016-02-23 22:07:32 +0100803 res->vval.v_float = NAN;
Bram Moolenaarf1b6ac72016-02-23 21:26:43 +0100804 }
805 return OK;
806 }
807 if (STRNICMP((char *)p, "Infinity", 8) == 0)
808 {
809 reader->js_used += 8;
810 if (res != NULL)
811 {
812 res->v_type = VAR_FLOAT;
Bram Moolenaar3ea0f1a2016-02-23 22:07:32 +0100813 res->vval.v_float = INFINITY;
Bram Moolenaarf1b6ac72016-02-23 21:26:43 +0100814 }
815 return OK;
816 }
817#endif
Bram Moolenaar56ead342016-02-02 18:20:08 +0100818 /* check for truncated name */
819 len = (int)(reader->js_end - (reader->js_buf + reader->js_used));
Bram Moolenaarf1b6ac72016-02-23 21:26:43 +0100820 if (
821 (len < 5 && STRNICMP((char *)p, "false", len) == 0)
822#ifdef FEAT_FLOAT
823 || (len < 8 && STRNICMP((char *)p, "Infinity", len) == 0)
824 || (len < 3 && STRNICMP((char *)p, "NaN", len) == 0)
825#endif
Bram Moolenaar56ead342016-02-02 18:20:08 +0100826 || (len < 4 && (STRNICMP((char *)p, "true", len) == 0
827 || STRNICMP((char *)p, "null", len) == 0)))
828 return MAYBE;
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100829 break;
830 }
831
Bram Moolenaar56ead342016-02-02 18:20:08 +0100832 if (res != NUL)
833 {
834 res->v_type = VAR_SPECIAL;
835 res->vval.v_number = VVAL_NONE;
836 }
837 return FAIL;
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100838}
839
840/*
841 * Decode the JSON from "reader" and store the result in "res".
Bram Moolenaar595e64e2016-02-07 19:19:53 +0100842 * "options" can be JSON_JS or zero;
Bram Moolenaar56ead342016-02-02 18:20:08 +0100843 * Return FAIL if not the whole message was consumed.
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100844 */
Bram Moolenaar19d2f152016-02-01 21:38:19 +0100845 int
Bram Moolenaar595e64e2016-02-07 19:19:53 +0100846json_decode_all(js_read_T *reader, typval_T *res, int options)
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100847{
Bram Moolenaar56ead342016-02-02 18:20:08 +0100848 int ret;
849
Bram Moolenaar595e64e2016-02-07 19:19:53 +0100850 /* We find the end once, to avoid calling strlen() many times. */
Bram Moolenaar56ead342016-02-02 18:20:08 +0100851 reader->js_end = reader->js_buf + STRLEN(reader->js_buf);
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100852 json_skip_white(reader);
Bram Moolenaar595e64e2016-02-07 19:19:53 +0100853 ret = json_decode_item(reader, res, options);
Bram Moolenaar56ead342016-02-02 18:20:08 +0100854 if (ret != OK)
855 return FAIL;
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100856 json_skip_white(reader);
857 if (reader->js_buf[reader->js_used] != NUL)
Bram Moolenaar19d2f152016-02-01 21:38:19 +0100858 return FAIL;
859 return OK;
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100860}
Bram Moolenaar56ead342016-02-02 18:20:08 +0100861
862/*
863 * Decode the JSON from "reader" and store the result in "res".
Bram Moolenaar595e64e2016-02-07 19:19:53 +0100864 * "options" can be JSON_JS or zero;
Bram Moolenaar56ead342016-02-02 18:20:08 +0100865 * Return FAIL if the message has a decoding error or the message is
866 * truncated. Consumes the message anyway.
867 */
868 int
Bram Moolenaar595e64e2016-02-07 19:19:53 +0100869json_decode(js_read_T *reader, typval_T *res, int options)
Bram Moolenaar56ead342016-02-02 18:20:08 +0100870{
871 int ret;
872
Bram Moolenaar595e64e2016-02-07 19:19:53 +0100873 /* We find the end once, to avoid calling strlen() many times. */
Bram Moolenaar56ead342016-02-02 18:20:08 +0100874 reader->js_end = reader->js_buf + STRLEN(reader->js_buf);
875 json_skip_white(reader);
Bram Moolenaar595e64e2016-02-07 19:19:53 +0100876 ret = json_decode_item(reader, res, options);
Bram Moolenaar56ead342016-02-02 18:20:08 +0100877 json_skip_white(reader);
878
879 return ret == OK ? OK : FAIL;
880}
881
882/*
883 * Decode the JSON from "reader" to find the end of the message.
Bram Moolenaar595e64e2016-02-07 19:19:53 +0100884 * "options" can be JSON_JS or zero;
Bram Moolenaar56ead342016-02-02 18:20:08 +0100885 * Return FAIL if the message has a decoding error.
886 * Return MAYBE if the message is truncated, need to read more.
887 * This only works reliable if the message contains an object, array or
888 * string. A number might be trucated without knowing.
889 * Does not advance the reader.
890 */
891 int
Bram Moolenaar595e64e2016-02-07 19:19:53 +0100892json_find_end(js_read_T *reader, int options)
Bram Moolenaar56ead342016-02-02 18:20:08 +0100893{
894 int used_save = reader->js_used;
895 int ret;
896
Bram Moolenaar595e64e2016-02-07 19:19:53 +0100897 /* We find the end once, to avoid calling strlen() many times. */
Bram Moolenaar56ead342016-02-02 18:20:08 +0100898 reader->js_end = reader->js_buf + STRLEN(reader->js_buf);
899 json_skip_white(reader);
Bram Moolenaar595e64e2016-02-07 19:19:53 +0100900 ret = json_decode_item(reader, NULL, options);
Bram Moolenaar56ead342016-02-02 18:20:08 +0100901 reader->js_used = used_save;
902 return ret;
903}
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100904#endif