/* 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 "libpikabase/pikabase.h" #include "libpikaconfig/pikaconfig.h" #include "core-types.h" #include "pika-memsize.h" #include "pikaparasitelist.h" enum { ADD, REMOVE, LAST_SIGNAL }; static void pika_parasite_list_finalize (GObject *object); static gint64 pika_parasite_list_get_memsize (PikaObject *object, gint64 *gui_size); static void pika_parasite_list_config_iface_init (gpointer iface, gpointer iface_data); static gboolean pika_parasite_list_serialize (PikaConfig *list, PikaConfigWriter *writer, gpointer data); static gboolean pika_parasite_list_deserialize (PikaConfig *list, GScanner *scanner, gint nest_level, gpointer data); static void parasite_serialize (const gchar *key, PikaParasite *parasite, PikaConfigWriter *writer); static void parasite_copy (const gchar *key, PikaParasite *parasite, PikaParasiteList *list); static gboolean parasite_free (const gchar *key, PikaParasite *parasite, gpointer unused); static void parasite_count_if_persistent (const gchar *key, PikaParasite *parasite, gint *count); G_DEFINE_TYPE_WITH_CODE (PikaParasiteList, pika_parasite_list, PIKA_TYPE_OBJECT, G_IMPLEMENT_INTERFACE (PIKA_TYPE_CONFIG, pika_parasite_list_config_iface_init)) #define parent_class pika_parasite_list_parent_class static guint parasite_list_signals[LAST_SIGNAL] = { 0 }; static const gchar parasite_symbol[] = "parasite"; static void pika_parasite_list_class_init (PikaParasiteListClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); PikaObjectClass *pika_object_class = PIKA_OBJECT_CLASS (klass); parasite_list_signals[ADD] = g_signal_new ("add", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_FIRST, G_STRUCT_OFFSET (PikaParasiteListClass, add), NULL, NULL, NULL, 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 (PikaParasiteListClass, remove), NULL, NULL, NULL, G_TYPE_NONE, 1, G_TYPE_POINTER); object_class->finalize = pika_parasite_list_finalize; pika_object_class->get_memsize = pika_parasite_list_get_memsize; klass->add = NULL; klass->remove = NULL; } static void pika_parasite_list_config_iface_init (gpointer iface, gpointer iface_data) { PikaConfigInterface *config_iface = (PikaConfigInterface *) iface; config_iface->serialize = pika_parasite_list_serialize; config_iface->deserialize = pika_parasite_list_deserialize; } static void pika_parasite_list_init (PikaParasiteList *list) { list->table = NULL; } static void pika_parasite_list_finalize (GObject *object) { PikaParasiteList *list = PIKA_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 pika_parasite_list_get_memsize (PikaObject *object, gint64 *gui_size) { PikaParasiteList *list = PIKA_PARASITE_LIST (object); gint64 memsize = 0; memsize += pika_g_hash_table_get_memsize_foreach (list->table, (PikaMemsizeFunc) pika_parasite_get_memsize, gui_size); return memsize + PIKA_OBJECT_CLASS (parent_class)->get_memsize (object, gui_size); } static gboolean pika_parasite_list_serialize (PikaConfig *list, PikaConfigWriter *writer, gpointer data) { if (PIKA_PARASITE_LIST (list)->table) g_hash_table_foreach (PIKA_PARASITE_LIST (list)->table, (GHFunc) parasite_serialize, writer); return TRUE; } static gboolean pika_parasite_list_deserialize (PikaConfig *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; PikaParasite *parasite; token = G_TOKEN_STRING; if (g_scanner_peek_next_token (scanner) != token) break; if (! pika_scanner_parse_string (scanner, ¶site_name)) break; token = G_TOKEN_INT; if (g_scanner_peek_next_token (scanner) != token) goto cleanup; if (! pika_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 (! pika_scanner_parse_string (scanner, &str)) goto cleanup; parasite_data_size = strlen (str); parasite_data = (guint8 *) str; } else { /* new format -- properly encoded binary data */ if (! pika_scanner_parse_int (scanner, ¶site_data_size)) goto cleanup; token = G_TOKEN_STRING; if (g_scanner_peek_next_token (scanner) != token) goto cleanup; if (! pika_scanner_parse_data (scanner, parasite_data_size, ¶site_data)) goto cleanup; } parasite = pika_parasite_new (parasite_name, parasite_flags, parasite_data_size, parasite_data); pika_parasite_list_add (PIKA_PARASITE_LIST (list), parasite); /* adds a copy */ pika_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 pika_config_deserialize_return (scanner, token, nest_level); } PikaParasiteList * pika_parasite_list_new (void) { PikaParasiteList *list; list = g_object_new (PIKA_TYPE_PARASITE_LIST, NULL); return list; } PikaParasiteList * pika_parasite_list_copy (PikaParasiteList *list) { PikaParasiteList *newlist; g_return_val_if_fail (PIKA_IS_PARASITE_LIST (list), NULL); newlist = pika_parasite_list_new (); if (list->table) g_hash_table_foreach (list->table, (GHFunc) parasite_copy, newlist); return newlist; } void pika_parasite_list_add (PikaParasiteList *list, const PikaParasite *parasite) { PikaParasite *copy; g_return_if_fail (PIKA_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); pika_parasite_list_remove (list, parasite->name); copy = pika_parasite_copy (parasite); g_hash_table_insert (list->table, copy->name, copy); g_signal_emit (list, parasite_list_signals[ADD], 0, copy); } void pika_parasite_list_remove (PikaParasiteList *list, const gchar *name) { g_return_if_fail (PIKA_IS_PARASITE_LIST (list)); if (list->table) { PikaParasite *parasite; parasite = (PikaParasite *) pika_parasite_list_find (list, name); if (parasite) { g_hash_table_remove (list->table, name); g_signal_emit (list, parasite_list_signals[REMOVE], 0, parasite); pika_parasite_free (parasite); } } } gint pika_parasite_list_length (PikaParasiteList *list) { g_return_val_if_fail (PIKA_IS_PARASITE_LIST (list), 0); if (! list->table) return 0; return g_hash_table_size (list->table); } gint pika_parasite_list_persistent_length (PikaParasiteList *list) { gint len = 0; g_return_val_if_fail (PIKA_IS_PARASITE_LIST (list), 0); if (! list->table) return 0; pika_parasite_list_foreach (list, (GHFunc) parasite_count_if_persistent, &len); return len; } void pika_parasite_list_foreach (PikaParasiteList *list, GHFunc function, gpointer user_data) { g_return_if_fail (PIKA_IS_PARASITE_LIST (list)); if (! list->table) return; g_hash_table_foreach (list->table, function, user_data); } const PikaParasite * pika_parasite_list_find (PikaParasiteList *list, const gchar *name) { g_return_val_if_fail (PIKA_IS_PARASITE_LIST (list), NULL); if (list->table) return (PikaParasite *) g_hash_table_lookup (list->table, name); return NULL; } static void parasite_serialize (const gchar *key, PikaParasite *parasite, PikaConfigWriter *writer) { const guint8 *parasite_contents; guint32 parasite_size; if (! pika_parasite_is_persistent (parasite)) return; pika_config_writer_open (writer, parasite_symbol); parasite_contents = pika_parasite_get_data (parasite, ¶site_size); pika_config_writer_printf (writer, "\"%s\" %lu %lu", pika_parasite_get_name (parasite), pika_parasite_get_flags (parasite), (long unsigned int) parasite_size); pika_config_writer_data (writer, parasite_size, parasite_contents); pika_config_writer_close (writer); pika_config_writer_linefeed (writer); } static void parasite_copy (const gchar *key, PikaParasite *parasite, PikaParasiteList *list) { pika_parasite_list_add (list, parasite); } static gboolean parasite_free (const gchar *key, PikaParasite *parasite, gpointer unused) { pika_parasite_free (parasite); return TRUE; } static void parasite_count_if_persistent (const gchar *key, PikaParasite *parasite, gint *count) { if (pika_parasite_is_persistent (parasite)) *count = *count + 1; }