Remove json schema validation
libcper is a cper parsing library. It is not a json schema validation
library. If we want to add support for this in the CLI, we should use a
relevant library. The json schema validation that's here isn't correct
to the json spec, to the point where it needed to be replaced in unit
tests. Adding internal json schema validation doesn't add value here.
It is trivial to run jsonschema as a cli app, there's not a lot of
reason to keep it here and take up the binary space.
Change-Id: I076c8eb9f81c34cdfc40525fe940e8fba0f945b3
Signed-off-by: Ed Tanous <etanous@nvidia.com>
diff --git a/cli-app/cper-convert.c b/cli-app/cper-convert.c
index c2a73e4..33c7af7 100644
--- a/cli-app/cper-convert.c
+++ b/cli-app/cper-convert.c
@@ -14,8 +14,7 @@
#include <libcper/json-schema.h>
void cper_to_json(char *in_file, char *out_file, int is_single_section);
-void json_to_cper(char *in_file, char *out_file, char *specification_file,
- char *program_dir, int no_validate, int debug);
+void json_to_cper(char *in_file, char *out_file);
void print_help(void);
int main(int argc, char *argv[])
@@ -62,14 +61,17 @@
}
}
+ // Debug is not used at the moment. Leave for compatibility.
+ (void)debug;
+ (void)no_validate;
+ (void)specification_file;
//Run the requested command.
if (strcmp(argv[1], "to-json") == 0) {
cper_to_json(input_file, output_file, 0);
} else if (strcmp(argv[1], "to-json-section") == 0) {
cper_to_json(input_file, output_file, 1);
} else if (strcmp(argv[1], "to-cper") == 0) {
- json_to_cper(input_file, output_file, specification_file,
- argv[0], no_validate, debug);
+ json_to_cper(input_file, output_file);
} else {
printf("Unrecognised argument '%s'. See 'cper-convert --help' for command information.\n",
argv[1]);
@@ -124,8 +126,7 @@
}
//Command for converting a provided CPER-JSON JSON file to CPER binary.
-void json_to_cper(char *in_file, char *out_file, char *specification_file,
- char *program_dir, int no_validate, int debug)
+void json_to_cper(char *in_file, char *out_file)
{
//Verify output file exists.
if (out_file == NULL) {
@@ -141,47 +142,6 @@
return;
}
- //Validate the JSON against specification, unless otherwise specified.
- if (!no_validate) {
- int using_default_spec_path = 0;
-
- //Is there a specification file path?
- if (specification_file == NULL) {
- using_default_spec_path = 1;
-
- //Make the specification path the assumed default (application directory + specification/cper-json.json).
- specification_file = malloc(PATH_MAX);
- char *dir = dirname(program_dir);
- strcpy(specification_file, dir);
- strcat(specification_file,
- "/specification/cper-json.json");
- }
-
- //Enable debug mode if indicated.
- if (debug) {
- validate_schema_debug_enable();
- }
-
- //Attempt to verify with the the specification.
- char *error_message = malloc(JSON_ERROR_MSG_MAX_LEN);
- int success = validate_schema_from_file(specification_file, ir,
- error_message);
-
- //Free specification path (if necessary).
- if (using_default_spec_path) {
- free(specification_file);
- }
-
- //If failed, early exit before conversion.
- if (!success) {
- printf("JSON format validation failed: %s\n",
- error_message);
- free(error_message);
- return;
- }
- free(error_message);
- }
-
//Open a read for the output file.
FILE *cper_file = fopen(out_file, "w");
if (cper_file == NULL) {
diff --git a/include/libcper/json-schema.h b/include/libcper/json-schema.h
index 7dbbe48..4e0eebc 100644
--- a/include/libcper/json-schema.h
+++ b/include/libcper/json-schema.h
@@ -14,8 +14,6 @@
json_object *object, char *error_message);
int validate_schema_from_file(const char *schema_file, json_object *object,
char *error_message);
-void validate_schema_debug_enable();
-void validate_schema_debug_disable();
#ifdef __cplusplus
}
diff --git a/json-schema.c b/json-schema.c
deleted file mode 100644
index 9eb60be..0000000
--- a/json-schema.c
+++ /dev/null
@@ -1,478 +0,0 @@
-/**
- * A very basic, non-complete implementation of a validator for the JSON Schema specification,
- * for validating CPER-JSON.
- *
- * Author: Lawrence.Tang@arm.com
- **/
-
-#include <stdio.h>
-#include <string.h>
-#include <unistd.h>
-#include <libgen.h>
-#include <limits.h>
-#include <stdarg.h>
-#include <json.h>
-#include <libcper/json-schema.h>
-#include <libcper/BaseTypes.h>
-
-//Field definitions.
-int json_validator_debug = 0;
-
-//Private pre-definitions.
-int validate_field(const char *name, json_object *schema, json_object *object,
- char *error_message);
-int validate_integer(const char *field_name, json_object *schema,
- json_object *object, char *error_message);
-int validate_string(const char *field_name, json_object *schema,
- json_object *object, const char *error_message);
-int validate_object(const char *field_name, json_object *schema,
- json_object *object, char *error_message);
-int validate_array(const char *field_name, json_object *schema,
- json_object *object, char *error_message);
-void log_validator_error(char *error_message, const char *format, ...);
-void log_validator_debug(const char *format, ...);
-void log_validator_msg(const char *format, va_list args);
-
-//Validates a single JSON object against a provided schema file, returning 1 on success and 0 on failure to validate.
-//Error message space must be allocated prior to call.
-int validate_schema_from_file(const char *schema_file, json_object *object,
- char *error_message)
-{
- //Load schema IR from file.
- json_object *schema_ir = json_object_from_file(schema_file);
- if (schema_ir == NULL) {
- log_validator_error(error_message,
- "Failed to load schema from file '%s'.",
- schema_file);
- return 0;
- }
-
- //Get the directory of the file.
- char *schema_file_copy = malloc(strlen(schema_file) + 1);
- strcpy(schema_file_copy, schema_file);
- char *schema_dir = dirname(schema_file_copy);
-
- int result =
- validate_schema(schema_ir, schema_dir, object, error_message);
-
- //Free memory from directory call.
- free(schema_file_copy);
- json_object_put(schema_ir);
-
- return result;
-}
-
-//Validates a single JSON object against a provided schema, returning 1 on success and 0 on failure to validate.
-//Error message space must be allocated prior to call.
-//If the schema does not include any other sub-schemas using "$ref", then leaving schema_directory as NULL is valid.
-int validate_schema(json_object *schema, char *schema_directory,
- json_object *object, char *error_message)
-{
- //Check that the schema version is the same as this validator.
- json_object *schema_ver = json_object_object_get(schema, "$schema");
- if (schema_ver == NULL || strcmp(json_object_get_string(schema_ver),
- JSON_SCHEMA_VERSION) != 0) {
- log_validator_error(
- error_message,
- "Provided schema is not of the same version that is referenced by this validator, or is not a schema.");
- return 0;
- }
-
- //Change current directory into the schema directory.
- char *original_cwd = malloc(PATH_MAX);
- if (getcwd(original_cwd, PATH_MAX) == NULL) {
- log_validator_error(error_message,
- "Failed fetching the current directory.");
- if (original_cwd) {
- free(original_cwd);
- }
- return 0;
- }
- if (chdir(schema_directory)) {
- log_validator_error(error_message,
- "Failed to chdir into schema directory.");
- if (original_cwd) {
- free(original_cwd);
- }
- return 0;
- }
-
- //Parse the top level structure appropriately.
- int result = validate_field("parent", schema, object, error_message);
- if (result < 0) {
- log_validator_error(error_message,
- "Failed validating schema for parent.");
- result = 0;
- }
-
- //Change back to original CWD.
- if (chdir(original_cwd)) {
- log_validator_error(error_message,
- "Failed to chdir into original directory.");
- }
-
- free(original_cwd);
-
- if (result) {
- log_validator_debug(
- "Successfully validated the provided object against schema.");
- }
- return result;
-}
-
-//Validates a single JSON field given a schema/object.
-//Returns -1 on fatal/error failure, 0 on validation failure, and 1 on validation.
-int validate_field(const char *field_name, json_object *schema,
- json_object *object, char *error_message)
-{
- int ret = -1;
-
- log_validator_debug("Validating field '%s'...", field_name);
-
- //If there is a "$ref" field, attempt to load the referenced schema.
- json_object *ref_field = json_object_object_get(schema, "$ref");
- if (ref_field != NULL &&
- json_object_get_type(ref_field) == json_type_string) {
- log_validator_debug("$ref schema detected for field '%s'.",
- field_name);
-
- //Attempt to load. If loading fails, report error.
- const char *ref_path = json_object_get_string(ref_field);
- json_object *ref_schema = json_object_from_file(ref_path);
- if (ref_schema == NULL) {
- log_validator_error(
- error_message,
- "Failed to open referenced schema file '%s'.",
- ref_path);
- return -1;
- }
-
- log_validator_debug("loaded schema path '%s' for field '%s'.",
- ref_path, field_name);
-
- //Validate field with schema.
- ret = validate_field(field_name, ref_schema, object,
- error_message);
- json_object_put(ref_schema);
-
- return ret;
- }
-
- //Get the schema field type.
- json_object *desired_field_type =
- json_object_object_get(schema, "type");
- if (desired_field_type == NULL ||
- !json_object_is_type(desired_field_type, json_type_string)) {
- log_validator_error(
- error_message,
- "Desired field type not provided within schema/is not a string for field '%s' (schema violation).",
- field_name);
- return 0;
- }
-
- //Check the field types are actually equal.
- const char *desired_field_type_str =
- json_object_get_string(desired_field_type);
- if (!((!strcmp(desired_field_type_str, "object") &&
- json_object_is_type(object, json_type_object)) ||
- (!strcmp(desired_field_type_str, "array") &&
- json_object_is_type(object, json_type_array)) ||
- (!strcmp(desired_field_type_str, "integer") &&
- json_object_is_type(object, json_type_int)) ||
- (!strcmp(desired_field_type_str, "string") &&
- json_object_is_type(object, json_type_string)) ||
- (!strcmp(desired_field_type_str, "boolean") &&
- json_object_is_type(object, json_type_boolean)) ||
- (!strcmp(desired_field_type_str, "double") &&
- json_object_is_type(object, json_type_double)))) {
- log_validator_error(error_message,
- "Field type match failed for field '%s'.",
- field_name);
- return 0;
- }
-
- //If the schema contains a "oneOf" array, we need to validate the field against each of the
- //possible options in turn.
- json_object *one_of = json_object_object_get(schema, "oneOf");
- if (one_of != NULL && json_object_get_type(one_of) == json_type_array) {
- log_validator_debug("oneOf options detected for field '%s'.",
- field_name);
-
- int len = json_object_array_length(one_of);
- int validated = 0;
- for (int i = 0; i < len; i++) {
- //If the "oneOf" member isn't an object, warn on schema violation.
- json_object *one_of_option =
- json_object_array_get_idx(one_of, i);
- if (one_of_option == NULL ||
- json_object_get_type(one_of_option) !=
- json_type_object) {
- log_validator_debug(
- "Schema Warning: 'oneOf' member for field '%s' is not an object, schema violation.",
- field_name);
- continue;
- }
-
- //Validate field with schema.
- validated = validate_field(field_name, one_of_option,
- object, error_message);
- if (validated == -1) {
- return -1;
- }
- if (validated) {
- break;
- }
- }
-
- //Return if failed all checks.
- if (!validated) {
- log_validator_error(
- error_message,
- "No schema object structures matched provided object for field '%s'.",
- field_name);
- return 0;
- }
- }
-
- //Switch and validate each type in turn.
- switch (json_object_get_type(object)) {
- case json_type_int:
- return validate_integer(field_name, schema, object,
- error_message);
- case json_type_string:
- return validate_string(field_name, schema, object,
- error_message);
- case json_type_object:
- return validate_object(field_name, schema, object,
- error_message);
- case json_type_array:
- return validate_array(field_name, schema, object,
- error_message);
-
- //We don't perform extra validation on this type.
- default:
- log_validator_debug(
- "validation passed for '%s' (no extra validation).",
- field_name);
- return 1;
- }
-}
-
-//Validates a single integer value according to the given specification.
-int validate_integer(const char *field_name, json_object *schema,
- json_object *object, char *error_message)
-{
- //Is there a minimum/maximum specified? If so, check those.
- //Validate minimum.
- json_object *min_value = json_object_object_get(schema, "minimum");
- if (min_value != NULL &&
- json_object_is_type(min_value, json_type_int)) {
- int min_value_int = json_object_get_int(min_value);
- if (json_object_get_uint64(object) < (uint64_t)min_value_int) {
- log_validator_error(
- error_message,
- "Failed to validate integer field '%s'. Value was below minimum of %d.",
- field_name, min_value_int);
- return 0;
- }
- }
-
- //Validate maximum.
- json_object *max_value = json_object_object_get(schema, "maximum");
- if (max_value != NULL &&
- json_object_is_type(max_value, json_type_int)) {
- int max_value_int = json_object_get_int(max_value);
- if (json_object_get_uint64(object) > (uint64_t)max_value_int) {
- log_validator_error(
- error_message,
- "Failed to validate integer field '%s'. Value was above maximum of %d.",
- field_name, max_value_int);
- return 0;
- }
- }
-
- return 1;
-}
-
-//Validates a single string value according to the given specification.
-int validate_string(const char *field_name, json_object *schema,
- json_object *object, const char *error_message)
-{
- //todo: if there is a "pattern" field, verify the string with RegEx.
- (void)field_name;
- (void)schema;
- (void)object;
- (void)error_message;
-
- return 1;
-}
-
-//Validates a single object value according to the given specification.
-int validate_object(const char *field_name, json_object *schema,
- json_object *object, char *error_message)
-{
- //Are there a set of "required" fields? If so, check they all exist.
- json_object *required_fields =
- json_object_object_get(schema, "required");
- if (required_fields != NULL &&
- json_object_get_type(required_fields) == json_type_array) {
- log_validator_debug(
- "Required fields found for '%s', matching...",
- field_name);
-
- int len = json_object_array_length(required_fields);
- for (int i = 0; i < len; i++) {
- //Get the required field from schema.
- json_object *required_field =
- json_object_array_get_idx(required_fields, i);
- if (json_object_get_type(required_field) !=
- json_type_string) {
- log_validator_error(
- error_message,
- "Required field for object '%s' is not a string (schema violation).",
- field_name);
- return 0;
- }
-
- //Does it exist in the object?
- const char *required_field_str =
- json_object_get_string(required_field);
- if (json_object_object_get(
- object, required_field_str) == NULL) {
- log_validator_error(
- error_message,
- "Required field '%s' was not present in object '%s'.",
- required_field_str, field_name);
- return 0;
- }
- }
- }
-
- //Get additional properties value in advance.
- json_object *additional_properties =
- json_object_object_get(schema, "additionalProperties");
- int additional_properties_allowed = 0;
- if (additional_properties != NULL &&
- json_object_get_type(additional_properties) == json_type_boolean) {
- additional_properties_allowed =
- json_object_get_boolean(additional_properties);
- }
-
- //Run through the "properties" object and validate each of those in turn.
- json_object *properties = json_object_object_get(schema, "properties");
- if (properties != NULL &&
- json_object_get_type(properties) == json_type_object) {
- json_object_object_foreach(properties, key, value)
- {
- //If the given property name does not exist on the target object, ignore and continue next.
- json_object *object_prop =
- json_object_object_get(object, key);
- if (object_prop == NULL) {
- continue;
- }
-
- //Validate against the schema.
- if (!validate_field(key, value, object_prop,
- error_message)) {
- return 0;
- }
- }
-
- //If additional properties are banned, validate that no additional properties exist.
- if (!additional_properties_allowed) {
- json_object_object_foreach(object, key, value)
- {
- //Avoid compiler warning
- (void)value;
-
- //If the given property name does not exist on the schema object, fail validation.
- const json_object *schema_prop =
- json_object_object_get(properties, key);
- if (schema_prop == NULL) {
- log_validator_error(
- error_message,
- "Invalid additional property '%s' detected on field '%s'.",
- key, field_name);
- return 0;
- }
- }
- }
- }
-
- return 1;
-}
-
-//Validates a single array value according to the given specification.
-int validate_array(const char *field_name, json_object *schema,
- json_object *object, char *error_message)
-{
- //Iterate all items in the array, and validate according to the "items" schema.
- json_object *items_schema = json_object_object_get(schema, "items");
- if (items_schema != NULL &&
- json_object_get_type(items_schema) == json_type_object) {
- int array_len = json_object_array_length(object);
- for (int i = 0; i < array_len; i++) {
- if (!validate_field(field_name, items_schema,
- json_object_array_get_idx(object,
- i),
- error_message)) {
- return 0;
- }
- }
- }
-
- return 1;
-}
-
-//Enables/disables debugging globally for the JSON validator.
-void validate_schema_debug_enable()
-{
- json_validator_debug = 1;
-}
-void validate_schema_debug_disable()
-{
- json_validator_debug = 0;
-}
-
-//Logs an error message to the given error message location and (optionally) provides debug output.
-void log_validator_error(char *error_message, const char *format, ...)
-{
- va_list args;
-
- //Log error to error out.
- va_start(args, format);
- vsnprintf(error_message, JSON_ERROR_MSG_MAX_LEN, format, args);
- va_end(args);
-
- //Debug message if necessary.
- va_start(args, format);
- log_validator_msg(format, args);
- va_end(args);
-}
-
-//Logs a debug message to stdout, if validator debug is enabled.
-void log_validator_debug(const char *format, ...)
-{
- va_list args;
- va_start(args, format);
- log_validator_msg(format, args);
- va_end(args);
-}
-
-//Logs a single validator debug/error message.
-void log_validator_msg(const char *format, va_list args)
-{
- //Print debug output if debug is on.
- if (json_validator_debug) {
- //Make new format string for error.
- const char *header = "json_validator: ";
- char *new_format = malloc(strlen(header) + strlen(format) + 2);
- strcpy(new_format, header);
- strcat(new_format, format);
- strcat(new_format, "\n");
-
- //Print & free format.
- vfprintf(stdout, new_format, args);
- free(new_format);
- }
-}
diff --git a/meson.build b/meson.build
index 7f805eb..6a46f42 100644
--- a/meson.build
+++ b/meson.build
@@ -89,7 +89,6 @@
'cper-parse.c',
'cper-utils.c',
'ir-parse.c',
- 'json-schema.c',
)
libcper_include = ['include']