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 reader->js_end = reader->js_buf + STRLEN(reader->js_buf); 354 continue; 355 } 356 if (c == NUL || c > ' ') 357 break; 358 ++reader->js_used; 359 } 360 fill_numbuflen(reader); 361 } 362 363 static int 364 json_decode_array(js_read_T *reader, typval_T *res, int options) 365 { 366 char_u *p; 367 typval_T item; 368 listitem_T *li; 369 int ret; 370 371 if (res != NULL && rettv_list_alloc(res) == FAIL) 372 { 373 res->v_type = VAR_SPECIAL; 374 res->vval.v_number = VVAL_NONE; 375 return FAIL; 376 } 377 ++reader->js_used; /* consume the '[' */ 378 379 while (TRUE) 380 { 381 json_skip_white(reader); 382 p = reader->js_buf + reader->js_used; 383 if (*p == NUL) 384 return MAYBE; 385 if (*p == ']') 386 { 387 ++reader->js_used; /* consume the ']' */ 388 break; 389 } 390 391 ret = json_decode_item(reader, res == NULL ? NULL : &item, options); 392 if (ret != OK) 393 return ret; 394 if (res != NULL) 395 { 396 li = listitem_alloc(); 397 if (li == NULL) 398 { 399 clear_tv(&item); 400 return FAIL; 401 } 402 li->li_tv = item; 403 list_append(res->vval.v_list, li); 404 } 405 406 json_skip_white(reader); 407 p = reader->js_buf + reader->js_used; 408 if (*p == ',') 409 ++reader->js_used; 410 else if (*p != ']') 411 { 412 if (*p == NUL) 413 return MAYBE; 414 return FAIL; 415 } 416 } 417 return OK; 418 } 419 420 static int 421 json_decode_object(js_read_T *reader, typval_T *res, int options) 422 { 423 char_u *p; 424 typval_T tvkey; 425 typval_T item; 426 dictitem_T *di; 427 char_u buf[NUMBUFLEN]; 428 char_u *key = NULL; 429 int ret; 430 431 if (res != NULL && rettv_dict_alloc(res) == FAIL) 432 { 433 res->v_type = VAR_SPECIAL; 434 res->vval.v_number = VVAL_NONE; 435 return FAIL; 436 } 437 ++reader->js_used; /* consume the '{' */ 438 439 while (TRUE) 440 { 441 json_skip_white(reader); 442 p = reader->js_buf + reader->js_used; 443 if (*p == NUL) 444 return MAYBE; 445 if (*p == '}') 446 { 447 ++reader->js_used; /* consume the '}' */ 448 break; 449 } 450 451 if ((options & JSON_JS) && reader->js_buf[reader->js_used] != '"') 452 { 453 /* accept a key that is not in quotes */ 454 key = p = reader->js_buf + reader->js_used; 455 while (*p != NUL && *p != ':' && *p > ' ') 456 ++p; 457 tvkey.v_type = VAR_STRING; 458 tvkey.vval.v_string = vim_strnsave(key, (int)(p - key)); 459 reader->js_used += (int)(p - key); 460 key = tvkey.vval.v_string; 461 } 462 else 463 { 464 ret = json_decode_item(reader, res == NULL ? NULL : &tvkey, 465 options); 466 if (ret != OK) 467 return ret; 468 if (res != NULL) 469 { 470 key = get_tv_string_buf_chk(&tvkey, buf); 471 if (key == NULL || *key == NUL) 472 { 473 clear_tv(&tvkey); 474 return FAIL; 475 } 476 } 477 } 478 479 json_skip_white(reader); 480 p = reader->js_buf + reader->js_used; 481 if (*p != ':') 482 { 483 if (res != NULL) 484 clear_tv(&tvkey); 485 if (*p == NUL) 486 return MAYBE; 487 return FAIL; 488 } 489 ++reader->js_used; 490 json_skip_white(reader); 491 492 ret = json_decode_item(reader, res == NULL ? NULL : &item, options); 493 if (ret != OK) 494 { 495 if (res != NULL) 496 clear_tv(&tvkey); 497 return ret; 498 } 499 500 if (res != NULL) 501 { 502 di = dictitem_alloc(key); 503 clear_tv(&tvkey); 504 if (di == NULL) 505 { 506 clear_tv(&item); 507 return FAIL; 508 } 509 di->di_tv = item; 510 di->di_tv.v_lock = 0; 511 if (dict_add(res->vval.v_dict, di) == FAIL) 512 { 513 dictitem_free(di); 514 return FAIL; 515 } 516 } 517 518 json_skip_white(reader); 519 p = reader->js_buf + reader->js_used; 520 if (*p == ',') 521 ++reader->js_used; 522 else if (*p != '}') 523 { 524 if (*p == NUL) 525 return MAYBE; 526 return FAIL; 527 } 528 } 529 return OK; 530 } 531 532 static int 533 json_decode_string(js_read_T *reader, typval_T *res) 534 { 535 garray_T ga; 536 int len; 537 char_u *p; 538 int c; 539 long nr; 540 char_u buf[NUMBUFLEN]; 541 542 if (res != NULL) 543 ga_init2(&ga, 1, 200); 544 545 p = reader->js_buf + reader->js_used + 1; /* skip over " */ 546 while (*p != '"') 547 { 548 /* The JSON is always expected to be utf-8, thus use utf functions 549 * here. The string is converted below if needed. */ 550 if (*p == NUL || p[1] == NUL 551 #ifdef FEAT_MBYTE 552 || utf_ptr2len(p) < utf_byte2len(*p) 553 #endif 554 ) 555 { 556 /* Not enough bytes to make a character or end of the string. Get 557 * more if possible. */ 558 if (reader->js_fill == NULL) 559 break; 560 len = (int)(reader->js_end - p); 561 reader->js_used = (int)(p - reader->js_buf); 562 if (!reader->js_fill(reader)) 563 break; /* didn't get more */ 564 p = reader->js_buf + reader->js_used; 565 reader->js_end = reader->js_buf + STRLEN(reader->js_buf); 566 continue; 567 } 568 569 if (*p == '\\') 570 { 571 c = -1; 572 switch (p[1]) 573 { 574 case '\\': c = '\\'; break; 575 case '"': c = '"'; break; 576 case 'b': c = BS; break; 577 case 't': c = TAB; break; 578 case 'n': c = NL; break; 579 case 'f': c = FF; break; 580 case 'r': c = CAR; break; 581 case 'u': 582 if (reader->js_fill != NULL 583 && (int)(reader->js_end - p) < NUMBUFLEN) 584 { 585 reader->js_used = (int)(p - reader->js_buf); 586 if (reader->js_fill(reader)) 587 { 588 p = reader->js_buf + reader->js_used; 589 reader->js_end = reader->js_buf 590 + STRLEN(reader->js_buf); 591 } 592 } 593 nr = 0; 594 len = 0; 595 vim_str2nr(p + 2, NULL, &len, 596 STR2NR_HEX + STR2NR_FORCE, &nr, NULL, 4); 597 p += len + 2; 598 if (0xd800 <= nr && nr <= 0xdfff 599 && (int)(reader->js_end - p) >= 6 600 && *p == '\\' && *(p+1) == 'u') 601 { 602 long nr2 = 0; 603 604 /* decode surrogate pair: \ud812\u3456 */ 605 len = 0; 606 vim_str2nr(p + 2, NULL, &len, 607 STR2NR_HEX + STR2NR_FORCE, &nr2, NULL, 4); 608 if (0xdc00 <= nr2 && nr2 <= 0xdfff) 609 { 610 p += len + 2; 611 nr = (((nr - 0xd800) << 10) | 612 ((nr2 - 0xdc00) & 0x3ff)) + 0x10000; 613 } 614 } 615 if (res != NULL) 616 { 617 #ifdef FEAT_MBYTE 618 buf[utf_char2bytes((int)nr, buf)] = NUL; 619 ga_concat(&ga, buf); 620 #else 621 ga_append(&ga, nr); 622 #endif 623 } 624 break; 625 default: 626 /* not a special char, skip over \ */ 627 ++p; 628 continue; 629 } 630 if (c > 0) 631 { 632 p += 2; 633 if (res != NULL) 634 ga_append(&ga, c); 635 } 636 } 637 else 638 { 639 #ifdef FEAT_MBYTE 640 len = utf_ptr2len(p); 641 #else 642 len = 1; 643 #endif 644 if (res != NULL) 645 { 646 if (ga_grow(&ga, len) == FAIL) 647 { 648 ga_clear(&ga); 649 return FAIL; 650 } 651 mch_memmove((char *)ga.ga_data + ga.ga_len, p, (size_t)len); 652 ga.ga_len += len; 653 } 654 p += len; 655 } 656 } 657 658 reader->js_used = (int)(p - reader->js_buf); 659 if (*p == '"') 660 { 661 ++reader->js_used; 662 if (res != NULL) 663 { 664 ga_append(&ga, NUL); 665 res->v_type = VAR_STRING; 666 #if defined(FEAT_MBYTE) && defined(USE_ICONV) 667 if (!enc_utf8) 668 { 669 vimconv_T conv; 670 671 /* Convert the utf-8 string to 'encoding'. */ 672 conv.vc_type = CONV_NONE; 673 convert_setup(&conv, (char_u*)"utf-8", p_enc); 674 if (conv.vc_type != CONV_NONE) 675 { 676 res->vval.v_string = 677 string_convert(&conv, ga.ga_data, NULL); 678 vim_free(ga.ga_data); 679 } 680 convert_setup(&conv, NULL, NULL); 681 } 682 else 683 #endif 684 res->vval.v_string = ga.ga_data; 685 } 686 return OK; 687 } 688 if (res != NULL) 689 { 690 res->v_type = VAR_SPECIAL; 691 res->vval.v_number = VVAL_NONE; 692 ga_clear(&ga); 693 } 694 return MAYBE; 695 } 696 697 /* 698 * Decode one item and put it in "res". If "res" is NULL only advance. 699 * Must already have skipped white space. 700 * 701 * Return FAIL for a decoding error. 702 * Return MAYBE for an incomplete message. 703 */ 704 static int 705 json_decode_item(js_read_T *reader, typval_T *res, int options) 706 { 707 char_u *p; 708 int len; 709 710 fill_numbuflen(reader); 711 p = reader->js_buf + reader->js_used; 712 switch (*p) 713 { 714 case '[': /* array */ 715 return json_decode_array(reader, res, options); 716 717 case '{': /* object */ 718 return json_decode_object(reader, res, options); 719 720 case '"': /* string */ 721 return json_decode_string(reader, res); 722 723 case ',': /* comma: empty item */ 724 if ((options & JSON_JS) == 0) 725 return FAIL; 726 /* FALLTHROUGH */ 727 case NUL: /* empty */ 728 if (res != NULL) 729 { 730 res->v_type = VAR_SPECIAL; 731 res->vval.v_number = VVAL_NONE; 732 } 733 return OK; 734 735 default: 736 if (VIM_ISDIGIT(*p) || *p == '-') 737 { 738 #ifdef FEAT_FLOAT 739 char_u *sp = p; 740 741 if (*sp == '-') 742 { 743 ++sp; 744 if (*sp == NUL) 745 return MAYBE; 746 if (!VIM_ISDIGIT(*sp)) 747 return FAIL; 748 } 749 sp = skipdigits(sp); 750 if (*sp == '.' || *sp == 'e' || *sp == 'E') 751 { 752 if (res == NULL) 753 { 754 float_T f; 755 756 len = string2float(p, &f); 757 } 758 else 759 { 760 res->v_type = VAR_FLOAT; 761 len = string2float(p, &res->vval.v_float); 762 } 763 } 764 else 765 #endif 766 { 767 long nr; 768 769 vim_str2nr(reader->js_buf + reader->js_used, 770 NULL, &len, 0, /* what */ 771 &nr, NULL, 0); 772 if (res != NULL) 773 { 774 res->v_type = VAR_NUMBER; 775 res->vval.v_number = nr; 776 } 777 } 778 reader->js_used += len; 779 return OK; 780 } 781 if (STRNICMP((char *)p, "false", 5) == 0) 782 { 783 reader->js_used += 5; 784 if (res != NULL) 785 { 786 res->v_type = VAR_SPECIAL; 787 res->vval.v_number = VVAL_FALSE; 788 } 789 return OK; 790 } 791 if (STRNICMP((char *)p, "true", 4) == 0) 792 { 793 reader->js_used += 4; 794 if (res != NULL) 795 { 796 res->v_type = VAR_SPECIAL; 797 res->vval.v_number = VVAL_TRUE; 798 } 799 return OK; 800 } 801 if (STRNICMP((char *)p, "null", 4) == 0) 802 { 803 reader->js_used += 4; 804 if (res != NULL) 805 { 806 res->v_type = VAR_SPECIAL; 807 res->vval.v_number = VVAL_NULL; 808 } 809 return OK; 810 } 811 #ifdef FEAT_FLOAT 812 if (STRNICMP((char *)p, "NaN", 3) == 0) 813 { 814 reader->js_used += 3; 815 if (res != NULL) 816 { 817 res->v_type = VAR_FLOAT; 818 res->vval.v_float = NAN; 819 } 820 return OK; 821 } 822 if (STRNICMP((char *)p, "Infinity", 8) == 0) 823 { 824 reader->js_used += 8; 825 if (res != NULL) 826 { 827 res->v_type = VAR_FLOAT; 828 res->vval.v_float = INFINITY; 829 } 830 return OK; 831 } 832 #endif 833 /* check for truncated name */ 834 len = (int)(reader->js_end - (reader->js_buf + reader->js_used)); 835 if ( 836 (len < 5 && STRNICMP((char *)p, "false", len) == 0) 837 #ifdef FEAT_FLOAT 838 || (len < 8 && STRNICMP((char *)p, "Infinity", len) == 0) 839 || (len < 3 && STRNICMP((char *)p, "NaN", len) == 0) 840 #endif 841 || (len < 4 && (STRNICMP((char *)p, "true", len) == 0 842 || STRNICMP((char *)p, "null", len) == 0))) 843 return MAYBE; 844 break; 845 } 846 847 if (res != NUL) 848 { 849 res->v_type = VAR_SPECIAL; 850 res->vval.v_number = VVAL_NONE; 851 } 852 return FAIL; 853 } 854 855 /* 856 * Decode the JSON from "reader" and store the result in "res". 857 * "options" can be JSON_JS or zero; 858 * Return FAIL if not the whole message was consumed. 859 */ 860 int 861 json_decode_all(js_read_T *reader, typval_T *res, int options) 862 { 863 int ret; 864 865 /* We find the end once, to avoid calling strlen() many times. */ 866 reader->js_end = reader->js_buf + STRLEN(reader->js_buf); 867 json_skip_white(reader); 868 ret = json_decode_item(reader, res, options); 869 if (ret != OK) 870 return FAIL; 871 json_skip_white(reader); 872 if (reader->js_buf[reader->js_used] != NUL) 873 return FAIL; 874 return OK; 875 } 876 877 /* 878 * Decode the JSON from "reader" and store the result in "res". 879 * "options" can be JSON_JS or zero; 880 * Return FAIL for a decoding error. 881 * Return MAYBE for an incomplete message. 882 * Consumes the message anyway. 883 */ 884 int 885 json_decode(js_read_T *reader, typval_T *res, int options) 886 { 887 int ret; 888 889 /* We find the end once, to avoid calling strlen() many times. */ 890 reader->js_end = reader->js_buf + STRLEN(reader->js_buf); 891 json_skip_white(reader); 892 ret = json_decode_item(reader, res, options); 893 json_skip_white(reader); 894 895 return ret; 896 } 897 898 /* 899 * Decode the JSON from "reader" to find the end of the message. 900 * "options" can be JSON_JS or zero; 901 * Return FAIL if the message has a decoding error. 902 * Return MAYBE if the message is truncated, need to read more. 903 * This only works reliable if the message contains an object, array or 904 * string. A number might be trucated without knowing. 905 * Does not advance the reader. 906 */ 907 int 908 json_find_end(js_read_T *reader, int options) 909 { 910 int used_save = reader->js_used; 911 int ret; 912 913 /* We find the end once, to avoid calling strlen() many times. */ 914 reader->js_end = reader->js_buf + STRLEN(reader->js_buf); 915 json_skip_white(reader); 916 ret = json_decode_item(reader, NULL, options); 917 reader->js_used = used_save; 918 return ret; 919 } 920 #endif 921