Mercurial > vim
comparison src/json.c @ 7967:45ea5ebf3a98 v7.4.1279
commit https://github.com/vim/vim/commit/595e64e259faefb330866852e1b9f6168544572a
Author: Bram Moolenaar <Bram@vim.org>
Date: Sun Feb 7 19:19:53 2016 +0100
patch 7.4.1279
Problem: jsonencode() is not producing strict JSON.
Solution: Add jsencode() and jsdecode(). Make jsonencode() and jsondecode()
strict.
author | Christian Brabandt <cb@256bit.org> |
---|---|
date | Sun, 07 Feb 2016 19:30:05 +0100 |
parents | 646d5148fee2 |
children | c6443e78cf2d |
comparison
equal
deleted
inserted
replaced
7966:79c5a86fcdfe | 7967:45ea5ebf3a98 |
---|---|
14 */ | 14 */ |
15 | 15 |
16 #include "vim.h" | 16 #include "vim.h" |
17 | 17 |
18 #if defined(FEAT_EVAL) || defined(PROTO) | 18 #if defined(FEAT_EVAL) || defined(PROTO) |
19 static int json_encode_item(garray_T *gap, typval_T *val, int copyID, int allow_none); | 19 static int json_encode_item(garray_T *gap, typval_T *val, int copyID, int options); |
20 static int json_decode_item(js_read_T *reader, typval_T *res); | 20 static int json_decode_item(js_read_T *reader, typval_T *res, int options); |
21 | 21 |
22 /* | 22 /* |
23 * Encode "val" into a JSON format string. | 23 * Encode "val" into a JSON format string. |
24 * The result is in allocated memory. | 24 * The result is in allocated memory. |
25 * The result is empty when encoding fails. | 25 * The result is empty when encoding fails. |
26 * "options" can be JSON_JS or zero; | |
26 */ | 27 */ |
27 char_u * | 28 char_u * |
28 json_encode(typval_T *val) | 29 json_encode(typval_T *val, int options) |
29 { | 30 { |
30 garray_T ga; | 31 garray_T ga; |
31 | 32 |
32 /* Store bytes in the growarray. */ | 33 /* Store bytes in the growarray. */ |
33 ga_init2(&ga, 1, 4000); | 34 ga_init2(&ga, 1, 4000); |
34 if (json_encode_item(&ga, val, get_copyID(), TRUE) == FAIL) | 35 if (json_encode_item(&ga, val, get_copyID(), options) == FAIL) |
35 { | 36 { |
36 vim_free(ga.ga_data); | 37 vim_free(ga.ga_data); |
37 return vim_strsave((char_u *)""); | 38 return vim_strsave((char_u *)""); |
38 } | 39 } |
39 return ga.ga_data; | 40 return ga.ga_data; |
40 } | 41 } |
41 | 42 |
42 /* | 43 /* |
43 * Encode ["nr", "val"] into a JSON format string in allocated memory. | 44 * Encode ["nr", "val"] into a JSON format string in allocated memory. |
45 * "options" can be JSON_JS or zero; | |
44 * Returns NULL when out of memory. | 46 * Returns NULL when out of memory. |
45 */ | 47 */ |
46 char_u * | 48 char_u * |
47 json_encode_nr_expr(int nr, typval_T *val) | 49 json_encode_nr_expr(int nr, typval_T *val, int options) |
48 { | 50 { |
49 typval_T listtv; | 51 typval_T listtv; |
50 typval_T nrtv; | 52 typval_T nrtv; |
51 char_u *text; | 53 char_u *text; |
52 | 54 |
59 { | 61 { |
60 list_unref(listtv.vval.v_list); | 62 list_unref(listtv.vval.v_list); |
61 return NULL; | 63 return NULL; |
62 } | 64 } |
63 | 65 |
64 text = json_encode(&listtv); | 66 text = json_encode(&listtv, options); |
65 list_unref(listtv.vval.v_list); | 67 list_unref(listtv.vval.v_list); |
66 return text; | 68 return text; |
67 } | 69 } |
68 | 70 |
69 static void | 71 static void |
121 ga_append(gap, '"'); | 123 ga_append(gap, '"'); |
122 } | 124 } |
123 } | 125 } |
124 | 126 |
125 /* | 127 /* |
128 * Return TRUE if "key" can be used without quotes. | |
129 * That is when it starts with a letter and only contains letters, digits and | |
130 * underscore. | |
131 */ | |
132 static int | |
133 is_simple_key(char_u *key) | |
134 { | |
135 char_u *p; | |
136 | |
137 if (!ASCII_ISALPHA(*key)) | |
138 return FALSE; | |
139 for (p = key + 1; *p != NUL; ++p) | |
140 if (!ASCII_ISALPHA(*p) && *p != '_' && !vim_isdigit(*p)) | |
141 return FALSE; | |
142 return TRUE; | |
143 } | |
144 | |
145 /* | |
126 * Encode "val" into "gap". | 146 * Encode "val" into "gap". |
127 * Return FAIL or OK. | 147 * Return FAIL or OK. |
128 */ | 148 */ |
129 static int | 149 static int |
130 json_encode_item(garray_T *gap, typval_T *val, int copyID, int allow_none) | 150 json_encode_item(garray_T *gap, typval_T *val, int copyID, int options) |
131 { | 151 { |
132 char_u numbuf[NUMBUFLEN]; | 152 char_u numbuf[NUMBUFLEN]; |
133 char_u *res; | 153 char_u *res; |
134 list_T *l; | 154 list_T *l; |
135 dict_T *d; | 155 dict_T *d; |
139 case VAR_SPECIAL: | 159 case VAR_SPECIAL: |
140 switch (val->vval.v_number) | 160 switch (val->vval.v_number) |
141 { | 161 { |
142 case VVAL_FALSE: ga_concat(gap, (char_u *)"false"); break; | 162 case VVAL_FALSE: ga_concat(gap, (char_u *)"false"); break; |
143 case VVAL_TRUE: ga_concat(gap, (char_u *)"true"); break; | 163 case VVAL_TRUE: ga_concat(gap, (char_u *)"true"); break; |
144 case VVAL_NONE: if (!allow_none) | 164 case VVAL_NONE: if ((options & JSON_JS) != 0 |
145 { | 165 && (options & JSON_NO_NONE) == 0) |
146 /* TODO: better error */ | 166 /* empty item */ |
147 EMSG(_(e_invarg)); | 167 break; |
148 return FAIL; | 168 /* FALLTHROUGH */ |
149 } | |
150 break; | |
151 case VVAL_NULL: ga_concat(gap, (char_u *)"null"); break; | 169 case VVAL_NULL: ga_concat(gap, (char_u *)"null"); break; |
152 } | 170 } |
153 break; | 171 break; |
154 | 172 |
155 case VAR_NUMBER: | 173 case VAR_NUMBER: |
183 | 201 |
184 l->lv_copyID = copyID; | 202 l->lv_copyID = copyID; |
185 ga_append(gap, '['); | 203 ga_append(gap, '['); |
186 for (li = l->lv_first; li != NULL && !got_int; ) | 204 for (li = l->lv_first; li != NULL && !got_int; ) |
187 { | 205 { |
188 if (json_encode_item(gap, &li->li_tv, copyID, TRUE) | 206 if (json_encode_item(gap, &li->li_tv, copyID, |
189 == FAIL) | 207 options & JSON_JS) == FAIL) |
190 return FAIL; | 208 return FAIL; |
209 if ((options & JSON_JS) | |
210 && li->li_next == NULL | |
211 && li->li_tv.v_type == VAR_SPECIAL | |
212 && li->li_tv.vval.v_number == VVAL_NONE) | |
213 /* add an extra comma if the last item is v:none */ | |
214 ga_append(gap, ','); | |
191 li = li->li_next; | 215 li = li->li_next; |
192 if (li != NULL) | 216 if (li != NULL) |
193 ga_append(gap, ','); | 217 ga_append(gap, ','); |
194 } | 218 } |
195 ga_append(gap, ']'); | 219 ga_append(gap, ']'); |
222 --todo; | 246 --todo; |
223 if (first) | 247 if (first) |
224 first = FALSE; | 248 first = FALSE; |
225 else | 249 else |
226 ga_append(gap, ','); | 250 ga_append(gap, ','); |
227 write_string(gap, hi->hi_key); | 251 if ((options & JSON_JS) |
252 && is_simple_key(hi->hi_key)) | |
253 ga_concat(gap, hi->hi_key); | |
254 else | |
255 write_string(gap, hi->hi_key); | |
228 ga_append(gap, ':'); | 256 ga_append(gap, ':'); |
229 if (json_encode_item(gap, &dict_lookup(hi)->di_tv, | 257 if (json_encode_item(gap, &dict_lookup(hi)->di_tv, |
230 copyID, FALSE) == FAIL) | 258 copyID, options | JSON_NO_NONE) == FAIL) |
231 return FAIL; | 259 return FAIL; |
232 } | 260 } |
233 ga_append(gap, '}'); | 261 ga_append(gap, '}'); |
234 d->dv_copyID = 0; | 262 d->dv_copyID = 0; |
235 } | 263 } |
263 reader->js_end = reader->js_buf + STRLEN(reader->js_buf); | 291 reader->js_end = reader->js_buf + STRLEN(reader->js_buf); |
264 } | 292 } |
265 } | 293 } |
266 | 294 |
267 /* | 295 /* |
268 * Skip white space in "reader". | 296 * Skip white space in "reader". All characters <= space are considered white |
297 * space. | |
269 * Also tops up readahead when needed. | 298 * Also tops up readahead when needed. |
270 */ | 299 */ |
271 static void | 300 static void |
272 json_skip_white(js_read_T *reader) | 301 json_skip_white(js_read_T *reader) |
273 { | 302 { |
280 { | 309 { |
281 if (reader->js_fill(reader)) | 310 if (reader->js_fill(reader)) |
282 reader->js_end = reader->js_buf + STRLEN(reader->js_buf); | 311 reader->js_end = reader->js_buf + STRLEN(reader->js_buf); |
283 continue; | 312 continue; |
284 } | 313 } |
285 if (c != ' ' && c != TAB && c != NL && c != CAR) | 314 if (c == NUL || c > ' ') |
286 break; | 315 break; |
287 ++reader->js_used; | 316 ++reader->js_used; |
288 } | 317 } |
289 fill_numbuflen(reader); | 318 fill_numbuflen(reader); |
290 } | 319 } |
291 | 320 |
292 static int | 321 static int |
293 json_decode_array(js_read_T *reader, typval_T *res) | 322 json_decode_array(js_read_T *reader, typval_T *res, int options) |
294 { | 323 { |
295 char_u *p; | 324 char_u *p; |
296 typval_T item; | 325 typval_T item; |
297 listitem_T *li; | 326 listitem_T *li; |
298 int ret; | 327 int ret; |
315 { | 344 { |
316 ++reader->js_used; /* consume the ']' */ | 345 ++reader->js_used; /* consume the ']' */ |
317 break; | 346 break; |
318 } | 347 } |
319 | 348 |
320 ret = json_decode_item(reader, res == NULL ? NULL : &item); | 349 ret = json_decode_item(reader, res == NULL ? NULL : &item, options); |
321 if (ret != OK) | 350 if (ret != OK) |
322 return ret; | 351 return ret; |
323 if (res != NULL) | 352 if (res != NULL) |
324 { | 353 { |
325 li = listitem_alloc(); | 354 li = listitem_alloc(); |
345 } | 374 } |
346 return OK; | 375 return OK; |
347 } | 376 } |
348 | 377 |
349 static int | 378 static int |
350 json_decode_object(js_read_T *reader, typval_T *res) | 379 json_decode_object(js_read_T *reader, typval_T *res, int options) |
351 { | 380 { |
352 char_u *p; | 381 char_u *p; |
353 typval_T tvkey; | 382 typval_T tvkey; |
354 typval_T item; | 383 typval_T item; |
355 dictitem_T *di; | 384 dictitem_T *di; |
375 { | 404 { |
376 ++reader->js_used; /* consume the '}' */ | 405 ++reader->js_used; /* consume the '}' */ |
377 break; | 406 break; |
378 } | 407 } |
379 | 408 |
380 ret = json_decode_item(reader, res == NULL ? NULL : &tvkey); | 409 if ((options & JSON_JS) && reader->js_buf[reader->js_used] != '"') |
381 if (ret != OK) | 410 { |
382 return ret; | 411 /* accept a key that is not in quotes */ |
383 if (res != NULL) | 412 key = p = reader->js_buf + reader->js_used; |
384 { | 413 while (*p != NUL && *p != ':' && *p > ' ') |
385 key = get_tv_string_buf_chk(&tvkey, buf); | 414 ++p; |
386 if (key == NULL || *key == NUL) | 415 tvkey.v_type = VAR_STRING; |
387 { | 416 tvkey.vval.v_string = vim_strnsave(key, (int)(p - key)); |
388 clear_tv(&tvkey); | 417 reader->js_used += (int)(p - key); |
389 return FAIL; | 418 key = tvkey.vval.v_string; |
419 } | |
420 else | |
421 { | |
422 ret = json_decode_item(reader, res == NULL ? NULL : &tvkey, | |
423 options); | |
424 if (ret != OK) | |
425 return ret; | |
426 if (res != NULL) | |
427 { | |
428 key = get_tv_string_buf_chk(&tvkey, buf); | |
429 if (key == NULL || *key == NUL) | |
430 { | |
431 clear_tv(&tvkey); | |
432 return FAIL; | |
433 } | |
390 } | 434 } |
391 } | 435 } |
392 | 436 |
393 json_skip_white(reader); | 437 json_skip_white(reader); |
394 p = reader->js_buf + reader->js_used; | 438 p = reader->js_buf + reader->js_used; |
401 return FAIL; | 445 return FAIL; |
402 } | 446 } |
403 ++reader->js_used; | 447 ++reader->js_used; |
404 json_skip_white(reader); | 448 json_skip_white(reader); |
405 | 449 |
406 ret = json_decode_item(reader, res == NULL ? NULL : &item); | 450 ret = json_decode_item(reader, res == NULL ? NULL : &item, options); |
407 if (ret != OK) | 451 if (ret != OK) |
408 { | 452 { |
409 if (res != NULL) | 453 if (res != NULL) |
410 clear_tv(&tvkey); | 454 clear_tv(&tvkey); |
411 return ret; | 455 return ret; |
567 * | 611 * |
568 * Return FAIL for a decoding error. | 612 * Return FAIL for a decoding error. |
569 * Return MAYBE for an incomplete message. | 613 * Return MAYBE for an incomplete message. |
570 */ | 614 */ |
571 static int | 615 static int |
572 json_decode_item(js_read_T *reader, typval_T *res) | 616 json_decode_item(js_read_T *reader, typval_T *res, int options) |
573 { | 617 { |
574 char_u *p; | 618 char_u *p; |
575 int len; | 619 int len; |
576 | 620 |
577 fill_numbuflen(reader); | 621 fill_numbuflen(reader); |
578 p = reader->js_buf + reader->js_used; | 622 p = reader->js_buf + reader->js_used; |
579 switch (*p) | 623 switch (*p) |
580 { | 624 { |
581 case '[': /* array */ | 625 case '[': /* array */ |
582 return json_decode_array(reader, res); | 626 return json_decode_array(reader, res, options); |
583 | 627 |
584 case '{': /* object */ | 628 case '{': /* object */ |
585 return json_decode_object(reader, res); | 629 return json_decode_object(reader, res, options); |
586 | 630 |
587 case '"': /* string */ | 631 case '"': /* string */ |
588 return json_decode_string(reader, res); | 632 return json_decode_string(reader, res); |
589 | 633 |
590 case ',': /* comma: empty item */ | 634 case ',': /* comma: empty item */ |
635 if ((options & JSON_JS) == 0) | |
636 return FAIL; | |
637 /* FALLTHROUGH */ | |
591 case NUL: /* empty */ | 638 case NUL: /* empty */ |
592 if (res != NULL) | 639 if (res != NULL) |
593 { | 640 { |
594 res->v_type = VAR_SPECIAL; | 641 res->v_type = VAR_SPECIAL; |
595 res->vval.v_number = VVAL_NONE; | 642 res->vval.v_number = VVAL_NONE; |
689 return FAIL; | 736 return FAIL; |
690 } | 737 } |
691 | 738 |
692 /* | 739 /* |
693 * Decode the JSON from "reader" and store the result in "res". | 740 * Decode the JSON from "reader" and store the result in "res". |
741 * "options" can be JSON_JS or zero; | |
694 * Return FAIL if not the whole message was consumed. | 742 * Return FAIL if not the whole message was consumed. |
695 */ | 743 */ |
696 int | 744 int |
697 json_decode_all(js_read_T *reader, typval_T *res) | 745 json_decode_all(js_read_T *reader, typval_T *res, int options) |
698 { | 746 { |
699 int ret; | 747 int ret; |
700 | 748 |
701 /* We get the end once, to avoid calling strlen() many times. */ | 749 /* We find the end once, to avoid calling strlen() many times. */ |
702 reader->js_end = reader->js_buf + STRLEN(reader->js_buf); | 750 reader->js_end = reader->js_buf + STRLEN(reader->js_buf); |
703 json_skip_white(reader); | 751 json_skip_white(reader); |
704 ret = json_decode_item(reader, res); | 752 ret = json_decode_item(reader, res, options); |
705 if (ret != OK) | 753 if (ret != OK) |
706 return FAIL; | 754 return FAIL; |
707 json_skip_white(reader); | 755 json_skip_white(reader); |
708 if (reader->js_buf[reader->js_used] != NUL) | 756 if (reader->js_buf[reader->js_used] != NUL) |
709 return FAIL; | 757 return FAIL; |
710 return OK; | 758 return OK; |
711 } | 759 } |
712 | 760 |
713 /* | 761 /* |
714 * Decode the JSON from "reader" and store the result in "res". | 762 * Decode the JSON from "reader" and store the result in "res". |
763 * "options" can be JSON_JS or zero; | |
715 * Return FAIL if the message has a decoding error or the message is | 764 * Return FAIL if the message has a decoding error or the message is |
716 * truncated. Consumes the message anyway. | 765 * truncated. Consumes the message anyway. |
717 */ | 766 */ |
718 int | 767 int |
719 json_decode(js_read_T *reader, typval_T *res) | 768 json_decode(js_read_T *reader, typval_T *res, int options) |
720 { | 769 { |
721 int ret; | 770 int ret; |
722 | 771 |
723 /* We get the end once, to avoid calling strlen() many times. */ | 772 /* We find the end once, to avoid calling strlen() many times. */ |
724 reader->js_end = reader->js_buf + STRLEN(reader->js_buf); | 773 reader->js_end = reader->js_buf + STRLEN(reader->js_buf); |
725 json_skip_white(reader); | 774 json_skip_white(reader); |
726 ret = json_decode_item(reader, res); | 775 ret = json_decode_item(reader, res, options); |
727 json_skip_white(reader); | 776 json_skip_white(reader); |
728 | 777 |
729 return ret == OK ? OK : FAIL; | 778 return ret == OK ? OK : FAIL; |
730 } | 779 } |
731 | 780 |
732 /* | 781 /* |
733 * Decode the JSON from "reader" to find the end of the message. | 782 * Decode the JSON from "reader" to find the end of the message. |
783 * "options" can be JSON_JS or zero; | |
734 * Return FAIL if the message has a decoding error. | 784 * Return FAIL if the message has a decoding error. |
735 * Return MAYBE if the message is truncated, need to read more. | 785 * Return MAYBE if the message is truncated, need to read more. |
736 * This only works reliable if the message contains an object, array or | 786 * This only works reliable if the message contains an object, array or |
737 * string. A number might be trucated without knowing. | 787 * string. A number might be trucated without knowing. |
738 * Does not advance the reader. | 788 * Does not advance the reader. |
739 */ | 789 */ |
740 int | 790 int |
741 json_find_end(js_read_T *reader) | 791 json_find_end(js_read_T *reader, int options) |
742 { | 792 { |
743 int used_save = reader->js_used; | 793 int used_save = reader->js_used; |
744 int ret; | 794 int ret; |
745 | 795 |
746 /* We get the end once, to avoid calling strlen() many times. */ | 796 /* We find the end once, to avoid calling strlen() many times. */ |
747 reader->js_end = reader->js_buf + STRLEN(reader->js_buf); | 797 reader->js_end = reader->js_buf + STRLEN(reader->js_buf); |
748 json_skip_white(reader); | 798 json_skip_white(reader); |
749 ret = json_decode_item(reader, NULL); | 799 ret = json_decode_item(reader, NULL, options); |
750 reader->js_used = used_save; | 800 reader->js_used = used_save; |
751 return ret; | 801 return ret; |
752 } | 802 } |
753 #endif | 803 #endif |