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