diff --git a/src/builder-manifest.c b/src/builder-manifest.c index 1208d45a..b8742280 100644 --- a/src/builder-manifest.c +++ b/src/builder-manifest.c @@ -2420,35 +2420,54 @@ builder_manifest_cleanup (BuilderManifest *self, if (appdata_file != NULL) { - g_autofree char *contents; - const char *to_replace; - const char *match; - g_autofree char *replace_src = NULL; - g_autofree char *replace_dst = NULL; + FlatpakXml *n_id; + FlatpakXml *n_root; + FlatpakXml *n_text; + g_autoptr(FlatpakXml) xml_root = NULL; + g_autoptr(GInputStream) in = NULL; g_autoptr(GString) new_contents = NULL; - if (!g_file_load_contents (appdata_file, NULL, &contents, NULL, NULL, error)) + in = (GInputStream *) g_file_read (appdata_file, NULL, error); + if (!in) + return FALSE; + xml_root = flatpak_xml_parse (in, FALSE, NULL, error); + if (!xml_root) return FALSE; - new_contents = g_string_sized_new (strlen (contents)); - - to_replace = contents; - - /* We only want to replace entire matches to id tag, so add the brackets - * and the end-tag. That way we don't do partial matches, or match - * other tags, while still handling e.g. foo.desktop */ - replace_src = g_strdup_printf (">%srename_desktop_file); - replace_dst = g_strdup_printf (">%s node"); + return FALSE; + } + n_id = flatpak_xml_find (n_root, "id", NULL); + if (n_id) + { + n_text = n_id->first_child; + if (n_text && g_strcmp0 (n_text->text, self->rename_desktop_file) == 0) + { + g_free (n_text->text); + n_text->text = g_strdup (self->id); + } } - g_string_append (new_contents, to_replace); + /* replace any optional launchable */ + n_id = flatpak_xml_find (n_root, "launchable", NULL); + if (n_id) + { + n_text = n_id->first_child; + if (n_text && g_strcmp0 (n_text->text, self->rename_desktop_file) == 0) + { + g_free (n_text->text); + n_text->text = g_strdup (desktop_basename); + } + } + new_contents = g_string_new (""); + flatpak_xml_to_string (xml_root, new_contents); if (!g_file_set_contents (flatpak_file_get_path_cached (appdata_file), new_contents->str, new_contents->len, diff --git a/src/builder-utils.c b/src/builder-utils.c index 081f0294..966987b1 100644 --- a/src/builder-utils.c +++ b/src/builder-utils.c @@ -2035,3 +2035,272 @@ builder_set_term_title (const gchar *format, g_print ("\033]2;flatpak-builder: %s\007", message); } + +typedef struct +{ + FlatpakXml *current; +} XmlData; + +FlatpakXml * +flatpak_xml_new (const gchar *element_name) +{ + FlatpakXml *node = g_new0 (FlatpakXml, 1); + + node->element_name = g_strdup (element_name); + return node; +} + +FlatpakXml * +flatpak_xml_new_text (const gchar *text) +{ + FlatpakXml *node = g_new0 (FlatpakXml, 1); + + node->text = g_strdup (text); + return node; +} + +void +flatpak_xml_add (FlatpakXml *parent, FlatpakXml *node) +{ + node->parent = parent; + + if (parent->first_child == NULL) + parent->first_child = node; + else + parent->last_child->next_sibling = node; + parent->last_child = node; +} + +static void +xml_start_element (GMarkupParseContext *context, + const gchar *element_name, + const gchar **attribute_names, + const gchar **attribute_values, + gpointer user_data, + GError **error) +{ + XmlData *data = user_data; + FlatpakXml *node; + + node = flatpak_xml_new (element_name); + node->attribute_names = g_strdupv ((char **) attribute_names); + node->attribute_values = g_strdupv ((char **) attribute_values); + + flatpak_xml_add (data->current, node); + data->current = node; +} + +static void +xml_end_element (GMarkupParseContext *context, + const gchar *element_name, + gpointer user_data, + GError **error) +{ + XmlData *data = user_data; + + data->current = data->current->parent; +} + +static void +xml_text (GMarkupParseContext *context, + const gchar *text, + gsize text_len, + gpointer user_data, + GError **error) +{ + XmlData *data = user_data; + FlatpakXml *node; + + node = flatpak_xml_new (NULL); + node->text = g_strndup (text, text_len); + flatpak_xml_add (data->current, node); +} + +static void +xml_passthrough (GMarkupParseContext *context, + const gchar *passthrough_text, + gsize text_len, + gpointer user_data, + GError **error) +{ +} + +static GMarkupParser xml_parser = { + xml_start_element, + xml_end_element, + xml_text, + xml_passthrough, + NULL +}; + +void +flatpak_xml_free (FlatpakXml *node) +{ + FlatpakXml *child; + + if (node == NULL) + return; + + child = node->first_child; + while (child != NULL) + { + FlatpakXml *next = child->next_sibling; + flatpak_xml_free (child); + child = next; + } + + g_free (node->element_name); + g_free (node->text); + g_strfreev (node->attribute_names); + g_strfreev (node->attribute_values); + g_free (node); +} + + +void +flatpak_xml_to_string (FlatpakXml *node, GString *res) +{ + int i; + FlatpakXml *child; + + if (node->parent == NULL) + g_string_append (res, "\n"); + + if (node->element_name) + { + if (node->parent != NULL) + { + g_string_append (res, "<"); + g_string_append (res, node->element_name); + if (node->attribute_names) + { + for (i = 0; node->attribute_names[i] != NULL; i++) + { + g_string_append_printf (res, " %s=\"%s\"", + node->attribute_names[i], + node->attribute_values[i]); + } + } + if (node->first_child == NULL) + g_string_append (res, "/>"); + else + g_string_append (res, ">"); + } + + child = node->first_child; + while (child != NULL) + { + flatpak_xml_to_string (child, res); + child = child->next_sibling; + } + if (node->parent != NULL) + { + if (node->first_child != NULL) + g_string_append_printf (res, "", node->element_name); + } + + } + else if (node->text) + { + g_autofree char *escaped = g_markup_escape_text (node->text, -1); + g_string_append (res, escaped); + } +} + +FlatpakXml * +flatpak_xml_unlink (FlatpakXml *node, + FlatpakXml *prev_sibling) +{ + FlatpakXml *parent = node->parent; + + if (parent == NULL) + return node; + + if (parent->first_child == node) + parent->first_child = node->next_sibling; + + if (parent->last_child == node) + parent->last_child = prev_sibling; + + if (prev_sibling) + prev_sibling->next_sibling = node->next_sibling; + + node->parent = NULL; + node->next_sibling = NULL; + + return node; +} + +FlatpakXml * +flatpak_xml_find (FlatpakXml *node, + const char *type, + FlatpakXml **prev_child_out) +{ + FlatpakXml *child = NULL; + FlatpakXml *prev_child = NULL; + + child = node->first_child; + prev_child = NULL; + while (child != NULL) + { + FlatpakXml *next = child->next_sibling; + + if (g_strcmp0 (child->element_name, type) == 0) + { + if (prev_child_out) + *prev_child_out = prev_child; + return child; + } + + prev_child = child; + child = next; + } + + return NULL; +} + + +FlatpakXml * +flatpak_xml_parse (GInputStream *in, + gboolean compressed, + GCancellable *cancellable, + GError **error) +{ + g_autoptr(GInputStream) real_in = NULL; + g_autoptr(FlatpakXml) xml_root = NULL; + XmlData data = { 0 }; + char buffer[32 * 1024]; + gssize len; + g_autoptr(GMarkupParseContext) ctx = NULL; + + if (compressed) + { + g_autoptr(GZlibDecompressor) decompressor = NULL; + decompressor = g_zlib_decompressor_new (G_ZLIB_COMPRESSOR_FORMAT_GZIP); + real_in = g_converter_input_stream_new (in, G_CONVERTER (decompressor)); + } + else + { + real_in = g_object_ref (in); + } + + xml_root = flatpak_xml_new ("root"); + data.current = xml_root; + + ctx = g_markup_parse_context_new (&xml_parser, + G_MARKUP_PREFIX_ERROR_POSITION, + &data, + NULL); + + while ((len = g_input_stream_read (real_in, buffer, sizeof (buffer), + cancellable, error)) > 0) + { + if (!g_markup_parse_context_parse (ctx, buffer, len, error)) + return NULL; + } + + if (len < 0) + return NULL; + + return g_steal_pointer (&xml_root); +} diff --git a/src/builder-utils.h b/src/builder-utils.h index 36f5223d..9412b853 100644 --- a/src/builder-utils.h +++ b/src/builder-utils.h @@ -123,6 +123,39 @@ xml_autoptr_cleanup_generic_free (void *p) G_DEFINE_AUTOPTR_CLEANUP_FUNC (xmlDoc, xmlFreeDoc) +typedef struct FlatpakXml FlatpakXml; + +struct FlatpakXml +{ + gchar *element_name; /* NULL == text */ + char **attribute_names; + char **attribute_values; + char *text; + FlatpakXml *parent; + FlatpakXml *first_child; + FlatpakXml *last_child; + FlatpakXml *next_sibling; +}; + +FlatpakXml *flatpak_xml_new (const gchar *element_name); +FlatpakXml *flatpak_xml_new_text (const gchar *text); +void flatpak_xml_add (FlatpakXml *parent, + FlatpakXml *node); +void flatpak_xml_free (FlatpakXml *node); +FlatpakXml *flatpak_xml_parse (GInputStream *in, + gboolean compressed, + GCancellable *cancellable, + GError **error); +void flatpak_xml_to_string (FlatpakXml *node, + GString *res); +FlatpakXml *flatpak_xml_unlink (FlatpakXml *node, + FlatpakXml *prev_sibling); +FlatpakXml *flatpak_xml_find (FlatpakXml *node, + const char *type, + FlatpakXml **prev_child_out); + +G_DEFINE_AUTOPTR_CLEANUP_FUNC (FlatpakXml, flatpak_xml_free); + G_END_DECLS #endif /* __BUILDER_UTILS_H__ */