xref: /vim-8.2.3635/src/json.c (revision cf2d8dee)
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