xref: /spdk/lib/json/json_parse.c (revision a6dbe3721eb3b5990707fc3e378c95e505dd8ab5)
1488570ebSJim Harris /*   SPDX-License-Identifier: BSD-3-Clause
2*a6dbe372Spaul luse  *   Copyright (C) 2016 Intel Corporation.
3f9193f4cSDaniel Verkamp  *   All rights reserved.
4f9193f4cSDaniel Verkamp  */
5f9193f4cSDaniel Verkamp 
67d716668SDaniel Verkamp #include "spdk/json.h"
77d716668SDaniel Verkamp 
80a97bd14SSeth Howell #include "spdk_internal/utf.h"
90a97bd14SSeth Howell 
100a97bd14SSeth Howell #define SPDK_JSON_MAX_NESTING_DEPTH	64
11f9193f4cSDaniel Verkamp 
12f9193f4cSDaniel Verkamp static int
hex_value(uint8_t c)13f9193f4cSDaniel Verkamp hex_value(uint8_t c)
14f9193f4cSDaniel Verkamp {
15f9193f4cSDaniel Verkamp #define V(x, y) [x] = y + 1
16f9193f4cSDaniel Verkamp 	static const int8_t val[256] = {
17f9193f4cSDaniel Verkamp 		V('0', 0), V('1', 1), V('2', 2), V('3', 3), V('4', 4),
18f9193f4cSDaniel Verkamp 		V('5', 5), V('6', 6), V('7', 7), V('8', 8), V('9', 9),
19f9193f4cSDaniel Verkamp 		V('A', 0xA), V('B', 0xB), V('C', 0xC), V('D', 0xD), V('E', 0xE), V('F', 0xF),
20f9193f4cSDaniel Verkamp 		V('a', 0xA), V('b', 0xB), V('c', 0xC), V('d', 0xD), V('e', 0xE), V('f', 0xF),
21f9193f4cSDaniel Verkamp 	};
22f9193f4cSDaniel Verkamp #undef V
23f9193f4cSDaniel Verkamp 
24f9193f4cSDaniel Verkamp 	return val[c] - 1;
25f9193f4cSDaniel Verkamp }
26f9193f4cSDaniel Verkamp 
27f9193f4cSDaniel Verkamp static int
json_decode_string_escape_unicode(uint8_t ** strp,uint8_t * buf_end,uint8_t * out)28f9193f4cSDaniel Verkamp json_decode_string_escape_unicode(uint8_t **strp, uint8_t *buf_end, uint8_t *out)
29f9193f4cSDaniel Verkamp {
30f9193f4cSDaniel Verkamp 	uint8_t *str = *strp;
31f9193f4cSDaniel Verkamp 	int v0, v1, v2, v3;
32f9193f4cSDaniel Verkamp 	uint32_t val;
33f9193f4cSDaniel Verkamp 	uint32_t surrogate_high = 0;
34f9193f4cSDaniel Verkamp 	int rc;
35f9193f4cSDaniel Verkamp decode:
36f9193f4cSDaniel Verkamp 	/* \uXXXX */
37f9193f4cSDaniel Verkamp 	assert(buf_end > str);
38f9193f4cSDaniel Verkamp 
3959970a89SDaniel Verkamp 	if (*str++ != '\\') { return SPDK_JSON_PARSE_INVALID; }
4059970a89SDaniel Verkamp 	if (buf_end == str) { return SPDK_JSON_PARSE_INCOMPLETE; }
41f9193f4cSDaniel Verkamp 
4259970a89SDaniel Verkamp 	if (*str++ != 'u') { return SPDK_JSON_PARSE_INVALID; }
4359970a89SDaniel Verkamp 	if (buf_end == str) { return SPDK_JSON_PARSE_INCOMPLETE; }
44f9193f4cSDaniel Verkamp 
4559970a89SDaniel Verkamp 	if ((v3 = hex_value(*str++)) < 0) { return SPDK_JSON_PARSE_INVALID; }
4659970a89SDaniel Verkamp 	if (buf_end == str) { return SPDK_JSON_PARSE_INCOMPLETE; }
47f9193f4cSDaniel Verkamp 
4859970a89SDaniel Verkamp 	if ((v2 = hex_value(*str++)) < 0) { return SPDK_JSON_PARSE_INVALID; }
4959970a89SDaniel Verkamp 	if (buf_end == str) { return SPDK_JSON_PARSE_INCOMPLETE; }
50f9193f4cSDaniel Verkamp 
5159970a89SDaniel Verkamp 	if ((v1 = hex_value(*str++)) < 0) { return SPDK_JSON_PARSE_INVALID; }
5259970a89SDaniel Verkamp 	if (buf_end == str) { return SPDK_JSON_PARSE_INCOMPLETE; }
53f9193f4cSDaniel Verkamp 
5459970a89SDaniel Verkamp 	if ((v0 = hex_value(*str++)) < 0) { return SPDK_JSON_PARSE_INVALID; }
5559970a89SDaniel Verkamp 	if (buf_end == str) { return SPDK_JSON_PARSE_INCOMPLETE; }
56f9193f4cSDaniel Verkamp 
57f9193f4cSDaniel Verkamp 	val = v0 | (v1 << 4) | (v2 << 8) | (v3 << 12);
58f9193f4cSDaniel Verkamp 
59f9193f4cSDaniel Verkamp 	if (surrogate_high) {
60f9193f4cSDaniel Verkamp 		/* We already parsed the high surrogate, so this should be the low part. */
61f9193f4cSDaniel Verkamp 		if (!utf16_valid_surrogate_low(val)) {
62f9193f4cSDaniel Verkamp 			return SPDK_JSON_PARSE_INVALID;
63f9193f4cSDaniel Verkamp 		}
64f9193f4cSDaniel Verkamp 
65f9193f4cSDaniel Verkamp 		/* Convert UTF-16 surrogate pair into codepoint and fall through to utf8_encode. */
66f9193f4cSDaniel Verkamp 		val = utf16_decode_surrogate_pair(surrogate_high, val);
67f9193f4cSDaniel Verkamp 	} else if (utf16_valid_surrogate_high(val)) {
68f9193f4cSDaniel Verkamp 		surrogate_high = val;
69f9193f4cSDaniel Verkamp 
70f9193f4cSDaniel Verkamp 		/*
71f9193f4cSDaniel Verkamp 		 * We parsed a \uXXXX sequence that decoded to the first half of a
72f9193f4cSDaniel Verkamp 		 *  UTF-16 surrogate pair, so it must be immediately followed by another
73f9193f4cSDaniel Verkamp 		 *  \uXXXX escape.
74f9193f4cSDaniel Verkamp 		 *
75f9193f4cSDaniel Verkamp 		 * Loop around to get the low half of the surrogate pair.
76f9193f4cSDaniel Verkamp 		 */
7759970a89SDaniel Verkamp 		if (buf_end == str) { return SPDK_JSON_PARSE_INCOMPLETE; }
78f9193f4cSDaniel Verkamp 		goto decode;
79f9193f4cSDaniel Verkamp 	} else if (utf16_valid_surrogate_low(val)) {
80f9193f4cSDaniel Verkamp 		/*
81f9193f4cSDaniel Verkamp 		 * We found the second half of surrogate pair without the first half;
82f9193f4cSDaniel Verkamp 		 *  this is an invalid encoding.
83f9193f4cSDaniel Verkamp 		 */
84f9193f4cSDaniel Verkamp 		return SPDK_JSON_PARSE_INVALID;
85f9193f4cSDaniel Verkamp 	}
86f9193f4cSDaniel Verkamp 
87f9193f4cSDaniel Verkamp 	/*
88f9193f4cSDaniel Verkamp 	 * Convert Unicode escape (or surrogate pair) to UTF-8 in place.
89f9193f4cSDaniel Verkamp 	 *
90f9193f4cSDaniel Verkamp 	 * This is safe (will not write beyond the buffer) because the \uXXXX sequence is 6 bytes
91f9193f4cSDaniel Verkamp 	 *  (or 12 bytes for surrogate pairs), and the longest possible UTF-8 encoding of a
92f9193f4cSDaniel Verkamp 	 *  single codepoint is 4 bytes.
93f9193f4cSDaniel Verkamp 	 */
94f9193f4cSDaniel Verkamp 	if (out) {
95f9193f4cSDaniel Verkamp 		rc = utf8_encode_unsafe(out, val);
96f9193f4cSDaniel Verkamp 	} else {
97f9193f4cSDaniel Verkamp 		rc = utf8_codepoint_len(val);
98f9193f4cSDaniel Verkamp 	}
99f9193f4cSDaniel Verkamp 	if (rc < 0) {
100f9193f4cSDaniel Verkamp 		return SPDK_JSON_PARSE_INVALID;
101f9193f4cSDaniel Verkamp 	}
102f9193f4cSDaniel Verkamp 
103f9193f4cSDaniel Verkamp 	*strp = str; /* update input pointer */
104f9193f4cSDaniel Verkamp 	return rc; /* return number of bytes decoded */
105f9193f4cSDaniel Verkamp }
106f9193f4cSDaniel Verkamp 
107f9193f4cSDaniel Verkamp static int
json_decode_string_escape_twochar(uint8_t ** strp,uint8_t * buf_end,uint8_t * out)108f9193f4cSDaniel Verkamp json_decode_string_escape_twochar(uint8_t **strp, uint8_t *buf_end, uint8_t *out)
109f9193f4cSDaniel Verkamp {
110f9193f4cSDaniel Verkamp 	static const uint8_t escapes[256] = {
111f9193f4cSDaniel Verkamp 		['b'] = '\b',
112f9193f4cSDaniel Verkamp 		['f'] = '\f',
113f9193f4cSDaniel Verkamp 		['n'] = '\n',
114f9193f4cSDaniel Verkamp 		['r'] = '\r',
115f9193f4cSDaniel Verkamp 		['t'] = '\t',
116f9193f4cSDaniel Verkamp 		['/'] = '/',
117f9193f4cSDaniel Verkamp 		['"'] = '"',
118f9193f4cSDaniel Verkamp 		['\\'] = '\\',
119f9193f4cSDaniel Verkamp 	};
120f9193f4cSDaniel Verkamp 	uint8_t *str = *strp;
121f9193f4cSDaniel Verkamp 	uint8_t c;
122f9193f4cSDaniel Verkamp 
123f9193f4cSDaniel Verkamp 	assert(buf_end > str);
124f9193f4cSDaniel Verkamp 	if (buf_end - str < 2) {
125f9193f4cSDaniel Verkamp 		return SPDK_JSON_PARSE_INCOMPLETE;
126f9193f4cSDaniel Verkamp 	}
127f9193f4cSDaniel Verkamp 
128f9193f4cSDaniel Verkamp 	assert(str[0] == '\\');
129f9193f4cSDaniel Verkamp 
130f9193f4cSDaniel Verkamp 	c = escapes[str[1]];
131f9193f4cSDaniel Verkamp 	if (c) {
132f9193f4cSDaniel Verkamp 		if (out) {
133f9193f4cSDaniel Verkamp 			*out = c;
134f9193f4cSDaniel Verkamp 		}
135f9193f4cSDaniel Verkamp 		*strp += 2; /* consumed two bytes */
136f9193f4cSDaniel Verkamp 		return 1; /* produced one byte */
137f9193f4cSDaniel Verkamp 	}
138f9193f4cSDaniel Verkamp 
139f9193f4cSDaniel Verkamp 	return SPDK_JSON_PARSE_INVALID;
140f9193f4cSDaniel Verkamp }
141f9193f4cSDaniel Verkamp 
142f9193f4cSDaniel Verkamp /*
143f9193f4cSDaniel Verkamp  * Decode JSON string backslash escape.
144f9193f4cSDaniel Verkamp  * \param strp pointer to pointer to first character of escape (the backslash).
145f9193f4cSDaniel Verkamp  *  *strp is also advanced to indicate how much input was consumed.
146f9193f4cSDaniel Verkamp  *
147f9193f4cSDaniel Verkamp  * \return Number of bytes appended to out
148f9193f4cSDaniel Verkamp  */
149f9193f4cSDaniel Verkamp static int
json_decode_string_escape(uint8_t ** strp,uint8_t * buf_end,uint8_t * out)150f9193f4cSDaniel Verkamp json_decode_string_escape(uint8_t **strp, uint8_t *buf_end, uint8_t *out)
151f9193f4cSDaniel Verkamp {
152f9193f4cSDaniel Verkamp 	int rc;
153f9193f4cSDaniel Verkamp 
154f9193f4cSDaniel Verkamp 	rc = json_decode_string_escape_twochar(strp, buf_end, out);
155f9193f4cSDaniel Verkamp 	if (rc > 0) {
156f9193f4cSDaniel Verkamp 		return rc;
157f9193f4cSDaniel Verkamp 	}
158f9193f4cSDaniel Verkamp 
159f9193f4cSDaniel Verkamp 	return json_decode_string_escape_unicode(strp, buf_end, out);
160f9193f4cSDaniel Verkamp }
161f9193f4cSDaniel Verkamp 
162f9193f4cSDaniel Verkamp /*
163f9193f4cSDaniel Verkamp  * Decode JSON string in place.
164f9193f4cSDaniel Verkamp  *
165f9193f4cSDaniel Verkamp  * \param str_start Pointer to the beginning of the string (the opening " character).
166f9193f4cSDaniel Verkamp  *
167f9193f4cSDaniel Verkamp  * \return Number of bytes in decoded string (beginning from start).
168f9193f4cSDaniel Verkamp  */
169f9193f4cSDaniel Verkamp static int
json_decode_string(uint8_t * str_start,uint8_t * buf_end,uint8_t ** str_end,uint32_t flags)170f9193f4cSDaniel Verkamp json_decode_string(uint8_t *str_start, uint8_t *buf_end, uint8_t **str_end, uint32_t flags)
171f9193f4cSDaniel Verkamp {
172f9193f4cSDaniel Verkamp 	uint8_t *str = str_start;
173f9193f4cSDaniel Verkamp 	uint8_t *out = str_start + 1; /* Decode string in place (skip the initial quote) */
174f9193f4cSDaniel Verkamp 	int rc;
175f9193f4cSDaniel Verkamp 
176f9193f4cSDaniel Verkamp 	if (buf_end - str_start < 2) {
177f9193f4cSDaniel Verkamp 		/*
178f9193f4cSDaniel Verkamp 		 * Shortest valid string (the empty string) is two bytes (""),
179f9193f4cSDaniel Verkamp 		 *  so this can't possibly be valid
180f9193f4cSDaniel Verkamp 		 */
181d6fd64cdSDaniel Verkamp 		*str_end = str;
182f9193f4cSDaniel Verkamp 		return SPDK_JSON_PARSE_INCOMPLETE;
183f9193f4cSDaniel Verkamp 	}
184f9193f4cSDaniel Verkamp 
185f9193f4cSDaniel Verkamp 	if (*str++ != '"') {
186d6fd64cdSDaniel Verkamp 		*str_end = str;
187f9193f4cSDaniel Verkamp 		return SPDK_JSON_PARSE_INVALID;
188f9193f4cSDaniel Verkamp 	}
189f9193f4cSDaniel Verkamp 
190f9193f4cSDaniel Verkamp 	while (str < buf_end) {
191f9193f4cSDaniel Verkamp 		if (str[0] == '"') {
192f9193f4cSDaniel Verkamp 			/*
193f9193f4cSDaniel Verkamp 			 * End of string.
194f9193f4cSDaniel Verkamp 			 * Update str_end to point at next input byte and return output length.
195f9193f4cSDaniel Verkamp 			 */
196f9193f4cSDaniel Verkamp 			*str_end = str + 1;
197f9193f4cSDaniel Verkamp 			return out - str_start - 1;
198f9193f4cSDaniel Verkamp 		} else if (str[0] == '\\') {
199f9193f4cSDaniel Verkamp 			rc = json_decode_string_escape(&str, buf_end,
200f9193f4cSDaniel Verkamp 						       flags & SPDK_JSON_PARSE_FLAG_DECODE_IN_PLACE ? out : NULL);
201f9193f4cSDaniel Verkamp 			assert(rc != 0);
202f9193f4cSDaniel Verkamp 			if (rc < 0) {
203d6fd64cdSDaniel Verkamp 				*str_end = str;
204f9193f4cSDaniel Verkamp 				return rc;
205f9193f4cSDaniel Verkamp 			}
206f9193f4cSDaniel Verkamp 			out += rc;
207f9193f4cSDaniel Verkamp 		} else if (str[0] <= 0x1f) {
208f9193f4cSDaniel Verkamp 			/* control characters must be escaped */
209d6fd64cdSDaniel Verkamp 			*str_end = str;
210f9193f4cSDaniel Verkamp 			return SPDK_JSON_PARSE_INVALID;
211f9193f4cSDaniel Verkamp 		} else {
212f9193f4cSDaniel Verkamp 			rc = utf8_valid(str, buf_end);
213f9193f4cSDaniel Verkamp 			if (rc == 0) {
214d6fd64cdSDaniel Verkamp 				*str_end = str;
215f9193f4cSDaniel Verkamp 				return SPDK_JSON_PARSE_INCOMPLETE;
216f9193f4cSDaniel Verkamp 			} else if (rc < 0) {
217d6fd64cdSDaniel Verkamp 				*str_end = str;
218f9193f4cSDaniel Verkamp 				return SPDK_JSON_PARSE_INVALID;
219f9193f4cSDaniel Verkamp 			}
220f9193f4cSDaniel Verkamp 
221f9193f4cSDaniel Verkamp 			if (out && out != str && (flags & SPDK_JSON_PARSE_FLAG_DECODE_IN_PLACE)) {
222f9193f4cSDaniel Verkamp 				memmove(out, str, rc);
223f9193f4cSDaniel Verkamp 			}
224f9193f4cSDaniel Verkamp 			out += rc;
225f9193f4cSDaniel Verkamp 			str += rc;
226f9193f4cSDaniel Verkamp 		}
227f9193f4cSDaniel Verkamp 	}
228f9193f4cSDaniel Verkamp 
229f9193f4cSDaniel Verkamp 	/* If execution gets here, we ran out of buffer. */
230d6fd64cdSDaniel Verkamp 	*str_end = str;
231f9193f4cSDaniel Verkamp 	return SPDK_JSON_PARSE_INCOMPLETE;
232f9193f4cSDaniel Verkamp }
233f9193f4cSDaniel Verkamp 
234f9193f4cSDaniel Verkamp static int
json_valid_number(uint8_t * start,uint8_t * buf_end)235f9193f4cSDaniel Verkamp json_valid_number(uint8_t *start, uint8_t *buf_end)
236f9193f4cSDaniel Verkamp {
237f9193f4cSDaniel Verkamp 	uint8_t *p = start;
23838c09e5eSDaniel Verkamp 	uint8_t c;
239f9193f4cSDaniel Verkamp 
24059970a89SDaniel Verkamp 	if (p >= buf_end) { return -1; }
241f9193f4cSDaniel Verkamp 
24238c09e5eSDaniel Verkamp 	c = *p++;
24359970a89SDaniel Verkamp 	if (c >= '1' && c <= '9') { goto num_int_digits; }
24459970a89SDaniel Verkamp 	if (c == '0') { goto num_frac_or_exp; }
24559970a89SDaniel Verkamp 	if (c == '-') { goto num_int_first_digit; }
246f9193f4cSDaniel Verkamp 	p--;
24738c09e5eSDaniel Verkamp 	goto done_invalid;
248f9193f4cSDaniel Verkamp 
24938c09e5eSDaniel Verkamp num_int_first_digit:
25038c09e5eSDaniel Verkamp 	if (spdk_likely(p != buf_end)) {
25138c09e5eSDaniel Verkamp 		c = *p++;
25259970a89SDaniel Verkamp 		if (c == '0') { goto num_frac_or_exp; }
25359970a89SDaniel Verkamp 		if (c >= '1' && c <= '9') { goto num_int_digits; }
25438c09e5eSDaniel Verkamp 		p--;
25538c09e5eSDaniel Verkamp 	}
25638c09e5eSDaniel Verkamp 	goto done_invalid;
25738c09e5eSDaniel Verkamp 
25838c09e5eSDaniel Verkamp num_int_digits:
25938c09e5eSDaniel Verkamp 	if (spdk_likely(p != buf_end)) {
26038c09e5eSDaniel Verkamp 		c = *p++;
26159970a89SDaniel Verkamp 		if (c >= '0' && c <= '9') { goto num_int_digits; }
26259970a89SDaniel Verkamp 		if (c == '.') { goto num_frac_first_digit; }
26359970a89SDaniel Verkamp 		if (c == 'e' || c == 'E') { goto num_exp_sign; }
26438c09e5eSDaniel Verkamp 		p--;
26538c09e5eSDaniel Verkamp 	}
26638c09e5eSDaniel Verkamp 	goto done_valid;
26738c09e5eSDaniel Verkamp 
26838c09e5eSDaniel Verkamp num_frac_or_exp:
26938c09e5eSDaniel Verkamp 	if (spdk_likely(p != buf_end)) {
27038c09e5eSDaniel Verkamp 		c = *p++;
27159970a89SDaniel Verkamp 		if (c == '.') { goto num_frac_first_digit; }
27259970a89SDaniel Verkamp 		if (c == 'e' || c == 'E') { goto num_exp_sign; }
27338c09e5eSDaniel Verkamp 		p--;
27438c09e5eSDaniel Verkamp 	}
27538c09e5eSDaniel Verkamp 	goto done_valid;
27638c09e5eSDaniel Verkamp 
27738c09e5eSDaniel Verkamp num_frac_first_digit:
27838c09e5eSDaniel Verkamp 	if (spdk_likely(p != buf_end)) {
27938c09e5eSDaniel Verkamp 		c = *p++;
28059970a89SDaniel Verkamp 		if (c >= '0' && c <= '9') { goto num_frac_digits; }
28138c09e5eSDaniel Verkamp 		p--;
28238c09e5eSDaniel Verkamp 	}
28338c09e5eSDaniel Verkamp 	goto done_invalid;
28438c09e5eSDaniel Verkamp 
28538c09e5eSDaniel Verkamp num_frac_digits:
28638c09e5eSDaniel Verkamp 	if (spdk_likely(p != buf_end)) {
28738c09e5eSDaniel Verkamp 		c = *p++;
28859970a89SDaniel Verkamp 		if (c >= '0' && c <= '9') { goto num_frac_digits; }
28959970a89SDaniel Verkamp 		if (c == 'e' || c == 'E') { goto num_exp_sign; }
29038c09e5eSDaniel Verkamp 		p--;
29138c09e5eSDaniel Verkamp 	}
29238c09e5eSDaniel Verkamp 	goto done_valid;
29338c09e5eSDaniel Verkamp 
29438c09e5eSDaniel Verkamp num_exp_sign:
29538c09e5eSDaniel Verkamp 	if (spdk_likely(p != buf_end)) {
29638c09e5eSDaniel Verkamp 		c = *p++;
29759970a89SDaniel Verkamp 		if (c >= '0' && c <= '9') { goto num_exp_digits; }
29859970a89SDaniel Verkamp 		if (c == '-' || c == '+') { goto num_exp_first_digit; }
29938c09e5eSDaniel Verkamp 		p--;
30038c09e5eSDaniel Verkamp 	}
30138c09e5eSDaniel Verkamp 	goto done_invalid;
30238c09e5eSDaniel Verkamp 
30338c09e5eSDaniel Verkamp num_exp_first_digit:
30438c09e5eSDaniel Verkamp 	if (spdk_likely(p != buf_end)) {
30538c09e5eSDaniel Verkamp 		c = *p++;
30659970a89SDaniel Verkamp 		if (c >= '0' && c <= '9') { goto num_exp_digits; }
30738c09e5eSDaniel Verkamp 		p--;
30838c09e5eSDaniel Verkamp 	}
30938c09e5eSDaniel Verkamp 	goto done_invalid;
31038c09e5eSDaniel Verkamp 
31138c09e5eSDaniel Verkamp num_exp_digits:
31238c09e5eSDaniel Verkamp 	if (spdk_likely(p != buf_end)) {
31338c09e5eSDaniel Verkamp 		c = *p++;
31459970a89SDaniel Verkamp 		if (c >= '0' && c <= '9') { goto num_exp_digits; }
31538c09e5eSDaniel Verkamp 		p--;
31638c09e5eSDaniel Verkamp 	}
31738c09e5eSDaniel Verkamp 	goto done_valid;
31838c09e5eSDaniel Verkamp 
31938c09e5eSDaniel Verkamp done_valid:
320f9193f4cSDaniel Verkamp 	/* Valid end state */
321f9193f4cSDaniel Verkamp 	return p - start;
322f9193f4cSDaniel Verkamp 
32338c09e5eSDaniel Verkamp done_invalid:
32438c09e5eSDaniel Verkamp 	/* Invalid end state */
32538c09e5eSDaniel Verkamp 	if (p == buf_end) {
32638c09e5eSDaniel Verkamp 		/* Hit the end of the buffer - the stream is incomplete. */
327f9193f4cSDaniel Verkamp 		return SPDK_JSON_PARSE_INCOMPLETE;
328f9193f4cSDaniel Verkamp 	}
32938c09e5eSDaniel Verkamp 
33038c09e5eSDaniel Verkamp 	/* Found an invalid character in an invalid end state */
33138c09e5eSDaniel Verkamp 	return SPDK_JSON_PARSE_INVALID;
332f9193f4cSDaniel Verkamp }
333f9193f4cSDaniel Verkamp 
33469c7ff06SDaniel Verkamp static int
json_valid_comment(const uint8_t * start,const uint8_t * buf_end)33569c7ff06SDaniel Verkamp json_valid_comment(const uint8_t *start, const uint8_t *buf_end)
33669c7ff06SDaniel Verkamp {
33769c7ff06SDaniel Verkamp 	const uint8_t *p = start;
33869c7ff06SDaniel Verkamp 	bool multiline;
33969c7ff06SDaniel Verkamp 
34069c7ff06SDaniel Verkamp 	assert(buf_end > p);
34169c7ff06SDaniel Verkamp 	if (buf_end - p < 2) {
34269c7ff06SDaniel Verkamp 		return SPDK_JSON_PARSE_INCOMPLETE;
34369c7ff06SDaniel Verkamp 	}
34469c7ff06SDaniel Verkamp 
34569c7ff06SDaniel Verkamp 	if (p[0] != '/') {
34669c7ff06SDaniel Verkamp 		return SPDK_JSON_PARSE_INVALID;
34769c7ff06SDaniel Verkamp 	}
34869c7ff06SDaniel Verkamp 	if (p[1] == '*') {
34969c7ff06SDaniel Verkamp 		multiline = true;
35069c7ff06SDaniel Verkamp 	} else if (p[1] == '/') {
35169c7ff06SDaniel Verkamp 		multiline = false;
35269c7ff06SDaniel Verkamp 	} else {
35369c7ff06SDaniel Verkamp 		return SPDK_JSON_PARSE_INVALID;
35469c7ff06SDaniel Verkamp 	}
35569c7ff06SDaniel Verkamp 	p += 2;
35669c7ff06SDaniel Verkamp 
35769c7ff06SDaniel Verkamp 	if (multiline) {
35869c7ff06SDaniel Verkamp 		while (p != buf_end - 1) {
35969c7ff06SDaniel Verkamp 			if (p[0] == '*' && p[1] == '/') {
36069c7ff06SDaniel Verkamp 				/* Include the terminating star and slash in the comment */
36169c7ff06SDaniel Verkamp 				return p - start + 2;
36269c7ff06SDaniel Verkamp 			}
36369c7ff06SDaniel Verkamp 			p++;
36469c7ff06SDaniel Verkamp 		}
36569c7ff06SDaniel Verkamp 	} else {
36669c7ff06SDaniel Verkamp 		while (p != buf_end) {
36769c7ff06SDaniel Verkamp 			if (*p == '\r' || *p == '\n') {
36869c7ff06SDaniel Verkamp 				/* Do not include the line terminator in the comment */
36969c7ff06SDaniel Verkamp 				return p - start;
37069c7ff06SDaniel Verkamp 			}
37169c7ff06SDaniel Verkamp 			p++;
37269c7ff06SDaniel Verkamp 		}
37369c7ff06SDaniel Verkamp 	}
37469c7ff06SDaniel Verkamp 
37569c7ff06SDaniel Verkamp 	return SPDK_JSON_PARSE_INCOMPLETE;
37669c7ff06SDaniel Verkamp }
37769c7ff06SDaniel Verkamp 
378f9193f4cSDaniel Verkamp struct json_literal {
379f9193f4cSDaniel Verkamp 	enum spdk_json_val_type type;
380f9193f4cSDaniel Verkamp 	uint32_t len;
381f9193f4cSDaniel Verkamp 	uint8_t str[8];
382f9193f4cSDaniel Verkamp };
383f9193f4cSDaniel Verkamp 
384f9193f4cSDaniel Verkamp /*
385f9193f4cSDaniel Verkamp  * JSON only defines 3 possible literals; they can be uniquely identified by bits
386f9193f4cSDaniel Verkamp  *  3 and 4 of the first character:
387f9193f4cSDaniel Verkamp  *   'f' = 0b11[00]110
388f9193f4cSDaniel Verkamp  *   'n' = 0b11[01]110
389f9193f4cSDaniel Verkamp  *   't' = 0b11[10]100
390f9193f4cSDaniel Verkamp  * These two bits can be used as an index into the g_json_literals array.
391f9193f4cSDaniel Verkamp  */
392f9193f4cSDaniel Verkamp static const struct json_literal g_json_literals[] = {
393f9193f4cSDaniel Verkamp 	{SPDK_JSON_VAL_FALSE, 5, "false"},
394f9193f4cSDaniel Verkamp 	{SPDK_JSON_VAL_NULL,  4, "null"},
395f9193f4cSDaniel Verkamp 	{SPDK_JSON_VAL_TRUE,  4, "true"},
396f9193f4cSDaniel Verkamp 	{}
397f9193f4cSDaniel Verkamp };
398f9193f4cSDaniel Verkamp 
399f9193f4cSDaniel Verkamp static int
match_literal(const uint8_t * start,const uint8_t * end,const uint8_t * literal,size_t len)400f9193f4cSDaniel Verkamp match_literal(const uint8_t *start, const uint8_t *end, const uint8_t *literal, size_t len)
401f9193f4cSDaniel Verkamp {
402f9193f4cSDaniel Verkamp 	assert(end >= start);
403f9193f4cSDaniel Verkamp 	if ((size_t)(end - start) < len) {
404f9193f4cSDaniel Verkamp 		return SPDK_JSON_PARSE_INCOMPLETE;
405f9193f4cSDaniel Verkamp 	}
406f9193f4cSDaniel Verkamp 
407f9193f4cSDaniel Verkamp 	if (memcmp(start, literal, len) != 0) {
408f9193f4cSDaniel Verkamp 		return SPDK_JSON_PARSE_INVALID;
409f9193f4cSDaniel Verkamp 	}
410f9193f4cSDaniel Verkamp 
411f9193f4cSDaniel Verkamp 	return len;
412f9193f4cSDaniel Verkamp }
413f9193f4cSDaniel Verkamp 
414f9193f4cSDaniel Verkamp ssize_t
spdk_json_parse(void * json,size_t size,struct spdk_json_val * values,size_t num_values,void ** end,uint32_t flags)415f9193f4cSDaniel Verkamp spdk_json_parse(void *json, size_t size, struct spdk_json_val *values, size_t num_values,
416f9193f4cSDaniel Verkamp 		void **end, uint32_t flags)
417f9193f4cSDaniel Verkamp {
418f9193f4cSDaniel Verkamp 	uint8_t *json_end = json + size;
419f9193f4cSDaniel Verkamp 	enum spdk_json_val_type containers[SPDK_JSON_MAX_NESTING_DEPTH];
420f9193f4cSDaniel Verkamp 	size_t con_value[SPDK_JSON_MAX_NESTING_DEPTH];
421f9193f4cSDaniel Verkamp 	enum spdk_json_val_type con_type = SPDK_JSON_VAL_INVALID;
422f9193f4cSDaniel Verkamp 	bool trailing_comma = false;
423f9193f4cSDaniel Verkamp 	size_t depth = 0; /* index into containers */
424f9193f4cSDaniel Verkamp 	size_t cur_value = 0; /* index into values */
425f9193f4cSDaniel Verkamp 	size_t con_start_value;
426f9193f4cSDaniel Verkamp 	uint8_t *data = json;
427f9193f4cSDaniel Verkamp 	uint8_t *new_data;
428d6fd64cdSDaniel Verkamp 	int rc = 0;
429f9193f4cSDaniel Verkamp 	const struct json_literal *lit;
430f9193f4cSDaniel Verkamp 	enum {
431f9193f4cSDaniel Verkamp 		STATE_VALUE, /* initial state */
432f9193f4cSDaniel Verkamp 		STATE_VALUE_SEPARATOR, /* value separator (comma) */
433f9193f4cSDaniel Verkamp 		STATE_NAME, /* "name": value */
434f9193f4cSDaniel Verkamp 		STATE_NAME_SEPARATOR, /* colon */
435f9193f4cSDaniel Verkamp 		STATE_END, /* parsed the complete value, so only whitespace is valid */
436f9193f4cSDaniel Verkamp 	} state = STATE_VALUE;
437f9193f4cSDaniel Verkamp 
438f9193f4cSDaniel Verkamp #define ADD_VALUE(t, val_start_ptr, val_end_ptr) \
439f9193f4cSDaniel Verkamp 	if (values && cur_value < num_values) { \
440f9193f4cSDaniel Verkamp 		values[cur_value].type = t; \
441f9193f4cSDaniel Verkamp 		values[cur_value].start = val_start_ptr; \
442f9193f4cSDaniel Verkamp 		values[cur_value].len = val_end_ptr - val_start_ptr; \
443f9193f4cSDaniel Verkamp 	} \
444f9193f4cSDaniel Verkamp 	cur_value++
445f9193f4cSDaniel Verkamp 
446f9193f4cSDaniel Verkamp 	while (data < json_end) {
447f9193f4cSDaniel Verkamp 		uint8_t c = *data;
448f9193f4cSDaniel Verkamp 
449f9193f4cSDaniel Verkamp 		switch (c) {
450f9193f4cSDaniel Verkamp 		case ' ':
451f9193f4cSDaniel Verkamp 		case '\t':
452f9193f4cSDaniel Verkamp 		case '\r':
453f9193f4cSDaniel Verkamp 		case '\n':
454f9193f4cSDaniel Verkamp 			/* Whitespace is allowed between any tokens. */
455f9193f4cSDaniel Verkamp 			data++;
456f9193f4cSDaniel Verkamp 			break;
457f9193f4cSDaniel Verkamp 
458f9193f4cSDaniel Verkamp 		case 't':
459f9193f4cSDaniel Verkamp 		case 'f':
460f9193f4cSDaniel Verkamp 		case 'n':
461f9193f4cSDaniel Verkamp 			/* true, false, or null */
46259970a89SDaniel Verkamp 			if (state != STATE_VALUE) { goto done_invalid; }
463f9193f4cSDaniel Verkamp 			lit = &g_json_literals[(c >> 3) & 3]; /* See comment above g_json_literals[] */
464f9193f4cSDaniel Verkamp 			assert(lit->str[0] == c);
465f9193f4cSDaniel Verkamp 			rc = match_literal(data, json_end, lit->str, lit->len);
46659970a89SDaniel Verkamp 			if (rc < 0) { goto done_rc; }
467f9193f4cSDaniel Verkamp 			ADD_VALUE(lit->type, data, data + rc);
468f9193f4cSDaniel Verkamp 			data += rc;
469f9193f4cSDaniel Verkamp 			state = depth ? STATE_VALUE_SEPARATOR : STATE_END;
470f9193f4cSDaniel Verkamp 			trailing_comma = false;
471f9193f4cSDaniel Verkamp 			break;
472f9193f4cSDaniel Verkamp 
473f9193f4cSDaniel Verkamp 		case '"':
47459970a89SDaniel Verkamp 			if (state != STATE_VALUE && state != STATE_NAME) { goto done_invalid; }
475f9193f4cSDaniel Verkamp 			rc = json_decode_string(data, json_end, &new_data, flags);
476d6fd64cdSDaniel Verkamp 			if (rc < 0) {
477d6fd64cdSDaniel Verkamp 				data = new_data;
478d6fd64cdSDaniel Verkamp 				goto done_rc;
479d6fd64cdSDaniel Verkamp 			}
480f9193f4cSDaniel Verkamp 			/*
481f9193f4cSDaniel Verkamp 			 * Start is data + 1 to skip initial quote.
482f9193f4cSDaniel Verkamp 			 * Length is data + rc - 1 to skip both quotes.
483f9193f4cSDaniel Verkamp 			 */
484f9193f4cSDaniel Verkamp 			ADD_VALUE(state == STATE_VALUE ? SPDK_JSON_VAL_STRING : SPDK_JSON_VAL_NAME,
485f9193f4cSDaniel Verkamp 				  data + 1, data + rc - 1);
486f9193f4cSDaniel Verkamp 			data = new_data;
487f9193f4cSDaniel Verkamp 			if (state == STATE_NAME) {
488f9193f4cSDaniel Verkamp 				state = STATE_NAME_SEPARATOR;
489f9193f4cSDaniel Verkamp 			} else {
490f9193f4cSDaniel Verkamp 				state = depth ? STATE_VALUE_SEPARATOR : STATE_END;
491f9193f4cSDaniel Verkamp 			}
492f9193f4cSDaniel Verkamp 			trailing_comma = false;
493f9193f4cSDaniel Verkamp 			break;
494f9193f4cSDaniel Verkamp 
495f9193f4cSDaniel Verkamp 		case '-':
496f9193f4cSDaniel Verkamp 		case '0':
497f9193f4cSDaniel Verkamp 		case '1':
498f9193f4cSDaniel Verkamp 		case '2':
499f9193f4cSDaniel Verkamp 		case '3':
500f9193f4cSDaniel Verkamp 		case '4':
501f9193f4cSDaniel Verkamp 		case '5':
502f9193f4cSDaniel Verkamp 		case '6':
503f9193f4cSDaniel Verkamp 		case '7':
504f9193f4cSDaniel Verkamp 		case '8':
505f9193f4cSDaniel Verkamp 		case '9':
50659970a89SDaniel Verkamp 			if (state != STATE_VALUE) { goto done_invalid; }
507f9193f4cSDaniel Verkamp 			rc = json_valid_number(data, json_end);
50859970a89SDaniel Verkamp 			if (rc < 0) { goto done_rc; }
509f9193f4cSDaniel Verkamp 			ADD_VALUE(SPDK_JSON_VAL_NUMBER, data, data + rc);
510f9193f4cSDaniel Verkamp 			data += rc;
511f9193f4cSDaniel Verkamp 			state = depth ? STATE_VALUE_SEPARATOR : STATE_END;
512f9193f4cSDaniel Verkamp 			trailing_comma = false;
513f9193f4cSDaniel Verkamp 			break;
514f9193f4cSDaniel Verkamp 
515f9193f4cSDaniel Verkamp 		case '{':
516f9193f4cSDaniel Verkamp 		case '[':
51759970a89SDaniel Verkamp 			if (state != STATE_VALUE) { goto done_invalid; }
518f9193f4cSDaniel Verkamp 			if (depth == SPDK_JSON_MAX_NESTING_DEPTH) {
519d6fd64cdSDaniel Verkamp 				rc = SPDK_JSON_PARSE_MAX_DEPTH_EXCEEDED;
520d6fd64cdSDaniel Verkamp 				goto done_rc;
521f9193f4cSDaniel Verkamp 			}
522f9193f4cSDaniel Verkamp 			if (c == '{') {
523f9193f4cSDaniel Verkamp 				con_type = SPDK_JSON_VAL_OBJECT_BEGIN;
524f9193f4cSDaniel Verkamp 				state = STATE_NAME;
525f9193f4cSDaniel Verkamp 			} else {
526f9193f4cSDaniel Verkamp 				con_type = SPDK_JSON_VAL_ARRAY_BEGIN;
527f9193f4cSDaniel Verkamp 				state = STATE_VALUE;
528f9193f4cSDaniel Verkamp 			}
529f9193f4cSDaniel Verkamp 			con_value[depth] = cur_value;
530f9193f4cSDaniel Verkamp 			containers[depth++] = con_type;
531f9193f4cSDaniel Verkamp 			ADD_VALUE(con_type, data, data + 1);
532f9193f4cSDaniel Verkamp 			data++;
533f9193f4cSDaniel Verkamp 			trailing_comma = false;
534f9193f4cSDaniel Verkamp 			break;
535f9193f4cSDaniel Verkamp 
536f9193f4cSDaniel Verkamp 		case '}':
537f9193f4cSDaniel Verkamp 		case ']':
53859970a89SDaniel Verkamp 			if (trailing_comma) { goto done_invalid; }
53959970a89SDaniel Verkamp 			if (depth == 0) { goto done_invalid; }
540f9193f4cSDaniel Verkamp 			con_type = containers[--depth];
541f9193f4cSDaniel Verkamp 			con_start_value = con_value[depth];
542f9193f4cSDaniel Verkamp 			if (values && con_start_value < num_values) {
543f9193f4cSDaniel Verkamp 				values[con_start_value].len = cur_value - con_start_value - 1;
544f9193f4cSDaniel Verkamp 			}
545f9193f4cSDaniel Verkamp 			if (c == '}') {
546f9193f4cSDaniel Verkamp 				if (state != STATE_NAME && state != STATE_VALUE_SEPARATOR) {
547d6fd64cdSDaniel Verkamp 					goto done_invalid;
548f9193f4cSDaniel Verkamp 				}
549f9193f4cSDaniel Verkamp 				if (con_type != SPDK_JSON_VAL_OBJECT_BEGIN) {
550d6fd64cdSDaniel Verkamp 					goto done_invalid;
551f9193f4cSDaniel Verkamp 				}
552f9193f4cSDaniel Verkamp 				ADD_VALUE(SPDK_JSON_VAL_OBJECT_END, data, data + 1);
553f9193f4cSDaniel Verkamp 			} else {
554f9193f4cSDaniel Verkamp 				if (state != STATE_VALUE && state != STATE_VALUE_SEPARATOR) {
555d6fd64cdSDaniel Verkamp 					goto done_invalid;
556f9193f4cSDaniel Verkamp 				}
557f9193f4cSDaniel Verkamp 				if (con_type != SPDK_JSON_VAL_ARRAY_BEGIN) {
558d6fd64cdSDaniel Verkamp 					goto done_invalid;
559f9193f4cSDaniel Verkamp 				}
560f9193f4cSDaniel Verkamp 				ADD_VALUE(SPDK_JSON_VAL_ARRAY_END, data, data + 1);
561f9193f4cSDaniel Verkamp 			}
562f9193f4cSDaniel Verkamp 			con_type = depth == 0 ? SPDK_JSON_VAL_INVALID : containers[depth - 1];
563f9193f4cSDaniel Verkamp 			data++;
564f9193f4cSDaniel Verkamp 			state = depth ? STATE_VALUE_SEPARATOR : STATE_END;
565f9193f4cSDaniel Verkamp 			trailing_comma = false;
566f9193f4cSDaniel Verkamp 			break;
567f9193f4cSDaniel Verkamp 
568f9193f4cSDaniel Verkamp 		case ',':
56959970a89SDaniel Verkamp 			if (state != STATE_VALUE_SEPARATOR) { goto done_invalid; }
570f9193f4cSDaniel Verkamp 			data++;
571f9193f4cSDaniel Verkamp 			assert(con_type == SPDK_JSON_VAL_ARRAY_BEGIN ||
572f9193f4cSDaniel Verkamp 			       con_type == SPDK_JSON_VAL_OBJECT_BEGIN);
573f9193f4cSDaniel Verkamp 			state = con_type == SPDK_JSON_VAL_ARRAY_BEGIN ? STATE_VALUE : STATE_NAME;
574f9193f4cSDaniel Verkamp 			trailing_comma = true;
575f9193f4cSDaniel Verkamp 			break;
576f9193f4cSDaniel Verkamp 
577f9193f4cSDaniel Verkamp 		case ':':
57859970a89SDaniel Verkamp 			if (state != STATE_NAME_SEPARATOR) { goto done_invalid; }
579f9193f4cSDaniel Verkamp 			data++;
580f9193f4cSDaniel Verkamp 			state = STATE_VALUE;
581f9193f4cSDaniel Verkamp 			break;
582f9193f4cSDaniel Verkamp 
58369c7ff06SDaniel Verkamp 		case '/':
58469c7ff06SDaniel Verkamp 			if (!(flags & SPDK_JSON_PARSE_FLAG_ALLOW_COMMENTS)) {
585d6fd64cdSDaniel Verkamp 				goto done_invalid;
58669c7ff06SDaniel Verkamp 			}
58769c7ff06SDaniel Verkamp 			rc = json_valid_comment(data, json_end);
58859970a89SDaniel Verkamp 			if (rc < 0) { goto done_rc; }
58969c7ff06SDaniel Verkamp 			/* Skip over comment */
59069c7ff06SDaniel Verkamp 			data += rc;
59169c7ff06SDaniel Verkamp 			break;
59269c7ff06SDaniel Verkamp 
593f9193f4cSDaniel Verkamp 		default:
594d6fd64cdSDaniel Verkamp 			goto done_invalid;
595f9193f4cSDaniel Verkamp 		}
596f9193f4cSDaniel Verkamp 
597f9193f4cSDaniel Verkamp 		if (state == STATE_END) {
598f9193f4cSDaniel Verkamp 			break;
599f9193f4cSDaniel Verkamp 		}
600f9193f4cSDaniel Verkamp 	}
601f9193f4cSDaniel Verkamp 
602f9193f4cSDaniel Verkamp 	if (state == STATE_END) {
603f9193f4cSDaniel Verkamp 		/* Skip trailing whitespace */
604f9193f4cSDaniel Verkamp 		while (data < json_end) {
605f9193f4cSDaniel Verkamp 			uint8_t c = *data;
606f9193f4cSDaniel Verkamp 
607f9193f4cSDaniel Verkamp 			if (c == ' ' || c == '\t' || c == '\r' || c == '\n') {
608f9193f4cSDaniel Verkamp 				data++;
609f9193f4cSDaniel Verkamp 			} else {
610f9193f4cSDaniel Verkamp 				break;
611f9193f4cSDaniel Verkamp 			}
612f9193f4cSDaniel Verkamp 		}
613f9193f4cSDaniel Verkamp 
614f9193f4cSDaniel Verkamp 		/*
615f9193f4cSDaniel Verkamp 		 * These asserts are just for sanity checking - they are guaranteed by the allowed
616f9193f4cSDaniel Verkamp 		 *  state transitions.
617f9193f4cSDaniel Verkamp 		 */
618f9193f4cSDaniel Verkamp 		assert(depth == 0);
619f9193f4cSDaniel Verkamp 		assert(trailing_comma == false);
620f9193f4cSDaniel Verkamp 		assert(data <= json_end);
621f9193f4cSDaniel Verkamp 		if (end) {
622f9193f4cSDaniel Verkamp 			*end = data;
623f9193f4cSDaniel Verkamp 		}
624f9193f4cSDaniel Verkamp 		return cur_value;
625f9193f4cSDaniel Verkamp 	}
626f9193f4cSDaniel Verkamp 
627f9193f4cSDaniel Verkamp 	/* Invalid end state - ran out of data */
628d6fd64cdSDaniel Verkamp 	rc = SPDK_JSON_PARSE_INCOMPLETE;
629d6fd64cdSDaniel Verkamp 
630d6fd64cdSDaniel Verkamp done_rc:
631d6fd64cdSDaniel Verkamp 	assert(rc < 0);
632f9193f4cSDaniel Verkamp 	if (end) {
633f9193f4cSDaniel Verkamp 		*end = data;
634f9193f4cSDaniel Verkamp 	}
635d6fd64cdSDaniel Verkamp 	return rc;
636d6fd64cdSDaniel Verkamp 
637d6fd64cdSDaniel Verkamp done_invalid:
638d6fd64cdSDaniel Verkamp 	rc = SPDK_JSON_PARSE_INVALID;
639d6fd64cdSDaniel Verkamp 	goto done_rc;
640f9193f4cSDaniel Verkamp }
641