1 /* 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 * 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 static int json_decode_item(js_read_T *reader, typval_T *res, int options); 23 24 /* 25 * Encode "val" into a JSON format string. 26 * The result is in allocated memory. 27 * The result is empty when encoding fails. 28 * "options" can be JSON_JS or zero; 29 */ 30 char_u * 31 json_encode(typval_T *val, int options) 32 { 33 garray_T ga; 34 35 /* Store bytes in the growarray. */ 36 ga_init2(&ga, 1, 4000); 37 if (json_encode_item(&ga, val, get_copyID(), options) == FAIL) 38 { 39 vim_free(ga.ga_data); 40 return vim_strsave((char_u *)""); 41 } 42 return ga.ga_data; 43 } 44 45 /* 46 * Encode ["nr", "val"] into a JSON format string in allocated memory. 47 * "options" can be JSON_JS or zero; 48 * Returns NULL when out of memory. 49 */ 50 char_u * 51 json_encode_nr_expr(int nr, typval_T *val, int options) 52 { 53 typval_T listtv; 54 typval_T nrtv; 55 char_u *text; 56 57 nrtv.v_type = VAR_NUMBER; 58 nrtv.vval.v_number = nr; 59 if (rettv_list_alloc(&listtv) == FAIL) 60 return NULL; 61 if (list_append_tv(listtv.vval.v_list, &nrtv) == FAIL 62 || list_append_tv(listtv.vval.v_list, val) == FAIL) 63 { 64 list_unref(listtv.vval.v_list); 65 return NULL; 66 } 67 68 text = json_encode(&listtv, options); 69 list_unref(listtv.vval.v_list); 70 return text; 71 } 72 73 static void 74 write_string(garray_T *gap, char_u *str) 75 { 76 char_u *res = str; 77 char_u numbuf[NUMBUFLEN]; 78 79 if (res == NULL) 80 ga_concat(gap, (char_u *)"null"); 81 else 82 { 83 #if defined(FEAT_MBYTE) && defined(USE_ICONV) 84 vimconv_T conv; 85 char_u *converted = NULL; 86 87 if (!enc_utf8) 88 { 89 /* Convert the text from 'encoding' to utf-8, the JSON string is 90 * always utf-8. */ 91 conv.vc_type = CONV_NONE; 92 convert_setup(&conv, p_enc, (char_u*)"utf-8"); 93 if (conv.vc_type != CONV_NONE) 94 converted = res = string_convert(&conv, res, NULL); 95 convert_setup(&conv, NULL, NULL); 96 } 97 #endif 98 ga_append(gap, '"'); 99 while (*res != NUL) 100 { 101 int c; 102 #ifdef FEAT_MBYTE 103 /* always use utf-8 encoding, ignore 'encoding' */ 104 c = utf_ptr2char(res); 105 #else 106 c = *res; 107 #endif 108 109 switch (c) 110 { 111 case 0x08: 112 ga_append(gap, '\\'); ga_append(gap, 'b'); break; 113 case 0x09: 114 ga_append(gap, '\\'); ga_append(gap, 't'); break; 115 case 0x0a: 116 ga_append(gap, '\\'); ga_append(gap, 'n'); break; 117 case 0x0c: 118 ga_append(gap, '\\'); ga_append(gap, 'f'); break; 119 case 0x0d: 120 ga_append(gap, '\\'); ga_append(gap, 'r'); break; 121 case 0x22: /* " */ 122 case 0x5c: /* \ */ 123 ga_append(gap, '\\'); 124 ga_append(gap, c); 125 break; 126 default: 127 if (c >= 0x20) 128 { 129 #ifdef FEAT_MBYTE 130 numbuf[utf_char2bytes(c, numbuf)] = NUL; 131 #else 132 numbuf[0] = c; 133 numbuf[1] = NUL; 134 #endif 135 ga_concat(gap, numbuf); 136 } 137 else 138 { 139 vim_snprintf((char *)numbuf, NUMBUFLEN, 140 "\\u%04lx", (long)c); 141 ga_concat(gap, numbuf); 142 } 143 } 144 #ifdef FEAT_MBYTE 145 res += utf_ptr2len(res); 146 #else 147 ++res; 148 #endif 149 } 150 ga_append(gap, '"'); 151 #if defined(FEAT_MBYTE) && defined(USE_ICONV) 152 vim_free(converted); 153 #endif 154 } 155 } 156 157 /* 158 * Return TRUE if "key" can be used without quotes. 159 * That is when it starts with a letter and only contains letters, digits and 160 * underscore. 161 */ 162 static int 163 is_simple_key(char_u *key) 164 { 165 char_u *p; 166 167 if (!ASCII_ISALPHA(*key)) 168 return FALSE; 169 for (p = key + 1; *p != NUL; ++p) 170 if (!ASCII_ISALPHA(*p) && *p != '_' && !vim_isdigit(*p)) 171 return FALSE; 172 return TRUE; 173 } 174 175 /* 176 * Encode "val" into "gap". 177 * Return FAIL or OK. 178 */ 179 static int 180 json_encode_item(garray_T *gap, typval_T *val, int copyID, int options) 181 { 182 char_u numbuf[NUMBUFLEN]; 183 char_u *res; 184 list_T *l; 185 dict_T *d; 186 187 switch (val->v_type) 188 { 189 case VAR_SPECIAL: 190 switch (val->vval.v_number) 191 { 192 case VVAL_FALSE: ga_concat(gap, (char_u *)"false"); break; 193 case VVAL_TRUE: ga_concat(gap, (char_u *)"true"); break; 194 case VVAL_NONE: if ((options & JSON_JS) != 0 195 && (options & JSON_NO_NONE) == 0) 196 /* empty item */ 197 break; 198 /* FALLTHROUGH */ 199 case VVAL_NULL: ga_concat(gap, (char_u *)"null"); break; 200 } 201 break; 202 203 case VAR_NUMBER: 204 vim_snprintf((char *)numbuf, NUMBUFLEN, "%ld", 205 (long)val->vval.v_number); 206 ga_concat(gap, numbuf); 207 break; 208 209 case VAR_STRING: 210 res = val->vval.v_string; 211 write_string(gap, res); 212 break; 213 214 case VAR_FUNC: 215 case VAR_PARTIAL: 216 case VAR_JOB: 217 case VAR_CHANNEL: 218 /* no JSON equivalent TODO: better error */ 219 EMSG(_(e_invarg)); 220 return FAIL; 221 222 case VAR_LIST: 223 l = val->vval.v_list; 224 if (l == NULL) 225 ga_concat(gap, (char_u *)"null"); 226 else 227 { 228 if (l->lv_copyID == copyID) 229 ga_concat(gap, (char_u *)"[]"); 230 else 231 { 232 listitem_T *li; 233 234 l->lv_copyID = copyID; 235 ga_append(gap, '['); 236 for (li = l->lv_first; li != NULL && !got_int; ) 237 { 238 if (json_encode_item(gap, &li->li_tv, copyID, 239 options & JSON_JS) == FAIL) 240 return FAIL; 241 if ((options & JSON_JS) 242 && li->li_next == NULL 243 && li->li_tv.v_type == VAR_SPECIAL 244 && li->li_tv.vval.v_number == VVAL_NONE) 245 /* add an extra comma if the last item is v:none */ 246 ga_append(gap, ','); 247 li = li->li_next; 248 if (li != NULL) 249 ga_append(gap, ','); 250 } 251 ga_append(gap, ']'); 252 l->lv_copyID = 0; 253 } 254 } 255 break; 256 257 case VAR_DICT: 258 d = val->vval.v_dict; 259 if (d == NULL) 260 ga_concat(gap, (char_u *)"null"); 261 else 262 { 263 if (d->dv_copyID == copyID) 264 ga_concat(gap, (char_u *)"{}"); 265 else 266 { 267 int first = TRUE; 268 int todo = (int)d->dv_hashtab.ht_used; 269 hashitem_T *hi; 270 271 d->dv_copyID = copyID; 272 ga_append(gap, '{'); 273 274 for (hi = d->dv_hashtab.ht_array; todo > 0 && !got_int; 275 ++hi) 276 if (!HASHITEM_EMPTY(hi)) 277 { 278 --todo; 279 if (first) 280 first = FALSE; 281 else 282 ga_append(gap, ','); 283 if ((options & JSON_JS) 284 && is_simple_key(hi->hi_key)) 285 ga_concat(gap, hi->hi_key); 286 else 287 write_string(gap, hi->hi_key); 288 ga_append(gap, ':'); 289 if (json_encode_item(gap, &dict_lookup(hi)->di_tv, 290 copyID, options | JSON_NO_NONE) == FAIL) 291 return FAIL; 292 } 293 ga_append(gap, '}'); 294 d->dv_copyID = 0; 295 } 296 } 297 break; 298 299 case VAR_FLOAT: 300 #ifdef FEAT_FLOAT 301 # if defined(HAVE_MATH_H) 302 if (isnan(val->vval.v_float)) 303 ga_concat(gap, (char_u *)"NaN"); 304 else if (isinf(val->vval.v_float)) 305 ga_concat(gap, (char_u *)"Infinity"); 306 else 307 # endif 308 { 309 vim_snprintf((char *)numbuf, NUMBUFLEN, "%g", 310 val->vval.v_float); 311 ga_concat(gap, numbuf); 312 } 313 break; 314 #endif 315 case VAR_UNKNOWN: 316 EMSG2(_(e_intern2), "json_encode_item()"); 317 return FAIL; 318 } 319 return OK; 320 } 321 322 /* 323 * When "reader" has less than NUMBUFLEN bytes available, call the fill 324 * callback to get more. 325 */ 326 static void 327 fill_numbuflen(js_read_T *reader) 328 { 329 if (reader->js_fill != NULL && (int)(reader->js_end - reader->js_buf) 330 - reader->js_used < NUMBUFLEN) 331 { 332 if (reader->js_fill(reader)) 333 reader->js_end = reader->js_buf + STRLEN(reader->js_buf); 334 } 335 } 336 337 /* 338 * Skip white space in "reader". All characters <= space are considered white 339 * space. 340 * Also tops up readahead when needed. 341 */ 342 static void 343 json_skip_white(js_read_T *reader) 344 { 345 int c; 346 347 for (;;) 348 { 349 c = reader->js_buf[reader->js_used]; 350 if (reader->js_fill != NULL && c == NUL) 351 { 352 if (reader->js_fill(reader)) 353 { 354 reader->js_end = reader->js_buf + STRLEN(reader->js_buf); 355 continue; 356 } 357 } 358 if (c == NUL || c > ' ') 359 break; 360 ++reader->js_used; 361 } 362 fill_numbuflen(reader); 363 } 364 365 static int 366 json_decode_array(js_read_T *reader, typval_T *res, int options) 367 { 368 char_u *p; 369 typval_T item; 370 listitem_T *li; 371 int ret; 372 373 if (res != NULL && rettv_list_alloc(res) == FAIL) 374 { 375 res->v_type = VAR_SPECIAL; 376 res->vval.v_number = VVAL_NONE; 377 return FAIL; 378 } 379 ++reader->js_used; /* consume the '[' */ 380 381 while (TRUE) 382 { 383 json_skip_white(reader); 384 p = reader->js_buf + reader->js_used; 385 if (*p == NUL) 386 return MAYBE; 387 if (*p == ']') 388 { 389 ++reader->js_used; /* consume the ']' */ 390 break; 391 } 392 393 ret = json_decode_item(reader, res == NULL ? NULL : &item, options); 394 if (ret != OK) 395 return ret; 396 if (res != NULL) 397 { 398 li = listitem_alloc(); 399 if (li == NULL) 400 { 401 clear_tv(&item); 402 return FAIL; 403 } 404 li->li_tv = item; 405 list_append(res->vval.v_list, li); 406 } 407 408 json_skip_white(reader); 409 p = reader->js_buf + reader->js_used; 410 if (*p == ',') 411 ++reader->js_used; 412 else if (*p != ']') 413 { 414 if (*p == NUL) 415 return MAYBE; 416 return FAIL; 417 } 418 } 419 return OK; 420 } 421 422 static int 423 json_decode_object(js_read_T *reader, typval_T *res, int options) 424 { 425 char_u *p; 426 typval_T tvkey; 427 typval_T item; 428 dictitem_T *di; 429 char_u buf[NUMBUFLEN]; 430 char_u *key = NULL; 431 int ret; 432 433 if (res != NULL && rettv_dict_alloc(res) == FAIL) 434 { 435 res->v_type = VAR_SPECIAL; 436 res->vval.v_number = VVAL_NONE; 437 return FAIL; 438 } 439 ++reader->js_used; /* consume the '{' */ 440 441 while (TRUE) 442 { 443 json_skip_white(reader); 444 p = reader->js_buf + reader->js_used; 445 if (*p == NUL) 446 return MAYBE; 447 if (*p == '}') 448 { 449 ++reader->js_used; /* consume the '}' */ 450 break; 451 } 452 453 if ((options & JSON_JS) && reader->js_buf[reader->js_used] != '"') 454 { 455 /* accept a key that is not in quotes */ 456 key = p = reader->js_buf + reader->js_used; 457 while (*p != NUL && *p != ':' && *p > ' ') 458 ++p; 459 tvkey.v_type = VAR_STRING; 460 tvkey.vval.v_string = vim_strnsave(key, (int)(p - key)); 461 reader->js_used += (int)(p - key); 462 key = tvkey.vval.v_string; 463 } 464 else 465 { 466 ret = json_decode_item(reader, res == NULL ? NULL : &tvkey, 467 options); 468 if (ret != OK) 469 return ret; 470 if (res != NULL) 471 { 472 key = get_tv_string_buf_chk(&tvkey, buf); 473 if (key == NULL || *key == NUL) 474 { 475 clear_tv(&tvkey); 476 return FAIL; 477 } 478 } 479 } 480 481 json_skip_white(reader); 482 p = reader->js_buf + reader->js_used; 483 if (*p != ':') 484 { 485 if (res != NULL) 486 clear_tv(&tvkey); 487 if (*p == NUL) 488 return MAYBE; 489 return FAIL; 490 } 491 ++reader->js_used; 492 json_skip_white(reader); 493 494 ret = json_decode_item(reader, res == NULL ? NULL : &item, options); 495 if (ret != OK) 496 { 497 if (res != NULL) 498 clear_tv(&tvkey); 499 return ret; 500 } 501 502 if (res != NULL) 503 { 504 di = dictitem_alloc(key); 505 clear_tv(&tvkey); 506 if (di == NULL) 507 { 508 clear_tv(&item); 509 return FAIL; 510 } 511 di->di_tv = item; 512 di->di_tv.v_lock = 0; 513 if (dict_add(res->vval.v_dict, di) == FAIL) 514 { 515 dictitem_free(di); 516 return FAIL; 517 } 518 } 519 520 json_skip_white(reader); 521 p = reader->js_buf + reader->js_used; 522 if (*p == ',') 523 ++reader->js_used; 524 else if (*p != '}') 525 { 526 if (*p == NUL) 527 return MAYBE; 528 return FAIL; 529 } 530 } 531 return OK; 532 } 533 534 static int 535 json_decode_string(js_read_T *reader, typval_T *res) 536 { 537 garray_T ga; 538 int len; 539 char_u *p; 540 int c; 541 long nr; 542 char_u buf[NUMBUFLEN]; 543 544 if (res != NULL) 545 ga_init2(&ga, 1, 200); 546 547 p = reader->js_buf + reader->js_used + 1; /* skip over " */ 548 while (*p != '"') 549 { 550 /* The JSON is always expected to be utf-8, thus use utf functions 551 * here. The string is converted below if needed. */ 552 if (*p == NUL || p[1] == NUL 553 #ifdef FEAT_MBYTE 554 || utf_ptr2len(p) < utf_byte2len(*p) 555 #endif 556 ) 557 { 558 /* Not enough bytes to make a character or end of the string. Get 559 * more if possible. */ 560 if (reader->js_fill == NULL) 561 break; 562 len = (int)(reader->js_end - p); 563 reader->js_used = (int)(p - reader->js_buf); 564 if (!reader->js_fill(reader)) 565 break; /* didn't get more */ 566 p = reader->js_buf + reader->js_used; 567 reader->js_end = reader->js_buf + STRLEN(reader->js_buf); 568 continue; 569 } 570 571 if (*p == '\\') 572 { 573 c = -1; 574 switch (p[1]) 575 { 576 case '\\': c = '\\'; break; 577 case '"': c = '"'; break; 578 case 'b': c = BS; break; 579 case 't': c = TAB; break; 580 case 'n': c = NL; break; 581 case 'f': c = FF; break; 582 case 'r': c = CAR; break; 583 case 'u': 584 if (reader->js_fill != NULL 585 && (int)(reader->js_end - p) < NUMBUFLEN) 586 { 587 reader->js_used = (int)(p - reader->js_buf); 588 if (reader->js_fill(reader)) 589 { 590 p = reader->js_buf + reader->js_used; 591 reader->js_end = reader->js_buf 592 + STRLEN(reader->js_buf); 593 } 594 } 595 nr = 0; 596 len = 0; 597 vim_str2nr(p + 2, NULL, &len, 598 STR2NR_HEX + STR2NR_FORCE, &nr, NULL, 4); 599 p += len + 2; 600 if (0xd800 <= nr && nr <= 0xdfff 601 && (int)(reader->js_end - p) >= 6 602 && *p == '\\' && *(p+1) == 'u') 603 { 604 long nr2 = 0; 605 606 /* decode surrogate pair: \ud812\u3456 */ 607 len = 0; 608 vim_str2nr(p + 2, NULL, &len, 609 STR2NR_HEX + STR2NR_FORCE, &nr2, NULL, 4); 610 if (0xdc00 <= nr2 && nr2 <= 0xdfff) 611 { 612 p += len + 2; 613 nr = (((nr - 0xd800) << 10) | 614 ((nr2 - 0xdc00) & 0x3ff)) + 0x10000; 615 } 616 } 617 if (res != NULL) 618 { 619 #ifdef FEAT_MBYTE 620 buf[utf_char2bytes((int)nr, buf)] = NUL; 621 ga_concat(&ga, buf); 622 #else 623 ga_append(&ga, nr); 624 #endif 625 } 626 break; 627 default: 628 /* not a special char, skip over \ */ 629 ++p; 630 continue; 631 } 632 if (c > 0) 633 { 634 p += 2; 635 if (res != NULL) 636 ga_append(&ga, c); 637 } 638 } 639 else 640 { 641 #ifdef FEAT_MBYTE 642 len = utf_ptr2len(p); 643 #else 644 len = 1; 645 #endif 646 if (res != NULL) 647 { 648 if (ga_grow(&ga, len) == FAIL) 649 { 650 ga_clear(&ga); 651 return FAIL; 652 } 653 mch_memmove((char *)ga.ga_data + ga.ga_len, p, (size_t)len); 654 ga.ga_len += len; 655 } 656 p += len; 657 } 658 } 659 660 reader->js_used = (int)(p - reader->js_buf); 661 if (*p == '"') 662 { 663 ++reader->js_used; 664 if (res != NULL) 665 { 666 ga_append(&ga, NUL); 667 res->v_type = VAR_STRING; 668 #if defined(FEAT_MBYTE) && defined(USE_ICONV) 669 if (!enc_utf8) 670 { 671 vimconv_T conv; 672 673 /* Convert the utf-8 string to 'encoding'. */ 674 conv.vc_type = CONV_NONE; 675 convert_setup(&conv, (char_u*)"utf-8", p_enc); 676 if (conv.vc_type != CONV_NONE) 677 { 678 res->vval.v_string = 679 string_convert(&conv, ga.ga_data, NULL); 680 vim_free(ga.ga_data); 681 } 682 convert_setup(&conv, NULL, NULL); 683 } 684 else 685 #endif 686 res->vval.v_string = ga.ga_data; 687 } 688 return OK; 689 } 690 if (res != NULL) 691 { 692 res->v_type = VAR_SPECIAL; 693 res->vval.v_number = VVAL_NONE; 694 ga_clear(&ga); 695 } 696 return MAYBE; 697 } 698 699 /* 700 * Decode one item and put it in "res". If "res" is NULL only advance. 701 * Must already have skipped white space. 702 * 703 * Return FAIL for a decoding error. 704 * Return MAYBE for an incomplete message. 705 */ 706 static int 707 json_decode_item(js_read_T *reader, typval_T *res, int options) 708 { 709 char_u *p; 710 int len; 711 712 fill_numbuflen(reader); 713 p = reader->js_buf + reader->js_used; 714 switch (*p) 715 { 716 case '[': /* array */ 717 return json_decode_array(reader, res, options); 718 719 case '{': /* object */ 720 return json_decode_object(reader, res, options); 721 722 case '"': /* string */ 723 return json_decode_string(reader, res); 724 725 case ',': /* comma: empty item */ 726 if ((options & JSON_JS) == 0) 727 return FAIL; 728 /* FALLTHROUGH */ 729 case NUL: /* empty */ 730 if (res != NULL) 731 { 732 res->v_type = VAR_SPECIAL; 733 res->vval.v_number = VVAL_NONE; 734 } 735 return OK; 736 737 default: 738 if (VIM_ISDIGIT(*p) || *p == '-') 739 { 740 #ifdef FEAT_FLOAT 741 char_u *sp = p; 742 743 if (*sp == '-') 744 { 745 ++sp; 746 if (*sp == NUL) 747 return MAYBE; 748 if (!VIM_ISDIGIT(*sp)) 749 return FAIL; 750 } 751 sp = skipdigits(sp); 752 if (*sp == '.' || *sp == 'e' || *sp == 'E') 753 { 754 if (res == NULL) 755 { 756 float_T f; 757 758 len = string2float(p, &f); 759 } 760 else 761 { 762 res->v_type = VAR_FLOAT; 763 len = string2float(p, &res->vval.v_float); 764 } 765 } 766 else 767 #endif 768 { 769 long nr; 770 771 vim_str2nr(reader->js_buf + reader->js_used, 772 NULL, &len, 0, /* what */ 773 &nr, NULL, 0); 774 if (res != NULL) 775 { 776 res->v_type = VAR_NUMBER; 777 res->vval.v_number = nr; 778 } 779 } 780 reader->js_used += len; 781 return OK; 782 } 783 if (STRNICMP((char *)p, "false", 5) == 0) 784 { 785 reader->js_used += 5; 786 if (res != NULL) 787 { 788 res->v_type = VAR_SPECIAL; 789 res->vval.v_number = VVAL_FALSE; 790 } 791 return OK; 792 } 793 if (STRNICMP((char *)p, "true", 4) == 0) 794 { 795 reader->js_used += 4; 796 if (res != NULL) 797 { 798 res->v_type = VAR_SPECIAL; 799 res->vval.v_number = VVAL_TRUE; 800 } 801 return OK; 802 } 803 if (STRNICMP((char *)p, "null", 4) == 0) 804 { 805 reader->js_used += 4; 806 if (res != NULL) 807 { 808 res->v_type = VAR_SPECIAL; 809 res->vval.v_number = VVAL_NULL; 810 } 811 return OK; 812 } 813 #ifdef FEAT_FLOAT 814 if (STRNICMP((char *)p, "NaN", 3) == 0) 815 { 816 reader->js_used += 3; 817 if (res != NULL) 818 { 819 res->v_type = VAR_FLOAT; 820 res->vval.v_float = NAN; 821 } 822 return OK; 823 } 824 if (STRNICMP((char *)p, "Infinity", 8) == 0) 825 { 826 reader->js_used += 8; 827 if (res != NULL) 828 { 829 res->v_type = VAR_FLOAT; 830 res->vval.v_float = INFINITY; 831 } 832 return OK; 833 } 834 #endif 835 /* check for truncated name */ 836 len = (int)(reader->js_end - (reader->js_buf + reader->js_used)); 837 if ( 838 (len < 5 && STRNICMP((char *)p, "false", len) == 0) 839 #ifdef FEAT_FLOAT 840 || (len < 8 && STRNICMP((char *)p, "Infinity", len) == 0) 841 || (len < 3 && STRNICMP((char *)p, "NaN", len) == 0) 842 #endif 843 || (len < 4 && (STRNICMP((char *)p, "true", len) == 0 844 || STRNICMP((char *)p, "null", len) == 0))) 845 return MAYBE; 846 break; 847 } 848 849 if (res != NUL) 850 { 851 res->v_type = VAR_SPECIAL; 852 res->vval.v_number = VVAL_NONE; 853 } 854 return FAIL; 855 } 856 857 /* 858 * Decode the JSON from "reader" and store the result in "res". 859 * "options" can be JSON_JS or zero; 860 * Return FAIL if not the whole message was consumed. 861 */ 862 int 863 json_decode_all(js_read_T *reader, typval_T *res, int options) 864 { 865 int ret; 866 867 /* We find the end once, to avoid calling strlen() many times. */ 868 reader->js_end = reader->js_buf + STRLEN(reader->js_buf); 869 json_skip_white(reader); 870 ret = json_decode_item(reader, res, options); 871 if (ret != OK) 872 return FAIL; 873 json_skip_white(reader); 874 if (reader->js_buf[reader->js_used] != NUL) 875 return FAIL; 876 return OK; 877 } 878 879 /* 880 * Decode the JSON from "reader" and store the result in "res". 881 * "options" can be JSON_JS or zero; 882 * Return FAIL for a decoding error. 883 * Return MAYBE for an incomplete message. 884 * Consumes the message anyway. 885 */ 886 int 887 json_decode(js_read_T *reader, typval_T *res, int options) 888 { 889 int ret; 890 891 /* We find the end once, to avoid calling strlen() many times. */ 892 reader->js_end = reader->js_buf + STRLEN(reader->js_buf); 893 json_skip_white(reader); 894 ret = json_decode_item(reader, res, options); 895 json_skip_white(reader); 896 897 return ret; 898 } 899 900 /* 901 * Decode the JSON from "reader" to find the end of the message. 902 * "options" can be JSON_JS or zero; 903 * Return FAIL if the message has a decoding error. 904 * Return MAYBE if the message is truncated, need to read more. 905 * This only works reliable if the message contains an object, array or 906 * string. A number might be trucated without knowing. 907 * Does not advance the reader. 908 */ 909 int 910 json_find_end(js_read_T *reader, int options) 911 { 912 int used_save = reader->js_used; 913 int ret; 914 915 /* We find the end once, to avoid calling strlen() many times. */ 916 reader->js_end = reader->js_buf + STRLEN(reader->js_buf); 917 json_skip_white(reader); 918 ret = json_decode_item(reader, NULL, options); 919 reader->js_used = used_save; 920 return ret; 921 } 922 #endif 923