xmlutils.c
Go to the documentation of this file.
/* SPDX-FileCopyrightText: 2009-2023 Greenbone AG
*
* SPDX-License-Identifier: GPL-2.0-or-later
*/
#include "xmlutils.h"
#include <assert.h> /* for assert */
#include <errno.h> /* for errno, EAGAIN, EINTR */
#include <fcntl.h> /* for fcntl, F_SETFL, O_NONBLOCK */
#include <glib.h> /* for g_free, GSList, g_markup_parse_context_free */
#include <glib/gtypes.h> /* for GPOINTER_TO_INT, GINT_TO_POINTER, gsize */
#include <libxml/parser.h>
#include <libxml/tree.h>
#include <string.h> /* for strcmp, strerror, strlen */
#include <time.h> /* for time, time_t */
#include <unistd.h> /* for ssize_t */
#undef G_LOG_DOMAIN
#define G_LOG_DOMAIN "libgvm util"
#define BUFFER_SIZE 1048576
static entity_t
make_entity (const char *name, const char *text)
{
entity_t entity;
entity = g_malloc (sizeof (*entity));
entity->name = g_strdup (name ? name : "");
entity->text = g_strdup (text ? text : "");
entity->entities = NULL;
entity->attributes = NULL;
return entity;
}
entities_t
next_entities (entities_t entities)
{
if (entities)
return (entities_t) entities->next;
return NULL;
}
entity_t
first_entity (entities_t entities)
{
if (entities)
return (entity_t) entities->data;
return NULL;
}
entity_t
add_entity (entities_t *entities, const char *name, const char *text)
{
entity_t entity = make_entity (name, text);
if (entities)
*entities = g_slist_append (*entities, entity);
return entity;
}
void
free_entity (entity_t entity)
{
if (entity)
{
g_free (entity->name);
g_free (entity->text);
if (entity->attributes)
g_hash_table_destroy (entity->attributes);
if (entity->entities)
{
GSList *list = entity->entities;
while (list)
{
free_entity (list->data);
list = list->next;
}
g_slist_free (entity->entities);
}
g_free (entity);
}
}
char *
entity_text (entity_t entity)
{
if (!entity)
return NULL;
return entity->text;
}
char *
entity_name (entity_t entity)
{
if (!entity)
return NULL;
return entity->name;
}
static int
compare_entity_with_name (gconstpointer entity, gconstpointer name)
{
return strcmp (entity_name ((entity_t) entity), (char *) name);
}
entity_t
entity_child (entity_t entity, const char *name)
{
if (!entity)
return NULL;
if (entity->entities)
{
entities_t match =
g_slist_find_custom (entity->entities, name, compare_entity_with_name);
return match ? (entity_t) match->data : NULL;
}
return NULL;
}
const char *
entity_attribute (entity_t entity, const char *name)
{
if (!entity)
return NULL;
if (entity->attributes)
return (const char *) g_hash_table_lookup (entity->attributes, name);
return NULL;
}
static void
add_attributes (entity_t entity, const gchar **names, const gchar **values)
{
if (names && values && *names && *values)
{
if (entity->attributes == NULL)
entity->attributes =
g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
while (*names && *values)
{
if (*values)
g_hash_table_insert (entity->attributes, g_strdup (*names),
g_strdup (*values));
names++;
values++;
}
}
}
static void
ignore_start_element (GMarkupParseContext *context, const gchar *element_name,
const gchar **attribute_names,
const gchar **attribute_values, gpointer user_data,
GError **error)
{
context_data_t *data = (context_data_t *) user_data;
(void) context;
(void) element_name;
(void) attribute_names;
(void) attribute_values;
(void) error;
data->current = GINT_TO_POINTER (GPOINTER_TO_INT (data->current) + 1);
}
static void
handle_start_element (GMarkupParseContext *context, const gchar *element_name,
const gchar **attribute_names,
const gchar **attribute_values, gpointer user_data,
GError **error)
{
entity_t entity;
context_data_t *data = (context_data_t *) user_data;
(void) context;
(void) error;
if (data->current)
{
entity_t current = (entity_t) data->current->data;
entity = add_entity (&current->entities, element_name, NULL);
}
else
entity = add_entity (NULL, element_name, NULL);
add_attributes (entity, attribute_names, attribute_values);
/* "Push" the element. */
if (data->first == NULL)
data->current = data->first = g_slist_prepend (NULL, entity);
else
data->current = g_slist_prepend (data->current, entity);
}
void
xml_handle_start_element (context_data_t *context, const gchar *element_name,
const gchar **attribute_names,
const gchar **attribute_values)
{
handle_start_element (NULL, element_name, attribute_names, attribute_values,
context, NULL);
}
static void
ignore_end_element (GMarkupParseContext *context, const gchar *element_name,
gpointer user_data, GError **error)
{
context_data_t *data = (context_data_t *) user_data;
(void) context;
(void) element_name;
(void) error;
data->current = GINT_TO_POINTER (GPOINTER_TO_INT (data->current) - 1);
if (data->current == NULL)
data->done = TRUE;
}
static void
handle_end_element (GMarkupParseContext *context, const gchar *element_name,
gpointer user_data, GError **error)
{
context_data_t *data = (context_data_t *) user_data;
(void) context;
(void) error;
(void) element_name;
assert (data->current && data->first);
if (data->current == data->first)
{
assert (strcmp (element_name,
/* The name of the very first entity. */
((entity_t) (data->first->data))->name)
== 0);
data->done = TRUE;
/* "Pop" the element. */
data->current = g_slist_next (data->current);
}
else if (data->current)
{
GSList *front;
/* "Pop" and free the element. */
front = data->current;
data->current = g_slist_next (data->current);
g_slist_free_1 (front);
}
}
void
xml_handle_end_element (context_data_t *context, const gchar *element_name)
{
handle_end_element (NULL, element_name, context, NULL);
}
static void
ignore_text (GMarkupParseContext *context, const gchar *text, gsize text_len,
gpointer user_data, GError **error)
{
(void) context;
(void) text;
(void) text_len;
(void) user_data;
(void) error;
}
static void
handle_text (GMarkupParseContext *context, const gchar *text, gsize text_len,
gpointer user_data, GError **error)
{
context_data_t *data = (context_data_t *) user_data;
(void) context;
(void) text_len;
(void) error;
entity_t current = (entity_t) data->current->data;
if (current->text)
{
gchar *old = current->text;
current->text = g_strconcat (current->text, text, NULL);
g_free (old);
}
else
current->text = g_strdup (text);
}
void
xml_handle_text (context_data_t *context, const gchar *text, gsize text_len)
{
handle_text (NULL, text, text_len, context, NULL);
}
static void
handle_error (GMarkupParseContext *context, GError *error, gpointer user_data)
{
(void) context;
(void) user_data;
g_message (" Error: %s\n", error->message);
}
int
try_read_entity_and_string (gnutls_session_t *session, int timeout,
entity_t *entity, GString **string_return)
{
GMarkupParser xml_parser;
GError *error = NULL;
GMarkupParseContext *xml_context;
GString *string;
int socket;
time_t last_time;
// Buffer for reading from the manager.
char *buffer;
/* Record the start time. */
if (time (&last_time) == -1)
{
g_warning (" failed to get current time: %s\n", strerror (errno));
return -1;
}
if (timeout > 0)
{
/* Turn off blocking. */
socket = GPOINTER_TO_INT (gnutls_transport_get_ptr (*session));
if (fcntl (socket, F_SETFL, O_NONBLOCK) == -1)
return -1;
}
else
/* Quiet compiler. */
socket = 0;
buffer = g_malloc0 (BUFFER_SIZE);
if (!buffer)
return -5;
/* Setup return arg. */
if (string_return == NULL)
string = NULL;
else if (*string_return == NULL)
string = g_string_new ("");
else
string = *string_return;
/* Create the XML parser. */
if (entity)
{
xml_parser.start_element = handle_start_element;
xml_parser.end_element = handle_end_element;
xml_parser.text = handle_text;
}
else
{
xml_parser.start_element = ignore_start_element;
xml_parser.end_element = ignore_end_element;
xml_parser.text = ignore_text;
}
xml_parser.passthrough = NULL;
xml_parser.error = handle_error;
context_data_t context_data;
context_data.done = FALSE;
context_data.first = NULL;
context_data.current = NULL;
/* Setup the XML context. */
xml_context =
g_markup_parse_context_new (&xml_parser, 0, &context_data, NULL);
/* Read and parse, until encountering end of file or error. */
while (1)
{
ssize_t count;
int retries = 10;
while (1)
{
g_debug (" asking for %i\n", BUFFER_SIZE);
count = gnutls_record_recv (*session, buffer, BUFFER_SIZE);
if (count < 0)
{
if (count == GNUTLS_E_INTERRUPTED)
/* Interrupted, try read again. */
continue;
if ((timeout > 0) && (count == GNUTLS_E_AGAIN))
{
/* Server still busy, either timeout or try read again. */
if ((timeout - (time (NULL) - last_time)) <= 0)
{
g_warning (" timeout\n");
if (fcntl (socket, F_SETFL, 0L) < 0)
g_warning ("%s :failed to set socket flag: %s",
__func__, strerror (errno));
g_markup_parse_context_free (xml_context);
g_free (buffer);
return -4;
}
continue;
}
else if ((timeout == 0) && (count == GNUTLS_E_AGAIN))
{
/* Server still busy, try read again.
If there is no timeout set and the server is still not
ready, it will try up to 10 times before closing the
socket.*/
if (retries > 0)
{
retries = retries - 1;
continue;
}
}
if (count == GNUTLS_E_REHANDSHAKE)
/* Try again. TODO Rehandshake. */
continue;
if (context_data.first && context_data.first->data)
{
free_entity (context_data.first->data);
g_slist_free_1 (context_data.first);
}
if (string && *string_return == NULL)
g_string_free (string, TRUE);
if (timeout > 0)
{
if (fcntl (socket, F_SETFL, 0L) < 0)
g_warning ("%s :failed to set socket flag: %s", __func__,
strerror (errno));
}
g_markup_parse_context_free (xml_context);
g_free (buffer);
return -1;
}
if (count == 0)
{
/* End of file. */
g_markup_parse_context_end_parse (xml_context, &error);
if (error)
{
g_warning (" End error: %s\n", error->message);
g_error_free (error);
}
if (context_data.first && context_data.first->data)
{
free_entity (context_data.first->data);
g_slist_free_1 (context_data.first);
}
if (string && *string_return == NULL)
g_string_free (string, TRUE);
if (timeout > 0)
{
if (fcntl (socket, F_SETFL, 0L) < 0)
g_warning ("%s :failed to set socket flag: %s", __func__,
strerror (errno));
}
g_markup_parse_context_free (xml_context);
g_free (buffer);
return -3;
}
break;
}
g_debug ("<= %.*s\n", (int) count, buffer);
if (string)
g_string_append_len (string, buffer, count);
g_markup_parse_context_parse (xml_context, buffer, count, &error);
if (error)
{
g_error_free (error);
if (context_data.first && context_data.first->data)
{
free_entity (context_data.first->data);
g_slist_free_1 (context_data.first);
}
if (string && *string_return == NULL)
g_string_free (string, TRUE);
if (timeout > 0)
{
if (fcntl (socket, F_SETFL, 0L) < 0)
g_warning ("%s :failed to set socket flag: %s", __func__,
strerror (errno));
}
g_markup_parse_context_free (xml_context);
g_free (buffer);
return -2;
}
if (context_data.done)
{
g_markup_parse_context_end_parse (xml_context, &error);
if (error)
{
g_warning (" End error: %s\n", error->message);
g_error_free (error);
if (context_data.first && context_data.first->data)
{
free_entity (context_data.first->data);
g_slist_free_1 (context_data.first);
}
if (timeout > 0)
fcntl (socket, F_SETFL, 0L);
g_markup_parse_context_free (xml_context);
g_free (buffer);
return -2;
}
if (entity)
*entity = (entity_t) context_data.first->data;
if (string)
*string_return = string;
if (timeout > 0)
fcntl (socket, F_SETFL, 0L);
g_markup_parse_context_free (xml_context);
g_free (buffer);
return 0;
}
if ((timeout > 0) && (time (&last_time) == -1))
{
g_warning (" failed to get current time (1): %s\n",
strerror (errno));
if (fcntl (socket, F_SETFL, 0L) < 0)
g_warning ("%s :failed to set socket flag: %s", __func__,
strerror (errno));
g_markup_parse_context_free (xml_context);
g_free (buffer);
return -1;
}
}
}
static int
try_read_string (gnutls_session_t *session, int timeout,
GString **string_return)
{
GString *string;
int socket;
time_t last_time;
char *buffer; // Buffer for reading from the server.
/* Record the start time. */
if (time (&last_time) == -1)
{
g_warning (" failed to get current time: %s\n", strerror (errno));
return -1;
}
if (timeout > 0)
{
/* Turn off blocking. */
socket = GPOINTER_TO_INT (gnutls_transport_get_ptr (*session));
if (fcntl (socket, F_SETFL, O_NONBLOCK) == -1)
return -1;
}
else
/* Quiet compiler. */
socket = 0;
buffer = g_malloc0 (BUFFER_SIZE);
if (!buffer)
return -5;
/* Setup return arg. */
if (string_return == NULL)
string = NULL;
else if (*string_return == NULL)
string = g_string_new ("");
else
string = *string_return;
/* Read until encountering end of file or error. */
while (1)
{
ssize_t count;
int retries = 10;
while (1)
{
g_debug (" asking for %i\n", BUFFER_SIZE);
count = gnutls_record_recv (*session, buffer, BUFFER_SIZE);
if (count < 0)
{
if (count == GNUTLS_E_INTERRUPTED)
/* Interrupted, try read again. */
continue;
if ((timeout > 0) && (count == GNUTLS_E_AGAIN))
{
/* Server still busy, either timeout or try read again. */
if ((timeout - (time (NULL) - last_time)) <= 0)
{
g_warning (" timeout\n");
if (fcntl (socket, F_SETFL, 0L) < 0)
g_warning ("%s: failed to set socket flag: %s",
__func__, strerror (errno));
g_free (buffer);
return -4;
}
continue;
}
else if ((timeout == 0) && (count == GNUTLS_E_AGAIN))
{
/* Server still busy, try read again.
* If there is no timeout set and the server is still not
* ready, it will try up to 10 times before closing the
* socket. */
if (retries > 0)
{
retries = retries - 1;
continue;
}
}
if (count == GNUTLS_E_REHANDSHAKE)
/* Try again. TODO Rehandshake. */
continue;
if (string && (*string_return == NULL))
g_string_free (string, TRUE);
if (timeout > 0)
{
if (fcntl (socket, F_SETFL, 0L) < 0)
g_warning ("%s: failed to set socket flag: %s", __func__,
strerror (errno));
}
g_free (buffer);
return -1;
}
if (count == 0)
{
/* End of file. */
if (timeout > 0)
{
if (fcntl (socket, F_SETFL, 0L) < 0)
g_warning ("%s :failed to set socket flag: %s", __func__,
strerror (errno));
}
if (string)
*string_return = string;
g_free (buffer);
return 0;
}
break;
}
g_debug ("<= %.*s\n", (int) count, buffer);
if (string)
g_string_append_len (string, buffer, count);
if ((timeout > 0) && (time (&last_time) == -1))
{
g_warning (" failed to get current time (1): %s\n",
strerror (errno));
if (fcntl (socket, F_SETFL, 0L) < 0)
g_warning ("%s :failed to set socket flag: %s", __func__,
strerror (errno));
g_free (buffer);
return -1;
}
}
}
static int
try_read_string_s (int socket, int timeout, GString **string_return)
{
GString *string;
time_t last_time;
/* Buffer for reading from the socket. */
char *buffer;
/* Record the start time. */
if (time (&last_time) == -1)
{
g_warning (" failed to get current time: %s\n", strerror (errno));
return -1;
}
if (timeout > 0)
{
/* Turn off blocking. */
if (fcntl (socket, F_SETFL, O_NONBLOCK) == -1)
return -1;
}
buffer = g_malloc0 (BUFFER_SIZE);
if (!buffer)
return -5;
/* Setup return arg. */
if (string_return == NULL)
string = NULL;
else if (*string_return == NULL)
string = g_string_sized_new (8192);
else
string = *string_return;
/* Read until encountering end of file or error. */
while (1)
{
int count;
while (1)
{
g_debug (" asking for %i\n", BUFFER_SIZE);
count = read (socket, buffer, BUFFER_SIZE);
if (count < 0)
{
if (errno == EINTR)
/* Interrupted, try read again. */
continue;
if (timeout > 0)
{
if (errno == EAGAIN)
{
/* Server still busy, either timeout or try read again. */
if ((timeout - (time (NULL) - last_time)) <= 0)
{
g_warning (" timeout\n");
if (fcntl (socket, F_SETFL, 0L) < 0)
g_warning ("%s :failed to set socket flag: %s",
__func__, strerror (errno));
g_free (buffer);
if (string && *string_return == NULL)
g_string_free (string, TRUE);
return -4;
}
}
continue;
}
if (string && *string_return == NULL)
g_string_free (string, TRUE);
if (timeout > 0)
fcntl (socket, F_SETFL, 0L);
g_free (buffer);
return -1;
}
if (count == 0)
{
/* End of file. */
if (timeout > 0)
{
if (fcntl (socket, F_SETFL, 0L) < 0)
g_warning ("%s :failed to set socket flag: %s", __func__,
strerror (errno));
}
if (string)
*string_return = string;
g_free (buffer);
return 0;
}
break;
}
g_debug ("<= %.*s\n", (int) count, buffer);
if (string)
g_string_append_len (string, buffer, count);
if ((timeout > 0) && (time (&last_time) == -1))
{
g_warning (" failed to get current time (1): %s\n",
strerror (errno));
if (fcntl (socket, F_SETFL, 0L) < 0)
g_warning ("%s :failed to set server socket flag: %s", __func__,
strerror (errno));
g_free (buffer);
if (string && *string_return == NULL)
g_string_free (string, TRUE);
return -1;
}
}
}
static int
try_read_entity_and_string_s (int socket, int timeout, entity_t *entity,
GString **string_return)
{
GMarkupParser xml_parser;
GError *error = NULL;
GMarkupParseContext *xml_context;
GString *string;
time_t last_time;
/* Buffer for reading from the socket. */
char *buffer;
/* Record the start time. */
if (time (&last_time) == -1)
{
g_warning (" failed to get current time: %s\n", strerror (errno));
return -1;
}
if (timeout > 0)
{
/* Turn off blocking. */
if (fcntl (socket, F_SETFL, O_NONBLOCK) == -1)
return -1;
}
buffer = g_malloc0 (BUFFER_SIZE);
if (!buffer)
return -5;
/* Setup return arg. */
if (string_return == NULL)
string = NULL;
else if (*string_return == NULL)
string = g_string_new ("");
else
string = *string_return;
/* Create the XML parser. */
if (entity)
{
xml_parser.start_element = handle_start_element;
xml_parser.end_element = handle_end_element;
xml_parser.text = handle_text;
}
else
{
xml_parser.start_element = ignore_start_element;
xml_parser.end_element = ignore_end_element;
xml_parser.text = ignore_text;
}
xml_parser.passthrough = NULL;
xml_parser.error = handle_error;
context_data_t context_data;
context_data.done = FALSE;
context_data.first = NULL;
context_data.current = NULL;
/* Setup the XML context. */
xml_context =
g_markup_parse_context_new (&xml_parser, 0, &context_data, NULL);
/* Read and parse, until encountering end of file or error. */
while (1)
{
int count;
while (1)
{
g_debug (" asking for %i\n", BUFFER_SIZE);
count = read (socket, buffer, BUFFER_SIZE);
if (count < 0)
{
if (errno == EINTR)
/* Interrupted, try read again. */
continue;
if (timeout > 0)
{
if (errno == EAGAIN)
{
/* Server still busy, either timeout or try read again. */
if ((timeout - (time (NULL) - last_time)) <= 0)
{
g_warning (" timeout\n");
if (fcntl (socket, F_SETFL, 0L) < 0)
g_warning ("%s :failed to set socket flag: %s",
__func__, strerror (errno));
g_markup_parse_context_free (xml_context);
g_free (buffer);
if (string && *string_return == NULL)
g_string_free (string, TRUE);
return -4;
}
}
continue;
}
if (context_data.first && context_data.first->data)
{
free_entity (context_data.first->data);
g_slist_free_1 (context_data.first);
}
if (string && *string_return == NULL)
g_string_free (string, TRUE);
if (timeout > 0)
fcntl (socket, F_SETFL, 0L);
g_markup_parse_context_free (xml_context);
g_free (buffer);
return -1;
}
if (count == 0)
{
/* End of file. */
g_markup_parse_context_end_parse (xml_context, &error);
if (error)
{
g_warning (" End error: %s\n", error->message);
g_error_free (error);
}
if (context_data.first && context_data.first->data)
{
free_entity (context_data.first->data);
g_slist_free_1 (context_data.first);
}
if (string && *string_return == NULL)
g_string_free (string, TRUE);
if (timeout > 0)
{
if (fcntl (socket, F_SETFL, 0L) < 0)
g_warning ("%s :failed to set socket flag: %s", __func__,
strerror (errno));
}
g_markup_parse_context_free (xml_context);
g_free (buffer);
return -3;
}
break;
}
g_debug ("<= %.*s\n", (int) count, buffer);
if (string)
g_string_append_len (string, buffer, count);
g_markup_parse_context_parse (xml_context, buffer, count, &error);
if (error)
{
g_error_free (error);
// FIX there may be multiple entries in list
if (context_data.first && context_data.first->data)
{
free_entity (context_data.first->data);
g_slist_free_1 (context_data.first);
}
if (string && *string_return == NULL)
g_string_free (string, TRUE);
if (timeout > 0)
{
if (fcntl (socket, F_SETFL, 0L) < 0)
g_warning ("%s :failed to set socket flag: %s", __func__,
strerror (errno));
}
g_markup_parse_context_free (xml_context);
g_free (buffer);
return -2;
}
if (context_data.done)
{
g_markup_parse_context_end_parse (xml_context, &error);
if (error)
{
g_warning (" End error: %s\n", error->message);
g_error_free (error);
if (context_data.first && context_data.first->data)
{
free_entity (context_data.first->data);
g_slist_free_1 (context_data.first);
}
if (timeout > 0)
fcntl (socket, F_SETFL, 0L);
g_markup_parse_context_free (xml_context);
g_free (buffer);
if (string && *string_return == NULL)
g_string_free (string, TRUE);
return -2;
}
if (entity)
*entity = (entity_t) context_data.first->data;
if (string)
*string_return = string;
if (timeout > 0)
fcntl (socket, F_SETFL, 0L);
g_slist_free (context_data.first);
g_markup_parse_context_free (xml_context);
g_free (buffer);
return 0;
}
if ((timeout > 0) && (time (&last_time) == -1))
{
g_warning (" failed to get current time (1): %s\n",
strerror (errno));
if (fcntl (socket, F_SETFL, 0L) < 0)
g_warning ("%s :failed to set server socket flag: %s", __func__,
strerror (errno));
g_markup_parse_context_free (xml_context);
g_free (buffer);
if (string && *string_return == NULL)
g_string_free (string, TRUE);
return -1;
}
}
}
int
read_entity_and_string (gnutls_session_t *session, entity_t *entity,
GString **string_return)
{
return try_read_entity_and_string (session, 0, entity, string_return);
}
int
read_entity_and_string_c (gvm_connection_t *connection, entity_t *entity,
GString **string_return)
{
if (connection->tls)
return try_read_entity_and_string (&connection->session, 0, entity,
string_return);
return try_read_entity_and_string_s (connection->socket, 0, entity,
string_return);
}
int
read_entity_and_text (gnutls_session_t *session, entity_t *entity, char **text)
{
if (text)
{
GString *string = NULL;
int ret = read_entity_and_string (session, entity, &string);
if (ret)
{
if (string)
g_string_free (string, TRUE);
return ret;
}
*text = g_string_free (string, FALSE);
return 0;
}
return read_entity_and_string (session, entity, NULL);
}
int
read_entity_and_text_c (gvm_connection_t *connection, entity_t *entity,
char **text)
{
if (text)
{
GString *string = NULL;
int ret = read_entity_and_string_c (connection, entity, &string);
if (ret)
{
if (string)
g_string_free (string, TRUE);
return ret;
}
*text = g_string_free (string, FALSE);
return 0;
}
return read_entity_and_string_c (connection, entity, NULL);
}
int
read_text_c (gvm_connection_t *connection, char **text)
{
GString *string;
int ret;
if (text == NULL)
return -2;
string = NULL;
if (connection->tls)
ret = try_read_string (&connection->session, 0, &string);
else
ret = try_read_string_s (connection->socket, 0, &string);
if (ret)
{
if (string)
g_string_free (string, TRUE);
return ret;
}
*text = g_string_free (string, FALSE);
return 0;
}
int
read_string (gnutls_session_t *session, GString **string)
{
int ret = 0;
entity_t entity;
if (!(ret = read_entity_and_string (session, &entity, string)))
free_entity (entity);
return ret;
}
int
read_string_c (gvm_connection_t *connection, GString **string)
{
return read_entity_and_string_c (connection, NULL, string);
}
int
try_read_entity (gnutls_session_t *session, int timeout, entity_t *entity)
{
return try_read_entity_and_string (session, timeout, entity, NULL);
}
int
try_read_entity_c (gvm_connection_t *connection, int timeout, entity_t *entity)
{
if (connection->tls)
return try_read_entity_and_string (&connection->session, 0, entity, NULL);
return try_read_entity_and_string_s (connection->socket, timeout, entity,
NULL);
}
int
read_entity (gnutls_session_t *session, entity_t *entity)
{
return try_read_entity (session, 0, entity);
}
int
read_entity_s (int socket, entity_t *entity)
{
return try_read_entity_and_string_s (socket, 0, entity, NULL);
}
int
read_entity_c (gvm_connection_t *connection, entity_t *entity)
{
return try_read_entity_c (connection, 0, entity);
}
int
parse_entity (const char *string, entity_t *entity)
{
GMarkupParser xml_parser;
GError *error = NULL;
GMarkupParseContext *xml_context;
context_data_t context_data;
/* Create the XML parser. */
xml_parser.start_element = handle_start_element;
xml_parser.end_element = handle_end_element;
xml_parser.text = handle_text;
xml_parser.passthrough = NULL;
xml_parser.error = handle_error;
context_data.done = FALSE;
context_data.first = NULL;
context_data.current = NULL;
/* Setup the XML context. */
xml_context =
g_markup_parse_context_new (&xml_parser, 0, &context_data, NULL);
/* Parse the string. */
g_markup_parse_context_parse (xml_context, string, strlen (string), &error);
if (error)
{
g_error_free (error);
if (context_data.first && context_data.first->data)
{
free_entity (context_data.first->data);
g_slist_free_1 (context_data.first);
}
g_markup_parse_context_free (xml_context);
return -2;
}
if (context_data.done)
{
g_markup_parse_context_end_parse (xml_context, &error);
if (error)
{
g_warning (" End error: %s\n", error->message);
g_error_free (error);
if (context_data.first && context_data.first->data)
{
free_entity (context_data.first->data);
g_slist_free_1 (context_data.first);
}
g_markup_parse_context_free (xml_context);
return -2;
}
*entity = (entity_t) context_data.first->data;
g_slist_free_1 (context_data.first);
g_markup_parse_context_free (xml_context);
return 0;
}
if (context_data.first && context_data.first->data)
{
free_entity (context_data.first->data);
g_slist_free_1 (context_data.first);
}
g_markup_parse_context_free (xml_context);
return -3;
}
static void
foreach_print_entity_to_string (gpointer entity, gpointer string)
{
print_entity_to_string ((entity_t) entity, (GString *) string);
}
static void
foreach_print_attribute_to_string (gpointer name, gpointer value,
gpointer string)
{
gchar *text_escaped;
text_escaped = g_markup_escape_text ((gchar *) value, -1);
g_string_append_printf ((GString *) string, " %s=\"%s\"", (char *) name,
text_escaped);
g_free (text_escaped);
}
void
print_entity_to_string (entity_t entity, GString *string)
{
gchar *text_escaped = NULL;
g_string_append_printf (string, "<%s", entity->name);
if (entity->attributes && g_hash_table_size (entity->attributes))
g_hash_table_foreach (entity->attributes, foreach_print_attribute_to_string,
string);
g_string_append_printf (string, ">");
text_escaped = g_markup_escape_text (entity->text, -1);
g_string_append_printf (string, "%s", text_escaped);
g_free (text_escaped);
g_slist_foreach (entity->entities, foreach_print_entity_to_string, string);
g_string_append_printf (string, "</%s>", entity->name);
}
static void
foreach_print_entity (gpointer entity, gpointer stream)
{
print_entity ((FILE *) stream, (entity_t) entity);
}
static void
foreach_print_attribute (gpointer name, gpointer value, gpointer stream)
{
fprintf ((FILE *) stream, " %s=\"%s\"", (char *) name, (char *) value);
}
void
print_entity (FILE *stream, entity_t entity)
{
gchar *text_escaped = NULL;
fprintf (stream, "<%s", entity->name);
if (entity->attributes && g_hash_table_size (entity->attributes))
g_hash_table_foreach (entity->attributes, foreach_print_attribute, stream);
fprintf (stream, ">");
text_escaped = g_markup_escape_text (entity->text, -1);
fprintf (stream, "%s", text_escaped);
g_free (text_escaped);
g_slist_foreach (entity->entities, foreach_print_entity, stream);
fprintf (stream, "</%s>", entity->name);
fflush (stream);
}
/* "Formatted" (indented) output of entity_t */
static void
foreach_print_attribute_format (gpointer name, gpointer value, gpointer none)
{
(void) none;
printf (" %s=\"%s\"", (char *) name, (char *) value);
}
void
print_entity_format (entity_t entity, gpointer indent)
{
int i = 0;
int indentation = GPOINTER_TO_INT (indent);
gchar *text_escaped = NULL;
for (i = 0; i < indentation; i++)
printf (" ");
printf ("<%s", entity->name);
if (entity->attributes && g_hash_table_size (entity->attributes))
g_hash_table_foreach (entity->attributes, foreach_print_attribute_format,
indent);
printf (">");
text_escaped = g_markup_escape_text (entity->text, -1);
printf ("%s", text_escaped);
g_free (text_escaped);
if (entity->entities)
{
printf ("\n");
g_slist_foreach (entity->entities, (GFunc) print_entity_format,
GINT_TO_POINTER (indentation + 1));
for (i = 0; i < indentation; i++)
printf (" ");
}
printf ("</%s>\n", entity->name);
}
static gboolean
compare_find_attribute (gpointer key, gpointer value, gpointer attributes2)
{
gchar *value2 = g_hash_table_lookup (attributes2, key);
if (value2 && strcmp (value, value2) == 0)
return FALSE;
g_debug (" compare failed attribute: %s\n", (char *) value);
return TRUE;
}
int
compare_entities (entity_t entity1, entity_t entity2)
{
if (entity1 == NULL)
return entity2 == NULL ? 0 : 1;
if (entity2 == NULL)
return 1;
if (strcmp (entity1->name, entity2->name))
{
g_debug (" compare failed name: %s vs %s\n", entity1->name,
entity2->name);
return 1;
}
if (strcmp (entity1->text, entity2->text))
{
g_debug (" compare failed text %s vs %s (%s)\n", entity1->text,
entity2->text, entity1->name);
return 1;
}
if (entity1->attributes == NULL)
{
if (entity2->attributes)
return 1;
}
else
{
if (entity2->attributes == NULL)
return 1;
if (g_hash_table_find (entity1->attributes, compare_find_attribute,
(gpointer) entity2->attributes))
{
g_debug (" compare failed attributes\n");
return 1;
}
}
// FIX entities can be in any order
GSList *list1 = entity1->entities;
GSList *list2 = entity2->entities;
while (list1 && list2)
{
if (compare_entities (list1->data, list2->data))
{
g_debug (" compare failed subentity\n");
return 1;
}
list1 = g_slist_next (list1);
list2 = g_slist_next (list2);
}
if (list1 == list2)
return 0;
/* More entities in one of the two. */
g_debug (" compare failed number of entities (%s)\n", entity1->name);
return 1;
}
int
xml_count_entities (entities_t entities)
{
int count = 0;
while (first_entity (entities))
{
entities = next_entities (entities);
count++;
}
return count;
}
void
xml_string_append (GString *xml, const char *format, ...)
{
gchar *piece;
va_list args;
va_start (args, format);
piece = g_markup_vprintf_escaped (format, args);
va_end (args);
g_string_append (xml, piece);
g_free (piece);
}
/* XML file utilities */
static void
xml_search_handle_start_element (GMarkupParseContext *ctx,
const gchar *element_name,
const gchar **attribute_names,
const gchar **attribute_values, gpointer data,
GError **error)
{
(void) ctx;
(void) error;
xml_search_data_t *search_data = ((xml_search_data_t *) data);
if (strcmp (element_name, search_data->find_element) == 0
&& search_data->found == 0)
{
g_debug ("%s: Found element <%s>", __func__, element_name);
if (search_data->find_attributes
&& g_hash_table_size (search_data->find_attributes))
{
int index;
GHashTable *found_attributes;
found_attributes =
g_hash_table_new_full (g_str_hash, g_str_equal, NULL, NULL);
index = 0;
while (attribute_names[index])
{
gchar *searched_value;
searched_value = g_hash_table_lookup (
search_data->find_attributes, attribute_names[index]);
if (searched_value
&& strcmp (searched_value, attribute_values[index]) == 0)
{
g_debug ("%s: Found attribute %s=\"%s\"", __func__,
attribute_names[index], searched_value);
g_hash_table_add (found_attributes, searched_value);
}
index++;
}
g_debug ("%s: Found %d of %d attributes", __func__,
g_hash_table_size (found_attributes),
g_hash_table_size (search_data->find_attributes));
if (g_hash_table_size (found_attributes)
== g_hash_table_size (search_data->find_attributes))
{
search_data->found = 1;
}
g_hash_table_destroy (found_attributes);
}
else
{
search_data->found = 1;
}
}
}
#define XML_FILE_BUFFER_SIZE 1048576
int
find_element_in_xml_file (gchar *file_path, gchar *find_element,
GHashTable *find_attributes)
{
gchar buffer[XML_FILE_BUFFER_SIZE];
FILE *file;
int read_len;
GMarkupParser xml_parser;
GMarkupParseContext *xml_context;
xml_search_data_t search_data;
GError *error = NULL;
search_data.find_element = find_element;
search_data.find_attributes = find_attributes;
search_data.found = 0;
/* Create the XML parser. */
xml_parser.start_element = xml_search_handle_start_element;
xml_parser.end_element = NULL;
xml_parser.text = NULL;
xml_parser.passthrough = NULL;
xml_parser.error = NULL;
xml_context = g_markup_parse_context_new (&xml_parser, 0, &search_data, NULL);
file = fopen (file_path, "r");
if (file == NULL)
{
g_markup_parse_context_free (xml_context);
g_warning ("%s: Failed to open '%s':", __func__, strerror (errno));
return 0;
}
while ((read_len = fread (&buffer, sizeof (char), XML_FILE_BUFFER_SIZE, file))
&& g_markup_parse_context_parse (xml_context, buffer, read_len, &error)
&& error == NULL)
{
}
g_markup_parse_context_end_parse (xml_context, &error);
fclose (file);
g_markup_parse_context_free (xml_context);
return search_data.found;
}
#undef XML_FILE_BUFFER_SIZE
/* The new faster parser that uses libxml2. */
int
parse_element (const gchar *string, element_t *element)
{
xmlDocPtr doc;
LIBXML_TEST_VERSION
if (element)
*element = NULL;
if (xmlMemSetup (g_free, g_malloc, g_realloc, g_strdup))
return -4;
doc =
xmlReadMemory (string, strlen (string), "noname.xml", NULL, XML_PARSE_HUGE);
if (doc == NULL)
return -2;
if (element)
*element = xmlDocGetRootElement (doc);
return 0;
}
void
element_free (element_t element)
{
if (element)
{
assert (element->doc);
xmlFreeDoc (element->doc);
}
}
const gchar *
element_name (element_t element)
{
if (element && (element->type == XML_ELEMENT_NODE))
return (const gchar *) element->name;
return "";
}
static element_t
find_child (element_t element, const gchar *name)
{
for (xmlNode *node = element->children; node; node = node->next)
if (xmlStrcmp (node->name, (const xmlChar *) name) == 0)
return node;
return NULL;
}
element_t
element_child (element_t element, const gchar *name)
{
const gchar *stripped_name;
if (!element)
return NULL;
stripped_name = strchr (name, ':');
if (stripped_name)
{
element_t child;
/* There was a namespace in the name.
*
* First try without the namespace, because libxml2 doesn't consider the
* namespace in the name when the namespace is defined. */
stripped_name++;
if (*stripped_name == '\0')
/* Don't search for child with empty stripped name, because we'll
* find text nodes. But search with just the namespace for glib
* compatibility. */
return find_child (element, name);
child = find_child (element, stripped_name);
if (child)
return child;
/* Didn't find anything. */
}
/* There was no namespace, or we didn't find anything without the namespace.
*
* Try with the full name. */
return find_child (element, name);
}
gchar *
element_text (element_t element)
{
gchar *string;
if (!element)
return NULL;
string =
(gchar *) xmlNodeListGetString (element->doc, element->xmlChildrenNode, 1);
if (string)
return string;
string = xmlMalloc (1);
string[0] = '\0';
return string;
}
gchar *
element_attribute (element_t element, const gchar *name)
{
const gchar *stripped_name;
if (!element)
return NULL;
stripped_name = strchr (name, ':');
if (stripped_name)
{
gchar *attribute;
/* There was a namespace in the name.
*
* First try without the namespace, because libxml2 doesn't consider the
* namespace in the name when the namespace is defined. */
stripped_name++;
if (*stripped_name == '\0')
/* Don't search for child with empty stripped name, because we'll
* find text nodes. But search with just the namespace for glib
* compatibility. */
return (gchar *) xmlGetProp (element, (const xmlChar *) name);
attribute =
(gchar *) xmlGetProp (element, (const xmlChar *) stripped_name);
if (attribute)
return attribute;
/* Didn't find anything. */
}
/* There was no namespace, or we didn't find anything without the namespace.
*
* Try with the full name. */
return (gchar *) xmlGetProp (element, (const xmlChar *) name);
}
element_t
element_first_child (element_t element)
{
if (element)
{
element = element->children;
while (element && (element->type != XML_ELEMENT_NODE))
element = element->next;
return element;
}
return NULL;
}
element_t
element_next (element_t element)
{
if (element)
{
element = element->next;
while (element && (element->type != XML_ELEMENT_NODE))
element = element->next;
return element;
}
return NULL;
}
gchar *
element_to_string (element_t element)
{
xmlBufferPtr buffer;
char *xml_string;
// Copy element to ensure XML namespaces are included
element_t element_copy;
element_copy = xmlCopyNode (element, 1);
buffer = xmlBufferCreate ();
xmlNodeDump (buffer, element_copy->doc, element_copy, 0, 0);
xmlFreeNode (element_copy);
xml_string = g_strdup ((char *) xmlBufferContent (buffer));
xmlBufferFree (buffer);
return xml_string;
}
void
print_element_to_string (element_t element, GString *string)
{
gchar *text_escaped, *text;
element_t ch;
xmlAttr *attribute;
text_escaped = NULL;
g_string_append_printf (string, "<%s", element_name (element));
attribute = element->properties;
while (attribute)
{
xmlChar *value;
value = xmlNodeListGetString (element->doc, attribute->children, 1);
text_escaped = g_markup_escape_text ((gchar *) value, -1);
g_string_append_printf (string, " %s=\"%s\"", attribute->name,
text_escaped);
g_free (text_escaped);
xmlFree (value);
attribute = attribute->next;
}
g_string_append_printf (string, ">");
text = element_text (element);
text_escaped = g_markup_escape_text (text, -1);
g_free (text);
g_string_append_printf (string, "%s", text_escaped);
g_free (text_escaped);
ch = element_first_child (element);
while (ch)
{
print_element_to_string (ch, string);
ch = element_next (ch);
}
g_string_append_printf (string, "</%s>", element_name (element));
}
/* XML file iterator */
struct xml_file_iterator_struct
{
int initialized; //< Whether the iterator is initialized.
int output_depth; //< Tree depth at which to output subelements
GQueue *element_queue; //< Queue of parsed XML subelements
xmlSAXHandler sax_handler; //< SAX handler structure
xmlParserCtxtPtr parser_ctxt; //< libXML parser context for building DOM
gchar *file_path; //< Path to the XML file being processed
FILE *file; //< Stream pointer for the XML file
int stack_depth; // track depth (replaces nodeNr)
};
static void
xml_file_iterator_start_element_ns (void *ctx, const xmlChar *localname,
const xmlChar *prefix, const xmlChar *URI,
int nb_namespaces,
const xmlChar **namespaces,
int nb_attributes, int nb_defaulted,
const xmlChar **attributes)
{
xml_file_iterator_t iterator = (xml_file_iterator_t) ctx;
xmlSAX2StartElementNs (iterator->parser_ctxt, localname, prefix, URI,
nb_namespaces, namespaces, nb_attributes, nb_defaulted,
attributes);
iterator->stack_depth++;
}
static void
xml_file_iterator_end_element_ns (void *ctx, const xmlChar *localname,
const xmlChar *prefix, const xmlChar *URI)
{
xml_file_iterator_t iterator = (xml_file_iterator_t) ctx;
xmlSAX2EndElementNs (iterator->parser_ctxt, localname, prefix, URI);
iterator->stack_depth--;
if (iterator->stack_depth == iterator->output_depth)
{
xmlNodePtr parent, child;
parent = iterator->parser_ctxt->node;
child = parent->children;
while (child)
{
if (child->type == XML_ELEMENT_NODE)
{
xmlDocPtr new_doc = xmlNewDoc ((const xmlChar *) "1.0");
element_t child_copy;
child_copy = xmlCopyNode (child, 1);
xmlDocSetRootElement (new_doc, child_copy);
if (child_copy)
{
g_queue_push_tail (iterator->element_queue, child_copy);
}
}
xmlUnlinkNode (child);
xmlFreeNode (child);
child = parent->children;
}
}
}
static void
xml_file_iterator_internal_subset (void *ctx, const xmlChar *name,
const xmlChar *ExternalID,
const xmlChar *SystemID)
{
xml_file_iterator_t iterator = (xml_file_iterator_t) ctx;
xmlSAX2InternalSubset (iterator->parser_ctxt, name, ExternalID, SystemID);
}
static void
xml_file_iterator_external_subset (void *ctx, const xmlChar *name,
const xmlChar *ExternalID,
const xmlChar *SystemID)
{
xml_file_iterator_t iterator = (xml_file_iterator_t) ctx;
xmlSAX2ExternalSubset (iterator->parser_ctxt, name, ExternalID, SystemID);
}
static int
xml_file_iterator_is_standalone (void *ctx)
{
xml_file_iterator_t iterator = (xml_file_iterator_t) ctx;
return xmlSAX2IsStandalone (iterator->parser_ctxt);
}
static int
xml_file_iterator_has_internal_subset (void *ctx)
{
xml_file_iterator_t iterator = (xml_file_iterator_t) ctx;
return xmlSAX2HasInternalSubset (iterator->parser_ctxt);
}
static int
xml_file_iterator_has_external_subset (void *ctx)
{
xml_file_iterator_t iterator = (xml_file_iterator_t) ctx;
return xmlSAX2HasExternalSubset (iterator->parser_ctxt);
}
static xmlParserInputPtr
xml_file_iterator_resolve_entity (void *ctx, const xmlChar *publicId,
const xmlChar *systemId)
{
xml_file_iterator_t iterator = (xml_file_iterator_t) ctx;
return xmlSAX2ResolveEntity (iterator->parser_ctxt, publicId, systemId);
}
static xmlEntityPtr
xml_file_iterator_get_entity (void *ctx, const xmlChar *name)
{
xml_file_iterator_t iterator = (xml_file_iterator_t) ctx;
return xmlSAX2GetEntity (iterator->parser_ctxt, name);
}
static xmlEntityPtr
xml_file_iterator_get_parameter_entity (void *ctx, const xmlChar *name)
{
xml_file_iterator_t iterator = (xml_file_iterator_t) ctx;
return xmlSAX2GetParameterEntity (iterator->parser_ctxt, name);
}
static void
xml_file_iterator_entity_decl (void *ctx, const xmlChar *name, int type,
const xmlChar *publicId, const xmlChar *systemId,
xmlChar *content)
{
xml_file_iterator_t iterator = (xml_file_iterator_t) ctx;
xmlSAX2EntityDecl (iterator->parser_ctxt, name, type, publicId, systemId,
content);
}
static void
xml_file_iterator_attribute_decl (void *ctx, const xmlChar *elem,
const xmlChar *fullname, int type, int def,
const xmlChar *defaultValue,
xmlEnumerationPtr tree)
{
xml_file_iterator_t iterator = (xml_file_iterator_t) ctx;
xmlSAX2AttributeDecl (iterator->parser_ctxt, elem, fullname, type, def,
defaultValue, tree);
}
static void
xml_file_iterator_element_decl (void *ctx, const xmlChar *name, int type,
xmlElementContentPtr content)
{
xml_file_iterator_t iterator = (xml_file_iterator_t) ctx;
xmlSAX2ElementDecl (iterator->parser_ctxt, name, type, content);
}
static void
xml_file_iterator_notation_decl (void *ctx, const xmlChar *name,
const xmlChar *publicId,
const xmlChar *systemId)
{
xml_file_iterator_t iterator = (xml_file_iterator_t) ctx;
xmlSAX2NotationDecl (iterator->parser_ctxt, name, publicId, systemId);
}
static void
xml_file_iterator_unparsed_entity_decl (void *ctx, const xmlChar *name,
const xmlChar *publicId,
const xmlChar *systemId,
const xmlChar *notationName)
{
xml_file_iterator_t iterator = (xml_file_iterator_t) ctx;
xmlSAX2UnparsedEntityDecl (iterator->parser_ctxt, name, publicId, systemId,
notationName);
}
static void
xml_file_iterator_set_document_locator (void *ctx, xmlSAXLocatorPtr loc)
{
xml_file_iterator_t iterator = (xml_file_iterator_t) ctx;
xmlSAX2SetDocumentLocator (iterator->parser_ctxt, loc);
}
static void
xml_file_iterator_start_document (void *ctx)
{
xml_file_iterator_t iterator = (xml_file_iterator_t) ctx;
xmlSAX2StartDocument (iterator->parser_ctxt);
}
static void
xml_file_iterator_end_document (void *ctx)
{
xml_file_iterator_t iterator = (xml_file_iterator_t) ctx;
xmlSAX2EndDocument (iterator->parser_ctxt);
}
static void
xml_file_iterator_characters (void *ctx, const xmlChar *ch, int len)
{
xml_file_iterator_t iterator = (xml_file_iterator_t) ctx;
xmlSAX2Characters (iterator->parser_ctxt, ch, len);
}
static void
xml_file_iterator_cdata_block (void *ctx, const xmlChar *ch, int len)
{
xml_file_iterator_t iterator = (xml_file_iterator_t) ctx;
xmlSAX2CDataBlock (iterator->parser_ctxt, ch, len);
}
static void
xml_file_iterator_processing_instruction (void *ctx, const xmlChar *target,
const xmlChar *data)
{
xml_file_iterator_t iterator = (xml_file_iterator_t) ctx;
xmlSAX2ProcessingInstruction (iterator->parser_ctxt, target, data);
}
static void
xml_file_iterator_comment (void *ctx, const xmlChar *value)
{
xml_file_iterator_t iterator = (xml_file_iterator_t) ctx;
xmlSAX2Comment (iterator->parser_ctxt, value);
}
static void
xml_file_iterator_init_sax_handler (xmlSAXHandlerPtr hdlr)
{
hdlr->startElementNs = xml_file_iterator_start_element_ns;
hdlr->endElementNs = xml_file_iterator_end_element_ns;
hdlr->error = NULL;
hdlr->initialized = XML_SAX2_MAGIC;
hdlr->startElement = NULL;
hdlr->endElement = NULL;
hdlr->internalSubset = xml_file_iterator_internal_subset;
hdlr->externalSubset = xml_file_iterator_external_subset;
hdlr->isStandalone = xml_file_iterator_is_standalone;
hdlr->hasInternalSubset = xml_file_iterator_has_internal_subset;
hdlr->hasExternalSubset = xml_file_iterator_has_external_subset;
hdlr->resolveEntity = xml_file_iterator_resolve_entity;
hdlr->getEntity = xml_file_iterator_get_entity;
hdlr->getParameterEntity = xml_file_iterator_get_parameter_entity;
hdlr->entityDecl = xml_file_iterator_entity_decl;
hdlr->attributeDecl = xml_file_iterator_attribute_decl;
hdlr->elementDecl = xml_file_iterator_element_decl;
hdlr->notationDecl = xml_file_iterator_notation_decl;
hdlr->unparsedEntityDecl = xml_file_iterator_unparsed_entity_decl;
hdlr->setDocumentLocator = xml_file_iterator_set_document_locator;
hdlr->startDocument = xml_file_iterator_start_document;
hdlr->endDocument = xml_file_iterator_end_document;
hdlr->reference = NULL;
hdlr->characters = xml_file_iterator_characters;
hdlr->cdataBlock = xml_file_iterator_cdata_block;
hdlr->ignorableWhitespace = xml_file_iterator_characters;
hdlr->processingInstruction = xml_file_iterator_processing_instruction;
hdlr->comment = xml_file_iterator_comment;
hdlr->warning = xmlParserWarning;
hdlr->error = xmlParserError;
hdlr->fatalError = xmlParserError;
}
xml_file_iterator_t
xml_file_iterator_new (void)
{
return g_malloc0 (sizeof (struct xml_file_iterator_struct));
}
int
xml_file_iterator_init_from_file_path (xml_file_iterator_t iterator,
const char *file_path, int output_depth)
{
if (iterator == NULL)
return -1;
if (iterator->initialized)
return 1;
memset (iterator, 0, sizeof (struct xml_file_iterator_struct));
LIBXML_TEST_VERSION
if (output_depth < 0)
output_depth = 0;
iterator->output_depth = output_depth;
iterator->file = fopen (file_path, "rb");
if (iterator->file == NULL)
return 2;
iterator->element_queue = g_queue_new ();
iterator->file_path = g_strdup (file_path);
xml_file_iterator_init_sax_handler (&(iterator->sax_handler));
iterator->parser_ctxt = xmlCreatePushParserCtxt (
&(iterator->sax_handler), iterator, NULL, 0, iterator->file_path);
if (iterator->parser_ctxt == NULL)
return 3;
iterator->initialized = 1;
iterator->stack_depth = 0;
return 0;
}
void
xml_file_iterator_free (xml_file_iterator_t iterator)
{
if (iterator == NULL)
return;
if (iterator->file)
{
fclose (iterator->file);
}
g_free (iterator->file_path);
if (iterator->element_queue)
{
g_queue_free_full (iterator->element_queue,
(GDestroyNotify) (element_free));
}
if (iterator->parser_ctxt)
{
if (iterator->parser_ctxt->myDoc)
xmlFreeDoc (iterator->parser_ctxt->myDoc);
xmlFreeParserCtxt (iterator->parser_ctxt);
}
g_free (iterator);
}
int
xml_file_iterator_rewind (xml_file_iterator_t iterator)
{
if (iterator == NULL)
return 0;
if (iterator->file)
{
rewind (iterator->file);
}
if (iterator->element_queue)
{
g_queue_clear_full (iterator->element_queue,
(GDestroyNotify) (element_free));
}
if (iterator->parser_ctxt)
{
if (iterator->parser_ctxt->myDoc)
xmlFreeDoc (iterator->parser_ctxt->myDoc);
xmlFreeParserCtxt (iterator->parser_ctxt);
iterator->parser_ctxt = xmlCreatePushParserCtxt (
&(iterator->sax_handler), iterator, NULL, 0, iterator->file_path);
if (iterator->parser_ctxt == NULL)
return 1;
}
iterator->stack_depth = 0;
return 0;
}
#define XML_FILE_ITERATOR_BUFFER_SIZE 8192
element_t
xml_file_iterator_next (xml_file_iterator_t iterator, gchar **error)
{
gboolean continue_read = TRUE;
if (error)
*error = NULL;
if (iterator->initialized == 0)
{
if (error)
*error = g_strdup ("iterator not initialized");
return NULL;
}
while (continue_read && g_queue_is_empty (iterator->element_queue))
{
int chars_read;
char buffer[XML_FILE_ITERATOR_BUFFER_SIZE];
chars_read =
fread (buffer, 1, XML_FILE_ITERATOR_BUFFER_SIZE, iterator->file);
if (chars_read == 0)
{
if (feof (iterator->file))
{
continue_read = FALSE;
}
else if (ferror (iterator->file))
{
if (error)
*error = g_strdup ("error reading file");
return NULL;
}
}
else
{
int ret;
ret = xmlParseChunk (iterator->parser_ctxt, buffer, chars_read,
continue_read == 0);
if (ret)
{
if (error)
{
const xmlError *xml_error;
xml_error = xmlCtxtGetLastError (iterator->parser_ctxt);
*error = g_strdup_printf ("error parsing XML"
" (line %d column %d): %s",
xml_error->line, xml_error->int2,
xml_error->message);
}
return NULL;
}
}
}
if (!g_queue_is_empty (iterator->element_queue))
{
return g_queue_pop_head (iterator->element_queue);
}
return NULL;
}
context_data_t
XML context.
Definition xmlutils.h:27
context_data_t::first
GSList * first
The very first entity.
Definition xmlutils.h:28
context_data_t::current
GSList * current
The element currently being parsed.
Definition xmlutils.h:29
context_data_t::done
gboolean done
Flag which is true when the first element is closed.
Definition xmlutils.h:30
entity_s::entities
entities_t entities
Children.
Definition xmlutils.h:56
entity_s::text
char * text
Text.
Definition xmlutils.h:54
entity_s::attributes
GHashTable * attributes
Attributes.
Definition xmlutils.h:55
entity_s::name
char * name
Name.
Definition xmlutils.h:53
gvm_connection_t
Connection.
Definition serverutils.h:30
gvm_connection_t::tls
int tls
Whether uses TCP-TLS (vs UNIX socket).
Definition serverutils.h:31
gvm_connection_t::socket
int socket
Socket.
Definition serverutils.h:32
gvm_connection_t::session
gnutls_session_t session
Session.
Definition serverutils.h:33
xml_file_iterator_struct
Opaque data structure for XML file iterator.
Definition xmlutils.c:2331
xml_file_iterator_struct::parser_ctxt
xmlParserCtxtPtr parser_ctxt
Definition xmlutils.c:2336
xml_file_iterator_struct::output_depth
int output_depth
Definition xmlutils.c:2333
xml_file_iterator_struct::element_queue
GQueue * element_queue
Definition xmlutils.c:2334
xml_file_iterator_struct::stack_depth
int stack_depth
Definition xmlutils.c:2339
xml_file_iterator_struct::sax_handler
xmlSAXHandler sax_handler
Definition xmlutils.c:2335
xml_file_iterator_struct::initialized
int initialized
Definition xmlutils.c:2332
xml_file_iterator_struct::file
FILE * file
Definition xmlutils.c:2338
xml_file_iterator_struct::file_path
gchar * file_path
Definition xmlutils.c:2337
xml_search_data_t
Data for xml search functions.
Definition xmlutils.h:64
xml_search_data_t::find_element
gchar * find_element
Definition xmlutils.h:67
xml_search_data_t::find_attributes
GHashTable * find_attributes
Definition xmlutils.h:68
xml_search_data_t::found
int found
Definition xmlutils.h:65
handle_text
static void handle_text(GMarkupParseContext *context, const gchar *text, gsize text_len, gpointer user_data, GError **error)
Handle additional text of an XML element.
Definition xmlutils.c:437
try_read_string_s
static int try_read_string_s(int socket, int timeout, GString **string_return)
Try read an XML entity tree from the socket.
Definition xmlutils.c:900
element_free
void element_free(element_t element)
Free an entire element tree.
Definition xmlutils.c:2035
read_entity_c
int read_entity_c(gvm_connection_t *connection, entity_t *entity)
Read an XML entity tree from the manager.
Definition xmlutils.c:1497
xml_handle_start_element
void xml_handle_start_element(context_data_t *context, const gchar *element_name, const gchar **attribute_names, const gchar **attribute_values)
Handle the start of an OMP XML element.
Definition xmlutils.c:326
entity_attribute
const char * entity_attribute(entity_t entity, const char *name)
Get an attribute of an entity.
Definition xmlutils.c:216
read_string
int read_string(gnutls_session_t *session, GString **string)
Read entity and text. Free the entity immediately.
Definition xmlutils.c:1400
read_string_c
int read_string_c(gvm_connection_t *connection, GString **string)
Read entity and text. Free the entity immediately.
Definition xmlutils.c:1420
ignore_text
static void ignore_text(GMarkupParseContext *context, const gchar *text, gsize text_len, gpointer user_data, GError **error)
Handle additional text of an XML element.
Definition xmlutils.c:417
xml_file_iterator_characters
static void xml_file_iterator_characters(void *ctx, const xmlChar *ch, int len)
XML file iterator parser callback when receiving some chars from the parser.
Definition xmlutils.c:2748
find_element_in_xml_file
int find_element_in_xml_file(gchar *file_path, gchar *find_element, GHashTable *find_attributes)
Tests if an XML file contains an element with given attributes.
Definition xmlutils.c:1942
xml_file_iterator_unparsed_entity_decl
static void xml_file_iterator_unparsed_entity_decl(void *ctx, const xmlChar *name, const xmlChar *publicId, const xmlChar *systemId, const xmlChar *notationName)
XML file iterator parser callback for when an unparsed entity declaration has been parsed.
Definition xmlutils.c:2680
entity_name
char * entity_name(entity_t entity)
Get the name an entity.
Definition xmlutils.c:161
entity_text
char * entity_text(entity_t entity)
Get the text an entity.
Definition xmlutils.c:145
handle_end_element
static void handle_end_element(GMarkupParseContext *context, const gchar *element_name, gpointer user_data, GError **error)
Handle the end of an XML element.
Definition xmlutils.c:366
xml_file_iterator_processing_instruction
static void xml_file_iterator_processing_instruction(void *ctx, const xmlChar *target, const xmlChar *data)
XML file iterator parser callback when a processing instruction has been parsed.
Definition xmlutils.c:2784
xml_file_iterator_entity_decl
static void xml_file_iterator_entity_decl(void *ctx, const xmlChar *name, int type, const xmlChar *publicId, const xmlChar *systemId, xmlChar *content)
XML file iterator parser callback for when an entity definition has been parsed.
Definition xmlutils.c:2590
element_name
const gchar * element_name(element_t element)
Get the name of an element.
Definition xmlutils.c:2052
xml_file_iterator_init_sax_handler
static void xml_file_iterator_init_sax_handler(xmlSAXHandlerPtr hdlr)
Initializes a xmlSAXHandler data structure for SAX version 2 parsing, assigning all the XML file iter...
Definition xmlutils.c:2814
xml_search_handle_start_element
static void xml_search_handle_start_element(GMarkupParseContext *ctx, const gchar *element_name, const gchar **attribute_names, const gchar **attribute_values, gpointer data, GError **error)
Handle the opening tag of an element in an XML search.
Definition xmlutils.c:1874
xml_file_iterator_new
xml_file_iterator_t xml_file_iterator_new(void)
Allocates a new, uninitialized XML file iterator.
Definition xmlutils.c:2857
xml_file_iterator_is_standalone
static int xml_file_iterator_is_standalone(void *ctx)
XML file iterator parser callback for checking if doc is standalone.
Definition xmlutils.c:2476
xml_file_iterator_start_document
static void xml_file_iterator_start_document(void *ctx)
XML file iterator parser callback at the document start.
Definition xmlutils.c:2715
try_read_entity_and_string_s
static int try_read_entity_and_string_s(int socket, int timeout, entity_t *entity, GString **string_return)
Try read an XML entity tree from the socket.
Definition xmlutils.c:1030
try_read_string
static int try_read_string(gnutls_session_t *session, int timeout, GString **string_return)
Try read a response from a TLS session.
Definition xmlutils.c:752
xml_file_iterator_get_entity
static xmlEntityPtr xml_file_iterator_get_entity(void *ctx, const xmlChar *name)
XML file iterator parser callback for getting an entity by name.
Definition xmlutils.c:2550
first_entity
entity_t first_entity(entities_t entities)
Return the first entity from an entities_t.
Definition xmlutils.c:82
element_text
gchar * element_text(element_t element)
Get text of an element.
Definition xmlutils.c:2137
read_entity_and_string_c
int read_entity_and_string_c(gvm_connection_t *connection, entity_t *entity, GString **string_return)
Try read an XML entity tree from the manager.
Definition xmlutils.c:1282
xml_file_iterator_init_from_file_path
int xml_file_iterator_init_from_file_path(xml_file_iterator_t iterator, const char *file_path, int output_depth)
Initializes an XML file iterator to read from a given path.
Definition xmlutils.c:2874
handle_error
static void handle_error(GMarkupParseContext *context, GError *error, gpointer user_data)
Handle an OMP XML parsing error.
Definition xmlutils.c:477
print_element_to_string
void print_element_to_string(element_t element, GString *string)
Print an XML element tree to a GString, appending it if string is not.
Definition xmlutils.c:2280
read_entity
int read_entity(gnutls_session_t *session, entity_t *entity)
Read an XML entity tree from the manager.
Definition xmlutils.c:1469
read_entity_and_string
int read_entity_and_string(gnutls_session_t *session, entity_t *entity, GString **string_return)
Try read an XML entity tree from the manager.
Definition xmlutils.c:1262
xml_file_iterator_internal_subset
static void xml_file_iterator_internal_subset(void *ctx, const xmlChar *name, const xmlChar *ExternalID, const xmlChar *SystemID)
XML file iterator parser callback for internal subset declaration.
Definition xmlutils.c:2437
xml_file_iterator_rewind
int xml_file_iterator_rewind(xml_file_iterator_t iterator)
Rewinds an XML file iterator by rewinding the file and creating a new XML parser context.
Definition xmlutils.c:2954
foreach_print_entity_to_string
static void foreach_print_entity_to_string(gpointer entity, gpointer string)
Print an XML entity for g_slist_foreach to a GString.
Definition xmlutils.c:1585
try_read_entity
int try_read_entity(gnutls_session_t *session, int timeout, entity_t *entity)
Try read an XML entity tree from the manager.
Definition xmlutils.c:1436
xml_file_iterator_comment
static void xml_file_iterator_comment(void *ctx, const xmlChar *value)
XML file iterator parser callback when a comment has been parsed.
Definition xmlutils.c:2801
foreach_print_entity
static void foreach_print_entity(gpointer entity, gpointer stream)
Print an XML entity for g_slist_foreach.
Definition xmlutils.c:1638
next_entities
entities_t next_entities(entities_t entities)
Return all the entities from an entities_t after the first.
Definition xmlutils.c:67
BUFFER_SIZE
#define BUFFER_SIZE
Size of the buffer for reading from the manager.
Definition xmlutils.c:37
element_attribute
gchar * element_attribute(element_t element, const gchar *name)
Get an attribute of an element.
Definition xmlutils.c:2162
foreach_print_attribute_format
static void foreach_print_attribute_format(gpointer name, gpointer value, gpointer none)
Print an XML attribute for g_hash_table_foreach to stdout.
Definition xmlutils.c:1688
element_first_child
element_t element_first_child(element_t element)
Get the first child of an element.
Definition xmlutils.c:2210
print_entity_format
void print_entity_format(entity_t entity, gpointer indent)
Print an XML entity to stdout, recursively printing its children.
Definition xmlutils.c:1706
xml_file_iterator_next
element_t xml_file_iterator_next(xml_file_iterator_t iterator, gchar **error)
Get the next subelement from a XML file iterator.
Definition xmlutils.c:3000
free_entity
void free_entity(entity_t entity)
Free an entity, recursively.
Definition xmlutils.c:115
compare_find_attribute
static gboolean compare_find_attribute(gpointer key, gpointer value, gpointer attributes2)
Look for a key-value pair in a hash table.
Definition xmlutils.c:1747
xml_file_iterator_get_parameter_entity
static xmlEntityPtr xml_file_iterator_get_parameter_entity(void *ctx, const xmlChar *name)
XML file iterator parser callback for getting a parameter entity by name.
Definition xmlutils.c:2569
xml_file_iterator_end_element_ns
static void xml_file_iterator_end_element_ns(void *ctx, const xmlChar *localname, const xmlChar *prefix, const xmlChar *URI)
XML file iterator parser callback for element end.
Definition xmlutils.c:2390
xml_file_iterator_free
void xml_file_iterator_free(xml_file_iterator_t iterator)
Frees an XML file iterator and all of its internal data structures.
Definition xmlutils.c:2917
find_child
static element_t find_child(element_t element, const gchar *name)
Find child in an element.
Definition xmlutils.c:2069
read_text_c
int read_text_c(gvm_connection_t *connection, char **text)
Read text from the server.
Definition xmlutils.c:1366
read_entity_and_text_c
int read_entity_and_text_c(gvm_connection_t *connection, entity_t *entity, char **text)
Read an XML entity tree from the manager.
Definition xmlutils.c:1336
parse_element
int parse_element(const gchar *string, element_t *element)
Read an XML element tree from a string.
Definition xmlutils.c:2003
xml_file_iterator_has_external_subset
static int xml_file_iterator_has_external_subset(void *ctx)
XML file iterator parser callback for checking if doc has an external subset.
Definition xmlutils.c:2512
xml_file_iterator_start_element_ns
static void xml_file_iterator_start_element_ns(void *ctx, const xmlChar *localname, const xmlChar *prefix, const xmlChar *URI, int nb_namespaces, const xmlChar **namespaces, int nb_attributes, int nb_defaulted, const xmlChar **attributes)
XML file iterator parser callback for element start.
Definition xmlutils.c:2361
read_entity_and_text
int read_entity_and_text(gnutls_session_t *session, entity_t *entity, char **text)
Read an XML entity tree from the manager.
Definition xmlutils.c:1305
try_read_entity_and_string
int try_read_entity_and_string(gnutls_session_t *session, int timeout, entity_t *entity, GString **string_return)
Try read an XML entity tree from the manager.
Definition xmlutils.c:501
xml_file_iterator_resolve_entity
static xmlParserInputPtr xml_file_iterator_resolve_entity(void *ctx, const xmlChar *publicId, const xmlChar *systemId)
XML file iterator parser callback for resolving an entity.
Definition xmlutils.c:2531
compare_entity_with_name
static int compare_entity_with_name(gconstpointer entity, gconstpointer name)
Compare a given name with the name of a given entity.
Definition xmlutils.c:179
add_entity
entity_t add_entity(entities_t *entities, const char *name, const char *text)
Add an XML entity to a tree of entities.
Definition xmlutils.c:101
xml_file_iterator_set_document_locator
static void xml_file_iterator_set_document_locator(void *ctx, xmlSAXLocatorPtr loc)
XML file iterator parser callback for setting the document locator.
Definition xmlutils.c:2700
xml_file_iterator_external_subset
static void xml_file_iterator_external_subset(void *ctx, const xmlChar *name, const xmlChar *ExternalID, const xmlChar *SystemID)
XML file iterator parser callback for external subset declaration.
Definition xmlutils.c:2457
xml_count_entities
int xml_count_entities(entities_t entities)
Count the number of entities.
Definition xmlutils.c:1830
xml_file_iterator_cdata_block
static void xml_file_iterator_cdata_block(void *ctx, const xmlChar *ch, int len)
XML file iterator parser callback when a cdata block has been parsed.
Definition xmlutils.c:2766
entity_child
entity_t entity_child(entity_t entity, const char *name)
Get a child of an entity.
Definition xmlutils.c:193
handle_start_element
static void handle_start_element(GMarkupParseContext *context, const gchar *element_name, const gchar **attribute_names, const gchar **attribute_values, gpointer user_data, GError **error)
Handle the start of an OMP XML element.
Definition xmlutils.c:290
xml_handle_end_element
void xml_handle_end_element(context_data_t *context, const gchar *element_name)
Handle the end of an XML element.
Definition xmlutils.c:402
ignore_start_element
static void ignore_start_element(GMarkupParseContext *context, const gchar *element_name, const gchar **attribute_names, const gchar **attribute_values, gpointer user_data, GError **error)
Handle the start of an OMP XML element.
Definition xmlutils.c:263
make_entity
static entity_t make_entity(const char *name, const char *text)
Create an entity.
Definition xmlutils.c:48
xml_file_iterator_attribute_decl
static void xml_file_iterator_attribute_decl(void *ctx, const xmlChar *elem, const xmlChar *fullname, int type, int def, const xmlChar *defaultValue, xmlEnumerationPtr tree)
XML file iterator parser callback for when an attribute definition has been parsed.
Definition xmlutils.c:2615
element_next
element_t element_next(element_t element)
Get the next sibling of an element.
Definition xmlutils.c:2230
element_to_string
gchar * element_to_string(element_t element)
Output the XML element as a string.
Definition xmlutils.c:2253
element_child
element_t element_child(element_t element, const gchar *name)
Get a child of an element.
Definition xmlutils.c:2086
parse_entity
int parse_entity(const char *string, entity_t *entity)
Read an XML entity tree from a string.
Definition xmlutils.c:1511
XML_FILE_BUFFER_SIZE
#define XML_FILE_BUFFER_SIZE
Definition xmlutils.c:1931
compare_entities
int compare_entities(entity_t entity1, entity_t entity2)
Compare two XML entity.
Definition xmlutils.c:1765
try_read_entity_c
int try_read_entity_c(gvm_connection_t *connection, int timeout, entity_t *entity)
Try read an XML entity tree from the manager.
Definition xmlutils.c:1452
foreach_print_attribute
static void foreach_print_attribute(gpointer name, gpointer value, gpointer stream)
Print an XML attribute for g_hash_table_foreach.
Definition xmlutils.c:1651
read_entity_s
int read_entity_s(int socket, entity_t *entity)
Read an XML entity tree from the socket.
Definition xmlutils.c:1483
xml_file_iterator_end_document
static void xml_file_iterator_end_document(void *ctx)
XML file iterator parser callback at the document end.
Definition xmlutils.c:2730
print_entity
void print_entity(FILE *stream, entity_t entity)
Print an XML entity.
Definition xmlutils.c:1663
xml_file_iterator_element_decl
static void xml_file_iterator_element_decl(void *ctx, const xmlChar *name, int type, xmlElementContentPtr content)
XML file iterator parser callback for when an element definition has been parsed.
Definition xmlutils.c:2638
ignore_end_element
static void ignore_end_element(GMarkupParseContext *context, const gchar *element_name, gpointer user_data, GError **error)
Handle the end of an XML element.
Definition xmlutils.c:343
add_attributes
static void add_attributes(entity_t entity, const gchar **names, const gchar **values)
Add attributes from an XML callback to an entity.
Definition xmlutils.c:234
XML_FILE_ITERATOR_BUFFER_SIZE
#define XML_FILE_ITERATOR_BUFFER_SIZE
File read buffer size for an XML file iterator.
Definition xmlutils.c:2988
foreach_print_attribute_to_string
static void foreach_print_attribute_to_string(gpointer name, gpointer value, gpointer string)
Print an XML attribute for g_hash_table_foreach to a GString.
Definition xmlutils.c:1598
xml_handle_text
void xml_handle_text(context_data_t *context, const gchar *text, gsize text_len)
Handle additional text of an XML element.
Definition xmlutils.c:464
xml_file_iterator_notation_decl
static void xml_file_iterator_notation_decl(void *ctx, const xmlChar *name, const xmlChar *publicId, const xmlChar *systemId)
XML file iterator parser callback for when a notation definition has been parsed.
Definition xmlutils.c:2658
xml_file_iterator_has_internal_subset
static int xml_file_iterator_has_internal_subset(void *ctx)
XML file iterator parser callback for checking if doc has an internal subset.
Definition xmlutils.c:2494
xml_string_append
void xml_string_append(GString *xml, const char *format,...)
Append formatted escaped XML to a string.
Definition xmlutils.c:1849
print_entity_to_string
void print_entity_to_string(entity_t entity, GString *string)
Print an XML entity tree to a GString, appending it if string is not.
Definition xmlutils.c:1616
xmlutils.h
Headers for simple XML reader.
entity_t
struct entity_s * entity_t
Definition xmlutils.h:58
xml_file_iterator_t
struct xml_file_iterator_struct * xml_file_iterator_t
Definition xmlutils.h:188
element_t
struct _xmlNode * element_t
Definition xmlutils.h:157
entities_t
GSList * entities_t
Entities.
Definition xmlutils.h:46