blob: 6688437aee437b704bbea688962f5b86b433c80d [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.
24 */
25 char_u *
26json_encode(typval_T *val)
27{
28 garray_T ga;
29
30 /* Store bytes in the growarray. */
31 ga_init2(&ga, 1, 4000);
Bram Moolenaar4f8b8fa2016-02-06 18:42:07 +010032 json_encode_item(&ga, val, get_copyID(), TRUE);
Bram Moolenaar520e1e42016-01-23 19:46:28 +010033 return ga.ga_data;
34}
35
Bram Moolenaarfb1f6262016-01-31 20:24:32 +010036/*
37 * Encode ["nr", "val"] into a JSON format string.
38 * Returns NULL when out of memory.
39 */
40 char_u *
41json_encode_nr_expr(int nr, typval_T *val)
42{
43 typval_T listtv;
44 typval_T nrtv;
45 char_u *text;
46
47 nrtv.v_type = VAR_NUMBER;
48 nrtv.vval.v_number = nr;
49 if (rettv_list_alloc(&listtv) == FAIL)
50 return NULL;
51 if (list_append_tv(listtv.vval.v_list, &nrtv) == FAIL
52 || list_append_tv(listtv.vval.v_list, val) == FAIL)
53 {
54 list_unref(listtv.vval.v_list);
55 return NULL;
56 }
57
58 text = json_encode(&listtv);
59 list_unref(listtv.vval.v_list);
60 return text;
61}
62
Bram Moolenaar520e1e42016-01-23 19:46:28 +010063 static void
64write_string(garray_T *gap, char_u *str)
65{
66 char_u *res = str;
67 char_u numbuf[NUMBUFLEN];
68
69 if (res == NULL)
70 ga_concat(gap, (char_u *)"null");
71 else
72 {
73 ga_append(gap, '"');
74 while (*res != NUL)
75 {
76 int c = PTR2CHAR(res);
77
78 switch (c)
79 {
80 case 0x08:
81 ga_append(gap, '\\'); ga_append(gap, 'b'); break;
82 case 0x09:
83 ga_append(gap, '\\'); ga_append(gap, 't'); break;
84 case 0x0a:
85 ga_append(gap, '\\'); ga_append(gap, 'n'); break;
86 case 0x0c:
87 ga_append(gap, '\\'); ga_append(gap, 'f'); break;
88 case 0x0d:
89 ga_append(gap, '\\'); ga_append(gap, 'r'); break;
90 case 0x22: /* " */
91 case 0x5c: /* \ */
92 ga_append(gap, '\\');
93 ga_append(gap, c);
94 break;
95 default:
96 if (c >= 0x20)
97 {
Bram Moolenaarfa06a512016-01-28 22:46:58 +010098#ifdef FEAT_MBYTE
Bram Moolenaar520e1e42016-01-23 19:46:28 +010099 numbuf[mb_char2bytes(c, numbuf)] = NUL;
Bram Moolenaarfa06a512016-01-28 22:46:58 +0100100#else
101 numbuf[0] = c;
102 numbuf[1] = NUL;
103#endif
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100104 ga_concat(gap, numbuf);
105 }
106 else
107 {
108 vim_snprintf((char *)numbuf, NUMBUFLEN,
109 "\\u%04lx", (long)c);
110 ga_concat(gap, numbuf);
111 }
112 }
113 mb_cptr_adv(res);
114 }
115 ga_append(gap, '"');
116 }
117}
118
Bram Moolenaarfcaaae62016-01-24 16:49:11 +0100119/*
120 * Encode "val" into "gap".
121 * Return FAIL or OK.
122 */
123 static int
Bram Moolenaar4f8b8fa2016-02-06 18:42:07 +0100124json_encode_item(garray_T *gap, typval_T *val, int copyID, int allow_none)
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100125{
126 char_u numbuf[NUMBUFLEN];
127 char_u *res;
128 list_T *l;
129 dict_T *d;
130
131 switch (val->v_type)
132 {
133 case VAR_SPECIAL:
Bram Moolenaarfcaaae62016-01-24 16:49:11 +0100134 switch (val->vval.v_number)
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100135 {
136 case VVAL_FALSE: ga_concat(gap, (char_u *)"false"); break;
137 case VVAL_TRUE: ga_concat(gap, (char_u *)"true"); break;
Bram Moolenaar4f8b8fa2016-02-06 18:42:07 +0100138 case VVAL_NONE: if (!allow_none)
139 /* TODO: better error */
140 EMSG(_(e_invarg));
141 break;
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100142 case VVAL_NULL: ga_concat(gap, (char_u *)"null"); break;
143 }
144 break;
145
146 case VAR_NUMBER:
147 vim_snprintf((char *)numbuf, NUMBUFLEN, "%ld",
148 (long)val->vval.v_number);
149 ga_concat(gap, numbuf);
150 break;
151
152 case VAR_STRING:
153 res = val->vval.v_string;
154 write_string(gap, res);
155 break;
156
157 case VAR_FUNC:
Bram Moolenaar4f8b8fa2016-02-06 18:42:07 +0100158 /* no JSON equivalent TODO: better error */
Bram Moolenaarfcaaae62016-01-24 16:49:11 +0100159 EMSG(_(e_invarg));
160 return FAIL;
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100161
162 case VAR_LIST:
163 l = val->vval.v_list;
164 if (l == NULL)
165 ga_concat(gap, (char_u *)"null");
166 else
167 {
168 if (l->lv_copyID == copyID)
169 ga_concat(gap, (char_u *)"[]");
170 else
171 {
172 listitem_T *li;
173
174 l->lv_copyID = copyID;
175 ga_append(gap, '[');
176 for (li = l->lv_first; li != NULL && !got_int; )
177 {
Bram Moolenaar4f8b8fa2016-02-06 18:42:07 +0100178 if (json_encode_item(gap, &li->li_tv, copyID, TRUE)
179 == FAIL)
Bram Moolenaarfcaaae62016-01-24 16:49:11 +0100180 return FAIL;
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100181 li = li->li_next;
182 if (li != NULL)
183 ga_append(gap, ',');
184 }
185 ga_append(gap, ']');
Bram Moolenaarfcaaae62016-01-24 16:49:11 +0100186 l->lv_copyID = 0;
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100187 }
188 }
189 break;
190
191 case VAR_DICT:
192 d = val->vval.v_dict;
193 if (d == NULL)
194 ga_concat(gap, (char_u *)"null");
195 else
196 {
197 if (d->dv_copyID == copyID)
198 ga_concat(gap, (char_u *)"{}");
199 else
200 {
201 int first = TRUE;
202 int todo = (int)d->dv_hashtab.ht_used;
203 hashitem_T *hi;
204
205 d->dv_copyID = copyID;
206 ga_append(gap, '{');
207
208 for (hi = d->dv_hashtab.ht_array; todo > 0 && !got_int;
209 ++hi)
210 if (!HASHITEM_EMPTY(hi))
211 {
212 --todo;
213 if (first)
214 first = FALSE;
215 else
216 ga_append(gap, ',');
217 write_string(gap, hi->hi_key);
218 ga_append(gap, ':');
Bram Moolenaarfcaaae62016-01-24 16:49:11 +0100219 if (json_encode_item(gap, &dict_lookup(hi)->di_tv,
Bram Moolenaar4f8b8fa2016-02-06 18:42:07 +0100220 copyID, FALSE) == FAIL)
Bram Moolenaarfcaaae62016-01-24 16:49:11 +0100221 return FAIL;
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100222 }
223 ga_append(gap, '}');
Bram Moolenaarfcaaae62016-01-24 16:49:11 +0100224 d->dv_copyID = 0;
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100225 }
226 }
227 break;
228
229#ifdef FEAT_FLOAT
230 case VAR_FLOAT:
231 vim_snprintf((char *)numbuf, NUMBUFLEN, "%g", val->vval.v_float);
232 ga_concat(gap, numbuf);
233 break;
234#endif
235 default: EMSG2(_(e_intern2), "json_encode_item()"); break;
Bram Moolenaarfcaaae62016-01-24 16:49:11 +0100236 return FAIL;
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100237 }
Bram Moolenaarfcaaae62016-01-24 16:49:11 +0100238 return OK;
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100239}
240
241/*
Bram Moolenaar56ead342016-02-02 18:20:08 +0100242 * When "reader" has less than NUMBUFLEN bytes available, call the fill
243 * callback to get more.
244 */
245 static void
246fill_numbuflen(js_read_T *reader)
247{
248 if (reader->js_fill != NULL && (int)(reader->js_end - reader->js_buf)
249 - reader->js_used < NUMBUFLEN)
250 {
251 if (reader->js_fill(reader))
252 reader->js_end = reader->js_buf + STRLEN(reader->js_buf);
253 }
254}
255
256/*
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100257 * Skip white space in "reader".
Bram Moolenaar56ead342016-02-02 18:20:08 +0100258 * Also tops up readahead when needed.
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100259 */
260 static void
261json_skip_white(js_read_T *reader)
262{
263 int c;
264
Bram Moolenaar56ead342016-02-02 18:20:08 +0100265 for (;;)
266 {
267 c = reader->js_buf[reader->js_used];
268 if (reader->js_fill != NULL && c == NUL)
269 {
270 if (reader->js_fill(reader))
271 reader->js_end = reader->js_buf + STRLEN(reader->js_buf);
272 continue;
273 }
274 if (c != ' ' && c != TAB && c != NL && c != CAR)
275 break;
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100276 ++reader->js_used;
Bram Moolenaar56ead342016-02-02 18:20:08 +0100277 }
278 fill_numbuflen(reader);
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100279}
280
Bram Moolenaar56ead342016-02-02 18:20:08 +0100281 static int
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100282json_decode_array(js_read_T *reader, typval_T *res)
283{
284 char_u *p;
285 typval_T item;
286 listitem_T *li;
Bram Moolenaar56ead342016-02-02 18:20:08 +0100287 int ret;
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100288
Bram Moolenaar56ead342016-02-02 18:20:08 +0100289 if (res != NULL && rettv_list_alloc(res) == FAIL)
290 {
291 res->v_type = VAR_SPECIAL;
292 res->vval.v_number = VVAL_NONE;
293 return FAIL;
294 }
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100295 ++reader->js_used; /* consume the '[' */
296
297 while (TRUE)
298 {
299 json_skip_white(reader);
300 p = reader->js_buf + reader->js_used;
301 if (*p == NUL)
Bram Moolenaar56ead342016-02-02 18:20:08 +0100302 return MAYBE;
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100303 if (*p == ']')
304 {
305 ++reader->js_used; /* consume the ']' */
Bram Moolenaar56ead342016-02-02 18:20:08 +0100306 break;
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100307 }
308
Bram Moolenaar56ead342016-02-02 18:20:08 +0100309 ret = json_decode_item(reader, res == NULL ? NULL : &item);
310 if (ret != OK)
311 return ret;
312 if (res != NULL)
313 {
314 li = listitem_alloc();
315 if (li == NULL)
316 {
317 clear_tv(&item);
318 return FAIL;
319 }
320 li->li_tv = item;
321 list_append(res->vval.v_list, li);
322 }
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100323
324 json_skip_white(reader);
325 p = reader->js_buf + reader->js_used;
326 if (*p == ',')
327 ++reader->js_used;
328 else if (*p != ']')
Bram Moolenaar56ead342016-02-02 18:20:08 +0100329 {
330 if (*p == NUL)
331 return MAYBE;
332 return FAIL;
333 }
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100334 }
Bram Moolenaar56ead342016-02-02 18:20:08 +0100335 return OK;
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100336}
337
Bram Moolenaar56ead342016-02-02 18:20:08 +0100338 static int
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100339json_decode_object(js_read_T *reader, typval_T *res)
340{
341 char_u *p;
342 typval_T tvkey;
343 typval_T item;
344 dictitem_T *di;
345 char_u buf[NUMBUFLEN];
Bram Moolenaarfbf9c6b2016-02-02 19:43:57 +0100346 char_u *key = NULL;
Bram Moolenaar56ead342016-02-02 18:20:08 +0100347 int ret;
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100348
Bram Moolenaar56ead342016-02-02 18:20:08 +0100349 if (res != NULL && rettv_dict_alloc(res) == FAIL)
350 {
351 res->v_type = VAR_SPECIAL;
352 res->vval.v_number = VVAL_NONE;
353 return FAIL;
354 }
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100355 ++reader->js_used; /* consume the '{' */
356
357 while (TRUE)
358 {
359 json_skip_white(reader);
360 p = reader->js_buf + reader->js_used;
361 if (*p == NUL)
Bram Moolenaar56ead342016-02-02 18:20:08 +0100362 return MAYBE;
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100363 if (*p == '}')
364 {
365 ++reader->js_used; /* consume the '}' */
Bram Moolenaar56ead342016-02-02 18:20:08 +0100366 break;
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100367 }
368
Bram Moolenaar56ead342016-02-02 18:20:08 +0100369 ret = json_decode_item(reader, res == NULL ? NULL : &tvkey);
370 if (ret != OK)
371 return ret;
372 if (res != NULL)
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100373 {
Bram Moolenaar56ead342016-02-02 18:20:08 +0100374 key = get_tv_string_buf_chk(&tvkey, buf);
375 if (key == NULL || *key == NUL)
376 {
377 clear_tv(&tvkey);
378 return FAIL;
379 }
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100380 }
381
382 json_skip_white(reader);
383 p = reader->js_buf + reader->js_used;
384 if (*p != ':')
385 {
Bram Moolenaar56ead342016-02-02 18:20:08 +0100386 if (res != NULL)
387 clear_tv(&tvkey);
388 if (*p == NUL)
389 return MAYBE;
390 return FAIL;
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100391 }
392 ++reader->js_used;
393 json_skip_white(reader);
394
Bram Moolenaar56ead342016-02-02 18:20:08 +0100395 ret = json_decode_item(reader, res == NULL ? NULL : &item);
396 if (ret != OK)
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100397 {
Bram Moolenaar56ead342016-02-02 18:20:08 +0100398 if (res != NULL)
399 clear_tv(&tvkey);
400 return ret;
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100401 }
Bram Moolenaar56ead342016-02-02 18:20:08 +0100402
403 if (res != NULL)
404 {
405 di = dictitem_alloc(key);
406 clear_tv(&tvkey);
407 if (di == NULL)
408 {
409 clear_tv(&item);
410 return FAIL;
411 }
412 di->di_tv = item;
413 if (dict_add(res->vval.v_dict, di) == FAIL)
414 {
415 dictitem_free(di);
416 return FAIL;
417 }
418 }
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100419
420 json_skip_white(reader);
421 p = reader->js_buf + reader->js_used;
422 if (*p == ',')
423 ++reader->js_used;
424 else if (*p != '}')
Bram Moolenaar56ead342016-02-02 18:20:08 +0100425 {
426 if (*p == NUL)
427 return MAYBE;
428 return FAIL;
429 }
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100430 }
Bram Moolenaar56ead342016-02-02 18:20:08 +0100431 return OK;
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100432}
433
Bram Moolenaar56ead342016-02-02 18:20:08 +0100434 static int
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100435json_decode_string(js_read_T *reader, typval_T *res)
436{
437 garray_T ga;
438 int len;
Bram Moolenaar56ead342016-02-02 18:20:08 +0100439 char_u *p;
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100440 int c;
441 long nr;
442 char_u buf[NUMBUFLEN];
443
Bram Moolenaar56ead342016-02-02 18:20:08 +0100444 if (res != NULL)
445 ga_init2(&ga, 1, 200);
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100446
Bram Moolenaar56ead342016-02-02 18:20:08 +0100447 p = reader->js_buf + reader->js_used + 1; /* skip over " */
448 while (*p != '"')
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100449 {
Bram Moolenaar56ead342016-02-02 18:20:08 +0100450 if (*p == NUL || p[1] == NUL
451#ifdef FEAT_MBYTE
452 || utf_ptr2len(p) < utf_byte2len(*p)
453#endif
454 )
455 {
456 if (reader->js_fill == NULL)
457 break;
458 len = (int)(reader->js_end - p);
459 reader->js_used = (int)(p - reader->js_buf);
460 if (!reader->js_fill(reader))
461 break; /* didn't get more */
462 p = reader->js_buf + reader->js_used;
463 reader->js_end = reader->js_buf + STRLEN(reader->js_buf);
464 continue;
465 }
466
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100467 if (*p == '\\')
468 {
469 c = -1;
470 switch (p[1])
471 {
Bram Moolenaar56ead342016-02-02 18:20:08 +0100472 case '\\': c = '\\'; break;
473 case '"': c = '"'; break;
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100474 case 'b': c = BS; break;
475 case 't': c = TAB; break;
476 case 'n': c = NL; break;
477 case 'f': c = FF; break;
478 case 'r': c = CAR; break;
479 case 'u':
Bram Moolenaar56ead342016-02-02 18:20:08 +0100480 if (reader->js_fill != NULL
481 && (int)(reader->js_end - p) < NUMBUFLEN)
482 {
483 reader->js_used = (int)(p - reader->js_buf);
484 if (reader->js_fill(reader))
485 {
486 p = reader->js_buf + reader->js_used;
487 reader->js_end = reader->js_buf
488 + STRLEN(reader->js_buf);
489 }
490 }
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100491 vim_str2nr(p + 2, NULL, &len,
492 STR2NR_HEX + STR2NR_FORCE, &nr, NULL, 4);
493 p += len + 2;
Bram Moolenaar56ead342016-02-02 18:20:08 +0100494 if (res != NULL)
495 {
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100496#ifdef FEAT_MBYTE
Bram Moolenaar56ead342016-02-02 18:20:08 +0100497 buf[(*mb_char2bytes)((int)nr, buf)] = NUL;
498 ga_concat(&ga, buf);
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100499#else
Bram Moolenaar56ead342016-02-02 18:20:08 +0100500 ga_append(&ga, nr);
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100501#endif
Bram Moolenaar56ead342016-02-02 18:20:08 +0100502 }
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100503 break;
Bram Moolenaar56ead342016-02-02 18:20:08 +0100504 default:
505 /* not a special char, skip over \ */
506 ++p;
507 continue;
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100508 }
509 if (c > 0)
510 {
511 p += 2;
Bram Moolenaar56ead342016-02-02 18:20:08 +0100512 if (res != NULL)
513 ga_append(&ga, c);
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100514 }
515 }
516 else
517 {
518 len = MB_PTR2LEN(p);
Bram Moolenaar56ead342016-02-02 18:20:08 +0100519 if (res != NULL)
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100520 {
Bram Moolenaar56ead342016-02-02 18:20:08 +0100521 if (ga_grow(&ga, len) == FAIL)
522 {
523 ga_clear(&ga);
524 return FAIL;
525 }
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100526 mch_memmove((char *)ga.ga_data + ga.ga_len, p, (size_t)len);
527 ga.ga_len += len;
528 }
529 p += len;
530 }
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100531 }
Bram Moolenaar56ead342016-02-02 18:20:08 +0100532
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100533 reader->js_used = (int)(p - reader->js_buf);
534 if (*p == '"')
535 {
536 ++reader->js_used;
Bram Moolenaar56ead342016-02-02 18:20:08 +0100537 if (res != NULL)
538 {
539 res->v_type = VAR_STRING;
Bram Moolenaar4b6a6dc2016-02-04 22:49:49 +0100540 res->vval.v_string = ga.ga_data;
Bram Moolenaar56ead342016-02-02 18:20:08 +0100541 }
542 return OK;
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100543 }
Bram Moolenaar56ead342016-02-02 18:20:08 +0100544 if (res != NULL)
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100545 {
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100546 res->v_type = VAR_SPECIAL;
547 res->vval.v_number = VVAL_NONE;
Bram Moolenaar56ead342016-02-02 18:20:08 +0100548 ga_clear(&ga);
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100549 }
Bram Moolenaar56ead342016-02-02 18:20:08 +0100550 return MAYBE;
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100551}
552
553/*
Bram Moolenaar56ead342016-02-02 18:20:08 +0100554 * Decode one item and put it in "res". If "res" is NULL only advance.
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100555 * Must already have skipped white space.
Bram Moolenaar56ead342016-02-02 18:20:08 +0100556 *
557 * Return FAIL for a decoding error.
558 * Return MAYBE for an incomplete message.
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100559 */
Bram Moolenaar56ead342016-02-02 18:20:08 +0100560 static int
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100561json_decode_item(js_read_T *reader, typval_T *res)
562{
Bram Moolenaar56ead342016-02-02 18:20:08 +0100563 char_u *p;
564 int len;
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100565
Bram Moolenaar56ead342016-02-02 18:20:08 +0100566 fill_numbuflen(reader);
567 p = reader->js_buf + reader->js_used;
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100568 switch (*p)
569 {
570 case '[': /* array */
Bram Moolenaar56ead342016-02-02 18:20:08 +0100571 return json_decode_array(reader, res);
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100572
573 case '{': /* object */
Bram Moolenaar56ead342016-02-02 18:20:08 +0100574 return json_decode_object(reader, res);
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100575
576 case '"': /* string */
Bram Moolenaar56ead342016-02-02 18:20:08 +0100577 return json_decode_string(reader, res);
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100578
579 case ',': /* comma: empty item */
580 case NUL: /* empty */
Bram Moolenaar56ead342016-02-02 18:20:08 +0100581 if (res != NULL)
582 {
583 res->v_type = VAR_SPECIAL;
584 res->vval.v_number = VVAL_NONE;
585 }
586 return OK;
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100587
588 default:
589 if (VIM_ISDIGIT(*p) || *p == '-')
590 {
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100591 char_u *sp = p;
Bram Moolenaar56ead342016-02-02 18:20:08 +0100592
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100593#ifdef FEAT_FLOAT
594 if (*sp == '-')
Bram Moolenaar56ead342016-02-02 18:20:08 +0100595 {
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100596 ++sp;
Bram Moolenaar56ead342016-02-02 18:20:08 +0100597 if (*sp == NUL)
598 return MAYBE;
599 if (!VIM_ISDIGIT(*sp))
600 return FAIL;
601 }
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100602 sp = skipdigits(sp);
603 if (*sp == '.' || *sp == 'e' || *sp == 'E')
604 {
Bram Moolenaar56ead342016-02-02 18:20:08 +0100605 if (res == NULL)
606 {
607 float_T f;
608
609 len = string2float(p, &f);
610 }
611 else
612 {
613 res->v_type = VAR_FLOAT;
614 len = string2float(p, &res->vval.v_float);
615 }
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100616 }
617 else
618#endif
619 {
620 long nr;
621
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100622 vim_str2nr(reader->js_buf + reader->js_used,
623 NULL, &len, 0, /* what */
624 &nr, NULL, 0);
Bram Moolenaar56ead342016-02-02 18:20:08 +0100625 if (res != NULL)
626 {
627 res->v_type = VAR_NUMBER;
628 res->vval.v_number = nr;
629 }
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100630 }
631 reader->js_used += len;
Bram Moolenaar56ead342016-02-02 18:20:08 +0100632 return OK;
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100633 }
634 if (STRNICMP((char *)p, "false", 5) == 0)
635 {
636 reader->js_used += 5;
Bram Moolenaar56ead342016-02-02 18:20:08 +0100637 if (res != NULL)
638 {
639 res->v_type = VAR_SPECIAL;
640 res->vval.v_number = VVAL_FALSE;
641 }
642 return OK;
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100643 }
644 if (STRNICMP((char *)p, "true", 4) == 0)
645 {
646 reader->js_used += 4;
Bram Moolenaar56ead342016-02-02 18:20:08 +0100647 if (res != NULL)
648 {
649 res->v_type = VAR_SPECIAL;
650 res->vval.v_number = VVAL_TRUE;
651 }
652 return OK;
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100653 }
654 if (STRNICMP((char *)p, "null", 4) == 0)
655 {
656 reader->js_used += 4;
Bram Moolenaar56ead342016-02-02 18:20:08 +0100657 if (res != NULL)
658 {
659 res->v_type = VAR_SPECIAL;
660 res->vval.v_number = VVAL_NULL;
661 }
662 return OK;
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100663 }
Bram Moolenaar56ead342016-02-02 18:20:08 +0100664 /* check for truncated name */
665 len = (int)(reader->js_end - (reader->js_buf + reader->js_used));
666 if ((len < 5 && STRNICMP((char *)p, "false", len) == 0)
667 || (len < 4 && (STRNICMP((char *)p, "true", len) == 0
668 || STRNICMP((char *)p, "null", len) == 0)))
669 return MAYBE;
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100670 break;
671 }
672
Bram Moolenaar56ead342016-02-02 18:20:08 +0100673 if (res != NUL)
674 {
675 res->v_type = VAR_SPECIAL;
676 res->vval.v_number = VVAL_NONE;
677 }
678 return FAIL;
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100679}
680
681/*
682 * Decode the JSON from "reader" and store the result in "res".
Bram Moolenaar56ead342016-02-02 18:20:08 +0100683 * Return FAIL if not the whole message was consumed.
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100684 */
Bram Moolenaar19d2f152016-02-01 21:38:19 +0100685 int
Bram Moolenaar56ead342016-02-02 18:20:08 +0100686json_decode_all(js_read_T *reader, typval_T *res)
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100687{
Bram Moolenaar56ead342016-02-02 18:20:08 +0100688 int ret;
689
690 /* We get the end once, to avoid calling strlen() many times. */
691 reader->js_end = reader->js_buf + STRLEN(reader->js_buf);
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100692 json_skip_white(reader);
Bram Moolenaar56ead342016-02-02 18:20:08 +0100693 ret = json_decode_item(reader, res);
694 if (ret != OK)
695 return FAIL;
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100696 json_skip_white(reader);
697 if (reader->js_buf[reader->js_used] != NUL)
Bram Moolenaar19d2f152016-02-01 21:38:19 +0100698 return FAIL;
699 return OK;
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100700}
Bram Moolenaar56ead342016-02-02 18:20:08 +0100701
702/*
703 * Decode the JSON from "reader" and store the result in "res".
704 * Return FAIL if the message has a decoding error or the message is
705 * truncated. Consumes the message anyway.
706 */
707 int
708json_decode(js_read_T *reader, typval_T *res)
709{
710 int ret;
711
712 /* We get the end once, to avoid calling strlen() many times. */
713 reader->js_end = reader->js_buf + STRLEN(reader->js_buf);
714 json_skip_white(reader);
715 ret = json_decode_item(reader, res);
716 json_skip_white(reader);
717
718 return ret == OK ? OK : FAIL;
719}
720
721/*
722 * Decode the JSON from "reader" to find the end of the message.
723 * Return FAIL if the message has a decoding error.
724 * Return MAYBE if the message is truncated, need to read more.
725 * This only works reliable if the message contains an object, array or
726 * string. A number might be trucated without knowing.
727 * Does not advance the reader.
728 */
729 int
730json_find_end(js_read_T *reader)
731{
732 int used_save = reader->js_used;
733 int ret;
734
735 /* We get the end once, to avoid calling strlen() many times. */
736 reader->js_end = reader->js_buf + STRLEN(reader->js_buf);
737 json_skip_white(reader);
738 ret = json_decode_item(reader, NULL);
739 reader->js_used = used_save;
740 return ret;
741}
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100742#endif