1 /* vi:set ts=8 sts=4 sw=4 noet: 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 * 13 * Follows this standard: https://tools.ietf.org/html/rfc7159.html 14 */ 15 #define USING_FLOAT_STUFF 16 17 #include "vim.h" 18 19 #if defined(FEAT_EVAL) || defined(PROTO) 20 21 static int json_encode_item(garray_T *gap, typval_T *val, int copyID, int options); 22 23 static char e_json_error[] = N_("E491: json decode error at '%s'"); 24 25 /* 26 * Encode "val" into a JSON format string. 27 * The result is added to "gap" 28 * Returns FAIL on failure and makes gap->ga_data empty. 29 */ 30 static int 31 json_encode_gap(garray_T *gap, typval_T *val, int options) 32 { 33 if (json_encode_item(gap, val, get_copyID(), options) == FAIL) 34 { 35 ga_clear(gap); 36 gap->ga_data = vim_strsave((char_u *)""); 37 return FAIL; 38 } 39 return OK; 40 } 41 42 /* 43 * Encode "val" into a JSON format string. 44 * The result is in allocated memory. 45 * The result is empty when encoding fails. 46 * "options" can contain JSON_JS, JSON_NO_NONE and JSON_NL. 47 */ 48 char_u * 49 json_encode(typval_T *val, int options) 50 { 51 garray_T ga; 52 53 // Store bytes in the growarray. 54 ga_init2(&ga, 1, 4000); 55 json_encode_gap(&ga, val, options); 56 ga_append(&ga, NUL); 57 return ga.ga_data; 58 } 59 60 #if defined(FEAT_JOB_CHANNEL) || defined(PROTO) 61 /* 62 * Encode ["nr", "val"] into a JSON format string in allocated memory. 63 * "options" can contain JSON_JS, JSON_NO_NONE and JSON_NL. 64 * Returns NULL when out of memory. 65 */ 66 char_u * 67 json_encode_nr_expr(int nr, typval_T *val, int options) 68 { 69 typval_T listtv; 70 typval_T nrtv; 71 garray_T ga; 72 73 nrtv.v_type = VAR_NUMBER; 74 nrtv.vval.v_number = nr; 75 if (rettv_list_alloc(&listtv) == FAIL) 76 return NULL; 77 if (list_append_tv(listtv.vval.v_list, &nrtv) == FAIL 78 || list_append_tv(listtv.vval.v_list, val) == FAIL) 79 { 80 list_unref(listtv.vval.v_list); 81 return NULL; 82 } 83 84 ga_init2(&ga, 1, 4000); 85 if (json_encode_gap(&ga, &listtv, options) == OK && (options & JSON_NL)) 86 ga_append(&ga, '\n'); 87 list_unref(listtv.vval.v_list); 88 ga_append(&ga, NUL); 89 return ga.ga_data; 90 } 91 #endif 92 93 static void 94 write_string(garray_T *gap, char_u *str) 95 { 96 char_u *res = str; 97 char_u numbuf[NUMBUFLEN]; 98 99 if (res == NULL) 100 ga_concat(gap, (char_u *)"\"\""); 101 else 102 { 103 #if defined(USE_ICONV) 104 vimconv_T conv; 105 char_u *converted = NULL; 106 107 if (!enc_utf8) 108 { 109 // Convert the text from 'encoding' to utf-8, the JSON string is 110 // always utf-8. 111 conv.vc_type = CONV_NONE; 112 convert_setup(&conv, p_enc, (char_u*)"utf-8"); 113 if (conv.vc_type != CONV_NONE) 114 converted = res = string_convert(&conv, res, NULL); 115 convert_setup(&conv, NULL, NULL); 116 } 117 #endif 118 ga_append(gap, '"'); 119 while (*res != NUL) 120 { 121 int c; 122 // always use utf-8 encoding, ignore 'encoding' 123 c = utf_ptr2char(res); 124 125 switch (c) 126 { 127 case 0x08: 128 ga_append(gap, '\\'); ga_append(gap, 'b'); break; 129 case 0x09: 130 ga_append(gap, '\\'); ga_append(gap, 't'); break; 131 case 0x0a: 132 ga_append(gap, '\\'); ga_append(gap, 'n'); break; 133 case 0x0c: 134 ga_append(gap, '\\'); ga_append(gap, 'f'); break; 135 case 0x0d: 136 ga_append(gap, '\\'); ga_append(gap, 'r'); break; 137 case 0x22: // " 138 case 0x5c: // backslash 139 ga_append(gap, '\\'); 140 ga_append(gap, c); 141 break; 142 default: 143 if (c >= 0x20) 144 { 145 numbuf[utf_char2bytes(c, numbuf)] = NUL; 146 ga_concat(gap, numbuf); 147 } 148 else 149 { 150 vim_snprintf((char *)numbuf, NUMBUFLEN, 151 "\\u%04lx", (long)c); 152 ga_concat(gap, numbuf); 153 } 154 } 155 res += utf_ptr2len(res); 156 } 157 ga_append(gap, '"'); 158 #if defined(USE_ICONV) 159 vim_free(converted); 160 #endif 161 } 162 } 163 164 /* 165 * Return TRUE if "key" can be used without quotes. 166 * That is when it starts with a letter and only contains letters, digits and 167 * underscore. 168 */ 169 static int 170 is_simple_key(char_u *key) 171 { 172 char_u *p; 173 174 if (!ASCII_ISALPHA(*key)) 175 return FALSE; 176 for (p = key + 1; *p != NUL; ++p) 177 if (!ASCII_ISALPHA(*p) && *p != '_' && !vim_isdigit(*p)) 178 return FALSE; 179 return TRUE; 180 } 181 182 /* 183 * Encode "val" into "gap". 184 * Return FAIL or OK. 185 */ 186 static int 187 json_encode_item(garray_T *gap, typval_T *val, int copyID, int options) 188 { 189 char_u numbuf[NUMBUFLEN]; 190 char_u *res; 191 blob_T *b; 192 list_T *l; 193 dict_T *d; 194 int i; 195 196 switch (val->v_type) 197 { 198 case VAR_BOOL: 199 switch ((long)val->vval.v_number) 200 { 201 case VVAL_FALSE: ga_concat(gap, (char_u *)"false"); break; 202 case VVAL_TRUE: ga_concat(gap, (char_u *)"true"); break; 203 } 204 break; 205 206 case VAR_SPECIAL: 207 switch ((long)val->vval.v_number) 208 { 209 case VVAL_NONE: if ((options & JSON_JS) != 0 210 && (options & JSON_NO_NONE) == 0) 211 // empty item 212 break; 213 // FALLTHROUGH 214 case VVAL_NULL: ga_concat(gap, (char_u *)"null"); break; 215 } 216 break; 217 218 case VAR_NUMBER: 219 vim_snprintf((char *)numbuf, NUMBUFLEN, "%lld", 220 (varnumber_T)val->vval.v_number); 221 ga_concat(gap, numbuf); 222 break; 223 224 case VAR_STRING: 225 res = val->vval.v_string; 226 write_string(gap, res); 227 break; 228 229 case VAR_FUNC: 230 case VAR_PARTIAL: 231 case VAR_JOB: 232 case VAR_CHANNEL: 233 case VAR_INSTR: 234 semsg(_(e_cannot_json_encode_str), vartype_name(val->v_type)); 235 return FAIL; 236 237 case VAR_BLOB: 238 b = val->vval.v_blob; 239 if (b == NULL || b->bv_ga.ga_len == 0) 240 ga_concat(gap, (char_u *)"[]"); 241 else 242 { 243 ga_append(gap, '['); 244 for (i = 0; i < b->bv_ga.ga_len; i++) 245 { 246 if (i > 0) 247 ga_concat(gap, (char_u *)","); 248 vim_snprintf((char *)numbuf, NUMBUFLEN, "%d", 249 (int)blob_get(b, i)); 250 ga_concat(gap, numbuf); 251 } 252 ga_append(gap, ']'); 253 } 254 break; 255 256 case VAR_LIST: 257 l = val->vval.v_list; 258 if (l == NULL) 259 ga_concat(gap, (char_u *)"[]"); 260 else 261 { 262 if (l->lv_copyID == copyID) 263 ga_concat(gap, (char_u *)"[]"); 264 else 265 { 266 listitem_T *li; 267 268 l->lv_copyID = copyID; 269 ga_append(gap, '['); 270 CHECK_LIST_MATERIALIZE(l); 271 for (li = l->lv_first; li != NULL && !got_int; ) 272 { 273 if (json_encode_item(gap, &li->li_tv, copyID, 274 options & JSON_JS) == FAIL) 275 return FAIL; 276 if ((options & JSON_JS) 277 && li->li_next == NULL 278 && li->li_tv.v_type == VAR_SPECIAL 279 && li->li_tv.vval.v_number == VVAL_NONE) 280 // add an extra comma if the last item is v:none 281 ga_append(gap, ','); 282 li = li->li_next; 283 if (li != NULL) 284 ga_append(gap, ','); 285 } 286 ga_append(gap, ']'); 287 l->lv_copyID = 0; 288 } 289 } 290 break; 291 292 case VAR_DICT: 293 d = val->vval.v_dict; 294 if (d == NULL) 295 ga_concat(gap, (char_u *)"{}"); 296 else 297 { 298 if (d->dv_copyID == copyID) 299 ga_concat(gap, (char_u *)"{}"); 300 else 301 { 302 int first = TRUE; 303 int todo = (int)d->dv_hashtab.ht_used; 304 hashitem_T *hi; 305 306 d->dv_copyID = copyID; 307 ga_append(gap, '{'); 308 309 for (hi = d->dv_hashtab.ht_array; todo > 0 && !got_int; 310 ++hi) 311 if (!HASHITEM_EMPTY(hi)) 312 { 313 --todo; 314 if (first) 315 first = FALSE; 316 else 317 ga_append(gap, ','); 318 if ((options & JSON_JS) 319 && is_simple_key(hi->hi_key)) 320 ga_concat(gap, hi->hi_key); 321 else 322 write_string(gap, hi->hi_key); 323 ga_append(gap, ':'); 324 if (json_encode_item(gap, &dict_lookup(hi)->di_tv, 325 copyID, options | JSON_NO_NONE) == FAIL) 326 return FAIL; 327 } 328 ga_append(gap, '}'); 329 d->dv_copyID = 0; 330 } 331 } 332 break; 333 334 case VAR_FLOAT: 335 #ifdef FEAT_FLOAT 336 # if defined(HAVE_MATH_H) 337 if (isnan(val->vval.v_float)) 338 ga_concat(gap, (char_u *)"NaN"); 339 else if (isinf(val->vval.v_float)) 340 { 341 if (val->vval.v_float < 0.0) 342 ga_concat(gap, (char_u *)"-Infinity"); 343 else 344 ga_concat(gap, (char_u *)"Infinity"); 345 } 346 else 347 # endif 348 { 349 vim_snprintf((char *)numbuf, NUMBUFLEN, "%g", 350 val->vval.v_float); 351 ga_concat(gap, numbuf); 352 } 353 break; 354 #endif 355 case VAR_UNKNOWN: 356 case VAR_ANY: 357 case VAR_VOID: 358 internal_error_no_abort("json_encode_item()"); 359 return FAIL; 360 } 361 return OK; 362 } 363 364 /* 365 * When "reader" has less than NUMBUFLEN bytes available, call the fill 366 * callback to get more. 367 */ 368 static void 369 fill_numbuflen(js_read_T *reader) 370 { 371 if (reader->js_fill != NULL && (int)(reader->js_end - reader->js_buf) 372 - reader->js_used < NUMBUFLEN) 373 { 374 if (reader->js_fill(reader)) 375 reader->js_end = reader->js_buf + STRLEN(reader->js_buf); 376 } 377 } 378 379 /* 380 * Skip white space in "reader". All characters <= space are considered white 381 * space. 382 * Also tops up readahead when needed. 383 */ 384 static void 385 json_skip_white(js_read_T *reader) 386 { 387 int c; 388 389 for (;;) 390 { 391 c = reader->js_buf[reader->js_used]; 392 if (reader->js_fill != NULL && c == NUL) 393 { 394 if (reader->js_fill(reader)) 395 { 396 reader->js_end = reader->js_buf + STRLEN(reader->js_buf); 397 continue; 398 } 399 } 400 if (c == NUL || c > ' ') 401 break; 402 ++reader->js_used; 403 } 404 fill_numbuflen(reader); 405 } 406 407 static int 408 json_decode_string(js_read_T *reader, typval_T *res, int quote) 409 { 410 garray_T ga; 411 int len; 412 char_u *p; 413 int c; 414 varnumber_T nr; 415 416 if (res != NULL) 417 ga_init2(&ga, 1, 200); 418 419 p = reader->js_buf + reader->js_used + 1; // skip over " or ' 420 while (*p != quote) 421 { 422 // The JSON is always expected to be utf-8, thus use utf functions 423 // here. The string is converted below if needed. 424 if (*p == NUL || p[1] == NUL || utf_ptr2len(p) < utf_byte2len(*p)) 425 { 426 // Not enough bytes to make a character or end of the string. Get 427 // more if possible. 428 if (reader->js_fill == NULL) 429 break; 430 len = (int)(reader->js_end - p); 431 reader->js_used = (int)(p - reader->js_buf); 432 if (!reader->js_fill(reader)) 433 break; // didn't get more 434 p = reader->js_buf + reader->js_used; 435 reader->js_end = reader->js_buf + STRLEN(reader->js_buf); 436 continue; 437 } 438 439 if (*p == '\\') 440 { 441 c = -1; 442 switch (p[1]) 443 { 444 case '\\': c = '\\'; break; 445 case '"': c = '"'; break; 446 case 'b': c = BS; break; 447 case 't': c = TAB; break; 448 case 'n': c = NL; break; 449 case 'f': c = FF; break; 450 case 'r': c = CAR; break; 451 case 'u': 452 if (reader->js_fill != NULL 453 && (int)(reader->js_end - p) < NUMBUFLEN) 454 { 455 reader->js_used = (int)(p - reader->js_buf); 456 if (reader->js_fill(reader)) 457 { 458 p = reader->js_buf + reader->js_used; 459 reader->js_end = reader->js_buf 460 + STRLEN(reader->js_buf); 461 } 462 } 463 nr = 0; 464 len = 0; 465 vim_str2nr(p + 2, NULL, &len, 466 STR2NR_HEX + STR2NR_FORCE, &nr, NULL, 4, TRUE); 467 if (len == 0) 468 { 469 if (res != NULL) 470 ga_clear(&ga); 471 return FAIL; 472 } 473 p += len + 2; 474 if (0xd800 <= nr && nr <= 0xdfff 475 && (int)(reader->js_end - p) >= 6 476 && *p == '\\' && *(p+1) == 'u') 477 { 478 varnumber_T nr2 = 0; 479 480 // decode surrogate pair: \ud812\u3456 481 len = 0; 482 vim_str2nr(p + 2, NULL, &len, 483 STR2NR_HEX + STR2NR_FORCE, &nr2, NULL, 4, TRUE); 484 if (len == 0) 485 { 486 if (res != NULL) 487 ga_clear(&ga); 488 return FAIL; 489 } 490 if (0xdc00 <= nr2 && nr2 <= 0xdfff) 491 { 492 p += len + 2; 493 nr = (((nr - 0xd800) << 10) | 494 ((nr2 - 0xdc00) & 0x3ff)) + 0x10000; 495 } 496 } 497 if (res != NULL) 498 { 499 char_u buf[NUMBUFLEN]; 500 501 buf[utf_char2bytes((int)nr, buf)] = NUL; 502 ga_concat(&ga, buf); 503 } 504 break; 505 default: 506 // not a special char, skip over backslash 507 ++p; 508 continue; 509 } 510 if (c > 0) 511 { 512 p += 2; 513 if (res != NULL) 514 ga_append(&ga, c); 515 } 516 } 517 else 518 { 519 len = utf_ptr2len(p); 520 if (res != NULL) 521 { 522 if (ga_grow(&ga, len) == FAIL) 523 { 524 ga_clear(&ga); 525 return FAIL; 526 } 527 mch_memmove((char *)ga.ga_data + ga.ga_len, p, (size_t)len); 528 ga.ga_len += len; 529 } 530 p += len; 531 } 532 } 533 534 reader->js_used = (int)(p - reader->js_buf); 535 if (*p == quote) 536 { 537 ++reader->js_used; 538 if (res != NULL) 539 { 540 ga_append(&ga, NUL); 541 res->v_type = VAR_STRING; 542 #if defined(USE_ICONV) 543 if (!enc_utf8) 544 { 545 vimconv_T conv; 546 547 // Convert the utf-8 string to 'encoding'. 548 conv.vc_type = CONV_NONE; 549 convert_setup(&conv, (char_u*)"utf-8", p_enc); 550 if (conv.vc_type != CONV_NONE) 551 { 552 res->vval.v_string = 553 string_convert(&conv, ga.ga_data, NULL); 554 vim_free(ga.ga_data); 555 } 556 convert_setup(&conv, NULL, NULL); 557 } 558 else 559 #endif 560 res->vval.v_string = ga.ga_data; 561 } 562 return OK; 563 } 564 if (res != NULL) 565 { 566 res->v_type = VAR_SPECIAL; 567 res->vval.v_number = VVAL_NONE; 568 ga_clear(&ga); 569 } 570 return MAYBE; 571 } 572 573 typedef enum { 574 JSON_ARRAY, // parsing items in an array 575 JSON_OBJECT_KEY, // parsing key of an object 576 JSON_OBJECT // parsing item in an object, after the key 577 } json_decode_T; 578 579 typedef struct { 580 json_decode_T jd_type; 581 typval_T jd_tv; // the list or dict 582 typval_T jd_key_tv; 583 char_u *jd_key; 584 } json_dec_item_T; 585 586 /* 587 * Decode one item and put it in "res". If "res" is NULL only advance. 588 * Must already have skipped white space. 589 * 590 * Return FAIL for a decoding error (and give an error). 591 * Return MAYBE for an incomplete message. 592 */ 593 static int 594 json_decode_item(js_read_T *reader, typval_T *res, int options) 595 { 596 char_u *p; 597 int i; 598 int len; 599 int retval; 600 garray_T stack; 601 typval_T item; 602 typval_T *cur_item; 603 json_dec_item_T *top_item; 604 char_u key_buf[NUMBUFLEN]; 605 606 ga_init2(&stack, sizeof(json_dec_item_T), 100); 607 cur_item = res; 608 init_tv(&item); 609 if (res != NULL) 610 init_tv(res); 611 612 fill_numbuflen(reader); 613 p = reader->js_buf + reader->js_used; 614 for (;;) 615 { 616 top_item = NULL; 617 if (stack.ga_len > 0) 618 { 619 top_item = ((json_dec_item_T *)stack.ga_data) + stack.ga_len - 1; 620 json_skip_white(reader); 621 p = reader->js_buf + reader->js_used; 622 if (*p == NUL) 623 { 624 retval = MAYBE; 625 goto theend; 626 } 627 if (top_item->jd_type == JSON_OBJECT_KEY 628 || top_item->jd_type == JSON_ARRAY) 629 { 630 // Check for end of object or array. 631 if (*p == (top_item->jd_type == JSON_ARRAY ? ']' : '}')) 632 { 633 ++reader->js_used; // consume the ']' or '}' 634 --stack.ga_len; 635 if (stack.ga_len == 0) 636 { 637 retval = OK; 638 goto theend; 639 } 640 if (cur_item != NULL) 641 cur_item = &top_item->jd_tv; 642 goto item_end; 643 } 644 } 645 } 646 647 if (top_item != NULL && top_item->jd_type == JSON_OBJECT_KEY 648 && (options & JSON_JS) 649 && reader->js_buf[reader->js_used] != '"' 650 && reader->js_buf[reader->js_used] != '\'' 651 && reader->js_buf[reader->js_used] != '[' 652 && reader->js_buf[reader->js_used] != '{') 653 { 654 char_u *key; 655 656 // accept an object key that is not in quotes 657 key = p = reader->js_buf + reader->js_used; 658 while (*p != NUL && *p != ':' && *p > ' ') 659 ++p; 660 if (cur_item != NULL) 661 { 662 cur_item->v_type = VAR_STRING; 663 cur_item->vval.v_string = vim_strnsave(key, p - key); 664 top_item->jd_key = cur_item->vval.v_string; 665 } 666 reader->js_used += (int)(p - key); 667 } 668 else 669 { 670 switch (*p) 671 { 672 case '[': // start of array 673 if (top_item && top_item->jd_type == JSON_OBJECT_KEY) 674 { 675 retval = FAIL; 676 break; 677 } 678 if (ga_grow(&stack, 1) == FAIL) 679 { 680 retval = FAIL; 681 break; 682 } 683 if (cur_item != NULL && rettv_list_alloc(cur_item) == FAIL) 684 { 685 cur_item->v_type = VAR_SPECIAL; 686 cur_item->vval.v_number = VVAL_NONE; 687 retval = FAIL; 688 break; 689 } 690 691 ++reader->js_used; // consume the '[' 692 top_item = ((json_dec_item_T *)stack.ga_data) 693 + stack.ga_len; 694 top_item->jd_type = JSON_ARRAY; 695 ++stack.ga_len; 696 if (cur_item != NULL) 697 { 698 top_item->jd_tv = *cur_item; 699 cur_item = &item; 700 } 701 continue; 702 703 case '{': // start of object 704 if (top_item && top_item->jd_type == JSON_OBJECT_KEY) 705 { 706 retval = FAIL; 707 break; 708 } 709 if (ga_grow(&stack, 1) == FAIL) 710 { 711 retval = FAIL; 712 break; 713 } 714 if (cur_item != NULL && rettv_dict_alloc(cur_item) == FAIL) 715 { 716 cur_item->v_type = VAR_SPECIAL; 717 cur_item->vval.v_number = VVAL_NONE; 718 retval = FAIL; 719 break; 720 } 721 722 ++reader->js_used; // consume the '{' 723 top_item = ((json_dec_item_T *)stack.ga_data) 724 + stack.ga_len; 725 top_item->jd_type = JSON_OBJECT_KEY; 726 ++stack.ga_len; 727 if (cur_item != NULL) 728 { 729 top_item->jd_tv = *cur_item; 730 cur_item = &top_item->jd_key_tv; 731 } 732 continue; 733 734 case '"': // string 735 retval = json_decode_string(reader, cur_item, *p); 736 break; 737 738 case '\'': 739 if (options & JSON_JS) 740 retval = json_decode_string(reader, cur_item, *p); 741 else 742 { 743 semsg(_(e_json_error), p); 744 retval = FAIL; 745 } 746 break; 747 748 case ',': // comma: empty item 749 if ((options & JSON_JS) == 0) 750 { 751 semsg(_(e_json_error), p); 752 retval = FAIL; 753 break; 754 } 755 // FALLTHROUGH 756 case NUL: // empty 757 if (cur_item != NULL) 758 { 759 cur_item->v_type = VAR_SPECIAL; 760 cur_item->vval.v_number = VVAL_NONE; 761 } 762 retval = OK; 763 break; 764 765 default: 766 if (VIM_ISDIGIT(*p) || (*p == '-' 767 && (VIM_ISDIGIT(p[1]) || p[1] == NUL))) 768 { 769 char_u *sp = p; 770 771 if (*sp == '-') 772 { 773 ++sp; 774 if (*sp == NUL) 775 { 776 retval = MAYBE; 777 break; 778 } 779 if (!VIM_ISDIGIT(*sp)) 780 { 781 semsg(_(e_json_error), p); 782 retval = FAIL; 783 break; 784 } 785 } 786 sp = skipdigits(sp); 787 #ifdef FEAT_FLOAT 788 if (*sp == '.' || *sp == 'e' || *sp == 'E') 789 { 790 if (cur_item == NULL) 791 { 792 float_T f; 793 794 len = string2float(p, &f, FALSE); 795 } 796 else 797 { 798 cur_item->v_type = VAR_FLOAT; 799 len = string2float(p, &cur_item->vval.v_float, 800 FALSE); 801 } 802 } 803 else 804 #endif 805 { 806 varnumber_T nr; 807 808 vim_str2nr(reader->js_buf + reader->js_used, 809 NULL, &len, 0, // what 810 &nr, NULL, 0, TRUE); 811 if (len == 0) 812 { 813 semsg(_(e_json_error), p); 814 retval = FAIL; 815 goto theend; 816 } 817 if (cur_item != NULL) 818 { 819 cur_item->v_type = VAR_NUMBER; 820 cur_item->vval.v_number = nr; 821 } 822 } 823 reader->js_used += len; 824 retval = OK; 825 break; 826 } 827 if (STRNICMP((char *)p, "false", 5) == 0) 828 { 829 reader->js_used += 5; 830 if (cur_item != NULL) 831 { 832 cur_item->v_type = VAR_BOOL; 833 cur_item->vval.v_number = VVAL_FALSE; 834 } 835 retval = OK; 836 break; 837 } 838 if (STRNICMP((char *)p, "true", 4) == 0) 839 { 840 reader->js_used += 4; 841 if (cur_item != NULL) 842 { 843 cur_item->v_type = VAR_BOOL; 844 cur_item->vval.v_number = VVAL_TRUE; 845 } 846 retval = OK; 847 break; 848 } 849 if (STRNICMP((char *)p, "null", 4) == 0) 850 { 851 reader->js_used += 4; 852 if (cur_item != NULL) 853 { 854 cur_item->v_type = VAR_SPECIAL; 855 cur_item->vval.v_number = VVAL_NULL; 856 } 857 retval = OK; 858 break; 859 } 860 #ifdef FEAT_FLOAT 861 if (STRNICMP((char *)p, "NaN", 3) == 0) 862 { 863 reader->js_used += 3; 864 if (cur_item != NULL) 865 { 866 cur_item->v_type = VAR_FLOAT; 867 cur_item->vval.v_float = NAN; 868 } 869 retval = OK; 870 break; 871 } 872 if (STRNICMP((char *)p, "-Infinity", 9) == 0) 873 { 874 reader->js_used += 9; 875 if (cur_item != NULL) 876 { 877 cur_item->v_type = VAR_FLOAT; 878 cur_item->vval.v_float = -INFINITY; 879 } 880 retval = OK; 881 break; 882 } 883 if (STRNICMP((char *)p, "Infinity", 8) == 0) 884 { 885 reader->js_used += 8; 886 if (cur_item != NULL) 887 { 888 cur_item->v_type = VAR_FLOAT; 889 cur_item->vval.v_float = INFINITY; 890 } 891 retval = OK; 892 break; 893 } 894 #endif 895 // check for truncated name 896 len = (int)(reader->js_end 897 - (reader->js_buf + reader->js_used)); 898 if ( 899 (len < 5 && STRNICMP((char *)p, "false", len) == 0) 900 #ifdef FEAT_FLOAT 901 || (len < 9 && STRNICMP((char *)p, "-Infinity", len) == 0) 902 || (len < 8 && STRNICMP((char *)p, "Infinity", len) == 0) 903 || (len < 3 && STRNICMP((char *)p, "NaN", len) == 0) 904 #endif 905 || (len < 4 && (STRNICMP((char *)p, "true", len) == 0 906 || STRNICMP((char *)p, "null", len) == 0))) 907 908 retval = MAYBE; 909 else 910 retval = FAIL; 911 break; 912 } 913 914 // We are finished when retval is FAIL or MAYBE and when at the 915 // toplevel. 916 if (retval == FAIL) 917 break; 918 if (retval == MAYBE || stack.ga_len == 0) 919 goto theend; 920 921 if (top_item != NULL && top_item->jd_type == JSON_OBJECT_KEY 922 && cur_item != NULL) 923 { 924 #ifdef FEAT_FLOAT 925 if (cur_item->v_type == VAR_FLOAT) 926 { 927 // cannot use a float as a key 928 emsg(_(e_float_as_string)); 929 retval = FAIL; 930 goto theend; 931 } 932 #endif 933 top_item->jd_key = tv_get_string_buf_chk(cur_item, key_buf); 934 if (top_item->jd_key == NULL) 935 { 936 emsg(_(e_invarg)); 937 retval = FAIL; 938 goto theend; 939 } 940 } 941 } 942 943 item_end: 944 top_item = ((json_dec_item_T *)stack.ga_data) + stack.ga_len - 1; 945 switch (top_item->jd_type) 946 { 947 case JSON_ARRAY: 948 if (res != NULL) 949 { 950 listitem_T *li = listitem_alloc(); 951 952 if (li == NULL) 953 { 954 clear_tv(cur_item); 955 retval = FAIL; 956 goto theend; 957 } 958 li->li_tv = *cur_item; 959 list_append(top_item->jd_tv.vval.v_list, li); 960 } 961 if (cur_item != NULL) 962 cur_item = &item; 963 964 json_skip_white(reader); 965 p = reader->js_buf + reader->js_used; 966 if (*p == ',') 967 ++reader->js_used; 968 else if (*p != ']') 969 { 970 if (*p == NUL) 971 retval = MAYBE; 972 else 973 { 974 semsg(_(e_json_error), p); 975 retval = FAIL; 976 } 977 goto theend; 978 } 979 break; 980 981 case JSON_OBJECT_KEY: 982 json_skip_white(reader); 983 p = reader->js_buf + reader->js_used; 984 if (*p != ':') 985 { 986 if (cur_item != NULL) 987 clear_tv(cur_item); 988 if (*p == NUL) 989 retval = MAYBE; 990 else 991 { 992 semsg(_(e_json_error), p); 993 retval = FAIL; 994 } 995 goto theend; 996 } 997 ++reader->js_used; 998 json_skip_white(reader); 999 top_item->jd_type = JSON_OBJECT; 1000 if (cur_item != NULL) 1001 cur_item = &item; 1002 break; 1003 1004 case JSON_OBJECT: 1005 if (cur_item != NULL 1006 && dict_find(top_item->jd_tv.vval.v_dict, 1007 top_item->jd_key, -1) != NULL) 1008 { 1009 semsg(_("E938: Duplicate key in JSON: \"%s\""), 1010 top_item->jd_key); 1011 clear_tv(cur_item); 1012 retval = FAIL; 1013 goto theend; 1014 } 1015 1016 if (cur_item != NULL) 1017 { 1018 dictitem_T *di = dictitem_alloc(top_item->jd_key); 1019 1020 clear_tv(&top_item->jd_key_tv); 1021 if (di == NULL) 1022 { 1023 clear_tv(cur_item); 1024 retval = FAIL; 1025 goto theend; 1026 } 1027 di->di_tv = *cur_item; 1028 di->di_tv.v_lock = 0; 1029 if (dict_add(top_item->jd_tv.vval.v_dict, di) == FAIL) 1030 { 1031 dictitem_free(di); 1032 retval = FAIL; 1033 goto theend; 1034 } 1035 } 1036 1037 json_skip_white(reader); 1038 p = reader->js_buf + reader->js_used; 1039 if (*p == ',') 1040 ++reader->js_used; 1041 else if (*p != '}') 1042 { 1043 if (*p == NUL) 1044 retval = MAYBE; 1045 else 1046 { 1047 semsg(_(e_json_error), p); 1048 retval = FAIL; 1049 } 1050 goto theend; 1051 } 1052 top_item->jd_type = JSON_OBJECT_KEY; 1053 if (cur_item != NULL) 1054 cur_item = &top_item->jd_key_tv; 1055 break; 1056 } 1057 } 1058 1059 // Get here when parsing failed. 1060 if (res != NULL) 1061 { 1062 clear_tv(res); 1063 res->v_type = VAR_SPECIAL; 1064 res->vval.v_number = VVAL_NONE; 1065 } 1066 semsg(_(e_json_error), p); 1067 1068 theend: 1069 for (i = 0; i < stack.ga_len; i++) 1070 clear_tv(&(((json_dec_item_T *)stack.ga_data) + i)->jd_key_tv); 1071 ga_clear(&stack); 1072 1073 return retval; 1074 } 1075 1076 /* 1077 * Decode the JSON from "reader" and store the result in "res". 1078 * "options" can be JSON_JS or zero; 1079 * Return FAIL if not the whole message was consumed. 1080 */ 1081 static int 1082 json_decode_all(js_read_T *reader, typval_T *res, int options) 1083 { 1084 int ret; 1085 1086 // We find the end once, to avoid calling strlen() many times. 1087 reader->js_end = reader->js_buf + STRLEN(reader->js_buf); 1088 json_skip_white(reader); 1089 ret = json_decode_item(reader, res, options); 1090 if (ret != OK) 1091 { 1092 if (ret == MAYBE) 1093 semsg(_(e_json_error), reader->js_buf); 1094 return FAIL; 1095 } 1096 json_skip_white(reader); 1097 if (reader->js_buf[reader->js_used] != NUL) 1098 { 1099 semsg(_(e_trailing_arg), reader->js_buf + reader->js_used); 1100 return FAIL; 1101 } 1102 return OK; 1103 } 1104 1105 #if defined(FEAT_JOB_CHANNEL) || defined(PROTO) 1106 /* 1107 * Decode the JSON from "reader" and store the result in "res". 1108 * "options" can be JSON_JS or zero; 1109 * Return FAIL for a decoding error. 1110 * Return MAYBE for an incomplete message. 1111 * Consumes the message anyway. 1112 */ 1113 int 1114 json_decode(js_read_T *reader, typval_T *res, int options) 1115 { 1116 int ret; 1117 1118 // We find the end once, to avoid calling strlen() many times. 1119 reader->js_end = reader->js_buf + STRLEN(reader->js_buf); 1120 json_skip_white(reader); 1121 ret = json_decode_item(reader, res, options); 1122 json_skip_white(reader); 1123 1124 return ret; 1125 } 1126 #endif 1127 1128 /* 1129 * Decode the JSON from "reader" to find the end of the message. 1130 * "options" can be JSON_JS or zero. 1131 * This is only used for testing. 1132 * Return FAIL if the message has a decoding error. 1133 * Return MAYBE if the message is truncated, need to read more. 1134 * This only works reliable if the message contains an object, array or 1135 * string. A number might be truncated without knowing. 1136 * Does not advance the reader. 1137 */ 1138 int 1139 json_find_end(js_read_T *reader, int options) 1140 { 1141 int used_save = reader->js_used; 1142 int ret; 1143 1144 // We find the end once, to avoid calling strlen() many times. 1145 reader->js_end = reader->js_buf + STRLEN(reader->js_buf); 1146 json_skip_white(reader); 1147 ret = json_decode_item(reader, NULL, options); 1148 reader->js_used = used_save; 1149 return ret; 1150 } 1151 1152 /* 1153 * "js_decode()" function 1154 */ 1155 void 1156 f_js_decode(typval_T *argvars, typval_T *rettv) 1157 { 1158 js_read_T reader; 1159 1160 if (in_vim9script() && check_for_string_arg(argvars, 0) == FAIL) 1161 return; 1162 1163 reader.js_buf = tv_get_string(&argvars[0]); 1164 reader.js_fill = NULL; 1165 reader.js_used = 0; 1166 if (json_decode_all(&reader, rettv, JSON_JS) != OK) 1167 emsg(_(e_invarg)); 1168 } 1169 1170 /* 1171 * "js_encode()" function 1172 */ 1173 void 1174 f_js_encode(typval_T *argvars, typval_T *rettv) 1175 { 1176 rettv->v_type = VAR_STRING; 1177 rettv->vval.v_string = json_encode(&argvars[0], JSON_JS); 1178 } 1179 1180 /* 1181 * "json_decode()" function 1182 */ 1183 void 1184 f_json_decode(typval_T *argvars, typval_T *rettv) 1185 { 1186 js_read_T reader; 1187 1188 if (in_vim9script() && check_for_string_arg(argvars, 0) == FAIL) 1189 return; 1190 1191 reader.js_buf = tv_get_string(&argvars[0]); 1192 reader.js_fill = NULL; 1193 reader.js_used = 0; 1194 json_decode_all(&reader, rettv, 0); 1195 } 1196 1197 /* 1198 * "json_encode()" function 1199 */ 1200 void 1201 f_json_encode(typval_T *argvars, typval_T *rettv) 1202 { 1203 rettv->v_type = VAR_STRING; 1204 rettv->vval.v_string = json_encode(&argvars[0], 0); 1205 } 1206 #endif 1207