master
h 670 lines 68.1 KB
Raw
1 // SPDX-License-Identifier: GPL-3.0-or-later
2
3 #ifndef NETDATA_JSON_C_PARSER_INLINE_H
4 #define NETDATA_JSON_C_PARSER_INLINE_H
5
6 // Flags for JSONC_PARSE_* macros (bitmask)
7 // JSONC_OPTIONAL - key may be absent; wrong type is silently ignored
8 // JSONC_REQUIRED - key must exist; wrong type is an error
9 // JSONC_STRICT - key may be absent, but if present the type must be correct
10 #define JSONC_OPTIONAL 0
11 #define JSONC_REQUIRED (1 << 0)
12 #define JSONC_STRICT (1 << 1)
13
14 // helper: convert a bool to JSONC_REQUIRED / JSONC_OPTIONAL
15 #define JSONC_REQUIRE_IF(cond) ((cond) ? JSONC_REQUIRED : JSONC_OPTIONAL)
16
17 #define JSONC_PARSE_BOOL_OR_ERROR_AND_RETURN(jobj, path, member, dst, error, flags) do { \
18 json_object *_j; \
19 if (json_object_object_get_ex(jobj, member, &_j)) { \
20 if (json_object_is_type(_j, json_type_boolean)) { \
21 dst = json_object_get_boolean(_j); \
22 } \
23 else if (json_object_is_type(_j, json_type_string)) { \
24 const char *_str = json_object_get_string(_j); \
25 if (strcasecmp(_str, "true") == 0 || strcasecmp(_str, "yes") == 0 || strcasecmp(_str, "on") == 0) { \
26 dst = true; \
27 } \
28 else if (strcasecmp(_str, "false") == 0 || strcasecmp(_str, "no") == 0 || strcasecmp(_str, "off") == 0) { \
29 dst = false; \
30 } \
31 else { \
32 buffer_sprintf(error, "invalid boolean string '%s' for '%s.%s'", _str, path, member); \
33 return false; \
34 } \
35 } \
36 else if (json_object_is_type(_j, json_type_int)) { \
37 dst = json_object_get_int64(_j) != 0; \
38 } \
39 else if (json_object_is_type(_j, json_type_double)) { \
40 dst = json_object_get_double(_j) != 0.0; \
41 } \
42 else if (json_object_is_type(_j, json_type_null)) { \
43 dst = false; \
44 } \
45 else if ((flags) & (JSONC_REQUIRED | JSONC_STRICT)) { \
46 buffer_sprintf(error, "cannot convert to boolean for '%s.%s'", path, member); \
47 return false; \
48 } \
49 } \
50 else if((flags) & JSONC_REQUIRED) { \
51 buffer_sprintf(error, "missing '%s.%s' boolean", path, member); \
52 return false; \
53 } \
54 } while(0)
55
56 #define JSONC_PARSE_TXT2STRING_OR_ERROR_AND_RETURN(jobj, path, member, dst, error, flags) do { \
57 json_object *_j; \
58 if (json_object_object_get_ex(jobj, member, &_j)) { \
59 if (json_object_is_type(_j, json_type_string)) { \
60 string_freez(dst); \
61 dst = string_strdupz(json_object_get_string(_j)); \
62 } \
63 else if (json_object_is_type(_j, json_type_int)) { \
64 char _buf[UINT64_MAX_LENGTH]; \
65 print_int64(_buf, json_object_get_int64(_j)); \
66 string_freez(dst); \
67 dst = string_strdupz(_buf); \
68 } \
69 else if (json_object_is_type(_j, json_type_double)) { \
70 char _buf[DOUBLE_MAX_LENGTH]; \
71 print_netdata_double(_buf, json_object_get_double(_j)); \
72 string_freez(dst); \
73 dst = string_strdupz(_buf); \
74 } \
75 else if (json_object_is_type(_j, json_type_boolean)) { \
76 string_freez(dst); \
77 dst = string_strdupz(json_object_get_boolean(_j) ? "true" : "false"); \
78 } \
79 else if (json_object_is_type(_j, json_type_null)) { \
80 string_freez(dst); \
81 dst = NULL; \
82 } \
83 else if ((flags) & (JSONC_REQUIRED | JSONC_STRICT)) { \
84 buffer_sprintf(error, "cannot convert to string for '%s.%s'", path, member); \
85 return false; \
86 } \
87 } \
88 else if((flags) & JSONC_REQUIRED) { \
89 buffer_sprintf(error, "missing '%s.%s'", path, member); \
90 return false; \
91 } \
92 } while(0)
93
94 #define JSONC_PARSE_TXT2CHAR_OR_ERROR_AND_RETURN(jobj, path, member, dst, error, flags) do { \
95 json_object *_j; \
96 if (json_object_object_get_ex(jobj, member, &_j)) { \
97 if (json_object_is_type(_j, json_type_string)) { \
98 strncpyz(dst, json_object_get_string(_j), sizeof(dst) - 1); \
99 } \
100 else if (json_object_is_type(_j, json_type_int)) { \
101 char _buf[UINT64_MAX_LENGTH]; \
102 print_int64(_buf, json_object_get_int64(_j)); \
103 strncpyz(dst, _buf, sizeof(dst) - 1); \
104 } \
105 else if (json_object_is_type(_j, json_type_double)) { \
106 char _buf[DOUBLE_MAX_LENGTH]; \
107 print_netdata_double(_buf, json_object_get_double(_j)); \
108 strncpyz(dst, _buf, sizeof(dst) - 1); \
109 } \
110 else if (json_object_is_type(_j, json_type_boolean)) { \
111 strncpyz(dst, json_object_get_boolean(_j) ? "true" : "false", sizeof(dst) - 1); \
112 } \
113 else if (json_object_is_type(_j, json_type_null)) { \
114 dst[0] = '\0'; \
115 } \
116 else if ((flags) & (JSONC_REQUIRED | JSONC_STRICT)) { \
117 buffer_sprintf(error, "cannot convert to string for '%s.%s'", path, member); \
118 return false; \
119 } \
120 else \
121 dst[0] = '\0'; \
122 } \
123 else { \
124 dst[0] = '\0'; \
125 if ((flags) & JSONC_REQUIRED) { \
126 buffer_sprintf(error, "missing '%s.%s'", path, member); \
127 return false; \
128 } \
129 } \
130 } while(0)
131
132 #define JSONC_PARSE_TXT2RFC3339_USEC_OR_ERROR_AND_RETURN(jobj, path, member, dst, error, flags) do { \
133 json_object *_j; \
134 if (json_object_object_get_ex(jobj, member, &_j)) { \
135 if (json_object_is_type(_j, json_type_string)) { \
136 char _datetime[RFC3339_MAX_LENGTH]; _datetime[0] = '\0'; \
137 strncpyz(_datetime, json_object_get_string(_j), sizeof(_datetime) - 1); \
138 dst = rfc3339_parse_ut(_datetime, NULL); \
139 } \
140 else { \
141 dst = 0; \
142 if ((flags) & (JSONC_REQUIRED | JSONC_STRICT)) { \
143 buffer_sprintf(error, "invalid type for '%s.%s' string", path, member); \
144 return false; \
145 } \
146 } \
147 } \
148 else { \
149 dst = 0; \
150 if ((flags) & JSONC_REQUIRED) { \
151 buffer_sprintf(error, "missing '%s.%s' string", path, member); \
152 return false; \
153 } \
154 } \
155 } while(0)
156
157 #define JSONC_PARSE_TXT2STRDUPZ_OR_ERROR_AND_RETURN(jobj, path, member, dst, error, flags) do { \
158 json_object *_j; \
159 if (json_object_object_get_ex(jobj, member, &_j)) { \
160 if (json_object_is_type(_j, json_type_string)) { \
161 freez((void *)dst); \
162 dst = strdupz(json_object_get_string(_j)); \
163 } \
164 else if (json_object_is_type(_j, json_type_int)) { \
165 char _buf[UINT64_MAX_LENGTH]; \
166 print_int64(_buf, json_object_get_int64(_j)); \
167 freez((void *)dst); \
168 dst = strdupz(_buf); \
169 } \
170 else if (json_object_is_type(_j, json_type_double)) { \
171 char _buf[DOUBLE_MAX_LENGTH]; \
172 print_netdata_double(_buf, json_object_get_double(_j)); \
173 freez((void *)dst); \
174 dst = strdupz(_buf); \
175 } \
176 else if (json_object_is_type(_j, json_type_boolean)) { \
177 freez((void *)dst); \
178 dst = strdupz(json_object_get_boolean(_j) ? "true" : "false"); \
179 } \
180 else if (json_object_is_type(_j, json_type_null)) { \
181 freez((void *)dst); \
182 dst = NULL; \
183 } \
184 else if ((flags) & (JSONC_REQUIRED | JSONC_STRICT)) { \
185 buffer_sprintf(error, "cannot convert to string for '%s.%s'", path, member); \
186 return false; \
187 } \
188 } \
189 else if((flags) & JSONC_REQUIRED) { \
190 buffer_sprintf(error, "missing '%s.%s'", path, member); \
191 return false; \
192 } \
193 } while(0)
194
195 #define JSONC_PARSE_SCALAR2STRDUPZ_OR_ERROR_AND_RETURN(jobj, path, member, dst, error, flags) do { \
196 json_object *_j; \
197 if (json_object_object_get_ex(jobj, member, &_j)) { \
198 if (json_object_is_type(_j, json_type_string)) { \
199 freez((void *)dst); \
200 dst = strdupz(json_object_get_string(_j)); \
201 } \
202 else if (json_object_is_type(_j, json_type_int)) { \
203 char _buf[UINT64_MAX_LENGTH]; \
204 print_int64(_buf, json_object_get_int64(_j)); \
205 freez((void *)dst); \
206 dst = strdupz(_buf); \
207 } \
208 else if (json_object_is_type(_j, json_type_double)) { \
209 char _buf[DOUBLE_MAX_LENGTH]; \
210 print_netdata_double(_buf, json_object_get_double(_j)); \
211 freez((void *)dst); \
212 dst = strdupz(_buf); \
213 } \
214 else if (json_object_is_type(_j, json_type_boolean)) { \
215 freez((void *)dst); \
216 dst = strdupz(json_object_get_boolean(_j) ? "true" : "false"); \
217 } \
218 else if (json_object_is_type(_j, json_type_null)) { \
219 freez((void *)dst); \
220 dst = NULL; \
221 } \
222 else if ((flags) & (JSONC_REQUIRED | JSONC_STRICT)) { \
223 buffer_sprintf(error, "non-scalar type for '%s.%s' (arrays and objects not supported)", path, member); \
224 return false; \
225 } \
226 } \
227 else if((flags) & JSONC_REQUIRED) { \
228 buffer_sprintf(error, "missing '%s.%s'", path, member); \
229 return false; \
230 } \
231 } while(0)
232
233 #define JSONC_PARSE_TXT2UUID_OR_ERROR_AND_RETURN(jobj, path, member, dst, error, flags) do { \
234 json_object *_j; \
235 if (json_object_object_get_ex(jobj, member, &_j)) { \
236 if (json_object_is_type(_j, json_type_string)) { \
237 if (uuid_parse(json_object_get_string(_j), dst) != 0) { \
238 if((flags) & (JSONC_REQUIRED | JSONC_STRICT)) { \
239 buffer_sprintf(error, "invalid UUID '%s.%s'", path, member); \
240 return false; \
241 } \
242 else \
243 uuid_clear(dst); \
244 } \
245 } \
246 else if (json_object_is_type(_j, json_type_null)) { \
247 uuid_clear(dst); \
248 } \
249 else if ((flags) & (JSONC_REQUIRED | JSONC_STRICT)) { \
250 buffer_sprintf(error, "invalid type for UUID '%s.%s'", path, member); \
251 return false; \
252 } \
253 } \
254 else if ((flags) & JSONC_REQUIRED) { \
255 buffer_sprintf(error, "missing UUID '%s.%s'", path, member); \
256 return false; \
257 } \
258 } while(0)
259
260 #define JSONC_PARSE_TXT2BUFFER_OR_ERROR_AND_RETURN(jobj, path, member, dst, error, flags) do { \
261 json_object *_j; \
262 if (json_object_object_get_ex(jobj, member, &_j)) { \
263 const char *_s = NULL; \
264 char _buf[DOUBLE_MAX_LENGTH]; \
265 bool _type_ok = true; \
266 if (json_object_is_type(_j, json_type_string)) { \
267 _s = json_object_get_string(_j); \
268 } \
269 else if (json_object_is_type(_j, json_type_int)) { \
270 print_int64(_buf, json_object_get_int64(_j)); \
271 _s = _buf; \
272 } \
273 else if (json_object_is_type(_j, json_type_double)) { \
274 print_netdata_double(_buf, json_object_get_double(_j)); \
275 _s = _buf; \
276 } \
277 else if (json_object_is_type(_j, json_type_boolean)) { \
278 _s = json_object_get_boolean(_j) ? "true" : "false"; \
279 } \
280 else if (json_object_is_type(_j, json_type_null)) { \
281 _s = NULL; \
282 } \
283 else if ((flags) & (JSONC_REQUIRED | JSONC_STRICT)) { \
284 buffer_sprintf(error, "cannot convert to string for '%s.%s'", path, member); \
285 return false; \
286 } \
287 else _type_ok = false; \
288 if(_type_ok) { \
289 if(!_s || !*_s) { \
290 buffer_free(dst); \
291 dst = NULL; \
292 } \
293 else { \
294 if (dst) \
295 buffer_flush(dst); \
296 else \
297 dst = buffer_create(0, NULL); \
298 buffer_strcat(dst, _s); \
299 } \
300 } \
301 } \
302 else if((flags) & JSONC_REQUIRED) { \
303 buffer_sprintf(error, "missing '%s.%s'", path, member); \
304 return false; \
305 } \
306 } while(0)
307
308 #define JSONC_PARSE_TXT2PATTERN_OR_ERROR_AND_RETURN(jobj, path, member, dst, error, flags) do { \
309 json_object *_j; \
310 if (json_object_object_get_ex(jobj, member, &_j)) { \
311 if (json_object_is_type(_j, json_type_string)) { \
312 string_freez(dst); \
313 const char *_v = json_object_get_string(_j); \
314 if(strcmp(_v, "*") == 0) \
315 dst = NULL; \
316 else \
317 dst = string_strdupz(_v); \
318 } \
319 else if ((flags) & (JSONC_REQUIRED | JSONC_STRICT)) { \
320 buffer_sprintf(error, "invalid type for '%s.%s' string", path, member); \
321 return false; \
322 } \
323 } \
324 else if((flags) & JSONC_REQUIRED) { \
325 buffer_sprintf(error, "missing '%s.%s' string", path, member); \
326 return false; \
327 } \
328 } while(0)
329
330 #define JSONC_PARSE_TXT2EXPRESSION_OR_ERROR_AND_RETURN(jobj, path, member, dst, error, flags) do { \
331 json_object *_j; \
332 if (json_object_object_get_ex(jobj, member, &_j)) { \
333 if (json_object_is_type(_j, json_type_string)) { \
334 const char *_t = json_object_get_string(_j); \
335 if(_t && *_t && strcmp(_t, "*") != 0) { \
336 const char *_failed_at = NULL; \
337 int _err = 0; \
338 expression_free(dst); \
339 dst = expression_parse(_t, &_failed_at, &_err); \
340 if(!dst) { \
341 buffer_sprintf(error, "expression '%s.%s' has a non-parseable expression '%s': %s at '%s'", \
342 path, member, _t, expression_strerror(_err), _failed_at); \
343 return false; \
344 } \
345 } \
346 } \
347 else if ((flags) & (JSONC_REQUIRED | JSONC_STRICT)) { \
348 buffer_sprintf(error, "invalid type for '%s.%s' expression", path, member); \
349 return false; \
350 } \
351 } \
352 else if((flags) & JSONC_REQUIRED) { \
353 buffer_sprintf(error, "missing '%s.%s' expression", path, member); \
354 return false; \
355 } \
356 } while(0)
357
358 #define JSONC_PARSE_ARRAY_OF_TXT2BITMAP_OR_ERROR_AND_RETURN(jobj, path, member, converter, dst, error, flags) do { \
359 json_object *_jarray; \
360 if (json_object_object_get_ex(jobj, member, &_jarray)) { \
361 if (json_object_is_type(_jarray, json_type_array)) { \
362 size_t _num_options = json_object_array_length(_jarray); \
363 dst = 0; \
364 for (size_t _i = 0; _i < _num_options; ++_i) { \
365 json_object *_joption = json_object_array_get_idx(_jarray, _i); \
366 if (!json_object_is_type(_joption, json_type_string)) { \
367 buffer_sprintf(error, "invalid type for '%s.%s' at index %zu", path, member, _i); \
368 return false; \
369 } \
370 const char *_option_str = json_object_get_string(_joption); \
371 typeof(dst) _bit = converter(_option_str); \
372 if (_bit == 0) { \
373 buffer_sprintf(error, "unknown option '%s' in '%s.%s' at index %zu", _option_str, path, member, _i); \
374 /* return false; */ \
375 } \
376 dst |= _bit; \
377 } \
378 } \
379 else if ((flags) & (JSONC_REQUIRED | JSONC_STRICT)) { \
380 buffer_sprintf(error, "invalid type for '%s.%s' array", path, member); \
381 return false; \
382 } \
383 } \
384 else if((flags) & JSONC_REQUIRED) { \
385 buffer_sprintf(error, "missing '%s.%s' array", path, member); \
386 return false; \
387 } \
388 } while(0)
389
390 #define JSONC_PARSE_TXT2ENUM_OR_ERROR_AND_RETURN(jobj, path, member, converter, dst, error, flags) do { \
391 json_object *_j; \
392 if (json_object_object_get_ex(jobj, member, &_j)) { \
393 if (json_object_is_type(_j, json_type_string)) \
394 dst = converter(json_object_get_string(_j)); \
395 else if ((flags) & (JSONC_REQUIRED | JSONC_STRICT)) { \
396 buffer_sprintf(error, "invalid type for '%s.%s' enum", path, member); \
397 return false; \
398 } \
399 } \
400 else if((flags) & JSONC_REQUIRED) { \
401 buffer_sprintf(error, "missing '%s.%s' enum", path, member); \
402 return false; \
403 } \
404 } while(0)
405
406 #define JSONC_PARSE_INT64_OR_ERROR_AND_RETURN(jobj, path, member, dst, error, flags) do { \
407 json_object *_j; \
408 if (json_object_object_get_ex(jobj, member, &_j)) { \
409 if (_j == NULL) { \
410 dst = 0; \
411 } \
412 else if (json_object_is_type(_j, json_type_int)) { \
413 dst = json_object_get_int64(_j); \
414 } \
415 else if (json_object_is_type(_j, json_type_double)) { \
416 dst = (typeof(dst))json_object_get_double(_j); \
417 } \
418 else if (json_object_is_type(_j, json_type_boolean)) { \
419 dst = json_object_get_boolean(_j) ? 1 : 0; \
420 } \
421 else if (json_object_is_type(_j, json_type_string)) { \
422 const char *_str = json_object_get_string(_j); \
423 char *_endptr; \
424 errno_clear(); \
425 long long _val = strtoll(_str, &_endptr, 10); \
426 if (errno != 0 || *_endptr != '\0' || _endptr == _str) { \
427 buffer_sprintf(error, "cannot convert string '%s' to int64 for '%s.%s'", _str, path, member); \
428 return false; \
429 } \
430 dst = (typeof(dst))_val; \
431 } \
432 else if ((flags) & (JSONC_REQUIRED | JSONC_STRICT)) { \
433 buffer_sprintf(error, "cannot convert to int64 for '%s.%s'", path, member); \
434 return false; \
435 } \
436 } else if((flags) & JSONC_REQUIRED) { \
437 buffer_sprintf(error, "missing '%s.%s'", path, member); \
438 return false; \
439 } \
440 } while(0)
441
442 #define JSONC_PARSE_UINT64_OR_ERROR_AND_RETURN(jobj, path, member, dst, error, flags) do { \
443 json_object *_j; \
444 if (json_object_object_get_ex(jobj, member, &_j)) { \
445 if (_j == NULL) { \
446 dst = 0; \
447 } \
448 else if (json_object_is_type(_j, json_type_int)) { \
449 dst = json_object_get_uint64(_j); \
450 } \
451 else if (json_object_is_type(_j, json_type_double)) { \
452 dst = (typeof(dst))json_object_get_double(_j); \
453 } \
454 else if (json_object_is_type(_j, json_type_boolean)) { \
455 dst = json_object_get_boolean(_j) ? 1 : 0; \
456 } \
457 else if (json_object_is_type(_j, json_type_string)) { \
458 const char *_str = json_object_get_string(_j); \
459 char *_endptr; \
460 errno_clear(); \
461 if (_str[0] == '-') { \
462 buffer_sprintf(error, "cannot convert negative string '%s' to uint64 for '%s.%s'", _str, path, member); \
463 return false; \
464 } \
465 unsigned long long _val = strtoull(_str, &_endptr, 10); \
466 if (errno != 0 || *_endptr != '\0' || _endptr == _str) { \
467 buffer_sprintf(error, "cannot convert string '%s' to uint64 for '%s.%s'", _str, path, member); \
468 return false; \
469 } \
470 dst = (typeof(dst))_val; \
471 } \
472 else if ((flags) & (JSONC_REQUIRED | JSONC_STRICT)) { \
473 buffer_sprintf(error, "cannot convert to uint64 for '%s.%s'", path, member); \
474 return false; \
475 } \
476 } else if((flags) & JSONC_REQUIRED) { \
477 buffer_sprintf(error, "missing '%s.%s'", path, member); \
478 return false; \
479 } \
480 } while(0)
481
482 #define JSONC_PARSE_DOUBLE_OR_ERROR_AND_RETURN(jobj, path, member, dst, error, flags) do { \
483 json_object *_j; \
484 if (json_object_object_get_ex(jobj, member, &_j)) { \
485 if (_j == NULL) { \
486 dst = NAN; \
487 } \
488 else if (json_object_is_type(_j, json_type_double)) { \
489 dst = json_object_get_double(_j); \
490 } \
491 else if (json_object_is_type(_j, json_type_int)) { \
492 dst = (typeof(dst))json_object_get_int64(_j); \
493 } \
494 else if (json_object_is_type(_j, json_type_boolean)) { \
495 dst = json_object_get_boolean(_j) ? 1.0 : 0.0; \
496 } \
497 else if (json_object_is_type(_j, json_type_string)) { \
498 const char *_str = json_object_get_string(_j); \
499 char *_endptr; \
500 errno_clear(); \
501 double _val = strtod(_str, &_endptr); \
502 if (errno != 0 || *_endptr != '\0' || _endptr == _str) { \
503 buffer_sprintf(error, "cannot convert string '%s' to double for '%s.%s'", _str, path, member); \
504 return false; \
505 } \
506 dst = (typeof(dst))_val; \
507 } \
508 else if ((flags) & (JSONC_REQUIRED | JSONC_STRICT)) { \
509 buffer_sprintf(error, "cannot convert to double for '%s.%s'", path, member); \
510 return false; \
511 } \
512 } else if((flags) & JSONC_REQUIRED) { \
513 buffer_sprintf(error, "missing '%s.%s'", path, member); \
514 return false; \
515 } \
516 } while(0)
517
518 #define JSONC_PARSE_SUBOBJECT_CB(jobj, path, member, dst, callback, error, flags) do { \
519 json_object *_j; \
520 if (json_object_object_get_ex(jobj, member, &_j)) { \
521 if (!json_object_is_type(_j, json_type_object)) { \
522 if ((flags) & (JSONC_REQUIRED | JSONC_STRICT)) { \
523 buffer_sprintf(error, "not an object '%s.%s'", path, member); \
524 return false; \
525 } \
526 } \
527 else { \
528 size_t _new_path_size = strlen(path) + strlen(member) + 2; \
529 char *_new_path = mallocz(_new_path_size); \
530 snprintfz(_new_path, _new_path_size, "%s%s%s", path, *path?".":"", member); \
531 if (!callback(_j, _new_path, dst, error, flags)) { \
532 freez(_new_path); \
533 return false; \
534 } \
535 freez(_new_path); \
536 } \
537 } else if((flags) & JSONC_REQUIRED) { \
538 buffer_sprintf(error, "missing '%s.%s' object", path, member); \
539 return false; \
540 } \
541 } while(0)
542
543 #define JSONC_TEMP_VAR(type, line) JSONC_TEMP_VAR_IMPL(type, line)
544 #define JSONC_TEMP_VAR_IMPL(type, line) _jsonc_temp_##type##line
545
546 #define JSONC_PATH_CONCAT(path, sizeof_path, prefix, member, error) do { \
547 size_t len = strlen(prefix); \
548 if(len >= sizeof_path - 1) { \
549 buffer_sprintf(error, "path too long while adding '%s'", member); \
550 return false; \
551 } \
552 if(len) { \
553 if(len >= sizeof_path - 2) { \
554 buffer_sprintf(error, "path too long while adding '.' before '%s'", member); \
555 return false; \
556 } \
557 strncpyz(path + len, ".", sizeof_path - len); \
558 len++; \
559 } \
560 strncpyz(path + len, member, sizeof_path - len); \
561 } while(0)
562
563 #define JSONC_PATH_CONCAT_INDEX(path, sizeof_path, index, error) do { \
564 char _idx_str[32]; \
565 snprintfz(_idx_str, sizeof(_idx_str), "[%zu]", index); \
566 size_t _path_len = strlen(path); \
567 if (_path_len + strlen(_idx_str) >= sizeof_path) { \
568 buffer_sprintf(error, "path too long while adding array index"); \
569 return false; \
570 } \
571 strncpyz(path + _path_len, _idx_str, sizeof_path - _path_len); \
572 } while(0)
573
574 #define JSONC_PARSE_SUBOBJECT(jobj, path, member, error, flags, block) do { \
575 BUILD_BUG_ON(sizeof(path) < 128); /* ensure path is an array of at least 128 bytes */ \
576 json_object *JSONC_TEMP_VAR(_j, __LINE__); \
577 if (!json_object_object_get_ex(jobj, member, &JSONC_TEMP_VAR(_j, __LINE__))) { \
578 if((flags) & JSONC_REQUIRED) { \
579 buffer_sprintf(error, "missing '%s.%s' object", *path ? path : "", member); \
580 return false; \
581 } \
582 } \
583 else { \
584 if (!json_object_is_type(JSONC_TEMP_VAR(_j, __LINE__), json_type_object)) { \
585 if((flags) & (JSONC_REQUIRED | JSONC_STRICT)) { \
586 buffer_sprintf(error, "not an object '%s.%s'", *path ? path : "", member); \
587 return false; \
588 } \
589 } \
590 else { \
591 json_object *JSONC_TEMP_VAR(saved_jobj, __LINE__) = jobj; \
592 jobj = JSONC_TEMP_VAR(_j, __LINE__); \
593 char JSONC_TEMP_VAR(saved_path, __LINE__)[sizeof(path)]; \
594 strncpyz(JSONC_TEMP_VAR(saved_path, __LINE__), path, sizeof(JSONC_TEMP_VAR(saved_path, __LINE__))); \
595 JSONC_PATH_CONCAT(path, sizeof(path), path, member, error); \
596 /* Run the user's code block */ \
597 block \
598 /* Restore the previous scope's values */ \
599 jobj = JSONC_TEMP_VAR(saved_jobj, __LINE__); \
600 strncpyz(path, JSONC_TEMP_VAR(saved_path, __LINE__), sizeof(path)); \
601 } \
602 } \
603 } while(0)
604
605 #define JSONC_PARSE_ARRAY(jobj, path, member, error, flags, block) do { \
606 BUILD_BUG_ON(sizeof(path) < 128); /* ensure path is an array of at least 128 bytes */ \
607 json_object *JSONC_TEMP_VAR(_jarray, __LINE__); \
608 if (!json_object_object_get_ex(jobj, member, &JSONC_TEMP_VAR(_jarray, __LINE__))) { \
609 if ((flags) & JSONC_REQUIRED) { \
610 buffer_sprintf(error, "missing '%s.%s' array", *path ? path : "", member); \
611 return false; \
612 } \
613 } \
614 else { \
615 if (!json_object_is_type(JSONC_TEMP_VAR(_jarray, __LINE__), json_type_array)) { \
616 if ((flags) & (JSONC_REQUIRED | JSONC_STRICT)) { \
617 buffer_sprintf(error, "not an array '%s.%s'", *path ? path : "", member); \
618 return false; \
619 } \
620 } \
621 else { \
622 json_object *JSONC_TEMP_VAR(saved_jobj, __LINE__) = jobj; \
623 jobj = JSONC_TEMP_VAR(_jarray, __LINE__); \
624 char JSONC_TEMP_VAR(saved_path, __LINE__)[sizeof(path)]; \
625 strncpyz(JSONC_TEMP_VAR(saved_path, __LINE__), path, sizeof(JSONC_TEMP_VAR(saved_path, __LINE__))); \
626 JSONC_PATH_CONCAT(path, sizeof(path), path, member, error); \
627 /* Run the user's code block */ \
628 block \
629 /* Restore the previous scope's values */ \
630 jobj = JSONC_TEMP_VAR(saved_jobj, __LINE__); \
631 strncpyz(path, JSONC_TEMP_VAR(saved_path, __LINE__), sizeof(path)); \
632 } \
633 } \
634 } while(0)
635
636 #define JSONC_PARSE_ARRAY_ITEM_OBJECT(jobj, path, index, flags, block) do { \
637 size_t JSONC_TEMP_VAR(_array_len, __LINE__) = json_object_array_length(jobj); \
638 for (index = 0; index < JSONC_TEMP_VAR(_array_len, __LINE__); index++) { \
639 json_object *JSONC_TEMP_VAR(_jitem, __LINE__) = json_object_array_get_idx(jobj, index); \
640 if (!json_object_is_type(JSONC_TEMP_VAR(_jitem, __LINE__), json_type_object)) { \
641 if((flags) & (JSONC_REQUIRED | JSONC_STRICT)) { \
642 buffer_sprintf(error, "not an object '%s[%zu]'", *path ? path : "", index); \
643 return false; \
644 } \
645 } \
646 else { \
647 json_object *JSONC_TEMP_VAR(saved_jobj, __LINE__) = jobj; \
648 jobj = JSONC_TEMP_VAR(_jitem, __LINE__); \
649 char JSONC_TEMP_VAR(saved_path, __LINE__)[sizeof(path)]; \
650 strncpyz(JSONC_TEMP_VAR(saved_path, __LINE__), path, sizeof(JSONC_TEMP_VAR(saved_path, __LINE__))); \
651 JSONC_PATH_CONCAT_INDEX(path, sizeof(path), index, error); \
652 /* Run the user's code block */ \
653 block \
654 /* Restore the previous scope's values */ \
655 jobj = JSONC_TEMP_VAR(saved_jobj, __LINE__); \
656 strncpyz(path, JSONC_TEMP_VAR(saved_path, __LINE__), sizeof(path)); \
657 } \
658 } \
659 } while(0)
660
661 typedef bool (*json_parse_function_payload_t)(json_object *jobj, void *data, BUFFER *error);
662 int rrd_call_function_error(BUFFER *wb, const char *msg, int code);
663 struct json_object *json_parse_function_payload_or_error(BUFFER *output, BUFFER *payload, int *code, json_parse_function_payload_t cb, void *cb_data);
664
665 // return HTTP response code
666 int json_parse_payload_or_error(BUFFER *payload, BUFFER *error, json_parse_function_payload_t cb, void *cb_data);
667
668 int json_c_parser_unittest(void);
669
670 #endif //NETDATA_JSON_C_PARSER_INLINE_H