blob: 72b065f9ac2180f9cb0a8b2fd9ad585780d2a046 [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 Moolenaarfcaaae62016-01-24 16:49:11 +010019static int json_encode_item(garray_T *gap, typval_T *val, int copyID);
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);
32 json_encode_item(&ga, val, get_copyID());
33 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 Moolenaar520e1e42016-01-23 19:46:28 +0100124json_encode_item(garray_T *gap, typval_T *val, int copyID)
125{
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;
138 case VVAL_NONE: break;
139 case VVAL_NULL: ga_concat(gap, (char_u *)"null"); break;
140 }
141 break;
142
143 case VAR_NUMBER:
144 vim_snprintf((char *)numbuf, NUMBUFLEN, "%ld",
145 (long)val->vval.v_number);
146 ga_concat(gap, numbuf);
147 break;
148
149 case VAR_STRING:
150 res = val->vval.v_string;
151 write_string(gap, res);
152 break;
153
154 case VAR_FUNC:
Bram Moolenaarfcaaae62016-01-24 16:49:11 +0100155 /* no JSON equivalent */
156 EMSG(_(e_invarg));
157 return FAIL;
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100158
159 case VAR_LIST:
160 l = val->vval.v_list;
161 if (l == NULL)
162 ga_concat(gap, (char_u *)"null");
163 else
164 {
165 if (l->lv_copyID == copyID)
166 ga_concat(gap, (char_u *)"[]");
167 else
168 {
169 listitem_T *li;
170
171 l->lv_copyID = copyID;
172 ga_append(gap, '[');
173 for (li = l->lv_first; li != NULL && !got_int; )
174 {
Bram Moolenaarfcaaae62016-01-24 16:49:11 +0100175 if (json_encode_item(gap, &li->li_tv, copyID) == FAIL)
176 return FAIL;
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100177 li = li->li_next;
178 if (li != NULL)
179 ga_append(gap, ',');
180 }
181 ga_append(gap, ']');
Bram Moolenaarfcaaae62016-01-24 16:49:11 +0100182 l->lv_copyID = 0;
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100183 }
184 }
185 break;
186
187 case VAR_DICT:
188 d = val->vval.v_dict;
189 if (d == NULL)
190 ga_concat(gap, (char_u *)"null");
191 else
192 {
193 if (d->dv_copyID == copyID)
194 ga_concat(gap, (char_u *)"{}");
195 else
196 {
197 int first = TRUE;
198 int todo = (int)d->dv_hashtab.ht_used;
199 hashitem_T *hi;
200
201 d->dv_copyID = copyID;
202 ga_append(gap, '{');
203
204 for (hi = d->dv_hashtab.ht_array; todo > 0 && !got_int;
205 ++hi)
206 if (!HASHITEM_EMPTY(hi))
207 {
208 --todo;
209 if (first)
210 first = FALSE;
211 else
212 ga_append(gap, ',');
213 write_string(gap, hi->hi_key);
214 ga_append(gap, ':');
Bram Moolenaarfcaaae62016-01-24 16:49:11 +0100215 if (json_encode_item(gap, &dict_lookup(hi)->di_tv,
216 copyID) == FAIL)
217 return FAIL;
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100218 }
219 ga_append(gap, '}');
Bram Moolenaarfcaaae62016-01-24 16:49:11 +0100220 d->dv_copyID = 0;
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100221 }
222 }
223 break;
224
225#ifdef FEAT_FLOAT
226 case VAR_FLOAT:
227 vim_snprintf((char *)numbuf, NUMBUFLEN, "%g", val->vval.v_float);
228 ga_concat(gap, numbuf);
229 break;
230#endif
231 default: EMSG2(_(e_intern2), "json_encode_item()"); break;
Bram Moolenaarfcaaae62016-01-24 16:49:11 +0100232 return FAIL;
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100233 }
Bram Moolenaarfcaaae62016-01-24 16:49:11 +0100234 return OK;
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100235}
236
237/*
Bram Moolenaar56ead342016-02-02 18:20:08 +0100238 * When "reader" has less than NUMBUFLEN bytes available, call the fill
239 * callback to get more.
240 */
241 static void
242fill_numbuflen(js_read_T *reader)
243{
244 if (reader->js_fill != NULL && (int)(reader->js_end - reader->js_buf)
245 - reader->js_used < NUMBUFLEN)
246 {
247 if (reader->js_fill(reader))
248 reader->js_end = reader->js_buf + STRLEN(reader->js_buf);
249 }
250}
251
252/*
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100253 * Skip white space in "reader".
Bram Moolenaar56ead342016-02-02 18:20:08 +0100254 * Also tops up readahead when needed.
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100255 */
256 static void
257json_skip_white(js_read_T *reader)
258{
259 int c;
260
Bram Moolenaar56ead342016-02-02 18:20:08 +0100261 for (;;)
262 {
263 c = reader->js_buf[reader->js_used];
264 if (reader->js_fill != NULL && c == NUL)
265 {
266 if (reader->js_fill(reader))
267 reader->js_end = reader->js_buf + STRLEN(reader->js_buf);
268 continue;
269 }
270 if (c != ' ' && c != TAB && c != NL && c != CAR)
271 break;
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100272 ++reader->js_used;
Bram Moolenaar56ead342016-02-02 18:20:08 +0100273 }
274 fill_numbuflen(reader);
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100275}
276
Bram Moolenaar56ead342016-02-02 18:20:08 +0100277 static int
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100278json_decode_array(js_read_T *reader, typval_T *res)
279{
280 char_u *p;
281 typval_T item;
282 listitem_T *li;
Bram Moolenaar56ead342016-02-02 18:20:08 +0100283 int ret;
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100284
Bram Moolenaar56ead342016-02-02 18:20:08 +0100285 if (res != NULL && rettv_list_alloc(res) == FAIL)
286 {
287 res->v_type = VAR_SPECIAL;
288 res->vval.v_number = VVAL_NONE;
289 return FAIL;
290 }
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100291 ++reader->js_used; /* consume the '[' */
292
293 while (TRUE)
294 {
295 json_skip_white(reader);
296 p = reader->js_buf + reader->js_used;
297 if (*p == NUL)
Bram Moolenaar56ead342016-02-02 18:20:08 +0100298 return MAYBE;
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100299 if (*p == ']')
300 {
301 ++reader->js_used; /* consume the ']' */
Bram Moolenaar56ead342016-02-02 18:20:08 +0100302 break;
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100303 }
304
Bram Moolenaar56ead342016-02-02 18:20:08 +0100305 ret = json_decode_item(reader, res == NULL ? NULL : &item);
306 if (ret != OK)
307 return ret;
308 if (res != NULL)
309 {
310 li = listitem_alloc();
311 if (li == NULL)
312 {
313 clear_tv(&item);
314 return FAIL;
315 }
316 li->li_tv = item;
317 list_append(res->vval.v_list, li);
318 }
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100319
320 json_skip_white(reader);
321 p = reader->js_buf + reader->js_used;
322 if (*p == ',')
323 ++reader->js_used;
324 else if (*p != ']')
Bram Moolenaar56ead342016-02-02 18:20:08 +0100325 {
326 if (*p == NUL)
327 return MAYBE;
328 return FAIL;
329 }
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100330 }
Bram Moolenaar56ead342016-02-02 18:20:08 +0100331 return OK;
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100332}
333
Bram Moolenaar56ead342016-02-02 18:20:08 +0100334 static int
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100335json_decode_object(js_read_T *reader, typval_T *res)
336{
337 char_u *p;
338 typval_T tvkey;
339 typval_T item;
340 dictitem_T *di;
341 char_u buf[NUMBUFLEN];
342 char_u *key;
Bram Moolenaar56ead342016-02-02 18:20:08 +0100343 int ret;
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100344
Bram Moolenaar56ead342016-02-02 18:20:08 +0100345 if (res != NULL && rettv_dict_alloc(res) == FAIL)
346 {
347 res->v_type = VAR_SPECIAL;
348 res->vval.v_number = VVAL_NONE;
349 return FAIL;
350 }
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100351 ++reader->js_used; /* consume the '{' */
352
353 while (TRUE)
354 {
355 json_skip_white(reader);
356 p = reader->js_buf + reader->js_used;
357 if (*p == NUL)
Bram Moolenaar56ead342016-02-02 18:20:08 +0100358 return MAYBE;
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100359 if (*p == '}')
360 {
361 ++reader->js_used; /* consume the '}' */
Bram Moolenaar56ead342016-02-02 18:20:08 +0100362 break;
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100363 }
364
Bram Moolenaar56ead342016-02-02 18:20:08 +0100365 ret = json_decode_item(reader, res == NULL ? NULL : &tvkey);
366 if (ret != OK)
367 return ret;
368 if (res != NULL)
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100369 {
Bram Moolenaar56ead342016-02-02 18:20:08 +0100370 key = get_tv_string_buf_chk(&tvkey, buf);
371 if (key == NULL || *key == NUL)
372 {
373 clear_tv(&tvkey);
374 return FAIL;
375 }
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100376 }
377
378 json_skip_white(reader);
379 p = reader->js_buf + reader->js_used;
380 if (*p != ':')
381 {
Bram Moolenaar56ead342016-02-02 18:20:08 +0100382 if (res != NULL)
383 clear_tv(&tvkey);
384 if (*p == NUL)
385 return MAYBE;
386 return FAIL;
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100387 }
388 ++reader->js_used;
389 json_skip_white(reader);
390
Bram Moolenaar56ead342016-02-02 18:20:08 +0100391 ret = json_decode_item(reader, res == NULL ? NULL : &item);
392 if (ret != OK)
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100393 {
Bram Moolenaar56ead342016-02-02 18:20:08 +0100394 if (res != NULL)
395 clear_tv(&tvkey);
396 return ret;
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100397 }
Bram Moolenaar56ead342016-02-02 18:20:08 +0100398
399 if (res != NULL)
400 {
401 di = dictitem_alloc(key);
402 clear_tv(&tvkey);
403 if (di == NULL)
404 {
405 clear_tv(&item);
406 return FAIL;
407 }
408 di->di_tv = item;
409 if (dict_add(res->vval.v_dict, di) == FAIL)
410 {
411 dictitem_free(di);
412 return FAIL;
413 }
414 }
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100415
416 json_skip_white(reader);
417 p = reader->js_buf + reader->js_used;
418 if (*p == ',')
419 ++reader->js_used;
420 else if (*p != '}')
Bram Moolenaar56ead342016-02-02 18:20:08 +0100421 {
422 if (*p == NUL)
423 return MAYBE;
424 return FAIL;
425 }
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100426 }
Bram Moolenaar56ead342016-02-02 18:20:08 +0100427 return OK;
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100428}
429
Bram Moolenaar56ead342016-02-02 18:20:08 +0100430 static int
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100431json_decode_string(js_read_T *reader, typval_T *res)
432{
433 garray_T ga;
434 int len;
Bram Moolenaar56ead342016-02-02 18:20:08 +0100435 char_u *p;
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100436 int c;
437 long nr;
438 char_u buf[NUMBUFLEN];
439
Bram Moolenaar56ead342016-02-02 18:20:08 +0100440 if (res != NULL)
441 ga_init2(&ga, 1, 200);
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100442
Bram Moolenaar56ead342016-02-02 18:20:08 +0100443 p = reader->js_buf + reader->js_used + 1; /* skip over " */
444 while (*p != '"')
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100445 {
Bram Moolenaar56ead342016-02-02 18:20:08 +0100446 if (*p == NUL || p[1] == NUL
447#ifdef FEAT_MBYTE
448 || utf_ptr2len(p) < utf_byte2len(*p)
449#endif
450 )
451 {
452 if (reader->js_fill == NULL)
453 break;
454 len = (int)(reader->js_end - p);
455 reader->js_used = (int)(p - reader->js_buf);
456 if (!reader->js_fill(reader))
457 break; /* didn't get more */
458 p = reader->js_buf + reader->js_used;
459 reader->js_end = reader->js_buf + STRLEN(reader->js_buf);
460 continue;
461 }
462
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100463 if (*p == '\\')
464 {
465 c = -1;
466 switch (p[1])
467 {
Bram Moolenaar56ead342016-02-02 18:20:08 +0100468 case '\\': c = '\\'; break;
469 case '"': c = '"'; break;
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100470 case 'b': c = BS; break;
471 case 't': c = TAB; break;
472 case 'n': c = NL; break;
473 case 'f': c = FF; break;
474 case 'r': c = CAR; break;
475 case 'u':
Bram Moolenaar56ead342016-02-02 18:20:08 +0100476 if (reader->js_fill != NULL
477 && (int)(reader->js_end - p) < NUMBUFLEN)
478 {
479 reader->js_used = (int)(p - reader->js_buf);
480 if (reader->js_fill(reader))
481 {
482 p = reader->js_buf + reader->js_used;
483 reader->js_end = reader->js_buf
484 + STRLEN(reader->js_buf);
485 }
486 }
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100487 vim_str2nr(p + 2, NULL, &len,
488 STR2NR_HEX + STR2NR_FORCE, &nr, NULL, 4);
489 p += len + 2;
Bram Moolenaar56ead342016-02-02 18:20:08 +0100490 if (res != NULL)
491 {
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100492#ifdef FEAT_MBYTE
Bram Moolenaar56ead342016-02-02 18:20:08 +0100493 buf[(*mb_char2bytes)((int)nr, buf)] = NUL;
494 ga_concat(&ga, buf);
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100495#else
Bram Moolenaar56ead342016-02-02 18:20:08 +0100496 ga_append(&ga, nr);
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100497#endif
Bram Moolenaar56ead342016-02-02 18:20:08 +0100498 }
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100499 break;
Bram Moolenaar56ead342016-02-02 18:20:08 +0100500 default:
501 /* not a special char, skip over \ */
502 ++p;
503 continue;
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100504 }
505 if (c > 0)
506 {
507 p += 2;
Bram Moolenaar56ead342016-02-02 18:20:08 +0100508 if (res != NULL)
509 ga_append(&ga, c);
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100510 }
511 }
512 else
513 {
514 len = MB_PTR2LEN(p);
Bram Moolenaar56ead342016-02-02 18:20:08 +0100515 if (res != NULL)
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100516 {
Bram Moolenaar56ead342016-02-02 18:20:08 +0100517 if (ga_grow(&ga, len) == FAIL)
518 {
519 ga_clear(&ga);
520 return FAIL;
521 }
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100522 mch_memmove((char *)ga.ga_data + ga.ga_len, p, (size_t)len);
523 ga.ga_len += len;
524 }
525 p += len;
526 }
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100527 }
Bram Moolenaar56ead342016-02-02 18:20:08 +0100528
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100529 reader->js_used = (int)(p - reader->js_buf);
530 if (*p == '"')
531 {
532 ++reader->js_used;
Bram Moolenaar56ead342016-02-02 18:20:08 +0100533 if (res != NULL)
534 {
535 res->v_type = VAR_STRING;
536 if (ga.ga_data == NULL)
537 res->vval.v_string = NULL;
538 else
539 res->vval.v_string = vim_strsave(ga.ga_data);
540 }
541 return OK;
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100542 }
Bram Moolenaar56ead342016-02-02 18:20:08 +0100543 if (res != NULL)
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100544 {
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100545 res->v_type = VAR_SPECIAL;
546 res->vval.v_number = VVAL_NONE;
Bram Moolenaar56ead342016-02-02 18:20:08 +0100547 ga_clear(&ga);
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100548 }
Bram Moolenaar56ead342016-02-02 18:20:08 +0100549 return MAYBE;
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100550}
551
552/*
Bram Moolenaar56ead342016-02-02 18:20:08 +0100553 * Decode one item and put it in "res". If "res" is NULL only advance.
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100554 * Must already have skipped white space.
Bram Moolenaar56ead342016-02-02 18:20:08 +0100555 *
556 * Return FAIL for a decoding error.
557 * Return MAYBE for an incomplete message.
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100558 */
Bram Moolenaar56ead342016-02-02 18:20:08 +0100559 static int
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100560json_decode_item(js_read_T *reader, typval_T *res)
561{
Bram Moolenaar56ead342016-02-02 18:20:08 +0100562 char_u *p;
563 int len;
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100564
Bram Moolenaar56ead342016-02-02 18:20:08 +0100565 fill_numbuflen(reader);
566 p = reader->js_buf + reader->js_used;
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100567 switch (*p)
568 {
569 case '[': /* array */
Bram Moolenaar56ead342016-02-02 18:20:08 +0100570 return json_decode_array(reader, res);
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100571
572 case '{': /* object */
Bram Moolenaar56ead342016-02-02 18:20:08 +0100573 return json_decode_object(reader, res);
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100574
575 case '"': /* string */
Bram Moolenaar56ead342016-02-02 18:20:08 +0100576 return json_decode_string(reader, res);
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100577
578 case ',': /* comma: empty item */
579 case NUL: /* empty */
Bram Moolenaar56ead342016-02-02 18:20:08 +0100580 if (res != NULL)
581 {
582 res->v_type = VAR_SPECIAL;
583 res->vval.v_number = VVAL_NONE;
584 }
585 return OK;
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100586
587 default:
588 if (VIM_ISDIGIT(*p) || *p == '-')
589 {
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100590 char_u *sp = p;
Bram Moolenaar56ead342016-02-02 18:20:08 +0100591
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100592#ifdef FEAT_FLOAT
593 if (*sp == '-')
Bram Moolenaar56ead342016-02-02 18:20:08 +0100594 {
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100595 ++sp;
Bram Moolenaar56ead342016-02-02 18:20:08 +0100596 if (*sp == NUL)
597 return MAYBE;
598 if (!VIM_ISDIGIT(*sp))
599 return FAIL;
600 }
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100601 sp = skipdigits(sp);
602 if (*sp == '.' || *sp == 'e' || *sp == 'E')
603 {
Bram Moolenaar56ead342016-02-02 18:20:08 +0100604 if (res == NULL)
605 {
606 float_T f;
607
608 len = string2float(p, &f);
609 }
610 else
611 {
612 res->v_type = VAR_FLOAT;
613 len = string2float(p, &res->vval.v_float);
614 }
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100615 }
616 else
617#endif
618 {
619 long nr;
620
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100621 vim_str2nr(reader->js_buf + reader->js_used,
622 NULL, &len, 0, /* what */
623 &nr, NULL, 0);
Bram Moolenaar56ead342016-02-02 18:20:08 +0100624 if (res != NULL)
625 {
626 res->v_type = VAR_NUMBER;
627 res->vval.v_number = nr;
628 }
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100629 }
630 reader->js_used += len;
Bram Moolenaar56ead342016-02-02 18:20:08 +0100631 return OK;
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100632 }
633 if (STRNICMP((char *)p, "false", 5) == 0)
634 {
635 reader->js_used += 5;
Bram Moolenaar56ead342016-02-02 18:20:08 +0100636 if (res != NULL)
637 {
638 res->v_type = VAR_SPECIAL;
639 res->vval.v_number = VVAL_FALSE;
640 }
641 return OK;
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100642 }
643 if (STRNICMP((char *)p, "true", 4) == 0)
644 {
645 reader->js_used += 4;
Bram Moolenaar56ead342016-02-02 18:20:08 +0100646 if (res != NULL)
647 {
648 res->v_type = VAR_SPECIAL;
649 res->vval.v_number = VVAL_TRUE;
650 }
651 return OK;
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100652 }
653 if (STRNICMP((char *)p, "null", 4) == 0)
654 {
655 reader->js_used += 4;
Bram Moolenaar56ead342016-02-02 18:20:08 +0100656 if (res != NULL)
657 {
658 res->v_type = VAR_SPECIAL;
659 res->vval.v_number = VVAL_NULL;
660 }
661 return OK;
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100662 }
Bram Moolenaar56ead342016-02-02 18:20:08 +0100663 /* check for truncated name */
664 len = (int)(reader->js_end - (reader->js_buf + reader->js_used));
665 if ((len < 5 && STRNICMP((char *)p, "false", len) == 0)
666 || (len < 4 && (STRNICMP((char *)p, "true", len) == 0
667 || STRNICMP((char *)p, "null", len) == 0)))
668 return MAYBE;
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100669 break;
670 }
671
Bram Moolenaar56ead342016-02-02 18:20:08 +0100672 if (res != NUL)
673 {
674 res->v_type = VAR_SPECIAL;
675 res->vval.v_number = VVAL_NONE;
676 }
677 return FAIL;
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100678}
679
680/*
681 * Decode the JSON from "reader" and store the result in "res".
Bram Moolenaar56ead342016-02-02 18:20:08 +0100682 * Return FAIL if not the whole message was consumed.
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100683 */
Bram Moolenaar19d2f152016-02-01 21:38:19 +0100684 int
Bram Moolenaar56ead342016-02-02 18:20:08 +0100685json_decode_all(js_read_T *reader, typval_T *res)
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100686{
Bram Moolenaar56ead342016-02-02 18:20:08 +0100687 int ret;
688
689 /* We get the end once, to avoid calling strlen() many times. */
690 reader->js_end = reader->js_buf + STRLEN(reader->js_buf);
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100691 json_skip_white(reader);
Bram Moolenaar56ead342016-02-02 18:20:08 +0100692 ret = json_decode_item(reader, res);
693 if (ret != OK)
694 return FAIL;
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100695 json_skip_white(reader);
696 if (reader->js_buf[reader->js_used] != NUL)
Bram Moolenaar19d2f152016-02-01 21:38:19 +0100697 return FAIL;
698 return OK;
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100699}
Bram Moolenaar56ead342016-02-02 18:20:08 +0100700
701/*
702 * Decode the JSON from "reader" and store the result in "res".
703 * Return FAIL if the message has a decoding error or the message is
704 * truncated. Consumes the message anyway.
705 */
706 int
707json_decode(js_read_T *reader, typval_T *res)
708{
709 int ret;
710
711 /* We get the end once, to avoid calling strlen() many times. */
712 reader->js_end = reader->js_buf + STRLEN(reader->js_buf);
713 json_skip_white(reader);
714 ret = json_decode_item(reader, res);
715 json_skip_white(reader);
716
717 return ret == OK ? OK : FAIL;
718}
719
720/*
721 * Decode the JSON from "reader" to find the end of the message.
722 * Return FAIL if the message has a decoding error.
723 * Return MAYBE if the message is truncated, need to read more.
724 * This only works reliable if the message contains an object, array or
725 * string. A number might be trucated without knowing.
726 * Does not advance the reader.
727 */
728 int
729json_find_end(js_read_T *reader)
730{
731 int used_save = reader->js_used;
732 int ret;
733
734 /* We get the end once, to avoid calling strlen() many times. */
735 reader->js_end = reader->js_buf + STRLEN(reader->js_buf);
736 json_skip_white(reader);
737 ret = json_decode_item(reader, NULL);
738 reader->js_used = used_save;
739 return ret;
740}
Bram Moolenaar520e1e42016-01-23 19:46:28 +0100741#endif