xref: /spdk/lib/json/json_util.c (revision 376d117c90d185e20b31062cd773e7af1eb14bae)
1 /*-
2  *   BSD LICENSE
3  *
4  *   Copyright (c) Intel Corporation.
5  *   All rights reserved.
6  *
7  *   Redistribution and use in source and binary forms, with or without
8  *   modification, are permitted provided that the following conditions
9  *   are met:
10  *
11  *     * Redistributions of source code must retain the above copyright
12  *       notice, this list of conditions and the following disclaimer.
13  *     * Redistributions in binary form must reproduce the above copyright
14  *       notice, this list of conditions and the following disclaimer in
15  *       the documentation and/or other materials provided with the
16  *       distribution.
17  *     * Neither the name of Intel Corporation nor the names of its
18  *       contributors may be used to endorse or promote products derived
19  *       from this software without specific prior written permission.
20  *
21  *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22  *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23  *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
24  *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
25  *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26  *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
27  *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28  *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29  *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30  *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
31  *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32  */
33 
34 #include "json_internal.h"
35 
36 size_t
37 spdk_json_val_len(const struct spdk_json_val *val)
38 {
39 	if (val == NULL) {
40 		return 0;
41 	}
42 
43 	if (val->type == SPDK_JSON_VAL_ARRAY_BEGIN || val->type == SPDK_JSON_VAL_OBJECT_BEGIN) {
44 		return val->len + 2;
45 	}
46 
47 	return 1;
48 }
49 
50 bool
51 spdk_json_strequal(const struct spdk_json_val *val, const char *str)
52 {
53 	size_t len;
54 
55 	if (val->type != SPDK_JSON_VAL_STRING && val->type != SPDK_JSON_VAL_NAME) {
56 		return false;
57 	}
58 
59 	len = strlen(str);
60 	if (val->len != len) {
61 		return false;
62 	}
63 
64 	return memcmp(val->start, str, len) == 0;
65 }
66 
67 char *
68 spdk_json_strdup(const struct spdk_json_val *val)
69 {
70 	size_t len;
71 	char *s;
72 
73 	if (val->type != SPDK_JSON_VAL_STRING && val->type != SPDK_JSON_VAL_NAME) {
74 		return NULL;
75 	}
76 
77 	len = val->len;
78 
79 	if (memchr(val->start, '\0', len)) {
80 		/* String contains embedded NUL, so it is not a valid C string. */
81 		return NULL;
82 	}
83 
84 	s = malloc(len + 1);
85 	if (s == NULL) {
86 		return s;
87 	}
88 
89 	memcpy(s, val->start, len);
90 	s[len] = '\0';
91 
92 	return s;
93 }
94 
95 int
96 spdk_json_number_to_double(const struct spdk_json_val *val, double *num)
97 {
98 	char buf[32];
99 	char *end;
100 
101 	if (val->type != SPDK_JSON_VAL_NUMBER || val->len >= sizeof(buf)) {
102 		*num = 0.0;
103 		return -1;
104 	}
105 
106 	memcpy(buf, val->start, val->len);
107 	buf[val->len] = '\0';
108 
109 	errno = 0;
110 	/* TODO: strtod() uses locale for decimal point (. is not guaranteed) */
111 	*num = strtod(buf, &end);
112 	if (*end != '\0' || errno != 0) {
113 		return -1;
114 	}
115 
116 	return 0;
117 }
118 
119 int
120 spdk_json_number_to_int32(const struct spdk_json_val *val, int32_t *num)
121 {
122 	double dbl;
123 
124 	if (spdk_json_number_to_double(val, &dbl)) {
125 		return -1;
126 	}
127 
128 	*num = (int32_t)dbl;
129 	if (dbl != (double)*num) {
130 		return -1;
131 	}
132 
133 	return 0;
134 }
135 
136 int
137 spdk_json_number_to_uint32(const struct spdk_json_val *val, uint32_t *num)
138 {
139 	double dbl;
140 
141 	if (spdk_json_number_to_double(val, &dbl)) {
142 		return -1;
143 	}
144 
145 	if (dbl < 0) {
146 		return -1;
147 	}
148 
149 	*num = (uint32_t)dbl;
150 	if (dbl != (double)*num) {
151 		return -1;
152 	}
153 
154 	return 0;
155 }
156 
157 int
158 spdk_json_decode_object(const struct spdk_json_val *values,
159 			const struct spdk_json_object_decoder *decoders, size_t num_decoders, void *out)
160 {
161 	uint32_t i;
162 	bool invalid = false;
163 	size_t decidx;
164 	bool *seen;
165 
166 	if (values == NULL || values->type != SPDK_JSON_VAL_OBJECT_BEGIN) {
167 		return -1;
168 	}
169 
170 	seen = calloc(sizeof(bool), num_decoders);
171 	if (seen == NULL) {
172 		return -1;
173 	}
174 
175 	for (i = 0; i < values->len;) {
176 		const struct spdk_json_val *name = &values[i + 1];
177 		const struct spdk_json_val *v = &values[i + 2];
178 		bool found = false;
179 
180 		for (decidx = 0; decidx < num_decoders; decidx++) {
181 			const struct spdk_json_object_decoder *dec = &decoders[decidx];
182 			if (spdk_json_strequal(name, dec->name)) {
183 				void *field = (void *)((uintptr_t)out + dec->offset);
184 
185 				found = true;
186 
187 				if (seen[decidx]) {
188 					/* duplicate field name */
189 					invalid = true;
190 				} else {
191 					seen[decidx] = true;
192 					if (dec->decode_func(v, field)) {
193 						invalid = true;
194 						/* keep going to fill out any other valid keys */
195 					}
196 				}
197 				break;
198 			}
199 		}
200 
201 		if (!found) {
202 			invalid = true;
203 		}
204 
205 		i += 1 + spdk_json_val_len(v);
206 	}
207 
208 	for (decidx = 0; decidx < num_decoders; decidx++) {
209 		if (!decoders[decidx].optional && !seen[decidx]) {
210 			/* required field is missing */
211 			invalid = true;
212 			break;
213 		}
214 	}
215 
216 	free(seen);
217 	return invalid ? -1 : 0;
218 }
219 
220 int
221 spdk_json_decode_array(const struct spdk_json_val *values, spdk_json_decode_fn decode_func,
222 		       void *out, size_t max_size, size_t *out_size, size_t stride)
223 {
224 	uint32_t i;
225 	char *field;
226 
227 	if (values == NULL || values->type != SPDK_JSON_VAL_ARRAY_BEGIN) {
228 		return -1;
229 	}
230 
231 	if (values->len >= max_size) {
232 		return -1;
233 	}
234 
235 	*out_size = 0;
236 	field = out;
237 	for (i = 0; i < values->len;) {
238 		const struct spdk_json_val *v = &values[i + 1];
239 
240 		if (decode_func(v, field)) {
241 			return -1;
242 		}
243 
244 		i += spdk_json_val_len(v);
245 		field += stride;
246 		(*out_size)++;
247 	}
248 
249 	return 0;
250 }
251 
252 int
253 spdk_json_decode_int32(const struct spdk_json_val *val, void *out)
254 {
255 	int32_t *i = out;
256 
257 	return spdk_json_number_to_int32(val, i);
258 }
259 
260 int
261 spdk_json_decode_uint32(const struct spdk_json_val *val, void *out)
262 {
263 	uint32_t *i = out;
264 
265 	return spdk_json_number_to_uint32(val, i);
266 }
267 
268 int
269 spdk_json_decode_string(const struct spdk_json_val *val, void *out)
270 {
271 	char **s = out;
272 
273 	if (*s) {
274 		free(*s);
275 	}
276 
277 	*s = spdk_json_strdup(val);
278 
279 	if (*s) {
280 		return 0;
281 	} else {
282 		return -1;
283 	}
284 }
285