From 1afbb254a0997366f969bcb7e95e7f4ad291abc2 Mon Sep 17 00:00:00 2001 From: Timo Pollmeier Date: Tue, 30 Jul 2024 13:57:23 +0200 Subject: [PATCH 01/11] Add: Incremental JSON "pull" parser utils Functions and data structures for incrementally parsing JSON streams are added. These can be used to parse large files while limiting the memory usage similar to the streaming parser for XML. --- CMakeLists.txt | 2 +- util/CMakeLists.txt | 25 +- util/jsonpull.c | 954 ++++++++++++++++++++++++++++++++++++++++++ util/jsonpull.h | 129 ++++++ util/jsonpull_tests.c | 505 ++++++++++++++++++++++ 5 files changed, 1611 insertions(+), 4 deletions(-) create mode 100644 util/jsonpull.c create mode 100644 util/jsonpull.h create mode 100644 util/jsonpull_tests.c diff --git a/CMakeLists.txt b/CMakeLists.txt index 100da742..e9ad3b0d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -231,7 +231,7 @@ if (BUILD_TESTS AND NOT SKIP_SRC) DEPENDS array-test alivedetection-test boreas_error-test boreas_io-test cli-test cpeutils-test cvss-test ping-test sniffer-test util-test networking-test passwordbasedauthentication-test xmlutils-test version-test osp-test - nvti-test hosts-test) + nvti-test hosts-test jsonpull-test) endif (BUILD_TESTS AND NOT SKIP_SRC) diff --git a/util/CMakeLists.txt b/util/CMakeLists.txt index 95c94235..6b656306 100644 --- a/util/CMakeLists.txt +++ b/util/CMakeLists.txt @@ -42,6 +42,9 @@ pkg_check_modules (GPGME REQUIRED gpgme>=1.7.0) # for serverutils we need libgcrypt pkg_check_modules (GCRYPT REQUIRED libgcrypt) +# for json parsing we need cJSON +pkg_check_modules (CJSON REQUIRED libcjson>=1.7.14) + # for mqtt find_library(LIBPAHO paho-mqtt3c) message (STATUS "Looking for paho-mqtt3c ... ${LIBPAHO}") @@ -111,11 +114,11 @@ include_directories (${GLIB_INCLUDE_DIRS} ${GPGME_INCLUDE_DIRS} ${GCRYPT_INCLUDE set (FILES cpeutils.c passwordbasedauthentication.c compressutils.c fileutils.c gpgmeutils.c kb.c ldaputils.c nvticache.c mqtt.c radiusutils.c serverutils.c sshutils.c uuidutils.c - xmlutils.c) + xmlutils.c jsonpull.c) set (HEADERS cpeutils.h passwordbasedauthentication.h authutils.h compressutils.h fileutils.h gpgmeutils.h kb.h ldaputils.h nvticache.h mqtt.h radiusutils.h serverutils.h sshutils.h - uuidutils.h xmlutils.h) + uuidutils.h xmlutils.h jsonpull.h) if (BUILD_STATIC) add_library (gvm_util_static STATIC ${FILES}) @@ -137,13 +140,29 @@ if (BUILD_SHARED) ${RADIUS_LDFLAGS} ${LIBSSH_LDFLAGS} ${GNUTLS_LDFLAGS} ${GCRYPT_LDFLAGS} ${LDAP_LDFLAGS} ${REDIS_LDFLAGS} ${LIBXML2_LDFLAGS} ${UUID_LDFLAGS} - ${LINKER_HARDENING_FLAGS} ${CRYPT_LDFLAGS}) + ${LINKER_HARDENING_FLAGS} ${CRYPT_LDFLAGS} + ${CJSON_LDFLAGS}) endif (BUILD_SHARED) ## Tests if (BUILD_TESTS) + add_executable (jsonpull-test + EXCLUDE_FROM_ALL + jsonpull_tests.c) + + add_test (jsonpull-test jsonpull-test) + + target_include_directories (jsonpull-test PRIVATE ${CGREEN_INCLUDE_DIRS}) + + target_link_libraries (jsonpull-test ${CGREEN_LIBRARIES} + ${GLIB_LDFLAGS} ${CJSON_LDFLAGS}) + + add_custom_target (tests-jsonpull + DEPENDS jsonpull-test) + + add_executable (passwordbasedauthentication-test EXCLUDE_FROM_ALL passwordbasedauthentication_tests.c) diff --git a/util/jsonpull.c b/util/jsonpull.c new file mode 100644 index 00000000..a138db25 --- /dev/null +++ b/util/jsonpull.c @@ -0,0 +1,954 @@ +/* SPDX-FileCopyrightText: 2024 Greenbone AG + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +#include "jsonpull.h" +#include "assert.h" + +#define GVM_JSON_CHAR_EOF -1 ///< End of file +#define GVM_JSON_CHAR_ERROR -2 ///< Error reading file +#define GVM_JSON_CHAR_UNDEFINED -3 ///< Undefined state + +/** + * @brief Creates a new JSON path element. + * + * @param[in] parent_type Type of the parent (array, object, none/root) + * @param[in] depth The depth in the document tree + * + * @return The newly allocated path element + */ +gvm_json_path_elem_t * +gvm_json_pull_path_elem_new (gvm_json_pull_container_type_t parent_type, + int depth) +{ + gvm_json_path_elem_t *new_elem = g_malloc0 (sizeof (gvm_json_path_elem_t)); + new_elem->parent_type = parent_type; + new_elem->depth = depth; + return new_elem; +} + +/** + * @brief Frees a JSON path element. + * + * @param[in] elem The element to free + */ +void +gvm_json_pull_path_elem_free (gvm_json_path_elem_t *elem) +{ + g_free (elem->key); + g_free (elem); +} + +/** + * @brief Initializes a JSON pull event data structure. + * + * @param[in] event The event structure to initialize + */ +void +gvm_json_pull_event_init (gvm_json_pull_event_t *event) +{ + memset (event, 0, sizeof(gvm_json_pull_event_t)); +} + +/** + * @brief Resets a JSON pull event data structure for reuse. + * + * @param[in] event The event structure to reset + */ +void +gvm_json_pull_event_reset (gvm_json_pull_event_t *event) +{ + cJSON_free (event->value); + memset (event, 0, sizeof(gvm_json_pull_event_t)); +} + +/** + * @brief Frees all data of JSON pull event data structure. + * + * @param[in] event The event structure to clean up + */ +void +gvm_json_pull_event_cleanup (gvm_json_pull_event_t *event) +{ + cJSON_free (event->value); + memset (event, 0, sizeof(gvm_json_pull_event_t)); +} + +/** + * @brief Initializes a JSON pull parser. + * + * @param[in] parser The parser data structure to initialize + * @param[in] input_stream The JSON input stream + * @param[in] parse_buffer_limit Maximum buffer size for parsing values + * @param[in] read_buffer_size Buffer size for reading from the stream + */ +void +gvm_json_pull_parser_init_full (gvm_json_pull_parser_t *parser, + FILE *input_stream, + size_t parse_buffer_limit, + size_t read_buffer_size) +{ + assert(parser); + assert (input_stream); + memset (parser, 0, sizeof(gvm_json_pull_parser_t)); + + if (parse_buffer_limit <= 0) + parse_buffer_limit = GVM_JSON_PULL_PARSE_BUFFER_LIMIT; + + if (read_buffer_size <= 0) + read_buffer_size = GVM_JSON_PULL_READ_BUFFER_SIZE; + + parser->input_stream = input_stream; + parser->path = g_queue_new (); + parser->expect = GVM_JSON_PULL_EXPECT_VALUE; + parser->parse_buffer_limit = parse_buffer_limit; + parser->parse_buffer = g_string_new (""); + parser->read_buffer_size = read_buffer_size; + parser->read_buffer = g_malloc0(read_buffer_size); + parser->last_read_char = GVM_JSON_CHAR_UNDEFINED; +} + +/** + * @brief Initializes a JSON pull parser with default buffer sizes. + * + * @param[in] parser The parser data structure to initialize + * @param[in] input_stream The JSON input stream + */ +void +gvm_json_pull_parser_init (gvm_json_pull_parser_t *parser, + FILE *input_stream) +{ + gvm_json_pull_parser_init_full (parser, input_stream, 0, 0); +} + +/** + * @brief Frees the data of a JSON pull parser. + * + * @param[in] parser The parser data structure to free the data of + */ +void +gvm_json_pull_parser_cleanup (gvm_json_pull_parser_t *parser) +{ + assert(parser); + g_queue_free_full (parser->path, + (GDestroyNotify) gvm_json_pull_path_elem_free); + g_string_free (parser->parse_buffer, TRUE); + g_free (parser->read_buffer); + memset (parser, 0, sizeof(gvm_json_pull_parser_t)); +} + +/** + * @brief Generates message for an error that occurred reading the JSON stream. + * + * @return The newly allocated error message + */ +static gchar * +gvm_json_read_stream_error_str () +{ + return g_strdup_printf ("error reading JSON stream: %s", strerror (errno)); +} + +/** + * @brief Checks if the parse buffer limit of a JSON pull parser is reached. + * + * @param[in] value_type The value type to include in the error message + * @param[in] parser The parser to check the parse buffer of + * @param[in] event Event data for error status and message if needed + * + * @return 0 if buffer size is okay, 1 if limit was reached + */ +static int +gvm_json_pull_check_parse_buffer_size (const char *value_type, + gvm_json_pull_parser_t *parser, + gvm_json_pull_event_t *event) +{ + if (parser->parse_buffer->len >= parser->parse_buffer_limit) + { + event->error_message + = g_strdup_printf ("%s exceeds size limit of %zu bytes", + value_type, + parser->parse_buffer_limit); + event->type = GVM_JSON_PULL_EVENT_ERROR; + return 1; + } + return 0; +} + +/** + * @brief Reads the next character in a pull parser input stream. + * + * @return The character code, GVM_JSON_CHAR_ERROR or GVM_JSON_CHAR_EOF. + */ +static int +gvm_json_pull_parser_next_char (gvm_json_pull_parser_t *parser) +{ + parser->read_pos++; + if (parser->read_pos < parser->last_read_size) + { + parser->last_read_char + = (unsigned char) parser->read_buffer[parser->read_pos]; + return parser->last_read_char; + } + else + { + parser->read_pos = 0; + parser->last_read_size = fread (parser->read_buffer, + 1, + parser->read_buffer_size, + parser->input_stream); + if (ferror (parser->input_stream)) + parser->last_read_char = GVM_JSON_CHAR_ERROR; + else if (parser->last_read_size <= 0) + parser->last_read_char = GVM_JSON_CHAR_EOF; + else + parser->last_read_char + = (unsigned char) parser->read_buffer[parser->read_pos]; + return parser->last_read_char; + } +} + +/** + * @brief Tries to parse the buffer content of a JSON pull parser. + * + * @param[in] parser The parser to use the parse buffer of + * @param[in] event Event set error of if necessary + * @param[in] value_name Name of the value for error message if needed + * @param[in] validate_func Function for validating the parsed value + * @param[out] cjson_value Return of the parsed cJSON object on success + * + * @return 0 success, 1 error + */ +static int +gvm_json_pull_parse_buffered (gvm_json_pull_parser_t *parser, + gvm_json_pull_event_t *event, + const char *value_name, + cJSON_bool (*validate_func)(const cJSON* const), + cJSON **cjson_value) +{ + cJSON* parsed_value = cJSON_Parse (parser->parse_buffer->str); + *cjson_value = NULL; + if (validate_func (parsed_value) == 0) + { + event->type = GVM_JSON_PULL_EVENT_ERROR; + event->error_message + = g_strdup_printf ("error parsing %s", value_name); + cJSON_free (parsed_value); + return 1; + } + *cjson_value = parsed_value; + return 0; +} + +/** + * @brief Handles error or EOF after reading a character in JSON pull parser. + * + * @param[in] parser Parser to get the last read character from + * @param[in] event Event data to set EOF or error status in + * @param[in] allow_eof Whether to allow EOF, generate error on EOF if FALSE + */ +static void +gvm_json_pull_handle_read_end (gvm_json_pull_parser_t *parser, + gvm_json_pull_event_t *event, + gboolean allow_eof) +{ + if (parser->last_read_char == GVM_JSON_CHAR_ERROR) + { + event->error_message = gvm_json_read_stream_error_str (); + event->type = GVM_JSON_PULL_EVENT_ERROR; + } + else if (allow_eof) + event->type = GVM_JSON_PULL_EVENT_EOF; + else + { + event->error_message = g_strdup ("unexpected EOF"); + event->type = GVM_JSON_PULL_EVENT_ERROR; + } +} + +/** + * @brief Skips whitespaces in the input stream of a JSON pull parser + * + * The parser will be at the first non-whitespace character on success. + * + * @param[in] parser Parser to skip the whitespaces in + * @param[in] event Event data to set EOF or error status in + * @param[in] allow_eof Whether to allow EOF, generate error on EOF if FALSE + * + * @return 1 if EOF was reached or an error occurred, 0 otherwise + */ +static int +gvm_json_pull_skip_space (gvm_json_pull_parser_t *parser, + gvm_json_pull_event_t *event, + gboolean allow_eof) +{ + while (g_ascii_isspace (parser->last_read_char)) + gvm_json_pull_parser_next_char (parser); + if (parser->last_read_char < 0) + { + gvm_json_pull_handle_read_end (parser, event, allow_eof); + return 1; + } + return 0; +} + +/** + * @brief Parses a string in a JSON pull parser. + * + * The parser is expected to be at the opening quote mark and will be at the + * character after the closing quote mark on success. + * + * @param[in] parser Parser to handle the string value in + * @param[in] event Event data to set EOF or error status in + * @param[out] cjson_value The cJSON value for the string on success + * + * @return 1 if an error occurred (including EOF), 0 otherwise + */ +static int +gvm_json_pull_parse_string (gvm_json_pull_parser_t *parser, + gvm_json_pull_event_t *event, + cJSON **cjson_value) +{ + gboolean escape_next_char = FALSE; + g_string_truncate (parser->parse_buffer, 0); + g_string_append_c (parser->parse_buffer, '"'); + while (gvm_json_pull_parser_next_char (parser) >= 0) + { + if (gvm_json_pull_check_parse_buffer_size ("string", parser, event)) + return 1; + g_string_append_c (parser->parse_buffer, parser->last_read_char); + if (escape_next_char) + escape_next_char = FALSE; + else if (parser->last_read_char == '\\') + escape_next_char = TRUE; + else if (parser->last_read_char == '"') + break; + } + + if (parser->last_read_char < 0) + { + gvm_json_pull_handle_read_end (parser, event, FALSE); + return 1; + } + + gvm_json_pull_parser_next_char (parser); + + return gvm_json_pull_parse_buffered (parser, + event, + "string", + cJSON_IsString, + cjson_value); +} + +/** + * @brief Parses a number in a JSON pull parser. + * + * The parser is expected to be at the first character of the number and will + * be at the first non-number character on success. + * + * @param[in] parser Parser to handle the number value in + * @param[in] event Event data to set EOF or error status in + * @param[out] cjson_value The cJSON value for the number on success. + * + * @return 1 if an error occurred, 0 otherwise + */ +static int +gvm_json_pull_parse_number (gvm_json_pull_parser_t *parser, + gvm_json_pull_event_t *event, + cJSON **cjson_value) +{ + g_string_truncate (parser->parse_buffer, 0); + g_string_append_c (parser->parse_buffer, parser->last_read_char); + while (gvm_json_pull_parser_next_char (parser) >= 0) + { + if (gvm_json_pull_check_parse_buffer_size ("number", parser, event)) + return 1; + if (g_ascii_isdigit (parser->last_read_char) + || parser->last_read_char == '.' + || parser->last_read_char == 'e' + || parser->last_read_char == '-' + || parser->last_read_char == '+') + g_string_append_c (parser->parse_buffer, parser->last_read_char); + else + break; + } + + if (parser->last_read_char == GVM_JSON_CHAR_ERROR) + { + event->error_message = gvm_json_read_stream_error_str (); + event->type = GVM_JSON_PULL_EVENT_ERROR; + return 1; + } + + return gvm_json_pull_parse_buffered (parser, + event, + "number", + cJSON_IsNumber, + cjson_value); +} + +/** + * @brief Parses a keyword value in a JSON pull parser. + * + * The parser is expected to be at the first character of the keyword and will + * be at the first character after the keyword on success. + * + * @param[in] parser Parser to handle the keyword value in + * @param[in] event Event data to set EOF or error status in + * @param[in] keyword The expected keyword, e.g. "null", "true", "false". + * + * @return 1 if an error occurred, 0 otherwise + */ +static int +gvm_json_pull_parse_keyword (gvm_json_pull_parser_t *parser, + gvm_json_pull_event_t *event, + const char *keyword) +{ + for (size_t i = 0; i < strlen(keyword); i++) + { + if (parser->last_read_char < 0) + { + gvm_json_pull_handle_read_end (parser, event, FALSE); + return 1; + } + else if (parser->last_read_char != keyword[i]) + { + event->type = GVM_JSON_PULL_EVENT_ERROR; + event->error_message + = g_strdup_printf ("misspelled keyword '%s'", keyword); + return 1; + } + gvm_json_pull_parser_next_char (parser); + } + return 0; +} + +#define PARSE_VALUE_NEXT_EXPECT \ + if (parser->path->length) \ + parser->expect = GVM_JSON_PULL_EXPECT_COMMA; \ + else \ + parser->expect = GVM_JSON_PULL_EXPECT_EOF; + +/** + * @brief Handles the case that an object key is expected in a JSON pull parser. + * + * This will continue the parsing until the value is expected, the end of the + * current object was reached or an error occurred. + * + * @param[in] parser Parser to process + * @param[in] event Event data to set error or end of object status in + * + * @return 1 if an error occurred, 0 otherwise + */ +static int +gvm_json_pull_parse_key (gvm_json_pull_parser_t *parser, + gvm_json_pull_event_t *event) +{ + if (gvm_json_pull_skip_space (parser, event, FALSE)) + return 1; + + cJSON *key_cjson = NULL; + gchar *key_str; + gvm_json_path_elem_t *path_elem; + + switch (parser->last_read_char) + { + case '"': + if (gvm_json_pull_parse_string (parser, event, &key_cjson)) + return 1; + key_str = g_strdup (key_cjson->valuestring); + cJSON_free (key_cjson); + + // Expect colon: + if (gvm_json_pull_skip_space (parser, event, FALSE)) + { + g_free (key_str); + return 1; + } + if (parser->last_read_char != ':') + { + event->type = GVM_JSON_PULL_EVENT_ERROR; + event->error_message = g_strdup_printf ("expected colon, got '%c'", parser->last_read_char); + g_free (key_str); + return 1; + } + gvm_json_pull_parser_next_char (parser); + + path_elem = g_queue_peek_tail (parser->path); + g_free (path_elem->key); + path_elem->key = key_str; + parser->expect = GVM_JSON_PULL_EXPECT_VALUE; + + break; + case '}': + path_elem = g_queue_peek_tail (parser->path); + if (path_elem == NULL + || path_elem->parent_type != GVM_JSON_PULL_CONTAINER_OBJECT) + { + event->type = GVM_JSON_PULL_EVENT_ERROR; + event->error_message = g_strdup ("unexpected closing curly brace"); + return 1; + } + event->type = GVM_JSON_PULL_EVENT_OBJECT_END; + event->value = NULL; + gvm_json_pull_path_elem_free (g_queue_pop_tail (parser->path)); + PARSE_VALUE_NEXT_EXPECT + gvm_json_pull_parser_next_char (parser); + break; + } + + return 0; +} + +/** + * @brief Handles the case that a comma is expected in a JSON pull parser. + * + * This will continue the parsing until a comma or the end of the + * current array/object was reached or an error occurred. + * + * @param[in] parser Parser to process + * @param[in] event Event data to set error or end of object status in + * + * @return 1 if an error occurred, 0 otherwise + */ +static int +gvm_json_pull_parse_comma (gvm_json_pull_parser_t *parser, + gvm_json_pull_event_t *event) +{ + if (gvm_json_pull_skip_space (parser, event, FALSE)) + return 1; + + gvm_json_path_elem_t *path_elem = NULL; + switch (parser->last_read_char) + { + case ',': + path_elem = g_queue_peek_tail (parser->path); + path_elem->index ++; + if (path_elem->parent_type == GVM_JSON_PULL_CONTAINER_OBJECT) + parser->expect = GVM_JSON_PULL_EXPECT_KEY; + else + parser->expect = GVM_JSON_PULL_EXPECT_VALUE; + gvm_json_pull_parser_next_char (parser); + break; + case ']': + path_elem = g_queue_peek_tail (parser->path); + if (path_elem == NULL + || path_elem->parent_type != GVM_JSON_PULL_CONTAINER_ARRAY) + { + event->type = GVM_JSON_PULL_EVENT_ERROR; + event->error_message = g_strdup ("unexpected closing square bracket"); + return 1; + } + event->type = GVM_JSON_PULL_EVENT_ARRAY_END; + event->value = NULL; + gvm_json_pull_path_elem_free (g_queue_pop_tail (parser->path)); + PARSE_VALUE_NEXT_EXPECT + gvm_json_pull_parser_next_char (parser); + break; + case '}': + path_elem = g_queue_peek_tail (parser->path); + if (path_elem == NULL + || path_elem->parent_type != GVM_JSON_PULL_CONTAINER_OBJECT) + { + event->type = GVM_JSON_PULL_EVENT_ERROR; + event->error_message = g_strdup ("unexpected closing curly brace"); + return 1; + } + event->type = GVM_JSON_PULL_EVENT_OBJECT_END; + event->value = NULL; + gvm_json_pull_path_elem_free (g_queue_pop_tail (parser->path)); + PARSE_VALUE_NEXT_EXPECT + gvm_json_pull_parser_next_char (parser); + break; + default: + event->error_message = g_strdup ("expected comma or end of container"); + event->type = GVM_JSON_PULL_EVENT_ERROR; + return 1; + } + return 0; +} + +/** + * @brief Handles the case that a value in a JSON pull parser. + * + * This will continue the parsing until a value or the end of the + * current array/object was parsed or an error occurred. + * + * @param[in] parser Parser to process + * @param[in] event Event data to set error or end of object status in + * + * @return 1 if an error occurred, 0 otherwise + */ +static int +gvm_json_pull_parse_value (gvm_json_pull_parser_t *parser, + gvm_json_pull_event_t *event) +{ + if (gvm_json_pull_skip_space (parser, event, FALSE)) + return 1; + + cJSON *cjson_value = NULL; + gvm_json_path_elem_t *path_elem = NULL; + + switch (parser->last_read_char) + { + case '"': + if (gvm_json_pull_parse_string (parser, event, &cjson_value)) + return 1; + event->type = GVM_JSON_PULL_EVENT_STRING; + event->value = cjson_value; + PARSE_VALUE_NEXT_EXPECT + break; + case 'n': + if (gvm_json_pull_parse_keyword (parser, event, "null")) + return 1; + event->type = GVM_JSON_PULL_EVENT_NULL; + event->value = cJSON_CreateNull (); + PARSE_VALUE_NEXT_EXPECT + break; + case 'f': + if (gvm_json_pull_parse_keyword (parser, event, "false")) + return 1; + event->type = GVM_JSON_PULL_EVENT_BOOLEAN; + event->value = cJSON_CreateFalse (); + PARSE_VALUE_NEXT_EXPECT + break; + case 't': + if (gvm_json_pull_parse_keyword (parser, event, "true")) + return 1; + event->type = GVM_JSON_PULL_EVENT_BOOLEAN; + event->value = cJSON_CreateTrue (); + PARSE_VALUE_NEXT_EXPECT + break; + case '[': + event->type = GVM_JSON_PULL_EVENT_ARRAY_START; + event->value = NULL; + parser->path_add + = gvm_json_pull_path_elem_new (GVM_JSON_PULL_CONTAINER_ARRAY, + parser->path->length); + parser->expect = GVM_JSON_PULL_EXPECT_VALUE; + gvm_json_pull_parser_next_char (parser); + break; + case ']': + path_elem = g_queue_peek_tail (parser->path); + if (path_elem == NULL + || path_elem->parent_type != GVM_JSON_PULL_CONTAINER_ARRAY) + { + event->type = GVM_JSON_PULL_EVENT_ERROR; + event->error_message = g_strdup ("unexpected closing square bracket"); + return 1; + } + event->type = GVM_JSON_PULL_EVENT_ARRAY_END; + event->value = NULL; + gvm_json_pull_path_elem_free (g_queue_pop_tail (parser->path)); + PARSE_VALUE_NEXT_EXPECT + gvm_json_pull_parser_next_char (parser); + break; + case '{': + event->type = GVM_JSON_PULL_EVENT_OBJECT_START; + event->value = NULL; + parser->path_add + = gvm_json_pull_path_elem_new (GVM_JSON_PULL_CONTAINER_OBJECT, + parser->path->length); + parser->expect = GVM_JSON_PULL_EXPECT_KEY; + gvm_json_pull_parser_next_char (parser); + break; + case '}': + path_elem = g_queue_peek_tail (parser->path); + if (path_elem == NULL + || path_elem->parent_type != GVM_JSON_PULL_CONTAINER_OBJECT) + { + event->type = GVM_JSON_PULL_EVENT_ERROR; + event->error_message = g_strdup ("unexpected closing curly brace"); + return 1; + } + event->type = GVM_JSON_PULL_EVENT_OBJECT_END; + event->value = NULL; + gvm_json_pull_path_elem_free (g_queue_pop_tail (parser->path)); + PARSE_VALUE_NEXT_EXPECT + gvm_json_pull_parser_next_char (parser); + break; + default: + if (g_ascii_isdigit (parser->last_read_char) + || parser->last_read_char == '-') + { + if (gvm_json_pull_parse_number (parser, event, &cjson_value)) + return 1; + event->type = GVM_JSON_PULL_EVENT_NUMBER; + event->value = cjson_value; + PARSE_VALUE_NEXT_EXPECT + } + else + { + event->type = GVM_JSON_PULL_EVENT_ERROR; + event->error_message = g_strdup ("unexpected character"); + return 1; + } + } + return 0; +} + +/** + * @brief Get the next event from a JSON pull parser. + * + * Note: This invalidates previous event data like the cJSON value. + * + * @param[in] parser The JSON pull parser to process until the next event + * @param[in] event Structure to store event data in. + */ +void +gvm_json_pull_parser_next (gvm_json_pull_parser_t *parser, + gvm_json_pull_event_t *event) +{ + assert (parser); + assert (event); + + gvm_json_pull_event_reset (event); + if (parser->last_read_char == GVM_JSON_CHAR_UNDEFINED) + { + // Handle first read of the stream + if (gvm_json_pull_parser_next_char (parser) < 0) + { + gvm_json_pull_handle_read_end (parser, event, TRUE); + return; + } + } + event->path = parser->path; + + // Delayed addition to path after a container start element + if (parser->path_add) + { + g_queue_push_tail (parser->path, parser->path_add); + parser->path_add = NULL; + } + + // Check for expected end of file + if (parser->expect == GVM_JSON_PULL_EXPECT_EOF) + { + if (gvm_json_pull_skip_space (parser, event, TRUE) == GVM_JSON_CHAR_ERROR) + return; + + if (parser->last_read_char != GVM_JSON_CHAR_EOF) + { + event->type = GVM_JSON_PULL_EVENT_ERROR; + event->error_message + = g_strdup_printf ("unexpected character at end of file (%d)", + parser->last_read_char); + return; + } + return; + } + + if (parser->expect == GVM_JSON_PULL_EXPECT_KEY) + { + if (gvm_json_pull_parse_key (parser, event)) + return; + } + + if (parser->expect == GVM_JSON_PULL_EXPECT_COMMA) + { + if (gvm_json_pull_parse_comma (parser, event)) + return; + } + + if (parser->expect == GVM_JSON_PULL_EXPECT_KEY) + { + if (gvm_json_pull_parse_key (parser, event)) + return; + } + + if (parser->expect == GVM_JSON_PULL_EXPECT_VALUE) + { + gvm_json_pull_parse_value (parser, event); + } +} + +/** + * @brief Expands the current array or object of a JSON pull parser. + * + * This should be called after an array or object start event. + * + * @param[in] parser Parser to get the current container element from + * @param[out] error_message Error message output + * + * @return The expanded container as a cJSON object if successful, else NULL + */ +cJSON * +gvm_json_pull_expand_container (gvm_json_pull_parser_t *parser, + gchar **error_message) +{ + gvm_json_path_elem_t *path_tail; + + int start_depth; + gboolean in_string, escape_next_char, in_expanded_container; + cJSON *expanded; + + g_string_truncate (parser->parse_buffer, 0); + + if (error_message) + *error_message = NULL; + + if (parser->path_add) + { + path_tail = parser->path_add; + g_queue_push_tail (parser->path, path_tail); + parser->path_add = NULL; + } + else + path_tail = g_queue_peek_tail (parser->path); + + if (path_tail + && path_tail->parent_type == GVM_JSON_PULL_CONTAINER_ARRAY) + g_string_append_c (parser->parse_buffer, '['); + else if (path_tail + && path_tail->parent_type == GVM_JSON_PULL_CONTAINER_OBJECT) + g_string_append_c (parser->parse_buffer, '{'); + else + { + if (error_message) + *error_message + = g_strdup ("can only expand after array or object start"); + return NULL; + } + + start_depth = path_tail->depth; + in_string = escape_next_char = FALSE; + in_expanded_container = TRUE; + + while (parser->last_read_char >= 0 && in_expanded_container) + { + if (parser->parse_buffer->len >= parser->parse_buffer_limit) + { + if (error_message) + *error_message + = g_strdup_printf ("container exceeds size limit of %zu bytes", + parser->parse_buffer_limit); + return NULL; + } + + g_string_append_c (parser->parse_buffer, parser->last_read_char); + + if (escape_next_char) + { + escape_next_char = FALSE; + } + else if (in_string) + { + escape_next_char = (parser->last_read_char == '\\'); + in_string = (parser->last_read_char != '"'); + } + else + { + switch (parser->last_read_char) + { + case '"': + in_string = TRUE; + break; + case '[': + path_tail + = gvm_json_pull_path_elem_new (GVM_JSON_PULL_CONTAINER_ARRAY, + parser->path->length); + g_queue_push_tail (parser->path, path_tail); + break; + case '{': + path_tail + = gvm_json_pull_path_elem_new (GVM_JSON_PULL_CONTAINER_OBJECT, + parser->path->length); + g_queue_push_tail (parser->path, path_tail); + break; + case ']': + path_tail = g_queue_pop_tail (parser->path); + if (path_tail->parent_type != GVM_JSON_PULL_CONTAINER_ARRAY) + { + if (error_message) + *error_message = g_strdup ("unexpected ']'"); + return NULL; + } + if (path_tail->depth == start_depth) + in_expanded_container = FALSE; + break; + case '}': + path_tail = g_queue_pop_tail (parser->path); + if (path_tail->parent_type != GVM_JSON_PULL_CONTAINER_OBJECT) + { + if (error_message) + *error_message = g_strdup ("unexpected '}'"); + return NULL; + } + if (path_tail->depth == start_depth) + in_expanded_container = FALSE; + break; + } + } + gvm_json_pull_parser_next_char (parser); + } + + if (parser->last_read_char == GVM_JSON_CHAR_ERROR) + { + if (error_message) + *error_message = gvm_json_read_stream_error_str (); + return NULL; + } + else if (in_expanded_container && parser->last_read_char == GVM_JSON_CHAR_EOF) + { + if (error_message) + *error_message = g_strdup ("unexpected EOF"); + return NULL; + } + + expanded = cJSON_Parse (parser->parse_buffer->str); + g_string_truncate (parser->parse_buffer, 0); + PARSE_VALUE_NEXT_EXPECT + + if (expanded == NULL && error_message) + *error_message = g_strdup ("could not parse expanded container"); + + return expanded; +} + +/** + * @brief Appends a string path element to a JSONPath string. + * + * @param[in] path_elem The path element to append + * @param[in] path_string The path string to append to + */ +static void +gvm_json_path_string_add_elem (gvm_json_path_elem_t *path_elem, + GString *path_string) +{ + if (path_elem->parent_type == GVM_JSON_PULL_CONTAINER_OBJECT) + { + char *point = path_elem->key; + g_string_append (path_string, "['"); + while (point && *point) + { + if (*point == '\\' || *point == '\'') + g_string_append_c (path_string, '\\'); + g_string_append_c (path_string, *point); + point ++; + } + g_string_append (path_string, "']"); + } + else + g_string_append_printf (path_string, "[%d]", path_elem->index); +} + +/** + * @brief Converts a path as used by a JSON pull parser to a JSONPath string. + * + * @param[in] path The path to convert + * + * @return Newly allocated string of the path in JSONPath bracket notation + */ +gchar * +gvm_json_path_to_string (GQueue *path) +{ + GString *path_string = g_string_new ("$"); + g_queue_foreach (path, + (GFunc) gvm_json_path_string_add_elem, + path_string); + return g_string_free (path_string, FALSE); +} + +#undef CASE_SPACES +#undef GVM_JSON_EOF +#undef GVM_JSON_ERROR \ No newline at end of file diff --git a/util/jsonpull.h b/util/jsonpull.h new file mode 100644 index 00000000..82850f2f --- /dev/null +++ b/util/jsonpull.h @@ -0,0 +1,129 @@ +/* SPDX-FileCopyrightText: 2024 Greenbone AG + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + + +#ifndef _GVM_JSONPULL_H +#define _GVM_JSONPULL_H + +#include +#include +#include + +/** + * @brief Type of container the parser is currently in + */ +typedef enum { + GVM_JSON_PULL_CONTAINER_NONE = 0, ///< No container / document root + GVM_JSON_PULL_CONTAINER_ARRAY, ///< Array + GVM_JSON_PULL_CONTAINER_OBJECT, ///< Object +} gvm_json_pull_container_type_t; + +/** + * @brief Path element types for the JSON pull parser. + */ +typedef struct gvm_json_path_elem { + gvm_json_pull_container_type_t parent_type; ///< parent container type + int index; ///< Index of the element within the parent + char *key; ///< Key if element is in an object + int depth; ///< Number of ancestor elements +} gvm_json_path_elem_t; + +/** + * @brief Event types for the JSON pull parser + */ +typedef enum { + GVM_JSON_PULL_EVENT_UNDEFINED = 0, + GVM_JSON_PULL_EVENT_ARRAY_START, + GVM_JSON_PULL_EVENT_ARRAY_END, + GVM_JSON_PULL_EVENT_OBJECT_START, + GVM_JSON_PULL_EVENT_OBJECT_END, + GVM_JSON_PULL_EVENT_STRING, + GVM_JSON_PULL_EVENT_NUMBER, + GVM_JSON_PULL_EVENT_BOOLEAN, + GVM_JSON_PULL_EVENT_NULL, + GVM_JSON_PULL_EVENT_EOF, + GVM_JSON_PULL_EVENT_ERROR, +} gvm_json_pull_event_type_t; + +/** + * @brief Event generated by the JSON pull parser. + */ +typedef struct { + gvm_json_pull_event_type_t type; ///< Type of event + GQueue *path; ///< Path to the event value + cJSON *value; ///< Value for non-container value events + gchar *error_message; ///< Error message, NULL on success +} gvm_json_pull_event_t; + +/** + * @brief Expected token state for the JSON pull parser + */ +typedef enum { + GVM_JSON_PULL_EXPECT_UNDEFINED = 0, ///< Undefined state + GVM_JSON_PULL_EXPECT_VALUE, ///< Expect start of a value + GVM_JSON_PULL_EXPECT_KEY, ///< Expect start of a key + GVM_JSON_PULL_EXPECT_COMMA, ///< Expect comma or container end brace + GVM_JSON_PULL_EXPECT_EOF ///< Expect end of file +} gvm_json_pull_expect_t; + +#define GVM_JSON_PULL_PARSE_BUFFER_LIMIT 10485760 + +#define GVM_JSON_PULL_READ_BUFFER_SIZE 4096 + +/** + * @brief A json pull parser + */ +typedef struct { + GQueue *path; ///< Path to the current value + gvm_json_path_elem_t *path_add; ///< Path elem to add in next step + gvm_json_pull_expect_t expect; ///< Current expected token + int keyword_pos; ///< Position in a keyword like "true" or "null" + FILE *input_stream; ///< Input stream + char *read_buffer; ///< Stream reading buffer + size_t read_buffer_size; ///< Size of the stream reading buffer + size_t last_read_size; ///< Size of last stream read + int last_read_char; ///< Character last read from stream + size_t read_pos; ///< Position in current read + GString *parse_buffer; ///< Buffer for parsing values and object keys + size_t parse_buffer_limit; ///< Maximum parse buffer size +} gvm_json_pull_parser_t; + +gvm_json_path_elem_t * +gvm_json_pull_path_elem_new (gvm_json_pull_container_type_t, int); + +void +gvm_json_pull_path_elem_free (gvm_json_path_elem_t *); + +void +gvm_json_pull_event_init (gvm_json_pull_event_t *); + +void +gvm_json_pull_event_reset (gvm_json_pull_event_t *); + +void +gvm_json_pull_event_cleanup (gvm_json_pull_event_t *); + +void +gvm_json_pull_parser_init_full (gvm_json_pull_parser_t *, FILE *, + size_t, size_t); + +void +gvm_json_pull_parser_init (gvm_json_pull_parser_t *, FILE *); + +void +gvm_json_pull_parser_cleanup (gvm_json_pull_parser_t *); + +void gvm_json_pull_parser_next(gvm_json_pull_parser_t*, + gvm_json_pull_event_t*); + +cJSON * +gvm_json_pull_expand_container (gvm_json_pull_parser_t *, + gchar **); + +gchar * +gvm_json_path_to_string (GQueue *path); + + +#endif /* _GVM_JSONPULL_H */ \ No newline at end of file diff --git a/util/jsonpull_tests.c b/util/jsonpull_tests.c new file mode 100644 index 00000000..edf1290e --- /dev/null +++ b/util/jsonpull_tests.c @@ -0,0 +1,505 @@ +/* SPDX-FileCopyrightText: 2019-2023 Greenbone AG + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +#include "jsonpull.c" + +#include +#include + +Describe (jsonpull); +BeforeEach (jsonpull) +{ +} +AfterEach (jsonpull) +{ +} + + +/* + * Helper function to open a string as a read-only stream. + */ +static inline FILE * +fstropen_r (const char *str) +{ + return fmemopen ((void*)str, strlen(str), "r"); +} + +#define INIT_JSON_PARSER(json_string) \ + gvm_json_pull_event_t event; \ + gvm_json_pull_parser_t parser; \ + FILE *jsonstream; \ + jsonstream = fstropen_r (json_string); \ + gvm_json_pull_event_init (&event); \ + gvm_json_pull_parser_init_full (&parser, jsonstream, 0, 4); + +#define CLEANUP_JSON_PARSER \ + gvm_json_pull_event_cleanup (&event); \ + gvm_json_pull_parser_cleanup (&parser); \ + fclose (jsonstream); \ + +#define CHECK_PATH_EQUALS(expected_path_str) \ + path_str = gvm_json_path_to_string (event.path); \ + assert_that (path_str, is_equal_to_string (expected_path_str)); \ + g_free (path_str); + +Ensure (jsonpull, can_parse_false) +{ + INIT_JSON_PARSER ("false"); + + gvm_json_pull_parser_next (&parser, &event); + assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_BOOLEAN)); + assert_that (cJSON_IsBool (event.value), is_true); + assert_that (cJSON_IsFalse (event.value), is_true); + + gvm_json_pull_parser_next (&parser, &event); + assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_EOF)); + CLEANUP_JSON_PARSER +} + +Ensure (jsonpull, can_parse_true) +{ + INIT_JSON_PARSER ("true"); + + gvm_json_pull_parser_next (&parser, &event); + assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_BOOLEAN)); + assert_that (cJSON_IsBool (event.value), is_true); + assert_that (cJSON_IsTrue (event.value), is_true); + + gvm_json_pull_parser_next (&parser, &event); + assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_EOF)); + CLEANUP_JSON_PARSER +} + +Ensure (jsonpull, can_parse_null) +{ + INIT_JSON_PARSER ("null"); + + gvm_json_pull_parser_next (&parser, &event); + assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_NULL)); + assert_that (cJSON_IsNull (event.value), is_true); + + gvm_json_pull_parser_next (&parser, &event); + assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_EOF)); + CLEANUP_JSON_PARSER +} + +Ensure (jsonpull, can_parse_empty_strings) +{ + INIT_JSON_PARSER ("\"\"") + + gvm_json_pull_parser_next (&parser, &event); + assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_STRING)); + assert_that (event.value->valuestring, is_equal_to_string ("")); + + gvm_json_pull_parser_next (&parser, &event); + assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_EOF)); + CLEANUP_JSON_PARSER +} + +Ensure (jsonpull, can_parse_strings_with_content) +{ + INIT_JSON_PARSER ("\n\"123\\tXYZ\\nÄöü\"\n") + + gvm_json_pull_parser_next (&parser, &event); + assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_STRING)); + assert_that (event.value->valuestring, + is_equal_to_string ("123\tXYZ\nÄöü")); + + gvm_json_pull_parser_next (&parser, &event); + assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_EOF)); + CLEANUP_JSON_PARSER +} + +Ensure (jsonpull, can_parse_integer_numbers) +{ + INIT_JSON_PARSER ("-0987") + + gvm_json_pull_parser_next (&parser, &event); + assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_NUMBER)); + assert_that (event.value->valueint, is_equal_to (-987)); + + gvm_json_pull_parser_next (&parser, &event); + assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_EOF)); + CLEANUP_JSON_PARSER +} + +Ensure (jsonpull, can_parse_floating_point_numbers) +{ + INIT_JSON_PARSER ("\t\n 1.2345e+4\n"); + + gvm_json_pull_parser_next (&parser, &event); + assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_NUMBER)); + assert_that (event.value->valuedouble, is_equal_to (1.2345e+4)); + + gvm_json_pull_parser_next (&parser, &event); + assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_EOF)); + CLEANUP_JSON_PARSER +} + +Ensure (jsonpull, can_parse_empty_arrays) +{ + INIT_JSON_PARSER ("[ ]"); + + gvm_json_pull_parser_next (&parser, &event); + assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_ARRAY_START)); + + gvm_json_pull_parser_next (&parser, &event); + assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_ARRAY_END)); + + gvm_json_pull_parser_next (&parser, &event); + assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_EOF)); + CLEANUP_JSON_PARSER +} + +Ensure (jsonpull, can_parse_single_elem_arrays) +{ + gchar *path_str; + INIT_JSON_PARSER ("[ 123 ]"); + + gvm_json_pull_parser_next (&parser, &event); + assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_ARRAY_START)); + + gvm_json_pull_parser_next (&parser, &event); + assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_NUMBER)); + assert_that (event.value->valueint, is_equal_to (123)); + CHECK_PATH_EQUALS ("$[0]") + + gvm_json_pull_parser_next (&parser, &event); + assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_ARRAY_END)); + + gvm_json_pull_parser_next (&parser, &event); + assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_EOF)); + CLEANUP_JSON_PARSER +} + +Ensure (jsonpull, can_parse_multiple_elem_arrays) +{ + gchar *path_str; + INIT_JSON_PARSER ("[123, \"ABC\", null]"); + + gvm_json_pull_parser_next (&parser, &event); + assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_ARRAY_START)); + + gvm_json_pull_parser_next (&parser, &event); + assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_NUMBER)); + assert_that (event.value->valueint, is_equal_to (123)); + CHECK_PATH_EQUALS ("$[0]") + + gvm_json_pull_parser_next (&parser, &event); + assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_STRING)); + assert_that (event.value->valuestring, is_equal_to_string ("ABC")); + CHECK_PATH_EQUALS ("$[1]") + + gvm_json_pull_parser_next (&parser, &event); + assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_NULL)); + CHECK_PATH_EQUALS ("$[2]") + + gvm_json_pull_parser_next (&parser, &event); + assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_ARRAY_END)); + + gvm_json_pull_parser_next (&parser, &event); + assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_EOF)); + CLEANUP_JSON_PARSER +} + +Ensure (jsonpull, can_parse_empty_objects) +{ + INIT_JSON_PARSER ("{ }"); + + gvm_json_pull_parser_next (&parser, &event); + assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_OBJECT_START)); + + gvm_json_pull_parser_next (&parser, &event); + assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_OBJECT_END)); + + gvm_json_pull_parser_next (&parser, &event); + assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_EOF)); + CLEANUP_JSON_PARSER +} + +Ensure (jsonpull, can_parse_single_elem_objects) +{ + gchar *path_str; + INIT_JSON_PARSER ("{ \"keyA\": \"valueA\" }"); + + gvm_json_pull_parser_next (&parser, &event); + assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_OBJECT_START)); + + gvm_json_pull_parser_next (&parser, &event); + assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_STRING)); + assert_that (event.value->valuestring, is_equal_to_string ("valueA")); + CHECK_PATH_EQUALS ("$['keyA']") + + gvm_json_pull_parser_next (&parser, &event); + assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_OBJECT_END)); + + gvm_json_pull_parser_next (&parser, &event); + assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_EOF)); + CLEANUP_JSON_PARSER +} + +Ensure (jsonpull, can_parse_multiple_elem_objects) +{ + gchar *path_str; + INIT_JSON_PARSER ("{ \"keyA\": \"valueA\", \"keyB\":12345 }"); + + gvm_json_pull_parser_next (&parser, &event); + assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_OBJECT_START)); + + gvm_json_pull_parser_next (&parser, &event); + assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_STRING)); + assert_that (event.value->valuestring, is_equal_to_string ("valueA")); + CHECK_PATH_EQUALS ("$['keyA']") + + gvm_json_pull_parser_next (&parser, &event); + assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_NUMBER)); + assert_that (event.value->valueint, is_equal_to (12345)); + CHECK_PATH_EQUALS ("$['keyB']") + + gvm_json_pull_parser_next (&parser, &event); + assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_OBJECT_END)); + + gvm_json_pull_parser_next (&parser, &event); + assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_EOF)); + CLEANUP_JSON_PARSER +} + +Ensure (jsonpull, can_parse_nested_containers) +{ + gchar *path_str; + INIT_JSON_PARSER ("[{\"A\":null, \"B\":{\"C\": [1,2]}, \"D\":\"3\"}, [4]]"); + + gvm_json_pull_parser_next (&parser, &event); + assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_ARRAY_START)); + CHECK_PATH_EQUALS ("$") + + gvm_json_pull_parser_next (&parser, &event); + assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_OBJECT_START)); + CHECK_PATH_EQUALS ("$[0]") + + gvm_json_pull_parser_next (&parser, &event); + assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_NULL)); + CHECK_PATH_EQUALS ("$[0]['A']") + + gvm_json_pull_parser_next (&parser, &event); + assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_OBJECT_START)); + CHECK_PATH_EQUALS ("$[0]['B']") + + gvm_json_pull_parser_next (&parser, &event); + assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_ARRAY_START)); + CHECK_PATH_EQUALS ("$[0]['B']['C']") + + gvm_json_pull_parser_next (&parser, &event); + assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_NUMBER)); + assert_that (event.value->valueint, is_equal_to (1)); + CHECK_PATH_EQUALS ("$[0]['B']['C'][0]") + + gvm_json_pull_parser_next (&parser, &event); + assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_NUMBER)); + assert_that (event.value->valueint, is_equal_to (2)); + CHECK_PATH_EQUALS ("$[0]['B']['C'][1]") + + gvm_json_pull_parser_next (&parser, &event); + assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_ARRAY_END)); + CHECK_PATH_EQUALS ("$[0]['B']['C']") + + gvm_json_pull_parser_next (&parser, &event); + assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_OBJECT_END)); + CHECK_PATH_EQUALS ("$[0]['B']") + + gvm_json_pull_parser_next (&parser, &event); + assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_STRING)); + assert_that (event.value->valuestring, is_equal_to_string ("3")); + CHECK_PATH_EQUALS ("$[0]['D']") + + gvm_json_pull_parser_next (&parser, &event); + assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_OBJECT_END)); + CHECK_PATH_EQUALS ("$[0]") + + gvm_json_pull_parser_next (&parser, &event); + assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_ARRAY_START)); + CHECK_PATH_EQUALS ("$[1]") + + gvm_json_pull_parser_next (&parser, &event); + assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_NUMBER)); + assert_that (event.value->valueint, is_equal_to (4)); + CHECK_PATH_EQUALS ("$[1][0]") + + gvm_json_pull_parser_next (&parser, &event); + assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_ARRAY_END)); + CHECK_PATH_EQUALS ("$[1]") + + gvm_json_pull_parser_next (&parser, &event); + assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_ARRAY_END)); + CHECK_PATH_EQUALS ("$") + + gvm_json_pull_parser_next (&parser, &event); + assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_EOF)); + CLEANUP_JSON_PARSER +} + +Ensure (jsonpull, can_expand_arrays) +{ + gchar *path_str, *error_message; + cJSON *expanded, *child; + INIT_JSON_PARSER ("[[], [1], [2, [3]], [\"A\", \"\\\"B]\"]]"); + + gvm_json_pull_parser_next (&parser, &event); + assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_ARRAY_START)); + CHECK_PATH_EQUALS ("$") + + // empty array + gvm_json_pull_parser_next (&parser, &event); + assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_ARRAY_START)); + CHECK_PATH_EQUALS ("$[0]") + expanded = gvm_json_pull_expand_container (&parser, &error_message); + assert_that (error_message, is_equal_to_string (NULL)); + assert_that (expanded, is_not_null); + assert_that (cJSON_IsArray (expanded), is_true); + assert_that (expanded->child, is_null); + cJSON_free (expanded); + + // single-element array + gvm_json_pull_parser_next (&parser, &event); + assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_ARRAY_START)); + CHECK_PATH_EQUALS ("$[1]") + expanded = gvm_json_pull_expand_container (&parser, &error_message); + assert_that (error_message, is_null); + assert_that (expanded, is_not_null); + assert_that (cJSON_IsArray (expanded), is_true); + child = expanded->child; + assert_that (child, is_not_null); + assert_that (cJSON_IsNumber(child), is_true); + assert_that (child->valueint, is_equal_to(1)); + child = child->next; + assert_that (child, is_null); + cJSON_free (expanded); + + // multi-element array + gvm_json_pull_parser_next (&parser, &event); + assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_ARRAY_START)); + CHECK_PATH_EQUALS ("$[2]") + expanded = gvm_json_pull_expand_container (&parser, &error_message); + assert_that (error_message, is_null); + assert_that (expanded, is_not_null); + assert_that (cJSON_IsArray (expanded), is_true); + child = expanded->child; + assert_that (child, is_not_null); + assert_that (cJSON_IsNumber(child), is_true); + assert_that (child->valueint, is_equal_to(2)); + child = child->next; + assert_that (child, is_not_null); + assert_that (cJSON_IsArray(child), is_true); + assert_that (child->child->valueint, is_equal_to(3)); + cJSON_free (expanded); + + // string array + gvm_json_pull_parser_next (&parser, &event); + assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_ARRAY_START)); + CHECK_PATH_EQUALS ("$[3]") + expanded = gvm_json_pull_expand_container (&parser, &error_message); + assert_that (error_message, is_null); + assert_that (expanded, is_not_null); + assert_that (cJSON_IsArray (expanded), is_true); + child = expanded->child; + assert_that (child, is_not_null); + assert_that (cJSON_IsString(child), is_true); + assert_that (child->valuestring, is_equal_to_string("A")); + child = child->next; + assert_that (child, is_not_null); + assert_that (cJSON_IsString(child), is_true); + assert_that (child->valuestring, is_equal_to_string("\"B]")); + cJSON_free (expanded); + + // array end and EOF + gvm_json_pull_parser_next (&parser, &event); + assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_ARRAY_END)); + CHECK_PATH_EQUALS ("$") + + gvm_json_pull_parser_next (&parser, &event); + assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_EOF)); + CLEANUP_JSON_PARSER +} + +Ensure (jsonpull, can_expand_objects) +{ + gchar *path_str, *error_message; + cJSON *expanded, *child; + INIT_JSON_PARSER ("{\"A\":{}, \"B\": {\"C\": \"\\\"D}\", \"E\":123}}"); + + gvm_json_pull_parser_next (&parser, &event); + assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_OBJECT_START)); + CHECK_PATH_EQUALS ("$") + + gvm_json_pull_parser_next (&parser, &event); + assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_OBJECT_START)); + CHECK_PATH_EQUALS ("$['A']") + expanded = gvm_json_pull_expand_container (&parser, &error_message); + assert_that (error_message, is_null); + assert_that (cJSON_IsObject (expanded), is_true); + assert_that (expanded->child, is_null); + cJSON_free (expanded); + + gvm_json_pull_parser_next (&parser, &event); + assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_OBJECT_START)); + CHECK_PATH_EQUALS ("$['B']") + expanded = gvm_json_pull_expand_container (&parser, &error_message); + assert_that (error_message, is_null); + assert_that (cJSON_IsObject (expanded), is_true); + child = expanded->child; + assert_that (child, is_not_null); + assert_that (cJSON_IsString(child), is_true); + assert_that (child->string, is_equal_to_string ("C")); + assert_that (child->valuestring, is_equal_to_string ("\"D}")); + child = child->next; + assert_that (child, is_not_null); + assert_that (cJSON_IsNumber(child), is_true); + assert_that (child->string, is_equal_to_string ("E")); + assert_that (child->valueint, is_equal_to (123)); + cJSON_free (expanded); + + // object end and EOF + gvm_json_pull_parser_next (&parser, &event); + assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_OBJECT_END)); + CHECK_PATH_EQUALS ("$") + + gvm_json_pull_parser_next (&parser, &event); + assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_EOF)); + CLEANUP_JSON_PARSER +} + + +int +main (int argc, char **argv) +{ + TestSuite *suite; + + suite = create_test_suite (); + + add_test_with_context (suite, jsonpull, can_parse_false); + add_test_with_context (suite, jsonpull, can_parse_true); + add_test_with_context (suite, jsonpull, can_parse_null); + + add_test_with_context (suite, jsonpull, can_parse_empty_strings); + add_test_with_context (suite, jsonpull, can_parse_strings_with_content); + + add_test_with_context (suite, jsonpull, can_parse_integer_numbers); + add_test_with_context (suite, jsonpull, can_parse_floating_point_numbers); + + add_test_with_context (suite, jsonpull, can_parse_empty_arrays); + add_test_with_context (suite, jsonpull, can_parse_single_elem_arrays); + add_test_with_context (suite, jsonpull, can_parse_multiple_elem_arrays); + + add_test_with_context (suite, jsonpull, can_parse_empty_objects); + add_test_with_context (suite, jsonpull, can_parse_single_elem_objects); + add_test_with_context (suite, jsonpull, can_parse_multiple_elem_objects); + add_test_with_context (suite, jsonpull, can_parse_nested_containers); + add_test_with_context (suite, jsonpull, can_expand_arrays); + add_test_with_context (suite, jsonpull, can_expand_objects); + + if (argc > 1) + return run_single_test (suite, argv[1], create_text_reporter ()); + return run_test_suite (suite, create_text_reporter ()); +} \ No newline at end of file From 4d5435eac6596e10217afc4d33c1312ae3fcbaf6 Mon Sep 17 00:00:00 2001 From: Timo Pollmeier Date: Wed, 31 Jul 2024 13:49:30 +0200 Subject: [PATCH 02/11] Add JSON string escaping, improve parser tests The function gvm_json_string_escape is added and used for escaping JSON paths. Some adjustments are made to the parser tests to improve coverage. --- util/jsonpull.c | 66 ++++++++++++++++++++++++++++++++++++------- util/jsonpull.h | 3 ++ util/jsonpull_tests.c | 48 +++++++++++++++++++++++++++++-- 3 files changed, 104 insertions(+), 13 deletions(-) diff --git a/util/jsonpull.c b/util/jsonpull.c index a138db25..6fb3e531 100644 --- a/util/jsonpull.c +++ b/util/jsonpull.c @@ -10,6 +10,59 @@ #define GVM_JSON_CHAR_ERROR -2 ///< Error reading file #define GVM_JSON_CHAR_UNDEFINED -3 ///< Undefined state +/** + * @brief Escapes a string according to the JSON or JSONPath standard + */ +gchar * +gvm_json_string_escape (const char *string, gboolean single_quote) +{ + gchar *point; + if (string == NULL) + return NULL; + + GString *escaped = g_string_sized_new (strlen (string)); + for (point = (char*)string; *point != 0; point++) + { + unsigned char character = *point;; + if ((character > 31) && (character != '\\') + && (single_quote || character != '\"') + && (!single_quote || character != '\'')) + { + g_string_append_c (escaped, character); + } + else + { + g_string_append_c (escaped, '\\'); + switch (*point) + { + case '\\': + case '\'': + case '\"': + g_string_append_c (escaped, *point); + break; + case '\b': + g_string_append_c (escaped, 'b'); + break; + case '\f': + g_string_append_c (escaped, 'f'); + break; + case '\n': + g_string_append_c (escaped, 'n'); + break; + case '\r': + g_string_append_c (escaped, 'r'); + break; + case '\t': + g_string_append_c (escaped, 't'); + break; + default: + g_string_append_printf (escaped, "u%04x", character); + } + } + } + return g_string_free (escaped, FALSE); +} + /** * @brief Creates a new JSON path element. * @@ -917,16 +970,9 @@ gvm_json_path_string_add_elem (gvm_json_path_elem_t *path_elem, { if (path_elem->parent_type == GVM_JSON_PULL_CONTAINER_OBJECT) { - char *point = path_elem->key; - g_string_append (path_string, "['"); - while (point && *point) - { - if (*point == '\\' || *point == '\'') - g_string_append_c (path_string, '\\'); - g_string_append_c (path_string, *point); - point ++; - } - g_string_append (path_string, "']"); + gchar *escaped_key = gvm_json_string_escape (path_elem->key, TRUE); + g_string_append_printf (path_string, "['%s']", escaped_key); + g_free (escaped_key); } else g_string_append_printf (path_string, "[%d]", path_elem->index); diff --git a/util/jsonpull.h b/util/jsonpull.h index 82850f2f..0e992adc 100644 --- a/util/jsonpull.h +++ b/util/jsonpull.h @@ -90,6 +90,9 @@ typedef struct { size_t parse_buffer_limit; ///< Maximum parse buffer size } gvm_json_pull_parser_t; +gchar * +gvm_json_string_escape (const char *, gboolean); + gvm_json_path_elem_t * gvm_json_pull_path_elem_new (gvm_json_pull_container_type_t, int); diff --git a/util/jsonpull_tests.c b/util/jsonpull_tests.c index edf1290e..e0b57d01 100644 --- a/util/jsonpull_tests.c +++ b/util/jsonpull_tests.c @@ -32,7 +32,7 @@ fstropen_r (const char *str) FILE *jsonstream; \ jsonstream = fstropen_r (json_string); \ gvm_json_pull_event_init (&event); \ - gvm_json_pull_parser_init_full (&parser, jsonstream, 0, 4); + gvm_json_pull_parser_init_full (&parser, jsonstream, 100, 4); #define CLEANUP_JSON_PARSER \ gvm_json_pull_event_cleanup (&event); \ @@ -44,6 +44,38 @@ fstropen_r (const char *str) assert_that (path_str, is_equal_to_string (expected_path_str)); \ g_free (path_str); +Ensure (jsonpull, can_json_escape_strings) +{ + const char *unescaped_string = "\"'Abc\\\b\f\n\r\t\001Äöü'\""; + const char *escaped_string_dq = "\\\"'Abc\\\\\\b\\f\\n\\r\\t\\u0001Äöü'\\\""; + const char *escaped_string_sq = "\"\\'Abc\\\\\\b\\f\\n\\r\\t\\u0001Äöü\\'\""; + + gchar *escaped_string = NULL; + escaped_string = gvm_json_string_escape (NULL, FALSE); + assert_that (escaped_string, is_null); + + escaped_string = gvm_json_string_escape (unescaped_string, FALSE); + assert_that (escaped_string, is_equal_to_string (escaped_string_dq)); + g_free (escaped_string); + + escaped_string = gvm_json_string_escape (unescaped_string, TRUE); + assert_that (escaped_string, is_equal_to_string (escaped_string_sq)); + g_free (escaped_string); +} + +Ensure (jsonpull, can_init_parser_with_defaults) +{ + gvm_json_pull_parser_t parser; + FILE *strfile = fstropen_r ("[]"); + + gvm_json_pull_parser_init (&parser, strfile); + assert_that (parser.input_stream, is_equal_to (strfile)); + assert_that (parser.parse_buffer_limit, + is_equal_to (GVM_JSON_PULL_PARSE_BUFFER_LIMIT)); + assert_that (parser.read_buffer_size, + is_equal_to (GVM_JSON_PULL_READ_BUFFER_SIZE)); +} + Ensure (jsonpull, can_parse_false) { INIT_JSON_PARSER ("false"); @@ -427,7 +459,8 @@ Ensure (jsonpull, can_expand_objects) { gchar *path_str, *error_message; cJSON *expanded, *child; - INIT_JSON_PARSER ("{\"A\":{}, \"B\": {\"C\": \"\\\"D}\", \"E\":123}}"); + INIT_JSON_PARSER ( + "{\"A\":{}, \"B\": {\"C\": \"\\\"D}\", \"E\":123, \"F\":{}}}"); gvm_json_pull_parser_next (&parser, &event); assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_OBJECT_START)); @@ -458,6 +491,11 @@ Ensure (jsonpull, can_expand_objects) assert_that (cJSON_IsNumber(child), is_true); assert_that (child->string, is_equal_to_string ("E")); assert_that (child->valueint, is_equal_to (123)); + child = child->next; + assert_that (child, is_not_null); + assert_that (cJSON_IsObject(child), is_true); + assert_that (child->string, is_equal_to_string ("F")); + assert_that (child->child, is_null); cJSON_free (expanded); // object end and EOF @@ -478,6 +516,10 @@ main (int argc, char **argv) suite = create_test_suite (); + add_test_with_context (suite, jsonpull, can_json_escape_strings); + + add_test_with_context (suite, jsonpull, can_init_parser_with_defaults); + add_test_with_context (suite, jsonpull, can_parse_false); add_test_with_context (suite, jsonpull, can_parse_true); add_test_with_context (suite, jsonpull, can_parse_null); @@ -498,7 +540,7 @@ main (int argc, char **argv) add_test_with_context (suite, jsonpull, can_parse_nested_containers); add_test_with_context (suite, jsonpull, can_expand_arrays); add_test_with_context (suite, jsonpull, can_expand_objects); - + if (argc > 1) return run_single_test (suite, argv[1], create_text_reporter ()); return run_test_suite (suite, create_text_reporter ()); From 093fd05d960b0b1aee6bacdd8c7fde3402449b96 Mon Sep 17 00:00:00 2001 From: Timo Pollmeier Date: Thu, 1 Aug 2024 12:46:56 +0200 Subject: [PATCH 03/11] Improve JSON pull error handling, add error tests The handling of some error cases for the JSON pull parser has been fixed and error messages are now more consistent. Tests to check the error handling of the parser have been added. --- util/jsonpull.c | 57 ++-- util/jsonpull.h | 2 + util/jsonpull_tests.c | 699 ++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 727 insertions(+), 31 deletions(-) diff --git a/util/jsonpull.c b/util/jsonpull.c index 6fb3e531..99aa23bd 100644 --- a/util/jsonpull.c +++ b/util/jsonpull.c @@ -521,7 +521,7 @@ gvm_json_pull_parse_key (gvm_json_pull_parser_t *parser, if (parser->last_read_char != ':') { event->type = GVM_JSON_PULL_EVENT_ERROR; - event->error_message = g_strdup_printf ("expected colon, got '%c'", parser->last_read_char); + event->error_message = g_strdup_printf ("expected colon"); g_free (key_str); return 1; } @@ -534,20 +534,20 @@ gvm_json_pull_parse_key (gvm_json_pull_parser_t *parser, break; case '}': - path_elem = g_queue_peek_tail (parser->path); - if (path_elem == NULL - || path_elem->parent_type != GVM_JSON_PULL_CONTAINER_OBJECT) - { - event->type = GVM_JSON_PULL_EVENT_ERROR; - event->error_message = g_strdup ("unexpected closing curly brace"); - return 1; - } event->type = GVM_JSON_PULL_EVENT_OBJECT_END; event->value = NULL; gvm_json_pull_path_elem_free (g_queue_pop_tail (parser->path)); PARSE_VALUE_NEXT_EXPECT gvm_json_pull_parser_next_char (parser); break; + case ']': + event->type = GVM_JSON_PULL_EVENT_ERROR; + event->error_message = g_strdup ("unexpected closing square bracket"); + return 1; + default: + event->type = GVM_JSON_PULL_EVENT_ERROR; + event->error_message = g_strdup ("unexpected character"); + return 1; } return 0; @@ -706,19 +706,9 @@ gvm_json_pull_parse_value (gvm_json_pull_parser_t *parser, gvm_json_pull_parser_next_char (parser); break; case '}': - path_elem = g_queue_peek_tail (parser->path); - if (path_elem == NULL - || path_elem->parent_type != GVM_JSON_PULL_CONTAINER_OBJECT) - { - event->type = GVM_JSON_PULL_EVENT_ERROR; - event->error_message = g_strdup ("unexpected closing curly brace"); - return 1; - } - event->type = GVM_JSON_PULL_EVENT_OBJECT_END; - event->value = NULL; - gvm_json_pull_path_elem_free (g_queue_pop_tail (parser->path)); - PARSE_VALUE_NEXT_EXPECT - gvm_json_pull_parser_next_char (parser); + event->type = GVM_JSON_PULL_EVENT_ERROR; + event->error_message = g_strdup ("unexpected closing curly brace"); + return 1; break; default: if (g_ascii_isdigit (parser->last_read_char) @@ -777,10 +767,14 @@ gvm_json_pull_parser_next (gvm_json_pull_parser_t *parser, // Check for expected end of file if (parser->expect == GVM_JSON_PULL_EXPECT_EOF) { - if (gvm_json_pull_skip_space (parser, event, TRUE) == GVM_JSON_CHAR_ERROR) - return; + gvm_json_pull_skip_space (parser, event, TRUE); - if (parser->last_read_char != GVM_JSON_CHAR_EOF) + if (parser->last_read_char == GVM_JSON_CHAR_ERROR) + { + event->type = GVM_JSON_PULL_EVENT_ERROR; + event->error_message = gvm_json_read_stream_error_str (); + } + else if (parser->last_read_char != GVM_JSON_CHAR_EOF) { event->type = GVM_JSON_PULL_EVENT_ERROR; event->error_message @@ -829,7 +823,7 @@ cJSON * gvm_json_pull_expand_container (gvm_json_pull_parser_t *parser, gchar **error_message) { - gvm_json_path_elem_t *path_tail; + gvm_json_path_elem_t *path_tail = NULL; int start_depth; gboolean in_string, escape_next_char, in_expanded_container; @@ -840,14 +834,13 @@ gvm_json_pull_expand_container (gvm_json_pull_parser_t *parser, if (error_message) *error_message = NULL; + // require "path_add" to only allow expansion at start of container if (parser->path_add) { path_tail = parser->path_add; g_queue_push_tail (parser->path, path_tail); parser->path_add = NULL; } - else - path_tail = g_queue_peek_tail (parser->path); if (path_tail && path_tail->parent_type == GVM_JSON_PULL_CONTAINER_ARRAY) @@ -858,7 +851,7 @@ gvm_json_pull_expand_container (gvm_json_pull_parser_t *parser, else { if (error_message) - *error_message + *error_message = g_strdup ("can only expand after array or object start"); return NULL; } @@ -913,7 +906,8 @@ gvm_json_pull_expand_container (gvm_json_pull_parser_t *parser, if (path_tail->parent_type != GVM_JSON_PULL_CONTAINER_ARRAY) { if (error_message) - *error_message = g_strdup ("unexpected ']'"); + *error_message + = g_strdup ("unexpected closing square bracket"); return NULL; } if (path_tail->depth == start_depth) @@ -924,7 +918,8 @@ gvm_json_pull_expand_container (gvm_json_pull_parser_t *parser, if (path_tail->parent_type != GVM_JSON_PULL_CONTAINER_OBJECT) { if (error_message) - *error_message = g_strdup ("unexpected '}'"); + *error_message + = g_strdup ("unexpected closing curly brace"); return NULL; } if (path_tail->depth == start_depth) diff --git a/util/jsonpull.h b/util/jsonpull.h index 0e992adc..01e12aa1 100644 --- a/util/jsonpull.h +++ b/util/jsonpull.h @@ -7,6 +7,8 @@ #ifndef _GVM_JSONPULL_H #define _GVM_JSONPULL_H +#define _GNU_SOURCE + #include #include #include diff --git a/util/jsonpull_tests.c b/util/jsonpull_tests.c index e0b57d01..18056cd5 100644 --- a/util/jsonpull_tests.c +++ b/util/jsonpull_tests.c @@ -5,6 +5,7 @@ #include "jsonpull.c" +#include #include #include @@ -26,6 +27,21 @@ fstropen_r (const char *str) return fmemopen ((void*)str, strlen(str), "r"); } +static ssize_t +read_with_error_on_eof (void *stream_cookie, char *buf, size_t size) +{ + FILE *stream = stream_cookie; + ssize_t ret = fread (buf, 1, size, stream); + if (ret <= 0) + { + errno = EIO; + return -1; + } + else + return ret; +} + + #define INIT_JSON_PARSER(json_string) \ gvm_json_pull_event_t event; \ gvm_json_pull_parser_t parser; \ @@ -34,6 +50,20 @@ fstropen_r (const char *str) gvm_json_pull_event_init (&event); \ gvm_json_pull_parser_init_full (&parser, jsonstream, 100, 4); +#define INIT_READ_ERROR_JSON_PARSER(json_string) \ + gvm_json_pull_event_t event; \ + gvm_json_pull_parser_t parser; \ + FILE *jsonstream = fstropen_r (json_string); \ + cookie_io_functions_t io_functions = { \ + .read = read_with_error_on_eof, \ + .write = NULL, \ + .seek = NULL, \ + .close = NULL \ + }; \ + FILE *errorstream = fopencookie (jsonstream, "r", io_functions); \ + gvm_json_pull_event_init (&event); \ + gvm_json_pull_parser_init_full (&parser, errorstream, 100, 4); + #define CLEANUP_JSON_PARSER \ gvm_json_pull_event_cleanup (&event); \ gvm_json_pull_parser_cleanup (&parser); \ @@ -44,6 +74,9 @@ fstropen_r (const char *str) assert_that (path_str, is_equal_to_string (expected_path_str)); \ g_free (path_str); +#define JSON_READ_ERROR "error reading JSON stream: Input/output error" + + Ensure (jsonpull, can_json_escape_strings) { const char *unescaped_string = "\"'Abc\\\b\f\n\r\t\001Äöü'\""; @@ -508,6 +541,610 @@ Ensure (jsonpull, can_expand_objects) CLEANUP_JSON_PARSER } +Ensure (jsonpull, fails_for_read_error) +{ + INIT_READ_ERROR_JSON_PARSER ("123") + + gvm_json_pull_parser_next (&parser, &event); + assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_ERROR)); + assert_that (event.error_message, is_equal_to_string (JSON_READ_ERROR)); + gvm_json_pull_parser_cleanup (&parser); + gvm_json_pull_event_cleanup (&event); + fclose (jsonstream); +} + +Ensure (jsonpull, fails_for_misspelled_true) +{ + INIT_JSON_PARSER ("trxyz"); + + gvm_json_pull_parser_next (&parser, &event); + assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_ERROR)); + assert_that (event.error_message, + is_equal_to_string ("misspelled keyword 'true'")); + CLEANUP_JSON_PARSER +} + +Ensure (jsonpull, fails_for_incomplete_true) +{ + INIT_JSON_PARSER ("tru"); + + gvm_json_pull_parser_next (&parser, &event); + assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_ERROR)); + assert_that (event.error_message, + is_equal_to_string ("unexpected EOF")); + CLEANUP_JSON_PARSER +} + +Ensure (jsonpull, fails_for_misspelled_false) +{ + INIT_JSON_PARSER ("falxyz"); + + gvm_json_pull_parser_next (&parser, &event); + assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_ERROR)); + assert_that (event.error_message, + is_equal_to_string ("misspelled keyword 'false'")); + CLEANUP_JSON_PARSER +} + +Ensure (jsonpull, fails_for_misspelled_null) +{ + INIT_JSON_PARSER ("nulx"); + + gvm_json_pull_parser_next (&parser, &event); + assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_ERROR)); + assert_that (event.error_message, + is_equal_to_string ("misspelled keyword 'null'")); + CLEANUP_JSON_PARSER +} + +Ensure (jsonpull, fails_for_string_read_error) +{ + INIT_READ_ERROR_JSON_PARSER ("\"ABCDEFG\""); + + gvm_json_pull_parser_next (&parser, &event); + assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_ERROR)); + assert_that (event.error_message, is_equal_to_string (JSON_READ_ERROR)); + CLEANUP_JSON_PARSER +} + +Ensure (jsonpull, fails_for_string_eof) +{ + INIT_JSON_PARSER ("\"no closing quote here"); + + gvm_json_pull_parser_next (&parser, &event); + assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_ERROR)); + assert_that (event.error_message, + is_equal_to_string ("unexpected EOF")); + CLEANUP_JSON_PARSER +} + +Ensure (jsonpull, fails_for_overlong_string) +{ + INIT_JSON_PARSER ("\"This should be too long for a small parse buffer\""); + parser.parse_buffer_limit = 10; + + gvm_json_pull_parser_next (&parser, &event); + assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_ERROR)); + assert_that (event.error_message, + is_equal_to_string ("string exceeds size limit of 10 bytes")); + CLEANUP_JSON_PARSER +} + +Ensure (jsonpull, fails_for_invalid_string) +{ + INIT_JSON_PARSER ("\"This has an invalid escape sequence: \\x\""); + + gvm_json_pull_parser_next (&parser, &event); + assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_ERROR)); + assert_that (event.error_message, + is_equal_to_string ("error parsing string")); + CLEANUP_JSON_PARSER +} + +Ensure (jsonpull, fails_for_number_read_error) +{ + INIT_READ_ERROR_JSON_PARSER ("12345.123456789"); + + gvm_json_pull_parser_next (&parser, &event); + assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_ERROR)); + assert_that (event.error_message, is_equal_to_string (JSON_READ_ERROR)); + CLEANUP_JSON_PARSER +} + +Ensure (jsonpull, fails_for_overlong_number) +{ + INIT_READ_ERROR_JSON_PARSER ("12345.123456789"); + parser.parse_buffer_limit = 10; + + gvm_json_pull_parser_next (&parser, &event); + assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_ERROR)); + assert_that (event.error_message, + is_equal_to_string ("number exceeds size limit of 10 bytes")); + CLEANUP_JSON_PARSER +} + +Ensure (jsonpull, fails_for_invalid_number) +{ + INIT_JSON_PARSER ("-+e"); + + gvm_json_pull_parser_next (&parser, &event); + assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_ERROR)); + assert_that (event.error_message, + is_equal_to_string ("error parsing number")); + CLEANUP_JSON_PARSER +} + +Ensure (jsonpull, fails_for_array_eof) +{ + INIT_JSON_PARSER ("["); + + gvm_json_pull_parser_next (&parser, &event); + assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_ARRAY_START)); + gvm_json_pull_parser_next (&parser, &event); + assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_ERROR)); + assert_that (event.error_message, + is_equal_to_string ("unexpected EOF")); + CLEANUP_JSON_PARSER +} + +Ensure (jsonpull, fails_for_array_eof_after_value) +{ + INIT_JSON_PARSER ("[123"); + + gvm_json_pull_parser_next (&parser, &event); + assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_ARRAY_START)); + gvm_json_pull_parser_next (&parser, &event); + assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_NUMBER)); + gvm_json_pull_parser_next (&parser, &event); + assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_ERROR)); + assert_that (event.error_message, + is_equal_to_string ("unexpected EOF")); + CLEANUP_JSON_PARSER +} + +Ensure (jsonpull, fails_for_array_eof_after_comma) +{ + INIT_JSON_PARSER ("[123,"); + + gvm_json_pull_parser_next (&parser, &event); + assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_ARRAY_START)); + gvm_json_pull_parser_next (&parser, &event); + assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_NUMBER)); + gvm_json_pull_parser_next (&parser, &event); + assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_ERROR)); + assert_that (event.error_message, + is_equal_to_string ("unexpected EOF")); + CLEANUP_JSON_PARSER +} + +Ensure (jsonpull, fails_for_array_read_error) +{ + INIT_READ_ERROR_JSON_PARSER ("[ "); + + gvm_json_pull_parser_next (&parser, &event); + assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_ARRAY_START)); + gvm_json_pull_parser_next (&parser, &event); + assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_ERROR)); + assert_that (event.error_message, is_equal_to_string (JSON_READ_ERROR)); + CLEANUP_JSON_PARSER +} + + +Ensure (jsonpull, fails_for_invalid_array_bracket) +{ + INIT_JSON_PARSER ("[}"); + + gvm_json_pull_parser_next (&parser, &event); + assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_ARRAY_START)); + gvm_json_pull_parser_next (&parser, &event); + assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_ERROR)); + assert_that (event.error_message, + is_equal_to_string ("unexpected closing curly brace")); + CLEANUP_JSON_PARSER +} + +Ensure (jsonpull, fails_for_invalid_array_bracket_after_value) +{ + INIT_JSON_PARSER ("[123}"); + + gvm_json_pull_parser_next (&parser, &event); + assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_ARRAY_START)); + gvm_json_pull_parser_next (&parser, &event); + assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_NUMBER)); + gvm_json_pull_parser_next (&parser, &event); + assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_ERROR)); + assert_that (event.error_message, + is_equal_to_string ("unexpected closing curly brace")); + CLEANUP_JSON_PARSER +} + +Ensure (jsonpull, fails_for_invalid_array_other_char) +{ + INIT_JSON_PARSER ("[!"); + + gvm_json_pull_parser_next (&parser, &event); + assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_ARRAY_START)); + gvm_json_pull_parser_next (&parser, &event); + assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_ERROR)); + assert_that (event.error_message, + is_equal_to_string ("unexpected character")); + CLEANUP_JSON_PARSER +} + +Ensure (jsonpull, fails_for_invalid_array_other_char_after_value) +{ + INIT_JSON_PARSER ("[123!"); + + gvm_json_pull_parser_next (&parser, &event); + assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_ARRAY_START)); + gvm_json_pull_parser_next (&parser, &event); + assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_NUMBER)); + gvm_json_pull_parser_next (&parser, &event); + assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_ERROR)); + assert_that (event.error_message, + is_equal_to_string ("expected comma or end of container")); + CLEANUP_JSON_PARSER +} + +Ensure (jsonpull, fails_for_object_key_eof) +{ + INIT_JSON_PARSER ("{"); + + gvm_json_pull_parser_next (&parser, &event); + assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_OBJECT_START)); + gvm_json_pull_parser_next (&parser, &event); + assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_ERROR)); + assert_that (event.error_message, + is_equal_to_string ("unexpected EOF")); + CLEANUP_JSON_PARSER +} + +Ensure (jsonpull, fails_for_object_key_read_error) +{ + INIT_READ_ERROR_JSON_PARSER ("{ "); + + gvm_json_pull_parser_next (&parser, &event); + assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_OBJECT_START)); + gvm_json_pull_parser_next (&parser, &event); + assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_ERROR)); + assert_that (event.error_message, is_equal_to_string (JSON_READ_ERROR)); + CLEANUP_JSON_PARSER +} + +Ensure (jsonpull, fails_for_object_key_invalid_string) +{ + INIT_JSON_PARSER ("{\"invalid escape:\\x\": 123}"); + + gvm_json_pull_parser_next (&parser, &event); + assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_OBJECT_START)); + gvm_json_pull_parser_next (&parser, &event); + assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_ERROR)); + assert_that (event.error_message, + is_equal_to_string ("error parsing string")); + CLEANUP_JSON_PARSER +} + +Ensure (jsonpull, fails_for_invalid_object_key_bracket) +{ + INIT_JSON_PARSER ("{]"); + + gvm_json_pull_parser_next (&parser, &event); + assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_OBJECT_START)); + gvm_json_pull_parser_next (&parser, &event); + assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_ERROR)); + assert_that (event.error_message, + is_equal_to_string ("unexpected closing square bracket")); + CLEANUP_JSON_PARSER +} + +Ensure (jsonpull, fails_for_invalid_object_key_other_char) +{ + INIT_JSON_PARSER ("{!"); + + gvm_json_pull_parser_next (&parser, &event); + assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_OBJECT_START)); + gvm_json_pull_parser_next (&parser, &event); + assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_ERROR)); + assert_that (event.error_message, + is_equal_to_string ("unexpected character")); + CLEANUP_JSON_PARSER +} + +Ensure (jsonpull, fails_for_object_colon_eof) +{ + INIT_JSON_PARSER ("{\"A\" "); + + gvm_json_pull_parser_next (&parser, &event); + assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_OBJECT_START)); + gvm_json_pull_parser_next (&parser, &event); + assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_ERROR)); + assert_that (event.error_message, + is_equal_to_string ("unexpected EOF")); + CLEANUP_JSON_PARSER +} + +Ensure (jsonpull, fails_for_object_colon_read_error) +{ + INIT_READ_ERROR_JSON_PARSER ("{\"A\" "); + + gvm_json_pull_parser_next (&parser, &event); + assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_OBJECT_START)); + gvm_json_pull_parser_next (&parser, &event); + assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_ERROR)); + assert_that (event.error_message, is_equal_to_string (JSON_READ_ERROR)); + CLEANUP_JSON_PARSER +} + +Ensure (jsonpull, fails_for_object_colon_other_char) +{ + INIT_JSON_PARSER ("{\"A\"!"); + + gvm_json_pull_parser_next (&parser, &event); + assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_OBJECT_START)); + gvm_json_pull_parser_next (&parser, &event); + assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_ERROR)); + assert_that (event.error_message, + is_equal_to_string ("expected colon")); + CLEANUP_JSON_PARSER +} + +Ensure (jsonpull, fails_for_object_value_eof) +{ + INIT_JSON_PARSER ("{\"A\": "); + + gvm_json_pull_parser_next (&parser, &event); + assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_OBJECT_START)); + gvm_json_pull_parser_next (&parser, &event); + assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_ERROR)); + assert_that (event.error_message, + is_equal_to_string ("unexpected EOF")); + CLEANUP_JSON_PARSER +} + +Ensure (jsonpull, fails_for_object_value_read_error) +{ + INIT_READ_ERROR_JSON_PARSER ("{\"A\": "); + + gvm_json_pull_parser_next (&parser, &event); + assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_OBJECT_START)); + gvm_json_pull_parser_next (&parser, &event); + assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_ERROR)); + assert_that (event.error_message, is_equal_to_string (JSON_READ_ERROR)); + CLEANUP_JSON_PARSER +} + +Ensure (jsonpull, fails_for_object_value_curly_brace) +{ + INIT_JSON_PARSER ("{\"A\": }"); + + gvm_json_pull_parser_next (&parser, &event); + assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_OBJECT_START)); + gvm_json_pull_parser_next (&parser, &event); + assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_ERROR)); + assert_that (event.error_message, + is_equal_to_string ("unexpected closing curly brace")); + CLEANUP_JSON_PARSER +} + +Ensure (jsonpull, fails_for_object_value_square_bracket) +{ + INIT_JSON_PARSER ("{\"A\": ]"); + + gvm_json_pull_parser_next (&parser, &event); + assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_OBJECT_START)); + gvm_json_pull_parser_next (&parser, &event); + assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_ERROR)); + assert_that (event.error_message, + is_equal_to_string ("unexpected closing square bracket")); + CLEANUP_JSON_PARSER +} + +Ensure (jsonpull, fails_for_object_eof_after_value) +{ + INIT_JSON_PARSER ("{\"A\": 123"); + + gvm_json_pull_parser_next (&parser, &event); + assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_OBJECT_START)); + gvm_json_pull_parser_next (&parser, &event); + assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_NUMBER)); + gvm_json_pull_parser_next (&parser, &event); + assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_ERROR)); + assert_that (event.error_message, + is_equal_to_string ("unexpected EOF")); + CLEANUP_JSON_PARSER +} + +Ensure (jsonpull, fails_for_object_square_bracket_after_value) +{ + INIT_JSON_PARSER ("{\"A\": 123 ]"); + + gvm_json_pull_parser_next (&parser, &event); + assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_OBJECT_START)); + gvm_json_pull_parser_next (&parser, &event); + assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_NUMBER)); + gvm_json_pull_parser_next (&parser, &event); + assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_ERROR)); + assert_that (event.error_message, + is_equal_to_string ("unexpected closing square bracket")); + CLEANUP_JSON_PARSER +} + +Ensure (jsonpull, fails_for_object_eof_after_comma) +{ + INIT_JSON_PARSER ("{\"A\": 123, "); + + gvm_json_pull_parser_next (&parser, &event); + assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_OBJECT_START)); + gvm_json_pull_parser_next (&parser, &event); + assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_NUMBER)); + gvm_json_pull_parser_next (&parser, &event); + assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_ERROR)); + assert_that (event.error_message, + is_equal_to_string ("unexpected EOF")); + CLEANUP_JSON_PARSER +} + +Ensure (jsonpull, fails_for_read_error_after_doc_end) +{ + INIT_READ_ERROR_JSON_PARSER ("123 "); + + gvm_json_pull_parser_next (&parser, &event); + assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_NUMBER)); + gvm_json_pull_parser_next (&parser, &event); + assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_ERROR)); + assert_that (event.error_message, is_equal_to_string (JSON_READ_ERROR)); + CLEANUP_JSON_PARSER +} + +Ensure (jsonpull, fails_for_content_after_doc_end) +{ + INIT_JSON_PARSER ("123 456"); + + gvm_json_pull_parser_next (&parser, &event); + assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_NUMBER)); + gvm_json_pull_parser_next (&parser, &event); + assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_ERROR)); + assert_that (event.error_message, + is_equal_to_string ("unexpected character at end of file (52)")); + CLEANUP_JSON_PARSER +} + +Ensure (jsonpull, fails_for_expand_before_container) +{ + cJSON *cjson_value; + gchar *error_message; + INIT_JSON_PARSER ("[]"); + + cjson_value = gvm_json_pull_expand_container (&parser, &error_message); + assert_that (cjson_value, is_null); + assert_that (error_message, + is_equal_to_string ("can only expand after" + " array or object start")); + + CLEANUP_JSON_PARSER +} + +Ensure (jsonpull, fails_for_expand_after_value) +{ + cJSON *cjson_value; + gchar *error_message; + INIT_JSON_PARSER ("[123, 456]"); + + gvm_json_pull_parser_next (&parser, &event); + assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_ARRAY_START)); + gvm_json_pull_parser_next (&parser, &event); + assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_NUMBER)); + + cjson_value = gvm_json_pull_expand_container (&parser, &error_message); + assert_that (cjson_value, is_null); + assert_that (error_message, + is_equal_to_string ("can only expand after" + " array or object start")); + + CLEANUP_JSON_PARSER +} + +Ensure (jsonpull, fails_for_expand_invalid_content) +{ + cJSON *cjson_value; + gchar *error_message; + INIT_JSON_PARSER ("[invalid content]"); + + gvm_json_pull_parser_next (&parser, &event); + assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_ARRAY_START)); + + cjson_value = gvm_json_pull_expand_container (&parser, &error_message); + assert_that (cjson_value, is_null); + assert_that (error_message, + is_equal_to_string ("could not parse expanded container")); + + CLEANUP_JSON_PARSER +} + +Ensure (jsonpull, fails_for_expand_overlong) +{ + cJSON *cjson_value; + gchar *error_message; + INIT_JSON_PARSER ("[1234567890.123456780]"); + parser.parse_buffer_limit = 10; + + gvm_json_pull_parser_next (&parser, &event); + assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_ARRAY_START)); + + cjson_value = gvm_json_pull_expand_container (&parser, &error_message); + assert_that (cjson_value, is_null); + assert_that (error_message, + is_equal_to_string ("container exceeds size limit of 10 bytes")); + + CLEANUP_JSON_PARSER +} + +Ensure (jsonpull, fails_for_expand_unexpected_curly_brace) +{ + cJSON *cjson_value; + gchar *error_message; + INIT_JSON_PARSER ("[ 123 }"); + + gvm_json_pull_parser_next (&parser, &event); + assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_ARRAY_START)); + + cjson_value = gvm_json_pull_expand_container (&parser, &error_message); + assert_that (cjson_value, is_null); + assert_that (error_message, + is_equal_to_string ("unexpected closing curly brace")); + + CLEANUP_JSON_PARSER +} + +Ensure (jsonpull, fails_for_expand_unexpected_square_bracket) +{ + cJSON *cjson_value; + gchar *error_message; + INIT_JSON_PARSER ("{ \"A\": 123 ]"); + + gvm_json_pull_parser_next (&parser, &event); + assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_OBJECT_START)); + + cjson_value = gvm_json_pull_expand_container (&parser, &error_message); + assert_that (cjson_value, is_null); + assert_that (error_message, + is_equal_to_string ("unexpected closing square bracket")); + + CLEANUP_JSON_PARSER +} + +Ensure (jsonpull, fails_for_expand_eof) +{ + cJSON *cjson_value; + gchar *error_message; + INIT_JSON_PARSER ("[ 123"); + + gvm_json_pull_parser_next (&parser, &event); + assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_ARRAY_START)); + + cjson_value = gvm_json_pull_expand_container (&parser, &error_message); + assert_that (cjson_value, is_null); + assert_that (error_message, is_equal_to_string ("unexpected EOF")); + + CLEANUP_JSON_PARSER +} + +Ensure (jsonpull, fails_for_expand_read_error) +{ + cJSON *cjson_value; + gchar *error_message; + INIT_READ_ERROR_JSON_PARSER ("[ 123 "); + + gvm_json_pull_parser_next (&parser, &event); + assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_ARRAY_START)); + + cjson_value = gvm_json_pull_expand_container (&parser, &error_message); + assert_that (cjson_value, is_null); + assert_that (error_message, is_equal_to_string (JSON_READ_ERROR)); + + CLEANUP_JSON_PARSER +} + int main (int argc, char **argv) @@ -541,6 +1178,68 @@ main (int argc, char **argv) add_test_with_context (suite, jsonpull, can_expand_arrays); add_test_with_context (suite, jsonpull, can_expand_objects); + add_test_with_context (suite, jsonpull, fails_for_read_error); + + add_test_with_context (suite, jsonpull, fails_for_misspelled_true); + add_test_with_context (suite, jsonpull, fails_for_incomplete_true); + add_test_with_context (suite, jsonpull, fails_for_misspelled_false); + add_test_with_context (suite, jsonpull, fails_for_misspelled_null); + + add_test_with_context (suite, jsonpull, fails_for_string_eof); + add_test_with_context (suite, jsonpull, fails_for_string_read_error); + add_test_with_context (suite, jsonpull, fails_for_overlong_string); + add_test_with_context (suite, jsonpull, fails_for_invalid_string); + + add_test_with_context (suite, jsonpull, fails_for_number_read_error); + add_test_with_context (suite, jsonpull, fails_for_overlong_number); + add_test_with_context (suite, jsonpull, fails_for_invalid_number); + + add_test_with_context (suite, jsonpull, fails_for_array_eof); + add_test_with_context (suite, jsonpull, fails_for_array_eof_after_value); + add_test_with_context (suite, jsonpull, fails_for_array_eof_after_comma); + add_test_with_context (suite, jsonpull, fails_for_array_read_error); + add_test_with_context (suite, jsonpull, fails_for_invalid_array_bracket); + add_test_with_context (suite, jsonpull, + fails_for_invalid_array_bracket_after_value); + add_test_with_context (suite, jsonpull, fails_for_invalid_array_other_char); + add_test_with_context (suite, jsonpull, + fails_for_invalid_array_other_char_after_value); + + add_test_with_context (suite, jsonpull, fails_for_object_key_eof); + add_test_with_context (suite, jsonpull, fails_for_object_key_read_error); + add_test_with_context (suite, jsonpull, fails_for_object_key_invalid_string); + add_test_with_context (suite, jsonpull, fails_for_invalid_object_key_bracket); + add_test_with_context (suite, jsonpull, + fails_for_invalid_object_key_other_char); + + add_test_with_context (suite, jsonpull, fails_for_object_colon_eof); + add_test_with_context (suite, jsonpull, fails_for_object_colon_read_error); + add_test_with_context (suite, jsonpull, fails_for_object_colon_other_char); + + add_test_with_context (suite, jsonpull, fails_for_object_value_eof); + add_test_with_context (suite, jsonpull, fails_for_object_value_read_error); + add_test_with_context (suite, jsonpull, fails_for_object_value_curly_brace); + add_test_with_context (suite, jsonpull, + fails_for_object_value_square_bracket); + add_test_with_context (suite, jsonpull, fails_for_object_eof_after_value); + add_test_with_context (suite, jsonpull, fails_for_object_eof_after_comma); + add_test_with_context (suite, jsonpull, + fails_for_object_square_bracket_after_value); + + add_test_with_context (suite, jsonpull, fails_for_read_error_after_doc_end); + add_test_with_context (suite, jsonpull, fails_for_content_after_doc_end); + + add_test_with_context (suite, jsonpull, fails_for_expand_before_container); + add_test_with_context (suite, jsonpull, fails_for_expand_after_value); + add_test_with_context (suite, jsonpull, fails_for_expand_invalid_content); + add_test_with_context (suite, jsonpull, fails_for_expand_overlong); + add_test_with_context (suite, jsonpull, + fails_for_expand_unexpected_curly_brace); + add_test_with_context (suite, jsonpull, + fails_for_expand_unexpected_square_bracket); + add_test_with_context (suite, jsonpull, fails_for_expand_read_error); + add_test_with_context (suite, jsonpull, fails_for_expand_eof); + if (argc > 1) return run_single_test (suite, argv[1], create_text_reporter ()); return run_test_suite (suite, create_text_reporter ()); From 115e910aa8796063f9b93c6f645e5e05cac595d6 Mon Sep 17 00:00:00 2001 From: Timo Pollmeier Date: Thu, 1 Aug 2024 12:59:04 +0200 Subject: [PATCH 04/11] Fix formatting for JSON parser --- util/jsonpull.c | 253 +++++++++++++++++++----------------------- util/jsonpull.h | 71 ++++++------ util/jsonpull_tests.c | 149 +++++++++++-------------- 3 files changed, 215 insertions(+), 258 deletions(-) diff --git a/util/jsonpull.c b/util/jsonpull.c index 99aa23bd..a51458fd 100644 --- a/util/jsonpull.c +++ b/util/jsonpull.c @@ -4,11 +4,12 @@ */ #include "jsonpull.h" -#include "assert.h" -#define GVM_JSON_CHAR_EOF -1 ///< End of file -#define GVM_JSON_CHAR_ERROR -2 ///< Error reading file -#define GVM_JSON_CHAR_UNDEFINED -3 ///< Undefined state +#include + +#define GVM_JSON_CHAR_EOF -1 ///< End of file +#define GVM_JSON_CHAR_ERROR -2 ///< Error reading file +#define GVM_JSON_CHAR_UNDEFINED -3 ///< Undefined state /** * @brief Escapes a string according to the JSON or JSONPath standard @@ -21,10 +22,11 @@ gvm_json_string_escape (const char *string, gboolean single_quote) return NULL; GString *escaped = g_string_sized_new (strlen (string)); - for (point = (char*)string; *point != 0; point++) + for (point = (char *) string; *point != 0; point++) { - unsigned char character = *point;; - if ((character > 31) && (character != '\\') + unsigned char character = *point; + ; + if ((character > 31) && (character != '\\') && (single_quote || character != '\"') && (!single_quote || character != '\'')) { @@ -34,7 +36,7 @@ gvm_json_string_escape (const char *string, gboolean single_quote) { g_string_append_c (escaped, '\\'); switch (*point) - { + { case '\\': case '\'': case '\"': @@ -57,7 +59,7 @@ gvm_json_string_escape (const char *string, gboolean single_quote) break; default: g_string_append_printf (escaped, "u%04x", character); - } + } } } return g_string_free (escaped, FALSE); @@ -101,7 +103,7 @@ gvm_json_pull_path_elem_free (gvm_json_path_elem_t *elem) void gvm_json_pull_event_init (gvm_json_pull_event_t *event) { - memset (event, 0, sizeof(gvm_json_pull_event_t)); + memset (event, 0, sizeof (gvm_json_pull_event_t)); } /** @@ -113,7 +115,7 @@ void gvm_json_pull_event_reset (gvm_json_pull_event_t *event) { cJSON_free (event->value); - memset (event, 0, sizeof(gvm_json_pull_event_t)); + memset (event, 0, sizeof (gvm_json_pull_event_t)); } /** @@ -125,7 +127,7 @@ void gvm_json_pull_event_cleanup (gvm_json_pull_event_t *event) { cJSON_free (event->value); - memset (event, 0, sizeof(gvm_json_pull_event_t)); + memset (event, 0, sizeof (gvm_json_pull_event_t)); } /** @@ -138,17 +140,16 @@ gvm_json_pull_event_cleanup (gvm_json_pull_event_t *event) */ void gvm_json_pull_parser_init_full (gvm_json_pull_parser_t *parser, - FILE *input_stream, - size_t parse_buffer_limit, + FILE *input_stream, size_t parse_buffer_limit, size_t read_buffer_size) { - assert(parser); + assert (parser); assert (input_stream); - memset (parser, 0, sizeof(gvm_json_pull_parser_t)); + memset (parser, 0, sizeof (gvm_json_pull_parser_t)); if (parse_buffer_limit <= 0) parse_buffer_limit = GVM_JSON_PULL_PARSE_BUFFER_LIMIT; - + if (read_buffer_size <= 0) read_buffer_size = GVM_JSON_PULL_READ_BUFFER_SIZE; @@ -158,7 +159,7 @@ gvm_json_pull_parser_init_full (gvm_json_pull_parser_t *parser, parser->parse_buffer_limit = parse_buffer_limit; parser->parse_buffer = g_string_new (""); parser->read_buffer_size = read_buffer_size; - parser->read_buffer = g_malloc0(read_buffer_size); + parser->read_buffer = g_malloc0 (read_buffer_size); parser->last_read_char = GVM_JSON_CHAR_UNDEFINED; } @@ -169,8 +170,7 @@ gvm_json_pull_parser_init_full (gvm_json_pull_parser_t *parser, * @param[in] input_stream The JSON input stream */ void -gvm_json_pull_parser_init (gvm_json_pull_parser_t *parser, - FILE *input_stream) +gvm_json_pull_parser_init (gvm_json_pull_parser_t *parser, FILE *input_stream) { gvm_json_pull_parser_init_full (parser, input_stream, 0, 0); } @@ -183,12 +183,12 @@ gvm_json_pull_parser_init (gvm_json_pull_parser_t *parser, void gvm_json_pull_parser_cleanup (gvm_json_pull_parser_t *parser) { - assert(parser); + assert (parser); g_queue_free_full (parser->path, (GDestroyNotify) gvm_json_pull_path_elem_free); g_string_free (parser->parse_buffer, TRUE); g_free (parser->read_buffer); - memset (parser, 0, sizeof(gvm_json_pull_parser_t)); + memset (parser, 0, sizeof (gvm_json_pull_parser_t)); } /** @@ -218,10 +218,9 @@ gvm_json_pull_check_parse_buffer_size (const char *value_type, { if (parser->parse_buffer->len >= parser->parse_buffer_limit) { - event->error_message - = g_strdup_printf ("%s exceeds size limit of %zu bytes", - value_type, - parser->parse_buffer_limit); + event->error_message = + g_strdup_printf ("%s exceeds size limit of %zu bytes", value_type, + parser->parse_buffer_limit); event->type = GVM_JSON_PULL_EVENT_ERROR; return 1; } @@ -239,24 +238,22 @@ gvm_json_pull_parser_next_char (gvm_json_pull_parser_t *parser) parser->read_pos++; if (parser->read_pos < parser->last_read_size) { - parser->last_read_char - = (unsigned char) parser->read_buffer[parser->read_pos]; + parser->last_read_char = + (unsigned char) parser->read_buffer[parser->read_pos]; return parser->last_read_char; } else { parser->read_pos = 0; - parser->last_read_size = fread (parser->read_buffer, - 1, - parser->read_buffer_size, - parser->input_stream); + parser->last_read_size = fread ( + parser->read_buffer, 1, parser->read_buffer_size, parser->input_stream); if (ferror (parser->input_stream)) parser->last_read_char = GVM_JSON_CHAR_ERROR; else if (parser->last_read_size <= 0) parser->last_read_char = GVM_JSON_CHAR_EOF; else - parser->last_read_char - = (unsigned char) parser->read_buffer[parser->read_pos]; + parser->last_read_char = + (unsigned char) parser->read_buffer[parser->read_pos]; return parser->last_read_char; } } @@ -276,16 +273,15 @@ static int gvm_json_pull_parse_buffered (gvm_json_pull_parser_t *parser, gvm_json_pull_event_t *event, const char *value_name, - cJSON_bool (*validate_func)(const cJSON* const), + cJSON_bool (*validate_func) (const cJSON *const), cJSON **cjson_value) { - cJSON* parsed_value = cJSON_Parse (parser->parse_buffer->str); + cJSON *parsed_value = cJSON_Parse (parser->parse_buffer->str); *cjson_value = NULL; if (validate_func (parsed_value) == 0) { event->type = GVM_JSON_PULL_EVENT_ERROR; - event->error_message - = g_strdup_printf ("error parsing %s", value_name); + event->error_message = g_strdup_printf ("error parsing %s", value_name); cJSON_free (parsed_value); return 1; } @@ -302,8 +298,7 @@ gvm_json_pull_parse_buffered (gvm_json_pull_parser_t *parser, */ static void gvm_json_pull_handle_read_end (gvm_json_pull_parser_t *parser, - gvm_json_pull_event_t *event, - gboolean allow_eof) + gvm_json_pull_event_t *event, gboolean allow_eof) { if (parser->last_read_char == GVM_JSON_CHAR_ERROR) { @@ -332,8 +327,7 @@ gvm_json_pull_handle_read_end (gvm_json_pull_parser_t *parser, */ static int gvm_json_pull_skip_space (gvm_json_pull_parser_t *parser, - gvm_json_pull_event_t *event, - gboolean allow_eof) + gvm_json_pull_event_t *event, gboolean allow_eof) { while (g_ascii_isspace (parser->last_read_char)) gvm_json_pull_parser_next_char (parser); @@ -359,24 +353,23 @@ gvm_json_pull_skip_space (gvm_json_pull_parser_t *parser, */ static int gvm_json_pull_parse_string (gvm_json_pull_parser_t *parser, - gvm_json_pull_event_t *event, - cJSON **cjson_value) + gvm_json_pull_event_t *event, cJSON **cjson_value) { gboolean escape_next_char = FALSE; g_string_truncate (parser->parse_buffer, 0); g_string_append_c (parser->parse_buffer, '"'); while (gvm_json_pull_parser_next_char (parser) >= 0) - { - if (gvm_json_pull_check_parse_buffer_size ("string", parser, event)) - return 1; - g_string_append_c (parser->parse_buffer, parser->last_read_char); - if (escape_next_char) - escape_next_char = FALSE; - else if (parser->last_read_char == '\\') - escape_next_char = TRUE; - else if (parser->last_read_char == '"') - break; - } + { + if (gvm_json_pull_check_parse_buffer_size ("string", parser, event)) + return 1; + g_string_append_c (parser->parse_buffer, parser->last_read_char); + if (escape_next_char) + escape_next_char = FALSE; + else if (parser->last_read_char == '\\') + escape_next_char = TRUE; + else if (parser->last_read_char == '"') + break; + } if (parser->last_read_char < 0) { @@ -386,10 +379,7 @@ gvm_json_pull_parse_string (gvm_json_pull_parser_t *parser, gvm_json_pull_parser_next_char (parser); - return gvm_json_pull_parse_buffered (parser, - event, - "string", - cJSON_IsString, + return gvm_json_pull_parse_buffered (parser, event, "string", cJSON_IsString, cjson_value); } @@ -407,24 +397,21 @@ gvm_json_pull_parse_string (gvm_json_pull_parser_t *parser, */ static int gvm_json_pull_parse_number (gvm_json_pull_parser_t *parser, - gvm_json_pull_event_t *event, - cJSON **cjson_value) + gvm_json_pull_event_t *event, cJSON **cjson_value) { g_string_truncate (parser->parse_buffer, 0); g_string_append_c (parser->parse_buffer, parser->last_read_char); while (gvm_json_pull_parser_next_char (parser) >= 0) - { - if (gvm_json_pull_check_parse_buffer_size ("number", parser, event)) - return 1; - if (g_ascii_isdigit (parser->last_read_char) - || parser->last_read_char == '.' - || parser->last_read_char == 'e' - || parser->last_read_char == '-' - || parser->last_read_char == '+') - g_string_append_c (parser->parse_buffer, parser->last_read_char); - else - break; - } + { + if (gvm_json_pull_check_parse_buffer_size ("number", parser, event)) + return 1; + if (g_ascii_isdigit (parser->last_read_char) + || parser->last_read_char == '.' || parser->last_read_char == 'e' + || parser->last_read_char == '-' || parser->last_read_char == '+') + g_string_append_c (parser->parse_buffer, parser->last_read_char); + else + break; + } if (parser->last_read_char == GVM_JSON_CHAR_ERROR) { @@ -433,10 +420,7 @@ gvm_json_pull_parse_number (gvm_json_pull_parser_t *parser, return 1; } - return gvm_json_pull_parse_buffered (parser, - event, - "number", - cJSON_IsNumber, + return gvm_json_pull_parse_buffered (parser, event, "number", cJSON_IsNumber, cjson_value); } @@ -454,10 +438,9 @@ gvm_json_pull_parse_number (gvm_json_pull_parser_t *parser, */ static int gvm_json_pull_parse_keyword (gvm_json_pull_parser_t *parser, - gvm_json_pull_event_t *event, - const char *keyword) + gvm_json_pull_event_t *event, const char *keyword) { - for (size_t i = 0; i < strlen(keyword); i++) + for (size_t i = 0; i < strlen (keyword); i++) { if (parser->last_read_char < 0) { @@ -467,8 +450,8 @@ gvm_json_pull_parse_keyword (gvm_json_pull_parser_t *parser, else if (parser->last_read_char != keyword[i]) { event->type = GVM_JSON_PULL_EVENT_ERROR; - event->error_message - = g_strdup_printf ("misspelled keyword '%s'", keyword); + event->error_message = + g_strdup_printf ("misspelled keyword '%s'", keyword); return 1; } gvm_json_pull_parser_next_char (parser); @@ -476,10 +459,10 @@ gvm_json_pull_parse_keyword (gvm_json_pull_parser_t *parser, return 0; } -#define PARSE_VALUE_NEXT_EXPECT \ - if (parser->path->length) \ - parser->expect = GVM_JSON_PULL_EXPECT_COMMA; \ - else \ +#define PARSE_VALUE_NEXT_EXPECT \ + if (parser->path->length) \ + parser->expect = GVM_JSON_PULL_EXPECT_COMMA; \ + else \ parser->expect = GVM_JSON_PULL_EXPECT_EOF; /** @@ -505,7 +488,7 @@ gvm_json_pull_parse_key (gvm_json_pull_parser_t *parser, gvm_json_path_elem_t *path_elem; switch (parser->last_read_char) - { + { case '"': if (gvm_json_pull_parse_string (parser, event, &key_cjson)) return 1; @@ -531,7 +514,7 @@ gvm_json_pull_parse_key (gvm_json_pull_parser_t *parser, g_free (path_elem->key); path_elem->key = key_str; parser->expect = GVM_JSON_PULL_EXPECT_VALUE; - + break; case '}': event->type = GVM_JSON_PULL_EVENT_OBJECT_END; @@ -548,7 +531,7 @@ gvm_json_pull_parse_key (gvm_json_pull_parser_t *parser, event->type = GVM_JSON_PULL_EVENT_ERROR; event->error_message = g_strdup ("unexpected character"); return 1; - } + } return 0; } @@ -570,13 +553,13 @@ gvm_json_pull_parse_comma (gvm_json_pull_parser_t *parser, { if (gvm_json_pull_skip_space (parser, event, FALSE)) return 1; - + gvm_json_path_elem_t *path_elem = NULL; switch (parser->last_read_char) - { + { case ',': path_elem = g_queue_peek_tail (parser->path); - path_elem->index ++; + path_elem->index++; if (path_elem->parent_type == GVM_JSON_PULL_CONTAINER_OBJECT) parser->expect = GVM_JSON_PULL_EXPECT_KEY; else @@ -585,7 +568,7 @@ gvm_json_pull_parse_comma (gvm_json_pull_parser_t *parser, break; case ']': path_elem = g_queue_peek_tail (parser->path); - if (path_elem == NULL + if (path_elem == NULL || path_elem->parent_type != GVM_JSON_PULL_CONTAINER_ARRAY) { event->type = GVM_JSON_PULL_EVENT_ERROR; @@ -600,7 +583,7 @@ gvm_json_pull_parse_comma (gvm_json_pull_parser_t *parser, break; case '}': path_elem = g_queue_peek_tail (parser->path); - if (path_elem == NULL + if (path_elem == NULL || path_elem->parent_type != GVM_JSON_PULL_CONTAINER_OBJECT) { event->type = GVM_JSON_PULL_EVENT_ERROR; @@ -617,7 +600,7 @@ gvm_json_pull_parse_comma (gvm_json_pull_parser_t *parser, event->error_message = g_strdup ("expected comma or end of container"); event->type = GVM_JSON_PULL_EVENT_ERROR; return 1; - } + } return 0; } @@ -638,12 +621,12 @@ gvm_json_pull_parse_value (gvm_json_pull_parser_t *parser, { if (gvm_json_pull_skip_space (parser, event, FALSE)) return 1; - + cJSON *cjson_value = NULL; gvm_json_path_elem_t *path_elem = NULL; switch (parser->last_read_char) - { + { case '"': if (gvm_json_pull_parse_string (parser, event, &cjson_value)) return 1; @@ -675,15 +658,14 @@ gvm_json_pull_parse_value (gvm_json_pull_parser_t *parser, case '[': event->type = GVM_JSON_PULL_EVENT_ARRAY_START; event->value = NULL; - parser->path_add - = gvm_json_pull_path_elem_new (GVM_JSON_PULL_CONTAINER_ARRAY, - parser->path->length); + parser->path_add = gvm_json_pull_path_elem_new ( + GVM_JSON_PULL_CONTAINER_ARRAY, parser->path->length); parser->expect = GVM_JSON_PULL_EXPECT_VALUE; gvm_json_pull_parser_next_char (parser); break; case ']': path_elem = g_queue_peek_tail (parser->path); - if (path_elem == NULL + if (path_elem == NULL || path_elem->parent_type != GVM_JSON_PULL_CONTAINER_ARRAY) { event->type = GVM_JSON_PULL_EVENT_ERROR; @@ -699,9 +681,8 @@ gvm_json_pull_parse_value (gvm_json_pull_parser_t *parser, case '{': event->type = GVM_JSON_PULL_EVENT_OBJECT_START; event->value = NULL; - parser->path_add - = gvm_json_pull_path_elem_new (GVM_JSON_PULL_CONTAINER_OBJECT, - parser->path->length); + parser->path_add = gvm_json_pull_path_elem_new ( + GVM_JSON_PULL_CONTAINER_OBJECT, parser->path->length); parser->expect = GVM_JSON_PULL_EXPECT_KEY; gvm_json_pull_parser_next_char (parser); break; @@ -726,15 +707,15 @@ gvm_json_pull_parse_value (gvm_json_pull_parser_t *parser, event->error_message = g_strdup ("unexpected character"); return 1; } - } + } return 0; } /** * @brief Get the next event from a JSON pull parser. - * + * * Note: This invalidates previous event data like the cJSON value. - * + * * @param[in] parser The JSON pull parser to process until the next event * @param[in] event Structure to store event data in. */ @@ -763,7 +744,7 @@ gvm_json_pull_parser_next (gvm_json_pull_parser_t *parser, g_queue_push_tail (parser->path, parser->path_add); parser->path_add = NULL; } - + // Check for expected end of file if (parser->expect == GVM_JSON_PULL_EXPECT_EOF) { @@ -777,9 +758,8 @@ gvm_json_pull_parser_next (gvm_json_pull_parser_t *parser, else if (parser->last_read_char != GVM_JSON_CHAR_EOF) { event->type = GVM_JSON_PULL_EVENT_ERROR; - event->error_message - = g_strdup_printf ("unexpected character at end of file (%d)", - parser->last_read_char); + event->error_message = g_strdup_printf ( + "unexpected character at end of file (%d)", parser->last_read_char); return; } return; @@ -796,7 +776,7 @@ gvm_json_pull_parser_next (gvm_json_pull_parser_t *parser, if (gvm_json_pull_parse_comma (parser, event)) return; } - + if (parser->expect == GVM_JSON_PULL_EXPECT_KEY) { if (gvm_json_pull_parse_key (parser, event)) @@ -842,20 +822,19 @@ gvm_json_pull_expand_container (gvm_json_pull_parser_t *parser, parser->path_add = NULL; } - if (path_tail - && path_tail->parent_type == GVM_JSON_PULL_CONTAINER_ARRAY) + if (path_tail && path_tail->parent_type == GVM_JSON_PULL_CONTAINER_ARRAY) g_string_append_c (parser->parse_buffer, '['); - else if (path_tail + else if (path_tail && path_tail->parent_type == GVM_JSON_PULL_CONTAINER_OBJECT) g_string_append_c (parser->parse_buffer, '{'); else { if (error_message) - *error_message - = g_strdup ("can only expand after array or object start"); + *error_message = + g_strdup ("can only expand after array or object start"); return NULL; } - + start_depth = path_tail->depth; in_string = escape_next_char = FALSE; in_expanded_container = TRUE; @@ -865,14 +844,14 @@ gvm_json_pull_expand_container (gvm_json_pull_parser_t *parser, if (parser->parse_buffer->len >= parser->parse_buffer_limit) { if (error_message) - *error_message - = g_strdup_printf ("container exceeds size limit of %zu bytes", - parser->parse_buffer_limit); + *error_message = + g_strdup_printf ("container exceeds size limit of %zu bytes", + parser->parse_buffer_limit); return NULL; } - + g_string_append_c (parser->parse_buffer, parser->last_read_char); - + if (escape_next_char) { escape_next_char = FALSE; @@ -885,20 +864,18 @@ gvm_json_pull_expand_container (gvm_json_pull_parser_t *parser, else { switch (parser->last_read_char) - { + { case '"': in_string = TRUE; break; case '[': - path_tail - = gvm_json_pull_path_elem_new (GVM_JSON_PULL_CONTAINER_ARRAY, - parser->path->length); + path_tail = gvm_json_pull_path_elem_new ( + GVM_JSON_PULL_CONTAINER_ARRAY, parser->path->length); g_queue_push_tail (parser->path, path_tail); break; case '{': - path_tail - = gvm_json_pull_path_elem_new (GVM_JSON_PULL_CONTAINER_OBJECT, - parser->path->length); + path_tail = gvm_json_pull_path_elem_new ( + GVM_JSON_PULL_CONTAINER_OBJECT, parser->path->length); g_queue_push_tail (parser->path, path_tail); break; case ']': @@ -906,8 +883,8 @@ gvm_json_pull_expand_container (gvm_json_pull_parser_t *parser, if (path_tail->parent_type != GVM_JSON_PULL_CONTAINER_ARRAY) { if (error_message) - *error_message - = g_strdup ("unexpected closing square bracket"); + *error_message = + g_strdup ("unexpected closing square bracket"); return NULL; } if (path_tail->depth == start_depth) @@ -918,14 +895,14 @@ gvm_json_pull_expand_container (gvm_json_pull_parser_t *parser, if (path_tail->parent_type != GVM_JSON_PULL_CONTAINER_OBJECT) { if (error_message) - *error_message - = g_strdup ("unexpected closing curly brace"); + *error_message = + g_strdup ("unexpected closing curly brace"); return NULL; } if (path_tail->depth == start_depth) in_expanded_container = FALSE; break; - } + } } gvm_json_pull_parser_next_char (parser); } @@ -946,7 +923,7 @@ gvm_json_pull_expand_container (gvm_json_pull_parser_t *parser, expanded = cJSON_Parse (parser->parse_buffer->str); g_string_truncate (parser->parse_buffer, 0); PARSE_VALUE_NEXT_EXPECT - + if (expanded == NULL && error_message) *error_message = g_strdup ("could not parse expanded container"); @@ -984,9 +961,7 @@ gchar * gvm_json_path_to_string (GQueue *path) { GString *path_string = g_string_new ("$"); - g_queue_foreach (path, - (GFunc) gvm_json_path_string_add_elem, - path_string); + g_queue_foreach (path, (GFunc) gvm_json_path_string_add_elem, path_string); return g_string_free (path_string, FALSE); } diff --git a/util/jsonpull.h b/util/jsonpull.h index 01e12aa1..8d8343a0 100644 --- a/util/jsonpull.h +++ b/util/jsonpull.h @@ -3,7 +3,6 @@ * SPDX-License-Identifier: GPL-2.0-or-later */ - #ifndef _GVM_JSONPULL_H #define _GVM_JSONPULL_H @@ -16,26 +15,29 @@ /** * @brief Type of container the parser is currently in */ -typedef enum { - GVM_JSON_PULL_CONTAINER_NONE = 0, ///< No container / document root - GVM_JSON_PULL_CONTAINER_ARRAY, ///< Array - GVM_JSON_PULL_CONTAINER_OBJECT, ///< Object +typedef enum +{ + GVM_JSON_PULL_CONTAINER_NONE = 0, ///< No container / document root + GVM_JSON_PULL_CONTAINER_ARRAY, ///< Array + GVM_JSON_PULL_CONTAINER_OBJECT, ///< Object } gvm_json_pull_container_type_t; /** * @brief Path element types for the JSON pull parser. */ -typedef struct gvm_json_path_elem { +typedef struct gvm_json_path_elem +{ gvm_json_pull_container_type_t parent_type; ///< parent container type - int index; ///< Index of the element within the parent - char *key; ///< Key if element is in an object - int depth; ///< Number of ancestor elements + int index; ///< Index of the element within the parent + char *key; ///< Key if element is in an object + int depth; ///< Number of ancestor elements } gvm_json_path_elem_t; /** * @brief Event types for the JSON pull parser */ -typedef enum { +typedef enum +{ GVM_JSON_PULL_EVENT_UNDEFINED = 0, GVM_JSON_PULL_EVENT_ARRAY_START, GVM_JSON_PULL_EVENT_ARRAY_END, @@ -52,17 +54,19 @@ typedef enum { /** * @brief Event generated by the JSON pull parser. */ -typedef struct { - gvm_json_pull_event_type_t type; ///< Type of event - GQueue *path; ///< Path to the event value - cJSON *value; ///< Value for non-container value events - gchar *error_message; ///< Error message, NULL on success +typedef struct +{ + gvm_json_pull_event_type_t type; ///< Type of event + GQueue *path; ///< Path to the event value + cJSON *value; ///< Value for non-container value events + gchar *error_message; ///< Error message, NULL on success } gvm_json_pull_event_t; /** * @brief Expected token state for the JSON pull parser */ -typedef enum { +typedef enum +{ GVM_JSON_PULL_EXPECT_UNDEFINED = 0, ///< Undefined state GVM_JSON_PULL_EXPECT_VALUE, ///< Expect start of a value GVM_JSON_PULL_EXPECT_KEY, ///< Expect start of a key @@ -77,19 +81,20 @@ typedef enum { /** * @brief A json pull parser */ -typedef struct { - GQueue *path; ///< Path to the current value +typedef struct +{ + GQueue *path; ///< Path to the current value gvm_json_path_elem_t *path_add; ///< Path elem to add in next step gvm_json_pull_expect_t expect; ///< Current expected token - int keyword_pos; ///< Position in a keyword like "true" or "null" - FILE *input_stream; ///< Input stream - char *read_buffer; ///< Stream reading buffer - size_t read_buffer_size; ///< Size of the stream reading buffer - size_t last_read_size; ///< Size of last stream read - int last_read_char; ///< Character last read from stream - size_t read_pos; ///< Position in current read - GString *parse_buffer; ///< Buffer for parsing values and object keys - size_t parse_buffer_limit; ///< Maximum parse buffer size + int keyword_pos; ///< Position in a keyword like "true" or "null" + FILE *input_stream; ///< Input stream + char *read_buffer; ///< Stream reading buffer + size_t read_buffer_size; ///< Size of the stream reading buffer + size_t last_read_size; ///< Size of last stream read + int last_read_char; ///< Character last read from stream + size_t read_pos; ///< Position in current read + GString *parse_buffer; ///< Buffer for parsing values and object keys + size_t parse_buffer_limit; ///< Maximum parse buffer size } gvm_json_pull_parser_t; gchar * @@ -111,8 +116,8 @@ void gvm_json_pull_event_cleanup (gvm_json_pull_event_t *); void -gvm_json_pull_parser_init_full (gvm_json_pull_parser_t *, FILE *, - size_t, size_t); +gvm_json_pull_parser_init_full (gvm_json_pull_parser_t *, FILE *, size_t, + size_t); void gvm_json_pull_parser_init (gvm_json_pull_parser_t *, FILE *); @@ -120,15 +125,13 @@ gvm_json_pull_parser_init (gvm_json_pull_parser_t *, FILE *); void gvm_json_pull_parser_cleanup (gvm_json_pull_parser_t *); -void gvm_json_pull_parser_next(gvm_json_pull_parser_t*, - gvm_json_pull_event_t*); +void +gvm_json_pull_parser_next (gvm_json_pull_parser_t *, gvm_json_pull_event_t *); cJSON * -gvm_json_pull_expand_container (gvm_json_pull_parser_t *, - gchar **); +gvm_json_pull_expand_container (gvm_json_pull_parser_t *, gchar **); gchar * gvm_json_path_to_string (GQueue *path); - #endif /* _GVM_JSONPULL_H */ \ No newline at end of file diff --git a/util/jsonpull_tests.c b/util/jsonpull_tests.c index 18056cd5..808c4333 100644 --- a/util/jsonpull_tests.c +++ b/util/jsonpull_tests.c @@ -5,9 +5,9 @@ #include "jsonpull.c" -#include #include #include +#include Describe (jsonpull); BeforeEach (jsonpull) @@ -17,14 +17,13 @@ AfterEach (jsonpull) { } - /* * Helper function to open a string as a read-only stream. */ static inline FILE * fstropen_r (const char *str) { - return fmemopen ((void*)str, strlen(str), "r"); + return fmemopen ((void *) str, strlen (str), "r"); } static ssize_t @@ -41,42 +40,38 @@ read_with_error_on_eof (void *stream_cookie, char *buf, size_t size) return ret; } - -#define INIT_JSON_PARSER(json_string) \ - gvm_json_pull_event_t event; \ - gvm_json_pull_parser_t parser; \ - FILE *jsonstream; \ - jsonstream = fstropen_r (json_string); \ - gvm_json_pull_event_init (&event); \ +#define INIT_JSON_PARSER(json_string) \ + gvm_json_pull_event_t event; \ + gvm_json_pull_parser_t parser; \ + FILE *jsonstream; \ + jsonstream = fstropen_r (json_string); \ + gvm_json_pull_event_init (&event); \ gvm_json_pull_parser_init_full (&parser, jsonstream, 100, 4); -#define INIT_READ_ERROR_JSON_PARSER(json_string) \ - gvm_json_pull_event_t event; \ - gvm_json_pull_parser_t parser; \ - FILE *jsonstream = fstropen_r (json_string); \ - cookie_io_functions_t io_functions = { \ - .read = read_with_error_on_eof, \ - .write = NULL, \ - .seek = NULL, \ - .close = NULL \ - }; \ - FILE *errorstream = fopencookie (jsonstream, "r", io_functions); \ - gvm_json_pull_event_init (&event); \ +#define INIT_READ_ERROR_JSON_PARSER(json_string) \ + gvm_json_pull_event_t event; \ + gvm_json_pull_parser_t parser; \ + FILE *jsonstream = fstropen_r (json_string); \ + cookie_io_functions_t io_functions = {.read = read_with_error_on_eof, \ + .write = NULL, \ + .seek = NULL, \ + .close = NULL}; \ + FILE *errorstream = fopencookie (jsonstream, "r", io_functions); \ + gvm_json_pull_event_init (&event); \ gvm_json_pull_parser_init_full (&parser, errorstream, 100, 4); -#define CLEANUP_JSON_PARSER \ - gvm_json_pull_event_cleanup (&event); \ - gvm_json_pull_parser_cleanup (&parser); \ - fclose (jsonstream); \ +#define CLEANUP_JSON_PARSER \ + gvm_json_pull_event_cleanup (&event); \ + gvm_json_pull_parser_cleanup (&parser); \ + fclose (jsonstream); -#define CHECK_PATH_EQUALS(expected_path_str) \ - path_str = gvm_json_path_to_string (event.path); \ - assert_that (path_str, is_equal_to_string (expected_path_str)); \ +#define CHECK_PATH_EQUALS(expected_path_str) \ + path_str = gvm_json_path_to_string (event.path); \ + assert_that (path_str, is_equal_to_string (expected_path_str)); \ g_free (path_str); #define JSON_READ_ERROR "error reading JSON stream: Input/output error" - Ensure (jsonpull, can_json_escape_strings) { const char *unescaped_string = "\"'Abc\\\b\f\n\r\t\001Äöü'\""; @@ -100,7 +95,7 @@ Ensure (jsonpull, can_init_parser_with_defaults) { gvm_json_pull_parser_t parser; FILE *strfile = fstropen_r ("[]"); - + gvm_json_pull_parser_init (&parser, strfile); assert_that (parser.input_stream, is_equal_to (strfile)); assert_that (parser.parse_buffer_limit, @@ -154,7 +149,7 @@ Ensure (jsonpull, can_parse_empty_strings) { INIT_JSON_PARSER ("\"\"") - gvm_json_pull_parser_next (&parser, &event); + gvm_json_pull_parser_next (&parser, &event); assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_STRING)); assert_that (event.value->valuestring, is_equal_to_string ("")); @@ -167,10 +162,9 @@ Ensure (jsonpull, can_parse_strings_with_content) { INIT_JSON_PARSER ("\n\"123\\tXYZ\\nÄöü\"\n") - gvm_json_pull_parser_next (&parser, &event); + gvm_json_pull_parser_next (&parser, &event); assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_STRING)); - assert_that (event.value->valuestring, - is_equal_to_string ("123\tXYZ\nÄöü")); + assert_that (event.value->valuestring, is_equal_to_string ("123\tXYZ\nÄöü")); gvm_json_pull_parser_next (&parser, &event); assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_EOF)); @@ -339,7 +333,7 @@ Ensure (jsonpull, can_parse_nested_containers) gvm_json_pull_parser_next (&parser, &event); assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_ARRAY_START)); CHECK_PATH_EQUALS ("$") - + gvm_json_pull_parser_next (&parser, &event); assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_OBJECT_START)); CHECK_PATH_EQUALS ("$[0]") @@ -369,7 +363,7 @@ Ensure (jsonpull, can_parse_nested_containers) gvm_json_pull_parser_next (&parser, &event); assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_ARRAY_END)); CHECK_PATH_EQUALS ("$[0]['B']['C']") - + gvm_json_pull_parser_next (&parser, &event); assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_OBJECT_END)); CHECK_PATH_EQUALS ("$[0]['B']") @@ -395,7 +389,7 @@ Ensure (jsonpull, can_parse_nested_containers) gvm_json_pull_parser_next (&parser, &event); assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_ARRAY_END)); CHECK_PATH_EQUALS ("$[1]") - + gvm_json_pull_parser_next (&parser, &event); assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_ARRAY_END)); CHECK_PATH_EQUALS ("$") @@ -436,12 +430,12 @@ Ensure (jsonpull, can_expand_arrays) assert_that (cJSON_IsArray (expanded), is_true); child = expanded->child; assert_that (child, is_not_null); - assert_that (cJSON_IsNumber(child), is_true); - assert_that (child->valueint, is_equal_to(1)); + assert_that (cJSON_IsNumber (child), is_true); + assert_that (child->valueint, is_equal_to (1)); child = child->next; assert_that (child, is_null); cJSON_free (expanded); - + // multi-element array gvm_json_pull_parser_next (&parser, &event); assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_ARRAY_START)); @@ -452,14 +446,14 @@ Ensure (jsonpull, can_expand_arrays) assert_that (cJSON_IsArray (expanded), is_true); child = expanded->child; assert_that (child, is_not_null); - assert_that (cJSON_IsNumber(child), is_true); - assert_that (child->valueint, is_equal_to(2)); + assert_that (cJSON_IsNumber (child), is_true); + assert_that (child->valueint, is_equal_to (2)); child = child->next; assert_that (child, is_not_null); - assert_that (cJSON_IsArray(child), is_true); - assert_that (child->child->valueint, is_equal_to(3)); + assert_that (cJSON_IsArray (child), is_true); + assert_that (child->child->valueint, is_equal_to (3)); cJSON_free (expanded); - + // string array gvm_json_pull_parser_next (&parser, &event); assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_ARRAY_START)); @@ -470,12 +464,12 @@ Ensure (jsonpull, can_expand_arrays) assert_that (cJSON_IsArray (expanded), is_true); child = expanded->child; assert_that (child, is_not_null); - assert_that (cJSON_IsString(child), is_true); - assert_that (child->valuestring, is_equal_to_string("A")); + assert_that (cJSON_IsString (child), is_true); + assert_that (child->valuestring, is_equal_to_string ("A")); child = child->next; assert_that (child, is_not_null); - assert_that (cJSON_IsString(child), is_true); - assert_that (child->valuestring, is_equal_to_string("\"B]")); + assert_that (cJSON_IsString (child), is_true); + assert_that (child->valuestring, is_equal_to_string ("\"B]")); cJSON_free (expanded); // array end and EOF @@ -498,7 +492,7 @@ Ensure (jsonpull, can_expand_objects) gvm_json_pull_parser_next (&parser, &event); assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_OBJECT_START)); CHECK_PATH_EQUALS ("$") - + gvm_json_pull_parser_next (&parser, &event); assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_OBJECT_START)); CHECK_PATH_EQUALS ("$['A']") @@ -516,17 +510,17 @@ Ensure (jsonpull, can_expand_objects) assert_that (cJSON_IsObject (expanded), is_true); child = expanded->child; assert_that (child, is_not_null); - assert_that (cJSON_IsString(child), is_true); + assert_that (cJSON_IsString (child), is_true); assert_that (child->string, is_equal_to_string ("C")); assert_that (child->valuestring, is_equal_to_string ("\"D}")); child = child->next; assert_that (child, is_not_null); - assert_that (cJSON_IsNumber(child), is_true); + assert_that (cJSON_IsNumber (child), is_true); assert_that (child->string, is_equal_to_string ("E")); assert_that (child->valueint, is_equal_to (123)); child = child->next; assert_that (child, is_not_null); - assert_that (cJSON_IsObject(child), is_true); + assert_that (cJSON_IsObject (child), is_true); assert_that (child->string, is_equal_to_string ("F")); assert_that (child->child, is_null); cJSON_free (expanded); @@ -570,8 +564,7 @@ Ensure (jsonpull, fails_for_incomplete_true) gvm_json_pull_parser_next (&parser, &event); assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_ERROR)); - assert_that (event.error_message, - is_equal_to_string ("unexpected EOF")); + assert_that (event.error_message, is_equal_to_string ("unexpected EOF")); CLEANUP_JSON_PARSER } @@ -613,8 +606,7 @@ Ensure (jsonpull, fails_for_string_eof) gvm_json_pull_parser_next (&parser, &event); assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_ERROR)); - assert_that (event.error_message, - is_equal_to_string ("unexpected EOF")); + assert_that (event.error_message, is_equal_to_string ("unexpected EOF")); CLEANUP_JSON_PARSER } @@ -682,8 +674,7 @@ Ensure (jsonpull, fails_for_array_eof) assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_ARRAY_START)); gvm_json_pull_parser_next (&parser, &event); assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_ERROR)); - assert_that (event.error_message, - is_equal_to_string ("unexpected EOF")); + assert_that (event.error_message, is_equal_to_string ("unexpected EOF")); CLEANUP_JSON_PARSER } @@ -697,8 +688,7 @@ Ensure (jsonpull, fails_for_array_eof_after_value) assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_NUMBER)); gvm_json_pull_parser_next (&parser, &event); assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_ERROR)); - assert_that (event.error_message, - is_equal_to_string ("unexpected EOF")); + assert_that (event.error_message, is_equal_to_string ("unexpected EOF")); CLEANUP_JSON_PARSER } @@ -712,8 +702,7 @@ Ensure (jsonpull, fails_for_array_eof_after_comma) assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_NUMBER)); gvm_json_pull_parser_next (&parser, &event); assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_ERROR)); - assert_that (event.error_message, - is_equal_to_string ("unexpected EOF")); + assert_that (event.error_message, is_equal_to_string ("unexpected EOF")); CLEANUP_JSON_PARSER } @@ -729,7 +718,6 @@ Ensure (jsonpull, fails_for_array_read_error) CLEANUP_JSON_PARSER } - Ensure (jsonpull, fails_for_invalid_array_bracket) { INIT_JSON_PARSER ("[}"); @@ -794,8 +782,7 @@ Ensure (jsonpull, fails_for_object_key_eof) assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_OBJECT_START)); gvm_json_pull_parser_next (&parser, &event); assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_ERROR)); - assert_that (event.error_message, - is_equal_to_string ("unexpected EOF")); + assert_that (event.error_message, is_equal_to_string ("unexpected EOF")); CLEANUP_JSON_PARSER } @@ -858,8 +845,7 @@ Ensure (jsonpull, fails_for_object_colon_eof) assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_OBJECT_START)); gvm_json_pull_parser_next (&parser, &event); assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_ERROR)); - assert_that (event.error_message, - is_equal_to_string ("unexpected EOF")); + assert_that (event.error_message, is_equal_to_string ("unexpected EOF")); CLEANUP_JSON_PARSER } @@ -883,8 +869,7 @@ Ensure (jsonpull, fails_for_object_colon_other_char) assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_OBJECT_START)); gvm_json_pull_parser_next (&parser, &event); assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_ERROR)); - assert_that (event.error_message, - is_equal_to_string ("expected colon")); + assert_that (event.error_message, is_equal_to_string ("expected colon")); CLEANUP_JSON_PARSER } @@ -896,8 +881,7 @@ Ensure (jsonpull, fails_for_object_value_eof) assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_OBJECT_START)); gvm_json_pull_parser_next (&parser, &event); assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_ERROR)); - assert_that (event.error_message, - is_equal_to_string ("unexpected EOF")); + assert_that (event.error_message, is_equal_to_string ("unexpected EOF")); CLEANUP_JSON_PARSER } @@ -949,8 +933,7 @@ Ensure (jsonpull, fails_for_object_eof_after_value) assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_NUMBER)); gvm_json_pull_parser_next (&parser, &event); assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_ERROR)); - assert_that (event.error_message, - is_equal_to_string ("unexpected EOF")); + assert_that (event.error_message, is_equal_to_string ("unexpected EOF")); CLEANUP_JSON_PARSER } @@ -979,8 +962,7 @@ Ensure (jsonpull, fails_for_object_eof_after_comma) assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_NUMBER)); gvm_json_pull_parser_next (&parser, &event); assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_ERROR)); - assert_that (event.error_message, - is_equal_to_string ("unexpected EOF")); + assert_that (event.error_message, is_equal_to_string ("unexpected EOF")); CLEANUP_JSON_PARSER } @@ -1017,9 +999,8 @@ Ensure (jsonpull, fails_for_expand_before_container) cjson_value = gvm_json_pull_expand_container (&parser, &error_message); assert_that (cjson_value, is_null); - assert_that (error_message, - is_equal_to_string ("can only expand after" - " array or object start")); + assert_that (error_message, is_equal_to_string ("can only expand after" + " array or object start")); CLEANUP_JSON_PARSER } @@ -1037,9 +1018,8 @@ Ensure (jsonpull, fails_for_expand_after_value) cjson_value = gvm_json_pull_expand_container (&parser, &error_message); assert_that (cjson_value, is_null); - assert_that (error_message, - is_equal_to_string ("can only expand after" - " array or object start")); + assert_that (error_message, is_equal_to_string ("can only expand after" + " array or object start")); CLEANUP_JSON_PARSER } @@ -1145,7 +1125,6 @@ Ensure (jsonpull, fails_for_expand_read_error) CLEANUP_JSON_PARSER } - int main (int argc, char **argv) { @@ -1160,7 +1139,7 @@ main (int argc, char **argv) add_test_with_context (suite, jsonpull, can_parse_false); add_test_with_context (suite, jsonpull, can_parse_true); add_test_with_context (suite, jsonpull, can_parse_null); - + add_test_with_context (suite, jsonpull, can_parse_empty_strings); add_test_with_context (suite, jsonpull, can_parse_strings_with_content); From b702bb5a2f7014dc28cda036b6a7dbd3d53da558 Mon Sep 17 00:00:00 2001 From: Timo Pollmeier Date: Fri, 2 Aug 2024 09:11:28 +0200 Subject: [PATCH 05/11] Change PARSE_VALUE_NEXT_EXPECT macro to a function --- util/jsonpull.c | 36 ++++++++++++++++++++++-------------- 1 file changed, 22 insertions(+), 14 deletions(-) diff --git a/util/jsonpull.c b/util/jsonpull.c index a51458fd..48aaa237 100644 --- a/util/jsonpull.c +++ b/util/jsonpull.c @@ -459,11 +459,19 @@ gvm_json_pull_parse_keyword (gvm_json_pull_parser_t *parser, return 0; } -#define PARSE_VALUE_NEXT_EXPECT \ - if (parser->path->length) \ - parser->expect = GVM_JSON_PULL_EXPECT_COMMA; \ - else \ +/** + * @brief Updates the expectation for a JSON pull parser according to the path. + * + * @param[in] parser The parser to update. + */ +static void +parse_value_next_expect (gvm_json_pull_parser_t *parser) +{ + if (parser->path->length) + parser->expect = GVM_JSON_PULL_EXPECT_COMMA; + else parser->expect = GVM_JSON_PULL_EXPECT_EOF; +} /** * @brief Handles the case that an object key is expected in a JSON pull parser. @@ -520,7 +528,7 @@ gvm_json_pull_parse_key (gvm_json_pull_parser_t *parser, event->type = GVM_JSON_PULL_EVENT_OBJECT_END; event->value = NULL; gvm_json_pull_path_elem_free (g_queue_pop_tail (parser->path)); - PARSE_VALUE_NEXT_EXPECT + parse_value_next_expect (parser); gvm_json_pull_parser_next_char (parser); break; case ']': @@ -578,7 +586,7 @@ gvm_json_pull_parse_comma (gvm_json_pull_parser_t *parser, event->type = GVM_JSON_PULL_EVENT_ARRAY_END; event->value = NULL; gvm_json_pull_path_elem_free (g_queue_pop_tail (parser->path)); - PARSE_VALUE_NEXT_EXPECT + parse_value_next_expect (parser); gvm_json_pull_parser_next_char (parser); break; case '}': @@ -593,7 +601,7 @@ gvm_json_pull_parse_comma (gvm_json_pull_parser_t *parser, event->type = GVM_JSON_PULL_EVENT_OBJECT_END; event->value = NULL; gvm_json_pull_path_elem_free (g_queue_pop_tail (parser->path)); - PARSE_VALUE_NEXT_EXPECT + parse_value_next_expect (parser); gvm_json_pull_parser_next_char (parser); break; default: @@ -632,28 +640,28 @@ gvm_json_pull_parse_value (gvm_json_pull_parser_t *parser, return 1; event->type = GVM_JSON_PULL_EVENT_STRING; event->value = cjson_value; - PARSE_VALUE_NEXT_EXPECT + parse_value_next_expect (parser); break; case 'n': if (gvm_json_pull_parse_keyword (parser, event, "null")) return 1; event->type = GVM_JSON_PULL_EVENT_NULL; event->value = cJSON_CreateNull (); - PARSE_VALUE_NEXT_EXPECT + parse_value_next_expect (parser); break; case 'f': if (gvm_json_pull_parse_keyword (parser, event, "false")) return 1; event->type = GVM_JSON_PULL_EVENT_BOOLEAN; event->value = cJSON_CreateFalse (); - PARSE_VALUE_NEXT_EXPECT + parse_value_next_expect (parser); break; case 't': if (gvm_json_pull_parse_keyword (parser, event, "true")) return 1; event->type = GVM_JSON_PULL_EVENT_BOOLEAN; event->value = cJSON_CreateTrue (); - PARSE_VALUE_NEXT_EXPECT + parse_value_next_expect (parser); break; case '[': event->type = GVM_JSON_PULL_EVENT_ARRAY_START; @@ -675,7 +683,7 @@ gvm_json_pull_parse_value (gvm_json_pull_parser_t *parser, event->type = GVM_JSON_PULL_EVENT_ARRAY_END; event->value = NULL; gvm_json_pull_path_elem_free (g_queue_pop_tail (parser->path)); - PARSE_VALUE_NEXT_EXPECT + parse_value_next_expect (parser); gvm_json_pull_parser_next_char (parser); break; case '{': @@ -699,7 +707,7 @@ gvm_json_pull_parse_value (gvm_json_pull_parser_t *parser, return 1; event->type = GVM_JSON_PULL_EVENT_NUMBER; event->value = cjson_value; - PARSE_VALUE_NEXT_EXPECT + parse_value_next_expect (parser); } else { @@ -922,7 +930,7 @@ gvm_json_pull_expand_container (gvm_json_pull_parser_t *parser, expanded = cJSON_Parse (parser->parse_buffer->str); g_string_truncate (parser->parse_buffer, 0); - PARSE_VALUE_NEXT_EXPECT + parse_value_next_expect (parser); if (expanded == NULL && error_message) *error_message = g_strdup ("could not parse expanded container"); From ab408d90046ca4ef6c46c56e3a7796a327f04817 Mon Sep 17 00:00:00 2001 From: Timo Pollmeier Date: Fri, 2 Aug 2024 09:12:38 +0200 Subject: [PATCH 06/11] Add end of file newlines, remove extra #undefs --- util/jsonpull.c | 4 ---- util/jsonpull.h | 2 +- util/jsonpull_tests.c | 2 +- 3 files changed, 2 insertions(+), 6 deletions(-) diff --git a/util/jsonpull.c b/util/jsonpull.c index 48aaa237..71b2fe7d 100644 --- a/util/jsonpull.c +++ b/util/jsonpull.c @@ -972,7 +972,3 @@ gvm_json_path_to_string (GQueue *path) g_queue_foreach (path, (GFunc) gvm_json_path_string_add_elem, path_string); return g_string_free (path_string, FALSE); } - -#undef CASE_SPACES -#undef GVM_JSON_EOF -#undef GVM_JSON_ERROR \ No newline at end of file diff --git a/util/jsonpull.h b/util/jsonpull.h index 8d8343a0..0b057a49 100644 --- a/util/jsonpull.h +++ b/util/jsonpull.h @@ -134,4 +134,4 @@ gvm_json_pull_expand_container (gvm_json_pull_parser_t *, gchar **); gchar * gvm_json_path_to_string (GQueue *path); -#endif /* _GVM_JSONPULL_H */ \ No newline at end of file +#endif /* _GVM_JSONPULL_H */ diff --git a/util/jsonpull_tests.c b/util/jsonpull_tests.c index 808c4333..b8a3feed 100644 --- a/util/jsonpull_tests.c +++ b/util/jsonpull_tests.c @@ -1222,4 +1222,4 @@ main (int argc, char **argv) if (argc > 1) return run_single_test (suite, argv[1], create_text_reporter ()); return run_test_suite (suite, create_text_reporter ()); -} \ No newline at end of file +} From 65e9abf654a726cd5e151d4f76cdd2fd86a27563 Mon Sep 17 00:00:00 2001 From: Timo Pollmeier Date: Fri, 2 Aug 2024 09:17:23 +0200 Subject: [PATCH 07/11] Remove trailing space in doc comment --- util/jsonpull.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/util/jsonpull.c b/util/jsonpull.c index 71b2fe7d..4037b64e 100644 --- a/util/jsonpull.c +++ b/util/jsonpull.c @@ -461,7 +461,7 @@ gvm_json_pull_parse_keyword (gvm_json_pull_parser_t *parser, /** * @brief Updates the expectation for a JSON pull parser according to the path. - * + * * @param[in] parser The parser to update. */ static void From 49de1904dee24a64494fef23bdf33178a3548901 Mon Sep 17 00:00:00 2001 From: Timo Pollmeier Date: Fri, 2 Aug 2024 09:30:33 +0200 Subject: [PATCH 08/11] Add missing semicolons after macros in JSON parser --- util/jsonpull_tests.c | 192 +++++++++++++++++++++--------------------- 1 file changed, 96 insertions(+), 96 deletions(-) diff --git a/util/jsonpull_tests.c b/util/jsonpull_tests.c index b8a3feed..444f5a66 100644 --- a/util/jsonpull_tests.c +++ b/util/jsonpull_tests.c @@ -115,7 +115,7 @@ Ensure (jsonpull, can_parse_false) gvm_json_pull_parser_next (&parser, &event); assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_EOF)); - CLEANUP_JSON_PARSER + CLEANUP_JSON_PARSER; } Ensure (jsonpull, can_parse_true) @@ -129,7 +129,7 @@ Ensure (jsonpull, can_parse_true) gvm_json_pull_parser_next (&parser, &event); assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_EOF)); - CLEANUP_JSON_PARSER + CLEANUP_JSON_PARSER; } Ensure (jsonpull, can_parse_null) @@ -142,12 +142,12 @@ Ensure (jsonpull, can_parse_null) gvm_json_pull_parser_next (&parser, &event); assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_EOF)); - CLEANUP_JSON_PARSER + CLEANUP_JSON_PARSER; } Ensure (jsonpull, can_parse_empty_strings) { - INIT_JSON_PARSER ("\"\"") + INIT_JSON_PARSER ("\"\""); gvm_json_pull_parser_next (&parser, &event); assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_STRING)); @@ -155,12 +155,12 @@ Ensure (jsonpull, can_parse_empty_strings) gvm_json_pull_parser_next (&parser, &event); assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_EOF)); - CLEANUP_JSON_PARSER + CLEANUP_JSON_PARSER; } Ensure (jsonpull, can_parse_strings_with_content) { - INIT_JSON_PARSER ("\n\"123\\tXYZ\\nÄöü\"\n") + INIT_JSON_PARSER ("\n\"123\\tXYZ\\nÄöü\"\n"); gvm_json_pull_parser_next (&parser, &event); assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_STRING)); @@ -168,12 +168,12 @@ Ensure (jsonpull, can_parse_strings_with_content) gvm_json_pull_parser_next (&parser, &event); assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_EOF)); - CLEANUP_JSON_PARSER + CLEANUP_JSON_PARSER; } Ensure (jsonpull, can_parse_integer_numbers) { - INIT_JSON_PARSER ("-0987") + INIT_JSON_PARSER ("-0987"); gvm_json_pull_parser_next (&parser, &event); assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_NUMBER)); @@ -181,7 +181,7 @@ Ensure (jsonpull, can_parse_integer_numbers) gvm_json_pull_parser_next (&parser, &event); assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_EOF)); - CLEANUP_JSON_PARSER + CLEANUP_JSON_PARSER; } Ensure (jsonpull, can_parse_floating_point_numbers) @@ -194,7 +194,7 @@ Ensure (jsonpull, can_parse_floating_point_numbers) gvm_json_pull_parser_next (&parser, &event); assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_EOF)); - CLEANUP_JSON_PARSER + CLEANUP_JSON_PARSER; } Ensure (jsonpull, can_parse_empty_arrays) @@ -209,7 +209,7 @@ Ensure (jsonpull, can_parse_empty_arrays) gvm_json_pull_parser_next (&parser, &event); assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_EOF)); - CLEANUP_JSON_PARSER + CLEANUP_JSON_PARSER; } Ensure (jsonpull, can_parse_single_elem_arrays) @@ -223,14 +223,14 @@ Ensure (jsonpull, can_parse_single_elem_arrays) gvm_json_pull_parser_next (&parser, &event); assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_NUMBER)); assert_that (event.value->valueint, is_equal_to (123)); - CHECK_PATH_EQUALS ("$[0]") + CHECK_PATH_EQUALS ("$[0]"); gvm_json_pull_parser_next (&parser, &event); assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_ARRAY_END)); gvm_json_pull_parser_next (&parser, &event); assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_EOF)); - CLEANUP_JSON_PARSER + CLEANUP_JSON_PARSER; } Ensure (jsonpull, can_parse_multiple_elem_arrays) @@ -244,23 +244,23 @@ Ensure (jsonpull, can_parse_multiple_elem_arrays) gvm_json_pull_parser_next (&parser, &event); assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_NUMBER)); assert_that (event.value->valueint, is_equal_to (123)); - CHECK_PATH_EQUALS ("$[0]") + CHECK_PATH_EQUALS ("$[0]"); gvm_json_pull_parser_next (&parser, &event); assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_STRING)); assert_that (event.value->valuestring, is_equal_to_string ("ABC")); - CHECK_PATH_EQUALS ("$[1]") + CHECK_PATH_EQUALS ("$[1]"); gvm_json_pull_parser_next (&parser, &event); assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_NULL)); - CHECK_PATH_EQUALS ("$[2]") + CHECK_PATH_EQUALS ("$[2]"); gvm_json_pull_parser_next (&parser, &event); assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_ARRAY_END)); gvm_json_pull_parser_next (&parser, &event); assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_EOF)); - CLEANUP_JSON_PARSER + CLEANUP_JSON_PARSER; } Ensure (jsonpull, can_parse_empty_objects) @@ -275,7 +275,7 @@ Ensure (jsonpull, can_parse_empty_objects) gvm_json_pull_parser_next (&parser, &event); assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_EOF)); - CLEANUP_JSON_PARSER + CLEANUP_JSON_PARSER; } Ensure (jsonpull, can_parse_single_elem_objects) @@ -289,14 +289,14 @@ Ensure (jsonpull, can_parse_single_elem_objects) gvm_json_pull_parser_next (&parser, &event); assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_STRING)); assert_that (event.value->valuestring, is_equal_to_string ("valueA")); - CHECK_PATH_EQUALS ("$['keyA']") + CHECK_PATH_EQUALS ("$['keyA']"); gvm_json_pull_parser_next (&parser, &event); assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_OBJECT_END)); gvm_json_pull_parser_next (&parser, &event); assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_EOF)); - CLEANUP_JSON_PARSER + CLEANUP_JSON_PARSER; } Ensure (jsonpull, can_parse_multiple_elem_objects) @@ -310,19 +310,19 @@ Ensure (jsonpull, can_parse_multiple_elem_objects) gvm_json_pull_parser_next (&parser, &event); assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_STRING)); assert_that (event.value->valuestring, is_equal_to_string ("valueA")); - CHECK_PATH_EQUALS ("$['keyA']") + CHECK_PATH_EQUALS ("$['keyA']"); gvm_json_pull_parser_next (&parser, &event); assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_NUMBER)); assert_that (event.value->valueint, is_equal_to (12345)); - CHECK_PATH_EQUALS ("$['keyB']") + CHECK_PATH_EQUALS ("$['keyB']"); gvm_json_pull_parser_next (&parser, &event); assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_OBJECT_END)); gvm_json_pull_parser_next (&parser, &event); assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_EOF)); - CLEANUP_JSON_PARSER + CLEANUP_JSON_PARSER; } Ensure (jsonpull, can_parse_nested_containers) @@ -332,71 +332,71 @@ Ensure (jsonpull, can_parse_nested_containers) gvm_json_pull_parser_next (&parser, &event); assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_ARRAY_START)); - CHECK_PATH_EQUALS ("$") + CHECK_PATH_EQUALS ("$"); gvm_json_pull_parser_next (&parser, &event); assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_OBJECT_START)); - CHECK_PATH_EQUALS ("$[0]") + CHECK_PATH_EQUALS ("$[0]"); gvm_json_pull_parser_next (&parser, &event); assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_NULL)); - CHECK_PATH_EQUALS ("$[0]['A']") + CHECK_PATH_EQUALS ("$[0]['A']"); gvm_json_pull_parser_next (&parser, &event); assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_OBJECT_START)); - CHECK_PATH_EQUALS ("$[0]['B']") + CHECK_PATH_EQUALS ("$[0]['B']"); gvm_json_pull_parser_next (&parser, &event); assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_ARRAY_START)); - CHECK_PATH_EQUALS ("$[0]['B']['C']") + CHECK_PATH_EQUALS ("$[0]['B']['C']"); gvm_json_pull_parser_next (&parser, &event); assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_NUMBER)); assert_that (event.value->valueint, is_equal_to (1)); - CHECK_PATH_EQUALS ("$[0]['B']['C'][0]") + CHECK_PATH_EQUALS ("$[0]['B']['C'][0]"); gvm_json_pull_parser_next (&parser, &event); assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_NUMBER)); assert_that (event.value->valueint, is_equal_to (2)); - CHECK_PATH_EQUALS ("$[0]['B']['C'][1]") + CHECK_PATH_EQUALS ("$[0]['B']['C'][1]"); gvm_json_pull_parser_next (&parser, &event); assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_ARRAY_END)); - CHECK_PATH_EQUALS ("$[0]['B']['C']") + CHECK_PATH_EQUALS ("$[0]['B']['C']"); gvm_json_pull_parser_next (&parser, &event); assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_OBJECT_END)); - CHECK_PATH_EQUALS ("$[0]['B']") + CHECK_PATH_EQUALS ("$[0]['B']"); gvm_json_pull_parser_next (&parser, &event); assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_STRING)); assert_that (event.value->valuestring, is_equal_to_string ("3")); - CHECK_PATH_EQUALS ("$[0]['D']") + CHECK_PATH_EQUALS ("$[0]['D']"); gvm_json_pull_parser_next (&parser, &event); assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_OBJECT_END)); - CHECK_PATH_EQUALS ("$[0]") + CHECK_PATH_EQUALS ("$[0]"); gvm_json_pull_parser_next (&parser, &event); assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_ARRAY_START)); - CHECK_PATH_EQUALS ("$[1]") + CHECK_PATH_EQUALS ("$[1]"); gvm_json_pull_parser_next (&parser, &event); assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_NUMBER)); assert_that (event.value->valueint, is_equal_to (4)); - CHECK_PATH_EQUALS ("$[1][0]") + CHECK_PATH_EQUALS ("$[1][0]"); gvm_json_pull_parser_next (&parser, &event); assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_ARRAY_END)); - CHECK_PATH_EQUALS ("$[1]") + CHECK_PATH_EQUALS ("$[1]"); gvm_json_pull_parser_next (&parser, &event); assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_ARRAY_END)); - CHECK_PATH_EQUALS ("$") + CHECK_PATH_EQUALS ("$"); gvm_json_pull_parser_next (&parser, &event); assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_EOF)); - CLEANUP_JSON_PARSER + CLEANUP_JSON_PARSER; } Ensure (jsonpull, can_expand_arrays) @@ -407,12 +407,12 @@ Ensure (jsonpull, can_expand_arrays) gvm_json_pull_parser_next (&parser, &event); assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_ARRAY_START)); - CHECK_PATH_EQUALS ("$") + CHECK_PATH_EQUALS ("$"); // empty array gvm_json_pull_parser_next (&parser, &event); assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_ARRAY_START)); - CHECK_PATH_EQUALS ("$[0]") + CHECK_PATH_EQUALS ("$[0]"); expanded = gvm_json_pull_expand_container (&parser, &error_message); assert_that (error_message, is_equal_to_string (NULL)); assert_that (expanded, is_not_null); @@ -423,7 +423,7 @@ Ensure (jsonpull, can_expand_arrays) // single-element array gvm_json_pull_parser_next (&parser, &event); assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_ARRAY_START)); - CHECK_PATH_EQUALS ("$[1]") + CHECK_PATH_EQUALS ("$[1]"); expanded = gvm_json_pull_expand_container (&parser, &error_message); assert_that (error_message, is_null); assert_that (expanded, is_not_null); @@ -439,7 +439,7 @@ Ensure (jsonpull, can_expand_arrays) // multi-element array gvm_json_pull_parser_next (&parser, &event); assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_ARRAY_START)); - CHECK_PATH_EQUALS ("$[2]") + CHECK_PATH_EQUALS ("$[2]"); expanded = gvm_json_pull_expand_container (&parser, &error_message); assert_that (error_message, is_null); assert_that (expanded, is_not_null); @@ -457,7 +457,7 @@ Ensure (jsonpull, can_expand_arrays) // string array gvm_json_pull_parser_next (&parser, &event); assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_ARRAY_START)); - CHECK_PATH_EQUALS ("$[3]") + CHECK_PATH_EQUALS ("$[3]"); expanded = gvm_json_pull_expand_container (&parser, &error_message); assert_that (error_message, is_null); assert_that (expanded, is_not_null); @@ -475,11 +475,11 @@ Ensure (jsonpull, can_expand_arrays) // array end and EOF gvm_json_pull_parser_next (&parser, &event); assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_ARRAY_END)); - CHECK_PATH_EQUALS ("$") + CHECK_PATH_EQUALS ("$"); gvm_json_pull_parser_next (&parser, &event); assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_EOF)); - CLEANUP_JSON_PARSER + CLEANUP_JSON_PARSER; } Ensure (jsonpull, can_expand_objects) @@ -491,11 +491,11 @@ Ensure (jsonpull, can_expand_objects) gvm_json_pull_parser_next (&parser, &event); assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_OBJECT_START)); - CHECK_PATH_EQUALS ("$") + CHECK_PATH_EQUALS ("$"); gvm_json_pull_parser_next (&parser, &event); assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_OBJECT_START)); - CHECK_PATH_EQUALS ("$['A']") + CHECK_PATH_EQUALS ("$['A']"); expanded = gvm_json_pull_expand_container (&parser, &error_message); assert_that (error_message, is_null); assert_that (cJSON_IsObject (expanded), is_true); @@ -504,7 +504,7 @@ Ensure (jsonpull, can_expand_objects) gvm_json_pull_parser_next (&parser, &event); assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_OBJECT_START)); - CHECK_PATH_EQUALS ("$['B']") + CHECK_PATH_EQUALS ("$['B']"); expanded = gvm_json_pull_expand_container (&parser, &error_message); assert_that (error_message, is_null); assert_that (cJSON_IsObject (expanded), is_true); @@ -528,16 +528,16 @@ Ensure (jsonpull, can_expand_objects) // object end and EOF gvm_json_pull_parser_next (&parser, &event); assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_OBJECT_END)); - CHECK_PATH_EQUALS ("$") + CHECK_PATH_EQUALS ("$"); gvm_json_pull_parser_next (&parser, &event); assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_EOF)); - CLEANUP_JSON_PARSER + CLEANUP_JSON_PARSER; } Ensure (jsonpull, fails_for_read_error) { - INIT_READ_ERROR_JSON_PARSER ("123") + INIT_READ_ERROR_JSON_PARSER ("123"); gvm_json_pull_parser_next (&parser, &event); assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_ERROR)); @@ -555,7 +555,7 @@ Ensure (jsonpull, fails_for_misspelled_true) assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_ERROR)); assert_that (event.error_message, is_equal_to_string ("misspelled keyword 'true'")); - CLEANUP_JSON_PARSER + CLEANUP_JSON_PARSER; } Ensure (jsonpull, fails_for_incomplete_true) @@ -565,7 +565,7 @@ Ensure (jsonpull, fails_for_incomplete_true) gvm_json_pull_parser_next (&parser, &event); assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_ERROR)); assert_that (event.error_message, is_equal_to_string ("unexpected EOF")); - CLEANUP_JSON_PARSER + CLEANUP_JSON_PARSER; } Ensure (jsonpull, fails_for_misspelled_false) @@ -576,7 +576,7 @@ Ensure (jsonpull, fails_for_misspelled_false) assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_ERROR)); assert_that (event.error_message, is_equal_to_string ("misspelled keyword 'false'")); - CLEANUP_JSON_PARSER + CLEANUP_JSON_PARSER; } Ensure (jsonpull, fails_for_misspelled_null) @@ -587,7 +587,7 @@ Ensure (jsonpull, fails_for_misspelled_null) assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_ERROR)); assert_that (event.error_message, is_equal_to_string ("misspelled keyword 'null'")); - CLEANUP_JSON_PARSER + CLEANUP_JSON_PARSER; } Ensure (jsonpull, fails_for_string_read_error) @@ -597,7 +597,7 @@ Ensure (jsonpull, fails_for_string_read_error) gvm_json_pull_parser_next (&parser, &event); assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_ERROR)); assert_that (event.error_message, is_equal_to_string (JSON_READ_ERROR)); - CLEANUP_JSON_PARSER + CLEANUP_JSON_PARSER; } Ensure (jsonpull, fails_for_string_eof) @@ -607,7 +607,7 @@ Ensure (jsonpull, fails_for_string_eof) gvm_json_pull_parser_next (&parser, &event); assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_ERROR)); assert_that (event.error_message, is_equal_to_string ("unexpected EOF")); - CLEANUP_JSON_PARSER + CLEANUP_JSON_PARSER; } Ensure (jsonpull, fails_for_overlong_string) @@ -619,7 +619,7 @@ Ensure (jsonpull, fails_for_overlong_string) assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_ERROR)); assert_that (event.error_message, is_equal_to_string ("string exceeds size limit of 10 bytes")); - CLEANUP_JSON_PARSER + CLEANUP_JSON_PARSER; } Ensure (jsonpull, fails_for_invalid_string) @@ -630,7 +630,7 @@ Ensure (jsonpull, fails_for_invalid_string) assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_ERROR)); assert_that (event.error_message, is_equal_to_string ("error parsing string")); - CLEANUP_JSON_PARSER + CLEANUP_JSON_PARSER; } Ensure (jsonpull, fails_for_number_read_error) @@ -640,7 +640,7 @@ Ensure (jsonpull, fails_for_number_read_error) gvm_json_pull_parser_next (&parser, &event); assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_ERROR)); assert_that (event.error_message, is_equal_to_string (JSON_READ_ERROR)); - CLEANUP_JSON_PARSER + CLEANUP_JSON_PARSER; } Ensure (jsonpull, fails_for_overlong_number) @@ -652,7 +652,7 @@ Ensure (jsonpull, fails_for_overlong_number) assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_ERROR)); assert_that (event.error_message, is_equal_to_string ("number exceeds size limit of 10 bytes")); - CLEANUP_JSON_PARSER + CLEANUP_JSON_PARSER; } Ensure (jsonpull, fails_for_invalid_number) @@ -663,7 +663,7 @@ Ensure (jsonpull, fails_for_invalid_number) assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_ERROR)); assert_that (event.error_message, is_equal_to_string ("error parsing number")); - CLEANUP_JSON_PARSER + CLEANUP_JSON_PARSER; } Ensure (jsonpull, fails_for_array_eof) @@ -675,7 +675,7 @@ Ensure (jsonpull, fails_for_array_eof) gvm_json_pull_parser_next (&parser, &event); assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_ERROR)); assert_that (event.error_message, is_equal_to_string ("unexpected EOF")); - CLEANUP_JSON_PARSER + CLEANUP_JSON_PARSER; } Ensure (jsonpull, fails_for_array_eof_after_value) @@ -689,7 +689,7 @@ Ensure (jsonpull, fails_for_array_eof_after_value) gvm_json_pull_parser_next (&parser, &event); assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_ERROR)); assert_that (event.error_message, is_equal_to_string ("unexpected EOF")); - CLEANUP_JSON_PARSER + CLEANUP_JSON_PARSER; } Ensure (jsonpull, fails_for_array_eof_after_comma) @@ -703,7 +703,7 @@ Ensure (jsonpull, fails_for_array_eof_after_comma) gvm_json_pull_parser_next (&parser, &event); assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_ERROR)); assert_that (event.error_message, is_equal_to_string ("unexpected EOF")); - CLEANUP_JSON_PARSER + CLEANUP_JSON_PARSER; } Ensure (jsonpull, fails_for_array_read_error) @@ -715,7 +715,7 @@ Ensure (jsonpull, fails_for_array_read_error) gvm_json_pull_parser_next (&parser, &event); assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_ERROR)); assert_that (event.error_message, is_equal_to_string (JSON_READ_ERROR)); - CLEANUP_JSON_PARSER + CLEANUP_JSON_PARSER; } Ensure (jsonpull, fails_for_invalid_array_bracket) @@ -728,7 +728,7 @@ Ensure (jsonpull, fails_for_invalid_array_bracket) assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_ERROR)); assert_that (event.error_message, is_equal_to_string ("unexpected closing curly brace")); - CLEANUP_JSON_PARSER + CLEANUP_JSON_PARSER; } Ensure (jsonpull, fails_for_invalid_array_bracket_after_value) @@ -743,7 +743,7 @@ Ensure (jsonpull, fails_for_invalid_array_bracket_after_value) assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_ERROR)); assert_that (event.error_message, is_equal_to_string ("unexpected closing curly brace")); - CLEANUP_JSON_PARSER + CLEANUP_JSON_PARSER; } Ensure (jsonpull, fails_for_invalid_array_other_char) @@ -756,7 +756,7 @@ Ensure (jsonpull, fails_for_invalid_array_other_char) assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_ERROR)); assert_that (event.error_message, is_equal_to_string ("unexpected character")); - CLEANUP_JSON_PARSER + CLEANUP_JSON_PARSER; } Ensure (jsonpull, fails_for_invalid_array_other_char_after_value) @@ -771,7 +771,7 @@ Ensure (jsonpull, fails_for_invalid_array_other_char_after_value) assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_ERROR)); assert_that (event.error_message, is_equal_to_string ("expected comma or end of container")); - CLEANUP_JSON_PARSER + CLEANUP_JSON_PARSER; } Ensure (jsonpull, fails_for_object_key_eof) @@ -783,7 +783,7 @@ Ensure (jsonpull, fails_for_object_key_eof) gvm_json_pull_parser_next (&parser, &event); assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_ERROR)); assert_that (event.error_message, is_equal_to_string ("unexpected EOF")); - CLEANUP_JSON_PARSER + CLEANUP_JSON_PARSER; } Ensure (jsonpull, fails_for_object_key_read_error) @@ -795,7 +795,7 @@ Ensure (jsonpull, fails_for_object_key_read_error) gvm_json_pull_parser_next (&parser, &event); assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_ERROR)); assert_that (event.error_message, is_equal_to_string (JSON_READ_ERROR)); - CLEANUP_JSON_PARSER + CLEANUP_JSON_PARSER; } Ensure (jsonpull, fails_for_object_key_invalid_string) @@ -808,7 +808,7 @@ Ensure (jsonpull, fails_for_object_key_invalid_string) assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_ERROR)); assert_that (event.error_message, is_equal_to_string ("error parsing string")); - CLEANUP_JSON_PARSER + CLEANUP_JSON_PARSER; } Ensure (jsonpull, fails_for_invalid_object_key_bracket) @@ -821,7 +821,7 @@ Ensure (jsonpull, fails_for_invalid_object_key_bracket) assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_ERROR)); assert_that (event.error_message, is_equal_to_string ("unexpected closing square bracket")); - CLEANUP_JSON_PARSER + CLEANUP_JSON_PARSER; } Ensure (jsonpull, fails_for_invalid_object_key_other_char) @@ -834,7 +834,7 @@ Ensure (jsonpull, fails_for_invalid_object_key_other_char) assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_ERROR)); assert_that (event.error_message, is_equal_to_string ("unexpected character")); - CLEANUP_JSON_PARSER + CLEANUP_JSON_PARSER; } Ensure (jsonpull, fails_for_object_colon_eof) @@ -846,7 +846,7 @@ Ensure (jsonpull, fails_for_object_colon_eof) gvm_json_pull_parser_next (&parser, &event); assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_ERROR)); assert_that (event.error_message, is_equal_to_string ("unexpected EOF")); - CLEANUP_JSON_PARSER + CLEANUP_JSON_PARSER; } Ensure (jsonpull, fails_for_object_colon_read_error) @@ -858,7 +858,7 @@ Ensure (jsonpull, fails_for_object_colon_read_error) gvm_json_pull_parser_next (&parser, &event); assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_ERROR)); assert_that (event.error_message, is_equal_to_string (JSON_READ_ERROR)); - CLEANUP_JSON_PARSER + CLEANUP_JSON_PARSER; } Ensure (jsonpull, fails_for_object_colon_other_char) @@ -870,7 +870,7 @@ Ensure (jsonpull, fails_for_object_colon_other_char) gvm_json_pull_parser_next (&parser, &event); assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_ERROR)); assert_that (event.error_message, is_equal_to_string ("expected colon")); - CLEANUP_JSON_PARSER + CLEANUP_JSON_PARSER; } Ensure (jsonpull, fails_for_object_value_eof) @@ -882,7 +882,7 @@ Ensure (jsonpull, fails_for_object_value_eof) gvm_json_pull_parser_next (&parser, &event); assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_ERROR)); assert_that (event.error_message, is_equal_to_string ("unexpected EOF")); - CLEANUP_JSON_PARSER + CLEANUP_JSON_PARSER; } Ensure (jsonpull, fails_for_object_value_read_error) @@ -894,7 +894,7 @@ Ensure (jsonpull, fails_for_object_value_read_error) gvm_json_pull_parser_next (&parser, &event); assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_ERROR)); assert_that (event.error_message, is_equal_to_string (JSON_READ_ERROR)); - CLEANUP_JSON_PARSER + CLEANUP_JSON_PARSER; } Ensure (jsonpull, fails_for_object_value_curly_brace) @@ -907,7 +907,7 @@ Ensure (jsonpull, fails_for_object_value_curly_brace) assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_ERROR)); assert_that (event.error_message, is_equal_to_string ("unexpected closing curly brace")); - CLEANUP_JSON_PARSER + CLEANUP_JSON_PARSER; } Ensure (jsonpull, fails_for_object_value_square_bracket) @@ -920,7 +920,7 @@ Ensure (jsonpull, fails_for_object_value_square_bracket) assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_ERROR)); assert_that (event.error_message, is_equal_to_string ("unexpected closing square bracket")); - CLEANUP_JSON_PARSER + CLEANUP_JSON_PARSER; } Ensure (jsonpull, fails_for_object_eof_after_value) @@ -934,7 +934,7 @@ Ensure (jsonpull, fails_for_object_eof_after_value) gvm_json_pull_parser_next (&parser, &event); assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_ERROR)); assert_that (event.error_message, is_equal_to_string ("unexpected EOF")); - CLEANUP_JSON_PARSER + CLEANUP_JSON_PARSER; } Ensure (jsonpull, fails_for_object_square_bracket_after_value) @@ -949,7 +949,7 @@ Ensure (jsonpull, fails_for_object_square_bracket_after_value) assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_ERROR)); assert_that (event.error_message, is_equal_to_string ("unexpected closing square bracket")); - CLEANUP_JSON_PARSER + CLEANUP_JSON_PARSER; } Ensure (jsonpull, fails_for_object_eof_after_comma) @@ -963,7 +963,7 @@ Ensure (jsonpull, fails_for_object_eof_after_comma) gvm_json_pull_parser_next (&parser, &event); assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_ERROR)); assert_that (event.error_message, is_equal_to_string ("unexpected EOF")); - CLEANUP_JSON_PARSER + CLEANUP_JSON_PARSER; } Ensure (jsonpull, fails_for_read_error_after_doc_end) @@ -975,7 +975,7 @@ Ensure (jsonpull, fails_for_read_error_after_doc_end) gvm_json_pull_parser_next (&parser, &event); assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_ERROR)); assert_that (event.error_message, is_equal_to_string (JSON_READ_ERROR)); - CLEANUP_JSON_PARSER + CLEANUP_JSON_PARSER; } Ensure (jsonpull, fails_for_content_after_doc_end) @@ -988,7 +988,7 @@ Ensure (jsonpull, fails_for_content_after_doc_end) assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_ERROR)); assert_that (event.error_message, is_equal_to_string ("unexpected character at end of file (52)")); - CLEANUP_JSON_PARSER + CLEANUP_JSON_PARSER; } Ensure (jsonpull, fails_for_expand_before_container) @@ -1002,7 +1002,7 @@ Ensure (jsonpull, fails_for_expand_before_container) assert_that (error_message, is_equal_to_string ("can only expand after" " array or object start")); - CLEANUP_JSON_PARSER + CLEANUP_JSON_PARSER; } Ensure (jsonpull, fails_for_expand_after_value) @@ -1021,7 +1021,7 @@ Ensure (jsonpull, fails_for_expand_after_value) assert_that (error_message, is_equal_to_string ("can only expand after" " array or object start")); - CLEANUP_JSON_PARSER + CLEANUP_JSON_PARSER; } Ensure (jsonpull, fails_for_expand_invalid_content) @@ -1038,7 +1038,7 @@ Ensure (jsonpull, fails_for_expand_invalid_content) assert_that (error_message, is_equal_to_string ("could not parse expanded container")); - CLEANUP_JSON_PARSER + CLEANUP_JSON_PARSER; } Ensure (jsonpull, fails_for_expand_overlong) @@ -1056,7 +1056,7 @@ Ensure (jsonpull, fails_for_expand_overlong) assert_that (error_message, is_equal_to_string ("container exceeds size limit of 10 bytes")); - CLEANUP_JSON_PARSER + CLEANUP_JSON_PARSER; } Ensure (jsonpull, fails_for_expand_unexpected_curly_brace) @@ -1073,7 +1073,7 @@ Ensure (jsonpull, fails_for_expand_unexpected_curly_brace) assert_that (error_message, is_equal_to_string ("unexpected closing curly brace")); - CLEANUP_JSON_PARSER + CLEANUP_JSON_PARSER; } Ensure (jsonpull, fails_for_expand_unexpected_square_bracket) @@ -1090,7 +1090,7 @@ Ensure (jsonpull, fails_for_expand_unexpected_square_bracket) assert_that (error_message, is_equal_to_string ("unexpected closing square bracket")); - CLEANUP_JSON_PARSER + CLEANUP_JSON_PARSER; } Ensure (jsonpull, fails_for_expand_eof) @@ -1106,7 +1106,7 @@ Ensure (jsonpull, fails_for_expand_eof) assert_that (cjson_value, is_null); assert_that (error_message, is_equal_to_string ("unexpected EOF")); - CLEANUP_JSON_PARSER + CLEANUP_JSON_PARSER; } Ensure (jsonpull, fails_for_expand_read_error) @@ -1122,7 +1122,7 @@ Ensure (jsonpull, fails_for_expand_read_error) assert_that (cjson_value, is_null); assert_that (error_message, is_equal_to_string (JSON_READ_ERROR)); - CLEANUP_JSON_PARSER + CLEANUP_JSON_PARSER; } int From 4869beb93edd0d9dc23cc6db04b3b7e7e05b9123 Mon Sep 17 00:00:00 2001 From: Timo Pollmeier Date: Fri, 2 Aug 2024 12:34:00 +0200 Subject: [PATCH 09/11] Remove stray semicolon in jsonpull.c --- util/jsonpull.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/util/jsonpull.c b/util/jsonpull.c index 4037b64e..c8b51f86 100644 --- a/util/jsonpull.c +++ b/util/jsonpull.c @@ -25,7 +25,7 @@ gvm_json_string_escape (const char *string, gboolean single_quote) for (point = (char *) string; *point != 0; point++) { unsigned char character = *point; - ; + if ((character > 31) && (character != '\\') && (single_quote || character != '\"') && (!single_quote || character != '\'')) From 4f9d16c23174369e799b303b1deca8c6f849b57e Mon Sep 17 00:00:00 2001 From: Johannes Helmold <83279292+jhelmold@users.noreply.github.com> Date: Wed, 21 Aug 2024 09:32:26 +0200 Subject: [PATCH 10/11] Update util/jsonpull.c Co-authored-by: Matt Mundell <32057441+mattmundell@users.noreply.github.com> --- util/jsonpull.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/util/jsonpull.c b/util/jsonpull.c index c8b51f86..c2c83c98 100644 --- a/util/jsonpull.c +++ b/util/jsonpull.c @@ -613,7 +613,7 @@ gvm_json_pull_parse_comma (gvm_json_pull_parser_t *parser, } /** - * @brief Handles the case that a value in a JSON pull parser. + * @brief Handles the case that a value is expected in a JSON pull parser. * * This will continue the parsing until a value or the end of the * current array/object was parsed or an error occurred. From 1bc1415da50ede438db17bddb1c7588f7c8a4edc Mon Sep 17 00:00:00 2001 From: Ahmed Abdelsalam Date: Mon, 16 Sep 2024 11:09:55 +0200 Subject: [PATCH 11/11] Apply review comments --- util/jsonpull.c | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/util/jsonpull.c b/util/jsonpull.c index c2c83c98..03dddf42 100644 --- a/util/jsonpull.c +++ b/util/jsonpull.c @@ -13,6 +13,11 @@ /** * @brief Escapes a string according to the JSON or JSONPath standard + * + * @param[in] string The string to escape + * @param[in] single_quote Whether to escape single quotes + * + * @return The escaped string */ gchar * gvm_json_string_escape (const char *string, gboolean single_quote) @@ -27,8 +32,7 @@ gvm_json_string_escape (const char *string, gboolean single_quote) unsigned char character = *point; if ((character > 31) && (character != '\\') - && (single_quote || character != '\"') - && (!single_quote || character != '\'')) + && (single_quote ? (character != '\'') : (character != '\"'))) { g_string_append_c (escaped, character); } @@ -115,6 +119,8 @@ void gvm_json_pull_event_reset (gvm_json_pull_event_t *event) { cJSON_free (event->value); + if (event->error_message) + g_free (event->error_message); memset (event, 0, sizeof (gvm_json_pull_event_t)); } @@ -127,6 +133,8 @@ void gvm_json_pull_event_cleanup (gvm_json_pull_event_t *event) { cJSON_free (event->value); + if (event->error_message) + g_free (event->error_message); memset (event, 0, sizeof (gvm_json_pull_event_t)); } @@ -230,6 +238,8 @@ gvm_json_pull_check_parse_buffer_size (const char *value_type, /** * @brief Reads the next character in a pull parser input stream. * + * @param[in] parser The parser to read the next character from + * * @return The character code, GVM_JSON_CHAR_ERROR or GVM_JSON_CHAR_EOF. */ static int @@ -773,12 +783,6 @@ gvm_json_pull_parser_next (gvm_json_pull_parser_t *parser, return; } - if (parser->expect == GVM_JSON_PULL_EXPECT_KEY) - { - if (gvm_json_pull_parse_key (parser, event)) - return; - } - if (parser->expect == GVM_JSON_PULL_EXPECT_COMMA) { if (gvm_json_pull_parse_comma (parser, event))