diff options
Diffstat (limited to 'src/glibext')
27 files changed, 2971 insertions, 262 deletions
diff --git a/src/glibext/Makefile.am b/src/glibext/Makefile.am index 81d13d2..b0a7c31 100644 --- a/src/glibext/Makefile.am +++ b/src/glibext/Makefile.am @@ -14,7 +14,6 @@ noinst_LTLIBRARIES = libglibext.la libglibextui.la # \ # proto.h \ # seq.h seq.c \ -# _signal.h signal.c \ # singleton.h singleton.c \ # linetoken.h linetoken.c \ # umemslice-int.h \ @@ -43,16 +42,25 @@ libglibext_la_SOURCES = \ hashable-int.h \ hashable.h hashable.c \ helpers.h \ + log-int.h \ + log.h log.c \ objhole-int.h \ objhole.h objhole.c \ portion-int.h \ portion.h portion.c \ secstorage-int.h \ secstorage.h secstorage.c \ + serialize-int.h \ + serialize.h serialize.c \ + sigredir.h sigredir.c \ singleton-int.h \ singleton.h singleton.c \ + storage-int.h \ + storage.h storage.c \ strbuilder-int.h \ strbuilder.h strbuilder.c \ + tpmem-int.h \ + tpmem.h tpmem.c \ work-int.h \ work.h work.c \ workgroup-int.h \ @@ -60,7 +68,7 @@ libglibext_la_SOURCES = \ workqueue-int.h \ workqueue.h workqueue.c -libglibext_la_CFLAGS = $(TOOLKIT_CFLAGS) +libglibext_la_CFLAGS = $(TOOLKIT_CFLAGS) $(LIBZIP_CFLAGS) RES_FILES = \ diff --git a/src/glibext/bufferline.c b/src/glibext/bufferline.c index 4862e9f..e3fb27b 100644 --- a/src/glibext/bufferline.c +++ b/src/glibext/bufferline.c @@ -24,14 +24,16 @@ #include "bufferline.h" +#include <assert.h> +#include <malloc.h> + + #include "bufferline-int.h" #if 0 -#include <assert.h> -#include <malloc.h> #include <string.h> @@ -273,158 +275,12 @@ bool g_buffer_line_create(GBufferLine *line, size_t col_count) } - - - - - - - -/****************************************************************************** -* * -* Paramètres : line = ligne à venir compléter. * -* column = colonne de la ligne visée par l'insertion. * -* tag = type de décorateur à utiliser. * -* text = texte à insérer dans l'existant. * -* length = taille du texte à traiter. * -* style = gestionnaire de paramètres de rendu à consulter. * -* creator = instance GLib quelconque à associer. * -* * -* Description : Ajoute du texte à formater dans une ligne donnée. * -* * -* Retour : - * -* * -* Remarques : - * -* * -******************************************************************************/ - -void g_buffer_line_append_text(GBufferLine *line, size_t column, TokenRenderingTag tag, const char *text, size_t length, const GTokenStyle *style, GObject *creator) -{ - size_t index; /* Indice d'insertion */ - //content_origin *origin; /* Définition d'une origine */ - - assert(column < line->col_count); - assert(length > 0); - - index = append_text_to_line_column(&line->columns[column], tag, text, length, style); - - /* - if (creator != NULL) - { - line->origins = realloc(line->origins, ++line->ocount * sizeof(content_origin)); - - origin = &line->origins[line->ocount - 1]; - - origin->coord.column = column; - origin->coord.index = index; - - origin->creator = creator; - g_object_ref(G_OBJECT(creator)); - - } - */ - -} - - - - - - - - - - - -/****************************************************************************** -* * -* Paramètres : line = ligne de texte à manipuler. * -* cr = contexte graphique dédié à la procédure. * -* column = (première) colonne à traiter. * -* y = ordonnée du point d'impression. * -* style = style de rendu pour les bribes de texte. * -* * -* Description : Imprime la ligne de texte représentée. * -* * -* Retour : - * -* * -* Remarques : - * -* * -******************************************************************************/ - -void g_buffer_line_draw(const GBufferLine *line, cairo_t *cr, size_t column, int y, const GTokenStyle *style) -{ -#if 0 - GBufferLineClass *class; /* Stockage de briques de base */ - bool has_src_surface; /* Note une présence définie */ -#endif - size_t max_column; /* Borne de fin des colonnes */ - int x; /* Point de départ d'impression*/ - size_t i; /* Boucle de parcours */ - - /* - if (line->flags != BLF_NONE) - { - class = G_BUFFER_LINE_GET_CLASS(line); - - if (line->flags & BLF_ENTRYPOINT) - { - cairo_set_source_surface(cairo, class->entrypoint_img, 5, y); - has_src_surface = true; - } - else if (line->flags & BLF_BOOKMARK) - { - cairo_set_source_surface(cairo, class->bookmark_img, 5, y); - has_src_surface = true; - } - else - has_src_surface = false; - - if (has_src_surface) - cairo_paint(cairo); - - } - */ - - - /* Détermination de l'éventail des colonnes à traiter */ - - if (column == line->merge_start) - max_column = line->col_count; - - else if (column > line->merge_start) - max_column = 0; - - else - max_column = column + 1; - - /* Dessin du contenu de ces colonnes */ - - x = 0; - - for (i = column; i < max_column; i++) - draw_line_column(&line->columns[i], cr, &x, y, style); - -} - - - - - - - - - - -#if 0 - - /****************************************************************************** * * -* Paramètres : line = ligne à venir compléter. * -* col = indice de la colonne à constituer. * -* size = taille souhaitée de l'impression des positions. * -* addr = localisation physique à venir représenter. * +* Paramètres : line = ligne à venir compléter. * +* column = indice de la colonne visée par l'insertion. * +* size = taille souhaitée de l'impression des positions. * +* addr = localisation physique à venir représenter. * * * * Description : Construit le tronc commun d'une ligne autour de sa position. * * * @@ -434,7 +290,7 @@ void g_buffer_line_draw(const GBufferLine *line, cairo_t *cr, size_t column, int * * ******************************************************************************/ -void g_buffer_line_fill_phys(GBufferLine *line, size_t col, MemoryDataSize size, const vmpa2t *addr) +void g_buffer_line_fill_physical(GBufferLine *line, size_t column, MemoryDataSize size, const vmpa2t *addr) { VMPA_BUFFER(position); /* Emplacement au format texte */ size_t len; /* Taille de l'élément inséré */ @@ -448,20 +304,22 @@ void g_buffer_line_fill_phys(GBufferLine *line, size_t col, MemoryDataSize size, if (i == len) i = len - 1; + assert(column < line->col_count); + if (i > 0) - g_buffer_line_append_text(line, col, position, i, RTT_PHYS_ADDR_PAD, NULL); + g_buffer_line_append_text(line, column, TRT_PHYS_ADDR_PAD, position, i, NULL, NULL); - g_buffer_line_append_text(line, col, &position[i], len - i, RTT_PHYS_ADDR, NULL); + g_buffer_line_append_text(line, column, TRT_PHYS_ADDR, &position[i], len - i, NULL, NULL); } /****************************************************************************** * * -* Paramètres : line = ligne à venir compléter. * -* col = indice de la colonne à constituer. * -* size = taille souhaitée de l'impression des positions. * -* addr = localisation virtuelle à venir représenter. * +* Paramètres : line = ligne à venir compléter. * +* column = indice de la colonne visée par l'insertion. * +* size = taille souhaitée de l'impression des positions. * +* addr = localisation virtuelle à venir représenter. * * * * Description : Construit le tronc commun d'une ligne autour de sa position. * * * @@ -471,7 +329,7 @@ void g_buffer_line_fill_phys(GBufferLine *line, size_t col, MemoryDataSize size, * * ******************************************************************************/ -void g_buffer_line_fill_virt(GBufferLine *line, size_t col, MemoryDataSize size, const vmpa2t *addr) +void g_buffer_line_fill_virtual(GBufferLine *line, size_t column, MemoryDataSize size, const vmpa2t *addr) { VMPA_BUFFER(position); /* Emplacement au format texte */ size_t len; /* Taille de l'élément inséré */ @@ -479,6 +337,8 @@ void g_buffer_line_fill_virt(GBufferLine *line, size_t col, MemoryDataSize size, vmpa2_virt_to_string(addr, size, position, &len); + assert(column < line->col_count); + if (has_virt_addr(addr)) { for (i = 2; i < len; i++) @@ -488,14 +348,14 @@ void g_buffer_line_fill_virt(GBufferLine *line, size_t col, MemoryDataSize size, i = len - 1; if (i > 0) - g_buffer_line_append_text(line, col, position, i, RTT_VIRT_ADDR_PAD, NULL); + g_buffer_line_append_text(line, column, TRT_VIRT_ADDR_PAD, position, i, NULL, NULL); - g_buffer_line_append_text(line, col, &position[i], len - i, RTT_VIRT_ADDR, NULL); + g_buffer_line_append_text(line, column, TRT_VIRT_ADDR, &position[i], len - i, NULL, NULL); } else - g_buffer_line_append_text(line, col, position, len, RTT_VIRT_ADDR_PAD, NULL); + g_buffer_line_append_text(line, column, TRT_VIRT_ADDR_PAD, position, len, NULL, NULL); } @@ -503,7 +363,7 @@ void g_buffer_line_fill_virt(GBufferLine *line, size_t col, MemoryDataSize size, /****************************************************************************** * * * Paramètres : line = ligne à venir compléter. * -* col = indice de la colonne à constituer. * +* column = indice de la colonne visée par l'insertion. * * content = contenu binaire global à venir lire. * * range = localisation des données à venir lire et présenter.* * max = taille maximale de la portion binaire en octets. * @@ -516,7 +376,7 @@ void g_buffer_line_fill_virt(GBufferLine *line, size_t col, MemoryDataSize size, * * ******************************************************************************/ -void g_buffer_line_fill_content(GBufferLine *line, size_t col, const GBinContent *content, const mrange_t *range, phys_t max) +void g_buffer_line_fill_content(GBufferLine *line, size_t column, const GBinContent *content, const mrange_t *range, phys_t max) { phys_t length; /* Taille de la couverture */ bool truncated; /* Indique si le code est coupé*/ @@ -548,7 +408,7 @@ void g_buffer_line_fill_content(GBufferLine *line, size_t col, const GBinContent if (required <= sizeof(static_buffer)) bin_code = static_buffer; else - bin_code = (char *)calloc(required, sizeof(char)); + bin_code = calloc(required, sizeof(char)); /* Code brut */ @@ -589,7 +449,7 @@ void g_buffer_line_fill_content(GBufferLine *line, size_t col, const GBinContent /* Conclusion */ - g_buffer_line_append_text(line, col, bin_code, iter - bin_code, RTT_RAW_CODE, NULL); + g_buffer_line_append_text(line, column, TRT_RAW_CODE, bin_code, iter - bin_code, NULL, NULL); if (bin_code != static_buffer) free(bin_code); @@ -599,6 +459,146 @@ void g_buffer_line_fill_content(GBufferLine *line, size_t col, const GBinContent /****************************************************************************** * * +* Paramètres : line = ligne à venir compléter. * +* column = colonne de la ligne visée par l'insertion. * +* tag = type de décorateur à utiliser. * +* text = texte à insérer dans l'existant. * +* length = taille du texte à traiter. * +* style = gestionnaire de paramètres de rendu à consulter. * +* creator = instance GLib quelconque à associer. * +* * +* Description : Ajoute du texte à formater dans une ligne donnée. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +void g_buffer_line_append_text(GBufferLine *line, size_t column, TokenRenderingTag tag, const char *text, size_t length, const GTokenStyle *style, GObject *creator) +{ + size_t index; /* Indice d'insertion */ + //content_origin *origin; /* Définition d'une origine */ + + assert(column < line->col_count); + assert(length > 0); + + index = append_text_to_line_column(&line->columns[column], tag, text, length, style); + + /* + if (creator != NULL) + { + line->origins = realloc(line->origins, ++line->ocount * sizeof(content_origin)); + + origin = &line->origins[line->ocount - 1]; + + origin->coord.column = column; + origin->coord.index = index; + + origin->creator = creator; + g_object_ref(G_OBJECT(creator)); + + } + */ + +} + + + + + + + + + + + +/****************************************************************************** +* * +* Paramètres : line = ligne de texte à manipuler. * +* cr = contexte graphique dédié à la procédure. * +* column = (première) colonne à traiter. * +* y = ordonnée du point d'impression. * +* style = style de rendu pour les bribes de texte. * +* * +* Description : Imprime la ligne de texte représentée. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +void g_buffer_line_draw(const GBufferLine *line, cairo_t *cr, size_t column, int y, const GTokenStyle *style) +{ +#if 0 + GBufferLineClass *class; /* Stockage de briques de base */ + bool has_src_surface; /* Note une présence définie */ +#endif + size_t max_column; /* Borne de fin des colonnes */ + int x; /* Point de départ d'impression*/ + size_t i; /* Boucle de parcours */ + + /* + if (line->flags != BLF_NONE) + { + class = G_BUFFER_LINE_GET_CLASS(line); + + if (line->flags & BLF_ENTRYPOINT) + { + cairo_set_source_surface(cairo, class->entrypoint_img, 5, y); + has_src_surface = true; + } + else if (line->flags & BLF_BOOKMARK) + { + cairo_set_source_surface(cairo, class->bookmark_img, 5, y); + has_src_surface = true; + } + else + has_src_surface = false; + + if (has_src_surface) + cairo_paint(cairo); + + } + */ + + + /* Détermination de l'éventail des colonnes à traiter */ + + if (column == line->merge_start) + max_column = line->col_count; + + else if (column > line->merge_start) + max_column = 0; + + else + max_column = column + 1; + + /* Dessin du contenu de ces colonnes */ + + x = 0; + + for (i = column; i < max_column; i++) + draw_line_column(&line->columns[i], cr, &x, y, style); + +} + + + + + + + + + + +#if 0 + + + +/****************************************************************************** +* * * Paramètres : line = ligne à venir consulter. * * column = indice de la colonne visée par les recherches. * * * diff --git a/src/glibext/bufferline.h b/src/glibext/bufferline.h index d6a2e2d..e95ee2b 100644 --- a/src/glibext/bufferline.h +++ b/src/glibext/bufferline.h @@ -30,6 +30,8 @@ #include "helpers.h" #include "tokenstyle.h" +#include "../arch/vmpa.h" +#include "../analysis/content.h" @@ -45,8 +47,6 @@ #ifdef INCLUDE_GTK_SUPPORT # include "widthtracker.h" #endif -#include "../analysis/content.h" -#include "../arch/vmpa.h" @@ -75,6 +75,9 @@ typedef struct _GBufferLineClass GBufferLineClass; + + + #define G_TYPE_BUFFER_LINE (g_buffer_line_get_type()) DECLARE_GTYPE(GBufferLine, g_buffer_line, G, BUFFER_LINE); @@ -98,7 +101,14 @@ typedef enum _BufferLineFlags /* Crée une nouvelle représentation de fragments de texte. */ GBufferLine *g_buffer_line_new(size_t); +/* Construit le tronc commun d'une ligne autour de sa position. */ +void g_buffer_line_fill_physical(GBufferLine *, size_t, MemoryDataSize, const vmpa2t *); + +/* Construit le tronc commun d'une ligne autour de sa position. */ +void g_buffer_line_fill_virtual(GBufferLine *, size_t, MemoryDataSize, const vmpa2t *); +/* Construit le tronc commun d'une ligne autour de son contenu. */ +void g_buffer_line_fill_content(GBufferLine *, size_t, const GBinContent *, const mrange_t *, phys_t); /* Ajoute du texte à formater dans une ligne donnée. */ void g_buffer_line_append_text(GBufferLine *, size_t, TokenRenderingTag, const char *, size_t, const GTokenStyle *, GObject *); diff --git a/src/glibext/comparable.c b/src/glibext/comparable.c index 95e7de7..40fd110 100644 --- a/src/glibext/comparable.c +++ b/src/glibext/comparable.c @@ -25,6 +25,7 @@ #include "comparable-int.h" +#include "../common/sort.h" @@ -72,11 +73,24 @@ static void g_comparable_object_default_init(GComparableObjectInterface *iface) int g_comparable_object_compare(const GComparableObject *object, const GComparableObject *other) { int result; /* Bilan à retourner */ + GType type_a; /* Type de l'object A */ + GType type_b; /* Type de l'object B */ GComparableObjectInterface *iface; /* Interface utilisée */ - iface = G_COMPARABLE_OBJECT_GET_IFACE(object); + type_a = G_OBJECT_TYPE(G_OBJECT(object)); + type_b = G_OBJECT_TYPE(G_OBJECT(other)); - result = iface->compare(object, other); + assert(sizeof(GType) <= sizeof(unsigned long)); + + result = sort_unsigned_long(type_a, type_b); + + if (result == 0) + { + iface = G_COMPARABLE_OBJECT_GET_IFACE(object); + + result = iface->compare(object, other); + + } return result; diff --git a/src/glibext/helpers.h b/src/glibext/helpers.h index cfcc85b..6176245 100644 --- a/src/glibext/helpers.h +++ b/src/glibext/helpers.h @@ -29,6 +29,9 @@ #include <glib-object.h> +#include "../common/compiler.h" + + /** * Les définitions issues de <glib-2.80>/gobject/gtype.h fournissent des macros @@ -118,6 +121,31 @@ } +/** + * Définition sous condition d'une inclusion d'interface. Cette inclusion se réalise + * lorsque la fonction d'initialisation renseignée est définie. + * + * Cette version étendue de la macro G_IMPLEMENT_INTERFACE d'origine est principalement + * pour les raffinements d'objets en forme graphique. + */ + +#define G_IMPLEMENT_INTERFACE_IF_SYM(iface_tp_getter, iface_init) \ + do \ + { \ + extern GType iface_tp_getter(void) __weak; \ + extern void iface_init(GTypeInterface *, gpointer) __weak; \ + if (&iface_tp_getter != NULL && &iface_init != NULL) \ + { \ + GType iface_type = iface_tp_getter(); \ + const GInterfaceInfo implementation_info = { \ + (GInterfaceInitFunc)(void (*)(void))iface_init, NULL, NULL \ + }; \ + g_type_add_interface_static(g_define_type_id, iface_type, &implementation_info);\ + } \ + } \ + while (0); + + /** * Les principales fonctions incrémentant ou réduisant le nombre de références diff --git a/src/glibext/log-int.h b/src/glibext/log-int.h new file mode 100644 index 0000000..3b3208a --- /dev/null +++ b/src/glibext/log-int.h @@ -0,0 +1,58 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * log-int.h - prototypes internes pour la conservation à destination graphique des éléments de journalisation + * + * Copyright (C) 2025 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide 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. + * + * Chrysalide 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 Foobar. If not, see <http://www.gnu.org/licenses/>. + */ + + +#ifndef _GLIBEXT_LOG_INT_H +#define _GLIBEXT_LOG_INT_H + + +#include <stdbool.h> + + +#include "log.h" + + + +/* Définition d'une conservation d'objets construits (instance) */ +struct _GLogEntry +{ + GObject parent; /* A laisser en premier */ + + LogMessageType type; /* Type de message porté */ + char *msg; /* Contenu du message diffusé */ + +}; + +/* Définition d'une conservation d'objets construits (classe) */ +struct _GLogEntryClass +{ + GObjectClass parent; /* A laisser en premier */ + +}; + + +/* Met en place une conservation pour élément de journalisation. */ +bool g_log_entry_create(GLogEntry *, LogMessageType, const char *); + + + +#endif /* _GLIBEXT_LOG_INT_H */ diff --git a/src/glibext/log.c b/src/glibext/log.c new file mode 100644 index 0000000..039172c --- /dev/null +++ b/src/glibext/log.c @@ -0,0 +1,306 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * log.c - conservation hors mémoire d'objets choisis + * + * Copyright (C) 2020-2025 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide 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. + * + * Chrysalide 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 Foobar. If not, see <http://www.gnu.org/licenses/>. + */ + + +#include "log.h" + + +#include <malloc.h> +#include <string.h> + + +#include "log-int.h" + + + +/* ---------------------------- ENTREE DE JOURNALISATION ---------------------------- */ + + +/* Liste des propriétés */ + +typedef enum _LogEntryProperty { + + PROP_0, /* Réservé */ + + PROP_ICON_NAME, /* Nom d'image de représentat° */ + PROP_MESSAGE, /* Contenu du message diffusé */ + + N_PROPERTIES + +} LogEntryProperty; + +static GParamSpec *_log_entry_properties[N_PROPERTIES] = { NULL, }; + + +/* Initialise la classe des conservations d'objets en place. */ +static void g_log_entry_class_init(GLogEntryClass *); + +/* Initialise une instance de conservation d'objets en place. */ +static void g_log_entry_init(GLogEntry *); + +/* Supprime toutes les références externes. */ +static void g_log_entry_dispose(GObject *); + +/* Procède à la libération totale de la mémoire. */ +static void g_log_entry_finalize(GObject *); + + + +/* --------------------- IMPLEMENTATION DES FONCTIONS DE CLASSE --------------------- */ + + +/* Fournit la valeur d'une propriété d'instance GObject. */ +static void gtk_log_entry_get_property(GObject *, guint, GValue *, GParamSpec *); + + + +/* ---------------------------------------------------------------------------------- */ +/* ENTREE DE JOURNALISATION */ +/* ---------------------------------------------------------------------------------- */ + + +/* Indique le type défini pour une conservation d'objets construits. */ +G_DEFINE_TYPE(GLogEntry, g_log_entry, G_TYPE_OBJECT); + + +/****************************************************************************** +* * +* Paramètres : klass = classe à initialiser. * +* * +* Description : Initialise la classe des conservations d'objets en place. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_log_entry_class_init(GLogEntryClass *klass) +{ + GObjectClass *object; /* Autre version de la classe */ + + object = G_OBJECT_CLASS(klass); + + object->dispose = g_log_entry_dispose; + object->finalize = g_log_entry_finalize; + object->get_property = gtk_log_entry_get_property; + + _log_entry_properties[PROP_ICON_NAME] = + g_param_spec_string("icon-name", NULL, NULL, + NULL, + G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); + + _log_entry_properties[PROP_MESSAGE] = + g_param_spec_string("message", NULL, NULL, + NULL, + G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); + + g_object_class_install_properties(object, N_PROPERTIES, _log_entry_properties); + +} + + +/****************************************************************************** +* * +* Paramètres : entry = instance à initialiser. * +* * +* Description : Initialise une instance de conservation d'objets en place. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_log_entry_init(GLogEntry *entry) +{ + entry->type = LMT_COUNT; + entry->msg = NULL; + +} + + +/****************************************************************************** +* * +* Paramètres : object = instance d'objet GLib à traiter. * +* * +* Description : Supprime toutes les références externes. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_log_entry_dispose(GObject *object) +{ + G_OBJECT_CLASS(g_log_entry_parent_class)->dispose(object); + +} + + +/****************************************************************************** +* * +* Paramètres : object = instance d'objet GLib à traiter. * +* * +* Description : Procède à la libération totale de la mémoire. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_log_entry_finalize(GObject *object) +{ + GLogEntry *entry; /* Version spécialisée */ + + entry = G_LOG_ENTRY(object); + + if (entry->msg != NULL) + free(entry->msg); + + G_OBJECT_CLASS(g_log_entry_parent_class)->finalize(object); + +} + + +/****************************************************************************** +* * +* Paramètres : type = espèce du message à représenter. * +* msg = message à faire apparaître à l'écran. * +* * +* Description : Crée une conservation pour un élément de journalisation. * +* * +* Retour : Conservation mise en place. * +* * +* Remarques : - * +* * +******************************************************************************/ + +GLogEntry *g_log_entry_new(LogMessageType type, const char *msg) +{ + GLogEntry *result; /* Structure à retourner */ + + result = g_object_new(G_TYPE_LOG_ENTRY, NULL); + + if (!g_log_entry_create(result, type, msg)) + g_clear_object(&result); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : entry = instance de conservation à initialiser pleinement. * +* type = espèce du message à représenter. * +* msg = message à faire apparaître à l'écran. * +* * +* Description : Met en place une conservation pour élément de journalisation.* +* * +* Retour : Conservation mise en place. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool g_log_entry_create(GLogEntry *entry, LogMessageType type, const char *msg) +{ + bool result; /* Bilan à retourner */ + + result = true; + + entry->type = type; + entry->msg = strdup(msg); + + return result; + +} + + + +/* ---------------------------------------------------------------------------------- */ +/* IMPLEMENTATION DES FONCTIONS DE CLASSE */ +/* ---------------------------------------------------------------------------------- */ + + +/****************************************************************************** +* * +* Paramètres : object = instance d'objet GLib à mamnipuler. * +* prop_id = identifiant de la propriété visée. * +* value = valeur à transmettre. [OUT] * +* pspec = définition de la propriété. * +* * +* Description : Fournit la valeur d'une propriété d'instance GObject. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void gtk_log_entry_get_property(GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) +{ + GLogEntry *entry; /* Version spécialisée */ + + entry = G_LOG_ENTRY(object); + + switch (prop_id) + { + case PROP_ICON_NAME: + switch (entry->type) + { + case LMT_INFO: + g_value_set_string(value, "dialog-information-symbolic"); + break; + + case LMT_PROCESS: + g_value_set_string(value, "system-run-symbolic"); + break; + + case LMT_WARNING: + case LMT_BAD_BINARY: + g_value_set_string(value, "dialog-warning-symbolic"); + break; + + case LMT_ERROR: + case LMT_EXT_ERROR: + g_value_set_string(value, "computer-fail-symbolic"); + break; + + + case LMT_COUNT: + g_value_set_string(value, "dialog-question-symbolic"); + break; + + } + break; + + case PROP_MESSAGE: + g_value_set_string(value, entry->msg); + break; + + } + +} diff --git a/src/glibext/log.h b/src/glibext/log.h new file mode 100644 index 0000000..472773c --- /dev/null +++ b/src/glibext/log.h @@ -0,0 +1,43 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * log.h - prototypes pour la conservation à destination graphique des éléments de journalisation + * + * Copyright (C) 2025 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide 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. + * + * Chrysalide 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 Foobar. If not, see <http://www.gnu.org/licenses/>. + */ + + +#ifndef _GLIBEXT_LOG_H +#define _GLIBEXT_LOG_H + + +#include "helpers.h" +#include "../core/logs.h" + + + +#define G_TYPE_LOG_ENTRY (g_log_entry_get_type()) + +DECLARE_GTYPE(GLogEntry, g_log_entry, G, LOG_ENTRY); + + +/* Crée une conservation pour un élément de journalisation. */ +GLogEntry *g_log_entry_new(LogMessageType, const char *); + + + +#endif /* _GLIBEXT_LOG_H */ diff --git a/src/glibext/objhole-int.h b/src/glibext/objhole-int.h index b4abf6f..dbfb412 100644 --- a/src/glibext/objhole-int.h +++ b/src/glibext/objhole-int.h @@ -105,6 +105,9 @@ #endif +#define GOBJECT_LOCK_BIT 3 + + /* Nouvelle version dense des objets (instance) */ typedef struct _GThickObject { @@ -142,23 +145,23 @@ struct _GThickObjectClass /* GLib 2.83.0 - cfa36f5e9 */ #define GOBJECT_RESERVED_EXTRA_BITS 5 -#define GET_GOBJECT_EXTRA(obj, tp) \ - ({ \ - BUILD_BUG_ON(sizeof(tp) > sizeof(guint)); \ - tp *___result; \ - guint __val; \ - __val = g_thick_object_get_extra(obj); \ - ___result = (tp *)(guint []){ __val }; \ - ___result; \ +#define GET_GOBJECT_EXTRA(obj, tp) \ + ({ \ + BUILD_BUG_ON(sizeof(tp) > sizeof(guint)); \ + tp ___result; \ + guint __val; \ + __val = g_thick_object_get_extra(G_THICK_OBJECT(obj)); \ + ___result = *(tp *)(guint []){ __val }; \ + ___result; \ }) -#define SET_GOBJECT_EXTRA(obj, tp, data) \ - ({ \ - BUILD_BUG_ON(sizeof(tp) > sizeof(guint)); \ - BUILD_BUG_ON(sizeof(data) > sizeof(guint *)); \ - guint __val; \ - __val = *(guint *)data; \ - g_thick_object_set_extra(obj, __val); \ +#define SET_GOBJECT_EXTRA(obj, tp, data) \ + ({ \ + BUILD_BUG_ON(sizeof(tp) > sizeof(guint)); \ + BUILD_BUG_ON(sizeof(data) > sizeof(guint *)); \ + guint __val; \ + __val = *(guint *)data; \ + g_thick_object_set_extra(G_THICK_OBJECT(obj), __val); \ }) diff --git a/src/glibext/objhole.c b/src/glibext/objhole.c index 20bb2a8..fd6fbc9 100644 --- a/src/glibext/objhole.c +++ b/src/glibext/objhole.c @@ -38,10 +38,10 @@ static void g_thick_object_class_init(GThickObjectClass *); static void g_thick_object_init(GThickObject *); /* Supprime toutes les références externes. */ -static void g_thick_object_dispose(GThickObject *); +static void g_thick_object_dispose(GObject *); /* Procède à la libération totale de la mémoire. */ -static void g_thick_object_finalize(GThickObject *); +static void g_thick_object_finalize(GObject *); @@ -66,8 +66,8 @@ static void g_thick_object_class_init(GThickObjectClass *klass) object = G_OBJECT_CLASS(klass); - object->dispose = (GObjectFinalizeFunc/* ! */)g_thick_object_dispose; - object->finalize = (GObjectFinalizeFunc)g_thick_object_finalize; + object->dispose = g_thick_object_dispose; + object->finalize = g_thick_object_finalize; } @@ -93,7 +93,7 @@ static void g_thick_object_init(GThickObject *obj) /****************************************************************************** * * -* Paramètres : obj = instance d'objet GLib à traiter. * +* Paramètres : object = instance d'objet GLib à traiter. * * * * Description : Supprime toutes les références externes. * * * @@ -103,16 +103,16 @@ static void g_thick_object_init(GThickObject *obj) * * ******************************************************************************/ -static void g_thick_object_dispose(GThickObject *obj) +static void g_thick_object_dispose(GObject *object) { - G_OBJECT_CLASS(g_thick_object_parent_class)->dispose(G_OBJECT(obj)); + G_OBJECT_CLASS(g_thick_object_parent_class)->dispose(object); } /****************************************************************************** * * -* Paramètres : obj = instance d'objet GLib à traiter. * +* Paramètres : object = instance d'objet GLib à traiter. * * * * Description : Procède à la libération totale de la mémoire. * * * @@ -122,15 +122,80 @@ static void g_thick_object_dispose(GThickObject *obj) * * ******************************************************************************/ -static void g_thick_object_finalize(GThickObject *obj) +static void g_thick_object_finalize(GObject *object) { - G_OBJECT_CLASS(g_thick_object_parent_class)->finalize(G_OBJECT(obj)); + G_OBJECT_CLASS(g_thick_object_parent_class)->finalize(object); } /****************************************************************************** * * +* Paramètres : obj = instance d'objet GLib à manipuler. * +* * +* Description : Pose un verrou à l'aide du bit dédié de GObject. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +void g_thick_object_lock(GThickObject *obj) +{ + g_bit_lock((gint *)&obj->extra, GOBJECT_LOCK_BIT); + +} + + +/****************************************************************************** +* * +* Paramètres : obj = instance d'objet GLib à manipuler. * +* * +* Description : Retire un verrou via le bit dédié de GObject. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +void g_thick_object_unlock(GThickObject *obj) +{ + g_bit_unlock((gint *)&obj->extra, GOBJECT_LOCK_BIT); + +} + + +/****************************************************************************** +* * +* Paramètres : obj = instance d'objet GLib à manipuler. * +* * +* Description : Vérifie qu'un verrou est appliqué à l'aide du bit de GObject.* +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ +#ifndef NDEBUG +bool g_thick_object_check_lock(GThickObject *obj) +{ + bool result; /* Bilan à retourner */ + gboolean status; /* Bilan d'une tentative */ + + status = g_bit_trylock((gint *)&obj->extra, GOBJECT_LOCK_BIT); + + result = (status == FALSE); + + return result; + +} +#endif + + +/****************************************************************************** +* * * Paramètres : obj = instance d'objet GLib à consulter. * * * * Description : Fournit la valeur courante de la zone de stockage d'un objet.* diff --git a/src/glibext/objhole.h b/src/glibext/objhole.h index c1e8cf1..461c37a 100644 --- a/src/glibext/objhole.h +++ b/src/glibext/objhole.h @@ -25,6 +25,11 @@ #define _GLIBEXT_OBJHOLE_H +#ifndef NDEBUG +# include <stdbool.h> +#endif + + #include "../glibext/helpers.h" @@ -34,6 +39,17 @@ DECLARE_GTYPE(GThickObject, g_thick_object, G, THICK_OBJECT); +/* Pose un verrou à l'aide du bit dédié de GObject. */ +void g_thick_object_lock(GThickObject *); + +/* Retire un verrou via le bit dédié de GObject. */ +void g_thick_object_unlock(GThickObject *); + +/* Vérifie qu'un verrou est appliqué à l'aide du bit de GObject. */ +#ifndef NDEBUG +bool g_thick_object_check_lock(GThickObject *obj); +#endif + /* Fournit la valeur courante de la zone de stockage d'un objet. */ guint g_thick_object_get_extra(const GThickObject *); diff --git a/src/glibext/options/Makefile.am b/src/glibext/options/Makefile.am index 448de7b..3f400c6 100644 --- a/src/glibext/options/Makefile.am +++ b/src/glibext/options/Makefile.am @@ -2,7 +2,8 @@ noinst_LTLIBRARIES = libglibextoptions.la -libglibextoptions_la_SOURCES = \ +libglibextoptions_la_SOURCES = \ + asm.h \ hex.h hex.c libglibextoptions_la_CFLAGS = $(TOOLKIT_CFLAGS) diff --git a/src/glibext/options/asm.h b/src/glibext/options/asm.h new file mode 100644 index 0000000..d7a2c86 --- /dev/null +++ b/src/glibext/options/asm.h @@ -0,0 +1,65 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * asm.h - prototypes pour les options de rendus de code désassemblé + * + * Copyright (C) 2025 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide 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. + * + * Chrysalide 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 Chrysalide. If not, see <http://www.gnu.org/licenses/>. + */ + + +#ifndef _GLIBEXT_OPTIONS_ASM_H +#define _GLIBEXT_OPTIONS_ASM_H + + +#include "../helpers.h" + + + +/* Liste des colonnes en options */ +typedef enum _DisassColumnOptions +{ + ACO_PHYSICAL, /* Position physique */ + ACO_VIRTUAL, /* Adresse virtuelle */ + ACO_BINARY, /* Contenu sous forme binaire */ + + ACO_COUNT + +} DisassColumnOptions; + + +#define ACO_ASSEMBLY_LABEL (ACO_COUNT + 0) /* Etiquette dans les données */ +#define ACO_ASSEMBLY_HEAD (ACO_COUNT + 1) /* Instruction pour assembleur */ +#define ACO_ASSEMBLY (ACO_COUNT + 2) /* Code pour assembleur */ +#define ACO_COMMENTS (ACO_COUNT + 3) /* Commentaires éventuels */ + + + + + + +#if 0 +#define G_TYPE_HEX_OPTIONS (g_hex_options_get_type()) + +DECLARE_GTYPE(GHexOptions, g_hex_options, G, HEX_OPTIONS); + + +/* Crée un groupe d'options pour le rendu d'hexadécimal. */ +GHexOptions *g_hex_options_new(void); +#endif + + +#endif /* _GLIBEXT_OPTIONS_HEX_H */ diff --git a/src/glibext/secstorage.c b/src/glibext/secstorage.c index b118aa6..161214c 100644 --- a/src/glibext/secstorage.c +++ b/src/glibext/secstorage.c @@ -160,7 +160,7 @@ static void g_secret_storage_init(GSecretStorage *storage) static void g_secret_storage_dispose(GObject *object) { - GSecretStorage *storage; /* Gestion de stockage sécurisé*/ + GSecretStorage *storage; /* Version spécialisée */ storage = G_SECRET_STORAGE(object); @@ -185,7 +185,7 @@ static void g_secret_storage_dispose(GObject *object) static void g_secret_storage_finalize(GObject *object) { - GSecretStorage *storage; /* Gestion de stockage sécurisé*/ + GSecretStorage *storage; /* Version spécialisée */ storage = G_SECRET_STORAGE(object); diff --git a/src/glibext/serialize-int.h b/src/glibext/serialize-int.h new file mode 100644 index 0000000..df9c597 --- /dev/null +++ b/src/glibext/serialize-int.h @@ -0,0 +1,54 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * serialize-int.h - définitions internes propres aux objets entreposables dans un cache + * + * Copyright (C) 2020-2025 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide 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. + * + * Chrysalide 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 Chrysalide. If not, see <http://www.gnu.org/licenses/>. + */ + + +#ifndef _GLIBEXT_SERIALIZE_INT_H +#define _GLIBEXT_SERIALIZE_INT_H + + +#include "serialize.h" + + +#include "storage.h" + + + +/* Charge un objet depuis une mémoire tampon. */ +typedef bool (* load_serializable_object_cb) (GSerializableObject *, GObjectStorage *, int); + +/* Sauvegarde un objet dans une mémoire tampon. */ +typedef bool (* store_serializable_object_cb) (const GSerializableObject *, GObjectStorage *, int); + + +/* Intermédiaire pour la mise en cache d'objet (interface) */ +struct _GSerializableObjectInterface +{ + GTypeInterface base_iface; /* A laisser en premier */ + + load_serializable_object_cb load; /* Chargement */ + store_serializable_object_cb store; /* Enregistrement */ + +}; + + + +#endif /* _GLIBEXT_SERIALIZE_INT_H */ diff --git a/src/glibext/serialize.c b/src/glibext/serialize.c new file mode 100644 index 0000000..b43f0c2 --- /dev/null +++ b/src/glibext/serialize.c @@ -0,0 +1,113 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * serialize.h - objets entreposables dans un cache + * + * Copyright (C) 2020-2025 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide 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. + * + * Chrysalide 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 Chrysalide. If not, see <http://www.gnu.org/licenses/>. + */ + + +#include "serialize.h" + + +#include "serialize-int.h" + + + +/* Procède à l'initialisation de l'interface de mise en cache. */ +static void g_serializable_object_default_init(GSerializableObjectInterface *); + + + +/* Détermine le type d'une interface pour la mise en cache d'objet. */ +G_DEFINE_INTERFACE(GSerializableObject, g_serializable_object, G_TYPE_OBJECT) + + +/****************************************************************************** +* * +* Paramètres : iface = interface GLib à initialiser. * +* * +* Description : Procède à l'initialisation de l'interface de mise en cache. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_serializable_object_default_init(GSerializableObjectInterface *iface) +{ + iface->load = NULL; + iface->store = NULL; + +} + + +/****************************************************************************** +* * +* Paramètres : object = élément GLib à constuire. * +* storage = conservateur de données à manipuler. * +* fd = flux ouvert en lecture. * +* * +* Description : Charge un objet depuis un flux de données. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool g_serializable_object_load(GSerializableObject *object, GObjectStorage *storage, int fd) +{ + bool result; /* Bilan à retourner */ + GSerializableObjectInterface *iface; /* Interface utilisée */ + + iface = G_SERIALIZABLE_OBJECT_GET_IFACE(object); + + result = iface->load(object, storage, fd); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : object = élément GLib à consulter. * +* storage = conservateur de données à manipuler. * +* fd = flux ouvert en écriture. * +* * +* Description : Sauvegarde un objet dans un flux de données. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool g_serializable_object_store(const GSerializableObject *object, GObjectStorage *storage, int fd) +{ + bool result; /* Bilan à retourner */ + GSerializableObjectInterface *iface; /* Interface utilisée */ + + iface = G_SERIALIZABLE_OBJECT_GET_IFACE(object); + + result = iface->store(object, storage, fd); + + return result; + +} diff --git a/src/glibext/serialize.h b/src/glibext/serialize.h new file mode 100644 index 0000000..c95ac30 --- /dev/null +++ b/src/glibext/serialize.h @@ -0,0 +1,52 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * serialize.h - prototypes pour les objets entreposables dans un cache + * + * Copyright (C) 2020-2025 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide 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. + * + * Chrysalide 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 Chrysalide. If not, see <http://www.gnu.org/licenses/>. + */ + + +#ifndef _GLIBEXT_SERIALIZE_H +#define _GLIBEXT_SERIALIZE_H + + +#include <stdbool.h> + + +#include "helpers.h" + + + +#define G_TYPE_SERIALIZABLE_OBJECT (g_serializable_object_get_type()) + +DECLARE_INTERFACE(GSerializableObject, g_serializable_object, G, SERIALIZABLE_OBJECT); + + +/* storage.h : définition d'une conservation d'objets construits */ +typedef struct _GObjectStorage GObjectStorage; + + +/* Charge un objet depuis un flux de données. */ +bool g_serializable_object_load(GSerializableObject *, GObjectStorage *, int); + +/* Sauvegarde un objet dans un flux de données. */ +bool g_serializable_object_store(const GSerializableObject *, GObjectStorage *, int); + + + +#endif /* _GLIBEXT_SERIALIZE_H */ diff --git a/src/glibext/signal.c b/src/glibext/sigredir.c index 33290fb..67e8563 100644 --- a/src/glibext/signal.c +++ b/src/glibext/sigredir.c @@ -1,8 +1,8 @@ /* Chrysalide - Outil d'analyse de fichiers binaires - * signal.c - encadrement des signaux supplémentaire par rapport à celui de la GLib + * sigredir.c - encadrement des signaux supplémentaire par rapport à celui de la GLib * - * Copyright (C) 2014-2018 Cyrille Bagard + * Copyright (C) 2014-2025 Cyrille Bagard * * This file is part of Chrysalide. * @@ -21,49 +21,55 @@ */ -#include "signal.h" +#include "sigredir.h" #include <assert.h> #include <malloc.h> #include <stdarg.h> #include <stdbool.h> +#include <gobject/gclosure.h> #include <gobject/gvaluecollector.h> -/* Prototype pour le transfert d'exécution. */ -typedef void (* GSignalCallback) (gpointer, ...); +/* Informations utiles à l'appel final */ +typedef struct _gsignal_wrapper_params_t +{ + GClosure *closure; /* Glue pour les appels */ + + guint n_params; /* Nombre de paramètres */ + GValue instance_and_params[0]; /* Instance & paramètres */ + +} gsignal_wrapper_params_t; + +/* Transmet un signal dans le contexte principal. */ +static gboolean to_main_wrapper(gpointer); +/* Supprime de la mémoire le transporteur d'informations. */ +static void destroy_wrapper_params(gpointer); /* Informations concernant une diffusion de signal */ -typedef struct _gsignal_wrapper_info +typedef struct _gsignal_wrapper_info_t { gpointer instance; /* Instance GLib initiatrice */ + gulong id; /* Identifiant de connexion */ GClosure *closure; /* Glue pour les appels */ - GType return_type; /* Type de la valeur retournée */ guint n_params; /* Nombre de paramètres */ - const GType *param_types; /* Type des paramètres associés*/ + GType param_types[0]; /* Type des paramètres associés*/ - GValue return_value; /* Valeur de retour */ - GValue instance_and_params[0]; /* Instance & paramètres */ - -} gsignal_wrapper_info; - - -/* Transmet un signal dans le contexte principal. */ -static gboolean to_main_wrapper(gsignal_wrapper_info *); +} gsignal_wrapper_info_t; /* Réceptionne un signal et redirige son exécution. */ -static void carry_signal_to_main_thread(gsignal_wrapper_info *, ...); +static void carry_signal_to_main_thread(gsignal_wrapper_info_t *, ...); /****************************************************************************** * * -* Paramètres : info = collecteur d'informations sur la diffusion. * +* Paramètres : data = collecteur d'informations sur la diffusion. * * * * Description : Transmet un signal dans le contexte principal. * * * @@ -73,11 +79,17 @@ static void carry_signal_to_main_thread(gsignal_wrapper_info *, ...); * * ******************************************************************************/ -static gboolean to_main_wrapper(gsignal_wrapper_info *info) +static gboolean to_main_wrapper(gpointer data) { - g_closure_invoke(info->closure, NULL/*&info->return_value*/, - info->n_params + 1, info->instance_and_params, - NULL); + gsignal_wrapper_params_t *params; /* Informations d'appel */ + + params = (gsignal_wrapper_params_t *)data; + + g_closure_invoke(params->closure, + NULL /* return_value */, + params->n_params + 1, + params->instance_and_params, + NULL /* invocation_hint */); return G_SOURCE_REMOVE; @@ -86,6 +98,35 @@ static gboolean to_main_wrapper(gsignal_wrapper_info *info) /****************************************************************************** * * +* Paramètres : data = collecteur d'informations à supprimer. * +* * +* Description : Supprime de la mémoire le transporteur d'informations. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void destroy_wrapper_params(gpointer data) +{ + gsignal_wrapper_params_t *params; /* Informations d'appel */ + guint i; /* Boucle de parcours */ + + params = (gsignal_wrapper_params_t *)data; + + g_closure_unref(params->closure); + + for (i = 0; i < (params->n_params + 1); i++) + g_value_unset(params->instance_and_params + i); + + free(params); + +} + + +/****************************************************************************** +* * * Paramètres : info = collecteur d'informations sur la diffusion. * * ... = arguments poussés par la GLib sur la pile. * * * @@ -97,23 +138,26 @@ static gboolean to_main_wrapper(gsignal_wrapper_info *info) * * ******************************************************************************/ -static void carry_signal_to_main_thread(gsignal_wrapper_info *info, ...) +static void carry_signal_to_main_thread(gsignal_wrapper_info_t *info, ...) { + gsignal_wrapper_params_t *params; /* Informations d'appel */ GValue *param_values; /* Paramètres d'appel */ va_list ap; /* Liste d'arguments sur pile */ guint i; /* Boucle de parcours */ bool static_scope; /* Portée des arguments */ gchar *error; /* Eventuelle erreur inattendue*/ - //g_value_init(&info->return_value, info->return_type & ~G_SIGNAL_TYPE_STATIC_SCOPE); + params = calloc(1, sizeof(gsignal_wrapper_params_t) + sizeof(GValue) * (info->n_params + 1)); + + params->closure = info->closure; + g_closure_ref(info->closure); - if (G_IS_VALUE(info->instance_and_params)) - g_value_unset(info->instance_and_params); + params->n_params = info->n_params; - g_value_init(info->instance_and_params, G_TYPE_FROM_INSTANCE(info->instance)); - g_value_set_instance(info->instance_and_params, info->instance); + g_value_init(params->instance_and_params, G_TYPE_FROM_INSTANCE(info->instance)); + g_value_set_instance(params->instance_and_params, info->instance); - param_values = info->instance_and_params + 1; + param_values = params->instance_and_params + 1; va_start(ap, info); @@ -121,9 +165,6 @@ static void carry_signal_to_main_thread(gsignal_wrapper_info *info, ...) for (i = 0; i < info->n_params; i++) { - if (G_IS_VALUE(param_values + i)) - g_value_unset(param_values + i); - static_scope = info->param_types[i] & G_SIGNAL_TYPE_STATIC_SCOPE; G_VALUE_COLLECT_INIT(param_values + i, @@ -143,7 +184,28 @@ static void carry_signal_to_main_thread(gsignal_wrapper_info *info, ...) va_end(ap); if (error == NULL) - g_idle_add_full(G_PRIORITY_HIGH_IDLE, (GSourceFunc)to_main_wrapper, info, NULL); + g_idle_add_full(G_PRIORITY_HIGH_IDLE, to_main_wrapper, params, destroy_wrapper_params); + +} + + +/****************************************************************************** +* * +* Paramètres : info = collecteur d'informations à supprimer. * +* * +* Description : Déconnecte un signal redirigé vers le contexte principal. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +void g_signal_disconnect_from_main(gsignal_wrapper_info_t *info) +{ + g_signal_handler_disconnect(info->instance, info->id); + + free(info); } @@ -165,41 +227,44 @@ static void carry_signal_to_main_thread(gsignal_wrapper_info *info, ...) * * ******************************************************************************/ -gulong _g_signal_connect_to_main(gpointer instance, const gchar *signal, GCallback handler, gpointer data, GClosureMarshal marshal, GConnectFlags flags) +gsignal_wrapper_info_t *_g_signal_connect_to_main(gpointer instance, const gchar *signal, GCallback handler, gpointer data, GClosureMarshal marshal, GConnectFlags flags) { + gsignal_wrapper_info_t *result; /* Structure à renvoyer */ guint signal_id; /* Identifiant du signal visé */ GSignalQuery query; /* Information sur le signal */ - gsignal_wrapper_info *info; /* Encapsulation des données */ /* Collection d'informations */ signal_id = g_signal_lookup(signal, G_TYPE_FROM_INSTANCE(instance)); g_signal_query(signal_id, &query); + assert(query.signal_id != 0); + assert(query.return_type == G_TYPE_NONE); /* Allocation adaptée */ - info = calloc(1, sizeof(gsignal_wrapper_info) + sizeof(GValue) * (query.n_params + 1)); + result = malloc(sizeof(gsignal_wrapper_info_t) + sizeof(GType) * query.n_params); - info->instance = instance; + result->instance = instance; if (flags & G_CONNECT_SWAPPED) - info->closure = g_cclosure_new_swap(handler, data, NULL); + result->closure = g_cclosure_new_swap(handler, data, NULL); else - info->closure = g_cclosure_new(handler, data, NULL); + result->closure = g_cclosure_new(handler, data, NULL); - g_closure_ref(info->closure); - g_closure_sink(info->closure); + g_closure_ref(result->closure); + g_closure_sink(result->closure); - g_closure_set_marshal(info->closure, marshal); + g_closure_set_marshal(result->closure, marshal); - info->return_type = query.return_type; - info->n_params = query.n_params; - info->param_types = query.param_types; + result->n_params = query.n_params; + memcpy(result->param_types, query.param_types, sizeof(GType) * query.n_params); - assert(query.return_type == G_TYPE_NONE); + /* Connexion au signal */ + + result->id = g_signal_connect_swapped(instance, signal, G_CALLBACK(carry_signal_to_main_thread), result); - return g_signal_connect_swapped(instance, signal, G_CALLBACK(carry_signal_to_main_thread), info); + return result; } diff --git a/src/glibext/_signal.h b/src/glibext/sigredir.h index 4f0ab4b..f394d77 100644 --- a/src/glibext/_signal.h +++ b/src/glibext/sigredir.h @@ -1,8 +1,8 @@ /* Chrysalide - Outil d'analyse de fichiers binaires - * signal.h - prototypes pour un encadrement des signaux supplémentaire par rapport à celui de la GLib + * sigredir.h - prototypes pour un encadrement des signaux supplémentaire par rapport à celui de la GLib * - * Copyright (C) 2014-2018 Cyrille Bagard + * Copyright (C) 2014-2025 Cyrille Bagard * * This file is part of Chrysalide. * @@ -21,20 +21,23 @@ */ -#ifndef _GLIBEXT_SIGNAL_H -#define _GLIBEXT_SIGNAL_H +#ifndef _GLIBEXT_SIGREDIR_H +#define _GLIBEXT_SIGREDIR_H #include <glib-object.h> -#include <gobject/gclosure.h> -#include <glib/gdataset.h> -#include <glib/glist.h> #include <gobject/gsignal.h> +/* Informations concernant une diffusion de signal */ +typedef struct _gsignal_wrapper_info_t gsignal_wrapper_info_t; + /* Reproduit le comportement de la fonction g_signal_connect(). */ -gulong _g_signal_connect_to_main(gpointer, const gchar *, GCallback, gpointer, GClosureMarshal, GConnectFlags); +gsignal_wrapper_info_t *_g_signal_connect_to_main(gpointer, const gchar *, GCallback, gpointer, GClosureMarshal, GConnectFlags); + +/* Déconnecte un signal redirigé vers le contexte principal. */ +void g_signal_disconnect_from_main(gsignal_wrapper_info_t *); #define g_signal_connect_to_main(instance, signal, handler, data, marshal) \ @@ -45,4 +48,4 @@ gulong _g_signal_connect_to_main(gpointer, const gchar *, GCallback, gpointer, G -#endif /* _GLIBEXT_SIGNAL_H */ +#endif /* _GLIBEXT_SIGREDIR_H */ diff --git a/src/glibext/singleton.c b/src/glibext/singleton.c index 0a50d19..ed49934 100644 --- a/src/glibext/singleton.c +++ b/src/glibext/singleton.c @@ -74,9 +74,9 @@ static void g_singleton_factory_finalize(GSingletonFactory *); /* Détermine le type d'une interface pour la constitution d'objets uniques. */ -G_DEFINE_INTERFACE_WITH_CODE(GSingletonCandidate, g_singleton_candidate, G_TYPE_OBJECT, - g_type_interface_add_prerequisite(g_define_type_id, G_TYPE_HASHABLE_OBJECT); - g_type_interface_add_prerequisite(g_define_type_id, G_TYPE_COMPARABLE_OBJECT)) +G_DEFINE_INTERFACE_WITH_CODE(GSingletonCandidate, g_singleton_candidate, G_TYPE_OBJECT,; + g_type_interface_add_prerequisite(g_define_type_id, G_TYPE_COMPARABLE_OBJECT); + g_type_interface_add_prerequisite(g_define_type_id, G_TYPE_HASHABLE_OBJECT)) /****************************************************************************** diff --git a/src/glibext/storage-int.h b/src/glibext/storage-int.h new file mode 100644 index 0000000..d89e1c8 --- /dev/null +++ b/src/glibext/storage-int.h @@ -0,0 +1,75 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * storage-int.h - prototypes internes pour la conservation sur disque d'objets construits + * + * Copyright (C) 2020-2025 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide 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. + * + * Chrysalide 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 Foobar. If not, see <http://www.gnu.org/licenses/>. + */ + + +#ifndef _GLIBEXT_STORAGE_INT_H +#define _GLIBEXT_STORAGE_INT_H + + +#include "storage.h" +#include "tpmem.h" +#include "../common/szbin.h" + + + +/* Gestion d'enregistrements spécifiques */ +typedef struct _storage_backend_t +{ + char *name; /* Désignation du groupe */ + + char *filename; /* Nom du fichier associé */ + int fd; /* Flux d'accès correspondant */ + +} storage_backend_t; + +/* Définition d'une conservation d'objets construits (instance) */ +struct _GObjectStorage +{ + GObject parent; /* A laisser en premier */ + + sized_binary_t type; /* Type de conservation */ + uint8_t version; /* Version correspondante */ + + sized_binary_t uid; /* Identifiant de distinction */ + + GTypeMemory *tpmem; /* Mémorisation de types */ + + storage_backend_t *backends; /* Gestionnaires existants */ + size_t count; /* Quantité de gestionnaires */ + GMutex mutex; /* Contrôle d'accès à la liste */ + +}; + +/* Définition d'une conservation d'objets construits (classe) */ +struct _GObjectStorageClass +{ + GObjectClass parent; /* A laisser en premier */ + +}; + + +/* Met en place un support d'une conservation d'objets en place. */ +bool g_object_storage_create(GObjectStorage *, const char *, uint8_t, const char *); + + + +#endif /* _GLIBEXT_STORAGE_INT_H */ diff --git a/src/glibext/storage.c b/src/glibext/storage.c new file mode 100644 index 0000000..0a3c4e7 --- /dev/null +++ b/src/glibext/storage.c @@ -0,0 +1,1147 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * storage.c - conservation hors mémoire d'objets choisis + * + * Copyright (C) 2020-2025 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide 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. + * + * Chrysalide 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 Foobar. If not, see <http://www.gnu.org/licenses/>. + */ + + +#include "storage.h" + + +#include <assert.h> +#include <malloc.h> +#include <string.h> +#include <unistd.h> +#include <zip.h> + + +#include "storage-int.h" +#include "../common/cpp.h" +#include "../common/pathname.h" +#include "../core/logs.h" + + +/** + * Historique du format : + * + * - 09/03/25 : 1.0 (version initiale) + * + */ +#define STORAGE_MAGIC "COBSTR" +#define STORAGE_NUMBER "\x01\x00" + + +/* Initialise la classe des conservations d'objets en place. */ +static void g_object_storage_class_init(GObjectStorageClass *); + +/* Initialise une instance de conservation d'objets en place. */ +static void g_object_storage_init(GObjectStorage *); + +/* Supprime toutes les références externes. */ +static void g_object_storage_dispose(GObject *); + +/* Procède à la libération totale de la mémoire. */ +static void g_object_storage_finalize(GObject *); + +/* Assure l'inexistence d'un groupe avec un nom donné. */ +static bool g_object_storage_has_no_backend_named(GObjectStorage *, const char *); + +/* Retrouve l'encadrement pour un nouveau groupe d'objets. */ +static storage_backend_t *g_object_storage_find_backend(GObjectStorage *, const char *); + +/* Ajoute le support d'un nouveau groupe d'objets construits. */ +static bool g_object_storage_add_backend(GObjectStorage *, const char *, storage_backend_t **); + +/* Charge un objet à partir de données rassemblées. */ +static GSerializableObject *g_object_storage_load_object_unlocked(GObjectStorage *, const char *, off64_t); + + + +/* Indique le type défini pour une conservation d'objets construits. */ +G_DEFINE_TYPE(GObjectStorage, g_object_storage, G_TYPE_OBJECT); + + +/****************************************************************************** +* * +* Paramètres : klass = classe à initialiser. * +* * +* Description : Initialise la classe des conservations d'objets en place. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_object_storage_class_init(GObjectStorageClass *klass) +{ + GObjectClass *object; /* Autre version de la classe */ + + object = G_OBJECT_CLASS(klass); + + object->dispose = g_object_storage_dispose; + object->finalize = g_object_storage_finalize; + +} + + +/****************************************************************************** +* * +* Paramètres : storage = instance à initialiser. * +* * +* Description : Initialise une instance de conservation d'objets en place. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_object_storage_init(GObjectStorage *storage) +{ + init_sized_binary(&storage->type); + storage->version = 0; + + init_sized_binary(&storage->uid); + + storage->tpmem = g_type_memory_new(); + + storage->backends = NULL; + storage->count = 0; + g_mutex_init(&storage->mutex); + +} + + +/****************************************************************************** +* * +* Paramètres : object = instance d'objet GLib à traiter. * +* * +* Description : Supprime toutes les références externes. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_object_storage_dispose(GObject *object) +{ + GObjectStorage *storage; /* Version spécialisée */ + + storage = G_OBJECT_STORAGE(object); + + g_clear_object(&storage->tpmem); + + G_OBJECT_CLASS(g_object_storage_parent_class)->dispose(object); + +} + + +/****************************************************************************** +* * +* Paramètres : object = instance d'objet GLib à traiter. * +* * +* Description : Procède à la libération totale de la mémoire. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_object_storage_finalize(GObject *object) +{ + GObjectStorage *storage; /* Version spécialisée */ + size_t i; /* Boucle de parcours */ + storage_backend_t *backend; /* Gestionnaire à manipuler */ + int ret; /* Bilan d'un appel */ + + storage = G_OBJECT_STORAGE(object); + + g_mutex_lock(&storage->mutex); + + for (i = 0; i < storage->count; i++) + { + backend = &storage->backends[i]; + + /** + * Chargement incomplet depuis g_object_storage_load(). + */ + if (backend->name == NULL) + break; + + if (backend->fd != -1) + close(backend->fd); + else + assert(false); + + ret = access(backend->filename, W_OK); + if (ret == 0) + { + ret = unlink(backend->filename); + if (ret != 0) LOG_ERROR_N("unlink"); + } + + free(backend->name); + + free(backend->filename); + + } + + if (storage->backends != NULL) + free(storage->backends); + + g_mutex_unlock(&storage->mutex); + + g_mutex_clear(&storage->mutex); + + exit_sized_binary(&storage->type); + + exit_sized_binary(&storage->uid); + + G_OBJECT_CLASS(g_object_storage_parent_class)->finalize(object); + +} + + +/****************************************************************************** +* * +* Paramètres : type = type global à indiquer dans une conservation. * +* version = numéro de version associé. * +* uid = identifiant arbitraire mais unique pour distinguer.* +* * +* Description : Crée le support d'une conservation d'objets en place. * +* * +* Retour : Mécanismes mis en place. * +* * +* Remarques : - * +* * +******************************************************************************/ + +GObjectStorage *g_object_storage_new(const char *type, uint8_t version, const char *uid) +{ + GObjectStorage *result; /* Structure à retourner */ + + result = g_object_new(G_TYPE_OBJECT_STORAGE, NULL); + + if (!g_object_storage_create(result, type, version, uid)) + g_clear_object(&result); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : storage = stockage d'objets à initialiser. * +* type = type global à indiquer dans une conservation. * +* version = numéro de version associé. * +* uid = identifiant arbitraire mais unique pour distinguer.* +* * +* Description : Met en place un support d'une conservation d'objets en place.* +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool g_object_storage_create(GObjectStorage *storage, const char *type, uint8_t version, const char *uid) +{ + bool result; /* Bilan à retourner */ + + result = true; + + dup_into_sized_binary(&storage->type, type, strlen(type)); + + storage->version = version; + + dup_into_sized_binary(&storage->uid, uid, strlen(uid) + 1); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : filename = fichier de source à traiter. * +* * +* Description : Charge le support d'une conservation d'objets en place. * +* * +* Retour : Gestionnaire de conservations construit ou NULL si erreur. * +* * +* Remarques : - * +* * +******************************************************************************/ + +GObjectStorage *g_object_storage_load(const char *filename) +{ + GObjectStorage *result; /* Structure à retourner */ + GObjectStorage *storage; /* Structure en construction */ + int err; /* Eventuel code d'erreur */ + zip_t *archive; /* Archive ZIP à manipuler */ + zip_error_t error; /* Suivi des erreurs obtenues */ + char *tpmem_filename; /* Chemin d'accès pour types */ + zip_int64_t entries_count; /* Nombre d'éléments ZIP */ + void *data; /* Données (décompressées) */ + zip_stat_t stats; /* Information sur les données */ + zip_file_t *file; /* Echantillon à extraire */ + zip_int64_t got; /* Nombre d'octets lus */ + int ret; /* Bilan d'un appel */ + const void *pos; /* Tête de lecture */ + const void *max; /* Fin des données lisibles */ + bool status; /* Bilan d'une extraction */ + char *prefix; /* Début de nom de fichier */ + int fd; /* Descripteur de flux ouvert */ + off_t moved; /* Nouvelle position établie */ + zip_int64_t i; /* Boucle de parcours */ + storage_backend_t *backend; /* Informations à intégrer */ + const char *slash; /* Pointeur vers un caractère /*/ + + result = NULL; + + storage = g_object_new(G_TYPE_OBJECT_STORAGE, NULL); + + archive = zip_open(filename, ZIP_RDONLY, &err); + if (archive == NULL) + { + zip_error_init_with_code(&error, err); + LOG_ERROR_ZIP("zip_open", &error); + goto exit; + } + + zip_error_init(&error); + + tpmem_filename = NULL; + + /* Validation du nombre d'entrées */ + + entries_count = zip_get_num_entries(archive, ZIP_FL_UNCHANGED); + + if (entries_count < 2) + goto exit_with_archive; + + data = NULL; + + /* Extraction de la partie de contrôle */ + + ret = zip_stat_index(archive, 0, ZIP_FL_UNCHANGED, &stats); + if (ret != 0) + { + LOG_ERROR_ZIP("zip_stat_index", zip_get_error(archive)); + goto exit_with_archive; + } + + if ((stats.valid & (ZIP_STAT_NAME | ZIP_STAT_SIZE)) != (ZIP_STAT_NAME | ZIP_STAT_SIZE)) + goto exit_with_archive; + + if (strcmp(stats.name, "control") != 0) + goto exit_with_archive; + + if (stats.size < (6 + 2 + 1 + 1 + 1)) + goto exit_with_archive; + + file = zip_fopen_index(archive, 0, ZIP_FL_UNCHANGED); + if (file == NULL) + { + LOG_ERROR_ZIP("zip_fopen_index", zip_get_error(archive)); + goto exit_with_archive; + } + + data = malloc(stats.size); + + got = zip_fread(file, data, stats.size); + + ret = zip_fclose(file); + if (ret != 0) + { + zip_error_set(&error, ret, 0); + LOG_ERROR_ZIP("zip_fclose", &error); + goto exit_with_data; + } + + if (got != stats.size) + goto exit_with_data; + + if (memcmp(data, STORAGE_MAGIC, 6) != 0) + goto exit_with_data; + + if (memcmp(((uint8_t *)data) + 6, STORAGE_NUMBER, 2) != 0) + goto exit_with_data; + + pos = (uint8_t *)data + 8; + max = (uint8_t *)data + got; + + status = unpack_sized_binary(&storage->type, &pos, max); + if (!status) goto exit_with_data; + + if (pos >= max) + goto exit_with_data; + + storage->version = *(uint8_t *)pos; + pos = (uint8_t *)pos + 1; + + unpack_sized_binary_as_string(&storage->uid, &pos, max); + if (!status) goto exit_with_data; + + if (pos != max) + goto exit_with_data; + + free(data); + data = NULL; + + /* Extraction de la conservation des types */ + + ret = zip_stat_index(archive, 1, ZIP_FL_UNCHANGED, &stats); + if (ret != 0) + { + LOG_ERROR_ZIP("zip_stat_index", zip_get_error(archive)); + goto exit_with_archive; + } + + if ((stats.valid & (ZIP_STAT_NAME | ZIP_STAT_SIZE)) != (ZIP_STAT_NAME | ZIP_STAT_SIZE)) + goto exit_with_archive; + + if (strcmp(stats.name, "types") != 0) + goto exit_with_archive; + + file = zip_fopen_index(archive, 1, ZIP_FL_UNCHANGED); + if (file == NULL) + { + LOG_ERROR_ZIP("zip_fopen_index", zip_get_error(archive)); + goto exit_with_archive; + } + + data = malloc(stats.size); + + got = zip_fread(file, data, stats.size); + + ret = zip_fclose(file); + if (ret != 0) + { + zip_error_set(&error, ret, 0); + LOG_ERROR_ZIP("zip_fclose", &error); + goto exit_with_data; + } + + asprintf(&prefix, "%s-types", storage->uid.static_data); + + fd = make_tmp_file(prefix, "cache", &tpmem_filename); + + free(prefix); + + if (fd == -1) + goto exit_with_data; + + status = safe_write(fd, data, stats.size); + if (!status) + { + close(fd); + goto exit_with_data; + } + + moved = lseek(fd, 0, SEEK_SET); + if (moved == ((off_t)-1)) + { + LOG_ERROR_N("lseek"); + close(fd); + goto exit_with_data; + } + + status = g_type_memory_load(storage->tpmem, fd); + + close(fd); + + if (!status) + goto exit_with_data; + + free(data); + data = NULL; + + /* Extraction des différents objects restants */ + + if (entries_count > 2) + { + storage->count = entries_count - 2; + storage->backends = calloc(storage->count, sizeof(storage_backend_t)); + + for (i = 2; i < entries_count; i++) + { + backend = &storage->backends[i - 2]; + + ret = zip_stat_index(archive, i, ZIP_FL_UNCHANGED, &stats); + if (ret != 0) + { + LOG_ERROR_ZIP("zip_stat_index", zip_get_error(archive)); + goto exit_with_archive; + } + + if ((stats.valid & (ZIP_STAT_NAME | ZIP_STAT_SIZE)) != (ZIP_STAT_NAME | ZIP_STAT_SIZE)) + goto exit_with_archive; + + if (strncmp(stats.name, SL("backends/")) != 0) + goto exit_with_archive; + + slash = strchr(stats.name, '/'); + + if (slash == NULL) + goto exit_with_archive; + + if (strchr(slash + 1, '/') != NULL) + goto exit_with_archive; + + if (!g_object_storage_has_no_backend_named(storage, slash + 1)) + goto exit_with_archive; + + file = zip_fopen_index(archive, i, ZIP_FL_UNCHANGED); + if (file == NULL) + { + LOG_ERROR_ZIP("zip_fopen_index", zip_get_error(archive)); + goto exit_with_archive; + } + + data = malloc(stats.size); + + got = zip_fread(file, data, stats.size); + + ret = zip_fclose(file); + if (ret != 0) + { + zip_error_set(&error, ret, 0); + LOG_ERROR_ZIP("zip_fclose", &error); + goto exit_with_data; + } + + backend->name = strdup(slash + 1); + + asprintf(&prefix, "%s-%s", storage->uid.static_data, backend->name); + + backend->fd = make_tmp_file(prefix, "cache", &backend->filename); + + free(prefix); + + if (backend->fd == -1) + goto exit_with_data; + + status = safe_write(backend->fd, data, stats.size); + if (!status) goto exit_with_data; + + moved = lseek(backend->fd, 0, SEEK_SET); + if (moved == ((off_t)-1)) + { + LOG_ERROR_N("lseek"); + goto exit_with_data; + } + + free(data); + data = NULL; + + } + + } + + /* Clôture des opérations */ + + result = storage; + ref_object(storage); + + exit_with_data: + + if (data != NULL) + free(data); + + exit_with_archive: + + ret = zip_close(archive); + + if (ret != 0) + LOG_ERROR_ZIP("zip_close", zip_get_error(archive)); + + if (tpmem_filename != NULL) + unlink(tpmem_filename); + + zip_error_fini(&error); + + exit: + + unref_object(storage); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : storage = gestionnaire de conservations à manipuler. * +* filename = fichier de destination à constituer. * +* * +* Description : Sauvegarde le support d'une conservation d'objets en place. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool g_object_storage_store(GObjectStorage *storage, const char *filename) +{ + bool result; /* Bilan à retourner */ + int err; /* Eventuel code d'erreur */ + zip_t *archive; /* Archive ZIP à manipuler */ + zip_error_t error; /* Suivi des erreurs obtenues */ + char *tpmem_filename; /* Chemin d'accès pour types */ + void *type_buf; /* Données pour le type */ + size_t type_buflen; /* Quantité de ces données */ + void *uid_buf; /* Données pour l'identifiant */ + size_t uid_buflen; /* Quantité de ces données */ + size_t control_len; /* Taille des premières données*/ + uint8_t *control; /* Premières données du fichier*/ + zip_source_t *zip_data; /* Données ZIP à intégrer */ + zip_int64_t index; /* Nouvel index du contenu */ + int ret; /* Bilan d'un appel */ + char *prefix; /* Début de nom de fichier */ + int fd; /* Descripteur de flux ouvert */ + bool status; /* Bilan d'une écriture */ + size_t i; /* Boucle de parcours */ + char *zip_name; /* Destination pour l'archive */ + + result = false; + + archive = zip_open(filename, ZIP_CREATE | ZIP_TRUNCATE, &err); + if (archive == NULL) + { + zip_error_init_with_code(&error, err); + LOG_ERROR_ZIP("zip_open", &error); + goto exit; + } + + zip_error_init(&error); + + tpmem_filename = NULL; + + /* Fichier de contrôle */ + + type_buf = pack_sized_binary(&storage->type, &type_buflen); + + uid_buf = pack_sized_binary_as_string(&storage->uid, &uid_buflen); + + assert((sizeof(STORAGE_MAGIC) - 1 + sizeof(STORAGE_NUMBER) - 1) == 8); + + control_len = 8 + type_buflen + 1 + uid_buflen; + control = malloc(control_len * sizeof(uint8_t)); + + memcpy(control, STORAGE_MAGIC, 6); + memcpy(control + 6, STORAGE_NUMBER, 2); + + memcpy(control + 8, type_buf, type_buflen); + + control[8 + type_buflen] = storage->version; + + memcpy(control + 8 + type_buflen + 1, uid_buf, uid_buflen); + + zip_data = zip_source_buffer_create(control, control_len, 0, &error); + if (zip_data == NULL) + { + LOG_ERROR_ZIP("zip_source_buffer_create", &error); + goto exit_with_control; + } + + index = zip_file_add(archive, "control", zip_data, ZIP_FL_ENC_UTF_8); + if (index == -1) + { + zip_source_free(zip_data); + LOG_ERROR_ZIP("zip_file_add", zip_get_error(archive)); + goto exit_with_control; + } + + ret = zip_set_file_compression(archive, index, ZIP_CM_STORE, 0 /* comp_flags */); + if (ret == -1) + { + LOG_ERROR_ZIP("zip_set_file_compression", zip_get_error(archive)); + goto exit_with_control; + } + + /* Composants de la conservation */ + + g_mutex_lock(&storage->mutex); + + /* Conservation des types */ + + asprintf(&prefix, "%s-types", storage->uid.static_data); + + fd = make_tmp_file(prefix, "cache", &tpmem_filename); + + free(prefix); + + if (fd == -1) + goto exit_with_lock; + + status = g_type_memory_store(storage->tpmem, fd); + + close(fd); + + if (!status) + goto exit_with_lock; + + zip_data = zip_source_file_create(tpmem_filename, 0, -1 /* ZIP_LENGTH_TO_END */, &error); + if (zip_data == NULL) + { + LOG_ERROR_ZIP("zip_source_file_create", &error); + goto exit_with_lock; + } + + index = zip_file_add(archive, "types", zip_data, ZIP_FL_ENC_UTF_8); + if (index == -1) + { + zip_source_free(zip_data); + LOG_ERROR_ZIP("zip_file_add", zip_get_error(archive)); + goto exit_with_lock; + } + + ret = zip_set_file_compression(archive, index, ZIP_CM_DEFLATE, 9 /* comp_flags */); + if (ret == -1) + { + LOG_ERROR_ZIP("zip_set_file_compression", zip_get_error(archive)); + goto exit_with_lock; + } + + /* Conservation des objets */ + + for (i = 0; i < storage->count; i++) + { + zip_data = zip_source_file_create(storage->backends[i].filename, 0, -1 /* ZIP_LENGTH_TO_END */, &error); + if (zip_data == NULL) + { + LOG_ERROR_ZIP("zip_source_file_create", &error); + goto exit_with_lock; + } + + /** + * Pas besoin de distinguer les chemins UNIX et Windows ici. + * + * Cf. https://pkware.cachefly.net/webdocs/casestudies/APPNOTE.TXT : + * + * 4.4.17 file name: (Variable) + * + * The path stored MUST NOT contain a drive or + * device letter, or a leading slash. All slashes + * MUST be forward slashes '/' as opposed to + * backwards slashes '\' for compatibility with Amiga + * and UNIX file systems etc. If input came from standard + * input, there is no file name field. + * + */ + + asprintf(&zip_name, "backends/%s", storage->backends[i].name); + + index = zip_file_add(archive, zip_name, zip_data, ZIP_FL_ENC_UTF_8); + + free(zip_name); + + if (index == -1) + { + zip_source_free(zip_data); + LOG_ERROR_ZIP("zip_file_add", zip_get_error(archive)); + goto exit_with_lock; + } + + ret = zip_set_file_compression(archive, index, ZIP_CM_DEFLATE, 9 /* comp_flags */); + if (ret == -1) + { + LOG_ERROR_ZIP("zip_set_file_compression", zip_get_error(archive)); + goto exit_with_lock; + } + + } + + result = true; + + /* Clôture des opérations */ + + exit_with_lock: + + g_mutex_unlock(&storage->mutex); + + exit_with_control: + + ret = zip_close(archive); + + if (ret != 0) + LOG_ERROR_ZIP("zip_close", zip_get_error(archive)); + + free(control); + + if (tpmem_filename != NULL) + unlink(tpmem_filename); + + zip_error_fini(&error); + + exit: + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : storage = gestionnaire de conservations à consulter. * +* name = désignation d'un nouveau groupe d'objets. * +* * +* Description : Assure l'inexistence d'un groupe avec un nom donné. * +* * +* Retour : Bilan des recherches. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static bool g_object_storage_has_no_backend_named(GObjectStorage *storage, const char *name) +{ + bool result; /* Bilan à retourner */ + size_t i; /* Boucle de parcours */ + + result = true; + + for (i = 0; i < storage->count && result; i++) + { + if (storage->backends[i].name == NULL) + break; + + if (strcmp(storage->backends[i].name, name) == 0) + result = false; + + } + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : storage = gestionnaire de conservations à compléter. * +* name = désignation d'un nouveau groupe d'objets. * +* * +* Description : Retrouve l'encadrement pour un nouveau groupe d'objets. * +* * +* Retour : Informations liées à un groupe ou NULL en cas d'échec. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static storage_backend_t *g_object_storage_find_backend(GObjectStorage *storage, const char *name) +{ + storage_backend_t *result; /* Encadrement à retourner */ + size_t i; /* Boucle de parcours */ + + assert(!g_mutex_trylock(&storage->mutex)); + + for (i = 0; i < storage->count; i++) + if (strcmp(storage->backends[i].name, name) == 0) + break; + + if (i == storage->count) + result = NULL; + else + result = &storage->backends[i]; + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : storage = gestionnaire de conservations à compléter. * +* name = désignation d'un nouveau groupe d'objets. * +* backend = support mis en place pour les enregistrements. * +* * +* Description : Ajoute le support d'un nouveau groupe d'objets construits. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static bool g_object_storage_add_backend(GObjectStorage *storage, const char *name, storage_backend_t **backend) +{ + bool result; /* Bilan à retourner */ + char *prefix; /* Début de nom de fichier */ + char *filename; /* Chemin d'accès aux données */ + int fd; /* Descripteur de flux ouvert */ + + result = false; + + *backend = NULL; + + assert(!g_mutex_trylock(&storage->mutex)); + + if (g_object_storage_find_backend(storage, name) != NULL) + goto exit; + + /* Préparatifs */ + + asprintf(&prefix, "%s-%s", storage->uid.static_data, name); + + fd = make_tmp_file(prefix, "cache", &filename); + + free(prefix); + + if (fd == -1) + goto exit; + + /* Inscription en bonne et due forme */ + + storage->backends = realloc(storage->backends, ++storage->count * sizeof(storage_backend_t)); + + *backend = &storage->backends[storage->count - 1]; + + (*backend)->name = strdup(name); + + (*backend)->filename = filename; + (*backend)->fd = fd; + + result = true; + + exit: + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : storage = gestionnaire à manipuler. * +* name = désignation d'un groupe d'objets à consulter. * +* pos = tête de lecture avant écriture. * +* * +* Description : Charge un objet à partir de données rassemblées. * +* * +* Retour : Objet restauré en mémoire ou NULL en cas d'échec. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static GSerializableObject *g_object_storage_load_object_unlocked(GObjectStorage *storage, const char *name, off64_t pos) +{ + GSerializableObject *result; /* Instance à retourner */ + storage_backend_t *backend; /* Informations à consulter */ + off64_t new; /* Nouvelle position de lecture*/ + bool status; /* Bilan d'une opération */ + + result = NULL; + + assert(!g_mutex_trylock(&storage->mutex)); + + /* Chargement */ + + backend = g_object_storage_find_backend(storage, name); + if (backend == NULL) goto exit; + + new = lseek64(backend->fd, pos, SEEK_SET); + if (new == (off_t)-1) + { + LOG_ERROR_N("lseek64"); + goto exit; + } + + assert (new == pos); + + /* Phase de conversion */ + + result = G_SERIALIZABLE_OBJECT(g_type_memory_create_object_from_gtype(storage->tpmem, backend->fd)); + + if (result) + { + status = g_serializable_object_load(result, storage, backend->fd); + + if (!status) + g_clear_object(&result); + + } + + exit: + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : storage = gestionnaire à manipuler. * +* name = désignation d'un groupe d'objets à consulter. * +* pos = tête de lecture avant écriture. * +* * +* Description : Charge un objet à partir de données rassemblées. * +* * +* Retour : Objet restauré en mémoire ou NULL en cas d'échec. * +* * +* Remarques : - * +* * +******************************************************************************/ + +GSerializableObject *g_object_storage_load_object(GObjectStorage *storage, const char *name, off64_t pos) +{ + GSerializableObject *result; /* Instance à retourner */ + + g_mutex_lock(&storage->mutex); + + result = g_object_storage_load_object_unlocked(storage, name, pos); + + g_mutex_unlock(&storage->mutex); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : storage = gestionnaire à manipuler. * +* fd = flux de données de l'objet courant. * +* name = désignation du groupe de l'objets à extraire. * +* * +* Description : Charge un objet interne à partir d'une référence embarquée. * +* * +* Retour : Objet restauré en mémoire ou NULL en cas d'échec. * +* * +* Remarques : - * +* * +******************************************************************************/ + +GSerializableObject *g_object_storage_unpack_object(GObjectStorage *storage, int fd, const char *name) +{ + GSerializableObject *result; /* Instance à retourner */ + storage_backend_t *backend; /* Informations à consulter */ + uleb128_t pos; /* Localisation des données */ + bool status; /* Bilan d'une opération */ + off64_t saved; /* Sauvegarde de position */ + off64_t new; /* Nouvelle position de lecture*/ + + result = NULL; + + g_mutex_lock(&storage->mutex); + + /* Récupération de la position */ + + backend = g_object_storage_find_backend(storage, name); + if (backend == NULL) goto exit; + + status = load_uleb128(&pos, backend->fd); + if (!status) goto exit; + + saved = lseek64(backend->fd, 0, SEEK_CUR); + if (saved == (off_t)-1) + { + LOG_ERROR_N("lseek64"); + goto exit; + } + + /* Chargement */ + + result = g_object_storage_load_object_unlocked(storage, name, pos); + + if (result == NULL) goto exit; + + /* Restauration de la position courante */ + + new = lseek64(backend->fd, saved, SEEK_SET); + if (new == (off_t)-1) + { + LOG_ERROR_N("lseek64"); + + g_clear_object(&result); + goto exit; + + } + + assert (new == saved); + + exit: + + g_mutex_unlock(&storage->mutex); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : storage = gestionnaire à manipuler. * +* name = désignation d'un groupe d'objets, nouveau ou non. * +* object = objet sérialisable à traiter. * +* pos = tête de lecture avant écriture. [OUT] * +* * +* Description : Sauvegarde un object sous forme de données rassemblées. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool g_object_storage_store_object(GObjectStorage *storage, const char *name, const GSerializableObject *object, off64_t *pos) +{ + bool result; /* Bilan à retourner */ + storage_backend_t *backend; /* Informations à consulter */ + off64_t tmp; /* Conservation éphémère */ + + result = false; + + g_mutex_lock(&storage->mutex); + + backend = g_object_storage_find_backend(storage, name); + + if (backend == NULL) + g_object_storage_add_backend(storage, name, &backend); + + if (backend != NULL) + { + if (pos == NULL) + pos = &tmp; + + *pos = lseek64(backend->fd, 0, SEEK_CUR); + + if (*pos != (off64_t)-1) + { + result = g_type_memory_store_object_gtype(storage->tpmem, G_OBJECT(object), backend->fd); + + if (result) + result = g_serializable_object_store(object, storage, backend->fd); + + } + + } + + g_mutex_unlock(&storage->mutex); + + return result; + +} diff --git a/src/glibext/storage.h b/src/glibext/storage.h new file mode 100644 index 0000000..ea06ed4 --- /dev/null +++ b/src/glibext/storage.h @@ -0,0 +1,81 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * storage.h - prototypes pour la conservation sur disque d'objets construits + * + * Copyright (C) 2020-2025 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide 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. + * + * Chrysalide 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 Foobar. If not, see <http://www.gnu.org/licenses/>. + */ + + +#ifndef _GLIBEXT_STORAGE_H +#define _GLIBEXT_STORAGE_H + + +#include <stdint.h> + + +#include "helpers.h" +#include "serialize.h" + + + +#define G_TYPE_OBJECT_STORAGE (g_object_storage_get_type()) + +DECLARE_GTYPE(GObjectStorage, g_object_storage, G, OBJECT_STORAGE); + + +/* Crée le support d'une conservation d'objets en place. */ +GObjectStorage *g_object_storage_new(const char *, uint8_t, const char *); + +/* Charge le support d'une conservation d'objets en place. */ +GObjectStorage *g_object_storage_load(const char *); + +/* Sauvegarde le support d'une conservation d'objets en place. */ +bool g_object_storage_store(GObjectStorage *, const char *); + +/* Charge un objet à partir de données rassemblées. */ +GSerializableObject *g_object_storage_load_object(GObjectStorage *, const char *, off64_t); + +/* Charge un objet interne à partir d'une référence embarquée. */ +GSerializableObject *g_object_storage_unpack_object(GObjectStorage *, int, const char *); + +/* Sauvegarde un object sous forme de données rassemblées. */ +bool g_object_storage_store_object(GObjectStorage *, const char *, const GSerializableObject *, off64_t *); + + + + +#if 0 + +/** + * TODO : REMME ? + */ + +#define get_storage_linked_format(s) \ + ({ \ + void*__result; \ + __result = g_object_get_data(G_OBJECT(s), "format"); \ + g_object_ref(G_OBJECT(__result)); \ + __result; \ + }) + +#endif + + + + +#endif /* _GLIBEXT_STORAGE_H */ diff --git a/src/glibext/tpmem-int.h b/src/glibext/tpmem-int.h new file mode 100644 index 0000000..b1b7eec --- /dev/null +++ b/src/glibext/tpmem-int.h @@ -0,0 +1,78 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * tpmem-int.h - définitions internes propres à la mémorisation des types d'objets mis en cache + * + * Copyright (C) 2020-2025 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide 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. + * + * Chrysalide 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 Chrysalide. If not, see <http://www.gnu.org/licenses/>. + */ + + +#ifndef _GLIBEXT_TPMEM_INT_H +#define _GLIBEXT_TPMEM_INT_H + + +#include "tpmem.h" + + +/* Conservation d'une référence sur un type */ +typedef struct _gtype_ref_info_t +{ + GType gtype; /* Type pour la GLib */ + gpointer gclass; /* Lien vers sa classe */ + + /** + * La GLib n'est pas très claire sur la taille de GType comme le montre le + * code issu de <sources>/gobject/gtype.h : + * + * #if GLIB_SIZEOF_SIZE_T != GLIB_SIZEOF_LONG || !defined __cplusplus + * typedef gsize GType; + * #else // for historic reasons, C++ links against gulong GTypes + * typedef gulong GType; + * #endif + * + * Et : + * + * typedef unsigned $glib_size_type_define gsize; + * + * On prend donc le parti de conserver ces types sous forme de valeurs 64 bits + * lors des enregistrements. + */ + +} gtype_ref_info_t; + + +/* Définition d'une mémoire de types d'objets (instance) */ +struct _GTypeMemory +{ + GObject parent; /* A laisser en premier */ + + gtype_ref_info_t *gtypes; /* Types des objets reconnus */ + size_t count; /* Quantité de ces objets */ + GMutex mutex; /* Contrôle d'accès à la liste */ + +}; + +/* Définition d'une mémoire de types d'objets (classe) */ +struct _GTypeMemoryClass +{ + GObjectClass parent; /* A laisser en premier */ + +}; + + + +#endif /* _GLIBEXT_TPMEM_INT_H */ diff --git a/src/glibext/tpmem.c b/src/glibext/tpmem.c new file mode 100644 index 0000000..14b5e33 --- /dev/null +++ b/src/glibext/tpmem.c @@ -0,0 +1,363 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * tpmem.c - mémorisation des types d'objets mis en cache + * + * Copyright (C) 2020-2025 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide 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. + * + * Chrysalide 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 Foobar. If not, see <http://www.gnu.org/licenses/>. + */ + + +#include "tpmem.h" + + +#include <assert.h> + + +#include "tpmem-int.h" +#include "../common/szbin.h" +#include "../core/logs.h" + + + +/* Initialise la classe des mémoires de types d'objets. */ +static void g_type_memory_class_init(GTypeMemoryClass *); + +/* Initialise une instance de mémoire de types d'objets. */ +static void g_type_memory_init(GTypeMemory *); + +/* Supprime toutes les références externes. */ +static void g_type_memory_dispose(GObject *); + +/* Procède à la libération totale de la mémoire. */ +static void g_type_memory_finalize(GObject *); + + + +/* Indique le type défini pour une mémoire de types d'objets. */ +G_DEFINE_TYPE(GTypeMemory, g_type_memory, G_TYPE_OBJECT); + + +/****************************************************************************** +* * +* Paramètres : klass = classe à initialiser. * +* * +* Description : Initialise la classe des mémoires de types d'objets. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_type_memory_class_init(GTypeMemoryClass *klass) +{ + GObjectClass *object; /* Autre version de la classe */ + + object = G_OBJECT_CLASS(klass); + + object->dispose = g_type_memory_dispose; + object->finalize = g_type_memory_finalize; + +} + + +/****************************************************************************** +* * +* Paramètres : tpmem = instance à initialiser. * +* * +* Description : Initialise une instance de mémoire de types d'objets. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_type_memory_init(GTypeMemory *tpmem) +{ + tpmem->gtypes = NULL; + tpmem->count = 0; + g_mutex_init(&tpmem->mutex); + +} + + +/****************************************************************************** +* * +* Paramètres : object = instance d'objet GLib à traiter. * +* * +* Description : Supprime toutes les références externes. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_type_memory_dispose(GObject *object) +{ + GTypeMemory *tpmem; /* Version spécialisée */ + uint64_t i; /* Boucle de parcours */ + + tpmem = G_TYPE_MEMORY(object); + + g_mutex_lock(&tpmem->mutex); + + for (i = 0; i < tpmem->count; i++) + if (tpmem->gtypes[i].gclass != NULL) + g_type_class_unref(tpmem->gtypes[i].gclass); + + g_mutex_unlock(&tpmem->mutex); + + g_mutex_clear(&tpmem->mutex); + + G_OBJECT_CLASS(g_type_memory_parent_class)->dispose(object); + +} + + +/****************************************************************************** +* * +* Paramètres : object = instance d'objet GLib à traiter. * +* * +* Description : Procède à la libération totale de la mémoire. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_type_memory_finalize(GObject *object) +{ + GTypeMemory *tpmem; /* Version spécialisée */ + + tpmem = G_TYPE_MEMORY(object); + + if (tpmem->gtypes != NULL) + free(tpmem->gtypes); + + G_OBJECT_CLASS(g_type_memory_parent_class)->finalize(object); + +} + + +/****************************************************************************** +* * +* Paramètres : - * +* * +* Description : Crée une mémoire pour types d'objets. * +* * +* Retour : Instance mise en place. * +* * +* Remarques : - * +* * +******************************************************************************/ + +GTypeMemory *g_type_memory_new(void) +{ + GTypeMemory *result; /* Structure à retourner */ + + result = g_object_new(G_TYPE_TYPE_MEMORY, NULL); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : tpmem = mémoire à compléter. * +* fd = flux ouvert en lecture. * +* * +* Description : Apprend tous les types mémorisés dans un tampon. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool g_type_memory_load(GTypeMemory *tpmem, int fd) +{ + bool result; /* Bilan à enregistrer */ + uleb128_t count; /* Nombre d'éléments détectés */ + uleb128_t i; /* Boucle de parcours */ + sized_binary_t str; /* Chaîne à charger */ + + result = load_uleb128(&count, fd); + + if (result) + { + g_mutex_lock(&tpmem->mutex); + + tpmem->count = count; + + assert(tpmem->gtypes == NULL); + tpmem->gtypes = calloc(count, sizeof(gtype_ref_info_t)); + + for (i = 0; i < tpmem->count && result; i++) + { + result = load_sized_binary_as_string(&str, fd); + if (!result) break; + + tpmem->gtypes[i].gtype = g_type_from_name(str.data); + result = (tpmem->gtypes[i].gtype != 0); + + if (!result) + log_variadic_message(LMT_ERROR, "Unknown type: '%s'", str.data); + + else + tpmem->gtypes[i].gclass = g_type_class_ref(tpmem->gtypes[i].gtype); + + exit_sized_binary(&str); + + } + + g_mutex_unlock(&tpmem->mutex); + + } + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : tpmem = mémoire à consulter. * +* fd = flux ouvert en écriture. * +* * +* Description : Enregistre tous les types mémorisés dans un tampon. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool g_type_memory_store(GTypeMemory *tpmem, int fd) +{ + bool result; /* Bilan à enregistrer */ + uint64_t i; /* Boucle de parcours */ + const gchar *name; /* Désignation d'un type */ + sized_binary_t str; /* Chaîne à conserver */ + + g_mutex_lock(&tpmem->mutex); + + result = store_uleb128((uleb128_t []){ tpmem->count }, fd); + + for (i = 0; i < tpmem->count && result; i++) + { + name = g_type_name(tpmem->gtypes[i].gtype); + + setup_sized_binary_from_static_string(&str, name); + + store_sized_binary_as_string(&str, fd); + + } + + g_mutex_unlock(&tpmem->mutex); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : tpmem = mémoire à manipuler. * +* fd = flux ouvert en lecture. * +* * +* Description : Crée une nouvelle instance d'objet à partir de son type. * +* * +* Retour : Instance issue de l'opération ou NULL. * +* * +* Remarques : - * +* * +******************************************************************************/ + +GObject *g_type_memory_create_object_from_gtype(GTypeMemory *tpmem, int fd) +{ + GObject *result; /* Nouvelle instance à renvoyer*/ + uleb128_t index; /* Indice du point d'insertion */ + bool status; /* Bilan d'une récupération */ + + result = NULL; + + status = load_uleb128(&index, fd); + + if (status) + { + g_mutex_lock(&tpmem->mutex); + + if (index < tpmem->count) + result = g_object_new(tpmem->gtypes[index].gtype, NULL); + + g_mutex_unlock(&tpmem->mutex); + + } + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : tpmem = mémoire à manipuler. * +* obj = instance dont le type est à mémoriser. * +* fd = flux ouvert en écriture. * +* * +* Description : Sauvegarde le type d'un objet instancié. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool g_type_memory_store_object_gtype(GTypeMemory *tpmem, GObject *obj, int fd) +{ + bool result; /* Bilan à retourner */ + GType gtype; /* Type à enregistrer */ + size_t index; /* Indice du point d'insertion */ + + gtype = G_TYPE_FROM_INSTANCE(obj); + + g_mutex_lock(&tpmem->mutex); + + for (index = 0; index < tpmem->count; index++) + if (tpmem->gtypes[index].gtype == gtype) + break; + + if (index == tpmem->count) + { + tpmem->gtypes = realloc(tpmem->gtypes, ++tpmem->count * sizeof(gtype_ref_info_t)); + + tpmem->gtypes[index].gtype = gtype; + tpmem->gtypes[index].gclass = g_type_class_ref(gtype); + + } + + g_mutex_unlock(&tpmem->mutex); + + result = store_uleb128((uleb128_t []){ index }, fd); + + return result; + +} diff --git a/src/glibext/tpmem.h b/src/glibext/tpmem.h new file mode 100644 index 0000000..ccb8323 --- /dev/null +++ b/src/glibext/tpmem.h @@ -0,0 +1,57 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * tpmem.h - prototypes pour la mémorisation des types d'objets mis en cache + * + * Copyright (C) 2020-2025 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide 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. + * + * Chrysalide 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 Foobar. If not, see <http://www.gnu.org/licenses/>. + */ + + +#ifndef _GLIBEXT_TPMEM_H +#define _GLIBEXT_TPMEM_H + + +#include <stdbool.h> + + +#include "helpers.h" + + + +#define G_TYPE_TYPE_MEMORY (g_type_memory_get_type()) + +DECLARE_GTYPE(GTypeMemory, g_type_memory, G, TYPE_MEMORY); + + +/* Crée une mémoire pour types d'objets. */ +GTypeMemory *g_type_memory_new(void); + +/* Apprend tous les types mémorisés dans un tampon. */ +bool g_type_memory_load(GTypeMemory *, int); + +/* Enregistre tous les types mémorisés dans un tampon. */ +bool g_type_memory_store(GTypeMemory *, int); + +/* Crée une nouvelle instance d'objet à partir de son type. */ +GObject *g_type_memory_create_object_from_gtype(GTypeMemory *, int); + +/* Sauvegarde le type d'un objet instancié. */ +bool g_type_memory_store_object_gtype(GTypeMemory *, GObject *, int); + + + +#endif /* _GLIBEXT_TPMEM_H */ diff --git a/src/glibext/widthtracker.c b/src/glibext/widthtracker.c index 7e06578..0a3dbe6 100644 --- a/src/glibext/widthtracker.c +++ b/src/glibext/widthtracker.c @@ -330,13 +330,17 @@ void g_width_tracker_set_column_min_width(GWidthTracker *tracker, size_t col, in void g_width_tracker_compute_width(const GWidthTracker *tracker, int *width) { + size_t col_count; /* Nombre maximum de colonnes */ size_t i; /* Boucle de parcours */ *width = 0; - // FIX access to col_count - for (i = 0; i < tracker->col_count; i++) + + col_count = tracker->opt_count + tracker->reg_count; + + + for (i = 0; i < col_count; i++) *width += tracker->min_widths[i]; } |