xref: /spdk/lib/json/json_util.c (revision c6480ea767bb81c01eda34cc804ef45b4a748b82)
1488570ebSJim Harris /*   SPDX-License-Identifier: BSD-3-Clause
2a6dbe372Spaul 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"
94e8e97c8STomasz Zawadzki #include "spdk/log.h"
10439641f7SPawel Wodkowski 
112172c432STomasz Zawadzki #define SPDK_JSON_DEBUG(...) SPDK_DEBUGLOG(json_util, __VA_ARGS__)
12f9193f4cSDaniel Verkamp 
13f9193f4cSDaniel Verkamp size_t
spdk_json_val_len(const struct spdk_json_val * val)14f9193f4cSDaniel Verkamp spdk_json_val_len(const struct spdk_json_val *val)
15f9193f4cSDaniel Verkamp {
16f9193f4cSDaniel Verkamp 	if (val == NULL) {
17f9193f4cSDaniel Verkamp 		return 0;
18f9193f4cSDaniel Verkamp 	}
19f9193f4cSDaniel Verkamp 
20f9193f4cSDaniel Verkamp 	if (val->type == SPDK_JSON_VAL_ARRAY_BEGIN || val->type == SPDK_JSON_VAL_OBJECT_BEGIN) {
21f9193f4cSDaniel Verkamp 		return val->len + 2;
22f9193f4cSDaniel Verkamp 	}
23f9193f4cSDaniel Verkamp 
24f9193f4cSDaniel Verkamp 	return 1;
25f9193f4cSDaniel Verkamp }
26f9193f4cSDaniel Verkamp 
27f9193f4cSDaniel Verkamp bool
spdk_json_strequal(const struct spdk_json_val * val,const char * str)28f9193f4cSDaniel Verkamp spdk_json_strequal(const struct spdk_json_val *val, const char *str)
29f9193f4cSDaniel Verkamp {
30f9193f4cSDaniel Verkamp 	size_t len;
31f9193f4cSDaniel Verkamp 
32f9193f4cSDaniel Verkamp 	if (val->type != SPDK_JSON_VAL_STRING && val->type != SPDK_JSON_VAL_NAME) {
33f9193f4cSDaniel Verkamp 		return false;
34f9193f4cSDaniel Verkamp 	}
35f9193f4cSDaniel Verkamp 
36f9193f4cSDaniel Verkamp 	len = strlen(str);
37f9193f4cSDaniel Verkamp 	if (val->len != len) {
38f9193f4cSDaniel Verkamp 		return false;
39f9193f4cSDaniel Verkamp 	}
40f9193f4cSDaniel Verkamp 
41f9193f4cSDaniel Verkamp 	return memcmp(val->start, str, len) == 0;
42f9193f4cSDaniel Verkamp }
43f9193f4cSDaniel Verkamp 
44f9193f4cSDaniel Verkamp char *
spdk_json_strdup(const struct spdk_json_val * val)45f9193f4cSDaniel Verkamp spdk_json_strdup(const struct spdk_json_val *val)
46f9193f4cSDaniel Verkamp {
47f9193f4cSDaniel Verkamp 	size_t len;
48f9193f4cSDaniel Verkamp 	char *s;
49f9193f4cSDaniel Verkamp 
50f9193f4cSDaniel Verkamp 	if (val->type != SPDK_JSON_VAL_STRING && val->type != SPDK_JSON_VAL_NAME) {
51f9193f4cSDaniel Verkamp 		return NULL;
52f9193f4cSDaniel Verkamp 	}
53f9193f4cSDaniel Verkamp 
54f9193f4cSDaniel Verkamp 	len = val->len;
55f9193f4cSDaniel Verkamp 
56f9193f4cSDaniel Verkamp 	if (memchr(val->start, '\0', len)) {
57f9193f4cSDaniel Verkamp 		/* String contains embedded NUL, so it is not a valid C string. */
58f9193f4cSDaniel Verkamp 		return NULL;
59f9193f4cSDaniel Verkamp 	}
60f9193f4cSDaniel Verkamp 
61f9193f4cSDaniel Verkamp 	s = malloc(len + 1);
62f9193f4cSDaniel Verkamp 	if (s == NULL) {
63f9193f4cSDaniel Verkamp 		return s;
64f9193f4cSDaniel Verkamp 	}
65f9193f4cSDaniel Verkamp 
66f9193f4cSDaniel Verkamp 	memcpy(s, val->start, len);
67f9193f4cSDaniel Verkamp 	s[len] = '\0';
68f9193f4cSDaniel Verkamp 
69f9193f4cSDaniel Verkamp 	return s;
70f9193f4cSDaniel Verkamp }
71f9193f4cSDaniel Verkamp 
727089d582SDaniel Verkamp struct spdk_json_num {
737089d582SDaniel Verkamp 	bool negative;
747089d582SDaniel Verkamp 	uint64_t significand;
757089d582SDaniel Verkamp 	int64_t exponent;
767089d582SDaniel Verkamp };
777089d582SDaniel Verkamp 
787089d582SDaniel Verkamp static int
json_number_split(const struct spdk_json_val * val,struct spdk_json_num * num)790be5557cSSeth Howell json_number_split(const struct spdk_json_val *val, struct spdk_json_num *num)
807089d582SDaniel Verkamp {
817089d582SDaniel Verkamp 	const char *iter;
827089d582SDaniel Verkamp 	size_t remaining;
837089d582SDaniel Verkamp 	uint64_t *pval;
847089d582SDaniel Verkamp 	uint64_t frac_digits = 0;
857089d582SDaniel Verkamp 	uint64_t exponent_u64 = 0;
867089d582SDaniel Verkamp 	bool exponent_negative = false;
877089d582SDaniel Verkamp 	enum {
887089d582SDaniel Verkamp 		NUM_STATE_INT,
897089d582SDaniel Verkamp 		NUM_STATE_FRAC,
907089d582SDaniel Verkamp 		NUM_STATE_EXP,
917089d582SDaniel Verkamp 	} state;
927089d582SDaniel Verkamp 
937089d582SDaniel Verkamp 	memset(num, 0, sizeof(*num));
947089d582SDaniel Verkamp 
957089d582SDaniel Verkamp 	if (val->type != SPDK_JSON_VAL_NUMBER) {
967089d582SDaniel Verkamp 		return -EINVAL;
977089d582SDaniel Verkamp 	}
987089d582SDaniel Verkamp 
997089d582SDaniel Verkamp 	remaining = val->len;
1007089d582SDaniel Verkamp 	if (remaining == 0) {
1017089d582SDaniel Verkamp 		return -EINVAL;
1027089d582SDaniel Verkamp 	}
1037089d582SDaniel Verkamp 
1047089d582SDaniel Verkamp 	iter = val->start;
1057089d582SDaniel Verkamp 	if (*iter == '-') {
1067089d582SDaniel Verkamp 		num->negative = true;
1077089d582SDaniel Verkamp 		iter++;
1087089d582SDaniel Verkamp 		remaining--;
1097089d582SDaniel Verkamp 	}
1107089d582SDaniel Verkamp 
1117089d582SDaniel Verkamp 	state = NUM_STATE_INT;
1127089d582SDaniel Verkamp 	pval = &num->significand;
1137089d582SDaniel Verkamp 	while (remaining--) {
1147089d582SDaniel Verkamp 		char c = *iter++;
1157089d582SDaniel Verkamp 
1167089d582SDaniel Verkamp 		if (c == '.') {
1177089d582SDaniel Verkamp 			state = NUM_STATE_FRAC;
1187089d582SDaniel Verkamp 		} else if (c == 'e' || c == 'E') {
1197089d582SDaniel Verkamp 			state = NUM_STATE_EXP;
1207089d582SDaniel Verkamp 			pval = &exponent_u64;
1217089d582SDaniel Verkamp 		} else if (c == '-') {
1227089d582SDaniel Verkamp 			assert(state == NUM_STATE_EXP);
1237089d582SDaniel Verkamp 			exponent_negative = true;
1247089d582SDaniel Verkamp 		} else if (c == '+') {
1257089d582SDaniel Verkamp 			assert(state == NUM_STATE_EXP);
1267089d582SDaniel Verkamp 			/* exp_negative = false; */ /* already false by default */
1277089d582SDaniel Verkamp 		} else {
1287089d582SDaniel Verkamp 			uint64_t new_val;
1297089d582SDaniel Verkamp 
1307089d582SDaniel Verkamp 			assert(c >= '0' && c <= '9');
1317089d582SDaniel Verkamp 			new_val = *pval * 10 + c - '0';
1327089d582SDaniel Verkamp 			if (new_val < *pval) {
1337089d582SDaniel Verkamp 				return -ERANGE;
1347089d582SDaniel Verkamp 			}
1357089d582SDaniel Verkamp 
1367089d582SDaniel Verkamp 			if (state == NUM_STATE_FRAC) {
1377089d582SDaniel Verkamp 				frac_digits++;
1387089d582SDaniel Verkamp 			}
1397089d582SDaniel Verkamp 
1407089d582SDaniel Verkamp 			*pval = new_val;
1417089d582SDaniel Verkamp 		}
1427089d582SDaniel Verkamp 	}
1437089d582SDaniel Verkamp 
1447089d582SDaniel Verkamp 	if (exponent_negative) {
1457089d582SDaniel Verkamp 		if (exponent_u64 > 9223372036854775808ULL) { /* abs(INT64_MIN) */
1467089d582SDaniel Verkamp 			return -ERANGE;
1477089d582SDaniel Verkamp 		}
1487089d582SDaniel Verkamp 		num->exponent = (int64_t) - exponent_u64;
1497089d582SDaniel Verkamp 	} else {
1507089d582SDaniel Verkamp 		if (exponent_u64 > INT64_MAX) {
1517089d582SDaniel Verkamp 			return -ERANGE;
1527089d582SDaniel Verkamp 		}
1537089d582SDaniel Verkamp 		num->exponent = exponent_u64;
1547089d582SDaniel Verkamp 	}
1557089d582SDaniel Verkamp 	num->exponent -= frac_digits;
1567089d582SDaniel Verkamp 
1577089d582SDaniel Verkamp 	/* Apply as much of the exponent as possible without overflow or truncation */
1587089d582SDaniel Verkamp 	if (num->exponent < 0) {
1597089d582SDaniel Verkamp 		while (num->exponent && num->significand >= 10 && num->significand % 10 == 0) {
1607089d582SDaniel Verkamp 			num->significand /= 10;
1617089d582SDaniel Verkamp 			num->exponent++;
1627089d582SDaniel Verkamp 		}
1637089d582SDaniel Verkamp 	} else { /* positive exponent */
1647089d582SDaniel Verkamp 		while (num->exponent) {
1657089d582SDaniel Verkamp 			uint64_t new_val = num->significand * 10;
1667089d582SDaniel Verkamp 
1677089d582SDaniel Verkamp 			if (new_val < num->significand) {
1687089d582SDaniel Verkamp 				break;
1697089d582SDaniel Verkamp 			}
1707089d582SDaniel Verkamp 
1717089d582SDaniel Verkamp 			num->significand = new_val;
1727089d582SDaniel Verkamp 			num->exponent--;
1737089d582SDaniel Verkamp 		}
1747089d582SDaniel Verkamp 	}
1757089d582SDaniel Verkamp 
1767089d582SDaniel Verkamp 	return 0;
1777089d582SDaniel Verkamp }
1787089d582SDaniel Verkamp 
179f9193f4cSDaniel Verkamp int
spdk_json_number_to_uint8(const struct spdk_json_val * val,uint8_t * num)180a827fd7eSJacek Kalwas spdk_json_number_to_uint8(const struct spdk_json_val *val, uint8_t *num)
181a827fd7eSJacek Kalwas {
182a827fd7eSJacek Kalwas 	struct spdk_json_num split_num;
183a827fd7eSJacek Kalwas 	int rc;
184a827fd7eSJacek Kalwas 
185a827fd7eSJacek Kalwas 	rc = json_number_split(val, &split_num);
186a827fd7eSJacek Kalwas 	if (rc) {
187a827fd7eSJacek Kalwas 		return rc;
188a827fd7eSJacek Kalwas 	}
189a827fd7eSJacek Kalwas 
190a827fd7eSJacek Kalwas 	if (split_num.exponent || split_num.negative) {
191a827fd7eSJacek Kalwas 		return -ERANGE;
192a827fd7eSJacek Kalwas 	}
193a827fd7eSJacek Kalwas 
194a827fd7eSJacek Kalwas 	if (split_num.significand > UINT8_MAX) {
195a827fd7eSJacek Kalwas 		return -ERANGE;
196a827fd7eSJacek Kalwas 	}
197a827fd7eSJacek Kalwas 	*num = (uint8_t)split_num.significand;
198a827fd7eSJacek Kalwas 	return 0;
199a827fd7eSJacek Kalwas }
200a827fd7eSJacek Kalwas 
201a827fd7eSJacek Kalwas int
spdk_json_number_to_uint16(const struct spdk_json_val * val,uint16_t * num)2026f872f5aSShuhei Matsumoto spdk_json_number_to_uint16(const struct spdk_json_val *val, uint16_t *num)
2036f872f5aSShuhei Matsumoto {
2046f872f5aSShuhei Matsumoto 	struct spdk_json_num split_num;
2056f872f5aSShuhei Matsumoto 	int rc;
2066f872f5aSShuhei Matsumoto 
2070be5557cSSeth Howell 	rc = json_number_split(val, &split_num);
2086f872f5aSShuhei Matsumoto 	if (rc) {
2096f872f5aSShuhei Matsumoto 		return rc;
2106f872f5aSShuhei Matsumoto 	}
2116f872f5aSShuhei Matsumoto 
2126f872f5aSShuhei Matsumoto 	if (split_num.exponent || split_num.negative) {
2136f872f5aSShuhei Matsumoto 		return -ERANGE;
2146f872f5aSShuhei Matsumoto 	}
2156f872f5aSShuhei Matsumoto 
2166f872f5aSShuhei Matsumoto 	if (split_num.significand > UINT16_MAX) {
2176f872f5aSShuhei Matsumoto 		return -ERANGE;
2186f872f5aSShuhei Matsumoto 	}
2196f872f5aSShuhei Matsumoto 	*num = (uint16_t)split_num.significand;
2206f872f5aSShuhei Matsumoto 	return 0;
2216f872f5aSShuhei Matsumoto }
2226f872f5aSShuhei Matsumoto 
2236f872f5aSShuhei Matsumoto int
spdk_json_number_to_int32(const struct spdk_json_val * val,int32_t * num)224f9193f4cSDaniel Verkamp spdk_json_number_to_int32(const struct spdk_json_val *val, int32_t *num)
225f9193f4cSDaniel Verkamp {
2267089d582SDaniel Verkamp 	struct spdk_json_num split_num;
2277089d582SDaniel Verkamp 	int rc;
228f9193f4cSDaniel Verkamp 
2290be5557cSSeth Howell 	rc = json_number_split(val, &split_num);
2307089d582SDaniel Verkamp 	if (rc) {
2317089d582SDaniel Verkamp 		return rc;
232f9193f4cSDaniel Verkamp 	}
233f9193f4cSDaniel Verkamp 
2347089d582SDaniel Verkamp 	if (split_num.exponent) {
2357089d582SDaniel Verkamp 		return -ERANGE;
236f9193f4cSDaniel Verkamp 	}
237f9193f4cSDaniel Verkamp 
2387089d582SDaniel Verkamp 	if (split_num.negative) {
2397089d582SDaniel Verkamp 		if (split_num.significand > 2147483648) { /* abs(INT32_MIN) */
2407089d582SDaniel Verkamp 			return -ERANGE;
2417089d582SDaniel Verkamp 		}
2427089d582SDaniel Verkamp 		*num = (int32_t) - (int64_t)split_num.significand;
2437089d582SDaniel Verkamp 		return 0;
2447089d582SDaniel Verkamp 	}
2457089d582SDaniel Verkamp 
2467089d582SDaniel Verkamp 	/* positive */
2477089d582SDaniel Verkamp 	if (split_num.significand > INT32_MAX) {
2487089d582SDaniel Verkamp 		return -ERANGE;
2497089d582SDaniel Verkamp 	}
2507089d582SDaniel Verkamp 	*num = (int32_t)split_num.significand;
251f9193f4cSDaniel Verkamp 	return 0;
252f9193f4cSDaniel Verkamp }
253f9193f4cSDaniel Verkamp 
254f9193f4cSDaniel Verkamp int
spdk_json_number_to_uint32(const struct spdk_json_val * val,uint32_t * num)255f9193f4cSDaniel Verkamp spdk_json_number_to_uint32(const struct spdk_json_val *val, uint32_t *num)
256f9193f4cSDaniel Verkamp {
2577089d582SDaniel Verkamp 	struct spdk_json_num split_num;
2587089d582SDaniel Verkamp 	int rc;
259f9193f4cSDaniel Verkamp 
2600be5557cSSeth Howell 	rc = json_number_split(val, &split_num);
2617089d582SDaniel Verkamp 	if (rc) {
2627089d582SDaniel Verkamp 		return rc;
263f9193f4cSDaniel Verkamp 	}
264f9193f4cSDaniel Verkamp 
2657089d582SDaniel Verkamp 	if (split_num.exponent || split_num.negative) {
2667089d582SDaniel Verkamp 		return -ERANGE;
267f9193f4cSDaniel Verkamp 	}
268f9193f4cSDaniel Verkamp 
2697089d582SDaniel Verkamp 	if (split_num.significand > UINT32_MAX) {
2707089d582SDaniel Verkamp 		return -ERANGE;
271f9193f4cSDaniel Verkamp 	}
2727089d582SDaniel Verkamp 	*num = (uint32_t)split_num.significand;
273f9193f4cSDaniel Verkamp 	return 0;
274f9193f4cSDaniel Verkamp }
275f9193f4cSDaniel Verkamp 
276f9193f4cSDaniel Verkamp int
spdk_json_number_to_uint64(const struct spdk_json_val * val,uint64_t * num)27761119d78SMaciej Szwed spdk_json_number_to_uint64(const struct spdk_json_val *val, uint64_t *num)
27861119d78SMaciej Szwed {
27961119d78SMaciej Szwed 	struct spdk_json_num split_num;
28061119d78SMaciej Szwed 	int rc;
28161119d78SMaciej Szwed 
2820be5557cSSeth Howell 	rc = json_number_split(val, &split_num);
28361119d78SMaciej Szwed 	if (rc) {
28461119d78SMaciej Szwed 		return rc;
28561119d78SMaciej Szwed 	}
28661119d78SMaciej Szwed 
28761119d78SMaciej Szwed 	if (split_num.exponent || split_num.negative) {
28861119d78SMaciej Szwed 		return -ERANGE;
28961119d78SMaciej Szwed 	}
29061119d78SMaciej Szwed 
29161119d78SMaciej Szwed 	*num = split_num.significand;
29261119d78SMaciej Szwed 	return 0;
29361119d78SMaciej Szwed }
29461119d78SMaciej Szwed 
29590472b86SJacek Kalwas static int
_json_decode_object(const struct spdk_json_val * values,const struct spdk_json_object_decoder * decoders,size_t num_decoders,void * out,bool relaxed)29690472b86SJacek Kalwas _json_decode_object(const struct spdk_json_val *values,
29790472b86SJacek Kalwas 		    const struct spdk_json_object_decoder *decoders, size_t num_decoders, void *out, bool relaxed)
298f9193f4cSDaniel Verkamp {
299f9193f4cSDaniel Verkamp 	uint32_t i;
300f9193f4cSDaniel Verkamp 	bool invalid = false;
301f9193f4cSDaniel Verkamp 	size_t decidx;
302f9193f4cSDaniel Verkamp 	bool *seen;
303f9193f4cSDaniel Verkamp 
304f9193f4cSDaniel Verkamp 	if (values == NULL || values->type != SPDK_JSON_VAL_OBJECT_BEGIN) {
305f9193f4cSDaniel Verkamp 		return -1;
306f9193f4cSDaniel Verkamp 	}
307f9193f4cSDaniel Verkamp 
308f9193f4cSDaniel Verkamp 	seen = calloc(sizeof(bool), num_decoders);
309f9193f4cSDaniel Verkamp 	if (seen == NULL) {
310f9193f4cSDaniel Verkamp 		return -1;
311f9193f4cSDaniel Verkamp 	}
312f9193f4cSDaniel Verkamp 
313f9193f4cSDaniel Verkamp 	for (i = 0; i < values->len;) {
314f9193f4cSDaniel Verkamp 		const struct spdk_json_val *name = &values[i + 1];
315f9193f4cSDaniel Verkamp 		const struct spdk_json_val *v = &values[i + 2];
316f9193f4cSDaniel Verkamp 		bool found = false;
317f9193f4cSDaniel Verkamp 
318f9193f4cSDaniel Verkamp 		for (decidx = 0; decidx < num_decoders; decidx++) {
319f9193f4cSDaniel Verkamp 			const struct spdk_json_object_decoder *dec = &decoders[decidx];
320f9193f4cSDaniel Verkamp 			if (spdk_json_strequal(name, dec->name)) {
321f9193f4cSDaniel Verkamp 				void *field = (void *)((uintptr_t)out + dec->offset);
322f9193f4cSDaniel Verkamp 
323f9193f4cSDaniel Verkamp 				found = true;
324f9193f4cSDaniel Verkamp 
325f9193f4cSDaniel Verkamp 				if (seen[decidx]) {
326f9193f4cSDaniel Verkamp 					/* duplicate field name */
327f9193f4cSDaniel Verkamp 					invalid = true;
32840f70de0SPawel Wodkowski 					SPDK_JSON_DEBUG("Duplicate key '%s'\n", dec->name);
329f9193f4cSDaniel Verkamp 				} else {
330f9193f4cSDaniel Verkamp 					seen[decidx] = true;
331f9193f4cSDaniel Verkamp 					if (dec->decode_func(v, field)) {
332f9193f4cSDaniel Verkamp 						invalid = true;
33340f70de0SPawel Wodkowski 						SPDK_JSON_DEBUG("Decoder failed to decode key '%s'\n", dec->name);
334f9193f4cSDaniel Verkamp 						/* keep going to fill out any other valid keys */
335f9193f4cSDaniel Verkamp 					}
336f9193f4cSDaniel Verkamp 				}
337f9193f4cSDaniel Verkamp 				break;
338f9193f4cSDaniel Verkamp 			}
339f9193f4cSDaniel Verkamp 		}
340f9193f4cSDaniel Verkamp 
34190472b86SJacek Kalwas 		if (!relaxed && !found) {
342f9193f4cSDaniel Verkamp 			invalid = true;
34340f70de0SPawel Wodkowski 			SPDK_JSON_DEBUG("Decoder not found for key '%.*s'\n", name->len, (char *)name->start);
344f9193f4cSDaniel Verkamp 		}
345f9193f4cSDaniel Verkamp 
346f9193f4cSDaniel Verkamp 		i += 1 + spdk_json_val_len(v);
347f9193f4cSDaniel Verkamp 	}
348f9193f4cSDaniel Verkamp 
349f9193f4cSDaniel Verkamp 	for (decidx = 0; decidx < num_decoders; decidx++) {
350f9193f4cSDaniel Verkamp 		if (!decoders[decidx].optional && !seen[decidx]) {
351f9193f4cSDaniel Verkamp 			/* required field is missing */
352f9193f4cSDaniel Verkamp 			invalid = true;
353f9193f4cSDaniel Verkamp 			break;
354f9193f4cSDaniel Verkamp 		}
355f9193f4cSDaniel Verkamp 	}
356f9193f4cSDaniel Verkamp 
357f9193f4cSDaniel Verkamp 	free(seen);
358f9193f4cSDaniel Verkamp 	return invalid ? -1 : 0;
359f9193f4cSDaniel Verkamp }
360f9193f4cSDaniel Verkamp 
361c77c6559SDarek Stojaczyk void
spdk_json_free_object(const struct spdk_json_object_decoder * decoders,size_t num_decoders,void * obj)362c77c6559SDarek Stojaczyk spdk_json_free_object(const struct spdk_json_object_decoder *decoders, size_t num_decoders,
363c77c6559SDarek Stojaczyk 		      void *obj)
364c77c6559SDarek Stojaczyk {
365c77c6559SDarek Stojaczyk 	struct spdk_json_val invalid_val = {
366c77c6559SDarek Stojaczyk 		.start = "",
367c77c6559SDarek Stojaczyk 		.len = 0,
368c77c6559SDarek Stojaczyk 		.type = SPDK_JSON_VAL_INVALID
369c77c6559SDarek Stojaczyk 	};
370c77c6559SDarek Stojaczyk 	size_t decidx;
371c77c6559SDarek Stojaczyk 
372c77c6559SDarek Stojaczyk 	for (decidx = 0; decidx < num_decoders; decidx++) {
373c77c6559SDarek Stojaczyk 		const struct spdk_json_object_decoder *dec = &decoders[decidx];
374c77c6559SDarek Stojaczyk 		void *field = (void *)((uintptr_t)obj + dec->offset);
375c77c6559SDarek Stojaczyk 
376c77c6559SDarek Stojaczyk 		/* decoding an invalid value will free the
377c77c6559SDarek Stojaczyk 		 * previous memory without allocating it again.
378c77c6559SDarek Stojaczyk 		 */
379c77c6559SDarek Stojaczyk 		dec->decode_func(&invalid_val, field);
380c77c6559SDarek Stojaczyk 	}
381c77c6559SDarek Stojaczyk }
382c77c6559SDarek Stojaczyk 
383c77c6559SDarek Stojaczyk 
384f9193f4cSDaniel Verkamp int
spdk_json_decode_object(const struct spdk_json_val * values,const struct spdk_json_object_decoder * decoders,size_t num_decoders,void * out)38590472b86SJacek Kalwas spdk_json_decode_object(const struct spdk_json_val *values,
38690472b86SJacek Kalwas 			const struct spdk_json_object_decoder *decoders, size_t num_decoders, void *out)
38790472b86SJacek Kalwas {
38890472b86SJacek Kalwas 	return _json_decode_object(values, decoders, num_decoders, out, false);
38990472b86SJacek Kalwas }
39090472b86SJacek Kalwas 
39190472b86SJacek Kalwas int
spdk_json_decode_object_relaxed(const struct spdk_json_val * values,const struct spdk_json_object_decoder * decoders,size_t num_decoders,void * out)39290472b86SJacek Kalwas spdk_json_decode_object_relaxed(const struct spdk_json_val *values,
39390472b86SJacek Kalwas 				const struct spdk_json_object_decoder *decoders, size_t num_decoders, void *out)
39490472b86SJacek Kalwas {
39590472b86SJacek Kalwas 	return _json_decode_object(values, decoders, num_decoders, out, true);
39690472b86SJacek Kalwas }
39790472b86SJacek Kalwas 
39890472b86SJacek Kalwas int
spdk_json_decode_array(const struct spdk_json_val * values,spdk_json_decode_fn decode_func,void * out,size_t max_size,size_t * out_size,size_t stride)399f9193f4cSDaniel Verkamp spdk_json_decode_array(const struct spdk_json_val *values, spdk_json_decode_fn decode_func,
400f9193f4cSDaniel Verkamp 		       void *out, size_t max_size, size_t *out_size, size_t stride)
401f9193f4cSDaniel Verkamp {
402f9193f4cSDaniel Verkamp 	uint32_t i;
403f9193f4cSDaniel Verkamp 	char *field;
404f9193f4cSDaniel Verkamp 
405f9193f4cSDaniel Verkamp 	if (values == NULL || values->type != SPDK_JSON_VAL_ARRAY_BEGIN) {
406f9193f4cSDaniel Verkamp 		return -1;
407f9193f4cSDaniel Verkamp 	}
408f9193f4cSDaniel Verkamp 
409f9193f4cSDaniel Verkamp 	*out_size = 0;
410f9193f4cSDaniel Verkamp 	field = out;
411f9193f4cSDaniel Verkamp 	for (i = 0; i < values->len;) {
412f9193f4cSDaniel Verkamp 		const struct spdk_json_val *v = &values[i + 1];
413f9193f4cSDaniel Verkamp 
414*c6480ea7SKonrad Sztyber 		if (*out_size == max_size) {
415b33e0cafSDaniel Verkamp 			return -1;
416b33e0cafSDaniel Verkamp 		}
417b33e0cafSDaniel Verkamp 
418f9193f4cSDaniel Verkamp 		if (decode_func(v, field)) {
419f9193f4cSDaniel Verkamp 			return -1;
420f9193f4cSDaniel Verkamp 		}
421f9193f4cSDaniel Verkamp 
422f9193f4cSDaniel Verkamp 		i += spdk_json_val_len(v);
423f9193f4cSDaniel Verkamp 		field += stride;
424f9193f4cSDaniel Verkamp 		(*out_size)++;
425f9193f4cSDaniel Verkamp 	}
426f9193f4cSDaniel Verkamp 
427f9193f4cSDaniel Verkamp 	return 0;
428f9193f4cSDaniel Verkamp }
429f9193f4cSDaniel Verkamp 
430f9193f4cSDaniel Verkamp int
spdk_json_decode_bool(const struct spdk_json_val * val,void * out)4311bc2c5abSPawel Wodkowski spdk_json_decode_bool(const struct spdk_json_val *val, void *out)
4321bc2c5abSPawel Wodkowski {
4331bc2c5abSPawel Wodkowski 	bool *f = out;
4341bc2c5abSPawel Wodkowski 
4351bc2c5abSPawel Wodkowski 	if (val->type != SPDK_JSON_VAL_TRUE && val->type != SPDK_JSON_VAL_FALSE) {
4361bc2c5abSPawel Wodkowski 		return -1;
4371bc2c5abSPawel Wodkowski 	}
4381bc2c5abSPawel Wodkowski 
4391bc2c5abSPawel Wodkowski 	*f = val->type == SPDK_JSON_VAL_TRUE;
4401bc2c5abSPawel Wodkowski 	return 0;
4411bc2c5abSPawel Wodkowski }
4421bc2c5abSPawel Wodkowski 
4431bc2c5abSPawel Wodkowski int
spdk_json_decode_uint8(const struct spdk_json_val * val,void * out)444a827fd7eSJacek Kalwas spdk_json_decode_uint8(const struct spdk_json_val *val, void *out)
445a827fd7eSJacek Kalwas {
446a827fd7eSJacek Kalwas 	uint8_t *i = out;
447a827fd7eSJacek Kalwas 
448a827fd7eSJacek Kalwas 	return spdk_json_number_to_uint8(val, i);
449a827fd7eSJacek Kalwas }
450a827fd7eSJacek Kalwas 
451a827fd7eSJacek Kalwas int
spdk_json_decode_uint16(const struct spdk_json_val * val,void * out)4526f872f5aSShuhei Matsumoto spdk_json_decode_uint16(const struct spdk_json_val *val, void *out)
4536f872f5aSShuhei Matsumoto {
4546f872f5aSShuhei Matsumoto 	uint16_t *i = out;
4556f872f5aSShuhei Matsumoto 
4566f872f5aSShuhei Matsumoto 	return spdk_json_number_to_uint16(val, i);
4576f872f5aSShuhei Matsumoto }
4586f872f5aSShuhei Matsumoto 
4596f872f5aSShuhei Matsumoto int
spdk_json_decode_int32(const struct spdk_json_val * val,void * out)460f9193f4cSDaniel Verkamp spdk_json_decode_int32(const struct spdk_json_val *val, void *out)
461f9193f4cSDaniel Verkamp {
462f9193f4cSDaniel Verkamp 	int32_t *i = out;
463f9193f4cSDaniel Verkamp 
464f9193f4cSDaniel Verkamp 	return spdk_json_number_to_int32(val, i);
465f9193f4cSDaniel Verkamp }
466f9193f4cSDaniel Verkamp 
467f9193f4cSDaniel Verkamp int
spdk_json_decode_uint32(const struct spdk_json_val * val,void * out)468f9193f4cSDaniel Verkamp spdk_json_decode_uint32(const struct spdk_json_val *val, void *out)
469f9193f4cSDaniel Verkamp {
470f9193f4cSDaniel Verkamp 	uint32_t *i = out;
471f9193f4cSDaniel Verkamp 
472f9193f4cSDaniel Verkamp 	return spdk_json_number_to_uint32(val, i);
473f9193f4cSDaniel Verkamp }
474f9193f4cSDaniel Verkamp 
475f9193f4cSDaniel Verkamp int
spdk_json_decode_uint64(const struct spdk_json_val * val,void * out)47661119d78SMaciej Szwed spdk_json_decode_uint64(const struct spdk_json_val *val, void *out)
47761119d78SMaciej Szwed {
47861119d78SMaciej Szwed 	uint64_t *i = out;
47961119d78SMaciej Szwed 
48061119d78SMaciej Szwed 	return spdk_json_number_to_uint64(val, i);
48161119d78SMaciej Szwed }
48261119d78SMaciej Szwed 
48361119d78SMaciej Szwed int
spdk_json_decode_string(const struct spdk_json_val * val,void * out)484f9193f4cSDaniel Verkamp spdk_json_decode_string(const struct spdk_json_val *val, void *out)
485f9193f4cSDaniel Verkamp {
486f9193f4cSDaniel Verkamp 	char **s = out;
487f9193f4cSDaniel Verkamp 
488f9193f4cSDaniel Verkamp 	free(*s);
489f9193f4cSDaniel Verkamp 
490f9193f4cSDaniel Verkamp 	*s = spdk_json_strdup(val);
491f9193f4cSDaniel Verkamp 
492f9193f4cSDaniel Verkamp 	if (*s) {
493f9193f4cSDaniel Verkamp 		return 0;
494f9193f4cSDaniel Verkamp 	} else {
495f9193f4cSDaniel Verkamp 		return -1;
496f9193f4cSDaniel Verkamp 	}
497f9193f4cSDaniel Verkamp }
498439641f7SPawel Wodkowski 
4993e449a54SKonrad Sztyber int
spdk_json_decode_uuid(const struct spdk_json_val * val,void * out)5003e449a54SKonrad Sztyber spdk_json_decode_uuid(const struct spdk_json_val *val, void *out)
5013e449a54SKonrad Sztyber {
5023e449a54SKonrad Sztyber 	struct spdk_uuid *uuid = out;
5033e449a54SKonrad Sztyber 	char *str = NULL;
5043e449a54SKonrad Sztyber 	int rc;
5053e449a54SKonrad Sztyber 
5063e449a54SKonrad Sztyber 	rc = spdk_json_decode_string(val, &str);
5073e449a54SKonrad Sztyber 	if (rc != 0) {
5083e449a54SKonrad Sztyber 		return rc;
5093e449a54SKonrad Sztyber 	}
5103e449a54SKonrad Sztyber 
5113e449a54SKonrad Sztyber 	rc = spdk_uuid_parse(uuid, str);
5123e449a54SKonrad Sztyber 	free(str);
5133e449a54SKonrad Sztyber 
51475b68561SKonrad Sztyber 	return rc == 0 ? 0 : -1;
5153e449a54SKonrad Sztyber }
5163e449a54SKonrad Sztyber 
517439641f7SPawel Wodkowski static struct spdk_json_val *
json_first(struct spdk_json_val * object,enum spdk_json_val_type type)5180be5557cSSeth Howell json_first(struct spdk_json_val *object, enum spdk_json_val_type type)
519439641f7SPawel Wodkowski {
520439641f7SPawel Wodkowski 	/* 'object' must be JSON object or array. 'type' might be combination of these two. */
521439641f7SPawel Wodkowski 	assert((type & (SPDK_JSON_VAL_ARRAY_BEGIN | SPDK_JSON_VAL_OBJECT_BEGIN)) != 0);
522439641f7SPawel Wodkowski 
523439641f7SPawel Wodkowski 	assert(object != NULL);
524439641f7SPawel Wodkowski 
525439641f7SPawel Wodkowski 	if ((object->type & type) == 0) {
526439641f7SPawel Wodkowski 		return NULL;
527439641f7SPawel Wodkowski 	}
528439641f7SPawel Wodkowski 
529439641f7SPawel Wodkowski 	object++;
530439641f7SPawel Wodkowski 	if (object->len == 0) {
531439641f7SPawel Wodkowski 		return NULL;
532439641f7SPawel Wodkowski 	}
533439641f7SPawel Wodkowski 
534439641f7SPawel Wodkowski 	return object;
535439641f7SPawel Wodkowski }
536439641f7SPawel Wodkowski 
537439641f7SPawel Wodkowski static struct spdk_json_val *
json_value(struct spdk_json_val * key)5380be5557cSSeth Howell json_value(struct spdk_json_val *key)
539439641f7SPawel Wodkowski {
540439641f7SPawel Wodkowski 	return key->type == SPDK_JSON_VAL_NAME ? key + 1 : NULL;
541439641f7SPawel Wodkowski }
542439641f7SPawel Wodkowski 
543439641f7SPawel Wodkowski int
spdk_json_find(struct spdk_json_val * object,const char * key_name,struct spdk_json_val ** key,struct spdk_json_val ** val,enum spdk_json_val_type type)544439641f7SPawel Wodkowski spdk_json_find(struct spdk_json_val *object, const char *key_name, struct spdk_json_val **key,
545439641f7SPawel Wodkowski 	       struct spdk_json_val **val, enum spdk_json_val_type type)
546439641f7SPawel Wodkowski {
547439641f7SPawel Wodkowski 	struct spdk_json_val *_key = NULL;
548439641f7SPawel Wodkowski 	struct spdk_json_val *_val = NULL;
549bb432b4eStongkunkun 	struct spdk_json_val *it_first, *it;
550439641f7SPawel Wodkowski 
551439641f7SPawel Wodkowski 	assert(object != NULL);
552439641f7SPawel Wodkowski 
553bb432b4eStongkunkun 	it_first = json_first(object, SPDK_JSON_VAL_OBJECT_BEGIN);
554bb432b4eStongkunkun 	if (!it_first) {
555bb432b4eStongkunkun 		SPDK_JSON_DEBUG("Not enclosed in {}\n");
556bb432b4eStongkunkun 		return -EPROTOTYPE;
557bb432b4eStongkunkun 	}
558bb432b4eStongkunkun 
559bb432b4eStongkunkun 	for (it = it_first;
560439641f7SPawel Wodkowski 	     it != NULL;
561439641f7SPawel Wodkowski 	     it = spdk_json_next(it)) {
562439641f7SPawel Wodkowski 		if (it->type != SPDK_JSON_VAL_NAME) {
563439641f7SPawel Wodkowski 			continue;
564439641f7SPawel Wodkowski 		}
565439641f7SPawel Wodkowski 
566439641f7SPawel Wodkowski 		if (spdk_json_strequal(it, key_name) != true) {
567439641f7SPawel Wodkowski 			continue;
568439641f7SPawel Wodkowski 		}
569439641f7SPawel Wodkowski 
570439641f7SPawel Wodkowski 		if (_key) {
571439641f7SPawel Wodkowski 			SPDK_JSON_DEBUG("Duplicate key '%s'", key_name);
572439641f7SPawel Wodkowski 			return -EINVAL;
573439641f7SPawel Wodkowski 		}
574439641f7SPawel Wodkowski 
575439641f7SPawel Wodkowski 		_key = it;
5760be5557cSSeth Howell 		_val = json_value(_key);
577439641f7SPawel Wodkowski 
578bb432b4eStongkunkun 		if (type != SPDK_JSON_VAL_ANY && (_val->type & type) == 0) {
579439641f7SPawel Wodkowski 			SPDK_JSON_DEBUG("key '%s' type is %#x but expected one of %#x\n", key_name, _val->type, type);
580439641f7SPawel Wodkowski 			return -EDOM;
581439641f7SPawel Wodkowski 		}
582439641f7SPawel Wodkowski 	}
583439641f7SPawel Wodkowski 
584439641f7SPawel Wodkowski 	if (key) {
585439641f7SPawel Wodkowski 		*key = _key;
586439641f7SPawel Wodkowski 	}
587439641f7SPawel Wodkowski 
588439641f7SPawel Wodkowski 	if (val) {
589439641f7SPawel Wodkowski 		*val = _val;
590439641f7SPawel Wodkowski 	}
591439641f7SPawel Wodkowski 
592439641f7SPawel Wodkowski 	return _val ? 0 : -ENOENT;
593439641f7SPawel Wodkowski }
594439641f7SPawel Wodkowski 
595439641f7SPawel Wodkowski int
spdk_json_find_string(struct spdk_json_val * object,const char * key_name,struct spdk_json_val ** key,struct spdk_json_val ** val)596439641f7SPawel Wodkowski spdk_json_find_string(struct spdk_json_val *object, const char *key_name,
597439641f7SPawel Wodkowski 		      struct spdk_json_val **key, struct spdk_json_val **val)
598439641f7SPawel Wodkowski {
599439641f7SPawel Wodkowski 	return spdk_json_find(object, key_name, key, val, SPDK_JSON_VAL_STRING);
600439641f7SPawel Wodkowski }
601439641f7SPawel Wodkowski 
602439641f7SPawel Wodkowski int
spdk_json_find_array(struct spdk_json_val * object,const char * key_name,struct spdk_json_val ** key,struct spdk_json_val ** val)603439641f7SPawel Wodkowski spdk_json_find_array(struct spdk_json_val *object, const char *key_name,
604439641f7SPawel Wodkowski 		     struct spdk_json_val **key, struct spdk_json_val **val)
605439641f7SPawel Wodkowski {
606439641f7SPawel Wodkowski 	return spdk_json_find(object, key_name, key, val, SPDK_JSON_VAL_ARRAY_BEGIN);
607439641f7SPawel Wodkowski }
608439641f7SPawel Wodkowski 
609439641f7SPawel Wodkowski struct spdk_json_val *
spdk_json_object_first(struct spdk_json_val * object)610439641f7SPawel Wodkowski spdk_json_object_first(struct spdk_json_val *object)
611439641f7SPawel Wodkowski {
6120be5557cSSeth Howell 	struct spdk_json_val *first = json_first(object, SPDK_JSON_VAL_OBJECT_BEGIN);
613439641f7SPawel Wodkowski 
614439641f7SPawel Wodkowski 	/* Empty object? */
615439641f7SPawel Wodkowski 	return first && first->type != SPDK_JSON_VAL_OBJECT_END ? first : NULL;
616439641f7SPawel Wodkowski }
617439641f7SPawel Wodkowski 
618439641f7SPawel Wodkowski struct spdk_json_val *
spdk_json_array_first(struct spdk_json_val * array_begin)619439641f7SPawel Wodkowski spdk_json_array_first(struct spdk_json_val *array_begin)
620439641f7SPawel Wodkowski {
6210be5557cSSeth Howell 	struct spdk_json_val *first = json_first(array_begin, SPDK_JSON_VAL_ARRAY_BEGIN);
622439641f7SPawel Wodkowski 
623439641f7SPawel Wodkowski 	/* Empty array? */
624439641f7SPawel Wodkowski 	return first && first->type != SPDK_JSON_VAL_ARRAY_END ? first : NULL;
625439641f7SPawel Wodkowski }
626439641f7SPawel Wodkowski 
627439641f7SPawel Wodkowski static struct spdk_json_val *
json_skip_object_or_array(struct spdk_json_val * val)6280be5557cSSeth Howell json_skip_object_or_array(struct spdk_json_val *val)
629439641f7SPawel Wodkowski {
630439641f7SPawel Wodkowski 	unsigned lvl;
631439641f7SPawel Wodkowski 	enum spdk_json_val_type end_type;
632439641f7SPawel Wodkowski 	struct spdk_json_val *it;
633439641f7SPawel Wodkowski 
634439641f7SPawel Wodkowski 	if (val->type == SPDK_JSON_VAL_OBJECT_BEGIN) {
635439641f7SPawel Wodkowski 		end_type = SPDK_JSON_VAL_OBJECT_END;
636439641f7SPawel Wodkowski 	} else if (val->type == SPDK_JSON_VAL_ARRAY_BEGIN) {
637439641f7SPawel Wodkowski 		end_type = SPDK_JSON_VAL_ARRAY_END;
638439641f7SPawel Wodkowski 	} else {
639439641f7SPawel Wodkowski 		SPDK_JSON_DEBUG("Expected JSON object (%#x) or array (%#x) but got %#x\n",
640c680a792SSeth Howell 				SPDK_JSON_VAL_OBJECT_BEGIN, SPDK_JSON_VAL_ARRAY_BEGIN, val->type);
641439641f7SPawel Wodkowski 		return NULL;
642439641f7SPawel Wodkowski 	}
643439641f7SPawel Wodkowski 
644439641f7SPawel Wodkowski 	lvl = 1;
645439641f7SPawel Wodkowski 	for (it = val + 1; it->type != SPDK_JSON_VAL_INVALID && lvl != 0; it++) {
646439641f7SPawel Wodkowski 		if (it->type == val->type) {
647439641f7SPawel Wodkowski 			lvl++;
648439641f7SPawel Wodkowski 		} else if (it->type == end_type) {
649439641f7SPawel Wodkowski 			lvl--;
650439641f7SPawel Wodkowski 		}
651439641f7SPawel Wodkowski 	}
652439641f7SPawel Wodkowski 
653439641f7SPawel Wodkowski 	/* if lvl != 0 we have invalid JSON object */
654439641f7SPawel Wodkowski 	if (lvl != 0) {
655439641f7SPawel Wodkowski 		SPDK_JSON_DEBUG("Can't find end of object (type: %#x): lvl (%u) != 0)\n", val->type, lvl);
656439641f7SPawel Wodkowski 		it = NULL;
657439641f7SPawel Wodkowski 	}
658439641f7SPawel Wodkowski 
659439641f7SPawel Wodkowski 	return it;
660439641f7SPawel Wodkowski }
661439641f7SPawel Wodkowski 
662439641f7SPawel Wodkowski struct spdk_json_val *
spdk_json_next(struct spdk_json_val * it)663439641f7SPawel Wodkowski spdk_json_next(struct spdk_json_val *it)
664439641f7SPawel Wodkowski {
665439641f7SPawel Wodkowski 	struct spdk_json_val *val, *next;
666439641f7SPawel Wodkowski 
667439641f7SPawel Wodkowski 	switch (it->type) {
668439641f7SPawel Wodkowski 	case SPDK_JSON_VAL_NAME:
6690be5557cSSeth Howell 		val = json_value(it);
670439641f7SPawel Wodkowski 		next = spdk_json_next(val);
671439641f7SPawel Wodkowski 		break;
672439641f7SPawel Wodkowski 
673439641f7SPawel Wodkowski 	/* We are in the middle of an array - get to next entry */
674439641f7SPawel Wodkowski 	case SPDK_JSON_VAL_NULL:
675439641f7SPawel Wodkowski 	case SPDK_JSON_VAL_TRUE:
676439641f7SPawel Wodkowski 	case SPDK_JSON_VAL_FALSE:
677439641f7SPawel Wodkowski 	case SPDK_JSON_VAL_NUMBER:
678439641f7SPawel Wodkowski 	case SPDK_JSON_VAL_STRING:
679439641f7SPawel Wodkowski 		val = it + 1;
680439641f7SPawel Wodkowski 		return val;
681439641f7SPawel Wodkowski 
682439641f7SPawel Wodkowski 	case SPDK_JSON_VAL_ARRAY_BEGIN:
683439641f7SPawel Wodkowski 	case SPDK_JSON_VAL_OBJECT_BEGIN:
6840be5557cSSeth Howell 		next = json_skip_object_or_array(it);
685439641f7SPawel Wodkowski 		break;
686439641f7SPawel Wodkowski 
687439641f7SPawel Wodkowski 	/* Can't go to the next object if started from the end of array or object */
688439641f7SPawel Wodkowski 	case SPDK_JSON_VAL_ARRAY_END:
689439641f7SPawel Wodkowski 	case SPDK_JSON_VAL_OBJECT_END:
690439641f7SPawel Wodkowski 	case SPDK_JSON_VAL_INVALID:
691439641f7SPawel Wodkowski 		return NULL;
692439641f7SPawel Wodkowski 	default:
693439641f7SPawel Wodkowski 		assert(false);
694439641f7SPawel Wodkowski 		return NULL;
695439641f7SPawel Wodkowski 
696439641f7SPawel Wodkowski 	}
697439641f7SPawel Wodkowski 
698439641f7SPawel Wodkowski 	/* EOF ? */
699439641f7SPawel Wodkowski 	if (next == NULL) {
700439641f7SPawel Wodkowski 		return NULL;
701439641f7SPawel Wodkowski 	}
702439641f7SPawel Wodkowski 
703439641f7SPawel Wodkowski 	switch (next->type) {
704439641f7SPawel Wodkowski 	case SPDK_JSON_VAL_ARRAY_END:
705439641f7SPawel Wodkowski 	case SPDK_JSON_VAL_OBJECT_END:
706439641f7SPawel Wodkowski 	case SPDK_JSON_VAL_INVALID:
707439641f7SPawel Wodkowski 		return NULL;
708439641f7SPawel Wodkowski 	default:
709439641f7SPawel Wodkowski 		/* Next value */
710439641f7SPawel Wodkowski 		return next;
711439641f7SPawel Wodkowski 	}
712439641f7SPawel Wodkowski }
713439641f7SPawel Wodkowski 
7142172c432STomasz Zawadzki SPDK_LOG_REGISTER_COMPONENT(json_util)
715