1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <string.h>
4 #include <math.h>
5 #include <json-c/json.h>
6
7 #include "validate.h"
8
9 json_object *json = NULL;
10 json_object *schema = NULL;
11 json_object *defs = NULL;
12
13 static char *schemavalidator_errstr[SCHEMAVALIDATOR_ERR_MAX] = {
14 "VALID",
15 "GENERAL ERROR",
16 "JSON FILE NOT FOUND",
17 "SCHEMA FILE NOT FOUND",
18 "WRONG ARGUEMNTS GIVEN",
19 "SCHEMA ERROR",
20 "INVALID",
21 "REGEX MISMATCH",
22 "REGEX MATCH",
23 "REGEX COMPILE FAILED"
24 };
25
schemavalidator_errorstr(unsigned int schemavalidator_errors)26 const char *schemavalidator_errorstr(unsigned int schemavalidator_errors)
27 {
28 if (schemavalidator_errors < SCHEMAVALIDATOR_ERR_MAX) {
29 return schemavalidator_errstr[schemavalidator_errors];
30 }
31 return NULL;
32 }
33
_schemavalidator_load(const char * jsonfile,const char * jsonschema)34 int _schemavalidator_load(const char *jsonfile, const char *jsonschema)
35 {
36 json = json_object_from_file(jsonfile);
37 if (json == NULL) {
38 return SCHEMAVALIDATOR_ERR_JSON_NOT_FOUND;
39 }
40
41 schema = json_object_from_file(jsonschema);
42 if (schema == NULL) {
43 json_object_put(json);
44 return SCHEMAVALIDATOR_ERR_SCHEMA_NOT_FOUND;
45 }
46
47 return SCHEMAVALIDATOR_ERR_VALID;
48 }
49
__schemavalidator_inspect_type(json_object * jobj,const char * type,json_object * joutput_node)50 int __schemavalidator_inspect_type(json_object *jobj, const char *type,
51 json_object *joutput_node)
52 {
53 if (strcmp(type, "object") == 0) {
54 if (json_object_is_type(jobj, json_type_object)) {
55 return SCHEMAVALIDATOR_ERR_VALID;
56 }
57 } else if (strcmp(type, "array") == 0) {
58 if (json_object_is_type(jobj, json_type_array)) {
59 return SCHEMAVALIDATOR_ERR_VALID;
60 }
61 } else if (strcmp(type, "string") == 0) {
62 if (json_object_is_type(jobj, json_type_string)) {
63 return SCHEMAVALIDATOR_ERR_VALID;
64 }
65 } else if (strcmp(type, "integer") == 0) {
66 if (json_object_is_type(jobj, json_type_int)) {
67 return SCHEMAVALIDATOR_ERR_VALID;
68 }
69 if (json_object_is_type(jobj, json_type_double)) {
70 double value = json_object_get_double(jobj);
71 if (value ==
72 round(value)) { // "zero fractional part is an integer"
73 return SCHEMAVALIDATOR_ERR_VALID;
74 }
75 }
76 } else if (strcmp(type, "double") == 0) {
77 if (json_object_is_type(jobj, json_type_double)) {
78 return SCHEMAVALIDATOR_ERR_VALID;
79 }
80 } else if (strcmp(type, "number") == 0) {
81 if (json_object_is_type(jobj, json_type_double) ||
82 json_object_is_type(jobj, json_type_int)) {
83 return SCHEMAVALIDATOR_ERR_VALID;
84 }
85 } else if (strcmp(type, "boolean") == 0) {
86 if (json_object_is_type(jobj, json_type_boolean)) {
87 return SCHEMAVALIDATOR_ERR_VALID;
88 }
89 } else if (strcmp(type, "null") == 0) {
90 if (json_object_is_type(jobj, json_type_null)) {
91 return SCHEMAVALIDATOR_ERR_VALID;
92 }
93 } else {
94 printf("WARN unknown type in check type %s\n", type);
95 json_object *jnode =
96 _schemavalidator_output_create_and_append_node(
97 joutput_node, "type");
98 _schemavalidator_output_apply_result(
99 jnode, SCHEMAVALIDATOR_ERR_SCHEMA_ERROR);
100 return SCHEMAVALIDATOR_ERR_SCHEMA_ERROR;
101 }
102 json_object *jnode = _schemavalidator_output_create_and_append_node(
103 joutput_node, "type");
104 _schemavalidator_output_apply_result(jnode,
105 SCHEMAVALIDATOR_ERR_INVALID);
106
107 return SCHEMAVALIDATOR_ERR_INVALID;
108 }
109
schemavalidator_check_bool(json_object * jobj,json_object * jschema,json_object * joutput_node)110 int schemavalidator_check_bool(json_object *jobj, json_object *jschema,
111 json_object *joutput_node)
112 {
113 (void)jobj;
114 // check if jschema is a bool, true or false
115 int err;
116 if (json_object_is_type(jschema, json_type_boolean)) {
117 json_object *jnode =
118 _schemavalidator_output_create_and_append_node(
119 joutput_node, "bool");
120 json_bool value = json_object_get_boolean(jschema);
121 err = value == 0 ? SCHEMAVALIDATOR_ERR_INVALID :
122 SCHEMAVALIDATOR_ERR_VALID;
123 _schemavalidator_output_apply_result(jnode, err);
124 return err;
125 }
126 return SCHEMAVALIDATOR_ERR_VALID;
127 }
128
_schemavalidator_check_type(json_object * jobj,json_object * jschema,json_object * joutput_node)129 int _schemavalidator_check_type(json_object *jobj, json_object *jschema,
130 json_object *joutput_node)
131 {
132 json_object *jnode;
133 json_object *jtype = json_object_object_get(jschema, "type");
134 if (jtype == NULL) {
135 return SCHEMAVALIDATOR_ERR_VALID;
136 }
137 if (json_object_is_type(jtype, json_type_string)) {
138 const char *type = json_object_get_string(jtype);
139 return __schemavalidator_inspect_type(jobj, type, joutput_node);
140 }
141 if (json_object_is_type(jtype, json_type_array)) {
142 int arraylen = json_object_array_length(jtype);
143 for (int i = 0; i < arraylen; i++) {
144 json_object *iobj = json_object_array_get_idx(jtype, i);
145 if (!json_object_is_type(iobj, json_type_string)) {
146 goto check_type_schema_error;
147 }
148 const char *type = json_object_get_string(iobj);
149 int err = __schemavalidator_inspect_type(jobj, type,
150 joutput_node);
151 if (err == SCHEMAVALIDATOR_ERR_VALID) {
152 return SCHEMAVALIDATOR_ERR_VALID;
153 }
154 }
155 jnode = _schemavalidator_output_create_and_append_node(
156 joutput_node, "type");
157 _schemavalidator_output_apply_result(
158 jnode, SCHEMAVALIDATOR_ERR_INVALID);
159 return SCHEMAVALIDATOR_ERR_INVALID;
160 }
161 check_type_schema_error:
162 jnode = _schemavalidator_output_create_and_append_node(joutput_node,
163 "type");
164 _schemavalidator_output_apply_result(jnode,
165 SCHEMAVALIDATOR_ERR_SCHEMA_ERROR);
166 return SCHEMAVALIDATOR_ERR_SCHEMA_ERROR;
167 }
168
_schemavalidator_check_required(json_object * jobj,json_object * jschema,json_object * joutput_node)169 int _schemavalidator_check_required(json_object *jobj, json_object *jschema,
170 json_object *joutput_node)
171 {
172 //printf("%s\n%s\n", __func__, json_object_to_json_string(jobj));
173 json_object *jarray = json_object_object_get(jschema, "required");
174 if (!jarray) {
175 return SCHEMAVALIDATOR_ERR_VALID;
176 }
177
178 json_object *jrequired_node =
179 _schemavalidator_output_create_and_append_node(joutput_node,
180 "required");
181 int missing_required_key = 0;
182
183 int arraylen = json_object_array_length(jarray);
184 for (int i = 0; i < arraylen; i++) {
185 json_object *iobj = json_object_array_get_idx(jarray, i);
186 const char *key = json_object_get_string(iobj);
187 if (key) {
188 //printf("%s\n", key);
189 // use json_object_object_get_ex becuase of json_type_null types
190 json_object *required_object = NULL;
191 int err = json_object_object_get_ex(jobj, key,
192 &required_object);
193 if (err == 0) {
194 // printf("required key missing: %s\n", key);
195 json_object *jkeynode =
196 _schemavalidator_output_create_and_append_node(
197 jrequired_node, key);
198 _schemavalidator_output_apply_result(
199 jkeynode, SCHEMAVALIDATOR_ERR_INVALID);
200 missing_required_key = 1;
201 }
202 }
203 }
204 int ret = missing_required_key == 1 ? SCHEMAVALIDATOR_ERR_INVALID :
205 SCHEMAVALIDATOR_ERR_VALID;
206 _schemavalidator_output_apply_result(jrequired_node, ret);
207 return ret;
208 }
209
_schemavalidator_check_properties(json_object * jobj,json_object * jschema,json_object * joutput_node)210 int _schemavalidator_check_properties(json_object *jobj, json_object *jschema,
211 json_object *joutput_node)
212 {
213 // printf("%s\n", __func__);
214
215 json_object *jprops = json_object_object_get(jschema, "properties");
216 if (!jprops) {
217 return SCHEMAVALIDATOR_ERR_VALID;
218 }
219
220 json_object *jproperties_node =
221 _schemavalidator_output_create_and_append_node(joutput_node,
222 "properties");
223 int properties_valid = 1;
224 json_object_object_foreach(jprops, jprop_key, jprop_val)
225 {
226 // printf("key of prop is %s\n", jprop_key);
227 json_object *iobj = json_object_object_get(jobj, jprop_key);
228 //printf("iobj %s type %d\nkey %s\nval %s\n", json_object_get_string(iobj), json_object_get_type(iobj), jprop_key, json_object_get_string(jprop_val));
229 if (iobj) {
230 json_object *jprop_item_tmp_node =
231 _schemavalidator_output_create_node(jprop_key);
232 int err = _schemavalidator_validate_instance(
233 iobj, jprop_val, jprop_item_tmp_node);
234 if (err != SCHEMAVALIDATOR_ERR_VALID) {
235 properties_valid = 0;
236 _schemavalidator_output_apply_result(
237 jprop_item_tmp_node, err);
238 _schemavalidator_output_append_node(
239 jproperties_node, jprop_item_tmp_node);
240 } else {
241 json_object_put(jprop_item_tmp_node);
242 }
243 }
244 }
245 int ret = properties_valid == 1 ? SCHEMAVALIDATOR_ERR_VALID :
246 SCHEMAVALIDATOR_ERR_INVALID;
247 _schemavalidator_output_apply_result(jproperties_node, ret);
248 return ret;
249 }
250
_schemavalidator_check_prefixItems_and_items(json_object * jobj,json_object * jschema,json_object * joutput_node)251 int _schemavalidator_check_prefixItems_and_items(json_object *jobj,
252 json_object *jschema,
253 json_object *joutput_node)
254 {
255 json_object *jprefixitems =
256 json_object_object_get(jschema, "prefixItems");
257 json_object *jitems = json_object_object_get(jschema, "items");
258
259 int prefixitems_ok = 1;
260 int items_ok = 1;
261
262 if (jprefixitems) {
263 json_object *jprefixitems_node =
264 _schemavalidator_output_create_and_append_node(
265 joutput_node, "prefixItems");
266
267 if (!json_object_is_type(jprefixitems, json_type_array)) {
268 _schemavalidator_output_apply_result(
269 jprefixitems_node,
270 SCHEMAVALIDATOR_ERR_SCHEMA_ERROR);
271 return SCHEMAVALIDATOR_ERR_SCHEMA_ERROR;
272 }
273
274 int jobj_arraylen = json_object_array_length(jobj);
275 int prefixitems_arraylen =
276 json_object_array_length(jprefixitems);
277 for (int i = 0; i < jobj_arraylen && i < prefixitems_arraylen;
278 i++) {
279 //printf("i=%d prefixitems\n", i);
280 json_object *iobj = json_object_array_get_idx(jobj, i);
281 json_object *ischema =
282 json_object_array_get_idx(jprefixitems, i);
283
284 char numstr[12];
285 snprintf(numstr, sizeof(numstr), "%d", i);
286 json_object *jarrayitem_tmp_node =
287 _schemavalidator_output_create_node(numstr);
288
289 int err = _schemavalidator_validate_instance(
290 iobj, ischema, jarrayitem_tmp_node);
291 if (err) {
292 _schemavalidator_output_apply_result(
293 jprefixitems_node, err);
294 _schemavalidator_output_append_node(
295 jprefixitems_node, jarrayitem_tmp_node);
296 prefixitems_ok = 0;
297 } else {
298 json_object_put(jarrayitem_tmp_node);
299 }
300 }
301 int prefixitems_ret = (prefixitems_ok == 1) ?
302 SCHEMAVALIDATOR_ERR_VALID :
303 SCHEMAVALIDATOR_ERR_INVALID;
304 _schemavalidator_output_apply_result(jprefixitems_node,
305 prefixitems_ret);
306 }
307
308 if (jitems) {
309 json_object *jitems_node =
310 _schemavalidator_output_create_and_append_node(
311 joutput_node, "items");
312
313 if (!json_object_is_type(jitems, json_type_object) &&
314 !json_object_is_type(jitems, json_type_boolean)) {
315 _schemavalidator_output_apply_result(
316 jitems_node, SCHEMAVALIDATOR_ERR_SCHEMA_ERROR);
317 return SCHEMAVALIDATOR_ERR_SCHEMA_ERROR;
318 }
319
320 int jobj_arraylen = json_object_array_length(jobj);
321 int items_arraylen = 0;
322 for (int i = items_arraylen; i < jobj_arraylen; i++) {
323 //printf("i=%d items\n", i);
324 json_object *iobj = json_object_array_get_idx(jobj, i);
325 char numstr[12];
326 snprintf(numstr, sizeof(numstr), "%d", i);
327 json_object *jarrayitem_tmp_node =
328 _schemavalidator_output_create_node(numstr);
329 int err = _schemavalidator_validate_instance(
330 iobj, jitems, jarrayitem_tmp_node);
331 if (err) {
332 _schemavalidator_output_apply_result(
333 jarrayitem_tmp_node, err);
334 _schemavalidator_output_append_node(
335 jitems_node, jarrayitem_tmp_node);
336 items_ok = 0;
337 } else {
338 json_object_put(jarrayitem_tmp_node);
339 }
340 }
341 int items_ret = (items_ok == 1) ? SCHEMAVALIDATOR_ERR_VALID :
342 SCHEMAVALIDATOR_ERR_INVALID;
343 _schemavalidator_output_apply_result(jitems_node, items_ret);
344 }
345 int ret = (prefixitems_ok == 1 && items_ok == 1) ?
346 SCHEMAVALIDATOR_ERR_VALID :
347 SCHEMAVALIDATOR_ERR_INVALID;
348 return ret;
349 }
350
_schemavalidator_value_is_equal(json_object * jobj1,json_object * jobj2)351 int _schemavalidator_value_is_equal(json_object *jobj1, json_object *jobj2)
352 {
353 if (json_object_equal(jobj1, jobj2)) {
354 return SCHEMAVALIDATOR_ERR_VALID;
355 }
356
357 if (json_object_is_type(jobj1, json_type_double) &&
358 json_object_is_type(jobj2, json_type_int)) {
359 double value = json_object_get_double(jobj1);
360 double value2 = json_object_get_int64(jobj2);
361 if (value == round(value) && value == value2) {
362 return SCHEMAVALIDATOR_ERR_VALID;
363 }
364 }
365
366 if (json_object_is_type(jobj1, json_type_int) &&
367 json_object_is_type(jobj2, json_type_double)) {
368 double value = json_object_get_double(jobj2);
369 double value2 = json_object_get_int64(jobj1);
370 if (value == round(value) && value == value2) {
371 return SCHEMAVALIDATOR_ERR_VALID;
372 }
373 }
374
375 return SCHEMAVALIDATOR_ERR_INVALID;
376 }
377
_schemavalidator_check_const(json_object * jobj,json_object * jschema,json_object * joutput_node)378 int _schemavalidator_check_const(json_object *jobj, json_object *jschema,
379 json_object *joutput_node)
380 {
381 json_object *jconst;
382 int err = json_object_object_get_ex(jschema, "const", &jconst);
383 if (err == 0) {
384 return SCHEMAVALIDATOR_ERR_VALID;
385 }
386
387 err = _schemavalidator_value_is_equal(jobj, jconst);
388 if (err == SCHEMAVALIDATOR_ERR_VALID) {
389 return SCHEMAVALIDATOR_ERR_VALID;
390 }
391
392 json_object *jnode = _schemavalidator_output_create_and_append_node(
393 joutput_node, "const");
394 _schemavalidator_output_apply_result(jnode,
395 SCHEMAVALIDATOR_ERR_INVALID);
396 return SCHEMAVALIDATOR_ERR_INVALID;
397 }
398
_schemavalidator_check_enums(json_object * jobj,json_object * jschema,json_object * joutput_node)399 int _schemavalidator_check_enums(json_object *jobj, json_object *jschema,
400 json_object *joutput_node)
401 {
402 json_object *jenum_array = json_object_object_get(jschema, "enum");
403
404 if (!jenum_array) {
405 return SCHEMAVALIDATOR_ERR_VALID;
406 }
407
408 if (!json_object_is_type(jenum_array, json_type_array)) {
409 json_object *jnode =
410 _schemavalidator_output_create_and_append_node(
411 joutput_node, "enum");
412 _schemavalidator_output_apply_result(
413 jnode, SCHEMAVALIDATOR_ERR_SCHEMA_ERROR);
414 return SCHEMAVALIDATOR_ERR_SCHEMA_ERROR;
415 }
416
417 int arraylen = json_object_array_length(jenum_array);
418 for (int i = 0; i < arraylen; i++) {
419 json_object *ienum = json_object_array_get_idx(jenum_array, i);
420 int err = _schemavalidator_value_is_equal(jobj, ienum);
421 if (err == SCHEMAVALIDATOR_ERR_VALID) {
422 return SCHEMAVALIDATOR_ERR_VALID;
423 }
424 }
425 // printf("ERROR: enum check failed (%s not in enum)\n", json_object_to_json_string(jobj));
426
427 json_object *jnode = _schemavalidator_output_create_and_append_node(
428 joutput_node, "enum");
429 _schemavalidator_output_apply_result(jnode,
430 SCHEMAVALIDATOR_ERR_INVALID);
431 return SCHEMAVALIDATOR_ERR_INVALID;
432 }
433
_schemavalidator_check_uniqueItems(json_object * jobj,json_object * jschema,json_object * joutput_node)434 int _schemavalidator_check_uniqueItems(json_object *jobj, json_object *jschema,
435 json_object *joutput_node)
436 {
437 json_object *juniq = json_object_object_get(jschema, "uniqueItems");
438 if (!juniq) {
439 return SCHEMAVALIDATOR_ERR_VALID;
440 }
441
442 json_object *juniqueitems_node =
443 _schemavalidator_output_create_and_append_node(joutput_node,
444 "uniqueItems");
445
446 if (!json_object_is_type(juniq, json_type_boolean)) {
447 _schemavalidator_output_apply_result(
448 juniqueitems_node, SCHEMAVALIDATOR_ERR_SCHEMA_ERROR);
449 return SCHEMAVALIDATOR_ERR_SCHEMA_ERROR;
450 }
451
452 // uniqueItems=false is valid
453 if (json_object_get_boolean(juniq) == 0) {
454 _schemavalidator_output_apply_result(juniqueitems_node,
455 SCHEMAVALIDATOR_ERR_VALID);
456 return SCHEMAVALIDATOR_ERR_VALID;
457 }
458
459 int uniqueitems_ok = 1;
460 int arraylen = json_object_array_length(jobj);
461 for (int i = 0; i < arraylen - 1; i++) {
462 json_object *iobj = json_object_array_get_idx(jobj, i);
463 for (int j = i + 1; j < arraylen; j++) {
464 json_object *uobj = json_object_array_get_idx(jobj, j);
465 if (json_object_equal(iobj, uobj) == 1) {
466 uniqueitems_ok = 0;
467 char numstr[12];
468 snprintf(numstr, sizeof(numstr), "%d", i);
469 json_object *jnotunique_node =
470 _schemavalidator_output_create_and_append_node(
471 juniqueitems_node, numstr);
472 _schemavalidator_output_apply_result(
473 jnotunique_node,
474 SCHEMAVALIDATOR_ERR_INVALID);
475 }
476 }
477 }
478 int ret = uniqueitems_ok == 1 ? SCHEMAVALIDATOR_ERR_VALID :
479 SCHEMAVALIDATOR_ERR_INVALID;
480 _schemavalidator_output_apply_result(juniqueitems_node, ret);
481 return ret;
482 }
483
_schemavalidator_check_maxmin_items(json_object * jobj,json_object * jschema,json_object * joutput_node)484 int _schemavalidator_check_maxmin_items(json_object *jobj, json_object *jschema,
485 json_object *joutput_node)
486 {
487 int err = SCHEMAVALIDATOR_ERR_VALID;
488 int arraylen = json_object_array_length(jobj);
489
490 json_object *jmax = json_object_object_get(jschema, "maxItems");
491 if (jmax) {
492 if (json_object_is_type(jmax, json_type_int) ||
493 json_object_is_type(jmax, json_type_double)) {
494 int maxitems = json_object_get_double(jmax);
495 if (arraylen > maxitems) {
496 json_object *jmaxitems_node =
497 _schemavalidator_output_create_and_append_node(
498 joutput_node, "maxItems");
499 _schemavalidator_output_apply_result(
500 jmaxitems_node,
501 SCHEMAVALIDATOR_ERR_INVALID);
502 err = SCHEMAVALIDATOR_ERR_INVALID;
503 }
504 }
505 }
506
507 json_object *jmin = json_object_object_get(jschema, "minItems");
508 if (jmin) {
509 if (json_object_is_type(jmin, json_type_int) ||
510 json_object_is_type(jmin, json_type_double)) {
511 int minitems = json_object_get_double(jmin);
512 if (arraylen < minitems) {
513 json_object *jminitems_node =
514 _schemavalidator_output_create_and_append_node(
515 joutput_node, "minItems");
516 _schemavalidator_output_apply_result(
517 jminitems_node,
518 SCHEMAVALIDATOR_ERR_INVALID);
519 err = SCHEMAVALIDATOR_ERR_INVALID;
520 }
521 }
522 }
523
524 // if (err)
525 // printf("ERROR: failed at maxItems or minItems check\n");
526 return err;
527 }
528
_schemavalidator_validate_array(json_object * jobj,json_object * jschema,json_object * joutput_node)529 int _schemavalidator_validate_array(json_object *jobj, json_object *jschema,
530 json_object *joutput_node)
531 {
532 int err;
533
534 err = _schemavalidator_check_prefixItems_and_items(jobj, jschema,
535 joutput_node);
536 if (err) {
537 return err;
538 }
539
540 err = _schemavalidator_check_uniqueItems(jobj, jschema, joutput_node);
541 if (err) {
542 return err;
543 }
544
545 err = _schemavalidator_check_maxmin_items(jobj, jschema, joutput_node);
546 if (err) {
547 return err;
548 }
549
550 return SCHEMAVALIDATOR_ERR_VALID;
551 }
552
_schemavalidator_validate_object(json_object * jobj,json_object * jschema,json_object * joutput_node)553 int _schemavalidator_validate_object(json_object *jobj, json_object *jschema,
554 json_object *joutput_node)
555 {
556 int err;
557 if (defs == NULL) {
558 defs = json_object_object_get(jschema, "$defs");
559 }
560
561 err = _schemavalidator_check_required(jobj, jschema, joutput_node);
562 if (err) {
563 return err;
564 }
565
566 err = _schemavalidator_check_properties(jobj, jschema, joutput_node);
567 if (err) {
568 return err;
569 }
570
571 return SCHEMAVALIDATOR_ERR_VALID;
572 }
573
utf8_length(const char * str)574 int utf8_length(const char *str)
575 {
576 const char *pointer = str;
577 int len = 0;
578 while (pointer[0]) {
579 if ((pointer[0] & 0xC0) != 0x80) {
580 len++;
581 }
582 pointer++;
583 }
584 return len;
585 }
586
_schemavalidator_validate_string(json_object * jobj,json_object * jschema,json_object * joutput_node)587 int _schemavalidator_validate_string(json_object *jobj, json_object *jschema,
588 json_object *joutput_node)
589 {
590 const char *str = json_object_get_string(jobj);
591 //printf("strlen of %s %ld %d %d\n", str, strlen(str), json_object_get_string_len(jobj), utf8_length(str));
592
593 int minlength_ok = 1;
594 json_object *jminlen = json_object_object_get(jschema, "minLength");
595 if (jminlen) {
596 int minlen = json_object_get_int64(jminlen);
597 if (utf8_length(str) < minlen) {
598 minlength_ok = 0;
599 json_object *jminlength_node =
600 _schemavalidator_output_create_and_append_node(
601 joutput_node, "minLength");
602 _schemavalidator_output_apply_result(
603 jminlength_node, SCHEMAVALIDATOR_ERR_INVALID);
604 }
605 }
606
607 int maxlength_ok = 1;
608 json_object *jmaxlen = json_object_object_get(jschema, "maxLength");
609 if (jmaxlen) {
610 int maxlen = json_object_get_int64(jmaxlen);
611 if (utf8_length(str) > maxlen) {
612 maxlength_ok = 0;
613 json_object *jmaxlength_node =
614 _schemavalidator_output_create_and_append_node(
615 joutput_node, "maxLength");
616 _schemavalidator_output_apply_result(
617 jmaxlength_node, SCHEMAVALIDATOR_ERR_INVALID);
618 }
619 }
620
621 int enums_ok = 1;
622 int err = _schemavalidator_check_enums(jobj, jschema, joutput_node);
623 if (err) {
624 if (err == SCHEMAVALIDATOR_ERR_SCHEMA_ERROR) {
625 // _schemavalidator_output_apply_result(joutput_node, SCHEMAVALIDATOR_ERR_SCHEMA_ERROR);
626 return err;
627 }
628 enums_ok = 0;
629 }
630
631 int ret = minlength_ok == 1 && maxlength_ok == 1 && enums_ok == 1 ?
632 SCHEMAVALIDATOR_ERR_VALID :
633 SCHEMAVALIDATOR_ERR_INVALID;
634 // _schemavalidator_output_apply_result(joutput_node, ret);
635 return ret;
636 }
637
_schemavalidator_validate_integer(json_object * jobj,json_object * jschema,json_object * joutput_node)638 int _schemavalidator_validate_integer(json_object *jobj, json_object *jschema,
639 json_object *joutput_node)
640 {
641 (void)jobj;
642 double value = (double)json_object_get_int64(jobj);
643 int err = _schemavalidator_validate_number(jobj, jschema, value,
644 joutput_node);
645 return err;
646 }
647
_schemavalidator_validate_double(json_object * jobj,json_object * jschema,json_object * joutput_node)648 int _schemavalidator_validate_double(json_object *jobj, json_object *jschema,
649 json_object *joutput_node)
650 {
651 (void)jobj;
652 double value = json_object_get_double(jobj);
653 int err = _schemavalidator_validate_number(jobj, jschema, value,
654 joutput_node);
655 return err;
656 }
657
_schemavalidator_validate_number(json_object * jobj,json_object * jschema,double value,json_object * joutput_node)658 int _schemavalidator_validate_number(json_object *jobj, json_object *jschema,
659 double value, json_object *joutput_node)
660 {
661 (void)jobj;
662 int multipleOf_ok = 1;
663 json_object *jmult = json_object_object_get(jschema, "multipleOf");
664 if (jmult) {
665 double multipland = (double)json_object_get_double(jmult);
666 if (multipland == 0.0) {
667 json_object *jmultipleOf_node =
668 _schemavalidator_output_create_and_append_node(
669 joutput_node, "multipleOf");
670 _schemavalidator_output_apply_result(
671 jmultipleOf_node,
672 SCHEMAVALIDATOR_ERR_SCHEMA_ERROR);
673 // _schemavalidator_output_apply_result(joutput_node, SCHEMAVALIDATOR_ERR_SCHEMA_ERROR);
674 return SCHEMAVALIDATOR_ERR_SCHEMA_ERROR;
675 }
676
677 double divided = value / multipland;
678 if (isinf(divided) != 0 || divided != round(divided)) {
679 multipleOf_ok = 0;
680 }
681 if (multipleOf_ok == 0) {
682 json_object *jmultipleOf_node =
683 _schemavalidator_output_create_and_append_node(
684 joutput_node, "multipleOf");
685 _schemavalidator_output_apply_result(
686 jmultipleOf_node, SCHEMAVALIDATOR_ERR_INVALID);
687 }
688 }
689
690 int minimum_ok = 1;
691 json_object *jmin = json_object_object_get(jschema, "minimum");
692 if (jmin) {
693 double min = (double)json_object_get_double(jmin);
694 if (value < min) {
695 minimum_ok = 0;
696 json_object *jminimum_node =
697 _schemavalidator_output_create_and_append_node(
698 joutput_node, "minimum");
699 _schemavalidator_output_apply_result(
700 jminimum_node, SCHEMAVALIDATOR_ERR_INVALID);
701 }
702 }
703
704 int exclusiveMinimum_ok = 1;
705 json_object *jexclmin =
706 json_object_object_get(jschema, "exclusiveMinimum");
707 if (jexclmin) {
708 double min = (double)json_object_get_double(jexclmin);
709 if (value <= min) {
710 exclusiveMinimum_ok = 0;
711 json_object *jexclusiveMinimum_node =
712 _schemavalidator_output_create_and_append_node(
713 joutput_node, "exclusiveMinimum");
714 _schemavalidator_output_apply_result(
715 jexclusiveMinimum_node,
716 SCHEMAVALIDATOR_ERR_INVALID);
717 }
718 }
719
720 int maximum_ok = 1;
721 json_object *jmax = json_object_object_get(jschema, "maximum");
722 if (jmax) {
723 double max = (double)json_object_get_double(jmax);
724 if (value > max) {
725 maximum_ok = 0;
726 json_object *jmaximum_node =
727 _schemavalidator_output_create_and_append_node(
728 joutput_node, "maximum");
729 _schemavalidator_output_apply_result(
730 jmaximum_node, SCHEMAVALIDATOR_ERR_INVALID);
731 }
732 }
733
734 int exclusiveMaximum_ok = 1;
735 json_object *jexclmax =
736 json_object_object_get(jschema, "exclusiveMaximum");
737 if (jexclmax) {
738 double max = (double)json_object_get_double(jexclmax);
739 if (value >= max) {
740 exclusiveMaximum_ok = 0;
741 json_object *jexclusiveMaximum_node =
742 _schemavalidator_output_create_and_append_node(
743 joutput_node, "exclusiveMaximum");
744 _schemavalidator_output_apply_result(
745 jexclusiveMaximum_node,
746 SCHEMAVALIDATOR_ERR_INVALID);
747 }
748 }
749 int ret = multipleOf_ok == 1 && minimum_ok == 1 &&
750 exclusiveMinimum_ok == 1 && maximum_ok == 1 &&
751 exclusiveMaximum_ok == 1 ?
752 SCHEMAVALIDATOR_ERR_VALID :
753 SCHEMAVALIDATOR_ERR_INVALID;
754 // _schemavalidator_output_apply_result(joutput_node, ret);
755 return ret;
756 }
757
_schemavalidator_validate_boolean(json_object * jobj,json_object * jschema,json_object * joutput_node)758 int _schemavalidator_validate_boolean(json_object *jobj, json_object *jschema,
759 json_object *joutput_node)
760 {
761 (void)jobj;
762 (void)jschema;
763 (void)joutput_node;
764 // printf("%s\n", __func__);
765 // _schemavalidator_output_apply_result(joutput_node, SCHEMAVALIDATOR_ERR_VALID);
766 return SCHEMAVALIDATOR_ERR_VALID;
767 }
768
_schemavalidator_validate_instance(json_object * jobj,json_object * jschema,json_object * joutput_node)769 int _schemavalidator_validate_instance(json_object *jobj, json_object *jschema,
770 json_object *joutput_node)
771 {
772 int err;
773 // printf("--validate instance--\n");
774 // printf("%s\n", json_object_get_string(jobj));
775 // printf("%s\n", json_object_get_string(jschema));
776
777 err = schemavalidator_check_bool(jobj, jschema, joutput_node);
778 if (err) {
779 return err;
780 }
781
782 err = _schemavalidator_check_type(jobj, jschema, joutput_node);
783 if (err) {
784 return err;
785 }
786
787 err = _schemavalidator_check_const(jobj, jschema, joutput_node);
788 if (err) {
789 return err;
790 }
791
792 err = _schemavalidator_check_enums(jobj, jschema, joutput_node);
793 if (err) {
794 return err;
795 }
796
797 json_type type = json_object_get_type(jobj);
798
799 if (type == json_type_object) {
800 return _schemavalidator_validate_object(jobj, jschema,
801 joutput_node);
802 }
803 if (type == json_type_array) {
804 return _schemavalidator_validate_array(jobj, jschema,
805 joutput_node);
806 }
807 if (type == json_type_string) {
808 return _schemavalidator_validate_string(jobj, jschema,
809 joutput_node);
810 }
811 if (type == json_type_boolean) {
812 return _schemavalidator_validate_boolean(jobj, jschema,
813 joutput_node);
814 }
815 if (type == json_type_int) {
816 return _schemavalidator_validate_integer(jobj, jschema,
817 joutput_node);
818 }
819 if (type == json_type_double) {
820 return _schemavalidator_validate_double(jobj, jschema,
821 joutput_node);
822 }
823 if (type == json_type_null) {
824 return SCHEMAVALIDATOR_ERR_VALID;
825 }
826 printf("%s: WARN: type %d not handled\n", __func__, type);
827
828 return SCHEMAVALIDATOR_ERR_VALID;
829 }
830
schemavalidator_validate(json_object * jobj,json_object * jschema)831 int schemavalidator_validate(json_object *jobj, json_object *jschema)
832 {
833 json_object *joutput = _schemavalidator_output_create_node("root");
834 int err = _schemavalidator_validate_instance(jobj, jschema, joutput);
835 _schemavalidator_output_apply_result(joutput, err);
836
837 if (joutput) {
838 //printf("Basic Output: %s\n", json_object_get_string(joutput));
839 _schemavalidator_output_print_errors(joutput);
840 }
841
842 if (joutput) {
843 json_object_put(joutput);
844 }
845 return err;
846 }
847