diff options
author | Jesusaves <cpntb1@ymail.com> | 2022-02-22 07:09:31 -0300 |
---|---|---|
committer | Jesusaves <cpntb1@ymail.com> | 2022-02-22 07:09:31 -0300 |
commit | b9d57b7ee57e79820c97c4d452c07972b73f3c7c (patch) | |
tree | 06a98c67240ee509b19d26ee54d8515f06f37230 /saedit/xml.c | |
parent | a0c410d5ac8eeeeb4d7295c8f54931fa32664f4d (diff) | |
download | tools-b9d57b7ee57e79820c97c4d452c07972b73f3c7c.tar.gz tools-b9d57b7ee57e79820c97c4d452c07972b73f3c7c.tar.bz2 tools-b9d57b7ee57e79820c97c4d452c07972b73f3c7c.tar.xz tools-b9d57b7ee57e79820c97c4d452c07972b73f3c7c.zip |
Include saedit2
Diffstat (limited to 'saedit/xml.c')
-rw-r--r-- | saedit/xml.c | 385 |
1 files changed, 385 insertions, 0 deletions
diff --git a/saedit/xml.c b/saedit/xml.c new file mode 100644 index 0000000..90c4d76 --- /dev/null +++ b/saedit/xml.c @@ -0,0 +1,385 @@ +#include "xml.h" +#include <string.h> + +gchar ** +xml_attr_new ( + const gchar *name, + const gchar *value +) { + gchar **attr = g_new0(gchar*, 2); + attr[0] = g_strdup(name); + attr[1] = g_strdup(value); + return attr; +} + +gchar * +xml_node_get_attr_value ( + const XMLNode *node, + const gchar *attr_name +) { + gchar **attr = node->attributes; + guint i; + for (i = 0; i < g_strv_length(attr); i += 2) + if (g_str_equal(attr[i], attr_name)) + return g_strdup (attr[i + 1]); + return NULL; +} + +gint +xml_node_get_int_attr_value ( + const XMLNode *node, + const gchar *attr_name, + gint retval +) { + gchar *val = xml_node_get_attr_value (node, attr_name); + + if (val != NULL) { + try_strtoint (val, &retval); + g_free (val); + } + + return retval; +} + +gint +xml_node_get_int_attr_value_limited ( + const XMLNode *node, + const gchar *attr_name, + gint retval, + gint lower, + gint upper +) { + g_assert (lower <= upper); + + retval = xml_node_get_int_attr_value ( + node, attr_name, retval + ); + + if (retval < lower) + retval = lower; + + if (retval > upper) + retval = upper; + return retval; +} + +gint +xml_node_compare_with_name_func ( + gconstpointer a, + gconstpointer b +) { + return g_strcmp0((gchar *) b, ((XMLNode *) a)->name); +} + +gint +xml_node_compare_with_action_node_by_imageset_name_func ( + gconstpointer a, + gconstpointer b +) { + return g_strcmp0("action", ((XMLNode *) a)->name) || + g_strcmp0((gchar *) b, xml_node_get_attr_value((XMLNode *) a, "imageset")); +} + +gint +xml_node_compare_with_attr_func ( + const XMLNode *node, + const gchar **attr +) { + return g_strcmp0(attr[1], + xml_node_get_attr_value(node, attr[0])); +} + +static GMarkupParser parser; + +void _xml_free_g_func (XMLNode *node, gpointer user_data) { + xml_free (node); +} + +void xml_free (XMLNode *node) { + g_free (node->name); + + g_free (node->text); + + g_strfreev (node->attributes); + + g_list_foreach (node->sub_nodes, (GFunc) _xml_free_g_func, NULL); + g_list_free (node->sub_nodes); + + g_slice_free (XMLNode, node); +} + +static void _start_root_element_cb ( GMarkupParseContext *context, + const gchar *element_name, + const gchar **attribute_names, + const gchar **attribute_values, + gpointer user_data, + GError **error +) { + XMLNode **node = (XMLNode **) user_data; + XMLNode *p; + GArray *attributes; + + g_assert (node != NULL); + + p = g_slice_new0 (XMLNode); + p->name = g_strdup (element_name); + + attributes = g_array_new (TRUE, TRUE, sizeof (gchar *)); + while (*attribute_names != NULL && *attribute_values != NULL) { + gchar *p2; + p2 = g_strdup (*attribute_names++); + g_array_append_val (attributes, p2); + p2 = g_strdup (*attribute_values++); + g_array_append_val (attributes, p2); + } + + p->attributes = (gchar **) g_array_free (attributes, FALSE); + + g_markup_parse_context_push (context, &parser, p); + *node = p; +} + + +static void _start_element_cb ( + GMarkupParseContext *context, + const gchar *element_name, + const gchar **attribute_names, + const gchar **attribute_values, + gpointer user_data, + GError **error +) { + XMLNode *p, *node = (XMLNode *) user_data; + GArray *attributes; + gint char_n, line_n; + + if (node->text) { + g_set_error (error, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT, " "); + return; + } + + p = g_slice_new0 (XMLNode); + + node->sub_nodes = g_list_append (node->sub_nodes, p); + g_markup_parse_context_push (context, &parser, p); + + p->name = g_strdup (element_name); + + attributes = g_array_new (TRUE, TRUE, sizeof (gchar *)); + while (*attribute_names != NULL && *attribute_values != NULL) { + gchar *p2; + p2 = g_strdup (*attribute_names++); + g_array_append_val (attributes, p2); + p2 = g_strdup (*attribute_values++); + g_array_append_val (attributes, p2); + } + + p->attributes = (gchar **)g_array_free (attributes, FALSE); + + g_markup_parse_context_get_position(context, &line_n, &char_n); + p->line_no = line_n - (char_n <= 1 ? 1 : 0); +} + +static void +_end_element_cb ( + GMarkupParseContext *context, + const gchar *element_name, + gpointer user_data, + GError **error +) { + XMLNode *p = (XMLNode *) g_markup_parse_context_pop (context); + + if (p->text && p->sub_nodes) { + g_warning ("Error"); + } + + if (p->text == NULL && p->sub_nodes == NULL) { + p->text = g_strdup (""); + } +} + +static gboolean +_is_space ( + const gchar *text, + gsize text_len +) { + gsize i = 0; + + for (i = 0; text[i] != '\0' && i < text_len; i++) { + switch (text[i]) { + case '\t': + case ' ': + case '\n': + case '\r': + continue; + default: + return FALSE; + } + } + + return TRUE; +} + +static void +_text_cb ( + GMarkupParseContext *context, + const gchar *text, + gsize text_len, + gpointer user_data, + GError **error +) { + XMLNode *p = (XMLNode *)user_data; + + if (_is_space (text, text_len)) { + return; + } + + if (p->sub_nodes || p->text) { + g_set_error (error, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT, " "); + return; + } + + p->text = g_strndup (text, text_len); +} + +static GMarkupParser parser = { + _start_element_cb, + _end_element_cb, + _text_cb, + 0, + 0, +}; + +XMLNode * +xml_parse_file (const gchar *filename) { + gboolean retval = FALSE; + GError *error = NULL; + GMarkupParseContext *context; + XMLNode *node; + + static const GMarkupParser root_parser = { + _start_root_element_cb, + _end_element_cb, + _text_cb, + 0, + 0, + }; + + FILE *pf = fopen (filename, "r"); + + if (pf == NULL) { + return NULL; + } + + do { + context = g_markup_parse_context_new (&root_parser, 0, &node, 0); + + while (!feof (pf)) { + gchar buf[1024]; + gssize len = 0; + + len = fread (buf, 1, sizeof (buf), pf); + retval = g_markup_parse_context_parse (context, buf, len, &error); + + if (!retval) + break; + } + fclose (pf); + + if (!retval) + break; + + retval = g_markup_parse_context_end_parse (context, &error); + if (!retval) + break; + + g_markup_parse_context_free (context); + + return node; + } while (0); + + g_warning ("Parse %s failed: %s", filename, error->message); + g_error_free (error); + g_markup_parse_context_free (context); + return NULL; +} + +XMLNode * +xml_parse_buffer (const gchar *buffer, GError **error) { + gboolean retval; + + GMarkupParseContext *context; + XMLNode *node; + + static const GMarkupParser root_parser = { + _start_root_element_cb, + _end_element_cb, + _text_cb, + 0, + 0, + }; + + context = g_markup_parse_context_new (&root_parser, 0, &node, 0); + + do { + retval = g_markup_parse_context_parse (context, buffer, strlen (buffer), error); + if (!retval) + break; + + retval = g_markup_parse_context_end_parse (context, error); + if (!retval) + break; + g_markup_parse_context_free (context); + return node; + } while (0); + + g_markup_parse_context_free (context); + return NULL; +} + + +static void output_indent (int level, GString *output) { + gint i; + for (i = 0; i < level; i++) { + g_string_append (output, " "); + } +} + +static void xml_output_indent ( + const XMLNode *node, + int level, + GString *output +) { + gchar **attrs; + + output_indent (level, output); + g_string_append_printf (output, "<%s", node->name); + + attrs = node->attributes; + + while (attrs != NULL && *attrs != NULL) { + g_string_append_printf (output, " %s", *(attrs++)); + g_string_append_printf (output, "=\"%s\"", *(attrs++)); + } + + if (node->sub_nodes != NULL) { + GList *sub_node; + g_string_append (output, ">\n"); + + for (sub_node = node->sub_nodes; sub_node != NULL; sub_node = sub_node->next) { + xml_output_indent (sub_node->data, level + 1, output); + } + output_indent (level, output); + g_string_append_printf (output, "</%s>\n",node->name); + } else if (node->text != NULL) { + gchar *text = g_markup_escape_text (node->text, -1); + g_string_append_printf (output, ">%s</%s>\n", text, node->name); + g_free (text); + } else { + g_string_append (output, "/>\n"); + } +} + +void xml_output (const XMLNode *node, GString *output) { + xml_output_indent (node, 0, output); +} + |