blob: 17eed4fa1094ab8d5d1cbd78e42778dee8b2472e [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 Moolenaar4f8b8fa2016-02-06 18:42:07 +010019static int json_encode_item(garray_T *gap, typval_T *val, int copyID, int allow_none);
Bram Moolenaar56ead342016-02-02 18:20:08 +010020static int json_decode_item(js_read_T *reader, typval_T *res);
Bram Moolenaar520e1e42016-01-23 19:46:28 +010021
22/*
23 * Encode "val" into a JSON format string.
Bram Moolenaar55fab432016-02-07 16:53:13 +010024 * The result is in allocated memory.
25 * The result is empty when encoding fails.
Bram Moolenaar520e1e42016-01-23 19:46:28 +010026 */
27 char_u *
28json_encode(typval_T *val)
29{
30 garray_T ga;
31
32 /* Store bytes in the growarray. */
33 ga_init2(&ga, 1, 4000);
Bram Moolenaar55fab432016-02-07 16:53:13 +010034 if (json_encode_item(&ga, val, get_copyID(), TRUE) == FAIL)
35 {
36 vim_free(ga.ga_data);
37 return vim_strsave((char_u *)"");
38 }
Bram Moolenaar520e1e42016-01-23 19:46:28 +010039 return ga.ga_data;
40}
41
Bram Moolenaarfb1f6262016-01-31 20:24:32 +010042/*
Bram Moolenaar55fab432016-02-07 16:53:13 +010043 * Encode ["nr", "val"] into a JSON format string in allocated memory.
Bram Moolenaarfb1f6262016-01-31 20:24:32 +010044 * Returns NULL when out of memory.
45 */
46 char_u *
47json_encode_nr_expr(int nr, typval_T *val)
48{
49 typval_T listtv;
50 typval_T nrtv;
51 char_u *text;
52
53 nrtv.v_type = VAR_NUMBER;
54 nrtv.vval.v_number = nr;
55 if (rettv_list_alloc(&listtv) == FAIL)
56 return NULL;
57 if (list_append_tv(listtv.vval.v_list, &nrtv) == FAIL
58 || list_append_tv(listtv.vval.v_list, val) == FAIL)
59 {
60 list_unref(listtv.vval.v_list);
61 return NULL;
62 }
63
64 text = json_encode(&listtv);
65 list_unref(listtv.vval.v_list);
66 return text;
67}
68
Bram Moolenaar520e1e42016-01-23 19:46:28 +010069 static void
70write_string(garray_T *gap, char_u *str)
71{
72 char_u *res = str;
73 char_u numbuf[NUMBUFLEN];
74
75 if (res == NULL)
76 ga_concat(gap, (char_u *)"null");
77 else
78 {
79 ga_append(gap, '"');
80 while (*res != NUL)
81 {
82 int c = PTR2CHAR(res);
83
84 switch (c)
85 {
86 case 0x08:
87 ga_append(gap, '\\'); ga_append(gap, 'b'); break;
88 case 0x09:
89 ga_append(gap, '\\'); ga_append(gap, 't'); break;
90 case 0x0a:
91 ga_append(gap, '\\'); ga_append(gap, 'n'); break;
92 case 0x0c:
93 ga_append(gap, '\\'); ga_append(gap, 'f'); break;
94 case 0x0d:
95 ga_append(gap, '\\'); ga_append(gap, 'r'); break;
96 case 0x22: /* " */
97 case 0x5c: /* \ */
98 ga_append(gap, '\\');
99 ga_append(gap, c);
100 break;
101 default:
102 if (c >= 0x20)
103 {
Bram Moolenaarfa06a512016-01-28 22:46:58 +0100104#ifdef FEAT_MBYTE
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100105 numbuf[mb_char2bytes(c, numbuf)] = NUL;
Bram Moolenaarfa06a512016-01-28 22:46:58 +0100106#else
107 numbuf[0] = c;
108 numbuf[1] = NUL;
109#endif
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100110 ga_concat(gap, numbuf);
111 }
112 else
113 {
114 vim_snprintf((char *)numbuf, NUMBUFLEN,
115 "\\u%04lx", (long)c);
116 ga_concat(gap, numbuf);
117 }
118 }
119 mb_cptr_adv(res);
120 }
121 ga_append(gap, '"');
122 }
123}
124
Bram Moolenaarfcaaae62016-01-24 16:49:11 +0100125/*
126 * Encode "val" into "gap".
127 * Return FAIL or OK.
128 */
129 static int
Bram Moolenaar4f8b8fa2016-02-06 18:42:07 +0100130json_encode_item(garray_T *gap, typval_T *val, int copyID, int allow_none)
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100131{
132 char_u numbuf[NUMBUFLEN];
133 char_u *res;
134 list_T *l;
135 dict_T *d;
136
137 switch (val->v_type)
138 {
139 case VAR_SPECIAL:
Bram Moolenaarfcaaae62016-01-24 16:49:11 +0100140 switch (val->vval.v_number)
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100141 {
142 case VVAL_FALSE: ga_concat(gap, (char_u *)"false"); break;
143 case VVAL_TRUE: ga_concat(gap, (char_u *)"true"); break;
Bram Moolenaar4f8b8fa2016-02-06 18:42:07 +0100144 case VVAL_NONE: if (!allow_none)
Bram Moolenaar55fab432016-02-07 16:53:13 +0100145 {
Bram Moolenaar4f8b8fa2016-02-06 18:42:07 +0100146 /* TODO: better error */
147 EMSG(_(e_invarg));
Bram Moolenaar55fab432016-02-07 16:53:13 +0100148 return FAIL;
149 }
Bram Moolenaar4f8b8fa2016-02-06 18:42:07 +0100150 break;
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100151 case VVAL_NULL: ga_concat(gap, (char_u *)"null"); break;
152 }
153 break;
154
155 case VAR_NUMBER:
156 vim_snprintf((char *)numbuf, NUMBUFLEN, "%ld",
157 (long)val->vval.v_number);
158 ga_concat(gap, numbuf);
159 break;
160
161 case VAR_STRING:
162 res = val->vval.v_string;
163 write_string(gap, res);
164 break;
165
166 case VAR_FUNC:
Bram Moolenaar55fab432016-02-07 16:53:13 +0100167 case VAR_JOB:
Bram Moolenaar4f8b8fa2016-02-06 18:42:07 +0100168 /* no JSON equivalent TODO: better error */
Bram Moolenaarfcaaae62016-01-24 16:49:11 +0100169 EMSG(_(e_invarg));
170 return FAIL;
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100171
172 case VAR_LIST:
173 l = val->vval.v_list;
174 if (l == NULL)
175 ga_concat(gap, (char_u *)"null");
176 else
177 {
178 if (l->lv_copyID == copyID)
179 ga_concat(gap, (char_u *)"[]");
180 else
181 {
182 listitem_T *li;
183
184 l->lv_copyID = copyID;
185 ga_append(gap, '[');
186 for (li = l->lv_first; li != NULL && !got_int; )
187 {
Bram Moolenaar4f8b8fa2016-02-06 18:42:07 +0100188 if (json_encode_item(gap, &li->li_tv, copyID, TRUE)
189 == FAIL)
Bram Moolenaarfcaaae62016-01-24 16:49:11 +0100190 return FAIL;
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100191 li = li->li_next;
192 if (li != NULL)
193 ga_append(gap, ',');
194 }
195 ga_append(gap, ']');
Bram Moolenaarfcaaae62016-01-24 16:49:11 +0100196 l->lv_copyID = 0;
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100197 }
198 }
199 break;
200
201 case VAR_DICT:
202 d = val->vval.v_dict;
203 if (d == NULL)
204 ga_concat(gap, (char_u *)"null");
205 else
206 {
207 if (d->dv_copyID == copyID)
208 ga_concat(gap, (char_u *)"{}");
209 else
210 {
211 int first = TRUE;
212 int todo = (int)d->dv_hashtab.ht_used;
213 hashitem_T *hi;
214
215 d->dv_copyID = copyID;
216 ga_append(gap, '{');
217
218 for (hi = d->dv_hashtab.ht_array; todo > 0 && !got_int;
219 ++hi)
220 if (!HASHITEM_EMPTY(hi))
221 {
222 --todo;
223 if (first)
224 first = FALSE;
225 else
226 ga_append(gap, ',');
227 write_string(gap, hi->hi_key);
228 ga_append(gap, ':');
Bram Moolenaarfcaaae62016-01-24 16:49:11 +0100229 if (json_encode_item(gap, &dict_lookup(hi)->di_tv,
Bram Moolenaar4f8b8fa2016-02-06 18:42:07 +0100230 copyID, FALSE) == FAIL)
Bram Moolenaarfcaaae62016-01-24 16:49:11 +0100231 return FAIL;
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100232 }
233 ga_append(gap, '}');
Bram Moolenaarfcaaae62016-01-24 16:49:11 +0100234 d->dv_copyID = 0;
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100235 }
236 }
237 break;
238
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100239 case VAR_FLOAT:
Bram Moolenaar55fab432016-02-07 16:53:13 +0100240#ifdef FEAT_FLOAT
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100241 vim_snprintf((char *)numbuf, NUMBUFLEN, "%g", val->vval.v_float);
242 ga_concat(gap, numbuf);
243 break;
244#endif
Bram Moolenaar55fab432016-02-07 16:53:13 +0100245 case VAR_UNKNOWN:
246 EMSG2(_(e_intern2), "json_encode_item()"); break;
247 return FAIL;
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100248 }
Bram Moolenaarfcaaae62016-01-24 16:49:11 +0100249 return OK;
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100250}
251
252/*
Bram Moolenaar56ead342016-02-02 18:20:08 +0100253 * When "reader" has less than NUMBUFLEN bytes available, call the fill
254 * callback to get more.
255 */
256 static void
257fill_numbuflen(js_read_T *reader)
258{
259 if (reader->js_fill != NULL && (int)(reader->js_end - reader->js_buf)
260 - reader->js_used < NUMBUFLEN)
261 {
262 if (reader->js_fill(reader))
263 reader->js_end = reader->js_buf + STRLEN(reader->js_buf);
264 }
265}
266
267/*
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100268 * Skip white space in "reader".
Bram Moolenaar56ead342016-02-02 18:20:08 +0100269 * Also tops up readahead when needed.
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100270 */
271 static void
272json_skip_white(js_read_T *reader)
273{
274 int c;
275
Bram Moolenaar56ead342016-02-02 18:20:08 +0100276 for (;;)
277 {
278 c = reader->js_buf[reader->js_used];
279 if (reader->js_fill != NULL && c == NUL)
280 {
281 if (reader->js_fill(reader))
282 reader->js_end = reader->js_buf + STRLEN(reader->js_buf);
283 continue;
284 }
285 if (c != ' ' && c != TAB && c != NL && c != CAR)
286 break;
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100287 ++reader->js_used;
Bram Moolenaar56ead342016-02-02 18:20:08 +0100288 }
289 fill_numbuflen(reader);
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100290}
291
Bram Moolenaar56ead342016-02-02 18:20:08 +0100292 static int
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100293json_decode_array(js_read_T *reader, typval_T *res)
294{
295 char_u *p;
296 typval_T item;
297 listitem_T *li;
Bram Moolenaar56ead342016-02-02 18:20:08 +0100298 int ret;
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100299
Bram Moolenaar56ead342016-02-02 18:20:08 +0100300 if (res != NULL && rettv_list_alloc(res) == FAIL)
301 {
302 res->v_type = VAR_SPECIAL;
303 res->vval.v_number = VVAL_NONE;
304 return FAIL;
305 }
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100306 ++reader->js_used; /* consume the '[' */
307
308 while (TRUE)
309 {
310 json_skip_white(reader);
311 p = reader->js_buf + reader->js_used;
312 if (*p == NUL)
Bram Moolenaar56ead342016-02-02 18:20:08 +0100313 return MAYBE;
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100314 if (*p == ']')
315 {
316 ++reader->js_used; /* consume the ']' */
Bram Moolenaar56ead342016-02-02 18:20:08 +0100317 break;
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100318 }
319
Bram Moolenaar56ead342016-02-02 18:20:08 +0100320 ret = json_decode_item(reader, res == NULL ? NULL : &item);
321 if (ret != OK)
322 return ret;
323 if (res != NULL)
324 {
325 li = listitem_alloc();
326 if (li == NULL)
327 {
328 clear_tv(&item);
329 return FAIL;
330 }
331 li->li_tv = item;
332 list_append(res->vval.v_list, li);
333 }
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100334
335 json_skip_white(reader);
336 p = reader->js_buf + reader->js_used;
337 if (*p == ',')
338 ++reader->js_used;
339 else if (*p != ']')
Bram Moolenaar56ead342016-02-02 18:20:08 +0100340 {
341 if (*p == NUL)
342 return MAYBE;
343 return FAIL;
344 }
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100345 }
Bram Moolenaar56ead342016-02-02 18:20:08 +0100346 return OK;
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100347}
348
Bram Moolenaar56ead342016-02-02 18:20:08 +0100349 static int
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100350json_decode_object(js_read_T *reader, typval_T *res)
351{
352 char_u *p;
353 typval_T tvkey;
354 typval_T item;
355 dictitem_T *di;
356 char_u buf[NUMBUFLEN];
Bram Moolenaarfbf9c6b2016-02-02 19:43:57 +0100357 char_u *key = NULL;
Bram Moolenaar56ead342016-02-02 18:20:08 +0100358 int ret;
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100359
Bram Moolenaar56ead342016-02-02 18:20:08 +0100360 if (res != NULL && rettv_dict_alloc(res) == FAIL)
361 {
362 res->v_type = VAR_SPECIAL;
363 res->vval.v_number = VVAL_NONE;
364 return FAIL;
365 }
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100366 ++reader->js_used; /* consume the '{' */
367
368 while (TRUE)
369 {
370 json_skip_white(reader);
371 p = reader->js_buf + reader->js_used;
372 if (*p == NUL)
Bram Moolenaar56ead342016-02-02 18:20:08 +0100373 return MAYBE;
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100374 if (*p == '}')
375 {
376 ++reader->js_used; /* consume the '}' */
Bram Moolenaar56ead342016-02-02 18:20:08 +0100377 break;
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100378 }
379
Bram Moolenaar56ead342016-02-02 18:20:08 +0100380 ret = json_decode_item(reader, res == NULL ? NULL : &tvkey);
381 if (ret != OK)
382 return ret;
383 if (res != NULL)
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100384 {
Bram Moolenaar56ead342016-02-02 18:20:08 +0100385 key = get_tv_string_buf_chk(&tvkey, buf);
386 if (key == NULL || *key == NUL)
387 {
388 clear_tv(&tvkey);
389 return FAIL;
390 }
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100391 }
392
393 json_skip_white(reader);
394 p = reader->js_buf + reader->js_used;
395 if (*p != ':')
396 {
Bram Moolenaar56ead342016-02-02 18:20:08 +0100397 if (res != NULL)
398 clear_tv(&tvkey);
399 if (*p == NUL)
400 return MAYBE;
401 return FAIL;
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100402 }
403 ++reader->js_used;
404 json_skip_white(reader);
405
Bram Moolenaar56ead342016-02-02 18:20:08 +0100406 ret = json_decode_item(reader, res == NULL ? NULL : &item);
407 if (ret != OK)
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100408 {
Bram Moolenaar56ead342016-02-02 18:20:08 +0100409 if (res != NULL)
410 clear_tv(&tvkey);
411 return ret;
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100412 }
Bram Moolenaar56ead342016-02-02 18:20:08 +0100413
414 if (res != NULL)
415 {
416 di = dictitem_alloc(key);
417 clear_tv(&tvkey);
418 if (di == NULL)
419 {
420 clear_tv(&item);
421 return FAIL;
422 }
423 di->di_tv = item;
424 if (dict_add(res->vval.v_dict, di) == FAIL)
425 {
426 dictitem_free(di);
427 return FAIL;
428 }
429 }
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100430
431 json_skip_white(reader);
432 p = reader->js_buf + reader->js_used;
433 if (*p == ',')
434 ++reader->js_used;
435 else if (*p != '}')
Bram Moolenaar56ead342016-02-02 18:20:08 +0100436 {
437 if (*p == NUL)
438 return MAYBE;
439 return FAIL;
440 }
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100441 }
Bram Moolenaar56ead342016-02-02 18:20:08 +0100442 return OK;
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100443}
444
Bram Moolenaar56ead342016-02-02 18:20:08 +0100445 static int
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100446json_decode_string(js_read_T *reader, typval_T *res)
447{
448 garray_T ga;
449 int len;
Bram Moolenaar56ead342016-02-02 18:20:08 +0100450 char_u *p;
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100451 int c;
452 long nr;
453 char_u buf[NUMBUFLEN];
454
Bram Moolenaar56ead342016-02-02 18:20:08 +0100455 if (res != NULL)
456 ga_init2(&ga, 1, 200);
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100457
Bram Moolenaar56ead342016-02-02 18:20:08 +0100458 p = reader->js_buf + reader->js_used + 1; /* skip over " */
459 while (*p != '"')
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100460 {
Bram Moolenaar56ead342016-02-02 18:20:08 +0100461 if (*p == NUL || p[1] == NUL
462#ifdef FEAT_MBYTE
463 || utf_ptr2len(p) < utf_byte2len(*p)
464#endif
465 )
466 {
467 if (reader->js_fill == NULL)
468 break;
469 len = (int)(reader->js_end - p);
470 reader->js_used = (int)(p - reader->js_buf);
471 if (!reader->js_fill(reader))
472 break; /* didn't get more */
473 p = reader->js_buf + reader->js_used;
474 reader->js_end = reader->js_buf + STRLEN(reader->js_buf);
475 continue;
476 }
477
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100478 if (*p == '\\')
479 {
480 c = -1;
481 switch (p[1])
482 {
Bram Moolenaar56ead342016-02-02 18:20:08 +0100483 case '\\': c = '\\'; break;
484 case '"': c = '"'; break;
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100485 case 'b': c = BS; break;
486 case 't': c = TAB; break;
487 case 'n': c = NL; break;
488 case 'f': c = FF; break;
489 case 'r': c = CAR; break;
490 case 'u':
Bram Moolenaar56ead342016-02-02 18:20:08 +0100491 if (reader->js_fill != NULL
492 && (int)(reader->js_end - p) < NUMBUFLEN)
493 {
494 reader->js_used = (int)(p - reader->js_buf);
495 if (reader->js_fill(reader))
496 {
497 p = reader->js_buf + reader->js_used;
498 reader->js_end = reader->js_buf
499 + STRLEN(reader->js_buf);
500 }
501 }
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100502 vim_str2nr(p + 2, NULL, &len,
503 STR2NR_HEX + STR2NR_FORCE, &nr, NULL, 4);
504 p += len + 2;
Bram Moolenaar56ead342016-02-02 18:20:08 +0100505 if (res != NULL)
506 {
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100507#ifdef FEAT_MBYTE
Bram Moolenaar56ead342016-02-02 18:20:08 +0100508 buf[(*mb_char2bytes)((int)nr, buf)] = NUL;
509 ga_concat(&ga, buf);
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100510#else
Bram Moolenaar56ead342016-02-02 18:20:08 +0100511 ga_append(&ga, nr);
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100512#endif
Bram Moolenaar56ead342016-02-02 18:20:08 +0100513 }
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100514 break;
Bram Moolenaar56ead342016-02-02 18:20:08 +0100515 default:
516 /* not a special char, skip over \ */
517 ++p;
518 continue;
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100519 }
520 if (c > 0)
521 {
522 p += 2;
Bram Moolenaar56ead342016-02-02 18:20:08 +0100523 if (res != NULL)
524 ga_append(&ga, c);
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100525 }
526 }
527 else
528 {
529 len = MB_PTR2LEN(p);
Bram Moolenaar56ead342016-02-02 18:20:08 +0100530 if (res != NULL)
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100531 {
Bram Moolenaar56ead342016-02-02 18:20:08 +0100532 if (ga_grow(&ga, len) == FAIL)
533 {
534 ga_clear(&ga);
535 return FAIL;
536 }
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100537 mch_memmove((char *)ga.ga_data + ga.ga_len, p, (size_t)len);
538 ga.ga_len += len;
539 }
540 p += len;
541 }
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100542 }
Bram Moolenaar56ead342016-02-02 18:20:08 +0100543
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100544 reader->js_used = (int)(p - reader->js_buf);
545 if (*p == '"')
546 {
547 ++reader->js_used;
Bram Moolenaar56ead342016-02-02 18:20:08 +0100548 if (res != NULL)
549 {
550 res->v_type = VAR_STRING;
Bram Moolenaar4b6a6dc2016-02-04 22:49:49 +0100551 res->vval.v_string = ga.ga_data;
Bram Moolenaar56ead342016-02-02 18:20:08 +0100552 }
553 return OK;
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100554 }
Bram Moolenaar56ead342016-02-02 18:20:08 +0100555 if (res != NULL)
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100556 {
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100557 res->v_type = VAR_SPECIAL;
558 res->vval.v_number = VVAL_NONE;
Bram Moolenaar56ead342016-02-02 18:20:08 +0100559 ga_clear(&ga);
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100560 }
Bram Moolenaar56ead342016-02-02 18:20:08 +0100561 return MAYBE;
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100562}
563
564/*
Bram Moolenaar56ead342016-02-02 18:20:08 +0100565 * Decode one item and put it in "res". If "res" is NULL only advance.
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100566 * Must already have skipped white space.
Bram Moolenaar56ead342016-02-02 18:20:08 +0100567 *
568 * Return FAIL for a decoding error.
569 * Return MAYBE for an incomplete message.
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100570 */
Bram Moolenaar56ead342016-02-02 18:20:08 +0100571 static int
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100572json_decode_item(js_read_T *reader, typval_T *res)
573{
Bram Moolenaar56ead342016-02-02 18:20:08 +0100574 char_u *p;
575 int len;
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100576
Bram Moolenaar56ead342016-02-02 18:20:08 +0100577 fill_numbuflen(reader);
578 p = reader->js_buf + reader->js_used;
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100579 switch (*p)
580 {
581 case '[': /* array */
Bram Moolenaar56ead342016-02-02 18:20:08 +0100582 return json_decode_array(reader, res);
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100583
584 case '{': /* object */
Bram Moolenaar56ead342016-02-02 18:20:08 +0100585 return json_decode_object(reader, res);
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100586
587 case '"': /* string */
Bram Moolenaar56ead342016-02-02 18:20:08 +0100588 return json_decode_string(reader, res);
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100589
590 case ',': /* comma: empty item */
591 case NUL: /* empty */
Bram Moolenaar56ead342016-02-02 18:20:08 +0100592 if (res != NULL)
593 {
594 res->v_type = VAR_SPECIAL;
595 res->vval.v_number = VVAL_NONE;
596 }
597 return OK;
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100598
599 default:
600 if (VIM_ISDIGIT(*p) || *p == '-')
601 {
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100602 char_u *sp = p;
Bram Moolenaar56ead342016-02-02 18:20:08 +0100603
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100604#ifdef FEAT_FLOAT
605 if (*sp == '-')
Bram Moolenaar56ead342016-02-02 18:20:08 +0100606 {
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100607 ++sp;
Bram Moolenaar56ead342016-02-02 18:20:08 +0100608 if (*sp == NUL)
609 return MAYBE;
610 if (!VIM_ISDIGIT(*sp))
611 return FAIL;
612 }
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100613 sp = skipdigits(sp);
614 if (*sp == '.' || *sp == 'e' || *sp == 'E')
615 {
Bram Moolenaar56ead342016-02-02 18:20:08 +0100616 if (res == NULL)
617 {
618 float_T f;
619
620 len = string2float(p, &f);
621 }
622 else
623 {
624 res->v_type = VAR_FLOAT;
625 len = string2float(p, &res->vval.v_float);
626 }
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100627 }
628 else
629#endif
630 {
631 long nr;
632
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100633 vim_str2nr(reader->js_buf + reader->js_used,
634 NULL, &len, 0, /* what */
635 &nr, NULL, 0);
Bram Moolenaar56ead342016-02-02 18:20:08 +0100636 if (res != NULL)
637 {
638 res->v_type = VAR_NUMBER;
639 res->vval.v_number = nr;
640 }
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100641 }
642 reader->js_used += len;
Bram Moolenaar56ead342016-02-02 18:20:08 +0100643 return OK;
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100644 }
645 if (STRNICMP((char *)p, "false", 5) == 0)
646 {
647 reader->js_used += 5;
Bram Moolenaar56ead342016-02-02 18:20:08 +0100648 if (res != NULL)
649 {
650 res->v_type = VAR_SPECIAL;
651 res->vval.v_number = VVAL_FALSE;
652 }
653 return OK;
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100654 }
655 if (STRNICMP((char *)p, "true", 4) == 0)
656 {
657 reader->js_used += 4;
Bram Moolenaar56ead342016-02-02 18:20:08 +0100658 if (res != NULL)
659 {
660 res->v_type = VAR_SPECIAL;
661 res->vval.v_number = VVAL_TRUE;
662 }
663 return OK;
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100664 }
665 if (STRNICMP((char *)p, "null", 4) == 0)
666 {
667 reader->js_used += 4;
Bram Moolenaar56ead342016-02-02 18:20:08 +0100668 if (res != NULL)
669 {
670 res->v_type = VAR_SPECIAL;
671 res->vval.v_number = VVAL_NULL;
672 }
673 return OK;
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100674 }
Bram Moolenaar56ead342016-02-02 18:20:08 +0100675 /* check for truncated name */
676 len = (int)(reader->js_end - (reader->js_buf + reader->js_used));
677 if ((len < 5 && STRNICMP((char *)p, "false", len) == 0)
678 || (len < 4 && (STRNICMP((char *)p, "true", len) == 0
679 || STRNICMP((char *)p, "null", len) == 0)))
680 return MAYBE;
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100681 break;
682 }
683
Bram Moolenaar56ead342016-02-02 18:20:08 +0100684 if (res != NUL)
685 {
686 res->v_type = VAR_SPECIAL;
687 res->vval.v_number = VVAL_NONE;
688 }
689 return FAIL;
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100690}
691
692/*
693 * Decode the JSON from "reader" and store the result in "res".
Bram Moolenaar56ead342016-02-02 18:20:08 +0100694 * Return FAIL if not the whole message was consumed.
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100695 */
Bram Moolenaar19d2f152016-02-01 21:38:19 +0100696 int
Bram Moolenaar56ead342016-02-02 18:20:08 +0100697json_decode_all(js_read_T *reader, typval_T *res)
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100698{
Bram Moolenaar56ead342016-02-02 18:20:08 +0100699 int ret;
700
701 /* We get the end once, to avoid calling strlen() many times. */
702 reader->js_end = reader->js_buf + STRLEN(reader->js_buf);
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100703 json_skip_white(reader);
Bram Moolenaar56ead342016-02-02 18:20:08 +0100704 ret = json_decode_item(reader, res);
705 if (ret != OK)
706 return FAIL;
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100707 json_skip_white(reader);
708 if (reader->js_buf[reader->js_used] != NUL)
Bram Moolenaar19d2f152016-02-01 21:38:19 +0100709 return FAIL;
710 return OK;
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100711}
Bram Moolenaar56ead342016-02-02 18:20:08 +0100712
713/*
714 * Decode the JSON from "reader" and store the result in "res".
715 * Return FAIL if the message has a decoding error or the message is
716 * truncated. Consumes the message anyway.
717 */
718 int
719json_decode(js_read_T *reader, typval_T *res)
720{
721 int ret;
722
723 /* We get the end once, to avoid calling strlen() many times. */
724 reader->js_end = reader->js_buf + STRLEN(reader->js_buf);
725 json_skip_white(reader);
726 ret = json_decode_item(reader, res);
727 json_skip_white(reader);
728
729 return ret == OK ? OK : FAIL;
730}
731
732/*
733 * Decode the JSON from "reader" to find the end of the message.
734 * Return FAIL if the message has a decoding error.
735 * Return MAYBE if the message is truncated, need to read more.
736 * This only works reliable if the message contains an object, array or
737 * string. A number might be trucated without knowing.
738 * Does not advance the reader.
739 */
740 int
741json_find_end(js_read_T *reader)
742{
743 int used_save = reader->js_used;
744 int ret;
745
746 /* We get the end once, to avoid calling strlen() many times. */
747 reader->js_end = reader->js_buf + STRLEN(reader->js_buf);
748 json_skip_white(reader);
749 ret = json_decode_item(reader, NULL);
750 reader->js_used = used_save;
751 return ret;
752}
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100753#endif