/* parasitelist.c: Copyright 1998 Jay Cox * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "config.h" #include #include #include #include "libgimpbase/gimpbase.h" #include "libgimpconfig/gimpconfig.h" #include "core-types.h" #include "gimp-memsize.h" #include "gimpmarshal.h" #include "gimpparasitelist.h" enum { ADD, REMOVE, LAST_SIGNAL }; static void gimp_parasite_list_finalize (GObject *object); static gint64 gimp_parasite_list_get_memsize (GimpObject *object, gint64 *gui_size); static void gimp_parasite_list_config_iface_init (gpointer iface, gpointer iface_data); static gboolean gimp_parasite_list_serialize (GimpConfig *list, GimpConfigWriter *writer, gpointer data); static gboolean gimp_parasite_list_deserialize (GimpConfig *list, GScanner *scanner, gint nest_level, gpointer data); static void parasite_serialize (const gchar *key, GimpParasite *parasite, GimpConfigWriter *writer); static void parasite_copy (const gchar *key, GimpParasite *parasite, GimpParasiteList *list); static gboolean parasite_free (const gchar *key, GimpParasite *parasite, gpointer unused); static void parasite_count_if_persistent (const gchar *key, GimpParasite *parasite, gint *count); G_DEFINE_TYPE_WITH_CODE (GimpParasiteList, gimp_parasite_list, GIMP_TYPE_OBJECT, G_IMPLEMENT_INTERFACE (GIMP_TYPE_CONFIG, gimp_parasite_list_config_iface_init)) #define parent_class gimp_parasite_list_parent_class static guint parasite_list_signals[LAST_SIGNAL] = { 0 }; static const gchar parasite_symbol[] = "parasite"; static void gimp_parasite_list_class_init (GimpParasiteListClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); GimpObjectClass *gimp_object_class = GIMP_OBJECT_CLASS (klass); parasite_list_signals[ADD] = g_signal_new ("add", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_FIRST, G_STRUCT_OFFSET (GimpParasiteListClass, add), NULL, NULL, gimp_marshal_VOID__POINTER, G_TYPE_NONE, 1, G_TYPE_POINTER); parasite_list_signals[REMOVE] = g_signal_new ("remove", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_FIRST, G_STRUCT_OFFSET (GimpParasiteListClass, remove), NULL, NULL, gimp_marshal_VOID__POINTER, G_TYPE_NONE, 1, G_TYPE_POINTER); object_class->finalize = gimp_parasite_list_finalize; gimp_object_class->get_memsize = gimp_parasite_list_get_memsize; klass->add = NULL; klass->remove = NULL; } static void gimp_parasite_list_config_iface_init (gpointer iface, gpointer iface_data) { GimpConfigInterface *config_iface = (GimpConfigInterface *) iface; config_iface->serialize = gimp_parasite_list_serialize; config_iface->deserialize = gimp_parasite_list_deserialize; } static void gimp_parasite_list_init (GimpParasiteList *list) { list->table = NULL; } static void gimp_parasite_list_finalize (GObject *object) { GimpParasiteList *list = GIMP_PARASITE_LIST (object); if (list->table) { g_hash_table_foreach_remove (list->table, (GHRFunc) parasite_free, NULL); g_hash_table_destroy (list->table); list->table = NULL; } G_OBJECT_CLASS (parent_class)->finalize (object); } static gint64 gimp_parasite_list_get_memsize (GimpObject *object, gint64 *gui_size) { GimpParasiteList *list = GIMP_PARASITE_LIST (object); gint64 memsize = 0; memsize += gimp_g_hash_table_get_memsize_foreach (list->table, (GimpMemsizeFunc) gimp_parasite_get_memsize, gui_size); return memsize + GIMP_OBJECT_CLASS (parent_class)->get_memsize (object, gui_size); } static gboolean gimp_parasite_list_serialize (GimpConfig *list, GimpConfigWriter *writer, gpointer data) { if (GIMP_PARASITE_LIST (list)->table) g_hash_table_foreach (GIMP_PARASITE_LIST (list)->table, (GHFunc) parasite_serialize, writer); return TRUE; } static gboolean gimp_parasite_list_deserialize (GimpConfig *list, GScanner *scanner, gint nest_level, gpointer data) { GTokenType token; g_scanner_scope_add_symbol (scanner, 0, parasite_symbol, (gpointer) parasite_symbol); token = G_TOKEN_LEFT_PAREN; while (g_scanner_peek_next_token (scanner) == token) { token = g_scanner_get_next_token (scanner); switch (token) { case G_TOKEN_LEFT_PAREN: token = G_TOKEN_SYMBOL; break; case G_TOKEN_SYMBOL: if (scanner->value.v_symbol == parasite_symbol) { gchar *parasite_name = NULL; gint parasite_flags = 0; guint8 *parasite_data = NULL; gint parasite_data_size = 0; GimpParasite *parasite; token = G_TOKEN_STRING; if (g_scanner_peek_next_token (scanner) != token) break; if (! gimp_scanner_parse_string (scanner, ¶site_name)) break; token = G_TOKEN_INT; if (g_scanner_peek_next_token (scanner) != token) goto cleanup; if (! gimp_scanner_parse_int (scanner, ¶site_flags)) goto cleanup; token = G_TOKEN_INT; if (g_scanner_peek_next_token (scanner) != token) { /* old format -- plain string */ gchar *str; if (g_scanner_peek_next_token (scanner) != G_TOKEN_STRING) goto cleanup; if (! gimp_scanner_parse_string (scanner, &str)) goto cleanup; parasite_data_size = strlen (str); parasite_data = (guint8 *) str; } else { /* new format -- properly encoded binary data */ if (! gimp_scanner_parse_int (scanner, ¶site_data_size)) goto cleanup; token = G_TOKEN_STRING; if (g_scanner_peek_next_token (scanner) != token) goto cleanup; if (! gimp_scanner_parse_data (scanner, parasite_data_size, ¶site_data)) goto cleanup; } parasite = gimp_parasite_new (parasite_name, parasite_flags, parasite_data_size, parasite_data); gimp_parasite_list_add (GIMP_PARASITE_LIST (list), parasite); /* adds a copy */ gimp_parasite_free (parasite); token = G_TOKEN_RIGHT_PAREN; g_free (parasite_data); cleanup: g_free (parasite_name); } break; case G_TOKEN_RIGHT_PAREN: token = G_TOKEN_LEFT_PAREN; break; default: /* do nothing */ break; } } return gimp_config_deserialize_return (scanner, token, nest_level); } GimpParasiteList * gimp_parasite_list_new (void) { GimpParasiteList *list; list = g_object_new (GIMP_TYPE_PARASITE_LIST, NULL); return list; } GimpParasiteList * gimp_parasite_list_copy (GimpParasiteList *list) { GimpParasiteList *newlist; g_return_val_if_fail (GIMP_IS_PARASITE_LIST (list), NULL); newlist = gimp_parasite_list_new (); if (list->table) g_hash_table_foreach (list->table, (GHFunc) parasite_copy, newlist); return newlist; } void gimp_parasite_list_add (GimpParasiteList *list, const GimpParasite *parasite) { GimpParasite *copy; g_return_if_fail (GIMP_IS_PARASITE_LIST (list)); g_return_if_fail (parasite != NULL); g_return_if_fail (parasite->name != NULL); if (list->table == NULL) list->table = g_hash_table_new (g_str_hash, g_str_equal); gimp_parasite_list_remove (list, parasite->name); copy = gimp_parasite_copy (parasite); g_hash_table_insert (list->table, copy->name, copy); g_signal_emit (list, parasite_list_signals[ADD], 0, copy); } void gimp_parasite_list_remove (GimpParasiteList *list, const gchar *name) { g_return_if_fail (GIMP_IS_PARASITE_LIST (list)); if (list->table) { GimpParasite *parasite; parasite = (GimpParasite *) gimp_parasite_list_find (list, name); if (parasite) { g_hash_table_remove (list->table, name); g_signal_emit (list, parasite_list_signals[REMOVE], 0, parasite); gimp_parasite_free (parasite); } } } gint gimp_parasite_list_length (GimpParasiteList *list) { g_return_val_if_fail (GIMP_IS_PARASITE_LIST (list), 0); if (! list->table) return 0; return g_hash_table_size (list->table); } gint gimp_parasite_list_persistent_length (GimpParasiteList *list) { gint len = 0; g_return_val_if_fail (GIMP_IS_PARASITE_LIST (list), 0); if (! list->table) return 0; gimp_parasite_list_foreach (list, (GHFunc) parasite_count_if_persistent, &len); return len; } void gimp_parasite_list_foreach (GimpParasiteList *list, GHFunc function, gpointer user_data) { g_return_if_fail (GIMP_IS_PARASITE_LIST (list)); if (! list->table) return; g_hash_table_foreach (list->table, function, user_data); } const GimpParasite * gimp_parasite_list_find (GimpParasiteList *list, const gchar *name) { g_return_val_if_fail (GIMP_IS_PARASITE_LIST (list), NULL); if (list->table) return (GimpParasite *) g_hash_table_lookup (list->table, name); return NULL; } static void parasite_serialize (const gchar *key, GimpParasite *parasite, GimpConfigWriter *writer) { if (! gimp_parasite_is_persistent (parasite)) return; gimp_config_writer_open (writer, parasite_symbol); gimp_config_writer_printf (writer, "\"%s\" %lu %lu", gimp_parasite_name (parasite), gimp_parasite_flags (parasite), gimp_parasite_data_size (parasite)); gimp_config_writer_data (writer, gimp_parasite_data_size (parasite), gimp_parasite_data (parasite)); gimp_config_writer_close (writer); gimp_config_writer_linefeed (writer); } static void parasite_copy (const gchar *key, GimpParasite *parasite, GimpParasiteList *list) { gimp_parasite_list_add (list, parasite); } static gboolean parasite_free (const gchar *key, GimpParasite *parasite, gpointer unused) { gimp_parasite_free (parasite); return TRUE; } static void parasite_count_if_persistent (const gchar *key, GimpParasite *parasite, gint *count) { if (gimp_parasite_is_persistent (parasite)) *count = *count + 1; }