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