jsonpull.c
Go to the documentation of this file.
/* 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
#define GVM_JSON_CHAR_ERROR -2
#define GVM_JSON_CHAR_UNDEFINED -3
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;
}
void
gvm_json_pull_path_elem_free (gvm_json_path_elem_t *elem)
{
g_free (elem->key);
g_free (elem);
}
void
gvm_json_pull_event_init (gvm_json_pull_event_t *event)
{
memset (event, 0, sizeof (gvm_json_pull_event_t));
}
void
gvm_json_pull_event_cleanup (gvm_json_pull_event_t *event)
{
cJSON_Delete (event->value);
if (event->error_message)
g_free (event->error_message);
memset (event, 0, sizeof (gvm_json_pull_event_t));
}
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;
}
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);
}
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));
}
static gchar *
gvm_json_read_stream_error_str ()
{
return g_strdup_printf ("error reading JSON stream: %s", strerror (errno));
}
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;
}
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;
}
}
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;
}
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;
}
}
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;
}
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);
}
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);
}
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;
}
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;
}
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_Delete (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");
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 '}':
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 (parser);
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;
}
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 (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 (parser);
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;
}
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 (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 (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 (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 (parser);
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 (parser);
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 '}':
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)
|| 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 (parser);
}
else
{
event->type = GVM_JSON_PULL_EVENT_ERROR;
event->error_message = g_strdup ("unexpected character");
return 1;
}
}
return 0;
}
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_cleanup (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))
{
// EOF was reached, or an error occurred.
// The event type is already set, and if an error occurred, then
// error_message is also already set.
return;
}
// Skipping space succeeded. Check for unexpected characters at EOF.
if (parser->last_read_char == GVM_JSON_CHAR_EOF)
return;
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;
}
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);
}
}
cJSON *
gvm_json_pull_expand_container (gvm_json_pull_parser_t *parser,
gchar **error_message)
{
gvm_json_path_elem_t *path_tail = NULL;
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;
// 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;
}
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 closing square bracket");
gvm_json_pull_path_elem_free (path_tail);
return NULL;
}
if (path_tail->depth == start_depth)
in_expanded_container = FALSE;
gvm_json_pull_path_elem_free (path_tail);
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 closing curly brace");
gvm_json_pull_path_elem_free (path_tail);
return NULL;
}
if (path_tail->depth == start_depth)
in_expanded_container = FALSE;
gvm_json_pull_path_elem_free (path_tail);
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 (parser);
if (expanded == NULL && error_message)
*error_message = g_strdup ("could not parse expanded container");
return expanded;
}
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)
{
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);
}
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);
}
gvm_json_string_escape
gchar * gvm_json_string_escape(const char *string, gboolean single_quote)
Escapes a string according to the JSON or JSONPath standard.
Definition json.c:17
gvm_json_pull_parse_number
static int gvm_json_pull_parse_number(gvm_json_pull_parser_t *parser, gvm_json_pull_event_t *event, cJSON **cjson_value)
Parses a number in a JSON pull parser.
Definition jsonpull.c:337
gvm_json_pull_parser_cleanup
void gvm_json_pull_parser_cleanup(gvm_json_pull_parser_t *parser)
Frees the data of a JSON pull parser.
Definition jsonpull.c:120
gvm_json_pull_parser_init_full
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)
Initializes a JSON pull parser.
Definition jsonpull.c:78
gvm_json_pull_parse_string
static int gvm_json_pull_parse_string(gvm_json_pull_parser_t *parser, gvm_json_pull_event_t *event, cJSON **cjson_value)
Parses a string in a JSON pull parser.
Definition jsonpull.c:293
gvm_json_pull_skip_space
static int gvm_json_pull_skip_space(gvm_json_pull_parser_t *parser, gvm_json_pull_event_t *event, gboolean allow_eof)
Skips whitespaces in the input stream of a JSON pull parser.
Definition jsonpull.c:267
gvm_json_pull_parse_comma
static int gvm_json_pull_parse_comma(gvm_json_pull_parser_t *parser, gvm_json_pull_event_t *event)
Handles the case that a comma is expected in a JSON pull parser.
Definition jsonpull.c:497
gvm_json_pull_parser_next_char
static int gvm_json_pull_parser_next_char(gvm_json_pull_parser_t *parser)
Reads the next character in a pull parser input stream.
Definition jsonpull.c:174
gvm_json_pull_event_cleanup
void gvm_json_pull_event_cleanup(gvm_json_pull_event_t *event)
Frees all data of JSON pull event data structure.
Definition jsonpull.c:61
gvm_json_pull_parse_value
static int gvm_json_pull_parse_value(gvm_json_pull_parser_t *parser, gvm_json_pull_event_t *event)
Handles the case that a value is expected in a JSON pull parser.
Definition jsonpull.c:565
gvm_json_pull_parser_next
void gvm_json_pull_parser_next(gvm_json_pull_parser_t *parser, gvm_json_pull_event_t *event)
Get the next event from a JSON pull parser.
Definition jsonpull.c:669
GVM_JSON_CHAR_UNDEFINED
#define GVM_JSON_CHAR_UNDEFINED
Undefined state.
Definition jsonpull.c:12
gvm_json_pull_parser_init
void gvm_json_pull_parser_init(gvm_json_pull_parser_t *parser, FILE *input_stream)
Initializes a JSON pull parser with default buffer sizes.
Definition jsonpull.c:109
gvm_json_pull_parse_key
static int gvm_json_pull_parse_key(gvm_json_pull_parser_t *parser, gvm_json_pull_event_t *event)
Handles the case that an object key is expected in a JSON pull parser.
Definition jsonpull.c:426
gvm_json_pull_handle_read_end
static void gvm_json_pull_handle_read_end(gvm_json_pull_parser_t *parser, gvm_json_pull_event_t *event, gboolean allow_eof)
Handles error or EOF after reading a character in JSON pull parser.
Definition jsonpull.c:238
gvm_json_path_to_string
gchar * gvm_json_path_to_string(GQueue *path)
Converts a path as used by a JSON pull parser to a JSONPath string.
Definition jsonpull.c:910
GVM_JSON_CHAR_ERROR
#define GVM_JSON_CHAR_ERROR
Error reading file.
Definition jsonpull.c:11
gvm_json_pull_expand_container
cJSON * gvm_json_pull_expand_container(gvm_json_pull_parser_t *parser, gchar **error_message)
Expands the current array or object of a JSON pull parser.
Definition jsonpull.c:746
gvm_json_pull_parse_keyword
static int gvm_json_pull_parse_keyword(gvm_json_pull_parser_t *parser, gvm_json_pull_event_t *event, const char *keyword)
Parses a keyword value in a JSON pull parser.
Definition jsonpull.c:378
gvm_json_path_string_add_elem
static void gvm_json_path_string_add_elem(gvm_json_path_elem_t *path_elem, GString *path_string)
Appends a string path element to a JSONPath string.
Definition jsonpull.c:889
gvm_json_pull_parse_buffered
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)
Tries to parse the buffer content of a JSON pull parser.
Definition jsonpull.c:211
parse_value_next_expect
static void parse_value_next_expect(gvm_json_pull_parser_t *parser)
Updates the expectation for a JSON pull parser according to the path.
Definition jsonpull.c:406
GVM_JSON_CHAR_EOF
#define GVM_JSON_CHAR_EOF
End of file.
Definition jsonpull.c:10
gvm_json_pull_check_parse_buffer_size
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)
Checks if the parse buffer limit of a JSON pull parser is reached.
Definition jsonpull.c:151
gvm_json_pull_path_elem_free
void gvm_json_pull_path_elem_free(gvm_json_path_elem_t *elem)
Frees a JSON path element.
Definition jsonpull.c:38
gvm_json_pull_path_elem_new
gvm_json_path_elem_t * gvm_json_pull_path_elem_new(gvm_json_pull_container_type_t parent_type, int depth)
Creates a new JSON path element.
Definition jsonpull.c:23
gvm_json_pull_event_init
void gvm_json_pull_event_init(gvm_json_pull_event_t *event)
Initializes a JSON pull event data structure.
Definition jsonpull.c:50
gvm_json_read_stream_error_str
static gchar * gvm_json_read_stream_error_str()
Generates message for an error that occurred reading the JSON stream.
Definition jsonpull.c:136
jsonpull.h
GVM_JSON_PULL_READ_BUFFER_SIZE
#define GVM_JSON_PULL_READ_BUFFER_SIZE
Definition jsonpull.h:80
GVM_JSON_PULL_PARSE_BUFFER_LIMIT
#define GVM_JSON_PULL_PARSE_BUFFER_LIMIT
Definition jsonpull.h:78
gvm_json_pull_container_type_t
gvm_json_pull_container_type_t
Type of container the parser is currently in.
Definition jsonpull.h:20
GVM_JSON_PULL_CONTAINER_OBJECT
@ GVM_JSON_PULL_CONTAINER_OBJECT
Object.
Definition jsonpull.h:23
GVM_JSON_PULL_CONTAINER_ARRAY
@ GVM_JSON_PULL_CONTAINER_ARRAY
Array.
Definition jsonpull.h:22
GVM_JSON_PULL_EXPECT_VALUE
@ GVM_JSON_PULL_EXPECT_VALUE
Expect start of a value.
Definition jsonpull.h:72
GVM_JSON_PULL_EXPECT_KEY
@ GVM_JSON_PULL_EXPECT_KEY
Expect start of a key.
Definition jsonpull.h:73
GVM_JSON_PULL_EXPECT_EOF
@ GVM_JSON_PULL_EXPECT_EOF
Expect end of file.
Definition jsonpull.h:75
GVM_JSON_PULL_EXPECT_COMMA
@ GVM_JSON_PULL_EXPECT_COMMA
Expect comma or container end brace.
Definition jsonpull.h:74
GVM_JSON_PULL_EVENT_STRING
@ GVM_JSON_PULL_EVENT_STRING
Definition jsonpull.h:47
GVM_JSON_PULL_EVENT_OBJECT_START
@ GVM_JSON_PULL_EVENT_OBJECT_START
Definition jsonpull.h:45
GVM_JSON_PULL_EVENT_ERROR
@ GVM_JSON_PULL_EVENT_ERROR
Definition jsonpull.h:52
GVM_JSON_PULL_EVENT_NULL
@ GVM_JSON_PULL_EVENT_NULL
Definition jsonpull.h:50
GVM_JSON_PULL_EVENT_EOF
@ GVM_JSON_PULL_EVENT_EOF
Definition jsonpull.h:51
GVM_JSON_PULL_EVENT_NUMBER
@ GVM_JSON_PULL_EVENT_NUMBER
Definition jsonpull.h:48
GVM_JSON_PULL_EVENT_ARRAY_END
@ GVM_JSON_PULL_EVENT_ARRAY_END
Definition jsonpull.h:44
GVM_JSON_PULL_EVENT_OBJECT_END
@ GVM_JSON_PULL_EVENT_OBJECT_END
Definition jsonpull.h:46
GVM_JSON_PULL_EVENT_ARRAY_START
@ GVM_JSON_PULL_EVENT_ARRAY_START
Definition jsonpull.h:43
GVM_JSON_PULL_EVENT_BOOLEAN
@ GVM_JSON_PULL_EVENT_BOOLEAN
Definition jsonpull.h:49
gvm_json_path_elem_t
struct gvm_json_path_elem gvm_json_path_elem_t
Path element types for the JSON pull parser.
gvm_json_path_elem::depth
int depth
Number of ancestor elements.
Definition jsonpull.h:34
gvm_json_path_elem::index
int index
Index of the element within the parent.
Definition jsonpull.h:32
gvm_json_path_elem::key
char * key
Key if element is in an object.
Definition jsonpull.h:33
gvm_json_path_elem::parent_type
gvm_json_pull_container_type_t parent_type
parent container type
Definition jsonpull.h:31
gvm_json_pull_event_t
Event generated by the JSON pull parser.
Definition jsonpull.h:59
gvm_json_pull_event_t::error_message
gchar * error_message
Error message, NULL on success.
Definition jsonpull.h:63
gvm_json_pull_event_t::value
cJSON * value
Value for non-container value events.
Definition jsonpull.h:62
gvm_json_pull_parser_t
A json pull parser.
Definition jsonpull.h:86
gvm_json_pull_parser_t::read_buffer
char * read_buffer
Stream reading buffer.
Definition jsonpull.h:92
gvm_json_pull_parser_t::read_buffer_size
size_t read_buffer_size
Size of the stream reading buffer.
Definition jsonpull.h:93
gvm_json_pull_parser_t::expect
gvm_json_pull_expect_t expect
Current expected token.
Definition jsonpull.h:89
gvm_json_pull_parser_t::last_read_size
size_t last_read_size
Size of last stream read.
Definition jsonpull.h:94
gvm_json_pull_parser_t::parse_buffer
GString * parse_buffer
Buffer for parsing values and object keys.
Definition jsonpull.h:97
gvm_json_pull_parser_t::parse_buffer_limit
size_t parse_buffer_limit
Maximum parse buffer size.
Definition jsonpull.h:98
gvm_json_pull_parser_t::path_add
gvm_json_path_elem_t * path_add
Path elem to add in next step.
Definition jsonpull.h:88
gvm_json_pull_parser_t::read_pos
size_t read_pos
Position in current read.
Definition jsonpull.h:96
gvm_json_pull_parser_t::path
GQueue * path
Path to the current value.
Definition jsonpull.h:87
gvm_json_pull_parser_t::last_read_char
int last_read_char
Character last read from stream.
Definition jsonpull.h:95
gvm_json_pull_parser_t::input_stream
FILE * input_stream
Input stream.
Definition jsonpull.h:91