diff options
Diffstat (limited to 'src')
287 files changed, 26276 insertions, 17438 deletions
diff --git a/src/Makefile.am b/src/Makefile.am index 1250b59..7411287 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -1,7 +1,7 @@  lib_LTLIBRARIES = libchrysacore4.la libchrysacoreui.la # libchrysacore.la -bin_PROGRAMS = framework # chrysalide chrysalide-hub rost +bin_PROGRAMS = chrysalide # chrysalide-hub rost  AM_CPPFLAGS = -I$(top_srcdir) -I$(top_srcdir)/intl @@ -39,18 +39,18 @@ GUI_SUBDIR =								\  endif -libchrysacore_la_LIBADD =					\ -	analysis/libanalysis.la					\ -	arch/libarch.la							\ -	common/libcommon.la						\ -	core/libcore.la							\ -	debug/libdebug.la						\ -	format/libformat.la						\ -	glibext/libglibext.la					\ -	$(GTKEXT_LIBADD)						\ -	$(GUI_LIBADD)							\ -	mangling/libmangling.la					\ -	plugins/libplugins.la +# libchrysacore_la_LIBADD =					\ +# 	analysis/libanalysis.la					\ +# 	arch/libarch.la							\ +# 	common/libcommon.la						\ +# 	core/libcore.la							\ +# 	debug/libdebug.la						\ +# 	format/libformat.la						\ +# 	glibext/libglibext.la					\ +# 	$(GTKEXT_LIBADD)						\ +# 	$(GUI_LIBADD)							\ +# 	mangling/libmangling.la					\ +# 	plugins/libplugins.la  # -ldl: dladdr(), dlerror() @@ -59,7 +59,7 @@ libchrysacore_la_LDFLAGS =					\  	-avoid-version -ldl -lm					\  	$(TOOLKIT_LIBS) $(LIBXML_LIBS)			\  	$(LIBSQLITE_LIBS) $(LIBARCHIVE_LIBS)	\ -	$(LIBSSL_LIBS)  $(LIBHS_LIBS) +	$(LIBSSL_LIBS)  if BUILD_CURL_SUPPORT @@ -73,19 +73,32 @@ libchrysacore_la_LDFLAGS += $(LIBMAGIC_LIBS)  endif +if BUILD_HS_SUPPORT + +libchrysacore_la_LDFLAGS += $(LIBHS_LIBS) + +endif +  libchrysacore4_la_SOURCES =  libchrysacore4_la_LIBADD =					\  	analysis/libanalysis4.la				\ -	arch/libarch4.la						\ +	arch/libarch.la							\  	common/libcommon4.la					\  	core/libcore4.la						\ -	glibext/libglibext4.la					\ +	format/libformat.la						\ +	glibext/libglibext.la					\  	plugins/libplugins.la  libchrysacore4_la_LDFLAGS =					\ -	$(TOOLKIT_LIBS) $(LIBSSL_LIBS) +	$(TOOLKIT_LIBS) $(LIBSSL_LIBS) $(LIBJSONGLIB_LIBS) $(LIBZIP_LIBS) + +if BUILD_CURL_SUPPORT + +libchrysacore4_la_LDFLAGS += $(LIBCURL_LIBS) + +endif  #--- libchrysacoreui @@ -95,13 +108,15 @@ EXTRA_libchrysacoreui_la_DEPENDENCIES = libchrysacore4.la  libchrysacoreui_la_SOURCES =  libchrysacoreui_la_LIBADD =					\ +	arch/libarchui.la						\ +	data/images/libdataimages.la			\  	glibext/libglibextui.la					\  	gtkext/libgtkext4.la					\  	gui/libgui4.la  # -lm: log()  libchrysacoreui_la_LDFLAGS =				\ -	$(LIBGTK4_CFLAGS) -L.libs -lchrysacore4	\ +	$(LIBGTK4_LIBS) -L.libs -lchrysacore4	\  	-lm @@ -111,33 +126,33 @@ libchrysacoreui_la_LDFLAGS =				\  # Programme principal  ############################################################ -EXTRA_chrysalide_DEPENDENCIES = libchrysacore.la +EXTRA_chrysalide0_DEPENDENCIES = libchrysacore.la -chrysalide_SOURCES = 					\ +chrysalide0_SOURCES = 					\  	$(GOBJECT_LEAKS_SOURCES)			\  	main.c -chrysalide_CFLAGS = $(TOOLKIT_CFLAGS) $(LIBXML_CFLAGS) $(LIBPYTHON_CFLAGS) +chrysalide0_CFLAGS = $(TOOLKIT_CFLAGS) $(LIBXML_CFLAGS) $(LIBPYTHON_CFLAGS) -chrysalide_LDFLAGS = $(TOOLKIT_LIBS) -L/usr/X11R6/lib -ldl -lm $(LIBXML_LIBS) $(LIBPYTHON_LIBS) $(LIBARCHIVE_LIBS) $(LIBSQLITE_LIBS) \ +chrysalide0_LDFLAGS = $(TOOLKIT_LIBS) -L/usr/X11R6/lib -ldl -lm $(LIBXML_LIBS) $(LIBPYTHON_LIBS) $(LIBARCHIVE_LIBS) $(LIBSQLITE_LIBS) \  	-L.libs -lchrysacore -chrysalide_LDADD = $(LIBINTL) +chrysalide0_LDADD = $(LIBINTL) -EXTRA_framework_DEPENDENCIES = libchrysacore4.la libchrysacoreui.la +EXTRA_chrysalide_DEPENDENCIES = libchrysacore4.la libchrysacoreui.la -framework_SOURCES = 						\ -	framework.h framework.c +chrysalide_SOURCES = 						\ +	app.h app.c -framework_CFLAGS = $(TOOLKIT4_CFLAGS) +chrysalide_CFLAGS = $(TOOLKIT4_CFLAGS) $(LIBGIOUNIX_CFLAGS) -framework_LDFLAGS = $(TOOLKIT4_LIBS) \ +chrysalide_LDFLAGS = $(TOOLKIT4_LIBS) $(LIBGIOUNIX_LIBS) \  	-L.libs -lchrysacore4 -lchrysacoreui -framework_LDADD = +chrysalide_LDADD = @@ -181,4 +196,4 @@ rost_LDFLAGS = $(LIBGOBJ_LIBS) -L.libs -lchrysacore  #SUBDIRS = core glibext $(GTKEXT_SUBDIR) analysis arch format common debug $(GUI_SUBDIR) mangling plugins schemas -SUBDIRS = analysis arch common core glibext gtkext gui plugins +SUBDIRS = analysis arch common core data format glibext gtkext gui plugins schemas diff --git a/src/analysis/contents/encapsulated.c b/src/analysis/contents/encapsulated.c index 451c340..22b61c0 100644 --- a/src/analysis/contents/encapsulated.c +++ b/src/analysis/contents/encapsulated.c @@ -30,8 +30,8 @@  #include "encapsulated-int.h"  #include "../db/misc/rlestr.h" -#include "../storage/serialize-int.h"  #include "../../common/extstr.h" +#include "../../glibext/serialize-int.h" diff --git a/src/analysis/contents/file.c b/src/analysis/contents/file.c index 791f8b6..125016c 100644 --- a/src/analysis/contents/file.c +++ b/src/analysis/contents/file.c @@ -35,8 +35,8 @@  #include "file-int.h"  #include "../db/misc/rlestr.h" -#include "../storage/serialize-int.h"  #include "../../core/logs.h" +#include "../../glibext/serialize-int.h" diff --git a/src/analysis/contents/memory.c b/src/analysis/contents/memory.c index f7d2bd0..c6ccb5b 100644 --- a/src/analysis/contents/memory.c +++ b/src/analysis/contents/memory.c @@ -34,11 +34,10 @@  #include "memory-int.h" -#include "../content-int.h"  #include "../db/misc/rlestr.h" -#include "../storage/serialize-int.h"  #include "../../common/extstr.h"  #include "../../core/logs.h" +#include "../../glibext/serialize-int.h" @@ -337,6 +336,7 @@ bool g_memory_content_create(GMemoryContent *content, const bin_t *data, phys_t      if (allocated == NULL)      {          LOG_ERROR_N("malloc"); +        result = false;          goto exit;      } diff --git a/src/analysis/contents/restricted.c b/src/analysis/contents/restricted.c index 95f513b..6f091ae 100644 --- a/src/analysis/contents/restricted.c +++ b/src/analysis/contents/restricted.c @@ -30,9 +30,9 @@  #include "restricted-int.h"  #include "../db/misc/rlestr.h" -#include "../storage/serialize-int.h"  #include "../../common/extstr.h"  #include "../../core/logs.h" +#include "../../glibext/serialize-int.h" diff --git a/src/analysis/scan/patterns/backends/Makefile.am b/src/analysis/scan/patterns/backends/Makefile.am index 23b0163..84711a7 100644 --- a/src/analysis/scan/patterns/backends/Makefile.am +++ b/src/analysis/scan/patterns/backends/Makefile.am @@ -6,10 +6,16 @@ libanalysisscanpatternsbackends_la_SOURCES =	\  	acism-int.h								\  	acism.h acism.c							\  	bitap-int.h								\ -	bitap.h bitap.c							\ +	bitap.h bitap.c + +if BUILD_HS_SUPPORT + +libanalysisscanpatternsbackends_la_SOURCES +=	\  	hyperscan-int.h							\  	hyperscan.h hyperscan.c +endif +  # Cf. https://www.gnu.org/software/automake/manual/html_node/Per_002dObject-Flags.html  AM_CFLAGS = $(LIBGOBJ_CFLAGS) $(LIBHS_CFLAGS) diff --git a/src/analysis/storage/Makefile.am b/src/analysis/storage/Makefile.am index 3eb287b..dad7411 100644 --- a/src/analysis/storage/Makefile.am +++ b/src/analysis/storage/Makefile.am @@ -6,12 +6,7 @@ libanalysisstorage_la_SOURCES =				\  	cache-int.h								\  	cache.h cache.c							\  	container-int.h							\ -	container.h container.c					\ -	serialize-int.h							\ -	serialize.h serialize.c					\ -	storage-int.h							\ -	storage.h storage.c						\ -	tpmem.h tpmem.c +	container.h container.c  libanalysisstorage_la_CFLAGS = $(TOOLKIT_CFLAGS) $(LIBXML_CFLAGS) diff --git a/src/analysis/storage/serialize.h b/src/analysis/storage/serialize.h deleted file mode 100644 index 93a4496..0000000 --- a/src/analysis/storage/serialize.h +++ /dev/null @@ -1,64 +0,0 @@ - -/* Chrysalide - Outil d'analyse de fichiers binaires - * serialize.h - prototypes pour les objets entreposables dans un cache - * - * Copyright (C) 2020 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 _ANALYSIS_STORAGE_SERIALIZE_H -#define _ANALYSIS_STORAGE_SERIALIZE_H - - -#include <glib-object.h> - - -#include "../../common/packed.h" - - - -#define G_TYPE_SERIALIZABLE_OBJECT             g_serializable_object_get_type() -#define G_SERIALIZABLE_OBJECT(obj)             (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_SERIALIZABLE_OBJECT, GSerializableObject)) -#define G_SERIALIZABLE_OBJECT_CLASS(vtable)    (G_TYPE_CHECK_CLASS_CAST((vtable), G_TYPE_SERIALIZABLE_OBJECT, GSerializableObjectIface)) -#define G_IS_SERIALIZABLE_OBJECT(obj)          (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_SERIALIZABLE_OBJECT)) -#define G_IS_SERIALIZABLE_OBJECT_CLASS(vtable) (G_TYPE_CHECK_CLASS_TYPE((vtable), G_TYPE_SERIALIZABLE_OBJECT)) -#define G_SERIALIZABLE_OBJECT_GET_IFACE(inst)  (G_TYPE_INSTANCE_GET_INTERFACE((inst), G_TYPE_SERIALIZABLE_OBJECT, GSerializableObjectIface)) - - -/* Intermédiaire pour la mise en cache d'objet (coquille vide) */ -typedef struct _GSerializableObject GSerializableObject; - -/* Intermédiaire pour la mise en cache d'objet (interface) */ -typedef struct _GSerializableObjectIface GSerializableObjectIface; - - -/* Détermine le type d'une interface pour la mise en cache d'objet. */ -GType g_serializable_object_get_type(void) G_GNUC_CONST; - -/* storage.h : définition d'une conservation d'objets construits */ -typedef struct _GObjectStorage GObjectStorage; - -/* Charge un objet depuis une mémoire tampon. */ -bool g_serializable_object_load(GSerializableObject *, GObjectStorage *, packed_buffer_t *); - -/* Sauvegarde un objet dans une mémoire tampon. */ -bool g_serializable_object_store(const GSerializableObject *, GObjectStorage *, packed_buffer_t *); - - - -#endif  /* _ANALYSIS_STORAGE_SERIALIZE_H */ diff --git a/src/analysis/storage/tpmem.h b/src/analysis/storage/tpmem.h deleted file mode 100644 index 34cbde6..0000000 --- a/src/analysis/storage/tpmem.h +++ /dev/null @@ -1,70 +0,0 @@ - -/* Chrysalide - Outil d'analyse de fichiers binaires - * tpmem.h - prototypes pour la mémorisation des types d'objets mis en cache - * - * Copyright (C) 2020 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 _ANALYSIS_STORAGE_TPMEM_H -#define _ANALYSIS_STORAGE_TPMEM_H - - -#include <glib-object.h> - - -#include "../../common/packed.h" - - - -#define G_TYPE_TYPE_MEMORY            g_type_memory_get_type() -#define G_TYPE_MEMORY(obj)            (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_TYPE_MEMORY, GTypeMemory)) -#define G_IS_TYPE_MEMORY(obj)         (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_TYPE_MEMORY)) -#define G_TYPE_MEMORY_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_TYPE_MEMORY, GTypeMemoryClass)) -#define G_IS_TYPE_MEMORY_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_TYPE_MEMORY)) -#define G_TYPE_MEMORY_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_TYPE_MEMORY, GTypeMemoryClass)) - - -/* Définition d'une mémoire de types d'objets (instance) */ -typedef struct _GTypeMemory GTypeMemory; - -/* Définition d'une mémoire de types d'objets (classe) */ -typedef struct _GTypeMemoryClass GTypeMemoryClass; - - -/* Indique le type défini pour une mémoire de types d'objets. */ -GType g_type_memory_get_type(void); - -/* 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_types(GTypeMemory *, packed_buffer_t *); - -/* Crée une nouvelle instance d'objet à partir de son type. */ -GObject *g_type_memory_create_object(GTypeMemory *, packed_buffer_t *); - -/* Sauvegarde le type d'un objet instancié. */ -bool g_type_memory_store_object_gtype(GTypeMemory *, GObject *, packed_buffer_t *); - -/* Enregistre tous les types mémorisés dans un tampon. */ -bool g_type_memory_store_types(GTypeMemory *, packed_buffer_t *); - - - -#endif  /* _ANALYSIS_STORAGE_TPMEM_H */ diff --git a/src/framework.c b/src/app.c index 96c97c3..ef62135 100644 --- a/src/framework.c +++ b/src/app.c @@ -1,6 +1,6 @@  /* Chrysalide - Outil d'analyse de fichiers binaires - * framework.c - fichier d'entrée du programme + * app.c - fichier d'entrée du programme   *   * Copyright (C) 2024 Cyrille Bagard   * @@ -22,15 +22,24 @@   */ +#include <assert.h> +#include <fcntl.h> +#include <getopt.h> +#include <libgen.h> +#include <string.h> +#include <gio/gdesktopappinfo.h> +#include <gio/gio.h> +#include <sys/auxv.h> -#include <gtk/gtk.h> - -#include "framework.h" -#include "glibext/helpers.h" +#include "app.h" +#include "common/io.h" +#include "common/xdg.h" +#include "core/core.h" +#include "core/logs.h"  #include "gui/core/core.h" -#include "analysis/contents/file.h" // REMME -#include "gtkext/hexview.h" // REMME +#include "gui/window.h" +#include "plugins/pglist.h" @@ -42,8 +51,6 @@ struct _GtkChrysalideFramework  {      GtkApplication parent;                  /* A laisser en premier        */ -    GSettings *settings;                    /* Paramètres globaux          */ -      GtkApplicationWindow *main_window;      /* Fenêtre principale          */  }; @@ -78,6 +85,20 @@ static void gtk_chrysalide_framework_activate(GApplication *); +/* ---------------------- POINT D'ENTREE PRINCIPAL D'EXECUTION ---------------------- */ + + +/* Affiche des indications quant à l'utilisation du programme. */ +static void show_chrysalide_help(const char *); + +/* Affiche des indications sur la version courante du programme. */ +static void show_chrysalide_version(void); + +/* Installe au besoin une définition locale pour le système. */ +static void ensure_wm_icon_and_name(void); + + +  /* ---------------------------------------------------------------------------------- */  /*                       DEFINITION D'APPLICATION PERSONNALISEE                       */  /* ---------------------------------------------------------------------------------- */ @@ -131,8 +152,6 @@ static void gtk_chrysalide_framework_class_init(GtkChrysalideFrameworkClass *kla  static void gtk_chrysalide_framework_init(GtkChrysalideFramework *app)  { -    app->settings = NULL; -      app->main_window = NULL;  } @@ -152,8 +171,6 @@ static void gtk_chrysalide_framework_init(GtkChrysalideFramework *app)  static void gtk_chrysalide_framework_dispose(GtkChrysalideFramework *app)  { -    g_clear_object(&app->settings); -      g_clear_object(&app->main_window);      G_OBJECT_CLASS(gtk_chrysalide_framework_parent_class)->dispose(G_OBJECT(app)); @@ -197,7 +214,7 @@ GtkChrysalideFramework *gtk_chrysalide_framework_new(void)      GtkChrysalideFramework *result;         /* Instance à retourner        */      result = g_object_new(GTK_TYPE_CHRYSALIDE_FRAMEWORK, -                          "application-id", "re.chrysalide.framework", +                          "application-id", FRAMEWORK_WINDOW_ID,                            "flags", G_APPLICATION_DEFAULT_FLAGS,                            NULL); @@ -227,104 +244,183 @@ GtkChrysalideFramework *gtk_chrysalide_framework_new(void)  static void gtk_chrysalide_framework_activate(GApplication *app)  {      GtkChrysalideFramework *real_app;       /* Version réelle de l'instance*/ -    GSettings *settings;                    /* Paramètres globaux          */ -    GtkWindow *window;                      /* Fenêtre mise en place       */ -    GtkCssProvider *css;                    /* Feuille de style maison     */      real_app = GTK_CHRYSALIDE_FRAMEWORK(app); -    /* Paramètres globaux */ +    real_app->main_window = gtk_framework_window_new(GTK_APPLICATION(app)); +    g_object_ref(G_OBJECT(real_app->main_window)); + +    gtk_window_present(GTK_WINDOW(real_app->main_window)); + +} + + + +/* ---------------------------------------------------------------------------------- */ +/*                        POINT D'ENTREE PRINCIPAL D'EXECUTION                        */ +/* ---------------------------------------------------------------------------------- */ + + +/****************************************************************************** +*                                                                             * +*  Paramètres  : name = nom du programme en question.                         * +*                                                                             * +*  Description : Affiche des indications quant à l'utilisation du programme.  * +*                                                                             * +*  Retour      : -                                                            * +*                                                                             * +*  Remarques   : -                                                            * +*                                                                             * +******************************************************************************/ -    settings = g_settings_new("re.chrysalide.framework.mainapp"); -    real_app->settings = settings; +static void show_chrysalide_help(const char *name) +{ +    char *tmp;                              /* Conservation modifiable     */ +    char *base;                             /* Version courte du nom       */ -    /* Fenêtre principale */ +    tmp = strdup(name); -    window = GTK_WINDOW(gtk_application_window_new(GTK_APPLICATION(app))); +    base = basename(tmp); -    real_app->main_window = GTK_APPLICATION_WINDOW(window); -    g_object_ref(G_OBJECT(window)); +    printf("\n"); -    g_settings_bind(settings, "window-width", G_OBJECT(window), "default-width", G_SETTINGS_BIND_DEFAULT); -    g_settings_bind(settings, "window-height", G_OBJECT(window), "default-height", G_SETTINGS_BIND_DEFAULT); -    g_settings_bind(settings, "window-maximized", G_OBJECT(window), "maximized", G_SETTINGS_BIND_DEFAULT); +    printf("Usage: %s [--help] [--version]\n", base); +    printf("       %s [args] <filename(s)...>\n", base); -    gtk_window_set_title(window, "Chrysalide"); -    gtk_window_present(window); +    free(tmp); +    printf("\n"); -    do -    { -        GBinContent *cnt; +    printf("\t-h --help\t\tShow this help message.\n"); +    printf("\t-v --version\t\tDisplay the program version.\n"); -        GtkWidget *parent; -        GtkHexView *wgt; +    printf("\n"); +    printf("\t-V --verbosity=level\tSet the log level (0 for all messages, %u for none).\n", LMT_COUNT); -#if 0 +    printf("\n"); -        cnt = g_file_content_new("tmp.bin"); +} -        parent = gtk_box_new(GTK_ORIENTATION_VERTICAL, 5); -        gtk_box_set_homogeneous(GTK_BOX(parent), FALSE); -        gtk_window_set_child(window, parent); -        wgt = gtk_hex_view_new(cnt); -        gtk_box_append(GTK_BOX(parent), GTK_WIDGET(wgt)); +/****************************************************************************** +*                                                                             * +*  Paramètres  : -                                                            * +*                                                                             * +*  Description : Affiche des indications sur la version courante du programme.* +*                                                                             * +*  Retour      : -                                                            * +*                                                                             * +*  Remarques   : -                                                            * +*                                                                             * +******************************************************************************/ -        wgt = gtk_hex_view_new(cnt); -        gtk_box_append(GTK_BOX(parent), GTK_WIDGET(wgt)); +static void show_chrysalide_version(void) +{ +    printf("\n"); -#else +    printf("-o-  Chrysalide r%u  -o-\n", REVISION); +    printf(_("Compiled on %s at %s\n"), __DATE__, __TIME__); -        cnt = g_file_content_new("/bin/id"); -        //cnt = g_file_content_new("tmp.bin"); +    printf("\n"); +} -        parent = gtk_scrolled_window_new(); -        gtk_window_set_child(window, parent); -        wgt = gtk_hex_view_new(cnt); -        gtk_scrolled_window_set_child(GTK_SCROLLED_WINDOW(parent), GTK_WIDGET(wgt)); +/****************************************************************************** +*                                                                             * +*  Paramètres  : -                                                            * +*                                                                             * +*  Description : Installe au besoin une définition locale pour le système.    * +*                                                                             * +*  Retour      : -                                                            * +*                                                                             * +*  Remarques   : -                                                            * +*                                                                             * +******************************************************************************/ -#endif +static void ensure_wm_icon_and_name(void) +{ +    GDesktopAppInfo *info;                  /* Information du système      */ +    GKeyFile *kfile;                        /* Définition d'application    */ +    unsigned long exec_path;                /* Chemin du programme         */ +    char *filename;                         /* Nom de fichier à écrire     */ +    GBytes *res;                            /* Données brutes d'une image  */ +    gsize size;                             /* Taille de ces données       */ +    gconstpointer data;                     /* Pointeur vers les données   */ +    int fd;                                 /* Flux ouvert en écriture     */ +    /* Evaluation du besoin */ +    info = g_desktop_app_info_new(FRAMEWORK_WINDOW_ID ".desktop"); +    /** +     * Si l'exécutable n'est pas valide (inconnu de $PATH), +     * la variable info n'est pas initialisée. +     */ +    if (info != NULL) +    { +        unref_object(info); +        goto done;      } -    while (0); +    /* Mise en place d'une définition d'application */ -    /* Chargement des extensions de thème */ +    exec_path = getauxval(AT_EXECFN); +    assert(exec_path != 0); -    /* -    css = gtk_css_provider_new(); +    kfile = g_key_file_new(); -    gtk_css_provider_load_from_resource(css, "/re/chrysalide/framework/glibext/linestyle.css"); +    g_key_file_set_string(kfile, "Desktop Entry", "Name", "Chrysalide"); +    g_key_file_set_string(kfile, "Desktop Entry", "Comment[fr]", "Cadriciel de rétronception ciblant principalement les systèmes embarqués"); +    g_key_file_set_string(kfile, "Desktop Entry", "Comment", "Reverse Engineering Framework focused on embedded systems"); +    g_key_file_set_string(kfile, "Desktop Entry", "Type", "Application"); +    g_key_file_set_string(kfile, "Desktop Entry", "Exec", (const char *)exec_path); +    g_key_file_set_string(kfile, "Desktop Entry", "Icon", "chrysalide-logo"); +    g_key_file_set_string(kfile, "Desktop Entry", "StartupNotify", "true"); +    g_key_file_set_string(kfile, "Desktop Entry", "MimeType", "application/vnd.android.package-archive"); -    gtk_style_context_add_provider_for_display(gtk_widget_get_display(GTK_WIDGET(window)), -                                               GTK_STYLE_PROVIDER(css), GTK_STYLE_PROVIDER_PRIORITY_APPLICATION); +    filename = get_xdg_data_dir("applications/re.chrysalide.framework.gui.desktop", true); -    unref_object(css); -    */ +    g_key_file_save_to_file(kfile, filename, NULL); -    css = gtk_css_provider_new(); +    free(filename); -    gtk_css_provider_load_from_resource(css, "/re/chrysalide/framework/gtkext/hexview.css"); +    g_key_file_free(kfile); -    gtk_style_context_add_provider_for_display(gtk_widget_get_display(GTK_WIDGET(window)), -                                               GTK_STYLE_PROVIDER(css), GTK_STYLE_PROVIDER_PRIORITY_APPLICATION); +    /* Ecriture de l'image */ -    unref_object(css); +    res = g_resources_lookup_data("/re/chrysalide/framework/images/chrysalide-logo.svg", +                                  G_RESOURCE_LOOKUP_FLAGS_NONE, NULL); +    assert(res != NULL); -} +    data = g_bytes_get_data(res, &size); +    filename = get_xdg_data_dir("icons/hicolor/scalable/apps/chrysalide-logo.svg", true); +    fd = open(filename, O_WRONLY | O_CREAT, S_IRUSR | S_IWUSR); -/* ---------------------------------------------------------------------------------- */ -/*                        POINT D'ENTREE PRINCIPAL D'EXECUTION                        */ -/* ---------------------------------------------------------------------------------- */ +    if (fd == -1) +        LOG_ERROR_N("open"); + +    else +    { +        safe_write(fd, data, size); +        close(fd); +    } + +    free(filename); + +    g_bytes_unref(res); + +    /* Sortie */ + + done: + +    ; + +}  /****************************************************************************** @@ -343,18 +439,125 @@ static void gtk_chrysalide_framework_activate(GApplication *app)  int main(int argc, char **argv)  {      int result;                             /* Bilan de l'exécution        */ +    bool show_help;                         /* Affichage de l'aide ?       */ +    bool show_version;                      /* Affichage de la version ?   */ +    LogMessageType verbosity;               /* Niveau de filtre de message */ +    int index;                              /* Indice d'argument           */ +    int ret;                                /* Bilan d'un appel            */      GtkChrysalideFramework *app;            /* Gestion d'application GTK   */ -    if (!load_gui_components(AGC_BUFFER_FEATURES)) -        return EXIT_FAILURE; +    static struct option long_options[] = { +        { "help",       no_argument,        NULL,   'h' }, +        { "version",    no_argument,        NULL,   'v' }, +        { "verbosity",  required_argument,  NULL,   'V' }, +        { NULL,         0,                  NULL,   0 } +    }; + +    result = EXIT_FAILURE; + +    /* Décodage des options */ + +    show_help = false; +    show_version = false; + +    verbosity = LMT_COUNT; + +    while (true) +    { +        ret = getopt_long(argc, argv, "hvV:", long_options, &index); +        if (ret == -1) break; + +        switch (ret) +        { +            case 'h': +                show_help = true; +                break; + +            case 'v': +                show_version = true; +                break; + +            case 'V': +                verbosity = strtoul(optarg, NULL, 10); +                break; + +        } + +    } + +    /* Actions de base */ + +    if (show_help) +    { +        show_chrysalide_help(argv[0]); +        result = EXIT_SUCCESS; +        goto exit; +    } + +    if (show_version) +    { +        show_chrysalide_version(); +        result = EXIT_SUCCESS; +        goto exit; +    } + +    /* Lancement des choses sérieuses */ + +    set_log_verbosity(verbosity); + +    /** +     * Même s'il est dit que l'usage de GtkApplication permet de s'affranchir +     * d'un appel à gtk_init(), il se trouve que la journalisation en mode +     * graphique peut solliciter le panneau en GTK pour afficher des messages +     * avant la mise en place de l'applicatif GTK principal : +     * +     * #2  0x00007ffff7b33403 in gtk_css_lookup_resolve (lookup=lookup@entry=0x7fffffff88a0, provider=provider@entry=0x0, sstyle=sstyle@entry=0x7fffe800a730, parent_style=parent_style@entry=0x0) at ../gtk/gtkcssstaticstyle.c:911 +     * #3  0x00007ffff7b3389f in gtk_css_static_style_new_compute (provider=0x0, filter=filter@entry=0x7fffffff8ea0, node=node@entry=0x0, change=<optimized out>, change@entry=0) at ../gtk/gtkcssstaticstyle.c:1026 +     * #4  0x00007ffff7b3392c in gtk_css_static_style_get_default () at ../gtk/gtkcssstaticstyle.c:711 +     * #5  0x00007ffff7b24b09 in gtk_css_node_init (cssnode=0x7fffe800a5b0) at ../gtk/gtkcssnode.c:641 +     * #6  0x00007ffff75d8dab in g_type_create_instance () at /lib/x86_64-linux-gnu/libgobject-2.0.so.0 +     * [...] +     * #10 0x00007ffff7b3b8fa in gtk_css_widget_node_new (widget=widget@entry=0x5555555bf1b0) at ../gtk/gtkcsswidgetnode.c:160 +     * #11 0x00007ffff7ae4576 in gtk_widget_init (instance=<optimized out>, g_class=0x5555555be380) at ../gtk/gtkwidget.c:2345 +     * [...] +     * #16 0x00007ffff73fd3f4 in get_framework_panel_singleton (...) at panels.c:329 +     * #17 0x00007ffff73fce35 in do_log_message_alt (...) at logs.c:56 +     * [...] +     * #23 0x00007ffff74566db in init_all_plugins (load=true) at pglist.c:103 +     * #24 0x0000555555556d44 in main (argc=2, argv=0x7fffffffb568) at app.c:514 +     * +     * L'initialisation permettant un retour de gtk_settings_get_default() non +     * nul est ainsi forcée au plus tôt avec un appel à gtk_init() manuel. +     */ +    gtk_init(); + +    if (!load_core_components(ACC_GLOBAL_VARS)) +        goto exit; + +    if (!load_gui_components(AGC_BUFFER_FEATURES | AGC_PANELS)) +        goto exit_with_core; + +    init_all_plugins(true); + +    ensure_wm_icon_and_name(); + +    g_set_prgname("Chrysalide");      app = gtk_chrysalide_framework_new(); -    result = g_application_run(G_APPLICATION(app), argc, argv); +    result = g_application_run(G_APPLICATION(app), 0, NULL);      g_object_unref(G_OBJECT(app)); -    unload_gui_components(AGC_BUFFER_FEATURES); +    exit_all_plugins(); + +    unload_gui_components(AGC_BUFFER_FEATURES | AGC_PANELS); + + exit_with_core: + +    unload_core_components(ACC_GLOBAL_VARS); + + exit:      return result; diff --git a/src/app.h b/src/app.h new file mode 100644 index 0000000..645fa6b --- /dev/null +++ b/src/app.h @@ -0,0 +1,56 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * app.h - prototypes pour le fichier d'entrée du programme + * + * Copyright (C) 2024 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 _APP_H +#define _APP_H + + +#include <gtk/gtk.h> + + +#include "glibext/helpers.h" + + + +/* --------------------- DEFINITION D'APPLICATION PERSONNALISEE --------------------- */ + + +#define GTK_TYPE_CHRYSALIDE_FRAMEWORK (gtk_chrysalide_framework_get_type()) + +DECLARE_GTYPE(GtkChrysalideFramework, gtk_chrysalide_framework, GTK, CHRYSALIDE_FRAMEWORK); + + +/* Crée une nouvelle application principale pour Chrysalide. */ +GtkChrysalideFramework *gtk_chrysalide_framework_new(void); + + + +/* ---------------------- POINT D'ENTREE PRINCIPAL D'EXECUTION ---------------------- */ + + +/* Point d'entrée du programme. */ +int main(int, char **); + + + +#endif  /* _APP_H */ diff --git a/src/arch/Makefile.am b/src/arch/Makefile.am index 6ee2690..6683854 100644 --- a/src/arch/Makefile.am +++ b/src/arch/Makefile.am @@ -1,43 +1,57 @@ -noinst_LTLIBRARIES = libarch4.la # libarch.la +noinst_LTLIBRARIES = libarch.la libarchui.la + +# libarch_la_SOURCES =						\ +# 	archbase.h archbase.c					\ +# 	context-int.h							\ +# 	context.h context.c						\ +# 	instriter.h instriter.c					\ +# 	link.h link.c							\ +# 	post.h post.c							\ +# 	storage.h storage.c + +# libarch_la_CFLAGS = $(TOOLKIT_CFLAGS) $(LIBXML_CFLAGS) + +# libarch_la_LIBADD =							\ +# 	operands/libarchoperands.la + + +# +# 	processor-int.h							\ +#	processor.h processor.c					\ +#  libarch_la_SOURCES =						\ -	archbase.h archbase.c					\ -	context-int.h							\ -	context.h context.c						\ -	instriter.h instriter.c					\  	instruction-int.h						\  	instruction.h instruction.c				\ -	link.h link.c							\ -	operand-int.h operand-int.c				\ +	operand-int.h							\  	operand.h operand.c						\ -	post.h post.c							\ -	processor-int.h							\ -	processor.h processor.c					\  	register-int.h							\  	register.h register.c					\ -	storage.h storage.c						\  	vmpa.h vmpa.c -libarch_la_CFLAGS = $(TOOLKIT_CFLAGS) $(LIBXML_CFLAGS) +libarch_la_CFLAGS = $(LIBGOBJ_CFLAGS)  libarch_la_LIBADD =							\  	instructions/libarchinstructions.la		\  	operands/libarchoperands.la -libarch4_la_SOURCES =						\ -	vmpa.h vmpa.c +libarchui_la_SOURCES =						\ +	instruction-ui-int.h					\ +	instruction-ui.h instruction-ui.c		\ +	operand-ui-int.h						\ +	operand-ui.h operand-ui.c -libarch4_la_CFLAGS = $(TOOLKIT_CFLAGS) +libarchui_la_CFLAGS = $(LIBGTK_CFLAGS) -libarch4_la_LIBADD = +libarchui_la_LIBADD =						\ +	operands/libarchoperandsui.la  devdir = $(includedir)/chrysalide/$(subdir:src/%=core/%) -dev_HEADERS = $(libarch_la_SOURCES:%c=) - +dev_HEADERS = $(libarch_la_SOURCES:%c=) $(libarchui_la_SOURCES:%c=) -#SUBDIRS = instructions operands +SUBDIRS = instructions operands diff --git a/src/arch/archbase.h b/src/arch/archbase.h index 59bf18e..b29d2a1 100644 --- a/src/arch/archbase.h +++ b/src/arch/archbase.h @@ -50,6 +50,7 @@ typedef uint64_t vmpa_t;  #define VMPA_MAX_SIZE   19 +#if 0  /* Taille des données intégrées */  typedef enum _MemoryDataSize  { @@ -68,6 +69,7 @@ typedef enum _MemoryDataSize      MDS_64_BITS_SIGNED      = 0x85          /* Opérande sur 64 bits signés */  } MemoryDataSize; +#endif  #define MDS_RANGE(mds) ((mds & 0xf) - 1) @@ -99,13 +101,13 @@ typedef enum _MemoryDataSize          __result;                                   \      }) - +#if 0  #define MDS_4_BITS  MDS_4_BITS_UNSIGNED  #define MDS_8_BITS  MDS_8_BITS_UNSIGNED  #define MDS_16_BITS MDS_16_BITS_UNSIGNED  #define MDS_32_BITS MDS_32_BITS_UNSIGNED  #define MDS_64_BITS MDS_64_BITS_UNSIGNED - +#endif  /* Etablit la comparaison entre deux adresses. */ diff --git a/src/arch/instruction-int.h b/src/arch/instruction-int.h index 7dbbe27..d426cea 100644 --- a/src/arch/instruction-int.h +++ b/src/arch/instruction-int.h @@ -2,7 +2,7 @@  /* Chrysalide - Outil d'analyse de fichiers binaires   * instruction-int.h - prototypes pour la définition générique interne des instructions   * - * Copyright (C) 2008-2020 Cyrille Bagard + * Copyright (C) 2008-2025 Cyrille Bagard   *   *  This file is part of Chrysalide.   * @@ -25,18 +25,29 @@  #define _ARCH_INSTRUCTION_INT_H +#include <stdint.h> + +  #include "instruction.h" -#include "../analysis/storage/storage.h"  #include "../common/array.h" -#include "../glibext/objhole.h" +#include "../glibext/objhole-int.h"  /* Indique l'encodage d'une instruction de façon détaillée. */ -typedef const char * (* get_instruction_encoding_fc) (const GArchInstruction *); +typedef char * (* get_instruction_encoding_fc) (const GArchInstruction *);  /* Fournit le nom humain de l'instruction manipulée. */ -typedef const char * (* get_instruction_keyword_fc) (GArchInstruction * ); +typedef char * (* get_instruction_keyword_fc) (const GArchInstruction *); + + + +#if 0 + +#include "../analysis/storage/storage.h" + + +  /* Complète un désassemblage accompli pour une instruction. */  typedef void (* call_instruction_hook_fc) (GArchInstruction *, InstrProcessHook, GArchProcessor *, GProcContext *, GExeFormat *); @@ -67,80 +78,45 @@ typedef bool (* store_instruction_fc) (GArchInstruction *, GObjectStorage *, pac -/* Informations glissées dans la structure GObject de GArchOperand */ -typedef struct _instr_extra_data_t -{ -    itid_t uid;                             /* Identifiant unique du type  */ - -    ArchInstrFlag flags;                    /* Informations complémentaires*/ - -} instr_extra_data_t; +#endif -/* Informations glissées dans la structure GObject de GArchInstruction */ -typedef union _instr_obj_extra_t -{ -    instr_extra_data_t data;                /* Données embarquées          */ -    lockable_obj_extra_t lockable;          /* Gestion d'accès aux fanions */ -} instr_obj_extra_t; +/* Conservation d'une adresse et de propriétées */ +typedef unsigned long compact_ins_link_t;  /* Définition générique d'une instruction d'architecture (instance) */  struct _GArchInstruction  { -    GObject parent;                         /* A laisser en premier        */ +    GThickObject parent;                    /* A laisser en premier        */ -#if 1 //__SIZEOF_INT__ == __SIZEOF_LONG__ +    GBinaryPortion *rel_area;               /* Zone de référence           */ +    rel_mrange_t rel_range;                 /* Emplacement compressé       */      /** -     * L'inclusion des informations suivantes dépend de l'architecture. -     * -     * Si la structure GObject possède un trou, on remplit de préférence -     * ce dernier. +     * A laisser à la suite de la localisation précédente pour éviter +     * les espaces vide dans la structure.       */ +    uint16_t link_count;                    /* Quantité de liens établis   */ -    instr_obj_extra_t extra;                /* Externalisation embarquée   */ - -#endif - -    mrange_t range;                         /* Emplacement en mémoire      */ +    compact_ins_link_t *links;              /* Liste de ces liens          */      flat_array_t *operands;                 /* Liste des opérandes         */ -    /** -     * Il existe le besoin indéniable d'un verrou pour les accès aux instructions -     * liées. Il faut par ailleurs un verrou distinct pour les sources et les -     * destinations car une même instruction peut boucler sur elle même et la -     * fonction g_arch_instruction_change_link() pose des verrous sur les -     * deux extrémités. -     * -     * La GLib propose les fonctions g_bit_lock() / g_bit_unlock(), légères mais -     * sans distinction entre lectures et écritures. Tant pis : la réduction de -     * l'empreinte mémoire prime ! -     * -     * Par contre la documentation indique : -     * -     * """ -     * Attempting to lock on two different bits within the same integer is not supported. -     * """ -     * -     * Donc on doit bien conserver un compteur distinct pour chaque extrémité. -     * Cela correspond de toute façon à la définition optimisée des tableaux -     * suivante. -     */ - -    flat_array_t *from;                     /* Origines des références     */ -    flat_array_t *to;                       /* Instructions visées         */ -  };  /* Définition générique d'une instruction d'architecture (classe) */  struct _GArchInstructionClass  { -    GObjectClass parent;                    /* A laisser en premier        */ +    GThickObjectClass parent;               /* A laisser en premier        */      get_instruction_encoding_fc get_encoding; /* Obtention de l'encodage   */      get_instruction_keyword_fc get_keyword; /* Texte humain équivalent     */ + +#if 0 + +    //get_instruction_encoding_fc get_encoding; /* Obtention de l'encodage   */ +    //get_instruction_keyword_fc get_keyword; /* Texte humain équivalent     */      call_instruction_hook_fc call_hook;     /* Décrochages éventuels       */      build_instruction_tooltip_fc build_tooltip; /* Construction d'une bulle*/      get_instruction_desc_fc get_desc;       /* Description assez complète  */ @@ -155,22 +131,50 @@ struct _GArchInstructionClass      //get_instruction_rw_regs_fc get_rw_regs; /* Liste des registres liés    */ +#endif +  }; +/* Met en place une instruction d'architecture. */ +bool g_arch_instruction_create(GArchInstruction *, itid_t); + + +  /**   * Accès aux informations éventuellement déportées.   */ -#if 1 //__SIZEOF_INT__ == __SIZEOF_LONG__ -#   define GET_ARCH_INSTR_EXTRA(ins) (instr_extra_data_t *)&ins->extra +#define ARCH_INSTRUCTION_EXTRA_DATA                         \ +                                                            \ +    unsigned int reserved : GOBJECT_RESERVED_EXTRA_BITS;    \ +                                                            \ +    /**                                                     \ +     * itid_t                                               \ +     */                                                     \ +    unsigned int tid : 16;                                  \ +                                                            \ +    /**                                                     \ +     * ArchOperandFlag                                      \ +     */                                                     \ +    unsigned int flags : 8; -#else -#   define GET_ARCH_INSTR_EXTRA(ins) GET_GOBJECT_EXTRA(G_OBJECT(ins), instr_extra_data_t) +/* Informations glissées dans la structure GObject de GArchOperand */ +typedef struct _instruction_extra_data_t +{ +    ARCH_INSTRUCTION_EXTRA_DATA;            /* Socle commun                */ + +} instruction_extra_data_t; + + +#define GET_ARCH_INSTR_EXTRA(op) \ +    GET_GOBJECT_EXTRA(op, instruction_extra_data_t) + +#define SET_ARCH_INSTR_EXTRA(op, data) \ +    SET_GOBJECT_EXTRA(op, instruction_extra_data_t, data) -#endif  /** diff --git a/src/arch/instruction-ui-int.h b/src/arch/instruction-ui-int.h new file mode 100644 index 0000000..b07f40c --- /dev/null +++ b/src/arch/instruction-ui-int.h @@ -0,0 +1,55 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * instruction-ui-int.h - prototypes pour la définition générique interne des instructions sous forme graphique + * + * 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 _ARCH_INSTRUCTION_UI_INT_H +#define _ARCH_INSTRUCTION_UI_INT_H + + +#include "instruction-ui.h" + + + +#if 0 + +/* Traduit un opérande en version humainement lisible. */ +typedef void (* print_operand_ui_fc) (const GArchOperandUI *, GBufferLine *); + +/* Construit un petit résumé concis de l'opérande. */ +typedef char * (* build_operand_ui_tooltip_fc) (const GArchOperandUI *, const GLoadedBinary *); + + + +/* Définition générique d'un opérande d'architecture (interface) */ +struct _GArchOperandUIInterface +{ +    GTypeInterface base_iface;              /* A laisser en premier        */ + +    print_operand_ui_fc print;              /* Texte humain équivalent     */ +    build_operand_ui_tooltip_fc build_tooltip; /* Définition de description*/ + +}; + +#endif + + +#endif  /* _ARCH_INSTRUCTION_UI_INT_H */ diff --git a/src/arch/instruction-ui.c b/src/arch/instruction-ui.c new file mode 100644 index 0000000..7f923d8 --- /dev/null +++ b/src/arch/instruction-ui.c @@ -0,0 +1,254 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * instruction-ui.c - gestion générique des instructions sous forme graphique + * + * 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/>. + */ + + +#include "instruction-ui.h" + + +#include "instruction-int.h" +#include "operand-ui.h" +#include "../analysis/content.h" +#include "../common/cpp.h" +#include "../glibext/generator-int.h" +#include "../glibext/options/asm.h" + + + +/* ------------------------ OFFRE DE CAPACITES DE GENERATION ------------------------ */ + + +/* Renseigne sur les propriétés liées à un générateur. */ +static BufferLineFlags g_arch_instruction_ui_get_flags(const GTokenGenerator *, size_t, size_t); + +/* Etablit dans une ligne de rendu le contenu représenté. */ +static void g_arch_instruction_ui_populate_line(const GTokenGenerator *, size_t, size_t, GBufferLine *, void *); + +#if 0 + +/* Retrouve l'emplacement correspondant à une position donnée. */ +static void g_arch_instruction_ui_compute_cursor(const GArchInstruction *, gint, size_t, size_t, GLineCursor **); + +/* Détermine si le conteneur s'inscrit dans une plage donnée. */ +static int g_arch_instruction_ui_contain_cursor(const GArchInstruction *, size_t, size_t, const GLineCursor *); + +#endif + + + +/* ---------------------------------------------------------------------------------- */ +/*                          OFFRE DE CAPACITES DE GENERATION                          */ +/* ---------------------------------------------------------------------------------- */ + + +/****************************************************************************** +*                                                                             * +*  Paramètres  : iface = interface GLib à initialiser.                        * +*                                                                             * +*  Description : Procède à l'initialisation de l'interface de génération.     * +*                                                                             * +*  Retour      : -                                                            * +*                                                                             * +*  Remarques   : -                                                            * +*                                                                             * +******************************************************************************/ + +void g_arch_instruction_ui_token_generator_iface_init(GTokenGeneratorInterface *iface) +{ +    /** +     * La procédure par défaut de iface->count() ne doit pas être retouchée ! +     */ + +    iface->get_flags = g_arch_instruction_ui_get_flags; +    iface->populate = g_arch_instruction_ui_populate_line; + +#if 0 +    iface->compute = (linegen_compute_fc)g_arch_instruction_ui_compute_cursor; +    iface->contain = (linegen_contain_fc)g_arch_instruction_ui_contain_cursor; +#endif + +} + + +/****************************************************************************** +*                                                                             * +*  Paramètres  : generator = générateur à consulter.                          * +*                index     = indice de cette même ligne dans le tampon global.* +*                repeat    = indice d'utilisations successives du générateur. * +*                                                                             * +*  Description : Renseigne sur les propriétés liées à un générateur.          * +*                                                                             * +*  Retour      : Propriétés particulières associées.                          * +*                                                                             * +*  Remarques   : -                                                            * +*                                                                             * +******************************************************************************/ + +static BufferLineFlags g_arch_instruction_ui_get_flags(const GTokenGenerator *generator, size_t index, size_t repeat) +{ +    BufferLineFlags result;                 /* Fanions à retourner         */ + +    result = BLF_HAS_CODE; + +    return result; + +} + + +/****************************************************************************** +*                                                                             * +*  Paramètres  : generator = générateur à utiliser pour l'impression.         * +*                index     = indice de cette même ligne dans le tampon global.* +*                repeat    = indice d'utilisations successives du générateur. * +*                line      = ligne de rendu à compléter.                      * +*                data      = éventuelle donnée complémentaire fournie.        * +*                                                                             * +*  Description : Etablit dans une ligne de rendu le contenu représenté.       * +*                                                                             * +*  Retour      : -                                                            * +*                                                                             * +*  Remarques   : -                                                            * +*                                                                             * +******************************************************************************/ + +static void g_arch_instruction_ui_populate_line(const GTokenGenerator *generator, size_t index, size_t repeat, GBufferLine *line, void *data) +{ +    GArchInstruction *instr;                /* Version spécialisée         */ +    GBinContent *content;                   /* Contenu brut d'origine      */ +    mrange_t range;                         /* Emplacement couvert         */ +    char *key;                              /* Mot clef principal          */ +    size_t count;                           /* Nombre d'opérandes en place */ +    size_t i;                               /* Boucle de parcours          */ +    GArchOperand *op;                       /* Opérande à manipuler        */ + +    instr = G_ARCH_INSTRUCTION(generator); +    content = G_BIN_CONTENT(data); + +    /* Prologue */ + +    if (g_arch_instruction_get_range(instr, &range)) +    { +        g_buffer_line_fill_physical(line, ACO_PHYSICAL, MDS_32_BITS_UNSIGNED, get_mrange_addr(&range)); + +        g_buffer_line_fill_virtual(line, ACO_VIRTUAL, MDS_32_BITS_UNSIGNED, get_mrange_addr(&range)); + +        g_buffer_line_fill_content(line, ACO_BINARY, content, &range, VMPA_NO_PHYSICAL); + +    } + +    /* Instruction proprement dite */ + +    key = g_arch_instruction_get_keyword(instr); + +    g_buffer_line_append_text(line, ACO_ASSEMBLY_HEAD, TRT_INSTRUCTION, SL(key), NULL, G_OBJECT(instr)); + +    free(key); + +    /* Liste des opérandes */ + +    g_thick_object_lock(G_THICK_OBJECT(instr)); + +    count = g_arch_instruction_count_operands(instr); + +    if (count > 0) +    { +        op = g_arch_instruction_get_operand(instr, 0); +        g_arch_operand_ui_print(G_ARCH_OPERAND_UI(op), line); +        unref_object(op); + +        for (i = 1; i < count; i++) +        { +            g_buffer_line_append_text(line, ACO_ASSEMBLY, TRT_PUNCT, STCSL(","), NULL, NULL); +            g_buffer_line_append_text(line, ACO_ASSEMBLY, TRT_NONE, STCSL(" "), NULL, NULL); + +            op = g_arch_instruction_get_operand(instr, i); +            g_arch_operand_ui_print(G_ARCH_OPERAND_UI(op), line); +            unref_object(op); + +        } + +    } + +    g_thick_object_unlock(G_THICK_OBJECT(instr)); + +} + + +#if 0 + + +/****************************************************************************** +*                                                                             * +*  Paramètres  : instr  = générateur à consulter.                             * +*                x      = position géographique sur la ligne concernée.       * +*                index  = indice de cette même ligne dans le tampon global.   * +*                repeat = indice d'utilisations successives du générateur.    * +*                cursor = emplacement à constituer. [OUT]                     * +*                                                                             * +*  Description : Retrouve l'emplacement correspondant à une position donnée.  * +*                                                                             * +*  Retour      : -                                                            * +*                                                                             * +*  Remarques   : -                                                            * +*                                                                             * +******************************************************************************/ + +static void g_arch_instruction_ui_compute_cursor(const GArchInstruction *instr, gint x, size_t index, size_t repeat, GLineCursor **cursor) +{ +    *cursor = g_binary_cursor_new(); + +    g_binary_cursor_update(G_BINARY_CURSOR(*cursor), get_mrange_addr(&instr->range)); + +} + + +/****************************************************************************** +*                                                                             * +*  Paramètres  : instr  = générateur à consulter.                             * +*                index  = indice de cette même ligne dans le tampon global.   * +*                repeat = indice d'utilisations successives du générateur.    * +*                cursor = emplacement à analyser.                             * +*                                                                             * +*  Description : Détermine si le conteneur s'inscrit dans une plage donnée.   * +*                                                                             * +*  Retour      : Bilan de la détermination, utilisable en comparaisons.       * +*                                                                             * +*  Remarques   : -                                                            * +*                                                                             * +******************************************************************************/ + +static int g_arch_instruction_ui_contain_cursor(const GArchInstruction *instr, size_t index, size_t repeat, const GLineCursor *cursor) +{ +    int result;                             /* Conclusion à retourner      */ +    vmpa2t addr;                            /* Autre emplacement à comparer*/ + +    assert(G_IS_BINARY_CURSOR(cursor)); + +    g_binary_cursor_retrieve(G_BINARY_CURSOR(cursor), &addr); + +    result = cmp_mrange_with_vmpa(&instr->range, &addr); + +    return result; + +} + + +#endif diff --git a/src/arch/instruction-ui.h b/src/arch/instruction-ui.h new file mode 100644 index 0000000..62a52f2 --- /dev/null +++ b/src/arch/instruction-ui.h @@ -0,0 +1,41 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * instruction-ui.h - prototypes pour la gestion générique des instructions sous forme graphique + * + * 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 _ARCH_INSTRUCTION_UI_H +#define _ARCH_INSTRUCTION_UI_H + + +#include "../glibext/generator.h" +#include "../glibext/helpers.h" + + + +/* ------------------------ OFFRE DE CAPACITES DE GENERATION ------------------------ */ + + +/* Procède à l'initialisation de l'interface de génération. */ +void g_arch_instruction_ui_token_generator_iface_init(GTokenGeneratorInterface *); + + + +#endif  /* _ARCH_INSTRUCTION_UI_H */ diff --git a/src/arch/instruction.c b/src/arch/instruction.c index cd1e9c7..36bdecb 100644 --- a/src/arch/instruction.c +++ b/src/arch/instruction.c @@ -2,7 +2,7 @@  /* Chrysalide - Outil d'analyse de fichiers binaires   * instruction.c - gestion générique des instructions   * - * Copyright (C) 2008-2020 Cyrille Bagard + * Copyright (C) 2008-2025 Cyrille Bagard   *   *  This file is part of Chrysalide.   * @@ -26,102 +26,93 @@  #include <assert.h>  #include <malloc.h> -#include <stdarg.h> -#include <stdio.h> -#include <stdlib.h> +#include <limits.h>  #include <string.h>  #include "instruction-int.h" -#include "storage.h" -#include "../analysis/storage/serialize-int.h" -#include "../core/columns.h" +#include "../common/leb128.h"  #include "../core/logs.h"  #include "../core/processors.h" -#include "../glibext/gbinarycursor.h" -#include "../glibext/linegen-int.h" +#include "../glibext/serialize-int.h" -/* Initialise la classe générique des instructions. */ -static void g_arch_instruction_class_init(GArchInstructionClass *); - -/* Initialise une instance d'opérande d'architecture. */ -static void g_arch_instruction_init(GArchInstruction *); -/* Procède à l'initialisation de l'interface de génération. */ -static void g_arch_instruction_generator_init(GLineGeneratorInterface *); -/* Procède à l'initialisation de l'interface de sérialisation. */ -static void g_arch_instruction_serializable_init(GSerializableObjectInterface *); - -/* Supprime toutes les références externes. */ -static void g_arch_instruction_dispose(GArchInstruction *); - -/* Procède à la libération totale de la mémoire. */ -static void g_arch_instruction_finalize(GArchInstruction *); +/* ----------------------- DEFINITION GENERIQUE D'INSTRUCTION ----------------------- */ +/* Initialise la classe générique des instructions. */ +static void g_arch_instruction_class_init(GArchInstructionClass *); +/* Procède à l'initialisation de l'interface de sérialisation. */ +static void g_arch_instruction_serializable_object_iface_init(GSerializableObjectInterface *); -/* Charge un contenu depuis une mémoire tampon. */ -static bool g_arch_instruction_load_destinations(GArchInstruction *, GObjectStorage *, packed_buffer_t *); +/* Initialise une instance d'opérande d'architecture. */ +static void g_arch_instruction_init(GArchInstruction *); -/* Sauvegarde toutes les destinations d'une instruction. */ -bool g_arch_instruction_store_destinations(GArchInstruction *, GObjectStorage *, packed_buffer_t *); +/* Supprime toutes les références externes. */ +static void g_arch_instruction_dispose(GObject *); +/* Procède à la libération totale de la mémoire. */ +static void g_arch_instruction_finalize(GObject *); +/* ------------------- DEFINITION DES LIAISONS ENTRE INSTRUCTIONS ------------------- */ -/* ------------------------ OFFRE DE CAPACITES DE GENERATION ------------------------ */ +#define COMPACT_INS_LINK_MASK_DIR   (1ul << (__WORDSIZE - 1)) +#define COMPACT_INS_LINK_MASK_TYPE  0xf +#define COMPACT_INS_LINK_MASK       (COMPACT_INS_LINK_MASK_DIR | COMPACT_INS_LINK_MASK_TYPE) -/* Indique le nombre de ligne prêtes à être générées. */ -static size_t g_arch_instruction_count_lines(const GArchInstruction *); +#define COMPACT_INS_LINK_FROM   (0ul << (__WORDSIZE - 1)) +#define COMPACT_INS_LINK_TO     (1ul << (__WORDSIZE - 1)) -#ifdef INCLUDE_GTK_SUPPORT +#define COMPACT_INS_LINK_DIR(cl) (cl & COMPACT_INS_LINK_MASK_DIR) +#define COMPACT_INS_LINK_PTR(cl) ((GArchInstruction *)(cl & ~COMPACT_INS_LINK_MASK)) +#define COMPACT_INS_LINK_TYPE(cl) (cl & COMPACT_INS_LINK_MASK_TYPE) -/* Retrouve l'emplacement correspondant à une position donnée. */ -static void g_arch_instruction_compute_cursor(const GArchInstruction *, gint, size_t, size_t, GLineCursor **); +#define MAKE_COMPACT_INS_LINK(d, i, t) \ +    (compact_ins_link_t)(d | (unsigned long)i | t) -/* Détermine si le conteneur s'inscrit dans une plage donnée. */ -static int g_arch_instruction_contain_cursor(const GArchInstruction *, size_t, size_t, const GLineCursor *); +/* Détermine si un type de lien existe dans une instruction. */ +static bool _g_arch_instruction_has_link(const GArchInstruction *, compact_ins_link_t, InstructionLinkType); -#endif +/* Détermine si un lien existe entre deux instructions. */ +static bool _g_arch_instruction_has_link_with(const GArchInstruction *, compact_ins_link_t, const GArchInstruction *); -/* Renseigne sur les propriétés liées à un générateur. */ -static BufferLineFlags g_arch_instruction_get_flags2(const GArchInstruction *, size_t, size_t); +/* Fournit la quantité d'instructions pointant vers une autre. */ +static size_t _g_arch_instruction_count_links(const GArchInstruction *, compact_ins_link_t); -/* Ajoute à un tampon GLib le contenu de l'instance spécifiée. */ -static void _g_arch_instruction_print(GArchInstruction *, GBufferLine *, size_t, size_t, const GBinContent *); +/* Fournit les détails d'un lien donné avec une instruction. */ +static GArchInstruction *_g_arch_instruction_get_linked_instruction(const GArchInstruction *, size_t, compact_ins_link_t, InstructionLinkType *); -/* Imprime dans une ligne de rendu le contenu représenté. */ -static void g_arch_instruction_print(GArchInstruction *, GBufferLine *, size_t, size_t, const GBinContent *); -/* -------------------- CONSERVATION ET RECHARGEMENT DES DONNEES -------------------- */ +/* ------------------- MECANISMES DE CONSERVATION ET RESTAURATION ------------------- */ -/* Charge un contenu depuis une mémoire tampon. */ -static bool _g_arch_instruction_load(GArchInstruction *, GObjectStorage *, packed_buffer_t *); +/* Charge un objet depuis un flux de données. */ +static bool g_arch_instruction_load(GSerializableObject *, GObjectStorage *, int); -/* Charge un contenu depuis une mémoire tampon. */ -static bool g_arch_instruction_load(GArchInstruction *, GObjectStorage *, packed_buffer_t *); +/* Sauvegarde un objet dans un flux de données. */ +static bool g_arch_instruction_store(const GSerializableObject *, GObjectStorage *, int); -/* Sauvegarde un contenu dans une mémoire tampon. */ -static bool _g_arch_instruction_store(GArchInstruction *, GObjectStorage *, packed_buffer_t *); -/* Sauvegarde un contenu dans une mémoire tampon. */ -static bool g_arch_instruction_store(GArchInstruction *, GObjectStorage *, packed_buffer_t *); +/* ---------------------------------------------------------------------------------- */ +/*                         DEFINITION GENERIQUE D'INSTRUCTION                         */ +/* ---------------------------------------------------------------------------------- */  /* Indique le type défini pour une instruction d'architecture. */ -G_DEFINE_TYPE_WITH_CODE(GArchInstruction, g_arch_instruction, G_TYPE_OBJECT, -                        G_IMPLEMENT_INTERFACE(G_TYPE_LINE_GENERATOR, g_arch_instruction_generator_init) -                        G_IMPLEMENT_INTERFACE(G_TYPE_SERIALIZABLE_OBJECT, g_arch_instruction_serializable_init)); +G_DEFINE_TYPE_WITH_CODE(GArchInstruction, g_arch_instruction, G_TYPE_THICK_OBJECT, +                        G_IMPLEMENT_INTERFACE(G_TYPE_SERIALIZABLE_OBJECT, g_arch_instruction_serializable_object_iface_init) +                        G_IMPLEMENT_INTERFACE_IF_SYM(g_token_generator_get_type, g_arch_instruction_ui_token_generator_iface_init)); +  /****************************************************************************** @@ -139,28 +130,20 @@ G_DEFINE_TYPE_WITH_CODE(GArchInstruction, g_arch_instruction, G_TYPE_OBJECT,  static void g_arch_instruction_class_init(GArchInstructionClass *klass)  {      GObjectClass *object;                   /* Autre version de la classe  */ -    GArchInstructionClass *instr;           /* Encore une autre vision...  */      object = G_OBJECT_CLASS(klass); -    object->dispose = (GObjectFinalizeFunc/* ! */)g_arch_instruction_dispose; -    object->finalize = (GObjectFinalizeFunc)g_arch_instruction_finalize; - -    instr = G_ARCH_INSTRUCTION_CLASS(klass); - -    instr->print = (print_instruction_fc)_g_arch_instruction_print; - -    instr->load = (load_instruction_fc)_g_arch_instruction_load; -    instr->store = (store_instruction_fc)_g_arch_instruction_store; +    object->dispose = g_arch_instruction_dispose; +    object->finalize = g_arch_instruction_finalize;  }  /******************************************************************************  *                                                                             * -*  Paramètres  : instr = instance à initialiser.                              * +*  Paramètres  : iface = interface GLib à initialiser.                        *  *                                                                             * -*  Description : Initialise une instance d'instruction d'architecture.        * +*  Description : Procède à l'initialisation de l'interface de sérialisation.  *  *                                                                             *  *  Retour      : -                                                            *  *                                                                             * @@ -168,27 +151,19 @@ static void g_arch_instruction_class_init(GArchInstructionClass *klass)  *                                                                             *  ******************************************************************************/ -static void g_arch_instruction_init(GArchInstruction *instr) +static void g_arch_instruction_serializable_object_iface_init(GSerializableObjectInterface *iface)  { -    instr_extra_data_t *extra;              /* Données insérées à modifier */ - -    extra = GET_ARCH_INSTR_EXTRA(instr); - -    INIT_GOBJECT_EXTRA_LOCK(extra); - -    instr->operands = NULL; - -    instr->from = NULL; -    instr->to = NULL; +    iface->load = g_arch_instruction_load; +    iface->store = g_arch_instruction_store;  }  /******************************************************************************  *                                                                             * -*  Paramètres  : iface = interface GLib à initialiser.                        * +*  Paramètres  : instr = instance à initialiser.                              *  *                                                                             * -*  Description : Procède à l'initialisation de l'interface de génération.     * +*  Description : Initialise une instance d'instruction d'architecture.        *  *                                                                             *  *  Retour      : -                                                            *  *                                                                             * @@ -196,42 +171,22 @@ static void g_arch_instruction_init(GArchInstruction *instr)  *                                                                             *  ******************************************************************************/ -static void g_arch_instruction_generator_init(GLineGeneratorInterface *iface) +static void g_arch_instruction_init(GArchInstruction *instr)  { -    iface->count = (linegen_count_lines_fc)g_arch_instruction_count_lines; -#ifdef INCLUDE_GTK_SUPPORT -    iface->compute = (linegen_compute_fc)g_arch_instruction_compute_cursor; -    iface->contain = (linegen_contain_fc)g_arch_instruction_contain_cursor; -#endif -    iface->get_flags = (linegen_get_flags_fc)g_arch_instruction_get_flags2; -    iface->print = (linegen_print_fc)g_arch_instruction_print; - -} +    instr->rel_area = NULL; +    instr->link_count = 0; -/****************************************************************************** -*                                                                             * -*  Paramètres  : iface = interface GLib à initialiser.                        * -*                                                                             * -*  Description : Procède à l'initialisation de l'interface de sérialisation.  * -*                                                                             * -*  Retour      : -                                                            * -*                                                                             * -*  Remarques   : -                                                            * -*                                                                             * -******************************************************************************/ +    instr->links = NULL; -static void g_arch_instruction_serializable_init(GSerializableObjectInterface *iface) -{ -    iface->load = (load_serializable_object_cb)g_arch_instruction_load; -    iface->store = (store_serializable_object_cb)g_arch_instruction_store; +    instr->operands = NULL;  }  /******************************************************************************  *                                                                             * -*  Paramètres  : instr = instance d'objet GLib à traiter.                     * +*  Paramètres  : object = instance d'objet GLib à traiter.                    *  *                                                                             *  *  Description : Supprime toutes les références externes.                     *  *                                                                             * @@ -241,43 +196,38 @@ static void g_arch_instruction_serializable_init(GSerializableObjectInterface *i  *                                                                             *  ******************************************************************************/ -static void g_arch_instruction_dispose(GArchInstruction *instr) +static void g_arch_instruction_dispose(GObject *object)  { +    GArchInstruction *instr;                /* Version spécialisée         */      size_t count;                           /* Nombre d'opérandes en place */      size_t i;                               /* Boucle de parcours          */      GArchOperand *op;                       /* Opérande à manipuler        */ -    g_arch_instruction_lock_operands(instr); +    instr = G_ARCH_INSTRUCTION(object); + +    g_clear_object(&instr->rel_area); + +    g_arch_instruction_delete_all_links(instr); -    count = _g_arch_instruction_count_operands(instr); +    g_thick_object_lock(G_THICK_OBJECT(instr)); + +    count = g_arch_instruction_count_operands(instr);      for (i = 0; i < count; i++)      { -        op = _g_arch_instruction_get_operand(instr, 0); +        op = g_arch_instruction_get_operand(instr, 0);          rem_item_from_flat_array(&instr->operands, 0, sizeof(GArchOperand *));          /**           * Une fois pour l'obtention, une autre pour la libération !           */ -        g_object_unref(G_OBJECT(op)); -        g_object_unref(G_OBJECT(op)); +        unref_object(op); +        unref_object(op);      } -    g_arch_instruction_unlock_operands(instr); - -#ifndef NDEBUG -    g_arch_instruction_lock_src(instr); -    assert(count_flat_array_items(instr->from) == 0); -    g_arch_instruction_unlock_src(instr); -#endif - -#ifndef NDEBUG -    g_arch_instruction_lock_dest(instr); -    assert(count_flat_array_items(instr->to) == 0); -    g_arch_instruction_unlock_dest(instr); -#endif +    g_thick_object_unlock(G_THICK_OBJECT(instr));      G_OBJECT_CLASS(g_arch_instruction_parent_class)->dispose(G_OBJECT(instr)); @@ -286,7 +236,7 @@ static void g_arch_instruction_dispose(GArchInstruction *instr)  /******************************************************************************  *                                                                             * -*  Paramètres  : instr = instance d'objet GLib à traiter.                     * +*  Paramètres  : object = instance d'objet GLib à traiter.                    *  *                                                                             *  *  Description : Procède à la libération totale de la mémoire.                *  *                                                                             * @@ -296,38 +246,26 @@ static void g_arch_instruction_dispose(GArchInstruction *instr)  *                                                                             *  ******************************************************************************/ -static void g_arch_instruction_finalize(GArchInstruction *instr) +static void g_arch_instruction_finalize(GObject *object)  { -    G_OBJECT_CLASS(g_arch_instruction_parent_class)->finalize(G_OBJECT(instr)); +    GArchInstruction *instr;                /* Version spécialisée         */ -} +    instr = G_ARCH_INSTRUCTION(object); +    if (instr->links != NULL) +        free(instr->links); -/****************************************************************************** -*                                                                             * -*  Paramètres  : instr = instruction quelconque à consulter.                  * -*                                                                             * -*  Description : Indique l'encodage d'une instruction de façon détaillée.     * -*                                                                             * -*  Retour      : Description humaine de l'encodage utilisé.                   * -*                                                                             * -*  Remarques   : -                                                            * -*                                                                             * -******************************************************************************/ - -const char *g_arch_instruction_get_encoding(const GArchInstruction *instr) -{ -    return G_ARCH_INSTRUCTION_GET_CLASS(instr)->get_encoding(instr); +    G_OBJECT_CLASS(g_arch_instruction_parent_class)->finalize(G_OBJECT(instr));  }  /******************************************************************************  *                                                                             * -*  Paramètres  : instr = instruction quelconque à modifier.                   * -*                flag  = drapeau d'information complémentaire à planter.      * +*  Paramètres  : instr = instance à initialiser pleinement.                   * +*                tid   = identifiant associé au type d'instructions ciblé.    *  *                                                                             * -*  Description : Ajoute une information complémentaire à une instruction.     * +*  Description : Met en place une instruction d'architecture.                 *  *                                                                             *  *  Retour      : Bilan de l'opération.                                        *  *                                                                             * @@ -335,22 +273,18 @@ const char *g_arch_instruction_get_encoding(const GArchInstruction *instr)  *                                                                             *  ******************************************************************************/ -bool g_arch_instruction_set_flag(GArchInstruction *instr, ArchInstrFlag flag) +bool g_arch_instruction_create(GArchInstruction *instr, itid_t tid)  {      bool result;                            /* Bilan à retourner           */ -    instr_extra_data_t *extra;              /* Données insérées à modifier */ +    instruction_extra_data_t extra;         /* Données insérées à modifier */ -    assert(flag <= AIF_HIGH_USER); +    result = true;      extra = GET_ARCH_INSTR_EXTRA(instr); -    LOCK_GOBJECT_EXTRA(extra); - -    result = !(extra->flags & flag); +    extra.tid = tid; -    extra->flags |= flag; - -    UNLOCK_GOBJECT_EXTRA(extra); +    SET_ARCH_INSTR_EXTRA(instr, &extra);      return result; @@ -359,33 +293,24 @@ bool g_arch_instruction_set_flag(GArchInstruction *instr, ArchInstrFlag flag)  /******************************************************************************  *                                                                             * -*  Paramètres  : instr = instruction quelconque à modifier.                   * -*                flag  = drapeau d'information complémentaire à planter.      * +*  Paramètres  : instr = instruction quelconque à consulter.                  *  *                                                                             * -*  Description : Retire une information complémentaire à une instruction.     * +*  Description : Fournit l'identifiant correspondant à un type d'instructions.*  *                                                                             * -*  Retour      : Bilan de l'opération.                                        * +*  Retour      : Identifiant unique par type d'instruction et architecture.   *  *                                                                             *  *  Remarques   : -                                                            *  *                                                                             *  ******************************************************************************/ -bool g_arch_instruction_unset_flag(GArchInstruction *instr, ArchInstrFlag flag) +itid_t g_arch_instruction_get_type_id(const GArchInstruction *instr)  { -    bool result;                            /* Bilan à retourner           */ -    instr_extra_data_t *extra;              /* Données insérées à modifier */ - -    assert(flag <= AIF_HIGH_USER); +    itid_t result;                          /* Numéro à retourner          */ +    instruction_extra_data_t extra;         /* Données insérées à modifier */      extra = GET_ARCH_INSTR_EXTRA(instr); -    LOCK_GOBJECT_EXTRA(extra); - -    result = (extra->flags & flag); - -    extra->flags &= ~flag; - -    UNLOCK_GOBJECT_EXTRA(extra); +    result = extra.tid;      return result; @@ -395,30 +320,23 @@ bool g_arch_instruction_unset_flag(GArchInstruction *instr, ArchInstrFlag flag)  /******************************************************************************  *                                                                             *  *  Paramètres  : instr = instruction quelconque à consulter.                  * -*                flag  = drapeau d'information à rechercher.                  *  *                                                                             * -*  Description : Détermine si une instruction possède un fanion particulier.  * +*  Description : Indique l'encodage d'une instruction de façon détaillée.     *  *                                                                             * -*  Retour      : Bilan de la détection.                                       * +*  Retour      : Description humaine de l'encodage utilisé.                   *  *                                                                             *  *  Remarques   : -                                                            *  *                                                                             *  ******************************************************************************/ -bool g_arch_instruction_has_flag(const GArchInstruction *instr, ArchInstrFlag flag) +char *g_arch_instruction_get_encoding(const GArchInstruction *instr)  { -    bool result;                            /* Bilan à retourner           */ -    instr_extra_data_t *extra;              /* Données insérées à modifier */ - -    assert(flag <= AIF_HIGH_USER); - -    extra = GET_ARCH_INSTR_EXTRA(instr); - -    LOCK_GOBJECT_EXTRA(extra); +    char *result;                           /* Encodage à retourner        */ +    GArchInstructionClass *class;           /* Classe des instructions     */ -    result = (extra->flags & flag); +    class = G_ARCH_INSTRUCTION_GET_CLASS(instr); -    UNLOCK_GOBJECT_EXTRA(extra); +    result = class->get_encoding(instr);      return result; @@ -427,28 +345,24 @@ bool g_arch_instruction_has_flag(const GArchInstruction *instr, ArchInstrFlag fl  /******************************************************************************  *                                                                             * -*  Paramètres  : instr = instruction quelconque à modifier.                   * +*  Paramètres  : instr = instruction d'assemblage à consulter.                *  *                                                                             * -*  Description : Fournit les informations complémentaires d'une instruction.  * +*  Description : Fournit le nom humain de l'instruction manipulée.            *  *                                                                             * -*  Retour      : Eventuels drapeaux d'information complémentaire à plantés.   * +*  Retour      : Mot clef de bas niveau.                                      *  *                                                                             *  *  Remarques   : -                                                            *  *                                                                             *  ******************************************************************************/ -ArchInstrFlag g_arch_instruction_get_flags(const GArchInstruction *instr) +char *g_arch_instruction_get_keyword(const GArchInstruction *instr)  { -    ArchInstrFlag result;                   /* Fanions à retourner         */ -    instr_extra_data_t *extra;              /* Données insérées à modifier */ - -    extra = GET_ARCH_INSTR_EXTRA(instr); - -    LOCK_GOBJECT_EXTRA(extra); +    char *result;                           /* Etiquette à retourner       */ +    GArchInstructionClass *class;           /* Classe des instructions     */ -    result = extra->flags; +    class = G_ARCH_INSTRUCTION_GET_CLASS(instr); -    UNLOCK_GOBJECT_EXTRA(extra); +    result = class->get_keyword(instr);      return result; @@ -457,10 +371,12 @@ ArchInstrFlag g_arch_instruction_get_flags(const GArchInstruction *instr)  /******************************************************************************  *                                                                             * -*  Paramètres  : instr = instruction quelconque à consulter.                  * -*                uid   = identifiant unique par type d'instruction.           * +*  Paramètres  : instr  = instruction quelconque à compléter.                 * +*                area   = portion de binaire incluant l'instruction.          * +*                start  = adresse virtuelle et/ou position physique.          * +*                length = taille de l'instruction.                            *  *                                                                             * -*  Description : Définit l'identifiant unique pour un ensemble d'instructions.* +*  Description : Calcule la localisation d'une instruction.                   *  *                                                                             *  *  Retour      : -                                                            *  *                                                                             * @@ -468,358 +384,214 @@ ArchInstrFlag g_arch_instruction_get_flags(const GArchInstruction *instr)  *                                                                             *  ******************************************************************************/ -void g_arch_instruction_set_unique_id(GArchInstruction *instr, itid_t uid) +void g_arch_instruction_compute_range(GArchInstruction *instr, GBinaryPortion *area, const vmpa2t *start, phys_t length)  { -    instr_extra_data_t *extra;              /* Données insérées à modifier */ +    const mrange_t *a_range;                /* Couverture de la portion    */ +    phys_t diff;                            /* Décalage à appliquer        */ -    extra = GET_ARCH_INSTR_EXTRA(instr); - -    LOCK_GOBJECT_EXTRA(extra); +    a_range = g_binary_portion_get_range(area); -    extra->uid = uid; +    assert(mrange_contains_addr(a_range, start)); -    UNLOCK_GOBJECT_EXTRA(extra); +    diff = compute_vmpa_diff(get_mrange_addr(a_range), start); -} +    instr->rel_area = area; +    ref_object(area); - -/****************************************************************************** -*                                                                             * -*  Paramètres  : instr = instruction quelconque à consulter.                  * -*                                                                             * -*  Description : Fournit l'identifiant unique pour un ensemble d'instructions.* -*                                                                             * -*  Retour      : Identifiant unique par type d'instruction et architecture.   * -*                                                                             * -*  Remarques   : -                                                            * -*                                                                             * -******************************************************************************/ - -itid_t g_arch_instruction_get_unique_id(const GArchInstruction *instr) -{ -    itid_t result;                          /* Numéro à retourner          */ -    instr_extra_data_t *extra;              /* Données insérées à consulter*/ - -    extra = GET_ARCH_INSTR_EXTRA(instr); - -    LOCK_GOBJECT_EXTRA(extra); - -    result = extra->uid; - -    UNLOCK_GOBJECT_EXTRA(extra); - -    return result; +    init_rel_mrange(&instr->rel_range, diff, length);  }  /******************************************************************************  *                                                                             * -*  Paramètres  : instr   = instruction quelconque à traiter.                  * -*                type    = type de procédure à utiliser.                      * -*                proc    = représentation de l'architecture utilisée.         * -*                context = contexte associé à la phase de désassemblage.      * -*                format  = accès aux données du binaire d'origine.            * +*  Paramètres  : instr   = instruction quelconque à consulter.                * +*                range = localisation de l'instruction. [OUT]                 *  *                                                                             * -*  Description : Complète un désassemblage accompli pour une instruction.     * +*  Description : Fournit la place mémoire d'une instruction.                  *  *                                                                             * -*  Retour      : -                                                            * +*  Retour      : Validité de la localisation : existence d'une définition ?   *  *                                                                             *  *  Remarques   : -                                                            *  *                                                                             *  ******************************************************************************/ -void g_arch_instruction_call_hook(GArchInstruction *instr, InstrProcessHook type, GArchProcessor *proc, GProcContext *context, GExeFormat *format) +bool g_arch_instruction_get_range(const GArchInstruction *instr, mrange_t *range)  { -    GArchInstructionClass *class;           /* Classe des instructions     */ +    bool result;                            /* Statut à retourner          */ +    const mrange_t *a_range;                /* Couverture de la portion    */ +    vmpa2t start;                           /* Position de départ complète */ -    class = G_ARCH_INSTRUCTION_GET_CLASS(instr); +    result = (instr->rel_area != NULL); -    if (class->call_hook != NULL) -        class->call_hook(instr, type, proc, context, format); +    if (result) +    { +        a_range = g_binary_portion_get_range(instr->rel_area); -} +        copy_vmpa(&start, get_mrange_addr(a_range)); +        advance_vmpa(&start, get_rel_mrange_offset(&instr->rel_range)); +        init_mrange(range, &start, get_rel_mrange_length(&instr->rel_range)); -/****************************************************************************** -*                                                                             * -*  Paramètres  : instr   = instruction quelconque à modifier.                 * -*                address = adresse virtuelle et/ou position physique.         * -*                length  = taille de l'instruction.                           * -*                                                                             * -*  Description : Définit la localisation d'une instruction.                   * -*                                                                             * -*  Retour      : -                                                            * -*                                                                             * -*  Remarques   : -                                                            * -*                                                                             * -******************************************************************************/ +    } -void g_arch_instruction_set_range(GArchInstruction *instr, const mrange_t *range) -{ -    copy_mrange(&instr->range, range); +    return result;  }  /******************************************************************************  *                                                                             * -*  Paramètres  : instr   = instruction quelconque à consulter.                * +*  Paramètres  : instr = instruction à venir modifier.                        * +*                flag  = drapeau d'information complémentaire à planter.      *  *                                                                             * -*  Description : Fournit la place mémoire d'une instruction.                  * +*  Description : Ajoute une information complémentaire à une instruction.     *  *                                                                             * -*  Retour      : Zone mémoire couverte par l'instruction.                     * +*  Retour      : Bilan de l'opération.                                        *  *                                                                             *  *  Remarques   : -                                                            *  *                                                                             *  ******************************************************************************/ -const mrange_t *g_arch_instruction_get_range(const GArchInstruction *instr) +bool g_arch_instruction_set_flag(GArchInstruction *instr, ArchInstructionFlag flag)  { -    return &instr->range; +    bool result;                            /* Bilan à retourner           */ +    instruction_extra_data_t extra;         /* Données insérées à modifier */ -} +    assert(flag <= AIF_HIGH_USER); +    extra = GET_ARCH_INSTR_EXTRA(instr); +    result = !(extra.flags & flag); -/****************************************************************************** -*                                                                             * -*  Paramètres  : instr   = instruction quelconque à consulter.                * -*                offset  = position physique dans le code binaire/NULL. [OUT] * -*                length  = taille de l'instruction ou NULL. [OUT]             * -*                address = adresse virtuelle ou position physique/NULL. [OUT] * -*                                                                             * -*  Description : Fournit la localisation d'une instruction.                   * -*                                                                             * -*  Retour      : -                                                            * -*                                                                             * -*  Remarques   : -                                                            * -*                                                                             * -******************************************************************************/ +    extra.flags |= flag; -void g_arch_instruction_get_location(const GArchInstruction *instr, off_t *offset, off_t *length, vmpa_t *address) -{ -    //if (offset != NULL) *offset = instr->offset; -    //if (length != NULL) *length = instr->length; +    SET_ARCH_INSTR_EXTRA(instr, &extra); -    //if (address != NULL) *address = instr->address; +    return result;  } -  /******************************************************************************  *                                                                             * -*  Paramètres  : instr  = instruction à consulter.                            * -*                rregs  = liste des rgistres lus. [OUT]                       * -*                rcount = nombre de registres lus. [OUT]                      * -*                wregs  = liste des rgistres écrits. [OUT]                    * -*                wcount = nombre de registres écrits. [OUT]                   * +*  Paramètres  : instr = instruction à venir modifier.                        * +*                flag  = drapeau d'information complémentaire à planter.      *  *                                                                             * -*  Description : Liste les registres lus et écrits par l'instruction.         * +*  Description : Retire une information complémentaire à une instruction.     *  *                                                                             * -*  Retour      : -                                                            * +*  Retour      : Bilan de l'opération.                                        *  *                                                                             * -*  Remarques   : Les compteurs de références sont à décrémenter après usage ! * +*  Remarques   : -                                                            *  *                                                                             *  ******************************************************************************/ -void g_arch_instruction_get_rw_registers(const GArchInstruction *instr, GArchRegister ***rregs, size_t *rcount, GArchRegister ***wregs, size_t *wcount) +bool g_arch_instruction_unset_flag(GArchInstruction *instr, ArchInstructionFlag flag)  { -#if 0 +    bool result;                            /* Bilan à retourner           */ +    instruction_extra_data_t extra;         /* Données insérées à modifier */ -    size_t i;                               /* Boucle de parcours          */ +    assert(flag <= AIF_HIGH_USER); -    *rregs = NULL; -    *rcount = 0; -    *wregs = NULL; -    *wcount = 0; +    extra = GET_ARCH_INSTR_EXTRA(instr); -    instr->get_rw_regs(instr, rregs, rcount, wregs, wcount); +    result = (extra.flags & flag); -    for (i = 0; i < *rcount; i++) -        g_object_ref(G_OBJECT((*rregs)[i])); +    extra.flags &= ~flag; -    for (i = 0; i < *wcount; i++) -        g_object_ref(G_OBJECT((*wregs)[i])); +    SET_ARCH_INSTR_EXTRA(instr, &extra); -#endif +    return result;  } - -/* ---------------------------------------------------------------------------------- */ -/*                             MANIPULATION DES OPERANDES                             */ -/* ---------------------------------------------------------------------------------- */ - -  /******************************************************************************  *                                                                             * -*  Paramètres  : instr = instruction à mettre à jour.                         * +*  Paramètres  : instr = instruction à venir consulter.                       * +*                flag  = drapeau d'information à rechercher.                  *  *                                                                             * -*  Description : Verrouille les accès à la liste des opérandes.               * +*  Description : Détermine si une instruction possède un fanion particulier.  *  *                                                                             * -*  Retour      : -                                                            * +*  Retour      : Bilan de la détection.                                       *  *                                                                             *  *  Remarques   : -                                                            *  *                                                                             *  ******************************************************************************/ -void g_arch_instruction_lock_operands(GArchInstruction *instr) +bool g_arch_instruction_has_flag(const GArchInstruction *instr, ArchInstructionFlag flag)  { -    lock_flat_array(&instr->operands); +    bool result;                            /* Bilan à retourner           */ +    instruction_extra_data_t extra;         /* Données insérées à modifier */ -} +    assert(flag <= AIF_HIGH_USER); +    extra = GET_ARCH_INSTR_EXTRA(instr); -/****************************************************************************** -*                                                                             * -*  Paramètres  : instr = instruction à mettre à jour.                         * -*                                                                             * -*  Description : Déverrouille les accès à la liste des opérandes.             * -*                                                                             * -*  Retour      : -                                                            * -*                                                                             * -*  Remarques   : -                                                            * -*                                                                             * -******************************************************************************/ +    result = (extra.flags & flag); -void g_arch_instruction_unlock_operands(GArchInstruction *instr) -{ -    unlock_flat_array(&instr->operands); +    return result;  }  /******************************************************************************  *                                                                             * -*  Paramètres  : instr   = instance à mettre à jour.                          * -*                operand = instruction à venir associer.                      * +*  Paramètres  : instr = instruction à venir consulter.                       *  *                                                                             * -*  Description : Attache un opérande supplémentaire à une instruction.        * +*  Description : Fournit les particularités de l'instruction.                 *  *                                                                             * -*  Retour      : -                                                            * +*  Retour      : Somme de tous les fanions associés à l'opérande.             *  *                                                                             *  *  Remarques   : -                                                            *  *                                                                             *  ******************************************************************************/ -void g_arch_instruction_attach_extra_operand(GArchInstruction *instr, GArchOperand *operand) +ArchInstructionFlag g_arch_instruction_get_flags(const GArchInstruction *instr)  { -    GSingletonFactory *factory;             /* Unise à instances uniques   */ -    GArchOperand *singleton;                /* Instance retenue            */ - -    factory = get_operands_factory(); - -    singleton = G_ARCH_OPERAND(g_singleton_factory_get_instance(factory, G_SINGLETON_CANDIDATE(operand))); - -    g_object_unref(G_OBJECT(operand)); -    g_object_unref(G_OBJECT(factory)); - -    g_arch_instruction_lock_operands(instr); - -    add_item_to_flat_array(&instr->operands, &singleton, sizeof(GArchOperand *)); - -    g_arch_instruction_unlock_operands(instr); +    ArchInstructionFlag result;             /* Fanions à retourner         */ +    instruction_extra_data_t extra;         /* Données insérées à modifier */ -} - - -/****************************************************************************** -*                                                                             * -*  Paramètres  : instr = instance à consulter.                                * -*                                                                             * -*  Description : Indique la quantité d'opérandes présents dans l'instruction. * -*                                                                             * -*  Retour      : Nombre d'opérandes attachés.                                 * -*                                                                             * -*  Remarques   : -                                                            * -*                                                                             * -******************************************************************************/ +    extra = GET_ARCH_INSTR_EXTRA(instr); -size_t _g_arch_instruction_count_operands(const GArchInstruction *instr) -{ -    size_t result;                          /* Décompte à retourner        */ - -    result = count_flat_array_items(instr->operands); +    result = extra.flags;      return result;  } -/****************************************************************************** -*                                                                             * -*  Paramètres  : instr = instance à consulter.                                * -*                index = indice de l'opérande concerné.                       * -*                                                                             * -*  Description : Fournit un opérande donné d'une instruction.                 * -*                                                                             * -*  Retour      : Opérande trouvée.                                            * -*                                                                             * -*  Remarques   : -                                                            * -*                                                                             * -******************************************************************************/ - -GArchOperand *_g_arch_instruction_get_operand(const GArchInstruction *instr, size_t index) -{ -    GArchOperand *result;                   /* Opérande à retourner        */ -    GArchOperand **ptr;                     /* Adresse dans le tableau     */ - -    ptr = get_flat_array_item(instr->operands, index, sizeof(GArchOperand *)); - -    result = *ptr; - -    g_object_ref(G_OBJECT(result)); - -    return result; -} +/* ---------------------------------------------------------------------------------- */ +/*                     DEFINITION DES LIAISONS ENTRE INSTRUCTIONS                     */ +/* ---------------------------------------------------------------------------------- */  /******************************************************************************  *                                                                             * -*  Paramètres  : instr = instance à mettre à jour.                            * -*                old   = ancienne opérande à détacher.                        * -*                new   = nouvelle opérande à attacher.                        * +*  Paramètres  : instr = instruction dont les liens sont à consulter.         * +*                dir   = direction du lien recherché.                         * +*                type  = type de lien à détecter.                             *  *                                                                             * -*  Description : Remplace un opérande d'une instruction par un autre.         * +*  Description : Détermine si un type de lien existe dans une instruction.    *  *                                                                             * -*  Retour      : Bilan de l'opération.                                        * +*  Retour      : Bilan du statut courant de l'instruction.                    *  *                                                                             *  *  Remarques   : -                                                            *  *                                                                             *  ******************************************************************************/ -bool _g_arch_instruction_replace_operand(GArchInstruction *instr, GArchOperand *old, GArchOperand *new) +static bool _g_arch_instruction_has_link(const GArchInstruction *instr, compact_ins_link_t dir, InstructionLinkType type)  {      bool result;                            /* Bilan à retourner           */ -    size_t count;                           /* Nombre d'opérandes en place */ -    size_t i;                               /* Boucle de parcours          */ -    GArchOperand *op;                       /* Opérande à manipuler        */ - -    result = false; - -    count = _g_arch_instruction_count_operands(instr); - -    for (i = 0; i < count && !result; i++) -    { -        op = _g_arch_instruction_get_operand(instr, i); +    uint16_t i;                             /* Boucle de parcours          */ -        result = (op == old); - -        g_object_unref(G_OBJECT(op)); - -    } - -    if (result) -    { -        rpl_item_in_flat_array(instr->operands, i - 1, &new, sizeof(GArchOperand *)); +    assert(g_thick_object_check_lock(G_THICK_OBJECT(instr))); -        g_object_unref(G_OBJECT(old)); +    result = false; -    } +    for (i = 0; i < instr->link_count && !result; i++) +        result = COMPACT_INS_LINK_DIR(instr->links[i]) == dir;      return result; @@ -828,45 +600,22 @@ bool _g_arch_instruction_replace_operand(GArchInstruction *instr, GArchOperand *  /******************************************************************************  *                                                                             * -*  Paramètres  : instr  = instance à mettre à jour.                           * -*                target = instruction à venir dissocier.                      * +*  Paramètres  : instr = instruction dont les liens sont à consulter.         * +*                type  = type de lien à détecter.                             *  *                                                                             * -*  Description : Détache un opérande liée d'une instruction.                  * +*  Description : Détermine si un type de lien amène à une instruction.        *  *                                                                             * -*  Retour      : Bilan de l'opération.                                        * +*  Retour      : Bilan du statut courant de l'instruction.                    *  *                                                                             *  *  Remarques   : -                                                            *  *                                                                             *  ******************************************************************************/ -bool _g_arch_instruction_detach_operand(GArchInstruction *instr, GArchOperand *target) +bool g_arch_instruction_has_src_link(const GArchInstruction *instr, InstructionLinkType type)  {      bool result;                            /* Bilan à retourner           */ -    size_t count;                           /* Nombre d'opérandes en place */ -    size_t i;                               /* Boucle de parcours          */ -    GArchOperand *op;                       /* Opérande à manipuler        */ - -    result = false; - -    count = _g_arch_instruction_count_operands(instr); -    for (i = 0; i < count && !result; i++) -    { -        op = _g_arch_instruction_get_operand(instr, i); - -        result = (op == target); - -        g_object_unref(G_OBJECT(op)); - -    } - -    if (result) -    { -        rem_item_from_flat_array(&instr->operands, i - 1, sizeof(GArchOperand *)); - -        g_object_unref(G_OBJECT(target)); - -    } +    result = _g_arch_instruction_has_link(instr, COMPACT_INS_LINK_FROM, type);      return result; @@ -875,78 +624,22 @@ bool _g_arch_instruction_detach_operand(GArchInstruction *instr, GArchOperand *t  /******************************************************************************  *                                                                             * -*  Paramètres  : instr  = instance à consulter.                               * -*                target = instruction à venir retrouver.                      * +*  Paramètres  : instr = instruction dont les liens sont à consulter.         * +*                type  = type de lien à détecter.                             *  *                                                                             * -*  Description : Détermine le chemin conduisant à un opérande.                * +*  Description : Détermine si un type de lien émerge d'une instruction.       *  *                                                                             * -*  Retour      : Chemin d'accès à l'opérande ou NULL en cas d'absence.        * +*  Retour      : Bilan du statut courant de l'instruction.                    *  *                                                                             *  *  Remarques   : -                                                            *  *                                                                             *  ******************************************************************************/ -char *g_arch_instruction_find_operand_path(GArchInstruction *instr, const GArchOperand *target) +bool g_arch_instruction_has_dest_link(const GArchInstruction *instr, InstructionLinkType type)  { -    char *result;                           /* Chemin à retourner          */ -    size_t count;                           /* Nombre d'opérandes en place */ -    size_t i;                               /* Boucle de parcours          */ -    GArchOperand *op;                       /* Opérande à manipuler        */ -    int ret;                                /* Bilan d'une construction    */ -    char *sub_path;                         /* Sous-chemin emprunté        */ - -    result = NULL; - -    g_arch_instruction_lock_operands(instr); - -    count = _g_arch_instruction_count_operands(instr); - -    /* Première passe : accès direct */ - -    for (i = 0; i < count && result == NULL; i++) -    { -        op = _g_arch_instruction_get_operand(instr, i); - -        if (op == target) -        { -            ret = asprintf(&result, "%zu", i); -            if (ret == -1) -            { -                LOG_ERROR_N("asprintf"); -                result = NULL; -            } -        } - -        g_object_unref(G_OBJECT(op)); - -    } - -    /* Seconde passe : accès profond */ - -    for (i = 0; i < count && result == NULL; i++) -    { -        op = _g_arch_instruction_get_operand(instr, i); - -        sub_path = g_arch_operand_find_inner_operand_path(op, target); - -        if (sub_path != NULL) -        { -            ret = asprintf(&result, "%zu:%s", i, sub_path); -            if (ret == -1) -            { -                LOG_ERROR_N("asprintf"); -                result = NULL; -            } - -            free(sub_path); - -        } - -        g_object_unref(G_OBJECT(op)); - -    } +    bool result;                            /* Bilan à retourner           */ -    g_arch_instruction_unlock_operands(instr); +    result = _g_arch_instruction_has_link(instr, COMPACT_INS_LINK_TO, type);      return result; @@ -955,104 +648,65 @@ char *g_arch_instruction_find_operand_path(GArchInstruction *instr, const GArchO  /******************************************************************************  *                                                                             * -*  Paramètres  : instr = instance à consulter.                                * -*                path  = chemin d'accès à un opérande à retrouver.            * +*  Paramètres  : instr  = instruction dont les liens sont à consulter.        * +*                dir    = direction du lien recherché.                        * +*                linked = seconde instruction à considérer.                   *  *                                                                             * -*  Description : Obtient l'opérande correspondant à un chemin donné.          * +*  Description : Détermine si un lien existe entre deux instructions.         *  *                                                                             * -*  Retour      : Opérande trouvé ou NULL en cas d'échec.                      * +*  Retour      : Bilan du statut courant de l'instruction.                    *  *                                                                             *  *  Remarques   : -                                                            *  *                                                                             *  ******************************************************************************/ -GArchOperand *g_arch_instruction_get_operand_from_path(GArchInstruction *instr, const char *path) +static bool _g_arch_instruction_has_link_with(const GArchInstruction *instr, compact_ins_link_t dir, const GArchInstruction *linked)  { -    GArchOperand *result;                   /* Opérande trouvée à renvoyer */ -    size_t index;                           /* Indice de l'opérande visé   */ -    char *end;                              /* Poursuite du parcours ?     */ -    GArchOperand *found;                    /* Opérande trouvé             */ - -    result = NULL; - -    g_arch_instruction_lock_operands(instr); - -    /* Recherche au premier niveau */ - -    index = strtoul(path, &end, 10); - -    if ((index == ULONG_MAX && errno == ERANGE) || (index == 0 && errno == EINVAL)) -    { -        LOG_ERROR_N("strtoul"); -        goto done; -    } - -    found = _g_arch_instruction_get_operand(instr, index); -    if (found == NULL) goto done; - -    if (*end == '\0') -    { -        result = found; -        goto done; -    } - -    /* Recherche en profondeur */ - -    assert(*end == ':'); - -    result = g_arch_operand_get_inner_operand_from_path(found, end + 1); +    bool result;                            /* Bilan à retourner           */ +    uint16_t i;                             /* Boucle de parcours          */ -    g_object_unref(G_OBJECT(found)); +    assert(g_thick_object_check_lock(G_THICK_OBJECT(instr))); - done: +    result = false; -    g_arch_instruction_unlock_operands(instr); +    for (i = 0; i < instr->link_count && !result; i++) +        result = COMPACT_INS_LINK_PTR(instr->links[i]) == linked;      return result;  } - -/* ---------------------------------------------------------------------------------- */ -/*                     DEFINITION DES LIAISONS ENTRE INSTRUCTIONS                     */ -/* ---------------------------------------------------------------------------------- */ - -  /******************************************************************************  *                                                                             * -*  Paramètres  : instr = instruction à mettre à jour.                         * -*                src   = sélection de l'extrémité à traiter.                  * -*                lock  = indique le sens du verrouillage à mener.             * +*  Paramètres  : instr = instruction dont les liens sont à consulter.         * +*                src   = seconde instruction à considérer.                    *  *                                                                             * -*  Description : Met à disposition un encadrement des accès aux liens.        * +*  Description : Détermine si une instruction est source d'une autre.         *  *                                                                             * -*  Retour      : -                                                            * +*  Retour      : Bilan du statut courant de l'instruction.                    *  *                                                                             *  *  Remarques   : -                                                            *  *                                                                             *  ******************************************************************************/ -void g_arch_instruction_lock_unlock_links(GArchInstruction *instr, bool src, bool lock) +bool g_arch_instruction_has_src_link_with(const GArchInstruction *instr, const GArchInstruction *src)  { -    flat_array_t **array;                   /* Choix du tableau ciblé      */ +    bool result;                            /* Bilan à retourner           */ -    array = (src ? &instr->from : &instr->to); +    result = _g_arch_instruction_has_link_with(instr, COMPACT_INS_LINK_FROM, src); -    if (lock) -        lock_flat_array(array); -    else -        unlock_flat_array(array); +    return result;  }  /******************************************************************************  *                                                                             * -*  Paramètres  : instr = instruction dont les informations sont à consulter.  * -*                type  = type de lien à détecter.                             * +*  Paramètres  : instr = instruction dont les liens sont à consulter.         * +*                dest  = seconde instruction à considérer.                    *  *                                                                             * -*  Description : Détermine si un type de lien existe dans une instruction.    * +*  Description : Détermine si une instruction est destination d'une autre.    *  *                                                                             *  *  Retour      : Bilan du statut courant de l'instruction.                    *  *                                                                             * @@ -1060,30 +714,11 @@ void g_arch_instruction_lock_unlock_links(GArchInstruction *instr, bool src, boo  *                                                                             *  ******************************************************************************/ -bool g_arch_instruction_has_link(GArchInstruction *instr, InstructionLinkType type) +bool g_arch_instruction_has_dest_link_with(const GArchInstruction *instr, const GArchInstruction *dest)  {      bool result;                            /* Bilan à retourner           */ -    size_t count;                           /* Nombre de liens à parcourir */ -    size_t i;                               /* Boucle de parcours          */ -    const instr_link_t *dlink;              /* Définition de destination   */ - -    result = false; - -    g_arch_instruction_lock_dest(instr); -    count = g_arch_instruction_count_destinations(instr); - -    for (i = 0; i < count && !result; i++) -    { -        dlink = g_arch_instruction_get_destination(instr, i); - -        result = (dlink->type == type); - -        unref_instr_link(dlink); - -    } - -    g_arch_instruction_unlock_dest(instr); +    result = _g_arch_instruction_has_link_with(instr, COMPACT_INS_LINK_TO, dest);      return result; @@ -1092,54 +727,53 @@ bool g_arch_instruction_has_link(GArchInstruction *instr, InstructionLinkType ty  /******************************************************************************  *                                                                             * -*  Paramètres  : instr = instruction dont les informations sont à consulter.  * +*  Paramètres  : instr = instruction dont les informations sont à manipuler.  *  *                dest  = ligne visée par la liaison (côté destination).       * +*                type  = type de lien à construire.                           *  *                                                                             * -*  Description : Détermine si un lien est déjà établi entre deux instructions.* +*  Description : Etablit un lien entre deux instructions.                     *  *                                                                             * -*  Retour      : Bilan de l'état actuel des liaisons.                         * +*  Retour      : -                                                            *  *                                                                             *  *  Remarques   : -                                                            *  *                                                                             *  ******************************************************************************/ -bool g_arch_instruction_has_link_to(GArchInstruction *instr, const GArchInstruction *dest) +void g_arch_instruction_link(GArchInstruction *instr, GArchInstruction *dest, InstructionLinkType type)  { -    bool result;                            /* Bilan à retourner           */ -    size_t count;                           /* Nombre de liens à parcourir */ -    size_t i;                               /* Boucle de parcours          */ -    const instr_link_t *dlink;              /* Définition de destination   */ +    compact_ins_link_t new_from;            /* Nouvel enregistrement #1    */ +    compact_ins_link_t new_to;              /* Nouvel enregistrement #2    */ -    result = false; +    new_from = MAKE_COMPACT_INS_LINK(COMPACT_INS_LINK_FROM, instr, type); +    ref_object(instr); -    g_arch_instruction_lock_dest(instr); +    new_to = MAKE_COMPACT_INS_LINK(COMPACT_INS_LINK_TO, dest, type); +    ref_object(dest); -    count = g_arch_instruction_count_destinations(instr); +    g_thick_object_lock(G_THICK_OBJECT(instr)); +    g_thick_object_lock(G_THICK_OBJECT(dest)); -    for (i = 0; i < count && !result; i++) -    { -        dlink = g_arch_instruction_get_destination(instr, i); - -        result = (dlink->linked == dest); +    dest->links = realloc(dest->links, ++dest->link_count * sizeof(compact_ins_link_t)); -        unref_instr_link(dlink); +    dest->links[dest->link_count - 1] = new_from; -    } +    instr->links = realloc(instr->links, ++instr->link_count * sizeof(compact_ins_link_t)); -    g_arch_instruction_unlock_dest(instr); +    instr->links[instr->link_count - 1] = new_to; -    return result; +    g_thick_object_unlock(G_THICK_OBJECT(dest)); +    g_thick_object_unlock(G_THICK_OBJECT(instr));  }  /******************************************************************************  *                                                                             * -*  Paramètres  : instr = instruction dont les informations sont à consulter.  * +*  Paramètres  : instr = instruction dont les informations sont à manipuler.  *  *                dest  = ligne visée par la liaison (côté destination).       *  *                type  = type de lien à construire.                           *  *                                                                             * -*  Description : Etablit un lien entre deux instructions.                     * +*  Description : Supprime un lien entre deux instructions.                    *  *                                                                             *  *  Retour      : -                                                            *  *                                                                             * @@ -1147,43 +781,59 @@ bool g_arch_instruction_has_link_to(GArchInstruction *instr, const GArchInstruct  *                                                                             *  ******************************************************************************/ -void g_arch_instruction_link_with(GArchInstruction *instr, GArchInstruction *dest, InstructionLinkType type) +void g_arch_instruction_unlink(GArchInstruction *instr, GArchInstruction *dest, InstructionLinkType type)  { -    instr_link_t new_src;                   /* Nouveau lien à définir #1   */ -    instr_link_t new_dst;                   /* Nouveau lien à définir #2   */ +    compact_ins_link_t old_from;            /* Ancien enregistrement #1    */ +    compact_ins_link_t old_to;              /* Ancien enregistrement #2    */ +    uint16_t i_from;                        /* Boucle de parcours #1       */ +    uint16_t i_to;                          /* Boucle de parcours #2       */ +    bool status;                            /* Bilan des recherches        */ + +    old_from = MAKE_COMPACT_INS_LINK(COMPACT_INS_LINK_FROM, instr, type); + +    old_to = MAKE_COMPACT_INS_LINK(COMPACT_INS_LINK_TO, dest, type); -    /* Côté destination */ +    g_thick_object_lock(G_THICK_OBJECT(instr)); +    g_thick_object_lock(G_THICK_OBJECT(dest)); -    new_src.linked = instr; -    new_src.type = type; +    for (i_from = 0; i_from < dest->link_count; i_from++) +        if (dest->links[i_from] == old_from) +            break; -    ref_instr_link((&new_src)); +    for (i_to = 0; i_to < instr->link_count; i_to++) +        if (instr->links[i_to] == old_to) +            break; -    /* Côté point de départ */ +    assert((i_from < dest->link_count && i_to < instr->link_count) +           || (i_from == dest->link_count && i_to == instr->link_count)); -    new_dst.linked = dest; -    new_dst.type = type; +    status = (i_from < dest->link_count && i_to < instr->link_count); -    ref_instr_link((&new_dst)); +    if (status) +    { +        if ((i_from + 1) < dest->link_count) +            memmove(&dest->links[i_from], &dest->links[i_from + 1], +                    (dest->link_count - i_from - 1) * sizeof(compact_ins_link_t)); -    /* Ajout dans le respect d'une cohérence globale */ +        dest->links = realloc(dest->links, --dest->link_count * sizeof(compact_ins_link_t)); -    g_arch_instruction_lock_src(dest); -    g_arch_instruction_lock_dest(instr); +        if ((i_to + 1) < instr->link_count) +            memmove(&instr->links[i_to], &instr->links[i_to + 1], +                    (instr->link_count - i_to - 1) * sizeof(compact_ins_link_t)); -    add_item_to_flat_array(&dest->from, &new_src, sizeof(instr_link_t)); +        instr->links = realloc(instr->links, --instr->link_count * sizeof(compact_ins_link_t)); -    add_item_to_flat_array(&instr->to, &new_dst, sizeof(instr_link_t)); +    } -    g_arch_instruction_unlock_dest(instr); -    g_arch_instruction_unlock_src(dest); +    g_thick_object_unlock(G_THICK_OBJECT(dest)); +    g_thick_object_unlock(G_THICK_OBJECT(instr));  }  /******************************************************************************  *                                                                             * -*  Paramètres  : instr = instruction dont les informations sont à consulter.  * +*  Paramètres  : instr = instruction dont les informations sont à manipuler.  *  *                dest  = ligne visée par la liaison (côté destination).       *  *                old   = ancien type de lien construit.                       *  *                new   = nouveau type de lien à construire.                   * @@ -1199,67 +849,43 @@ void g_arch_instruction_link_with(GArchInstruction *instr, GArchInstruction *des  bool g_arch_instruction_change_link(GArchInstruction *instr, GArchInstruction *dest, InstructionLinkType old, InstructionLinkType new)  {      bool result;                            /* Bilan à retourner           */ -    size_t count;                           /* Raccourci pour la lecture   */ -    size_t i;                               /* Boucle de parcours          */ -    instr_link_t *slink;                    /* Définition de source        */ -    instr_link_t *dlink;                    /* Définition de destination   */ - -    result = false; +    compact_ins_link_t old_from;            /* Ancien enregistrement #1    */ +    compact_ins_link_t new_from;            /* Nouvel enregistrement #1    */ +    compact_ins_link_t old_to;              /* Ancien enregistrement #2    */ +    compact_ins_link_t new_to;              /* Nouvel enregistrement #2    */ +    uint16_t i_from;                        /* Boucle de parcours #1       */ +    uint16_t i_to;                          /* Boucle de parcours #2       */ -    /** -     * Note : pour la récupération des liens de sources et de destinations, -     * on n'utilise pas les fonctions g_arch_instruction_get_(source|destination)(), -     * qui renvoient un pointeur non modifiable. -     * -     * On a en effet besoin de modifier le type de lien. -     */ +    old_from = MAKE_COMPACT_INS_LINK(COMPACT_INS_LINK_FROM, instr, old); +    new_from = MAKE_COMPACT_INS_LINK(COMPACT_INS_LINK_FROM, instr, new); +    old_to = MAKE_COMPACT_INS_LINK(COMPACT_INS_LINK_TO, dest, old); +    new_to = MAKE_COMPACT_INS_LINK(COMPACT_INS_LINK_TO, dest, new); -    g_arch_instruction_lock_src(dest); +    g_thick_object_lock(G_THICK_OBJECT(instr)); +    g_thick_object_lock(G_THICK_OBJECT(dest)); -    /* Côté destination */ - -    count = g_arch_instruction_count_sources(dest); - -    for (i = 0; i < count; i++) -    { -        slink = get_flat_array_item(dest->from, i, sizeof(instr_link_t)); - -        if (slink->linked == instr && slink->type == old) +    for (i_from = 0; i_from < dest->link_count; i_from++) +        if (dest->links[i_from] == old_from)              break; -    } - -    if (i == count) -        goto gaicl_exit; +    for (i_to = 0; i_to < instr->link_count; i_to++) +        if (instr->links[i_to] == old_to) +            break; -    /* Côté point de départ */ +    assert((i_from < dest->link_count && i_to < instr->link_count) +           || (i_from == dest->link_count && i_to == instr->link_count)); -    count = g_arch_instruction_count_destinations(instr); +    result = (i_from < dest->link_count && i_to < instr->link_count); -    for (i = 0; i < count; i++) +    if (result)      { -        dlink = get_flat_array_item(instr->to, i, sizeof(instr_link_t)); - -        if (dlink->linked == dest && dlink->type == old) -            break; - +        dest->links[i_from] = new_from; +        instr->links[i_to] = new_to;      } -    if (i == count) -        goto gaicl_exit; - -    /* Si les deux extrémités sont raccord... */ - -    slink->type = new; - -    dlink->type = new; - -    result = true; - - gaicl_exit: - -    g_arch_instruction_unlock_src(dest); +    g_thick_object_unlock(G_THICK_OBJECT(dest)); +    g_thick_object_unlock(G_THICK_OBJECT(instr));      return result; @@ -1280,116 +906,92 @@ bool g_arch_instruction_change_link(GArchInstruction *instr, GArchInstruction *d  void g_arch_instruction_delete_all_links(GArchInstruction *instr)  { -    instr_link_t *link_src;                 /* Lien à supprimer #2         */ -    GArchInstruction *other;                /* Instruction de l'autre bout */ -    size_t count;                           /* Quantié de liens présents   */ -    size_t i;                               /* Boucle de parcours          */ -    instr_link_t *link_dst;                 /* Lien à supprimer #1         */ +    GArchInstruction *linked;               /* Autre instruction liée      */ +    InstructionLinkType type;               /* Type de liaison             */ -    /* Coté sources */ +    g_thick_object_lock(G_THICK_OBJECT(instr)); -    g_arch_instruction_lock_src(instr); - -    while (count_flat_array_items(instr->from) > 0) +    while (g_arch_instruction_count_src_links(instr) > 0)      { -        link_src = get_flat_array_item(instr->from, 0, sizeof(instr_link_t)); - -        other = link_src->linked; +        linked = g_arch_instruction_get_linked_source(instr, 0, &type); -        g_arch_instruction_lock_dest(other); +        g_thick_object_unlock(G_THICK_OBJECT(instr)); -        count = count_flat_array_items(other->to); +        g_arch_instruction_unlink(linked, instr, type); -        for (i = 0; i < count; i++) -        { -            link_dst = get_flat_array_item(other->to, i, sizeof(instr_link_t)); +        g_thick_object_lock(G_THICK_OBJECT(instr)); -            if (link_dst->linked == instr && link_dst->type == link_src->type) -            { -                unref_instr_link(link_dst); - -                rem_item_from_flat_array(&other->to, i, sizeof(instr_link_t)); - -                break; - -            } - -        } - -        assert(i < count); - -        g_arch_instruction_unlock_dest(other); - -        unref_instr_link(link_src); - -        rem_item_from_flat_array(&instr->from, 0, sizeof(instr_link_t)); +        unref_object(linked);      } -    g_arch_instruction_unlock_src(instr); - -    /* Coté destinations */ - -    g_arch_instruction_lock_dest(instr); - -    while (count_flat_array_items(instr->to) > 0) +    while (g_arch_instruction_count_dest_links(instr) > 0)      { -        link_dst = get_flat_array_item(instr->to, 0, sizeof(instr_link_t)); +        linked = g_arch_instruction_get_linked_destination(instr, 0, &type); -        other = link_dst->linked; +        g_thick_object_unlock(G_THICK_OBJECT(instr)); -        g_arch_instruction_lock_src(other); +        g_arch_instruction_unlink(instr, linked, type); -        count = count_flat_array_items(other->from); +        g_thick_object_lock(G_THICK_OBJECT(instr)); -        for (i = 0; i < count; i++) -        { -            link_src = get_flat_array_item(other->from, i, sizeof(instr_link_t)); +        unref_object(linked); -            if (link_src->linked == instr && link_src->type == link_dst->type) -            { -                unref_instr_link(link_src); - -                rem_item_from_flat_array(&other->from, i, sizeof(instr_link_t)); +    } -                break; +    g_thick_object_unlock(G_THICK_OBJECT(instr)); -            } +} -        } -        assert(i < count); +/****************************************************************************** +*                                                                             * +*  Paramètres  : instr = instruction dont les liens sont à consulter.         * +*                dir   = direction des liens à considérer.                    * +*                                                                             * +*  Description : Fournit la quantité d'instructions pointant vers une autre.  * +*                                                                             * +*  Retour      : Nombre de ces liens.                                         * +*                                                                             * +*  Remarques   : -                                                            * +*                                                                             * +******************************************************************************/ -        g_arch_instruction_unlock_src(other); +static size_t _g_arch_instruction_count_links(const GArchInstruction *instr, compact_ins_link_t dir) +{ +    size_t result;                          /* Nombre de liens à renvoyer  */ +    uint16_t i;                             /* Boucle de parcours          */ -        unref_instr_link(link_dst); +    assert(g_thick_object_check_lock(G_THICK_OBJECT(instr))); -        rem_item_from_flat_array(&instr->to, 0, sizeof(instr_link_t)); +    result = 0; -    } +    for (i = 0; i < instr->link_count; i++) +        if (COMPACT_INS_LINK_DIR(instr->links[i]) == dir) +            result++; -    g_arch_instruction_unlock_dest(instr); +    return result;  }  /******************************************************************************  *                                                                             * -*  Paramètres  : instr = instruction dont les informations sont à consulter.  * +*  Paramètres  : instr = instruction dont les liens sont à consulter.         *  *                                                                             * -*  Description : Fournit la quantité d'instructions pointant vers une autre.  * +*  Description : Fournit la quantité d'instructions placées en source.        *  *                                                                             * -*  Retour      : Nombre de ces origines.                                      * +*  Retour      : Nombre de ces liens.                                         *  *                                                                             *  *  Remarques   : -                                                            *  *                                                                             *  ******************************************************************************/ -size_t g_arch_instruction_count_sources(const GArchInstruction *instr) +size_t g_arch_instruction_count_src_links(const GArchInstruction *instr)  {      size_t result;                          /* Nombre de liens à renvoyer  */ -    result = count_flat_array_items(instr->from); +    result = _g_arch_instruction_count_links(instr, COMPACT_INS_LINK_FROM);      return result; @@ -1398,24 +1000,21 @@ size_t g_arch_instruction_count_sources(const GArchInstruction *instr)  /******************************************************************************  *                                                                             * -*  Paramètres  : instr = instruction dont les informations sont à consulter.  * -*                index = indice de l'élément à retrouver.                     * +*  Paramètres  : instr = instruction dont les liens sont à consulter.         *  *                                                                             * -*  Description : Fournit les détails d'une origine d'une instruction donnée.  * +*  Description : Fournit la quantité d'instructions placées en destination.   *  *                                                                             * -*  Retour      : Lien déterminé vers une instruction d'origine.               * +*  Retour      : Nombre de ces liens.                                         *  *                                                                             *  *  Remarques   : -                                                            *  *                                                                             *  ******************************************************************************/ -const instr_link_t *g_arch_instruction_get_source(GArchInstruction *instr, size_t index) +size_t g_arch_instruction_count_dest_links(const GArchInstruction *instr)  { -    instr_link_t *result;                   /* Détails présents à renvoyer */ - -    result = get_flat_array_item(instr->from, index, sizeof(instr_link_t)); +    size_t result;                          /* Nombre de liens à renvoyer  */ -    ref_instr_link(result); +    result = _g_arch_instruction_count_links(instr, COMPACT_INS_LINK_TO);      return result; @@ -1424,43 +1023,47 @@ const instr_link_t *g_arch_instruction_get_source(GArchInstruction *instr, size_  /******************************************************************************  *                                                                             * -*  Paramètres  : instr = instruction dont les informations sont à consulter.  * -*                count = quantié de liens présents. [OUT]                     * +*  Paramètres  : instr = instruction dont les liens sont à consulter.         * +*                index = indice de l'élément à retrouver.                     * +*                dir   = direction des liens à considérer.                    * +*                type  = type de lien enregistré. [OUT]                       *  *                                                                             * -*  Description : Fournit tous les détails d'origine d'une instruction donnée. * +*  Description : Fournit les détails d'un lien donné avec une instruction.    *  *                                                                             * -*  Retour      : Liens vers des instructions d'origine à libérer.             * +*  Retour      : Autre instruction pointée par l'instruction, voire NULL.     *  *                                                                             *  *  Remarques   : -                                                            *  *                                                                             *  ******************************************************************************/ -instr_link_t *g_arch_instruction_get_sources(GArchInstruction *instr, size_t *count) +static GArchInstruction *_g_arch_instruction_get_linked_instruction(const GArchInstruction *instr, size_t index, compact_ins_link_t dir, InstructionLinkType *type)  { -    instr_link_t *result;                   /* Détails présents à renvoyer */ -    size_t i;                               /* Boucle de parcours          */ -    const instr_link_t *link;               /* Lien à fournir              */ - -    g_arch_instruction_lock_src(instr); +    GArchInstruction *result;               /* Instance ciblée à renvoyer  */ +    uint16_t i;                             /* Boucle de parcours          */ -    *count = g_arch_instruction_count_sources(instr); +    assert(g_thick_object_check_lock(G_THICK_OBJECT(instr))); -    if (*count == 0) -        result = NULL; +    result = NULL; +    *type = ILT_COUNT; -    else +    for (i = 0; i < instr->link_count; i++)      { -        result = (instr_link_t *)malloc(*count * sizeof(instr_link_t)); +        if (COMPACT_INS_LINK_DIR(instr->links[i]) != dir) +            continue; -        for (i = 0; i < *count; i++) +        if (index == 0)          { -            link = g_arch_instruction_get_source(instr, i); -            memcpy(&result[i], link, sizeof(instr_link_t)); +            result = COMPACT_INS_LINK_PTR(instr->links[i]); +            *type = COMPACT_INS_LINK_TYPE(instr->links[i]);          } +        else +            index--; +      } -    g_arch_instruction_unlock_src(instr); +    if (result != NULL) +        ref_object(result);      return result; @@ -1469,21 +1072,23 @@ instr_link_t *g_arch_instruction_get_sources(GArchInstruction *instr, size_t *co  /******************************************************************************  *                                                                             * -*  Paramètres  : instr = instruction dont les informations sont à consulter.  * +*  Paramètres  : instr = instruction dont les liens sont à consulter.         * +*                index = indice de l'élément à retrouver.                     * +*                type  = type de lien enregistré. [OUT]                       *  *                                                                             * -*  Description : Donne le nombre d'instructions non naturellement suivantes.  * +*  Description : Fournit les détails d'une source donnée d'une instruction.   *  *                                                                             * -*  Retour      : Nombre de ces destinations.                                  * +*  Retour      : Autre instruction pointée par l'instruction, voire NULL.     *  *                                                                             *  *  Remarques   : -                                                            *  *                                                                             *  ******************************************************************************/ -size_t g_arch_instruction_count_destinations(const GArchInstruction *instr) +GArchInstruction *g_arch_instruction_get_linked_source(const GArchInstruction *instr, size_t index, InstructionLinkType *type)  { -    size_t result;                          /* Nombre de liens à renvoyer  */ +    GArchInstruction *result;               /* Instance ciblée à renvoyer  */ -    result = count_flat_array_items(instr->to); +    result = _g_arch_instruction_get_linked_instruction(instr, index, COMPACT_INS_LINK_FROM, type);      return result; @@ -1492,71 +1097,54 @@ size_t g_arch_instruction_count_destinations(const GArchInstruction *instr)  /******************************************************************************  *                                                                             * -*  Paramètres  : instr = instruction dont les informations sont à consulter.  * +*  Paramètres  : instr = instruction dont les liens sont à consulter.         *  *                index = indice de l'élément à retrouver.                     * +*                type  = type de lien enregistré. [OUT]                       *  *                                                                             * -*  Description : Fournit les détails d'une destination d'une instruction.     * +*  Description : Fournit les détails d'une destination donnée d'une instruct. *  *                                                                             * -*  Retour      : Lien déterminé vers une instruction de destination.          * +*  Retour      : Autre instruction pointée par l'instruction, voire NULL.     *  *                                                                             *  *  Remarques   : -                                                            *  *                                                                             *  ******************************************************************************/ -const instr_link_t *g_arch_instruction_get_destination(GArchInstruction *instr, size_t index) +GArchInstruction *g_arch_instruction_get_linked_destination(const GArchInstruction *instr, size_t index, InstructionLinkType *type)  { -    instr_link_t *result;                   /* Détails présents à renvoyer */ - -    result = get_flat_array_item(instr->to, index, sizeof(instr_link_t)); +    GArchInstruction *result;               /* Instance ciblée à renvoyer  */ -    ref_instr_link(result); +    result = _g_arch_instruction_get_linked_instruction(instr, index, COMPACT_INS_LINK_TO, type);      return result;  } + +/* ---------------------------------------------------------------------------------- */ +/*                             MANIPULATION DES OPERANDES                             */ +/* ---------------------------------------------------------------------------------- */ + +  /******************************************************************************  *                                                                             * -*  Paramètres  : instr = instruction dont les informations sont à consulter.  * -*                type  = type de lien recherché.                              * +*  Paramètres  : instr = instance à consulter.                                *  *                                                                             * -*  Description : Fournit la destination d'une instruction et d'un type donné. * +*  Description : Indique la quantité d'opérandes présents dans l'instruction. *  *                                                                             * -*  Retour      : Instruction de destination trouvée ou NULL.                  * +*  Retour      : Nombre d'opérandes attachés.                                 *  *                                                                             *  *  Remarques   : -                                                            *  *                                                                             *  ******************************************************************************/ -GArchInstruction *g_arch_instruction_get_given_destination(GArchInstruction *instr, InstructionLinkType type) +size_t g_arch_instruction_count_operands(const GArchInstruction *instr)  { -    GArchInstruction *result;               /* Résultat à remonter         */ -    size_t count;                           /* Nombre de liens à parcourir */ -    size_t i;                               /* Boucle de parcours          */ -    const instr_link_t *dest;               /* Destination à étudier       */ - -    result = NULL; - -    g_arch_instruction_lock_dest(instr); - -    count = g_arch_instruction_count_destinations(instr); - -    for (i = 0; i < count && result == NULL; i++) -    { -        dest = g_arch_instruction_get_destination(instr, i); - -        if (dest->type == type) -        { -            result = dest->linked; -            g_object_ref(G_OBJECT(result)); -        } +    size_t result;                          /* Décompte à retourner        */ -        unref_instr_link(dest); +    assert(g_thick_object_check_lock(G_THICK_OBJECT(instr))); -    } - -    g_arch_instruction_unlock_dest(instr); +    result = count_flat_array_items(instr->operands);      return result; @@ -1565,56 +1153,45 @@ GArchInstruction *g_arch_instruction_get_given_destination(GArchInstruction *ins  /******************************************************************************  *                                                                             * -*  Paramètres  : instr = instruction dont les informations sont à consulter.  * -*                count = quantié de liens présents. [OUT]                     * +*  Paramètres  : instr   = instance à mettre à jour.                          * +*                operand = instruction à venir associer.                      *  *                                                                             * -*  Description : Fournit tous les détails de destination d'une instruction.   * +*  Description : Attache un opérande supplémentaire à une instruction.        *  *                                                                             * -*  Retour      : Liens vers des instructions de destination à libérer.        * +*  Retour      : -                                                            *  *                                                                             *  *  Remarques   : -                                                            *  *                                                                             *  ******************************************************************************/ -instr_link_t *g_arch_instruction_get_destinations(GArchInstruction *instr, size_t *count) +void g_arch_instruction_attach_operand(GArchInstruction *instr, GArchOperand *operand)  { -    instr_link_t *result;                   /* Détails présents à renvoyer */ -    size_t i;                               /* Boucle de parcours          */ -    const instr_link_t *link;               /* Lien à fournir              */ - -    g_arch_instruction_lock_dest(instr); - -    *count = g_arch_instruction_count_destinations(instr); +    GSingletonFactory *factory;             /* Unise à instances uniques   */ +    GSingletonCandidate *singleton;         /* Instance retenue            */ +    GArchOperand *stored;                   /* Forme d'opérande conservée  */ -    if (*count == 0) -        result = NULL; +    assert(g_thick_object_check_lock(G_THICK_OBJECT(instr))); -    else -    { -        result = (instr_link_t *)malloc(*count * sizeof(instr_link_t)); +    factory = get_operands_factory(); -        for (i = 0; i < *count; i++) -        { -            link = g_arch_instruction_get_destination(instr, i); -            memcpy(&result[i], link, sizeof(instr_link_t)); -        } +    singleton = g_singleton_factory_get_instance(factory, G_SINGLETON_CANDIDATE(operand)); -    } +    unref_object(factory); -    g_arch_instruction_unlock_dest(instr); +    stored = G_ARCH_OPERAND(singleton); -    return result; +    add_item_to_flat_array(&instr->operands, &stored, sizeof(GArchOperand *));  }  /******************************************************************************  *                                                                             * -*  Paramètres  : instr   = élément GLib à constuire.                          * -*                storage = conservateur de données à manipuler ou NULL.       * -*                pbuf    = zone tampon à lire.                                * +*  Paramètres  : instr = instance à mettre à jour.                            * +*                old   = ancienne opérande à détacher.                        * +*                new   = nouvelle opérande à attacher.                        *  *                                                                             * -*  Description : Charge un contenu depuis une mémoire tampon.                 * +*  Description : Remplace un opérande d'une instruction par un autre.         *  *                                                                             *  *  Retour      : Bilan de l'opération.                                        *  *                                                                             * @@ -1622,40 +1199,47 @@ instr_link_t *g_arch_instruction_get_destinations(GArchInstruction *instr, size_  *                                                                             *  ******************************************************************************/ -static bool g_arch_instruction_load_destinations(GArchInstruction *instr, GObjectStorage *storage, packed_buffer_t *pbuf) +bool g_arch_instruction_replace_operand(GArchInstruction *instr, GArchOperand *old, GArchOperand *new)  {      bool result;                            /* Bilan à retourner           */ -    uleb128_t count;                        /* Nombre de liens à charger   */ -    uleb128_t i;                            /* Boucle de parcours          */ -    GArchInstruction *linked;               /* Lien vers une instruction   */ -    uleb128_t type;                         /* Valeur ULEB128 à charger    */ +    size_t count;                           /* Nombre d'opérandes en place */ +    size_t i;                               /* Boucle de parcours          */ +    GArchOperand *op;                       /* Opérande à manipuler        */ +    GSingletonFactory *factory;             /* Unise à instances uniques   */ +    GSingletonCandidate *singleton;         /* Instance retenue            */ +    GArchOperand *stored;                   /* Forme d'opérande conservée  */ -    g_arch_instruction_lock_dest(instr); +    assert(g_thick_object_check_lock(G_THICK_OBJECT(instr))); -    result = unpack_uleb128(&count, pbuf); +    result = false; -    for (i = 0; i < count && result; i++) +    count = g_arch_instruction_count_operands(instr); + +    for (i = 0; i < count && !result; i++)      { -        linked = G_ARCH_INSTRUCTION(g_object_storage_unpack_object(storage, "instructions", pbuf)); -        if (linked == NULL) -        { -            result = false; -            break; -        } +        op = g_arch_instruction_get_operand(instr, i); -        result = unpack_uleb128(&type, pbuf); -        if (!result) -        { -            g_object_unref(G_OBJECT(linked)); -            break; -        } +        result = (op == old); -        g_arch_instruction_link_with(instr, linked, type); -        g_object_unref(G_OBJECT(linked)); +        unref_object(op);      } -    g_arch_instruction_unlock_dest(instr); +    if (result) +    { +        factory = get_operands_factory(); + +        singleton = g_singleton_factory_get_instance(factory, G_SINGLETON_CANDIDATE(new)); + +        unref_object(factory); + +        stored = G_ARCH_OPERAND(singleton); + +        rpl_item_in_flat_array(instr->operands, i - 1, &stored, sizeof(GArchOperand *)); + +        unref_object(old); + +    }      return result; @@ -1664,11 +1248,10 @@ static bool g_arch_instruction_load_destinations(GArchInstruction *instr, GObjec  /******************************************************************************  *                                                                             * -*  Paramètres  : instr   = instruction dont les informations sont à consulter.* -*                storage = conservateur de données à manipuler ou NULL.       * -*                pbuf    = zone tampon à remplir.                             * +*  Paramètres  : instr  = instance à mettre à jour.                           * +*                target = instruction à venir dissocier.                      *  *                                                                             * -*  Description : Sauvegarde toutes les destinations d'une instruction.        * +*  Description : Détache un opérande liée d'une instruction.                  *  *                                                                             *  *  Retour      : Bilan de l'opération.                                        *  *                                                                             * @@ -1676,87 +1259,67 @@ static bool g_arch_instruction_load_destinations(GArchInstruction *instr, GObjec  *                                                                             *  ******************************************************************************/ -bool g_arch_instruction_store_destinations(GArchInstruction *instr, GObjectStorage *storage, packed_buffer_t *pbuf) +bool g_arch_instruction_detach_operand(GArchInstruction *instr, GArchOperand *target)  {      bool result;                            /* Bilan à retourner           */ -    size_t count;                           /* Nombre d'éléments à traiter */ -    size_t kept;                            /* Nombre de liens conservés   */ +    size_t count;                           /* Nombre d'opérandes en place */      size_t i;                               /* Boucle de parcours          */ -    const instr_link_t *link;               /* Lien vers une instruction   */ - -    g_arch_instruction_lock_dest(instr); +    GArchOperand *op;                       /* Opérande à manipuler        */ -    count = g_arch_instruction_count_destinations(instr); +    assert(g_thick_object_check_lock(G_THICK_OBJECT(instr))); -    /** -     * Le type de lien ILT_REF n'est mis en place que lors de la création -     * d'opérandes de type G_TYPE_TARGET_OPERAND, et sera donc remis en place -     * dynamiquement lors de la restauration de ces derniers. -     */ +    result = false; -    kept = 0; +    count = g_arch_instruction_count_operands(instr); -    for (i = 0; i < count; i++) +    for (i = 0; i < count && !result; i++)      { -        link = g_arch_instruction_get_destination(instr, i); +        op = g_arch_instruction_get_operand(instr, i); -        if (link->type != ILT_REF) -            kept++; +        result = (op == target); -        unref_instr_link(link); +        unref_object(op);      } -    result = pack_uleb128((uleb128_t []){ kept }, pbuf); - -    for (i = 0; i < count && result; i++) +    if (result)      { -        link = g_arch_instruction_get_destination(instr, i); - -        if (link->type != ILT_REF) -        { -            result = g_object_storage_pack_object(storage, "instructions", -                                                  G_SERIALIZABLE_OBJECT(link->linked), pbuf); - -            if (result) -                result = pack_uleb128((uleb128_t []){ link->type }, pbuf); - -        } +        rem_item_from_flat_array(&instr->operands, i - 1, sizeof(GArchOperand *)); -        unref_instr_link(link); +        unref_object(target);      } -    g_arch_instruction_unlock_dest(instr); -      return result;  } - -/* ---------------------------------------------------------------------------------- */ -/*                       CONVERSIONS DU FORMAT DES INSTRUCTIONS                       */ -/* ---------------------------------------------------------------------------------- */ - -  /******************************************************************************  *                                                                             * -*  Paramètres  : instr = instruction d'assemblage à consulter.                * +*  Paramètres  : instr = instance à consulter.                                * +*                index = indice de l'opérande concerné.                       *  *                                                                             * -*  Description : Fournit le nom humain de l'instruction manipulée.            * +*  Description : Fournit un opérande donné d'une instruction.                 *  *                                                                             * -*  Retour      : Mot clef de bas niveau.                                      * +*  Retour      : Opérande trouvée.                                            *  *                                                                             *  *  Remarques   : -                                                            *  *                                                                             *  ******************************************************************************/ -const char *g_arch_instruction_get_keyword(GArchInstruction *instr) +GArchOperand *g_arch_instruction_get_operand(const GArchInstruction *instr, size_t index)  { -    const char *result;                     /* Désignation à retourner     */ +    GArchOperand *result;                   /* Opérande à retourner        */ +    GArchOperand **ptr;                     /* Adresse dans le tableau     */ + +    assert(g_thick_object_check_lock(G_THICK_OBJECT(instr))); -    result = G_ARCH_INSTRUCTION_GET_CLASS(instr)->get_keyword(instr); +    ptr = get_flat_array_item(instr->operands, index, sizeof(GArchOperand *)); + +    result = *ptr; + +    ref_object(result);      return result; @@ -1765,450 +1328,396 @@ const char *g_arch_instruction_get_keyword(GArchInstruction *instr)  /******************************************************************************  *                                                                             * -*  Paramètres  : instr = instruction d'assemblage à consulter.                * +*  Paramètres  : instr  = instance à consulter.                               * +*                target = instruction à venir retrouver.                      *  *                                                                             * -*  Description : Construit un petit résumé concis de l'instruction.           * +*  Description : Détermine le chemin conduisant à un opérande.                *  *                                                                             * -*  Retour      : Chaîne de caractères à libérer après usage ou NULL.          * +*  Retour      : Chemin d'accès à l'opérande ou NULL en cas d'absence.        *  *                                                                             *  *  Remarques   : -                                                            *  *                                                                             *  ******************************************************************************/ -char *g_arch_instruction_build_tooltip(const GArchInstruction *instr) +char *g_arch_instruction_find_operand_path(GArchInstruction *instr, const GArchOperand *target)  { -    char *result;                           /* Description à retourner     */ -    GArchInstructionClass *class;           /* Classe des instructions     */ +    char *result;                           /* Chemin à retourner          */ +    size_t count;                           /* Nombre d'opérandes en place */ +    size_t i;                               /* Boucle de parcours          */ +    GArchOperand *op;                       /* Opérande à manipuler        */ +    int ret;                                /* Bilan d'une construction    */ +    char *sub_path;                         /* Sous-chemin emprunté        */ -    class = G_ARCH_INSTRUCTION_GET_CLASS(instr); +    result = NULL; -    if (class->build_tooltip != NULL) -        result = class->build_tooltip(instr); +    g_thick_object_lock(G_THICK_OBJECT(instr)); -    else -        result = NULL; +    count = g_arch_instruction_count_operands(instr); -    return result; +    /* Première passe : accès direct */ -} +    for (i = 0; i < count && result == NULL; i++) +    { +        op = g_arch_instruction_get_operand(instr, i); +        if (op == target) +        { +            ret = asprintf(&result, "%zu", i); +            if (ret == -1) +            { +                LOG_ERROR_N("asprintf"); +                result = NULL; +            } +        } -/****************************************************************************** -*                                                                             * -*  Paramètres  : instr = instruction d'assemblage à consulter.                * -*                                                                             * -*  Description : Fournit une description pour l'instruction manipulée.        * -*                                                                             * -*  Retour      : Chaîne de caractères avec balises éventuelles.               * -*                                                                             * -*  Remarques   : -                                                            * -*                                                                             * -******************************************************************************/ +        unref_object(op); -const char *g_arch_instruction_get_description(const GArchInstruction *instr) -{ -    const char *result;                     /* Description à retourner     */ +    } -    result = G_ARCH_INSTRUCTION_GET_CLASS(instr)->get_desc(instr); +    /* Seconde passe : accès profond */ -    return result; -   -} +    for (i = 0; i < count && result == NULL; i++) +    { +        op = g_arch_instruction_get_operand(instr, i); +        sub_path = NULL;//g_arch_operand_find_inner_operand_path(op, target); +        if (sub_path != NULL) +        { +            ret = asprintf(&result, "%zu:%s", i, sub_path); +            if (ret == -1) +            { +                LOG_ERROR_N("asprintf"); +                result = NULL; +            } -/* ---------------------------------------------------------------------------------- */ -/*                          OFFRE DE CAPACITES DE GENERATION                          */ -/* ---------------------------------------------------------------------------------- */ +            free(sub_path); +        } -/****************************************************************************** -*                                                                             * -*  Paramètres  : instr = générateur à consulter.                              * -*                                                                             * -*  Description : Indique le nombre de ligne prêtes à être générées.           * -*                                                                             * -*  Retour      : Nombre de lignes devant apparaître au final.                 * -*                                                                             * -*  Remarques   : -                                                            * -*                                                                             * -******************************************************************************/ +        unref_object(op); -static size_t g_arch_instruction_count_lines(const GArchInstruction *instr) -{ -    return 1; +    } -} +    g_thick_object_unlock(G_THICK_OBJECT(instr)); +    return result; -#ifdef INCLUDE_GTK_SUPPORT +}  /******************************************************************************  *                                                                             * -*  Paramètres  : instr  = générateur à consulter.                             * -*                x      = position géographique sur la ligne concernée.       * -*                index  = indice de cette même ligne dans le tampon global.   * -*                repeat = indice d'utilisations successives du générateur.    * -*                cursor = emplacement à constituer. [OUT]                     * +*  Paramètres  : instr = instance à consulter.                                * +*                path  = chemin d'accès à un opérande à retrouver.            *  *                                                                             * -*  Description : Retrouve l'emplacement correspondant à une position donnée.  * +*  Description : Obtient l'opérande correspondant à un chemin donné.          *  *                                                                             * -*  Retour      : -                                                            * +*  Retour      : Opérande trouvé ou NULL en cas d'échec.                      *  *                                                                             *  *  Remarques   : -                                                            *  *                                                                             *  ******************************************************************************/ -static void g_arch_instruction_compute_cursor(const GArchInstruction *instr, gint x, size_t index, size_t repeat, GLineCursor **cursor) +GArchOperand *g_arch_instruction_get_operand_from_path(GArchInstruction *instr, const char *path)  { -    *cursor = g_binary_cursor_new(); +    GArchOperand *result;                   /* Opérande trouvée à renvoyer */ +    size_t index;                           /* Indice de l'opérande visé   */ +    char *end;                              /* Poursuite du parcours ?     */ +    GArchOperand *found;                    /* Opérande trouvé             */ -    g_binary_cursor_update(G_BINARY_CURSOR(*cursor), get_mrange_addr(&instr->range)); +    result = NULL; -} +    g_thick_object_lock(G_THICK_OBJECT(instr)); +    /* Recherche au premier niveau */ -/****************************************************************************** -*                                                                             * -*  Paramètres  : instr  = générateur à consulter.                             * -*                index  = indice de cette même ligne dans le tampon global.   * -*                repeat = indice d'utilisations successives du générateur.    * -*                cursor = emplacement à analyser.                             * -*                                                                             * -*  Description : Détermine si le conteneur s'inscrit dans une plage donnée.   * -*                                                                             * -*  Retour      : Bilan de la détermination, utilisable en comparaisons.       * -*                                                                             * -*  Remarques   : -                                                            * -*                                                                             * -******************************************************************************/ +    index = strtoul(path, &end, 10); -static int g_arch_instruction_contain_cursor(const GArchInstruction *instr, size_t index, size_t repeat, const GLineCursor *cursor) -{ -    int result;                             /* Conclusion à retourner      */ -    vmpa2t addr;                            /* Autre emplacement à comparer*/ +    if ((index == ULONG_MAX && errno == ERANGE) || (index == 0 && errno == EINVAL)) +    { +        LOG_ERROR_N("strtoul"); +        goto done; +    } + +    found = g_arch_instruction_get_operand(instr, index); +    if (found == NULL) goto done; + +    if (*end == '\0') +    { +        result = found; +        goto done; +    } + +    /* Recherche en profondeur */ + +    assert(*end == ':'); + +    result = NULL;//g_arch_operand_get_inner_operand_from_path(found, end + 1); -    assert(G_IS_BINARY_CURSOR(cursor)); +    unref_object(found); -    g_binary_cursor_retrieve(G_BINARY_CURSOR(cursor), &addr); + done: -    result = cmp_mrange_with_vmpa(&instr->range, &addr); +    g_thick_object_unlock(G_THICK_OBJECT(instr));      return result;  } -#endif + +/* ---------------------------------------------------------------------------------- */ +/*                     MECANISMES DE CONSERVATION ET RESTAURATION                     */ +/* ---------------------------------------------------------------------------------- */  /******************************************************************************  *                                                                             * -*  Paramètres  : instr  = générateur à consulter.                             * -*                index  = indice de cette même ligne dans le tampon global.   * -*                repeat = indice d'utilisations successives du générateur.    * +*  Paramètres  : object  = élément GLib à constuire.                          * +*                storage = conservateur de données à manipuler.               * +*                fd      = flux ouvert en lecture.                            *  *                                                                             * -*  Description : Renseigne sur les propriétés liées à un générateur.          * +*  Description : Charge un objet depuis un flux de données.                   *  *                                                                             * -*  Retour      : Propriétés particulières associées.                          * +*  Retour      : Bilan de l'opération.                                        *  *                                                                             *  *  Remarques   : -                                                            *  *                                                                             *  ******************************************************************************/ -static BufferLineFlags g_arch_instruction_get_flags2(const GArchInstruction *instr, size_t index, size_t repeat) +static bool g_arch_instruction_load(GSerializableObject *object, GObjectStorage *storage, int fd)  { -    return BLF_HAS_CODE; +    bool result;                            /* Bilan à retourner           */ +    uleb128_t extra;                        /* Données embarquées          */ + +    /* Propriétés internes */ + +    result = load_uleb128(&extra, fd); + +    if (result) +        g_thick_object_set_extra(G_THICK_OBJECT(object), extra); + +    /* Liaisons avec d'autres instructions */ + +    return result;  }  /******************************************************************************  *                                                                             * -*  Paramètres  : instr   = instruction d'assemblage à représenter.            * -*                line    = ligne de rendu à compléter.                        * -*                index   = indice de cette même ligne dans le tampon global.  * -*                repeat  = indice d'utilisations successives du générateur.   * -*                content = éventuel contenu binaire brut à imprimer.          * +*  Paramètres  : object  = élément GLib à consulter.                          * +*                storage = conservateur de données à manipuler.               * +*                fd      = flux ouvert en écriture.                           *  *                                                                             * -*  Description : Ajoute à un tampon GLib le contenu de l'instance spécifiée.  * +*  Description : Sauvegarde un objet dans un flux de données.                 *  *                                                                             * -*  Retour      : -                                                            * +*  Retour      : Bilan de l'opération.                                        *  *                                                                             *  *  Remarques   : -                                                            *  *                                                                             *  ******************************************************************************/ -static void _g_arch_instruction_print(GArchInstruction *instr, GBufferLine *line, size_t index, size_t repeat, const GBinContent *content) +static bool g_arch_instruction_store(const GSerializableObject *object, GObjectStorage *storage, int fd)  { -    const char *key;                        /* Mot clef principal          */ -    size_t klen;                            /* Taille de ce mot clef       */ -    size_t count;                           /* Nombre d'opérandes en place */ +    bool result;                            /* Bilan à retourner           */ +    GArchInstruction *instr;                /* Version spécialisée         */ +    size_t src_count;                       /* Quantité de sources         */ +    size_t dest_count;                      /* Quantité de destinations    */ +    off64_t *ins_offsets;                   /* Emplacements d'instructions */      size_t i;                               /* Boucle de parcours          */ -    GArchOperand *op;                       /* Opérande à manipuler        */ +    GArchInstruction *linked;               /* Instruction liée            */ +    size_t op_count;                        /* Quantité d'opérandes        */ +    off64_t *op_offsets;                    /* Emplacements d'opérandes    */ +    GArchOperand *op;                       /* Opérande à traiter          */ +    guint extra;                            /* Données embarquées          */ +    InstructionLinkType type;               /* Type de lien                */ -    g_buffer_line_fill_phys(line, DLC_PHYSICAL, MDS_32_BITS_UNSIGNED, get_mrange_addr(&instr->range)); +    assert(g_thick_object_check_lock(G_THICK_OBJECT(object))); -    g_buffer_line_fill_virt(line, DLC_VIRTUAL, MDS_32_BITS_UNSIGNED, get_mrange_addr(&instr->range)); +    /* Préparation des références aux instructions liées */ -    g_buffer_line_fill_content(line, DLC_BINARY, content, &instr->range, VMPA_NO_PHYSICAL); +    instr = G_ARCH_INSTRUCTION(object); -    /* Instruction proprement dite */ +    src_count = g_arch_instruction_count_src_links(instr); +    dest_count = g_arch_instruction_count_dest_links(instr); -    key = g_arch_instruction_get_keyword(instr); -    klen = strlen(key); +    ins_offsets = malloc((src_count + dest_count) * sizeof(off64_t)); -    g_buffer_line_append_text(line, DLC_ASSEMBLY_HEAD, key, klen, RTT_INSTRUCTION, G_OBJECT(instr)); +    for (i = 0; i < src_count && result; i++) +    { +        linked = g_arch_instruction_get_linked_source(instr, i, (InstructionLinkType []) { 0 }); -    /* Liste des opérandes */ +        result = g_object_storage_store_object(storage, "instructions", +                                               G_SERIALIZABLE_OBJECT(linked), &ins_offsets[i]); -    g_arch_instruction_lock_operands(instr); +        unref_object(linked); -    count = _g_arch_instruction_count_operands(instr); +    } -    if (count > 0) +    for (i = 0; i < dest_count && result; i++)      { -        op = _g_arch_instruction_get_operand(instr, 0); -        g_arch_operand_print(op, line); -        g_object_unref(G_OBJECT(op)); +        linked = g_arch_instruction_get_linked_destination(instr, i, (InstructionLinkType []) { 0 }); -        for (i = 1; i < count; i++) -        { -            g_buffer_line_append_text(line, DLC_ASSEMBLY, ",", 1, RTT_PUNCT, NULL); -            g_buffer_line_append_text(line, DLC_ASSEMBLY, " ", 1, RTT_RAW, NULL); +        result = g_object_storage_store_object(storage, "instructions", +                                               G_SERIALIZABLE_OBJECT(linked), &ins_offsets[src_count + i]); -            op = _g_arch_instruction_get_operand(instr, i); +        unref_object(linked); -            g_arch_operand_print(op, line); +    } -            g_object_unref(G_OBJECT(op)); +    if (!result) +        goto exit_with_ins_off; -        } +    /* Préparation des références aux opérandes embarqués */ -    } +    op_count = g_arch_instruction_count_operands(instr); -    g_arch_instruction_unlock_operands(instr); +    op_offsets = malloc(op_count * sizeof(off64_t)); -} +    for (i = 0; i < op_count && result; i++) +    { +        op = g_arch_instruction_get_operand(instr, i); +        result = g_object_storage_store_object(storage, "operandss", +                                               G_SERIALIZABLE_OBJECT(op), &op_offsets[i]); -/****************************************************************************** -*                                                                             * -*  Paramètres  : instr   = générateur à utiliser pour l'impression.           * -*                line    = ligne de rendu à compléter.                        * -*                index   = indice de cette même ligne dans le tampon global.  * -*                repeat  = indice d'utilisations successives du générateur.   * -*                content = éventuel contenu binaire brut à imprimer.          * -*                                                                             * -*  Description : Imprime dans une ligne de rendu le contenu représenté.       * -*                                                                             * -*  Retour      : -                                                            * -*                                                                             * -*  Remarques   : -                                                            * -*                                                                             * -******************************************************************************/ +        unref_object(op); -static void g_arch_instruction_print(GArchInstruction *instr, GBufferLine *line, size_t index, size_t repeat, const GBinContent *content) -{ -    G_ARCH_INSTRUCTION_GET_CLASS(instr)->print(instr, line, index, repeat, content); +    } -} +    if (!result) +        goto exit_with_op_off; +    /* Propriétés internes */ +    extra = g_thick_object_get_extra(G_THICK_OBJECT(object)); -/* ---------------------------------------------------------------------------------- */ -/*                      CONSERVATION ET RECHARGEMENT DES DONNEES                      */ -/* ---------------------------------------------------------------------------------- */ +    result = store_uleb128((uleb128_t []) { extra }, fd); +    if (!result) goto exit; +    /* Liaisons avec d'autres instructions */ -/****************************************************************************** -*                                                                             * -*  Paramètres  : instr   = élément GLib à constuire.                          * -*                storage = conservateur de données à manipuler ou NULL.       * -*                pbuf    = zone tampon à lire.                                * -*                                                                             * -*  Description : Charge un contenu depuis une mémoire tampon.                 * -*                                                                             * -*  Retour      : Bilan de l'opération.                                        * -*                                                                             * -*  Remarques   : -                                                            * -*                                                                             * -******************************************************************************/ +    instr = G_ARCH_INSTRUCTION(object); -static bool _g_arch_instruction_load(GArchInstruction *instr, GObjectStorage *storage, packed_buffer_t *pbuf) -{ -    bool result;                            /* Bilan à retourner           */ -    instr_extra_data_t *extra;              /* Données insérées à consulter*/ -    uleb128_t value;                        /* Valeur ULEB128 à charger    */ -    uleb128_t count;                        /* Nombre d'éléments à traiter */ -    uleb128_t i;                            /* Boucle de parcours          */ -    GArchOperand *op;                       /* Opérande à traiter          */ +    src_count = g_arch_instruction_count_src_links(instr); +    dest_count = g_arch_instruction_count_dest_links(instr); -    extra = GET_ARCH_INSTR_EXTRA(instr); +    result = store_uleb128((uleb128_t []) { src_count }, fd); +    if (!result) goto exit; -    LOCK_GOBJECT_EXTRA(extra); +    result = store_uleb128((uleb128_t []) { dest_count }, fd); +    if (!result) goto exit; -    result = unpack_uleb128(&value, pbuf); +    for (i = 0; i < src_count && result; i++) +    { +        linked = g_arch_instruction_get_linked_source(instr, i, &type); -    if (result) -        extra->uid = value; +        result = store_uleb128((uleb128_t []) { type }, fd); -    if (result) -    { -        result = unpack_uleb128(&value, pbuf); +        unref_object(linked);          if (result) -            extra->flags = value; +            result = store_uleb128((uleb128_t []) { ins_offsets[i] }, fd);      } -    UNLOCK_GOBJECT_EXTRA(extra); - -    if (result) -        result = unpack_mrange(&instr->range, pbuf); - -    if (result) +    for (i = 0; i < dest_count && result; i++)      { -        result = unpack_uleb128(&count, pbuf); +        linked = g_arch_instruction_get_linked_destination(instr, i, &type); -        for (i = 0; i < count && result; i++) -        { -            op = G_ARCH_OPERAND(g_object_storage_unpack_object(storage, "operands", pbuf)); -            result = (op != NULL); +        result = store_uleb128((uleb128_t []) { type }, fd); -            if (result) -                g_arch_instruction_attach_extra_operand(instr, op); +        unref_object(linked); -        } +        if (result) +            result = store_uleb128((uleb128_t []) { ins_offsets[src_count + i] }, fd);      } -    if (result) -        result = g_arch_instruction_load_destinations(instr, storage, pbuf); - -    return result; +    /* Opérandes embarqués */ -} +    result = store_uleb128((uleb128_t []) { op_count }, fd); +    if (!result) goto exit; +    for (i = 0; i < op_count && result; i++) +        result = store_uleb128((uleb128_t []) { op_offsets[i] }, fd); -/****************************************************************************** -*                                                                             * -*  Paramètres  : instr   = élément GLib à constuire.                          * -*                storage = conservateur de données à manipuler ou NULL.       * -*                pbuf    = zone tampon à lire.                                * -*                                                                             * -*  Description : Charge un contenu depuis une mémoire tampon.                 * -*                                                                             * -*  Retour      : Bilan de l'opération.                                        * -*                                                                             * -*  Remarques   : -                                                            * -*                                                                             * -******************************************************************************/ + exit: + exit_with_op_off: -static bool g_arch_instruction_load(GArchInstruction *instr, GObjectStorage *storage, packed_buffer_t *pbuf) -{ -    bool result;                            /* Bilan à retourner           */ -    GArchInstructionClass *class;           /* Classe à activer            */ +    free(op_offsets); -    class = G_ARCH_INSTRUCTION_GET_CLASS(instr); + exit_with_ins_off: -    result = class->load(instr, storage, pbuf); +    free(ins_offsets);      return result;  } -/****************************************************************************** -*                                                                             * -*  Paramètres  : instr   = élément GLib à consulter.                          * -*                storage = conservateur de données à manipuler ou NULL.       * -*                pbuf    = zone tampon à remplir.                             * -*                                                                             * -*  Description : Sauvegarde un contenu dans une mémoire tampon.               * -*                                                                             * -*  Retour      : Bilan de l'opération.                                        * -*                                                                             * -*  Remarques   : -                                                            * -*                                                                             * -******************************************************************************/ -static bool _g_arch_instruction_store(GArchInstruction *instr, GObjectStorage *storage, packed_buffer_t *pbuf) -{ -    bool result;                            /* Bilan à retourner           */ -    instr_extra_data_t *extra;              /* Données insérées à consulter*/ -    size_t count;                           /* Nombre d'éléments à traiter */ -    size_t i;                               /* Boucle de parcours          */ -    GArchOperand *op;                       /* Opérande à traiter          */ - -    extra = GET_ARCH_INSTR_EXTRA(instr); -    LOCK_GOBJECT_EXTRA(extra); -    result = pack_uleb128((uleb128_t []){ extra->uid }, pbuf); -    if (result) -        result = pack_uleb128((uleb128_t []){ extra->flags }, pbuf); -    UNLOCK_GOBJECT_EXTRA(extra); -    if (result) -        result = pack_mrange(&instr->range, pbuf); -    if (result) -    { -        g_arch_instruction_lock_operands(instr); -        count = _g_arch_instruction_count_operands(instr); -        result = pack_uleb128((uleb128_t []){ count }, pbuf); -        for (i = 0; i < count && result; i++) -        { -            op = _g_arch_instruction_get_operand(instr, i); -            result = g_object_storage_pack_object(storage, "operands", G_SERIALIZABLE_OBJECT(op), pbuf); -            g_object_unref(G_OBJECT(op)); -        } -        g_arch_instruction_unlock_operands(instr); -    } -    if (result) -        result = g_arch_instruction_store_destinations(instr, storage, pbuf); +#if 0 -    return result; -}  /******************************************************************************  *                                                                             * -*  Paramètres  : instr   = élément GLib à consulter.                          * -*                storage = conservateur de données à manipuler ou NULL.       * -*                pbuf    = zone tampon à remplir.                             * +*  Paramètres  : instr   = instruction quelconque à traiter.                  * +*                type    = type de procédure à utiliser.                      * +*                proc    = représentation de l'architecture utilisée.         * +*                context = contexte associé à la phase de désassemblage.      * +*                format  = accès aux données du binaire d'origine.            *  *                                                                             * -*  Description : Sauvegarde un contenu dans une mémoire tampon.               * +*  Description : Complète un désassemblage accompli pour une instruction.     *  *                                                                             * -*  Retour      : Bilan de l'opération.                                        * +*  Retour      : -                                                            *  *                                                                             *  *  Remarques   : -                                                            *  *                                                                             *  ******************************************************************************/ -static bool g_arch_instruction_store(GArchInstruction *instr, GObjectStorage *storage, packed_buffer_t *pbuf) +void g_arch_instruction_call_hook(GArchInstruction *instr, InstrProcessHook type, GArchProcessor *proc, GProcContext *context, GExeFormat *format)  { -    bool result;                            /* Bilan à retourner           */ -    GArchInstructionClass *class;           /* Classe à activer            */ +    GArchInstructionClass *class;           /* Classe des instructions     */      class = G_ARCH_INSTRUCTION_GET_CLASS(instr); -    result = class->store(instr, storage, pbuf); - -    return result; +    if (class->call_hook != NULL) +        class->call_hook(instr, type, proc, context, format);  } + + + + + +#endif + + + + + + + + + + diff --git a/src/arch/instruction.h b/src/arch/instruction.h index 3c9c149..98bc73e 100644 --- a/src/arch/instruction.h +++ b/src/arch/instruction.h @@ -2,7 +2,7 @@  /* Chrysalide - Outil d'analyse de fichiers binaires   * instruction.h - prototypes pour la gestion générique des instructions   * - * Copyright (C) 2008-2020 Cyrille Bagard + * Copyright (C) 2008-2025 Cyrille Bagard   *   *  This file is part of Chrysalide.   * @@ -25,194 +25,118 @@  #define _ARCH_INSTRUCTION_H -#include <sys/types.h> +#include <stdbool.h> +#include <stdint.h> -#include "context.h"  #include "operand.h" -#include "register.h"  #include "vmpa.h" -#include "../analysis/type.h" -#include "../common/packed.h" -#include "../format/executable.h" +#include "../glibext/helpers.h" +#include "../glibext/portion.h" -#define G_TYPE_ARCH_INSTRUCTION            g_arch_instruction_get_type() -#define G_ARCH_INSTRUCTION(obj)            (G_TYPE_CHECK_INSTANCE_CAST((obj), g_arch_instruction_get_type(), GArchInstruction)) -#define G_IS_ARCH_INSTRUCTION(obj)         (G_TYPE_CHECK_INSTANCE_TYPE((obj), g_arch_instruction_get_type())) -#define G_ARCH_INSTRUCTION_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_ARCH_INSTRUCTION, GArchInstructionClass)) -#define G_IS_ARCH_INSTRUCTION_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_ARCH_INSTRUCTION)) -#define G_ARCH_INSTRUCTION_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_ARCH_INSTRUCTION, GArchInstructionClass)) +/* ----------------------- DEFINITION GENERIQUE D'INSTRUCTION ----------------------- */ -/* Définition générique d'une instruction d'architecture (instance) */ -typedef struct _GArchInstruction GArchInstruction; +#define G_TYPE_ARCH_INSTRUCTION (g_arch_instruction_get_type()) -/* Définition générique d'une instruction d'architecture (classe) */ -typedef struct _GArchInstructionClass GArchInstructionClass; +DECLARE_GTYPE(GArchInstruction, g_arch_instruction, G, ARCH_INSTRUCTION); -/* Drapeaux pour informations complémentaires */ - -#define AIF_USER_BIT 4 - -typedef enum _ArchInstrFlag -{ -    AIF_NONE              = (0 << 0),       /* Aucune information          */ -    AIF_ROUTINE_START     = (1 << 0),       /* Début de routine            */ -    AIF_RETURN_POINT      = (1 << 1),       /* Retour de fonction appelée  */ -    AIF_COND_RETURN_POINT = (1 << 2),       /* Retour éventuel de fonction */ -    AIF_CALL              = (1 << 3),       /* Instruction d'appel         */ - -    AIF_LOW_USER          = (1 << AIF_USER_BIT), /* Premier bit disponible */ -    AIF_HIGH_USER         = (1 << 7),      /* Dernier bit disponible      */ - -} ArchInstrFlag; -  /* Type pour les types d'instructions */  typedef uint16_t itid_t; -/* Types de crochet de traitement */ -typedef enum _InstrProcessHook -{ -    IPH_FETCH,                              /* Itinéraire de désassemblage */ -    IPH_LINK,                               /* Edition des liens           */ -    IPH_POST,                               /* Résolution des symboles     */ - -    IPH_COUNT - -} InstrProcessHook; - - -/* Indique le type défini pour une instruction d'architecture. */ -GType g_arch_instruction_get_type(void); +/* Fournit l'identifiant correspondant à un type d'instructions. */ +itid_t g_arch_instruction_get_type_id(const GArchInstruction *);  /* Indique l'encodage d'une instruction de façon détaillée. */ -const char *g_arch_instruction_get_encoding(const GArchInstruction *); - -/* Ajoute une information complémentaire à une instruction. */ -bool g_arch_instruction_set_flag(GArchInstruction *, ArchInstrFlag); +char *g_arch_instruction_get_encoding(const GArchInstruction *); -/* Retire une information complémentaire à une instruction. */ -bool g_arch_instruction_unset_flag(GArchInstruction *, ArchInstrFlag); - -/* Détermine si une instruction possède un fanion particulier. */ -bool g_arch_instruction_has_flag(const GArchInstruction *, ArchInstrFlag); +/* Fournit le nom humain de l'instruction manipulée. */ +char *g_arch_instruction_get_keyword(const GArchInstruction *); -/* Fournit les informations complémentaires d'une instruction. */ -ArchInstrFlag g_arch_instruction_get_flags(const GArchInstruction *); -/* Définit l'identifiant unique pour un ensemble d'instructions. */ -void g_arch_instruction_set_unique_id(GArchInstruction *, itid_t); + /* Type de masques pour les encodages d'instructions */ +typedef enum _InstructionBytesMask +{ +    /** +     * Correspond aux bits fixes : pas de valeurs de registre ni de valeur entière. +     */ +    IBM_LOOSE, -/* Fournit l'identifiant unique pour un ensemble d'instructions. */ -itid_t g_arch_instruction_get_unique_id(const GArchInstruction *); +    /** +     * Dissimulation des références à des éléments externes pouvant varier avec +     * entre compilations : adresses de saut ou d'appel, références vers des tables, +     * etc. +     */ +    IBM_LOCAL, +    /** +     * Dissimulation des déplacements à partir d'une base. +     */ +    IBM_STRICT, -/** - * La définition de "GArchProcessor", utile aux traitements complémentaires, ne peut - * se faire en incluant le fichier d'en-tête "processor.h", pour cause de références - * circulaires. - * - * On procède donc à une seconde déclaration, en attendant éventuellement mieux. - */ +    /** +     * Conservation de toutes les valeurs immédiates et dissimulation des registres. +     */ +    IBM_LARGE, -/* Depuis "processeur.h" : définition générique d'un processeur d'architecture (instance) */ -typedef struct _GArchProcessor GArchProcessor; +    IBM_COUNT +} InstructionBytesMask; -/* Complète un désassemblage accompli pour une instruction. */ -typedef void (* instr_hook_fc) (GArchInstruction *, GArchProcessor *, GProcContext *, GExeFormat *); - -/* Complète un désassemblage accompli pour une instruction. */ -void g_arch_instruction_call_hook(GArchInstruction *, InstrProcessHook, GArchProcessor *, GProcContext *, GExeFormat *); -/* Définit la localisation d'une instruction. */ -void g_arch_instruction_set_range(GArchInstruction *, const mrange_t *); +/* Calcule la localisation d'une instruction. */ +void g_arch_instruction_compute_range(GArchInstruction *, GBinaryPortion *, const vmpa2t *, phys_t);  /* Fournit la place mémoire d'une instruction. */ -const mrange_t *g_arch_instruction_get_range(const GArchInstruction *); - - - -/* Fournit la localisation d'une instruction. */ -void g_arch_instruction_get_location(const GArchInstruction *, off_t *, off_t *, vmpa_t *) __attribute__ ((deprecated)); +bool g_arch_instruction_get_range(const GArchInstruction *, mrange_t *); +#define AIF_USER_BIT 4 -/* Liste les registres lus et écrits par l'instruction. */ -void g_arch_instruction_get_rw_registers(const GArchInstruction *, GArchRegister ***, size_t *, GArchRegister ***, size_t *) __attribute__ ((deprecated)); +typedef enum _ArchInstructionFlag +{ +    AIF_NONE              = (0 << 0),       /* Aucune information          */ +    AIF_ROUTINE_START     = (1 << 0),       /* Début de routine            */ +    AIF_RETURN_POINT      = (1 << 1),       /* Retour de fonction appelée  */ +    AIF_COND_RETURN_POINT = (1 << 2),       /* Retour éventuel de fonction */ +    AIF_CALL              = (1 << 3),       /* Instruction d'appel         */ +    AIF_LOW_USER          = (1 << AIF_USER_BIT), /* Premier bit disponible */ +    AIF_HIGH_USER         = (1 << 7),      /* Dernier bit disponible      */ +} ArchInstructionFlag; -/* --------------------------- MANIPULATION DES OPERANDES --------------------------- */ +#define AIF_USER_FLAG(n) (1 << (AIF_USER_BIT + n)) -/* Verrouille les accès à la liste des opérandes. */ -void g_arch_instruction_lock_operands(GArchInstruction *); +/* Ajoute une information complémentaire à une instruction. */ +bool g_arch_instruction_set_flag(GArchInstruction *, ArchInstructionFlag); -/* Déverrouille les accès à la liste des opérandes. */ -void g_arch_instruction_unlock_operands(GArchInstruction *); +/* Retire une information complémentaire à une instruction. */ +bool g_arch_instruction_unset_flag(GArchInstruction *, ArchInstructionFlag); -/* Attache un opérande supplémentaire à une instruction. */ -void g_arch_instruction_attach_extra_operand(GArchInstruction *, GArchOperand *); +/* Détermine si une instruction possède un fanion particulier. */ +bool g_arch_instruction_has_flag(const GArchInstruction *, ArchInstructionFlag); -/* Indique la quantité d'opérandes présents dans l'instruction. */ -size_t _g_arch_instruction_count_operands(const GArchInstruction *); +/* Fournit les particularités de l'instruction. */ +ArchInstructionFlag g_arch_instruction_get_flags(const GArchInstruction *); -/* Fournit un opérande donné d'une instruction. */ -GArchOperand *_g_arch_instruction_get_operand(const GArchInstruction *, size_t); -/* Remplace un opérande d'une instruction par un autre. */ -bool _g_arch_instruction_replace_operand(GArchInstruction *, GArchOperand *, GArchOperand *); +/* Types de crochet de traitement */ +typedef enum _InstrProcessHook +{ +    IPH_FETCH,                              /* Itinéraire de désassemblage */ +    IPH_LINK,                               /* Edition des liens           */ +    IPH_POST,                               /* Résolution des symboles     */ -/* Détache un opérande liée d'une instruction. */ -bool _g_arch_instruction_detach_operand(GArchInstruction *, GArchOperand *); - - -#define g_arch_instruction_count_operands(ins)                      \ -    ({                                                              \ -        size_t __result;                                            \ -        g_arch_instruction_lock_operands(ins);                      \ -        __result = _g_arch_instruction_count_operands(ins);         \ -        g_arch_instruction_unlock_operands(ins);                    \ -        __result;                                                   \ -    }) - -#define g_arch_instruction_get_operand(ins, idx)                    \ -    ({                                                              \ -        GArchOperand *__result;                                     \ -        g_arch_instruction_lock_operands(ins);                      \ -        __result = _g_arch_instruction_get_operand(ins, idx);       \ -        g_arch_instruction_unlock_operands(ins);                    \ -        __result;                                                   \ -    }) - -#define g_arch_instruction_replace_operand(ins, o, n)               \ -    ({                                                              \ -        bool __result;                                              \ -        g_arch_instruction_lock_operands(ins);                      \ -        __result = _g_arch_instruction_replace_operand(ins, o, n);  \ -        g_arch_instruction_unlock_operands(ins);                    \ -        __result;                                                   \ -    }) - -#define g_arch_instruction_detach_operand(ins, o)                   \ -    ({                                                              \ -        bool __result;                                              \ -        g_arch_instruction_lock_operands(ins);                      \ -        __result = _g_arch_instruction_detach_operand(ins, o);      \ -        g_arch_instruction_unlock_operands(ins);                    \ -        __result;                                                   \ -    }) +    IPH_COUNT +} InstrProcessHook; -/* Détermine le chemin conduisant à un opérande. */ -char *g_arch_instruction_find_operand_path(GArchInstruction *, const GArchOperand *); -/* Obtient l'opérande correspondant à un chemin donné. */ -GArchOperand *g_arch_instruction_get_operand_from_path(GArchInstruction *, const char *); @@ -236,30 +160,24 @@ typedef enum _InstructionLinkType  } InstructionLinkType; -/* Déscription d'une liaison entre deux instructions */ -typedef struct _instr_link_t -{ -    GArchInstruction *linked;               /* Autre instruction liée      */ -    InstructionLinkType type;               /* Type de liaison             */ - -} instr_link_t; - -#define ref_instr_link(l) g_object_ref(G_OBJECT(l->linked)); -#define unref_instr_link(l) g_object_unref(G_OBJECT(l->linked)); +/* Détermine si un type de lien amène à une instruction. */ +bool g_arch_instruction_has_src_link(const GArchInstruction *, InstructionLinkType); +/* Détermine si un type de lien émerge d'une instruction. */ +bool g_arch_instruction_has_dest_link(const GArchInstruction *, InstructionLinkType); -/* Met à disposition un encadrement des accès aux liens. */ -void g_arch_instruction_lock_unlock_links(GArchInstruction *, bool, bool); +/* Détermine si une instruction est source d'une autre. */ +bool g_arch_instruction_has_src_link_with(const GArchInstruction *, const GArchInstruction *); -/* Détermine si un type de lien existe dans une instruction. */ -bool g_arch_instruction_has_link(GArchInstruction *, InstructionLinkType); - -/* Détermine si un lien est déjà établi entre deux instructions. */ -bool g_arch_instruction_has_link_to(GArchInstruction *, const GArchInstruction *); +/* Détermine si une instruction est destination d'une autre. */ +bool g_arch_instruction_has_dest_link_with(const GArchInstruction *, const GArchInstruction *);  /* Etablit un lien entre deux instructions. */ -void g_arch_instruction_link_with(GArchInstruction *, GArchInstruction *, InstructionLinkType); +void g_arch_instruction_link(GArchInstruction *, GArchInstruction *, InstructionLinkType); + +/* Supprime un lien entre deux instructions. */ +void g_arch_instruction_unlink(GArchInstruction *, GArchInstruction *, InstructionLinkType);  /* Change la nature d'un lien entre deux instructions. */  bool g_arch_instruction_change_link(GArchInstruction *, GArchInstruction *, InstructionLinkType, InstructionLinkType); @@ -267,46 +185,72 @@ bool g_arch_instruction_change_link(GArchInstruction *, GArchInstruction *, Inst  /* Supprime tous les liens établis avec d'autres instructions. */  void g_arch_instruction_delete_all_links(GArchInstruction *); -#define g_arch_instruction_lock_src(ins) g_arch_instruction_lock_unlock_links(ins, true, true) -#define g_arch_instruction_unlock_src(ins) g_arch_instruction_lock_unlock_links(ins, true, false) +/* Fournit la quantité d'instructions placées en source. */ +size_t g_arch_instruction_count_src_links(const GArchInstruction *); -/* Fournit la quantité d'instructions pointant vers une autre. */ -size_t g_arch_instruction_count_sources(const GArchInstruction *); +/* Fournit la quantité d'instructions placées en destination. */ +size_t g_arch_instruction_count_dest_links(const GArchInstruction *); -/* Fournit les détails d'une origine d'une instruction donnée. */ -const instr_link_t *g_arch_instruction_get_source(GArchInstruction *, size_t); +/* Fournit les détails d'une source donnée d'une instruction. */ +GArchInstruction *g_arch_instruction_get_linked_source(const GArchInstruction *, size_t, InstructionLinkType *); -/* Fournit tous les détails d'origine d'une instruction donnée. */ -instr_link_t *g_arch_instruction_get_sources(GArchInstruction *, size_t *); +/* Fournit les détails d'une destination donnée d'une instruction. */ +GArchInstruction *g_arch_instruction_get_linked_destination(const GArchInstruction *, size_t, InstructionLinkType *); -#define g_arch_instruction_lock_dest(ins) g_arch_instruction_lock_unlock_links(ins, false, true) -#define g_arch_instruction_unlock_dest(ins) g_arch_instruction_lock_unlock_links(ins, false, false) -/* Donne le nombre d'instructions non naturellement suivantes. */ -size_t g_arch_instruction_count_destinations(const GArchInstruction *); -/* Fournit les détails d'une destination d'une instruction. */ -const instr_link_t *g_arch_instruction_get_destination(GArchInstruction *, size_t); +/* --------------------------- MANIPULATION DES OPERANDES --------------------------- */ -/* Fournit la destination d'une instruction et d'un type donné. */ -GArchInstruction *g_arch_instruction_get_given_destination(GArchInstruction *, InstructionLinkType); -/* Fournit tous les détails de destination d'une instruction. */ -instr_link_t *g_arch_instruction_get_destinations(GArchInstruction *, size_t *); +/* Indique la quantité d'opérandes présents dans l'instruction. */ +size_t g_arch_instruction_count_operands(const GArchInstruction *); +/* Attache un opérande supplémentaire à une instruction. */ +void g_arch_instruction_attach_operand(GArchInstruction *, GArchOperand *); +/* Remplace un opérande d'une instruction par un autre. */ +bool g_arch_instruction_replace_operand(GArchInstruction *, GArchOperand *, GArchOperand *); -/* --------------------- CONVERSIONS DU FORMAT DES INSTRUCTIONS --------------------- */ +/* Détache un opérande liée d'une instruction. */ +bool g_arch_instruction_detach_operand(GArchInstruction *, GArchOperand *); +/* Fournit un opérande donné d'une instruction. */ +GArchOperand *g_arch_instruction_get_operand(const GArchInstruction *, size_t); + +/* Détermine le chemin conduisant à un opérande. */ +char *g_arch_instruction_find_operand_path(GArchInstruction *, const GArchOperand *); + +/* Obtient l'opérande correspondant à un chemin donné. */ +GArchOperand *g_arch_instruction_get_operand_from_path(GArchInstruction *, const char *); + + + + +#if 0 + + + +/** + * La définition de "GArchProcessor", utile aux traitements complémentaires, ne peut + * se faire en incluant le fichier d'en-tête "processor.h", pour cause de références + * circulaires. + * + * On procède donc à une seconde déclaration, en attendant éventuellement mieux. + */ + +/* Depuis "processeur.h" : définition générique d'un processeur d'architecture (instance) */ +typedef struct _GArchProcessor GArchProcessor; + + +/* Complète un désassemblage accompli pour une instruction. */ +typedef void (* instr_hook_fc) (GArchInstruction *, GArchProcessor *, GProcContext *, GExeFormat *); + +/* Complète un désassemblage accompli pour une instruction. */ +void g_arch_instruction_call_hook(GArchInstruction *, InstrProcessHook, GArchProcessor *, GProcContext *, GExeFormat *); -/* Fournit le nom humain de l'instruction manipulée. */ -const char *g_arch_instruction_get_keyword(GArchInstruction *); -/* Construit un petit résumé concis de l'instruction. */ -char *g_arch_instruction_build_tooltip(const GArchInstruction *); -/* Fournit une description pour l'instruction manipulée. */ -const char *g_arch_instruction_get_description(const GArchInstruction *); +#endif diff --git a/src/arch/instructions/Makefile.am b/src/arch/instructions/Makefile.am index 28cf90f..d6fc4bd 100644 --- a/src/arch/instructions/Makefile.am +++ b/src/arch/instructions/Makefile.am @@ -1,12 +1,19 @@ -noinst_LTLIBRARIES = libarchinstructions.la +noinst_LTLIBRARIES = libarchinstructions.la libarchinstructionsui.la  libarchinstructions_la_SOURCES =			\ +	raw-int.h								\  	raw.h raw.c								\  	undefined-int.h							\  	undefined.h undefined.c -libarchinstructions_la_CFLAGS = $(TOOLKIT_CFLAGS) $(LIBXML_CFLAGS) +libarchinstructions_la_CFLAGS = $(LIBGOBJ_CFLAGS) + +libarchinstructionsui_la_SOURCES =			\ +	raw-ui.h raw-ui.c						\ +	undefined-ui.h undefined-ui.c + +libarchinstructionsui_la_CFLAGS = $(LIBGTK4_CFLAGS)  devdir = $(includedir)/chrysalide/$(subdir:src/%=core/%) diff --git a/src/arch/instructions/raw-int.h b/src/arch/instructions/raw-int.h new file mode 100644 index 0000000..4a5e64b --- /dev/null +++ b/src/arch/instructions/raw-int.h @@ -0,0 +1,56 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * raw-int.h - prototypes pour la définition interne des instructions de données brutes + * + * 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 _ARCH_INSTRUCTIONS_RAW_INT_H +#define _ARCH_INSTRUCTIONS_RAW_INT_H + + +#include "raw.h" +#include "../instruction-int.h" + + + +/* Définition générique d'une instruction brute d'architecture (instance) */ +struct _GRawInstruction +{ +    GArchInstruction parent;                /* A laisser en premier        */ + +}; + +/* Définition générique d'une instruction brute d'architecture (instance) */ +struct _GRawInstructionClass +{ +    GArchInstructionClass parent;           /* A laisser en premier        */ + +}; + + +/* Met en place une instruction de type 'db/dw/etc' simple. */ +bool g_raw_instruction_create_value(GRawInstruction *, GBinaryPortion *, const vmpa2t *, MemoryDataSize, uint64_t); + +/* Met en place une instruction de type 'db/dw/etc' étendue. */ +bool g_raw_instruction_create_array(GRawInstruction *, GBinaryPortion *, vmpa2t *, MemoryDataSize, const GBinContent *, size_t, SourceEndian); + + + +#endif  /* _ARCH_INSTRUCTIONS_RAW_INT_H */ diff --git a/src/arch/instructions/raw-ui.c b/src/arch/instructions/raw-ui.c new file mode 100644 index 0000000..1026dfb --- /dev/null +++ b/src/arch/instructions/raw-ui.c @@ -0,0 +1,261 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * raw-ui.c - opérandes représentant des instructions de données brutes sous forme graphique + * + * 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/>. + */ + + +#include "raw-ui.h" + + +#include <assert.h> +#include <ctype.h> +#include <malloc.h> + + +#include "raw.h" +#include "../operand-ui.h" +#include "../operands/immediate.h" +#include "../../glibext/objhole.h" +#include "../../glibext/options/asm.h" + + + +/* Etablit dans une ligne de rendu le contenu représenté. */ +static void g_raw_instruction_ui_populate_line(const GTokenGenerator *, size_t, size_t, GBufferLine *, void *); + + + +/****************************************************************************** +*                                                                             * +*  Paramètres  : iface = interface GLib à initialiser.                        * +*                                                                             * +*  Description : Procède à l'initialisation de l'interface de génération.     * +*                                                                             * +*  Retour      : -                                                            * +*                                                                             * +*  Remarques   : -                                                            * +*                                                                             * +******************************************************************************/ + +void g_raw_instruction_ui_token_generator_iface_init(GTokenGeneratorInterface *iface) +{ +    iface->populate = g_raw_instruction_ui_populate_line; + +} + + +/****************************************************************************** +*                                                                             * +*  Paramètres  : generator = générateur à utiliser pour l'impression.         * +*                index     = indice de cette même ligne dans le tampon global.* +*                repeat    = indice d'utilisations successives du générateur. * +*                line      = ligne de rendu à compléter.                      * +*                data      = éventuelle donnée complémentaire fournie.        * +*                                                                             * +*  Description : Etablit dans une ligne de rendu le contenu représenté.       * +*                                                                             * +*  Retour      : -                                                            * +*                                                                             * +*  Remarques   : -                                                            * +*                                                                             * +******************************************************************************/ + +static void g_raw_instruction_ui_populate_line(const GTokenGenerator *generator, size_t index, size_t repeat, GBufferLine *line, void *data) +{ +    GArchInstruction *instr;                /* Version spécialisée #1      */ +    GRawInstruction *raw;                   /* Version spécialisée #2      */ +    GBinContent *content;                   /* Contenu brut d'origine      */ +    mrange_t range;                         /* Emplacement couvert         */ +    phys_t max_displayed_len;               /* Quantité de code affichée   */ +    char *key;                              /* Mot clef principal          */ +    char *string;                           /* Chaîne reconstituée         */ +    size_t iter;                            /* Tête d'écriture             */ +    bool first;                             /* Mémorise une énumération    */ +    size_t count;                           /* Nombre d'opérandes en place */ +    size_t i;                               /* Boucle de parcours          */ +    GArchOperand *op;                       /* Opérande à manipuler        */ +    GImmediateOperand *imm;                 /* Version opérande de valeur  */ +    char byte;                              /* Octet à afficher (ou pas)   */ +#ifndef NDEBUG +    bool status;                            /* Bilan d'une récupération    */ +#endif + +    instr = G_ARCH_INSTRUCTION(generator); +    raw = G_RAW_INSTRUCTION(instr); +    content = G_BIN_CONTENT(data); + +    g_thick_object_lock(G_THICK_OBJECT(instr)); + +    /* Prologue */ + +    if (g_arch_instruction_get_range(instr, &range)) +    { +        /* Localisation */ + +        g_buffer_line_fill_physical(line, ACO_PHYSICAL, MDS_32_BITS_UNSIGNED, get_mrange_addr(&range)); + +        g_buffer_line_fill_virtual(line, ACO_VIRTUAL, MDS_32_BITS_UNSIGNED, get_mrange_addr(&range)); + +        /* Contenu */ + +        if (g_raw_instruction_is_padding(raw)) +            max_displayed_len = 0; + +        else if (g_raw_instruction_is_string(raw)) +            max_displayed_len = 1; + +        else +        { +            max_displayed_len = get_mrange_length(&range); +            max_displayed_len /= g_arch_instruction_count_operands(instr); +        } + +        g_buffer_line_fill_content(line, ACO_BINARY, content, &range, max_displayed_len); + +    } + +    /* Instruction proprement dite */ + +    key = g_arch_instruction_get_keyword(instr); + +    g_buffer_line_append_text(line, ACO_ASSEMBLY_HEAD, TRT_INSTRUCTION, SL(key), NULL, G_OBJECT(instr)); + +    free(key); + +    /* Contenu sous forme d'opérandes */ + +    if (g_raw_instruction_is_padding(raw)) +        g_buffer_line_append_text(line, ACO_ASSEMBLY, TRT_CHR_PRINTABLE, STCSL("..."), NULL, NULL); + +    else +    { +        string = NULL; +        iter = 0; + +        first = true; + +        count = g_arch_instruction_count_operands(instr); + +        for (i = 0; i < count; i++) +        { +            op = g_arch_instruction_get_operand(instr, i); + +            if (!G_IS_IMMEDIATE_OPERAND(op)) +                goto fallback; + +            imm = G_IMMEDIATE_OPERAND(op); + +            if (g_immediate_operand_get_size(imm) != MDS_8_BITS) +                goto fallback; + +            if (!g_raw_instruction_is_string(raw) && g_immediate_operand_get_display(imm) != IOD_CHAR) +                goto fallback; + +#ifndef NDEBUG +            status = g_immediate_operand_get_value(imm, MDS_8_BITS, &byte); +            assert(status); +#else +            g_immediate_operand_get_value(imm, MDS_8_BITS, &byte); +#endif + +            /* Si le caractère doit apparaître en hexadécimal... */ + +            if (!isprint(byte)) +                goto fallback; + +            /* Impression de l'octet */ + +            if (string == NULL) +            { +                string = calloc(count + 3, sizeof(char)); + +                strcpy(string, "\""); +                iter = 1; + +            } + +            string[iter++] = byte; + +            unref_object(op); + +            continue; + + fallback: + +            /* Si une chaîne précède */ + +            if (string != NULL && iter > 1) +            { +                if (!first) +                { +                    g_buffer_line_append_text(line, ACO_ASSEMBLY, TRT_PUNCT, STCSL(","), NULL, NULL); +                    g_buffer_line_append_text(line, ACO_ASSEMBLY, TRT_CHR_PRINTABLE, STCSL(" "), NULL, NULL); +                } +                else +                    first = false; + +                string[iter++] = '"'; + +                g_buffer_line_append_text(line, ACO_ASSEMBLY, TRT_STRING, string, iter, NULL, NULL); + +                iter = 1; + +            } + +            /* Intégration en tant qu'opérande classique */ + +            if (!first) +            { +                g_buffer_line_append_text(line, ACO_ASSEMBLY, TRT_PUNCT, STCSL(","), NULL, NULL); +                g_buffer_line_append_text(line, ACO_ASSEMBLY, TRT_CHR_PRINTABLE, STCSL(" "), NULL, NULL); +            } +            else +                first = false; + +            g_arch_operand_ui_print(G_ARCH_OPERAND_UI(op), line); + +            unref_object(op); + +        } + +        /* Si au final une chaîne traine encore */ + +        if (string != NULL && iter > 1) +        { +            if (!first) +            { +                g_buffer_line_append_text(line, ACO_ASSEMBLY, TRT_PUNCT, STCSL(","), NULL, NULL); +                g_buffer_line_append_text(line, ACO_ASSEMBLY, TRT_CHR_PRINTABLE, STCSL(" "), NULL, NULL); +            } + +            string[iter++] = '"'; + +            g_buffer_line_append_text(line, ACO_ASSEMBLY, TRT_STRING, string, iter, NULL, NULL); + +        } + +        if (string != NULL) +            free(string); + +    } + +    g_thick_object_unlock(G_THICK_OBJECT(instr)); + +} diff --git a/src/arch/instructions/raw-ui.h b/src/arch/instructions/raw-ui.h new file mode 100644 index 0000000..cd604e6 --- /dev/null +++ b/src/arch/instructions/raw-ui.h @@ -0,0 +1,37 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * raw-ui.h - prototypes pour les opérandes représentant des instructions de données brutes sous forme graphique + * + * 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 _ARCH_OPERANDS_RAW_UI_H +#define _ARCH_OPERANDS_RAW_UI_H + + +#include "../../glibext/generator-int.h" + + + +/* Procède à l'initialisation de l'interface de génération. */ +void g_raw_instruction_ui_token_generator_iface_init(GTokenGeneratorInterface *); + + + +#endif  /* _ARCH_OPERANDS_RAW_UI_H */ diff --git a/src/arch/instructions/raw.c b/src/arch/instructions/raw.c index 26282fa..87297f1 100644 --- a/src/arch/instructions/raw.c +++ b/src/arch/instructions/raw.c @@ -2,7 +2,7 @@  /* Chrysalide - Outil d'analyse de fichiers binaires   * raw.c - instructions pures vues de l'esprit   * - * Copyright (C) 2014-2020 Cyrille Bagard + * Copyright (C) 2014-2025 Cyrille Bagard   *   *  This file is part of Chrysalide.   * @@ -25,36 +25,19 @@  #include <assert.h> -#include <ctype.h>  #include <string.h>  #include <i18n.h> -#include "../instruction-int.h" +#include "raw-int.h"  #include "../operands/immediate.h" -#include "../operands/target.h" -#include "../../core/columns.h" +//#include "../operands/target.h" // FIXME -/* ------------------------- INSTRUCTION INCONNUE / DONNEES ------------------------- */ - - -/* Définition générique d'une instruction brute d'architecture (instance) */ -struct _GRawInstruction -{ -    GArchInstruction parent;                /* A laisser en premier        */ - -}; - -/* Définition générique d'une instruction brute d'architecture (classe) */ -struct _GRawInstructionClass -{ -    GArchInstructionClass parent;           /* A laisser en premier        */ - -}; +/* --------------------- INSTRUCTION AVEC JEU DE DONNEES BRUTES --------------------- */  /* Initialise la classe des instructions brutes d'architecture. */ @@ -64,40 +47,26 @@ static void g_raw_instruction_class_init(GRawInstructionClass *);  static void g_raw_instruction_init(GRawInstruction *);  /* Supprime toutes les références externes. */ -static void g_raw_instruction_dispose(GRawInstruction *); +static void g_raw_instruction_dispose(GObject *);  /* Procède à la libération totale de la mémoire. */ -static void g_raw_instruction_finalize(GRawInstruction *); - -/* Indique l'encodage d'une instruction de façon détaillée. */ -static const char *g_raw_instruction_get_encoding(const GRawInstruction *); - -/* Fournit le nom humain de l'instruction manipulée. */ -static const char *g_raw_instruction_get_keyword(const GRawInstruction *); +static void g_raw_instruction_finalize(GObject *); -/* -------------------- CONSERVATION SUR DISQUE DES INSTRUCTIONS -------------------- */ +/* --------------------- IMPLEMENTATION DES FONCTIONS DE CLASSE --------------------- */ -/* Charge une instruction depuis une mémoire tampon. */ -static bool g_raw_instruction_unserialize(GRawInstruction *, GAsmStorage *, GBinFormat *, packed_buffer_t *); - -/* Sauvegarde une instruction dans une mémoire tampon. */ -static bool g_raw_instruction_serialize(GRawInstruction *, GAsmStorage *, packed_buffer_t *); - - - -/* ------------------------ OFFRE DE CAPACITES DE GENERATION ------------------------ */ - +/* Indique l'encodage d'une instruction de façon détaillée. */ +static char *g_raw_instruction_get_encoding(const GArchInstruction *); -/* Ajoute à un tampon GLib le contenu de l'instance spécifiée. */ -static void g_raw_instruction_print(GRawInstruction *, GBufferLine *, size_t, size_t, const GBinContent *); +/* Fournit le nom humain de l'instruction manipulée. */ +static char *g_raw_instruction_get_keyword(const GArchInstruction *);  /* ---------------------------------------------------------------------------------- */ -/*                           INSTRUCTION INCONNUE / DONNEES                           */ +/*                       INSTRUCTION AVEC JEU DE DONNEES BRUTES                       */  /* ---------------------------------------------------------------------------------- */ @@ -124,18 +93,13 @@ static void g_raw_instruction_class_init(GRawInstructionClass *klass)      object = G_OBJECT_CLASS(klass); -    object->dispose = (GObjectFinalizeFunc/* ! */)g_raw_instruction_dispose; -    object->finalize = (GObjectFinalizeFunc)g_raw_instruction_finalize; +    object->dispose = g_raw_instruction_dispose; +    object->finalize = g_raw_instruction_finalize;      instr = G_ARCH_INSTRUCTION_CLASS(klass); -    instr->get_encoding = (get_instruction_encoding_fc)g_raw_instruction_get_encoding; -    instr->get_keyword = (get_instruction_keyword_fc)g_raw_instruction_get_keyword; - -    instr->unserialize = (unserialize_instruction_fc)g_raw_instruction_unserialize; -    instr->serialize = (serialize_instruction_fc)g_raw_instruction_serialize; - -    instr->print = (print_instruction_fc)g_raw_instruction_print; +    instr->get_encoding = g_raw_instruction_get_encoding; +    instr->get_keyword = g_raw_instruction_get_keyword;  } @@ -160,7 +124,7 @@ static void g_raw_instruction_init(GRawInstruction *instr)  /******************************************************************************  *                                                                             * -*  Paramètres  : instr = instance d'objet GLib à traiter.                     * +*  Paramètres  : object = instance d'objet GLib à traiter.                    *  *                                                                             *  *  Description : Supprime toutes les références externes.                     *  *                                                                             * @@ -170,16 +134,16 @@ static void g_raw_instruction_init(GRawInstruction *instr)  *                                                                             *  ******************************************************************************/ -static void g_raw_instruction_dispose(GRawInstruction *instr) +static void g_raw_instruction_dispose(GObject *object)  { -    G_OBJECT_CLASS(g_raw_instruction_parent_class)->dispose(G_OBJECT(instr)); +    G_OBJECT_CLASS(g_raw_instruction_parent_class)->dispose(object);  }  /******************************************************************************  *                                                                             * -*  Paramètres  : instr = instance d'objet GLib à traiter.                     * +*  Paramètres  : object = instance d'objet GLib à traiter.                    *  *                                                                             *  *  Description : Procède à la libération totale de la mémoire.                *  *                                                                             * @@ -189,16 +153,17 @@ static void g_raw_instruction_dispose(GRawInstruction *instr)  *                                                                             *  ******************************************************************************/ -static void g_raw_instruction_finalize(GRawInstruction *instr) +static void g_raw_instruction_finalize(GObject *object)  { -    G_OBJECT_CLASS(g_raw_instruction_parent_class)->finalize(G_OBJECT(instr)); +    G_OBJECT_CLASS(g_raw_instruction_parent_class)->finalize(object);  }  /******************************************************************************  *                                                                             * -*  Paramètres  : addr  = position à associer à l'instruction.                 * +*  Paramètres  : area  = portion de binaire incluant l'instruction.           * +*                addr  = adresse virtuelle et/ou position physique.           *  *                size  = taille de l'opérande souhaitée.                      *  *                value = valeur sur x bits à venir récupérer.                 *  *                                                                             * @@ -210,127 +175,106 @@ static void g_raw_instruction_finalize(GRawInstruction *instr)  *                                                                             *  ******************************************************************************/ -GArchInstruction *g_raw_instruction_new_from_value(const vmpa2t *addr, MemoryDataSize size, uint64_t value) +GArchInstruction *g_raw_instruction_new_from_value(GBinaryPortion *area, const vmpa2t *addr, MemoryDataSize size, uint64_t value)  {      GArchInstruction *result;               /* Instruction à retourner     */ -    GArchOperand *operand;                  /* Octet non décodé à afficher */ -    mrange_t range;                         /* Couverture de l'instruction */      result = g_object_new(G_TYPE_RAW_INSTRUCTION, NULL); -    operand = g_imm_operand_new_from_value(size, value); -    if (operand == NULL) goto error; +    if (!g_raw_instruction_create_value(G_RAW_INSTRUCTION(result), area, addr, size, value)) +        g_clear_object(&result); + +    return result; + +} + + +/****************************************************************************** +*                                                                             * +*  Paramètres  : instr   = instance à initialiser pleinement.                 * +*                area    = portion de binaire incluant l'instruction.         * +*                addr    = adresse virtuelle et/ou position physique.         * +*                size    = taille de chacun des éléments à représenter.       * +*                value = valeur sur x bits à venir récupérer.                 * +*                                                                             * +*  Description : Met en place une instruction de type 'db/dw/etc' simple.     * +*                                                                             * +*  Retour      : Bilan de l'opération.                                        * +*                                                                             * +*  Remarques   : -                                                            * +*                                                                             * +******************************************************************************/ + +bool g_raw_instruction_create_value(GRawInstruction *instr, GBinaryPortion *area, const vmpa2t *addr, MemoryDataSize size, uint64_t value) +{ +    bool result;                            /* Bilan à retourner           */ +    GArchOperand *operand;                  /* Octet non décodé à afficher */ +    uint16_t length;                        /* Taille de l'instruction     */ + +    result = false; + +    operand = g_immediate_operand_new_from_value(size, value); +    if (operand == NULL) goto exit;      g_arch_operand_set_flag(operand, IOF_ZERO_PADDING_BY_DEFAULT | IOF_ZERO_PADDING); -    g_arch_instruction_attach_extra_operand(result, operand); +    g_thick_object_lock(G_THICK_OBJECT(instr)); + +    g_arch_instruction_attach_operand(G_ARCH_INSTRUCTION(instr), operand); +    unref_object(operand); + +    g_thick_object_unlock(G_THICK_OBJECT(instr));      switch (size)      {          case MDS_8_BITS_UNSIGNED:          case MDS_8_BITS_SIGNED: -            init_mrange(&range, addr, 1); +            length = 1;              break;          case MDS_16_BITS_UNSIGNED:          case MDS_16_BITS_SIGNED: -            init_mrange(&range, addr, 2); +            length = 2;              break;          case MDS_32_BITS_UNSIGNED:          case MDS_32_BITS_SIGNED: -            init_mrange(&range, addr, 4); +            length = 4;              break;          case MDS_64_BITS_UNSIGNED:          case MDS_64_BITS_SIGNED: -            init_mrange(&range, addr, 8); +            length = 8;              break;          default:              assert(false); -            goto error; +            goto exit;              break;      } -    g_arch_instruction_set_range(result, &range); +    g_arch_instruction_compute_range(G_ARCH_INSTRUCTION(instr), area, addr, length); -    return result; - - error: - -    g_object_unref(G_OBJECT(result)); - -    return NULL; - -} +    result = true; - -/****************************************************************************** -*                                                                             * -*  Paramètres  : content = flux de données à analyser.                        * -*                addr    = position courante dans ce flux. [OUT]              * -*                                                                             * -*  Description : Crée une instruction de type 'db/dw/etc' pour un uleb128.    * -*                                                                             * -*  Retour      : Instruction mise en place.                                   * -*                                                                             * -*  Remarques   : -                                                            * -*                                                                             * -******************************************************************************/ - -GArchInstruction *g_raw_instruction_new_uleb128(const GBinContent *content, vmpa2t *addr) -{ -    GArchInstruction *result;               /* Instruction à retourner     */ -    vmpa2t start;                           /* Départ original de lecture  */ -    uleb128_t value;                        /* Valeur uleb128 à représenter*/ -    phys_t diff;                            /* Couverture de la lecture    */ -    MemoryDataSize leb_size;                /* Taille de la valeur         */ -    GArchOperand *operand;                  /* Octet non décodé à afficher */ -    mrange_t range;                         /* Couverture de l'instruction */ - -    result = NULL; - -    copy_vmpa(&start, addr); - -    if (!g_binary_content_read_uleb128(content, addr, &value)) -        goto error; - -    diff = compute_vmpa_diff(&start, addr); - -    leb_size = MDS_FROM_BYTES(diff); -    assert(leb_size != MDS_UNDEFINED); - -    result = g_object_new(G_TYPE_RAW_INSTRUCTION, NULL); - -    init_mrange(&range, &start, diff); -    g_arch_instruction_set_range(result, &range); - -    operand = g_imm_operand_new_from_value(leb_size, (uint64_t)value); -    if (operand == NULL) goto error; - -    g_arch_operand_set_flag(operand, IOF_ZERO_PADDING_BY_DEFAULT | IOF_ZERO_PADDING); - -    g_arch_instruction_attach_extra_operand(result, operand); + exit:      return result; - error: - -    g_clear_object(&result); - -    return NULL; -  }  /******************************************************************************  *                                                                             * -*  Paramètres  : content = flux de données à analyser.                        * -*                addr    = position courante dans ce flux. [OUT]              * +*  Paramètres  : area    = portion de binaire incluant l'instruction.         * +*                addr    = adresse virtuelle et/ou position physique.         * +*                size    = taille de chacun des éléments à représenter.       * +*                content = flux de données à analyser.                        * +*                count   = nombre de ces éléments.                            * +*                endian  = ordre des bits dans la source.                     *  *                                                                             * -*  Description : Crée une instruction de type 'db/dw/etc' pour un sleb128.    * +*  Description : Crée une instruction de type 'db/dw/etc' étendue.            *  *                                                                             *  *  Retour      : Instruction mise en place.                                   *  *                                                                             * @@ -338,256 +282,174 @@ GArchInstruction *g_raw_instruction_new_uleb128(const GBinContent *content, vmpa  *                                                                             *  ******************************************************************************/ -GArchInstruction *g_raw_instruction_new_sleb128(const GBinContent *content, vmpa2t *addr) +GArchInstruction *g_raw_instruction_new_array(GBinaryPortion *area, vmpa2t *addr, MemoryDataSize size, const GBinContent *content, size_t count, SourceEndian endian)  {      GArchInstruction *result;               /* Instruction à retourner     */ -    vmpa2t start;                           /* Départ original de lecture  */ -    uleb128_t value;                        /* Valeur uleb128 à représenter*/ -    phys_t diff;                            /* Couverture de la lecture    */ -    MemoryDataSize leb_size;                /* Taille de la valeur         */ -    GArchOperand *operand;                  /* Octet non décodé à afficher */ -    mrange_t range;                         /* Couverture de l'instruction */ - -    result = NULL; - -    copy_vmpa(&start, addr); - -    if (!g_binary_content_read_uleb128(content, addr, &value)) -        goto error; - -    diff = compute_vmpa_diff(&start, addr); - -    leb_size = MDS_FROM_BYTES(diff) | MDS_SIGN; -    assert(leb_size != MDS_SIGN);      result = g_object_new(G_TYPE_RAW_INSTRUCTION, NULL); -    init_mrange(&range, &start, diff); -    g_arch_instruction_set_range(result, &range); - -    operand = g_imm_operand_new_from_value(leb_size, (uint64_t)value); -    if (operand == NULL) goto error; - -    g_arch_operand_set_flag(operand, IOF_ZERO_PADDING_BY_DEFAULT | IOF_ZERO_PADDING); - -    g_arch_instruction_attach_extra_operand(result, operand); +    if (!g_raw_instruction_create_array(G_RAW_INSTRUCTION(result), area, addr, size, content, count, endian)) +        g_clear_object(&result);      return result; - error: - -    g_clear_object(&result); - -    return NULL; -  }  /******************************************************************************  *                                                                             * -*  Paramètres  : content = flux de données à analyser.                        * +*  Paramètres  : instr   = instance à initialiser pleinement.                 * +*                area    = portion de binaire incluant l'instruction.         * +*                addr    = adresse virtuelle et/ou position physique.         *  *                size    = taille de chacun des éléments à représenter.       * +*                content = flux de données à analyser.                        *  *                count   = nombre de ces éléments.                            * -*                addr    = position courante dans ce flux. [OUT]              *  *                endian  = ordre des bits dans la source.                     *  *                                                                             * -*  Description : Crée une instruction de type 'db/dw/etc' étendue.            * +*  Description : Met en place une instruction de type 'db/dw/etc' étendue.    *  *                                                                             * -*  Retour      : Instruction mise en place.                                   * +*  Retour      : Bilan de l'opération.                                        *  *                                                                             *  *  Remarques   : -                                                            *  *                                                                             *  ******************************************************************************/ -GArchInstruction *g_raw_instruction_new_array(const GBinContent *content, MemoryDataSize size, size_t count, vmpa2t *addr, SourceEndian endian) +bool g_raw_instruction_create_array(GRawInstruction *instr, GBinaryPortion *area, vmpa2t *addr, MemoryDataSize size, const GBinContent *content, size_t count, SourceEndian endian)  { -    GArchInstruction *result;               /* Instruction à retourner     */ -    vmpa2t old;                             /* Sauvegarde de la position   */ +    bool result;                            /* Bilan à retourner           */ +    vmpa2t start;                           /* Sauvegarde de la position   */      size_t i;                               /* Boucle de parcours          */      GArchOperand *operand;                  /* Octet non décodé à afficher */ -    mrange_t range;                         /* Couverture de l'instruction */ +    phys_t diff;                            /* Décalage à appliquer        */ + +    result = false;      /* Par soucis de cohérence */ -    if (count == 0) return NULL; +    if (count == 0) +        goto exit; -    result = g_object_new(G_TYPE_RAW_INSTRUCTION, NULL); +    copy_vmpa(&start, addr); -    copy_vmpa(&old, addr); +    g_thick_object_lock(G_THICK_OBJECT(instr));      for (i = 0; i < count; i++)      { -        operand = g_imm_operand_new_from_data(size, content, addr, endian); -        if (operand == NULL) goto error; +        operand = g_immediate_operand_new_from_data(size, content, addr, (bool []){ false /* unused */ }, endian); +        if (operand == NULL) break;          g_arch_operand_set_flag(operand, IOF_ZERO_PADDING_BY_DEFAULT | IOF_ZERO_PADDING); -        g_arch_instruction_attach_extra_operand(result, operand); +        g_arch_instruction_attach_operand(G_ARCH_INSTRUCTION(instr), operand); +        unref_object(operand);      } -    init_mrange(&range, &old, compute_vmpa_diff(addr, &old)); +    g_thick_object_unlock(G_THICK_OBJECT(instr)); -    g_arch_instruction_set_range(result, &range); +    if (i < count) +        goto exit; -    return result; +    diff = compute_vmpa_diff(addr, &start); + +    g_arch_instruction_compute_range(G_ARCH_INSTRUCTION(instr), area, &start, diff); - error: +    result = true; -    g_object_unref(G_OBJECT(result)); + exit: -    return NULL; +    return result;  }  /******************************************************************************  *                                                                             * -*  Paramètres  : instr = instruction quelconque à consulter.                  * +*  Paramètres  : instr      = instruction à traiter.                          * +*                is_padding = nouveau statut à associer au contenu.           *  *                                                                             * -*  Description : Indique l'encodage d'une instruction de façon détaillée.     * +*  Description : Marque l'instruction comme ne contenant que du bourrage.     *  *                                                                             * -*  Retour      : Description humaine de l'encodage utilisé.                   * +*  Retour      : -                                                            *  *                                                                             *  *  Remarques   : -                                                            *  *                                                                             *  ******************************************************************************/ -static const char *g_raw_instruction_get_encoding(const GRawInstruction *instr) +void g_raw_instruction_mark_as_padding(GRawInstruction *instr, bool is_padding)  { -    const char *result;                     /* Description à retourner     */ - -    if (g_raw_instruction_is_string(instr)) -        result = _("String"); +    if (is_padding) +        g_arch_instruction_set_flag(G_ARCH_INSTRUCTION(instr), RIF_PADDING);      else -        result = _("Raw"); - -    return result; +        g_arch_instruction_unset_flag(G_ARCH_INSTRUCTION(instr), RIF_PADDING);  }  /******************************************************************************  *                                                                             * -*  Paramètres  : instr = instruction d'assemblage à consulter.                * +*  Paramètres  : instr      = instruction à traiter.                          * +*                is_padding = nouveau statut à associer au contenu.           *  *                                                                             * -*  Description : Fournit le nom humain de l'instruction manipulée.            * +*  Description : Indique si le contenu de l'instruction est du bourrage.      *  *                                                                             * -*  Retour      : Mot clef de bas niveau.                                      * +*  Retour      : Statut du contenu de l'instruction.                          *  *                                                                             *  *  Remarques   : -                                                            *  *                                                                             *  ******************************************************************************/ -static const char *g_raw_instruction_get_keyword(const GRawInstruction *instr) +bool g_raw_instruction_is_padding(const GRawInstruction *instr)  { -    GArchOperand *operand;                  /* Octet décodé à afficher     */ -    MemoryDataSize size;                    /* Taille de valeur associée   */ - -    static char *defines[] = { "dn", "db", "dw", "dd", "dq" }; - -    operand = g_arch_instruction_get_operand(G_ARCH_INSTRUCTION(instr), 0); - -    if (G_IS_TARGET_OPERAND(operand)) -        size = g_target_operand_get_size(G_TARGET_OPERAND(operand)); -    else -        size = g_imm_operand_get_size(G_IMM_OPERAND(operand)); +    bool result;                            /* Indication à retourner      */ -    g_object_unref(G_OBJECT(operand)); +    result = g_arch_instruction_has_flag(G_ARCH_INSTRUCTION(instr), RIF_PADDING); -    return defines[MDS_RANGE(size)]; +    return result;  } - -/* ---------------------------------------------------------------------------------- */ -/*                      CONSERVATION SUR DISQUE DES INSTRUCTIONS                      */ -/* ---------------------------------------------------------------------------------- */ - -  /******************************************************************************  *                                                                             * -*  Paramètres  : instr   = instruction d'assemblage à consulter.              * -*                storage = mécanisme de sauvegarde à manipuler.               * -*                format  = format binaire chargé associé à l'architecture.    * -*                pbuf    = zone tampon à remplir.                             * +*  Paramètres  : instr     = instruction à traiter.                           * +*                is_string = nouveau statut à associer au contenu.            *  *                                                                             * -*  Description : Charge une instruction depuis une mémoire tampon.            * +*  Description : Marque l'instruction comme contenant une chaîne de texte.    *  *                                                                             * -*  Retour      : Bilan de l'opération.                                        * +*  Retour      : -                                                            *  *                                                                             *  *  Remarques   : -                                                            *  *                                                                             *  ******************************************************************************/ -static bool g_raw_instruction_unserialize(GRawInstruction *instr, GAsmStorage *storage, GBinFormat *format, packed_buffer_t *pbuf) +void g_raw_instruction_mark_as_string(GRawInstruction *instr, bool is_string)  { -    bool result;                            /* Bilan à retourner           */ -    GArchInstructionClass *parent;          /* Classe parente à consulter  */ -    uint8_t boolean;                        /* Valeur booléenne            */ - -    parent = G_ARCH_INSTRUCTION_CLASS(g_raw_instruction_parent_class); - -    result = parent->unserialize(G_ARCH_INSTRUCTION(instr), storage, format, pbuf); - -    if (result) -    { -        result = extract_packed_buffer(pbuf, &boolean, sizeof(uint8_t), false); - -        if (result) -            g_raw_instruction_mark_as_padding(instr, (boolean == 1)); - -    } - -    if (result) -    { -        result = extract_packed_buffer(pbuf, &boolean, sizeof(uint8_t), false); - -        if (result) -            g_raw_instruction_mark_as_string(instr, (boolean == 1)); - -    } - -    return result; +    if (is_string) +        g_arch_instruction_set_flag(G_ARCH_INSTRUCTION(instr), RIF_STRING); +    else +        g_arch_instruction_unset_flag(G_ARCH_INSTRUCTION(instr), RIF_STRING);  }  /******************************************************************************  *                                                                             * -*  Paramètres  : instr   = instruction d'assemblage à consulter.              * -*                storage = mécanisme de sauvegarde à manipuler.               * -*                pbuf    = zone tampon à remplir.                             * +*  Paramètres  : instr     = instruction à traiter.                           * +*                is_string = nouveau statut à associer au contenu.            *  *                                                                             * -*  Description : Sauvegarde une instruction dans une mémoire tampon.          * +*  Description : Indique si le contenu de l'instruction est un texte.         *  *                                                                             * -*  Retour      : Bilan de l'opération.                                        * +*  Retour      : Statut du contenu de l'instruction.                          *  *                                                                             *  *  Remarques   : -                                                            *  *                                                                             *  ******************************************************************************/ -static bool g_raw_instruction_serialize(GRawInstruction *instr, GAsmStorage *storage, packed_buffer_t *pbuf) +bool g_raw_instruction_is_string(const GRawInstruction *instr)  { -    bool result;                            /* Bilan à retourner           */ -    GArchInstructionClass *parent;          /* Classe parente à consulter  */ -    uint8_t boolean;                        /* Valeur booléenne            */ - -    parent = G_ARCH_INSTRUCTION_CLASS(g_raw_instruction_parent_class); - -    result = parent->serialize(G_ARCH_INSTRUCTION(instr), storage, pbuf); - -    if (result) -    { -        boolean = (g_raw_instruction_is_padding(instr) ? 1 : 0); -        result = extend_packed_buffer(pbuf, &boolean, sizeof(uint8_t), false); -    } +    bool result;                            /* Indication à retourner      */ -    if (result) -    { -        boolean = (g_raw_instruction_is_string(instr) ? 1 : 0); -        result = extend_packed_buffer(pbuf, &boolean, sizeof(uint8_t), false); -    } +    result = g_arch_instruction_has_flag(G_ARCH_INSTRUCTION(instr), RIF_STRING);      return result; @@ -596,285 +458,73 @@ static bool g_raw_instruction_serialize(GRawInstruction *instr, GAsmStorage *sto  /* ---------------------------------------------------------------------------------- */ -/*                          OFFRE DE CAPACITES DE GENERATION                          */ +/*                       IMPLEMENTATION DES FONCTIONS DE CLASSE                       */  /* ---------------------------------------------------------------------------------- */  /******************************************************************************  *                                                                             * -*  Paramètres  : instr   = instruction d'assemblage à représenter.            * -*                line    = ligne de rendu à compléter.                        * -*                index   = indice de cette même ligne dans le tampon global.  * -*                repeat  = indice d'utilisations successives du générateur.   * -*                content = éventuel contenu binaire brut à imprimer.          * +*  Paramètres  : instr = instruction quelconque à consulter.                  *  *                                                                             * -*  Description : Ajoute à un tampon GLib le contenu de l'instance spécifiée.  * +*  Description : Indique l'encodage d'une instruction de façon détaillée.     *  *                                                                             * -*  Retour      : -                                                            * +*  Retour      : Description humaine de l'encodage utilisé.                   *  *                                                                             *  *  Remarques   : -                                                            *  *                                                                             *  ******************************************************************************/ -static void g_raw_instruction_print(GRawInstruction *instr, GBufferLine *line, size_t index, size_t repeat, const GBinContent *content) +static char *g_raw_instruction_get_encoding(const GArchInstruction *instr)  { -    GArchInstruction *base;                 /* Autre version de l'instance */ -    phys_t max_displayed_len;               /* Quantité de code affichée   */ -    const char *key;                        /* Mot clef principal          */ -    size_t klen;                            /* Taille de ce mot clef       */ -    char *string;                           /* Chaîne reconstituée         */ -    size_t iter;                            /* Tête d'écriture             */ -    bool first;                             /* Mémorise une énumération    */ -    size_t count;                           /* Nombre d'opérandes en place */ -    size_t i;                               /* Boucle de parcours          */ -    GArchOperand *op;                       /* Opérande à manipuler        */ -    GImmOperand *imm;                       /* Version opérande de valeur  */ -    char byte;                              /* Octet à afficher (ou pas)   */ -#ifndef NDEBUG -    bool status;                            /* Bilan d'une récupération    */ -#endif - -    base = G_ARCH_INSTRUCTION(instr); - -    /* Localisation */ - -    g_buffer_line_fill_phys(line, DLC_PHYSICAL, MDS_32_BITS_UNSIGNED, get_mrange_addr(&base->range)); - -    g_buffer_line_fill_virt(line, DLC_VIRTUAL, MDS_32_BITS_UNSIGNED, get_mrange_addr(&base->range)); - -    /* Contenu */ - -    if (g_raw_instruction_is_padding(instr)) -        max_displayed_len = 0; - -    else if (g_raw_instruction_is_string(instr)) -        max_displayed_len = 1; - -    else -    { -        max_displayed_len = get_mrange_length(&base->range); -        max_displayed_len /= g_arch_instruction_count_operands(base); -    } - -    g_buffer_line_fill_content(line, DLC_BINARY, content, &base->range, max_displayed_len); - -    /* Zone du code d'assemblage */ +    char *result;                           /* Description à retourner     */ +    GRawInstruction *raw;                   /* Version spécialisée         */ -    key = g_arch_instruction_get_keyword(base); -    klen = strlen(key); - -    g_buffer_line_append_text(line, DLC_ASSEMBLY_HEAD, key, klen, RTT_INSTRUCTION, NULL); - -    if (g_raw_instruction_is_padding(instr)) -        g_buffer_line_append_text(line, DLC_ASSEMBLY, "...", 3, RTT_RAW, NULL); +    raw = G_RAW_INSTRUCTION(instr); +    if (g_raw_instruction_is_string(raw)) +        result = strdup(_("String"));      else -    { -        string = NULL; -        iter = 0; - -        first = true; - -        g_arch_instruction_lock_operands(base); - -        count = _g_arch_instruction_count_operands(base); - -        for (i = 0; i < count; i++) -        { -            op = _g_arch_instruction_get_operand(base, i); - -            if (!G_IS_IMM_OPERAND(op)) -                goto grip_fallback; - -            imm = G_IMM_OPERAND(op); - -            if (g_imm_operand_get_size(imm) != MDS_8_BITS) -                goto grip_fallback; - -            if (!g_raw_instruction_is_string(instr) && g_imm_operand_get_display(imm) != IOD_CHAR) -                goto grip_fallback; - -#ifndef NDEBUG -            status = g_imm_operand_get_value(imm, MDS_8_BITS, &byte); -            assert(status); -#else -            g_imm_operand_get_value(imm, MDS_8_BITS, &byte); -#endif - -            /* Si le caractère doit apparaître en hexadécimal... */ - -            if (!isprint(byte)) -                goto grip_fallback; - -            /* Impression de l'octet */ - -            if (string == NULL) -            { -                string = (char *)calloc(count + 3, sizeof(char)); - -                strcpy(string, "\""); -                iter = 1; - -            } - -            string[iter++] = byte; - -            g_object_unref(G_OBJECT(op)); - -            continue; - - grip_fallback: - -            /* Si une chaîne précède */ - -            if (string != NULL && iter > 1) -            { -                if (!first) -                { -                    g_buffer_line_append_text(line, DLC_ASSEMBLY, ",", 1, RTT_PUNCT, NULL); -                    g_buffer_line_append_text(line, DLC_ASSEMBLY, " ", 1, RTT_RAW, NULL); -                } -                else -                    first = false; - -                string[iter++] = '"'; - -                g_buffer_line_append_text(line, DLC_ASSEMBLY, string, iter, RTT_STRING, NULL); - -                iter = 1; - -            } - -            /* Intégration en tant qu'opérande classique */ - -            if (!first) -            { -                g_buffer_line_append_text(line, DLC_ASSEMBLY, ",", 1, RTT_PUNCT, NULL); -                g_buffer_line_append_text(line, DLC_ASSEMBLY, " ", 1, RTT_RAW, NULL); -            } -            else -                first = false; - -            g_arch_operand_print(op, line); - -            g_object_unref(G_OBJECT(op)); - -        } - -        /* Si au final une chaîne traine encore */ - -        if (string != NULL && iter > 1) -        { -            if (!first) -            { -                g_buffer_line_append_text(line, DLC_ASSEMBLY, ",", 1, RTT_PUNCT, NULL); -                g_buffer_line_append_text(line, DLC_ASSEMBLY, " ", 1, RTT_RAW, NULL); -            } - -            string[iter++] = '"'; - -            g_buffer_line_append_text(line, DLC_ASSEMBLY, string, iter, RTT_STRING, NULL); - -        } +        result = strdup(_("Raw")); -        g_arch_instruction_unlock_operands(base); - -        if (string != NULL) -            free(string); - -    } - -} - - -/****************************************************************************** -*                                                                             * -*  Paramètres  : instr      = instruction à traiter.                          * -*                is_padding = nouveau statut à associer au contenu.           * -*                                                                             * -*  Description : Marque l'instruction comme ne contenant que du bourrage.     * -*                                                                             * -*  Retour      : -                                                            * -*                                                                             * -*  Remarques   : -                                                            * -*                                                                             * -******************************************************************************/ - -void g_raw_instruction_mark_as_padding(GRawInstruction *instr, bool is_padding) -{ -    if (is_padding) -        g_arch_instruction_set_flag(G_ARCH_INSTRUCTION(instr), RIF_PADDING); -    else -        g_arch_instruction_unset_flag(G_ARCH_INSTRUCTION(instr), RIF_PADDING); +    return result;  }  /******************************************************************************  *                                                                             * -*  Paramètres  : instr      = instruction à traiter.                          * -*                is_padding = nouveau statut à associer au contenu.           * +*  Paramètres  : instr = instruction d'assemblage à consulter.                *  *                                                                             * -*  Description : Indique si le contenu de l'instruction est du bourrage.      * +*  Description : Fournit le nom humain de l'instruction manipulée.            *  *                                                                             * -*  Retour      : Statut du contenu de l'instruction.                          * +*  Retour      : Mot clef de bas niveau.                                      *  *                                                                             *  *  Remarques   : -                                                            *  *                                                                             *  ******************************************************************************/ -bool g_raw_instruction_is_padding(const GRawInstruction *instr) +static char *g_raw_instruction_get_keyword(const GArchInstruction *instr)  { -    bool result;                            /* Indication à retourner      */ - -    result = g_arch_instruction_has_flag(G_ARCH_INSTRUCTION(instr), RIF_PADDING); - -    return result; - -} +    char *result;                           /* Désignation à retourner     */ +    GArchOperand *operand;                  /* Octet décodé à afficher     */ +    MemoryDataSize size;                    /* Taille de valeur associée   */ +    static char *defines[] = { "dn", "db", "dw", "dd", "dq" }; -/****************************************************************************** -*                                                                             * -*  Paramètres  : instr     = instruction à traiter.                           * -*                is_string = nouveau statut à associer au contenu.            * -*                                                                             * -*  Description : Marque l'instruction comme contenant une chaîne de texte.    * -*                                                                             * -*  Retour      : -                                                            * -*                                                                             * -*  Remarques   : -                                                            * -*                                                                             * -******************************************************************************/ +    g_thick_object_lock(G_THICK_OBJECT(instr)); -void g_raw_instruction_mark_as_string(GRawInstruction *instr, bool is_string) -{ -    if (is_string) -        g_arch_instruction_set_flag(G_ARCH_INSTRUCTION(instr), RIF_STRING); -    else -        g_arch_instruction_unset_flag(G_ARCH_INSTRUCTION(instr), RIF_STRING); - -} +    operand = g_arch_instruction_get_operand(instr, 0); +    /*if (G_IS_TARGET_OPERAND(operand)) FIXME  +        size = g_target_operand_get_size(G_TARGET_OPERAND(operand)); +        else*/ +        size = g_immediate_operand_get_size(G_IMMEDIATE_OPERAND(operand)); -/****************************************************************************** -*                                                                             * -*  Paramètres  : instr     = instruction à traiter.                           * -*                is_string = nouveau statut à associer au contenu.            * -*                                                                             * -*  Description : Indique si le contenu de l'instruction est un texte.         * -*                                                                             * -*  Retour      : Statut du contenu de l'instruction.                          * -*                                                                             * -*  Remarques   : -                                                            * -*                                                                             * -******************************************************************************/ +    unref_object(operand); -bool g_raw_instruction_is_string(const GRawInstruction *instr) -{ -    bool result;                            /* Indication à retourner      */ +    g_thick_object_unlock(G_THICK_OBJECT(instr)); -    result = g_arch_instruction_has_flag(G_ARCH_INSTRUCTION(instr), RIF_STRING); +    result = strdup(defines[MDS_RANGE(size)]);      return result; diff --git a/src/arch/instructions/raw.h b/src/arch/instructions/raw.h index 4e92cd4..712f877 100644 --- a/src/arch/instructions/raw.h +++ b/src/arch/instructions/raw.h @@ -1,8 +1,8 @@  /* Chrysalide - Outil d'analyse de fichiers binaires - * raw.h - prototypes pour les instructions pures vues de l'esprit + * raw.h - prototypes pour les instructions de données brutes   * - * Copyright (C) 2014-2020 Cyrille Bagard + * Copyright (C) 2014-2025 Cyrille Bagard   *   *  This file is part of Chrysalide.   * @@ -25,46 +25,24 @@  #define _ARCH_INSTRUCTIONS_RAW_H -#include <glib-object.h> - -  #include "../instruction.h"  #include "../vmpa.h" +#include "../../analysis/content.h" +#include "../../glibext/helpers.h" -/* ------------------------- INSTRUCTION INCONNUE / DONNEES ------------------------- */ - - -#define G_TYPE_RAW_INSTRUCTION            g_raw_instruction_get_type() -#define G_RAW_INSTRUCTION(obj)            (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_RAW_INSTRUCTION, GRawInstruction)) -#define G_IS_RAW_INSTRUCTION(obj)         (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_RAW_INSTRUCTION)) -#define G_RAW_INSTRUCTION_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_RAW_INSTRUCTION, GRawInstructionClass)) -#define G_IS_RAW_INSTRUCTION_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_RAW_INSTRUCTION)) -#define G_RAW_INSTRUCTION_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_RAW_INSTRUCTION, GRawInstructionClass)) - +#define G_TYPE_RAW_INSTRUCTION (g_raw_instruction_get_type()) -/* Définition générique d'une instruction brute d'architecture (instance) */ -typedef struct _GRawInstruction GRawInstruction; +DECLARE_GTYPE(GRawInstruction, g_raw_instruction, G, RAW_INSTRUCTION); -/* Définition générique d'une instruction brute d'architecture (classe) */ -typedef struct _GRawInstructionClass GRawInstructionClass; - - -/* Indique le type défini pour une instruction inconnue d'architecture. */ -GType g_raw_instruction_get_type(void);  /* Crée une instruction de type 'db/dw/etc' simple. */ -GArchInstruction *g_raw_instruction_new_from_value(const vmpa2t *, MemoryDataSize, uint64_t); +GArchInstruction *g_raw_instruction_new_from_value(GBinaryPortion *, const vmpa2t *, MemoryDataSize, uint64_t); -/* Crée une instruction de type 'db/dw/etc' pour un uleb128. */ -GArchInstruction *g_raw_instruction_new_uleb128(const GBinContent *content, vmpa2t *); +/*  Crée une instruction de type 'db/dw/etc' étendue. */ +GArchInstruction *g_raw_instruction_new_array(GBinaryPortion *, vmpa2t *, MemoryDataSize, const GBinContent *, size_t, SourceEndian); -/* Crée une instruction de type 'db/dw/etc' pour un sleb128. */ -GArchInstruction *g_raw_instruction_new_sleb128(const GBinContent *content, vmpa2t *); - -/* Crée une instruction de type 'db/dw/etc' étendue. */ -GArchInstruction *g_raw_instruction_new_array(const GBinContent *, MemoryDataSize, size_t, vmpa2t *, SourceEndian);  /* Drapeaux pour informations complémentaires */  typedef enum _RawInstrFlag @@ -74,6 +52,7 @@ typedef enum _RawInstrFlag  } RawInstrFlag; +  /* Marque l'instruction comme ne contenant que du bourrage. */  void g_raw_instruction_mark_as_padding(GRawInstruction *, bool); diff --git a/src/arch/instructions/undefined-int.h b/src/arch/instructions/undefined-int.h index a9b7627..faf0b4b 100644 --- a/src/arch/instructions/undefined-int.h +++ b/src/arch/instructions/undefined-int.h @@ -1,8 +1,8 @@  /* Chrysalide - Outil d'analyse de fichiers binaires - * undefined-int.h - prototypes pour la définition générique interne des instructions au comportement non défini + * undefined-int.h - prototypes pour la définition interne des instructions au comportement non défini   * - * Copyright (C) 2019 Cyrille Bagard + * Copyright (C) 2019-2025 Cyrille Bagard   *   *  This file is part of Chrysalide.   * @@ -27,42 +27,18 @@  #include "undefined.h"  #include "../instruction-int.h" -#include "../../glibext/objhole.h" -/* Informations glissées dans la structure GObject de GArchInstruction */ -typedef struct _undef_extra_data_t -{ -    /** -     * Le champ uid de la structure parente attendue conduit à une taille -     * alignée sur 2 octets, donc à une taille totale de 4 octets ce qui -     * représente la limite maximale de taille supportée. -     * -     * Pour 3 octets à la base, qui devraient laisser 8 - 1 octets disponbibles -     * en incluant le bit de verrouillage. -     * -     * On reproduit donc la structure instr_extra_data_t ici, en basculant -     * l'énumération InstrExpectedBehavior en champ de bits. -     */ - -    itid_t uid;                             /* Identifiant unique du type  */ -    ArchInstrFlag flags;                    /* Informations complémentaires*/ - -    unsigned int behavior : 2;              /* Conséquences réelles        */ - -} undef_extra_data_t; - -  /* Définition générique d'une instruction au comportement non défini (instance) */ -struct _GUndefInstruction +struct _GUndefinedInstruction  {      GArchInstruction parent;                /* A laisser en premier        */  };  /* Définition générique d'une instruction au comportement non défini (classe) */ -struct _GUndefInstructionClass +struct _GUndefinedInstructionClass  {      GArchInstructionClass parent;           /* A laisser en premier        */ @@ -73,15 +49,25 @@ struct _GUndefInstructionClass   * Accès aux informations éventuellement déportées.   */ -#if 1 //__SIZEOF_INT__ == __SIZEOF_LONG__ +/* Informations glissées dans la structure GObject de GArchInstruction */ +typedef struct _undef_extra_data_t +{ +    ARCH_INSTRUCTION_EXTRA_DATA + +    unsigned int behavior : 2;              /* Conséquences réelles        */ + +} undef_extra_data_t; + -#   define GET_UNDEF_INSTR_EXTRA(ins) ((undef_extra_data_t *)&((GArchInstruction *)ins)->extra) +#define GET_UNDEF_INSTR_EXTRA(op) \ +    GET_GOBJECT_EXTRA(op, undef_extra_data_t) -#else +#define SET_UNDEF_INSTR_EXTRA(op, data) \ +    SET_GOBJECT_EXTRA(op, undef_extra_data_t, data) -#   define GET_UNDEF_INSTR_EXTRA(ins) GET_GOBJECT_EXTRA(G_OBJECT(ins), undef_extra_data_t) -#endif +/* Met en place une instruction au comportement indéfini. */ +bool g_undefined_instruction_create(GUndefinedInstruction *, InstrExpectedBehavior); diff --git a/src/arch/instructions/undefined-ui.c b/src/arch/instructions/undefined-ui.c new file mode 100644 index 0000000..fbc0452 --- /dev/null +++ b/src/arch/instructions/undefined-ui.c @@ -0,0 +1,102 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * undefined-ui.c - opérandes représentant des instructions indéfinies sous forme graphique + * + * 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/>. + */ + + +#include "undefined-ui.h" + + +#include "../instruction.h" +#include "../../glibext/options/asm.h" + + + +/* Etablit dans une ligne de rendu le contenu représenté. */ +static void g_undefined_instruction_ui_populate_line(const GTokenGenerator *, size_t, size_t, GBufferLine *, void *); + + + +/****************************************************************************** +*                                                                             * +*  Paramètres  : iface = interface GLib à initialiser.                        * +*                                                                             * +*  Description : Procède à l'initialisation de l'interface de génération.     * +*                                                                             * +*  Retour      : -                                                            * +*                                                                             * +*  Remarques   : -                                                            * +*                                                                             * +******************************************************************************/ + +void g_undefined_instruction_ui_token_generator_iface_init(GTokenGeneratorInterface *iface) +{ +    iface->populate = g_undefined_instruction_ui_populate_line; + +} + + +/****************************************************************************** +*                                                                             * +*  Paramètres  : generator = générateur à utiliser pour l'impression.         * +*                index     = indice de cette même ligne dans le tampon global.* +*                repeat    = indice d'utilisations successives du générateur. * +*                line      = ligne de rendu à compléter.                      * +*                data      = éventuelle donnée complémentaire fournie.        * +*                                                                             * +*  Description : Etablit dans une ligne de rendu le contenu représenté.       * +*                                                                             * +*  Retour      : -                                                            * +*                                                                             * +*  Remarques   : -                                                            * +*                                                                             * +******************************************************************************/ + +static void g_undefined_instruction_ui_populate_line(const GTokenGenerator *generator, size_t index, size_t repeat, GBufferLine *line, void *data) +{ +    GArchInstruction *instr;                /* Version spécialisée         */ +    GBinContent *content;                   /* Contenu brut d'origine      */ +    mrange_t range;                         /* Emplacement couvert         */ +    char *key;                              /* Mot clef principal          */ + +    instr = G_ARCH_INSTRUCTION(generator); +    content = G_BIN_CONTENT(data); + +    /* Prologue */ + +    if (g_arch_instruction_get_range(instr, &range)) +    { +        g_buffer_line_fill_physical(line, ACO_PHYSICAL, MDS_32_BITS_UNSIGNED, get_mrange_addr(&range)); + +        g_buffer_line_fill_virtual(line, ACO_VIRTUAL, MDS_32_BITS_UNSIGNED, get_mrange_addr(&range)); + +        g_buffer_line_fill_content(line, ACO_BINARY, content, &range, VMPA_NO_PHYSICAL); + +    } + +    /* Instruction proprement dite */ + +    key = g_arch_instruction_get_keyword(instr); + +    g_buffer_line_append_text(line, ACO_ASSEMBLY_HEAD, TRT_ERROR, SL(key), NULL, G_OBJECT(instr)); + +    free(key); + +} diff --git a/src/arch/instructions/undefined-ui.h b/src/arch/instructions/undefined-ui.h new file mode 100644 index 0000000..8bc2d67 --- /dev/null +++ b/src/arch/instructions/undefined-ui.h @@ -0,0 +1,37 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * undefined-ui.h - prototypes pour les opérandes représentant des instructions indéfinies sous forme graphique + * + * 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 _ARCH_OPERANDS_UNDEFINED_UI_H +#define _ARCH_OPERANDS_UNDEFINED_UI_H + + +#include "../../glibext/generator-int.h" + + + +/* Procède à l'initialisation de l'interface de génération. */ +void g_undefined_instruction_ui_token_generator_iface_init(GTokenGeneratorInterface *); + + + +#endif  /* _ARCH_OPERANDS_UNDEFINED_UI_H */ diff --git a/src/arch/instructions/undefined.c b/src/arch/instructions/undefined.c index 15c63e7..75df493 100644 --- a/src/arch/instructions/undefined.c +++ b/src/arch/instructions/undefined.c @@ -2,7 +2,7 @@  /* Chrysalide - Outil d'analyse de fichiers binaires   * undefined.c - instructions au comportement non défini   * - * Copyright (C) 2016-2019 Cyrille Bagard + * Copyright (C) 2016-2025 Cyrille Bagard   *   *  This file is part of Chrysalide.   * @@ -25,63 +25,42 @@  #include <assert.h> +#include <string.h>  #include <i18n.h>  #include "undefined-int.h" -#include "../../core/columns.h" +#include "../../glibext/serialize-int.h" +/* ------------------------- INSTRUCTION INCONNUE / DONNEES ------------------------- */ + +  /* Initialise la classe des instructions non définies. */ -static void g_undef_instruction_class_init(GUndefInstructionClass *); +static void g_undefined_instruction_class_init(GUndefinedInstructionClass *);  /* Initialise une instance d'instruction non définie. */ -static void g_undef_instruction_init(GUndefInstruction *); +static void g_undefined_instruction_init(GUndefinedInstruction *);  /* Supprime toutes les références externes. */ -static void g_undef_instruction_dispose(GUndefInstruction *); +static void g_undefined_instruction_dispose(GObject *);  /* Procède à la libération totale de la mémoire. */ -static void g_undef_instruction_finalize(GUndefInstruction *); - -/* Indique l'encodage d'une instruction de façon détaillée. */ -static const char *g_undef_instruction_get_encoding(const GUndefInstruction *); - -/* Fournit le nom humain de l'instruction manipulée. */ -static const char *g_undef_instruction_get_keyword(const GUndefInstruction *); - - - -/* -------------------- CONSERVATION SUR DISQUE DES INSTRUCTIONS -------------------- */ - - -/* Charge une instruction depuis une mémoire tampon. */ -static bool g_undef_instruction_unserialize(GUndefInstruction *, GAsmStorage *, GBinFormat *, packed_buffer_t *); - -/* Sauvegarde une instruction dans une mémoire tampon. */ -static bool g_undef_instruction_serialize(GUndefInstruction *, GAsmStorage *, packed_buffer_t *); - - - -/* ------------------------ OFFRE DE CAPACITES DE GENERATION ------------------------ */ - - -/* Ajoute à un tampon GLib le contenu de l'instance spécifiée. */ -static void g_undef_instruction_print(GUndefInstruction *, GBufferLine *, size_t, size_t, const GBinContent *); +static void g_undefined_instruction_finalize(GObject *);  /* --------------------- IMPLEMENTATION DES FONCTIONS DE CLASSE --------------------- */ -/* Charge un contenu depuis une mémoire tampon. */ -static bool g_undef_instruction_load(GUndefInstruction *, GObjectStorage *, packed_buffer_t *); +/* Indique l'encodage d'une instruction de façon détaillée. */ +static char *g_undefined_instruction_get_encoding(const GArchInstruction *); -/* Sauvegarde un contenu dans une mémoire tampon. */ -static bool g_undef_instruction_store(GUndefInstruction *, GObjectStorage *, packed_buffer_t *); +/* Fournit le nom humain de l'instruction manipulée. */ +static char *g_undefined_instruction_get_keyword(const GArchInstruction *); @@ -91,7 +70,9 @@ static bool g_undef_instruction_store(GUndefInstruction *, GObjectStorage *, pac  /* Indique le type défini pour une instruction au comportement non défini. */ -G_DEFINE_TYPE(GUndefInstruction, g_undef_instruction, G_TYPE_ARCH_INSTRUCTION); +G_DEFINE_TYPE_WITH_CODE(GUndefinedInstruction, g_undefined_instruction, G_TYPE_ARCH_INSTRUCTION, +                        G_IMPLEMENT_INTERFACE_IF_SYM(g_token_generator_get_type, g_undefined_instruction_ui_token_generator_iface_init)); +  /****************************************************************************** @@ -106,28 +87,20 @@ G_DEFINE_TYPE(GUndefInstruction, g_undef_instruction, G_TYPE_ARCH_INSTRUCTION);  *                                                                             *  ******************************************************************************/ -static void g_undef_instruction_class_init(GUndefInstructionClass *klass) +static void g_undefined_instruction_class_init(GUndefinedInstructionClass *klass)  {      GObjectClass *object;                   /* Autre version de la classe  */      GArchInstructionClass *instr;           /* Encore une autre vision...  */      object = G_OBJECT_CLASS(klass); -    object->dispose = (GObjectFinalizeFunc/* ! */)g_undef_instruction_dispose; -    object->finalize = (GObjectFinalizeFunc)g_undef_instruction_finalize; +    object->dispose = g_undefined_instruction_dispose; +    object->finalize = g_undefined_instruction_finalize;      instr = G_ARCH_INSTRUCTION_CLASS(klass); -    instr->get_encoding = (get_instruction_encoding_fc)g_undef_instruction_get_encoding; -    instr->get_keyword = (get_instruction_keyword_fc)g_undef_instruction_get_keyword; - -    instr->unserialize = (unserialize_instruction_fc)g_undef_instruction_unserialize; -    instr->serialize = (serialize_instruction_fc)g_undef_instruction_serialize; - -    instr->print = (print_instruction_fc)g_undef_instruction_print; - -    instr->load = (load_instruction_fc)g_undef_instruction_load; -    instr->store = (store_instruction_fc)g_undef_instruction_store; +    instr->get_encoding = g_undefined_instruction_get_encoding; +    instr->get_keyword = g_undefined_instruction_get_keyword;  } @@ -144,16 +117,22 @@ static void g_undef_instruction_class_init(GUndefInstructionClass *klass)  *                                                                             *  ******************************************************************************/ -static void g_undef_instruction_init(GUndefInstruction *instr) +static void g_undefined_instruction_init(GUndefinedInstruction *instr)  { -    GET_UNDEF_INSTR_EXTRA(instr)->behavior = IEB_UNDEFINED; +    undef_extra_data_t extra;               /* Données insérées à consulter*/ + +    extra = GET_UNDEF_INSTR_EXTRA(instr); + +    extra.behavior = IEB_UNDEFINED; + +    SET_UNDEF_INSTR_EXTRA(instr, &extra);  }  /******************************************************************************  *                                                                             * -*  Paramètres  : instr = instance d'objet GLib à traiter.                     * +*  Paramètres  : object = instance d'objet GLib à traiter.                    *  *                                                                             *  *  Description : Supprime toutes les références externes.                     *  *                                                                             * @@ -163,16 +142,16 @@ static void g_undef_instruction_init(GUndefInstruction *instr)  *                                                                             *  ******************************************************************************/ -static void g_undef_instruction_dispose(GUndefInstruction *instr) +static void g_undefined_instruction_dispose(GObject *object)  { -    G_OBJECT_CLASS(g_undef_instruction_parent_class)->dispose(G_OBJECT(instr)); +    G_OBJECT_CLASS(g_undefined_instruction_parent_class)->dispose(object);  }  /******************************************************************************  *                                                                             * -*  Paramètres  : instr = instance d'objet GLib à traiter.                     * +*  Paramètres  : object = instance d'objet GLib à traiter.                    *  *                                                                             *  *  Description : Procède à la libération totale de la mémoire.                *  *                                                                             * @@ -182,9 +161,9 @@ static void g_undef_instruction_dispose(GUndefInstruction *instr)  *                                                                             *  ******************************************************************************/ -static void g_undef_instruction_finalize(GUndefInstruction *instr) +static void g_undefined_instruction_finalize(GObject *object)  { -    G_OBJECT_CLASS(g_undef_instruction_parent_class)->finalize(G_OBJECT(instr)); +    G_OBJECT_CLASS(g_undefined_instruction_parent_class)->finalize(object);  } @@ -201,16 +180,14 @@ static void g_undef_instruction_finalize(GUndefInstruction *instr)  *                                                                             *  ******************************************************************************/ -GArchInstruction *g_undef_instruction_new(InstrExpectedBehavior behavior) +GArchInstruction *g_undefined_instruction_new(InstrExpectedBehavior behavior)  {      GArchInstruction *result;               /* Instruction à retourner     */ -    undef_extra_data_t *extra;              /* Données insérées à modifier */ -    result = g_object_new(G_TYPE_UNDEF_INSTRUCTION, NULL); +    result = g_object_new(G_TYPE_UNDEFINED_INSTRUCTION, NULL); -    extra = GET_UNDEF_INSTR_EXTRA(result); - -    extra->behavior = behavior; +    if (!g_undefined_instruction_create(G_UNDEFINED_INSTRUCTION(result), behavior)) +        g_clear_object(&result);      return result; @@ -219,90 +196,10 @@ GArchInstruction *g_undef_instruction_new(InstrExpectedBehavior behavior)  /******************************************************************************  *                                                                             * -*  Paramètres  : instr = instruction quelconque à consulter.                  * -*                                                                             * -*  Description : Indique l'encodage d'une instruction de façon détaillée.     * -*                                                                             * -*  Retour      : Description humaine de l'encodage utilisé.                   * -*                                                                             * -*  Remarques   : -                                                            * -*                                                                             * -******************************************************************************/ - -static const char *g_undef_instruction_get_encoding(const GUndefInstruction *instr) -{ -    const char *result;                     /* Description à retourner     */ - -    result = _("Undefined"); - -    return result; - -} - - -/****************************************************************************** +*  Paramètres  : instr    = instance à initialiser pleinement.                * +*                behavior = état réel du CPU après une passe de l'instruction.*  *                                                                             * -*  Paramètres  : instr = instruction d'assemblage à consulter.                * -*                                                                             * -*  Description : Fournit le nom humain de l'instruction manipulée.            * -*                                                                             * -*  Retour      : Mot clef de bas niveau.                                      * -*                                                                             * -*  Remarques   : -                                                            * -*                                                                             * -******************************************************************************/ - -const char *g_undef_instruction_get_keyword(const GUndefInstruction *instr) -{ -    const char *result;                     /* Désignation à retourner     */ -    undef_extra_data_t *extra;              /* Données insérées à consulter*/ - -    extra = GET_UNDEF_INSTR_EXTRA(instr); - -    switch (extra->behavior) -    { -        case IEB_NOP: -            result = "nop"; -            break; - -        case IEB_UNDEFINED: -            result = "undefined"; -            break; - -        case IEB_UNPREDICTABLE: -            result = "unpredictable"; -            break; - -        case IEB_RESERVED: -            result = "reserved"; -            break; - -        default: -            assert(false); -            result = NULL; -            break; - -    } - -    return result; - -} - - - -/* ---------------------------------------------------------------------------------- */ -/*                      CONSERVATION SUR DISQUE DES INSTRUCTIONS                      */ -/* ---------------------------------------------------------------------------------- */ - - -/****************************************************************************** -*                                                                             * -*  Paramètres  : instr   = instruction d'assemblage à consulter.              * -*                storage = mécanisme de sauvegarde à manipuler.               * -*                format  = format binaire chargé associé à l'architecture.    * -*                pbuf    = zone tampon à remplir.                             * -*                                                                             * -*  Description : Charge une instruction depuis une mémoire tampon.            * +*  Description : Met en place une instruction au comportement indéfini.       *  *                                                                             *  *  Retour      : Bilan de l'opération.                                        *  *                                                                             * @@ -310,122 +207,24 @@ const char *g_undef_instruction_get_keyword(const GUndefInstruction *instr)  *                                                                             *  ******************************************************************************/ -static bool g_undef_instruction_unserialize(GUndefInstruction *instr, GAsmStorage *storage, GBinFormat *format, packed_buffer_t *pbuf) +bool g_undefined_instruction_create(GUndefinedInstruction *instr, InstrExpectedBehavior behavior)  {      bool result;                            /* Bilan à retourner           */ -    GArchInstructionClass *parent;          /* Classe parente à consulter  */ -    undef_extra_data_t *extra;              /* Données insérées à consulter*/ -    uint8_t val;                            /* Champ de bits manipulé      */ - -    parent = G_ARCH_INSTRUCTION_CLASS(g_undef_instruction_parent_class); +    undef_extra_data_t extra;               /* Données insérées à modifier */ -    result = parent->unserialize(G_ARCH_INSTRUCTION(instr), storage, format, pbuf); +    result = true; -    if (result) -    { -        extra = GET_UNDEF_INSTR_EXTRA(instr); - -        LOCK_GOBJECT_EXTRA(extra); - -        result = extract_packed_buffer(pbuf, &val, sizeof(uint8_t), false); -        extra->behavior = val; - -        UNLOCK_GOBJECT_EXTRA(extra); - -    } - -    return result; - -} - - -/****************************************************************************** -*                                                                             * -*  Paramètres  : instr   = instruction d'assemblage à consulter.              * -*                storage = mécanisme de sauvegarde à manipuler.               * -*                pbuf    = zone tampon à remplir.                             * -*                                                                             * -*  Description : Sauvegarde une instruction dans une mémoire tampon.          * -*                                                                             * -*  Retour      : Bilan de l'opération.                                        * -*                                                                             * -*  Remarques   : -                                                            * -*                                                                             * -******************************************************************************/ - -static bool g_undef_instruction_serialize(GUndefInstruction *instr, GAsmStorage *storage, packed_buffer_t *pbuf) -{ -    bool result;                            /* Bilan à retourner           */ -    GArchInstructionClass *parent;          /* Classe parente à consulter  */ -    undef_extra_data_t *extra;              /* Données insérées à consulter*/ - -    parent = G_ARCH_INSTRUCTION_CLASS(g_undef_instruction_parent_class); - -    result = parent->serialize(G_ARCH_INSTRUCTION(instr), storage, pbuf); - -    if (result) -    { -        extra = GET_UNDEF_INSTR_EXTRA(instr); - -        LOCK_GOBJECT_EXTRA(extra); - -        result = extend_packed_buffer(pbuf, (uint8_t []){ extra->behavior }, sizeof(uint8_t), false); +    extra = GET_UNDEF_INSTR_EXTRA(instr); -        UNLOCK_GOBJECT_EXTRA(extra); +    extra.behavior = behavior; -    } +    SET_UNDEF_INSTR_EXTRA(instr, &extra);      return result;  } - -/* ---------------------------------------------------------------------------------- */ -/*                          OFFRE DE CAPACITES DE GENERATION                          */ -/* ---------------------------------------------------------------------------------- */ - - -/****************************************************************************** -*                                                                             * -*  Paramètres  : instr   = instruction d'assemblage à représenter.            * -*                line    = ligne de rendu à compléter.                        * -*                index   = indice de cette même ligne dans le tampon global.  * -*                repeat  = indice d'utilisations successives du générateur.   * -*                content = éventuel contenu binaire brut à imprimer.          * -*                                                                             * -*  Description : Ajoute à un tampon GLib le contenu de l'instance spécifiée.  * -*                                                                             * -*  Retour      : -                                                            * -*                                                                             * -*  Remarques   : -                                                            * -*                                                                             * -******************************************************************************/ - -static void g_undef_instruction_print(GUndefInstruction *instr, GBufferLine *line, size_t index, size_t repeat, const GBinContent *content) -{ -    GArchInstruction *base;                 /* Version de base             */ -    const char *key;                        /* Mot clef principal          */ -    size_t klen;                            /* Taille de ce mot clef       */ - -    base = G_ARCH_INSTRUCTION(instr); - -    g_buffer_line_fill_phys(line, DLC_PHYSICAL, MDS_32_BITS_UNSIGNED, get_mrange_addr(&base->range)); - -    g_buffer_line_fill_virt(line, DLC_VIRTUAL, MDS_32_BITS_UNSIGNED, get_mrange_addr(&base->range)); - -    g_buffer_line_fill_content(line, DLC_BINARY, content, &base->range, VMPA_NO_PHYSICAL); - -    /* Instruction proprement dite */ - -    key = g_arch_instruction_get_keyword(base); -    klen = strlen(key); - -    g_buffer_line_append_text(line, DLC_ASSEMBLY_HEAD, key, klen, RTT_ERROR, NULL); - -} - -  /******************************************************************************  *                                                                             *  *  Paramètres  : instr  = instruction à consulter.                            * @@ -438,18 +237,14 @@ static void g_undef_instruction_print(GUndefInstruction *instr, GBufferLine *lin  *                                                                             *  ******************************************************************************/ -InstrExpectedBehavior g_undef_instruction_get_behavior(const GUndefInstruction *instr) +InstrExpectedBehavior g_undefined_instruction_get_behavior(const GUndefinedInstruction *instr)  {      InstrExpectedBehavior result;           /* Comportement à retourner    */ -    undef_extra_data_t *extra;              /* Données insérées à consulter*/ +    undef_extra_data_t extra;               /* Données insérées à consulter*/      extra = GET_UNDEF_INSTR_EXTRA(instr); -    LOCK_GOBJECT_EXTRA(extra); - -    result = extra->behavior; - -    UNLOCK_GOBJECT_EXTRA(extra); +    result = extra.behavior;      return result; @@ -464,41 +259,21 @@ InstrExpectedBehavior g_undef_instruction_get_behavior(const GUndefInstruction *  /******************************************************************************  *                                                                             * -*  Paramètres  : instr   = élément GLib à constuire.                          * -*                storage = conservateur de données à manipuler ou NULL.       * -*                pbuf    = zone tampon à lire.                                * +*  Paramètres  : instr = instruction quelconque à consulter.                  *  *                                                                             * -*  Description : Charge un contenu depuis une mémoire tampon.                 * +*  Description : Indique l'encodage d'une instruction de façon détaillée.     *  *                                                                             * -*  Retour      : Bilan de l'opération.                                        * +*  Retour      : Description humaine de l'encodage utilisé.                   *  *                                                                             *  *  Remarques   : -                                                            *  *                                                                             *  ******************************************************************************/ -static bool g_undef_instruction_load(GUndefInstruction *instr, GObjectStorage *storage, packed_buffer_t *pbuf) +static char *g_undefined_instruction_get_encoding(const GArchInstruction *instr)  { -    bool result;                            /* Bilan à retourner           */ -    GArchInstructionClass *parent;          /* Classe parente à consulter  */ -    undef_extra_data_t *extra;              /* Données insérées à consulter*/ -    uint8_t val;                            /* Champ de bits manipulé      */ - -    parent = G_ARCH_INSTRUCTION_CLASS(g_undef_instruction_parent_class); - -    result = parent->load(G_ARCH_INSTRUCTION(instr), storage, pbuf); - -    if (result) -    { -        extra = GET_UNDEF_INSTR_EXTRA(instr); - -        LOCK_GOBJECT_EXTRA(extra); +    char *result;                           /* Description à retourner     */ -        result = extract_packed_buffer(pbuf, &val, sizeof(uint8_t), false); -        extra->behavior = val; - -        UNLOCK_GOBJECT_EXTRA(extra); - -    } +    result = strdup(_("Undefined"));      return result; @@ -507,37 +282,45 @@ static bool g_undef_instruction_load(GUndefInstruction *instr, GObjectStorage *s  /******************************************************************************  *                                                                             * -*  Paramètres  : instr   = élément GLib à consulter.                          * -*                storage = conservateur de données à manipuler ou NULL.       * -*                pbuf    = zone tampon à remplir.                             * +*  Paramètres  : instr = instruction d'assemblage à consulter.                *  *                                                                             * -*  Description : Sauvegarde un contenu dans une mémoire tampon.               * +*  Description : Fournit le nom humain de l'instruction manipulée.            *  *                                                                             * -*  Retour      : Bilan de l'opération.                                        * +*  Retour      : Mot clef de bas niveau.                                      *  *                                                                             *  *  Remarques   : -                                                            *  *                                                                             *  ******************************************************************************/ -static bool g_undef_instruction_store(GUndefInstruction *instr, GObjectStorage *storage, packed_buffer_t *pbuf) +static char *g_undefined_instruction_get_keyword(const GArchInstruction *instr)  { -    bool result;                            /* Bilan à retourner           */ -    GArchInstructionClass *parent;          /* Classe parente à consulter  */ -    undef_extra_data_t *extra;              /* Données insérées à consulter*/ - -    parent = G_ARCH_INSTRUCTION_CLASS(g_undef_instruction_parent_class); +    char *result;                           /* Désignation à retourner     */ +    undef_extra_data_t extra;               /* Données insérées à consulter*/ -    result = parent->store(G_ARCH_INSTRUCTION(instr), storage, pbuf); +    extra = GET_UNDEF_INSTR_EXTRA(instr); -    if (result) +    switch (extra.behavior)      { -        extra = GET_UNDEF_INSTR_EXTRA(instr); +        case IEB_NOP: +            result = strdup("nop"); +            break; -        LOCK_GOBJECT_EXTRA(extra); +        case IEB_UNDEFINED: +            result = strdup("undefined"); +            break; -        result = extend_packed_buffer(pbuf, (uint8_t []){ extra->behavior }, sizeof(uint8_t), false); +        case IEB_UNPREDICTABLE: +            result = strdup("unpredictable"); +            break; -        UNLOCK_GOBJECT_EXTRA(extra); +        case IEB_RESERVED: +            result = strdup("reserved"); +            break; + +        default: +            assert(false); +            result = NULL; +            break;      } diff --git a/src/arch/instructions/undefined.h b/src/arch/instructions/undefined.h index 8f35f35..d4b35f4 100644 --- a/src/arch/instructions/undefined.h +++ b/src/arch/instructions/undefined.h @@ -2,7 +2,7 @@  /* Chrysalide - Outil d'analyse de fichiers binaires   * undefined.h - prototypes pour les instructions au comportement non défini   * - * Copyright (C) 2016-2019 Cyrille Bagard + * Copyright (C) 2016-2025 Cyrille Bagard   *   *  This file is part of Chrysalide.   * @@ -25,27 +25,14 @@  #define _ARCH_INSTRUCTIONS_UNDEFINED_H -#include <glib-object.h> - -  #include "../instruction.h" -#include "../vmpa.h" - +#include "../../glibext/helpers.h" -#define G_TYPE_UNDEF_INSTRUCTION            g_undef_instruction_get_type() -#define G_UNDEF_INSTRUCTION(obj)            (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_UNDEF_INSTRUCTION, GUndefInstruction)) -#define G_IS_UNDEF_INSTRUCTION(obj)         (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_UNDEF_INSTRUCTION)) -#define G_UNDEF_INSTRUCTION_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_UNDEF_INSTRUCTION, GUndefInstructionClass)) -#define G_IS_UNDEF_INSTRUCTION_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_UNDEF_INSTRUCTION)) -#define G_UNDEF_INSTRUCTION_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_UNDEF_INSTRUCTION, GUndefInstructionClass)) +#define G_TYPE_UNDEFINED_INSTRUCTION (g_undefined_instruction_get_type()) -/* Définition générique d'une instruction au comportement non défini (instance) */ -typedef struct _GUndefInstruction GUndefInstruction; - -/* Définition générique d'une instruction au comportement non défini (classe) */ -typedef struct _GUndefInstructionClass GUndefInstructionClass; +DECLARE_GTYPE(GUndefinedInstruction, g_undefined_instruction, G, UNDEFINED_INSTRUCTION);  /* Etat précis de l'instruction */ @@ -59,14 +46,11 @@ typedef enum _InstrExpectedBehavior  } InstrExpectedBehavior; -/* Indique le type défini pour une instruction au comportement non défini. */ -GType g_undef_instruction_get_type(void); -  /* Crée une instruction au comportement nominalement indéfini. */ -GArchInstruction *g_undef_instruction_new(InstrExpectedBehavior); +GArchInstruction *g_undefined_instruction_new(InstrExpectedBehavior);  /* Indique le type de conséquences réél de l'instruction. */ -InstrExpectedBehavior g_undef_instruction_get_behavior(const GUndefInstruction *); +InstrExpectedBehavior g_undefined_instruction_get_behavior(const GUndefinedInstruction *); diff --git a/src/arch/operand-int.h b/src/arch/operand-int.h index e6c1232..10c079b 100644 --- a/src/arch/operand-int.h +++ b/src/arch/operand-int.h @@ -2,7 +2,7 @@  /* Chrysalide - Outil d'analyse de fichiers binaires   * operand-int.h - prototypes pour la définition générique interne des opérandes   * - * Copyright (C) 2008-2020 Cyrille Bagard + * Copyright (C) 2008-2024 Cyrille Bagard   *   *  This file is part of Chrysalide.   * @@ -26,13 +26,23 @@  #include "operand.h" +#include "../common/szbin.h" +#include "../glibext/objhole-int.h" + + + +/* Exporte une chaîne de caractères à partir d'un objet. */ +//typedef bool (* arch_operand_to_string_fc) (const GArchOperand *operand, unsigned int flags, sized_binary_t *); + + + +#if 0  #include <stdbool.h>  #include "../analysis/storage/storage.h" -#include "../glibext/objhole.h" @@ -71,46 +81,29 @@ typedef bool (* load_operand_fc) (GArchOperand *, GObjectStorage *, packed_buffe  typedef bool (* store_operand_fc) (GArchOperand *, GObjectStorage *, packed_buffer_t *); -/* Informations glissées dans la structure GObject de GArchOperand */ -typedef struct _operand_extra_data_t -{ -    ArchOperandFlag flags;                  /* Informations diverses       */ -} operand_extra_data_t; -/* Encapsulation avec un verrou d'accès */ -typedef union _operand_obj_extra_t -{ -    operand_extra_data_t data;              /* Données embarquées          */ -    lockable_obj_extra_t lockable;          /* Gestion d'accès aux fanions */ +#endif -} operand_obj_extra_t;  /* Définition générique d'un opérande d'architecture (instance) */  struct _GArchOperand  { -    GObject parent;                         /* A laisser en premier        */ - -#if 1 //__SIZEOF_INT__ == __SIZEOF_LONG__ - -    /** -     * L'inclusion des informations suivantes dépend de l'architecture. -     * -     * Si la structure GObject possède un trou, on remplit de préférence -     * ce dernier. -     */ - -    operand_obj_extra_t extra;              /* Externalisation embarquée   */ - -#endif +    GThickObject parent;                    /* A laisser en premier        */  };  /* Définition générique d'un opérande d'architecture (classe) */  struct _GArchOperandClass  { -    GObjectClass parent;                    /* A laisser en premier        */ +    GThickObjectClass parent;               /* A laisser en premier        */ + + + + + +#if 0      operand_compare_fc compare;             /* Comparaison d'opérandes     */      find_inner_operand_fc find_inner;       /* Définition d'un chemin      */ @@ -128,29 +121,57 @@ struct _GArchOperandClass      load_operand_fc load;                   /* Chargement depuis un tampon */      store_operand_fc store;                 /* Conservation dans un tampon */ +#endif +  }; +  /**   * Accès aux informations éventuellement déportées.   */ -#if 1 //__SIZEOF_INT__ == __SIZEOF_LONG__ -#   define GET_ARCH_OP_EXTRA(op) (operand_extra_data_t *)&op->extra +#define ARCH_OPERAND_EXTRA_DATA(mx)                         \ +                                                            \ +    unsigned int reserved : GOBJECT_RESERVED_EXTRA_BITS;    \ +                                                            \ +    /**                                                     \ +     * ArchOperandFlag                                      \ +     */                                                     \ +    unsigned int flags : mx; -#else -#   define GET_ARCH_OP_EXTRA(op) GET_GOBJECT_EXTRA(G_OBJECT(op), operand_extra_data_t) +/* Informations glissées dans la structure GObject de GArchOperand */ +typedef struct _operand_extra_data_t +{ +    ARCH_OPERAND_EXTRA_DATA(3);             /* Informations pour l'opérande*/ + +} operand_extra_data_t; + + +#define GET_ARCH_OP_EXTRA(op) \ +    GET_GOBJECT_EXTRA(op, operand_extra_data_t) + +#define SET_ARCH_OP_EXTRA(op, data) \ +    SET_GOBJECT_EXTRA(op, operand_extra_data_t, data) + + + + + + + + +#if 0 -#endif  /* Ajoute une information complémentaire à un opérande. */ -bool _g_arch_operand_set_flag(GArchOperand *, ArchOperandFlag, bool); +//bool _g_arch_operand_set_flag(GArchOperand *, ArchOperandFlag, bool);  /* Retire une information complémentaire à un opérande. */ -bool _g_arch_operand_unset_flag(GArchOperand *, ArchOperandFlag, bool); +//bool _g_arch_operand_unset_flag(GArchOperand *, ArchOperandFlag, bool); @@ -190,5 +211,7 @@ bool g_arch_operand_store_generic_fixed(GArchOperand *, GObjectStorage *, packed  bool g_arch_operand_store_generic_variadic(GArchOperand *, GObjectStorage *, packed_buffer_t *); +#endif +  #endif  /* _ARCH_OPERAND_INT_H */ diff --git a/src/arch/operand-ui-int.h b/src/arch/operand-ui-int.h new file mode 100644 index 0000000..c1173f3 --- /dev/null +++ b/src/arch/operand-ui-int.h @@ -0,0 +1,52 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * operand-ui-int.h - prototypes pour la définition générique interne des opérandes sous forme graphique + * + * Copyright (C) 2024 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 _ARCH_OPERAND_UI_INT_H +#define _ARCH_OPERAND_UI_INT_H + + +#include "operand-ui.h" + + + +/* Traduit un opérande en version humainement lisible. */ +typedef void (* print_operand_ui_fc) (const GArchOperandUI *, GBufferLine *); + +/* Construit un petit résumé concis de l'opérande. */ +typedef char * (* build_operand_ui_tooltip_fc) (const GArchOperandUI *, const GLoadedBinary *); + + + +/* Définition générique d'un opérande d'architecture (interface) */ +struct _GArchOperandUIInterface +{ +    GTypeInterface base_iface;              /* A laisser en premier        */ + +    print_operand_ui_fc print;              /* Texte humain équivalent     */ +    build_operand_ui_tooltip_fc build_tooltip; /* Définition de description*/ + +}; + + + +#endif  /* _ARCH_OPERAND_UI_INT_H */ diff --git a/src/arch/operand-ui.c b/src/arch/operand-ui.c new file mode 100644 index 0000000..ff7ad1b --- /dev/null +++ b/src/arch/operand-ui.c @@ -0,0 +1,111 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * operand-ui.c - gestion générique des opérandes sous forme graphique + * + * Copyright (C) 2024 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 "operand-ui.h" + + +#include "operand-ui-int.h" + + + +/* Procède à l'initialisation de l'interface d'opérande UI. */ +static void g_arch_operand_ui_default_init(GArchOperandUIInterface *); + + + +/* Indique le type défini pour un opérande d'architecture avec représentation graphique. */ +G_DEFINE_INTERFACE(GArchOperandUI, g_arch_operand_ui, G_TYPE_OBJECT); + + +/****************************************************************************** +*                                                                             * +*  Paramètres  : iface = interface GLib à initialiser.                        * +*                                                                             * +*  Description : Procède à l'initialisation de l'interface d'opérande UI.     * +*                                                                             * +*  Retour      : -                                                            * +*                                                                             * +*  Remarques   : -                                                            * +*                                                                             * +******************************************************************************/ + +static void g_arch_operand_ui_default_init(GArchOperandUIInterface *iface) +{ +    iface->print = NULL; +    iface->build_tooltip = NULL; + +} + + +/****************************************************************************** +*                                                                             * +*  Paramètres  : operand = opérande à traiter.                                * +*                line    = ligne tampon où imprimer l'opérande donné.         * +*                                                                             * +*  Description : Traduit un opérande en version humainement lisible.          * +*                                                                             * +*  Retour      : -                                                            * +*                                                                             * +*  Remarques   : -                                                            * +*                                                                             * +******************************************************************************/ + +void g_arch_operand_ui_print(const GArchOperandUI *operand, GBufferLine *line) +{ +    GArchOperandUIInterface *iface;         /* Interface utilisée          */ + +    iface = G_ARCH_OPERAND_UI_GET_IFACE(operand); + +    iface->print(operand, line); + +} + + +/****************************************************************************** +*                                                                             * +*  Paramètres  : operand = opérande à consulter.                              * +*                binary  = informations relatives au binaire chargé.          * +*                                                                             * +*  Description : Construit un petit résumé concis de l'opérande.              * +*                                                                             * +*  Retour      : Chaîne de caractères à libérer après usage ou NULL.          * +*                                                                             * +*  Remarques   : -                                                            * +*                                                                             * +******************************************************************************/ + +char *g_arch_operand_ui_build_tooltip(const GArchOperandUI *operand, const GLoadedBinary *binary) +{ +    char *result;                           /* Description à retourner     */ +    GArchOperandUIInterface *iface;         /* Interface utilisée          */ + +    iface = G_ARCH_OPERAND_UI_GET_IFACE(operand); + +    if (iface->build_tooltip != NULL) +        result = iface->build_tooltip(operand, binary); +    else +        result = NULL; + +    return result; + +} diff --git a/src/arch/operand-ui.h b/src/arch/operand-ui.h new file mode 100644 index 0000000..b197645 --- /dev/null +++ b/src/arch/operand-ui.h @@ -0,0 +1,54 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * operand-ui.h - prototypes pour la gestion générique des opérandes sous forme graphique + * + * Copyright (C) 2024 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 _ARCH_OPERAND_UI_H +#define _ARCH_OPERAND_UI_H + + +#include "../glibext/bufferline.h" +#include "../glibext/helpers.h" + + + +#define G_TYPE_ARCH_OPERAND_UI (g_arch_operand_ui_get_type()) + +DECLARE_INTERFACE(GArchOperandUI, g_arch_operand_ui, G, ARCH_OPERAND_UI); + + + +// TODO : REMME +//typedef void *GBufferLine; +typedef void *GLoadedBinary; +///// + + + +/* Traduit un opérande en version humainement lisible. */ +void g_arch_operand_ui_print(const GArchOperandUI *, GBufferLine *); + +/* Construit un petit résumé concis de l'opérande. */ +char *g_arch_operand_ui_build_tooltip(const GArchOperandUI *, const GLoadedBinary *); + + + +#endif  /* _ARCH_OPERAND_UI_H */ diff --git a/src/arch/operand.c b/src/arch/operand.c index 0f5ffd5..d3e837c 100644 --- a/src/arch/operand.c +++ b/src/arch/operand.c @@ -2,7 +2,7 @@  /* Chrysalide - Outil d'analyse de fichiers binaires   * operand.c - gestion générique des opérandes   * - * Copyright (C) 2008-2020 Cyrille Bagard + * Copyright (C) 2008-2025 Cyrille Bagard   *   *  This file is part of Chrysalide.   * @@ -25,17 +25,16 @@  #include <assert.h> -#include <malloc.h> -#include <string.h>  #include "operand-int.h" -#include "storage.h" -#include "../analysis/storage/serialize-int.h"  #include "../common/fnv1a.h"  #include "../common/sort.h" -#include "../core/logs.h" +#include "../glibext/comparable-int.h" +#include "../glibext/hashable-int.h" +#include "../glibext/serialize-int.h"  #include "../glibext/singleton-int.h" +#include "../glibext/strbuilder-int.h" @@ -45,66 +44,67 @@  /* Initialise la classe générique des opérandes. */  static void g_arch_operand_class_init(GArchOperandClass *); -/* Initialise une instance d'opérande d'architecture. */ -static void g_arch_operand_init(GArchOperand *); +/* Procède à l'initialisation de l'interface de comparaison. */ +static void g_arch_operand_comparable_object_iface_init(GComparableObjectInterface *); -/* Procède à l'initialisation de l'interface de singleton. */ -static void g_arch_operand_singleton_init(GSingletonCandidateInterface *); +/* Procède à l'initialisation de l'interface de détermination. */ +static void g_arch_operand_hashable_object_iface_init(GHashableObjectInterface *);  /* Procède à l'initialisation de l'interface de sérialisation. */ -static void g_arch_operand_serializable_init(GSerializableObjectInterface *); +static void g_arch_operand_serializable_object_iface_init(GSerializableObjectInterface *); + +/* Procède à l'initialisation de l'interface de rassemblement. */ +static void g_arch_operand_singleton_candidate_iface_init(GSingletonCandidateInterface *); + +/* Procède à l'initialisation de l'interface d'exportation. */ +static void g_arch_operand_string_builder_iface_init(GStringBuilderInterface *); + +/* Initialise une instance d'opérande d'architecture. */ +static void g_arch_operand_init(GArchOperand *);  /* Supprime toutes les références externes. */ -static void g_arch_operand_dispose(GArchOperand *); +static void g_arch_operand_dispose(GObject *);  /* Procède à la libération totale de la mémoire. */ -static void g_arch_operand_finalize(GArchOperand *); +static void g_arch_operand_finalize(GObject *); -/* Compare un opérande avec un autre. */ -static int _g_arch_operand_compare(const GArchOperand *, const GArchOperand *, bool); +/* ---------------------- COMPARAISON DETAILLEE DE DEUX OBJETS ---------------------- */ -/* ------------------------ CONTROLE DU VOLUME DES INSTANCES ------------------------ */ +/* Réalise une comparaison étendue entre objets. */ +static int g_arch_operand_compare(const GComparableObject *, const GComparableObject *); -/* Fournit une liste de candidats embarqués par un candidat. */ -GArchOperand **g_arch_operand_list_inner_instances(const GArchOperand *, size_t *); -/* Met à jour une liste de candidats embarqués par un candidat. */ -void g_arch_operand_update_inner_instances(GArchOperand *, GArchOperand **, size_t); -/* Fournit l'empreinte d'un candidat à une centralisation. */ -static guint _g_arch_operand_hash(const GArchOperand *, bool); +/* ---------------------- CALCUL D'UNE EMPREINTE DE L'INSTANCE ---------------------- */ -/* Fournit l'empreinte d'un candidat à une centralisation. */ -static guint g_arch_operand_hash(const GArchOperand *); -/* Détermine si deux candidats à l'unicité sont identiques. */ -static gboolean g_arch_operand_is_equal(const GArchOperand *, const GArchOperand *); +/* Calcule l'empreinte sur 32 bits d'un objet. */ +static guint g_arch_operand_hash(const GHashableObject *); -/* Marque un candidat comme figé. */ -static void g_arch_operand_set_read_only(GArchOperand *); -/* Indique si le candidat est figé. */ -static bool g_arch_operand_is_read_only(GArchOperand *); +/* ------------------- MECANISMES DE CONSERVATION ET RESTAURATION ------------------- */ -/* -------------------- CONSERVATION ET RECHARGEMENT DES DONNEES -------------------- */ +/* Charge un objet depuis un flux de données. */ +static bool g_arch_operand_load(GSerializableObject *, GObjectStorage *, int); +/* Sauvegarde un objet dans un flux de données. */ +static bool g_arch_operand_store(const GSerializableObject *, GObjectStorage *, int); -/* Charge un contenu depuis une mémoire tampon. */ -static bool _g_arch_operand_load(GArchOperand *, GObjectStorage *, packed_buffer_t *); -/* Charge un contenu depuis une mémoire tampon. */ -static bool g_arch_operand_load(GArchOperand *, GObjectStorage *, packed_buffer_t *); -/* Sauvegarde un contenu dans une mémoire tampon. */ -static bool _g_arch_operand_store(GArchOperand *, GObjectStorage *, packed_buffer_t *); +/* ------------------------ CONTROLE DU VOLUME DES INSTANCES ------------------------ */ -/* Sauvegarde un contenu dans une mémoire tampon. */ -static bool g_arch_operand_store(GArchOperand *, GObjectStorage *, packed_buffer_t *); + +/* Marque un candidat comme figé. */ +static void g_arch_operand_mark_as_read_only(GSingletonCandidate *); + +/* Indique si le candidat est figé. */ +static bool g_arch_operand_is_read_only(const GSingletonCandidate *); @@ -114,9 +114,12 @@ static bool g_arch_operand_store(GArchOperand *, GObjectStorage *, packed_buffer  /* Indique le type défini pour un opérande d'architecture. */ -G_DEFINE_TYPE_WITH_CODE(GArchOperand, g_arch_operand, G_TYPE_OBJECT, -                        G_IMPLEMENT_INTERFACE(G_TYPE_SINGLETON_CANDIDATE, g_arch_operand_singleton_init) -                        G_IMPLEMENT_INTERFACE(G_TYPE_SERIALIZABLE_OBJECT, g_arch_operand_serializable_init)); +G_DEFINE_TYPE_WITH_CODE(GArchOperand, g_arch_operand, G_TYPE_THICK_OBJECT, +                        G_IMPLEMENT_INTERFACE(G_TYPE_COMPARABLE_OBJECT, g_arch_operand_comparable_object_iface_init) +                        G_IMPLEMENT_INTERFACE(G_TYPE_HASHABLE_OBJECT, g_arch_operand_hashable_object_iface_init) +                        G_IMPLEMENT_INTERFACE(G_TYPE_SERIALIZABLE_OBJECT, g_arch_operand_serializable_object_iface_init) +                        G_IMPLEMENT_INTERFACE(G_TYPE_SINGLETON_CANDIDATE, g_arch_operand_singleton_candidate_iface_init) +                        G_IMPLEMENT_INTERFACE(G_TYPE_STRING_BUILDER, g_arch_operand_string_builder_iface_init));  /****************************************************************************** @@ -134,30 +137,20 @@ G_DEFINE_TYPE_WITH_CODE(GArchOperand, g_arch_operand, G_TYPE_OBJECT,  static void g_arch_operand_class_init(GArchOperandClass *klass)  {      GObjectClass *object;                   /* Autre version de la classe  */ -    GArchOperandClass *operand;             /* Encore une autre vision...  */      object = G_OBJECT_CLASS(klass); -    object->dispose = (GObjectFinalizeFunc/* ! */)g_arch_operand_dispose; -    object->finalize = (GObjectFinalizeFunc)g_arch_operand_finalize; - -    operand = G_ARCH_OPERAND_CLASS(klass); - -    operand->compare = (operand_compare_fc)_g_arch_operand_compare; - -    operand->hash = _g_arch_operand_hash; - -    operand->load = (load_operand_fc)_g_arch_operand_load; -    operand->store = (store_operand_fc)_g_arch_operand_store; +    object->dispose = g_arch_operand_dispose; +    object->finalize = g_arch_operand_finalize;  }  /******************************************************************************  *                                                                             * -*  Paramètres  : operand = instance à initialiser.                            * +*  Paramètres  : iface = interface GLib à initialiser.                        *  *                                                                             * -*  Description : Initialise une instance d'opérande d'architecture.           * +*  Description : Procède à l'initialisation de l'interface de comparaison.    *  *                                                                             *  *  Retour      : -                                                            *  *                                                                             * @@ -165,13 +158,9 @@ static void g_arch_operand_class_init(GArchOperandClass *klass)  *                                                                             *  ******************************************************************************/ -static void g_arch_operand_init(GArchOperand *operand) +static void g_arch_operand_comparable_object_iface_init(GComparableObjectInterface *iface)  { -    operand_extra_data_t *extra;            /* Données insérées à modifier */ - -    extra = GET_ARCH_OP_EXTRA(operand); - -    INIT_GOBJECT_EXTRA_LOCK(extra); +    iface->compare = g_arch_operand_compare;  } @@ -180,7 +169,7 @@ static void g_arch_operand_init(GArchOperand *operand)  *                                                                             *  *  Paramètres  : iface = interface GLib à initialiser.                        *  *                                                                             * -*  Description : Procède à l'initialisation de l'interface de singleton.      * +*  Description : Procède à l'initialisation de l'interface de détermination.  *  *                                                                             *  *  Retour      : -                                                            *  *                                                                             * @@ -188,16 +177,9 @@ static void g_arch_operand_init(GArchOperand *operand)  *                                                                             *  ******************************************************************************/ -static void g_arch_operand_singleton_init(GSingletonCandidateInterface *iface) +static void g_arch_operand_hashable_object_iface_init(GHashableObjectInterface *iface)  { -    iface->list_inner = (list_inner_instances_fc)g_arch_operand_list_inner_instances; -    iface->update_inner = (update_inner_instances_fc)g_arch_operand_update_inner_instances; - -    iface->hash = (hash_candidate_fc)g_arch_operand_hash; -    iface->is_equal = (is_candidate_equal_fc)g_arch_operand_is_equal; - -    iface->set_ro = (set_candidate_ro_fc)g_arch_operand_set_read_only; -    iface->is_ro = (is_candidate_ro_fc)g_arch_operand_is_read_only; +    iface->hash = g_arch_operand_hash;  } @@ -214,38 +196,19 @@ static void g_arch_operand_singleton_init(GSingletonCandidateInterface *iface)  *                                                                             *  ******************************************************************************/ -static void g_arch_operand_serializable_init(GSerializableObjectInterface *iface) +static void g_arch_operand_serializable_object_iface_init(GSerializableObjectInterface *iface)  { -    iface->load = (load_serializable_object_cb)g_arch_operand_load; -    iface->store = (store_serializable_object_cb)g_arch_operand_store; +    iface->load = g_arch_operand_load; +    iface->store = g_arch_operand_store;  }  /******************************************************************************  *                                                                             * -*  Paramètres  : operand = instance d'objet GLib à traiter.                   * -*                                                                             * -*  Description : Supprime toutes les références externes.                     * -*                                                                             * -*  Retour      : -                                                            * -*                                                                             * -*  Remarques   : -                                                            * -*                                                                             * -******************************************************************************/ - -static void g_arch_operand_dispose(GArchOperand *operand) -{ -    G_OBJECT_CLASS(g_arch_operand_parent_class)->dispose(G_OBJECT(operand)); - -} - - -/****************************************************************************** -*                                                                             * -*  Paramètres  : operand = instance d'objet GLib à traiter.                   * +*  Paramètres  : iface = interface GLib à initialiser.                        *  *                                                                             * -*  Description : Procède à la libération totale de la mémoire.                * +*  Description : Procède à l'initialisation de l'interface de rassemblement.  *  *                                                                             *  *  Retour      : -                                                            *  *                                                                             * @@ -253,147 +216,59 @@ static void g_arch_operand_dispose(GArchOperand *operand)  *                                                                             *  ******************************************************************************/ -static void g_arch_operand_finalize(GArchOperand *operand) +static void g_arch_operand_singleton_candidate_iface_init(GSingletonCandidateInterface *iface)  { -    G_OBJECT_CLASS(g_arch_operand_parent_class)->finalize(G_OBJECT(operand)); - -} - - -/****************************************************************************** -*                                                                             * -*  Paramètres  : a    = premier opérande à consulter.                         * -*                b    = second opérande à consulter.                          * -*                lock = précise le besoin en verrouillage.                    * -*                                                                             * -*  Description : Compare un opérande avec un autre.                           * -*                                                                             * -*  Retour      : Bilan de la comparaison.                                     * -*                                                                             * -*  Remarques   : -                                                            * -*                                                                             * -******************************************************************************/ - -static int _g_arch_operand_compare(const GArchOperand *a, const GArchOperand *b, bool lock) -{ -    int result;                             /* Bilan à faire remonter      */ -    operand_extra_data_t *ea;               /* Données insérées à consulter*/ -    operand_extra_data_t *eb;               /* Données insérées à consulter*/ - -    assert(!lock); - -    ea = GET_ARCH_OP_EXTRA(a); -    eb = GET_ARCH_OP_EXTRA(b); +    iface->list_inner = NULL; +    iface->update_inner = NULL; -    result = sort_unsigned_long(ea->flags, eb->flags); - -    return result; +    iface->mark_as_ro = g_arch_operand_mark_as_read_only; +    iface->is_ro = g_arch_operand_is_read_only;  }  /******************************************************************************  *                                                                             * -*  Paramètres  : a = premier opérande à consulter.                            * -*                b = second opérande à consulter.                             * -*                                                                             * -*  Description : Compare un opérande avec un autre.                           * -*                                                                             * -*  Retour      : Bilan de la comparaison.                                     * -*                                                                             * -*  Remarques   : -                                                            * -*                                                                             * -******************************************************************************/ - -int g_arch_operand_compare(const GArchOperand *a, const GArchOperand *b) -{ -    int result;                             /* Bilan à faire remonter      */ -    GType type_a;                           /* Type de l'object A          */ -    GType type_b;                           /* Type de l'object B          */ - -    type_a = G_OBJECT_TYPE(G_OBJECT(a)); -    type_b = G_OBJECT_TYPE(G_OBJECT(b)); - -    assert(sizeof(GType) <= sizeof(unsigned long)); - -    result = sort_unsigned_long(type_a, type_b); - -    if (result == 0) -        result = G_ARCH_OPERAND_GET_CLASS(a)->compare(a, b, true); - -    return result; - -} - - -/****************************************************************************** +*  Paramètres  : iface = interface GLib à initialiser.                        *  *                                                                             * -*  Paramètres  : operand = opérande à consulter.                              * -*                target  = instruction à venir retrouver.                     * +*  Description : Procède à l'initialisation de l'interface d'exportation.     *  *                                                                             * -*  Description : Détermine le chemin conduisant à un opérande interne.        * -*                                                                             * -*  Retour      : Chemin d'accès à l'opérande ou NULL en cas d'absence.        * +*  Retour      : -                                                            *  *                                                                             *  *  Remarques   : -                                                            *  *                                                                             *  ******************************************************************************/ -char *g_arch_operand_find_inner_operand_path(const GArchOperand *operand, const GArchOperand *target) +static void g_arch_operand_string_builder_iface_init(GStringBuilderInterface *iface)  { -    char *result;                           /* Chemin à retourner          */ -    GArchOperandClass *class;               /* Classe associée à l'objet   */ - -    class = G_ARCH_OPERAND_GET_CLASS(operand); - -    if (class->find_inner != NULL) -        result = class->find_inner(operand, target); - -    else -        result = NULL; - -    return result; +    iface->to_string = NULL;  }  /******************************************************************************  *                                                                             * -*  Paramètres  : operand = opérande à consulter.                              * -*                path  = chemin d'accès à un opérande à retrouver.            * +*  Paramètres  : operand = instance à initialiser.                            *  *                                                                             * -*  Description : Obtient l'opérande correspondant à un chemin donné.          * +*  Description : Initialise une instance d'opérande d'architecture.           *  *                                                                             * -*  Retour      : Opérande trouvé ou NULL en cas d'échec.                      * +*  Retour      : -                                                            *  *                                                                             *  *  Remarques   : -                                                            *  *                                                                             *  ******************************************************************************/ -GArchOperand *g_arch_operand_get_inner_operand_from_path(const GArchOperand *operand, const char *path) +static void g_arch_operand_init(GArchOperand *operand)  { -    GArchOperand *result;                   /* Opérande trouvée à renvoyer */ -    GArchOperandClass *class;               /* Classe associée à l'objet   */ - -    class = G_ARCH_OPERAND_GET_CLASS(operand); - -    if (class->get_inner != NULL) -        result = class->get_inner(operand, path); - -    else -        result = NULL; - -    return result;  }  /******************************************************************************  *                                                                             * -*  Paramètres  : operand = opérande à traiter.                                * -*                line    = ligne tampon où imprimer l'opérande donné.         * +*  Paramètres  : object = instance d'objet GLib à traiter.                    *  *                                                                             * -*  Description : Traduit un opérande en version humainement lisible.          * +*  Description : Supprime toutes les références externes.                     *  *                                                                             *  *  Retour      : -                                                            *  *                                                                             * @@ -401,54 +276,36 @@ GArchOperand *g_arch_operand_get_inner_operand_from_path(const GArchOperand *ope  *                                                                             *  ******************************************************************************/ -void g_arch_operand_print(const GArchOperand *operand, GBufferLine *line) +static void g_arch_operand_dispose(GObject *object)  { -    G_ARCH_OPERAND_GET_CLASS(operand)->print(operand, line); +    G_OBJECT_CLASS(g_arch_operand_parent_class)->dispose(object);  } -#ifdef INCLUDE_GTK_SUPPORT - -  /******************************************************************************  *                                                                             * -*  Paramètres  : operand = opérande à consulter.                              * -*                binary  = informations relatives au binaire chargé.          * +*  Paramètres  : object = instance d'objet GLib à traiter.                    *  *                                                                             * -*  Description : Construit un petit résumé concis de l'opérande.              * +*  Description : Procède à la libération totale de la mémoire.                *  *                                                                             * -*  Retour      : Chaîne de caractères à libérer après usage ou NULL.          * +*  Retour      : -                                                            *  *                                                                             *  *  Remarques   : -                                                            *  *                                                                             *  ******************************************************************************/ -char *g_arch_operand_build_tooltip(const GArchOperand *operand, const GLoadedBinary *binary) +static void g_arch_operand_finalize(GObject *object)  { -    char *result;                           /* Description à retourner     */ -    GArchOperandClass *class;               /* Classe associée à l'objet   */ - -    class = G_ARCH_OPERAND_GET_CLASS(operand); - -    if (class->build_tooltip != NULL) -        result = class->build_tooltip(operand, binary); -    else -        result = NULL; - -    return result; +    G_OBJECT_CLASS(g_arch_operand_parent_class)->finalize(object);  } -#endif - -  /******************************************************************************  *                                                                             *  *  Paramètres  : operand = opérande à venir modifier.                         *  *                flag    = drapeau d'information complémentaire à planter.    * -*                lock    = indique un besoin de verrouillage des données.     *  *                                                                             *  *  Description : Ajoute une information complémentaire à un opérande.         *  *                                                                             * @@ -458,48 +315,20 @@ char *g_arch_operand_build_tooltip(const GArchOperand *operand, const GLoadedBin  *                                                                             *  ******************************************************************************/ -bool _g_arch_operand_set_flag(GArchOperand *operand, ArchOperandFlag flag, bool lock) +bool g_arch_operand_set_flag(GArchOperand *operand, ArchOperandFlag flag)  {      bool result;                            /* Bilan à retourner           */ -    operand_extra_data_t *extra;            /* Données insérées à modifier */ +    operand_extra_data_t extra;             /* Données insérées à modifier */      assert(flag <= AOF_HIGH_USER);      extra = GET_ARCH_OP_EXTRA(operand); -    if (lock) -        LOCK_GOBJECT_EXTRA(extra); - -    result = !(extra->flags & flag); - -    extra->flags |= flag; - -    if (lock) -        UNLOCK_GOBJECT_EXTRA(extra); - -    return result; - -} - - -/****************************************************************************** -*                                                                             * -*  Paramètres  : operand = opérande à venir modifier.                         * -*                flag    = drapeau d'information complémentaire à planter.    * -*                                                                             * -*  Description : Ajoute une information complémentaire à un opérande.         * -*                                                                             * -*  Retour      : Bilan de l'opération.                                        * -*                                                                             * -*  Remarques   : -                                                            * -*                                                                             * -******************************************************************************/ +    result = !(extra.flags & flag); -bool g_arch_operand_set_flag(GArchOperand *operand, ArchOperandFlag flag) -{ -    bool result;                            /* Bilan à retourner           */ +    extra.flags |= flag; -    result = _g_arch_operand_set_flag(operand, flag, true); +    SET_ARCH_OP_EXTRA(operand, &extra);      return result; @@ -510,7 +339,6 @@ bool g_arch_operand_set_flag(GArchOperand *operand, ArchOperandFlag flag)  *                                                                             *  *  Paramètres  : operand = opérande à venir modifier.                         *  *                flag    = drapeau d'information complémentaire à planter.    * -*                lock    = indique un besoin de verrouillage des données.     *  *                                                                             *  *  Description : Retire une information complémentaire à un opérande.         *  *                                                                             * @@ -520,46 +348,20 @@ bool g_arch_operand_set_flag(GArchOperand *operand, ArchOperandFlag flag)  *                                                                             *  ******************************************************************************/ -bool _g_arch_operand_unset_flag(GArchOperand *operand, ArchOperandFlag flag, bool lock) +bool g_arch_operand_unset_flag(GArchOperand *operand, ArchOperandFlag flag)  {      bool result;                            /* Bilan à retourner           */ -    operand_extra_data_t *extra;            /* Données insérées à modifier */ +    operand_extra_data_t extra;             /* Données insérées à modifier */      assert(flag <= AOF_HIGH_USER);      extra = GET_ARCH_OP_EXTRA(operand); -    LOCK_GOBJECT_EXTRA(extra); - -    result = (extra->flags & flag); - -    extra->flags &= ~flag; - -    UNLOCK_GOBJECT_EXTRA(extra); - -    return result; - -} - - -/****************************************************************************** -*                                                                             * -*  Paramètres  : operand = opérande à venir modifier.                         * -*                flag    = drapeau d'information complémentaire à planter.    * -*                                                                             * -*  Description : Retire une information complémentaire à un opérande.         * -*                                                                             * -*  Retour      : Bilan de l'opération.                                        * -*                                                                             * -*  Remarques   : -                                                            * -*                                                                             * -******************************************************************************/ +    result = (extra.flags & flag); -bool g_arch_operand_unset_flag(GArchOperand *operand, ArchOperandFlag flag) -{ -    bool result;                            /* Bilan à retourner           */ +    extra.flags &= ~flag; -    result = _g_arch_operand_unset_flag(operand, flag, true); +    SET_ARCH_OP_EXTRA(operand, &extra);      return result; @@ -582,17 +384,13 @@ bool g_arch_operand_unset_flag(GArchOperand *operand, ArchOperandFlag flag)  bool g_arch_operand_has_flag(const GArchOperand *operand, ArchOperandFlag flag)  {      bool result;                            /* Bilan à retourner           */ -    operand_extra_data_t *extra;            /* Données insérées à modifier */ +    operand_extra_data_t extra;             /* Données insérées à modifier */      assert(flag <= AOF_HIGH_USER);      extra = GET_ARCH_OP_EXTRA(operand); -    LOCK_GOBJECT_EXTRA(extra); - -    result = (extra->flags & flag); - -    UNLOCK_GOBJECT_EXTRA(extra); +    result = (extra.flags & flag);      return result; @@ -614,15 +412,11 @@ bool g_arch_operand_has_flag(const GArchOperand *operand, ArchOperandFlag flag)  ArchOperandFlag g_arch_operand_get_flags(const GArchOperand *operand)  {      ArchOperandFlag result;                 /* Fanions à retourner         */ -    operand_extra_data_t *extra;            /* Données insérées à modifier */ +    operand_extra_data_t extra;             /* Données insérées à modifier */      extra = GET_ARCH_OP_EXTRA(operand); -    LOCK_GOBJECT_EXTRA(extra); - -    result = extra->flags; - -    UNLOCK_GOBJECT_EXTRA(extra); +    result = extra.flags;      return result; @@ -630,39 +424,40 @@ ArchOperandFlag g_arch_operand_get_flags(const GArchOperand *operand) -/* ---------------------------------------------------------------------------------- */ -/*                          CONTROLE DU VOLUME DES INSTANCES                          */ -/* ---------------------------------------------------------------------------------- */ + + + + +#if 0 + +  /******************************************************************************  *                                                                             * -*  Paramètres  : operand = objet dont l'instance se veut unique.              * -*                count   = quantité d'instances à l'unicité internes.         * +*  Paramètres  : operand = opérande à consulter.                              * +*                target  = instruction à venir retrouver.                     *  *                                                                             * -*  Description : Fournit une liste de candidats embarqués par un candidat.    * +*  Description : Détermine le chemin conduisant à un opérande interne.        *  *                                                                             * -*  Retour      : Liste de candidats internes ou NULL si aucun.                * +*  Retour      : Chemin d'accès à l'opérande ou NULL en cas d'absence.        *  *                                                                             *  *  Remarques   : -                                                            *  *                                                                             *  ******************************************************************************/ -GArchOperand **g_arch_operand_list_inner_instances(const GArchOperand *operand, size_t *count) +char *g_arch_operand_find_inner_operand_path(const GArchOperand *operand, const GArchOperand *target)  { -    GArchOperand **result;                  /* Instances à retourner       */ +    char *result;                           /* Chemin à retourner          */      GArchOperandClass *class;               /* Classe associée à l'objet   */      class = G_ARCH_OPERAND_GET_CLASS(operand); -    if (class->list_inner == NULL) -    { -        *count = 0; -        result = NULL; -    } +    if (class->find_inner != NULL) +        result = class->find_inner(operand, target);      else -        result = class->list_inner(operand, count); +        result = NULL;      return result; @@ -671,105 +466,59 @@ GArchOperand **g_arch_operand_list_inner_instances(const GArchOperand *operand,  /******************************************************************************  *                                                                             * -*  Paramètres  : operand   = objet dont l'instance se veut unique.            * -*                instances = liste de candidats internes devenus singletons.  * -*                count     = quantité d'instances à l'unicité internes.       * +*  Paramètres  : operand = opérande à consulter.                              * +*                path  = chemin d'accès à un opérande à retrouver.            *  *                                                                             * -*  Description : Met à jour une liste de candidats embarqués par un candidat. * +*  Description : Obtient l'opérande correspondant à un chemin donné.          *  *                                                                             * -*  Retour      : -                                                            * +*  Retour      : Opérande trouvé ou NULL en cas d'échec.                      *  *                                                                             *  *  Remarques   : -                                                            *  *                                                                             *  ******************************************************************************/ -void g_arch_operand_update_inner_instances(GArchOperand *operand, GArchOperand **instances, size_t count) +GArchOperand *g_arch_operand_get_inner_operand_from_path(const GArchOperand *operand, const char *path)  { +    GArchOperand *result;                   /* Opérande trouvée à renvoyer */      GArchOperandClass *class;               /* Classe associée à l'objet   */      class = G_ARCH_OPERAND_GET_CLASS(operand); -    if (class->update_inner == NULL) -        assert(class->list_inner == NULL); +    if (class->get_inner != NULL) +        result = class->get_inner(operand, path);      else -    { -        assert(class->list_inner != NULL); -        class->update_inner(operand, instances, count); -    } +        result = NULL; + +    return result;  } -/****************************************************************************** -*                                                                             * -*  Paramètres  : operand = objet dont l'instance se veut unique.              * -*                lock    = précise le besoin en verrouillage.                 * -*                                                                             * -*  Description : Fournit l'empreinte d'un candidat à une centralisation.      * -*                                                                             * -*  Retour      : Empreinte de l'élément représenté.                           * -*                                                                             * -*  Remarques   : -                                                            * -*                                                                             * -******************************************************************************/ +#endif -static guint _g_arch_operand_hash(const GArchOperand *operand, bool lock) -{ -    guint result;                           /* Valeur à retourner          */ -    const char *name;                       /* Désignation du type d'object*/ -    fnv64_t name_hash;                      /* Empreinte du nom            */ -    operand_extra_data_t *extra;            /* Données insérées à modifier */ -    assert(!lock); -    name = G_OBJECT_TYPE_NAME(G_OBJECT(operand)); -    name_hash = fnv_64a_hash(name); -    result = (name_hash & 0xffffffff); -    result ^= (name_hash >> 32); -    extra = GET_ARCH_OP_EXTRA(operand); -    result ^= extra->flags; -    return result; -} -/****************************************************************************** -*                                                                             * -*  Paramètres  : operand = objet dont l'instance se veut unique.              * -*                                                                             * -*  Description : Fournit l'empreinte d'un candidat à une centralisation.      * -*                                                                             * -*  Retour      : Empreinte de l'élément représenté.                           * -*                                                                             * -*  Remarques   : -                                                            * -*                                                                             * -******************************************************************************/ -static guint g_arch_operand_hash(const GArchOperand *operand) -{ -    guint result;                           /* Valeur à retourner          */ -    GArchOperandClass *class;               /* Classe associée à l'objet   */ - -    class = G_ARCH_OPERAND_GET_CLASS(operand); - -    result = class->hash(operand, true); -    return result; - -} +/* ---------------------------------------------------------------------------------- */ +/*                        COMPARAISON DETAILLEE DE DEUX OBJETS                        */ +/* ---------------------------------------------------------------------------------- */  /******************************************************************************  *                                                                             * -*  Paramètres  : operand = objet dont l'instance se veut unique.              * -*                other   = second élément à analyser.                         * +*  Paramètres  : object = premier objet à consulter pour une comparaison.     * +*                other  = second objet à consulter pour une comparaison.      *  *                                                                             * -*  Description : Détermine si deux candidats à l'unicité sont identiques.     * +*  Description : Réalise une comparaison étendue entre objets.                *  *                                                                             *  *  Retour      : Bilan de la comparaison.                                     *  *                                                                             * @@ -777,56 +526,56 @@ static guint g_arch_operand_hash(const GArchOperand *operand)  *                                                                             *  ******************************************************************************/ -static gboolean g_arch_operand_is_equal(const GArchOperand *operand, const GArchOperand *other) +static int g_arch_operand_compare(const GComparableObject *object, const GComparableObject *other)  { -    gboolean result;                        /* Bilan à renvoyer            */ -    int ret;                                /* Bilan d'une comparaison     */ +    int result;                             /* Bilan à retourner           */ +    operand_extra_data_t extra_op;          /* Données insérées à consulter*/ +    operand_extra_data_t extra_other;       /* Données insérées à consulter*/ -    ret = g_arch_operand_compare(operand, other); +    extra_op = GET_ARCH_OP_EXTRA(object); +    extra_other = GET_ARCH_OP_EXTRA(other); -    result = (ret == 0); +    result = sort_unsigned_long(extra_op.flags, extra_other.flags);      return result;  } -/****************************************************************************** -*                                                                             * -*  Paramètres  : operand = objet dont l'instance se veut unique.              * -*                                                                             * -*  Description : Marque un candidat comme figé.                               * -*                                                                             * -*  Retour      : -                                                            * -*                                                                             * -*  Remarques   : -                                                            * -*                                                                             * -******************************************************************************/ - -static void g_arch_operand_set_read_only(GArchOperand *operand) -{ -    g_arch_operand_set_flag(operand, AOF_READ_ONLY); -} +/* ---------------------------------------------------------------------------------- */ +/*                        CALCUL D'UNE EMPREINTE DE L'INSTANCE                        */ +/* ---------------------------------------------------------------------------------- */  /******************************************************************************  *                                                                             * -*  Paramètres  : operand = objet dont l'instance se veut unique.              * +*  Paramètres  : object = objet dont l'instance est à consulter.              *  *                                                                             * -*  Description : Indique si le candidat est figé.                             * +*  Description : Calcule l'empreinte sur 32 bits d'un objet.                  *  *                                                                             * -*  Retour      : true si le contenu du candidat ne peut plus être modifié.    * +*  Retour      : Valeur de représentation, unique pour l'objet ou non.        *  *                                                                             *  *  Remarques   : -                                                            *  *                                                                             *  ******************************************************************************/ -static bool g_arch_operand_is_read_only(GArchOperand *operand) +static guint g_arch_operand_hash(const GHashableObject *object)  { -    bool result;                            /* Etat à retourner            */ +    guint result;                           /* Valeur à retourner          */ +    const char *name;                       /* Désignation du type d'object*/ +    fnv64_t name_hash;                      /* Empreinte du nom            */ +    operand_extra_data_t extra;             /* Données insérées à consulter*/ -    result = g_arch_operand_has_flag(operand, AOF_READ_ONLY); +    name = G_OBJECT_TYPE_NAME(G_OBJECT(object)); +    name_hash = fnv_64a_hash(name); + +    result = (name_hash & 0xffffffff); +    result ^= (name_hash >> 32); + +    extra = GET_ARCH_OP_EXTRA(object); + +    result ^= extra.flags;      return result; @@ -835,17 +584,17 @@ static bool g_arch_operand_is_read_only(GArchOperand *operand)  /* ---------------------------------------------------------------------------------- */ -/*                      CONSERVATION ET RECHARGEMENT DES DONNEES                      */ +/*                     MECANISMES DE CONSERVATION ET RESTAURATION                     */  /* ---------------------------------------------------------------------------------- */  /******************************************************************************  *                                                                             * -*  Paramètres  : operand = élément GLib à constuire.                          * -*                storage = conservateur de données à manipuler ou NULL.       * -*                pbuf    = zone tampon à lire.                                * +*  Paramètres  : object  = élément GLib à constuire.                          * +*                storage = conservateur de données à manipuler.               * +*                fd      = flux ouvert en lecture.                            *  *                                                                             * -*  Description : Charge un contenu depuis une mémoire tampon.                 * +*  Description : Charge un objet depuis un flux de données.                   *  *                                                                             *  *  Retour      : Bilan de l'opération.                                        *  *                                                                             * @@ -853,22 +602,15 @@ static bool g_arch_operand_is_read_only(GArchOperand *operand)  *                                                                             *  ******************************************************************************/ -static bool _g_arch_operand_load(GArchOperand *operand, GObjectStorage *storage, packed_buffer_t *pbuf) +static bool g_arch_operand_load(GSerializableObject *object, GObjectStorage *storage, int fd)  {      bool result;                            /* Bilan à retourner           */ -    operand_extra_data_t *extra;            /* Données insérées à consulter*/ -    uleb128_t value;                        /* Valeur ULEB128 à charger    */ - -    extra = GET_ARCH_OP_EXTRA(operand); +    uleb128_t extra;                        /* Données embarquées          */ -    LOCK_GOBJECT_EXTRA(extra); - -    result = unpack_uleb128(&value, pbuf); +    result = load_uleb128(&extra, fd);      if (result) -        extra->flags = value; - -    UNLOCK_GOBJECT_EXTRA(extra); +        g_thick_object_set_extra(G_THICK_OBJECT(object), extra);      return result; @@ -877,11 +619,11 @@ static bool _g_arch_operand_load(GArchOperand *operand, GObjectStorage *storage,  /******************************************************************************  *                                                                             * -*  Paramètres  : operand = élément GLib à constuire.                          * -*                storage = conservateur de données à manipuler ou NULL.       * -*                pbuf    = zone tampon à lire.                                * +*  Paramètres  : object  = élément GLib à consulter.                          * +*                storage = conservateur de données à manipuler.               * +*                fd      = flux ouvert en écriture.                           *  *                                                                             * -*  Description : Charge un contenu depuis une mémoire tampon.                 * +*  Description : Sauvegarde un objet dans un flux de données.                 *  *                                                                             *  *  Retour      : Bilan de l'opération.                                        *  *                                                                             * @@ -889,74 +631,69 @@ static bool _g_arch_operand_load(GArchOperand *operand, GObjectStorage *storage,  *                                                                             *  ******************************************************************************/ -static bool g_arch_operand_load(GArchOperand *operand, GObjectStorage *storage, packed_buffer_t *pbuf) +static bool g_arch_operand_store(const GSerializableObject *object, GObjectStorage *storage, int fd)  {      bool result;                            /* Bilan à retourner           */ -    GArchOperandClass *class;               /* Classe à activer            */ +    guint extra;                            /* Données embarquées          */ -    class = G_ARCH_OPERAND_GET_CLASS(operand); +    extra = g_thick_object_get_extra(G_THICK_OBJECT(object)); -    result = class->load(operand, storage, pbuf); +    result = store_uleb128((uleb128_t []) { extra }, fd);      return result;  } + +/* ---------------------------------------------------------------------------------- */ +/*                          CONTROLE DU VOLUME DES INSTANCES                          */ +/* ---------------------------------------------------------------------------------- */ + +  /******************************************************************************  *                                                                             * -*  Paramètres  : operand = élément GLib à consulter.                          * -*                storage = conservateur de données à manipuler ou NULL.       * -*                pbuf    = zone tampon à remplir.                             * +*  Paramètres  : candidate = objet dont l'instance se veut unique.            *  *                                                                             * -*  Description : Sauvegarde un contenu dans une mémoire tampon.               * +*  Description : Marque un candidat comme figé.                               *  *                                                                             * -*  Retour      : Bilan de l'opération.                                        * +*  Retour      : -                                                            *  *                                                                             *  *  Remarques   : -                                                            *  *                                                                             *  ******************************************************************************/ -static bool _g_arch_operand_store(GArchOperand *operand, GObjectStorage *storage, packed_buffer_t *pbuf) +static void g_arch_operand_mark_as_read_only(GSingletonCandidate *candidate)  { -    bool result;                            /* Bilan à retourner           */ -    operand_extra_data_t *extra;            /* Données insérées à consulter*/ - -    extra = GET_ARCH_OP_EXTRA(operand); - -    LOCK_GOBJECT_EXTRA(extra); - -    result = pack_uleb128((uleb128_t []){ extra->flags }, pbuf); +    GArchOperand *operand;                  /* Version spécialisée         */ -    UNLOCK_GOBJECT_EXTRA(extra); +    operand = G_ARCH_OPERAND(candidate); -    return result; +    g_arch_operand_set_flag(operand, AOF_READ_ONLY);  }  /******************************************************************************  *                                                                             * -*  Paramètres  : operand = élément GLib à consulter.                          * -*                storage = conservateur de données à manipuler ou NULL.       * -*                pbuf    = zone tampon à remplir.                             * +*  Paramètres  : operand = objet dont l'instance se veut unique.              *  *                                                                             * -*  Description : Sauvegarde un contenu dans une mémoire tampon.               * +*  Description : Indique si le candidat est figé.                             *  *                                                                             * -*  Retour      : Bilan de l'opération.                                        * +*  Retour      : true si le contenu du candidat ne peut plus être modifié.    *  *                                                                             *  *  Remarques   : -                                                            *  *                                                                             *  ******************************************************************************/ -static bool g_arch_operand_store(GArchOperand *operand, GObjectStorage *storage, packed_buffer_t *pbuf) +static bool g_arch_operand_is_read_only(const GSingletonCandidate *candidate)  { -    bool result;                            /* Bilan à retourner           */ -    GArchOperandClass *class;               /* Classe à activer            */ +    bool result;                            /* Etat à retourner            */ +    GArchOperand *operand;                  /* Version spécialisée         */ -    class = G_ARCH_OPERAND_GET_CLASS(operand); +    operand = G_ARCH_OPERAND(candidate); -    result = class->store(operand, storage, pbuf); +    result = g_arch_operand_has_flag(operand, AOF_READ_ONLY);      return result; diff --git a/src/arch/operand.h b/src/arch/operand.h index 234ee64..72a1b56 100644 --- a/src/arch/operand.h +++ b/src/arch/operand.h @@ -2,7 +2,7 @@  /* Chrysalide - Outil d'analyse de fichiers binaires   * operand.h - prototypes pour la gestion générique des opérandes   * - * Copyright (C) 2008-2020 Cyrille Bagard + * Copyright (C) 2008-2024 Cyrille Bagard   *   *  This file is part of Chrysalide.   * @@ -25,20 +25,16 @@  #define _ARCH_OPERAND_H -#include <glib-object.h> - +#include <stdbool.h> -#include "../common/packed.h" -#include "../format/format.h" -#include "../glibext/bufferline.h" +#include "../glibext/helpers.h" -/* ------------------------ DEFINITION D'OPERANDE QUELCONQUE ------------------------ */ +#define G_TYPE_ARCH_OPERAND (g_arch_operand_get_type()) -/* Depuis "../analysis/binary.h" : description de fichier binaire */ -typedef struct _GLoadedBinary GLoadedBinary; +DECLARE_GTYPE(GArchOperand, g_arch_operand, G, ARCH_OPERAND);  /* Indications supplémentaires liées aux opérandes */ @@ -58,6 +54,41 @@ typedef enum _ArchOperandFlag  #define AOF_USER_FLAG(n) (1 << (AOF_USER_BIT + n)) +/* Ajoute une information complémentaire à un opérande. */ +bool g_arch_operand_set_flag(GArchOperand *, ArchOperandFlag); + +/* Retire une information complémentaire à un opérande. */ +bool g_arch_operand_unset_flag(GArchOperand *, ArchOperandFlag); + +/* Détermine si un opérande possède un fanion particulier. */ +bool g_arch_operand_has_flag(const GArchOperand *, ArchOperandFlag); + +/* Fournit les particularités de l'opérande. */ +ArchOperandFlag g_arch_operand_get_flags(const GArchOperand *); + + + + +#if 0 + + +#include <glib-object.h> + + +#include "../common/packed.h" +#include "../format/format.h" +#include "../glibext/bufferline.h" + + + +/* ------------------------ DEFINITION D'OPERANDE QUELCONQUE ------------------------ */ + + +/* Depuis "../analysis/binary.h" : description de fichier binaire */ +typedef struct _GLoadedBinary GLoadedBinary; + + +  #define G_TYPE_ARCH_OPERAND            g_arch_operand_get_type()  #define G_ARCH_OPERAND(obj)            (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_ARCH_OPERAND, GArchOperand))  #define G_IS_ARCH_OPERAND(obj)         (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_ARCH_OPERAND)) @@ -95,18 +126,6 @@ char *g_arch_operand_build_tooltip(const GArchOperand *, const GLoadedBinary *);  #endif -/* Ajoute une information complémentaire à un opérande. */ -bool g_arch_operand_set_flag(GArchOperand *, ArchOperandFlag); - -/* Retire une information complémentaire à un opérande. */ -bool g_arch_operand_unset_flag(GArchOperand *, ArchOperandFlag); - -/* Détermine si un opérande possède un fanion particulier. */ -bool g_arch_operand_has_flag(const GArchOperand *, ArchOperandFlag); - -/* Fournit les particularités de l'opérande. */ -ArchOperandFlag g_arch_operand_get_flags(const GArchOperand *); -  /* --------------------- TRANSPOSITIONS VIA CACHE DES OPERANDES --------------------- */ @@ -116,5 +135,8 @@ ArchOperandFlag g_arch_operand_get_flags(const GArchOperand *);  typedef struct _GAsmStorage GAsmStorage; +#endif + +  #endif  /* _ARCH_OPERAND_H */ diff --git a/src/arch/operands/Makefile.am b/src/arch/operands/Makefile.am index f2a8767..3d9cbde 100644 --- a/src/arch/operands/Makefile.am +++ b/src/arch/operands/Makefile.am @@ -1,26 +1,36 @@ -noinst_LTLIBRARIES = libarchoperands.la +noinst_LTLIBRARIES = libarchoperands.la libarchoperandsui.la + +# libarchoperands_la_SOURCES =			\ +# 	feeder-int.h						\ +# 	feeder.h feeder.c					\ +# 	proxy-int.h							\ +# 	proxy.h proxy.c						\ +# 	rename-int.h						\ +# 	rename.h rename.c					\ +# 	target-int.h						\ +# 	target.h target.c					\ +# 	targetable-int.h					\ +# 	targetable.h targetable.c  libarchoperands_la_SOURCES =			\ -	feeder-int.h						\ -	feeder.h feeder.c					\  	immediate-int.h						\  	immediate.h immediate.c				\ +	known-int.h							\  	known.h known.c						\  	register-int.h						\ -	register.h register.c				\ -	proxy-int.h							\ -	proxy.h proxy.c						\ -	rename-int.h						\ -	rename.h rename.c					\ -	target-int.h						\ -	target.h target.c					\ -	targetable-int.h					\ -	targetable.h targetable.c +	register.h register.c + +libarchoperands_la_CFLAGS = $(LIBGOBJ_CFLAGS) + +libarchoperandsui_la_SOURCES =			\ +	immediate-ui.h immediate-ui.c		\ +	known-ui.h known-ui.c				\ +	register-ui.h register-ui.c -libarchoperands_la_CFLAGS = $(TOOLKIT_CFLAGS) $(LIBXML_CFLAGS) +libarchoperandsui_la_CFLAGS = $(LIBGTK4_CFLAGS)  devdir = $(includedir)/chrysalide/$(subdir:src/%=core/%) -dev_HEADERS = $(libarchoperands_la_SOURCES:%c=) +dev_HEADERS = $(libarchoperands_la_SOURCES:%c=) $(libarchoperandsui_la_SOURCES:%c=) diff --git a/src/arch/operands/immediate-int.h b/src/arch/operands/immediate-int.h index d2313f5..3d60c7d 100644 --- a/src/arch/operands/immediate-int.h +++ b/src/arch/operands/immediate-int.h @@ -2,7 +2,7 @@  /* Chrysalide - Outil d'analyse de fichiers binaires   * immediate-int.h - définitions internes propres aux opérandes représentant des valeurs numériques   * - * Copyright (C) 2021 Cyrille Bagard + * Copyright (C) 2021-2024 Cyrille Bagard   *   *  This file is part of Chrysalide.   * @@ -30,27 +30,8 @@ -/* Informations glissées dans la structure GObject de GArchOperand */ -typedef struct _immop_extra_data_t -{ -    operand_extra_data_t parent;            /* A laisser en premier        */ - -    MemoryDataSize size;                    /* Taille de l'opérande        */ - -    /** -     * Les deux éléments suivants sont de type ImmOperandDisplay ; -     * leur espace de conservation est réduit au maximum afin d'éviter -     * un recouvrement . -     */ - -    unsigned int def_display : 3;           /* Type par défaut d'affichage */ -    unsigned int display : 3;               /* Format général d'affichage  */ - -} immop_extra_data_t; - -  /* Définition d'un opérande de valeur numérique (instance) */ -struct _GImmOperand +struct _GImmediateOperand  {      GArchOperand parent;                    /* Instance parente            */ @@ -59,7 +40,7 @@ struct _GImmOperand  };  /* Définition d'un opérande de valeur numérique (classe) */ -struct _GImmOperandClass +struct _GImmediateOperandClass  {      GArchOperandClass parent;               /* Classe parente              */ @@ -70,15 +51,46 @@ struct _GImmOperandClass   * Accès aux informations éventuellement déportées.   */ -#if 1 //__SIZEOF_INT__ == __SIZEOF_LONG__ +/* Informations glissées dans la structure GObject de GArchOperand */ +typedef struct _immop_extra_data_t +{ +    ARCH_OPERAND_EXTRA_DATA(3);             /* Informations pour l'opérande*/ -#   define GET_IMM_OP_EXTRA(op) ((immop_extra_data_t *)&((GArchOperand *)op)->extra) +    /** +     * MemoryDataSize +     */ +    unsigned int size : 4;                  /* Taille de l'opérande        */ + +    /** +     * ImmOperandDisplay x 2 +     */ +    unsigned int def_display : 3;           /* Type par défaut d'affichage */ +    unsigned int display : 3;               /* Format général d'affichage  */ + +} immop_extra_data_t; + + +#define GET_IMM_OP_EXTRA(op) \ +    GET_GOBJECT_EXTRA(op, immop_extra_data_t) + +#define SET_IMM_OP_EXTRA(op, data) \ +    SET_GOBJECT_EXTRA(op, immop_extra_data_t, data) -#else -#   define GET_IMM_OP_EXTRA(op) GET_GOBJECT_EXTRA(G_OBJECT(op), immop_extra_data_t) +/*  Met en place un opérande réprésentant une valeur numérique. */ +bool g_immediate_operand_create_from_value(GImmediateOperand *, MemoryDataSize, uint64_t); + +/* Crée un opérande réprésentant une valeur numérique. */ +bool g_immediate_operand_create_from_data(GImmediateOperand *, MemoryDataSize, const GBinContent *, vmpa2t *, bool *, SourceEndian); + +/** + * La taille d'impression d'un opérande n'est pas VMPA_MAX_SIZE, + * mais 1 + 64 caractères + octet nul final en cas d'impression en binaire. + */ +#define IMM_MAX_SIZE 66 -#endif +/* Construit la chaîne de caractères correspondant à l'opérande. */ +size_t _g_immediate_operand_to_string(const GImmediateOperand *, ImmOperandDisplay, char [IMM_MAX_SIZE]); diff --git a/src/arch/operands/immediate-ui.c b/src/arch/operands/immediate-ui.c new file mode 100644 index 0000000..62058b3 --- /dev/null +++ b/src/arch/operands/immediate-ui.c @@ -0,0 +1,184 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * immediate-ui.c - opérandes représentant des valeurs numériques sous forme graphique + * + * Copyright (C) 2024 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 "immediate-ui.h" + + +#include <i18n.h> + + +#include "immediate-int.h" +#include "../../common/extstr.h" +#include "../../glibext/tokenstyle.h" +#include "../../glibext/options/asm.h" + + + +/* Traduit un opérande en version humainement lisible. */ +static void g_immediate_operand_ui_print(const GImmediateOperand *, GBufferLine *); + +/* Construit un petit résumé concis de l'opérande. */ +static char *g_immediate_operand_ui_build_tooltip(const GImmediateOperand *, const GLoadedBinary *); + + + +/****************************************************************************** +*                                                                             * +*  Paramètres  : iface = interface GLib à initialiser.                        * +*                                                                             * +*  Description : Procède à l'initialisation de l'interface d'opérande UI.     * +*                                                                             * +*  Retour      : -                                                            * +*                                                                             * +*  Remarques   : -                                                            * +*                                                                             * +******************************************************************************/ + +void g_immediate_operand_ui_arch_operand_ui_iface_init(GArchOperandUIInterface *iface) +{ +    iface->print = (print_operand_ui_fc)g_immediate_operand_ui_print; +    iface->build_tooltip = (build_operand_ui_tooltip_fc)g_immediate_operand_ui_build_tooltip; + +} + + +/****************************************************************************** +*                                                                             * +*  Paramètres  : operand = opérande à traiter.                                * +*                line    = ligne tampon où imprimer l'opérande donné.         * +*                                                                             * +*  Description : Traduit un opérande en version humainement lisible.          * +*                                                                             * +*  Retour      : -                                                            * +*                                                                             * +*  Remarques   : -                                                            * +*                                                                             * +******************************************************************************/ + +static void g_immediate_operand_ui_print(const GImmediateOperand *operand, GBufferLine *line) +{ +    GImmediateOperand *base;                /* Version d'instance basique  */ +    ImmOperandDisplay display;              /* Type d'affichage courant    */ +    char value[IMM_MAX_SIZE];               /* Chaîne à imprimer           */ +    size_t len;                             /* Taille de l'élément inséré  */ + +    base = G_IMMEDIATE_OPERAND(operand); + +    display = g_immediate_operand_get_display(base); + +    len = _g_immediate_operand_to_string(base, display, value); + +    g_buffer_line_append_text(line, ACO_ASSEMBLY, TRT_IMMEDIATE, value, len, NULL, G_OBJECT(operand)); + +} + + +/****************************************************************************** +*                                                                             * +*  Paramètres  : operand = opérande à consulter.                              * +*                binary  = informations relatives au binaire chargé.          * +*                                                                             * +*  Description : Construit un petit résumé concis de l'opérande.              * +*                                                                             * +*  Retour      : Chaîne de caractères à libérer après usage ou NULL.          * +*                                                                             * +*  Remarques   : -                                                            * +*                                                                             * +******************************************************************************/ + +static char *g_immediate_operand_ui_build_tooltip(const GImmediateOperand *operand, const GLoadedBinary *binary) +{ +    char *result;                           /* Description à retourner     */ +    GImmediateOperand *base;                /* Version d'instance basique  */ +    char value[IMM_MAX_SIZE];               /* Conversion artificielle     */ +    char *conv;                             /* Affichage de la Conversion  */ + +    base = G_IMMEDIATE_OPERAND(operand); + +    if (base->raw <= UCHAR_MAX && isprint(base->raw)) +        switch (base->raw) +        { +            case '&': +                asprintf(&result, _("Character: '&'")); +                break; +            case '<': +                asprintf(&result, _("Character: '<'")); +                break; +            case '>': +                asprintf(&result, _("Character: '>'")); +                break; +            default: +                asprintf(&result, _("Character: '%c'"), (char)base->raw); +                break; +        } + +    else +        asprintf(&result, _("Character: <not printable>")); + +    /* Binaire */ + +    _g_immediate_operand_to_string(base, IOD_BIN, value); + +    asprintf(&conv, _("Binary: %s"), value); + +    result = stradd(result, "\n"); +    result = stradd(result, conv); + +    free(conv); + +    /* Octal */ + +    _g_immediate_operand_to_string(base, IOD_OCT, value); + +    asprintf(&conv, _("Octal: %s"), value); + +    result = stradd(result, "\n"); +    result = stradd(result, conv); + +    free(conv); + +    /* Décimal */ + +    _g_immediate_operand_to_string(base, IOD_DEC, value); + +    asprintf(&conv, _("Decimal: %s"), value); + +    result = stradd(result, "\n"); +    result = stradd(result, conv); + +    free(conv); + +    /* Hexadécimal */ + +    _g_immediate_operand_to_string(base, IOD_HEX, value); + +    asprintf(&conv, _("Hexadecimal: %s"), value); + +    result = stradd(result, "\n"); +    result = stradd(result, conv); + +    free(conv); + +    return result; + +} diff --git a/src/arch/operands/immediate-ui.h b/src/arch/operands/immediate-ui.h new file mode 100644 index 0000000..4dbddae --- /dev/null +++ b/src/arch/operands/immediate-ui.h @@ -0,0 +1,37 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * immediate-ui.h - prototypes pour les opérandes représentant des valeurs numériques sous forme graphique + * + * Copyright (C) 2024 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 _ARCH_OPERANDS_IMMEDIATE_UI_H +#define _ARCH_OPERANDS_IMMEDIATE_UI_H + + +#include "../operand-ui-int.h" + + + +/* Procède à l'initialisation de l'interface d'opérande UI. */ +void g_immediate_operand_ui_arch_operand_ui_iface_init(GArchOperandUIInterface *); + + + +#endif  /* _ARCH_OPERANDS_IMMEDIATE_UI_H */ diff --git a/src/arch/operands/immediate.c b/src/arch/operands/immediate.c index f40c645..f99b421 100644 --- a/src/arch/operands/immediate.c +++ b/src/arch/operands/immediate.c @@ -2,7 +2,7 @@  /* Chrysalide - Outil d'analyse de fichiers binaires   * immediate.c - opérandes représentant des valeurs numériques   * - * Copyright (C) 2020 Cyrille Bagard + * Copyright (C) 2020-2024 Cyrille Bagard   *   *  This file is part of Chrysalide.   * @@ -25,25 +25,32 @@  #include <assert.h> +#include <stdarg.h> + + + +#if 0 +  #include <ctype.h>  #include <inttypes.h>  #include <limits.h>  #include <malloc.h> -#include <stdarg.h>  #include <stdio.h>  #include <i18n.h> +#endif + +  #include "immediate-int.h" -#include "known.h" -#include "rename-int.h" -#include "targetable-int.h"  #include "../../common/asm.h" -#include "../../common/extstr.h"  #include "../../common/sort.h" -#include "../../core/columns.h" +#include "../../glibext/comparable-int.h" +#include "../../glibext/hashable-int.h" +#include "../../glibext/serialize-int.h" +#include "../../glibext/strbuilder-int.h" @@ -51,68 +58,75 @@  /* Initialise la classe des opérandes de valeur immédiate. */ -static void g_imm_operand_class_init(GImmOperandClass *); +static void g_immediate_operand_class_init(GImmediateOperandClass *); -/* Initialise un opérande de valeur immédiate. */ -static void g_imm_operand_init(GImmOperand *); +/* Procède à l'initialisation de l'interface de comparaison. */ +static void g_immediate_operand_comparable_object_iface_init(GComparableObjectInterface *); + +/* Procède à l'initialisation de l'interface de détermination. */ +static void g_immediate_operand_hashable_object_iface_init(GHashableObjectInterface *); + +/* Procède à l'initialisation de l'interface de sérialisation. */ +static void g_immediate_operand_serializable_object_iface_init(GSerializableObjectInterface *); + +/* Procède à l'initialisation de l'interface d'exportation. */ +static void g_immediate_operand_string_builder_iface_init(GStringBuilderInterface *, gpointer); + +#if 0  /* Procède à l'initialisation de l'interface de ciblage. */ -static void g_imm_operand_targetable_interface_init(GTargetableOperandInterface *); +static void g_immediate_operand_targetable_interface_init(GTargetableOperandInterface *);  /* Procède à l'initialisation de l'interface de renommage. */ -static void g_imm_operand_renameable_interface_init(GRenameableOperandInterface *); +static void g_immediate_operand_renameable_interface_init(GRenameableOperandInterface *); + +#endif + +/* Initialise un opérande de valeur immédiate. */ +static void g_immediate_operand_init(GImmediateOperand *);  /* Supprime toutes les références externes. */ -static void g_imm_operand_dispose(GImmOperand *); +static void g_immediate_operand_dispose(GObject *);  /* Procède à la libération totale de la mémoire. */ -static void g_imm_operand_finalize(GImmOperand *); +static void g_immediate_operand_finalize(GObject *); -/* Construit la chaîne de caractères correspondant à l'opérande. */ -static size_t _g_imm_operand_to_string(const GImmOperand *, ImmOperandDisplay, char [IMM_MAX_SIZE]); -/* Traduit un opérande en version humainement lisible. */ -static void g_imm_operand_print(const GImmOperand *, GBufferLine *); +/* ---------------------- COMPARAISON DETAILLEE DE DEUX OBJETS ---------------------- */ -/* --------------------- IMPLEMENTATION DES FONCTIONS DE CLASSE --------------------- */ +/* Réalise une comparaison étendue entre objets. */ +static int g_immediate_operand_compare(const GComparableObject *, const GComparableObject *); -/* Compare un opérande avec un autre. */ -static int g_imm_operand_compare(const GImmOperand *, const GImmOperand *, bool); -#ifdef INCLUDE_GTK_SUPPORT +/* ---------------------- CALCUL D'UNE EMPREINTE DE L'INSTANCE ---------------------- */ -/* Construit un petit résumé concis de l'opérande. */ -static char *g_imm_operand_build_tooltip(const GImmOperand *, const GLoadedBinary *); -#endif +/* Calcule l'empreinte sur 32 bits d'un objet. */ +static guint g_immediate_operand_hash(const GHashableObject *); -/* Fournit l'empreinte d'un candidat à une centralisation. */ -static guint g_imm_operand_hash(const GImmOperand *, bool); -/* Charge un contenu depuis une mémoire tampon. */ -static bool g_imm_operand_load(GImmOperand *, GObjectStorage *, packed_buffer_t *); -/* Sauvegarde un contenu dans une mémoire tampon. */ -static bool g_imm_operand_store(GImmOperand *, GObjectStorage *, packed_buffer_t *); +/* ------------------- MECANISMES DE CONSERVATION ET RESTAURATION ------------------- */ +/* Charge un objet depuis un flux de données. */ +static bool g_immediate_operand_load(GSerializableObject *, GObjectStorage *, int); -/* ---------------------- COMMUNICATION D'UN CIBLAGE POTENTIEL ---------------------- */ +/* Sauvegarde un objet dans un flux de données. */ +static bool g_immediate_operand_store(const GSerializableObject *, GObjectStorage *, int); -/* Obtient l'adresse de la cible visée par un opérande. */ -static bool g_imm_operand_get_addr(const GImmOperand *, const vmpa2t *, GBinFormat *, GArchProcessor *, vmpa2t *); +/* ----------------- EXPORTATION SOUS FORME DE CHAINE DE CARACTERES ----------------- */ -/* ---------------------- CONSTRUCTION D'UN CONTENU ALTERNATIF ---------------------- */ +/* Exporte une chaîne de caractères à partir d'un objet. */ +static bool g_immediate_operand_to_string(const GStringBuilder *, unsigned int, sized_binary_t *); -/* Construit un opérande de représentation alternative. */ -static GRenamedOperand *g_imm_operand_build(const GImmOperand *, const char *); @@ -122,9 +136,12 @@ static GRenamedOperand *g_imm_operand_build(const GImmOperand *, const char *);  /* Indique le type défini pour un opérande de valeur numérique. */ -G_DEFINE_TYPE_WITH_CODE(GImmOperand, g_imm_operand, G_TYPE_ARCH_OPERAND, -                        G_IMPLEMENT_INTERFACE(G_TYPE_TARGETABLE_OPERAND, g_imm_operand_targetable_interface_init) -                        G_IMPLEMENT_INTERFACE(G_TYPE_RENAMEABLE_OPERAND, g_imm_operand_renameable_interface_init)); +G_DEFINE_TYPE_WITH_CODE(GImmediateOperand, g_immediate_operand, G_TYPE_ARCH_OPERAND, +                        G_IMPLEMENT_INTERFACE(G_TYPE_COMPARABLE_OBJECT, g_immediate_operand_comparable_object_iface_init) +                        G_IMPLEMENT_INTERFACE(G_TYPE_HASHABLE_OBJECT, g_immediate_operand_hashable_object_iface_init) +                        G_IMPLEMENT_INTERFACE(G_TYPE_SERIALIZABLE_OBJECT, g_immediate_operand_serializable_object_iface_init) +                        G_IMPLEMENT_INTERFACE(G_TYPE_STRING_BUILDER, g_immediate_operand_string_builder_iface_init) +                        G_IMPLEMENT_INTERFACE_IF_SYM(g_arch_operand_ui_get_type, g_immediate_operand_ui_arch_operand_ui_iface_init));  /****************************************************************************** @@ -139,36 +156,42 @@ G_DEFINE_TYPE_WITH_CODE(GImmOperand, g_imm_operand, G_TYPE_ARCH_OPERAND,  *                                                                             *  ******************************************************************************/ -static void g_imm_operand_class_init(GImmOperandClass *klass) +static void g_immediate_operand_class_init(GImmediateOperandClass *klass)  {      GObjectClass *object;                   /* Autre version de la classe  */ -    GArchOperandClass *operand;             /* Version de classe parente   */      object = G_OBJECT_CLASS(klass); -    operand = G_ARCH_OPERAND_CLASS(klass); -    object->dispose = (GObjectFinalizeFunc/* ! */)g_imm_operand_dispose; -    object->finalize = (GObjectFinalizeFunc)g_imm_operand_finalize; +    object->dispose = g_immediate_operand_dispose; +    object->finalize = g_immediate_operand_finalize; -    operand->compare = (operand_compare_fc)g_imm_operand_compare; -    operand->print = (operand_print_fc)g_imm_operand_print; -#ifdef INCLUDE_GTK_SUPPORT -    operand->build_tooltip = (operand_build_tooltip_fc)g_imm_operand_build_tooltip; -#endif +} -    operand->hash = (operand_hash_fc)g_imm_operand_hash; -    operand->load = (load_operand_fc)g_imm_operand_load; -    operand->store = (store_operand_fc)g_imm_operand_store; +/****************************************************************************** +*                                                                             * +*  Paramètres  : iface = interface GLib à initialiser.                        * +*                                                                             * +*  Description : Procède à l'initialisation de l'interface de comparaison.    * +*                                                                             * +*  Retour      : -                                                            * +*                                                                             * +*  Remarques   : -                                                            * +*                                                                             * +******************************************************************************/ + +static void g_immediate_operand_comparable_object_iface_init(GComparableObjectInterface *iface) +{ +    iface->compare = g_immediate_operand_compare;  }  /******************************************************************************  *                                                                             * -*  Paramètres  : operand = instance à initialiser.                            * +*  Paramètres  : iface = interface GLib à initialiser.                        *  *                                                                             * -*  Description : Initialise un opérande de valeur immédiate.                  * +*  Description : Procède à l'initialisation de l'interface de détermination.  *  *                                                                             *  *  Retour      : -                                                            *  *                                                                             * @@ -176,23 +199,39 @@ static void g_imm_operand_class_init(GImmOperandClass *klass)  *                                                                             *  ******************************************************************************/ -static void g_imm_operand_init(GImmOperand *operand) +static void g_immediate_operand_hashable_object_iface_init(GHashableObjectInterface *iface)  { -    GET_IMM_OP_EXTRA(operand)->size = MDS_UNDEFINED; +    iface->hash = g_immediate_operand_hash; -    GET_IMM_OP_EXTRA(operand)->def_display = IOD_HEX; -    GET_IMM_OP_EXTRA(operand)->display = IOD_COUNT; +} -    operand->raw = 0; + +/****************************************************************************** +*                                                                             * +*  Paramètres  : iface = interface GLib à initialiser.                        * +*                                                                             * +*  Description : Procède à l'initialisation de l'interface de sérialisation.  * +*                                                                             * +*  Retour      : -                                                            * +*                                                                             * +*  Remarques   : -                                                            * +*                                                                             * +******************************************************************************/ + +static void g_immediate_operand_serializable_object_iface_init(GSerializableObjectInterface *iface) +{ +    iface->load = g_immediate_operand_load; +    iface->store = g_immediate_operand_store;  }  /******************************************************************************  *                                                                             * -*  Paramètres  : iface = interface GLib à initialiser.                        * +*  Paramètres  : iface  = interface GLib à initialiser.                       * +*                unused = pointeur non utilisé ici.                           *  *                                                                             * -*  Description : Procède à l'initialisation de l'interface de ciblage.        * +*  Description : Procède à l'initialisation de l'interface d'exportation.     *  *                                                                             *  *  Retour      : -                                                            *  *                                                                             * @@ -200,18 +239,18 @@ static void g_imm_operand_init(GImmOperand *operand)  *                                                                             *  ******************************************************************************/ -static void g_imm_operand_targetable_interface_init(GTargetableOperandInterface *iface) +static void g_immediate_operand_string_builder_iface_init(GStringBuilderInterface *iface, gpointer unused)  { -    iface->get_addr = (get_targetable_addr_fc)g_imm_operand_get_addr; +    iface->to_string = g_immediate_operand_to_string;  }  /******************************************************************************  *                                                                             * -*  Paramètres  : iface = interface GLib à initialiser.                        * +*  Paramètres  : operand = instance à initialiser.                            *  *                                                                             * -*  Description : Procède à l'initialisation de l'interface de renommage.      * +*  Description : Initialise un opérande de valeur immédiate.                  *  *                                                                             *  *  Retour      : -                                                            *  *                                                                             * @@ -219,16 +258,27 @@ static void g_imm_operand_targetable_interface_init(GTargetableOperandInterface  *                                                                             *  ******************************************************************************/ -static void g_imm_operand_renameable_interface_init(GRenameableOperandInterface *iface) +static void g_immediate_operand_init(GImmediateOperand *operand)  { -    iface->build = (build_renameable_fc)g_imm_operand_build; +    immop_extra_data_t extra;               /* Données insérées à consulter*/ + +    extra = GET_IMM_OP_EXTRA(operand); + +    extra.size = MDS_UNDEFINED; + +    extra.def_display = IOD_HEX; +    extra.display = IOD_COUNT; + +    SET_IMM_OP_EXTRA(operand, &extra); + +    operand->raw = 0;  }  /******************************************************************************  *                                                                             * -*  Paramètres  : operand = instance d'objet GLib à traiter.                   * +*  Paramètres  : object = instance d'objet GLib à traiter.                    *  *                                                                             *  *  Description : Supprime toutes les références externes.                     *  *                                                                             * @@ -238,16 +288,16 @@ static void g_imm_operand_renameable_interface_init(GRenameableOperandInterface  *                                                                             *  ******************************************************************************/ -static void g_imm_operand_dispose(GImmOperand *operand) +static void g_immediate_operand_dispose(GObject *object)  { -    G_OBJECT_CLASS(g_imm_operand_parent_class)->dispose(G_OBJECT(operand)); +    G_OBJECT_CLASS(g_immediate_operand_parent_class)->dispose(object);  }  /******************************************************************************  *                                                                             * -*  Paramètres  : operand = instance d'objet GLib à traiter.                   * +*  Paramètres  : object = instance d'objet GLib à traiter.                    *  *                                                                             *  *  Description : Procède à la libération totale de la mémoire.                *  *                                                                             * @@ -257,9 +307,74 @@ static void g_imm_operand_dispose(GImmOperand *operand)  *                                                                             *  ******************************************************************************/ -static void g_imm_operand_finalize(GImmOperand *operand) +static void g_immediate_operand_finalize(GObject *object) +{ +    G_OBJECT_CLASS(g_immediate_operand_parent_class)->finalize(object); + +} + + +/****************************************************************************** +*                                                                             * +*  Paramètres  : size  = taille de l'opérande souhaitée.                      * +*                value = valeur sur x bits à venir récupérer.                 * +*                                                                             * +*  Description : Crée un opérande réprésentant une valeur numérique.          * +*                                                                             * +*  Retour      : Instruction mise en place.                                   * +*                                                                             * +*  Remarques   : -                                                            * +*                                                                             * +******************************************************************************/ + +GArchOperand *g_immediate_operand_new_from_value(MemoryDataSize size, uint64_t value)  { -    G_OBJECT_CLASS(g_imm_operand_parent_class)->finalize(G_OBJECT(operand)); +    GImmediateOperand *result;                    /* Opérande à retourner        */ + +    result = g_object_new(G_TYPE_IMMEDIATE_OPERAND, NULL); + +    if (!g_immediate_operand_create_from_value(result, size, value)) +        g_clear_object(&result); + +    return G_ARCH_OPERAND(result); + +} + + +/****************************************************************************** +*                                                                             * +*  Paramètres  : operand = instance à initialiser pleinement.                 * +*                size    = taille de l'opérande souhaitée.                    * +*                value   = valeur sur x bits à venir récupérer.               * +*                                                                             * +*  Description : Met en place un opérande réprésentant une valeur numérique.  * +*                                                                             * +*  Retour      : Bilan de l'opération.                                        * +*                                                                             * +*  Remarques   : -                                                            * +*                                                                             * +******************************************************************************/ + +bool g_immediate_operand_create_from_value(GImmediateOperand *operand, MemoryDataSize size, uint64_t value) +{ +    bool result;                            /* Bilan à retourner           */ +    immop_extra_data_t extra;               /* Données insérées à consulter*/ + +    result = (size != MDS_UNDEFINED); + +    if (result) +    { +        extra = GET_IMM_OP_EXTRA(operand); + +        extra.size = size; + +        operand->raw = value; + +        SET_IMM_OP_EXTRA(operand, &extra); + +    } + +    return result;  } @@ -280,10 +395,41 @@ static void g_imm_operand_finalize(GImmOperand *operand)  *                                                                             *  ******************************************************************************/ -GArchOperand *_g_imm_operand_new_from_data(MemoryDataSize size, const GBinContent *content, vmpa2t *addr, bool *low, SourceEndian endian) +GArchOperand *g_immediate_operand_new_from_data(MemoryDataSize size, const GBinContent *content, vmpa2t *addr, bool *low, SourceEndian endian)  { -    GImmOperand *result;                    /* Opérande à retourner        */ -    immop_extra_data_t *extra;              /* Données insérées à modifier */ +    GImmediateOperand *result;                    /* Opérande à retourner        */ + +    result = g_object_new(G_TYPE_IMMEDIATE_OPERAND, NULL); + +    if (!g_immediate_operand_create_from_data(result, size, content, addr, low, endian)) +        g_clear_object(&result); + +    return G_ARCH_OPERAND(result); + +} + + +/****************************************************************************** +*                                                                             * +*  Paramètres  : operand = instance à initialiser pleinement.                 * +*                size    = taille de l'opérande souhaitée.                    * +*                content = flux de données à analyser.                        * +*                addr    = position courante dans ce flux. [OUT]              * +*                low     = position éventuelle des 4 bits visés. [OUT]        * +*                endian  = ordre des bits dans la source.                     * +*                                                                             * +*  Description : Crée un opérande réprésentant une valeur numérique.          * +*                                                                             * +*  Retour      : Instruction mise en place.                                   * +*                                                                             * +*  Remarques   : -                                                            * +*                                                                             * +******************************************************************************/ + +bool g_immediate_operand_create_from_data(GImmediateOperand *operand, MemoryDataSize size, const GBinContent *content, vmpa2t *addr, bool *low, SourceEndian endian) +{ +    bool result;                            /* Bilan à retourner           */ +    uint64_t raw;                           /* Valeur brute lue            */      uint8_t uval8;                          /* Valeur sur 8 bits           */      uint16_t uval16;                        /* Valeur sur 16 bits          */      uint32_t uval32;                        /* Valeur sur 32 bits          */ @@ -293,125 +439,78 @@ GArchOperand *_g_imm_operand_new_from_data(MemoryDataSize size, const GBinConten      int32_t sval32;                         /* Valeur sur 32 bits          */      int64_t sval64;                         /* Valeur sur 64 bits          */ -    result = g_object_new(G_TYPE_IMM_OPERAND, NULL); - -    extra = GET_IMM_OP_EXTRA(result); - -    extra->size = size; -      switch (size)      {          case MDS_4_BITS_UNSIGNED: -            if (!g_binary_content_read_u4(content, addr, low, &uval8)) -                goto gionfd_error; -            result->raw = uval8; +            result = g_binary_content_read_u4(content, addr, low, &uval8); +            if (result) +                raw = uval8;              break;          case MDS_8_BITS_UNSIGNED: -            if (!g_binary_content_read_u8(content, addr, &uval8)) -                goto gionfd_error; -            result->raw = uval8; +            result = g_binary_content_read_u8(content, addr, &uval8); +            if (result) +                raw = uval8;              break;          case MDS_16_BITS_UNSIGNED: -            if (!g_binary_content_read_u16(content, addr, endian, &uval16)) -                goto gionfd_error; -            result->raw = uval16; +            result = g_binary_content_read_u16(content, addr, endian, &uval16); +            if (result) +                raw = uval16;              break;          case MDS_32_BITS_UNSIGNED: -            if (!g_binary_content_read_u32(content, addr, endian, &uval32)) -                goto gionfd_error; -            result->raw = uval32; +            result = g_binary_content_read_u32(content, addr, endian, &uval32); +            if (result) +                raw = uval32;              break;          case MDS_64_BITS_UNSIGNED: -            if (!g_binary_content_read_u64(content, addr, endian, &uval64)) -                goto gionfd_error; -            result->raw = uval64; +            result = g_binary_content_read_u64(content, addr, endian, &uval64); +            if (result) +                raw = uval64;              break;          case MDS_4_BITS_SIGNED: -            if (!g_binary_content_read_s4(content, addr, low, &sval8)) -                goto gionfd_error; -            result->raw = sval8; +            result = g_binary_content_read_s4(content, addr, low, &sval8); +            if (result) +                raw = sval8;              break;          case MDS_8_BITS_SIGNED: -            if (!g_binary_content_read_s8(content, addr, &sval8)) -                goto gionfd_error; -            result->raw = sval8; +            result = g_binary_content_read_s8(content, addr, &sval8); +            if (result) +                raw = sval8;              break;          case MDS_16_BITS_SIGNED: -            if (!g_binary_content_read_s16(content, addr, endian, &sval16)) -                goto gionfd_error; -            result->raw = sval16; +            result = g_binary_content_read_s16(content, addr, endian, &sval16); +            if (result) +                raw = sval16;              break;          case MDS_32_BITS_SIGNED: -            if (!g_binary_content_read_s32(content, addr, endian, &sval32)) -                goto gionfd_error; -            result->raw = sval32; +            result = g_binary_content_read_s32(content, addr, endian, &sval32); +            if (result) +                raw = sval32;              break;          case MDS_64_BITS_SIGNED: -            if (!g_binary_content_read_s64(content, addr, endian, &sval64)) -                goto gionfd_error; -            result->raw = sval64; +            result = g_binary_content_read_s64(content, addr, endian, &sval64); +            if (result) +                raw = sval64;              break;          case MDS_UNDEFINED: -            goto gionfd_error; +            result = false;              break;      } -    return G_ARCH_OPERAND(result); - - gionfd_error: - -    g_object_unref(G_OBJECT(result)); - -    return NULL; - -} - - -/****************************************************************************** -*                                                                             * -*  Paramètres  : size  = taille de l'opérande souhaitée.                      * -*                value = valeur sur x bits à venir récupérer.                 * -*                                                                             * -*  Description : Crée un opérande réprésentant une valeur numérique.          * -*                                                                             * -*  Retour      : Instruction mise en place.                                   * -*                                                                             * -*  Remarques   : -                                                            * -*                                                                             * -******************************************************************************/ - -GArchOperand *g_imm_operand_new_from_value(MemoryDataSize size, uint64_t value) -{ -    GImmOperand *result;                    /* Opérande à retourner        */ -    immop_extra_data_t *extra;              /* Données insérées à modifier */ - -    if (size == MDS_UNDEFINED) -        result = NULL; - -    else -    { -        result = g_object_new(G_TYPE_IMM_OPERAND, NULL); - -        extra = GET_IMM_OP_EXTRA(result); - -        extra->size = size; - -        result->raw = value; - -    } +    if (result) +        result = g_immediate_operand_create_from_value(operand, size, raw); -    return (result != NULL ? G_ARCH_OPERAND(result) : NULL); +    return result;  } @@ -428,18 +527,14 @@ GArchOperand *g_imm_operand_new_from_value(MemoryDataSize size, uint64_t value)  *                                                                             *  ******************************************************************************/ -MemoryDataSize g_imm_operand_get_size(const GImmOperand *operand) +MemoryDataSize g_immediate_operand_get_size(const GImmediateOperand *operand)  {      MemoryDataSize result;                  /* Taille à retourner          */ -    immop_extra_data_t *extra;              /* Données insérées à consulter*/ +    immop_extra_data_t extra;               /* Données insérées à consulter*/      extra = GET_IMM_OP_EXTRA(operand); -    LOCK_GOBJECT_EXTRA(extra); - -    result = extra->size; - -    UNLOCK_GOBJECT_EXTRA(extra); +    result = extra.size;      return result; @@ -460,10 +555,10 @@ MemoryDataSize g_imm_operand_get_size(const GImmOperand *operand)  *                                                                             *  ******************************************************************************/ -bool g_imm_operand_get_value(const GImmOperand *operand, MemoryDataSize size, ...) +bool g_immediate_operand_get_value(const GImmediateOperand *operand, MemoryDataSize size, ...)  {      bool result;                            /* Bilan à retourner           */ -    immop_extra_data_t *extra;              /* Données insérées à consulter*/ +    immop_extra_data_t extra;               /* Données insérées à consulter*/      va_list ap;                             /* Liste des compléments       */      uint8_t *uval8;                         /* Valeur sur 8 bits           */      uint16_t *uval16;                       /* Valeur sur 16 bits          */ @@ -478,9 +573,7 @@ bool g_imm_operand_get_value(const GImmOperand *operand, MemoryDataSize size, ..      extra = GET_IMM_OP_EXTRA(operand); -    LOCK_GOBJECT_EXTRA(extra); - -    if (extra->size != size) +    if (extra.size != size)          goto exit;      va_start(ap, size); @@ -533,8 +626,6 @@ bool g_imm_operand_get_value(const GImmOperand *operand, MemoryDataSize size, ..   exit: -    UNLOCK_GOBJECT_EXTRA(extra); -      return result;  } @@ -542,6 +633,37 @@ bool g_imm_operand_get_value(const GImmOperand *operand, MemoryDataSize size, ..  /******************************************************************************  *                                                                             * +*  Paramètres  : operand = structure dont le contenu est à actualiser. [OUT]  * +*                size    = taille de l'opérande souhaitée.                    * +*                value   = valeur sur x bits à venir récupérer.               * +*                                                                             * +*  Description : Définit la nouvelle valeur de l'opérande à une valeur.       * +*                                                                             * +*  Retour      : -                                                            * +*                                                                             * +*  Remarques   : -                                                            * +*                                                                             * +******************************************************************************/ + +void g_immediate_operand_set_value(GImmediateOperand *operand, MemoryDataSize size, uint64_t value) +{ +    immop_extra_data_t extra;               /* Données insérées à consulter*/ + +    assert(size != MDS_UNDEFINED); + +    extra = GET_IMM_OP_EXTRA(operand); + +    extra.size = size; + +    operand->raw = value; + +    SET_IMM_OP_EXTRA(operand, &extra); + +} + + +/****************************************************************************** +*                                                                             *  *  Paramètres  : operand = opérande à consulter.                              *  *                                                                             *  *  Description : Fournit la valeur brute représentée par l'opérande.          * @@ -552,42 +674,55 @@ bool g_imm_operand_get_value(const GImmOperand *operand, MemoryDataSize size, ..  *                                                                             *  ******************************************************************************/ -uint64_t g_imm_operand_get_raw_value(const GImmOperand *operand) +uint64_t g_immediate_operand_get_raw_value(const GImmediateOperand *operand)  { -    return operand->raw; +    uint64_t result;                        /* Valeur brute à retourner    */ + +    result = operand->raw; + +    return result;  }  /******************************************************************************  *                                                                             * -*  Paramètres  : operand = structure dont le contenu est à actualiser. [OUT]  * -*                size    = taille de l'opérande souhaitée.                    * -*                value   = valeur sur x bits à venir récupérer.               * +*  Paramètres  : operand = structure dont le contenu est à consulter.         *  *                                                                             * -*  Description : Définit la nouvelle valeur de l'opérande à une valeur.       * +*  Description : Indique le signe d'une valeur immédiate.                     *  *                                                                             * -*  Retour      : -                                                            * +*  Retour      : true si la valeur est strictement négative, false sinon.     *  *                                                                             *  *  Remarques   : -                                                            *  *                                                                             *  ******************************************************************************/ -void g_imm_operand_set_value(GImmOperand *operand, MemoryDataSize size, uint64_t value) +bool g_immediate_operand_is_negative(const GImmediateOperand *operand)  { -    immop_extra_data_t *extra;              /* Données insérées à consulter*/ - -    assert(size != MDS_UNDEFINED); +    bool result;                            /* Bilan à renvoyer            */ +    immop_extra_data_t extra;               /* Données insérées à consulter*/      extra = GET_IMM_OP_EXTRA(operand); -    LOCK_GOBJECT_EXTRA(extra); - -    extra->size = size; - -    operand->raw = value; +    switch (extra.size) +    { +        case MDS_4_BITS_SIGNED: +        case MDS_8_BITS_SIGNED: +        case MDS_16_BITS_SIGNED: +        case MDS_32_BITS_SIGNED: +        case MDS_64_BITS_SIGNED: +            /** +             * Pour les valeurs plus petites que 64 bits, le compilateur +             * réalise une extension de signe lors du transtypage. +             */ +            result = (operand->raw & 0x8000000000000000ll); +            break; +        default: +            result = false; +            break; +    } -    UNLOCK_GOBJECT_EXTRA(extra); +    return result;  } @@ -605,17 +740,15 @@ void g_imm_operand_set_value(GImmOperand *operand, MemoryDataSize size, uint64_t  *                                                                             *  ******************************************************************************/ -void g_imm_operand_set_default_display(GImmOperand *operand, ImmOperandDisplay display) +void g_immediate_operand_set_default_display(GImmediateOperand *operand, ImmOperandDisplay display)  { -    immop_extra_data_t *extra;              /* Données insérées à consulter*/ +    immop_extra_data_t extra;               /* Données insérées à consulter*/      extra = GET_IMM_OP_EXTRA(operand); -    LOCK_GOBJECT_EXTRA(extra); +    extra.def_display = display; -    extra->def_display = display; - -    UNLOCK_GOBJECT_EXTRA(extra); +    SET_IMM_OP_EXTRA(operand, &extra);  } @@ -632,18 +765,14 @@ void g_imm_operand_set_default_display(GImmOperand *operand, ImmOperandDisplay d  *                                                                             *  ******************************************************************************/ -ImmOperandDisplay g_imm_operand_get_default_display(const GImmOperand *operand) +ImmOperandDisplay g_immediate_operand_get_default_display(const GImmediateOperand *operand)  {      ImmOperandDisplay result;               /* Affichage à retourner       */ -    immop_extra_data_t *extra;              /* Données insérées à consulter*/ +    immop_extra_data_t extra;               /* Données insérées à consulter*/      extra = GET_IMM_OP_EXTRA(operand); -    LOCK_GOBJECT_EXTRA(extra); - -    result = extra->def_display; - -    UNLOCK_GOBJECT_EXTRA(extra); +    result = extra.def_display;      return result; @@ -663,17 +792,15 @@ ImmOperandDisplay g_imm_operand_get_default_display(const GImmOperand *operand)  *                                                                             *  ******************************************************************************/ -void g_imm_operand_set_display(GImmOperand *operand, ImmOperandDisplay display) +void g_immediate_operand_set_display(GImmediateOperand *operand, ImmOperandDisplay display)  { -    immop_extra_data_t *extra;              /* Données insérées à consulter*/ +    immop_extra_data_t extra;               /* Données insérées à consulter*/      extra = GET_IMM_OP_EXTRA(operand); -    LOCK_GOBJECT_EXTRA(extra); +    extra.display = display; -    extra->display = display; - -    UNLOCK_GOBJECT_EXTRA(extra); +    SET_IMM_OP_EXTRA(operand, &extra);  } @@ -690,94 +817,225 @@ void g_imm_operand_set_display(GImmOperand *operand, ImmOperandDisplay display)  *                                                                             *  ******************************************************************************/ -ImmOperandDisplay g_imm_operand_get_display(const GImmOperand *operand) +ImmOperandDisplay g_immediate_operand_get_display(const GImmediateOperand *operand)  {      ImmOperandDisplay result;               /* Affichage à retourner       */ -    immop_extra_data_t *extra;              /* Données insérées à consulter*/ +    immop_extra_data_t extra;               /* Données insérées à consulter*/      extra = GET_IMM_OP_EXTRA(operand); -    LOCK_GOBJECT_EXTRA(extra); - -    if (extra->display != IOD_COUNT) -        result = extra->display; +    if (extra.display != IOD_COUNT) +        result = extra.display;      else -        result = extra->def_display; - -    UNLOCK_GOBJECT_EXTRA(extra); +        result = extra.def_display;      return result;  } + +/* ---------------------------------------------------------------------------------- */ +/*                        COMPARAISON DETAILLEE DE DEUX OBJETS                        */ +/* ---------------------------------------------------------------------------------- */ + +  /******************************************************************************  *                                                                             * -*  Paramètres  : operand = structure dont le contenu est à consulter.         * +*  Paramètres  : object = premier objet à consulter pour une comparaison.     * +*                other  = second objet à consulter pour une comparaison.      *  *                                                                             * -*  Description : Indique le signe d'une valeur immédiate.                     * +*  Description : Réalise une comparaison étendue entre objets.                *  *                                                                             * -*  Retour      : true si la valeur est strictement négative, false sinon.     * +*  Retour      : Bilan de la comparaison.                                     *  *                                                                             *  *  Remarques   : -                                                            *  *                                                                             *  ******************************************************************************/ -bool g_imm_operand_is_negative(const GImmOperand *operand) +static int g_immediate_operand_compare(const GComparableObject *object, const GComparableObject *other)  { -    bool result;                            /* Bilan à renvoyer            */ -    immop_extra_data_t *extra;              /* Données insérées à consulter*/ +    int result;                             /* Bilan à retourner           */ +    GComparableObjectInterface *iface;      /* Interface utilisée          */ +    GComparableObjectInterface *parent_iface; /* Interface parente         */ +    GImmediateOperand *operand_a;           /* Version spécialisée #0      */ +    GImmediateOperand *operand_b;           /* Version spécialisée #1      */ +    immop_extra_data_t extra_a;             /* Données insérées à consulter*/ +    immop_extra_data_t extra_b;             /* Données insérées à consulter*/ -    extra = GET_IMM_OP_EXTRA(operand); +    iface = G_COMPARABLE_OBJECT_GET_IFACE(object); + +    parent_iface = g_type_interface_peek_parent(iface); -    LOCK_GOBJECT_EXTRA(extra); +    result = parent_iface->compare(object, other); -    switch (extra->size) +    if (result == 0)      { -        case MDS_4_BITS_SIGNED: -        case MDS_8_BITS_SIGNED: -        case MDS_16_BITS_SIGNED: -        case MDS_32_BITS_SIGNED: -        case MDS_64_BITS_SIGNED: -            /** -             * Pour les valeurs plus petites que 64 bits, le compilateur -             * réalise une extension de signe lors du transtypage. -             */ -            result = (operand->raw & 0x8000000000000000ll); -            break; -        default: -            result = false; -            break; +        operand_a = G_IMMEDIATE_OPERAND(object); + +        extra_a = GET_IMM_OP_EXTRA(operand_a); + +        operand_b = G_IMMEDIATE_OPERAND(other); + +        extra_b = GET_IMM_OP_EXTRA(operand_b); + +        result = sort_unsigned_long(extra_a.size, extra_b.size); + +        if (result == 0) +            sort_uint64_t(operand_a->raw, operand_b->raw); + +        if (result == 0) +            result = sort_unsigned_long(extra_a.def_display, extra_b.def_display); + +        if (result == 0) +            result = sort_unsigned_long(extra_a.display, extra_b.display); +      } -    UNLOCK_GOBJECT_EXTRA(extra); +    return result; + +} + + + +/* ---------------------------------------------------------------------------------- */ +/*                        CALCUL D'UNE EMPREINTE DE L'INSTANCE                        */ +/* ---------------------------------------------------------------------------------- */ + + +/****************************************************************************** +*                                                                             * +*  Paramètres  : object = objet dont l'instance est à consulter.              * +*                                                                             * +*  Description : Calcule l'empreinte sur 32 bits d'un objet.                  * +*                                                                             * +*  Retour      : Valeur de représentation, unique pour l'objet ou non.        * +*                                                                             * +*  Remarques   : -                                                            * +*                                                                             * +******************************************************************************/ + +static guint g_immediate_operand_hash(const GHashableObject *object) +{ +    guint result;                           /* Valeur à retourner          */ +    GHashableObjectInterface *iface;        /* Interface utilisée          */ +    GHashableObjectInterface *parent_iface; /* Interface parente           */ +    GImmediateOperand *operand;             /* Version spécialisée         */ + +    iface = G_HASHABLE_OBJECT_GET_IFACE(object); + +    parent_iface = g_type_interface_peek_parent(iface); + +    result = parent_iface->hash(object); + +    operand = G_IMMEDIATE_OPERAND(object); + +    result ^= (operand->raw & 0xffffffff); +    result ^= (operand->raw >> 32);      return result;  } + +/* ---------------------------------------------------------------------------------- */ +/*                     MECANISMES DE CONSERVATION ET RESTAURATION                     */ +/* ---------------------------------------------------------------------------------- */ + +  /******************************************************************************  *                                                                             * -*  Paramètres  : operand = structure dont le contenu est à consulter.         * +*  Paramètres  : object  = élément GLib à constuire.                          * +*                storage = conservateur de données à manipuler.               * +*                fd      = flux ouvert en lecture.                            *  *                                                                             * -*  Description : Indique si une valeur immédiate est nulle ou non.            * +*  Description : Charge un objet depuis un flux de données.                   *  *                                                                             * -*  Retour      : true si la valeur est nulle, false sinon.                    * +*  Retour      : Bilan de l'opération.                                        *  *                                                                             *  *  Remarques   : -                                                            *  *                                                                             *  ******************************************************************************/ -bool g_imm_operand_is_null(const GImmOperand *operand) +static bool g_immediate_operand_load(GSerializableObject *object, GObjectStorage *storage, int fd)  { -    return (operand->raw == 0ll); +    bool result;                            /* Bilan à retourner           */ +    GSerializableObjectInterface *iface;    /* Interface utilisée          */ +    GSerializableObjectInterface *parent_iface; /* Interface parente       */ +    uleb128_t val;                          /* Valeur sauvegardée          */ +    GImmediateOperand *operand;             /* Version spécialisée         */ + +    iface = G_SERIALIZABLE_OBJECT_GET_IFACE(object); + +    parent_iface = g_type_interface_peek_parent(iface); + +    result = parent_iface->load(object, storage, fd); + +    if (result) +    { +        result = load_uleb128(&val, fd); + +        if (result) +        { +            operand = G_IMMEDIATE_OPERAND(object); +            operand->raw = val; +        } + +    } + +    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   : -                                                            * +*                                                                             * +******************************************************************************/ + +static bool g_immediate_operand_store(const GSerializableObject *object, GObjectStorage *storage, int fd) +{ +    bool result;                            /* Bilan à retourner           */ +    GSerializableObjectInterface *iface;    /* Interface utilisée          */ +    GSerializableObjectInterface *parent_iface; /* Interface parente       */ +    GImmediateOperand *operand;             /* Version spécialisée         */ + +    iface = G_SERIALIZABLE_OBJECT_GET_IFACE(object); + +    parent_iface = g_type_interface_peek_parent(iface); + +    result = parent_iface->store(object, storage, fd); +    if (!result) goto exit; + +    operand = G_IMMEDIATE_OPERAND(object); + +    result = store_uleb128((uleb128_t []) { operand->raw }, fd); + + exit: + +    return result; + +} + + + +/* ---------------------------------------------------------------------------------- */ +/*                   EXPORTATION SOUS FORME DE CHAINE DE CARACTERES                   */ +/* ---------------------------------------------------------------------------------- */ + + +/****************************************************************************** +*                                                                             *  *  Paramètres  : operand = opérande à transcrire.                             *  *                display = type d'affichage demandé.                          *  *                value   = valeur portée par l'opérande transcrite. [OUT]     * @@ -790,10 +1048,10 @@ bool g_imm_operand_is_null(const GImmOperand *operand)  *                                                                             *  ******************************************************************************/ -static size_t _g_imm_operand_to_string(const GImmOperand *operand, ImmOperandDisplay display, char value[IMM_MAX_SIZE]) +size_t _g_immediate_operand_to_string(const GImmediateOperand *operand, ImmOperandDisplay display, char value[IMM_MAX_SIZE])  {      size_t result;                          /* Longueur à retourner        */ -    immop_extra_data_t *extra;              /* Données insérées à consulter*/ +    immop_extra_data_t extra;               /* Données insérées à consulter*/      unsigned int range;                     /* Catégorie de la taille      */      const char *prefix;                     /* Entrée en matière           */      const char *suffix;                     /* Sortie de matière           */ @@ -813,13 +1071,11 @@ static size_t _g_imm_operand_to_string(const GImmOperand *operand, ImmOperandDis      static const char *conv_si_defs[] = { "", "o", "d", "x", "c" };      static const char *conv_us_defs[] = { "", "o", "u", "x", "c" }; -    assert(display <= IOD_LAST_VALID); +    assert(display < IOD_COUNT);      extra = GET_IMM_OP_EXTRA(operand); -    //LOCK_GOBJECT_EXTRA(extra); - -    range = MDS_RANGE(extra->size); +    range = MDS_RANGE(extra.size);      /* Encadrement pour les caractères */      if (display == IOD_CHAR) @@ -862,10 +1118,10 @@ static size_t _g_imm_operand_to_string(const GImmOperand *operand, ImmOperandDis      if (do_padding)      { -        if (extra->display != IOD_COUNT) -            do_padding = (extra->display != IOD_BIN && extra->display != IOD_HEX); +        if (extra.display != IOD_COUNT) +            do_padding = (extra.display == IOD_BIN || extra.display == IOD_HEX);          else -            do_padding = (extra->def_display != IOD_BIN && extra->def_display != IOD_HEX); +            do_padding = (extra.def_display == IOD_BIN || extra.def_display == IOD_HEX);      }      switch (display) @@ -892,7 +1148,7 @@ static size_t _g_imm_operand_to_string(const GImmOperand *operand, ImmOperandDis      if (display != IOD_BIN)      { -        if (MDS_IS_SIGNED(extra->size)) +        if (MDS_IS_SIGNED(extra.size))              conv = conv_si_defs[display];          else              conv = conv_us_defs[display]; @@ -929,7 +1185,7 @@ static size_t _g_imm_operand_to_string(const GImmOperand *operand, ImmOperandDis      snprintf(format, sizeof(format), "%s%s%s%s%s%s%s", prefix, alternate, intro, zpad, lmod, conv, suffix); -    switch (extra->size) +    switch (extra.size)      {          case MDS_UNDEFINED:              result = snprintf(value, IMM_MAX_SIZE, "<? undef value ?>"); @@ -982,8 +1238,6 @@ static size_t _g_imm_operand_to_string(const GImmOperand *operand, ImmOperandDis      } -    //UNLOCK_GOBJECT_EXTRA(extra); -      assert(result > 0);      return result; @@ -993,555 +1247,37 @@ static size_t _g_imm_operand_to_string(const GImmOperand *operand, ImmOperandDis  /******************************************************************************  *                                                                             * -*  Paramètres  : operand = opérande à transcrire.                             * -*                syntax  = type de représentation demandée.                   * -*                value   = valeur portée par l'opérande transcrite. [OUT]     * +*  Paramètres  : builder = objet dont l'instance est exportable.              * +*                flags   = éventuelles indications pour l'opération.          * +*                out     = chaîne de caractères mise en place. [OUT]          *  *                                                                             * -*  Description : Construit la chaîne de caractères correspondant à l'opérande.* +*  Description : Exporte une chaîne de caractères à partir d'un objet.        *  *                                                                             * -*  Retour      : Nombre de caractères utilisés.                               * +*  Retour      : Bilan de l'opération.                                        *  *                                                                             * -*  Remarques   : -                                                            * +*  Remarques   : La sortie out est à nettoyer avec exit_sized_binary() après  * +*                usage.                                                       *  *                                                                             *  ******************************************************************************/ -size_t g_imm_operand_to_string(const GImmOperand *operand, char value[IMM_MAX_SIZE]) +static bool g_immediate_operand_to_string(const GStringBuilder *builder, unsigned int flags, sized_binary_t *out)  { -    size_t result;                          /* Longueur à retourner        */ +    bool result;                            /* Bilan à retourner           */ +    const GImmediateOperand *operand;       /* Version spécialisée         */      ImmOperandDisplay display;              /* Type d'affichage courant    */ - -    display = g_imm_operand_get_display(operand); - -    result = _g_imm_operand_to_string(operand, display, value); - -    return result; - -} - - -/****************************************************************************** -*                                                                             * -*  Paramètres  : operand = opérande à traiter.                                * -*                line    = ligne tampon où imprimer l'opérande donné.         * -*                                                                             * -*  Description : Traduit un opérande en version humainement lisible.          * -*                                                                             * -*  Retour      : -                                                            * -*                                                                             * -*  Remarques   : -                                                            * -*                                                                             * -******************************************************************************/ - -static void g_imm_operand_print(const GImmOperand *operand, GBufferLine *line) -{      char value[IMM_MAX_SIZE];               /* Chaîne à imprimer           */      size_t len;                             /* Taille de l'élément inséré  */ -    len = g_imm_operand_to_string(operand, value); - -    g_buffer_line_append_text(line, DLC_ASSEMBLY, value, len, RTT_IMMEDIATE, G_OBJECT(operand)); - -} - - -/****************************************************************************** -*                                                                             * -*  Paramètres  : operand = opérande à traiter.                                * -*                pos     = valeur résultante. [OUT]                           * -*                                                                             * -*  Description : Convertit une valeur immédiate en position de type phys_t.   * -*                                                                             * -*  Retour      : Bilan de l'opération.                                        * -*                                                                             * -*  Remarques   : -                                                            * -*                                                                             * -******************************************************************************/ - -bool g_imm_operand_to_phys_t(const GImmOperand *operand, phys_t *pos) -{ -    bool result;                            /* Bilan à renvoyer            */ -    immop_extra_data_t *extra;              /* Données insérées à consulter*/ - -    extra = GET_IMM_OP_EXTRA(operand); - -    LOCK_GOBJECT_EXTRA(extra); - -    result = !MDS_IS_SIGNED(extra->size); - -    if (result) -        *pos = operand->raw; - -    UNLOCK_GOBJECT_EXTRA(extra); - -    return result; - -} - - -/****************************************************************************** -*                                                                             * -*  Paramètres  : operand = opérande à traiter.                                * -*                addr    = valeur résultante. [OUT]                           * -*                                                                             * -*  Description : Convertit une valeur immédiate en adresse de type virt_t.    * -*                                                                             * -*  Retour      : Bilan de l'opération.                                        * -*                                                                             * -*  Remarques   : -                                                            * -*                                                                             * -******************************************************************************/ - -bool g_imm_operand_to_virt_t(const GImmOperand *operand, virt_t *addr) -{ -    bool result;                            /* Bilan à renvoyer            */ -    immop_extra_data_t *extra;              /* Données insérées à consulter*/ - -    extra = GET_IMM_OP_EXTRA(operand); - -    LOCK_GOBJECT_EXTRA(extra); - -    result = !MDS_IS_SIGNED(extra->size); - -    if (result) -        *addr = operand->raw; - -    UNLOCK_GOBJECT_EXTRA(extra); - -    return result; - -} - - -/****************************************************************************** -*                                                                             * -*  Paramètres  : operand = opérande à traiter.                                * -*                val     = valeur résultante. [OUT]                           * -*                                                                             * -*  Description : Convertit une valeur immédiate en valeur de type leb128_t.   * -*                                                                             * -*  Retour      : Bilan de l'opération.                                        * -*                                                                             * -*  Remarques   : -                                                            * -*                                                                             * -******************************************************************************/ - -void g_imm_operand_as_leb128(const GImmOperand *operand, leb128_t *val) -{ -    immop_extra_data_t *extra;              /* Données insérées à consulter*/ - -    extra = GET_IMM_OP_EXTRA(operand); - -    LOCK_GOBJECT_EXTRA(extra); - -    *val = operand->raw; - -    UNLOCK_GOBJECT_EXTRA(extra); - -} - - -/****************************************************************************** -*                                                                             * -*  Paramètres  : operand = opérande à traiter.                                * -*                val     = valeur résultante. [OUT]                           * -*                                                                             * -*  Description : Convertit une valeur immédiate en valeur de type uleb128_t.  * -*                                                                             * -*  Retour      : Bilan de l'opération.                                        * -*                                                                             * -*  Remarques   : -                                                            * -*                                                                             * -******************************************************************************/ - -void g_imm_operand_as_uleb128(const GImmOperand *operand, uleb128_t *val) -{ -    immop_extra_data_t *extra;              /* Données insérées à consulter*/ - -    extra = GET_IMM_OP_EXTRA(operand); - -    LOCK_GOBJECT_EXTRA(extra); - -    *val = operand->raw; - -    UNLOCK_GOBJECT_EXTRA(extra); - -} - - - -/* ---------------------------------------------------------------------------------- */ -/*                       IMPLEMENTATION DES FONCTIONS DE CLASSE                       */ -/* ---------------------------------------------------------------------------------- */ - - -/****************************************************************************** -*                                                                             * -*  Paramètres  : a    = premier opérande à consulter.                         * -*                b    = second opérande à consulter.                          * -*                lock = précise le besoin en verrouillage.                    * -*                                                                             * -*  Description : Compare un opérande avec un autre.                           * -*                                                                             * -*  Retour      : Bilan de la comparaison.                                     * -*                                                                             * -*  Remarques   : -                                                            * -*                                                                             * -******************************************************************************/ - -static int g_imm_operand_compare(const GImmOperand *a, const GImmOperand *b, bool lock) -{ -    int result;                             /* Bilan à retourner           */ -    immop_extra_data_t *ea;                 /* Données insérées à modifier */ -    immop_extra_data_t *eb;                 /* Données insérées à modifier */ -    GArchOperandClass *class;               /* Classe parente normalisée   */ - -    ea = GET_IMM_OP_EXTRA(a); -    eb = GET_IMM_OP_EXTRA(b); - -    if (lock) -    { -        LOCK_GOBJECT_EXTRA(ea); -        LOCK_GOBJECT_EXTRA(eb); -    } - -    result = sort_unsigned_long(ea->size, eb->size); - -    if (result == 0) -        sort_uint64_t(a->raw, b->raw); - -    if (result == 0) -        result = sort_unsigned_long(ea->def_display, eb->def_display); - -    if (result == 0) -        result = sort_unsigned_long(ea->display, eb->display); - -    if (result == 0) -    { -        class = G_ARCH_OPERAND_CLASS(g_imm_operand_parent_class); -        result = class->compare(G_ARCH_OPERAND(a), G_ARCH_OPERAND(b), false); -    } - -    if (lock) -    { -        UNLOCK_GOBJECT_EXTRA(eb); -        UNLOCK_GOBJECT_EXTRA(ea); -    } - -    return result; - -} - - -#ifdef INCLUDE_GTK_SUPPORT - - -/****************************************************************************** -*                                                                             * -*  Paramètres  : operand = opérande à consulter.                              * -*                binary  = informations relatives au binaire chargé.          * -*                                                                             * -*  Description : Construit un petit résumé concis de l'opérande.              * -*                                                                             * -*  Retour      : Chaîne de caractères à libérer après usage ou NULL.          * -*                                                                             * -*  Remarques   : -                                                            * -*                                                                             * -******************************************************************************/ - -static char *g_imm_operand_build_tooltip(const GImmOperand *operand, const GLoadedBinary *binary) -{ -    char *result;                           /* Description à retourner     */ -    char value[IMM_MAX_SIZE];               /* Conversion artificielle     */ -    char *conv;                             /* Affichage de la Conversion  */ - -    if (operand->raw <= UCHAR_MAX && isprint(operand->raw)) -        switch (operand->raw) -        { -            case '&': -                asprintf(&result, _("Character: '&'")); -                break; -            case '<': -                asprintf(&result, _("Character: '<'")); -                break; -            case '>': -                asprintf(&result, _("Character: '>'")); -                break; -            default: -                asprintf(&result, _("Character: '%c'"), (char)operand->raw); -                break; -        } - -    else -        asprintf(&result, _("Character: <not printable>")); - -    /* Binaire */ - -    _g_imm_operand_to_string(operand, IOD_BIN, value); - -    asprintf(&conv, _("Binary: %s"), value); - -    result = stradd(result, "\n"); -    result = stradd(result, conv); - -    free(conv); - -    /* Octal */ - -    _g_imm_operand_to_string(operand, IOD_OCT, value); - -    asprintf(&conv, _("Octal: %s"), value); - -    result = stradd(result, "\n"); -    result = stradd(result, conv); - -    free(conv); - -    /* Décimal */ - -    _g_imm_operand_to_string(operand, IOD_DEC, value); - -    asprintf(&conv, _("Decimal: %s"), value); - -    result = stradd(result, "\n"); -    result = stradd(result, conv); - -    free(conv); - -    /* Hexadécimal */ - -    _g_imm_operand_to_string(operand, IOD_HEX, value); - -    asprintf(&conv, _("Hexadecimal: %s"), value); - -    result = stradd(result, "\n"); -    result = stradd(result, conv); - -    free(conv); - -    return result; - -} - - -#endif - - -/****************************************************************************** -*                                                                             * -*  Paramètres  : operand = objet dont l'instance se veut unique.              * -*                lock    = précise le besoin en verrouillage.                 * -*                                                                             * -*  Description : Fournit l'empreinte d'un candidat à une centralisation.      * -*                                                                             * -*  Retour      : Empreinte de l'élément représenté.                           * -*                                                                             * -*  Remarques   : -                                                            * -*                                                                             * -******************************************************************************/ - -static guint g_imm_operand_hash(const GImmOperand *operand, bool lock) -{ -    guint result;                           /* Valeur à retourner          */ -    immop_extra_data_t *extra;              /* Données insérées à modifier */ -    GArchOperandClass *class;               /* Classe parente normalisée   */ - -    extra = GET_IMM_OP_EXTRA(operand); - -    if (lock) -        LOCK_GOBJECT_EXTRA(extra); - -    class = G_ARCH_OPERAND_CLASS(g_imm_operand_parent_class); -    result = class->hash(G_ARCH_OPERAND(operand), false); - -    result ^= (operand->raw & 0xffffffff); -    result ^= (operand->raw >> 32); - -    if (lock) -        UNLOCK_GOBJECT_EXTRA(extra); - -    return result; - -} - - -/****************************************************************************** -*                                                                             * -*  Paramètres  : operand = élément GLib à constuire.                          * -*                storage = conservateur de données à manipuler ou NULL.       * -*                pbuf    = zone tampon à lire.                                * -*                                                                             * -*  Description : Charge un contenu depuis une mémoire tampon.                 * -*                                                                             * -*  Retour      : Bilan de l'opération.                                        * -*                                                                             * -*  Remarques   : -                                                            * -*                                                                             * -******************************************************************************/ - -static bool g_imm_operand_load(GImmOperand *operand, GObjectStorage *storage, packed_buffer_t *pbuf) -{ -    bool result;                            /* Bilan à retourner           */ -    GArchOperandClass *parent;              /* Classe parente à consulter  */ -    immop_extra_data_t *extra;              /* Données insérées à modifier */ -    uleb128_t value;                        /* Valeur ULEB128 à charger    */ -    uint8_t val;                            /* Champ de bits manipulé      */ - -    parent = G_ARCH_OPERAND_CLASS(g_imm_operand_parent_class); - -    result = parent->load(G_ARCH_OPERAND(operand), storage, pbuf); - -    if (result) -    { -        extra = GET_IMM_OP_EXTRA(operand); - -        LOCK_GOBJECT_EXTRA(extra); - -        result = unpack_uleb128(&value, pbuf); - -        if (result) -            extra->size = value; - -        if (result) -        { -            result = extract_packed_buffer(pbuf, &val, sizeof(uint8_t), false); - -            if (result) -                extra->def_display = val; - -        } - -        if (result) -        { -            result = extract_packed_buffer(pbuf, &val, sizeof(uint8_t), false); - -            if (result) -                extra->display = val; - -        } - -        UNLOCK_GOBJECT_EXTRA(extra); - -    } - -    if (result) -        result = extract_packed_buffer(pbuf, &operand->raw, sizeof(uint64_t), true); - -    return result; - -} - - -/****************************************************************************** -*                                                                             * -*  Paramètres  : operand = élément GLib à consulter.                          * -*                storage = conservateur de données à manipuler ou NULL.       * -*                pbuf    = zone tampon à remplir.                             * -*                                                                             * -*  Description : Sauvegarde un contenu dans une mémoire tampon.               * -*                                                                             * -*  Retour      : Bilan de l'opération.                                        * -*                                                                             * -*  Remarques   : -                                                            * -*                                                                             * -******************************************************************************/ - -static bool g_imm_operand_store(GImmOperand *operand, GObjectStorage *storage, packed_buffer_t *pbuf) -{ -    bool result;                            /* Bilan à retourner           */ -    GArchOperandClass *parent;              /* Classe parente à consulter  */ -    immop_extra_data_t *extra;              /* Données insérées à modifier */ +    operand = G_IMMEDIATE_OPERAND(builder); -    parent = G_ARCH_OPERAND_CLASS(g_imm_operand_parent_class); +    display = g_immediate_operand_get_display(operand); -    result = parent->store(G_ARCH_OPERAND(operand), storage, pbuf); +    len =  _g_immediate_operand_to_string(operand, display, value); -    if (result) -    { -        extra = GET_IMM_OP_EXTRA(operand); - -        LOCK_GOBJECT_EXTRA(extra); - -        result = pack_uleb128((uleb128_t []){ extra->size }, pbuf); - -        if (result) -            result = extend_packed_buffer(pbuf, (uint8_t []) { extra->def_display }, sizeof(uint8_t), false); - -        if (result) -            result = extend_packed_buffer(pbuf, (uint8_t []) { extra->display }, sizeof(uint8_t), false); - -        UNLOCK_GOBJECT_EXTRA(extra); - -    } +    result = (len > 0);      if (result) -        result = extend_packed_buffer(pbuf, &operand->raw, sizeof(uint64_t), true); - -    return result; - -} - - - -/* ---------------------------------------------------------------------------------- */ -/*                        COMMUNICATION D'UN CIBLAGE POTENTIEL                        */ -/* ---------------------------------------------------------------------------------- */ - - -/****************************************************************************** -*                                                                             * -*  Paramètres  : operand = operande à consulter.                              * -*                src     = localisation de l'instruction mère.                * -*                format  = format reconnu pour le binaire chargé.             * -*                proc    = architecture associée à ce même binaire.           * -*                addr    = localisation de la cible. [OUT]                    * -*                                                                             * -*  Description : Obtient l'adresse de la cible visée par un opérande.         * -*                                                                             * -*  Retour      : true si la cible est valide, false sinon.                    * -*                                                                             * -*  Remarques   : -                                                            * -*                                                                             * -******************************************************************************/ - -static bool g_imm_operand_get_addr(const GImmOperand *operand, const vmpa2t *src, GBinFormat *format, GArchProcessor *proc, vmpa2t *addr) -{ -    bool result;                            /* Bilan à retourner           */ -    virt_t virt;                            /* Adresse virtuelle           */ - -    result = g_imm_operand_to_virt_t(operand, &virt); - -    if (result) -        result = g_exe_format_translate_address_into_vmpa(G_EXE_FORMAT(format), virt, addr); - -    return result; - -} - - - -/* ---------------------------------------------------------------------------------- */ -/*                        CONSTRUCTION D'UN CONTENU ALTERNATIF                        */ -/* ---------------------------------------------------------------------------------- */ - - -/****************************************************************************** -*                                                                             * -*  Paramètres  : operand = operande à consulter.                              * -*                text    = texte alternatif de représentation.                * -*                                                                             * -*  Description : Construit un opérande de représentation alternative.         * -*                                                                             * -*  Retour      : Nouvel opérande, en version renommée.                        * -*                                                                             * -*  Remarques   : -                                                            * -*                                                                             * -******************************************************************************/ - -static GRenamedOperand *g_imm_operand_build(const GImmOperand *operand, const char *text) -{ -    GRenamedOperand *result;                /* Instance à retourner        */ - -    result = G_RENAMED_OPERAND(g_known_imm_operand_new(operand, text)); +        add_to_sized_binary(out, value, len);      return result; diff --git a/src/arch/operands/immediate.h b/src/arch/operands/immediate.h index 7c1ff03..d66349a 100644 --- a/src/arch/operands/immediate.h +++ b/src/arch/operands/immediate.h @@ -2,7 +2,7 @@  /* Chrysalide - Outil d'analyse de fichiers binaires   * immediate.h - prototypes pour les opérandes représentant des valeurs numériques   * - * Copyright (C) 2020 Cyrille Bagard + * Copyright (C) 2020-2024 Cyrille Bagard   *   *  This file is part of Chrysalide.   * @@ -25,17 +25,22 @@  #define _ARCH_OPERANDS_IMMEDIATE_H -#include <glib-object.h>  #include <stdbool.h>  #include <stdint.h> -#include "../archbase.h"  #include "../operand.h"  #include "../../analysis/content.h" +#include "../../common/datatypes.h" +#include "../../glibext/helpers.h" +#define G_TYPE_IMMEDIATE_OPERAND (g_immediate_operand_get_type()) + +DECLARE_GTYPE(GImmediateOperand, g_immediate_operand, G, IMMEDIATE_OPERAND); + +  /* Etats particuliers d'un opérande de valeur immédiate */  typedef enum _ImmOpFlag  { @@ -57,86 +62,39 @@ typedef enum _ImmOperandDisplay  } ImmOperandDisplay; -#define IOD_LAST_VALID IOD_CHAR - - -#define G_TYPE_IMM_OPERAND            g_imm_operand_get_type() -#define G_IMM_OPERAND(obj)            (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_IMM_OPERAND, GImmOperand)) -#define G_IS_IMM_OPERAND(obj)         (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_IMM_OPERAND)) -#define G_IMM_OPERAND_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_IMM_OPERAND, GImmOperandClass)) -#define G_IS_IMM_OPERAND_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_IMM_OPERAND)) -#define G_IMM_OPERAND_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_IMM_OPERAND, GImmOperandClass)) - - -/* Définition d'un opérande de valeur numérique (instance) */ -typedef struct _GImmOperand GImmOperand; - -/* Définition d'un opérande de valeur numérique (classe) */ -typedef struct _GImmOperandClass GImmOperandClass; - - -/* Indique le type défini pour un opérande d'architecture. */ -GType g_imm_operand_get_type(void);  /* Crée un opérande réprésentant une valeur numérique. */ -GArchOperand *_g_imm_operand_new_from_data(MemoryDataSize, const GBinContent *, vmpa2t *, bool *, SourceEndian); - -#define g_imm_operand_new_from_data(size, content, addr, endian) \ -    _g_imm_operand_new_from_data(size, content, addr, NULL, endian) +GArchOperand *g_immediate_operand_new_from_value(MemoryDataSize, uint64_t);  /* Crée un opérande réprésentant une valeur numérique. */ -GArchOperand *g_imm_operand_new_from_value(MemoryDataSize, uint64_t); +GArchOperand *g_immediate_operand_new_from_data(MemoryDataSize, const GBinContent *, vmpa2t *, bool *, SourceEndian);  /* Renseigne la taille de la valeur indiquée à la construction. */ -MemoryDataSize g_imm_operand_get_size(const GImmOperand *); +MemoryDataSize g_immediate_operand_get_size(const GImmediateOperand *);  /* Fournit la valeur portée par une opérande numérique. */ -bool g_imm_operand_get_value(const GImmOperand *, MemoryDataSize, ...); +bool g_immediate_operand_get_value(const GImmediateOperand *, MemoryDataSize, ...); + +/* Définit la nouvelle valeur de l'opérande à une valeur. */ +void g_immediate_operand_set_value(GImmediateOperand *, MemoryDataSize, uint64_t);  /* Fournit la valeur brute représentée par l'opérande. */ -uint64_t g_imm_operand_get_raw_value(const GImmOperand *); +uint64_t g_immediate_operand_get_raw_value(const GImmediateOperand *); -/* Définit la nouvelle valeur de l'opérande à une valeur. */ -void g_imm_operand_set_value(GImmOperand *, MemoryDataSize, uint64_t); +/* Indique le signe d'une valeur immédiate. */ +bool g_immediate_operand_is_negative(const GImmediateOperand *);  /* Définit le format textuel par défaut de la valeur. */ -void g_imm_operand_set_default_display(GImmOperand *, ImmOperandDisplay); +void g_immediate_operand_set_default_display(GImmediateOperand *, ImmOperandDisplay);  /* Indique le format textuel par défaut de la valeur. */ -ImmOperandDisplay g_imm_operand_get_default_display(const GImmOperand *); +ImmOperandDisplay g_immediate_operand_get_default_display(const GImmediateOperand *);  /* Définit la grande ligne du format textuel de la valeur. */ -void g_imm_operand_set_display(GImmOperand *, ImmOperandDisplay); +void g_immediate_operand_set_display(GImmediateOperand *, ImmOperandDisplay);  /* Indique la grande ligne du format textuel de la valeur. */ -ImmOperandDisplay g_imm_operand_get_display(const GImmOperand *); - -/* Indique le signe d'une valeur immédiate. */ -bool g_imm_operand_is_negative(const GImmOperand *); - -/* Indique si une valeur immédiate est nulle ou non. */ -bool g_imm_operand_is_null(const GImmOperand *); - -/** - * La taille d'impression d'un opérande n'est pas VMPA_MAX_SIZE, - * mais 1 + 64 caractères + octet nul final en cas d'impression en binaire. - */ -#define IMM_MAX_SIZE 66 - -/* Construit la chaîne de caractères correspondant à l'opérande. */ -size_t g_imm_operand_to_string(const GImmOperand *, char [IMM_MAX_SIZE]); - -/* Convertit une valeur immédiate en position de type phys_t. */ -bool g_imm_operand_to_phys_t(const GImmOperand *, phys_t *); - -/* Convertit une valeur immédiate en adresse de type virt_t. */ -bool g_imm_operand_to_virt_t(const GImmOperand *, virt_t *); - -/* Convertit une valeur immédiate en valeur de type leb128_t. */ -void g_imm_operand_as_leb128(const GImmOperand *, leb128_t *); - -/* Convertit une valeur immédiate en valeur de type uleb128_t. */ -void g_imm_operand_as_uleb128(const GImmOperand *, uleb128_t *); +ImmOperandDisplay g_immediate_operand_get_display(const GImmediateOperand *); diff --git a/src/arch/operands/known-int.h b/src/arch/operands/known-int.h new file mode 100644 index 0000000..021fbf2 --- /dev/null +++ b/src/arch/operands/known-int.h @@ -0,0 +1,55 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * known-int.h - définitions internes pour les opérandes représentant des valeurs numériques avec sémantique + * + * 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 _ARCH_OPERANDS_KNOWN_INT_H +#define _ARCH_OPERANDS_KNOWN_INT_H + + +#include "immediate-int.h" +#include "known.h" + + + +/* Définition d'un remplacement d'opérande de valeur numérique (instance) */ +struct _GKnownImmediateOperand +{ +    GImmediateOperand parent;               /* Instance parente            */ + +    char *alt_text;                         /* Alternative humaine         */ + +}; + +/* Définition d'un remplacement d'opérande de valeur numérique (classe) */ +struct _GKnownImmediateOperandClass +{ +    GImmediateOperandClass parent;          /* Classe parente              */ + +}; + + +/* Met en place un opérande remplaçant visuellement une valeur. */ +bool g_known_immediate_operand_create(GKnownImmediateOperand *, const GImmediateOperand *, const char *); + + + +#endif  /* _ARCH_OPERANDS_KNOWN_INT_H */ diff --git a/src/arch/operands/known-ui.c b/src/arch/operands/known-ui.c new file mode 100644 index 0000000..9b7507a --- /dev/null +++ b/src/arch/operands/known-ui.c @@ -0,0 +1,79 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * known-ui.c - opérandes représentant des valeurs numériques avec sémantique sous forme graphique + * + * 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/>. + */ + + +#include "known-ui.h" + + +#include "known-int.h" +#include "../../common/cpp.h" +#include "../../glibext/options/asm.h" + + + +/* Traduit un opérande en version humainement lisible. */ +static void g_known_immediate_operand_ui_print(const GArchOperandUI *, GBufferLine *); + + + +/****************************************************************************** +*                                                                             * +*  Paramètres  : iface = interface GLib à initialiser.                        * +*                                                                             * +*  Description : Procède à l'initialisation de l'interface d'opérande UI.     * +*                                                                             * +*  Retour      : -                                                            * +*                                                                             * +*  Remarques   : -                                                            * +*                                                                             * +******************************************************************************/ + +void g_known_immediate_operand_ui_arch_operand_ui_iface_init(GArchOperandUIInterface *iface) +{ +    iface->print = g_known_immediate_operand_ui_print; +    iface->build_tooltip = NULL; + +} + + +/****************************************************************************** +*                                                                             * +*  Paramètres  : operand = opérande à traiter.                                * +*                line    = ligne tampon où imprimer l'opérande donné.         * +*                                                                             * +*  Description : Traduit un opérande en version humainement lisible.          * +*                                                                             * +*  Retour      : -                                                            * +*                                                                             * +*  Remarques   : -                                                            * +*                                                                             * +******************************************************************************/ + +static void g_known_immediate_operand_ui_print(const GArchOperandUI *operand, GBufferLine *line) +{ +    GKnownImmediateOperand *known;          /* Version de base             */ + +    known = G_KNOWN_IMMEDIATE_OPERAND(operand); + +    g_buffer_line_append_text(line, ACO_ASSEMBLY, TRT_IMMEDIATE, SL(known->alt_text), NULL, G_OBJECT(operand)); + +} diff --git a/src/arch/operands/known-ui.h b/src/arch/operands/known-ui.h new file mode 100644 index 0000000..fa2dc62 --- /dev/null +++ b/src/arch/operands/known-ui.h @@ -0,0 +1,37 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * known-ui.h - prototypes pour les opérandes représentant des valeurs numériques avec sémantique sous forme graphique + * + * 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 _ARCH_OPERANDS_KNOWN_UI_H +#define _ARCH_OPERANDS_KNOWN_UI_H + + +#include "../operand-ui-int.h" + + + +/* Procède à l'initialisation de l'interface d'opérande UI. */ +void g_known_immediate_operand_ui_arch_operand_ui_iface_init(GArchOperandUIInterface *); + + + +#endif  /* _ARCH_OPERANDS_KNOWN_UI_H */ diff --git a/src/arch/operands/known.c b/src/arch/operands/known.c index 5402879..c9e177f 100644 --- a/src/arch/operands/known.c +++ b/src/arch/operands/known.c @@ -2,7 +2,7 @@  /* Chrysalide - Outil d'analyse de fichiers binaires   * known.c - opérandes représentant des valeurs numériques avec sémantique   * - * Copyright (C) 2020 Cyrille Bagard + * Copyright (C) 2020-2025 Cyrille Bagard   *   *  This file is part of Chrysalide.   * @@ -24,81 +24,80 @@  #include "known.h" -#include <assert.h>  #include <malloc.h>  #include <string.h> -#include "immediate-int.h" -#include "rename-int.h" -#include "../../analysis/db/misc/rlestr.h" -#include "../../core/columns.h" -#include "../../core/logs.h" +#include "known-int.h" +#include "../../common/cpp.h" +#include "../../glibext/comparable-int.h" +#include "../../glibext/hashable-int.h" +#include "../../glibext/serialize-int.h" +#include "../../glibext/strbuilder-int.h"  /* ----------------------- REMPLACEMENT DE VALEURS IMMEDIATES ----------------------- */ -/* Définition d'un remplacement d'opérande de valeur numérique (instance) */ -struct _GKnownImmOperand -{ -    GImmOperand parent;                     /* Instance parente            */ +/* Initialise la classe des remplacements d'opérandes. */ +static void g_known_immediate_operand_class_init(GKnownImmediateOperandClass *); -    char *alt_text;                         /* Alternative humaine         */ +/* Procède à l'initialisation de l'interface de comparaison. */ +static void g_known_immediate_operand_comparable_object_iface_init(GComparableObjectInterface *); -}; +/* Procède à l'initialisation de l'interface de détermination. */ +static void g_known_immediate_operand_hashable_object_iface_init(GHashableObjectInterface *); -/* Définition d'un remplacement d'opérande de valeur numérique (classe) */ -struct _GKnownImmOperandClass -{ -    GImmOperandClass parent;                /* Classe parente              */ +/* Procède à l'initialisation de l'interface de sérialisation. */ +static void g_known_immediate_operand_serializable_object_iface_init(GSerializableObjectInterface *); -}; - - -/* Initialise la classe des remplacements d'opérandes. */ -static void g_known_imm_operand_class_init(GKnownImmOperandClass *); +/* Procède à l'initialisation de l'interface d'exportation. */ +static void g_known_immediate_operand_string_builder_iface_init(GStringBuilderInterface *);  /* Initialise un remplacement d'opérande de valeur immédiate. */ -static void g_known_imm_operand_init(GKnownImmOperand *); - -/* Procède à l'initialisation de l'interface de renommage. */ -static void g_known_imm_operand_renamed_interface_init(GRenamedOperandInterface *); +static void g_known_immediate_operand_init(GKnownImmediateOperand *);  /* Supprime toutes les références externes. */ -static void g_known_imm_operand_dispose(GKnownImmOperand *); +static void g_known_immediate_operand_dispose(GObject *);  /* Procède à la libération totale de la mémoire. */ -static void g_known_imm_operand_finalize(GKnownImmOperand *); +static void g_known_immediate_operand_finalize(GObject *); + + +/* ---------------------- COMPARAISON DETAILLEE DE DEUX OBJETS ---------------------- */ -/* --------------------- IMPLEMENTATION DES FONCTIONS DE CLASSE --------------------- */ +/* Réalise une comparaison étendue entre objets. */ +static int g_known_immediate_operand_compare(const GComparableObject *, const GComparableObject *); -/* Compare un opérande avec un autre. */ -static int g_known_imm_operand_compare(const GKnownImmOperand *, const GKnownImmOperand *, bool); -/* Traduit un opérande en version humainement lisible. */ -static void g_known_imm_operand_print(const GKnownImmOperand *, GBufferLine *); +/* ---------------------- CALCUL D'UNE EMPREINTE DE L'INSTANCE ---------------------- */ -/* Fournit l'empreinte d'un candidat à une centralisation. */ -static guint g_known_imm_operand_hash(const GKnownImmOperand *, bool); -/* Charge un contenu depuis une mémoire tampon. */ -static bool g_known_imm_operand_load(GKnownImmOperand *, GObjectStorage *, packed_buffer_t *); +/* Calcule l'empreinte sur 32 bits d'un objet. */ +static guint g_known_immediate_operand_hash(const GHashableObject *); -/* Sauvegarde un contenu dans une mémoire tampon. */ -static bool g_known_imm_operand_store(GKnownImmOperand *, GObjectStorage *, packed_buffer_t *); +/* ------------------- MECANISMES DE CONSERVATION ET RESTAURATION ------------------- */ -/* ------------------------- AFFICHAGE D'UN CONTENU RENOMME ------------------------- */ +/* Charge un objet depuis un flux de données. */ +static bool g_known_immediate_operand_load(GSerializableObject *, GObjectStorage *, int); -/* Fournit un texte comme représentation alternative d'opérande. */ -static const char *g_known_imm_operand_get_text(const GKnownImmOperand *); +/* Sauvegarde un objet dans un flux de données. */ +static bool g_known_immediate_operand_store(const GSerializableObject *, GObjectStorage *, int); + + + +/* ----------------- EXPORTATION SOUS FORME DE CHAINE DE CARACTERES ----------------- */ + + +/* Exporte une chaîne de caractères à partir d'un objet. */ +static bool g_known_immediate_operand_to_string(const GStringBuilder *, unsigned int, sized_binary_t *); @@ -108,8 +107,12 @@ static const char *g_known_imm_operand_get_text(const GKnownImmOperand *);  /* Indique le type défini pour un remplacemet d'opérande de valeur numérique. */ -G_DEFINE_TYPE_WITH_CODE(GKnownImmOperand, g_known_imm_operand, G_TYPE_IMM_OPERAND, -                        G_IMPLEMENT_INTERFACE(G_TYPE_RENAMED_OPERAND, g_known_imm_operand_renamed_interface_init)); +G_DEFINE_TYPE_WITH_CODE(GKnownImmediateOperand, g_known_immediate_operand, G_TYPE_IMMEDIATE_OPERAND, +                        G_IMPLEMENT_INTERFACE(G_TYPE_COMPARABLE_OBJECT, g_known_immediate_operand_comparable_object_iface_init) +                        G_IMPLEMENT_INTERFACE(G_TYPE_HASHABLE_OBJECT, g_known_immediate_operand_hashable_object_iface_init) +                        G_IMPLEMENT_INTERFACE(G_TYPE_SERIALIZABLE_OBJECT, g_known_immediate_operand_serializable_object_iface_init) +                        G_IMPLEMENT_INTERFACE(G_TYPE_STRING_BUILDER, g_known_immediate_operand_string_builder_iface_init) +                        G_IMPLEMENT_INTERFACE_IF_SYM(g_arch_operand_ui_get_type, g_known_immediate_operand_ui_arch_operand_ui_iface_init));  /****************************************************************************** @@ -124,33 +127,42 @@ G_DEFINE_TYPE_WITH_CODE(GKnownImmOperand, g_known_imm_operand, G_TYPE_IMM_OPERAN  *                                                                             *  ******************************************************************************/ -static void g_known_imm_operand_class_init(GKnownImmOperandClass *klass) +static void g_known_immediate_operand_class_init(GKnownImmediateOperandClass *klass)  {      GObjectClass *object;                   /* Autre version de la classe  */ -    GArchOperandClass *operand;             /* Version de classe parente   */      object = G_OBJECT_CLASS(klass); -    operand = G_ARCH_OPERAND_CLASS(klass); -    object->dispose = (GObjectFinalizeFunc/* ! */)g_known_imm_operand_dispose; -    object->finalize = (GObjectFinalizeFunc)g_known_imm_operand_finalize; +    object->dispose = g_known_immediate_operand_dispose; +    object->finalize = g_known_immediate_operand_finalize; + +} -    operand->compare = (operand_compare_fc)g_known_imm_operand_compare; -    operand->print = (operand_print_fc)g_known_imm_operand_print; -    operand->hash = (operand_hash_fc)g_known_imm_operand_hash; +/****************************************************************************** +*                                                                             * +*  Paramètres  : iface = interface GLib à initialiser.                        * +*                                                                             * +*  Description : Procède à l'initialisation de l'interface de comparaison.    * +*                                                                             * +*  Retour      : -                                                            * +*                                                                             * +*  Remarques   : -                                                            * +*                                                                             * +******************************************************************************/ -    operand->load = (load_operand_fc)g_known_imm_operand_load; -    operand->store = (store_operand_fc)g_known_imm_operand_store; +static void g_known_immediate_operand_comparable_object_iface_init(GComparableObjectInterface *iface) +{ +    iface->compare = g_known_immediate_operand_compare;  }  /******************************************************************************  *                                                                             * -*  Paramètres  : operand = instance à initialiser.                            * +*  Paramètres  : iface = interface GLib à initialiser.                        *  *                                                                             * -*  Description : Initialise un remplacement d'opérande de valeur immédiate.   * +*  Description : Procède à l'initialisation de l'interface de détermination.  *  *                                                                             *  *  Retour      : -                                                            *  *                                                                             * @@ -158,9 +170,9 @@ static void g_known_imm_operand_class_init(GKnownImmOperandClass *klass)  *                                                                             *  ******************************************************************************/ -static void g_known_imm_operand_init(GKnownImmOperand *operand) +static void g_known_immediate_operand_hashable_object_iface_init(GHashableObjectInterface *iface)  { -    operand->alt_text = NULL; +    iface->hash = g_known_immediate_operand_hash;  } @@ -169,7 +181,7 @@ static void g_known_imm_operand_init(GKnownImmOperand *operand)  *                                                                             *  *  Paramètres  : iface = interface GLib à initialiser.                        *  *                                                                             * -*  Description : Procède à l'initialisation de l'interface de renommage.      * +*  Description : Procède à l'initialisation de l'interface de sérialisation.  *  *                                                                             *  *  Retour      : -                                                            *  *                                                                             * @@ -177,18 +189,19 @@ static void g_known_imm_operand_init(GKnownImmOperand *operand)  *                                                                             *  ******************************************************************************/ -static void g_known_imm_operand_renamed_interface_init(GRenamedOperandInterface *iface) +static void g_known_immediate_operand_serializable_object_iface_init(GSerializableObjectInterface *iface)  { -    iface->get_text = (get_renamed_text_fc)g_known_imm_operand_get_text; +    iface->load = g_known_immediate_operand_load; +    iface->store = g_known_immediate_operand_store;  }  /******************************************************************************  *                                                                             * -*  Paramètres  : operand = instance d'objet GLib à traiter.                   * +*  Paramètres  : iface = interface GLib à initialiser.                        *  *                                                                             * -*  Description : Supprime toutes les références externes.                     * +*  Description : Procède à l'initialisation de l'interface d'exportation.     *  *                                                                             *  *  Retour      : -                                                            *  *                                                                             * @@ -196,12 +209,28 @@ static void g_known_imm_operand_renamed_interface_init(GRenamedOperandInterface  *                                                                             *  ******************************************************************************/ -static void g_known_imm_operand_dispose(GKnownImmOperand *operand) +static void g_known_immediate_operand_string_builder_iface_init(GStringBuilderInterface *iface)  { -    if (operand->alt_text != NULL) -        free(operand->alt_text); +    iface->to_string = g_known_immediate_operand_to_string; -    G_OBJECT_CLASS(g_known_imm_operand_parent_class)->dispose(G_OBJECT(operand)); +} + + +/****************************************************************************** +*                                                                             * +*  Paramètres  : operand = instance à initialiser.                            * +*                                                                             * +*  Description : Initialise un remplacement d'opérande de valeur immédiate.   * +*                                                                             * +*  Retour      : -                                                            * +*                                                                             * +*  Remarques   : -                                                            * +*                                                                             * +******************************************************************************/ + +static void g_known_immediate_operand_init(GKnownImmediateOperand *operand) +{ +    operand->alt_text = NULL;  } @@ -210,7 +239,7 @@ static void g_known_imm_operand_dispose(GKnownImmOperand *operand)  *                                                                             *  *  Paramètres  : operand = instance d'objet GLib à traiter.                   *  *                                                                             * -*  Description : Procède à la libération totale de la mémoire.                * +*  Description : Supprime toutes les références externes.                     *  *                                                                             *  *  Retour      : -                                                            *  *                                                                             * @@ -218,180 +247,199 @@ static void g_known_imm_operand_dispose(GKnownImmOperand *operand)  *                                                                             *  ******************************************************************************/ -static void g_known_imm_operand_finalize(GKnownImmOperand *operand) +static void g_known_immediate_operand_dispose(GObject *object)  { -    G_OBJECT_CLASS(g_known_imm_operand_parent_class)->finalize(G_OBJECT(operand)); +    G_OBJECT_CLASS(g_known_immediate_operand_parent_class)->dispose(object);  }  /******************************************************************************  *                                                                             * -*  Paramètres  : old = opérande à venir copier avant son remplacement.        * -*                alt = texte alternatif à présenter pour l'impression.        * +*  Paramètres  : object = instance d'objet GLib à traiter.                    *  *                                                                             * -*  Description : Crée un opérande remplaçant visuellement une valeur.         * +*  Description : Procède à la libération totale de la mémoire.                *  *                                                                             * -*  Retour      : Instruction mise en place.                                   * +*  Retour      : -                                                            *  *                                                                             *  *  Remarques   : -                                                            *  *                                                                             *  ******************************************************************************/ -GArchOperand *g_known_imm_operand_new(const GImmOperand *old, const char *alt) +static void g_known_immediate_operand_finalize(GObject *object)  { -    GKnownImmOperand *result;               /* Remplacement à retourner    */ -    immop_extra_data_t *src;                /* Données insérées à consulter*/ -    immop_extra_data_t *dest;               /* Données insérées à modifier */ +    GKnownImmediateOperand *operand;        /* Version spécialisée         */ -    result = g_object_new(G_TYPE_KNOWN_IMM_OPERAND, NULL); +    operand = G_KNOWN_IMMEDIATE_OPERAND(object); -    result->parent.raw = old->raw; +    if (operand->alt_text != NULL) +        free(operand->alt_text); -    src = GET_IMM_OP_EXTRA(old); -    dest = GET_IMM_OP_EXTRA(&result->parent); +    G_OBJECT_CLASS(g_known_immediate_operand_parent_class)->finalize(object); -    LOCK_GOBJECT_EXTRA(src); +} -    *(&dest->parent) = *(&src->parent); -    dest->size = src->size; +/****************************************************************************** +*                                                                             * +*  Paramètres  : old = opérande à venir copier avant son remplacement.        * +*                alt = texte alternatif à présenter pour l'impression.        * +*                                                                             * +*  Description : Crée un opérande remplaçant visuellement une valeur.         * +*                                                                             * +*  Retour      : Instruction mise en place.                                   * +*                                                                             * +*  Remarques   : -                                                            * +*                                                                             * +******************************************************************************/ -    dest->def_display = src->def_display; -    dest->display = src->display; +GArchOperand *g_known_immediate_operand_new(const GImmediateOperand *old, const char *alt) +{ +    GKnownImmediateOperand *result;         /* Remplacement à retourner    */ -    UNLOCK_GOBJECT_EXTRA(src); +    result = g_object_new(G_TYPE_KNOWN_IMMEDIATE_OPERAND, NULL); -    result->alt_text = strdup(alt); +    if (!g_known_immediate_operand_create(result, old, alt)) +        g_clear_object(&result);      return G_ARCH_OPERAND(result);  } - -/* ---------------------------------------------------------------------------------- */ -/*                       IMPLEMENTATION DES FONCTIONS DE CLASSE                       */ -/* ---------------------------------------------------------------------------------- */ - -  /******************************************************************************  *                                                                             * -*  Paramètres  : a    = premier opérande à consulter.                         * -*                b    = second opérande à consulter.                          * -*                lock = précise le besoin en verrouillage.                    * +*  Paramètres  : operand = instance à initialiser pleinement.                 * +*                old = opérande à venir copier avant son remplacement.        * +*                alt = texte alternatif à présenter pour l'impression.        *  *                                                                             * -*  Description : Compare un opérande avec un autre.                           * +*  Description : Met en place un opérande remplaçant visuellement une valeur. *  *                                                                             * -*  Retour      : Bilan de la comparaison.                                     * +*  Retour      : Bilan de l'opération.                                        *  *                                                                             *  *  Remarques   : -                                                            *  *                                                                             *  ******************************************************************************/ -static int g_known_imm_operand_compare(const GKnownImmOperand *a, const GKnownImmOperand *b, bool lock) +bool g_known_immediate_operand_create(GKnownImmediateOperand *operand, const GImmediateOperand *old, const char *alt)  { -    int result;                             /* Bilan à retourner           */ -    immop_extra_data_t *ea;                 /* Données insérées à consulter*/ -    immop_extra_data_t *eb;                 /* Données insérées à consulter*/ -    GArchOperandClass *class;               /* Classe parente normalisée   */ +    bool result;                            /* Bilan à retourner           */ +    immop_extra_data_t extra;               /* Données insérées à consulter*/ -    ea = GET_IMM_OP_EXTRA(G_IMM_OPERAND(a)); -    eb = GET_IMM_OP_EXTRA(G_IMM_OPERAND(b)); +    result = true; -    if (lock) -    { -        LOCK_GOBJECT_EXTRA(ea); -        LOCK_GOBJECT_EXTRA(eb); -    } +    extra = GET_IMM_OP_EXTRA(old); -    result = strcmp(a->alt_text, b->alt_text); +    SET_IMM_OP_EXTRA(operand, &extra); -    if (result == 0) -    { -        class = G_ARCH_OPERAND_CLASS(g_known_imm_operand_parent_class); -        result = class->compare(G_ARCH_OPERAND(a), G_ARCH_OPERAND(b), false); -    } +    G_IMMEDIATE_OPERAND(operand)->raw = G_IMMEDIATE_OPERAND(old)->raw; -    if (lock) -    { -        UNLOCK_GOBJECT_EXTRA(eb); -        UNLOCK_GOBJECT_EXTRA(ea); -    } +    operand->alt_text = strdup(alt);      return result;  } + +/* ---------------------------------------------------------------------------------- */ +/*                        COMPARAISON DETAILLEE DE DEUX OBJETS                        */ +/* ---------------------------------------------------------------------------------- */ + +  /******************************************************************************  *                                                                             * -*  Paramètres  : operand = opérande à traiter.                                * -*                line    = ligne tampon où imprimer l'opérande donné.         * +*  Paramètres  : object = premier objet à consulter pour une comparaison.     * +*                other  = second objet à consulter pour une comparaison.      *  *                                                                             * -*  Description : Traduit un opérande en version humainement lisible.          * +*  Description : Réalise une comparaison étendue entre objets.                *  *                                                                             * -*  Retour      : -                                                            * +*  Retour      : Bilan de la comparaison.                                     *  *                                                                             *  *  Remarques   : -                                                            *  *                                                                             *  ******************************************************************************/ -static void g_known_imm_operand_print(const GKnownImmOperand *operand, GBufferLine *line) +static int g_known_immediate_operand_compare(const GComparableObject *object, const GComparableObject *other)  { -    size_t len;                             /* Taille de l'élément inséré  */ +    int result;                             /* Bilan à retourner           */ +    GComparableObjectInterface *iface;      /* Interface utilisée          */ +    GComparableObjectInterface *parent_iface; /* Interface parente         */ +    GKnownImmediateOperand *operand_a;      /* Version spécialisée #0      */ +    GKnownImmediateOperand *operand_b;      /* Version spécialisée #1      */ + +    iface = G_COMPARABLE_OBJECT_GET_IFACE(object); -    len = strlen(operand->alt_text); +    parent_iface = g_type_interface_peek_parent(iface); -    g_buffer_line_append_text(line, DLC_ASSEMBLY, operand->alt_text, len, RTT_IMMEDIATE, G_OBJECT(operand)); +    result = parent_iface->compare(object, other); + +    if (result == 0) +    { +        operand_a = G_KNOWN_IMMEDIATE_OPERAND(object); +        operand_b = G_KNOWN_IMMEDIATE_OPERAND(other); + +        result = strcmp(operand_a->alt_text, operand_b->alt_text); + +    } + +    return result;  } +/* ---------------------------------------------------------------------------------- */ +/*                        CALCUL D'UNE EMPREINTE DE L'INSTANCE                        */ +/* ---------------------------------------------------------------------------------- */ + +  /******************************************************************************  *                                                                             * -*  Paramètres  : operand = objet dont l'instance se veut unique.              * -*                lock    = précise le besoin en verrouillage.                 * +*  Paramètres  : object = objet dont l'instance est à consulter.              *  *                                                                             * -*  Description : Fournit l'empreinte d'un candidat à une centralisation.      * +*  Description : Calcule l'empreinte sur 32 bits d'un objet.                  *  *                                                                             * -*  Retour      : Empreinte de l'élément représenté.                           * +*  Retour      : Valeur de représentation, unique pour l'objet ou non.        *  *                                                                             *  *  Remarques   : -                                                            *  *                                                                             *  ******************************************************************************/ -static guint g_known_imm_operand_hash(const GKnownImmOperand *operand, bool lock) +static guint g_known_immediate_operand_hash(const GHashableObject *object)  {      guint result;                           /* Valeur à retourner          */ -    immop_extra_data_t *extra;              /* Données insérées à consulter*/ -    GArchOperandClass *class;               /* Classe parente normalisée   */ +    GHashableObjectInterface *iface;        /* Interface utilisée          */ +    GHashableObjectInterface *parent_iface; /* Interface parente           */ +    GKnownImmediateOperand *operand;        /* Version spécialisée         */ -    extra = GET_IMM_OP_EXTRA(G_IMM_OPERAND(operand)); +    iface = G_HASHABLE_OBJECT_GET_IFACE(object); -    if (lock) -        LOCK_GOBJECT_EXTRA(extra); +    parent_iface = g_type_interface_peek_parent(iface); -    class = G_ARCH_OPERAND_CLASS(g_known_imm_operand_parent_class); -    result = class->hash(G_ARCH_OPERAND(operand), false); +    result = parent_iface->hash(object); -    result ^= g_str_hash(operand->alt_text); +    operand = G_KNOWN_IMMEDIATE_OPERAND(object); -    if (lock) -        UNLOCK_GOBJECT_EXTRA(extra); +    result ^= g_str_hash(operand->alt_text);      return result;  } + +/* ---------------------------------------------------------------------------------- */ +/*                     MECANISMES DE CONSERVATION ET RESTAURATION                     */ +/* ---------------------------------------------------------------------------------- */ + +  /******************************************************************************  *                                                                             * -*  Paramètres  : operand = élément GLib à constuire.                          * -*                storage = conservateur de données à manipuler ou NULL.       * -*                pbuf    = zone tampon à lire.                                * +*  Paramètres  : object  = élément GLib à constuire.                          * +*                storage = conservateur de données à manipuler.               * +*                fd      = flux ouvert en lecture.                            *  *                                                                             * -*  Description : Charge un contenu depuis une mémoire tampon.                 * +*  Description : Charge un objet depuis un flux de données.                   *  *                                                                             *  *  Retour      : Bilan de l'opération.                                        *  *                                                                             * @@ -399,30 +447,31 @@ static guint g_known_imm_operand_hash(const GKnownImmOperand *operand, bool lock  *                                                                             *  ******************************************************************************/ -static bool g_known_imm_operand_load(GKnownImmOperand *operand, GObjectStorage *storage, packed_buffer_t *pbuf) +static bool g_known_immediate_operand_load(GSerializableObject *object, GObjectStorage *storage, int fd)  {      bool result;                            /* Bilan à retourner           */ -    GArchOperandClass *parent;              /* Classe parente à consulter  */ -    rle_string str;                         /* Chaîne à charger            */ +    GSerializableObjectInterface *iface;    /* Interface utilisée          */ +    GSerializableObjectInterface *parent_iface; /* Interface parente       */ +    sized_binary_t str;                     /* Texte alternatif rechargé   */ +    GKnownImmediateOperand *operand;        /* Version spécialisée         */ + +    iface = G_SERIALIZABLE_OBJECT_GET_IFACE(object); -    parent = G_ARCH_OPERAND_CLASS(g_known_imm_operand_parent_class); +    parent_iface = g_type_interface_peek_parent(iface); -    result = parent->load(G_ARCH_OPERAND(operand), storage, pbuf); +    result = parent_iface->load(object, storage, fd);      if (result)      { -        setup_empty_rle_string(&str); +        init_sized_binary(&str); -        result = unpack_rle_string(&str, pbuf); +        load_sized_binary_as_string(&str, fd); -        if (result) -        { -            if (get_rle_string(&str) != NULL) -                operand->alt_text = strdup(get_rle_string(&str)); +        operand = G_KNOWN_IMMEDIATE_OPERAND(object); -            exit_rle_string(&str); +        operand->alt_text = strdup(str.static_data); -        } +        exit_sized_binary(&str);      } @@ -433,11 +482,11 @@ static bool g_known_imm_operand_load(GKnownImmOperand *operand, GObjectStorage *  /******************************************************************************  *                                                                             * -*  Paramètres  : operand = élément GLib à consulter.                          * -*                storage = conservateur de données à manipuler ou NULL.       * -*                pbuf    = zone tampon à remplir.                             * +*  Paramètres  : object  = élément GLib à consulter.                          * +*                storage = conservateur de données à manipuler.               * +*                fd      = flux ouvert en écriture.                           *  *                                                                             * -*  Description : Sauvegarde un contenu dans une mémoire tampon.               * +*  Description : Sauvegarde un objet dans un flux de données.                 *  *                                                                             *  *  Retour      : Bilan de l'opération.                                        *  *                                                                             * @@ -445,54 +494,64 @@ static bool g_known_imm_operand_load(GKnownImmOperand *operand, GObjectStorage *  *                                                                             *  ******************************************************************************/ -static bool g_known_imm_operand_store(GKnownImmOperand *operand, GObjectStorage *storage, packed_buffer_t *pbuf) +static bool g_known_immediate_operand_store(const GSerializableObject *object, GObjectStorage *storage, int fd)  {      bool result;                            /* Bilan à retourner           */ -    GArchOperandClass *parent;              /* Classe parente à consulter  */ -    rle_string str;                         /* Chaîne à conserver          */ +    GSerializableObjectInterface *iface;    /* Interface utilisée          */ +    GSerializableObjectInterface *parent_iface; /* Interface parente       */ +    GKnownImmediateOperand *operand;        /* Version spécialisée         */ +    sized_binary_t str;                     /* Texte alternatif à conserver*/ -    parent = G_ARCH_OPERAND_CLASS(g_known_imm_operand_parent_class); +    iface = G_SERIALIZABLE_OBJECT_GET_IFACE(object); -    result = parent->store(G_ARCH_OPERAND(operand), storage, pbuf); +    parent_iface = g_type_interface_peek_parent(iface); -    if (result) -    { -        init_static_rle_string(&str, operand->alt_text); +    result = parent_iface->store(object, storage, fd); +    if (!result) goto exit; -        result = pack_rle_string(&str, pbuf); +    operand = G_KNOWN_IMMEDIATE_OPERAND(object); -        exit_rle_string(&str); +    setup_sized_binary_from_static_string(&str, operand->alt_text); -    } +    result = store_sized_binary_as_string(&str, fd); + + exit:      return result;  } -  /* ---------------------------------------------------------------------------------- */ -/*                           AFFICHAGE D'UN CONTENU RENOMME                           */ +/*                   EXPORTATION SOUS FORME DE CHAINE DE CARACTERES                   */  /* ---------------------------------------------------------------------------------- */  /******************************************************************************  *                                                                             * -*  Paramètres  : operand = operande à consulter.                              * +*  Paramètres  : builder = objet dont l'instance est exportable.              * +*                flags   = éventuelles indications pour l'opération.          * +*                out     = chaîne de caractères mise en place. [OUT]          *  *                                                                             * -*  Description : Fournit un texte comme représentation alternative d'opérande.* +*  Description : Exporte une chaîne de caractères à partir d'un objet.        *  *                                                                             * -*  Retour      : Chaîne de caractère de représentation alternative.           * +*  Retour      : Bilan de l'opération.                                        *  *                                                                             * -*  Remarques   : -                                                            * +*  Remarques   : La sortie out est à nettoyer avec exit_sized_binary() après  * +*                usage.                                                       *  *                                                                             *  ******************************************************************************/ -static const char *g_known_imm_operand_get_text(const GKnownImmOperand *operand) +static bool g_known_immediate_operand_to_string(const GStringBuilder *builder, unsigned int flags, sized_binary_t *out)  { -    const char *result;                     /* Texte à retourner           */ +    bool result;                            /* Bilan à retourner           */ +    const GKnownImmediateOperand *operand;  /* Version spécialisée         */ + +    result = true; + +    operand = G_KNOWN_IMMEDIATE_OPERAND(builder); -    result = operand->alt_text; +    add_to_sized_binary(out, operand->alt_text, strlen(operand->alt_text));      return result; diff --git a/src/arch/operands/known.h b/src/arch/operands/known.h index eb84d3b..a8b563f 100644 --- a/src/arch/operands/known.h +++ b/src/arch/operands/known.h @@ -2,7 +2,7 @@  /* Chrysalide - Outil d'analyse de fichiers binaires   * known.h - prototypes pour les opérandes représentant des valeurs numériques avec sémantique   * - * Copyright (C) 2021 Cyrille Bagard + * Copyright (C) 2021-2025 Cyrille Bagard   *   *  This file is part of Chrysalide.   * @@ -25,34 +25,18 @@  #define _ARCH_OPERANDS_KNOWN_H -#include <glib-object.h> - -  #include "immediate.h" -#include "../operand.h" - - - -#define G_TYPE_KNOWN_IMM_OPERAND            g_known_imm_operand_get_type() -#define G_KNOWN_IMM_OPERAND(obj)            (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_KNOWN_IMM_OPERAND, GKnownImmOperand)) -#define G_IS_KNOWN_IMM_OPERAND(obj)         (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_KNOWN_IMM_OPERAND)) -#define G_KNOWN_IMM_OPERAND_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_KNOWN_IMM_OPERAND, GKnownImmOperandClass)) -#define G_IS_KNOWN_IMM_OPERAND_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_KNOWN_IMM_OPERAND)) -#define G_KNOWN_IMM_OPERAND_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_KNOWN_IMM_OPERAND, GKnownImmOperandClass)) +#include "../../glibext/helpers.h" -/* Définition d'un remplacement d'opérande de valeur numérique (instance) */ -typedef struct _GKnownImmOperand GKnownImmOperand; -/* Définition d'un remplacement d'opérande de valeur numérique (classe) */ -typedef struct _GKnownImmOperandClass GKnownImmOperandClass; +#define G_TYPE_KNOWN_IMMEDIATE_OPERAND (g_known_immediate_operand_get_type()) +DECLARE_GTYPE(GKnownImmediateOperand, g_known_immediate_operand, G, KNOWN_IMMEDIATE_OPERAND); -/* Indique le type défini pour un remplacemet d'opérande de valeur numérique. */ -GType g_known_imm_operand_get_type(void);  /* Crée un opérande remplaçant visuellement une valeur. */ -GArchOperand *g_known_imm_operand_new(const GImmOperand *, const char *); +GArchOperand *g_known_immediate_operand_new(const GImmediateOperand *, const char *); diff --git a/src/arch/operands/register-int.h b/src/arch/operands/register-int.h index a887567..93cf025 100644 --- a/src/arch/operands/register-int.h +++ b/src/arch/operands/register-int.h @@ -26,8 +26,6 @@  #include "register.h" - -  #include "../operand-int.h" @@ -49,5 +47,9 @@ struct _GRegisterOperandClass  }; +/* Met en place un opérande réprésentant une valeur numérique. */ +bool g_register_operand_create(GRegisterOperand *, GArchRegister *); + +  #endif  /* _ARCH_OPERANDS_REGISTER_INT_H */ diff --git a/src/arch/operands/register-ui.c b/src/arch/operands/register-ui.c new file mode 100644 index 0000000..513a24f --- /dev/null +++ b/src/arch/operands/register-ui.c @@ -0,0 +1,93 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * register-ui.c - opérandes représentant des registres sous forme graphique + * + * 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/>. + */ + + +#include "register-ui.h" + + +#include "register.h" +#include "../../glibext/strbuilder.h" +#include "../../glibext/options/asm.h" + + + +/* Traduit un opérande en version humainement lisible. */ +static void g_register_operand_ui_print(const GArchOperandUI *, GBufferLine *); + + + +/****************************************************************************** +*                                                                             * +*  Paramètres  : iface = interface GLib à initialiser.                        * +*                                                                             * +*  Description : Procède à l'initialisation de l'interface d'opérande UI.     * +*                                                                             * +*  Retour      : -                                                            * +*                                                                             * +*  Remarques   : -                                                            * +*                                                                             * +******************************************************************************/ + +void g_register_operand_ui_arch_operand_ui_iface_init(GArchOperandUIInterface *iface) +{ +    iface->print = g_register_operand_ui_print; +    iface->build_tooltip = NULL; + +} + + +/****************************************************************************** +*                                                                             * +*  Paramètres  : operand = opérande à traiter.                                * +*                line    = ligne tampon où imprimer l'opérande donné.         * +*                                                                             * +*  Description : Traduit un opérande en version humainement lisible.          * +*                                                                             * +*  Retour      : -                                                            * +*                                                                             * +*  Remarques   : -                                                            * +*                                                                             * +******************************************************************************/ + +static void g_register_operand_ui_print(const GArchOperandUI *operand, GBufferLine *line) +{ +    GStringBuilder *builder;                /* Autre version de l'opérande */ +    sized_binary_t str;                     /* Chaîne équivalente produite */ +    bool status;                            /* Bilan d'une conversion      */ + +    builder = G_STRING_BUILDER(operand); + +    init_sized_binary(&str); + +    status = g_string_builder_to_string(builder, 0 /* flags */, &str); + +    if (status) +        g_buffer_line_append_text(line, ACO_ASSEMBLY, TRT_REGISTER, +                                  str.static_data, str.size, NULL, G_OBJECT(operand)); + +    else +        g_buffer_line_append_text(line, ACO_ASSEMBLY, TRT_REGISTER, +                                  "??", 2, NULL, G_OBJECT(operand)); + +    exit_sized_binary(&str); + +} diff --git a/src/arch/operands/register-ui.h b/src/arch/operands/register-ui.h new file mode 100644 index 0000000..16be67b --- /dev/null +++ b/src/arch/operands/register-ui.h @@ -0,0 +1,37 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * register-ui.h - prototypes pour les opérandes représentant des registres sous forme graphique + * + * 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 _ARCH_OPERANDS_REGISTER_UI_H +#define _ARCH_OPERANDS_REGISTER_UI_H + + +#include "../operand-ui-int.h"      // FIXME ?? + + + +/* Procède à l'initialisation de l'interface d'opérande UI. */ +void g_register_operand_ui_arch_operand_ui_iface_init(GArchOperandUIInterface *); + + + +#endif  /* _ARCH_OPERANDS_REGISTER_UI_H */ diff --git a/src/arch/operands/register.c b/src/arch/operands/register.c index 4615a99..cad2c4e 100644 --- a/src/arch/operands/register.c +++ b/src/arch/operands/register.c @@ -28,7 +28,10 @@  #include "register-int.h" -#include "../storage.h" +#include "../../glibext/comparable-int.h" +#include "../../glibext/hashable-int.h" +#include "../../glibext/serialize-int.h" +#include "../../glibext/strbuilder-int.h" @@ -38,34 +41,61 @@  /* Initialise la classe des opérandes de registre. */  static void g_register_operand_class_init(GRegisterOperandClass *); +/* Procède à l'initialisation de l'interface de comparaison. */ +static void g_register_operand_comparable_object_iface_init(GComparableObjectInterface *); + +/* Procède à l'initialisation de l'interface de détermination. */ +static void g_register_operand_hashable_object_iface_init(GHashableObjectInterface *); + +/* Procède à l'initialisation de l'interface de sérialisation. */ +static void g_register_operand_serializable_object_iface_init(GSerializableObjectInterface *); + +/* Procède à l'initialisation de l'interface d'exportation. */ +static void g_register_operand_string_builder_iface_init(GStringBuilderInterface *); +  /* Initialise une instance d'opérande de registre. */  static void g_register_operand_init(GRegisterOperand *);  /* Supprime toutes les références externes. */ -static void g_register_operand_dispose(GRegisterOperand *); +static void g_register_operand_dispose(GObject *);  /* Procède à la libération totale de la mémoire. */ -static void g_register_operand_finalize(GRegisterOperand *); +static void g_register_operand_finalize(GObject *); + + + +/* ---------------------- COMPARAISON DETAILLEE DE DEUX OBJETS ---------------------- */ + + +/* Réalise une comparaison étendue entre objets. */ +static int g_register_operand_compare(const GComparableObject *, const GComparableObject *); + +/* ---------------------- CALCUL D'UNE EMPREINTE DE L'INSTANCE ---------------------- */ -/* --------------------- IMPLEMENTATION DES FONCTIONS DE CLASSE --------------------- */ +/* Calcule l'empreinte sur 32 bits d'un objet. */ +static guint g_register_operand_hash(const GHashableObject *); -/* Compare un opérande avec un autre. */ -static int g_register_operand_compare(const GRegisterOperand *, const GRegisterOperand *, bool); -/* Traduit un opérande en version humainement lisible. */ -static void g_register_operand_print(const GRegisterOperand *, GBufferLine *); -/* Fournit l'empreinte d'un candidat à une centralisation. */ -static guint g_register_operand_hash(const GRegisterOperand *, bool); +/* ------------------- MECANISMES DE CONSERVATION ET RESTAURATION ------------------- */ -/* Charge un contenu depuis une mémoire tampon. */ -static bool g_register_operand_load(GRegisterOperand *, GObjectStorage *, packed_buffer_t *); -/* Sauvegarde un contenu dans une mémoire tampon. */ -static bool g_register_operand_store(GRegisterOperand *, GObjectStorage *, packed_buffer_t *); +/* Charge un objet depuis un flux de données. */ +static bool g_register_operand_load(GSerializableObject *, GObjectStorage *, int); + +/* Sauvegarde un objet dans un flux de données. */ +static bool g_register_operand_store(const GSerializableObject *, GObjectStorage *, int); + + + +/* ----------------- EXPORTATION SOUS FORME DE CHAINE DE CARACTERES ----------------- */ + + +/* Exporte une chaîne de caractères à partir d'un objet. */ +static bool g_register_operand_to_string(const GStringBuilder *, unsigned int, sized_binary_t *); @@ -75,7 +105,12 @@ static bool g_register_operand_store(GRegisterOperand *, GObjectStorage *, packe  /* Indique le type défini par la GLib pour un opérande de registre Dalvik. */ -G_DEFINE_TYPE(GRegisterOperand, g_register_operand, G_TYPE_ARCH_OPERAND); +G_DEFINE_TYPE_WITH_CODE(GRegisterOperand, g_register_operand, G_TYPE_ARCH_OPERAND, +                        G_IMPLEMENT_INTERFACE(G_TYPE_COMPARABLE_OBJECT, g_register_operand_comparable_object_iface_init) +                        G_IMPLEMENT_INTERFACE(G_TYPE_HASHABLE_OBJECT, g_register_operand_hashable_object_iface_init) +                        G_IMPLEMENT_INTERFACE(G_TYPE_SERIALIZABLE_OBJECT, g_register_operand_serializable_object_iface_init) +                        G_IMPLEMENT_INTERFACE(G_TYPE_STRING_BUILDER, g_register_operand_string_builder_iface_init) +                        G_IMPLEMENT_INTERFACE_IF_SYM(g_arch_operand_ui_get_type, g_register_operand_ui_arch_operand_ui_iface_init));  /****************************************************************************** @@ -93,23 +128,88 @@ G_DEFINE_TYPE(GRegisterOperand, g_register_operand, G_TYPE_ARCH_OPERAND);  static void g_register_operand_class_init(GRegisterOperandClass *klass)  {      GObjectClass *object;                   /* Autre version de la classe  */ -    GArchOperandClass *operand;             /* Version de classe parente   */      object = G_OBJECT_CLASS(klass); -    operand = G_ARCH_OPERAND_CLASS(klass); -    object->dispose = (GObjectFinalizeFunc/* ! */)g_register_operand_dispose; -    object->finalize = (GObjectFinalizeFunc)g_register_operand_finalize; +    object->dispose = g_register_operand_dispose; +    object->finalize = g_register_operand_finalize; -    operand = G_ARCH_OPERAND_CLASS(klass); +} -    operand->compare = (operand_compare_fc)g_register_operand_compare; -    operand->print = (operand_print_fc)g_register_operand_print; -    operand->hash = (operand_hash_fc)g_register_operand_hash; +/****************************************************************************** +*                                                                             * +*  Paramètres  : iface = interface GLib à initialiser.                        * +*                                                                             * +*  Description : Procède à l'initialisation de l'interface de comparaison.    * +*                                                                             * +*  Retour      : -                                                            * +*                                                                             * +*  Remarques   : -                                                            * +*                                                                             * +******************************************************************************/ -    operand->load = (load_operand_fc)g_register_operand_load; -    operand->store = (store_operand_fc)g_register_operand_store; +static void g_register_operand_comparable_object_iface_init(GComparableObjectInterface *iface) +{ +    iface->compare = g_register_operand_compare; + +} + + +/****************************************************************************** +*                                                                             * +*  Paramètres  : iface = interface GLib à initialiser.                        * +*                                                                             * +*  Description : Procède à l'initialisation de l'interface de détermination.  * +*                                                                             * +*  Retour      : -                                                            * +*                                                                             * +*  Remarques   : -                                                            * +*                                                                             * +******************************************************************************/ + +static void g_register_operand_hashable_object_iface_init(GHashableObjectInterface *iface) +{ +    iface->hash = g_register_operand_hash; + +} + + +/****************************************************************************** +*                                                                             * +*  Paramètres  : iface = interface GLib à initialiser.                        * +*                                                                             * +*  Description : Procède à l'initialisation de l'interface de sérialisation.  * +*                                                                             * +*  Retour      : -                                                            * +*                                                                             * +*  Remarques   : -                                                            * +*                                                                             * +******************************************************************************/ + +static void g_register_operand_serializable_object_iface_init(GSerializableObjectInterface *iface) +{ +    iface->load = g_register_operand_load; +    iface->store = g_register_operand_store; + +} + + +/****************************************************************************** +*                                                                             * +*  Paramètres  : iface = interface GLib à initialiser.                        * +*                                                                             * +*  Description : Procède à l'initialisation de l'interface d'exportation.     * +*                                                                             * +*  Retour      : -                                                            * +*                                                                             * +*  Remarques   : -                                                            * +*                                                                             * +******************************************************************************/ + +static void g_register_operand_string_builder_iface_init(GStringBuilderInterface *iface) +{ +    iface->to_string = g_register_operand_to_string;  } @@ -135,7 +235,7 @@ static void g_register_operand_init(GRegisterOperand *operand)  /******************************************************************************  *                                                                             * -*  Paramètres  : binary = instance d'objet GLib à traiter.                    * +*  Paramètres  : object = instance d'objet GLib à traiter.                    *  *                                                                             *  *  Description : Supprime toutes les références externes.                     *  *                                                                             * @@ -145,18 +245,22 @@ static void g_register_operand_init(GRegisterOperand *operand)  *                                                                             *  ******************************************************************************/ -static void g_register_operand_dispose(GRegisterOperand *operand) +static void g_register_operand_dispose(GObject *object)  { +    GRegisterOperand *operand;              /* Version spécialisée         */ + +    operand = G_REGISTER_OPERAND(object); +      g_clear_object(&operand->reg); -    G_OBJECT_CLASS(g_register_operand_parent_class)->dispose(G_OBJECT(operand)); +    G_OBJECT_CLASS(g_register_operand_parent_class)->dispose(object);  }  /******************************************************************************  *                                                                             * -*  Paramètres  : binary = instance d'objet GLib à traiter.                    * +*  Paramètres  : object = instance d'objet GLib à traiter.                    *  *                                                                             *  *  Description : Procède à la libération totale de la mémoire.                *  *                                                                             * @@ -166,9 +270,36 @@ static void g_register_operand_dispose(GRegisterOperand *operand)  *                                                                             *  ******************************************************************************/ -static void g_register_operand_finalize(GRegisterOperand *operand) +static void g_register_operand_finalize(GObject *object) +{ +    G_OBJECT_CLASS(g_register_operand_parent_class)->finalize(object); + +} + + +/****************************************************************************** +*                                                                             * +*  Paramètres  : operand = instance à initialiser pleinement.                 * +*                reg     = registre matériel à représenter.                   * +*                                                                             * +*  Description : Met en place un opérande réprésentant une valeur numérique.  * +*                                                                             * +*  Retour      : Bilan de l'opération.                                        * +*                                                                             * +*  Remarques   : -                                                            * +*                                                                             * +******************************************************************************/ + +bool g_register_operand_create(GRegisterOperand *operand, GArchRegister *reg)  { -    G_OBJECT_CLASS(g_register_operand_parent_class)->finalize(G_OBJECT(operand)); +    bool result;                            /* Bilan à retourner           */ + +    result = true; + +    operand->reg = reg; +    ref_object(reg); + +    return result;  } @@ -190,8 +321,7 @@ GArchRegister *g_register_operand_get_register(const GRegisterOperand *operand)      GArchRegister *result;                  /* Instance à retourner        */      result = operand->reg; - -    g_object_ref(G_OBJECT(result)); +    ref_object(result);      return result; @@ -200,17 +330,16 @@ GArchRegister *g_register_operand_get_register(const GRegisterOperand *operand)  /* ---------------------------------------------------------------------------------- */ -/*                       IMPLEMENTATION DES FONCTIONS DE CLASSE                       */ +/*                        COMPARAISON DETAILLEE DE DEUX OBJETS                        */  /* ---------------------------------------------------------------------------------- */  /******************************************************************************  *                                                                             * -*  Paramètres  : a    = premier opérande à consulter.                         * -*                b    = second opérande à consulter.                          * -*                lock = précise le besoin en verrouillage.                    * +*  Paramètres  : object = premier objet à consulter pour une comparaison.     * +*                other  = second objet à consulter pour une comparaison.      *  *                                                                             * -*  Description : Compare un opérande avec un autre.                           * +*  Description : Réalise une comparaison étendue entre objets.                *  *                                                                             *  *  Retour      : Bilan de la comparaison.                                     *  *                                                                             * @@ -218,17 +347,25 @@ GArchRegister *g_register_operand_get_register(const GRegisterOperand *operand)  *                                                                             *  ******************************************************************************/ -static int g_register_operand_compare(const GRegisterOperand *a, const GRegisterOperand *b, bool lock) +static int g_register_operand_compare(const GComparableObject *object, const GComparableObject *other)  {      int result;                             /* Bilan à retourner           */ -    GArchOperandClass *class;               /* Classe parente normalisée   */ +    GComparableObjectInterface *iface;      /* Interface utilisée          */ +    GComparableObjectInterface *parent_iface; /* Interface parente         */ +    GRegisterOperand *operand;              /* Version spécialisée         */ + +    iface = G_COMPARABLE_OBJECT_GET_IFACE(object); -    result = g_arch_register_compare(a->reg, b->reg); +    parent_iface = g_type_interface_peek_parent(iface); + +    result = parent_iface->compare(object, other);      if (result == 0)      { -        class = G_ARCH_OPERAND_CLASS(g_register_operand_parent_class); -        result = class->compare(G_ARCH_OPERAND(a), G_ARCH_OPERAND(b), false); +        operand = G_REGISTER_OPERAND(object); + +        result = g_comparable_object_compare(G_COMPARABLE_OBJECT(operand->reg), other); +      }      return result; @@ -236,53 +373,96 @@ static int g_register_operand_compare(const GRegisterOperand *a, const GRegister  } + +/* ---------------------------------------------------------------------------------- */ +/*                        CALCUL D'UNE EMPREINTE DE L'INSTANCE                        */ +/* ---------------------------------------------------------------------------------- */ + +  /******************************************************************************  *                                                                             * -*  Paramètres  : operand = opérande à traiter.                                * -*                line    = ligne tampon où imprimer l'opérande donné.         * +*  Paramètres  : object = objet dont l'instance est à consulter.              *  *                                                                             * -*  Description : Traduit un opérande en version humainement lisible.          * +*  Description : Calcule l'empreinte sur 32 bits d'un objet.                  *  *                                                                             * -*  Retour      : -                                                            * +*  Retour      : Valeur de représentation, unique pour l'objet ou non.        *  *                                                                             *  *  Remarques   : -                                                            *  *                                                                             *  ******************************************************************************/ -static void g_register_operand_print(const GRegisterOperand *operand, GBufferLine *line) +static guint g_register_operand_hash(const GHashableObject *object)  { -    g_arch_register_print(operand->reg, line); +    guint result;                           /* Valeur à retourner          */ +    GHashableObjectInterface *iface;        /* Interface utilisée          */ +    GHashableObjectInterface *parent_iface; /* Interface parente           */ +    GRegisterOperand *operand;              /* Version spécialisée         */ + +    iface = G_HASHABLE_OBJECT_GET_IFACE(object); + +    parent_iface = g_type_interface_peek_parent(iface); + +    result = parent_iface->hash(object); + +    operand = G_REGISTER_OPERAND(object); + +    result ^= g_hashable_object_hash(G_HASHABLE_OBJECT(operand->reg)); + +    return result;  } + +/* ---------------------------------------------------------------------------------- */ +/*                     MECANISMES DE CONSERVATION ET RESTAURATION                     */ +/* ---------------------------------------------------------------------------------- */ + +  /******************************************************************************  *                                                                             * -*  Paramètres  : operand = objet dont l'instance se veut unique.              * -*                lock    = précise le besoin en verrouillage.                 * +*  Paramètres  : object  = élément GLib à constuire.                          * +*                storage = conservateur de données à manipuler.               * +*                fd      = flux ouvert en lecture.                            *  *                                                                             * -*  Description : Fournit l'empreinte d'un candidat à une centralisation.      * +*  Description : Charge un objet depuis un flux de données.                   *  *                                                                             * -*  Retour      : Empreinte de l'élément représenté.                           * +*  Retour      : Bilan de l'opération.                                        *  *                                                                             *  *  Remarques   : -                                                            *  *                                                                             *  ******************************************************************************/ -static guint g_register_operand_hash(const GRegisterOperand *operand, bool lock) +static bool g_register_operand_load(GSerializableObject *object, GObjectStorage *storage, int fd)  { -    guint result;                           /* Valeur à retourner          */ -    GArchOperandClass *class;               /* Classe parente normalisée   */ -    GArchRegister *reg;                     /* Registre visé par l'opérande*/ +    bool result;                            /* Bilan à retourner           */ +    GSerializableObjectInterface *iface;    /* Interface utilisée          */ +    GSerializableObjectInterface *parent_iface; /* Interface parente       */ +    GSerializableObject *reg;               /* Registre récupéré           */ +    GRegisterOperand *operand;              /* Version spécialisée         */ + +    iface = G_SERIALIZABLE_OBJECT_GET_IFACE(object); + +    parent_iface = g_type_interface_peek_parent(iface); + +    result = parent_iface->load(object, storage, fd); + +    if (result) +    { +        reg = g_object_storage_unpack_object(storage, fd, "registers"); -    class = G_ARCH_OPERAND_CLASS(g_register_operand_parent_class); -    result = class->hash(G_ARCH_OPERAND(operand), false); +        if (reg == NULL) +            result = false; -    reg = g_register_operand_get_register(operand); +        else +        { +            operand = G_REGISTER_OPERAND(object); -    result ^= g_arch_register_hash(reg); +            operand->reg = G_ARCH_REGISTER(reg); + +        } -    g_object_unref(G_OBJECT(reg)); +    }      return result; @@ -291,11 +471,11 @@ static guint g_register_operand_hash(const GRegisterOperand *operand, bool lock)  /******************************************************************************  *                                                                             * -*  Paramètres  : operand = élément GLib à constuire.                          * -*                storage = conservateur de données à manipuler ou NULL.       * -*                pbuf    = zone tampon à lire.                                * +*  Paramètres  : object  = élément GLib à consulter.                          * +*                storage = conservateur de données à manipuler.               * +*                fd      = flux ouvert en écriture.                           *  *                                                                             * -*  Description : Charge un contenu depuis une mémoire tampon.                 * +*  Description : Sauvegarde un objet dans un flux de données.                 *  *                                                                             *  *  Retour      : Bilan de l'opération.                                        *  *                                                                             * @@ -303,61 +483,64 @@ static guint g_register_operand_hash(const GRegisterOperand *operand, bool lock)  *                                                                             *  ******************************************************************************/ -static bool g_register_operand_load(GRegisterOperand *operand, GObjectStorage *storage, packed_buffer_t *pbuf) +static bool g_register_operand_store(const GSerializableObject *object, GObjectStorage *storage, int fd)  {      bool result;                            /* Bilan à retourner           */ -    GArchOperandClass *parent;              /* Classe parente à consulter  */ -    GSerializableObject *reg;               /* Registre manipulé           */ +    GRegisterOperand *operand;              /* Version spécialisée         */ +    off64_t reg_pos;                        /* Position renvoyant au reg.  */ +    GSerializableObjectInterface *iface;    /* Interface utilisée          */ +    GSerializableObjectInterface *parent_iface; /* Interface parente       */ -    parent = G_ARCH_OPERAND_CLASS(g_register_operand_parent_class); +    operand = G_REGISTER_OPERAND(object); -    result = parent->load(G_ARCH_OPERAND(operand), storage, pbuf); +    result = g_object_storage_store_object(storage, "registers", G_SERIALIZABLE_OBJECT(operand->reg), ®_pos); +    if (!result) goto exit; -    if (result) -    { -        reg = g_object_storage_unpack_object(storage, "registers", pbuf); +    iface = G_SERIALIZABLE_OBJECT_GET_IFACE(object); -        result = (reg != NULL); +    parent_iface = g_type_interface_peek_parent(iface); -        if (result) -            operand->reg = G_ARCH_REGISTER(reg); +    result = parent_iface->store(object, storage, fd); +    if (!result) goto exit; -    } +    result = store_uleb128((uleb128_t []) { reg_pos }, fd); + + exit:      return result;  } + +/* ---------------------------------------------------------------------------------- */ +/*                   EXPORTATION SOUS FORME DE CHAINE DE CARACTERES                   */ +/* ---------------------------------------------------------------------------------- */ + +  /******************************************************************************  *                                                                             * -*  Paramètres  : operand = élément GLib à consulter.                          * -*                storage = conservateur de données à manipuler ou NULL.       * -*                pbuf    = zone tampon à remplir.                             * +*  Paramètres  : builder = objet dont l'instance est exportable.              * +*                flags   = éventuelles indications pour l'opération.          * +*                out     = chaîne de caractères mise en place. [OUT]          *  *                                                                             * -*  Description : Sauvegarde un contenu dans une mémoire tampon.               * +*  Description : Exporte une chaîne de caractères à partir d'un objet.        *  *                                                                             *  *  Retour      : Bilan de l'opération.                                        *  *                                                                             * -*  Remarques   : -                                                            * +*  Remarques   : La sortie out est à nettoyer avec exit_sized_binary() après  * +*                usage.                                                       *  *                                                                             *  ******************************************************************************/ -static bool g_register_operand_store(GRegisterOperand *operand, GObjectStorage *storage, packed_buffer_t *pbuf) +static bool g_register_operand_to_string(const GStringBuilder *builder, unsigned int flags, sized_binary_t *out)  {      bool result;                            /* Bilan à retourner           */ -    GArchOperandClass *parent;              /* Classe parente à consulter  */  -    GSerializableObject *reg;               /* Registre manipulé           */ +    const GRegisterOperand *operand;        /* Version spécialisée         */ -    parent = G_ARCH_OPERAND_CLASS(g_register_operand_parent_class); +    operand = G_REGISTER_OPERAND(builder); -    result = parent->store(G_ARCH_OPERAND(operand), storage, pbuf); - -    if (result) -    { -        reg = G_SERIALIZABLE_OBJECT(operand->reg); -        result = g_object_storage_pack_object(storage, "registers", reg, pbuf); -    } +    result = g_string_builder_to_string(G_STRING_BUILDER(operand->reg), flags, out);      return result; diff --git a/src/arch/register-int.h b/src/arch/register-int.h index f0b9af9..22ef2cc 100644 --- a/src/arch/register-int.h +++ b/src/arch/register-int.h @@ -2,7 +2,7 @@  /* Chrysalide - Outil d'analyse de fichiers binaires   * register-int.h - définitions internes pour la représentation générique d'un registre   * - * Copyright (C) 2012-2018 Cyrille Bagard + * Copyright (C) 2012-2025 Cyrille Bagard   *   *  This file is part of Chrysalide.   * @@ -26,31 +26,15 @@  #include "register.h" -#include "../analysis/storage/serialize-int.h" -/* Produit une empreinte à partir d'un registre. */ -typedef guint (* reg_hash_fc) (const GArchRegister *); - -/* Compare un registre avec un autre. */ -typedef int (* reg_compare_fc) (const GArchRegister *, const GArchRegister *); - -/* Traduit un registre en version humainement lisible. */ -typedef void (* reg_print_fc) (const GArchRegister *, GBufferLine *); -  /* Indique si le registre correspond à ebp ou similaire. */  typedef bool (* reg_is_base_pointer_fc) (const GArchRegister *);  /* Indique si le registre correspond à esp ou similaire. */  typedef bool (* reg_is_stack_pointer_fc) (const GArchRegister *); -/* Charge un contenu depuis une mémoire tampon. */ -typedef bool (* load_register_fc) (GArchRegister *, GObjectStorage *, packed_buffer_t *); - -/* Sauvegarde un contenu dans une mémoire tampon. */ -typedef bool (* store_register_fc) (GArchRegister *, GObjectStorage *, packed_buffer_t *); -  /* Représentation d'un registre (instance) */  struct _GArchRegister @@ -64,15 +48,9 @@ struct _GArchRegisterClass  {      GObjectClass parent;                    /* A laisser en premier        */ -    reg_hash_fc hash;                       /* Production d'empreinte      */ -    reg_compare_fc compare;                 /* Comparaison de registres    */ -    reg_print_fc print;                     /* Impression du registre      */      reg_is_base_pointer_fc is_bp;           /* Correspondance avec ebp     */      reg_is_stack_pointer_fc is_sp;          /* Correspondance avec esp     */ -    load_register_fc load;                  /* Chargement depuis un tampon */ -    store_register_fc store;                /* Conservation dans un tampon */ -  }; diff --git a/src/arch/register.c b/src/arch/register.c index f487419..6017373 100644 --- a/src/arch/register.c +++ b/src/arch/register.c @@ -2,7 +2,7 @@  /* Chrysalide - Outil d'analyse de fichiers binaires   * registers.c - aides auxiliaires relatives aux registres Dalvik   * - * Copyright (C) 2012-2018 Cyrille Bagard + * Copyright (C) 2012-2025 Cyrille Bagard   *   *  This file is part of Chrysalide.   * @@ -25,6 +25,10 @@  #include "register-int.h" +#include "../glibext/comparable-int.h" +#include "../glibext/hashable-int.h" +#include "../glibext/serialize-int.h" +#include "../glibext/strbuilder-int.h" @@ -34,34 +38,26 @@  /* Initialise la classe des registres. */  static void g_arch_register_class_init(GArchRegisterClass *); -/* Initialise une instance de registre. */ -static void g_arch_register_init(GArchRegister *); +/* Procède à l'initialisation de l'interface de comparaison. */ +static void g_arch_register_comparable_object_iface_init(GComparableObjectInterface *); + +/* Procède à l'initialisation de l'interface de détermination. */ +static void g_arch_register_hashable_object_iface_init(GHashableObjectInterface *);  /* Procède à l'initialisation de l'interface de sérialisation. */  static void g_arch_register_serializable_init(GSerializableObjectInterface *); -/* Supprime toutes les références externes. */ -static void g_arch_register_dispose(GArchRegister *); - -/* Procède à la libération totale de la mémoire. */ -static void g_arch_register_finalize(GArchRegister *); - +/* Procède à l'initialisation de l'interface d'exportation. */ +static void g_arch_register_string_builder_iface_init(GStringBuilderInterface *); +/* Initialise une instance de registre. */ +static void g_arch_register_init(GArchRegister *); -/* -------------------- CONSERVATION ET RECHARGEMENT DES DONNEES -------------------- */ - - -/* Charge un contenu depuis une mémoire tampon. */ -static bool _g_arch_register_load(GArchRegister *, GObjectStorage *, packed_buffer_t *); - -/* Charge un contenu depuis une mémoire tampon. */ -static bool g_arch_register_load(GArchRegister *, GObjectStorage *, packed_buffer_t *); - -/* Sauvegarde un contenu dans une mémoire tampon. */ -static bool _g_arch_register_store(GArchRegister *, GObjectStorage *, packed_buffer_t *); +/* Supprime toutes les références externes. */ +static void g_arch_register_dispose(GObject *); -/* Sauvegarde un contenu dans une mémoire tampon. */ -static bool g_arch_register_store(GArchRegister *, GObjectStorage *, packed_buffer_t *); +/* Procède à la libération totale de la mémoire. */ +static void g_arch_register_finalize(GObject *); @@ -72,7 +68,10 @@ static bool g_arch_register_store(GArchRegister *, GObjectStorage *, packed_buff  /* Indique le type défini pour une représentation d'un registre. */  G_DEFINE_TYPE_WITH_CODE(GArchRegister, g_arch_register, G_TYPE_OBJECT, -                        G_IMPLEMENT_INTERFACE(G_TYPE_SERIALIZABLE_OBJECT, g_arch_register_serializable_init)); +                        G_IMPLEMENT_INTERFACE(G_TYPE_COMPARABLE_OBJECT, g_arch_register_comparable_object_iface_init) +                        G_IMPLEMENT_INTERFACE(G_TYPE_HASHABLE_OBJECT, g_arch_register_hashable_object_iface_init) +                        G_IMPLEMENT_INTERFACE(G_TYPE_SERIALIZABLE_OBJECT, g_arch_register_serializable_init) +                        G_IMPLEMENT_INTERFACE(G_TYPE_STRING_BUILDER, g_arch_register_string_builder_iface_init));  /****************************************************************************** @@ -93,20 +92,18 @@ static void g_arch_register_class_init(GArchRegisterClass *klass)      object = G_OBJECT_CLASS(klass); -    object->dispose = (GObjectFinalizeFunc/* ! */)g_arch_register_dispose; -    object->finalize = (GObjectFinalizeFunc)g_arch_register_finalize; - -    klass->load = (load_register_fc)_g_arch_register_load; -    klass->store = (store_register_fc)_g_arch_register_store; +    object->dispose = g_arch_register_dispose; +    object->finalize = g_arch_register_finalize;  } +  /******************************************************************************  *                                                                             * -*  Paramètres  : reg = instance à initialiser.                                * +*  Paramètres  : iface = interface GLib à initialiser.                        *  *                                                                             * -*  Description : Initialise une instance de registre.                         * +*  Description : Procède à l'initialisation de l'interface de comparaison.    *  *                                                                             *  *  Retour      : -                                                            *  *                                                                             * @@ -114,8 +111,9 @@ static void g_arch_register_class_init(GArchRegisterClass *klass)  *                                                                             *  ******************************************************************************/ -static void g_arch_register_init(GArchRegister *reg) +static void g_arch_register_comparable_object_iface_init(GComparableObjectInterface *iface)  { +    iface->compare = NULL;  } @@ -124,7 +122,7 @@ static void g_arch_register_init(GArchRegister *reg)  *                                                                             *  *  Paramètres  : iface = interface GLib à initialiser.                        *  *                                                                             * -*  Description : Procède à l'initialisation de l'interface de sérialisation.  * +*  Description : Procède à l'initialisation de l'interface de détermination.  *  *                                                                             *  *  Retour      : -                                                            *  *                                                                             * @@ -132,19 +130,18 @@ static void g_arch_register_init(GArchRegister *reg)  *                                                                             *  ******************************************************************************/ -static void g_arch_register_serializable_init(GSerializableObjectInterface *iface) +static void g_arch_register_hashable_object_iface_init(GHashableObjectInterface *iface)  { -    iface->load = (load_serializable_object_cb)g_arch_register_load; -    iface->store = (store_serializable_object_cb)g_arch_register_store; +    iface->hash = NULL;  }  /******************************************************************************  *                                                                             * -*  Paramètres  : reg = instance d'objet GLib à traiter.                       * +*  Paramètres  : iface = interface GLib à initialiser.                        *  *                                                                             * -*  Description : Supprime toutes les références externes.                     * +*  Description : Procède à l'initialisation de l'interface de sérialisation.  *  *                                                                             *  *  Retour      : -                                                            *  *                                                                             * @@ -152,18 +149,19 @@ static void g_arch_register_serializable_init(GSerializableObjectInterface *ifac  *                                                                             *  ******************************************************************************/ -static void g_arch_register_dispose(GArchRegister *reg) +static void g_arch_register_serializable_init(GSerializableObjectInterface *iface)  { -    G_OBJECT_CLASS(g_arch_register_parent_class)->dispose(G_OBJECT(reg)); +    iface->load = NULL; +    iface->store = NULL;  }  /******************************************************************************  *                                                                             * -*  Paramètres  : reg = instance d'objet GLib à traiter.                       * +*  Paramètres  : iface = interface GLib à initialiser.                        *  *                                                                             * -*  Description : Procède à la libération totale de la mémoire.                * +*  Description : Procède à l'initialisation de l'interface d'exportation.     *  *                                                                             *  *  Retour      : -                                                            *  *                                                                             * @@ -171,58 +169,55 @@ static void g_arch_register_dispose(GArchRegister *reg)  *                                                                             *  ******************************************************************************/ -static void g_arch_register_finalize(GArchRegister *reg) +static void g_arch_register_string_builder_iface_init(GStringBuilderInterface *iface)  { -    G_OBJECT_CLASS(g_arch_register_parent_class)->finalize(G_OBJECT(reg)); +    iface->to_string = NULL;  }  /******************************************************************************  *                                                                             * -*  Paramètres  : reg = opérande à consulter pour le calcul.                   * +*  Paramètres  : reg = instance à initialiser.                                *  *                                                                             * -*  Description : Produit une empreinte à partir d'un registre.                * +*  Description : Initialise une instance de registre.                         *  *                                                                             * -*  Retour      : Bilan de l'opération.                                        * +*  Retour      : -                                                            *  *                                                                             *  *  Remarques   : -                                                            *  *                                                                             *  ******************************************************************************/ -guint g_arch_register_hash(const GArchRegister *reg) +static void g_arch_register_init(GArchRegister *reg)  { -    return G_ARCH_REGISTER_GET_CLASS(reg)->hash(reg);  }  /******************************************************************************  *                                                                             * -*  Paramètres  : a = premier registre à consulter.                            * -*                b = second registre à consulter.                             * +*  Paramètres  : object = instance d'objet GLib à traiter.                    *  *                                                                             * -*  Description : Compare un registre avec un autre.                           * +*  Description : Supprime toutes les références externes.                     *  *                                                                             * -*  Retour      : Bilan de la comparaison.                                     * +*  Retour      : -                                                            *  *                                                                             *  *  Remarques   : -                                                            *  *                                                                             *  ******************************************************************************/ -int g_arch_register_compare(const GArchRegister *a, const GArchRegister *b) +static void g_arch_register_dispose(GObject *object)  { -    return G_ARCH_REGISTER_GET_CLASS(a)->compare(a, b); +    G_OBJECT_CLASS(g_arch_register_parent_class)->dispose(object);  }  /******************************************************************************  *                                                                             * -*  Paramètres  : reg  = registre à transcrire.                                * -*                line = ligne tampon où imprimer l'opérande donné.            * +*  Paramètres  : object = instance d'objet GLib à traiter.                    *  *                                                                             * -*  Description : Traduit un registre en version humainement lisible.          * +*  Description : Procède à la libération totale de la mémoire.                *  *                                                                             *  *  Retour      : -                                                            *  *                                                                             * @@ -230,9 +225,9 @@ int g_arch_register_compare(const GArchRegister *a, const GArchRegister *b)  *                                                                             *  ******************************************************************************/ -void g_arch_register_print(const GArchRegister *reg, GBufferLine *line) +static void g_arch_register_finalize(GObject *object)  { -    G_ARCH_REGISTER_GET_CLASS(reg)->print(reg, line); +    G_OBJECT_CLASS(g_arch_register_parent_class)->finalize(object);  } @@ -287,115 +282,3 @@ bool g_arch_register_is_stack_pointer(const GArchRegister *reg)      return result;  } - - - -/* ---------------------------------------------------------------------------------- */ -/*                      CONSERVATION ET RECHARGEMENT DES DONNEES                      */ -/* ---------------------------------------------------------------------------------- */ - - -/****************************************************************************** -*                                                                             * -*  Paramètres  : reg     = élément GLib à constuire.                          * -*                storage = conservateur de données à manipuler ou NULL.       * -*                pbuf    = zone tampon à lire.                                * -*                                                                             * -*  Description : Charge un contenu depuis une mémoire tampon.                 * -*                                                                             * -*  Retour      : Bilan de l'opération.                                        * -*                                                                             * -*  Remarques   : -                                                            * -*                                                                             * -******************************************************************************/ - -static bool _g_arch_register_load(GArchRegister *reg, GObjectStorage *storage, packed_buffer_t *pbuf) -{ -    bool result;                            /* Bilan à retourner           */ - -    result = true; - -    return result; - -} - - -/****************************************************************************** -*                                                                             * -*  Paramètres  : reg     = élément GLib à constuire.                          * -*                storage = conservateur de données à manipuler ou NULL.       * -*                pbuf    = zone tampon à lire.                                * -*                                                                             * -*  Description : Charge un contenu depuis une mémoire tampon.                 * -*                                                                             * -*  Retour      : Bilan de l'opération.                                        * -*                                                                             * -*  Remarques   : -                                                            * -*                                                                             * -******************************************************************************/ - -static bool g_arch_register_load(GArchRegister *reg, GObjectStorage *storage, packed_buffer_t *pbuf) -{ -    bool result;                            /* Bilan à retourner           */ -    GArchRegisterClass *class;              /* Classe à activer            */ - -    class = G_ARCH_REGISTER_GET_CLASS(reg); - -    result = class->load(reg, storage, pbuf); - -    return result; - -} - - -/****************************************************************************** -*                                                                             * -*  Paramètres  : reg     = élément GLib à consulter.                          * -*                storage = conservateur de données à manipuler ou NULL.       * -*                pbuf    = zone tampon à remplir.                             * -*                                                                             * -*  Description : Sauvegarde un contenu dans une mémoire tampon.               * -*                                                                             * -*  Retour      : Bilan de l'opération.                                        * -*                                                                             * -*  Remarques   : -                                                            * -*                                                                             * -******************************************************************************/ - -static bool _g_arch_register_store(GArchRegister *reg, GObjectStorage *storage, packed_buffer_t *pbuf) -{ -    bool result;                            /* Bilan à retourner           */ - -    result = true; - -    return result; - -} - - -/****************************************************************************** -*                                                                             * -*  Paramètres  : reg     = élément GLib à consulter.                          * -*                storage = conservateur de données à manipuler ou NULL.       * -*                pbuf    = zone tampon à remplir.                             * -*                                                                             * -*  Description : Sauvegarde un contenu dans une mémoire tampon.               * -*                                                                             * -*  Retour      : Bilan de l'opération.                                        * -*                                                                             * -*  Remarques   : -                                                            * -*                                                                             * -******************************************************************************/ - -static bool g_arch_register_store(GArchRegister *reg, GObjectStorage *storage, packed_buffer_t *pbuf) -{ -    bool result;                            /* Bilan à retourner           */ -    GArchRegisterClass *class;              /* Classe à activer            */ - -    class = G_ARCH_REGISTER_GET_CLASS(reg); - -    result = class->store(reg, storage, pbuf); - -    return result; - -} diff --git a/src/arch/register.h b/src/arch/register.h index 0265a73..16275e0 100644 --- a/src/arch/register.h +++ b/src/arch/register.h @@ -2,7 +2,7 @@  /* Chrysalide - Outil d'analyse de fichiers binaires   * register.h - prototypes pour les aides auxiliaires relatives aux registres Dalvik   * - * Copyright (C) 2012-2018 Cyrille Bagard + * Copyright (C) 2012-2025 Cyrille Bagard   *   *  This file is part of Chrysalide.   * @@ -25,44 +25,19 @@  #define _ARCH_REGISTER_H -#include <glib-object.h>  #include <stdbool.h> -#include "../glibext/bufferline.h" +#include "../glibext/helpers.h" -/* ---------------------------- PUR REGISTRE DU MATERIEL ---------------------------- */ +#define G_TYPE_ARCH_REGISTER (g_arch_register_get_type()) +DECLARE_GTYPE(GArchRegister, g_arch_register, G, ARCH_REGISTER); -#define G_TYPE_ARCH_REGISTER            g_arch_register_get_type() -#define G_ARCH_REGISTER(obj)            (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_ARCH_REGISTER, GArchRegister)) -#define G_IS_ARCH_REGISTER(obj)         (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_ARCH_REGISTER)) -#define G_ARCH_REGISTER_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_ARCH_REGISTER, GArchRegisterClass)) -#define G_IS_ARCH_REGISTER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_ARCH_REGISTER)) -#define G_ARCH_REGISTER_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_ARCH_REGISTER, GArchRegisterClass)) -/* Représentation d'un registre (instance) */ -typedef struct _GArchRegister GArchRegister; - -/* Représentation d'un registre (classe) */ -typedef struct _GArchRegisterClass GArchRegisterClass; - - -/* Indique le type défini pour une représentation d'un registre. */ -GType g_arch_register_get_type(void); - -/* Produit une empreinte à partir d'un registre. */ -guint g_arch_register_hash(const GArchRegister *); - -/* Compare un registre avec un autre. */ -int g_arch_register_compare(const GArchRegister *, const GArchRegister *); - -/* Traduit un registre en version humainement lisible. */ -void g_arch_register_print(const GArchRegister *, GBufferLine *); -  /* Indique si le registre correspond à ebp ou similaire. */  bool g_arch_register_is_base_pointer(const GArchRegister *); diff --git a/src/arch/vmpa.h b/src/arch/vmpa.h index 42136e2..7a11deb 100644 --- a/src/arch/vmpa.h +++ b/src/arch/vmpa.h @@ -30,7 +30,6 @@  #include <stdint.h> -#include "archbase.h"  #include "../common/cpp.h"  #include "../common/datatypes.h"  #include "../common/packed.h" @@ -297,4 +296,33 @@ char *mrange_length_to_string(const mrange_t *, MemoryDataSize, char [VMPA_MAX_L +/* ------------------- DEFINITION D'UN ESPACE RELATIVE EN MEMOIRE ------------------- */ + + +/* Couverture mémoire */ +typedef struct _rel_mrange_t +{ +    uint32_t offset;                        /* Décalage depuis une ref.    */ +    uint16_t length;                        /* Taille de la couverture     */ + +} rel_mrange_t; + + +#define init_rel_mrange(rr, o, l)   \ +    do                              \ +    {                               \ +        (rr)->offset = o;           \ +        (rr)->length = l;           \ +    }                               \ +    while (0); + + +#define get_rel_mrange_offset(rr) \ +    (rr)->offset + +#define get_rel_mrange_length(rr) \ +    (rr)->length + + +  #endif  /* _ARCH_VMPA_H */ diff --git a/src/common/Makefile.am b/src/common/Makefile.am index 27ead1d..1056cb2 100644 --- a/src/common/Makefile.am +++ b/src/common/Makefile.am @@ -6,7 +6,6 @@ libcommon_la_SOURCES =					\  	array.h array.c						\  	asm.h asm.c							\  	bconst.h							\ -	bits.h bits.c						\  	compression.h compression.c			\  	cpp.h								\  	cpu.h cpu.c							\ @@ -21,7 +20,6 @@ libcommon_la_SOURCES =					\  	packed.h packed.c					\  	pathname.h pathname.c				\  	pearson.h pearson.c					\ -	shuffle.h shuffle.c					\  	sort.h sort.c						\  	sqlite.h sqlite.c					\  	szstr.h								\ @@ -49,11 +47,14 @@ endif  libcommon4_la_SOURCES =						\ +	array.h array.c							\  	asm.h asm.c								\  	bits.h bits.c							\  	compiler.h								\ +	cpp.h									\  	datatypes.h								\  	dllist.h dllist.c						\ +	entropy.h entropy.c						\  	environment.h environment.c				\  	extstr.h extstr.c						\  	fnv1a.h fnv1a.c							\ @@ -62,10 +63,38 @@ libcommon4_la_SOURCES =						\  	macros.h								\  	packed.h packed.c						\  	pathname.h pathname.c					\ +	shuffle.h shuffle.c						\  	sort.h sort.c							\ +	szbin.h									\  	xdg.h xdg.c -libcommon4_la_CFLAGS = $(TOOLKIT_CFLAGS) $(LIBSSL_CFLAGS) +if BUILD_CURL_SUPPORT + +libcommon4_la_SOURCES +=					\ +	curl.h curl.c + +endif + +if BUILD_JSONGLIB_SUPPORT + +libcommon4_la_SOURCES +=					\ +	json.h json.c + +endif + +libcommon4_la_CFLAGS = $(TOOLKIT_CFLAGS) $(LIBSSL_CFLAGS) $(LIBJSONGLIB_CFLAGS) + +if BUILD_CURL_SUPPORT + +libcommon4_la_CFLAGS += $(LIBCURL_CFLAGS) + +endif + +if BUILD_JSONGLIB_SUPPORT + +libcommon4_la_CFLAGS += $(LIBJSONGLIB_CFLAGS) + +endif  devdir = $(includedir)/chrysalide/$(subdir:src/%=core/%) diff --git a/src/common/bits.c b/src/common/bits.c index 37e3141..27296f2 100644 --- a/src/common/bits.c +++ b/src/common/bits.c @@ -31,6 +31,8 @@  #include "asm.h" +#include "io.h" +#include "leb128.h" @@ -50,7 +52,8 @@ struct _bitfield_t  /* Taille des mots intégrés */ -#define BF_WORD_SIZE (sizeof(unsigned long) * 8) +#define BF_WORD_BIT_SIZE (sizeof(unsigned long) * 8) +#define BF_WORD_BYTE_SIZE sizeof(unsigned long)  /* Crée un champ de bits initialisé à zéro. */ @@ -82,10 +85,10 @@ static bitfield_t *_create_bit_field(size_t length)      size_t needed;                          /* Nombre de mots à allouer    */      size_t base;                            /* Allocation de base en octets*/ -    needed = length / (sizeof(unsigned long) * 8); -    if (length % (sizeof(unsigned long) * 8) != 0) needed++; +    needed = length / BF_WORD_BIT_SIZE; +    if (length % BF_WORD_BIT_SIZE != 0) needed++; -    base = sizeof(bitfield_t) + needed * sizeof(unsigned long); +    base = sizeof(bitfield_t) + needed * BF_WORD_BYTE_SIZE;      result = malloc(base); @@ -148,7 +151,7 @@ bitfield_t *dup_bit_field(const bitfield_t *field)      result = _create_bit_field(field->length); -    memcpy(result->bits, field->bits, result->used_words * sizeof(unsigned long)); +    memcpy(result->bits, field->bits, result->used_words * BF_WORD_BYTE_SIZE);      return result; @@ -191,7 +194,7 @@ void copy_bit_field(bitfield_t *dest, const bitfield_t *src)  {      assert(dest->length == src->length); -    memcpy(dest->bits, src->bits, dest->used_words * sizeof(unsigned long)); +    memcpy(dest->bits, src->bits, dest->used_words * BF_WORD_BYTE_SIZE);  } @@ -217,8 +220,8 @@ void truncate_bit_field(bitfield_t **field, size_t length)      _field = *field; -    needed = length / (sizeof(unsigned long) * 8); -    if (length % (sizeof(unsigned long) * 8) != 0) needed++; +    needed = length / BF_WORD_BIT_SIZE; +    if (length % BF_WORD_BIT_SIZE != 0) needed++;      if (needed <= _field->allocated_words)      { @@ -263,10 +266,10 @@ void resize_bit_field(bitfield_t **field, size_t length)      {          /* Redimensionnement */ -        needed = length / (sizeof(unsigned long) * 8); -        if (length % (sizeof(unsigned long) * 8) != 0) needed++; +        needed = length / BF_WORD_BIT_SIZE; +        if (length % BF_WORD_BIT_SIZE != 0) needed++; -        base = sizeof(bitfield_t) + needed * sizeof(unsigned long); +        base = sizeof(bitfield_t) + needed * BF_WORD_BYTE_SIZE;          /* Initialisation, si nécessaire */ @@ -275,8 +278,8 @@ void resize_bit_field(bitfield_t **field, size_t length)              *field = realloc(_field, base);              _field = *field; -            last = _field->length / (sizeof(unsigned long) * 8); -            remaining = _field->length % (sizeof(unsigned long) * 8); +            last = _field->length / BF_WORD_BIT_SIZE; +            remaining = _field->length % BF_WORD_BIT_SIZE;              if (remaining != 0)              { @@ -367,7 +370,7 @@ int compare_bit_fields(const bitfield_t *a, const bitfield_t *b)      else      { -        final = a->length % (8 * sizeof(unsigned long)); +        final = a->length % BF_WORD_BIT_SIZE;          if (final == 0)              final = ~0lu; @@ -414,7 +417,7 @@ int compare_bit_fields(const bitfield_t *a, const bitfield_t *b)  void reset_all_in_bit_field(bitfield_t *field)  { -    memset(field->bits, 0u, field->used_words * sizeof(unsigned long)); +    memset(field->bits, 0u, field->used_words * BF_WORD_BYTE_SIZE);  } @@ -433,7 +436,35 @@ void reset_all_in_bit_field(bitfield_t *field)  void set_all_in_bit_field(bitfield_t *field)  { -    memset(field->bits, ~0u, field->used_words * sizeof(unsigned long)); +    memset(field->bits, ~0u, field->used_words * BF_WORD_BYTE_SIZE); + +} + + +/****************************************************************************** +*                                                                             * +*  Paramètres  : field = champ de bits à modifier.                            * +*                first = indice du premier bit à traiter.                     * +*                                                                             * +*  Description : Bascule à 0 une partie d'un champ de bits.                   * +*                                                                             * +*  Retour      : -                                                            * +*                                                                             * +*  Remarques   : -                                                            * +*                                                                             * +******************************************************************************/ + +void reset_in_bit_field(bitfield_t *field, size_t first) +{ +    size_t index;                           /* Cellule de tableau visée    */ +    size_t remaining;                       /* Nombre de bits restants     */ + +    assert(first < field->length); + +    index = first / BF_WORD_BIT_SIZE; +    remaining = first % BF_WORD_BIT_SIZE; + +    field->bits[index] &= ~(1ul << remaining);  } @@ -452,7 +483,7 @@ void set_all_in_bit_field(bitfield_t *field)  *                                                                             *  ******************************************************************************/ -void reset_in_bit_field(bitfield_t *field, size_t first, size_t count) +void reset_multi_in_bit_field(bitfield_t *field, size_t first, size_t count)  {      size_t last;                            /* Point d'arrêt de la boucle  */      size_t i;                               /* Boucle de parcours          */ @@ -465,8 +496,8 @@ void reset_in_bit_field(bitfield_t *field, size_t first, size_t count)      for (i = first; i < last; i++)      { -        index = i / (sizeof(unsigned long) * 8); -        remaining = i % (sizeof(unsigned long) * 8); +        index = i / BF_WORD_BIT_SIZE; +        remaining = i % BF_WORD_BIT_SIZE;          field->bits[index] &= ~(1ul << remaining); @@ -479,6 +510,34 @@ void reset_in_bit_field(bitfield_t *field, size_t first, size_t count)  *                                                                             *  *  Paramètres  : field = champ de bits à modifier.                            *  *                first = indice du premier bit à traiter.                     * +*                                                                             * +*  Description : Bascule à 1 une partie d'un champ de bits.                   * +*                                                                             * +*  Retour      : -                                                            * +*                                                                             * +*  Remarques   : -                                                            * +*                                                                             * +******************************************************************************/ + +void set_in_bit_field(bitfield_t *field, size_t first) +{ +    size_t index;                           /* Cellule de tableau visée    */ +    size_t remaining;                       /* Nombre de bits restants     */ + +    assert(first < field->length); + +    index = first / BF_WORD_BIT_SIZE; +    remaining = first % BF_WORD_BIT_SIZE; + +    field->bits[index] |= (1ul << remaining); + +} + + +/****************************************************************************** +*                                                                             * +*  Paramètres  : field = champ de bits à modifier.                            * +*                first = indice du premier bit à traiter.                     *  *                count = nombre de bits à marquer.                            *  *                                                                             *  *  Description : Bascule à 1 une partie d'un champ de bits.                   * @@ -489,7 +548,7 @@ void reset_in_bit_field(bitfield_t *field, size_t first, size_t count)  *                                                                             *  ******************************************************************************/ -void set_in_bit_field(bitfield_t *field, size_t first, size_t count) +void set_multi_in_bit_field(bitfield_t *field, size_t first, size_t count)  {      size_t last;                            /* Point d'arrêt de la boucle  */      size_t i;                               /* Boucle de parcours          */ @@ -502,8 +561,8 @@ void set_in_bit_field(bitfield_t *field, size_t first, size_t count)      for (i = first; i < last; i++)      { -        index = i / (sizeof(unsigned long) * 8); -        remaining = i % (sizeof(unsigned long) * 8); +        index = i / BF_WORD_BIT_SIZE; +        remaining = i % BF_WORD_BIT_SIZE;          field->bits[index] |= (1ul << remaining); @@ -587,12 +646,12 @@ void or_bit_field_at(bitfield_t *dest, const bitfield_t *src, size_t first)      assert((first + src->length) <= dest->length); -    start = first / (sizeof(unsigned long) * 8); -    offset = first % (sizeof(unsigned long) * 8); +    start = first / BF_WORD_BIT_SIZE; +    offset = first % BF_WORD_BIT_SIZE; -    remaining = (first + src->length) % (sizeof(unsigned long) * 8); +    remaining = (first + src->length) % BF_WORD_BIT_SIZE; -    if ((first + src->length) % (sizeof(unsigned long) * 8) > 0) +    if ((first + src->length) % BF_WORD_BIT_SIZE > 0)          last_iter = src->used_words;      else          last_iter = src->used_words - 1; @@ -605,7 +664,7 @@ void or_bit_field_at(bitfield_t *dest, const bitfield_t *src, size_t first)              word = 0;          if (i > 0 && offset > 0) -            word |= src->bits[i - 1] >> (sizeof(unsigned long) * 8 - offset); +            word |= src->bits[i - 1] >> (BF_WORD_BIT_SIZE - offset);          if (i == last_iter && remaining > 0)              word &= (1ul << remaining) - 1; @@ -638,8 +697,8 @@ bool test_in_bit_field(const bitfield_t *field, size_t n)      assert(n < field->length); -    index = n / (sizeof(unsigned long) * 8); -    remaining = n % (sizeof(unsigned long) * 8); +    index = n / BF_WORD_BIT_SIZE; +    remaining = n % BF_WORD_BIT_SIZE;      result = field->bits[index] & (1ul << remaining); @@ -670,8 +729,8 @@ bool test_and_set_in_bit_field(bitfield_t *field, size_t n)      assert(n < field->length); -    index = n / (sizeof(unsigned long) * 8); -    remaining = n % (sizeof(unsigned long) * 8); +    index = n / BF_WORD_BIT_SIZE; +    remaining = n % BF_WORD_BIT_SIZE;      bits = field->bits + index; @@ -713,8 +772,8 @@ static bool test_state_in_bit_field(const bitfield_t *field, size_t first, size_      for (i = first; i < last; i++)      { -        index = i / (sizeof(unsigned long) * 8); -        remaining = i % (sizeof(unsigned long) * 8); +        index = i / BF_WORD_BIT_SIZE; +        remaining = i % BF_WORD_BIT_SIZE;          current = field->bits[index] & (1ul << remaining); @@ -805,14 +864,30 @@ static bool test_state_within_bit_field(const bitfield_t *field, size_t first, c      unsigned long bitmask;                  /* Masque à appliquer          */      unsigned long test;                     /* Valeur résultante du test   */ -    result = true; +    /** +     * Si un masque est à appliquer avec débordement, les bits débordés sont considérés +     * comme initialisés à la valeur par défaut. +     */ + +    if ((first + mask->length) > field->length) +    { +        assert(mask->length > 0); + +        result = (state == field->default_state); +        if (!result) goto done; + +        if (first >= field->length) +            goto done; -    assert((first + mask->length) <= field->length); +    } -    start = first / (sizeof(unsigned long) * 8); -    offset = first % (sizeof(unsigned long) * 8); +    else +        result = true; -    remaining = mask->length % (sizeof(unsigned long) * 8); +    start = first / BF_WORD_BIT_SIZE; +    offset = first % BF_WORD_BIT_SIZE; + +    remaining = mask->length % BF_WORD_BIT_SIZE;      if (remaining == 0)          finalcut = ~0lu; @@ -830,7 +905,7 @@ static bool test_state_within_bit_field(const bitfield_t *field, size_t first, c          {              word = field->bits[windex] >> offset;              if ((windex + 1) < field->used_words) -                word |= field->bits[windex + 1] << (sizeof(unsigned long) * 8 - offset); +                word |= field->bits[windex + 1] << (BF_WORD_BIT_SIZE - offset);          }          bitmask = mask->bits[i]; @@ -849,6 +924,8 @@ static bool test_state_within_bit_field(const bitfield_t *field, size_t first, c      } + done: +      return result;  } @@ -934,7 +1011,7 @@ size_t find_next_set_in_bit_field(const bitfield_t *field, const size_t *prev)      }      else      { -        i = *prev / BF_WORD_SIZE; +        i = *prev / BF_WORD_BIT_SIZE;          if (i >= field->used_words)          { @@ -944,9 +1021,9 @@ size_t find_next_set_in_bit_field(const bitfield_t *field, const size_t *prev)          word = field->bits[i]; -        last_pos = *prev % BF_WORD_SIZE; +        last_pos = *prev % BF_WORD_BIT_SIZE; -        if ((last_pos + 1) == BF_WORD_SIZE) +        if ((last_pos + 1) == BF_WORD_BIT_SIZE)              goto next_word;          word &= ~((1lu << (last_pos + 1)) - 1); @@ -957,7 +1034,7 @@ size_t find_next_set_in_bit_field(const bitfield_t *field, const size_t *prev)      if (found > 0)      { -        result = i * BF_WORD_SIZE + found - 1; +        result = i * BF_WORD_BIT_SIZE + found - 1;          goto done;      } @@ -973,7 +1050,7 @@ size_t find_next_set_in_bit_field(const bitfield_t *field, const size_t *prev)          if (found > 0)          { -            result = i * BF_WORD_SIZE + found - 1; +            result = i * BF_WORD_BIT_SIZE + found - 1;              /**               * Validation des bornes finales, pour le dernier mot. @@ -1148,7 +1225,7 @@ size_t popcount_for_bit_field(const bitfield_t *field)      {          value = field->bits[i]; -        if (remaining < (8 * sizeof(unsigned long))) +        if (remaining < BF_WORD_BIT_SIZE)              value &= (1lu << remaining) - 1;  #if __WORDSIZE == 64 @@ -1159,7 +1236,7 @@ size_t popcount_for_bit_field(const bitfield_t *field)  #   error "Unkown word size"  #endif -        remaining -= 8 * sizeof(unsigned long); +        remaining -= BF_WORD_BIT_SIZE;      } @@ -1190,8 +1267,6 @@ void output_bit_field(const bitfield_t *field)      printf("[len=%zu] \n", field->length); -#define MAX_BITS (sizeof(unsigned long) * 8) -      for (i = 0; i < field->used_words; i++)      {          value = field->bits[i]; @@ -1199,9 +1274,9 @@ void output_bit_field(const bitfield_t *field)          if (i > 0)              printf("| "); -        for (k = 0; k < MAX_BITS; k++) +        for (k = 0; k < BF_WORD_BIT_SIZE; k++)          { -            if ((i * MAX_BITS + k) >= field->length) +            if ((i * BF_WORD_BIT_SIZE + k) >= field->length)                  break;              printf("%c", value & (1lu << k) ? '1' : '.'); @@ -1218,3 +1293,133 @@ void output_bit_field(const bitfield_t *field)  }  #endif + + +/****************************************************************************** +*                                                                             * +*  Paramètres  : fd        = flux ouvert en lecture.                          * +*                length    = éventuelle indication de la taille du champ ?    * +*                def_state = éventuelle indication de l'état par défaut ?     * +*                endian    = ordre des bits dans la source.                   * +*                                                                             * +*  Description : Restaure un champ de bits depuis un flux ouvert.             * +*                                                                             * +*  Retour      : Adresse du champs de bits mis en place, NULL en cas d'échec. * +*                                                                             * +*  Remarques   : -                                                            * +*                                                                             * +******************************************************************************/ + +bitfield_t *load_bit_field(int fd, const size_t *length, const bool *def_state, SourceEndian endian) +{ +    bitfield_t *result;                     /* Structure à retourner       */ +    size_t final_length;                    /* Nombre de bits représentés  */ +    uleb128_t leb128_value;                 /* Valeur LEB128 chargée       */ +    bool status;                            /* Bilan d'une lecture         */ +    bool final_default_state;               /* Etat d'initialisation       */ +    uint8_t u8_value;                       /* Valeur sur 8 bits chargée   */ +    size_t i;                               /* Boucle de parcours          */ + +    result = NULL; + +    if (length != NULL) +        final_length = *length; +    else +    { +        status = load_uleb128(&leb128_value, fd); +        if (!status) goto exit; + +        final_length = leb128_value; + +    } + +    if (def_state != NULL) +        final_default_state = *def_state; + +    else +    { +        status = load_u8(fd, &u8_value); +        if (!status) goto exit; + +        final_default_state = !!u8_value; + +    } + +    result = _create_bit_field(final_length); + +    result->default_state = final_default_state; + +    for (i = 0; i < result->used_words; i++) +    { +        status = load_uleb128(&leb128_value, fd); + +        if (status) +            result->bits[i] = leb128_value; + +        else +        { +            delete_bit_field(result); +            result =  NULL; +            break; +        } + +    } + + exit: + +    return result; + +} + + +/****************************************************************************** +*                                                                             * +*  Paramètres  : field    = champ de bits à consulter.                        * +*                fd       = flux ouvert en écriture.                          * +*                skip_len = saute la sauvegarde de la taille du champ ?       * +*                skip_def = saute la sauvegarde de l'état par défaut ?        * +*                endian = ordre des bits dans la source.                      * +*                                                                             * +*  Description : Sauvegarde un champ de bits dans un flux ouvert.             * +*                                                                             * +*  Retour      : Bilan de l'opération : true en cas de succès, false sinon.   * +*                                                                             * +*  Remarques   : -                                                            * +*                                                                             * +******************************************************************************/ + +bool store_bit_field(const bitfield_t *field, int fd, bool skip_len, bool skip_def, SourceEndian endian) +{ +    bool result;                            /* Bilan à retourner           */ +    size_t i;                               /* Boucle de parcours          */ + +    if (skip_len) +        result = true; +    else +    { +        result = store_uleb128((const uleb128_t []) { field->length }, fd); +        if (!result) goto exit; +    } + +    if (skip_def) +        result = true; +    else +    { +        result = store_u8(fd, field->default_state); +        if (!result) goto exit; +    } + +    for (i = 0; i < field->used_words; i++) +    { +        result = store_uleb128((const uleb128_t []) { field->bits[i] }, fd); + +        if (!result) +            break; + +    } + + exit: + +    return result; + +} diff --git a/src/common/bits.h b/src/common/bits.h index a66c6f0..d9c83c8 100644 --- a/src/common/bits.h +++ b/src/common/bits.h @@ -29,6 +29,9 @@  #include <sys/types.h> +#include "datatypes.h" + +  /* Champ de bits simple */  typedef struct _bitfield_t bitfield_t; @@ -65,10 +68,16 @@ void reset_all_in_bit_field(bitfield_t *);  void set_all_in_bit_field(bitfield_t *);  /* Bascule à 0 une partie d'un champ de bits. */ -void reset_in_bit_field(bitfield_t *, size_t, size_t); +void reset_in_bit_field(bitfield_t *, size_t); + +/* Bascule à 0 une partie d'un champ de bits. */ +void reset_multi_in_bit_field(bitfield_t *, size_t, size_t);  /* Bascule à 1 une partie d'un champ de bits. */ -void set_in_bit_field(bitfield_t *, size_t, size_t); +void set_in_bit_field(bitfield_t *, size_t); + +/* Bascule à 1 une partie d'un champ de bits. */ +void set_multi_in_bit_field(bitfield_t *, size_t, size_t);  /* Réalise une opération ET logique entre deux champs de bits. */  void and_bit_field(bitfield_t *, const bitfield_t *); @@ -113,6 +122,12 @@ void output_bit_field(const bitfield_t *);  #endif +/* Restaure un champ de bits depuis un flux ouvert. */ +bitfield_t *load_bit_field(int, const size_t *, const bool *, SourceEndian); + +/* Sauvegarde un champ de bits dans un flux ouvert. */ +bool store_bit_field(const bitfield_t *, int, bool, bool, SourceEndian); +  #endif  /* _COMMON_BITS_H */ diff --git a/src/common/compiler.h b/src/common/compiler.h index 2585e47..65df8a4 100644 --- a/src/common/compiler.h +++ b/src/common/compiler.h @@ -2,7 +2,7 @@  /* Chrysalide - Outil d'analyse de fichiers binaires   * compiler.h - prototypes pour le regroupement d'astuces à destination du compilateur   * - * Copyright (C) 2024 Cyrille Bagard + * Copyright (C) 2024-2025 Cyrille Bagard   *   *  This file is part of Chrysalide.   * @@ -34,5 +34,19 @@  #define __weak __attribute__((weak)) +/** + * Contournement des avertissements de la forme suivante : + * + *    assignment to 'const char * const*' from incompatible pointer type 'char **' [-Wincompatible-pointer-types] + * + * Références : + *  - https://www.reddit.com/r/C_Programming/comments/qa2231/const_char_const_and_char_are_incompatible/ + *  - https://stackoverflow.com/questions/78125/why-cant-i-convert-char-to-a-const-char-const-in-c + *  - https://c-faq.com/ansi/constmismatch.html + */ + +#define CONST_ARRAY_CAST(a, tp) (const tp **)a + +  #endif  /* _COMMON_COMPILER_H */ diff --git a/src/common/cpp.h b/src/common/cpp.h index 39e7676..4ebad82 100644 --- a/src/common/cpp.h +++ b/src/common/cpp.h @@ -2,7 +2,7 @@  /* Chrysalide - Outil d'analyse de fichiers binaires   * cpp.h - prototypes pour avoir à disposition un langage C plus plus mieux   * - * Copyright (C) 2010-2020 Cyrille Bagard + * Copyright (C) 2010-2025 Cyrille Bagard   *   *  This file is part of Chrysalide.   * @@ -31,12 +31,27 @@  /** + * Fournit la taille d'une chaîne statique. + */ +#define STATIC_STR_SIZE(s) (sizeof(s) - 1) + + +/**   * Fournit la taille d'un tableau statique.   */  #define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0]))  /** + * Facilite la transmission d'arguement pour des fonctions + * comme strncmp() et Cie. + */ +#define SL(str) str, strlen(str) + +#define STCSL(str) str, STATIC_STR_SIZE(str) + + +/**   * Détermine la taille de la plus longue chaîne de caractères   * correspondant à un type donné.   */ diff --git a/src/common/curl.c b/src/common/curl.c index 573180f..e9fb92f 100644 --- a/src/common/curl.c +++ b/src/common/curl.c @@ -2,7 +2,7 @@  /* Chrysalide - Outil d'analyse de fichiers binaires   * curl.c - encapsulation des fonctionnalités de cURL   * - * Copyright (C) 2022 Cyrille Bagard + * Copyright (C) 2022-2024 Cyrille Bagard   *   *  This file is part of Chrysalide.   * @@ -28,14 +28,62 @@  #include <string.h> +#include "../core/global.h" + + + +/* Mémorise un volume de données transférées. */ +static int track_curl_data_transfers(CURL *, curl_infotype, char *, size_t, void *);  /* Mémorise les données reçues en réponse à une requête. */ -static size_t receive_data_from_internet(void *, size_t, size_t, curl_net_data_t *); +static size_t receive_data_from_internet(void *, size_t, size_t, sized_binary_t *);  /******************************************************************************  *                                                                             * +*  Paramètres  : handle = gestionnaire de la requête cURL concernée.          * +*                type   = type de transfert réalisé.                          * +*                data   = pointeur vers les données manipulées.               * +*                size   = quantité de données transférées.                    * +*                unused = adresse non utilisée ici.                           * +*                                                                             * +*  Description : Mémorise un volume de données transférées.                   * +*                                                                             * +*  Retour      : CURLE_OK.                                                    * +*                                                                             * +*  Remarques   : -                                                            * +*                                                                             * +******************************************************************************/ + +static int track_curl_data_transfers(CURL *handle, curl_infotype type, char *data, size_t size, void *unused) +{ +    switch (type) +    { +        case CURLINFO_HEADER_IN: +        case CURLINFO_DATA_IN: +        /*case CURLINFO_SSL_DATA_IN:*/ +            update_network_stats(size, 0); +            break; + +        case CURLINFO_HEADER_OUT: +        case CURLINFO_DATA_OUT: +        /*case CURLINFO_SSL_DATA_OUT:*/ +            update_network_stats(0, size); +            break; + +        default: +            break; + +    } + +    return 0; + +} + + +/****************************************************************************** +*                                                                             *  *  Paramètres  : contents = contenu nouveau en arrivance d'Internet.          *  *                size     = taille d'un élément reçu.                         *  *                nmemb    = quantité de ces éléments.                         * @@ -49,19 +97,19 @@ static size_t receive_data_from_internet(void *, size_t, size_t, curl_net_data_t  *                                                                             *  ******************************************************************************/ -static size_t receive_data_from_internet(void *contents, size_t size, size_t nmemb, curl_net_data_t *data) +static size_t receive_data_from_internet(void *contents, size_t size, size_t nmemb, sized_binary_t *data)  {      size_t realsize;                        /* Taille brute en octets      */      realsize = size * nmemb; -    data->memory = realloc(data->memory, data->size + realsize + 1); +    data->data = realloc(data->data, data->size + realsize + 1); -    memcpy(&(data->memory[data->size]), contents, realsize); +    memcpy(&(data->data[data->size]), contents, realsize);      data->size += realsize; -    data->memory[data->size] = 0; +    data->data[data->size] = 0;      return realsize; @@ -85,7 +133,7 @@ static size_t receive_data_from_internet(void *contents, size_t size, size_t nme  *                                                                             *  ******************************************************************************/ -bool send_http_get_request(const char *url, char * const headers[], size_t hcount, const char *cookies, setup_extra_curl_cb ecb, curl_net_data_t *resp) +bool send_http_get_request(const char *url, char * const headers[], size_t hcount, const char *cookies, setup_extra_curl_cb ecb, sized_binary_t *resp)  {      bool result;                            /* Bilan d'opération à renvoyer*/      CURL *req;                              /* Requête HTTP                */ @@ -95,12 +143,14 @@ bool send_http_get_request(const char *url, char * const headers[], size_t hcoun      result = false; -    resp->memory = NULL; -    resp->size = 0; +    init_sized_binary(resp);      req = curl_easy_init();      if (req == NULL) goto exit; +    curl_easy_setopt(req, CURLOPT_DEBUGFUNCTION, track_curl_data_transfers); +    curl_easy_setopt(req, CURLOPT_VERBOSE, 1L); +      curl_easy_setopt(req, CURLOPT_URL, url);      /* Entêtes à transmettre */ @@ -165,7 +215,7 @@ bool send_http_get_request(const char *url, char * const headers[], size_t hcoun  *                                                                             *  ******************************************************************************/ -bool send_http_post_request(const char *url, char * const headers[], size_t hcount, const char *cookies, const curl_net_data_t *payload, setup_extra_curl_cb ecb, curl_net_data_t *resp) +bool send_http_post_request(const char *url, char * const headers[], size_t hcount, const char *cookies, const sized_binary_t *payload, setup_extra_curl_cb ecb, sized_binary_t *resp)  {      bool result;                            /* Bilan d'opération à renvoyer*/      CURL *req;                              /* Requête HTTP                */ @@ -175,12 +225,14 @@ bool send_http_post_request(const char *url, char * const headers[], size_t hcou      result = false; -    resp->memory = NULL; -    resp->size = 0; +    init_sized_binary(resp);      req = curl_easy_init();      if (req == NULL) goto exit; +    curl_easy_setopt(req, CURLOPT_DEBUGFUNCTION, track_curl_data_transfers); +    curl_easy_setopt(req, CURLOPT_VERBOSE, 1L); +      curl_easy_setopt(req, CURLOPT_URL, url);      /* Entêtes à transmettre */ @@ -205,7 +257,7 @@ bool send_http_post_request(const char *url, char * const headers[], size_t hcou      curl_easy_setopt(req, CURLOPT_POST, 1); -    curl_easy_setopt(req, CURLOPT_POSTFIELDS, payload->memory); +    curl_easy_setopt(req, CURLOPT_POSTFIELDS, payload->data);      curl_easy_setopt(req, CURLOPT_POSTFIELDSIZE, payload->size);      /* Emission de la requête */ diff --git a/src/common/curl.h b/src/common/curl.h index 02d9e91..1fc8f54 100644 --- a/src/common/curl.h +++ b/src/common/curl.h @@ -2,7 +2,7 @@  /* Chrysalide - Outil d'analyse de fichiers binaires   * curl.h - prototypes pour l'encapsulation des fonctionnalités de cURL   * - * Copyright (C) 2022 Cyrille Bagard + * Copyright (C) 2022-2024 Cyrille Bagard   *   *  This file is part of Chrysalide.   * @@ -29,14 +29,8 @@  #include <curl/curl.h> +#include "szbin.h" -/* Données échangées avec Internet */ -typedef struct _curl_net_data_t -{ -    char *memory;                           /* Zone de mémoire allouée     */ -    size_t size;                            /* Quantité de données         */ - -} curl_net_data_t;  /* Prototype pour une intervention complémentaire dans la préparation des requêtes */ @@ -44,10 +38,10 @@ typedef CURLcode (* setup_extra_curl_cb) (CURL *);  /* Mémorise les données reçues en réponse à une requête. */ -bool send_http_get_request(const char *, char * const [], size_t, const char *, setup_extra_curl_cb, curl_net_data_t *); +bool send_http_get_request(const char *, char * const [], size_t, const char *, setup_extra_curl_cb, sized_binary_t *);  /* Mémorise les données reçues en réponse à une requête. */ -bool send_http_post_request(const char *, char * const [], size_t, const char *, const curl_net_data_t *, setup_extra_curl_cb, curl_net_data_t *); +bool send_http_post_request(const char *, char * const [], size_t, const char *, const sized_binary_t *, setup_extra_curl_cb, sized_binary_t *); diff --git a/src/common/datatypes.h b/src/common/datatypes.h index 3983267..248f4a1 100644 --- a/src/common/datatypes.h +++ b/src/common/datatypes.h @@ -52,5 +52,35 @@ typedef enum _SourceEndian  } SourceEndian; +/* Taille des données intégrées */ +typedef enum _MemoryDataSize +{ +    MDS_UNDEFINED           = 0x0,          /* Taille non définie          */ + +    MDS_4_BITS_UNSIGNED     = 0x1,          /* Opérande sur 4 bits n.-s.   */ +    MDS_8_BITS_UNSIGNED     = 0x2,          /* Opérande sur 8 bits n.-s.   */ +    MDS_16_BITS_UNSIGNED    = 0x3,          /* Opérande sur 16 bits n.-s.  */ +    MDS_32_BITS_UNSIGNED    = 0x4,          /* Opérande sur 32 bits n.-s.  */ +    MDS_64_BITS_UNSIGNED    = 0x5,          /* Opérande sur 64 bits n.-s.  */ + +    MDS_4_BITS_SIGNED       = 0x8 | 0x1,    /* Opérande sur 4 bits  signés */ +    MDS_8_BITS_SIGNED       = 0x8 | 0x2,    /* Opérande sur 8 bits  signés */ +    MDS_16_BITS_SIGNED      = 0x8 | 0x3,    /* Opérande sur 16 bits signés */ +    MDS_32_BITS_SIGNED      = 0x8 | 0x4,    /* Opérande sur 32 bits signés */ +    MDS_64_BITS_SIGNED      = 0x8 | 0x5     /* Opérande sur 64 bits signés */ + +} MemoryDataSize; + +#define MDS_RANGE(mds) ((mds & 0x7) - 1) +#define MDS_SIGN 0x8 +#define MDS_IS_SIGNED(mds) (mds & MDS_SIGN) + +#define MDS_4_BITS  MDS_4_BITS_UNSIGNED +#define MDS_8_BITS  MDS_8_BITS_UNSIGNED +#define MDS_16_BITS MDS_16_BITS_UNSIGNED +#define MDS_32_BITS MDS_32_BITS_UNSIGNED +#define MDS_64_BITS MDS_64_BITS_UNSIGNED + +  #endif  /* _COMMON_DATATYPES_H */ diff --git a/src/common/entropy.c b/src/common/entropy.c new file mode 100644 index 0000000..8dae698 --- /dev/null +++ b/src/common/entropy.c @@ -0,0 +1,88 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * entropy.c - calcul de l'entropie d'un contenu binaire + * + * Copyright (C) 2024 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 "entropy.h" + + +#include <math.h> +#include <string.h> + + + +/****************************************************************************** +*                                                                             * +*  Paramètres  : data = séquence d'octets à traiter.                          * +*                len  = quantité de ces octets.                               * +*                bits = calcul en concidérant les bits et non les octets ?    * +*                                                                             * +*  Description : Détermine l'entropie d'un contenu binaire.                   * +*                                                                             * +*  Retour      : Valeur d'entropie du contenu fourni.                         * +*                                                                             * +*  Remarques   : -                                                            * +*                                                                             * +******************************************************************************/ + +double compute_entropy(const bin_t *data, size_t len, bool bits) +{ +    double result;                          /* Valeur calculée à renvoyer  */ +    unsigned long counters[256];            /* Décompte des valeurs        */ +    const bin_t *d_max;                     /* Borne de fin de parcours #1 */ +    const bin_t *d_iter;                    /* Boucle de parcours #1       */ +    double log_2;                           /* Valeur constante de log2    */ +    unsigned long *c_max;                   /* Borne de fin de parcours #2 */ +    unsigned long *c_iter;                  /* Boucle de parcours #2       */ +    double freq;                            /* Fréquence liée à une valeur */ + +    result = 0.0; + +    memset(counters, 0, sizeof(counters)); + +    d_max = data + len; + +    for (d_iter = data; d_iter < d_max; d_iter++) +        counters[*d_iter]++; + +    /** +     * Explication du choix de log : +     * https://stackoverflow.com/questions/990477/how-to-calculate-the-entropy-of-a-file/990646#990646 +     */ + +    log_2 = log(bits ? 2.0 : 256.0); + +    c_max = counters + 256; + +    for (c_iter = counters; c_iter < c_max; c_iter++) +    { +        if (*c_iter == 0lu) +            continue; + +        freq = ((double)*c_iter) / ((double)len); + +        result -= freq * (log(freq) / log_2); + +    } + +    return result; + +} diff --git a/src/common/entropy.h b/src/common/entropy.h new file mode 100644 index 0000000..cfd51ef --- /dev/null +++ b/src/common/entropy.h @@ -0,0 +1,41 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * entropy.h - prototypes pour le calcul de l'entropie d'un contenu binaire + * + * Copyright (C) 2024 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 _COMMON_ENTROPY_H +#define _COMMON_ENTROPY_H + + +#include <stdbool.h> +#include <stddef.h> + + +#include "../common/datatypes.h" + + + +/* Détermine l'entropie d'un contenu binaire. */ +double compute_entropy(const bin_t *, size_t, bool); + + + +#endif  /* _COMMON_ENTROPY_H */ diff --git a/src/common/extstr.c b/src/common/extstr.c index bd3491f..fe0bab4 100644 --- a/src/common/extstr.c +++ b/src/common/extstr.c @@ -636,7 +636,7 @@ const void *memcasemem(const void *haystack, size_t haystacklen, const void *nee  *                                                                             *  *  Description : Compare sans casse deux série d'octets entre elles.          *  *                                                                             * -*  Retour      : Status de la comparaison des séries d'octets.                * +*  Retour      : Statut de la comparaison des séries d'octets.                *  *                                                                             *  *  Remarques   : -                                                            *  *                                                                             * diff --git a/src/common/fnv1a.c b/src/common/fnv1a.c index a8afd0a..057d6c9 100644 --- a/src/common/fnv1a.c +++ b/src/common/fnv1a.c @@ -2,7 +2,7 @@  /* Chrysalide - Outil d'analyse de fichiers binaires   * fnv1a.c - implémentaton du calcul rapide d'empreintes de chaînes   * - * Copyright (C) 2012-2018 Cyrille Bagard + * Copyright (C) 2012-2024 Cyrille Bagard   *   *  This file is part of Chrysalide.   * @@ -87,3 +87,34 @@ fnv64_t fnv_64a_hash(const char *str)      return result;  } + + +/****************************************************************************** +*                                                                             * +*  Paramètres  : data = données binaires à traiter.                           * +*                size = quantité de ces données.                              * +*                                                                             * +*  Description : Détermine l'empreinte FNV1a d'une séquence d'octets.         * +*                                                                             * +*  Retour      : Valeur calculée.                                             * +*                                                                             * +*  Remarques   : -                                                            * +*                                                                             * +******************************************************************************/ + +fnv64_t fnv_64a_hash_data(const uint8_t *data, size_t size) +{ +    fnv64_t result;                         /* Valeur à retourner          */ +    size_t i;                               /* Boucle de parcours          */ + +    result = FNV1A_64_INIT; + +    for (i = 0; i < size; i++) +    { +        result ^= (fnv64_t)data[i]; +        result *= FNV_64_PRIME; +    } + +    return result; + +} diff --git a/src/common/fnv1a.h b/src/common/fnv1a.h index eec1460..4da3108 100644 --- a/src/common/fnv1a.h +++ b/src/common/fnv1a.h @@ -2,7 +2,7 @@  /* Chrysalide - Outil d'analyse de fichiers binaires   * fnv1a.h - prototypes pour l'implémentaton du calcul rapide d'empreintes de chaînes   * - * Copyright (C) 2012-2018 Cyrille Bagard + * Copyright (C) 2012-2024 Cyrille Bagard   *   *  This file is part of Chrysalide.   * @@ -27,6 +27,7 @@  #include <stdbool.h>  #include <stdint.h> +#include <sys/types.h>  /** @@ -46,6 +47,9 @@ int cmp_fnv_64a(fnv64_t, fnv64_t);  /* Détermine l'empreinte FNV1a d'une chaîne de caractères. */  fnv64_t fnv_64a_hash(const char *); +/* Détermine l'empreinte FNV1a d'une séquence d'octets. */ +fnv64_t fnv_64a_hash_data(const uint8_t *, size_t); +  #endif  /* _COMMON_FNV1A_H */ diff --git a/src/common/io.h b/src/common/io.h index 7fe9d9d..1932b12 100644 --- a/src/common/io.h +++ b/src/common/io.h @@ -39,12 +39,69 @@  /* Lit des données depuis un flux local. */  bool safe_read(int, void *, size_t); +#define load_u8(f, v) \ +    safe_read(f, v, sizeof(uint8_t)); + +#define load_u16(f, v, e)                               \ +    ({                                                  \ +        bool __ret;                                     \ +        uint16_t __val;                                 \ +        __ret = safe_read(f, &__val, sizeof(uint16_t)); \ +        __val = swap_u16(&__val, e);                    \ +        *(v) = __val;                                   \ +        __ret;                                          \ +    }) + +#define load_u32(f, v, e)                               \ +    ({                                                  \ +        bool __ret;                                     \ +        uint32_t __val;                                 \ +        __ret = safe_read(f, &__val, sizeof(uint32_t)); \ +        __val = swap_u32(&__val, e);                    \ +        *(v) = __val;                                   \ +        __ret;                                          \ +    }) + +#define load_u64(f, v, e)                               \ +    ({                                                  \ +        bool __ret;                                     \ +        uint64_t __val;                                 \ +        __ret = safe_read(f, &__val, sizeof(uint64_t)); \ +        __val = swap_u64(&__val, e);                    \ +        *(v) = __val;                                   \ +        __ret;                                          \ +    }) +  /* Lit des données depuis un flux local. */  ssize_t safe_read_partial(int, void *, size_t);  /* Ecrit des données dans un flux local. */  bool safe_write(int, const void *, size_t); +#define store_u8(f, v) \ +    safe_write(f, (const uint8_t []){ v }, sizeof(uint8_t)); + +#define store_u16(f, v, e)                              \ +    ({                                                  \ +        uint16_t __val;                                 \ +        __val = swap_u16((const uint16_t []){ v }, e);  \ +        safe_write(f, &__val, sizeof(uint16_t));        \ +    }) + +#define store_u32(f, v, e)                              \ +    ({                                                  \ +        uint32_t __val;                                 \ +        __val = swap_u32((const uint32_t []){ v }, e);  \ +        safe_write(f, &__val, sizeof(uint32_t));        \ +    }) + +#define store_u64(f, v, e)                              \ +    ({                                                  \ +        uint64_t __val;                                 \ +        __val = swap_u64((const uint64_t []){ v }, e);  \ +        safe_write(f, &__val, sizeof(uint64_t));        \ +    }) +  /* Réceptionne des données depuis un flux réseau. */  bool safe_recv(int, void *, size_t, int); diff --git a/src/common/json.c b/src/common/json.c new file mode 100644 index 0000000..cb64822 --- /dev/null +++ b/src/common/json.c @@ -0,0 +1,203 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * json.c - manipulations génériques de données au format JSON + * + * Copyright (C) 2024 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 "json.h" + + +#include <assert.h> + + + +/****************************************************************************** +*                                                                             * +*  Paramètres  : root  = racine d'une arborescence JSON chargée.              * +*                query = chemin XPath d'une requête à mener.                  * +*                error = description d'une éventuelle erreur rencontrée. [OUT]* +*                                                                             * +*  Description : Détermine la présence d'un élément avec une valeur textuelle.* +*                                                                             * +*  Retour      : true si le noeud existe et porte une chaîne comme valeur.    * +*                                                                             * +*  Remarques   : -                                                            * +*                                                                             * +******************************************************************************/ + +bool has_json_string_value(JsonNode *root, const char *xpath, GError **error) +{ +    bool result;                            /* Bilan à retourner           */ +    JsonNode *found;                        /* Accès direct aux trouvailles*/ +    JsonArray *array;                       /* Liste des résultats         */ +    guint count;                            /* Taille de la liste          */ +    JsonNode *node;                         /* Noeud portant la cible      */ +    GValue value;                           /* Valeur correspondante       */ + +    result = false; + +    *error = NULL; +    found = json_path_query(xpath, root, error); + +    if (found != NULL) +    { +        assert(*error == NULL); + +        array = json_node_get_array(found); + +        count = json_array_get_length(array); + +        if (count == 1) +        { +            node = json_array_get_element(array, 0); + +            memset(&value, 0, sizeof(GValue)); +            json_node_get_value(node, &value); + +            if (G_VALUE_HOLDS(&value, G_TYPE_STRING)) +                result = true; + +        } + +        json_node_unref(found); + +    } + +    return result; + +} + + +/****************************************************************************** +*                                                                             * +*  Paramètres  : root  = racine d'une arborescence JSON chargée.              * +*                query = chemin XPath d'une requête à mener.                  * +*                error = description d'une éventuelle erreur rencontrée. [OUT]* +*                                                                             * +*  Description : Fournit le contenu d'un élément avec une valeur textuelle.   * +*                                                                             * +*  Retour      : Valeur trouvée ou NULL en cas d'échec.                       * +*                                                                             * +*  Remarques   : -                                                            * +*                                                                             * +******************************************************************************/ + +char *get_json_string_value(JsonNode *root, const char *xpath, GError **error) +{ +    char *result;                           /* Valeur à retourner          */ +    JsonNode *found;                        /* Accès direct aux trouvailles*/ +    JsonArray *array;                       /* Liste des résultats         */ +    guint count;                            /* Taille de la liste          */ +    JsonNode *node;                         /* Noeud portant la cible      */ +    GValue value;                           /* Valeur correspondante       */ +    const gchar *raw;                       /* Valeur brute présente       */ + +    result = NULL; + +    *error = NULL; +    found = json_path_query(xpath, root, error); + +    if (found != NULL) +    { +        assert(*error == NULL); + +        array = json_node_get_array(found); + +        count = json_array_get_length(array); + +        if (count == 1) +        { +            node = json_array_get_element(array, 0); + +            memset(&value, 0, sizeof(GValue)); +            json_node_get_value(node, &value); + +            if (G_VALUE_HOLDS(&value, G_TYPE_STRING)) +            { +                raw = json_array_get_string_element(array, 0); +                result = strdup(raw); +            } + +        } + +        json_node_unref(found); + +    } + +    return result; + +} + + +/****************************************************************************** +*                                                                             * +*  Paramètres  : root  = racine d'une arborescence JSON chargée.              * +*                query = chemin XPath d'une requête à mener.                  * +*                error = description d'une éventuelle erreur rencontrée. [OUT]* +*                                                                             * +*  Description : Fournit le contenu d'un élément avec une valeur entière.     * +*                                                                             * +*  Retour      : Valeur trouvée ou NULL en cas d'échec.                       * +*                                                                             * +*  Remarques   : -                                                            * +*                                                                             * +******************************************************************************/ + +long long get_json_integer_value(JsonNode *root, const char *xpath, GError **error) +{ +    long long result;                       /* Valeur à retourner          */ +    JsonNode *found;                        /* Accès direct aux trouvailles*/ +    JsonArray *array;                       /* Liste des résultats         */ +    guint count;                            /* Taille de la liste          */ +    JsonNode *node;                         /* Noeud portant la cible      */ +    GValue value;                           /* Valeur correspondante       */ + +    result = 0xffffffffffffffffll; + +    *error = NULL; +    found = json_path_query(xpath, root, error); + +    if (found != NULL) +    { +        assert(*error == NULL); + +        array = json_node_get_array(found); + +        count = json_array_get_length(array); + +        if (count == 1) +        { +            node = json_array_get_element(array, 0); + +            memset(&value, 0, sizeof(GValue)); +            json_node_get_value(node, &value); + +            if (G_VALUE_HOLDS(&value, G_TYPE_INT64)) +                result = json_array_get_int_element(array, 0); + +        } + +        json_node_unref(found); + +    } + +    return result; + +} diff --git a/src/common/json.h b/src/common/json.h new file mode 100644 index 0000000..8794bf6 --- /dev/null +++ b/src/common/json.h @@ -0,0 +1,44 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * json.h - prototypes pour des manipulations génériques de données au format JSON + * + * Copyright (C) 2024 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 _COMMON_JSON_H +#define _COMMON_JSON_H + + +#include <stdbool.h> +#include <json-glib/json-glib.h> + + + +/* Détermine la présence d'un élément avec une valeur textuelle. */ +bool has_json_string_value(JsonNode *, const char *, GError **); + +/* Fournit le contenu d'un élément avec une valeur textuelle. */ +char *get_json_string_value(JsonNode *, const char *, GError **); + +/* Fournit le contenu d'un élément avec une valeur entière. */ +long long get_json_integer_value(JsonNode *, const char *, GError **); + + + +#endif  /* _COMMON_JSON_H */ diff --git a/src/common/leb128.c b/src/common/leb128.c index c8d2ace..7fae4d0 100644 --- a/src/common/leb128.c +++ b/src/common/leb128.c @@ -24,6 +24,20 @@  #include "leb128.h" +#include <malloc.h> + + +#include "io.h" + + +/** + * Quantité maximale d'octets de représentation. + * + *    sizeof([u]leb128_t) / 7 = 9.142857142857142 + * + */ +#define MAX_LEB128_BYTES 9 +  /******************************************************************************  *                                                                             * @@ -113,10 +127,63 @@ bool read_leb128(leb128_t *target, const bin_t *data, phys_t *pos, phys_t len)  /******************************************************************************  *                                                                             * +*  Paramètres  : value = valeur à constituer. [OUT]                           * +*                fd    = flux ouvert en lecture à consulter.                  * +*                                                                             * +*  Description : Restaure un nombre non signé encodé au format LEB128.        * +*                                                                             * +*  Retour      : Bilan de l'opération : true en cas de succès, false sinon.   * +*                                                                             * +*  Remarques   : -                                                            * +*                                                                             * +******************************************************************************/ + +bool load_uleb128(uleb128_t *value, int fd) +{ +    bool result;                            /* Bilan à retourner           */ +    unsigned int shift;                     /* Décalage à appliquer        */ +    uint8_t byte;                           /* Octet à transposer          */ + +    result = false; + +    *value = 0; + +    shift = 0; + +    while (true) +    { +        /* Encodage sur trop d'octets ? */ +        if (shift > (7 * MAX_LEB128_BYTES)) +        { +            result = false; +            break; +        } + +        result = safe_read(fd, &byte, sizeof(uint8_t)); +        if (!result) break; + +        *value |= ((byte & 0x7f) << shift); + +        result = true; + +        if ((byte & 0x80) == 0x00) +            break; + +        shift += 7; + +    } + +    return result; + +} + + +/****************************************************************************** +*                                                                             *  *  Paramètres  : value = valeur à consigner.                                  * -*                pbuf  = tampon de données à constituer. [OUT]                * +*                fd    = flux ouvert en écriture.                             *  *                                                                             * -*  Description : Encode un nombre non signé encodé au format LEB128.          * +*  Description : Sauvegarde un nombre non signé encodé au format LEB128.      *  *                                                                             *  *  Retour      : Bilan de l'opération : true en cas de succès, false sinon.   *  *                                                                             * @@ -124,7 +191,7 @@ bool read_leb128(leb128_t *target, const bin_t *data, phys_t *pos, phys_t len)  *                                                                             *  ******************************************************************************/ -bool pack_uleb128(const uleb128_t *value, packed_buffer_t *pbuf) +bool store_uleb128(const uleb128_t *value, int fd)  {      bool result;                            /* Bilan à retourner           */      uleb128_t tmp;                          /* Valeur modifiable           */ @@ -140,7 +207,7 @@ bool pack_uleb128(const uleb128_t *value, packed_buffer_t *pbuf)          if (tmp != 0)              byte |= 0x80; -        result = extend_packed_buffer(pbuf, &byte, sizeof(uint8_t), false); +        result = safe_write(fd, &byte, sizeof(uint8_t));      }      while (result && tmp != 0); @@ -153,9 +220,9 @@ bool pack_uleb128(const uleb128_t *value, packed_buffer_t *pbuf)  /******************************************************************************  *                                                                             *  *  Paramètres  : value = valeur à consigner.                                  * -*                pbuf  = tampon de données à constituer. [OUT]                * +*                len   = taille du tampon de données à constitué. [OUT]       *  *                                                                             * -*  Description : Encode un nombre signé encodé au format LEB128.              * +*  Description : Encode un nombre non signé encodé au format LEB128.          *  *                                                                             *  *  Retour      : Bilan de l'opération : true en cas de succès, false sinon.   *  *                                                                             * @@ -163,19 +230,81 @@ bool pack_uleb128(const uleb128_t *value, packed_buffer_t *pbuf)  *                                                                             *  ******************************************************************************/ -bool pack_leb128(const leb128_t *value, packed_buffer_t *pbuf) +void *pack_uleb128(const uleb128_t *value, size_t *len)  { +    uint8_t *result;                        /* Données à retourner         */ +    uleb128_t tmp;                          /* Valeur modifiable           */ +    uint8_t *byte;                          /* Octet à transposer          */ -    bool result;                            /* Bilan à retourner           */ +    /* Calcul de la quantité d'octets nécessaires */ + +    *len = 0; + +    tmp = *value; + +    do +    { +        tmp >>= 7; +        (*len)++; +    } +    while (tmp != 0); + +    /* Exportation */ + +    result = malloc(*len * sizeof(uint8_t)); +    byte = result; + +    tmp = *value; + +    do +    { +        *byte = (tmp & 0x7f); +        tmp >>= 7; + +        if (tmp != 0) +            *byte |= 0x80; + +        byte++; + +    } +    while (tmp != 0); + +    return result; + +} + + +/****************************************************************************** +*                                                                             * +*  Paramètres  : value = valeur à consigner.                                  * +*                len   = taille du tampon de données à constitué. [OUT]       * +*                                                                             * +*  Description : Encode un nombre signé encodé au format LEB128.              * +*                                                                             * +*  Retour      : Bilan de l'opération : true en cas de succès, false sinon.   * +*                                                                             * +*  Remarques   : -                                                            * +*                                                                             * +******************************************************************************/ + +void *pack_leb128(const leb128_t *value, size_t *len) +{ +    uint8_t *result;                        /* Données à retourner         */ +    bool negative;                          /* Nature de la valeur         */      uleb128_t tmp;                          /* Valeur modifiable           */      bool more;                              /* Poursuite des traitements   */ -    bool negative;                          /* Nature de la valeur         */      uint8_t byte;                           /* Octet à transposer          */ +    uint8_t *iter;                          /* Boucle de parcours          */ + +    negative = (*value < 0); + +    /* Calcul de la quantité d'octets nécessaires */ + +    *len = 0;      tmp = *value;      more = true; -    negative = (*value < 0);      while (more)      { @@ -198,10 +327,44 @@ bool pack_leb128(const leb128_t *value, packed_buffer_t *pbuf)          if ((tmp == 0 && (byte & 0x40) == 0x00) || (tmp == -1 && (byte & 0x40) == 0x40))              more = false; +        (*len)++; + +    } + +    /* Exportation */ + +    result = malloc(*len * sizeof(uint8_t)); +    iter = result; + +    tmp = *value; + +    more = true; + +    while (more) +    { +        *iter = (tmp & 0x7f); +        tmp >>= 7; + +        /** +         * Propagation forcée du bit de signe pour les implémentations de +         * décalage basées sur une opération logique et non arithmétique. +         */ + +        if (negative) +            tmp |= (~0llu << (LEB128_BITS_COUNT - 7)); + +        /** +         * Le bit de signe n'est pas le bit de poids fort ici : +         * On travaille sur 7 bits, donc le masque est 0x40 ! +         */ + +        if ((tmp == 0 && (*iter & 0x40) == 0x00) || (tmp == -1 && (*iter & 0x40) == 0x40)) +            more = false; +          else -            byte |= 0x80; +            *iter |= 0x80; -        result = extend_packed_buffer(pbuf, &byte, sizeof(uint8_t), false); +        iter++;      } @@ -213,7 +376,8 @@ bool pack_leb128(const leb128_t *value, packed_buffer_t *pbuf)  /******************************************************************************  *                                                                             *  *  Paramètres  : value = valeur à constituer. [OUT]                           * -*                pbuf  = tampon de données à consulter.                       * +*                pos   = tête de lecture à faire évoluer. [OUT]               * +*                max   = position maximale liée à la fin des données.         *  *                                                                             *  *  Description : Décode un nombre non signé encodé au format LEB128.          *  *                                                                             * @@ -223,38 +387,45 @@ bool pack_leb128(const leb128_t *value, packed_buffer_t *pbuf)  *                                                                             *  ******************************************************************************/ -bool unpack_uleb128(uleb128_t *value, packed_buffer_t *pbuf) +bool unpack_uleb128(uleb128_t *value, const void **pos, const void *max)  {      bool result;                            /* Bilan à retourner           */      unsigned int shift;                     /* Décalage à appliquer        */ -    uint8_t byte;                           /* Octet à transposer          */ +    uint8_t *byte;                          /* Octet à transposer          */ -    result = true; +    result = false;      *value = 0;      shift = 0; +    byte = *(uint8_t **)pos; -    while (true) +    do      {          /* Encodage sur trop d'octets ? */ -        if (shift > (7 * sizeof(uleb128_t))) +        if (shift > (7 * MAX_LEB128_BYTES))          {              result = false;              break;          } -        result = extract_packed_buffer(pbuf, &byte, sizeof(uint8_t), false); -        if (!result) break; +        /* Atteinte de la fin des données ? */ +        if ((void *)byte >= max) +        { +            result = false; +            break; +        } -        *value |= ((byte & 0x7f) << shift); +        *value |= ((*byte & 0x7f) << shift); -        if ((byte & 0x80) == 0x00) -            break; +        result = true;          shift += 7;      } +    while ((*byte++ & 0x80) == 0x80); + +    *pos = byte;      return result; @@ -264,7 +435,8 @@ bool unpack_uleb128(uleb128_t *value, packed_buffer_t *pbuf)  /******************************************************************************  *                                                                             *  *  Paramètres  : value = valeur à constituer. [OUT]                           * -*                pbuf  = tampon de données à consulter.                       * +*                pos   = tête de lecture à faire évoluer. [OUT]               * +*                max   = position maximale liée à la fin des données.         *  *                                                                             *  *  Description : Décode un nombre signé encodé au format LEB128.              *  *                                                                             * @@ -274,44 +446,56 @@ bool unpack_uleb128(uleb128_t *value, packed_buffer_t *pbuf)  *                                                                             *  ******************************************************************************/ -bool unpack_leb128(leb128_t *value, packed_buffer_t *pbuf) +bool unpack_leb128(leb128_t *value, const void **pos, const void *max)  {      bool result;                            /* Bilan à retourner           */      unsigned int shift;                     /* Décalage à appliquer        */ -    uint8_t byte;                           /* Octet à transposer          */ +    uint8_t *byte;                          /* Octet à transposer          */ -    result = true; +    result = false;      *value = 0;      shift = 0; +    byte = *(uint8_t **)pos;      do      {          /* Encodage sur trop d'octets ? */ -        if (shift > (7 * sizeof(leb128_t))) +        if (shift > (7 * MAX_LEB128_BYTES))          {              result = false;              break;          } -        result = extract_packed_buffer(pbuf, &byte, sizeof(uint8_t), false); -        if (!result) break; +        /* Atteinte de la fin des données ? */ +        if ((void *)byte >= max) +        { +            result = false; +            break; +        } -        *value |= ((byte & 0x7f) << shift); +        *value |= ((*byte & 0x7f) << shift); + +        result = true;          shift += 7;      } -    while ((byte & 0x80) == 0x80); +    while ((*byte++ & 0x80) == 0x80);      /**       * Le bit de signe n'est pas le bit de poids fort ici :       * On travaille sur 7 bits, donc le masque est 0x40 !       */ -    if (shift < LEB128_BITS_COUNT && (byte & 0x40) == 0x40) -        *value |= (~0llu << shift); +    if (result) +    { +        if (shift < LEB128_BITS_COUNT && (byte[-1] & 0x40) == 0x40) +            *value |= (~0llu << shift); +    } + +    *pos = byte;      return result; diff --git a/src/common/leb128.h b/src/common/leb128.h index f438068..cb712a3 100644 --- a/src/common/leb128.h +++ b/src/common/leb128.h @@ -30,7 +30,6 @@  #include "datatypes.h" -#include "packed.h" @@ -58,17 +57,23 @@ bool read_uleb128(uleb128_t *, const bin_t *, phys_t *, phys_t);  /* Lit un nombre signé encodé au format LEB128. */  bool read_leb128(leb128_t *, const bin_t *, phys_t *, phys_t); +/* Charge un nombre non signé encodé au format LEB128. */ +bool load_uleb128(uleb128_t *, int); + +/* Sauvegarde un nombre non signé encodé au format LEB128. */ +bool store_uleb128(const uleb128_t *, int); +  /* Encode un nombre non signé encodé au format LEB128. */ -bool pack_uleb128(const uleb128_t *, packed_buffer_t *); +void *pack_uleb128(const uleb128_t *, size_t *);  /* Encode un nombre signé encodé au format LEB128. */ -bool pack_leb128(const leb128_t *, packed_buffer_t *); +void *pack_leb128(const leb128_t *, size_t *); -/* Décode un nombre non signé encodé au format LEB128. */ -bool unpack_uleb128(uleb128_t *, packed_buffer_t *); +/* Encode un nombre non signé encodé au format LEB128. */ +bool unpack_uleb128(uleb128_t *, const void **, const void *);  /* Décode un nombre signé encodé au format LEB128. */ -bool unpack_leb128(leb128_t *, packed_buffer_t *); +bool unpack_leb128(leb128_t *, const void **, const void *); diff --git a/src/common/pathname.c b/src/common/pathname.c index dd3ec9e..81dc1e3 100644 --- a/src/common/pathname.c +++ b/src/common/pathname.c @@ -33,13 +33,13 @@  #include <stdlib.h>  #include <string.h>  #include <unistd.h> +#include <gio/gio.h>  #include <sys/stat.h>  #include "extstr.h"  #include "io.h"  #include "../core/logs.h" -//#include "../core/params.h"   // TODO : config @@ -316,16 +316,19 @@ int ensure_path_exists(const char *path)  *  Remarques   : -                                                            *  *                                                                             *  ******************************************************************************/ -#if 0 // TODO +  int make_tmp_file(const char *prefix, const char *suffix, char **filename)  {      int result;                             /* Flux ou code à retourner    */ -    const char *tmpdir;                     /* Répertoire d'accueil        */ -    bool status;                            /* Bilan d'un consultation     */ +    GSettings *settings;                    /* Configuration sollicitée    */ +    gchar *tmpdir;                          /* Répertoire d'accueil        */      size_t slen;                            /* Taille du suffixe           */ -    status = g_generic_config_get_value(get_main_configuration(), MPK_TMPDIR, &tmpdir); -    if (!status) return -1; +    /* Récupération d'un répertoire de travail temporaire */ + +    settings = g_settings_new("re.chrysalide.framework.paths"); + +    tmpdir = g_settings_get_string(settings, "tmp-work-dir");      slen = strlen(suffix); @@ -334,6 +337,12 @@ int make_tmp_file(const char *prefix, const char *suffix, char **filename)      else          asprintf(filename, "%s" G_DIR_SEPARATOR_S "%s-%d.XXXXXX", tmpdir, prefix, getpid()); +    g_free(tmpdir); + +    g_clear_object(&settings); + +    /* Mise en place d'un fichier temporaire */ +      result = ensure_path_exists(*filename);      if (result == 0) @@ -356,7 +365,7 @@ int make_tmp_file(const char *prefix, const char *suffix, char **filename)      return result;  } -#endif +  /******************************************************************************  *                                                                             * diff --git a/src/common/pathname.h b/src/common/pathname.h index 1b6624c..104833b 100644 --- a/src/common/pathname.h +++ b/src/common/pathname.h @@ -42,9 +42,7 @@ bool mkpath(const char *);  int ensure_path_exists(const char *);  /* Met en place un fichier temporaire. */ -#if 0 // TODO  int make_tmp_file(const char *, const char *, char **); -#endif  /* Copie un fichier. */  bool copy_file(const char *, const char *); diff --git a/src/common/sort.h b/src/common/sort.h index 39a6f33..27e3739 100644 --- a/src/common/sort.h +++ b/src/common/sort.h @@ -37,6 +37,9 @@ int sort_boolean(bool, bool);  /* Compare une valeur avec une autre. */  int sort_unsigned_long(unsigned long, unsigned long); +#define sort_size(v1, v2) \ +    sort_unsigned_long(v1, v2) +  /* Compare une valeur avec une autre. */  int sort_signed_long_long(signed long long, signed long long); diff --git a/src/common/szbin.h b/src/common/szbin.h new file mode 100644 index 0000000..8524ae3 --- /dev/null +++ b/src/common/szbin.h @@ -0,0 +1,282 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * szbin.h - prototypes pour une manipulation de données accompagnées d'une taille + * + * Copyright (C) 2024 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 _COMMON_SZBIN_H +#define _COMMON_SZBIN_H + + +#include <assert.h> +#include <malloc.h> +#include <string.h> + + +#include "datatypes.h" +#include "io.h" +#include "leb128.h" +#include "sort.h" + + + +/* Structure associant données et taille */ +typedef struct _sized_binary_t +{ +    union { + +        const char *static_data;        /* Données non modifiées       */ +        char *data;                     /* Chaîne de caractères        */ + +        const bin_t *static_bin_data;   /* Données brutes non modifiées*/ +        bin_t *bin_data;                /* Données brutes              */ + +    }; + +    size_t size;                        /* Taille correspondante       */ + +} sized_binary_t; + + +#define init_sized_binary(sb)               \ +    do                                      \ +    {                                       \ +        (sb)->data = NULL;                  \ +        (sb)->size = 0;                     \ +    }                                       \ +    while (0) + + +#define setup_sized_binary(sb, s)           \ +    do                                      \ +    {                                       \ +        (sb)->data = malloc(s);             \ +        (sb)->size = s;                     \ +    }                                       \ +    while (0) + + +#define setup_sized_binary_from_static_string(sb, s)    \ +    do                                                  \ +    {                                                   \ +        (sb)->static_data = s;                          \ +        (sb)->size = strlen(s) + 1;                     \ +    }                                                   \ +    while (0) + + +#define dup_into_sized_binary(sb, d, s)     \ +    do                                      \ +    {                                       \ +        size_t __size_once;                 \ +        __size_once = s;                    \ +        setup_sized_binary(sb, __size_once);\ +        memcpy((sb)->data, d, __size_once); \ +    }                                       \ +    while (0) + + +#define dup_sized_binary(dst, src)          \ +    dup_into_sized_binary((dst), (src)->static_data, (src)->size) + + +#define exit_sized_binary(sb)               \ +    do                                      \ +    {                                       \ +        if ((sb)->data != NULL)             \ +        {                                   \ +            free((sb)->data);               \ +            init_sized_binary(sb);          \ +        }                                   \ +    }                                       \ +    while (0) + + +#define resize_sized_binary(sb, s)          \ +    do                                      \ +    {                                       \ +        (sb)->size = s;                     \ +        (sb)->data = realloc((sb)->data,    \ +                             (sb)->size);   \ +    }                                       \ +    while (0) + + +#define add_to_sized_binary(sb, d, s)       \ +    do                                      \ +    {                                       \ +        size_t __old_size;                  \ +        __old_size = (sb)->size;            \ +        (sb)->size += s;                    \ +        (sb)->data = realloc((sb)->data,    \ +                             (sb)->size);   \ +        memcpy((sb)->data + __old_size,     \ +               d, s);                       \ +    }                                       \ +    while (0) + + +#define add_static_to_sized_binary(sb, d)   \ +    do                                      \ +    {                                       \ +        size_t __len;                       \ +        __len = sizeof(d) - 1;              \ +        add_to_sized_binary(sb, d, __len);  \ +    }                                       \ +    while (0) + + +#define memcmp_sized_binary(s1, s2)                             \ +    ({                                                          \ +        int __ret;                                              \ +        __ret = sort_size((s1)->size, (s2)->size);              \ +        if (__ret == 0)                                         \ +            __ret = memcmp((s1)->data, (s2)->data, (s1)->size); \ +        __ret;                                                  \ +    }) + + + +/** + * Conservations et rechargements. + */ + +#define load_sized_binary(sb, f)                                        \ +    ({                                                                  \ +        uleb128_t __sz;                                                 \ +        bool __ret;                                                     \ +        __ret = load_uleb128(&__sz, f);                                 \ +        if (__ret)                                                      \ +        {                                                               \ +            setup_sized_binary(sb, __sz);                               \ +            __ret = safe_read(f, (sb)->data, (sb)->size);               \ +            if (!__ret)                                                 \ +                exit_sized_binary(sb);                                  \ +        }                                                               \ +        __ret;                                                          \ +    }) + + +#define load_sized_binary_as_string(sb, f)                              \ +    ({                                                                  \ +        uleb128_t __sz;                                                 \ +        bool __ret;                                                     \ +        __ret = load_uleb128(&__sz, f);                                 \ +        if (__ret)                                                      \ +        {                                                               \ +            setup_sized_binary(sb, __sz + 1);                           \ +            __ret = safe_read(f, (sb)->data, __sz);                     \ +            if (!__ret)                                                 \ +                exit_sized_binary(sb);                                  \ +            (sb)->data[__sz] = '\0';                                    \ +        }                                                               \ +        __ret;                                                          \ +    }) + + +#define store_sized_binary(sb, f)                                       \ +    ({                                                                  \ +        bool __ret;                                                     \ +        __ret = store_uleb128((const uleb128_t []){ (sb)->size }, f);   \ +        if (__ret)                                                      \ +            __ret = safe_write(f, (sb)->static_data, (sb)->size);       \ +        __ret;                                                          \ +    }) + + +#define store_sized_binary_as_string(sb, f)                             \ +    ({                                                                  \ +        bool __ret;                                                     \ +        size_t __length;                                                \ +        assert((sb)->size >= 1);                                        \ +        __length = (sb)->size - 1;                                      \ +        assert((sb)->static_data[__length] == '\0');                    \ +        __ret = store_uleb128((const uleb128_t []){ __length }, f);     \ +        if (__ret)                                                      \ +            __ret = safe_write(f, (sb)->static_data, __length);         \ +        __ret;                                                          \ +    }) + + +#define unpack_sized_binary(sb, p, m)                                   \ +    ({                                                                  \ +        uleb128_t __sz;                                                 \ +        bool __ret;                                                     \ +        __ret = unpack_uleb128(&__sz, p, m);                            \ +        if (__ret)                                                      \ +        {                                                               \ +            setup_sized_binary(sb, __sz);                               \ +            memcpy((sb)->data, *p, (sb)->size);                         \ +            *((uint8_t **)p) += __sz;                                   \ +        }                                                               \ +        __ret;                                                          \ +    }) + + +#define unpack_sized_binary_as_string(sb, p, m)                         \ +    ({                                                                  \ +        uleb128_t __sz;                                                 \ +        bool __ret;                                                     \ +        __ret = unpack_uleb128(&__sz, p, m);                            \ +        if (__ret)                                                      \ +        {                                                               \ +            setup_sized_binary(sb, __sz + 1);                           \ +            memcpy((sb)->data, *p, __sz);                               \ +            (sb)->data[__sz] = '\0';                                    \ +            *((uint8_t **)p) += __sz;                                   \ +        }                                                               \ +        __ret;                                                          \ +    }) + + +#define pack_sized_binary(sb, l)                                        \ +    ({                                                                  \ +        uint8_t *__result;                                              \ +        size_t __pos;                                                   \ +        __result = pack_uleb128((const uleb128_t []){ (sb)->size }, l); \ +        __pos = *(l);                                                   \ +        *(l) += (sb)->size;                                             \ +        __result = realloc(__result, *(l) * sizeof(uint8_t));           \ +        memcpy(&__result[__pos], (sb)->static_data,                     \ +               ((sb)->size * sizeof(uint8_t)));                         \ +        __result;                                                       \ +    }) + + +#define pack_sized_binary_as_string(sb, l)                              \ +    ({                                                                  \ +        uint8_t *__result;                                              \ +        size_t __length;                                                \ +        size_t __pos;                                                   \ +        assert((sb)->size >= 1);                                        \ +        __length = (sb)->size - 1;                                      \ +        assert((sb)->static_data[__length] == '\0');                    \ +        __result = pack_uleb128((const uleb128_t []){ __length }, l);   \ +        __pos = *(l);                                                   \ +        *(l) += __length;                                               \ +        __result = realloc(__result, *(l) * sizeof(uint8_t));           \ +        memcpy(&__result[__pos], (sb)->static_data,                     \ +               (__length * sizeof(uint8_t)));                           \ +        __result;                                                       \ +    }) + + + +#endif  /* _COMMON_SZBIN_H */ diff --git a/src/common/szstr.h b/src/common/szstr.h index 406a9f1..c48d81f 100644 --- a/src/common/szstr.h +++ b/src/common/szstr.h @@ -54,7 +54,7 @@ typedef struct _sized_string_t  typedef sized_string_t sized_binary_t; - +/*  #define init_szstr(s)       \      do                      \      {                       \ @@ -62,6 +62,7 @@ typedef sized_string_t sized_binary_t;          (s)->len = 0;       \      }                       \      while (0) +*/  #define szstrdup(dst, src)                              \      do                                                  \ @@ -74,6 +75,7 @@ typedef sized_string_t sized_binary_t;  #define copy_szstr(d, s) (d) = (s); +/*  #define exit_szstr(s)           \      do                          \      {                           \ @@ -84,6 +86,7 @@ typedef sized_string_t sized_binary_t;          }                       \      }                           \      while (0) +*/  #define szstrcmp(s1, s2)                                            \      ({                                                              \ diff --git a/src/common/xdg.c b/src/common/xdg.c index cabff75..eb64dad 100644 --- a/src/common/xdg.c +++ b/src/common/xdg.c @@ -24,20 +24,41 @@  #include "xdg.h" -#include <dirent.h> -#include <errno.h> +#include <assert.h>  #include <glib.h>  #include <malloc.h> -#include <stdlib.h>  #include <string.h> +#include <unistd.h> + + +#include "pathname.h" + + + +/** + * Cf. https://specifications.freedesktop.org/basedir-spec/basedir-spec-latest.html + */ + +/* $HOME/.cache */ +#define CACHE_HOME_SUFFIX ".cache" G_DIR_SEPARATOR_S + +/* $HOME/.config */ +#define CONFIG_HOME_SUFFIX ".config" G_DIR_SEPARATOR_S + +/* $HOME/.local/share */ +#define DATA_HOME_SUFFIX ".local" G_DIR_SEPARATOR_S "share" G_DIR_SEPARATOR_S + +/* $HOME/.local/state */ +#define STATE_HOME_SUFFIX ".local" G_DIR_SEPARATOR_S "state" G_DIR_SEPARATOR_S  /******************************************************************************  *                                                                             *  *  Paramètres  : suffix = élément visé dans le répertoire de configuration.   * +*                create = assure la mise en place du répertoire final.        *  *                                                                             * -*  Description : Détermine le chemin d'un répertoire selon les specs. XDG.    * +*  Description : Détermine le chemin d'un répertoire de données XDG.          *  *                                                                             *  *  Retour      : Chemin d'accès aux configurations personnelles ou NULL.      *  *                                                                             * @@ -45,70 +66,321 @@  *                                                                             *  ******************************************************************************/ -char *get_xdg_config_dir(const char *suffix) +char *get_xdg_cache_dir(const char *suffix, bool create)  {      char *result;                           /* Chemin d'accès à renvoyer   */      const char *env;                        /* Valeur de l'environnement   */ -    DIR *directory;                         /* Répertoire avec contenu ?   */ -    struct dirent *entry;                   /* Elément de répertoire       */ +    int ret;                                /* Bilan d'une assurance       */ + +    assert(suffix[0] != G_DIR_SEPARATOR);      result = NULL; -    env = getenv("XDG_CONFIG_HOME"); +    env = getenv("XDG_CACHE_HOME");      if (env != NULL && env[0] != '\0')      { -        directory = opendir(env); -        if (directory == NULL) goto default_cfg_dir; +        result = calloc(strlen(env) + 1 + strlen(suffix) + 1, sizeof(char)); + +        strcpy(result, env); + +        if (env[strlen(env) - 1] != G_DIR_SEPARATOR) +            strcat(result, G_DIR_SEPARATOR_S); + +        strcat(result, suffix); + +    } + +    else +    { +        env = getenv("HOME"); +        if (env == NULL || env[0] == '\0') goto no_env; + +        result = calloc(strlen(env) + 1 + strlen(CACHE_HOME_SUFFIX) + strlen(suffix) + 1, sizeof(char)); + +        strcpy(result, env); + +        if (env[strlen(env) - 1] != G_DIR_SEPARATOR) +            strcat(result, G_DIR_SEPARATOR_S); + +        strcat(result, CACHE_HOME_SUFFIX); +        strcat(result, suffix); + +    } + +    if (create) +    { +        ret = ensure_path_exists(result); -        while (1) +        if (ret != 0)          { -            errno = 0; +            free(result); +            result = NULL; +        } -            entry = readdir(directory); +    } -            if (entry == NULL) -            { -                if (errno != 0) -                    perror("readdir"); + no_env: -                break; +    return result; + +} -            } -            if (strcmp(entry->d_name, ".") == 0) continue; -            if (strcmp(entry->d_name, "..") == 0) continue; +/****************************************************************************** +*                                                                             * +*  Paramètres  : suffix = élément visé dans le répertoire de configuration.   * +*                create = assure la mise en place du répertoire final.        * +*                                                                             * +*  Description : Détermine le chemin d'un répertoire de données XDG.          * +*                                                                             * +*  Retour      : Chemin d'accès aux configurations personnelles ou NULL.      * +*                                                                             * +*  Remarques   : cf. http://standards.freedesktop.org/basedir-spec/.          * +*                                                                             * +******************************************************************************/ -            result = calloc(strlen(env) + 2 + strlen(suffix) + 1, sizeof(char)); -            strcpy(result, env); +char *get_xdg_config_dir(const char *suffix, bool create) +{ +    char *result;                           /* Chemin d'accès à renvoyer   */ +    const char *env;                        /* Valeur de l'environnement   */ +    int ret;                                /* Bilan d'une assurance       */ -            if (env[strlen(env) - 1] != G_DIR_SEPARATOR) -                strcat(result, G_DIR_SEPARATOR_S); +    assert(suffix[0] != G_DIR_SEPARATOR); -            strcat(result, "."); -            strcat(result, suffix); +    result = NULL; +    env = getenv("XDG_CONFIG_HOME"); + +    if (env != NULL && env[0] != '\0') +    { +        result = calloc(strlen(env) + 1 + strlen(suffix) + 1, sizeof(char)); + +        strcpy(result, env); + +        if (env[strlen(env) - 1] != G_DIR_SEPARATOR) +            strcat(result, G_DIR_SEPARATOR_S); + +        strcat(result, suffix); + +    } + +    else +    { +        env = getenv("HOME"); +        if (env == NULL || env[0] == '\0') goto no_env; + +        result = calloc(strlen(env) + 1 + strlen(CONFIG_HOME_SUFFIX) + strlen(suffix) + 1, sizeof(char)); + +        strcpy(result, env); + +        if (env[strlen(env) - 1] != G_DIR_SEPARATOR) +            strcat(result, G_DIR_SEPARATOR_S); + +        strcat(result, CONFIG_HOME_SUFFIX); +        strcat(result, suffix); + +    } + +    if (create) +    { +        ret = ensure_path_exists(result); + +        if (ret != 0) +        { +            free(result); +            result = NULL;          } -        closedir(directory); +    } + + no_env: + +    return result; + +} + + +/****************************************************************************** +*                                                                             * +*  Paramètres  : suffix = élément visé dans le répertoire de configuration.   * +*                create = assure la mise en place du répertoire final.        * +*                                                                             * +*  Description : Détermine le chemin d'un répertoire de données XDG.          * +*                                                                             * +*  Retour      : Chemin d'accès aux configurations personnelles ou NULL.      * +*                                                                             * +*  Remarques   : cf. http://standards.freedesktop.org/basedir-spec/.          * +*                                                                             * +******************************************************************************/ + +char *get_xdg_data_dir(const char *suffix, bool create) +{ +    char *result;                           /* Chemin d'accès à renvoyer   */ +    const char *env;                        /* Valeur de l'environnement   */ +    int ret;                                /* Bilan d'une assurance       */ + +    assert(suffix[0] != G_DIR_SEPARATOR); + +    result = NULL; + +    env = getenv("XDG_DATA_HOME"); + +    if (env != NULL && env[0] != '\0') +    { +        result = calloc(strlen(env) + 1 + strlen(suffix) + 1, sizeof(char)); + +        strcpy(result, env); + +        if (env[strlen(env) - 1] != G_DIR_SEPARATOR) +            strcat(result, G_DIR_SEPARATOR_S); + +        strcat(result, suffix); + +    } + +    else +    { +        env = getenv("HOME"); +        if (env == NULL || env[0] == '\0') goto no_env; + +        result = calloc(strlen(env) + 1 + strlen(DATA_HOME_SUFFIX) + strlen(suffix) + 1, sizeof(char)); + +        strcpy(result, env); + +        if (env[strlen(env) - 1] != G_DIR_SEPARATOR) +            strcat(result, G_DIR_SEPARATOR_S); + +        strcat(result, DATA_HOME_SUFFIX); +        strcat(result, suffix);      } - default_cfg_dir: +    if (create) +    { +        ret = ensure_path_exists(result); + +        if (ret != 0) +        { +            free(result); +            result = NULL; +        } + +    } + + no_env: + +    return result; + +} + + +/****************************************************************************** +*                                                                             * +*  Paramètres  : suffix = élément visé dans le répertoire de configuration.   * +*                create = assure la mise en place du répertoire final.        * +*                                                                             * +*  Description : Détermine le chemin d'un répertoire de données XDG.          * +*                                                                             * +*  Retour      : Chemin d'accès aux configurations personnelles ou NULL.      * +*                                                                             * +*  Remarques   : cf. http://standards.freedesktop.org/basedir-spec/.          * +*                                                                             * +******************************************************************************/ + +char *get_xdg_state_dir(const char *suffix, bool create) +{ +    char *result;                           /* Chemin d'accès à renvoyer   */ +    const char *env;                        /* Valeur de l'environnement   */ +    int ret;                                /* Bilan d'une assurance       */ + +    assert(suffix[0] != G_DIR_SEPARATOR); + +    result = NULL; + +    env = getenv("XDG_STATE_HOME"); + +    if (env != NULL && env[0] != '\0') +    { +        result = calloc(strlen(env) + 1 + strlen(suffix) + 1, sizeof(char)); + +        strcpy(result, env); + +        if (env[strlen(env) - 1] != G_DIR_SEPARATOR) +            strcat(result, G_DIR_SEPARATOR_S); -    if (result == NULL) +        strcat(result, suffix); + +    } + +    else      {          env = getenv("HOME"); -        if (env == NULL || env[0] == '\0') return NULL; +        if (env == NULL || env[0] == '\0') goto no_env; + +        result = calloc(strlen(env) + 1 + strlen(STATE_HOME_SUFFIX) + strlen(suffix) + 1, sizeof(char)); + +        strcpy(result, env); + +        if (env[strlen(env) - 1] != G_DIR_SEPARATOR) +            strcat(result, G_DIR_SEPARATOR_S); + +        strcat(result, STATE_HOME_SUFFIX); +        strcat(result, suffix); + +    } + +    if (create) +    { +        ret = ensure_path_exists(result); + +        if (ret != 0) +        { +            free(result); +            result = NULL; +        } + +    } -        result = calloc(strlen(env) + 1 + strlen(".config" G_DIR_SEPARATOR_S) + strlen(suffix) + 1, sizeof(char)); + no_env: + +    return result; + +} + + +/****************************************************************************** +*                                                                             * +*  Paramètres  : suffix = élément visé dans le répertoire de configuration.   * +*                                                                             * +*  Description : Détermine le chemin d'un répertoire éphémère XDG.            * +*                                                                             * +*  Retour      : Chemin d'accès aux configurations personnelles ou NULL.      * +*                                                                             * +*  Remarques   : cf. http://standards.freedesktop.org/basedir-spec/.          * +*                                                                             * +******************************************************************************/ + +char *get_xdg_runtime_dir(const char *suffix) +{ +    char *result;                           /* Chemin d'accès à renvoyer   */ +    const char *env;                        /* Valeur de l'environnement   */ + +    assert(suffix[0] != G_DIR_SEPARATOR); + +    result = NULL; + +    env = getenv("XDG_RUNTIME_DIR"); + +    if (env != NULL && env[0] != '\0') +    { +        result = calloc(strlen(env) + 1 + strlen(suffix) + 1, sizeof(char));          strcpy(result, env);          if (env[strlen(env) - 1] != G_DIR_SEPARATOR)              strcat(result, G_DIR_SEPARATOR_S); -        strcat(result, ".config" G_DIR_SEPARATOR_S);          strcat(result, suffix);      } diff --git a/src/common/xdg.h b/src/common/xdg.h index c9c2327..a6cd91d 100644 --- a/src/common/xdg.h +++ b/src/common/xdg.h @@ -25,9 +25,24 @@  #define _COMMON_XDG_H +#include <stdbool.h> -/* Détermine le chemin d'un répertoire selon les specs. XDG. */ -char *get_xdg_config_dir(const char *); + + +/* Détermine le chemin d'un répertoire de données XDG. */ +char *get_xdg_cache_dir(const char *, bool); + +/* Détermine le chemin d'un répertoire de données XDG. */ +char *get_xdg_config_dir(const char *, bool); + +/* Détermine le chemin d'un répertoire de données XDG. */ +char *get_xdg_data_dir(const char *, bool); + +/* Détermine le chemin d'un répertoire de données XDG. */ +char *get_xdg_state_dir(const char *, bool); + +/* Détermine le chemin d'un répertoire éphémère XDG. */ +char *get_xdg_runtime_dir(const char *); diff --git a/src/core/Makefile.am b/src/core/Makefile.am index 5bcb13a..15ed866 100644 --- a/src/core/Makefile.am +++ b/src/core/Makefile.am @@ -4,11 +4,8 @@ noinst_LTLIBRARIES = libcore4.la # libcore.la  libcore_la_SOURCES =					\  	collections.h collections.c			\  	columns.h							\ -	core.h core.c						\  	demanglers.h demanglers.c			\ -	global.h global.c					\  	logs.h logs.c						\ -	nproc.h nproc.c						\  	params.h params.c					\  	paths.h paths.c						\  	processors.h processors.c			\ @@ -18,10 +15,15 @@ libcore_la_CFLAGS = $(TOOLKIT_CFLAGS) $(LIBXML_CFLAGS)  libcore4_la_SOURCES =						\ +	core.h core.c							\ +	global.h global.c						\  	logs.h logs.c							\ -	paths.h paths.c +	nox.h nox.c								\ +	nproc.h nproc.c							\ +	paths.h paths.c							\ +	processors.h processors.c -libcore4_la_CFLAGS = $(TOOLKIT_CFLAGS) +libcore4_la_CFLAGS = $(TOOLKIT_CFLAGS) $(LIBSSL_CFLAGS)  devdir = $(includedir)/chrysalide/$(subdir:src/%=core/%) diff --git a/src/core/core.c b/src/core/core.c index f67e23d..c730fad 100644 --- a/src/core/core.c +++ b/src/core/core.c @@ -2,7 +2,7 @@  /* Chrysalide - Outil d'analyse de fichiers binaires   * core.c - chargement et le déchargement du tronc commun   * - * Copyright (C) 2014-2019 Cyrille Bagard + * Copyright (C) 2014-2024 Cyrille Bagard   *   *  This file is part of Chrysalide.   * @@ -24,6 +24,97 @@  #include "core.h" +#include "global.h" +#include "processors.h" + + + +/* Statuts de chargement */ +static AvailableCoreComponent __loaded = ACC_NONE; + + + +/****************************************************************************** +*                                                                             * +*  Paramètres  : flags = liste d'éléments à charger.                          * +*                                                                             * +*  Description : Charge une sélection d'éléments de base du programme.        * +*                                                                             * +*  Retour      : Bilan de l'opération.                                        * +*                                                                             * +*  Remarques   : -                                                            * +*                                                                             * +******************************************************************************/ + +bool load_core_components(AvailableCoreComponent flags) +{ +    bool result;                            /* Bilan à retourner           */ + +    result = true; + +    if ((flags & ACC_GLOBAL_VARS) != 0 && (__loaded & ACC_GLOBAL_VARS) == 0) +    { +        set_secret_storage(g_secret_storage_new(NULL)); + +        set_work_queue(g_work_queue_new()); + +        __loaded |= ACC_GLOBAL_VARS; + +    } + +    if ((flags & ACC_CODE_ANALYSIS) != 0 && (__loaded & ACC_CODE_ANALYSIS) == 0) +    { +        register_arch_gtypes(); + +        init_operands_factory(); + +    } + +    return result; + +} + + +/****************************************************************************** +*                                                                             * +*  Paramètres  : flags = liste d'éléments à décharger.                        * +*                                                                             * +*  Description : Décharge une sélection d'éléments de base du programme.      * +*                                                                             * +*  Retour      : -                                                            * +*                                                                             * +*  Remarques   : -                                                            * +*                                                                             * +******************************************************************************/ + +void unload_core_components(AvailableCoreComponent flags) +{ +    if ((flags & ACC_CODE_ANALYSIS) != 0 && (__loaded & ACC_CODE_ANALYSIS) == 0) +    { +        exit_operands_factory(); + +    } + +    if ((flags & ACC_GLOBAL_VARS) != 0 && (__loaded & ACC_GLOBAL_VARS) == 0) +    { +        set_work_queue(NULL); + +        set_secret_storage(NULL); + +        __loaded &= ~ACC_GLOBAL_VARS; + +    } + +} + + + + + + + +#if 0 +  #include <stdlib.h>  #include <time.h>  #include <unistd.h> @@ -35,7 +126,6 @@  #include "demanglers.h"  #include "global.h"  #include "params.h" -#include "processors.h"  #include "queue.h"  #include "../analysis/scan/core.h"  #ifdef INCLUDE_MAGIC_SUPPORT @@ -119,9 +209,6 @@ bool load_all_core_components(bool cs)              if (result) result = init_segment_content_hash_table(); -            register_arch_gtypes(); -            init_operands_factory(); -          }      } @@ -147,8 +234,6 @@ void unload_all_core_components(bool cs)  {      if (cs)      { -        exit_operands_factory(); -          exit_segment_content_hash_table();          unload_demanglers_definitions(); @@ -255,3 +340,5 @@ void unload_core_components(AvailableCoreComponent flags)      }  } + +#endif diff --git a/src/core/core.h b/src/core/core.h index def2813..640476a 100644 --- a/src/core/core.h +++ b/src/core/core.h @@ -2,7 +2,7 @@  /* Chrysalide - Outil d'analyse de fichiers binaires   * core.h - prototypes pour le chargement et le déchargement du tronc commun   * - * Copyright (C) 2014-2018 Cyrille Bagard + * Copyright (C) 2014-2024 Cyrille Bagard   *   *  This file is part of Chrysalide.   * @@ -29,17 +29,15 @@ -/* Charge les éléments de base du programme. */ -bool load_all_core_components(bool); - -/* Décharge les éléments de base du programme. */ -void unload_all_core_components(bool); - -  /* Eléments à (dé)charger disponibles */  typedef enum _AvailableCoreComponent  { -    ACC_SCAN_FEATURES = (1 << 0),           /* Espace de noms pour scan    */ +    ACC_NONE            = (0 << 0),         /* Statut initial              */ +    ACC_GLOBAL_VARS     = (1 << 0),         /* Singletons globaux          */ +    ACC_CODE_ANALYSIS   = (1 << 1),         /* Désassemblage de code       */ +    ACC_SCAN_FEATURES   = (1 << 2),         /* Espace de noms pour scan    */ + +    ACC_ALL_COMPONENTS  = (1 << 3) - 1  } AvailableCoreComponent; diff --git a/src/core/global.c b/src/core/global.c index c99d711..0275e09 100644 --- a/src/core/global.c +++ b/src/core/global.c @@ -2,7 +2,7 @@  /* Chrysalide - Outil d'analyse de fichiers binaires   * global.c - conservation et accès aux variables globales   * - * Copyright (C) 2017-2019 Cyrille Bagard + * Copyright (C) 2017-2024 Cyrille Bagard   *   *  This file is part of Chrysalide.   * @@ -24,38 +24,29 @@  #include "global.h" -#include <assert.h> +#include "../glibext/helpers.h" -/* Mode de fonctionnement */ -static bool _batch_mode = false; +/* Décompte des émissions et réceptions */ +static GMutex _network_mutex; +static size_t _bytes_received = 0; +static size_t _bytes_sent = 0;  /* Gestionnaire de tâches parallèles */  static GWorkQueue *_queue = NULL; -/* Explorateur de contenus */ -static GContentExplorer *_explorer = NULL; - -/* Résolveur de contenus */ -static GContentResolver *_resolver = NULL; - -/* Espace de noms racine pour ROST */ -static GScanNamespace *_rost_root_ns = NULL; - -/* Projet global actif */ -static GStudyProject *_project = NULL; - -/* Avertisseur de changement de projet principal */ -static current_project_change_cb _project_notify = NULL; +/* Gardien des secrets avec support des stockages */ +static GSecretStorage *_storage = NULL;  /******************************************************************************  *                                                                             * -*  Paramètres  : -                                                            * +*  Paramètres  : received = quantité d'octets reçus jusqu'à présent. [OUT]    * +*                sent     = quantité d'octets émis jusqu'à présent. [OUT]     *  *                                                                             * -*  Description : Note un mode d'exécution sans interface.                     * +*  Description : Fournit les volumes d'octets échangés sur le réseau.         *  *                                                                             *  *  Retour      : -                                                            *  *                                                                             * @@ -63,28 +54,39 @@ static current_project_change_cb _project_notify = NULL;  *                                                                             *  ******************************************************************************/ -void set_batch_mode(void) +void get_network_stats(size_t *received, size_t *sent)  { -    _batch_mode = true; +    g_mutex_lock(&_network_mutex); + +    *received = _bytes_received; +    *sent = _bytes_sent; + +    g_mutex_unlock(&_network_mutex);  }  /******************************************************************************  *                                                                             * -*  Paramètres  : -                                                            * +*  Paramètres  : received = quantité d'octets reçus supplémentaire.           * +*                sent     = quantité d'octets émis supplémentaire.            *  *                                                                             * -*  Description : Indique le mode d'exécution courant du programme.            * +*  Description : Augmente les volumes d'octets échangés sur le réseau.        *  *                                                                             * -*  Retour      : true si le fonctionnement est sans interface.                * +*  Retour      : -                                                            *  *                                                                             *  *  Remarques   : -                                                            *  *                                                                             *  ******************************************************************************/ -bool is_batch_mode(void) +void update_network_stats(size_t received, size_t sent)  { -    return _batch_mode; +    g_mutex_lock(&_network_mutex); + +    _bytes_received += received; +    _bytes_sent += sent; + +    g_mutex_unlock(&_network_mutex);  } @@ -101,9 +103,10 @@ bool is_batch_mode(void)  *                                                                             *  ******************************************************************************/ -void set_work_queue(GWorkQueue *queue) +void set_work_queue(/* __steal */GWorkQueue *queue)  { -    assert(_queue == NULL); +    if (_queue != NULL) +        unref_object(_queue);      _queue = queue; @@ -124,6 +127,8 @@ void set_work_queue(GWorkQueue *queue)  GWorkQueue *get_work_queue(void)  { +    ref_object(_queue); +      return _queue;  } @@ -131,6 +136,131 @@ GWorkQueue *get_work_queue(void)  /******************************************************************************  *                                                                             * +*  Paramètres  : queue = nouveau stockage sécurisé à mémoriser ou NULL.       * +*                                                                             * +*  Description : Définit le stockage sécurisé principal.                      * +*                                                                             * +*  Retour      : -                                                            * +*                                                                             * +*  Remarques   : -                                                            * +*                                                                             * +******************************************************************************/ + +void set_secret_storage(/* __steal */GSecretStorage *storage) +{ +    if (_storage != NULL) +        unref_object(_storage); + +    _storage = storage; + +} + + +/****************************************************************************** +*                                                                             * +*  Paramètres  : -                                                            * +*                                                                             * +*  Description : Fournit le stockage sécurisé principal.                      * +*                                                                             * +*  Retour      : Gestionnaire de traitements parallèles courant.              * +*                                                                             * +*  Remarques   : -                                                            * +*                                                                             * +******************************************************************************/ + +GSecretStorage *get_secret_storage(void) +{ +    ref_object(_storage); + +    return _storage; + +} + + + + + + + + + + + + + + + +#if 0 + +#include <assert.h> + + + +/* Mode de fonctionnement */ +static bool _batch_mode = false; + +/* Gestionnaire de tâches parallèles */ +//static GWorkQueue *_queue = NULL; + +/* Explorateur de contenus */ +static GContentExplorer *_explorer = NULL; + +/* Résolveur de contenus */ +static GContentResolver *_resolver = NULL; + +/* Espace de noms racine pour ROST */ +static GScanNamespace *_rost_root_ns = NULL; + +/* Projet global actif */ +static GStudyProject *_project = NULL; + +/* Avertisseur de changement de projet principal */ +static current_project_change_cb _project_notify = NULL; + + + +/****************************************************************************** +*                                                                             * +*  Paramètres  : -                                                            * +*                                                                             * +*  Description : Note un mode d'exécution sans interface.                     * +*                                                                             * +*  Retour      : -                                                            * +*                                                                             * +*  Remarques   : -                                                            * +*                                                                             * +******************************************************************************/ + +void set_batch_mode(void) +{ +    _batch_mode = true; + +} + + +/****************************************************************************** +*                                                                             * +*  Paramètres  : -                                                            * +*                                                                             * +*  Description : Indique le mode d'exécution courant du programme.            * +*                                                                             * +*  Retour      : true si le fonctionnement est sans interface.                * +*                                                                             * +*  Remarques   : -                                                            * +*                                                                             * +******************************************************************************/ + +bool is_batch_mode(void) +{ +    return _batch_mode; + +} + + + + +/****************************************************************************** +*                                                                             *  *  Paramètres  : explorer = éventuelle adresse du nouveau gestionnaire.       *  *                                                                             *  *  Description : Définit l'adresse de l'explorateur de contenus courant.      * @@ -343,3 +473,5 @@ void register_project_change_notification(current_project_change_cb notify)      _project_notify = notify;  } + +#endif diff --git a/src/core/global.h b/src/core/global.h index 0a9172b..f5d8a62 100644 --- a/src/core/global.h +++ b/src/core/global.h @@ -2,7 +2,7 @@  /* Chrysalide - Outil d'analyse de fichiers binaires   * global.h - prototypes pour la conservation et l'accès aux variables globales   * - * Copyright (C) 2017-2018 Cyrille Bagard + * Copyright (C) 2017-2024 Cyrille Bagard   *   *  This file is part of Chrysalide.   * @@ -25,6 +25,35 @@  #define _CORE_GLOBAL_H +#include "../glibext/secstorage.h" +#include "../glibext/workqueue.h" + + + +/* Fournit les volumes d'octets échangés sur le réseau. */ +void get_network_stats(size_t *, size_t *); + +/* Augmente les volumes d'octets échangés sur le réseau. */ +void update_network_stats(size_t, size_t); + +/* Définit le gestionnaire de traitements parallèles courant. */ +void set_work_queue(/* __steal */GWorkQueue *); + +/* Fournit le gestionnaire de traitements parallèles courant. */ +GWorkQueue *get_work_queue(void); + +/* Définit le stockage sécurisé principal. */ +void set_secret_storage(/* __steal */GSecretStorage *); + +/* Fournit le stockage sécurisé principal. */ +GSecretStorage *get_secret_storage(void); + + + + + +#if 0 +  #include <stdbool.h> @@ -42,10 +71,10 @@ void set_batch_mode(void);  bool is_batch_mode(void);  /* Définit le gestionnaire de traitements parallèles courant. */ -void set_work_queue(GWorkQueue *); +//void set_work_queue(GWorkQueue *);  /* Fournit le gestionnaire de traitements parallèles courant. */ -GWorkQueue *get_work_queue(void); +//GWorkQueue *get_work_queue(void);  /* Définit l'adresse de l'explorateur de contenus courant. */  void set_current_content_explorer(GContentExplorer *); @@ -78,5 +107,8 @@ typedef void (* current_project_change_cb) (GStudyProject *, bool);  void register_project_change_notification(current_project_change_cb); +#endif + +  #endif  /* _CORE_GLOBAL_H */ diff --git a/src/core/logs.h b/src/core/logs.h index e8df8bd..3719c6b 100644 --- a/src/core/logs.h +++ b/src/core/logs.h @@ -162,6 +162,15 @@ void log_variadic_message(LogMessageType, const char *, ...);      }                                                                                                   \      while (0) +#define LOG_ERROR_ZIP(func, err)                                                                        \ +    do                                                                                                  \ +    {                                                                                                   \ +        const char *__msg;                                                                              \ +         __msg = zip_error_strerror(err);                                                               \ +        log_variadic_message(LMT_EXT_ERROR, "[%s:%u] %s: %s", __FUNCTION__, __LINE__, func, __msg);     \ +    }                                                                                                   \ +    while (0) +  #endif  /* _CORE_LOGS_H */ diff --git a/src/core/nox.c b/src/core/nox.c new file mode 100644 index 0000000..ccf9de2 --- /dev/null +++ b/src/core/nox.c @@ -0,0 +1,62 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * nox.c - indication de présence ou d'absence de support graphique + * + * Copyright (C) 2024 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 "nox.h" + + +#include <stddef.h> + + +#include "../common/compiler.h" + + + +/*  Indique la présence ou l'absence d'un affichage graphique. */ +__weak bool _run_in_nox_mode(void); + + + +/****************************************************************************** +*                                                                             * +*  Paramètres  : -                                                            * +*                                                                             * +*  Description : Indique la présence ou l'absence d'un affichage graphique.   * +*                                                                             * +*  Retour      : Statut à transmettre.                                        * +*                                                                             * +*  Remarques   : -                                                            * +*                                                                             * +******************************************************************************/ + +bool run_in_nox_mode(void) +{ +    bool result;                            /* Statut à retournr           */ + +    if (_run_in_nox_mode == NULL) +        result = true; +    else +        result = _run_in_nox_mode(); + +    return result; + +} diff --git a/src/core/nox.h b/src/core/nox.h new file mode 100644 index 0000000..c2c225d --- /dev/null +++ b/src/core/nox.h @@ -0,0 +1,37 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * nox.h - prototypes pour l'indication de présence ou d'absence de support graphique + * + * Copyright (C) 2024 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 _CORE_NOX_H +#define _CORE_NOX_H + + +#include <stdbool.h> + + + +/* Indique la présence ou l'absence d'un affichage graphique. */ +bool run_in_nox_mode(void); + + + +#endif  /* _CORE_NOX_H */ diff --git a/src/core/processors.c b/src/core/processors.c index e4a558f..056fc23 100644 --- a/src/core/processors.c +++ b/src/core/processors.c @@ -2,7 +2,7 @@  /* Chrysalide - Outil d'analyse de fichiers binaires   * processors.c - enregistrement et fourniture des architectures supportées   * - * Copyright (C) 2015-2020 Cyrille Bagard + * Copyright (C) 2015-2025 Cyrille Bagard   *   *  This file is part of Chrysalide.   * @@ -29,13 +29,13 @@  #include <pthread.h>  #include <string.h> - +#if 0  #include "../arch/instructions/raw.h"  #include "../arch/instructions/undefined.h"  #include "../arch/operands/immediate.h"  #include "../arch/operands/register.h"  #include "../arch/operands/target.h" - +#endif  /* Cache des singletons d'opérandes */ @@ -77,12 +77,12 @@ static proc_t *find_processor_by_key(const char *);  void register_arch_gtypes(void)  { -    g_type_ensure(G_TYPE_RAW_INSTRUCTION); -    g_type_ensure(G_TYPE_UNDEF_INSTRUCTION); +    //g_type_ensure(G_TYPE_RAW_INSTRUCTION); +    //g_type_ensure(G_TYPE_UNDEF_INSTRUCTION); -    g_type_ensure(G_TYPE_IMM_OPERAND); -    g_type_ensure(G_TYPE_REGISTER_OPERAND); -    g_type_ensure(G_TYPE_TARGET_OPERAND); +    //g_type_ensure(G_TYPE_IMM_OPERAND); +    //g_type_ensure(G_TYPE_REGISTER_OPERAND); +    //g_type_ensure(G_TYPE_TARGET_OPERAND);  } @@ -126,7 +126,7 @@ GSingletonFactory *get_operands_factory(void)      result = __operands_factory; -    g_object_ref(G_OBJECT(result)); +    ref_object(result);      return result; @@ -154,7 +154,7 @@ void exit_operands_factory(void)  } - +#if 0  /******************************************************************************  *                                                                             *  *  Paramètres  : type = type GLib représentant le type à instancier.          * @@ -206,7 +206,7 @@ bool register_processor_type(GType type)   done: -    g_object_unref(G_OBJECT(proc)); +    unref_object(proc);      return result; @@ -341,3 +341,4 @@ GArchProcessor *get_arch_processor_for_key(const char *key)      return result;  } +#endif diff --git a/src/core/processors.h b/src/core/processors.h index 6aa2d1e..b622305 100644 --- a/src/core/processors.h +++ b/src/core/processors.h @@ -29,7 +29,7 @@  #include <stdbool.h> -#include "../arch/processor.h" +//#include "../arch/processor.h"  #include "../glibext/singleton.h" @@ -45,7 +45,7 @@ GSingletonFactory *get_operands_factory(void);  /* Supprime le fournisseur d'instances uniques d'opérandes. */  void exit_operands_factory(void); - +#if 0  /* Enregistre un processeur pour une architecture donnée. */  bool register_processor_type(GType); @@ -57,7 +57,7 @@ char **get_all_processor_keys(size_t *);  /* Fournit le processeur d'architecture correspondant à un nom. */  GArchProcessor *get_arch_processor_for_key(const char *); - +#endif  #endif  /* _CORE_PROCESSORS_H */ diff --git a/src/data/Makefile.am b/src/data/Makefile.am new file mode 100644 index 0000000..8cbe67a --- /dev/null +++ b/src/data/Makefile.am @@ -0,0 +1,2 @@ + +SUBDIRS = images diff --git a/src/data/images/Makefile.am b/src/data/images/Makefile.am new file mode 100644 index 0000000..d5ec84f --- /dev/null +++ b/src/data/images/Makefile.am @@ -0,0 +1,33 @@ + +BUILT_SOURCES = resources.h resources.c + +noinst_LTLIBRARIES  = libdataimages.la + +RES_FILES =									\ +	about-bg.png							\ +	dock-station-left-symbolic.svg			\ +	dock-station-right-symbolic.svg			\ +	dock-station-bottom-symbolic.svg		\ +	logs-symbolic.svg + +libdataimages_la_SOURCES =					\ +	resources.h resources.c + +libdataimages_la_CFLAGS = $(LIBGIOUNIX_CFLAGS) + + +devdir = $(includedir)/chrysalide/$(subdir:src/%=core/%) + +dev_HEADERS = $(libdataimages_la_SOURCES:%c=) + + +resources.c: gresource.xml $(RES_FILES) +	glib-compile-resources --target=$@ --sourcedir=$(srcdir) --generate-source --c-name data_images gresource.xml + +resources.h: gresource.xml +	glib-compile-resources --target=$@ --sourcedir=$(srcdir) --generate-header --c-name data_images gresource.xml + + +CLEANFILES = resources.h resources.c + +EXTRA_DIST = gresource.xml $(RES_FILES) diff --git a/src/data/images/dock-station-bottom-symbolic.svg b/src/data/images/dock-station-bottom-symbolic.svg new file mode 100644 index 0000000..37084ac --- /dev/null +++ b/src/data/images/dock-station-bottom-symbolic.svg @@ -0,0 +1,197 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<!-- Created with Inkscape (http://www.inkscape.org/) --> + +<svg +   width="180" +   height="180" +   viewBox="0 0 180 180" +   version="1.1" +   id="svg5" +   inkscape:version="1.2.2 (b0a8486541, 2022-12-01)" +   sodipodi:docname="dock-station-bottom-symbolic.svg" +   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" +   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" +   xmlns="http://www.w3.org/2000/svg" +   xmlns:svg="http://www.w3.org/2000/svg"> +  <sodipodi:namedview +     id="namedview7" +     pagecolor="#ffffff" +     bordercolor="#000000" +     borderopacity="0.25" +     inkscape:showpageshadow="2" +     inkscape:pageopacity="0.0" +     inkscape:pagecheckerboard="true" +     inkscape:deskcolor="#d1d1d1" +     inkscape:document-units="px" +     showgrid="false" +     inkscape:zoom="4.2708118" +     inkscape:cx="87.219952" +     inkscape:cy="89.444353" +     inkscape:window-width="1920" +     inkscape:window-height="1011" +     inkscape:window-x="0" +     inkscape:window-y="0" +     inkscape:window-maximized="1" +     inkscape:current-layer="g3929" /> +  <defs +     id="defs2"> +    <clipPath +       id="k"> +      <path +         d="M 0,0 H 800 V 800 H 0 Z" +         id="path1320" /> +    </clipPath> +    <mask +       id="j"> +      <g +         filter="url(#a)" +         id="g1317"> +        <path +           d="M 0,0 H 16 V 16 H 0 Z" +           fill-opacity="0.35" +           id="path1315" /> +      </g> +    </mask> +    <filter +       id="a" +       height="1" +       width="1" +       x="0" +       y="0"> +      <feColorMatrix +         in="SourceGraphic" +         type="matrix" +         values="0 0 0 0 1 0 0 0 0 1 0 0 0 0 1 0 0 0 1 0" +         id="feColorMatrix1280" /> +    </filter> +    <clipPath +       id="i"> +      <path +         d="M 0,0 H 800 V 800 H 0 Z" +         id="path1312" /> +    </clipPath> +    <mask +       id="h"> +      <g +         filter="url(#a)" +         id="g1309"> +        <path +           d="M 0,0 H 16 V 16 H 0 Z" +           fill-opacity="0.35" +           id="path1307" /> +      </g> +    </mask> +    <filter +       id="filter3652" +       height="1" +       width="1" +       x="0" +       y="0"> +      <feColorMatrix +         in="SourceGraphic" +         type="matrix" +         values="0 0 0 0 1 0 0 0 0 1 0 0 0 0 1 0 0 0 1 0" +         id="feColorMatrix3650" /> +    </filter> +    <clipPath +       id="g"> +      <path +         d="M 0,0 H 800 V 800 H 0 Z" +         id="path1304" /> +    </clipPath> +    <mask +       id="f"> +      <g +         filter="url(#a)" +         id="g1301"> +        <path +           d="M 0,0 H 16 V 16 H 0 Z" +           fill-opacity="0.35" +           id="path1299" /> +      </g> +    </mask> +    <filter +       id="filter3661" +       height="1" +       width="1" +       x="0" +       y="0"> +      <feColorMatrix +         in="SourceGraphic" +         type="matrix" +         values="0 0 0 0 1 0 0 0 0 1 0 0 0 0 1 0 0 0 1 0" +         id="feColorMatrix3659" /> +    </filter> +    <clipPath +       id="e"> +      <path +         d="M 0,0 H 800 V 800 H 0 Z" +         id="path1296" /> +    </clipPath> +    <mask +       id="d"> +      <g +         filter="url(#a)" +         id="g1293"> +        <path +           d="M 0,0 H 16 V 16 H 0 Z" +           fill-opacity="0.35" +           id="path1291" /> +      </g> +    </mask> +    <filter +       id="filter3670" +       height="1" +       width="1" +       x="0" +       y="0"> +      <feColorMatrix +         in="SourceGraphic" +         type="matrix" +         values="0 0 0 0 1 0 0 0 0 1 0 0 0 0 1 0 0 0 1 0" +         id="feColorMatrix3668" /> +    </filter> +    <clipPath +       id="c"> +      <path +         d="M 0,0 H 800 V 800 H 0 Z" +         id="path1288" /> +    </clipPath> +    <mask +       id="b"> +      <g +         filter="url(#a)" +         id="g1285"> +        <path +           d="M 0,0 H 16 V 16 H 0 Z" +           fill-opacity="0.3" +           id="path1283" /> +      </g> +    </mask> +    <filter +       id="filter3679" +       height="1" +       width="1" +       x="0" +       y="0"> +      <feColorMatrix +         in="SourceGraphic" +         type="matrix" +         values="0 0 0 0 1 0 0 0 0 1 0 0 0 0 1 0 0 0 1 0" +         id="feColorMatrix3677" /> +    </filter> +  </defs> +  <g +     inkscape:label="Calque 1" +     inkscape:groupmode="layer" +     id="g3929"> +    <path +       id="rect3921" +       style="fill:#000000;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;paint-order:fill markers stroke;fill-opacity:1" +       d="M 30 15 C 13.380034 15 0 28.380034 0 45 L 0 100 L 0 110 L 0 135 C 0 151.61996 13.380034 165 30 165 L 150 165 C 166.61996 165 180 151.61996 180 135 L 180 110 L 180 100 L 180 45 C 180 28.380034 166.61996 15 150 15 L 30 15 z M 35 35 L 145 35 C 153.30998 35 160 41.690016 160 50 L 160 100 L 20 100 L 20 50 C 20 41.690016 26.690016 35 35 35 z M 20 110 L 160 110 L 160 130 C 160 138.30998 153.30998 145 145 145 L 35 145 C 26.690016 145 20 138.30998 20 130 L 20 110 z " /> +    <path +       id="rect3923" +       style="fill:#000000;fill-opacity:0.41999999;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;paint-order:fill markers stroke" +       d="M 20 110 L 20 130 C 20 138.30999 26.690008 145 35 145 L 145 145 C 153.30999 145 160 138.30999 160 130 L 160 110 L 20 110 z " /> +  </g> +</svg> diff --git a/src/data/images/dock-station-left-symbolic.svg b/src/data/images/dock-station-left-symbolic.svg new file mode 100644 index 0000000..0f90e8f --- /dev/null +++ b/src/data/images/dock-station-left-symbolic.svg @@ -0,0 +1,51 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<!-- Created with Inkscape (http://www.inkscape.org/) --> + +<svg +   width="180" +   height="180" +   viewBox="0 0 180 180" +   version="1.1" +   id="svg5" +   inkscape:version="1.2.2 (b0a8486541, 2022-12-01)" +   sodipodi:docname="dock-station-left-symbolic.svg" +   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" +   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" +   xmlns="http://www.w3.org/2000/svg" +   xmlns:svg="http://www.w3.org/2000/svg"> +  <sodipodi:namedview +     id="namedview7" +     pagecolor="#ffffff" +     bordercolor="#000000" +     borderopacity="0.25" +     inkscape:showpageshadow="2" +     inkscape:pageopacity="0.0" +     inkscape:pagecheckerboard="true" +     inkscape:deskcolor="#d1d1d1" +     inkscape:document-units="px" +     showgrid="false" +     inkscape:zoom="4.4555556" +     inkscape:cx="88.541146" +     inkscape:cy="89.999999" +     inkscape:window-width="1920" +     inkscape:window-height="1011" +     inkscape:window-x="0" +     inkscape:window-y="0" +     inkscape:window-maximized="1" +     inkscape:current-layer="layer1" /> +  <defs +     id="defs2" /> +  <g +     inkscape:label="Calque 1" +     inkscape:groupmode="layer" +     id="layer1"> +    <path +       id="rect254" +       style="fill:#000000;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;paint-order:fill markers stroke;fill-opacity:1" +       d="M 30 15 C 13.380034 15 0 28.380034 0 45 L 0 135 C 0 151.61996 13.380034 165 30 165 L 65 165 L 75 165 L 150 165 C 166.61996 165 180 151.61996 180 135 L 180 45 C 180 28.380034 166.61996 15 150 15 L 75 15 L 65 15 L 30 15 z M 35 35 L 65 35 L 65 145 L 35 145 C 26.690016 145 20 138.30998 20 130 L 20 50 C 20 41.690016 26.690016 35 35 35 z M 75 35 L 145 35 C 153.30998 35 160 41.690016 160 50 L 160 130 C 160 138.30998 153.30998 145 145 145 L 75 145 L 75 35 z " /> +    <path +       id="rect390" +       style="fill:#000000;fill-opacity:0.41999999;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;paint-order:fill markers stroke" +       d="M 35 35 C 26.690008 35 20 41.690008 20 50 L 20 130 C 20 138.30999 26.690008 145 35 145 L 65 145 L 65 35 L 35 35 z " /> +  </g> +</svg> diff --git a/src/data/images/dock-station-right-symbolic.svg b/src/data/images/dock-station-right-symbolic.svg new file mode 100644 index 0000000..774476a --- /dev/null +++ b/src/data/images/dock-station-right-symbolic.svg @@ -0,0 +1,76 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<!-- Created with Inkscape (http://www.inkscape.org/) --> + +<svg +   width="180" +   height="180" +   viewBox="0 0 180 180" +   version="1.1" +   id="svg5" +   inkscape:version="1.2.2 (b0a8486541, 2022-12-01)" +   sodipodi:docname="dock-station-right-symbolic.svg" +   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" +   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" +   xmlns="http://www.w3.org/2000/svg" +   xmlns:svg="http://www.w3.org/2000/svg"> +  <sodipodi:namedview +     id="namedview7" +     pagecolor="#ffffff" +     bordercolor="#000000" +     borderopacity="0.25" +     inkscape:showpageshadow="2" +     inkscape:pageopacity="0.0" +     inkscape:pagecheckerboard="true" +     inkscape:deskcolor="#d1d1d1" +     inkscape:document-units="px" +     showgrid="false" +     inkscape:zoom="4.4555556" +     inkscape:cx="86.408977" +     inkscape:cy="89.999999" +     inkscape:window-width="1920" +     inkscape:window-height="1011" +     inkscape:window-x="0" +     inkscape:window-y="0" +     inkscape:window-maximized="1" +     inkscape:current-layer="layer1" /> +  <defs +     id="defs2" /> +  <g +     inkscape:label="Calque 1" +     inkscape:groupmode="layer" +     id="layer1"> +    <path +       id="rect254" +       style="fill:#000000;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;paint-order:fill markers stroke;fill-opacity:1" +       d="M 30 15 C 13.380034 15 0 28.380034 0 45 L 0 135 C 0 151.61996 13.380034 165 30 165 L 105 165 L 115 165 L 150 165 C 166.61996 165 180 151.61996 180 135 L 180 45 C 180 28.380034 166.61996 15 150 15 L 115 15 L 105 15 L 30 15 z M 35 35 L 105 35 L 105 145 L 35 145 C 26.690016 145 20 138.30998 20 130 L 20 50 C 20 41.690016 26.690016 35 35 35 z M 115 35 L 145 35 C 153.30998 35 160 41.690016 160 50 L 160 130 C 160 138.30998 153.30998 145 145 145 L 115 145 L 115 35 z " /> +    <path +       id="rect390" +       style="fill:#000000;fill-opacity:0.41999999;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;paint-order:fill markers stroke" +       d="M 115 35 L 115 145 L 145 145 C 153.30999 145 160 138.30999 160 130 L 160 50 C 160 41.690008 153.30999 35 145 35 L 115 35 z " /> +  </g> +  <g +     inkscape:groupmode="layer" +     id="layer2" +     inkscape:label="Calque 2" +     style="display:none;opacity:0.700936"> +    <g +       fill="#2e3436" +       id="g182" +       transform="matrix(11.328515,0,0,10.683311,-1.25624,4.6587097)" +       style="stroke-width:0.0908993"> +      <path +         d="m 6.5,13.988281 v -12 h -5 v 12 z m 0,0" +         fill-opacity="0.35" +         id="path176" +         style="stroke-width:0.00826268" /> +      <path +         d="m 3,0.988281 c -1.644531,0 -3,1.355469 -3,3 v 8 c 0,1.644531 1.355469,3 3,3 h 10 c 1.644531,0 3,-1.355469 3,-3 v -8 c 0,-1.644531 -1.355469,-3 -3,-3 z m 0,2 h 10 c 0.570312,0 1,0.429688 1,1 v 8 c 0,0.570313 -0.429688,1 -1,1 H 3 c -0.570312,0 -1,-0.429687 -1,-1 v -8 c 0,-0.570312 0.429688,-1 1,-1 z m 0,0" +         id="path178" +         style="stroke-width:0.0908993" /> +      <path +         d="m 6,1.988281 h 1 v 12 H 6 Z m 0,0" +         id="path180" +         style="stroke-width:0.0908993" /> +    </g> +  </g> +</svg> diff --git a/src/data/images/gresource.xml b/src/data/images/gresource.xml new file mode 100644 index 0000000..25c8274 --- /dev/null +++ b/src/data/images/gresource.xml @@ -0,0 +1,12 @@ +<?xml version="1.0" encoding="UTF-8"?> +<gresources> +    <gresource prefix="/re/chrysalide/framework/gui/dialogs/about"> +        <file compressed="true" alias="bg.png">about-bg.png</file> +    </gresource> +    <gresource prefix="/re/chrysalide/framework/gui/icons/scalable/actions"> +        <file compressed="true">dock-station-left-symbolic.svg</file> +        <file compressed="true">dock-station-right-symbolic.svg</file> +        <file compressed="true">dock-station-bottom-symbolic.svg</file> +        <file compressed="true">logs-symbolic.svg</file> +    </gresource> +</gresources> diff --git a/src/data/images/logs-symbolic.svg b/src/data/images/logs-symbolic.svg new file mode 100644 index 0000000..f541607 --- /dev/null +++ b/src/data/images/logs-symbolic.svg @@ -0,0 +1,93 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<!-- Created with Inkscape (http://www.inkscape.org/) --> + +<svg +   width="180" +   height="180" +   viewBox="0 0 180 180" +   version="1.1" +   id="svg5" +   inkscape:version="1.2.2 (b0a8486541, 2022-12-01)" +   sodipodi:docname="logs-symbolic.svg" +   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" +   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" +   xmlns="http://www.w3.org/2000/svg" +   xmlns:svg="http://www.w3.org/2000/svg"> +  <sodipodi:namedview +     id="namedview7" +     pagecolor="#ffffff" +     bordercolor="#000000" +     borderopacity="0.25" +     inkscape:showpageshadow="2" +     inkscape:pageopacity="0.0" +     inkscape:pagecheckerboard="0" +     inkscape:deskcolor="#d1d1d1" +     inkscape:document-units="px" +     showgrid="false" +     inkscape:zoom="3.9657403" +     inkscape:cx="110.44596" +     inkscape:cy="77.413036" +     inkscape:window-width="1920" +     inkscape:window-height="1011" +     inkscape:window-x="0" +     inkscape:window-y="0" +     inkscape:window-maximized="1" +     inkscape:current-layer="layer1" /> +  <defs +     id="defs2" /> +  <g +     inkscape:label="Calque 1" +     inkscape:groupmode="layer" +     id="layer1" +     style="fill:#25ff4c;fill-opacity:1"> +    <path +       id="rect495" +       style="opacity:1;fill:#000000;fill-opacity:1;stroke-width:1.99999;stroke-linecap:round;stroke-linejoin:round;paint-order:fill markers stroke" +       d="M 45 0 C 31.150014 0 20 11.150014 20 25 L 20 155 C 20 168.84999 31.150014 180 45 180 L 155 180 C 168.84999 180 180 168.84999 180 155 L 180 25 C 180 11.150014 168.84999 0 155 0 L 45 0 z M 55 10 L 145 10 C 158.84999 10 170 21.150014 170 35 L 170 145 C 170 158.84999 158.84999 170 145 170 L 55 170 C 41.150014 170 30 158.84999 30 145 L 30 35 C 30 21.150014 41.150014 10 55 10 z " /> +    <rect +       style="display:inline;opacity:1;fill:#000000;fill-opacity:1;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;paint-order:fill markers stroke" +       id="rect3619" +       width="75" +       height="12" +       x="62.5" +       y="84" +       rx="6" +       ry="6" /> +    <rect +       style="display:inline;opacity:1;fill:#000000;fill-opacity:1;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;paint-order:fill markers stroke" +       id="rect5029" +       width="75" +       height="12" +       x="62.5" +       y="127" +       rx="6" +       ry="6" /> +    <rect +       style="display:inline;opacity:1;fill:#000000;fill-opacity:1;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;paint-order:fill markers stroke" +       id="rect5031" +       width="75" +       height="12" +       x="62.5" +       y="41" +       rx="6" +       ry="6" /> +    <rect +       style="display:inline;opacity:1;fill:#000000;fill-opacity:1;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;paint-order:fill markers stroke" +       id="rect5049" +       width="34" +       height="12" +       x="8.2744884" +       y="41" +       rx="6" +       ry="6" /> +    <rect +       style="display:inline;opacity:1;fill:#000000;fill-opacity:1;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;paint-order:fill markers stroke" +       id="rect5051" +       width="34" +       height="12" +       x="8.2744884" +       y="127" +       rx="6" +       ry="6" /> +  </g> +</svg> diff --git a/src/format/Makefile.am b/src/format/Makefile.am index 305cd92..3ffe24e 100644 --- a/src/format/Makefile.am +++ b/src/format/Makefile.am @@ -1,23 +1,25 @@  noinst_LTLIBRARIES = libformat.la +# 	debuggable-int.h					\ +# 	debuggable.h debuggable.c			\ +# 	executable-int.c	\ +# 	preload-int.h						\ +# 	preload.h preload.c					\ +# 	strsym.h strsym.c					\ +# 	symiter.h symiter.c					\ +# 	symbol-int.h						\ +# 	symbol.h symbol.c +  libformat_la_SOURCES =					\ -	debuggable-int.h					\ -	debuggable.h debuggable.c			\ -	executable-int.h executable-int.c	\ +	executable-int.h					\  	executable.h executable.c			\  	flat-int.h							\  	flat.h flat.c						\ -	format-int.h						\ -	format.h format.c					\  	known-int.h							\  	known.h known.c						\ -	preload-int.h						\ -	preload.h preload.c					\ -	strsym.h strsym.c					\ -	symiter.h symiter.c					\ -	symbol-int.h						\ -	symbol.h symbol.c +	program-int.h						\ +	program.h program.c  libformat_la_CFLAGS = $(TOOLKIT_CFLAGS) $(LIBXML_CFLAGS) diff --git a/src/format/executable-int.c b/src/format/executable-int.c deleted file mode 100644 index 0e94e74..0000000 --- a/src/format/executable-int.c +++ /dev/null @@ -1,155 +0,0 @@ - -/* Chrysalide - Outil d'analyse de fichiers binaires - * executable-int.c - code utile aux formats d'exécutables - * - * Copyright (C) 2015-2018 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 "executable-int.h" - - - -/****************************************************************************** -*                                                                             * -*  Paramètres  : format = description de l'exécutable à consulter.            * -*                off    = position physique à retrouver.                      * -*                pos    = position correspondante. [OUT]                      * -*                                                                             * -*  Description : Fournit l'emplacement correspondant à une position physique. * -*                                                                             * -*  Retour      : Bilan de l'opération.                                        * -*                                                                             * -*  Remarques   : -                                                            * -*                                                                             * -******************************************************************************/ - -bool g_exe_format_without_virt_translate_offset_into_vmpa(const GExeFormat *format, phys_t off, vmpa2t *pos) -{ -    init_vmpa(pos, off, VMPA_NO_VIRTUAL); - -    return true; - -} - - -/****************************************************************************** -*                                                                             * -*  Paramètres  : format = description de l'exécutable à consulter.            * -*                addr   = adresse virtuelle à retrouver.                      * -*                pos    = position correspondante. [OUT]                      * -*                                                                             * -*  Description : Fournit l'emplacement correspondant à une adresse virtuelle. * -*                                                                             * -*  Retour      : Bilan de l'opération.                                        * -*                                                                             * -*  Remarques   : -                                                            * -*                                                                             * -******************************************************************************/ - -bool g_exe_format_without_virt_translate_address_into_vmpa(const GExeFormat *format, virt_t addr, vmpa2t *pos) -{ -    /** -     * S'il n'y a pas de notion de mémoire virtuelle, positions physiques et -     * adresses virtuelles se confondent. -     * -     * On reste néanmoins cohérent, et on n'utilise donc pas d'adresse virtuelle. -     * -     * Les sauts dans le code renvoient de façon transparente vers des positions -     * physiques. -     */ - -    init_vmpa(pos, addr, VMPA_NO_VIRTUAL); - -    return true; - -} - - -/****************************************************************************** -*                                                                             * -*  Paramètres  : format = description de l'exécutable à consulter.            * -*                off    = position physique à retrouver.                      * -*                pos    = position correspondante. [OUT]                      * -*                                                                             * -*  Description : Fournit l'emplacement correspondant à une position physique. * -*                                                                             * -*  Retour      : Bilan de l'opération.                                        * -*                                                                             * -*  Remarques   : -                                                            * -*                                                                             * -******************************************************************************/ - -bool g_exe_format_translate_offset_into_vmpa_using_portions(GExeFormat *format, phys_t off, vmpa2t *pos) -{ -    bool result;                            /* Bilan à retourner           */ -    GBinPortion *portions;                  /* Liste de découpages         */ - -    portions = g_exe_format_get_portions(format); - -    if (portions == NULL) -        result = false; - -    else -    { -        result = g_binary_portion_translate_offset_into_vmpa(portions, off, pos); - -        g_object_unref(G_OBJECT(portions)); - -    } - -    return result; - -} - - -/****************************************************************************** -*                                                                             * -*  Paramètres  : format = description de l'exécutable à consulter.            * -*                addr   = adresse virtuelle à retrouver.                      * -*                pos    = position correspondante. [OUT]                      * -*                                                                             * -*  Description : Fournit l'emplacement correspondant à une adresse virtuelle. * -*                                                                             * -*  Retour      : Bilan de l'opération.                                        * -*                                                                             * -*  Remarques   : -                                                            * -*                                                                             * -******************************************************************************/ - -bool g_exe_format_translate_address_into_vmpa_using_portions(GExeFormat *format, virt_t addr, vmpa2t *pos) -{ -    bool result;                            /* Bilan à retourner           */ -    GBinPortion *portions;                  /* Liste de découpages         */ - -    portions = g_exe_format_get_portions(format); - -    if (portions == NULL) -        result = false; - -    else -    { -        result = g_binary_portion_translate_address_into_vmpa(portions, addr, pos); - -        g_object_unref(G_OBJECT(portions)); - -    } - -    return result; - -} diff --git a/src/format/executable-int.h b/src/format/executable-int.h index 8722795..1ca1bdb 100644 --- a/src/format/executable-int.h +++ b/src/format/executable-int.h @@ -2,7 +2,7 @@  /* Chrysalide - Outil d'analyse de fichiers binaires   * executable-int.h - prototypes de code utile aux formats d'exécutables   * - * Copyright (C) 2009-2019 Cyrille Bagard + * Copyright (C) 2009-2024 Cyrille Bagard   *   *  This file is part of Chrysalide.   * @@ -28,79 +28,65 @@  #include "executable.h" -#include "format-int.h" +#include "program-int.h"  /* Indique le type d'architecture visée par le format. */ -typedef const char * (* get_target_machine_fc) (const GExeFormat *); +typedef char * (* get_target_machine_fc) (const GExecutableFormat *);  /* Fournit l'adresse principale associée à un format. */ -typedef bool (* get_main_addr_fc) (GExeFormat *, vmpa2t *); +typedef bool (* get_main_addr_fc) (GExecutableFormat *, vmpa2t *);  /* Etend la définition des portions au sein d'un binaire. */ -typedef void (* refine_portions_fc) (GExeFormat *); +typedef bool (* refine_portions_fc) (GExecutableFormat *);  /* Fournit l'emplacement correspondant à une position physique. */ -typedef bool (* translate_phys_fc) (GExeFormat *, phys_t, vmpa2t *); +typedef bool (* translate_phys_fc) (GExecutableFormat *, phys_t, vmpa2t *);  /* Fournit l'emplacement correspondant à une adresse virtuelle. */ -typedef bool (* translate_virt_fc) (GExeFormat *, virt_t, vmpa2t *); - -/* Fournit l'emplacement d'une section donnée. */ -typedef bool (* get_range_by_name_fc) (const GExeFormat *, const char *, mrange_t *); - +typedef bool (* translate_virt_fc) (GExecutableFormat *, virt_t, vmpa2t *);  /* Format d'exécutable générique (instance) */ -struct _GExeFormat +struct _GExecutableFormat  { -    GBinFormat parent;                      /* A laisser en premier        */ +    GProgramFormat parent;                  /* A laisser en premier        */ -    GDbgFormat **debugs;                    /* Informations de débogage    */ -    size_t debugs_count;                    /* Nombre de ces informations  */ - -    GBinPortion **user_portions;            /* Couches de morceaux binaires*/ -    size_t user_count;                      /* Nombre de ces portions      */ -    GBinPortion *portions;                  /* Couches de morceaux binaires*/ -    GMutex mutex;                           /* Accès à l'arborescence      */ +    GBinaryPortion *portions;               /* Couches de morceaux binaires*/  };  /* Format d'exécutable générique (classe) */ -struct _GExeFormatClass +struct _GExecutableFormatClass  { -    GBinFormatClass parent;                 /* A laisser en premier        */ +    GProgramFormatClass parent;             /* A laisser en premier        */      get_target_machine_fc get_machine;      /* Architecture ciblée         */ +      get_main_addr_fc get_main_addr;         /* Obtention d'adresse première*/      refine_portions_fc refine_portions;     /* Décrit les portions binaires*/      translate_phys_fc translate_phys;       /* Correspondance phys -> vmpa */      translate_virt_fc translate_virt;       /* Correspondance virt -> vmpa */ -    get_range_by_name_fc get_range_by_name; /* Emplacement de sections     */      -  }; -/* Crée les portions potentiellement utiles aux traductions. */ -void g_executable_format_setup_portions(GExeFormat *, GtkStatusStack *); +/* Met en place un nouveau contenu binaire à analyser. */ +bool g_executable_format_create(GExecutableFormat *, GBinContent *); -/* Effectue les ultimes opérations de chargement d'un binaire. */ -bool g_executable_format_complete_loading(GExeFormat *, wgroup_id_t, GtkStatusStack *); +/* Fournit l'emplacement correspondant à une position physique. */ +bool g_executable_format_translate_offset_into_vmpa_without_virt(const GExecutableFormat *, phys_t, vmpa2t *);  /* Fournit l'emplacement correspondant à une position physique. */ -bool g_exe_format_without_virt_translate_offset_into_vmpa(const GExeFormat *, phys_t, vmpa2t *); +bool g_executable_format_translate_offset_into_vmpa_with_portions(GExecutableFormat *, phys_t, vmpa2t *);  /* Fournit l'emplacement correspondant à une adresse virtuelle. */ -bool g_exe_format_without_virt_translate_address_into_vmpa(const GExeFormat *, virt_t, vmpa2t *); - -/* Fournit l'emplacement correspondant à une position physique. */ -bool g_exe_format_translate_offset_into_vmpa_using_portions(GExeFormat *, phys_t, vmpa2t *); +bool g_executable_format_translate_address_into_vmpa_without_virt(const GExecutableFormat *, virt_t, vmpa2t *);  /* Fournit l'emplacement correspondant à une adresse virtuelle. */ -bool g_exe_format_translate_address_into_vmpa_using_portions(GExeFormat *, virt_t, vmpa2t *); +bool g_executable_format_translate_address_into_vmpa_with_portions(GExecutableFormat *, virt_t, vmpa2t *); diff --git a/src/format/executable.c b/src/format/executable.c index 26c418e..d0fc3e2 100644 --- a/src/format/executable.c +++ b/src/format/executable.c @@ -27,35 +27,48 @@  #include <assert.h>  #include <malloc.h>  #include <stdio.h> -#include <stdlib.h>  #include <i18n.h>  #include "executable-int.h" -#include "format.h"  #include "../core/logs.h" -#include "../plugins/pglist.h" +/* ------------------------- GESTION D'UN FORMAT EXECUTABLE ------------------------- */ + +  /* Initialise la classe des formats d'exécutables génériques. */ -static void g_executable_format_class_init(GExeFormatClass *); +static void g_executable_format_class_init(GExecutableFormatClass *);  /* Initialise une instance de format d'exécutable générique. */ -static void g_executable_format_init(GExeFormat *); +static void g_executable_format_init(GExecutableFormat *);  /* Supprime toutes les références externes. */ -static void g_executable_format_dispose(GExeFormat *); +static void g_executable_format_dispose(GExecutableFormat *);  /* Procède à la libération totale de la mémoire. */ -static void g_executable_format_finalize(GExeFormat *); +static void g_executable_format_finalize(GExecutableFormat *); + + + +/* --------------------- IMPLEMENTATION DES FONCTIONS DE CLASSE --------------------- */ + + +/* Assure l'interprétation d'un format en différé. */ +static bool g_executable_format_analyze(GExecutableFormat *); + +/* ---------------------------------------------------------------------------------- */ +/*                           GESTION D'UN FORMAT EXECUTABLE                           */ +/* ---------------------------------------------------------------------------------- */ +  /* Indique le type défini pour un format d'exécutable générique. */ -G_DEFINE_TYPE(GExeFormat, g_executable_format, G_TYPE_BIN_FORMAT); +G_DEFINE_TYPE(GExecutableFormat, g_executable_format, G_TYPE_PROGRAM_FORMAT);  /****************************************************************************** @@ -70,15 +83,20 @@ G_DEFINE_TYPE(GExeFormat, g_executable_format, G_TYPE_BIN_FORMAT);  *                                                                             *  ******************************************************************************/ -static void g_executable_format_class_init(GExeFormatClass *klass) +static void g_executable_format_class_init(GExecutableFormatClass *klass)  {      GObjectClass *object;                   /* Autre version de la classe  */ +    GKnownFormatClass *known;               /* Version de format connu     */      object = G_OBJECT_CLASS(klass);      object->dispose = (GObjectFinalizeFunc/* ! */)g_executable_format_dispose;      object->finalize = (GObjectFinalizeFunc)g_executable_format_finalize; +    known = G_KNOWN_FORMAT_CLASS(klass); + +    known->analyze = (known_analyze_fc)g_executable_format_analyze; +  } @@ -94,9 +112,9 @@ static void g_executable_format_class_init(GExeFormatClass *klass)  *                                                                             *  ******************************************************************************/ -static void g_executable_format_init(GExeFormat *format) +static void g_executable_format_init(GExecutableFormat *format)  { -    g_mutex_init(&format->mutex); +    format->portions = NULL;  } @@ -113,20 +131,10 @@ static void g_executable_format_init(GExeFormat *format)  *                                                                             *  ******************************************************************************/ -static void g_executable_format_dispose(GExeFormat *format) +static void g_executable_format_dispose(GExecutableFormat *format)  { -    size_t i;                               /* Boucle de parcours          */ - -    for (i = 0; i < format->debugs_count; i++) -        g_clear_object(&format->debugs[i]); - -    for (i = 0; i < format->user_count; i++) -        g_clear_object(&format->user_portions[i]); -      g_clear_object(&format->portions); -    g_mutex_clear(&format->mutex); -      G_OBJECT_CLASS(g_executable_format_parent_class)->dispose(G_OBJECT(format));  } @@ -144,14 +152,8 @@ static void g_executable_format_dispose(GExeFormat *format)  *                                                                             *  ******************************************************************************/ -static void g_executable_format_finalize(GExeFormat *format) +static void g_executable_format_finalize(GExecutableFormat *format)  { -    if (format->debugs != NULL) -        free(format->debugs); - -    if (format->user_portions != NULL) -        free(format->user_portions); -      G_OBJECT_CLASS(g_executable_format_parent_class)->finalize(G_OBJECT(format));  } @@ -159,79 +161,66 @@ static void g_executable_format_finalize(GExeFormat *format)  /******************************************************************************  *                                                                             * -*  Paramètres  : format = informations chargées à compléter.                  * -*                info   = informations de débogage à lier.                    * +*  Paramètres  : format  = description du format à initialiser pleinement.    * +*                content = contenu binaire à parcourir.                       *  *                                                                             * -*  Description : Rajoute des informations de débogage à un exécutable.        * +*  Description : Met en place un nouveau contenu binaire à analyser.          *  *                                                                             * -*  Retour      : -                                                            * +*  Retour      : Bilan de l'opération.                                        *  *                                                                             *  *  Remarques   : -                                                            *  *                                                                             *  ******************************************************************************/ -void g_exe_format_add_debug_info(GExeFormat *format, GDbgFormat *info) +bool g_executable_format_create(GExecutableFormat *format, GBinContent *content)  { -    const char *desc;                       /* Description humaine associée*/ +    bool result;                            /* Bilan à retourner           */ +    vmpa2t addr;                            /* Emplacement vide de sens    */ +    phys_t length;                          /* Taille de portion globale   */ -    desc = g_known_format_get_description(G_KNOWN_FORMAT(info)); +    result = g_program_format_create(G_PROGRAM_FORMAT(format), content); +    if (!result) goto exit; -    if (desc == NULL) -        log_simple_message(LMT_WARNING, _("Unnamed debug information")); -    else -        log_variadic_message(LMT_INFO, _("Found debug information: %s"), desc); +    /* Définition de portions */ -    format->debugs = realloc(format->debugs, ++format->debugs_count * sizeof(GDbgFormat *)); - -    format->debugs[format->debugs_count - 1] = info; +    /** +     * Avant de lire l'entête du format, on ne sait pas où on se trouve ! +     */ +    init_vmpa(&addr, 0, VMPA_NO_VIRTUAL); -} +    length = g_binary_content_compute_size(G_KNOWN_FORMAT(format)->content); +    format->portions = g_binary_portion_new(&addr, length); -/****************************************************************************** -*                                                                             * -*  Paramètres  : format = informations chargées à consulter.                  * -*                                                                             * -*  Description : Compte le nombre de formats de débogage liés à l'exécutable. * -*                                                                             * -*  Retour      : Nombre de formats de débogage attachés.                      * -*                                                                             * -*  Remarques   : -                                                            * -*                                                                             * -******************************************************************************/ + exit: -size_t g_exe_format_count_debug_info(const GExeFormat *format) -{ -    return format->debugs_count; +    return result;  }  /******************************************************************************  *                                                                             * -*  Paramètres  : format = informations chargées à consulter.                  * -*                index  = indice des informations à transmettre.              * +*  Paramètres  : format = description du format exécutable à consulter.       *  *                                                                             * -*  Description : Fournit un format de débogage attaché à l'exécutable.        * +*  Description : Indique le type d'architecture visée par le format.          *  *                                                                             * -*  Retour      : Informations de débogage attachées.                          * +*  Retour      : Identifiant de l'architecture ciblée par le format.          *  *                                                                             *  *  Remarques   : -                                                            *  *                                                                             *  ******************************************************************************/ -GDbgFormat *g_exe_format_get_debug_info(const GExeFormat *format, size_t index) +char *g_executable_format_get_target_machine(const GExecutableFormat *format)  { -    GDbgFormat *result;                     /* Format à retourner          */ +    char *result;                           /* Désignation à retourner     */ +    GExecutableFormatClass *class;          /* Classe de l'instance        */ -    if (index >= format->debugs_count) -        result = NULL; +    class = G_EXECUTABLE_FORMAT_GET_CLASS(format); -    else -    { -        result = format->debugs[index]; -        g_object_ref(G_OBJECT(result)); -    } +    result = class->get_machine(format); + +    //assert(result != NULL);      return result; @@ -240,56 +229,96 @@ GDbgFormat *g_exe_format_get_debug_info(const GExeFormat *format, size_t index)  /******************************************************************************  *                                                                             * -*  Paramètres  : format = informations chargées à consulter.                  * +*  Paramètres  : format = description de l'exécutable à consulter.            * +*                addr   = adresse principale trouvée si possible. [OUT]       *  *                                                                             * -*  Description : Indique le type d'architecture visée par le format.          * +*  Description : Fournit l'adresse principale associée à un format.           *  *                                                                             * -*  Retour      : Identifiant de l'architecture ciblée par le format.          * +*  Retour      : Validité de l'adresse transmise.                             *  *                                                                             *  *  Remarques   : -                                                            *  *                                                                             *  ******************************************************************************/ -const char *g_exe_format_get_target_machine(const GExeFormat *format) +bool g_executable_format_get_main_address(GExecutableFormat *format, vmpa2t *addr)  { -    return G_EXE_FORMAT_GET_CLASS(format)->get_machine(format); +    bool result;                            /* Bilan à retourner           */ +    GExecutableFormatClass *class;          /* Classe de l'instance        */ + +    class = G_EXECUTABLE_FORMAT_GET_CLASS(format); + +    result = class->get_main_addr(format, addr); + +    return result;  }  /******************************************************************************  *                                                                             * -*  Paramètres  : format = description de l'exécutable à consulter.            * -*                addr   = adresse principale trouvée si possible. [OUT]       * +*  Paramètres  : format  = description de l'exécutable à modifier.            * +*                portion = portion à inclure dans les définitions du format.  * +*                origin  = source de définition de la portion fournie.        *  *                                                                             * -*  Description : Fournit l'adresse principale associée à un format.           * +*  Description : Procède à l'enregistrement d'une portion dans un format.     *  *                                                                             * -*  Retour      : Bilan des recherches.                                        * +*  Retour      : Bilan de l'opération : true si inclusion, false sinon.       *  *                                                                             *  *  Remarques   : -                                                            *  *                                                                             *  ******************************************************************************/ -bool g_exe_format_get_main_address(GExeFormat *format, vmpa2t *addr) +bool g_executable_format_include_portion(GExecutableFormat *format, GBinaryPortion *portion, const vmpa2t *origin)  {      bool result;                            /* Bilan à retourner           */ -    GBinFormat *base;                       /* Version d'instance parente  */ +    phys_t available;                       /* Taille totale du bianire    */ +    const mrange_t *range;                  /* Emplacement de la portion   */ +    phys_t start;                           /* Début de zone de la portion */ +    vmpa2t no_origin;                       /* Emplacement inconnu         */ +    char *msg;                              /* Description d'une erreur    */ +    phys_t remaining;                       /* Taille maximale envisageable*/ +    bool truncated;                         /* Modification faite ?        */      result = false; -    if (G_EXE_FORMAT_GET_CLASS(format)->get_main_addr != NULL) -        result = G_EXE_FORMAT_GET_CLASS(format)->get_main_addr(format, addr); +    available = g_binary_content_compute_size(G_KNOWN_FORMAT(format)->content); + +    range = g_binary_portion_get_range(portion); + +    start = get_phy_addr(get_mrange_addr(range)); + +    if (get_mrange_length(range) == 0) +        log_variadic_message(LMT_BAD_BINARY, _("The binary portion '%s' is empty and thus useless... Discarding!"), +                             g_binary_portion_get_desc(portion)); -    if (!result) +    else if (start >= available)      { -        base = G_BIN_FORMAT(format); +        if (origin == NULL) +        { +            init_vmpa(&no_origin, VMPA_NO_PHYSICAL, VMPA_NO_VIRTUAL); +            origin = &no_origin; +        } -        g_rw_lock_reader_lock(&base->pt_lock); +        asprintf(&msg, _("Defined binary portion '%s' is out of the file scope... Discarding!"), +                 g_binary_portion_get_desc(portion)); -        if (base->pt_count[DPL_ENTRY_POINT] > 0) -            result = g_exe_format_translate_address_into_vmpa(format, base->start_points[DPL_ENTRY_POINT][0], addr); +        //g_binary_format_add_error(G_BIN_FORMAT(format), BFE_STRUCTURE, origin, msg); -        g_rw_lock_reader_unlock(&base->pt_lock); +        free(msg); + +    } + +    else +    { +        remaining = available - start; + +        truncated = g_binary_portion_limit_range(portion, remaining); + +        if (truncated) +            log_variadic_message(LMT_BAD_BINARY, _("Truncated binary portion '%s' to fit the binary content size!"), +                                 g_binary_portion_get_desc(portion)); + +        result = g_binary_portion_include(format->portions, portion);      } @@ -300,54 +329,39 @@ bool g_exe_format_get_main_address(GExeFormat *format, vmpa2t *addr)  /******************************************************************************  *                                                                             * -*  Paramètres  : format = instance à traiter.                                 * -*                status = barre de statut à tenir informée.                   * +*  Paramètres  : format = description de l'exécutable à consulter.            *  *                                                                             * -*  Description : Crée les portions potentiellement utiles aux traductions.    * +*  Description : Fournit la première couche des portions composent le binaire.*  *                                                                             * -*  Retour      : -                                                            * +*  Retour      : Arborescence des différentes portions binaires.              *  *                                                                             * -*  Remarques   : -                                                            * +*  Remarques   : Le compteur de références de l'instance renvoyée doit être   * +*                décrémenté après usage.                                      *  *                                                                             *  ******************************************************************************/ -void g_executable_format_setup_portions(GExeFormat *format, GtkStatusStack *status) +GBinaryPortion *g_executable_format_get_portions(GExecutableFormat *format)  { -    vmpa2t addr;                            /* Emplacement vide de sens    */ -    phys_t length;                          /* Taille de portion globale   */ -    GExeFormatClass *class;                 /* Classe de l'instance        */ -    size_t i;                               /* Boucle de parcours          */ - -    /** -     * Avant de lire l'entête du format, on ne sait pas où on se trouve ! -     */ -    init_vmpa(&addr, 0, VMPA_NO_VIRTUAL); +    GBinaryPortion *result;                 /* Instance à retourner        */ -    length = g_binary_content_compute_size(G_KNOWN_FORMAT(format)->content); - -    format->portions = g_binary_portion_new(BPC_RAW, &addr, length); +    result = format->portions; -    class = G_EXE_FORMAT_GET_CLASS(format); +    assert(result != NULL); -    if (class->refine_portions != NULL) -        class->refine_portions(format); +    ref_object(result); -    for (i = 0; i < format->user_count; i++) -    { -        g_object_ref(G_OBJECT(format->user_portions[i])); -        g_exe_format_include_portion(format, format->user_portions[i], NULL); -    } +    return result;  }  /******************************************************************************  *                                                                             * -*  Paramètres  : format = instance à traiter.                                 * -*                gid    = groupe de travail dédié.                            * -*                status = barre de statut à tenir informée.                   * +*  Paramètres  : format = description de l'exécutable à consulter.            * +*                off    = position physique à retrouver.                      * +*                pos    = position correspondante. [OUT]                      *  *                                                                             * -*  Description : Effectue les ultimes opérations de chargement d'un binaire.  * +*  Description : Fournit l'emplacement correspondant à une position physique. *  *                                                                             *  *  Retour      : Bilan de l'opération.                                        *  *                                                                             * @@ -355,28 +369,14 @@ void g_executable_format_setup_portions(GExeFormat *format, GtkStatusStack *stat  *                                                                             *  ******************************************************************************/ -bool g_executable_format_complete_loading(GExeFormat *format, wgroup_id_t gid, GtkStatusStack *status) +bool g_executable_format_translate_offset_into_vmpa(GExecutableFormat *format, phys_t off, vmpa2t *pos)  { -    bool result;                            /* Bilan à faire remonter      */ -    size_t count;                           /* Qté d'infos supplémentaires */ -    size_t i;                               /* Boucle de parcours          */ -    GDbgFormat *dbg;                        /* Informations de débogage    */ - -    result = true; - -    attach_debug_format(format); - -    count = g_exe_format_count_debug_info(format); - -    for (i = 0; i < count && result; i++) -    { -        dbg = g_exe_format_get_debug_info(format, i); - -        result = g_known_format_analyze(G_KNOWN_FORMAT(dbg), gid, status); +    bool result;                            /* Bilan à retourner           */ +    GExecutableFormatClass *class;          /* Classe de l'instance        */ -        g_object_unref(G_OBJECT(dbg)); +    class = G_EXECUTABLE_FORMAT_GET_CLASS(format); -    } +    result = class->translate_phys(format, off, pos);      return result; @@ -385,105 +385,52 @@ bool g_executable_format_complete_loading(GExeFormat *format, wgroup_id_t gid, G  /******************************************************************************  *                                                                             * -*  Paramètres  : format  = description de l'exécutable à modifier.            * -*                portion = portion à inclure dans les définitions du format.  * +*  Paramètres  : format = description de l'exécutable à consulter.            * +*                off    = position physique à retrouver.                      * +*                pos    = position correspondante. [OUT]                      *  *                                                                             * -*  Description : Enregistre une portion artificielle pour le format.          * +*  Description : Fournit l'emplacement correspondant à une position physique. *  *                                                                             * -*  Retour      : -                                                            * +*  Retour      : Bilan de l'opération.                                        *  *                                                                             *  *  Remarques   : -                                                            *  *                                                                             *  ******************************************************************************/ -void g_exe_format_register_user_portion(GExeFormat *format, GBinPortion *portion) +bool g_executable_format_translate_offset_into_vmpa_without_virt(const GExecutableFormat *format, phys_t off, vmpa2t *pos)  { -    g_mutex_lock(&format->mutex); +    init_vmpa(pos, off, VMPA_NO_VIRTUAL); -    format->user_portions = realloc(format->user_portions, ++format->user_count * sizeof(GBinPortion *)); - -    format->user_portions[format->user_count - 1] = portion; - -    g_mutex_unlock(&format->mutex); +    return true;  }  /******************************************************************************  *                                                                             * -*  Paramètres  : format  = description de l'exécutable à modifier.            * -*                portion = portion à inclure dans les définitions du format.  * -*                origin  = source de définition de la portion fournie.        * +*  Paramètres  : format = description de l'exécutable à consulter.            * +*                off    = position physique à retrouver.                      * +*                pos    = position correspondante. [OUT]                      *  *                                                                             * -*  Description : Procède à l'enregistrement d'une portion dans un format.     * +*  Description : Fournit l'emplacement correspondant à une position physique. *  *                                                                             * -*  Retour      : -                                                            * +*  Retour      : Bilan de l'opération.                                        *  *                                                                             *  *  Remarques   : -                                                            *  *                                                                             *  ******************************************************************************/ -void g_exe_format_include_portion(GExeFormat *format, GBinPortion *portion, const vmpa2t *origin) +bool g_executable_format_translate_offset_into_vmpa_with_portions(GExecutableFormat *format, phys_t off, vmpa2t *pos)  { -    phys_t available;                       /* Taille totale du bianire    */ -    const mrange_t *range;                  /* Emplacement de la portion   */ -    phys_t start;                           /* Début de zone de la portion */ -    vmpa2t no_origin;                       /* Emplacement inconnu         */ -    char *msg;                              /* Description d'une erreur    */ -    phys_t remaining;                       /* Taille maximale envisageable*/ -    bool truncated;                         /* Modification faite ?        */ - -    available = g_binary_content_compute_size(G_KNOWN_FORMAT(format)->content); - -    range = g_binary_portion_get_range(portion); - -    start = get_phy_addr(get_mrange_addr(range)); - -    if (get_mrange_length(range) == 0) -    { -        log_variadic_message(LMT_BAD_BINARY, _("The binary portion '%s' is empty and thus useless... Discarding!"), -                             g_binary_portion_get_desc(portion)); - -        g_object_unref(G_OBJECT(portion)); - -    } - -    else if (start >= available) -    { -        if (origin == NULL) -        { -            init_vmpa(&no_origin, VMPA_NO_PHYSICAL, VMPA_NO_VIRTUAL); -            origin = &no_origin; -        } - -        asprintf(&msg, _("Defined binary portion '%s' is out of the file scope... Discarding!"), -                 g_binary_portion_get_desc(portion)); - -        g_binary_format_add_error(G_BIN_FORMAT(format), BFE_STRUCTURE, origin, msg); - -        free(msg); - -        g_object_unref(G_OBJECT(portion)); +    bool result;                            /* Bilan à retourner           */ -    } +    if (format->portions == NULL) +        result = false;      else -    { -        remaining = available - start; - -        truncated = g_binary_portion_limit_range(portion, remaining); - -        if (truncated) -            log_variadic_message(LMT_BAD_BINARY, _("Truncated binary portion '%s' to fit the binary content size!"), -                                 g_binary_portion_get_desc(portion)); +        result = g_binary_portion_translate_offset_into_vmpa(format->portions, off, pos); -        g_mutex_lock(&format->mutex); - -        g_binary_portion_include(format->portions, portion); - -        g_mutex_unlock(&format->mutex); - -    } +    return result;  } @@ -491,28 +438,25 @@ void g_exe_format_include_portion(GExeFormat *format, GBinPortion *portion, cons  /******************************************************************************  *                                                                             *  *  Paramètres  : format = description de l'exécutable à consulter.            * +*                addr   = adresse virtuelle à retrouver.                      * +*                pos    = position correspondante. [OUT]                      *  *                                                                             * -*  Description : Fournit la première couche des portions composent le binaire.* +*  Description : Fournit l'emplacement correspondant à une adresse virtuelle. *  *                                                                             * -*  Retour      : Arborescence des différentes portions binaires.              * +*  Retour      : Bilan de l'opération.                                        *  *                                                                             * -*  Remarques   : Le compteur de références de l'instance renvoyée doit être   * -*                décrémenté après usage.                                      * +*  Remarques   : -                                                            *  *                                                                             *  ******************************************************************************/ -GBinPortion *g_exe_format_get_portions(GExeFormat *format) +bool g_executable_format_translate_address_into_vmpa(GExecutableFormat *format, virt_t addr, vmpa2t *pos)  { -    GBinPortion *result;                    /* Instance à retourner        */ - -    g_mutex_lock(&format->mutex); - -    result = format->portions; +    bool result;                            /* Bilan à retourner           */ +    GExecutableFormatClass *class;          /* Classe de l'instance        */ -    if (result != NULL) -        g_object_ref(G_OBJECT(result)); +    class = G_EXECUTABLE_FORMAT_GET_CLASS(format); -    g_mutex_unlock(&format->mutex); +    result = class->translate_virt(format, addr, pos);      return result; @@ -522,10 +466,10 @@ GBinPortion *g_exe_format_get_portions(GExeFormat *format)  /******************************************************************************  *                                                                             *  *  Paramètres  : format = description de l'exécutable à consulter.            * -*                off    = position physique à retrouver.                      * +*                addr   = adresse virtuelle à retrouver.                      *  *                pos    = position correspondante. [OUT]                      *  *                                                                             * -*  Description : Fournit l'emplacement correspondant à une position physique. * +*  Description : Fournit l'emplacement correspondant à une adresse virtuelle. *  *                                                                             *  *  Retour      : Bilan de l'opération.                                        *  *                                                                             * @@ -533,13 +477,21 @@ GBinPortion *g_exe_format_get_portions(GExeFormat *format)  *                                                                             *  ******************************************************************************/ -bool g_exe_format_translate_offset_into_vmpa(GExeFormat *format, phys_t off, vmpa2t *pos) +bool g_executable_format_translate_address_into_vmpa_without_virt(const GExecutableFormat *format, virt_t addr, vmpa2t *pos)  { -    bool result;                            /* Bilan à retourner           */ +    /** +     * S'il n'y a pas de notion de mémoire virtuelle, positions physiques et +     * adresses virtuelles se confondent. +     * +     * On reste néanmoins cohérent, et on n'utilise donc pas d'adresse virtuelle. +     * +     * Les sauts dans le code renvoient de façon transparente vers des positions +     * physiques. +     */ -    result = G_EXE_FORMAT_GET_CLASS(format)->translate_phys(format, off, pos); +    init_vmpa(pos, addr, VMPA_NO_VIRTUAL); -    return result; +    return true;  } @@ -558,24 +510,32 @@ bool g_exe_format_translate_offset_into_vmpa(GExeFormat *format, phys_t off, vmp  *                                                                             *  ******************************************************************************/ -bool g_exe_format_translate_address_into_vmpa(GExeFormat *format, virt_t addr, vmpa2t *pos) +bool g_executable_format_translate_address_into_vmpa_with_portions(GExecutableFormat *format, virt_t addr, vmpa2t *pos)  {      bool result;                            /* Bilan à retourner           */ -    result = G_EXE_FORMAT_GET_CLASS(format)->translate_virt(format, addr, pos); +    if (format->portions == NULL) +        result = false; + +    else +        result = g_binary_portion_translate_address_into_vmpa(format->portions, addr, pos);      return result;  } + +/* ---------------------------------------------------------------------------------- */ +/*                       IMPLEMENTATION DES FONCTIONS DE CLASSE                       */ +/* ---------------------------------------------------------------------------------- */ + +  /******************************************************************************  *                                                                             * -*  Paramètres  : format = description de l'exécutable à consulter.            * -*                name   = nom de la section recherchée.                       * -*                range  = emplacement en mémoire à renseigner. [OUT]          * +*  Paramètres  : format = format chargé dont l'analyse est lancée.            *  *                                                                             * -*  Description : Fournit l'emplacement d'une section donnée.                  * +*  Description : Assure l'interprétation d'un format en différé.              *  *                                                                             *  *  Retour      : Bilan de l'opération.                                        *  *                                                                             * @@ -583,18 +543,17 @@ bool g_exe_format_translate_address_into_vmpa(GExeFormat *format, virt_t addr, v  *                                                                             *  ******************************************************************************/ -bool g_exe_format_get_section_range_by_name(const GExeFormat *format, const char *name, mrange_t *range) +static bool g_executable_format_analyze(GExecutableFormat *format)  {      bool result;                            /* Bilan à retourner           */ -    GExeFormatClass *class;                 /* Classe de l'instance        */ +    GExecutableFormatClass *class;          /* Classe de l'instance        */ -    class = G_EXE_FORMAT_GET_CLASS(format); - -    if (class->get_range_by_name == NULL) -        result = false; +    class = G_EXECUTABLE_FORMAT_GET_CLASS(format); +    if (class->refine_portions != NULL) +        result = class->refine_portions(format);      else -        result = class->get_range_by_name(format, name, range); +        result = true;      return result; diff --git a/src/format/executable.h b/src/format/executable.h index 4f5abc7..da71d66 100644 --- a/src/format/executable.h +++ b/src/format/executable.h @@ -2,7 +2,7 @@  /* Chrysalide - Outil d'analyse de fichiers binaires   * executable.h - prototypes pour le support des formats d'exécutables   * - * Copyright (C) 2009-2019 Cyrille Bagard + * Copyright (C) 2009-2024 Cyrille Bagard   *   *  This file is part of Chrysalide.   * @@ -25,88 +25,56 @@  #define _FORMAT_EXECUTABLE_H -#include <glib-object.h> +#include <stdbool.h> -#include "debuggable.h" -#include "../glibext/gbinportion.h" +#include "../glibext/helpers.h" +#include "../glibext/portion.h" -#define G_TYPE_EXE_FORMAT            g_executable_format_get_type() -#define G_EXE_FORMAT(obj)            (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_EXE_FORMAT, GExeFormat)) -#define G_IS_EXE_FORMAT(obj)         (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_EXE_FORMAT)) -#define G_EXE_FORMAT_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_EXE_FORMAT, GExeFormatClass)) -#define G_IS_EXE_FORMAT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_EXE_FORMAT)) -#define G_EXE_FORMAT_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_EXE_FORMAT, GExeFormatClass)) +#define G_TYPE_EXECUTABLE_FORMAT (g_executable_format_get_type()) +DECLARE_GTYPE(GExecutableFormat, g_executable_format, G, EXECUTABLE_FORMAT); -/* Format d'exécutable générique (instance) */ -typedef struct _GExeFormat GExeFormat; - -/* Format d'exécutable générique (classe) */ -typedef struct _GExeFormatClass GExeFormatClass; - - -/* Indique le type défini pour un format d'exécutable générique. */ -GType g_executable_format_get_type(void); - -/* Rajoute des informations de débogage à un exécutable. */ -void g_exe_format_add_debug_info(GExeFormat *, GDbgFormat *); - -/* Compte le nombre de formats de débogage liés à l'exécutable. */ -size_t g_exe_format_count_debug_info(const GExeFormat *); - -/* Fournit un format de débogage attaché à l'exécutable. */ -GDbgFormat *g_exe_format_get_debug_info(const GExeFormat *, size_t);  /* Indique le type d'architecture visée par le format. */ -const char *g_exe_format_get_target_machine(const GExeFormat *); +char *g_executable_format_get_target_machine(const GExecutableFormat *);  /* Fournit l'adresse principale associée à un format. */ -bool g_exe_format_get_main_address(GExeFormat *, vmpa2t *); - -/* Enregistre une portion artificielle pour le format. */ -void g_exe_format_register_user_portion(GExeFormat *, GBinPortion *); +bool g_executable_format_get_main_address(GExecutableFormat *, vmpa2t *);  /* Procède à l'enregistrement d'une portion dans un format. */ -void g_exe_format_include_portion(GExeFormat *, GBinPortion *, const vmpa2t *); +bool g_executable_format_include_portion(GExecutableFormat *, GBinaryPortion *, const vmpa2t *);  /* Fournit la première couche des portions composent le binaire. */ -GBinPortion *g_exe_format_get_portions(GExeFormat *); - -/* Fournit les espaces mémoires des portions exécutables. */ -mrange_t *g_exe_format_get_x_ranges(GExeFormat *, size_t *); +GBinaryPortion *g_executable_format_get_portions(GExecutableFormat *);  /* Fournit l'emplacement correspondant à une position physique. */ -bool g_exe_format_translate_offset_into_vmpa(GExeFormat *, phys_t, vmpa2t *); +bool g_executable_format_translate_offset_into_vmpa(GExecutableFormat *, phys_t, vmpa2t *);  /* Fournit l'emplacement correspondant à une position physique. */ -bool g_exe_format_translate_address_into_vmpa(GExeFormat *, virt_t, vmpa2t *); +bool g_executable_format_translate_address_into_vmpa(GExecutableFormat *, virt_t, vmpa2t *); -#define g_exe_format_translate_offset_into_address(fmt, off, addr)              \ -    ({                                                                          \ -        bool __result;                                                          \ -        vmpa2t __pos;                                                           \ -        __result = g_exe_format_translate_offset_into_vmpa(fmt, off, &__pos);   \ -        *addr = get_virt_addr(&__pos);                                          \ -        __result;                                                               \ +#define g_executable_format_translate_offset_into_address(fmt, off, addr)               \ +    ({                                                                                  \ +        bool __result;                                                                  \ +        vmpa2t __pos;                                                                   \ +        __result = g_executable_format_translate_offset_into_vmpa(fmt, off, &__pos);    \ +        *addr = get_virt_addr(&__pos);                                                  \ +        __result;                                                                       \      }) -#define g_exe_format_translate_address_into_offset(fmt, addr, off)              \ -    ({                                                                          \ -        bool __result;                                                          \ -        vmpa2t __pos;                                                           \ -        __result = g_exe_format_translate_address_into_vmpa(fmt, addr, &__pos); \ -        *off = get_phy_addr(&__pos);                                            \ -        __result;                                                               \ +#define g_executable_format_translate_address_into_offset(fmt, addr, off)               \ +    ({                                                                                  \ +        bool __result;                                                                  \ +        vmpa2t __pos;                                                                   \ +        __result = g_executable_format_translate_address_into_vmpa(fmt, addr, &__pos);  \ +        *off = get_phy_addr(&__pos);                                                    \ +        __result;                                                                       \      }) -/* Fournit l'emplacement d'une section donnée. */ -bool g_exe_format_get_section_range_by_name(const GExeFormat *, const char *, mrange_t *); - -  #endif  /* _FORMAT_EXECUTABLE_H */ diff --git a/src/format/flat-int.h b/src/format/flat-int.h index d785e5f..f858ba3 100644 --- a/src/format/flat-int.h +++ b/src/format/flat-int.h @@ -2,7 +2,7 @@  /* Chrysalide - Outil d'analyse de fichiers binaires   * flat-int.h - prototypes de code utile aux formats d'exécutables à plat   * - * Copyright (C) 2018 Cyrille Bagard + * Copyright (C) 2018-2024 Cyrille Bagard   *   *  This file is part of Chrysalide.   * @@ -35,7 +35,7 @@  /* Format d'exécutable à plat (instance) */  struct _GFlatFormat  { -    GExeFormat parent;                      /* A laisser en premier        */ +    GExecutableFormat parent;               /* A laisser en premier        */      char *machine;                          /* Architecture imposée        */      SourceEndian endian;                    /* Boutisme imposé             */ @@ -45,10 +45,14 @@ struct _GFlatFormat  /* Format d'exécutable à plat (classe) */  struct _GFlatFormatClass  { -    GExeFormatClass parent;                 /* A laisser en premier        */ +    GExecutableFormatClass parent;          /* A laisser en premier        */  }; +/* Met en place une nouvelle instance de format à plat. */ +bool g_flat_format_create(GFlatFormat *, GBinContent *, const char *, SourceEndian); + +  #endif  /* _FORMAT_FLAT_INT_H */ diff --git a/src/format/flat.c b/src/format/flat.c index 6b8b074..51f37fa 100644 --- a/src/format/flat.c +++ b/src/format/flat.c @@ -2,7 +2,7 @@  /* Chrysalide - Outil d'analyse de fichiers binaires   * flat.c - support des formats à plat   * - * Copyright (C) 2018-2019 Cyrille Bagard + * Copyright (C) 2018-2024 Cyrille Bagard   *   *  This file is part of Chrysalide.   * @@ -32,6 +32,9 @@ +/* ------------------------- DEFINITION D'UN NOUVEAU FORMAT ------------------------- */ + +  /* Initialise la classe des formats d'exécutables à plat. */  static void g_flat_format_class_init(GFlatFormatClass *); @@ -44,28 +47,39 @@ static void g_flat_format_dispose(GFlatFormat *);  /* Procède à la libération totale de la mémoire. */  static void g_flat_format_finalize(GFlatFormat *); + + +/* --------------------- IMPLEMENTATION DES FONCTIONS DE CLASSE --------------------- */ + +  /* Indique la désignation interne du format. */  static char *g_flat_format_get_key(const GFlatFormat *);  /* Fournit une description humaine du format. */  static char *g_flat_format_get_description(const GFlatFormat *); -/* Assure l'interprétation d'un format en différé. */ -static bool g_flat_format_analyze(GFlatFormat *, wgroup_id_t, GtkStatusStack *); -  /* Informe quant au boutisme utilisé. */  static SourceEndian g_flat_format_get_endianness(const GFlatFormat *);  /* Indique le type d'architecture visée par le format. */ -static const char *g_flat_format_get_target_machine(const GFlatFormat *); +static char *g_flat_format_get_target_machine(const GFlatFormat *); + +#if 0  /* Fournit l'adresse principale associée à un format à plat. */  static bool g_flat_format_get_main_address(GFlatFormat *, vmpa2t *); +#endif + + + +/* ---------------------------------------------------------------------------------- */ +/*                           DEFINITION D'UN NOUVEAU FORMAT                           */ +/* ---------------------------------------------------------------------------------- */  /* Indique le type défini pour un format d'exécutable à plat. */ -G_DEFINE_TYPE(GFlatFormat, g_flat_format, G_TYPE_EXE_FORMAT); +G_DEFINE_TYPE(GFlatFormat, g_flat_format, G_TYPE_EXECUTABLE_FORMAT);  /****************************************************************************** @@ -84,8 +98,8 @@ static void g_flat_format_class_init(GFlatFormatClass *klass)  {      GObjectClass *object;                   /* Autre version de la classe  */      GKnownFormatClass *known;               /* Version de format connu     */ -    GBinFormatClass *fmt;                   /* Version en format basique   */ -    GExeFormatClass *exe;                   /* Version en exécutable       */ +    GProgramFormatClass *prgm;              /* Version en format basique   */ +    GExecutableFormatClass *exe;            /* Version en exécutable       */      object = G_OBJECT_CLASS(klass); @@ -97,19 +111,18 @@ static void g_flat_format_class_init(GFlatFormatClass *klass)      known->get_key = (known_get_key_fc)g_flat_format_get_key;      known->get_desc = (known_get_desc_fc)g_flat_format_get_description; -    known->analyze = (known_analyze_fc)g_flat_format_analyze; - -    fmt = G_BIN_FORMAT_CLASS(klass); +    prgm = G_PROGRAM_FORMAT_CLASS(klass); -    fmt->get_endian = (format_get_endian_fc)g_flat_format_get_endianness; +    prgm->get_endian = (program_get_endian_fc)g_flat_format_get_endianness; -    exe = G_EXE_FORMAT_CLASS(klass); +    exe = G_EXECUTABLE_FORMAT_CLASS(klass);      exe->get_machine = (get_target_machine_fc)g_flat_format_get_target_machine; +#if 0      exe->get_main_addr = (get_main_addr_fc)g_flat_format_get_main_address; - -    exe->translate_phys = (translate_phys_fc)g_exe_format_translate_offset_into_vmpa_using_portions; -    exe->translate_virt = (translate_virt_fc)g_exe_format_translate_address_into_vmpa_using_portions; +#endif +    exe->translate_phys = g_executable_format_translate_offset_into_vmpa_with_portions; +    exe->translate_virt = g_executable_format_translate_address_into_vmpa_with_portions;  } @@ -178,8 +191,10 @@ static void g_flat_format_finalize(GFlatFormat *format)  /******************************************************************************  *                                                                             *  *  Paramètres  : content = contenu binaire à parcourir.                       * +*                machine = architecture déterminée pour le code.              * +                 endian  = boutisme à observer pour les données.              *  *                                                                             * -*  Description : Prend en charge un nouveau format à plat.                    * +*  Description : Crée une nouvelle instance de format à plat.                 *  *                                                                             *  *  Retour      : Adresse de la structure mise en place ou NULL en cas d'échec.*  *                                                                             * @@ -187,62 +202,72 @@ static void g_flat_format_finalize(GFlatFormat *format)  *                                                                             *  ******************************************************************************/ -GExeFormat *g_flat_format_new(GBinContent *content, const char *machine, SourceEndian endian) +GFlatFormat *g_flat_format_new(GBinContent *content, const char *machine, SourceEndian endian)  {      GFlatFormat *result;                     /* Structure à retourner       */      result = g_object_new(G_TYPE_FLAT_FORMAT, NULL); -    g_known_format_set_content(G_KNOWN_FORMAT(result), content); +    if (!g_flat_format_create(result, content, machine, endian)) +        g_clear_object(&result); -    result->machine = strdup(machine); -    result->endian = endian; - -    return G_EXE_FORMAT(result); +    return result;  }  /******************************************************************************  *                                                                             * -*  Paramètres  : format = description de l'exécutable à consulter.            * +*  Paramètres  : format  = description du format connu à consulter.           * +*                content = contenu binaire à parcourir.                       * +*                machine = architecture déterminée pour le code.              * +                 endian  = boutisme à observer pour les données.              *  *                                                                             * -*  Description : Indique la désignation interne du format.                    * +*  Description : Met en place une nouvelle instance de format à plat.         *  *                                                                             * -*  Retour      : Désignation du format.                                       * +*  Retour      : Bilan de l'opération.                                        *  *                                                                             *  *  Remarques   : -                                                            *  *                                                                             *  ******************************************************************************/ -static char *g_flat_format_get_key(const GFlatFormat *format) +bool g_flat_format_create(GFlatFormat *format, GBinContent *content, const char *machine, SourceEndian endian)  { -    char *result;                           /* Désignation à retourner     */ +    bool result;                            /* Bilan à retourner           */ -    result = strdup("flat"); +    result = g_executable_format_create(G_EXECUTABLE_FORMAT(format), content); + +    format->machine = strdup(machine); +    format->endian = endian;      return result;  } + +/* ---------------------------------------------------------------------------------- */ +/*                       IMPLEMENTATION DES FONCTIONS DE CLASSE                       */ +/* ---------------------------------------------------------------------------------- */ + +  /******************************************************************************  *                                                                             *  *  Paramètres  : format = description de l'exécutable à consulter.            *  *                                                                             * -*  Description : Fournit une description humaine du format.                   * +*  Description : Indique la désignation interne du format.                    *  *                                                                             * -*  Retour      : Description du format.                                       * +*  Retour      : Désignation du format.                                       *  *                                                                             *  *  Remarques   : -                                                            *  *                                                                             *  ******************************************************************************/ -static char *g_flat_format_get_description(const GFlatFormat *format) +static char *g_flat_format_get_key(const GFlatFormat *format)  {      char *result;                           /* Désignation à retourner     */ -    result = strdup("Flat executable format"); +    result = strdup("flat");      return result; @@ -251,25 +276,21 @@ static char *g_flat_format_get_description(const GFlatFormat *format)  /******************************************************************************  *                                                                             * -*  Paramètres  : format = format chargé dont l'analyse est lancée.            * -*                gid    = groupe de travail dédié.                            * -*                status = barre de statut à tenir informée.                   * +*  Paramètres  : format = description de l'exécutable à consulter.            *  *                                                                             * -*  Description : Assure l'interprétation d'un format en différé.              * +*  Description : Fournit une description humaine du format.                   *  *                                                                             * -*  Retour      : Bilan de l'opération.                                        * +*  Retour      : Description du format.                                       *  *                                                                             *  *  Remarques   : -                                                            *  *                                                                             *  ******************************************************************************/ -static bool g_flat_format_analyze(GFlatFormat *format, wgroup_id_t gid, GtkStatusStack *status) +static char *g_flat_format_get_description(const GFlatFormat *format)  { -    bool result;                            /* Bilan à retourner           */ - -    result = true; +    char *result;                           /* Désignation à retourner     */ -    g_executable_format_setup_portions(G_EXE_FORMAT(format), status); +    result = strdup("Flat executable format");      return result; @@ -290,14 +311,18 @@ static bool g_flat_format_analyze(GFlatFormat *format, wgroup_id_t gid, GtkStatu  static SourceEndian g_flat_format_get_endianness(const GFlatFormat *format)  { -    return format->endian; +    SourceEndian result;                    /* Valeur à retourner          */ + +    result = format->endian; + +    return result;  }  /******************************************************************************  *                                                                             * -*  Paramètres  : format = informations chargées à consulter.                  * +*  Paramètres  : format = description du format exécutable à consulter.       *  *                                                                             *  *  Description : Indique le type d'architecture visée par le format.          *  *                                                                             * @@ -307,17 +332,17 @@ static SourceEndian g_flat_format_get_endianness(const GFlatFormat *format)  *                                                                             *  ******************************************************************************/ -static const char *g_flat_format_get_target_machine(const GFlatFormat *format) +static char *g_flat_format_get_target_machine(const GFlatFormat *format)  { -    const char *result;                     /* Identifiant à retourner     */ +    char *result;                           /* Identifiant à retourner     */ -    result = format->machine; +    result = strdup(format->machine);      return result;  } - +#if 0  /******************************************************************************  *                                                                             *  *  Paramètres  : format = description de l'exécutable à consulter.            * @@ -350,3 +375,5 @@ static bool g_flat_format_get_main_address(GFlatFormat *format, vmpa2t *addr)      return result;  } + +#endif diff --git a/src/format/flat.h b/src/format/flat.h index 83c5e3c..2168221 100644 --- a/src/format/flat.h +++ b/src/format/flat.h @@ -2,7 +2,7 @@  /* Chrysalide - Outil d'analyse de fichiers binaires   * flat.h - prototypes pour le support des formats à plat   * - * Copyright (C) 2018 Cyrille Bagard + * Copyright (C) 2018-2024 Cyrille Bagard   *   *  This file is part of Chrysalide.   * @@ -25,34 +25,19 @@  #define _FORMAT_FLAT_H -#include <glib-object.h> - - -#include "executable.h"  #include "../analysis/content.h" +#include "../glibext/helpers.h" -#define G_TYPE_FLAT_FORMAT            g_flat_format_get_type() -#define G_FLAT_FORMAT(obj)            (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_FLAT_FORMAT, GFlatFormat)) -#define G_IS_FLAT_FORMAT(obj)         (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_FLAT_FORMAT)) -#define G_FLAT_FORMAT_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_FLAT_FORMAT, GFlatFormatClass)) -#define G_IS_FLAT_FORMAT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_FLAT_FORMAT)) -#define G_FLAT_FORMAT_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_FLAT_FORMAT, GFlatFormatClass)) - - -/* Format d'exécutable à plat (instance) */ -typedef struct _GFlatFormat GFlatFormat; +#define G_TYPE_FLAT_FORMAT (g_flat_format_get_type()) -/* Format d'exécutable à plat (classe) */ -typedef struct _GFlatFormatClass GFlatFormatClass; +DECLARE_GTYPE(GFlatFormat, g_flat_format, G, FLAT_FORMAT); -/* Indique le type défini pour un format d'exécutable à plat. */ -GType g_flat_format_get_type(void); -/* Prend en charge un nouveau format à plat. */ -GExeFormat *g_flat_format_new(GBinContent *, const char *, SourceEndian); +/* Crée une nouvelle instance de format à plat. */ +GFlatFormat *g_flat_format_new(GBinContent *, const char *, SourceEndian); diff --git a/src/format/known-int.h b/src/format/known-int.h index 3328a96..75d0dab 100644 --- a/src/format/known-int.h +++ b/src/format/known-int.h @@ -2,7 +2,7 @@  /* Chrysalide - Outil d'analyse de fichiers binaires   * known-int.h - prototypes utiles aux formats binaires reconnus   * - * Copyright (C) 2019 Cyrille Bagard + * Copyright (C) 2019-2024 Cyrille Bagard   *   *  This file is part of Chrysalide.   * @@ -26,7 +26,7 @@  #include "known.h" -#include "../analysis/storage/storage.h" +//#include "../analysis/storage/storage.h" @@ -37,16 +37,15 @@ typedef char * (* known_get_key_fc) (const GKnownFormat *);  typedef char * (* known_get_desc_fc) (const GKnownFormat *);  /*Assure l'interprétation d'un format en différé. */ -typedef bool (* known_analyze_fc) (GKnownFormat *, wgroup_id_t, GtkStatusStack *); - -/* Réalise un traitement post-désassemblage. */ -typedef void (* known_complete_analysis_fc) (GKnownFormat *, wgroup_id_t, GtkStatusStack *); +typedef bool (* known_analyze_fc) (GKnownFormat *); +#if 0  /* Charge un format depuis une mémoire tampon. */  typedef bool (* load_known_fc) (GKnownFormat *, GObjectStorage *, packed_buffer_t *);  /* Sauvegarde un format dans une mémoire tampon. */  typedef bool (* store_known_fc) (GKnownFormat *, GObjectStorage *, packed_buffer_t *); +#endif  /* Format binaire générique (instance) */ @@ -67,13 +66,18 @@ struct _GKnownFormatClass      known_get_desc_fc get_desc;             /* Désignation humaine         */      known_analyze_fc analyze;               /* Interprétation du format    */ -    known_complete_analysis_fc complete;    /* Terminaison d'analyse       */ +#if 0      load_known_fc load;                     /* Chargement depuis un tampon */      store_known_fc store;                   /* Conservation dans un tampon */ +#endif  }; +/* Met en place un nouveau contenu binaire à analyser. */ +bool g_known_format_create(GKnownFormat *, GBinContent *); + +  #endif  /* _FORMAT_KNOWN_INT_H */ diff --git a/src/format/known.c b/src/format/known.c index 7512ae1..bc03793 100644 --- a/src/format/known.c +++ b/src/format/known.c @@ -2,7 +2,7 @@  /* Chrysalide - Outil d'analyse de fichiers binaires   * format.c - support des différents formats binaires reconnus   * - * Copyright (C) 2019 Cyrille Bagard + * Copyright (C) 2019-2024 Cyrille Bagard   *   *  This file is part of Chrysalide.   * @@ -28,8 +28,8 @@  #include "known-int.h" -#include "../analysis/storage/serialize-int.h" -#include "../plugins/pglist.h" +//#include "../analysis/storage/serialize-int.h" +//#include "../plugins/pglist.h" @@ -43,7 +43,7 @@ static void g_known_format_class_init(GKnownFormatClass *);  static void g_known_format_init(GKnownFormat *);  /* Procède à l'initialisation de l'interface de sérialisation. */ -static void g_known_format_serializable_init(GSerializableObjectInterface *); +//static void g_known_format_serializable_init(GSerializableObjectInterface *);  /* Supprime toutes les références externes. */  static void g_known_format_dispose(GKnownFormat *); @@ -56,6 +56,7 @@ static void g_known_format_finalize(GKnownFormat *);  /* -------------------- CONSERVATION ET RECHARGEMENT DES DONNEES -------------------- */ +#if 0  /* Charge un format depuis une mémoire tampon. */  static bool _g_known_format_load(GKnownFormat *, GObjectStorage *, packed_buffer_t *); @@ -67,7 +68,7 @@ static bool _g_known_format_store(GKnownFormat *, GObjectStorage *, packed_buffe  /* Sauvegarde un format dans une mémoire tampon. */  static bool g_known_format_store(GKnownFormat *, GObjectStorage *, packed_buffer_t *); - +#endif  /* ---------------------------------------------------------------------------------- */ @@ -76,8 +77,9 @@ static bool g_known_format_store(GKnownFormat *, GObjectStorage *, packed_buffer  /* Indique le type défini pour un format binaire générique. */ -G_DEFINE_TYPE_WITH_CODE(GKnownFormat, g_known_format, G_TYPE_OBJECT, -                        G_IMPLEMENT_INTERFACE(G_TYPE_SERIALIZABLE_OBJECT, g_known_format_serializable_init)); +//G_DEFINE_TYPE_WITH_CODE(GKnownFormat, g_known_format, G_TYPE_OBJECT, +//                        G_IMPLEMENT_INTERFACE(G_TYPE_SERIALIZABLE_OBJECT, g_known_format_serializable_init)); +G_DEFINE_TYPE(GKnownFormat, g_known_format, G_TYPE_OBJECT);  /****************************************************************************** @@ -101,8 +103,10 @@ static void g_known_format_class_init(GKnownFormatClass *klass)      object->dispose = (GObjectFinalizeFunc/* ! */)g_known_format_dispose;      object->finalize = (GObjectFinalizeFunc)g_known_format_finalize; +    /*      klass->load = (load_known_fc)_g_known_format_load;      klass->store = (store_known_fc)_g_known_format_store; +    */  } @@ -126,6 +130,7 @@ static void g_known_format_init(GKnownFormat *format)  } +#if 0  /******************************************************************************  *                                                                             *  *  Paramètres  : iface = interface GLib à initialiser.                        * @@ -144,6 +149,7 @@ static void g_known_format_serializable_init(GSerializableObjectInterface *iface      iface->store = (store_serializable_object_cb)g_known_format_store;  } +#endif  /****************************************************************************** @@ -188,24 +194,27 @@ static void g_known_format_finalize(GKnownFormat *format)  /******************************************************************************  *                                                                             * -*  Paramètres  : format = description du format connu à consulter.            * +*  Paramètres  : format = description du format à initialiser pleinement.     *  *                content = contenu binaire à parcourir.                       *  *                                                                             * -*  Description : Définit le contenu binaire à analyser.                       * +*  Description : Met en place un nouveau contenu binaire à analyser.          *  *                                                                             * -*  Retour      : -                                                            * +*  Retour      : Bilan de l'opération.                                        *  *                                                                             *  *  Remarques   : -                                                            *  *                                                                             *  ******************************************************************************/ -void g_known_format_set_content(GKnownFormat *format, GBinContent *content) +bool g_known_format_create(GKnownFormat *format, GBinContent *content)  { -    assert(format->content == NULL); +    bool result;                            /* Bilan à retourner           */ -    g_object_ref_sink(G_OBJECT(content)); +    result = true;      format->content = content; +    ref_object(content); + +    return result;  } @@ -251,8 +260,13 @@ GBinContent *g_known_format_get_content(const GKnownFormat *format)  char *g_known_format_get_key(const GKnownFormat *format)  {      char *result;                           /* Désignation à retourner     */ +    GKnownFormatClass *class;               /* Classe de l'instance        */ + +    class = G_KNOWN_FORMAT_GET_CLASS(format); -    result = G_KNOWN_FORMAT_GET_CLASS(format)->get_key(format); +    result = class->get_key(format); + +    //assert(result != NULL);      return result; @@ -274,8 +288,13 @@ char *g_known_format_get_key(const GKnownFormat *format)  char *g_known_format_get_description(const GKnownFormat *format)  {      char *result;                           /* Description à retourner     */ +    GKnownFormatClass *class;               /* Classe de l'instance        */ + +    class = G_KNOWN_FORMAT_GET_CLASS(format); + +    result = class->get_desc(format); -    result = G_KNOWN_FORMAT_GET_CLASS(format)->get_desc(format); +    //assert(result != NULL);      return result; @@ -285,8 +304,6 @@ char *g_known_format_get_description(const GKnownFormat *format)  /******************************************************************************  *                                                                             *  *  Paramètres  : format = format chargé dont l'analyse est lancée.            * -*                gid    = groupe de travail dédié.                            * -*                status = barre de statut à tenir informée.                   *  *                                                                             *  *  Description : Assure l'interprétation d'un format en différé.              *  *                                                                             * @@ -296,60 +313,30 @@ char *g_known_format_get_description(const GKnownFormat *format)  *                                                                             *  ******************************************************************************/ -bool g_known_format_analyze(GKnownFormat *format, wgroup_id_t gid, GtkStatusStack *status) +bool g_known_format_analyze(GKnownFormat *format)  {      bool result;                            /* Bilan à retourner           */      GKnownFormatClass *class;               /* Classe de l'instance        */ -    handle_known_format_analysis(PGA_FORMAT_ANALYSIS_STARTED, format, gid, status); +    //handle_known_format_analysis(PGA_FORMAT_ANALYSIS_STARTED, format, gid, status);      class = G_KNOWN_FORMAT_GET_CLASS(format); -    result = class->analyze(format, gid, status); +    result = class->analyze(format); -    handle_known_format_analysis(PGA_FORMAT_ANALYSIS_ENDED, format, gid, status); +    //handle_known_format_analysis(PGA_FORMAT_ANALYSIS_ENDED, format, gid, status);      return result;  } -/****************************************************************************** -*                                                                             * -*  Paramètres  : format = description de l'exécutable à manipuler.            * -*                gid    = groupe de travail dédié.                            * -*                status = barre de statut à tenir informée.                   * -*                                                                             * -*  Description : Réalise un traitement post-désassemblage.                    * -*                                                                             * -*  Retour      : -                                                            * -*                                                                             * -*  Remarques   : -                                                            * -*                                                                             * -******************************************************************************/ - -void g_known_format_complete_analysis(GKnownFormat *format, wgroup_id_t gid, GtkStatusStack *status) -{ -    GKnownFormatClass *class;               /* Classe de l'instance        */ - -    handle_known_format_analysis(PGA_FORMAT_POST_ANALYSIS_STARTED, format, gid, status); - -    class = G_KNOWN_FORMAT_GET_CLASS(format); - -    if (class->complete != NULL) -        class->complete(format, gid, status); - -    handle_known_format_analysis(PGA_FORMAT_POST_ANALYSIS_ENDED, format, gid, status); - -} - -  /* ---------------------------------------------------------------------------------- */  /*                      CONSERVATION ET RECHARGEMENT DES DONNEES                      */  /* ---------------------------------------------------------------------------------- */ - +#if 0  /******************************************************************************  *                                                                             *  *  Paramètres  : operand = élément GLib à constuire.                          * @@ -468,3 +455,4 @@ static bool g_known_format_store(GKnownFormat *format, GObjectStorage *storage,      return result;  } +#endif diff --git a/src/format/known.h b/src/format/known.h index dcc8669..41236df 100644 --- a/src/format/known.h +++ b/src/format/known.h @@ -2,7 +2,7 @@  /* Chrysalide - Outil d'analyse de fichiers binaires   * format.h - prototypes pour le support des différents formats binaires reconnus   * - * Copyright (C) 2019 Cyrille Bagard + * Copyright (C) 2019-2024 Cyrille Bagard   *   *  This file is part of Chrysalide.   * @@ -25,37 +25,17 @@  #define _FORMAT_KNOWN_H -#include <glib-object.h> -#include <stdbool.h> - -  #include "../analysis/content.h" -#include "../glibext/delayed.h" -#include "../glibext/notifier.h" - +#include "../glibext/helpers.h" -#define G_TYPE_KNOWN_FORMAT            g_known_format_get_type() -#define G_KNOWN_FORMAT(obj)            (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_KNOWN_FORMAT, GKnownFormat)) -#define G_IS_KNOWN_FORMAT(obj)         (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_KNOWN_FORMAT)) -#define G_KNOWN_FORMAT_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_KNOWN_FORMAT, GKnownFormatClass)) -#define G_IS_KNOWN_FORMAT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_KNOWN_FORMAT)) -#define G_KNOWN_FORMAT_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_KNOWN_FORMAT, GKnownFormatClass)) +#define G_TYPE_KNOWN_FORMAT (g_known_format_get_type()) -/* Format binaire générique (instance) */ -typedef struct _GKnownFormat GKnownFormat; +DECLARE_GTYPE(GKnownFormat, g_known_format, G, KNOWN_FORMAT); -/* Format binaire générique (classe) */ -typedef struct _GKnownFormatClass GKnownFormatClass; -/* Indique le type défini pour un format binaire générique. */ -GType g_known_format_get_type(void); - -/* Définit le contenu binaire à analyser. */ -void g_known_format_set_content(GKnownFormat *, GBinContent *); -  /* Fournit une référence vers le contenu binaire analysé. */  GBinContent *g_known_format_get_content(const GKnownFormat *); @@ -66,10 +46,7 @@ char *g_known_format_get_key(const GKnownFormat *);  char *g_known_format_get_description(const GKnownFormat *);  /* Assure l'interprétation d'un format en différé. */ -bool g_known_format_analyze(GKnownFormat *, wgroup_id_t, GtkStatusStack *); - -/* Réalise un traitement post-désassemblage. */ -void g_known_format_complete_analysis(GKnownFormat *, wgroup_id_t, GtkStatusStack *); +bool g_known_format_analyze(GKnownFormat *); diff --git a/src/format/format-int.h b/src/format/program-int.h index f18bb24..8464fe4 100644 --- a/src/format/format-int.h +++ b/src/format/program-int.h @@ -1,8 +1,8 @@  /* Chrysalide - Outil d'analyse de fichiers binaires - * format-int.h - prototypes utiles aux formats binaires + * program-int.h - prototypes internes pour le support des différents formats de programmes   * - * Copyright (C) 2009-2018 Cyrille Bagard + * Copyright (C) 2009-2024 Cyrille Bagard   *   *  This file is part of Chrysalide.   * @@ -21,14 +21,59 @@   */ -#ifndef _FORMAT_FORMAT_INT_H -#define _FORMAT_FORMAT_INT_H +#ifndef _FORMAT_PROGRAM_INT_H +#define _FORMAT_PROGRAM_INT_H -#include "format.h" +#include "program.h"  #include "known-int.h" + + + +/* Indique le boutisme employé par le format binaire analysé. */ +typedef SourceEndian (* program_get_endian_fc) (const GProgramFormat *); + +/* Fournit l'emplacement d'une section donnée. */ +typedef bool (* find_range_by_name_fc) (const GProgramFormat *, const char *, mrange_t *); + + +/* Format de programme générique (instance) */ +struct _GProgramFormat +{ +    GKnownFormat parent;                    /* A laisser en premier        */ + +}; + +/* Format de programme générique (classe) */ +struct _GProgramFormatClass +{ +    GKnownFormatClass parent;               /* A laisser en premier        */ + +    program_get_endian_fc get_endian;       /* Boutisme employé            */ +    find_range_by_name_fc find_range_by_name; /* Emplacement de sections   */ + +}; + + +/* Met en place un nouveau contenu binaire à analyser. */ +bool g_program_format_create(GProgramFormat *, GBinContent *); + + + + + + + + + + + + + +#if 0 +  #include "preload.h"  #include "../glibext/objhole.h"  #include "../mangling/demangler.h" @@ -38,9 +83,6 @@  /* ------------------------ TRAITEMENT INDIVIDUEL DE FORMATS ------------------------ */ -/* Indique le boutisme employé par le format binaire analysé. */ -typedef SourceEndian (* format_get_endian_fc) (const GBinFormat *); -  /* Rythme des allocations pour les entrées de code */  #define EXTRA_POINT_BLOCK 20 @@ -120,8 +162,6 @@ struct _GBinFormatClass  {      GKnownFormatClass parent;               /* A laisser en premier        */ -    format_get_endian_fc get_endian;        /* Boutisme employé            */ -      /* Signaux */      void (* symbol_added) (GBinFormat *, GBinSymbol *); @@ -156,5 +196,8 @@ GDataType *g_binary_format_decode_type(const GBinFormat *, const char *);  GBinRoutine *g_binary_format_decode_routine(const GBinFormat *, const char *); +#endif + + -#endif  /* _FORMAT_FORMAT_INT_H */ +#endif  /* _FORMAT_PROGRAM_INT_H */ diff --git a/src/format/format.c b/src/format/program.c index d126236..9b9df81 100644 --- a/src/format/format.c +++ b/src/format/program.c @@ -1,8 +1,8 @@  /* Chrysalide - Outil d'analyse de fichiers binaires - * format.c - support des différents formats binaires + * program.c - support des différents formats de programmes   * - * Copyright (C) 2009-2020 Cyrille Bagard + * Copyright (C) 2009-2024 Cyrille Bagard   *   *  This file is part of Chrysalide.   * @@ -21,40 +21,45 @@   */ -#include "format.h" +#include "program.h" -#include <assert.h> -#include <malloc.h> -#include <string.h> +//#include <assert.h> +//#include <malloc.h> +//#include <string.h> -#include "format-int.h" +#include "program-int.h" + +/*  #include "preload.h"  #include "../arch/processor.h"  #include "../common/sort.h"  #include "../core/demanglers.h"  #include "../plugins/pglist.h" +*/  /* Initialise la classe des formats binaires génériques. */ -static void g_binary_format_class_init(GBinFormatClass *); +static void g_program_format_class_init(GProgramFormatClass *);  /* Initialise une instance de format binaire générique. */ -static void g_binary_format_init(GBinFormat *); +static void g_program_format_init(GProgramFormat *);  /* Supprime toutes les références externes. */ -static void g_binary_format_dispose(GBinFormat *); +static void g_program_format_dispose(GProgramFormat *);  /* Procède à la libération totale de la mémoire. */ -static void g_binary_format_finalize(GBinFormat *); +static void g_program_format_finalize(GProgramFormat *); + +#if 0  /* Charge les plages de couvertures depuis une mémoire tampon. */ -static bool g_binary_format_load_start_points(GBinFormat *, packed_buffer_t *); +static bool g_program_format_load_start_points(GProgramFormat *, packed_buffer_t *);  /* Sauvegarde les points de départ enregistrés pour un format. */ -static bool g_binary_format_store_start_points(GBinFormat *, packed_buffer_t *); +static bool g_program_format_store_start_points(GProgramFormat *, packed_buffer_t *); @@ -62,13 +67,13 @@ static bool g_binary_format_store_start_points(GBinFormat *, packed_buffer_t *);  /* Retire un symbole de la collection du format binaire. */ -static void _g_binary_format_remove_symbol(GBinFormat *, size_t); +static void _g_program_format_remove_symbol(GProgramFormat *, size_t);  /* Recherche le symbole associé à une adresse. */ -static bool _g_binary_format_find_symbol(const GBinFormat *, const vmpa2t *, __compar_fn_t, size_t *, GBinSymbol **); +static bool _g_program_format_find_symbol(const GProgramFormat *, const vmpa2t *, __compar_fn_t, size_t *, GBinSymbol **);  /* Recherche un symbole particulier. */ -static bool __g_binary_format_find_symbol(const GBinFormat *, const void *, __compar_fn_t, size_t *, GBinSymbol **); +static bool __g_program_format_find_symbol(const GProgramFormat *, const void *, __compar_fn_t, size_t *, GBinSymbol **); @@ -76,10 +81,10 @@ static bool __g_binary_format_find_symbol(const GBinFormat *, const void *, __co  /* Charge les erreurs de chargement depuis une mémoire tampon. */ -static bool g_binary_format_load_errors(GBinFormat *, packed_buffer_t *); +static bool g_program_format_load_errors(GProgramFormat *, packed_buffer_t *);  /* Sauvegarde les erreurs de chargement dans une mémoire tampon. */ -static bool g_binary_format_store_errors(GBinFormat *, packed_buffer_t *); +static bool g_program_format_store_errors(GProgramFormat *, packed_buffer_t *); @@ -87,17 +92,18 @@ static bool g_binary_format_store_errors(GBinFormat *, packed_buffer_t *);  /* Charge un format depuis une mémoire tampon. */ -static bool g_binary_format_load(GBinFormat *, GObjectStorage *, packed_buffer_t *); +static bool g_program_format_load(GProgramFormat *, GObjectStorage *, packed_buffer_t *);  /* Sauvegarde un format dans une mémoire tampon. */ -static bool g_binary_format_store(GBinFormat *, GObjectStorage *, packed_buffer_t *); +static bool g_program_format_store(GProgramFormat *, GObjectStorage *, packed_buffer_t *); +#endif  /* Indique le type défini pour un format binaire générique. */ -G_DEFINE_TYPE(GBinFormat, g_binary_format, G_TYPE_KNOWN_FORMAT); +G_DEFINE_TYPE(GProgramFormat, g_program_format, G_TYPE_KNOWN_FORMAT);  /****************************************************************************** @@ -112,25 +118,27 @@ G_DEFINE_TYPE(GBinFormat, g_binary_format, G_TYPE_KNOWN_FORMAT);  *                                                                             *  ******************************************************************************/ -static void g_binary_format_class_init(GBinFormatClass *klass) +static void g_program_format_class_init(GProgramFormatClass *klass)  {      GObjectClass *object;                   /* Autre version de la classe  */ -    GKnownFormatClass *known;               /* Version de classe parente   */ +    //GKnownFormatClass *known;               /* Version de classe parente   */      object = G_OBJECT_CLASS(klass); -    object->dispose = (GObjectFinalizeFunc/* ! */)g_binary_format_dispose; -    object->finalize = (GObjectFinalizeFunc)g_binary_format_finalize; +    object->dispose = (GObjectFinalizeFunc/* ! */)g_program_format_dispose; +    object->finalize = (GObjectFinalizeFunc)g_program_format_finalize; + +#if 0      known = G_KNOWN_FORMAT_CLASS(klass); -    known->load = (load_known_fc)g_binary_format_load; -    known->store = (load_known_fc)g_binary_format_store; +    known->load = (load_known_fc)g_program_format_load; +    known->store = (load_known_fc)g_program_format_store;      g_signal_new("symbol-added",                   G_TYPE_BIN_FORMAT,                   G_SIGNAL_RUN_LAST, -                 G_STRUCT_OFFSET(GBinFormatClass, symbol_added), +                 G_STRUCT_OFFSET(GProgramFormatClass, symbol_added),                   NULL, NULL,                   g_cclosure_marshal_VOID__OBJECT,                   G_TYPE_NONE, 1, G_TYPE_OBJECT); @@ -138,11 +146,13 @@ static void g_binary_format_class_init(GBinFormatClass *klass)      g_signal_new("symbol-removed",                   G_TYPE_BIN_FORMAT,                   G_SIGNAL_RUN_LAST, -                 G_STRUCT_OFFSET(GBinFormatClass, symbol_removed), +                 G_STRUCT_OFFSET(GProgramFormatClass, symbol_removed),                   NULL, NULL,                   g_cclosure_marshal_VOID__OBJECT,                   G_TYPE_NONE, 1, G_TYPE_OBJECT); +#endif +  } @@ -158,8 +168,10 @@ static void g_binary_format_class_init(GBinFormatClass *klass)  *                                                                             *  ******************************************************************************/ -static void g_binary_format_init(GBinFormat *format) +static void g_program_format_init(GProgramFormat *format)  { + +#if 0      fmt_extra_data_t *extra;                /* Données insérées à modifier */      extra = GET_BIN_FORMAT_EXTRA(format); @@ -184,6 +196,8 @@ static void g_binary_format_init(GBinFormat *format)      g_atomic_int_set(&format->error_locked, 0);  #endif +#endif +  } @@ -199,8 +213,10 @@ static void g_binary_format_init(GBinFormat *format)  *                                                                             *  ******************************************************************************/ -static void g_binary_format_dispose(GBinFormat *format) +static void g_program_format_dispose(GProgramFormat *format)  { +#if 0 +      size_t i;                               /* Boucle de parcours          */      g_rw_lock_clear(&format->pt_lock); @@ -216,7 +232,10 @@ static void g_binary_format_dispose(GBinFormat *format)      g_mutex_clear(&format->error_mutex); -    G_OBJECT_CLASS(g_binary_format_parent_class)->dispose(G_OBJECT(format)); +#endif + + +    G_OBJECT_CLASS(g_program_format_parent_class)->dispose(G_OBJECT(format));  } @@ -233,8 +252,10 @@ static void g_binary_format_dispose(GBinFormat *format)  *                                                                             *  ******************************************************************************/ -static void g_binary_format_finalize(GBinFormat *format) +static void g_program_format_finalize(GProgramFormat *format)  { +#if 0 +      DisassPriorityLevel i;                  /* Boucle de parcours #1       */      size_t k;                               /* Boucle de parcours #2       */ @@ -255,13 +276,43 @@ static void g_binary_format_finalize(GBinFormat *format)      } -    G_OBJECT_CLASS(g_binary_format_parent_class)->finalize(G_OBJECT(format)); +#endif + + + +    G_OBJECT_CLASS(g_program_format_parent_class)->finalize(G_OBJECT(format));  }  /******************************************************************************  *                                                                             * +*  Paramètres  : format  = description du format à initialiser pleinement.    * +*                content = contenu binaire à parcourir.                       * +*                                                                             * +*  Description : Met en place un nouveau contenu binaire à analyser.          * +*                                                                             * +*  Retour      : Bilan de l'opération.                                        * +*                                                                             * +*  Remarques   : -                                                            * +*                                                                             * +******************************************************************************/ + +bool g_program_format_create(GProgramFormat *format, GBinContent *content) +{ +    bool result;                            /* Bilan à retourner           */ + +    result = g_known_format_create(G_KNOWN_FORMAT(format), content); + +    return result; + +} + + +#if 0 + +/****************************************************************************** +*                                                                             *  *  Paramètres  : format = format à venir modifier.                            *  *                flag   = drapeau d'information complémentaire à planter.     *  *                                                                             * @@ -273,7 +324,7 @@ static void g_binary_format_finalize(GBinFormat *format)  *                                                                             *  ******************************************************************************/ -bool g_binary_format_set_flag(GBinFormat *format, FormatFlag flag) +bool g_program_format_set_flag(GProgramFormat *format, FormatFlag flag)  {      bool result;                            /* Bilan à retourner           */      fmt_extra_data_t *extra;                /* Données insérées à modifier */ @@ -306,7 +357,7 @@ bool g_binary_format_set_flag(GBinFormat *format, FormatFlag flag)  *                                                                             *  ******************************************************************************/ -bool g_binary_format_unset_flag(GBinFormat *format, FormatFlag flag) +bool g_program_format_unset_flag(GProgramFormat *format, FormatFlag flag)  {      bool result;                            /* Bilan à retourner           */      fmt_extra_data_t *extra;                /* Données insérées à modifier */ @@ -339,7 +390,7 @@ bool g_binary_format_unset_flag(GBinFormat *format, FormatFlag flag)  *                                                                             *  ******************************************************************************/ -bool g_binary_format_has_flag(const GBinFormat *format, FormatFlag flag) +bool g_program_format_has_flag(const GProgramFormat *format, FormatFlag flag)  {      bool result;                            /* Bilan à retourner           */      fmt_extra_data_t *extra;                /* Données insérées à modifier */ @@ -369,7 +420,7 @@ bool g_binary_format_has_flag(const GBinFormat *format, FormatFlag flag)  *                                                                             *  ******************************************************************************/ -FormatFlag g_binary_format_get_flags(const GBinFormat *format) +FormatFlag g_program_format_get_flags(const GProgramFormat *format)  {      FormatFlag result;                      /* Fanions à retourner         */      fmt_extra_data_t *extra;                /* Données insérées à modifier */ @@ -386,6 +437,8 @@ FormatFlag g_binary_format_get_flags(const GBinFormat *format)  } +#endif +  /******************************************************************************  *                                                                             * @@ -399,11 +452,14 @@ FormatFlag g_binary_format_get_flags(const GBinFormat *format)  *                                                                             *  ******************************************************************************/ -SourceEndian g_binary_format_get_endianness(const GBinFormat *format) +SourceEndian g_program_format_get_endianness(const GProgramFormat *format)  {      SourceEndian result;                    /* Boutisme à retourner        */ +    GProgramFormatClass *class;             /* Classe de l'instance        */ + +    class = G_PROGRAM_FORMAT_GET_CLASS(format); -    result = G_BIN_FORMAT_GET_CLASS(format)->get_endian(format); +    result = class->get_endian(format);      return result; @@ -412,6 +468,40 @@ SourceEndian g_binary_format_get_endianness(const GBinFormat *format)  /******************************************************************************  *                                                                             * +*  Paramètres  : format = description du programme à consulter.               * +*                name   = nom de la section recherchée.                       * +*                range  = emplacement en mémoire à renseigner. [OUT]          * +*                                                                             * +*  Description : Fournit l'emplacement d'une section donnée.                  * +*                                                                             * +*  Retour      : Bilan de l'opération.                                        * +*                                                                             * +*  Remarques   : -                                                            * +*                                                                             * +******************************************************************************/ + +bool g_program_format_find_section_range_by_name(const GProgramFormat *format, const char *name, mrange_t *range) +{ +    bool result;                            /* Bilan à retourner           */ +    GProgramFormatClass *class;             /* Classe de l'instance        */ + +    class = G_PROGRAM_FORMAT_GET_CLASS(format); + +    if (class->find_range_by_name == NULL) +        result = false; + +    else +        result = class->find_range_by_name(format, name, range); + +    return result; + +} + + +#if 0 + +/****************************************************************************** +*                                                                             *  *  Paramètres  : format = description de l'exécutable à compléter.            *  *                pt     = point de l'espace mémoire à considérer.             *  *                level  = indication de priorité et d'origine de l'adresse.   * @@ -424,7 +514,7 @@ SourceEndian g_binary_format_get_endianness(const GBinFormat *format)  *                                                                             *  ******************************************************************************/ -void g_binary_format_register_code_point(GBinFormat *format, virt_t pt, DisassPriorityLevel level) +void g_program_format_register_code_point(GProgramFormat *format, virt_t pt, DisassPriorityLevel level)  {      assert(level < DPL_COUNT); @@ -459,7 +549,7 @@ void g_binary_format_register_code_point(GBinFormat *format, virt_t pt, DisassPr  *                                                                             *  ******************************************************************************/ -static bool g_binary_format_load_start_points(GBinFormat *format, packed_buffer_t *pbuf) +static bool g_program_format_load_start_points(GProgramFormat *format, packed_buffer_t *pbuf)  {      bool result;                            /* Bilan à retourner           */      DisassPriorityLevel i;                  /* Boucle de parcours #1       */ @@ -512,7 +602,7 @@ static bool g_binary_format_load_start_points(GBinFormat *format, packed_buffer_  *                                                                             *  ******************************************************************************/ -static bool g_binary_format_store_start_points(GBinFormat *format, packed_buffer_t *pbuf) +static bool g_program_format_store_start_points(GProgramFormat *format, packed_buffer_t *pbuf)  {      bool result;                            /* Bilan à retourner           */      DisassPriorityLevel i;                  /* Boucle de parcours #1       */ @@ -555,7 +645,7 @@ static bool g_binary_format_store_start_points(GBinFormat *format, packed_buffer  *                                                                             *  ******************************************************************************/ -void g_binary_format_preload_disassembling_context(GBinFormat *format, GProcContext *ctx, GtkStatusStack *status) +void g_program_format_preload_disassembling_context(GProgramFormat *format, GProcContext *ctx, GtkStatusStack *status)  {      g_preload_info_copy(format->info, G_PRELOAD_INFO(ctx)); @@ -576,7 +666,7 @@ void g_binary_format_preload_disassembling_context(GBinFormat *format, GProcCont  *                                                                             *  ******************************************************************************/ -void g_binary_format_activate_disassembling_context(GBinFormat *format, GProcContext *ctx, GtkStatusStack *status) +void g_program_format_activate_disassembling_context(GProgramFormat *format, GProcContext *ctx, GtkStatusStack *status)  {      DisassPriorityLevel i;                  /* Boucle de parcours #1       */      size_t k;                               /* Boucle de parcours #2       */ @@ -610,7 +700,7 @@ void g_binary_format_activate_disassembling_context(GBinFormat *format, GProcCon  *                                                                             *  ******************************************************************************/ -GCompDemangler *g_binary_format_get_demangler(const GBinFormat *format) +GCompDemangler *g_program_format_get_demangler(const GProgramFormat *format)  {      GCompDemangler *result;                 /* Décodeur à retourner        */ @@ -637,7 +727,7 @@ GCompDemangler *g_binary_format_get_demangler(const GBinFormat *format)  *                                                                             *  ******************************************************************************/ -GDataType *g_binary_format_decode_type(const GBinFormat *format, const char *desc) +GDataType *g_program_format_decode_type(const GProgramFormat *format, const char *desc)  {      GDataType *result;                      /* Construction à remonter     */      GCompDemangler *demangler;              /* Accès plus lisible          */ @@ -667,7 +757,7 @@ GDataType *g_binary_format_decode_type(const GBinFormat *format, const char *des  *                                                                             *  ******************************************************************************/ -GBinRoutine *g_binary_format_decode_routine(const GBinFormat *format, const char *desc) +GBinRoutine *g_program_format_decode_routine(const GProgramFormat *format, const char *desc)  {      GBinRoutine *result;                    /* Construction à remonter     */      GCompDemangler *demangler;              /* Accès plus lisible          */ @@ -708,7 +798,7 @@ GBinRoutine *g_binary_format_decode_routine(const GBinFormat *format, const char  *                                                                             *  ******************************************************************************/ -void g_binary_format_lock_unlock_symbols_rd(GBinFormat *format, bool state) +void g_program_format_lock_unlock_symbols_rd(GProgramFormat *format, bool state)  {  #ifndef NDEBUG      gint test;                              /* Test de valeur courante     */ @@ -746,7 +836,7 @@ void g_binary_format_lock_unlock_symbols_rd(GBinFormat *format, bool state)  *                                                                             *  ******************************************************************************/ -void g_binary_format_lock_unlock_symbols_wr(GBinFormat *format, bool state) +void g_program_format_lock_unlock_symbols_wr(GProgramFormat *format, bool state)  {      if (state)      { @@ -778,7 +868,7 @@ void g_binary_format_lock_unlock_symbols_wr(GBinFormat *format, bool state)  *                                                                             *  ******************************************************************************/  #ifndef NDEBUG -void g_binary_format_check_for_symbols_lock(const GBinFormat *format) +void g_program_format_check_for_symbols_lock(const GProgramFormat *format)  {      assert(g_atomic_int_get(&format->sym_locked) > 0); @@ -798,7 +888,7 @@ void g_binary_format_check_for_symbols_lock(const GBinFormat *format)  *                                                                             *  ******************************************************************************/ -unsigned int g_binary_format_get_symbols_stamp(const GBinFormat *format) +unsigned int g_program_format_get_symbols_stamp(const GProgramFormat *format)  {      return format->sym_stamp; @@ -817,7 +907,7 @@ unsigned int g_binary_format_get_symbols_stamp(const GBinFormat *format)  *                                                                             *  ******************************************************************************/ -size_t g_binary_format_count_symbols(const GBinFormat *format) +size_t g_program_format_count_symbols(const GProgramFormat *format)  {      assert(g_atomic_int_get(&format->sym_locked) > 0); @@ -839,7 +929,7 @@ size_t g_binary_format_count_symbols(const GBinFormat *format)  *                                                                             *  ******************************************************************************/ -GBinSymbol *g_binary_format_get_symbol(const GBinFormat *format, size_t index) +GBinSymbol *g_program_format_get_symbol(const GProgramFormat *format, size_t index)  {      GBinSymbol *result;                     /* Symbole à retourner         */ @@ -877,7 +967,7 @@ GBinSymbol *g_binary_format_get_symbol(const GBinFormat *format, size_t index)  *                                                                             *  ******************************************************************************/ -bool g_binary_format_add_symbol(GBinFormat *format, GBinSymbol *symbol) +bool g_program_format_add_symbol(GProgramFormat *format, GBinSymbol *symbol)  {      bool result;                            /* Statut d'ajout à retourner  */  #ifndef NDEBUG @@ -887,7 +977,7 @@ bool g_binary_format_add_symbol(GBinFormat *format, GBinSymbol *symbol)      size_t index;                           /* Indice du point d'insertion */      /** -     * Pour que les fonctions de recherche basées sur _g_binary_format_find_symbol() +     * Pour que les fonctions de recherche basées sur _g_program_format_find_symbol()       * fassent bien leur office, il faut que les symboles soient triés.       *       * Cependant, les localisations à satisfaire lors d'une recherche recontrent @@ -912,7 +1002,7 @@ bool g_binary_format_add_symbol(GBinFormat *format, GBinSymbol *symbol)      assert(has_phys_addr(addr) || g_binary_symbol_get_status(symbol) == SSS_DYNAMIC);  #endif -    g_binary_format_lock_unlock_symbols_wr(format, true); +    g_program_format_lock_unlock_symbols_wr(format, true);      /**       * Avec tous les traitements parallèles, il est possible que plusieurs chemins d'exécution @@ -939,7 +1029,7 @@ bool g_binary_format_add_symbol(GBinFormat *format, GBinSymbol *symbol)      else          g_object_unref(G_OBJECT(symbol)); -    g_binary_format_lock_unlock_symbols_wr(format, false); +    g_program_format_lock_unlock_symbols_wr(format, false);      if (result)          g_signal_emit_by_name(format, "symbol-added", symbol); @@ -963,7 +1053,7 @@ bool g_binary_format_add_symbol(GBinFormat *format, GBinSymbol *symbol)  *                                                                             *  ******************************************************************************/ -bool g_binary_format_add_symbols(GBinFormat *format, GBinSymbol **symbols, size_t count) +bool g_program_format_add_symbols(GProgramFormat *format, GBinSymbol **symbols, size_t count)  {      bool result;                            /* Statut d'ajout à retourner  */  #ifndef NDEBUG @@ -977,7 +1067,7 @@ bool g_binary_format_add_symbols(GBinFormat *format, GBinSymbol **symbols, size_      size_t index;                           /* Indice du point d'insertion */      /** -     * Pour que les fonctions de recherche basées sur _g_binary_format_find_symbol() +     * Pour que les fonctions de recherche basées sur _g_program_format_find_symbol()       * fassent bien leur office, il faut que les symboles soient triés.       *       * Cependant, les localisations à satisfaire lors d'une recherche recontrent @@ -1014,7 +1104,7 @@ bool g_binary_format_add_symbols(GBinFormat *format, GBinSymbol **symbols, size_      }  #endif -    g_binary_format_lock_unlock_symbols_wr(format, true); +    g_program_format_lock_unlock_symbols_wr(format, true);      /**       * Avec tous les traitements parallèles, il est possible que plusieurs chemins d'exécution @@ -1042,7 +1132,7 @@ bool g_binary_format_add_symbols(GBinFormat *format, GBinSymbol **symbols, size_      } -    g_binary_format_lock_unlock_symbols_wr(format, false); +    g_program_format_lock_unlock_symbols_wr(format, false);      if (result)          for (i = 0; i < count; i++) @@ -1066,7 +1156,7 @@ bool g_binary_format_add_symbols(GBinFormat *format, GBinSymbol **symbols, size_  *                                                                             *  ******************************************************************************/ -static void _g_binary_format_remove_symbol(GBinFormat *format, size_t index) +static void _g_program_format_remove_symbol(GProgramFormat *format, size_t index)  {      assert(g_atomic_int_get(&format->sym_locked) == 1); @@ -1096,22 +1186,22 @@ static void _g_binary_format_remove_symbol(GBinFormat *format, size_t index)  *                                                                             *  ******************************************************************************/ -void g_binary_format_remove_symbol(GBinFormat *format, GBinSymbol *symbol) +void g_program_format_remove_symbol(GProgramFormat *format, GBinSymbol *symbol)  {      bool found;                             /* Jeton de présence           */      size_t index;                           /* Indice du point de retrait  */      g_object_ref(G_OBJECT(symbol)); -    g_binary_format_lock_unlock_symbols_wr(format, true); +    g_program_format_lock_unlock_symbols_wr(format, true);      found = bsearch_index(&symbol, format->symbols, format->sym_count,                            sizeof(GBinSymbol *), (__compar_fn_t)g_binary_symbol_cmp, &index);      if (found) -        _g_binary_format_remove_symbol(format, index); +        _g_program_format_remove_symbol(format, index); -    g_binary_format_lock_unlock_symbols_wr(format, false); +    g_program_format_lock_unlock_symbols_wr(format, false);      if (found)          g_signal_emit_by_name(format, "symbol-removed", symbol); @@ -1135,7 +1225,7 @@ void g_binary_format_remove_symbol(GBinFormat *format, GBinSymbol *symbol)  *                                                                             *  ******************************************************************************/ -bool g_binary_format_find_symbol_by_label(GBinFormat *format, const char *label, GBinSymbol **symbol) +bool g_program_format_find_symbol_by_label(GProgramFormat *format, const char *label, GBinSymbol **symbol)  {      bool result;                            /* Bilan à retourner           */      size_t i;                               /* Boucle de parcours          */ @@ -1143,7 +1233,7 @@ bool g_binary_format_find_symbol_by_label(GBinFormat *format, const char *label,      result = false; -    g_binary_format_lock_symbols_rd(format); +    g_program_format_lock_symbols_rd(format);      for (i = 0; i < format->sym_count && !result; i++)      { @@ -1163,7 +1253,7 @@ bool g_binary_format_find_symbol_by_label(GBinFormat *format, const char *label,      } -    g_binary_format_unlock_symbols_rd(format); +    g_program_format_unlock_symbols_rd(format);      return result; @@ -1186,16 +1276,16 @@ bool g_binary_format_find_symbol_by_label(GBinFormat *format, const char *label,  *                                                                             *  ******************************************************************************/ -static bool _g_binary_format_find_symbol(const GBinFormat *format, const vmpa2t *addr, __compar_fn_t fn, size_t *index, GBinSymbol **symbol) +static bool _g_program_format_find_symbol(const GProgramFormat *format, const vmpa2t *addr, __compar_fn_t fn, size_t *index, GBinSymbol **symbol)  {      /**       * Pour ce qui est des justifications quant à la vérification suivante, -     * se référer aux commentaires placés dans g_binary_format_add_symbol(). +     * se référer aux commentaires placés dans g_program_format_add_symbol().       */      assert(has_phys_addr(addr)); -    return __g_binary_format_find_symbol(format, addr, fn, index, symbol); +    return __g_program_format_find_symbol(format, addr, fn, index, symbol);  } @@ -1216,7 +1306,7 @@ static bool _g_binary_format_find_symbol(const GBinFormat *format, const vmpa2t  *                                                                             *  ******************************************************************************/ -static bool __g_binary_format_find_symbol(const GBinFormat *format, const void *key, __compar_fn_t fn, size_t *index, GBinSymbol **symbol) +static bool __g_program_format_find_symbol(const GProgramFormat *format, const void *key, __compar_fn_t fn, size_t *index, GBinSymbol **symbol)  {      bool result;                            /* Bilan à retourner           */      void *found;                            /* Résultat de recherches      */ @@ -1268,7 +1358,7 @@ static bool __g_binary_format_find_symbol(const GBinFormat *format, const void *  *                                                                             *  ******************************************************************************/ -bool g_binary_format_find_symbol_index_at(GBinFormat *format, const vmpa2t *addr, size_t *index) +bool g_program_format_find_symbol_index_at(GProgramFormat *format, const vmpa2t *addr, size_t *index)  {      bool result;                            /* Bilan à retourner           */ @@ -1282,11 +1372,11 @@ bool g_binary_format_find_symbol_index_at(GBinFormat *format, const vmpa2t *addr      } -    g_binary_format_lock_symbols_rd(format); +    g_program_format_lock_symbols_rd(format); -    result = _g_binary_format_find_symbol(format, addr, (__compar_fn_t)find_symbol, index, NULL); +    result = _g_program_format_find_symbol(format, addr, (__compar_fn_t)find_symbol, index, NULL); -    g_binary_format_unlock_symbols_rd(format); +    g_program_format_unlock_symbols_rd(format);      return result; @@ -1307,7 +1397,7 @@ bool g_binary_format_find_symbol_index_at(GBinFormat *format, const vmpa2t *addr  *                                                                             *  ******************************************************************************/ -bool g_binary_format_find_symbol_at(GBinFormat *format, const vmpa2t *addr, GBinSymbol **symbol) +bool g_program_format_find_symbol_at(GProgramFormat *format, const vmpa2t *addr, GBinSymbol **symbol)  {      bool result;                            /* Bilan à retourner           */ @@ -1321,11 +1411,11 @@ bool g_binary_format_find_symbol_at(GBinFormat *format, const vmpa2t *addr, GBin      } -    g_binary_format_lock_symbols_rd(format); +    g_program_format_lock_symbols_rd(format); -    result = _g_binary_format_find_symbol(format, addr, (__compar_fn_t)find_symbol, NULL, symbol); +    result = _g_program_format_find_symbol(format, addr, (__compar_fn_t)find_symbol, NULL, symbol); -    g_binary_format_unlock_symbols_rd(format); +    g_program_format_unlock_symbols_rd(format);      return result; @@ -1346,7 +1436,7 @@ bool g_binary_format_find_symbol_at(GBinFormat *format, const vmpa2t *addr, GBin  *                                                                             *  ******************************************************************************/ -bool g_binary_format_find_symbol_for(GBinFormat *format, const vmpa2t *addr, GBinSymbol **symbol) +bool g_program_format_find_symbol_for(GProgramFormat *format, const vmpa2t *addr, GBinSymbol **symbol)  {      bool result;                            /* Bilan à retourner           */ @@ -1360,11 +1450,11 @@ bool g_binary_format_find_symbol_for(GBinFormat *format, const vmpa2t *addr, GBi      } -    g_binary_format_lock_symbols_rd(format); +    g_program_format_lock_symbols_rd(format); -    result = _g_binary_format_find_symbol(format, addr, (__compar_fn_t)find_symbol, NULL, symbol); +    result = _g_program_format_find_symbol(format, addr, (__compar_fn_t)find_symbol, NULL, symbol); -    g_binary_format_unlock_symbols_rd(format); +    g_program_format_unlock_symbols_rd(format);      return result; @@ -1385,7 +1475,7 @@ bool g_binary_format_find_symbol_for(GBinFormat *format, const vmpa2t *addr, GBi  *                                                                             *  ******************************************************************************/ -bool g_binary_format_find_next_symbol_at(GBinFormat *format, const vmpa2t *addr, GBinSymbol **symbol) +bool g_program_format_find_next_symbol_at(GProgramFormat *format, const vmpa2t *addr, GBinSymbol **symbol)  {      bool result;                            /* Bilan à retourner           */      size_t index;                           /* Indice à considérer         */ @@ -1400,9 +1490,9 @@ bool g_binary_format_find_next_symbol_at(GBinFormat *format, const vmpa2t *addr,      } -    g_binary_format_lock_symbols_rd(format); +    g_program_format_lock_symbols_rd(format); -    result = _g_binary_format_find_symbol(format, addr, (__compar_fn_t)find_symbol, &index, NULL); +    result = _g_program_format_find_symbol(format, addr, (__compar_fn_t)find_symbol, &index, NULL);      if (result && (index + 1) < format->sym_count)      { @@ -1417,7 +1507,7 @@ bool g_binary_format_find_next_symbol_at(GBinFormat *format, const vmpa2t *addr,          result = false;      } -    g_binary_format_unlock_symbols_rd(format); +    g_program_format_unlock_symbols_rd(format);      return result; @@ -1438,7 +1528,7 @@ bool g_binary_format_find_next_symbol_at(GBinFormat *format, const vmpa2t *addr,  *                                                                             *  ******************************************************************************/ -bool g_binary_format_find_first_symbol_inside(GBinFormat *format, const mrange_t *range, size_t *index) +bool g_program_format_find_first_symbol_inside(GProgramFormat *format, const mrange_t *range, size_t *index)  {      bool result;                            /* Bilan à retourner           */      const GBinSymbol *prev;                 /* Symbole précédent           */ @@ -1463,7 +1553,7 @@ bool g_binary_format_find_first_symbol_inside(GBinFormat *format, const mrange_t      g_rw_lock_reader_lock(&format->syms_lock); -    result = __g_binary_format_find_symbol(format, range, (__compar_fn_t)find_symbol, index, NULL); +    result = __g_program_format_find_symbol(format, range, (__compar_fn_t)find_symbol, index, NULL);      if (result)          while (*index > 0) @@ -1502,15 +1592,15 @@ bool g_binary_format_find_first_symbol_inside(GBinFormat *format, const mrange_t  *                                                                             *  ******************************************************************************/ -bool g_binary_format_resolve_symbol(GBinFormat *format, const vmpa2t *addr, bool strict, GBinSymbol **symbol, phys_t *diff) +bool g_program_format_resolve_symbol(GProgramFormat *format, const vmpa2t *addr, bool strict, GBinSymbol **symbol, phys_t *diff)  {       bool result;                            /* Bilan à retourner           */       const mrange_t *range;                  /* Espace mémoire parcouru     */       if (strict) -         result = g_binary_format_find_symbol_at(format, addr, symbol); +         result = g_program_format_find_symbol_at(format, addr, symbol);       else -         result = g_binary_format_find_symbol_for(format, addr, symbol); +         result = g_program_format_find_symbol_for(format, addr, symbol);       if (result)       { @@ -1548,7 +1638,7 @@ bool g_binary_format_resolve_symbol(GBinFormat *format, const vmpa2t *addr, bool  *                                                                             *  ******************************************************************************/ -void g_binary_format_lock_unlock_errors(GBinFormat *format, bool state) +void g_program_format_lock_unlock_errors(GProgramFormat *format, bool state)  {      if (state)      { @@ -1584,11 +1674,11 @@ void g_binary_format_lock_unlock_errors(GBinFormat *format, bool state)  *                                                                             *  ******************************************************************************/ -void g_binary_format_add_error(GBinFormat *format, BinaryFormatError type, const vmpa2t *addr, const char *desc) +void g_program_format_add_error(GProgramFormat *format, BinaryFormatError type, const vmpa2t *addr, const char *desc)  {      fmt_error *error;                       /* Raccourci de confort        */ -    g_binary_format_lock_errors(format); +    g_program_format_lock_errors(format);      format->errors = realloc(format->errors, ++format->error_count * sizeof(fmt_error)); @@ -1603,7 +1693,7 @@ void g_binary_format_add_error(GBinFormat *format, BinaryFormatError type, const      else          error->desc = NULL; -    g_binary_format_unlock_errors(format); +    g_program_format_unlock_errors(format);  } @@ -1620,7 +1710,7 @@ void g_binary_format_add_error(GBinFormat *format, BinaryFormatError type, const  *                                                                             *  ******************************************************************************/ -size_t g_binary_format_count_errors(GBinFormat *format) +size_t g_program_format_count_errors(GProgramFormat *format)  {      size_t result;                          /* Quantité à retourner        */ @@ -1649,7 +1739,7 @@ size_t g_binary_format_count_errors(GBinFormat *format)  *                                                                             *  ******************************************************************************/ -bool g_binary_format_get_error(GBinFormat *format, size_t index, BinaryFormatError *type, vmpa2t *addr, char **desc) +bool g_program_format_get_error(GProgramFormat *format, size_t index, BinaryFormatError *type, vmpa2t *addr, char **desc)  {      bool result;                            /* Bilan à retourner           */      fmt_error *error;                       /* Raccourci de confort        */ @@ -1693,7 +1783,7 @@ bool g_binary_format_get_error(GBinFormat *format, size_t index, BinaryFormatErr  *                                                                             *  ******************************************************************************/ -static bool g_binary_format_load_errors(GBinFormat *format, packed_buffer_t *pbuf) +static bool g_program_format_load_errors(GProgramFormat *format, packed_buffer_t *pbuf)  {      bool result;                            /* Bilan à retourner           */      uleb128_t value;                        /* Valeur ULEB128 à charger    */ @@ -1701,7 +1791,7 @@ static bool g_binary_format_load_errors(GBinFormat *format, packed_buffer_t *pbu      fmt_error *error;                       /* Raccourci de confort        */      rle_string str;                         /* Chaîne à charger            */ -    g_binary_format_lock_errors(format); +    g_program_format_lock_errors(format);      result = unpack_uleb128(&value, pbuf);      if (!result) goto exit; @@ -1736,7 +1826,7 @@ static bool g_binary_format_load_errors(GBinFormat *format, packed_buffer_t *pbu   exit: -    g_binary_format_unlock_errors(format); +    g_program_format_unlock_errors(format);      return result; @@ -1756,14 +1846,14 @@ static bool g_binary_format_load_errors(GBinFormat *format, packed_buffer_t *pbu  *                                                                             *  ******************************************************************************/ -static bool g_binary_format_store_errors(GBinFormat *format, packed_buffer_t *pbuf) +static bool g_program_format_store_errors(GProgramFormat *format, packed_buffer_t *pbuf)  {      bool result;                            /* Bilan à retourner           */      size_t i;                               /* Boucle de parcours          */      fmt_error *error;                       /* Raccourci de confort        */      rle_string str;                         /* Chaîne à conserver          */ -    g_binary_format_lock_errors(format); +    g_program_format_lock_errors(format);      result = pack_uleb128((uleb128_t []){ format->error_count }, pbuf); @@ -1785,7 +1875,7 @@ static bool g_binary_format_store_errors(GBinFormat *format, packed_buffer_t *pb      } -    g_binary_format_unlock_errors(format); +    g_program_format_unlock_errors(format);      return result; @@ -1812,7 +1902,7 @@ static bool g_binary_format_store_errors(GBinFormat *format, packed_buffer_t *pb  *                                                                             *  ******************************************************************************/ -static bool g_binary_format_load(GBinFormat *format, GObjectStorage *storage, packed_buffer_t *pbuf) +static bool g_program_format_load(GProgramFormat *format, GObjectStorage *storage, packed_buffer_t *pbuf)  {      bool result;                            /* Bilan à retourner           */      fmt_extra_data_t *extra;                /* Données insérées à consulter*/ @@ -1831,7 +1921,7 @@ static bool g_binary_format_load(GBinFormat *format, GObjectStorage *storage, pa      UNLOCK_GOBJECT_EXTRA(extra);      if (result) -        result = g_binary_format_load_start_points(format, pbuf); +        result = g_program_format_load_start_points(format, pbuf);      if (result)      { @@ -1857,7 +1947,7 @@ static bool g_binary_format_load(GBinFormat *format, GObjectStorage *storage, pa      if (result) -        result = g_binary_format_load_errors(format, pbuf); +        result = g_program_format_load_errors(format, pbuf);      return result; @@ -1878,7 +1968,7 @@ static bool g_binary_format_load(GBinFormat *format, GObjectStorage *storage, pa  *                                                                             *  ******************************************************************************/ -static bool g_binary_format_store(GBinFormat *format, GObjectStorage *storage, packed_buffer_t *pbuf) +static bool g_program_format_store(GProgramFormat *format, GObjectStorage *storage, packed_buffer_t *pbuf)  {      bool result;                            /* Bilan à retourner           */      fmt_extra_data_t *extra;                /* Données insérées à consulter*/ @@ -1894,7 +1984,7 @@ static bool g_binary_format_store(GBinFormat *format, GObjectStorage *storage, p      UNLOCK_GOBJECT_EXTRA(extra);      if (result) -        result = g_binary_format_store_start_points(format, pbuf); +        result = g_program_format_store_start_points(format, pbuf);      if (result)      { @@ -1913,8 +2003,10 @@ static bool g_binary_format_store(GBinFormat *format, GObjectStorage *storage, p      if (result) -        result = g_binary_format_store_errors(format, pbuf); +        result = g_program_format_store_errors(format, pbuf);      return result;  } + +#endif diff --git a/src/format/format.h b/src/format/program.h index f9aa430..12b095c 100644 --- a/src/format/format.h +++ b/src/format/program.h @@ -1,8 +1,8 @@  /* Chrysalide - Outil d'analyse de fichiers binaires - * format.h - prototypes pour le support des différents formats binaires + * program.h - prototypes pour le support des différents formats de programmes   * - * Copyright (C) 2009-2020 Cyrille Bagard + * Copyright (C) 2009-2024 Cyrille Bagard   *   *  This file is part of Chrysalide.   * @@ -21,12 +21,35 @@   */ -#ifndef _FORMAT_FORMAT_H -#define _FORMAT_FORMAT_H +#ifndef _FORMAT_PROGRAM_H +#define _FORMAT_PROGRAM_H -#include <glib-object.h>  #include <stdbool.h> + + +#include "../arch/vmpa.h" +#include "../common/datatypes.h" +#include "../glibext/helpers.h" + + + +#define G_TYPE_PROGRAM_FORMAT (g_program_format_get_type()) + +DECLARE_GTYPE(GProgramFormat, g_program_format, G, PROGRAM_FORMAT); + + +/* Indique le boutisme employé par le format binaire analysé. */ +SourceEndian g_program_format_get_endianness(const GProgramFormat *); + +/* Fournit l'emplacement d'une section donnée. */ +bool g_program_format_find_section_range_by_name(const GProgramFormat *, const char *, mrange_t *); + + + + +#if 0 +  #include <sys/types.h> @@ -52,47 +75,31 @@ typedef enum _FormatFlag  } FormatFlag; -#define G_TYPE_BIN_FORMAT            g_binary_format_get_type() -#define G_BIN_FORMAT(obj)            (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_BIN_FORMAT, GBinFormat)) -#define G_IS_BIN_FORMAT(obj)         (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_BIN_FORMAT)) -#define G_BIN_FORMAT_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_BIN_FORMAT, GBinFormatClass)) -#define G_IS_BIN_FORMAT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_BIN_FORMAT)) -#define G_BIN_FORMAT_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_BIN_FORMAT, GBinFormatClass)) -/* Format binaire générique (instance) */ -typedef struct _GBinFormat GBinFormat; - -/* Format binaire générique (classe) */ -typedef struct _GBinFormatClass GBinFormatClass; - - -/* Indique le type défini pour un format binaire générique. */ -GType g_binary_format_get_type(void); -  /* Ajoute une information complémentaire à un format. */ -bool g_binary_format_set_flag(GBinFormat *, FormatFlag); +bool g_program_format_set_flag(GProgramFormat *, FormatFlag);  /* Retire une information complémentaire à un format. */ -bool g_binary_format_unset_flag(GBinFormat *, FormatFlag); +bool g_program_format_unset_flag(GProgramFormat *, FormatFlag);  /* Détermine si un format possède un fanion particulier. */ -bool g_binary_format_has_flag(const GBinFormat *, FormatFlag); +bool g_program_format_has_flag(const GProgramFormat *, FormatFlag);  /* Fournit les particularités du format. */ -FormatFlag g_binary_format_get_flags(const GBinFormat *); +FormatFlag g_program_format_get_flags(const GProgramFormat *);  /* Indique le boutisme employé par le format binaire analysé. */ -SourceEndian g_binary_format_get_endianness(const GBinFormat *); +//SourceEndian g_program_format_get_endianness(const GProgramFormat *);  /* Enregistre une adresse comme début d'une zone de code. */ -void g_binary_format_register_code_point(GBinFormat *, virt_t, DisassPriorityLevel); +void g_program_format_register_code_point(GProgramFormat *, virt_t, DisassPriorityLevel);  /* Intègre dans un contexte les informations tirées d'un format. */ -void g_binary_format_preload_disassembling_context(GBinFormat *, GProcContext *, GtkStatusStack *); +void g_program_format_preload_disassembling_context(GProgramFormat *, GProcContext *, GtkStatusStack *);  /* Définit les points de départ d'un contexte de désassemblage. */ -void g_binary_format_activate_disassembling_context(GBinFormat *, GProcContext *, GtkStatusStack *); +void g_program_format_activate_disassembling_context(GProgramFormat *, GProcContext *, GtkStatusStack *); @@ -100,7 +107,7 @@ void g_binary_format_activate_disassembling_context(GBinFormat *, GProcContext *  /* Fournit le décodeur de symboles privilégié pour un format. */ -GCompDemangler *g_binary_format_get_demangler(const GBinFormat *); +GCompDemangler *g_program_format_get_demangler(const GProgramFormat *); @@ -108,60 +115,60 @@ GCompDemangler *g_binary_format_get_demangler(const GBinFormat *);  /* Protège ou lève la protection de l'accès aux symboles. */ -void g_binary_format_lock_unlock_symbols_rd(GBinFormat *, bool); +void g_program_format_lock_unlock_symbols_rd(GProgramFormat *, bool); -#define g_binary_format_lock_symbols_rd(f) g_binary_format_lock_unlock_symbols_rd(f, true) -#define g_binary_format_unlock_symbols_rd(f) g_binary_format_lock_unlock_symbols_rd(f, false) +#define g_program_format_lock_symbols_rd(f) g_program_format_lock_unlock_symbols_rd(f, true) +#define g_program_format_unlock_symbols_rd(f) g_program_format_lock_unlock_symbols_rd(f, false)  /* Protège ou lève la protection de l'accès aux symboles. */ -void g_binary_format_lock_unlock_symbols_wr(GBinFormat *, bool); +void g_program_format_lock_unlock_symbols_wr(GProgramFormat *, bool); -#define g_binary_format_lock_symbols_wr(f) g_binary_format_lock_unlock_symbols_wr(f, true) -#define g_binary_format_unlock_symbols_wr(f) g_binary_format_lock_unlock_symbols_wr(f, false) +#define g_program_format_lock_symbols_wr(f) g_program_format_lock_unlock_symbols_wr(f, true) +#define g_program_format_unlock_symbols_wr(f) g_program_format_lock_unlock_symbols_wr(f, false)  /* Assure qu'un verrou est bien posé pour l'accès aux symboles. */  #ifndef NDEBUG -void g_binary_format_check_for_symbols_lock(const GBinFormat *); +void g_program_format_check_for_symbols_lock(const GProgramFormat *);  #endif  /* Fournit la marque de dernière modification des symboles. */ -unsigned int g_binary_format_get_symbols_stamp(const GBinFormat *); +unsigned int g_program_format_get_symbols_stamp(const GProgramFormat *);  /* Compte le nombre de symboles représentés. */ -size_t g_binary_format_count_symbols(const GBinFormat *); +size_t g_program_format_count_symbols(const GProgramFormat *);  /* Fournit un symbole lié à un format. */ -GBinSymbol *g_binary_format_get_symbol(const GBinFormat *, size_t); +GBinSymbol *g_program_format_get_symbol(const GProgramFormat *, size_t);  /* Ajoute un symbole à la collection du format binaire. */ -bool g_binary_format_add_symbol(GBinFormat *, GBinSymbol *); +bool g_program_format_add_symbol(GProgramFormat *, GBinSymbol *);  /* Ajoute plusieurs symboles à la collection du format binaire. */ -bool g_binary_format_add_symbols(GBinFormat *, GBinSymbol **, size_t); +bool g_program_format_add_symbols(GProgramFormat *, GBinSymbol **, size_t);  /* Retire un symbole de la collection du format binaire. */ -void g_binary_format_remove_symbol(GBinFormat *, GBinSymbol *); +void g_program_format_remove_symbol(GProgramFormat *, GBinSymbol *);  /* Recherche le symbole correspondant à une étiquette. */ -bool g_binary_format_find_symbol_by_label(GBinFormat *, const char *, GBinSymbol **); +bool g_program_format_find_symbol_by_label(GProgramFormat *, const char *, GBinSymbol **);  /* Recherche l'indice du symbole correspondant à une adresse. */ -bool g_binary_format_find_symbol_index_at(GBinFormat *, const vmpa2t *, size_t *); +bool g_program_format_find_symbol_index_at(GProgramFormat *, const vmpa2t *, size_t *);  /* Recherche le symbole correspondant à une adresse. */ -bool g_binary_format_find_symbol_at(GBinFormat *, const vmpa2t *, GBinSymbol **); +bool g_program_format_find_symbol_at(GProgramFormat *, const vmpa2t *, GBinSymbol **);  /* Recherche le symbole contenant une adresse. */ -bool g_binary_format_find_symbol_for(GBinFormat *, const vmpa2t *, GBinSymbol **); +bool g_program_format_find_symbol_for(GProgramFormat *, const vmpa2t *, GBinSymbol **);  /* Recherche le symbole suivant celui lié à une adresse. */ -bool g_binary_format_find_next_symbol_at(GBinFormat *, const vmpa2t *, GBinSymbol **); +bool g_program_format_find_next_symbol_at(GProgramFormat *, const vmpa2t *, GBinSymbol **);  /* Recherche le premier symbole inclus dans une zone mémoire. */ -bool g_binary_format_find_first_symbol_inside(GBinFormat *, const mrange_t *, size_t *); +bool g_program_format_find_first_symbol_inside(GProgramFormat *, const mrange_t *, size_t *);  /* Recherche le symbole correspondant à une adresse. */ -bool g_binary_format_resolve_symbol(GBinFormat *, const vmpa2t *, bool, GBinSymbol **, phys_t *); +bool g_program_format_resolve_symbol(GProgramFormat *, const vmpa2t *, bool, GBinSymbol **, phys_t *); @@ -181,20 +188,21 @@ typedef enum _BinaryFormatError  /* Protège ou lève la protection de l'accès aux erreurs. */ -void g_binary_format_lock_unlock_errors(GBinFormat *, bool); +void g_program_format_lock_unlock_errors(GProgramFormat *, bool); -#define g_binary_format_lock_errors(f) g_binary_format_lock_unlock_errors(f, true) -#define g_binary_format_unlock_errors(f) g_binary_format_lock_unlock_errors(f, false) +#define g_program_format_lock_errors(f) g_program_format_lock_unlock_errors(f, true) +#define g_program_format_unlock_errors(f) g_program_format_lock_unlock_errors(f, false)  /* Etend la liste des soucis détectés avec de nouvelles infos. */ -void g_binary_format_add_error(GBinFormat *, BinaryFormatError, const vmpa2t *, const char *); +void g_program_format_add_error(GProgramFormat *, BinaryFormatError, const vmpa2t *, const char *);  /* Indique le nombre d'erreurs relevées au niveau assembleur. */ -size_t g_binary_format_count_errors(GBinFormat *); +size_t g_program_format_count_errors(GProgramFormat *);  /* Fournit les éléments concernant un soucis détecté. */ -bool g_binary_format_get_error(GBinFormat *, size_t, BinaryFormatError *, vmpa2t *, char **); +bool g_program_format_get_error(GProgramFormat *, size_t, BinaryFormatError *, vmpa2t *, char **); +#endif -#endif  /* _FORMAT_FORMAT_H */ +#endif  /* _FORMAT_PROGRAM_H */ diff --git a/src/framework.h b/src/framework.h deleted file mode 100644 index e8e88fe..0000000 --- a/src/framework.h +++ /dev/null @@ -1,66 +0,0 @@ - -/* Chrysalide - Outil d'analyse de fichiers binaires - * framework.h - prototypes pour le fichier d'entrée du programme - * - * Copyright (C) 2024 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 _FRAMEWORK_H -#define _FRAMEWORK_H - - -#include <glib-object.h> - - - -/* --------------------- DEFINITION D'APPLICATION PERSONNALISEE --------------------- */ - - -#define GTK_TYPE_CHRYSALIDE_FRAMEWORK            gtk_chrysalide_framework_get_type() -#define GTK_CHRYSALIDE_FRAMEWORK(obj)            (G_TYPE_CHECK_INSTANCE_CAST((obj), GTK_TYPE_CHRYSALIDE_FRAMEWORK, GtkChrysalideFramework)) -#define GTK_IS_CHRYSALIDE_FRAMEWORK(obj)         (G_TYPE_CHECK_INSTANCE_TYPE((obj), GTK_TYPE_CHRYSALIDE_FRAMEWORK)) -#define GTK_CHRYSALIDE_FRAMEWORK_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST((klass), GTK_TYPE_CHRYSALIDE_FRAMEWORK, GtkChrysalideFrameworkClass)) -#define GTK_IS_CHRYSALIDE_FRAMEWORK_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), GTK_TYPE_CHRYSALIDE_FRAMEWORK)) -#define GTK_CHRYSALIDE_FRAMEWORK_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS((obj), GTK_TYPE_CHRYSALIDE_FRAMEWORK, GtkChrysalideFrameworkClass)) - - -/* Définition de l'application principale graphique (instance) */ -typedef struct _GtkChrysalideFramework GtkChrysalideFramework; - -/* Définition de l'application principale graphique (classe) */ -typedef struct _GtkChrysalideFrameworkClass GtkChrysalideFrameworkClass; - - -/* Indique le type défini pour une application principale graphique de Chrysalide. */ -GType gtk_chrysalide_framework_get_type(void); - -/* Crée une nouvelle application principale pour Chrysalide. */ -GtkChrysalideFramework *gtk_chrysalide_framework_new(void); - - - -/* ---------------------- POINT D'ENTREE PRINCIPAL D'EXECUTION ---------------------- */ - - -/* Point d'entrée du programme. */ -int main(int, char **); - - - -#endif  /* _FRAMEWORK_H */ diff --git a/src/glibext/Makefile.am b/src/glibext/Makefile.am index b5ea0f0..b0a7c31 100644 --- a/src/glibext/Makefile.am +++ b/src/glibext/Makefile.am @@ -1,50 +1,74 @@  BUILT_SOURCES = chrysamarshal.h chrysamarshal.c resources.h resources.c -noinst_LTLIBRARIES  = libglibext4.la libglibextui.la # libglibext.la - -libglibext_la_SOURCES =						\ -	comparison-int.h						\ -	comparison.h comparison.c				\ -	configuration-int.h						\ -	configuration.h configuration.c			\ -	gbinarycursor.h gbinarycursor.c			\ -	gbinportion-int.h						\ -	gbinportion.h gbinportion.c				\ -	glinecursor-int.h						\ -	glinecursor.h glinecursor.c				\ -	gnhash.h gnhash.c						\ -	notifier.h								\ -	objhole.h								\ -	proto.h									\ -	seq.h seq.c								\ -	_signal.h signal.c						\ -	singleton.h singleton.c					\ -	linetoken.h linetoken.c					\ -	umemslice-int.h							\ -	umemslice.h umemslice.c - -if BUILD_GTK_SUPPORT - -libglibext_la_SOURCES +=					\ -	gloadedpanel-int.h						\ -	gloadedpanel.h gloadedpanel.c			\ -	named-int.h								\ -	named.h named.c - -endif - -libglibext_la_CFLAGS = $(TOOLKIT_CFLAGS) $(LIBXML_CFLAGS) +noinst_LTLIBRARIES  = libglibext.la libglibextui.la + +# libglibext_la_SOURCES =						\ +# 	configuration-int.h						\ +# 	configuration.h configuration.c			\ +# 	gbinarycursor.h gbinarycursor.c			\ +# 	glinecursor-int.h						\ +# 	glinecursor.h glinecursor.c				\ +# 	gnhash.h gnhash.c						\ +# 	notifier.h								\ +# 									\ +# 	proto.h									\ +# 	seq.h seq.c								\ +# 	singleton.h singleton.c					\ +# 	linetoken.h linetoken.c					\ +# 	umemslice-int.h							\ +# 	umemslice.h umemslice.c + +# if BUILD_GTK_SUPPORT + +# libglibext_la_SOURCES +=					\ +# 	gloadedpanel-int.h						\ +# 	gloadedpanel.h gloadedpanel.c			\ +# 	named-int.h								\ +# 	named.h named.c + +# endif + +# libglibext_la_CFLAGS = $(TOOLKIT_CFLAGS) $(LIBXML_CFLAGS)  #libglibext_la_LIBADD = 					\  #	generators/libglibextgenerators.la -libglibext4_la_SOURCES =					\ +libglibext_la_SOURCES =						\  	chrysamarshal.h chrysamarshal.c			\ -	helpers.h - -libglibext4_la_CFLAGS = $(TOOLKIT_CFLAGS) +	comparable-int.h						\ +	comparable.h comparable.c				\ +	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							\ +	workgroup.h workgroup.c					\ +	workqueue-int.h							\ +	workqueue.h workqueue.c + +libglibext_la_CFLAGS = $(TOOLKIT_CFLAGS) $(LIBZIP_CFLAGS)  RES_FILES =									\ @@ -78,7 +102,7 @@ libglibextui_la_LIBADD = 					\  devdir = $(includedir)/chrysalide/$(subdir:src/%=core/%) -dev_HEADERS = $(libglibext_la_SOURCES:%c=) +dev_HEADERS = $(libglibext_la_SOURCES:%c=) $(libglibextui_la_SOURCES:%c=)  SUBDIRS = generators options 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-int.h b/src/glibext/comparable-int.h new file mode 100644 index 0000000..18972c2 --- /dev/null +++ b/src/glibext/comparable-int.h @@ -0,0 +1,47 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * comparable-int.h - définitions internes propres aux opérations de comparaison d'objets + * + * Copyright (C) 2022-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_COMPARABLE_INT_H +#define _GLIBEXT_COMPARABLE_INT_H + + +#include "comparable.h" + + + +/* Réalise une comparaison étendue entre objets. */ +typedef int (* compare_object_fc) (const GComparableObject *, const GComparableObject *); + + +/* Instance d'objet comparable (interface) */ +struct _GComparableObjectInterface +{ +    GTypeInterface base_iface;              /* A laisser en premier        */ + +    compare_object_fc compare;              /* Comparaison étendue         */ + +}; + + + +#endif  /* _GLIBEXT_COMPARABLE_INT_H */ diff --git a/src/glibext/comparable.c b/src/glibext/comparable.c new file mode 100644 index 0000000..40fd110 --- /dev/null +++ b/src/glibext/comparable.c @@ -0,0 +1,124 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * comparable.c - opérations de comparaison d'objets + * + * Copyright (C) 2022-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 "comparable.h" + + +#include "comparable-int.h" +#include "../common/sort.h" + + + +/* Procède à l'initialisation de l'interface de comparaison. */ +static void g_comparable_object_default_init(GComparableObjectInterface *); + + + +/* Détermine le type d'une interface pour un objet comparable. */ +G_DEFINE_INTERFACE(GComparableObject, g_comparable_object, G_TYPE_OBJECT) + + +/****************************************************************************** +*                                                                             * +*  Paramètres  : iface = interface GLib à initialiser.                        * +*                                                                             * +*  Description : Procède à l'initialisation de l'interface de comparaison.    * +*                                                                             * +*  Retour      : -                                                            * +*                                                                             * +*  Remarques   : -                                                            * +*                                                                             * +******************************************************************************/ + +static void g_comparable_object_default_init(GComparableObjectInterface *iface) +{ +    iface->compare = NULL; + +} + + +/****************************************************************************** +*                                                                             * +*  Paramètres  : object = premier objet à consulter pour une comparaison.     * +*                other  = second objet à consulter pour une comparaison.      * +*                                                                             * +*  Description : Réalise une comparaison étendue entre objets.                * +*                                                                             * +*  Retour      : Bilan de la comparaison.                                     * +*                                                                             * +*  Remarques   : -                                                            * +*                                                                             * +******************************************************************************/ + +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          */ + +    type_a = G_OBJECT_TYPE(G_OBJECT(object)); +    type_b = G_OBJECT_TYPE(G_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; + +} + + +/****************************************************************************** +*                                                                             * +*  Paramètres  : object = premier objet à consulter pour une comparaison.     * +*                other  = second objet à consulter pour une comparaison.      * +*                                                                             * +*  Description : Détermine si deux objets sont fonctionnellement identiques.  * +*                                                                             * +*  Retour      : Bilan de la comparaison.                                     * +*                                                                             * +*  Remarques   : -                                                            * +*                                                                             * +******************************************************************************/ + +gboolean g_comparable_object_is_equal(const GComparableObject *object, const GComparableObject *other) +{ +    gboolean result;                        /* Bilan à renvoyer            */ +    int ret;                                /* Bilan d'une comparaison     */ + +    ret = g_comparable_object_compare(object, other); + +    result = (ret == 0); + +    return result; + +} diff --git a/src/glibext/comparable.h b/src/glibext/comparable.h new file mode 100644 index 0000000..7a652ff --- /dev/null +++ b/src/glibext/comparable.h @@ -0,0 +1,46 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * comparable.h - prototypes pour les opérations de comparaison d'objets + * + * Copyright (C) 2022-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_COMPARABLE_H +#define _GLIBEXT_COMPARABLE_H + + +#include "helpers.h" + + + +#define G_TYPE_COMPARABLE_OBJECT (g_comparable_object_get_type()) + +DECLARE_INTERFACE(GComparableObject, g_comparable_object, G, COMPARABLE_OBJECT); + + + +/* Réalise une comparaison étendue entre objets. */ +int g_comparable_object_compare(const GComparableObject *, const GComparableObject *); + +/* Détermine si deux objets sont fonctionnellement identiques. */ +gboolean g_comparable_object_is_equal(const GComparableObject *, const GComparableObject *); + + + +#endif  /* _GLIBEXT_COMPARABLE_H */ diff --git a/src/glibext/comparison-int.h b/src/glibext/comparison-int.h deleted file mode 100644 index 446f25d..0000000 --- a/src/glibext/comparison-int.h +++ /dev/null @@ -1,58 +0,0 @@ - -/* Chrysalide - Outil d'analyse de fichiers binaires - * comparison-int.h - définitions internes propres aux opérations de comparaison d'objets - * - * Copyright (C) 2022 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_COMPARISON_INT_H -#define _GLIBEXT_COMPARISON_INT_H - - -#include "comparison.h" - - - -/* Réalise une comparaison entre objets selon un critère précis. */ -typedef bool (* compare_rich_fc) (const GComparableItem *, const GComparableItem *, RichCmpOperation, bool *); - - -/* Instance d'élément comparable (interface) */ -struct _GComparableItemIface -{ -    GTypeInterface base_iface;              /* A laisser en premier        */ - -    compare_rich_fc cmp_rich;               /* Comparaison de façon précise*/ - -}; - - -/* Redéfinition */ -typedef GComparableItemIface GComparableItemInterface; - - -/* Réalise une comparaison riche entre valeurs entière. */ -bool compare_rich_integer_values_signed(long long, long long, RichCmpOperation); - -/* Réalise une comparaison riche entre valeurs entière. */ -bool compare_rich_integer_values_unsigned(unsigned long long, unsigned long long, RichCmpOperation); - - - -#endif  /* _GLIBEXT_COMPARISON_INT_H */ diff --git a/src/glibext/comparison.c b/src/glibext/comparison.c deleted file mode 100644 index 8ce6941..0000000 --- a/src/glibext/comparison.c +++ /dev/null @@ -1,199 +0,0 @@ - -/* Chrysalide - Outil d'analyse de fichiers binaires - * comparison.c - opérations de comparaison d'objets - * - * Copyright (C) 2022 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 "comparison.h" - - -#include <assert.h> - - -#include "comparison-int.h" - - - -/* Procède à l'initialisation de l'interface de comparaison. */ -static void g_comparable_item_default_init(GComparableItemInterface *); - - - -/* Détermine le type d'une interface pour un objet comparable. */ -G_DEFINE_INTERFACE(GComparableItem, g_comparable_item, G_TYPE_OBJECT) - - -/****************************************************************************** -*                                                                             * -*  Paramètres  : iface = interface GLib à initialiser.                        * -*                                                                             * -*  Description : Procède à l'initialisation de l'interface de comparaison.    * -*                                                                             * -*  Retour      : -                                                            * -*                                                                             * -*  Remarques   : -                                                            * -*                                                                             * -******************************************************************************/ - -static void g_comparable_item_default_init(GComparableItemInterface *iface) -{ - -} - - -/****************************************************************************** -*                                                                             * -*  Paramètres  : item   = premier objet à consulter pour une comparaison.     * -*                other  = second objet à consulter pour une comparaison.      * -*                op     = opération de comparaison à réaliser.                * -*                status = bilan des opérations de comparaison. [OUT]          * -*                                                                             * -*  Description : Réalise une comparaison entre objets selon un critère précis.* -*                                                                             * -*  Retour      : true si la comparaison a pu être effectuée, false sinon.     * -*                                                                             * -*  Remarques   : -                                                            * -*                                                                             * -******************************************************************************/ - -bool g_comparable_item_compare_rich(const GComparableItem *item, const GComparableItem *other, RichCmpOperation op, bool *status) -{ -    bool result;                            /* Etat à retourner            */ -    GComparableItemIface *iface;            /* Interface utilisée          */ - -    iface = G_COMPARABLE_ITEM_GET_IFACE(item); - -    result = iface->cmp_rich(item, other, op, status); - -    return result; - -} - - -/****************************************************************************** -*                                                                             * -*  Paramètres  : a  = premier élément à consulter pour une comparaison.       * -*                b  = second objet à consulter pour une comparaison.          * -*                op = opération de comparaison à réaliser.                    * -*                                                                             * -*  Description : Réalise une comparaison riche entre valeurs entière.         * -*                                                                             * -*  Retour      : Bilan des opérations de comparaison.                         * -*                                                                             * -*  Remarques   : -                                                            * -*                                                                             * -******************************************************************************/ - -bool compare_rich_integer_values_signed(long long a, long long b, RichCmpOperation op) -{ -    bool result;                            /* Bilan  à retourner          */ - -    switch (op) -    { -        case RCO_LT: -            result = (a < b); -            break; - -        case RCO_LE: -            result = (a <= b); -            break; - -        case RCO_EQ: -            result = (a == b); -            break; - -        case RCO_NE: -            result = (a != b); -            break; - -        case RCO_GT: -            result = (a > b); -            break; - -        case RCO_GE: -            result = (a >= b); -            break; - -        default: -            assert(false); -            result = false; -            break; - -    } - -    return result; - -} - - -/****************************************************************************** -*                                                                             * -*  Paramètres  : a  = premier élément à consulter pour une comparaison.       * -*                b  = second objet à consulter pour une comparaison.          * -*                op = opération de comparaison à réaliser.                    * -*                                                                             * -*  Description : Réalise une comparaison riche entre valeurs entière.         * -*                                                                             * -*  Retour      : Bilan des opérations de comparaison.                         * -*                                                                             * -*  Remarques   : -                                                            * -*                                                                             * -******************************************************************************/ - -bool compare_rich_integer_values_unsigned(unsigned long long a, unsigned long long b, RichCmpOperation op) -{ -    bool result;                            /* Bilan  à retourner          */ - -    switch (op) -    { -        case RCO_LT: -            result = (a < b); -            break; - -        case RCO_LE: -            result = (a <= b); -            break; - -        case RCO_EQ: -            result = (a == b); -            break; - -        case RCO_NE: -            result = (a != b); -            break; - -        case RCO_GT: -            result = (a > b); -            break; - -        case RCO_GE: -            result = (a >= b); -            break; - -        default: -            assert(false); -            result = false; -            break; - -    } - -    return result; - -} diff --git a/src/glibext/comparison.h b/src/glibext/comparison.h deleted file mode 100644 index 8d43210..0000000 --- a/src/glibext/comparison.h +++ /dev/null @@ -1,80 +0,0 @@ - -/* Chrysalide - Outil d'analyse de fichiers binaires - * comparison.h - prototypes pour les opérations de comparaison d'objets - * - * Copyright (C) 2022 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_COMPARISON_H -#define _GLIBEXT_COMPARISON_H - - -#include <glib-object.h> -#include <stdbool.h> - - - -#define G_TYPE_COMPARABLE_ITEM             (g_comparable_item_get_type()) -#define G_COMPARABLE_ITEM(obj)             (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_COMPARABLE_ITEM, GComparableItem)) -#define G_COMPARABLE_ITEM_CLASS(vtable)    (G_TYPE_CHECK_CLASS_CAST((vtable), G_TYPE_COMPARABLE_ITEM, GComparableItemIface)) -#define G_IS_COMPARABLE_ITEM(obj)          (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_COMPARABLE_ITEM)) -#define G_IS_COMPARABLE_ITEM_CLASS(vtable) (G_TYPE_CHECK_CLASS_TYPE((vtable), G_TYPE_COMPARABLE_ITEM)) -#define G_COMPARABLE_ITEM_GET_IFACE(inst)  (G_TYPE_INSTANCE_GET_INTERFACE((inst), G_TYPE_COMPARABLE_ITEM, GComparableItemIface)) - - -/* Instance d'élément comparable (coquille vide) */ -typedef struct _GComparableItem GComparableItem; - -/* Instance d'élément comparable (interface) */ -typedef struct _GComparableItemIface GComparableItemIface; - - -/* Modes de comparaison */ -typedef enum _RichCmpOperation -{ -    RCO_LT,                                 /* Equivalent de '<'           */ -    RCO_LE,                                 /* Equivalent de '<='          */ -    RCO_EQ,                                 /* Equivalent de '=='          */ -    RCO_NE,                                 /* Equivalent de '!='          */ -    RCO_GT,                                 /* Equivalent de '>'           */ -    RCO_GE,                                 /* Equivalent de '>°'          */ - -} RichCmpOperation; - -/* Détermination d'un besoin de comparaison supplémentaire */ -#define STATUS_NOT_EQUAL(_s, _o)                            \ -    ({                                                      \ -        bool __result;                                      \ -        if (_o == RCO_LE || _o == RCO_EQ || _o == RCO_GE)   \ -            __result = !_s;                                 \ -        else                                                \ -            __result = _s;                                  \ -        __result;                                           \ -    }) - - -/* Détermine le type d'une interface pour un objet comparable. */ -GType g_comparable_item_get_type(void) G_GNUC_CONST; - -/* Réalise une comparaison entre objets selon un critère précis. */ -bool g_comparable_item_compare_rich(const GComparableItem *, const GComparableItem *, RichCmpOperation, bool *); - - - -#endif  /* _GLIBEXT_COMPARISON_H */ diff --git a/src/glibext/hashable-int.h b/src/glibext/hashable-int.h new file mode 100644 index 0000000..f8a85e1 --- /dev/null +++ b/src/glibext/hashable-int.h @@ -0,0 +1,47 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * hashable-int.h - définitions internes propres aux calculs de l'empreinte d'un objet + * + * 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_HASHABLE_INT_H +#define _GLIBEXT_HASHABLE_INT_H + + +#include "hashable.h" + + + +/* Calcule l'empreinte sur 32 bits d'un objet. */ +typedef guint (* hash_object_fc) (const GHashableObject *); + + +/* Instance d'objet visant à être unique (interface) */ +struct _GHashableObjectInterface +{ +    GTypeInterface base_iface;              /* A laisser en premier        */ + +    hash_object_fc hash;                    /* Réduction en valeur         */ + +}; + + + +#endif  /* _GLIBEXT_HASHABLE_INT_H */ diff --git a/src/glibext/hashable.c b/src/glibext/hashable.c new file mode 100644 index 0000000..f988a90 --- /dev/null +++ b/src/glibext/hashable.c @@ -0,0 +1,82 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * hashable.c - calculs de l'empreinte d'un objet + * + * 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/>. + */ + + +#include "hashable.h" + + +#include "hashable-int.h" + + + +/* Procède à l'initialisation de l'interface de détermination. */ +static void g_hashable_object_default_init(GHashableObjectInterface *); + + + +/* Détermine le type d'une interface pour la réduction d'un objet à une valeur. */ +G_DEFINE_INTERFACE(GHashableObject, g_hashable_object, G_TYPE_OBJECT) + + +/****************************************************************************** +*                                                                             * +*  Paramètres  : iface = interface GLib à initialiser.                        * +*                                                                             * +*  Description : Procède à l'initialisation de l'interface de détermination.  * +*                                                                             * +*  Retour      : -                                                            * +*                                                                             * +*  Remarques   : -                                                            * +*                                                                             * +******************************************************************************/ + +static void g_hashable_object_default_init(GHashableObjectInterface *iface) +{ +    iface->hash = NULL; + +} + + +/****************************************************************************** +*                                                                             * +*  Paramètres  : object = objet dont l'instance est à consulter.              * +*                                                                             * +*  Description : Calcule l'empreinte sur 32 bits d'un objet.                  * +*                                                                             * +*  Retour      : Valeur de représentation, unique pour l'objet ou non.        * +*                                                                             * +*  Remarques   : -                                                            * +*                                                                             * +******************************************************************************/ + +guint g_hashable_object_hash(const GHashableObject *object) +{ +    guint result;                       /* Valeur à retourner              */ +    GHashableObjectInterface *iface;    /* Interface utilisée              */ + +    iface = G_HASHABLE_OBJECT_GET_IFACE(object); + +    result = iface->hash(object); + +    return result; + +} diff --git a/src/glibext/hashable.h b/src/glibext/hashable.h new file mode 100644 index 0000000..165c744 --- /dev/null +++ b/src/glibext/hashable.h @@ -0,0 +1,42 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * hashable.h - prototypes pour les calculs de l'empreinte d'un objet + * + * 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_HASHABLE_H +#define _GLIBEXT_HASHABLE_H + + +#include "helpers.h" + + + +#define G_TYPE_HASHABLE_OBJECT (g_hashable_object_get_type()) + +DECLARE_INTERFACE(GHashableObject, g_hashable_object, G, HASHABLE_OBJECT); + + +/* Calcule l'empreinte sur 32 bits d'un objet. */ +guint g_hashable_object_hash(const GHashableObject *); + + + +#endif  /* _GLIBEXT_HASHABLE_H */ diff --git a/src/glibext/helpers.h b/src/glibext/helpers.h index 04e51ad..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 @@ -193,4 +221,5 @@  #endif +  #endif  /* _GLIBEXT_HELPERS_H */ 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 new file mode 100644 index 0000000..dbfb412 --- /dev/null +++ b/src/glibext/objhole-int.h @@ -0,0 +1,169 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * objhole.h - définitions internes pour ll'utilisation d'un espace inutilisé dans la structure GObject + * + * Copyright (C) 2024 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_OBJHOLE_INT_H +#define _GLIBEXT_OBJHOLE_INT_H + + +#include "objhole.h" + + +#include "../common/cpp.h" + + + +/** + * Une structure GObject a la définition suivante : + * + *    struct  _GObject + *    { + *        GTypeInstance  g_type_instance; + *        volatile guint ref_count; + *        GData          *qdata; + *    }; + * + * Chaque objet GLib alloué comporte ainsi 4 octets inutilisés : + * + *    (gdb) pt /o GObject + *    type = struct _GObject { + *    /      0      |       8 /    GTypeInstance g_type_instance; + *    /      8      |       4 /    guint ref_count; + *    / XXX  4-byte hole      / + *    /     16      |       8 /    GData *qdata; + * + *                                 / total size (bytes):   24 / + *    } + * + * La situation n'a pas échappé aux développeurs GLib, avec la définition réelle + * de la structure  (cf. https://github.com/GNOME/glib/blob/main/gobject/gobject.c) : + * + *    #if SIZEOF_INT == 4 && GLIB_SIZEOF_VOID_P == 8 + *    #define HAVE_OPTIONAL_FLAGS + *    #endif + * + *    typedef struct + *    { + *      GTypeInstance  g_type_instance; + *      guint          ref_count; + *    #ifdef HAVE_OPTIONAL_FLAGS + *      guint          optional_flags; + *    #endif + *      GData         *qdata; + *    } GObjectReal; + * + *    G_STATIC_ASSERT(sizeof(GObject) == sizeof(GObjectReal)); + *    G_STATIC_ASSERT(G_STRUCT_OFFSET(GObject, ref_count) == G_STRUCT_OFFSET(GObjectReal, ref_count)); + *    G_STATIC_ASSERT(G_STRUCT_OFFSET(GObject, qdata) == G_STRUCT_OFFSET(GObjectReal, qdata)); + * + * L'espace entre les deux derniers champs ne peut donc être pleinement exploité deux fois. + */ + +/** + * Les bits effectivements utilisés par GLib s'identifie ainsi (02/12/24) : + * + *    $ wget -qO /dev/stdout https://raw.githubusercontent.com/GNOME/glib/refs/heads/main/gobject/gobject.c \ + *        | grep ' *    #define OPTIONAL_FLAG_' + *    #define OPTIONAL_FLAG_IN_CONSTRUCTION    (1 << 0) + *    #define OPTIONAL_FLAG_HAS_SIGNAL_HANDLER (1 << 1) + *    #define OPTIONAL_FLAG_HAS_NOTIFY_HANDLER (1 << 2) + *    #define OPTIONAL_FLAG_LOCK               (1 << 3) + *    #define OPTIONAL_FLAG_EVER_HAD_WEAK_REF  (1 << 4) + * + * Les n premiers bits doivent ainsi être préservés, même s'il est possible de + * partager le bit de verrouilage OPTIONAL_FLAG_LOCK. + */ + + +#ifndef HAVE_OPTIONAL_FLAGS_IN_GOBJECT + +#   if SIZEOF_INT == 4 && GLIB_SIZEOF_VOID_P >= 8 +#       define HAVE_OPTIONAL_FLAGS_IN_GOBJECT 1 +#   else +#       define HAVE_OPTIONAL_FLAGS_IN_GOBJECT 0 +#   endif + +#endif + + +#define GOBJECT_LOCK_BIT 3 + + +/* Nouvelle version dense des objets (instance) */ +typedef struct _GThickObject +{ +    /** +     * (cf. structure GObjectReal officielle). +     */ + +    GTypeInstance g_type_instance;          /* Type d'objet                */ +    guint ref_count;                        /* Décompte des références     */ + +#ifdef HAVE_OPTIONAL_FLAGS_IN_GOBJECT +    guint extra;                            /* Zone partagée avec GLib     */ +#endif + +    GData *qdata;                           /* Données complémentaires ?   */ + +#ifndef HAVE_OPTIONAL_FLAGS_IN_GOBJECT +    guint extra;                            /* Zone supplémentaire propre  */ +#endif + +} GThickObject; + +/* Nouvelle version dense des objets (classe) */ +struct _GThickObjectClass +{ +    GObjectClass parent;                    /* A laisser en premier        */ + +}; + + +/** + * Définition du périmètre et des moyens d'accès. + */ + +/* 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(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(G_THICK_OBJECT(obj), __val);   \ +    }) + + + +#endif  /* _GLIBEXT_OBJHOLE_INT_H */ diff --git a/src/glibext/objhole.c b/src/glibext/objhole.c new file mode 100644 index 0000000..fd6fbc9 --- /dev/null +++ b/src/glibext/objhole.c @@ -0,0 +1,256 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * objhole.c - utilisation d'un espace inutilisé dans la structure GObject + * + * Copyright (C) 2024 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 "objhole.h" + + +#include <assert.h> + + +#include "objhole-int.h" + + + +/* Initialise la classe des objets à la structure dense. */ +static void g_thick_object_class_init(GThickObjectClass *); + +/* Initialise une instance d'objet à la structure dense. */ +static void g_thick_object_init(GThickObject *); + +/* Supprime toutes les références externes. */ +static void g_thick_object_dispose(GObject *); + +/* Procède à la libération totale de la mémoire. */ +static void g_thick_object_finalize(GObject *); + + + +G_DEFINE_TYPE(GThickObject, g_thick_object, G_TYPE_OBJECT); + + +/****************************************************************************** +*                                                                             * +*  Paramètres  : klass = classe à initialiser.                                * +*                                                                             * +*  Description : Initialise la classe des objets à la structure dense.        * +*                                                                             * +*  Retour      : -                                                            * +*                                                                             * +*  Remarques   : -                                                            * +*                                                                             * +******************************************************************************/ + +static void g_thick_object_class_init(GThickObjectClass *klass) +{ +    GObjectClass *object;                   /* Autre version de la classe  */ + +    object = G_OBJECT_CLASS(klass); + +    object->dispose = g_thick_object_dispose; +    object->finalize = g_thick_object_finalize; + +} + + +/****************************************************************************** +*                                                                             * +*  Paramètres  : obj = instance à initialiser.                                * +*                                                                             * +*  Description : Initialise une instance d'objet à la structure dense.        * +*                                                                             * +*  Retour      : -                                                            * +*                                                                             * +*  Remarques   : -                                                            * +*                                                                             * +******************************************************************************/ + +static void g_thick_object_init(GThickObject *obj) +{ +    obj->extra = 0; + +} + + +/****************************************************************************** +*                                                                             * +*  Paramètres  : object = instance d'objet GLib à traiter.                    * +*                                                                             * +*  Description : Supprime toutes les références externes.                     * +*                                                                             * +*  Retour      : -                                                            * +*                                                                             * +*  Remarques   : -                                                            * +*                                                                             * +******************************************************************************/ + +static void g_thick_object_dispose(GObject *object) +{ +    G_OBJECT_CLASS(g_thick_object_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_thick_object_finalize(GObject *object) +{ +    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.* +*                                                                             * +*  Retour      : Valeur de 32 lues et expurgées des bits GLib.                * +*                                                                             * +*  Remarques   : -                                                            * +*                                                                             * +******************************************************************************/ + +guint g_thick_object_get_extra(const GThickObject *obj) +{ +    guint result;                           /* Valeur à retourner          */ +    guint mask;                             /* Masque à appliquer          */ + +    result = g_atomic_int_get(&obj->extra); + +    assert(GOBJECT_RESERVED_EXTRA_BITS < 30); + +    mask = (1 << GOBJECT_RESERVED_EXTRA_BITS) - 1; + +    result &= ~mask; + +    return result; + +} + + +/****************************************************************************** +*                                                                             * +*  Paramètres  : obj = instance d'objet GLib à consulter.                     * +*                val = valeur de 32 à conserver.                              * +*                                                                             * +*  Description : Définit la valeur courante de la zone de stockage d'un objet.* +*                                                                             * +*  Retour      : -                                                            * +*                                                                             * +*  Remarques   : -                                                            * +*                                                                             * +******************************************************************************/ + +void g_thick_object_set_extra(GThickObject *obj, guint val) +{ +    guint mask;                             /* Masque à appliquer          */ + +    assert(GOBJECT_RESERVED_EXTRA_BITS < 30); + +    mask = (1 << GOBJECT_RESERVED_EXTRA_BITS) - 1; + +    assert((val & mask) == 0); + +    val &= ~mask; + +    g_atomic_int_and(&obj->extra, val | mask); + +    g_atomic_int_or(&obj->extra, val); + +} diff --git a/src/glibext/objhole.h b/src/glibext/objhole.h index 38f4bd5..461c37a 100644 --- a/src/glibext/objhole.h +++ b/src/glibext/objhole.h @@ -2,7 +2,7 @@  /* Chrysalide - Outil d'analyse de fichiers binaires   * objhole.h - prototypes pour l'utilisation d'un espace inutilisé dans la structure GObject   * - * Copyright (C) 2020 Cyrille Bagard + * Copyright (C) 2020-2024 Cyrille Bagard   *   *  This file is part of Chrysalide.   * @@ -25,118 +25,36 @@  #define _GLIBEXT_OBJHOLE_H -#include <glib.h> -#include <glib-object.h> - - -#include "../common/cpp.h" - - - -/** - * Une structure GObject a la définition suivante : - * - *    struct  _GObject - *    { - *        GTypeInstance  g_type_instance; - *        volatile guint ref_count; - *        GData          *qdata; - *    }; - * - * En revanche, le fichier "glib/gobject/gobject.c" précise la définition - * réelle de la structure selon l'environnement : - * - *    #if SIZEOF_INT == 4 && GLIB_SIZEOF_VOID_P == 8 - *    #define HAVE_OPTIONAL_FLAGS - *    #endif - * - *    typedef struct - *    { - *      GTypeInstance  g_type_instance; - *      guint          ref_count; - *    #ifdef HAVE_OPTIONAL_FLAGS - *      guint          optional_flags; - *    #endif - *      GData         *qdata; - *    } GObjectReal; - * - *    G_STATIC_ASSERT(sizeof(GObject) == sizeof(GObjectReal)); - *    G_STATIC_ASSERT(G_STRUCT_OFFSET(GObject, ref_count) == G_STRUCT_OFFSET(GObjectReal, ref_count)); - *    G_STATIC_ASSERT(G_STRUCT_OFFSET(GObject, qdata) == G_STRUCT_OFFSET(GObjectReal, qdata)); - * - * L'espace entre les deux derniers champs ne peut donc être pleinement exploité deux fois. - */ - -#if 0 - -#   define GET_GOBJECT_EXTRA(obj, tp)                           \ -    ({                                                          \ -        BUILD_BUG_ON(sizeof(tp) > sizeof(guint));               \ -        tp *___result;                                          \ -        ___result = (tp *)(((guint *)&obj->ref_count) + 1);     \ -        BUILD_BUG_ON((___result + 1) == (tp *)&obj->qdata);     \ -        ___result;                                              \ -    }) - +#ifndef NDEBUG +#   include <stdbool.h>  #endif -/** - * Choix du bit de verrou pour le champ "lock". - * - * Dans la structure exploitant le mot utilisé ici, ce verrou est généralement - * placé dans le bit de poids fort pour les objets qui l'utilisent. - */ +#include "../glibext/helpers.h" + -#if __BYTE_ORDER == __LITTLE_ENDIAN -#   define HOLE_LOCK_BIT 31 +#define G_TYPE_THICK_OBJECT (g_thick_object_get_type()) -#elif __BYTE_ORDER == __BIG_ENDIAN +DECLARE_GTYPE(GThickObject, g_thick_object, G, THICK_OBJECT); -#   define HOLE_LOCK_BIT 0 -#else +/* Pose un verrou à l'aide du bit dédié de GObject. */ +void g_thick_object_lock(GThickObject *); -#   error "Unknown byte order" +/* 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 *); -/* Verrou d'accès pour une encapsulation */ -typedef struct _lockable_obj_extra_t -{ -    gint lock;                              /* Gestion d'accès aux fanions */ - -} lockable_obj_extra_t; - - -#define INIT_GOBJECT_EXTRA_LOCK(xtr)                    \ -    do                                                  \ -    {                                                   \ -        lockable_obj_extra_t *__lockable;               \ -        __lockable = (lockable_obj_extra_t *)xtr;       \ -        __lockable->lock = 0;                           \ -    }                                                   \ -    while (0) - -#define LOCK_GOBJECT_EXTRA(xtr)                         \ -    do                                                  \ -    {                                                   \ -        lockable_obj_extra_t *__lockable;               \ -        __lockable = (lockable_obj_extra_t *)xtr;       \ -        g_bit_lock(&__lockable->lock, HOLE_LOCK_BIT);   \ -    }                                                   \ -    while (0) - -#define UNLOCK_GOBJECT_EXTRA(xtr)                       \ -    do                                                  \ -    {                                                   \ -        lockable_obj_extra_t *__lockable;               \ -        __lockable = (lockable_obj_extra_t *)xtr;       \ -        g_bit_unlock(&__lockable->lock, HOLE_LOCK_BIT); \ -    }                                                   \ -    while (0) +/* Définit la valeur courante de la zone de stockage d'un objet. */ +void g_thick_object_set_extra(GThickObject *, guint); 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/gbinportion-int.h b/src/glibext/portion-int-ui.h index a29f53c..a29f53c 100644 --- a/src/glibext/gbinportion-int.h +++ b/src/glibext/portion-int-ui.h diff --git a/src/glibext/portion-int.h b/src/glibext/portion-int.h new file mode 100644 index 0000000..c044206 --- /dev/null +++ b/src/glibext/portion-int.h @@ -0,0 +1,69 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * portion-int.h - prototypes internes pour la définition interne des portions de binaire + * + * Copyright (C) 2019-2024 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_PORTION_INT_H +#define GLIBEXT_PORTION_INT_H + + +#include "portion.h" + + + +/* Portion de données binaires quelconques (instance) */ +struct _GBinaryPortion +{ +    GObject parent;                         /* A laisser en premier        */ + +    char *desc;                             /* Désignation humaine         */ + +    mrange_t range;                         /* Emplacement dans le code    */ +    bool continued;                         /* Suite d'une découpe ?       */ + +    PortionAccessRights rights;             /* Droits d'accès              */ + +    GBinaryPortion **subs;                  /* Portions incluses           */ +    size_t count;                           /* Quantité d'inclusions       */ + +}; + +/* Portion de données binaires quelconques (classe) */ +struct _GBinaryPortionClass +{ +    GObjectClass parent;                    /* A laisser en premier        */ + +}; + + +/* Met en place une description de partie de code vierge.       * +*                                                                             * +*  Retour      : Bilan de l'opération.                                        * +*                                                                             * +*  Remarques   : -                                                            * +*                                                                             * +******************************************************************************/ + +bool g_binary_portion_create(GBinaryPortion *, const vmpa2t *, phys_t); + + + +#endif  /* GLIBEXT_PORTION_INT_H */ diff --git a/src/glibext/gbinportion.c b/src/glibext/portion-ui.c index 12e12fb..12e12fb 100644 --- a/src/glibext/gbinportion.c +++ b/src/glibext/portion-ui.c diff --git a/src/glibext/gbinportion.h b/src/glibext/portion-ui.h index ea4b4aa..ea4b4aa 100644 --- a/src/glibext/gbinportion.h +++ b/src/glibext/portion-ui.h diff --git a/src/glibext/portion.c b/src/glibext/portion.c new file mode 100644 index 0000000..096a39d --- /dev/null +++ b/src/glibext/portion.c @@ -0,0 +1,974 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * portion.c - représentation graphique de portions de binaire + * + * Copyright (C) 2013-2024 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 "portion.h" + + +#include <assert.h> +#include <malloc.h> +//#include <stdio.h> +//#include <stdlib.h> +#include <string.h> + + +#include <i18n.h> + + +#include "portion-int.h" +//#include "../analysis/human/asm/lang.h" +#include "../common/extstr.h" +#include "../common/sort.h" +//#include "../core/columns.h" +//#include "../glibext/gbinarycursor.h" +//#include "../glibext/linegen-int.h" + + + +/* ------------------------------- PORTION DE BINAIRE ------------------------------- */ + + +/* Initialise la classe des portions de données binaires. */ +static void g_binary_portion_class_init(GBinaryPortionClass *); + +/* Initialise une instance de portion de données binaires. */ +static void g_binary_portion_init(GBinaryPortion *); + +/* Supprime toutes les références externes. */ +static void g_binary_portion_dispose(GBinaryPortion *); + +/* Procède à la libération totale de la mémoire. */ +static void g_binary_portion_finalize(GBinaryPortion *); + + + +/* ------------------------ PARCOURS D'ENSEMBLES DE PORTIONS ------------------------ */ + + +/* Détermine si une portion contient une adresse donnée. */ +static bool g_binary_portion_contains_vmpa(const GBinaryPortion *, const vmpa2t *); + + + +/* ---------------------------------------------------------------------------------- */ +/*                                 PORTION DE BINAIRE                                 */ +/* ---------------------------------------------------------------------------------- */ + + +/* Indique le type défini par la GLib pour les portions de données binaires. */ +G_DEFINE_TYPE(GBinaryPortion, g_binary_portion, G_TYPE_OBJECT); + + +/****************************************************************************** +*                                                                             * +*  Paramètres  : klass = classe à initialiser.                                * +*                                                                             * +*  Description : Initialise la classe des portions de données binaires.       * +*                                                                             * +*  Retour      : -                                                            * +*                                                                             * +*  Remarques   : -                                                            * +*                                                                             * +******************************************************************************/ + +static void g_binary_portion_class_init(GBinaryPortionClass *klass) +{ +    GObjectClass *object;                   /* Autre version de la classe  */ + +    object = G_OBJECT_CLASS(klass); + +    object->dispose = (GObjectFinalizeFunc/* ! */)g_binary_portion_dispose; +    object->finalize = (GObjectFinalizeFunc)g_binary_portion_finalize; + + +} + + +/****************************************************************************** +*                                                                             * +*  Paramètres  : portion = instance à initialiser.                            * +*                                                                             * +*  Description : Initialise une instance de portion de données binaires.      * +*                                                                             * +*  Retour      : -                                                            * +*                                                                             * +*  Remarques   : -                                                            * +*                                                                             * +******************************************************************************/ + +static void g_binary_portion_init(GBinaryPortion *portion) +{ +    vmpa2t dummy;                           /* Coquille presque vide       */ + +    portion->desc = NULL; + +    init_vmpa(&dummy, VMPA_NO_PHYSICAL, VMPA_NO_VIRTUAL); +    init_mrange(&portion->range, &dummy, VMPA_NO_VIRTUAL); + +    portion->continued = false; + +    portion->rights = PAC_NONE; + +    portion->subs = NULL; +    portion->count = 0; + +} + + +/****************************************************************************** +*                                                                             * +*  Paramètres  : portion = instance d'objet GLib à traiter.                   * +*                                                                             * +*  Description : Supprime toutes les références externes.                     * +*                                                                             * +*  Retour      : -                                                            * +*                                                                             * +*  Remarques   : -                                                            * +*                                                                             * +******************************************************************************/ + +static void g_binary_portion_dispose(GBinaryPortion *portion) +{ +    size_t i;                               /* Boucle de parcours          */ + +    for (i = 0; i < portion->count; i++) +        g_clear_object(&portion->subs[i]); + +    G_OBJECT_CLASS(g_binary_portion_parent_class)->dispose(G_OBJECT(portion)); + +} + + +/****************************************************************************** +*                                                                             * +*  Paramètres  : portion = instance d'objet GLib à traiter.                   * +*                                                                             * +*  Description : Procède à la libération totale de la mémoire.                * +*                                                                             * +*  Retour      : -                                                            * +*                                                                             * +*  Remarques   : -                                                            * +*                                                                             * +******************************************************************************/ + +static void g_binary_portion_finalize(GBinaryPortion *portion) +{ +    if (portion->desc != NULL) +        free(portion->desc); + +    if (portion->subs != NULL) +        free(portion->subs); + +    G_OBJECT_CLASS(g_binary_portion_parent_class)->finalize(G_OBJECT(portion)); + +} + + +/****************************************************************************** +*                                                                             * +*  Paramètres  : addr = emplacement de la section à conserver.                * +*                size = taille de la section à conserver.                     * +*                                                                             * +*  Description : Crée une description de partie de code vierge.               * +*                                                                             * +*  Retour      : Instance mise en place.                                      * +*                                                                             * +*  Remarques   : -                                                            * +*                                                                             * +******************************************************************************/ + +GBinaryPortion *g_binary_portion_new(const vmpa2t *addr, phys_t size) +{ +    GBinaryPortion *result;                    /* Structure à retourner       */ + +    result = g_object_new(G_TYPE_BINARY_PORTION, NULL); + +    if (!g_binary_portion_create(result, addr, size)) +        g_clear_object(&result); + +    return result; + +} + + +/****************************************************************************** +*                                                                             * +*  Paramètres  : portion = instance à initialiser pleinement.                 * +*                addr    = emplacement de la section à conserver.             * +*                size    = taille de la section à conserver.                  * +*                                                                             * +*  Description : Met en place une description de partie de code vierge.       * +*                                                                             * +*  Retour      : Bilan de l'opération.                                        * +*                                                                             * +*  Remarques   : -                                                            * +*                                                                             * +******************************************************************************/ + +bool g_binary_portion_create(GBinaryPortion *portion, const vmpa2t *addr, phys_t size) +{ +    bool result;                            /* Bilan à retourner           */ + +    result = true; + +    init_mrange(&portion->range, addr, size); + +    return result; + +} + + +/****************************************************************************** +*                                                                             * +*  Paramètres  : a = premières informations à consulter.                      * +*                b = secondes informations à consulter.                       * +*                                                                             * +*  Description : Etablit la comparaison ascendante entre deux portions.       * +*                                                                             * +*  Retour      : Bilan : -1 (a < b), 0 (a == b) ou 1 (a > b).                 * +*                                                                             * +*  Remarques   : -                                                            * +*                                                                             * +******************************************************************************/ + +int g_binary_portion_compare(const GBinaryPortion **a, const GBinaryPortion **b) +{ +    int result;                             /* Bilan à retourner           */ +    const vmpa2t *addr_a;                   /* Adresse de la portion 'a'   */ +    const vmpa2t *addr_b;                   /* Adresse de la portion 'b'   */ + +    addr_a = get_mrange_addr(&(*a)->range); +    addr_b = get_mrange_addr(&(*b)->range); + +    result = cmp_vmpa(addr_a, addr_b); + +    return result; + +} + + +/****************************************************************************** +*                                                                             * +*  Paramètres  : portion = description de partie à mettre à jour.             * +*                desc    = nom à donner à la partie.                          * +*                                                                             * +*  Description : Attribue une description humaine à une partie de code.       * +*                                                                             * +*  Retour      : -                                                            * +*                                                                             * +*  Remarques   : -                                                            * +*                                                                             * +******************************************************************************/ + +void g_binary_portion_set_desc(GBinaryPortion *portion, const char *desc) +{ +    if (portion->desc != NULL) +        free(portion->desc); + +    if (desc == NULL) +        portion->desc = NULL; + +    else +    { +        portion->desc = strdup(desc); + +        if (portion->continued) +            portion->desc = stradd(portion->desc, _(" (continued)")); + +    } + +} + + +/****************************************************************************** +*                                                                             * +*  Paramètres  : portion = description de partie à consulter.                 * +*                                                                             * +*  Description : Fournit la description attribuée à une partie de code.       * +*                                                                             * +*  Retour      : Nom donné à la partie.                                       * +*                                                                             * +*  Remarques   : -                                                            * +*                                                                             * +******************************************************************************/ + +const char *g_binary_portion_get_desc(const GBinaryPortion *portion) +{ +    return portion->desc; + +} + + +/****************************************************************************** +*                                                                             * +*  Paramètres  : portion = description de partie à mettre à jour.             * +*                                                                             * +*  Description : Fournit l'emplacement d'une partie de code binaire.          * +*                                                                             * +*  Retour      : Espace de couverture associé à la portion.                   * +*                                                                             * +*  Remarques   : -                                                            * +*                                                                             * +******************************************************************************/ + +const mrange_t *g_binary_portion_get_range(const GBinaryPortion *portion) +{ +    return &portion->range; + +} + +/****************************************************************************** +*                                                                             * +*  Paramètres  : portion = description de partie à mettre à jour.             * +*                max     = taille maximale accordée à la portion.             * +*                                                                             * +*  Description : Assure qu'une portion ne dépasse pas une position donnée.    * +*                                                                             * +*  Retour      : true si la portion a été modifiée, false sinon.              * +*                                                                             * +*  Remarques   : -                                                            * +*                                                                             * +******************************************************************************/ + +bool g_binary_portion_limit_range(GBinaryPortion *portion, phys_t max) +{ +    bool result;                            /* Bilan à retourner           */ +    phys_t current;                         /* Taille courante             */ + +    current = get_mrange_length(&portion->range); + +    result = (current > max); + +    if (result) +        set_mrange_length(&portion->range, max); + +    return result; + +} + + +/****************************************************************************** +*                                                                             * +*  Paramètres  : portion = portion dont la définition est à metre à jour.     * +*                                                                             * +*  Description : Définit la nature de la portion en terme d'originalité.      * +*                                                                             * +*  Retour      : -                                                            * +*                                                                             * +*  Remarques   : L'action ne modifie aucunement la description courante.      * +*                C'est le changement de description qui s'appuie sur la       * +*                notée ici.                                                   * +*                                                                             * +******************************************************************************/ + +void g_binary_portion_mark_as_continued(GBinaryPortion *portion, bool continued) +{ +    portion->continued = continued; + +} + + +/****************************************************************************** +*                                                                             * +*  Paramètres  : portion = portion dont la définition est à consulter.        * +*                                                                             * +*  Description : Indique la nature de la portion en terme d'originalité.      * +*                                                                             * +*  Retour      : true si la portion est la suite d'une portion découpée.      * +*                                                                             * +*  Remarques   : -                                                            * +*                                                                             * +******************************************************************************/ + +bool g_binary_portion_is_continuation(const GBinaryPortion *portion) +{ +    return portion->continued; + +} + + +/****************************************************************************** +*                                                                             * +*  Paramètres  : portion = description de partie à mettre à jour.             * +*                rights  = droits d'accès de la partie.                       * +*                                                                             * +*  Description : Définit les droits associés à une partie de code.            * +*                                                                             * +*  Retour      : -                                                            * +*                                                                             * +*  Remarques   : -                                                            * +*                                                                             * +******************************************************************************/ + +void g_binary_portion_set_rights(GBinaryPortion *portion, PortionAccessRights rights) +{ +    portion->rights = rights; + +} + + +/****************************************************************************** +*                                                                             * +*  Paramètres  : portion = description de partie à consulter.                 * +*                                                                             * +*  Description : Fournit les droits associés à une partie de code.            * +*                                                                             * +*  Retour      : Droits d'accès de la partie.                                 * +*                                                                             * +*  Remarques   : -                                                            * +*                                                                             * +******************************************************************************/ + +PortionAccessRights g_binary_portion_get_rights(const GBinaryPortion *portion) +{ +    return portion->rights; + +} + + +/****************************************************************************** +*                                                                             * +*  Paramètres  : portion = portion principale à compléter.                    * +*                sub     = portion à inclure dans la définition courante.     * +*                                                                             * +*  Description : Procède à l'inclusion d'une portion dans une autre.          * +*                                                                             * +*  Retour      : Bilan de l'opération : true si inclusion, false sinon.       * +*                                                                             * +*  Remarques   : -                                                            * +*                                                                             * +******************************************************************************/ + +bool g_binary_portion_include(GBinaryPortion *portion, GBinaryPortion *sub) +{ +    bool result;                            /* Bilan à retourner           */ +    bool found;                             /* Zone d'accueil trouvée ?    */ +    size_t best;                            /* Meilleur point d'insertion  */ +    size_t missed;                          /* Indice de zone à déplacer   */ +    const mrange_t *brange;                 /* Raccourci de confort d'usage*/ +    vmpa2t end;                             /* Fin de la zone commune      */ +    phys_t overlapping;                     /* Taille de la zone commune   */ +    bool continued;                         /* Suite d'une découpe ?       */ +    GBinaryPortion *left_part;                 /* Partie intégrable           */ +    vmpa2t start;                           /* Départ de la seconde partie */ +    GBinaryPortion *right_part;                /* Partie restante             */ + +    int g_binary_portion_is_included(const GBinaryPortion **a, const GBinaryPortion **b) +    { +        int result;                         /* Bilan à retourner           */ + +        result = mrange_includes_mrange(&(*b)->range, &(*a)->range); + +        return result; + +    } + +    found = bsearch_index(&sub, portion->subs, portion->count, sizeof(GBinaryPortion *), +                          (__compar_fn_t)g_binary_portion_is_included, &best); + +    if (!found) +    { +        /** +         * On se prépare à réaliser une insertion au niveau courant. Mais des +         * portions précédentes sont peut-être à déplacer dans la nouvelle zone : +         * +         *   EXIDX          0x001178 0x00009178 0x00009178 0x00008 0x00008 R   0x4 +         *   PHDR           0x000034 0x00008034 0x00008034 0x00120 0x00120 R E 0x4 +         *   INTERP         0x000154 0x00008154 0x00008154 0x00019 0x00019 R   0x1 +         *   LOAD           0x000000 0x00008000 0x00008000 0x01184 0x01184 R E 0x8000 +         * +         * On refait donc une passe sur toutes les sous-portions du niveau. +         * +         * Cette approche a le mérite de traiter également et naturellement les +         * sections définies dans le désordre : +         * +         *   [21] .bss                NOBITS          00088240 07823c 0018c8 00  WA  0   0  8 +         *   [22] __libc_freeres_ptrs NOBITS          00089b08 07823c 000018 00  WA  0   0  4 +         *   [23] .comment            PROGBITS        00000000 07823c 000022 01  MS  0   0  1 +         * +         * Quant aux cas de figure où les portions sont identiques, l'ordre d'appel +         * induit l'ordre d'inclusion. +         * +         * Cela concerne par exemple les zones de données : +         * +         *   En-têtes de section: +         *     [Nr] Nom               Type            Adr      Décala.Taille ES Fan LN Inf Al +         *     ... +         *     [ 2] .data             PROGBITS        00010098 000098 00000c 00  WA  0   0  1 +         * +         *   En-têtes de programme: +         *     Type           Décalage Adr. vir.  Adr.phys.  T.Fich. T.Mém.  Fan Alignement +         *     ... +         *     LOAD           0x000098 0x00010098 0x00010098 0x0000c 0x0000c RW  0x8000 +         * +         */ + +        int g_binary_portion_track_missed_inclusion(const GBinaryPortion **a, const GBinaryPortion **b) +        { +            int result;                     /* Bilan à retourner           */ + +            result = mrange_includes_mrange(&(*a)->range, &(*b)->range); + +            return result; + +        } + +        do +        { +            found = bsearch_index(&sub, portion->subs, portion->count, sizeof(GBinaryPortion *), +                                  (__compar_fn_t)g_binary_portion_track_missed_inclusion, &missed); + +            if (found) +            { +                result = g_binary_portion_include(sub, portion->subs[missed]); +                assert(result); + +                portion->subs = _qdelete(portion->subs, &portion->count, sizeof(GBinaryPortion *), missed); + +            } + +        } +        while (found); + +        /** +         * Il peut arriver que certaines portions débordent de leur zone d'inclusion : +         * +         *   [24] .bss              NOBITS          00012088 002084 000044 00  WA  0   0  8 +         *   [25] .ARM.attributes   ARM_ATTRIBUTES  00000000 002084 000037 00      0   0  1 +         *   [26] .shstrtab         STRTAB          00000000 0020bb 0000ed 00      0   0  1 +         * +         * Afin de respecter une certaine cohérence dans l'arbre des portions, on choisit +         * de découper la portion qui déborde. +         */ + +        int g_binary_portion_track_partial_inclusion(const GBinaryPortion **a, const GBinaryPortion **b) +        { +            int result;                     /* Bilan à retourner           */ + +            result = cmp_mrange_with_vmpa(&(*b)->range, get_mrange_addr(&(*a)->range)); + +            return result; + +        } + +        found = bsearch_index(&sub, portion->subs, portion->count, sizeof(GBinaryPortion *), +                              (__compar_fn_t)g_binary_portion_track_partial_inclusion, &best); + +        if (found) +        { +            brange = &portion->subs[best]->range; + +            compute_mrange_end_addr(brange, &end); +            overlapping = compute_vmpa_diff(get_mrange_addr(&sub->range), &end); + +            continued = g_binary_portion_is_continuation(sub); + +            /* Partie contenue */ + +            left_part = g_binary_portion_new(get_mrange_addr(&sub->range), overlapping); + +            g_binary_portion_set_desc(left_part, sub->desc); +            g_binary_portion_mark_as_continued(left_part, continued); +            g_binary_portion_set_rights(left_part, sub->rights); + +            /* Partie qui déborde... */ + +            /** +             * Comme la portion incluante peut avoir une définition d'adresse +             * virtuelle différente de celle de la portion incluse, on recalcule +             * la position de départ de la seconde partie de la portion découpée +             * à partir des données d'origine. +             */ + +            copy_vmpa(&start, get_mrange_addr(&sub->range)); +            advance_vmpa(&start, overlapping); + +            right_part = g_binary_portion_new(&start, get_mrange_length(&sub->range) - overlapping); + +            if (!continued) +                g_binary_portion_mark_as_continued(right_part, true); + +            g_binary_portion_set_desc(right_part, sub->desc); + +            if (continued) +                g_binary_portion_mark_as_continued(right_part, true); + +            g_binary_portion_set_rights(right_part, sub->rights); + +            /* Inclusions des parties */ + +            result = g_binary_portion_include(portion, left_part); + +            if (result) +                result = g_binary_portion_include(portion, right_part); + +            unref_object(left_part); +            unref_object(right_part); + +        } + +        else +        { +            ref_object(sub); + +            portion->subs = qinsert(portion->subs, &portion->count, sizeof(GBinaryPortion *), +                                    (__compar_fn_t)g_binary_portion_compare, &sub); + +            result = true; + +        } + +    } + +    /* Poursuite de l'inclusion dans la sous-portion adaptée... */ +    else +        result = g_binary_portion_include(portion->subs[best], sub); + +    return result; + +} + + +/****************************************************************************** +*                                                                             * +*  Paramètres  : portion = première couche amorçant la visite.                * +*                visitor = fonction à appeler à chaque étape de la descente.  * +*                data    = adresse pointant vers des données de l'utilisateur.* +*                                                                             * +*  Description : Parcourt un ensemble de portions binaires.                   * +*                                                                             * +*  Retour      : true si la visite a été jusqu'à son terme, false sinon.      * +*                                                                             * +*  Remarques   : -                                                            * +*                                                                             * +******************************************************************************/ + +bool g_binary_portion_visit(GBinaryPortion *portion, visit_portion_fc visitor, void *data) +{ +    bool result;                            /* Etat à retourner            */ + +    bool visit_portion(GBinaryPortion *p, GBinaryPortion *pp) +    { +        bool ret;                           /* Etat à retourner            */ +        size_t i;                           /* Boucle de parcours          */ + +        if (p->count == 0) +            ret = visitor(p, pp, BPV_SHOW, data); + +        else +        { +            ret = visitor(p, pp, BPV_ENTER, data); + +            for (i = 0; i < p->count && ret; i++) +                ret = visit_portion(p->subs[i], p); + +            if (ret) +                ret = visitor(p, pp, BPV_EXIT, data); + +        } + +        return ret; + +    } + +    result = visit_portion(portion, NULL); + +    return result; + +} + + + +/* ---------------------------------------------------------------------------------- */ +/*                          PARCOURS D'ENSEMBLES DE PORTIONS                          */ +/* ---------------------------------------------------------------------------------- */ + + +/****************************************************************************** +*                                                                             * +*  Paramètres  : portion = portion mère à consulter.                          * +*                addr    = adresse du point de recherche.                     * +*                                                                             * +*  Description : Détermine si une portion contient une adresse donnée.        * +*                                                                             * +*  Retour      : true ou false selon le résultat.                             * +*                                                                             * +*  Remarques   : -                                                            * +*                                                                             * +******************************************************************************/ + +static bool g_binary_portion_contains_vmpa(const GBinaryPortion *portion, const vmpa2t *addr) +{ +    bool result;                            /* Bilan à retourner           */ +    const mrange_t *range;                  /* Emplacement de portion      */ + +    result = false; + +    range = g_binary_portion_get_range(portion); + +    /* Portion non allouée en mémoire : on écarte */ +    if (!has_virt_addr(get_mrange_addr(range))) +        goto not_found; + +    result = mrange_contains_addr(range, addr); + + not_found: + +    return result; + +} + + +/****************************************************************************** +*                                                                             * +*  Paramètres  : portion = couche de portions à parcourir pour les recherches.* +*                addr    = adresse du point de recherche.                     * +*                                                                             * +*  Description : Recherche la portion présente à une adresse donnée.          * +*                                                                             * +*  Retour      : Portion trouvée à l'endroit indiqué.                         * +*                                                                             * +*  Remarques   : -                                                            * +*                                                                             * +******************************************************************************/ + +GBinaryPortion *g_binary_portion_find_at_addr(GBinaryPortion *portion, const vmpa2t *addr) +{ +    GBinaryPortion *result;                    /* Portion à retourner         */ +    size_t i;                                  /* Boucle de parcours          */ +    GBinaryPortion *sub;                       /* Portion incluse à traiter   */ + +    result = NULL; + +    if (!g_binary_portion_contains_vmpa(portion, addr)) +        goto done; + +    for (i = 0; i < portion->count && result == NULL; i++) +    { +        sub = portion->subs[i]; + +        if (!g_binary_portion_contains_vmpa(sub, addr)) +            continue; + +        result = g_binary_portion_find_at_addr(sub, addr); + +    } + +    if (result == NULL) +    { +        result = portion; +        ref_object(result); +    } + + done: + +    return result; + +} + + +/****************************************************************************** +*                                                                             * +*  Paramètres  : portion = portion mère à consulter.                          * +*                off     = position physique du point de recherche.           * +*                                                                             * +*  Description : Détermine si une portion contient une position donnée.       * +*                                                                             * +*  Retour      : true ou false selon le résultat.                             * +*                                                                             * +*  Remarques   : -                                                            * +*                                                                             * +******************************************************************************/ + +static bool g_binary_portion_contains_physical(const GBinaryPortion *portion, phys_t off) +{ +    bool result;                            /* Bilan à retourner           */ +    const mrange_t *range;                  /* Emplacement de portion      */ +    const vmpa2t *addr;                     /* Départ de la portion        */ + +    range = g_binary_portion_get_range(portion); +    addr = get_mrange_addr(range); + +    if (!has_phys_addr(addr)) +        result = false; + +    else +        result = (addr->physical <= off && off < (addr->physical + range->length)); + +    return result; + +} + + +/****************************************************************************** +*                                                                             * +*  Paramètres  : portion = couche de portions à parcourir pour les recherches.* +*                off     = position physique à retrouver.                     * +*                pos     = position correspondante. [OUT]                     * +*                                                                             * +*  Description : Fournit l'emplacement correspondant à une position physique. * +*                                                                             * +*  Retour      : Bilan de l'opération.                                        * +*                                                                             * +*  Remarques   : -                                                            * +*                                                                             * +******************************************************************************/ + +bool g_binary_portion_translate_offset_into_vmpa(const GBinaryPortion *portion, phys_t off, vmpa2t *pos) +{ +    bool result;                            /* Bilan à retourner           */ +    size_t i;                               /* Boucle de parcours #1       */ +    GBinaryPortion *sub;                       /* Portion incluse à traiter   */ +    const mrange_t *range;                  /* Emplacement de portion      */ +    const vmpa2t *addr;                     /* Départ de la portion        */ + +    result = false; + +    for (i = 0; i < portion->count; i++) +    { +        sub = portion->subs[i]; + +        if (!g_binary_portion_contains_physical(sub, off)) +            continue; + +        result = g_binary_portion_translate_offset_into_vmpa(sub, off, pos); + +        break; + +    } + +    if (i == portion->count) +    { +        result = g_binary_portion_contains_physical(portion, off); + +        if (result) +        { +            range = g_binary_portion_get_range(portion); +            addr = get_mrange_addr(range); + +            if (has_virt_addr(get_mrange_addr(range))) +                init_vmpa(pos, off, addr->virtual + off - addr->physical); + +            else +                init_vmpa(pos, off, VMPA_NO_VIRTUAL); + +        } + +    } + +    return result; + +} + + +/****************************************************************************** +*                                                                             * +*  Paramètres  : portion = portion mère à consulter.                          * +*                virt    = adresse virtuelle du point de recherche.           * +*                                                                             * +*  Description : Détermine si une portion contient une adresse donnée.        * +*                                                                             * +*  Retour      : true ou false selon le résultat.                             * +*                                                                             * +*  Remarques   : -                                                            * +*                                                                             * +******************************************************************************/ + +static bool g_binary_portion_contains_virtual(const GBinaryPortion *portion, virt_t virt) +{ +    bool result;                            /* Bilan à retourner           */ +    const mrange_t *range;                  /* Emplacement de portion      */ +    const vmpa2t *addr;                     /* Départ de la portion        */ + +    range = g_binary_portion_get_range(portion); +    addr = get_mrange_addr(range); + +    if (!has_virt_addr(addr)) +        result = false; + +    else +        result = (addr->virtual <= virt && virt < (addr->virtual + range->length)); + +    return result; + +} + + +/****************************************************************************** +*                                                                             * +*  Paramètres  : portion = couche de portions à parcourir pour les recherches.* +*                virt    = adresse virtuelle à retrouver.                     * +*                pos     = position correspondante. [OUT]                     * +*                                                                             * +*  Description : Fournit l'emplacement correspondant à une adresse virtuelle. * +*                                                                             * +*  Retour      : Bilan de l'opération.                                        * +*                                                                             * +*  Remarques   : -                                                            * +*                                                                             * +******************************************************************************/ + +bool g_binary_portion_translate_address_into_vmpa(const GBinaryPortion *portion, virt_t virt, vmpa2t *pos) +{ +    bool result;                            /* Bilan à retourner           */ +    size_t i;                               /* Boucle de parcours #1       */ +    GBinaryPortion *sub;                       /* Portion incluse à traiter   */ +    const mrange_t *range;                  /* Emplacement de portion      */ +    const vmpa2t *addr;                     /* Départ de la portion        */ + +    result = false; + +    for (i = 0; i < portion->count; i++) +    { +        sub = portion->subs[i]; + +        if (!g_binary_portion_contains_virtual(sub, virt)) +            continue; + +        result = g_binary_portion_translate_address_into_vmpa(sub, virt, pos); + +        break; + +    } + +    if (i == portion->count) +    { +        result = g_binary_portion_contains_virtual(portion, virt); + +        if (result) +        { +            range = g_binary_portion_get_range(portion); +            addr = get_mrange_addr(range); + +            if (has_phys_addr(addr) && has_virt_addr(addr)) +                init_vmpa(pos, addr->physical + virt - addr->virtual, virt); + +            else +                init_vmpa(pos, VMPA_NO_PHYSICAL, virt); + +        } + +    } + +    return result; + +} diff --git a/src/glibext/portion.h b/src/glibext/portion.h new file mode 100644 index 0000000..88d69b6 --- /dev/null +++ b/src/glibext/portion.h @@ -0,0 +1,121 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * portion.h - prototypes pour la représentation graphique de portions de binaire + * + * Copyright (C) 2013-2024 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_PORTION_H +#define _GLIBEXT_PORTION_H + + +#include <stdbool.h> + + +#include "helpers.h" +#include "../arch/vmpa.h" + + + +/* ------------------------------- PORTION DE BINAIRE ------------------------------- */ + + +#define G_TYPE_BINARY_PORTION (g_binary_portion_get_type()) + +DECLARE_GTYPE(GBinaryPortion, g_binary_portion, G, BINARY_PORTION); + + +/* Crée une description de partie de code vierge. */ +GBinaryPortion *g_binary_portion_new(const vmpa2t *, phys_t); + +/* Etablit la comparaison ascendante entre deux portions. */ +int g_binary_portion_compare(const GBinaryPortion **, const GBinaryPortion **); + +/* Attribue une description humaine à une partie de code. */ +void g_binary_portion_set_desc(GBinaryPortion *, const char *); + +/* Fournit la description attribuée à une partie de code. */ +const char *g_binary_portion_get_desc(const GBinaryPortion *); + +/* Fournit l'emplacement d'une partie de code binaire. */ +const mrange_t *g_binary_portion_get_range(const GBinaryPortion *); + +/* Assure qu'une portion ne dépasse pas une position donnée. */ +bool g_binary_portion_limit_range(GBinaryPortion *, phys_t); + +/* Définit la nature de la portion en terme d'originalité. */ +void g_binary_portion_mark_as_continued(GBinaryPortion *, bool); + +/* Indique la nature de la portion en terme d'originalité. */ +bool g_binary_portion_is_continuation(const GBinaryPortion *); + +/* Droits d'accès à une portion */ +typedef enum _PortionAccessRights +{ +    PAC_NONE    = (0 << 0),                 /* Aucun                       */ +    PAC_READ    = (1 << 0),                 /* Lecture                     */ +    PAC_WRITE   = (1 << 1),                 /* Ecriture                    */ +    PAC_EXEC    = (1 << 2)                  /* Exécution                   */ + +} PortionAccessRights; + +#define PAC_ALL ((PortionAccessRights)(PAC_READ | PAC_WRITE | PAC_EXEC)) + +/* Définit les droits associés à une partie de code. */ +void g_binary_portion_set_rights(GBinaryPortion *, PortionAccessRights); + +/* Fournit les droits associés à une partie de code. */ +PortionAccessRights g_binary_portion_get_rights(const GBinaryPortion *); + +/* Procède à l'inclusion d'une portion dans une autre. */ +bool g_binary_portion_include(GBinaryPortion *, GBinaryPortion *); + +/* Sens des visites */ +typedef enum _BinaryPortionVisit +{ +    BPV_ENTER,                              /* Arrivée sur une branche     */ +    BPV_SHOW,                               /* Visite d'une feuille        */ +    BPV_EXIT                                /* Départ d'une branche        */ + +} BinaryPortionVisit; + + +/* Fonction appelée à chaque visite de portion.*/ +typedef bool (* visit_portion_fc) (GBinaryPortion *, GBinaryPortion *, BinaryPortionVisit, void *); + +/* Parcourt un ensemble de portions binaires. */ +bool g_binary_portion_visit(GBinaryPortion *, visit_portion_fc, void *); + + + +/* ------------------------ PARCOURS D'ENSEMBLES DE PORTIONS ------------------------ */ + + +/* Recherche la portion présente à une adresse donnée. */ +GBinaryPortion *g_binary_portion_find_at_addr(GBinaryPortion *, const vmpa2t *); + +/* Fournit l'emplacement correspondant à une position physique. */ +bool g_binary_portion_translate_offset_into_vmpa(const GBinaryPortion *, phys_t, vmpa2t *); + +/* Fournit l'emplacement correspondant à une adresse virtuelle. */ +bool g_binary_portion_translate_address_into_vmpa(const GBinaryPortion *, virt_t, vmpa2t *); + + + +#endif  /* _GLIBEXT_BINPORTION_H */ diff --git a/src/glibext/secstorage-int.h b/src/glibext/secstorage-int.h new file mode 100644 index 0000000..bbac133 --- /dev/null +++ b/src/glibext/secstorage-int.h @@ -0,0 +1,60 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * secstorage-int.h - définitions internes pour la conservation sécurisée d'éléments de configuration + * + * 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_SECSTORAGE_INT_H +#define _GLIBEXT_SECSTORAGE_INT_H + + +#include "secstorage.h" + + + +/* Gardien des secrets avec support des stockages (instance) */ +struct _GSecretStorage +{ +    GObject parent;                         /* A laisser en premier        */ + +    GSettings *settings;                    /* Configuration sollicitée    */ + +    void *master_key;                       /* Clef déverrouillée          */ + +}; + +/* Gardien des secrets avec support des stockages (classe) */ +struct _GSecretStorageClass +{ +    GObjectClass parent;                    /* A laisser en premier        */ + +    /* Signaux */ + +    void (* lock_update) (GSecretStorage *); + +}; + + +/* Met en place un gardien des secrets avec support de stockage. */ +bool g_secret_storage_create(GSecretStorage *, GSettings *); + + + +#endif  /* _GLIBEXT_SECSTORAGE_INT_H */ diff --git a/src/glibext/secstorage.c b/src/glibext/secstorage.c new file mode 100644 index 0000000..161214c --- /dev/null +++ b/src/glibext/secstorage.c @@ -0,0 +1,950 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * secstorage.c - conservation sécurisée d'éléments de configuration + * + * 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/>. + */ + + +#include "secstorage.h" + + +#include <assert.h> +#include <string.h> +#include <openssl/evp.h> +#include <openssl/rand.h> + + +#include "secstorage-int.h" +#include "../core/logs.h" + + + +/** + * Les mécanismes de hachage de mot de passe doivent être utilisés avec un sel, + * et la longueur du sel doit être d’au moins 128 bits. + * + * Cette note concerne le hachage de mots de passe et non la dérivation de secrets + * cependant. + * + * Source : https://cyber.gouv.fr/sites/default/files/2021/03/anssi-guide-selection_crypto-1.0.pdf + */ + +#define SECRET_STORAGE_SALT_SIZE (256 / 8) + + +/** + * Nombre d'itérations pour PBKDF2 : en 2023, OWASP recommande 600000 itérations + * pour PBKDF2-HMAC-SHA256 (et 210000 pour PBKDF2-HMAC-SHA512). + * + * Source : https://cheatsheetseries.owasp.org/cheatsheets/Password_Storage_Cheat_Sheet.html#pbkdf2 + */ + +#define PBKDF2_HMAC_SHA256_ITERATIONS (2 << 20) + + +/** + * AES 256 : clef de 256 bits, IV de 128 bits + */ + +#define SECRET_STORAGE_KEK_SIZE (256 / 8) + +#define SECRET_STORAGE_KEY_SIZE (256 / 8) + +#define SECRET_STORAGE_BLOCK_SIZE (128 / 8) + +#define SECRET_STORAGE_IV_SIZE SECRET_STORAGE_BLOCK_SIZE + + + +/* Initialise la classe des stockages de secrets. */ +static void g_secret_storage_class_init(GSecretStorageClass *); + +/* Initialise une instance de stockage de secrets. */ +static void g_secret_storage_init(GSecretStorage *); + +/* Supprime toutes les références externes. */ +static void g_secret_storage_dispose(GObject *); + +/* Procède à la libération totale de la mémoire. */ +static void g_secret_storage_finalize(GObject *); + +/* Teste un mot de passe par Déverrouillage de clef maître. */ +static bool g_secret_storage_check_primary_password(GSecretStorage *, const char *, void **); + + + +/* Indique le type défini pour un gardien des secrets avec support des stockages. */ +G_DEFINE_TYPE(GSecretStorage, g_secret_storage, G_TYPE_OBJECT); + + +/****************************************************************************** +*                                                                             * +*  Paramètres  : klass = classe à initialiser.                                * +*                                                                             * +*  Description : Initialise la classe des stockages de secrets.               * +*                                                                             * +*  Retour      : -                                                            * +*                                                                             * +*  Remarques   : -                                                            * +*                                                                             * +******************************************************************************/ + +static void g_secret_storage_class_init(GSecretStorageClass *klass) +{ +    GObjectClass *object;                   /* Autre version de la classe  */ + +    object = G_OBJECT_CLASS(klass); + +    object->dispose = g_secret_storage_dispose; +    object->finalize = g_secret_storage_finalize; + +    g_signal_new("lock-update", +                 G_TYPE_SECRET_STORAGE, +                 G_SIGNAL_RUN_LAST, +                 G_STRUCT_OFFSET(GSecretStorageClass, lock_update), +                 NULL, NULL, +                 g_cclosure_marshal_VOID__VOID, +                 G_TYPE_NONE, 0); + +} + + +/****************************************************************************** +*                                                                             * +*  Paramètres  : storage = instance à initialiser.                            * +*                                                                             * +*  Description : Initialise une instance de stockage de secrets.              * +*                                                                             * +*  Retour      : -                                                            * +*                                                                             * +*  Remarques   : -                                                            * +*                                                                             * +******************************************************************************/ + +static void g_secret_storage_init(GSecretStorage *storage) +{ +    storage->settings = NULL; + +    storage->master_key = NULL; + +} + + +/****************************************************************************** +*                                                                             * +*  Paramètres  : object = instance d'objet GLib à traiter.                    * +*                                                                             * +*  Description : Supprime toutes les références externes.                     * +*                                                                             * +*  Retour      : -                                                            * +*                                                                             * +*  Remarques   : -                                                            * +*                                                                             * +******************************************************************************/ + +static void g_secret_storage_dispose(GObject *object) +{ +    GSecretStorage *storage;                /* Version spécialisée         */ + +    storage = G_SECRET_STORAGE(object); + +    g_clear_object(&storage->settings); + +    G_OBJECT_CLASS(g_secret_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_secret_storage_finalize(GObject *object) +{ +    GSecretStorage *storage;                /* Version spécialisée         */ + +    storage = G_SECRET_STORAGE(object); + +    if (storage->master_key != NULL) +        free(storage->master_key); + +    G_OBJECT_CLASS(g_secret_storage_parent_class)->finalize(object); + +} + + +/****************************************************************************** +*                                                                             * +*  Paramètres  : settings = éventuel espace de configuration à utiliser.      * +*                                                                             * +*  Description : Créé un nouveau gardien des secrets avec support de stockage.* +*                                                                             * +*  Retour      : Gestionnaire de stockage sécurisé mis en place.              * +*                                                                             * +*  Remarques   : -                                                            * +*                                                                             * +******************************************************************************/ + +GSecretStorage *g_secret_storage_new(GSettings *settings) +{ +    GSecretStorage *result;                 /* Instance à retourner        */ + +    result = g_object_new(G_TYPE_SECRET_STORAGE, NULL); + +    if (!g_secret_storage_create(result, settings)) +        g_clear_object(&result); + +    return result; + +} + + +/****************************************************************************** +*                                                                             * +*  Paramètres  : storage  = stockage sécurisé à initialiser.                  * +*                settings = éventuel espace de configuration à utiliser.      * +*                                                                             * +*  Description : Met en place un gardien des secrets avec support de stockage.* +*                                                                             * +*  Retour      : Bilan de l'opération.                                        * +*                                                                             * +*  Remarques   : -                                                            * +*                                                                             * +******************************************************************************/ + +bool g_secret_storage_create(GSecretStorage *storage, GSettings *settings) +{ +    bool result;                            /* Bilan à retourner           */ + +    result = true; + +    if (settings != NULL) +    { +        ref_object(settings); +        storage->settings = settings; +    } +    else +        storage->settings = g_settings_new("re.chrysalide.framework.secstorage"); + +    return result; + +} + + +/****************************************************************************** +*                                                                             * +*  Paramètres  : storage = espace de stockage sécurisé à consulter.           * +*                                                                             * +*  Description : Détermine si une clef de chiffrement protégée est en place.  * +*                                                                             * +*  Retour      : Bilan de l'analyse.                                          * +*                                                                             * +*  Remarques   : -                                                            * +*                                                                             * +******************************************************************************/ + +bool g_secret_storage_has_key(const GSecretStorage *storage) +{ +    bool result;                            /* Bilan à retourner           */ +    GVariant *value;                        /* Valeur de configuration     */ +    gsize length;                           /* Taille d'une valeur donnée  */ + +    result = false; + +    value = g_settings_get_value(storage->settings, "master"); + +    g_variant_get_fixed_array(value, &length, 1); + +    result = (length > SECRET_STORAGE_IV_SIZE); + +    g_variant_unref(value); + +    return result;; + +} + + +/****************************************************************************** +*                                                                             * +*  Paramètres  : storage  = espace de stockage sécurisé à consulter.          * +*                password = mot de passe principal à appliquer.               * +*                                                                             * +*  Description : Définit un mot de passe pour protéger une clef maître.       * +*                                                                             * +*  Retour      : Bilan de la mise en place.                                   * +*                                                                             * +*  Remarques   : -                                                            * +*                                                                             * +******************************************************************************/ + +bool g_secret_storage_set_password(GSecretStorage *storage, const char *passwd) +{ +    bool result;                            /* Bilan à retourner           */ +    unsigned char salt[SECRET_STORAGE_SALT_SIZE]; /* Sel pour la dérivation*/ +    int ret;                                /* Bilan à d'un appel          */ +    GVariant *value;                        /* Valeur de configuration     */ +    unsigned char kek[SECRET_STORAGE_KEK_SIZE]; /* Clef de protection      */ +    unsigned char key[SECRET_STORAGE_KEY_SIZE]; /* Clef maître             */ +    unsigned char iv[SECRET_STORAGE_IV_SIZE]; /* IV associé                */ +    EVP_CIPHER_CTX *ctx;                    /* Contexte pour le chiffrement*/ +    unsigned char encrypted[64];            /* Partie chiffrée à conserver */ +    unsigned char *iter;                    /* Tête d'écriture             */ +    int outlen;                             /* Taille des données utiles   */ + +    result = false; + +    if (g_secret_storage_has_key(storage)) +        goto exit; + +    /* Création d'un sel pour la dérivation du mot de passe */ + +    ret = RAND_bytes(salt, sizeof(salt)); +    if (ret != 1) +    { +        LOG_ERROR_OPENSSL; +        goto exit; +    } + +    /** +     * La fonction g_variant_new_fixed_array() retourne un variant +     * avec un décompte de référence flottant. +     */ + +    value = g_variant_new_fixed_array(G_VARIANT_TYPE_BYTE, +                                      salt, SECRET_STORAGE_SALT_SIZE, sizeof(unsigned char)); + +    /** +     * Comme le variant à une référence flottante, la fonction +     * g_settings_set_value() consomme cette référence. +     * +     * Il n'y a donc pas lieu d'appeler g_variant_unref(). +     */ + +    g_settings_set_value(storage->settings, "salt", value); + +    /* Dérivation du mot de passe */ + +    ret = PKCS5_PBKDF2_HMAC(passwd, strlen(passwd), +                            salt, SECRET_STORAGE_SALT_SIZE, +                            PBKDF2_HMAC_SHA256_ITERATIONS, EVP_sha256(), +                            SECRET_STORAGE_KEK_SIZE, kek); + +    if (ret != 1) +    { +        LOG_ERROR_OPENSSL; +        goto exit; +    } + +    /* Définition de la clef maître et de son IV de chiffrement */ + +    ret = RAND_bytes(key, sizeof(key)); +    if (ret != 1) +    { +        LOG_ERROR_OPENSSL; +        goto exit; +    } + +    ret = RAND_bytes(iv, sizeof(iv)); +    if (ret != 1) +    { +        LOG_ERROR_OPENSSL; +        goto exit; +    } + +    /* Chiffrement de la clef maître */ + +    ctx	= EVP_CIPHER_CTX_new(); + +    if (ctx == NULL) +    { +        LOG_ERROR_OPENSSL; +        goto exit; +    } + +    EVP_CIPHER_CTX_set_flags(ctx, EVP_CIPHER_CTX_FLAG_WRAP_ALLOW); + +    ret = EVP_EncryptInit_ex2(ctx, EVP_aes_256_wrap_pad(), kek, iv, NULL); +    if (ret != 1) +    { +        LOG_ERROR_OPENSSL; +        goto exit_with_ctx; +    } + +    memcpy(encrypted, iv, SECRET_STORAGE_IV_SIZE); + +    iter = encrypted + SECRET_STORAGE_IV_SIZE; + +    ret = EVP_EncryptUpdate(ctx, iter, &outlen, key, SECRET_STORAGE_KEY_SIZE); +    if (ret != 1) +    { +        LOG_ERROR_OPENSSL; +        goto exit_with_ctx; +    } + +    iter += outlen; + +    ret = EVP_EncryptFinal_ex(ctx, iter, &outlen); +    if (ret != 1) +    { +        LOG_ERROR_OPENSSL; +        goto exit_with_ctx; +    } + +    iter += outlen; + +    assert((iter - encrypted) < 64); + +    /* Conservation de la clef protégée */ + +    value = g_variant_new_fixed_array(G_VARIANT_TYPE_BYTE, +                                      encrypted, iter - encrypted, sizeof(unsigned char)); + +    g_settings_set_value(storage->settings, "master", value); + +    g_signal_emit_by_name(storage, "lock-update"); + +    result = true; + + exit_with_ctx: + +    EVP_CIPHER_CTX_free(ctx); + + exit: + +    return result; + +} + + +/****************************************************************************** +*                                                                             * +*  Paramètres  : storage = espace de stockage sécurisé à consulter.           * +*                old     = ancien mot de passe principal à vérifier.          * +*                new     = nouveau mot de passe principal à appliquer.        * +*                                                                             * +*  Description : Modifie le mot de passe protégeant une clef maître.          * +*                                                                             * +*  Retour      : Bilan de la mise en place.                                   * +*                                                                             * +*  Remarques   : -                                                            * +*                                                                             * +******************************************************************************/ + +bool g_secret_storage_change_password(GSecretStorage *storage, const char *old, const char *new) +{ +    bool result;                            /* Bilan à retourner           */ + +    result = false; + +    if (!g_secret_storage_has_key(storage)) +        goto exit; + +    if (!g_secret_storage_check_primary_password(storage, old, NULL)) +        goto exit; + +    if (!g_secret_storage_is_locked(storage)) +        g_secret_storage_lock(storage); + +    g_settings_reset(storage->settings, "salt"); +    g_settings_reset(storage->settings, "master"); + +    result = g_secret_storage_set_password(storage, new); + + exit: + +    return result; + +} + + +/****************************************************************************** +*                                                                             * +*  Paramètres  : storage  = espace de stockage sécurisé à consulter.          * +*                password = mot de passe principal à appliquer.               * +*                                                                             * +*  Description : Supprime le mot de passe protégeant une clef maître.         * +*                                                                             * +*  Retour      : Bilan de la mise en place.                                   * +*                                                                             * +*  Remarques   : -                                                            * +*                                                                             * +******************************************************************************/ + +bool g_secret_storage_remove_password(GSecretStorage *storage, const char *passwd) +{ +    bool result;                            /* Bilan à retourner           */ + +    result = false; + +    if (!g_secret_storage_has_key(storage)) +        goto exit; + +    if (!g_secret_storage_check_primary_password(storage, passwd, NULL)) +        goto exit; + +    if (!g_secret_storage_is_locked(storage)) +        g_secret_storage_lock(storage); + +    g_settings_reset(storage->settings, "salt"); +    g_settings_reset(storage->settings, "master"); + +    g_signal_emit_by_name(storage, "lock-update"); + +    result = true; + + exit: + +    return result; + +} + + +/****************************************************************************** +*                                                                             * +*  Paramètres  : storage = espace de stockage sécurisé à consulter.           * +*                                                                             * +*  Description : Détermine si la clef de chiffrement maître est vérouillée.   * +*                                                                             * +*  Retour      : Bilan de la détermination.                                   * +*                                                                             * +*  Remarques   : -                                                            * +*                                                                             * +******************************************************************************/ + +bool g_secret_storage_is_locked(const GSecretStorage *storage) +{ +    bool result;                            /* Bilan à retourner           */ + +    result = (storage->master_key == NULL); + +    return result; + +} + + +/****************************************************************************** +*                                                                             * +*  Paramètres  : storage  = espace de stockage sécurisé à manipuler.          * +*                password = mot de passe principal à utiliser.                * +*                master   = éventuelle adresse pour un stockage de clef. [OUT]* +*                                                                             * +*  Description : Teste un mot de passe par Déverrouillage de clef maître.     * +*                                                                             * +*  Retour      : Bilan de l'opération.                                        * +*                                                                             * +*  Remarques   : -                                                            * +*                                                                             * +******************************************************************************/ + +static bool g_secret_storage_check_primary_password(GSecretStorage *storage, const char *passwd, void **master) +{ +    bool result;                            /* Bilan à retourner           */ +    GVariant *salt_value;                   /* Valeur du sel configuré     */ +    gsize salt_length;                      /* Taille du sel conservé      */ +    gconstpointer salt;                     /* Données associées #1        */ +    unsigned char kek[SECRET_STORAGE_KEK_SIZE]; /* Clef de protection      */ +    int ret;                                /* Bilan à d'un appel          */ +    GVariant *enc_value;                    /* Paramètres de chiffrement   */ +    gsize enc_length;                       /* Taille de ces paramètrs     */ +    gconstpointer encrypted;                /* Données associées #2        */ +    EVP_CIPHER_CTX *ctx;                    /* Contexte de déchiffrement   */ +    unsigned char iv[SECRET_STORAGE_IV_SIZE]; /* IV associé                */ +    unsigned char key[SECRET_STORAGE_KEY_SIZE]; /* Clef maître             */ +    unsigned char *iter;                    /* Tête d'écriture             */ +    int outlen;                             /* Taille des données utiles   */ + +    result = false; + +    if (!g_secret_storage_is_locked(storage)) +    { +        result = true; +        goto quick_exit; +    } + +    /* Récupération du sel mis en place */ + +    salt_value = g_settings_get_value(storage->settings, "salt"); + +    salt = g_variant_get_fixed_array(salt_value, &salt_length, sizeof(bin_t)); + +    if (salt_length != SECRET_STORAGE_SALT_SIZE) +        goto exit_with_salt; + +    /* Dérivation du mot de passe */ + +    ret = PKCS5_PBKDF2_HMAC(passwd, strlen(passwd), +                            salt, SECRET_STORAGE_SALT_SIZE, +                            PBKDF2_HMAC_SHA256_ITERATIONS, EVP_sha256(), +                            SECRET_STORAGE_KEK_SIZE, kek); + +    if (ret != 1) +    { +        LOG_ERROR_OPENSSL; +        goto exit_with_salt; +    } + +    /* Récupération des paramètres chiffrés */ + +    enc_value = g_settings_get_value(storage->settings, "master"); + +    encrypted = g_variant_get_fixed_array(enc_value, &enc_length, sizeof(bin_t)); + +    if (enc_length <= SECRET_STORAGE_IV_SIZE) +        goto exit_with_enc; + +    /* Déhiffrement de la clef maître */ + +    ctx	= EVP_CIPHER_CTX_new(); + +    if (ctx == NULL) +    { +        LOG_ERROR_OPENSSL; +        goto exit_with_enc; +    } + +    EVP_CIPHER_CTX_set_flags(ctx, EVP_CIPHER_CTX_FLAG_WRAP_ALLOW); + +    memcpy(iv, encrypted, SECRET_STORAGE_IV_SIZE); + +    ret = EVP_DecryptInit_ex2(ctx, EVP_aes_256_wrap_pad(), kek, iv, NULL); +    if (ret != 1) +    { +        LOG_ERROR_OPENSSL; +        goto exit_with_ctx; +    } + +    iter = key; + +    ret = EVP_DecryptUpdate(ctx, iter, &outlen, +                            ((unsigned char *)encrypted) + SECRET_STORAGE_IV_SIZE, +                            enc_length - SECRET_STORAGE_IV_SIZE); +    if (ret != 1) +    { +        LOG_ERROR_OPENSSL; +        goto exit_with_ctx; +    } + +    iter += outlen; + +    ret = EVP_DecryptFinal_ex(ctx, iter, &outlen); +    if (ret != 1) +    { +        LOG_ERROR_OPENSSL; +        goto exit_with_ctx; +    } + +    assert((iter - key) == SECRET_STORAGE_KEY_SIZE); + +    /* Stockage de la clef maître en mémoire */ + +    if (master != NULL) +    { +        *master = malloc(SECRET_STORAGE_KEY_SIZE); +        memcpy(*master, key, SECRET_STORAGE_KEY_SIZE); +    } + +    result = true; + +    /* Sortie */ + + exit_with_ctx: + +    EVP_CIPHER_CTX_free(ctx); + + exit_with_enc: + +    g_variant_unref(enc_value); + + exit_with_salt: + +    g_variant_unref(salt_value); + + quick_exit: + +    return result; + +} + + +/****************************************************************************** +*                                                                             * +*  Paramètres  : storage  = espace de stockage sécurisé à manipuler.          * +*                password = mot de passe principal à utiliser.                * +*                                                                             * +*  Description : Déverrouille la clef de chiffrement maître.                  * +*                                                                             * +*  Retour      : Bilan de l'opération.                                        * +*                                                                             * +*  Remarques   : -                                                            * +*                                                                             * +******************************************************************************/ + +bool g_secret_storage_unlock(GSecretStorage *storage, const char *passwd) +{ +    bool result;                            /* Bilan à retourner           */ + +    result = g_secret_storage_check_primary_password(storage, passwd, &storage->master_key); + +    if (result) +        g_signal_emit_by_name(storage, "lock-update"); + +    return result; + +} + + +/****************************************************************************** +*                                                                             * +*  Paramètres  : storage = espace de stockage sécurisé à manipuler.           * +*                                                                             * +*  Description : Verrouille la clef de chiffrement maître.                    * +*                                                                             * +*  Retour      : -                                                            * +*                                                                             * +*  Remarques   : -                                                            * +*                                                                             * +******************************************************************************/ + +void g_secret_storage_lock(GSecretStorage *storage) +{ +    if (storage->master_key != NULL) +    { +        free(storage->master_key); +        storage->master_key = NULL; + +        g_signal_emit_by_name(storage, "lock-update"); + +    } + +} + + +/****************************************************************************** +*                                                                             * +*  Paramètres  : storage = espace de stockage sécurisé à consulter.           * +*                in      = séquence d'octets à traiter.                       * +*                out     = séquence d'octets résultantes. [OUT]               * +*                                                                             * +*  Description : Chiffre des données avec la clef de chiffrement maître.      * +*                                                                             * +*  Retour      : Bilan de l'opération.                                        * +*                                                                             * +*  Remarques   : -                                                            * +*                                                                             * +******************************************************************************/ + +bool g_secret_storage_encrypt_data(const GSecretStorage *storage, const sized_binary_t *in, sized_binary_t *out) +{ +    bool result;                            /* Bilan à retourner           */ +    unsigned char iv[SECRET_STORAGE_IV_SIZE]; /* IV associé                */ +    int ret;                                /* Bilan à d'un appel          */ +    EVP_CIPHER_CTX *ctx;                    /* Contexte pour le chiffrement*/ +    size_t needed;                          /* Taille de la sortie         */ +    unsigned char *iter;                    /* Tête d'écriture             */ +    int outlen;                             /* Taille des données utiles   */ + +    result = false; + +    if (g_secret_storage_is_locked(storage)) +        goto quick_exit; + +    /* Récupération de la clef maître et d'un IV de chiffrement */ + +    ret = RAND_bytes(iv, sizeof(iv)); +    if (ret != 1) +    { +        LOG_ERROR_OPENSSL; +        goto exit; +    } + +    /* Préparation de la zone de réception */ + +    needed = SECRET_STORAGE_IV_SIZE + ((in->size / SECRET_STORAGE_BLOCK_SIZE) + 1) * SECRET_STORAGE_BLOCK_SIZE; + +    setup_sized_binary(out, needed); + +    /* Chiffrement des données */ + +    ctx	= EVP_CIPHER_CTX_new(); + +    if (ctx == NULL) +    { +        LOG_ERROR_OPENSSL; +        goto exit; +    } + +    ret = EVP_EncryptInit_ex2(ctx, EVP_aes_256_cbc(), storage->master_key, iv, NULL); +    if (ret != 1) +    { +        LOG_ERROR_OPENSSL; +        goto exit_with_ctx; +    } + +    memcpy(out->data, iv, SECRET_STORAGE_IV_SIZE); + +    iter = out->bin_data + SECRET_STORAGE_IV_SIZE; + +    ret = EVP_EncryptUpdate(ctx, iter, &outlen, in->bin_data, in->size); +    if (ret != 1) +    { +        LOG_ERROR_OPENSSL; +        goto exit_with_ctx; +    } + +    iter += outlen; + +    ret = EVP_EncryptFinal_ex(ctx, iter, &outlen); +    if (ret != 1) +    { +        LOG_ERROR_OPENSSL; +        goto exit_with_ctx; +    } + +    iter += outlen; + +    assert((iter - out->bin_data) == out->size); + +    result = true; + +    /* Sortie */ + + exit_with_ctx: + +    EVP_CIPHER_CTX_free(ctx); + +    if (!result) +        exit_sized_binary(out); + + exit: + quick_exit: + +    return result; + +} + + +/****************************************************************************** +*                                                                             * +*  Paramètres  : storage = espace de stockage sécurisé à consulter.           * +*                in      = séquence d'octets à traiter.                       * +*                out     = séquence d'octets résultantes. [OUT]               * +*                                                                             * +*  Description : Déchiffre des données avec la clef de chiffrement maître.    * +*                                                                             * +*  Retour      : Bilan de l'opération.                                        * +*                                                                             * +*  Remarques   : -                                                            * +*                                                                             * +******************************************************************************/ + +bool g_secret_storage_decrypt_data(const GSecretStorage *storage, const sized_binary_t *in, sized_binary_t *out) +{ +    bool result;                            /* Bilan à retourner           */ +    unsigned char iv[SECRET_STORAGE_IV_SIZE]; /* IV associé                */ +    int ret;                                /* Bilan à d'un appel          */ +    EVP_CIPHER_CTX *ctx;                    /* Contexte pour le chiffrement*/ +    size_t needed;                          /* Taille de la sortie         */ +    unsigned char *iter;                    /* Tête d'écriture             */ +    int outlen;                             /* Taille des données utiles   */ + +    result = false; + +    if (g_secret_storage_is_locked(storage)) +        goto quick_exit; + +    /* Récupération d'un IV de déchiffrement */ + +    if (in->size < SECRET_STORAGE_IV_SIZE) +        goto exit; + +    memcpy(iv, in->data, SECRET_STORAGE_IV_SIZE); + +    /* Préparation de la zone de réception */ + +    needed = in->size - SECRET_STORAGE_IV_SIZE; + +    setup_sized_binary(out, needed); + +    /* Chiffrement des données */ + +    ctx	= EVP_CIPHER_CTX_new(); + +    if (ctx == NULL) +    { +        LOG_ERROR_OPENSSL; +        goto exit; +    } + +    ret = EVP_DecryptInit_ex2(ctx, EVP_aes_256_cbc(), storage->master_key, iv, NULL); +    if (ret != 1) +    { +        LOG_ERROR_OPENSSL; +        goto exit_with_ctx; +    } + +    iter = out->bin_data; + +    ret = EVP_DecryptUpdate(ctx, iter, &outlen, +                            in->bin_data + SECRET_STORAGE_IV_SIZE, in->size - SECRET_STORAGE_IV_SIZE); +    if (ret != 1) +    { +        LOG_ERROR_OPENSSL; +        goto exit_with_ctx; +    } + +    iter += outlen; + +    ret = EVP_DecryptFinal_ex(ctx, iter, &outlen); +    if (ret != 1) +    { +        LOG_ERROR_OPENSSL; +        goto exit_with_ctx; +    } + +    iter += outlen; + +    assert((iter - out->bin_data) <= out->size); + +    resize_sized_binary(out, iter - out->bin_data); + +    result = true; + +    /* Sortie */ + + exit_with_ctx: + +    EVP_CIPHER_CTX_free(ctx); + +    if (!result) +        exit_sized_binary(out); + + exit: + quick_exit: + +    return result; + +} diff --git a/src/glibext/secstorage.h b/src/glibext/secstorage.h new file mode 100644 index 0000000..ed3f79c --- /dev/null +++ b/src/glibext/secstorage.h @@ -0,0 +1,74 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * secstorage.h - prototypes pour la conservation sécurisée d'éléments de configuration + * + * 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_SECSTORAGE_H +#define _GLIBEXT_SECSTORAGE_H + + +#include <stdbool.h> +#include <gio/gio.h> + + +#include "helpers.h" +#include "../common/szbin.h" + + + +#define G_TYPE_SECRET_STORAGE (g_secret_storage_get_type()) + +DECLARE_GTYPE(GSecretStorage, g_secret_storage, G, SECRET_STORAGE); + + +/* Créé un nouveau gardien des secrets avec support de stockage. */ +GSecretStorage *g_secret_storage_new(GSettings *); + +/* Détermine si une clef de chiffrement protégée est en place. */ +bool g_secret_storage_has_key(const GSecretStorage *); + +/* Définit un mot de passe pour protéger une clef maître. */ +bool g_secret_storage_set_password(GSecretStorage *, const char *); + +/* Modifie le mot de passe protégeant une clef maître. */ +bool g_secret_storage_change_password(GSecretStorage *, const char *, const char *); + +/* Supprime le mot de passe protégeant une clef maître. */ +bool g_secret_storage_remove_password(GSecretStorage *, const char *); + +/* Détermine si la clef de chiffrement maître est vérouillée. */ +bool g_secret_storage_is_locked(const GSecretStorage *); + +/* Déverrouille la clef de chiffrement maître. */ +bool g_secret_storage_unlock(GSecretStorage *, const char *); + +/* Verrouille la clef de chiffrement maître. */ +void g_secret_storage_lock(GSecretStorage *); + +/* Chiffre des données avec la clef de chiffrement maître. */ +bool g_secret_storage_encrypt_data(const GSecretStorage *, const sized_binary_t *, sized_binary_t *); + +/* Déchiffre des données avec la clef de chiffrement maître. */ +bool g_secret_storage_decrypt_data(const GSecretStorage *, const sized_binary_t *, sized_binary_t *); + + + +#endif  /* _GLIBEXT_SECSTORAGE_H */ diff --git a/src/analysis/storage/serialize-int.h b/src/glibext/serialize-int.h index de8d3e3..df9c597 100644 --- a/src/analysis/storage/serialize-int.h +++ b/src/glibext/serialize-int.h @@ -2,7 +2,7 @@  /* Chrysalide - Outil d'analyse de fichiers binaires   * serialize-int.h - définitions internes propres aux objets entreposables dans un cache   * - * Copyright (C) 2020 Cyrille Bagard + * Copyright (C) 2020-2025 Cyrille Bagard   *   *  This file is part of Chrysalide.   * @@ -21,8 +21,8 @@   */ -#ifndef _ANALYSIS_STORAGE_SERIALIZE_INT_H -#define _ANALYSIS_STORAGE_SERIALIZE_INT_H +#ifndef _GLIBEXT_SERIALIZE_INT_H +#define _GLIBEXT_SERIALIZE_INT_H  #include "serialize.h" @@ -33,14 +33,14 @@  /* Charge un objet depuis une mémoire tampon. */ -typedef bool (* load_serializable_object_cb) (GSerializableObject *, GObjectStorage *, packed_buffer_t *); +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 *, packed_buffer_t *); +typedef bool (* store_serializable_object_cb) (const GSerializableObject *, GObjectStorage *, int);  /* Intermédiaire pour la mise en cache d'objet (interface) */ -struct _GSerializableObjectIface +struct _GSerializableObjectInterface  {      GTypeInterface base_iface;              /* A laisser en premier        */ @@ -50,9 +50,5 @@ struct _GSerializableObjectIface  }; -/* Redéfinition */ -typedef GSerializableObjectIface GSerializableObjectInterface; - - -#endif  /* _ANALYSIS_STORAGE_SERIALIZE_INT_H */ +#endif  /* _GLIBEXT_SERIALIZE_INT_H */ diff --git a/src/analysis/storage/serialize.c b/src/glibext/serialize.c index d1b0502..b43f0c2 100644 --- a/src/analysis/storage/serialize.c +++ b/src/glibext/serialize.c @@ -2,7 +2,7 @@  /* Chrysalide - Outil d'analyse de fichiers binaires   * serialize.h - objets entreposables dans un cache   * - * Copyright (C) 2020 Cyrille Bagard + * Copyright (C) 2020-2025 Cyrille Bagard   *   *  This file is part of Chrysalide.   * @@ -51,6 +51,8 @@ G_DEFINE_INTERFACE(GSerializableObject, g_serializable_object, G_TYPE_OBJECT)  static void g_serializable_object_default_init(GSerializableObjectInterface *iface)  { +    iface->load = NULL; +    iface->store = NULL;  } @@ -58,10 +60,10 @@ static void g_serializable_object_default_init(GSerializableObjectInterface *ifa  /******************************************************************************  *                                                                             *  *  Paramètres  : object  = élément GLib à constuire.                          * -*                storage = conservateur de données à manipuler ou NULL.       * -*                pbuf    = zone tampon à lire.                                * +*                storage = conservateur de données à manipuler.               * +*                fd      = flux ouvert en lecture.                            *  *                                                                             * -*  Description : Charge un objet depuis une mémoire tampon.                   * +*  Description : Charge un objet depuis un flux de données.                   *  *                                                                             *  *  Retour      : Bilan de l'opération.                                        *  *                                                                             * @@ -69,14 +71,14 @@ static void g_serializable_object_default_init(GSerializableObjectInterface *ifa  *                                                                             *  ******************************************************************************/ -bool g_serializable_object_load(GSerializableObject *object, GObjectStorage *storage, packed_buffer_t *pbuf) +bool g_serializable_object_load(GSerializableObject *object, GObjectStorage *storage, int fd)  {      bool result;                            /* Bilan à retourner           */ -    GSerializableObjectIface *iface;        /* Interface utilisée          */ +    GSerializableObjectInterface *iface;    /* Interface utilisée          */      iface = G_SERIALIZABLE_OBJECT_GET_IFACE(object); -    result = iface->load(object, storage, pbuf); +    result = iface->load(object, storage, fd);      return result; @@ -86,10 +88,10 @@ bool g_serializable_object_load(GSerializableObject *object, GObjectStorage *sto  /******************************************************************************  *                                                                             *  *  Paramètres  : object  = élément GLib à consulter.                          * -*                storage = conservateur de données à manipuler ou NULL.       * -*                pbuf    = zone tampon à remplir.                             * +*                storage = conservateur de données à manipuler.               * +*                fd      = flux ouvert en écriture.                           *  *                                                                             * -*  Description : Sauvegarde un objet dans une mémoire tampon.                 * +*  Description : Sauvegarde un objet dans un flux de données.                 *  *                                                                             *  *  Retour      : Bilan de l'opération.                                        *  *                                                                             * @@ -97,14 +99,14 @@ bool g_serializable_object_load(GSerializableObject *object, GObjectStorage *sto  *                                                                             *  ******************************************************************************/ -bool g_serializable_object_store(const GSerializableObject *object, GObjectStorage *storage, packed_buffer_t *pbuf) +bool g_serializable_object_store(const GSerializableObject *object, GObjectStorage *storage, int fd)  {      bool result;                            /* Bilan à retourner           */ -    GSerializableObjectIface *iface;        /* Interface utilisée          */ +    GSerializableObjectInterface *iface;    /* Interface utilisée          */      iface = G_SERIALIZABLE_OBJECT_GET_IFACE(object); -    result = iface->store(object, storage, pbuf); +    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-int.h b/src/glibext/singleton-int.h index 3db17f9..747e64a 100644 --- a/src/glibext/singleton-int.h +++ b/src/glibext/singleton-int.h @@ -2,7 +2,7 @@  /* Chrysalide - Outil d'analyse de fichiers binaires   * singleton-int.h - définitions internes propres aux réductions du nombre d'instances d'un même type   * - * Copyright (C) 2021 Cyrille Bagard + * Copyright (C) 2021-2024 Cyrille Bagard   *   *  This file is part of Chrysalide.   * @@ -29,44 +29,61 @@ +/* ------------------ INTERFACE POUR CANDIDAT A UNE CENTRALISATION ------------------ */ + +  /* Fournit une liste de candidats embarqués par un candidat. */  typedef GSingletonCandidate ** (* list_inner_instances_fc) (const GSingletonCandidate *, size_t *);  /* Met à jour une liste de candidats embarqués par un candidat. */  typedef void (* update_inner_instances_fc) (GSingletonCandidate *, GSingletonCandidate **, size_t); -/* Fournit l'empreinte d'un candidat à une centralisation. */ -typedef guint (* hash_candidate_fc) (const GSingletonCandidate *); - -/* Détermine si deux candidats à l'unicité sont identiques. */ -typedef gboolean (* is_candidate_equal_fc) (const GSingletonCandidate *, const GSingletonCandidate *); -  /* Marque un candidat comme figé. */ -typedef void (* set_candidate_ro_fc) (GSingletonCandidate *); +typedef void (* mark_candidate_as_ro_fc) (GSingletonCandidate *);  /* Indique si le candidat est figé. */  typedef bool (* is_candidate_ro_fc) (const GSingletonCandidate *); +/* Crée une copie modifiable d'un object unique. */ +typedef GSingletonCandidate * (* dup_candidate_fc) (const GSingletonCandidate *); +  /* Instance d'objet visant à être unique (interface) */ -struct _GSingletonCandidateIface +struct _GSingletonCandidateInterface  {      GTypeInterface base_iface;              /* A laisser en premier        */      list_inner_instances_fc list_inner;     /* Récupération d'internes     */      update_inner_instances_fc update_inner; /* Mise à jour des éléments    */ -    hash_candidate_fc hash;                 /* Prise d'empreinte           */ -    is_candidate_equal_fc is_equal;         /* Comparaison                 */ - -    set_candidate_ro_fc set_ro;             /* Bascule en mode figé        */ +    mark_candidate_as_ro_fc mark_as_ro;     /* Bascule en mode figé        */      is_candidate_ro_fc is_ro;               /* Consultation de l'état      */ +    dup_candidate_fc dup;                   /* Création de copie modifiable*/ + +}; + + + +/* ------------------------- COLLECTION D'INSTANCES UNIQUES ------------------------- */ + + +/* Définition d'un compacteur d'instances de types (instance) */ +struct _GSingletonFactory +{ +    GObject parent;                         /* A laisser en premier        */ + +    GHashTable *table;                      /* Suivi des conservations     */ +    GMutex access;                          /* Verrou pour la concurrence  */ +  }; +/* Définition d'un compacteur d'instances de types (classe) */ +struct _GSingletonFactoryClass +{ +    GObjectClass parent;                    /* A laisser en premier        */ -/* Redéfinition */ -typedef GSingletonCandidateIface GSingletonCandidateInterface; +}; diff --git a/src/glibext/singleton.c b/src/glibext/singleton.c index 78a3ad4..ed49934 100644 --- a/src/glibext/singleton.c +++ b/src/glibext/singleton.c @@ -2,7 +2,7 @@  /* Chrysalide - Outil d'analyse de fichiers binaires   * singleton.c - réduction du nombre d'instances d'un même type   * - * Copyright (C) 2021 Cyrille Bagard + * Copyright (C) 2021-2024 Cyrille Bagard   *   *  This file is part of Chrysalide.   * @@ -25,52 +25,35 @@  #include <assert.h> +#include <malloc.h> +#include "comparable.h" +#include "hashable.h"  #include "singleton-int.h"  /* ------------------ INTERFACE POUR CANDIDAT A UNE CENTRALISATION ------------------ */ +  /* Procède à l'initialisation de l'interface de rassemblement. */  static void g_singleton_candidate_default_init(GSingletonCandidateInterface *); +/* Fournit une liste de candidats embarqués par un candidat. */ +static GSingletonCandidate **g_singleton_candidate_list_inner_instances(const GSingletonCandidate *, size_t *); +  /* Met à jour une liste de candidats embarqués par un candidat. */  static void g_singleton_candidate_update_inner_instances(GSingletonCandidate *, GSingletonCandidate **, size_t); -/* Fournit l'empreinte d'un candidat à une centralisation. */ -static guint _g_singleton_candidate_hash(GSingletonCandidate *, GList **); - -/* Détermine si deux candidats à l'unicité sont identiques. */ -static gboolean _g_singleton_candidate_is_equal(GSingletonCandidate *, GSingletonCandidate *, GList **); -  /* Marque un candidat comme figé. */ -static void _g_singleton_candidate_set_read_only(GSingletonCandidate *, GList **); +static void g_singleton_candidate_mark_as_read_only(GSingletonCandidate *);  /* ------------------------- COLLECTION D'INSTANCES UNIQUES ------------------------- */ -/* Définition d'un compacteur d'instances de types (instance) */ -struct _GSingletonFactory -{ -    GObject parent;                         /* A laisser en premier        */ - -    GHashTable *table;                      /* Suivi des conservations     */ -    GMutex access;                          /* Verrou pour la concurrence  */ - -}; - -/* Définition d'un compacteur d'instances de types (classe) */ -struct _GSingletonFactoryClass -{ -    GObjectClass parent;                    /* A laisser en premier        */ - -}; - -  /* Initialise la classe des compacteurs d'instances de types. */  static void g_singleton_factory_class_init(GSingletonFactoryClass *); @@ -90,8 +73,10 @@ static void g_singleton_factory_finalize(GSingletonFactory *);  /* ---------------------------------------------------------------------------------- */ -/* Détermine le type d'une interface pour la lecture de binaire. */ -G_DEFINE_INTERFACE(GSingletonCandidate, g_singleton_candidate, G_TYPE_OBJECT) +/* 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_COMPARABLE_OBJECT); +                             g_type_interface_add_prerequisite(g_define_type_id, G_TYPE_HASHABLE_OBJECT))  /****************************************************************************** @@ -108,6 +93,13 @@ G_DEFINE_INTERFACE(GSingletonCandidate, g_singleton_candidate, G_TYPE_OBJECT)  static void g_singleton_candidate_default_init(GSingletonCandidateInterface *iface)  { +    iface->list_inner = NULL; +    iface->update_inner = NULL; + +    iface->mark_as_ro = NULL; +    iface->is_ro = NULL; + +    iface->dup = NULL;  } @@ -128,14 +120,17 @@ static void g_singleton_candidate_default_init(GSingletonCandidateInterface *ifa  GSingletonCandidate **g_singleton_candidate_list_inner_instances(const GSingletonCandidate *candidate, size_t *count)  {      GSingletonCandidate **result;           /* Instances à retourner       */ -    GSingletonCandidateIface *iface;        /* Interface utilisée          */ +    GSingletonCandidateInterface *iface;    /* Interface utilisée          */      iface = G_SINGLETON_CANDIDATE_GET_IFACE(candidate);      if (iface->list_inner == NULL)      { +        assert(iface->update_inner == NULL); +          *count = 0;          result = NULL; +      }      else @@ -162,7 +157,7 @@ GSingletonCandidate **g_singleton_candidate_list_inner_instances(const GSingleto  static void g_singleton_candidate_update_inner_instances(GSingletonCandidate *candidate, GSingletonCandidate **instances, size_t count)  { -    GSingletonCandidateIface *iface;        /* Interface utilisée          */ +    GSingletonCandidateInterface *iface;    /* Interface utilisée          */      iface = G_SINGLETON_CANDIDATE_GET_IFACE(candidate); @@ -181,82 +176,36 @@ static void g_singleton_candidate_update_inner_instances(GSingletonCandidate *ca  /******************************************************************************  *                                                                             *  *  Paramètres  : candidate = objet dont l'instance se veut unique.            * -*                processed = liste de candidats déjà traités.                 *  *                                                                             * -*  Description : Fournit l'empreinte d'un candidat à une centralisation.      * +*  Description : Marque un candidat comme figé.                               *  *                                                                             * -*  Retour      : Empreinte de l'élément représenté.                           * +*  Retour      : -                                                            *  *                                                                             *  *  Remarques   : -                                                            *  *                                                                             *  ******************************************************************************/ -static guint _g_singleton_candidate_hash(GSingletonCandidate *candidate, GList **processed) +static void g_singleton_candidate_mark_as_read_only(GSingletonCandidate *candidate)  { -    guint result;                           /* Valeur à retourner          */ -    GList *skip;                            /* Détection de boucle         */ -    GSingletonCandidateIface *iface;        /* Interface utilisée          */ +    GSingletonCandidateInterface *iface;    /* Interface utilisée          */      GSingletonCandidate **children;         /* Instances internes          */      size_t count;                           /* Quantité de ces instances   */      size_t i;                               /* Boucle de parcours          */ -    skip = g_list_find(*processed, candidate); - -    if (skip != NULL) -        result = 0; - -    else -    { -        iface = G_SINGLETON_CANDIDATE_GET_IFACE(candidate); - -        result = iface->hash(candidate); - -        *processed = g_list_append(*processed, candidate); - -        children = g_singleton_candidate_list_inner_instances(candidate, &count); +    iface = G_SINGLETON_CANDIDATE_GET_IFACE(candidate); -        for (i = 0; i < count; i++) -        { -            result ^= _g_singleton_candidate_hash(children[i], processed); -            g_object_unref(G_OBJECT(children[i])); -        } +    iface->mark_as_ro(candidate); -        if (children != NULL) -            free(children); +    children = g_singleton_candidate_list_inner_instances(candidate, &count); +    for (i = 0; i < count; i++) +    { +        g_singleton_candidate_mark_as_read_only(children[i]); +        unref_object(G_OBJECT(children[i]));      } -    return result; - -} - - -/****************************************************************************** -*                                                                             * -*  Paramètres  : candidate = objet dont l'instance se veut unique.            * -*                                                                             * -*  Description : Fournit l'empreinte d'un candidat à une centralisation.      * -*                                                                             * -*  Retour      : Empreinte de l'élément représenté.                           * -*                                                                             * -*  Remarques   : -                                                            * -*                                                                             * -******************************************************************************/ - -guint g_singleton_candidate_hash(GSingletonCandidate *candidate) -{ -    guint result;                           /* Valeur à retourner          */ -    GList *processed;                       /* Suivi des traitements       */ - -    processed = NULL; - -    result = _g_singleton_candidate_hash(candidate, &processed); - -    assert(processed != NULL); - -    g_list_free(processed); - -    return result; +    if (children != NULL) +        free(children);  } @@ -264,116 +213,43 @@ guint g_singleton_candidate_hash(GSingletonCandidate *candidate)  /******************************************************************************  *                                                                             *  *  Paramètres  : candidate = objet dont l'instance se veut unique.            * -*                other     = second élément à analyser.                       * -*                processed = liste de candidats déjà traités.                 *  *                                                                             * -*  Description : Détermine si deux candidats à l'unicité sont identiques.     * +*  Description : Indique si le candidat est figé.                             *  *                                                                             * -*  Retour      : Bilan de la comparaison.                                     * +*  Retour      : true si le contenu du candidat ne peut plus être modifié.    *  *                                                                             *  *  Remarques   : -                                                            *  *                                                                             *  ******************************************************************************/ -static gboolean _g_singleton_candidate_is_equal(GSingletonCandidate *candidate, GSingletonCandidate *other, GList **processed) +bool g_singleton_candidate_is_read_only(const GSingletonCandidate *candidate)  { -    gboolean result;                        /* Bilan à renvoyer            */ -    GList *skip;                            /* Détection de boucle         */ -    GSingletonCandidateIface *iface;        /* Interface utilisée          */ -    GSingletonCandidate **children[2];      /* Instances internes          */ -    size_t count[2];                        /* Quantité de ces instances   */ +    bool result;                            /* Etat à retourner            */ +    GSingletonCandidateInterface *iface;    /* Interface utilisée          */ +#ifndef NDEBUG +    GSingletonCandidate **children;         /* Instances internes          */ +    size_t count;                           /* Quantité de ces instances   */      size_t i;                               /* Boucle de parcours          */ +#endif -    skip = g_list_find(processed[0], candidate); - -    if (skip != NULL) -        result = (g_list_find(processed[1], other) != NULL); - -    else -    { -        iface = G_SINGLETON_CANDIDATE_GET_IFACE(candidate); - -        result = iface->is_equal(candidate, other); - -        processed[0] = g_list_append(processed[0], candidate); -        processed[1] = g_list_append(processed[1], other); - -        if (!result) -            goto done; - -        children[0] = g_singleton_candidate_list_inner_instances(candidate, &count[0]); -        children[1] = g_singleton_candidate_list_inner_instances(other, &count[1]); - -        if (count[0] != count[1]) -        { -            for (i = 0; i < count[0]; i++) -                g_object_unref(G_OBJECT(children[0][i])); - -            for (i = 0; i < count[1]; i++) -                g_object_unref(G_OBJECT(children[1][i])); - -        } - -        else -        { -            for (i = 0; i < count[0] && result; i++) -            { -                result = _g_singleton_candidate_is_equal(children[0][i], children[1][i], processed); -                g_object_unref(G_OBJECT(children[0][i])); -                g_object_unref(G_OBJECT(children[1][i])); -            } - -            for (; i < count[0]; i++) -            { -                g_object_unref(G_OBJECT(children[0][i])); -                g_object_unref(G_OBJECT(children[1][i])); -            } +    iface = G_SINGLETON_CANDIDATE_GET_IFACE(candidate); -            if (children[0] != NULL) -                free(children[0]); +    result = iface->is_ro(candidate); -            if (children[1] != NULL) -                free(children[1]); +#ifndef NDEBUG -        } +    children = g_singleton_candidate_list_inner_instances(candidate, &count); +    for (i = 0; i < count; i++) +    { +        assert(result == g_singleton_candidate_is_read_only(children[i])); +        unref_object(G_OBJECT(children[i]));      } - done: - -    return result; - -} - - -/****************************************************************************** -*                                                                             * -*  Paramètres  : candidate = objet dont l'instance se veut unique.            * -*                other     = second élément à analyser.                       * -*                                                                             * -*  Description : Détermine si deux candidats à l'unicité sont identiques.     * -*                                                                             * -*  Retour      : Bilan de la comparaison.                                     * -*                                                                             * -*  Remarques   : -                                                            * -*                                                                             * -******************************************************************************/ - -gboolean g_singleton_candidate_is_equal(GSingletonCandidate *candidate, GSingletonCandidate *other) -{ -    gboolean result;                        /* Bilan à renvoyer            */ -    GList *processed[2];                    /* Suivi des traitements       */ +    if (children != NULL) +        free(children); -    processed[0] = NULL; -    processed[1] = NULL; - -    result = _g_singleton_candidate_is_equal(candidate, other, processed); - -    assert(processed[0] != NULL); -    assert(processed[1] != NULL); - -    g_list_free(processed[0]); -    g_list_free(processed[1]); +#endif      return result; @@ -383,97 +259,60 @@ gboolean g_singleton_candidate_is_equal(GSingletonCandidate *candidate, GSinglet  /******************************************************************************  *                                                                             *  *  Paramètres  : candidate = objet dont l'instance se veut unique.            * -*                processed = liste de candidats déjà traités.                 *  *                                                                             * -*  Description : Marque un candidat comme figé.                               * +*  Description : Crée une copie modifiable d'un object unique.                *  *                                                                             * -*  Retour      : -                                                            * +*  Retour      : Nouvelle instance mise en place.                             *  *                                                                             *  *  Remarques   : -                                                            *  *                                                                             *  ******************************************************************************/ -static void _g_singleton_candidate_set_read_only(GSingletonCandidate *candidate, GList **processed) +GSingletonCandidate *g_singleton_candidate_dup(const GSingletonCandidate *candidate)  { -    GList *skip;                            /* Détection de boucle         */ -    GSingletonCandidateIface *iface;        /* Interface utilisée          */ -    GSingletonCandidate **children;         /* Instances internes          */ -    size_t count;                           /* Quantité de ces instances   */ +    GSingletonCandidate *result;            /* Instance à retourner        */ +    GSingletonCandidateInterface *iface;    /* Interface utilisée          */ +    size_t count;                           /* Quantité d'objets internes  */ +    GSingletonCandidate **children;         /* Liste d'instances internes  */      size_t i;                               /* Boucle de parcours          */ +    GSingletonCandidate **new_children;     /* Nouvelle liste d'instances  */ -    skip = g_list_find(*processed, candidate); +    iface = G_SINGLETON_CANDIDATE_GET_IFACE(candidate); -    if (skip == NULL) -    { -        iface = G_SINGLETON_CANDIDATE_GET_IFACE(candidate); +    result = iface->dup(candidate); -        iface->set_ro(candidate); +    assert(!g_singleton_candidate_is_read_only(result)); -        *processed = g_list_append(*processed, candidate); +    children = g_singleton_candidate_list_inner_instances(candidate, &count); -        children = g_singleton_candidate_list_inner_instances(candidate, &count); +    if (count > 0) +    { +        new_children = malloc(count * sizeof(GSingletonCandidate *));          for (i = 0; i < count; i++)          { -            _g_singleton_candidate_set_read_only(candidate, processed); -            g_object_unref(G_OBJECT(children[i])); -        } - -        if (children != NULL) -            free(children); - -    } - -} +            new_children[i] = g_singleton_candidate_dup(children[i]); +            assert(!g_singleton_candidate_is_read_only(new_children[i])); -/****************************************************************************** -*                                                                             * -*  Paramètres  : candidate = objet dont l'instance se veut unique.            * -*                                                                             * -*  Description : Marque un candidat comme figé.                               * -*                                                                             * -*  Retour      : -                                                            * -*                                                                             * -*  Remarques   : -                                                            * -*                                                                             * -******************************************************************************/ - -void g_singleton_candidate_set_read_only(GSingletonCandidate *candidate) -{ -    GList *processed;                       /* Suivi des traitements       */ - -    processed = NULL; - -    _g_singleton_candidate_set_read_only(candidate, &processed); - -    assert(processed != NULL); +        } -    g_list_free(processed); - -} +        g_singleton_candidate_update_inner_instances(result, new_children, count); +        for (i = 0; i < count; i++) +        { +            unref_object(G_OBJECT(new_children[i])); +            unref_object(G_OBJECT(children[i])); +        } -/****************************************************************************** -*                                                                             * -*  Paramètres  : candidate = objet dont l'instance se veut unique.            * -*                                                                             * -*  Description : Indique si le candidat est figé.                             * -*                                                                             * -*  Retour      : true si le contenu du candidat ne peut plus être modifié.    * -*                                                                             * -*  Remarques   : -                                                            * -*                                                                             * -******************************************************************************/ +        free(new_children); -bool g_singleton_candidate_is_read_only(const GSingletonCandidate *candidate) -{ -    bool result;                            /* Etat à retourner            */ -    GSingletonCandidateIface *iface;        /* Interface utilisée          */ +    } -    iface = G_SINGLETON_CANDIDATE_GET_IFACE(candidate); +    if (children != NULL) +        free(children); -    result = iface->is_ro(candidate); +    assert(G_OBJECT_TYPE(result) == G_OBJECT_TYPE(candidate));      return result; @@ -528,8 +367,8 @@ static void g_singleton_factory_class_init(GSingletonFactoryClass *klass)  static void g_singleton_factory_init(GSingletonFactory *factory)  { -    factory->table = g_hash_table_new_full((GHashFunc)g_singleton_candidate_hash, -                                           (GEqualFunc)g_singleton_candidate_is_equal, +    factory->table = g_hash_table_new_full((GHashFunc)g_hashable_object_hash, +                                           (GEqualFunc)g_comparable_object_is_equal,                                             g_object_unref, NULL);      g_mutex_init(&factory->access); @@ -688,7 +527,7 @@ GSingletonCandidate *g_singleton_factory_get_instance(GSingletonFactory *factory          g_hash_table_add(factory->table, candidate);  #endif -        g_singleton_candidate_set_read_only(candidate); +        g_singleton_candidate_mark_as_read_only(candidate);          result = candidate; diff --git a/src/glibext/singleton.h b/src/glibext/singleton.h index 629687a..11afffd 100644 --- a/src/glibext/singleton.h +++ b/src/glibext/singleton.h @@ -2,7 +2,7 @@  /* Chrysalide - Outil d'analyse de fichiers binaires   * singleton.h - prototypes pour la réduction du nombre d'instances d'un même type   * - * Copyright (C) 2021 Cyrille Bagard + * Copyright (C) 2021-2024 Cyrille Bagard   *   *  This file is part of Chrysalide.   * @@ -25,71 +25,36 @@  #define _GLIBEXT_SINGLETON_H -#include <glib-object.h>  #include <stdbool.h> - -/* Définition d'un compacteur d'instances de types (instance) */ -typedef struct _GSingletonFactory GSingletonFactory; +#include "helpers.h"  /* ------------------ INTERFACE POUR CANDIDAT A UNE CENTRALISATION ------------------ */ -#define G_TYPE_SINGLETON_CANDIDATE             (g_singleton_candidate_get_type()) -#define G_SINGLETON_CANDIDATE(obj)             (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_SINGLETON_CANDIDATE, GSingletonCandidate)) -#define G_SINGLETON_CANDIDATE_CLASS(vtable)    (G_TYPE_CHECK_CLASS_CAST((vtable), G_TYPE_SINGLETON_CANDIDATE, GSingletonCandidateIface)) -#define G_IS_SINGLETON_CANDIDATE(obj)          (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_SINGLETON_CANDIDATE)) -#define G_IS_SINGLETON_CANDIDATE_CLASS(vtable) (G_TYPE_CHECK_CLASS_TYPE((vtable), G_TYPE_SINGLETON_CANDIDATE)) -#define G_SINGLETON_CANDIDATE_GET_IFACE(inst)  (G_TYPE_INSTANCE_GET_INTERFACE((inst), G_TYPE_SINGLETON_CANDIDATE, GSingletonCandidateIface)) - - -/* Instance d'objet visant à être unique (coquille vide) */ -typedef struct _GSingletonCandidate GSingletonCandidate; - -/* Instance d'objet visant à être unique (interface) */ -typedef struct _GSingletonCandidateIface GSingletonCandidateIface; - - -/* Détermine le type d'une interface pour la lecture de binaire. */ -GType g_singleton_candidate_get_type(void) G_GNUC_CONST; +#define G_TYPE_SINGLETON_CANDIDATE (g_singleton_candidate_get_type()) -/* Fournit une liste de candidats embarqués par un candidat. */ -GSingletonCandidate **g_singleton_candidate_list_inner_instances(const GSingletonCandidate *, size_t *); +DECLARE_INTERFACE(GSingletonCandidate, g_singleton_candidate, G, SINGLETON_CANDIDATE); -/* Fournit l'empreinte d'un candidat à une centralisation. */ -guint g_singleton_candidate_hash(GSingletonCandidate *); - -/* Détermine si deux candidats à l'unicité sont identiques. */ -gboolean g_singleton_candidate_is_equal(GSingletonCandidate *, GSingletonCandidate *); - -/* Marque un candidat comme figé. */ -void g_singleton_candidate_set_read_only(GSingletonCandidate *);  /* Indique si le candidat est figé. */  bool g_singleton_candidate_is_read_only(const GSingletonCandidate *); +/* Crée une copie modifiable d'un object unique. */ +GSingletonCandidate *g_singleton_candidate_dup(const GSingletonCandidate *); -/* ------------------------- COLLECTION D'INSTANCES UNIQUES ------------------------- */ - -#define G_TYPE_SINGLETON_FACTORY            g_singleton_factory_get_type() -#define G_SINGLETON_FACTORY(obj)            (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_SINGLETON_FACTORY, GSingletonFactory)) -#define G_IS_SINGLETON_FACTORY(obj)         (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_SINGLETON_FACTORY)) -#define G_SINGLETON_FACTORY_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_SINGLETON_FACTORY, GSingletonFactoryClass)) -#define G_IS_SINGLETON_FACTORY_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_SINGLETON_FACTORY)) -#define G_SINGLETON_FACTORY_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_SINGLETON_FACTORY, GSingletonFactoryClass)) +/* ------------------------- COLLECTION D'INSTANCES UNIQUES ------------------------- */ -/* Définition d'un compacteur d'instances de types (classe) */ -typedef struct _GSingletonFactoryClass GSingletonFactoryClass; +#define G_TYPE_SINGLETON_FACTORY (g_singleton_factory_get_type()) +DECLARE_GTYPE(GSingletonFactory, g_singleton_factory, G, SINGLETON_FACTORY); -/* Indique le type défini pour une mémoire de types d'objets. */ -GType g_singleton_factory_get_type(void);  /* Crée un compacteur d'instances de types. */  GSingletonFactory *g_singleton_factory_new(void); diff --git a/src/analysis/storage/storage-int.h b/src/glibext/storage-int.h index 4883aa8..d89e1c8 100644 --- a/src/analysis/storage/storage-int.h +++ b/src/glibext/storage-int.h @@ -1,8 +1,8 @@  /* Chrysalide - Outil d'analyse de fichiers binaires - * storage.h - prototypes internes pour la conservation sur disque d'objets construits + * storage-int.h - prototypes internes pour la conservation sur disque d'objets construits   * - * Copyright (C) 2020 Cyrille Bagard + * Copyright (C) 2020-2025 Cyrille Bagard   *   *  This file is part of Chrysalide.   * @@ -21,11 +21,13 @@   */ -#ifndef _ANALYSIS_STORAGE_STORAGE_INT_H -#define _ANALYSIS_STORAGE_STORAGE_INT_H +#ifndef _GLIBEXT_STORAGE_INT_H +#define _GLIBEXT_STORAGE_INT_H  #include "storage.h" +#include "tpmem.h" +#include "../common/szbin.h" @@ -44,9 +46,12 @@ struct _GObjectStorage  {      GObject parent;                         /* A laisser en premier        */ -    GTypeMemory *tpmem;                     /* Mémorisation de types       */ +    sized_binary_t type;                    /* Type de conservation        */ +    uint8_t version;                        /* Version correspondante      */ + +    sized_binary_t uid;                     /* Identifiant de distinction  */ -    char *hash;                             /* Empreinte du contenu        */ +    GTypeMemory *tpmem;                     /* Mémorisation de types       */      storage_backend_t *backends;            /* Gestionnaires existants     */      size_t count;                           /* Quantité de gestionnaires   */ @@ -62,5 +67,9 @@ struct _GObjectStorageClass  }; +/* 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  /* _ANALYSIS_STORAGE_STORAGE_INT_H */ +#endif  /* _GLIBEXT_STORAGE_INT_H */ diff --git a/src/analysis/storage/storage.c b/src/glibext/storage.c index 610a0f6..0a3c4e7 100644 --- a/src/analysis/storage/storage.c +++ b/src/glibext/storage.c @@ -2,7 +2,7 @@  /* Chrysalide - Outil d'analyse de fichiers binaires   * storage.c - conservation hors mémoire d'objets choisis   * - * Copyright (C) 2020 Cyrille Bagard + * Copyright (C) 2020-2025 Cyrille Bagard   *   *  This file is part of Chrysalide.   * @@ -28,20 +28,23 @@  #include <malloc.h>  #include <string.h>  #include <unistd.h> -#include <stdarg.h> +#include <zip.h>  #include "storage-int.h" -#include "../db/misc/rlestr.h" -#include "../../common/io.h" -#include "../../common/leb128.h" -#include "../../common/pathname.h" -#include "../../core/logs.h" +#include "../common/cpp.h" +#include "../common/pathname.h" +#include "../core/logs.h" - -#define STORAGE_MAGIC "CSTR" -#define STORAGE_NUMBER "\x00\x01" +/** + * 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. */ @@ -51,10 +54,13 @@ static void g_object_storage_class_init(GObjectStorageClass *);  static void g_object_storage_init(GObjectStorage *);  /* Supprime toutes les références externes. */ -static void g_object_storage_dispose(GObjectStorage *); +static void g_object_storage_dispose(GObject *);  /* Procède à la libération totale de la mémoire. */ -static void g_object_storage_finalize(GObjectStorage *); +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 *); @@ -62,11 +68,8 @@ static storage_backend_t *g_object_storage_find_backend(GObjectStorage *, const  /* Ajoute le support d'un nouveau groupe d'objets construits. */  static bool g_object_storage_add_backend(GObjectStorage *, const char *, storage_backend_t **); -/* Extrait d'un tampon des enregistrements spécifiques. */ -static bool g_object_storage_load_backend(GObjectStorage *, packed_buffer_t *); - -/* Place dans un tampon les données liées à des enregistrements. */ -static bool pack_storage_backend(const storage_backend_t *, packed_buffer_t *); +/* Charge un objet à partir de données rassemblées. */ +static GSerializableObject *g_object_storage_load_object_unlocked(GObjectStorage *, const char *, off64_t); @@ -92,8 +95,8 @@ static void g_object_storage_class_init(GObjectStorageClass *klass)      object = G_OBJECT_CLASS(klass); -    object->dispose = (GObjectFinalizeFunc/* ! */)g_object_storage_dispose; -    object->finalize = (GObjectFinalizeFunc)g_object_storage_finalize; +    object->dispose = g_object_storage_dispose; +    object->finalize = g_object_storage_finalize;  } @@ -112,9 +115,12 @@ static void g_object_storage_class_init(GObjectStorageClass *klass)  static void g_object_storage_init(GObjectStorage *storage)  { -    storage->tpmem = g_type_memory_new(); +    init_sized_binary(&storage->type); +    storage->version = 0; -    storage->hash = NULL; +    init_sized_binary(&storage->uid); + +    storage->tpmem = g_type_memory_new();      storage->backends = NULL;      storage->count = 0; @@ -125,7 +131,7 @@ static void g_object_storage_init(GObjectStorage *storage)  /******************************************************************************  *                                                                             * -*  Paramètres  : storage = instance d'objet GLib à traiter.                   * +*  Paramètres  : object = instance d'objet GLib à traiter.                    *  *                                                                             *  *  Description : Supprime toutes les références externes.                     *  *                                                                             * @@ -135,18 +141,22 @@ static void g_object_storage_init(GObjectStorage *storage)  *                                                                             *  ******************************************************************************/ -static void g_object_storage_dispose(GObjectStorage *storage) +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(G_OBJECT(storage)); +    G_OBJECT_CLASS(g_object_storage_parent_class)->dispose(object);  }  /******************************************************************************  *                                                                             * -*  Paramètres  : storage = instance d'objet GLib à traiter.                   * +*  Paramètres  : object = instance d'objet GLib à traiter.                    *  *                                                                             *  *  Description : Procède à la libération totale de la mémoire.                *  *                                                                             * @@ -156,18 +166,27 @@ static void g_object_storage_dispose(GObjectStorage *storage)  *                                                                             *  ******************************************************************************/ -static void g_object_storage_finalize(GObjectStorage *storage) +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 @@ -193,17 +212,20 @@ static void g_object_storage_finalize(GObjectStorage *storage)      g_mutex_clear(&storage->mutex); -    if (storage->hash != NULL) -        free(storage->hash); +    exit_sized_binary(&storage->type); + +    exit_sized_binary(&storage->uid); -    G_OBJECT_CLASS(g_object_storage_parent_class)->finalize(G_OBJECT(storage)); +    G_OBJECT_CLASS(g_object_storage_parent_class)->finalize(object);  }  /******************************************************************************  *                                                                             * -*  Paramètres  : loaded = contenu binaire à associer.                         * +*  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.        *  *                                                                             * @@ -213,13 +235,14 @@ static void g_object_storage_finalize(GObjectStorage *storage)  *                                                                             *  ******************************************************************************/ -GObjectStorage *g_object_storage_new(const char *hash) +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); -    result->hash = strdup(hash); +    if (!g_object_storage_create(result, type, version, uid)) +        g_clear_object(&result);      return result; @@ -228,7 +251,39 @@ GObjectStorage *g_object_storage_new(const char *hash)  /******************************************************************************  *                                                                             * -*  Paramètres  : pbuf = zone tampon à lire.                                   * +*  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.      *  *                                                                             * @@ -238,140 +293,297 @@ GObjectStorage *g_object_storage_new(const char *hash)  *                                                                             *  ******************************************************************************/ -GObjectStorage *g_object_storage_load(packed_buffer_t *pbuf) +GObjectStorage *g_object_storage_load(const char *filename)  {      GObjectStorage *result;                 /* Structure à retourner       */ -    char header[6];                         /* Entête attendue des données */ +    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      */ -    rle_string str;                         /* Chaîne à conserver          */ -    uleb128_t count;                        /* Nombre de groupes à charger */ -    uleb128_t i;                            /* Boucle de parcours          */ +    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; -    status = extract_packed_buffer(pbuf, header, 6, false); -    if (!status) goto quick_exit; +    storage = g_object_new(G_TYPE_OBJECT_STORAGE, NULL); -    if (strncmp(header, STORAGE_MAGIC STORAGE_NUMBER, 6) != 0) -        goto quick_exit; +    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); -    setup_empty_rle_string(&str); +    if (entries_count < 2) +        goto exit_with_archive; -    status = unpack_rle_string(&str, pbuf); -    if (!status) goto quick_exit; +    data = NULL; -    if (get_rle_string(&str) == NULL) +    /* Extraction de la partie de contrôle */ + +    ret = zip_stat_index(archive, 0, ZIP_FL_UNCHANGED, &stats); +    if (ret != 0)      { -        exit_rle_string(&str); -        goto quick_exit; +        LOG_ERROR_ZIP("zip_stat_index", zip_get_error(archive)); +        goto exit_with_archive;      } -    result = g_object_new(G_TYPE_OBJECT_STORAGE, NULL); - -    result->hash = strdup(get_rle_string(&str)); +    if ((stats.valid & (ZIP_STAT_NAME | ZIP_STAT_SIZE)) != (ZIP_STAT_NAME | ZIP_STAT_SIZE)) +        goto exit_with_archive; -    exit_rle_string(&str); +    if (strcmp(stats.name, "control") != 0) +        goto exit_with_archive; -    status = g_type_memory_load_types(result->tpmem, pbuf); -    if (!status) goto exit_while_loading; +    if (stats.size < (6 + 2 + 1 + 1 + 1)) +        goto exit_with_archive; -    status = unpack_uleb128(&count, pbuf); +    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; +    } -    for (i = 0; i < count && status; i++) -        status = g_object_storage_load_backend(result, pbuf); +    data = malloc(stats.size); - exit_while_loading: +    got = zip_fread(file, data, stats.size); -    if (!status) +    ret = zip_fclose(file); +    if (ret != 0)      { -        g_object_unref(G_OBJECT(result)); -        result = NULL; +        zip_error_set(&error, ret, 0); +        LOG_ERROR_ZIP("zip_fclose", &error); +        goto exit_with_data;      } - quick_exit: +    if (got != stats.size) +        goto exit_with_data; -    return result; +    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; -/****************************************************************************** -*                                                                             * -*  Paramètres  : storage = gestionnaire de conservations à manipuler.         * -*                pbuf    = zone tampon à remplir. [OUT]                       * -*                                                                             * -*  Description : Sauvegarde le support d'une conservation d'objets en place.  * -*                                                                             * -*  Retour      : Bilan de l'opération.                                        * -*                                                                             * -*  Remarques   : -                                                            * -*                                                                             * -******************************************************************************/ +    status = unpack_sized_binary(&storage->type, &pos, max); +    if (!status) goto exit_with_data; -bool g_object_storage_store(GObjectStorage *storage, packed_buffer_t *pbuf) -{ -    bool result;                            /* Bilan à retourner           */ -    rle_string str;                         /* Chaîne à conserver          */ -    size_t i;                               /* Boucle de parcours          */ +    if (pos >= max) +        goto exit_with_data; -    result = extend_packed_buffer(pbuf, STORAGE_MAGIC STORAGE_NUMBER, 6, false); +    storage->version = *(uint8_t *)pos; +    pos = (uint8_t *)pos + 1; -    if (result) +    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)      { -        init_static_rle_string(&str, storage->hash); +        LOG_ERROR_ZIP("zip_stat_index", zip_get_error(archive)); +        goto exit_with_archive; +    } -        result = pack_rle_string(&str, pbuf); +    if ((stats.valid & (ZIP_STAT_NAME | ZIP_STAT_SIZE)) != (ZIP_STAT_NAME | ZIP_STAT_SIZE)) +        goto exit_with_archive; -        exit_rle_string(&str); +    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;      } -    g_mutex_lock(&storage->mutex); +    data = malloc(stats.size); -    if (result) -        result = g_type_memory_store_types(storage->tpmem, pbuf); +    got = zip_fread(file, data, stats.size); -    if (result) -        result = pack_uleb128((uleb128_t []){ storage->count }, pbuf); +    ret = zip_fclose(file); +    if (ret != 0) +    { +        zip_error_set(&error, ret, 0); +        LOG_ERROR_ZIP("zip_fclose", &error); +        goto exit_with_data; +    } -    for (i = 0; i < storage->count && result; i++) -        result = pack_storage_backend(&storage->backends[i], pbuf); +    asprintf(&prefix, "%s-types", storage->uid.static_data); -    g_mutex_unlock(&storage->mutex); +    fd = make_tmp_file(prefix, "cache", &tpmem_filename); -    return result; +    free(prefix); -} +    if (fd == -1) +        goto exit_with_data; +    status = safe_write(fd, data, stats.size); +    if (!status) +    { +        close(fd); +        goto exit_with_data; +    } -/****************************************************************************** -*                                                                             * -*  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   : -                                                            * -*                                                                             * -******************************************************************************/ +    moved = lseek(fd, 0, SEEK_SET); +    if (moved == ((off_t)-1)) +    { +        LOG_ERROR_N("lseek"); +        close(fd); +        goto exit_with_data; +    } -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          */ +    status = g_type_memory_load(storage->tpmem, fd); -    assert(!g_mutex_trylock(&storage->mutex)); +    close(fd); -    for (i = 0; i < storage->count; i++) -        if (strcmp(storage->backends[i].name, name) == 0) -            break; +    if (!status) +        goto exit_with_data; -    if (i == storage->count) -        result = NULL; -    else -        result = &storage->backends[i]; +    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; @@ -380,11 +592,10 @@ static storage_backend_t *g_object_storage_find_backend(GObjectStorage *storage,  /******************************************************************************  *                                                                             * -*  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.     * +*  Paramètres  : storage  = gestionnaire de conservations à manipuler.        * +*                filename = fichier de destination à constituer.              *  *                                                                             * -*  Description : Ajoute le support d'un nouveau groupe d'objets construits.   * +*  Description : Sauvegarde le support d'une conservation d'objets en place.  *  *                                                                             *  *  Retour      : Bilan de l'opération.                                        *  *                                                                             * @@ -392,46 +603,199 @@ static storage_backend_t *g_object_storage_find_backend(GObjectStorage *storage,  *                                                                             *  ******************************************************************************/ -static bool g_object_storage_add_backend(GObjectStorage *storage, const char *name, storage_backend_t **backend) +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     */ -    char *filename;                         /* Chemin d'accès aux données  */      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; -    *backend = NULL; +    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; +    } -    assert(!g_mutex_trylock(&storage->mutex)); +    zip_error_init(&error); -    if (g_object_storage_find_backend(storage, name) != NULL) -        goto exit; +    tpmem_filename = NULL; -    /* Préparatifs */ +    /* Fichier de contrôle */ -    asprintf(&prefix, "%s-%s", storage->hash, name); +    type_buf = pack_sized_binary(&storage->type, &type_buflen); -    fd = make_tmp_file(prefix, "cache", &filename); +    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; +        goto exit_with_lock; -    /* Inscription en bonne et due forme */ +    status = g_type_memory_store(storage->tpmem, fd); -    storage->backends = realloc(storage->backends, ++storage->count * sizeof(storage_backend_t)); +    close(fd); -    *backend = &storage->backends[storage->count - 1]; +    if (!status) +        goto exit_with_lock; -    (*backend)->name = strdup(name); +    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; +    } -    (*backend)->filename = filename; -    (*backend)->fd = fd; +    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; @@ -441,71 +805,67 @@ static bool g_object_storage_add_backend(GObjectStorage *storage, const char *na  /******************************************************************************  *                                                                             * -*  Paramètres  : storage = gestionnaire de conservations à compléter.         * -*                pbuf    = zone tampon à lire.                                * +*  Paramètres  : storage = gestionnaire de conservations à consulter.         * +*                name    = désignation d'un nouveau groupe d'objets.          *  *                                                                             * -*  Description : Extrait d'un tampon des enregistrements spécifiques.         * +*  Description : Assure l'inexistence d'un groupe avec un nom donné.          *  *                                                                             * -*  Retour      : Bilan de l'opération.                                        * +*  Retour      : Bilan des recherches.                                        *  *                                                                             *  *  Remarques   : -                                                            *  *                                                                             *  ******************************************************************************/ -static bool g_object_storage_load_backend(GObjectStorage *storage, packed_buffer_t *pbuf) +static bool g_object_storage_has_no_backend_named(GObjectStorage *storage, const char *name)  {      bool result;                            /* Bilan à retourner           */ -    rle_string str;                         /* Chaîne à conserver          */ -    bool status;                            /* Bilan de lecture de contenu */ -    storage_backend_t *backend;             /* Informations à intégrer     */ -    uleb128_t length;                       /* Taille des données à charger*/ -    off_t moved;                            /* Nouvelle position établie   */ - -    result = false; - -    g_mutex_lock(&storage->mutex); - -    /* Récupération du nom et création du support */ - -    setup_empty_rle_string(&str); +    size_t i;                               /* Boucle de parcours          */ -    status = unpack_rle_string(&str, pbuf); -    if (!status) goto exit; +    result = true; -    if (get_rle_string(&str) == NULL) +    for (i = 0; i < storage->count && result; i++)      { -        exit_rle_string(&str); -        goto exit; -    } - -    status = g_object_storage_add_backend(storage, get_rle_string(&str), &backend); +        if (storage->backends[i].name == NULL) +            break; -    exit_rle_string(&str); +        if (strcmp(storage->backends[i].name, name) == 0) +            result = false; -    if (!status) goto exit; +    } -    /* Récupération du contenu */ +    return result; -    status = unpack_uleb128(&length, pbuf); -    if (!status) goto exit; +} -    status = safe_write(backend->fd, pbuf->data + pbuf->pos, length); -    if (!status) goto exit; -    advance_packed_buffer(pbuf, length); +/****************************************************************************** +*                                                                             * +*  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   : -                                                            * +*                                                                             * +******************************************************************************/ -    moved = lseek(backend->fd, 0, SEEK_SET); -    if (moved == ((off_t)-1)) -    { -        LOG_ERROR_N("lseek"); -        goto exit; -    } +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          */ -    result = true; +    assert(!g_mutex_trylock(&storage->mutex)); - exit: +    for (i = 0; i < storage->count; i++) +        if (strcmp(storage->backends[i].name, name) == 0) +            break; -    g_mutex_unlock(&storage->mutex); +    if (i == storage->count) +        result = NULL; +    else +        result = &storage->backends[i];      return result; @@ -514,10 +874,11 @@ static bool g_object_storage_load_backend(GObjectStorage *storage, packed_buffer  /******************************************************************************  *                                                                             * -*  Paramètres  : backend = stockage des enregistrements spécifiques.          * -*                pbuf    = zone tampon à remplir. [OUT]                       * +*  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 : Place dans un tampon les données liées à des enregistrements.* +*  Description : Ajoute le support d'un nouveau groupe d'objets construits.   *  *                                                                             *  *  Retour      : Bilan de l'opération.                                        *  *                                                                             * @@ -525,72 +886,45 @@ static bool g_object_storage_load_backend(GObjectStorage *storage, packed_buffer  *                                                                             *  ******************************************************************************/ -static bool pack_storage_backend(const storage_backend_t *backend, packed_buffer_t *pbuf) +static bool g_object_storage_add_backend(GObjectStorage *storage, const char *name, storage_backend_t **backend)  {      bool result;                            /* Bilan à retourner           */ -    rle_string str;                         /* Chaîne à conserver          */ -    bool status;                            /* Bilan de lecture de contenu */ -    off_t current;                          /* Position courante           */ -    off_t moved;                            /* Nouvelle position établie   */ -    void *data;                             /* Données à transférer        */ +    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; -    /* Inscription du nom */ +    *backend = NULL; -    init_static_rle_string(&str, backend->name); +    assert(!g_mutex_trylock(&storage->mutex)); -    status = pack_rle_string(&str, pbuf); +    if (g_object_storage_find_backend(storage, name) != NULL) +        goto exit; -    exit_rle_string(&str); +    /* Préparatifs */ -    if (!status) goto exit; +    asprintf(&prefix, "%s-%s", storage->uid.static_data, name); -    /* Inscription du contenu */ +    fd = make_tmp_file(prefix, "cache", &filename); -    current = lseek(backend->fd, 0, SEEK_CUR); -    if (current == ((off_t)-1)) -    { -        LOG_ERROR_N("lseek"); -        goto exit; -    } +    free(prefix); -    moved = lseek(backend->fd, 0, SEEK_SET); -    if (moved == ((off_t)-1)) -    { -        LOG_ERROR_N("lseek"); +    if (fd == -1)          goto exit; -    } -    data = malloc(current); -    if (data == NULL) -    { -        LOG_ERROR_N("malloc"); -        goto restore; -    } - -    status = safe_read(backend->fd, data, current); -    if (!status) goto free_mem; - -    status = pack_uleb128((uleb128_t []){ current }, pbuf); -    if (!status) goto free_mem; - -    status = extend_packed_buffer(pbuf, data, current, false); +    /* Inscription en bonne et due forme */ - free_mem: +    storage->backends = realloc(storage->backends, ++storage->count * sizeof(storage_backend_t)); -    free(data); +    *backend = &storage->backends[storage->count - 1]; - restore: +    (*backend)->name = strdup(name); -    moved = lseek(backend->fd, current, SEEK_SET); -    if (moved == ((off_t)-1)) -    { -        LOG_ERROR_N("lseek"); -        goto exit; -    } +    (*backend)->filename = filename; +    (*backend)->fd = fd; -    result = status; +    result = true;   exit: @@ -602,7 +936,7 @@ static bool pack_storage_backend(const storage_backend_t *backend, packed_buffer  /******************************************************************************  *                                                                             *  *  Paramètres  : storage = gestionnaire à manipuler.                          * -*                name    = désignation d'un nouveau groupe d'objets.          * +*                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.             * @@ -613,56 +947,44 @@ static bool pack_storage_backend(const storage_backend_t *backend, packed_buffer  *                                                                             *  ******************************************************************************/ -GSerializableObject *g_object_storage_load_object(GObjectStorage *storage, const char *name, off64_t pos) +static GSerializableObject *g_object_storage_load_object_unlocked(GObjectStorage *storage, const char *name, off64_t pos)  {      GSerializableObject *result;            /* Instance à retourner        */ -    bool status;                            /* Bilan d'une opération       */      storage_backend_t *backend;             /* Informations à consulter    */ -    packed_buffer_t pbuf;                   /* Tampon des données à lire   */      off64_t new;                            /* Nouvelle position de lecture*/ +    bool status;                            /* Bilan d'une opération       */      result = NULL; -    /* Chargement */ - -    status = false; +    assert(!g_mutex_trylock(&storage->mutex)); -    g_mutex_lock(&storage->mutex); +    /* Chargement */      backend = g_object_storage_find_backend(storage, name); +    if (backend == NULL) goto exit; -    if (backend != NULL) +    new = lseek64(backend->fd, pos, SEEK_SET); +    if (new == (off_t)-1)      { -        new = lseek64(backend->fd, pos, SEEK_SET); - -        if (new == pos) -        { -            init_packed_buffer(&pbuf); -            status = read_packed_buffer(&pbuf, backend->fd); -        } - +        LOG_ERROR_N("lseek64"); +        goto exit;      } -    g_mutex_unlock(&storage->mutex); - -    if (!status) -        goto exit; +    assert (new == pos);      /* Phase de conversion */ -    result = G_SERIALIZABLE_OBJECT(g_type_memory_create_object(storage->tpmem, &pbuf)); +    result = G_SERIALIZABLE_OBJECT(g_type_memory_create_object_from_gtype(storage->tpmem, backend->fd));      if (result)      { -        status = g_serializable_object_load(result, storage, &pbuf); +        status = g_serializable_object_load(result, storage, backend->fd);          if (!status)              g_clear_object(&result);      } -    exit_packed_buffer(&pbuf); -   exit:      return result; @@ -673,10 +995,10 @@ GSerializableObject *g_object_storage_load_object(GObjectStorage *storage, const  /******************************************************************************  *                                                                             *  *  Paramètres  : storage = gestionnaire à manipuler.                          * -*                name    = désignation d'un nouveau groupe d'objets.          * -*                pbuf    = zone tampon à parcourir.                           * +*                name    = désignation d'un groupe d'objets à consulter.      * +*                pos     = tête de lecture avant écriture.                    *  *                                                                             * -*  Description : Charge un objet interne à partir de données rassemblées.     * +*  Description : Charge un objet à partir de données rassemblées.             *  *                                                                             *  *  Retour      : Objet restauré en mémoire ou NULL en cas d'échec.            *  *                                                                             * @@ -684,18 +1006,15 @@ GSerializableObject *g_object_storage_load_object(GObjectStorage *storage, const  *                                                                             *  ******************************************************************************/ -GSerializableObject *g_object_storage_unpack_object(GObjectStorage *storage, const char *name, packed_buffer_t *pbuf) +GSerializableObject *g_object_storage_load_object(GObjectStorage *storage, const char *name, off64_t pos)  {      GSerializableObject *result;            /* Instance à retourner        */ -    uint64_t pos;                           /* Localisation des données    */ -    bool status;                            /* Bilan d'une opération       */ -    result = NULL; +    g_mutex_lock(&storage->mutex); -    status = extract_packed_buffer(pbuf, &pos, sizeof(uint64_t), true); +    result = g_object_storage_load_object_unlocked(storage, name, pos); -    if (status) -        result = g_object_storage_load_object(storage, name, pos); +    g_mutex_unlock(&storage->mutex);      return result; @@ -704,60 +1023,70 @@ GSerializableObject *g_object_storage_unpack_object(GObjectStorage *storage, con  /******************************************************************************  *                                                                             * -*  Paramètres  : storage  = gestionnaire à manipuler.                         * -*                name     = désignation d'un nouveau groupe d'objets.         * -*                pbuf     = zone tampon à parcourir.                          * -*                expected = type d'objet attendu.                             * -*                ...      = élément restauré ou NULL en cas d'échec. [OUT]    * +*  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 de données rassemblées.     * +*  Description : Charge un objet interne à partir d'une référence embarquée.  *  *                                                                             * -*  Retour      : Bilan de l'opération.                                        * +*  Retour      : Objet restauré en mémoire ou NULL en cas d'échec.            *  *                                                                             *  *  Remarques   : -                                                            *  *                                                                             *  ******************************************************************************/ -bool g_object_storage_unpack_object_2(GObjectStorage *storage, const char *name, packed_buffer_t *pbuf, GType expected, ...) +GSerializableObject *g_object_storage_unpack_object(GObjectStorage *storage, int fd, const char *name)  { -    bool result;                            /* Bilan d'une opération       */ -    uint64_t pos;                           /* Localisation des données    */ -    GSerializableObject *instance;          /* Objet rechargé à valider    */ -    va_list ap;                             /* Liste d'arguments variables */ -    void **object;                          /* Lieu d'enregistrement final */ +    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 = extract_packed_buffer(pbuf, &pos, sizeof(uint64_t), true); +    result = NULL; -    if (result) -    { -        if (pos == 0) -            *object = NULL; +    g_mutex_lock(&storage->mutex); -        else -        { -            instance = g_object_storage_load_object(storage, name, pos); +    /* Récupération de la position */ -            result = G_TYPE_CHECK_INSTANCE_TYPE(instance, expected); +    backend = g_object_storage_find_backend(storage, name); +    if (backend == NULL) goto exit; -            if (result) -            { -                va_start(ap, expected); +    status = load_uleb128(&pos, backend->fd); +    if (!status) goto exit; -                object = va_arg(ap, void **); +    saved = lseek64(backend->fd, 0, SEEK_CUR); +    if (saved == (off_t)-1) +    { +        LOG_ERROR_N("lseek64"); +        goto exit; +    } -                *object = instance; +    /* Chargement */ -                va_end(ap); +    result = g_object_storage_load_object_unlocked(storage, name, pos); -            } +    if (result == NULL) goto exit; -            else -                g_clear_object(&instance); +    /* 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;  } @@ -766,7 +1095,7 @@ bool g_object_storage_unpack_object_2(GObjectStorage *storage, const char *name,  /******************************************************************************  *                                                                             *  *  Paramètres  : storage = gestionnaire à manipuler.                          * -*                name    = désignation d'un nouveau groupe d'objets.          * +*                name    = désignation d'un groupe d'objets, nouveau ou non.  *  *                object  = objet sérialisable à traiter.                      *  *                pos     = tête de lecture avant écriture. [OUT]              *  *                                                                             * @@ -781,22 +1110,9 @@ bool g_object_storage_unpack_object_2(GObjectStorage *storage, const char *name,  bool g_object_storage_store_object(GObjectStorage *storage, const char *name, const GSerializableObject *object, off64_t *pos)  {      bool result;                            /* Bilan à retourner           */ -    packed_buffer_t pbuf;                   /* Tampon des données à écrire */      storage_backend_t *backend;             /* Informations à consulter    */      off64_t tmp;                            /* Conservation éphémère       */ -    /* Phase de conversion */ - -    init_packed_buffer(&pbuf); - -    result = g_type_memory_store_object_gtype(storage->tpmem, G_OBJECT(object), &pbuf); -    if (!result) goto exit; - -    result = g_serializable_object_store(object, storage, &pbuf); -    if (!result) goto exit; - -    /* Enregistrement */ -      result = false;      g_mutex_lock(&storage->mutex); @@ -814,54 +1130,18 @@ bool g_object_storage_store_object(GObjectStorage *storage, const char *name, co          *pos = lseek64(backend->fd, 0, SEEK_CUR);          if (*pos != (off64_t)-1) -            result = write_packed_buffer(&pbuf, backend->fd); - -    } - -    g_mutex_unlock(&storage->mutex); - -    /* Sortie propre */ - - exit: - -    exit_packed_buffer(&pbuf); - -    return result; - -} - - -/****************************************************************************** -*                                                                             * -*  Paramètres  : storage = gestionnaire à manipuler.                          * -*                name    = désignation d'un nouveau groupe d'objets.          * -*                pbuf    = zone tampon à remplir.                             * -*                                                                             * -*  Description : Sauvegarde un object interne sous forme de données.          * -*                                                                             * -*  Retour      : Bilan de l'opération.                                        * -*                                                                             * -*  Remarques   : -                                                            * -*                                                                             * -******************************************************************************/ - -bool g_object_storage_pack_object(GObjectStorage *storage, const char *name, const GSerializableObject *object, packed_buffer_t *pbuf) -{ -    bool result;                            /* Bilan à retourner           */ -    off64_t pos;                            /* Localisation des données    */ - -    if (object == NULL) -        result = extend_packed_buffer(pbuf, (uint64_t []){ 0 }, sizeof(uint64_t), true); +        { +            result = g_type_memory_store_object_gtype(storage->tpmem, G_OBJECT(object), backend->fd); -    else -    { -        result = g_object_storage_store_object(storage, name, object, &pos); +            if (result) +                result = g_serializable_object_store(object, storage, backend->fd); -        if (result) -            result = extend_packed_buffer(pbuf, (uint64_t []){ pos }, sizeof(uint64_t), true); +        }      } +    g_mutex_unlock(&storage->mutex); +      return result;  } diff --git a/src/analysis/storage/storage.h b/src/glibext/storage.h index cc0caad..ea06ed4 100644 --- a/src/analysis/storage/storage.h +++ b/src/glibext/storage.h @@ -2,7 +2,7 @@  /* Chrysalide - Outil d'analyse de fichiers binaires   * storage.h - prototypes pour la conservation sur disque d'objets construits   * - * Copyright (C) 2020 Cyrille Bagard + * Copyright (C) 2020-2025 Cyrille Bagard   *   *  This file is part of Chrysalide.   * @@ -21,69 +21,61 @@   */ -#ifndef _ANALYSIS_STORAGE_STORAGE_H -#define _ANALYSIS_STORAGE_STORAGE_H +#ifndef _GLIBEXT_STORAGE_H +#define _GLIBEXT_STORAGE_H -#include <glib-object.h> -#include <stdbool.h> +#include <stdint.h> +#include "helpers.h"  #include "serialize.h" -#include "tpmem.h" -#define G_TYPE_OBJECT_STORAGE            g_object_storage_get_type() -#define G_OBJECT_STORAGE(obj)            (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_OBJECT_STORAGE, GObjectStorage)) -#define G_IS_OBJECT_STORAGE(obj)         (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_OBJECT_STORAGE)) -#define G_OBJECT_STORAGE_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_OBJECT_STORAGE, GObjectStorageClass)) -#define G_IS_OBJECT_STORAGE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_OBJECT_STORAGE)) -#define G_OBJECT_STORAGE_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_OBJECT_STORAGE, GObjectStorageClass)) +#define G_TYPE_OBJECT_STORAGE (g_object_storage_get_type()) +DECLARE_GTYPE(GObjectStorage, g_object_storage, G, OBJECT_STORAGE); -/* Définition d'une conservation d'objets construits (instance) */ -typedef struct _GObjectStorage GObjectStorage; - -/* Définition d'une conservation d'objets construits (classe) */ -typedef struct _GObjectStorageClass GObjectStorageClass; - - -/* Indique le type défini pour une conservation d'objets construits. */ -GType g_object_storage_get_type(void);  /* Crée le support d'une conservation d'objets en place. */ -GObjectStorage *g_object_storage_new(const char *); - -#define get_storage_linked_format(s)                            \ -    ({                                                          \ -        void*__result;                                          \ -        __result = g_object_get_data(G_OBJECT(s), "format");    \ -        g_object_ref(G_OBJECT(__result));                       \ -        __result;                                               \ -    }) +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(packed_buffer_t *); +GObjectStorage *g_object_storage_load(const char *);  /* Sauvegarde le support d'une conservation d'objets en place. */ -bool g_object_storage_store(GObjectStorage *, packed_buffer_t *); +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 de données rassemblées. */ -GSerializableObject *g_object_storage_unpack_object(GObjectStorage *, const char *, packed_buffer_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 *); -/* Charge un objet interne à partir de données rassemblées. */ -bool g_object_storage_unpack_object_2(GObjectStorage *, const char *, packed_buffer_t *, GType, ...); -/* Sauvegarde un object interne sous forme de données. */ -bool g_object_storage_pack_object(GObjectStorage *, const char *, const GSerializableObject *, packed_buffer_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  /* _ANALYSIS_STORAGE_STORAGE_H */ +#endif  /* _GLIBEXT_STORAGE_H */ diff --git a/src/glibext/strbuilder-int.h b/src/glibext/strbuilder-int.h new file mode 100644 index 0000000..d74e65c --- /dev/null +++ b/src/glibext/strbuilder-int.h @@ -0,0 +1,47 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * strbuilder-int.h - définitions internes propres aux éléments exportant une chaîne de caractères + * + * 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_STRBUILDER_INT_H +#define _GLIBEXT_STRBUILDER_INT_H + + +#include "strbuilder.h" + + + +/* Exporte une chaîne de caractères à partir d'un objet. */ +typedef bool (* strbuilder_to_string_fc) (const GStringBuilder *, unsigned int, sized_binary_t *); + + +/* Instance d'objet visant à être unique (interface) */ +struct _GStringBuilderInterface +{ +    GTypeInterface base_iface;              /* A laisser en premier        */ + +    strbuilder_to_string_fc to_string;      /* Conversion en chaîne        */ + +}; + + + +#endif  /* _GLIBEXT_STRBUILDER_INT_H */ diff --git a/src/glibext/strbuilder.c b/src/glibext/strbuilder.c new file mode 100644 index 0000000..e48674c --- /dev/null +++ b/src/glibext/strbuilder.c @@ -0,0 +1,89 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * strbuilder.c - exportation d'une chaîne de caractères depuis un élément + * + * 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/>. + */ + + +#include "strbuilder.h" + + +#include "strbuilder-int.h" + + + +/* Procède à l'initialisation de l'interface d'exportation. */ +static void g_string_builder_default_init(GStringBuilderInterface *); + + + +/* Détermine le type d'une interface pour la constitution d'objets uniques. */ +G_DEFINE_INTERFACE(GStringBuilder, g_string_builder, G_TYPE_OBJECT) + + +/****************************************************************************** +*                                                                             * +*  Paramètres  : iface = interface GLib à initialiser.                        * +*                                                                             * +*  Description : Procède à l'initialisation de l'interface d'exportation.     * +*                                                                             * +*  Retour      : -                                                            * +*                                                                             * +*  Remarques   : -                                                            * +*                                                                             * +******************************************************************************/ + +static void g_string_builder_default_init(GStringBuilderInterface *iface) +{ +    iface->to_string = NULL; + +} + + +/****************************************************************************** +*                                                                             * +*  Paramètres  : builder = objet dont l'instance est exportable.              * +*                flags   = éventuelles indications pour l'opération.          * +*                out     = chaîne de caractères mise en place. [OUT]          * +*                                                                             * +*  Description : Exporte une chaîne de caractères à partir d'un objet.        * +*                                                                             * +*  Retour      : Bilan de l'opération.                                        * +*                                                                             * +*  Remarques   : La sortie out est à nettoyer avec exit_sized_binary() après  * +*                usage.                                                       * +*                                                                             * +******************************************************************************/ + +bool g_string_builder_to_string(const GStringBuilder *builder, unsigned int flags, sized_binary_t *out) +{ +    bool result;                        /* Bilan à retourner               */ +    GStringBuilderInterface *iface;     /* Interface utilisée              */ + +    iface = G_STRING_BUILDER_GET_IFACE(builder); + +    if (iface->to_string == NULL) +        result = false; + +    else +        result = iface->to_string(builder, flags, out); + +    return result; + +} diff --git a/src/glibext/strbuilder.h b/src/glibext/strbuilder.h new file mode 100644 index 0000000..b6422f7 --- /dev/null +++ b/src/glibext/strbuilder.h @@ -0,0 +1,46 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * strbuilder.h - prototypes pour l'exportation d'une chaîne de caractères depuis un élément + * + * 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_STRBUILDER_H +#define _GLIBEXT_STRBUILDER_H + + +#include <stdbool.h> + + +#include "helpers.h" +#include "../common/szbin.h" + + + +#define G_TYPE_STRING_BUILDER (g_string_builder_get_type()) + +DECLARE_INTERFACE(GStringBuilder, g_string_builder, G, STRING_BUILDER); + + +/* Exporte une chaîne de caractères à partir d'un objet. */ +bool g_string_builder_to_string(const GStringBuilder *, unsigned int, sized_binary_t *); + + + +#endif  /* _GLIBEXT_STRBUILDER_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/analysis/storage/tpmem.c b/src/glibext/tpmem.c index 0703aeb..14b5e33 100644 --- a/src/analysis/storage/tpmem.c +++ b/src/glibext/tpmem.c @@ -2,7 +2,7 @@  /* Chrysalide - Outil d'analyse de fichiers binaires   * tpmem.c - mémorisation des types d'objets mis en cache   * - * Copyright (C) 2020 Cyrille Bagard + * Copyright (C) 2020-2025 Cyrille Bagard   *   *  This file is part of Chrysalide.   * @@ -25,59 +25,14 @@  #include <assert.h> -#include <stdint.h> -#include "../db/misc/rlestr.h" -#include "../../arch/operands/target.h" -#include "../../core/logs.h" +#include "tpmem-int.h" +#include "../common/szbin.h" +#include "../core/logs.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 : -     * -     *    #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        */ - -}; - -  /* Initialise la classe des mémoires de types d'objets. */  static void g_type_memory_class_init(GTypeMemoryClass *); @@ -85,10 +40,10 @@ static void g_type_memory_class_init(GTypeMemoryClass *);  static void g_type_memory_init(GTypeMemory *);  /* Supprime toutes les références externes. */ -static void g_type_memory_dispose(GTypeMemory *); +static void g_type_memory_dispose(GObject *);  /* Procède à la libération totale de la mémoire. */ -static void g_type_memory_finalize(GTypeMemory *); +static void g_type_memory_finalize(GObject *); @@ -114,8 +69,8 @@ static void g_type_memory_class_init(GTypeMemoryClass *klass)      object = G_OBJECT_CLASS(klass); -    object->dispose = (GObjectFinalizeFunc/* ! */)g_type_memory_dispose; -    object->finalize = (GObjectFinalizeFunc)g_type_memory_finalize; +    object->dispose = g_type_memory_dispose; +    object->finalize = g_type_memory_finalize;  } @@ -143,7 +98,7 @@ static void g_type_memory_init(GTypeMemory *tpmem)  /******************************************************************************  *                                                                             * -*  Paramètres  : tpmem = instance d'objet GLib à traiter.                     * +*  Paramètres  : object = instance d'objet GLib à traiter.                    *  *                                                                             *  *  Description : Supprime toutes les références externes.                     *  *                                                                             * @@ -153,10 +108,13 @@ static void g_type_memory_init(GTypeMemory *tpmem)  *                                                                             *  ******************************************************************************/ -static void g_type_memory_dispose(GTypeMemory *tpmem) +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++) @@ -167,14 +125,14 @@ static void g_type_memory_dispose(GTypeMemory *tpmem)      g_mutex_clear(&tpmem->mutex); -    G_OBJECT_CLASS(g_type_memory_parent_class)->dispose(G_OBJECT(tpmem)); +    G_OBJECT_CLASS(g_type_memory_parent_class)->dispose(object);  }  /******************************************************************************  *                                                                             * -*  Paramètres  : tpmem = instance d'objet GLib à traiter.                     * +*  Paramètres  : object = instance d'objet GLib à traiter.                    *  *                                                                             *  *  Description : Procède à la libération totale de la mémoire.                *  *                                                                             * @@ -184,12 +142,16 @@ static void g_type_memory_dispose(GTypeMemory *tpmem)  *                                                                             *  ******************************************************************************/ -static void g_type_memory_finalize(GTypeMemory *tpmem) +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(G_OBJECT(tpmem)); +    G_OBJECT_CLASS(g_type_memory_parent_class)->finalize(object);  } @@ -220,7 +182,7 @@ GTypeMemory *g_type_memory_new(void)  /******************************************************************************  *                                                                             *  *  Paramètres  : tpmem = mémoire à compléter.                                 * -*                pbuf  = zone tampon à lire.                                  * +*                fd    = flux ouvert en lecture.                              *  *                                                                             *  *  Description : Apprend tous les types mémorisés dans un tampon.             *  *                                                                             * @@ -230,14 +192,14 @@ GTypeMemory *g_type_memory_new(void)  *                                                                             *  ******************************************************************************/ -bool g_type_memory_load_types(GTypeMemory *tpmem, packed_buffer_t *pbuf) +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          */ -    rle_string str;                         /* Chaîne à charger            */ +    sized_binary_t str;                     /* Chaîne à charger            */ -    result = unpack_uleb128(&count, pbuf); +    result = load_uleb128(&count, fd);      if (result)      { @@ -248,35 +210,27 @@ bool g_type_memory_load_types(GTypeMemory *tpmem, packed_buffer_t *pbuf)          assert(tpmem->gtypes == NULL);          tpmem->gtypes = calloc(count, sizeof(gtype_ref_info_t)); -        setup_empty_rle_string(&str); -          for (i = 0; i < tpmem->count && result; i++)          { -            result = unpack_rle_string(&str, pbuf); +            result = load_sized_binary_as_string(&str, fd);              if (!result) break; -            if (get_rle_string(&str) == NULL) -            { -                exit_rle_string(&str); -                break; -            } - -            tpmem->gtypes[i].gtype = g_type_from_name(get_rle_string(&str)); +            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'", get_rle_string(&str)); +                log_variadic_message(LMT_ERROR, "Unknown type: '%s'", str.data);              else                  tpmem->gtypes[i].gclass = g_type_class_ref(tpmem->gtypes[i].gtype); -            exit_rle_string(&str); +            exit_sized_binary(&str);          } -    } +        g_mutex_unlock(&tpmem->mutex); -    g_mutex_unlock(&tpmem->mutex); +    }      return result; @@ -285,38 +239,40 @@ bool g_type_memory_load_types(GTypeMemory *tpmem, packed_buffer_t *pbuf)  /******************************************************************************  *                                                                             * -*  Paramètres  : tpmem = mémoire à manipuler.                                 * -*                pbuf  = zone tampon à venir lire.                            * +*  Paramètres  : tpmem = mémoire à consulter.                                 * +*                fd    = flux ouvert en écriture.                             *  *                                                                             * -*  Description : Crée une nouvelle instance d'objet à partir de son type.     * +*  Description : Enregistre tous les types mémorisés dans un tampon.          *  *                                                                             * -*  Retour      : Instance issue de l'opération ou NULL.                       * +*  Retour      : Bilan de l'opération.                                        *  *                                                                             *  *  Remarques   : -                                                            *  *                                                                             *  ******************************************************************************/ -GObject *g_type_memory_create_object(GTypeMemory *tpmem, packed_buffer_t *pbuf) +bool g_type_memory_store(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    */ +    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          */ -    result = NULL; +    g_mutex_lock(&tpmem->mutex); -    status = unpack_uleb128(&index, pbuf); +    result = store_uleb128((uleb128_t []){ tpmem->count }, fd); -    if (status) +    for (i = 0; i < tpmem->count && result; i++)      { -        g_mutex_lock(&tpmem->mutex); +        name = g_type_name(tpmem->gtypes[i].gtype); -        if (index < tpmem->count) -            result = g_object_new(tpmem->gtypes[index].gtype, NULL); +        setup_sized_binary_from_static_string(&str, name); -        g_mutex_unlock(&tpmem->mutex); +        store_sized_binary_as_string(&str, fd);      } +    g_mutex_unlock(&tpmem->mutex); +      return result;  } @@ -325,60 +281,35 @@ GObject *g_type_memory_create_object(GTypeMemory *tpmem, packed_buffer_t *pbuf)  /******************************************************************************  *                                                                             *  *  Paramètres  : tpmem = mémoire à manipuler.                                 * -*                obj   = instance dont le type est à mémoriser.               * -*                pbuf  = zone tampon à remplir. [OUT]                         * +*                fd    = flux ouvert en lecture.                              *  *                                                                             * -*  Description : Sauvegarde le type d'un objet instancié.                     * +*  Description : Crée une nouvelle instance d'objet à partir de son type.     *  *                                                                             * -*  Retour      : Bilan de l'opération.                                        * +*  Retour      : Instance issue de l'opération ou NULL.                       *  *                                                                             *  *  Remarques   : -                                                            *  *                                                                             *  ******************************************************************************/ -bool g_type_memory_store_object_gtype(GTypeMemory *tpmem, GObject *obj, packed_buffer_t *pbuf) +GObject *g_type_memory_create_object_from_gtype(GTypeMemory *tpmem, int fd)  { -    bool result;                            /* Bilan à retourner           */ -    GType gtype;                            /* Type à enregistrer          */ -    size_t index;                           /* Indice du point d'insertion */ - -    gtype = G_TYPE_FROM_INSTANCE(obj); +    GObject *result;                        /* Nouvelle instance à renvoyer*/ +    uleb128_t index;                        /* Indice du point d'insertion */ +    bool status;                            /* Bilan d'une récupération    */ -    /** -     * Pour quelques explications sur l'esquive suivante, se rapporter aux -     * commentaires de g_target_operand_unserialize(). -     * -     * Dans la situation présente, on ne doit pas enregistrer le type dans le tampon, -     * car l'opérande va relancer l'opération entière (avec un opérande temporaire), -     * ce qui conduirait à l'enregistrement de deux types successifs dans les données. -     */ +    result = NULL; -    if (gtype == G_TYPE_TARGET_OPERAND) -        result = true; +    status = load_uleb128(&index, fd); -    else +    if (status)      {          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)); - -            assert(tpmem->count > 0); - -            tpmem->gtypes[index].gtype = gtype; -            tpmem->gtypes[index].gclass = g_type_class_ref(gtype); - -        } +        if (index < tpmem->count) +            result = g_object_new(tpmem->gtypes[index].gtype, NULL);          g_mutex_unlock(&tpmem->mutex); -        result = pack_uleb128((uleb128_t []){ index }, pbuf); -      }      return result; @@ -388,10 +319,11 @@ bool g_type_memory_store_object_gtype(GTypeMemory *tpmem, GObject *obj, packed_b  /******************************************************************************  *                                                                             * -*  Paramètres  : tpmem = mémoire à consulter.                                 * -*                pbuf  = zone tampon à remplir. [OUT]                         * +*  Paramètres  : tpmem = mémoire à manipuler.                                 * +*                obj   = instance dont le type est à mémoriser.               * +*                fd    = flux ouvert en écriture.                             *  *                                                                             * -*  Description : Enregistre tous les types mémorisés dans un tampon.          * +*  Description : Sauvegarde le type d'un objet instancié.                     *  *                                                                             *  *  Retour      : Bilan de l'opération.                                        *  *                                                                             * @@ -399,31 +331,33 @@ bool g_type_memory_store_object_gtype(GTypeMemory *tpmem, GObject *obj, packed_b  *                                                                             *  ******************************************************************************/ -bool g_type_memory_store_types(GTypeMemory *tpmem, packed_buffer_t *pbuf) +bool g_type_memory_store_object_gtype(GTypeMemory *tpmem, GObject *obj, int fd)  { -    bool result;                            /* Bilan à enregistrer         */ -    uint64_t i;                             /* Boucle de parcours          */ -    const gchar *name;                      /* Désignation d'un type       */ -    rle_string str;                         /* Chaîne à conserver          */ +    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); -    result = pack_uleb128((uleb128_t []){ tpmem->count }, pbuf); +    for (index = 0; index < tpmem->count; index++) +        if (tpmem->gtypes[index].gtype == gtype) +            break; -    for (i = 0; i < tpmem->count && result; i++) +    if (index == tpmem->count)      { -        name = g_type_name(tpmem->gtypes[i].gtype); - -        init_static_rle_string(&str, name); +        tpmem->gtypes = realloc(tpmem->gtypes, ++tpmem->count * sizeof(gtype_ref_info_t)); -        result = pack_rle_string(&str, pbuf); - -        exit_rle_string(&str); +        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];  } diff --git a/src/glibext/work-int.h b/src/glibext/work-int.h index 4f84e86..58293e5 100644 --- a/src/glibext/work-int.h +++ b/src/glibext/work-int.h @@ -1,8 +1,8 @@  /* Chrysalide - Outil d'analyse de fichiers binaires - * delayed-int.h - définitions internes pour la gestion des travaux différés + * work-int.h - définitions internes pour la gestion des travaux différés   * - * Copyright (C) 2009-2018 Cyrille Bagard + * Copyright (C) 2009-2024 Cyrille Bagard   *   *  This file is part of Chrysalide.   * @@ -21,27 +21,26 @@   */ -#ifndef _GLIBEXT_DELAYED_INT_H -#define _GLIBEXT_DELAYED_INT_H +#ifndef _GLIBEXT_WORK_INT_H +#define _GLIBEXT_WORK_INT_H -#include "delayed.h" +#include "work.h" -#include "notifier.h" -#include "../common/dllist.h" +#include <stdbool.h> +#include "../common/dllist.h" -/* -------------------------- TACHE DIFFEREE DANS LE TEMPS -------------------------- */  /* Traite un travail programmé. */ -typedef void (* run_task_fc) (GDelayedWork *, GtkStatusStack *); +typedef void (* run_work_fc) (GGenericWork *);  /* Travail différé (instance) */ -struct _GDelayedWork +struct _GGenericWork  {      GObject parent;                         /* A laisser en premier        */ @@ -54,22 +53,18 @@ struct _GDelayedWork  };  /* Travail différé (classe) */ -struct _GDelayedWorkClass +struct _GGenericWorkClass  {      GObjectClass parent;                    /* A laisser en premier        */ -    run_task_fc run;                        /* Traitement externalisé      */ +    run_work_fc run;                        /* Traitement externalisé      */      /* Signaux */ -    void (* work_completed) (GDelayedWork *); +    void (* work_completed) (GGenericWork *);  }; -#define delayed_work_list_add_tail(new, head) dl_list_add_tail(new, head, GDelayedWork, link) -#define delayed_work_list_del(item, head) dl_list_del(item, head, GDelayedWork, link) - - -#endif  /* _GLIBEXT_DELAYED_INT_H */ +#endif  /* _GLIBEXT_WORK_INT_H */ diff --git a/src/glibext/work.c b/src/glibext/work.c index 6b5ac35..218fcf8 100644 --- a/src/glibext/work.c +++ b/src/glibext/work.c @@ -1,8 +1,8 @@  /* Chrysalide - Outil d'analyse de fichiers binaires - * delayed.c - gestion des travaux différés + * work.c - gestion des travaux différés   * - * Copyright (C) 2009-2018 Cyrille Bagard + * Copyright (C) 2009-2024 Cyrille Bagard   *   *  This file is part of Chrysalide.   * @@ -21,178 +21,29 @@   */ -#include "delayed.h" +#include "work.h" -#include <assert.h> -#include <inttypes.h> -#include <malloc.h> -#include <stdio.h> -#include <string.h> +#include "work-int.h" -#include "delayed-int.h" -#include "../core/nproc.h" -#ifdef INCLUDE_GTK_SUPPORT -#   include "../gui/core/global.h" -#endif - - - -/* -------------------------- TACHE DIFFEREE DANS LE TEMPS -------------------------- */ -  /* Initialise la classe des travaux différés. */ -static void g_delayed_work_class_init(GDelayedWorkClass *); +static void g_generic_work_class_init(GGenericWorkClass *);  /* Initialise une instance de travail différé. */ -static void g_delayed_work_init(GDelayedWork *); +static void g_generic_work_init(GGenericWork *);  /* Supprime toutes les références externes. */ -static void g_delayed_work_dispose(GDelayedWork *); +static void g_generic_work_dispose(GGenericWork *);  /* Procède à la libération totale de la mémoire. */ -static void g_delayed_work_finalize(GDelayedWork *); - -/* Mène l'opération programmée. */ -static void g_delayed_work_process(GDelayedWork *, GtkStatusStack *); - - - -/* -------------------------- THREAD DE TRAITEMENTS DEDIES -------------------------- */ - - -#define G_TYPE_WORK_GROUP               g_work_group_get_type() -#define G_WORK_GROUP(obj)               (G_TYPE_CHECK_INSTANCE_CAST((obj), g_work_group_get_type(), GWorkGroup)) -#define G_IS_WORK_GROUP(obj)            (G_TYPE_CHECK_INSTANCE_TYPE((obj), g_work_group_get_type())) -#define G_WORK_GROUP_CLASS(klass)       (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_WORK_GROUP, GWorkGroupClass)) -#define G_IS_WORK_GROUP_CLASS(klass)    (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_WORK_GROUP)) -#define G_WORK_GROUP_GET_CLASS(obj)     (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_WORK_GROUP, GWorkGroupClass)) - - -/* File de traitement pour un type donné (instance) */ -typedef struct _GWorkGroup -{ -    GObject parent;                         /* A laisser en premier        */ - -    wgroup_id_t id;                         /* Identifiant de travaux menés*/ - -    GDelayedWork *works;                    /* Tâches à mener à bien       */ -    GMutex mutex;                           /* Verrou pour l'accès         */ -    GCond cond;                             /* Réveil pour un traitement   */ -    GCond wait_cond;                        /* Réveil d'attente de fin     */ -    gint pending;                           /* Tâches en cours d'exécution */ - -    GThread **threads;                      /* Procédure de traitement     */ -    guint threads_count;                    /* Nombre de procédures        */ -    bool force_exit;                        /* Procédure d'arrêt           */ - -    wait_for_incoming_works_cb callback;    /* Encadre les attentes de fin */ -    void *data;                             /* Données à associer          */ - -} GWorkGroup; - -/* File de traitement pour un type donné (classe) */ -typedef struct _GWorkGroupClass -{ -    GObjectClass parent;                    /* A laisser en premier        */ - -} GWorkGroupClass; - - -/* Indique le type défini pour les groupes de travail. */ -static GType g_work_group_get_type(void); - -/* Initialise la classe des groupes de travail. */ -static void g_work_group_class_init(GWorkGroupClass *); - -/* Initialise une instance de groupe de travail. */ -static void g_work_group_init(GWorkGroup *); - -/* Supprime toutes les références externes. */ -static void g_work_group_dispose(GWorkGroup *); - -/* Procède à la libération totale de la mémoire. */ -static void g_work_group_finalize(GWorkGroup *); - -/* Crée un nouveau thread dédié à un type de travaux donné. */ -static GWorkGroup *g_work_group_new(wgroup_id_t, const guint *); - -/* Fournit l'identifiant associé à un groupe de travail. */ -static wgroup_id_t g_work_group_get_id(const GWorkGroup *); - -/* Place une nouvelle tâche en attente dans une file dédiée. */ -static void g_work_group_schedule(GWorkGroup *, GDelayedWork *); - -/* Assure le traitement en différé. */ -static void *g_work_group_process(GWorkGroup *); - -/* Détermine si le groupe est vide de toute programmation. */ -static bool g_work_group_is_empty(GWorkGroup *); - -/* Attend que toutes les tâches d'un groupe soient traitées. */ -static void g_work_group_wait_for_completion(GWorkGroup *, GWorkQueue *); - -/* Modifie les conditions d'attente des fins d'exécutions. */ -static void g_work_group_set_extra_wait_callback(GWorkGroup *, wait_for_incoming_works_cb, void *); - -/* Force un réveil d'une attente en cours pour la confirmer. */ -static void g_work_group_wake_up_waiters(GWorkGroup *); - - +static void g_generic_work_finalize(GGenericWork *); -/* ------------------------- TRAITEMENT DE TACHES DIFFEREES ------------------------- */ - - -/* Gestionnaire des travaux différés (instance) */ -struct _GWorkQueue -{ -    GObject parent;                         /* A laisser en premier        */ - -    wgroup_id_t generator;                  /* Générateur d'identifiants   */ - -    GWorkGroup **groups;                    /* Files de traitement         */ -    size_t groups_count;                    /* Nombre de files internes    */ -    GMutex mutex;                           /* Verrou pour l'accès         */ -    GCond wait_all;                         /* Réveil d'attente globale    */ - -}; - -/* Gestionnaire des travaux différés (classe) */ -struct _GWorkQueueClass -{ -    GObjectClass parent;                    /* A laisser en premier        */ - -}; - - -/* Initialise la classe des travaux différés. */ -static void g_work_queue_class_init(GWorkQueueClass *); - -/* Initialise une instance de gestionnaire de travaux différés. */ -static void g_work_queue_init(GWorkQueue *); - -/* Supprime toutes les références externes. */ -static void g_work_queue_dispose(GWorkQueue *); - -/* Procède à la libération totale de la mémoire. */ -static void g_work_queue_finalize(GWorkQueue *); - -/* Donne l'assurance de l'existence d'un groupe de travail. */ -static bool g_work_queue_ensure_group_exists(GWorkQueue *, wgroup_id_t, const guint *); - -/* Fournit le groupe de travail correspondant à un identifiant. */ -static GWorkGroup *g_work_queue_find_group_for_id(GWorkQueue *, wgroup_id_t); - - - -/* ---------------------------------------------------------------------------------- */ -/*                            TACHE DIFFEREE DANS LE TEMPS                            */ -/* ---------------------------------------------------------------------------------- */  /* Indique le type défini pour les travaux différés. */ -G_DEFINE_TYPE(GDelayedWork, g_delayed_work, G_TYPE_OBJECT); +G_DEFINE_TYPE(GGenericWork, g_generic_work, G_TYPE_OBJECT);  /****************************************************************************** @@ -207,19 +58,19 @@ G_DEFINE_TYPE(GDelayedWork, g_delayed_work, G_TYPE_OBJECT);  *                                                                             *  ******************************************************************************/ -static void g_delayed_work_class_init(GDelayedWorkClass *klass) +static void g_generic_work_class_init(GGenericWorkClass *klass)  {      GObjectClass *object;                   /* Autre version de la classe  */      object = G_OBJECT_CLASS(klass); -    object->dispose = (GObjectFinalizeFunc/* ! */)g_delayed_work_dispose; -    object->finalize = (GObjectFinalizeFunc)g_delayed_work_finalize; +    object->dispose = (GObjectFinalizeFunc/* ! */)g_generic_work_dispose; +    object->finalize = (GObjectFinalizeFunc)g_generic_work_finalize;      g_signal_new("work-completed", -                 G_TYPE_DELAYED_WORK, +                 G_TYPE_GENERIC_WORK,                   G_SIGNAL_RUN_LAST, -                 G_STRUCT_OFFSET(GDelayedWorkClass, work_completed), +                 G_STRUCT_OFFSET(GGenericWorkClass, work_completed),                   NULL, NULL,                   g_cclosure_marshal_VOID__VOID,                   G_TYPE_NONE, 0); @@ -239,8 +90,10 @@ static void g_delayed_work_class_init(GDelayedWorkClass *klass)  *                                                                             *  ******************************************************************************/ -static void g_delayed_work_init(GDelayedWork *work) +static void g_generic_work_init(GGenericWork *work)  { +    DL_LIST_ITEM_INIT(&work->link); +      work->completed = false;      g_mutex_init(&work->mutex);      g_cond_init(&work->cond); @@ -260,12 +113,12 @@ static void g_delayed_work_init(GDelayedWork *work)  *                                                                             *  ******************************************************************************/ -static void g_delayed_work_dispose(GDelayedWork *work) +static void g_generic_work_dispose(GGenericWork *work)  {      g_mutex_clear(&work->mutex);      g_cond_clear(&work->cond); -    G_OBJECT_CLASS(g_delayed_work_parent_class)->dispose(G_OBJECT(work)); +    G_OBJECT_CLASS(g_generic_work_parent_class)->dispose(G_OBJECT(work));  } @@ -282,281 +135,19 @@ static void g_delayed_work_dispose(GDelayedWork *work)  *                                                                             *  ******************************************************************************/ -static void g_delayed_work_finalize(GDelayedWork *work) -{ -    G_OBJECT_CLASS(g_delayed_work_parent_class)->finalize(G_OBJECT(work)); - -} - - -/****************************************************************************** -*                                                                             * -*  Paramètres  : work   = travail à effectuer.                                * -*                status = barre de statut à tenir informée.                   * -*                                                                             * -*  Description : Mène l'opération programmée.                                 * -*                                                                             * -*  Retour      : -                                                            * -*                                                                             * -*  Remarques   : -                                                            * -*                                                                             * -******************************************************************************/ - -static void g_delayed_work_process(GDelayedWork *work, GtkStatusStack *status) -{ -    G_DELAYED_WORK_GET_CLASS(work)->run(work, status); - -    g_mutex_lock(&work->mutex); - -    work->completed = true; - -    g_cond_signal(&work->cond); -    g_mutex_unlock(&work->mutex); - -    g_signal_emit_by_name(work, "work-completed"); - -} - - -/****************************************************************************** -*                                                                             * -*  Paramètres  : work = travail à surveiller.                                 * -*                                                                             * -*  Description : Attend la fin de l'exécution d'une tâche donnée.             * -*                                                                             * -*  Retour      : -                                                            * -*                                                                             * -*  Remarques   : -                                                            * -*                                                                             * -******************************************************************************/ - -void g_delayed_work_wait_for_completion(GDelayedWork *work) -{ -    g_mutex_lock(&work->mutex); - -    while (!work->completed) -        g_cond_wait(&work->cond, &work->mutex); - -    g_mutex_unlock(&work->mutex); - -} - - - -/* ---------------------------------------------------------------------------------- */ -/*                           THREADS DES TRAITEMENTS DEDIES                           */ -/* ---------------------------------------------------------------------------------- */ - - -/* Indique le type défini pour les groupes de travail. */ -G_DEFINE_TYPE(GWorkGroup, g_work_group, G_TYPE_OBJECT); - - -/****************************************************************************** -*                                                                             * -*  Paramètres  : klass = classe à initialiser.                                * -*                                                                             * -*  Description : Initialise la classe des groupes de travail.                 * -*                                                                             * -*  Retour      : -                                                            * -*                                                                             * -*  Remarques   : -                                                            * -*                                                                             * -******************************************************************************/ - -static void g_work_group_class_init(GWorkGroupClass *klass) -{ -    GObjectClass *object;                   /* Autre version de la classe  */ - -    object = G_OBJECT_CLASS(klass); - -    object->dispose = (GObjectFinalizeFunc/* ! */)g_work_group_dispose; -    object->finalize = (GObjectFinalizeFunc)g_work_group_finalize; - -} - - -/****************************************************************************** -*                                                                             * -*  Paramètres  : group = instance à initialiser.                              * -*                                                                             * -*  Description : Initialise une instance de groupe de travail.                * -*                                                                             * -*  Retour      : -                                                            * -*                                                                             * -*  Remarques   : -                                                            * -*                                                                             * -******************************************************************************/ - -static void g_work_group_init(GWorkGroup *group) -{ -    group->works = NULL; - -    g_mutex_init(&group->mutex); -    g_cond_init(&group->cond); -    g_cond_init(&group->wait_cond); - -    g_atomic_int_set(&group->pending, 0); - -    group->threads = NULL; -    group->threads_count = 0; -    group->force_exit = false; - -    group->callback = NULL; -    group->data = NULL; - -} - - -/****************************************************************************** -*                                                                             * -*  Paramètres  : queue = instance d'objet GLib à traiter.                     * -*                                                                             * -*  Description : Supprime toutes les références externes.                     * -*                                                                             * -*  Retour      : -                                                            * -*                                                                             * -*  Remarques   : -                                                            * -*                                                                             * -******************************************************************************/ - -static void g_work_group_dispose(GWorkGroup *group) -{ -    guint i;                                /* Boucle de parcours          */ -    GDelayedWork *work;                     /* Travail à oublier           */ - -    group->force_exit = true; - -    /** -     * Concernant la pose du verrou, se référer aux commentaires de la -     * fonction g_work_group_process(). -     */ - -    g_mutex_lock(&group->mutex); - -    g_cond_broadcast(&group->cond); - -    g_mutex_unlock(&group->mutex); - -    for (i = 0; i < group->threads_count; i++) -        g_thread_join(group->threads[i]); - -    while (!dl_list_empty(group->works)) -    { -        work = group->works; -        delayed_work_list_del(work, &group->works); - -        g_object_unref(G_OBJECT(work)); - -    } - -    g_mutex_clear(&group->mutex); -    g_cond_clear(&group->cond); -    g_cond_clear(&group->wait_cond); - -    G_OBJECT_CLASS(g_work_group_parent_class)->dispose(G_OBJECT(group)); - -} - - -/****************************************************************************** -*                                                                             * -*  Paramètres  : group = instance d'objet GLib à traiter.                     * -*                                                                             * -*  Description : Procède à la libération totale de la mémoire.                * -*                                                                             * -*  Retour      : -                                                            * -*                                                                             * -*  Remarques   : -                                                            * -*                                                                             * -******************************************************************************/ - -static void g_work_group_finalize(GWorkGroup *group) -{ -    if (group->threads != NULL) -        free(group->threads); - -    G_OBJECT_CLASS(g_work_group_parent_class)->finalize(G_OBJECT(group)); - -} - - -/****************************************************************************** -*                                                                             * -*  Paramètres  : id    = identifiant accordé au nouveau groupe.               * -*                count = quantité de threads à allouer.                       * -*                                                                             * -*  Description : Crée un nouveau thread dédié à un type de travaux donné.     * -*                                                                             * -*  Retour      : Structure associée au thread mise en place.                  * -*                                                                             * -*  Remarques   : -                                                            * -*                                                                             * -******************************************************************************/ - -static GWorkGroup *g_work_group_new(wgroup_id_t id, const guint *count) -{ -    GWorkGroup *result;                    /* Traiteur à retourner        */ -    guint i;                                /* Boucle de parcours          */ -    char name[16];                          /* Désignation humaine         */ - -    result = g_object_new(G_TYPE_WORK_GROUP, NULL); - -    result->id = id; - -    result->threads_count = get_max_online_threads(); - -    if (count != NULL && *count < result->threads_count) -        result->threads_count = *count; - -    result->threads = (GThread **)calloc(result->threads_count, sizeof(GThread *)); - -    for (i = 0; i < result->threads_count; i++) -    { -        snprintf(name, sizeof(name), "wgrp_%" PRIu64 "-%u", id, i); - -        result->threads[i] = g_thread_new(name, (GThreadFunc)g_work_group_process, result); -        if (!result->threads[i]) -            goto start_error; - -    } - - start_error: - -    result->threads_count = i; - -    assert(i > 0); - -    return result; - -} - - -/****************************************************************************** -*                                                                             * -*  Paramètres  : group = gestionnaire des actions à mener.                    * -*                                                                             * -*  Description : Fournit l'identifiant associé à un groupe de travail.        * -*                                                                             * -*  Retour      : Identifiant unique attribué au groupe de travail.            * -*                                                                             * -*  Remarques   : -                                                            * -*                                                                             * -******************************************************************************/ - -static wgroup_id_t g_work_group_get_id(const GWorkGroup *group) +static void g_generic_work_finalize(GGenericWork *work)  { -    return group->id; +    G_OBJECT_CLASS(g_generic_work_parent_class)->finalize(G_OBJECT(work));  }  /******************************************************************************  *                                                                             * -*  Paramètres  : group = gestionnaire des actions à mener.                    * -*                work  = nouvelle tâche à programmer, puis effectuer.         * +*  Paramètres  : work = travail à traiter.                                    * +*                list = ensemble de travaux à considérer. [OUT]               *  *                                                                             * -*  Description : Place une nouvelle tâche en attente dans une file dédiée.    * +*  Description : Intègre un travail dans une liste de tâches à effectuer.     *  *                                                                             *  *  Retour      : -                                                            *  *                                                                             * @@ -564,161 +155,19 @@ static wgroup_id_t g_work_group_get_id(const GWorkGroup *group)  *                                                                             *  ******************************************************************************/ -static void g_work_group_schedule(GWorkGroup *group, GDelayedWork *work) +void g_generic_work_add_to_list(GGenericWork *work, GGenericWork **list)  { -    g_mutex_lock(&group->mutex); - -    g_atomic_int_inc(&group->pending); - -    delayed_work_list_add_tail(work, &group->works); - -    g_cond_signal(&group->cond); - -    g_mutex_unlock(&group->mutex); +    dl_list_add_tail(work, list, GGenericWork, link);  }  /******************************************************************************  *                                                                             * -*  Paramètres  : group = gestionnaire des actions à mener.                    * -*                                                                             * -*  Description : Assure le traitement en différé.                             * -*                                                                             * -*  Retour      : Bilan de l'opération.                                        * -*                                                                             * -*  Remarques   : -                                                            * -*                                                                             * -******************************************************************************/ - -static void *g_work_group_process(GWorkGroup *group) -{ -    GDelayedWork *work;                     /* Traitement à mener          */ -    GtkStatusStack *status;                 /* Zone d'info éventuelle      */ - -    while (1) -    { -        g_mutex_lock(&group->mutex); - -        while (dl_list_empty(group->works) && !group->force_exit) -            g_cond_wait(&group->cond, &group->mutex); - -        if (group->force_exit) -        { -            g_mutex_unlock(&group->mutex); -            break; -        } - -        work = group->works; -        delayed_work_list_del(work, &group->works); - -        g_mutex_unlock(&group->mutex); - -#ifdef INCLUDE_GTK_SUPPORT -        status = get_global_status(); -#else -        status = NULL; -#endif -        g_delayed_work_process(work, status); - -        g_object_unref(G_OBJECT(work)); - -        /** -         * Verrou ou pas verrou ? -         * -         * La documentation de la GLib indique que ce n'est pas nécessaire : -         * -         *    ''' -         *    It is good practice to lock the same mutex as the waiting threads -         *    while calling this function, though not required. -         *    ''' -         * -         * Ce conseil se trouve verbatim à l'adresse : -         * -         *    https://developer.gnome.org/glib/stable/glib-Threads.html#g-cond-broadcast -         * -         * Dans la pratique, il peut arriver que l'attente de la fonction -         * g_work_group_wait_for_completion() ne soit jamais interrompue. -         * -         * La documentation POSIX est un peu plus orientée : -         * -         *    ''' -         *    The pthread_cond_broadcast() functions may be called by a thread -         *    whether or not it currently owns the mutex that threads calling -         *    pthread_cond_wait() have associated with the condition variable -         *    during their waits; however, if predictable scheduling behavior is -         *    required, then that mutex shall be locked by the thread calling -         *    pthread_cond_broadcast(). -         *    ''' -         * -         * Ce passage complet est consultable à l'adresse : -         * -         *    http://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_cond_broadcast.html -         * -         * La page de manuel pthread_cond_broadcast(3) est quant à elle plus -         * directrice : aucun complément d'information sur le sujet n'est fourni -         * et les exemples associés utilisent implicement un verrou pendant -         * sont appel. -         */ - -        g_mutex_lock(&group->mutex); - -        if (g_atomic_int_dec_and_test(&group->pending)) -            g_cond_broadcast(&group->wait_cond); - -        g_mutex_unlock(&group->mutex); - -    } - -    return NULL; - -} - - -/****************************************************************************** -*                                                                             * -*  Paramètres  : group = gestionnaire des actions à consulter.                * -*                                                                             * -*  Description : Détermine si le groupe est vide de toute programmation.      * +*  Paramètres  : work = travail à traiter.                                    * +*                list = ensemble de travaux à considérer. [OUT]               *  *                                                                             * -*  Retour      : Etat du groupe de travail.                                   * -*                                                                             * -*  Remarques   : -                                                            * -*                                                                             * -******************************************************************************/ - -static bool g_work_group_is_empty(GWorkGroup *group) -{ -    bool result;                            /* Etat à retourner            */ - -    /** -     * Pour que le résultat soit exploitable, il ne doit pas varier -     * en dehors de la zone couverte par le verrou du groupe avant -     * son utilisation par l'appelant. -     * -     * Il doit donc logiquement y avoir un autre verrou en amont et, -     * comme à priori on ne devrait pas bloquer les groupes principaux -     * pour un traitement particulier, cette procédure ne devrait concerner -     * que des groupes dynamiques. -     */ - -    g_mutex_lock(&group->mutex); - -    result = dl_list_empty(group->works); - -    g_mutex_unlock(&group->mutex); - -    return result; - -} - - -/****************************************************************************** -*                                                                             * -*  Paramètres  : group = groupe dont les conclusions sont attendues.          * -*                queue = queue d'appartenance pour les appels externes.       * -*                                                                             * -*  Description : Attend que toutes les tâches d'un groupe soient traitées.    * +*  Description : Supprime un travail d'une liste de tâches à effectuer.       *  *                                                                             *  *  Retour      : -                                                            *  *                                                                             * @@ -726,530 +175,18 @@ static bool g_work_group_is_empty(GWorkGroup *group)  *                                                                             *  ******************************************************************************/ -static void g_work_group_wait_for_completion(GWorkGroup *group, GWorkQueue *queue) +void g_generic_work_remove_from_list(GGenericWork *work, GGenericWork **list)  { -    wait_for_incoming_works_cb callback;    /* Procédure complémentaire    */ - -    bool no_extra_check(GWorkQueue *_q, wgroup_id_t _id, void *_data) -    { -        return false; -    } - -    callback = group->callback != NULL ? group->callback : no_extra_check; - -    g_mutex_lock(&group->mutex); - -    /** -     * On attend que : -     *  - la liste des tâches programmées soit vide. -     *  - il n'existe plus de tâche en cours. -     *  - rien n'indique que de nouvelles tâches supplémentaires vont arriver. -     */ - -    while ((g_atomic_int_get(&group->pending) > 0 || callback(queue, group->id, group->data)) -           && !group->force_exit) -    { -        g_cond_wait(&group->wait_cond, &group->mutex); -    } - -    g_mutex_unlock(&group->mutex); +    dl_list_del(work, list, GGenericWork, link);  }  /******************************************************************************  *                                                                             * -*  Paramètres  : group    = groupe dont les paramètres sont à modifier.       * -*                callback = éventuelle fonction à appeler ou NULL.            * -*                data     = données devant accompagner l'appel.               * -*                                                                             * -*  Description : Modifie les conditions d'attente des fins d'exécutions.      * -*                                                                             * -*  Retour      : -                                                            * -*                                                                             * -*  Remarques   : -                                                            * -*                                                                             * -******************************************************************************/ - -static void g_work_group_set_extra_wait_callback(GWorkGroup *group, wait_for_incoming_works_cb callback, void *data) -{ -    group->callback = callback; -    group->data = data; - -} - - -/****************************************************************************** +*  Paramètres  : work = travail à effectuer.                                  *  *                                                                             * -*  Paramètres  : queue    = gestionnaire de l'ensemble des groupes de travail.* -*                id       = identifiant d'un groupe de travail.               * -*                                                                             * -*  Description : Force un réveil d'une attente en cours pour la confirmer.    * -*                                                                             * -*  Retour      : -                                                            * -*                                                                             * -*  Remarques   : -                                                            * -*                                                                             * -******************************************************************************/ - -static void g_work_group_wake_up_waiters(GWorkGroup *group) -{ -    /** -     * Concernant la pose du verrou, se référer aux commentaires de la -     * fonction g_work_group_process(). -     */ - -    g_mutex_lock(&group->mutex); - -    g_cond_broadcast(&group->wait_cond); - -    g_mutex_unlock(&group->mutex); - -} - - - -/* ---------------------------------------------------------------------------------- */ -/*                           TRAITEMENT DE TACHES DIFFEREES                           */ -/* ---------------------------------------------------------------------------------- */ - - -/* Indique le type défini pour le gestionnaire des travaux différés. */ -G_DEFINE_TYPE(GWorkQueue, g_work_queue, G_TYPE_OBJECT); - - -/****************************************************************************** -*                                                                             * -*  Paramètres  : klass = classe à initialiser.                                * -*                                                                             * -*  Description : Initialise la classe des travaux différés.                   * -*                                                                             * -*  Retour      : -                                                            * -*                                                                             * -*  Remarques   : -                                                            * -*                                                                             * -******************************************************************************/ - -static void g_work_queue_class_init(GWorkQueueClass *klass) -{ -    GObjectClass *object;                   /* Autre version de la classe  */ - -    object = G_OBJECT_CLASS(klass); - -    object->dispose = (GObjectFinalizeFunc/* ! */)g_work_queue_dispose; -    object->finalize = (GObjectFinalizeFunc)g_work_queue_finalize; - -} - - -/****************************************************************************** -*                                                                             * -*  Paramètres  : queue = instance à initialiser.                              * -*                                                                             * -*  Description : Initialise une instance de gestionnaire de travaux différés. * -*                                                                             * -*  Retour      : -                                                            * -*                                                                             * -*  Remarques   : -                                                            * -*                                                                             * -******************************************************************************/ - -static void g_work_queue_init(GWorkQueue *queue) -{ -    queue->generator = 0; - -    queue->groups = NULL; -    queue->groups_count = 0; -    g_mutex_init(&queue->mutex); -    g_cond_init(&queue->wait_all); - -} - - -/****************************************************************************** -*                                                                             * -*  Paramètres  : queue = instance d'objet GLib à traiter.                     * -*                                                                             * -*  Description : Supprime toutes les références externes.                     * -*                                                                             * -*  Retour      : -                                                            * -*                                                                             * -*  Remarques   : -                                                            * -*                                                                             * -******************************************************************************/ - -static void g_work_queue_dispose(GWorkQueue *queue) -{ -    size_t i;                               /* Boucle de parcours          */ - -    g_mutex_lock(&queue->mutex); - -    for (i = 0; i < queue->groups_count; i++) -        g_clear_object(&queue->groups[i]); - -    g_mutex_unlock(&queue->mutex); - -    g_mutex_clear(&queue->mutex); -    g_cond_clear(&queue->wait_all); - -    G_OBJECT_CLASS(g_work_queue_parent_class)->dispose(G_OBJECT(queue)); - -} - - -/****************************************************************************** -*                                                                             * -*  Paramètres  : queue = instance d'objet GLib à traiter.                     * -*                                                                             * -*  Description : Procède à la libération totale de la mémoire.                * -*                                                                             * -*  Retour      : -                                                            * -*                                                                             * -*  Remarques   : -                                                            * -*                                                                             * -******************************************************************************/ - -static void g_work_queue_finalize(GWorkQueue *queue) -{ -    if (queue->groups != NULL) -        free(queue->groups); - -    G_OBJECT_CLASS(g_work_queue_parent_class)->finalize(G_OBJECT(queue)); - -} - - -/****************************************************************************** -*                                                                             * -*  Paramètres  : -                                                            * -*                                                                             * -*  Description : Créé un nouveau gestionnaire de tâches parallèles.           * -*                                                                             * -*  Retour      : Gestionnaire de traitements mis en place.                    * -*                                                                             * -*  Remarques   : -                                                            * -*                                                                             * -******************************************************************************/ - -GWorkQueue *g_work_queue_new(void) -{ -    GWorkQueue *result;                     /* Instance à retourner        */ - -    result = g_object_new(G_TYPE_WORK_QUEUE, NULL); - -    return result; - -} - - -/****************************************************************************** -*                                                                             * -*  Paramètres  : queue = gestionnaire de l'ensemble des groupes de travail.   * -*                id    = identifiant d'un groupe de travail.                  * -*                count = quantité de threads à allouer.                       * -*                                                                             * -*  Description : Donne l'assurance de l'existence d'un groupe de travail.     * -*                                                                             * -*  Retour      : true si un nouveau groupe a été constitué, false sinon.      * -*                                                                             * -*  Remarques   : Le verrou d'accès doit être posé par l'appelant.             * -*                                                                             * -******************************************************************************/ - -static bool g_work_queue_ensure_group_exists(GWorkQueue *queue, wgroup_id_t id, const guint *count) -{ -    bool found;                             /* Bilan des recherches        */ -    size_t i;                               /* Boucle de parcours          */ -    GWorkGroup *group;                      /* Groupe à consulter          */ - -    assert(!g_mutex_trylock(&queue->mutex)); - -    found = false; - -    for (i = 0; i < queue->groups_count && !found; i++) -    { -        group = queue->groups[i]; -        found = (g_work_group_get_id(group) == id); -    } - -    if (!found) -    { -        queue->groups_count++; -        queue->groups = (GWorkGroup **)realloc(queue->groups, -                                               queue->groups_count * sizeof(GWorkGroup *)); - -        group = g_work_group_new(id, count); -        queue->groups[queue->groups_count - 1] = group; - -    } - -    return !found; - -} - - -/****************************************************************************** -*                                                                             * -*  Paramètres  : queue = gestionnaire de l'ensemble des groupes de travail.   * -*                                                                             * -*  Description : Constitue un nouveau groupe de travail.                      * -*                                                                             * -*  Retour      : Nouvel identifiant unique d'un nouveau groupe de travail.    * -*                                                                             * -*  Remarques   : -                                                            * -*                                                                             * -******************************************************************************/ - -wgroup_id_t g_work_queue_define_work_group(GWorkQueue *queue) -{ -    wgroup_id_t result;                     /* Valeur à retourner          */ -    bool created;                           /* Bilan d'une tentative       */ - -    g_mutex_lock(&queue->mutex); - -    do -    { -        result = queue->generator++; -        created = g_work_queue_ensure_group_exists(queue, result, NULL); -    } -    while (!created); - -    g_mutex_unlock(&queue->mutex); - -    return result; - -} - - -/****************************************************************************** -*                                                                             * -*  Paramètres  : queue = gestionnaire de l'ensemble des groupes de travail.   * -*                count = quantité de threads à allouer.                       * -*                                                                             * -*  Description : Constitue un nouveau petit groupe de travail.                * -*                                                                             * -*  Retour      : Nouvel identifiant unique d'un nouveau groupe de travail.    * -*                                                                             * -*  Remarques   : -                                                            * -*                                                                             * -******************************************************************************/ - -wgroup_id_t g_work_queue_define_tiny_work_group(GWorkQueue *queue, guint count) -{ -    wgroup_id_t result;                     /* Valeur à retourner          */ -    bool created;                           /* Bilan d'une tentative       */ - -    g_mutex_lock(&queue->mutex); - -    do -    { -        result = queue->generator++; -        created = g_work_queue_ensure_group_exists(queue, result, &count); -    } -    while (!created); - -    g_mutex_unlock(&queue->mutex); - -    return result; - -} - - -/****************************************************************************** -*                                                                             * -*  Paramètres  : queue = gestionnaire de l'ensemble des groupes de travail.   * -*                id    = identifiant d'un groupe de travail.                  * -*                                                                             * -*  Description : Dissout un groupe de travail existant.                       * -*                                                                             * -*  Retour      : -                                                            * -*                                                                             * -*  Remarques   : -                                                            * -*                                                                             * -******************************************************************************/ - -void g_work_queue_delete_work_group(GWorkQueue *queue, wgroup_id_t id) -{ -    size_t i;                               /* Boucle de parcours          */ -    GWorkGroup *group;                      /* Groupe de travail manipulé  */ -#ifndef NDEBUG -    bool found;                             /* Repérage du groupe visé     */ -#endif - -#ifndef NDEBUG -    found = false; -#endif - -    g_mutex_lock(&queue->mutex); - -    for (i = 0; i < queue->groups_count; i++) -    { -        group = queue->groups[i]; - -        if (g_work_group_get_id(group) == id) -        { -            g_object_unref(G_OBJECT(group)); - -            memmove(&queue->groups[i], &queue->groups[i + 1], -                    (queue->groups_count - i - 1) * sizeof(GWorkGroup *)); - -            queue->groups_count--; -            queue->groups = (GWorkGroup **)realloc(queue->groups, -                                                   queue->groups_count * sizeof(GWorkGroup *)); - -#ifndef NDEBUG -            found = true; -#endif - -            break; - -        } - -    } - -    assert(found); - -    g_cond_broadcast(&queue->wait_all); - -    g_mutex_unlock(&queue->mutex); - -} - - -/****************************************************************************** -*                                                                             * -*  Paramètres  : queue = gestionnaire des actions à mener.                    * -*                work  = nouvelle tâche à programmer, puis effectuer.         * -*                id    = identifiant du groupe de travail d'affectation.      * -*                                                                             * -*  Description : Place une nouvelle tâche en attente.                         * -*                                                                             * -*  Retour      : -                                                            * -*                                                                             * -*  Remarques   : -                                                            * -*                                                                             * -******************************************************************************/ - -void g_work_queue_schedule_work(GWorkQueue *queue, GDelayedWork *work, wgroup_id_t id) -{ -    GWorkGroup *group;                      /* Groupe de travail à attendre*/ - -    group = g_work_queue_find_group_for_id(queue, id); -    assert(group != NULL); - -    g_work_group_schedule(group, work); - -    g_object_unref(G_OBJECT(group)); - -} - - -/****************************************************************************** -*                                                                             * -*  Paramètres  : queue = gestionnaire de l'ensemble des groupes de travail.   * -*                id    = identifiant d'un groupe de travail.                  * -*                                                                             * -*  Description : Fournit le groupe de travail correspondant à un identifiant. * -*                                                                             * -*  Retour      : Eventuel groupe existant trouvé ou NULL si aucun.            * -*                                                                             * -*  Remarques   : -                                                            * -*                                                                             * -******************************************************************************/ - -static GWorkGroup *g_work_queue_find_group_for_id(GWorkQueue *queue, wgroup_id_t id) -{ -    GWorkGroup *result;                     /* Trouvaille à retourner      */ -    size_t i;                               /* Boucle de parcours          */ - -    result = NULL; - -    g_mutex_lock(&queue->mutex); - -    for (i = 0; i < queue->groups_count; i++) -        if (g_work_group_get_id(queue->groups[i]) == id) -        { -            result = queue->groups[i]; -            g_object_ref(G_OBJECT(result)); -            break; -        } - -    g_mutex_unlock(&queue->mutex); - -    return result; - -} - - -/****************************************************************************** -*                                                                             * -*  Paramètres  : queue = gestionnaire de l'ensemble des groupes de travail.   * -*                id    = identifiant d'un groupe de travail.                  * -*                                                                             * -*  Description : Détermine si un groupe est vide de toute programmation.      * -*                                                                             * -*  Retour      : Etat du groupe de travail.                                   * -*                                                                             * -*  Remarques   : -                                                            * -*                                                                             * -******************************************************************************/ - -bool g_work_queue_is_empty(GWorkQueue *queue, wgroup_id_t id) -{ -    bool result;                            /* Etat à retourner            */ -    GWorkGroup *group;                      /* Groupe de travail à attendre*/ - -    group = g_work_queue_find_group_for_id(queue, id); - -    if (group != NULL) -    { -        result = g_work_group_is_empty(group); -        g_object_unref(G_OBJECT(group)); -    } - -    else -        result = true; - -    return result; - -} - - -/****************************************************************************** -*                                                                             * -*  Paramètres  : queue = gestionnaire de l'ensemble des groupes de travail.   * -*                id    = identifiant d'un groupe de travail.                  * -*                                                                             * -*  Description : Attend que toutes les tâches d'un groupe soient traitées.    * -*                                                                             * -*  Retour      : -                                                            * -*                                                                             * -*  Remarques   : -                                                            * -*                                                                             * -******************************************************************************/ - -void g_work_queue_wait_for_completion(GWorkQueue *queue, wgroup_id_t id) -{ -    GWorkGroup *group;                      /* Groupe de travail à attendre*/ - -    group = g_work_queue_find_group_for_id(queue, id); - -    if (group != NULL) -    { -        g_work_group_wait_for_completion(group, queue); -        g_object_unref(G_OBJECT(group)); -    } - -} - - -/****************************************************************************** -*                                                                             * -*  Paramètres  : queue    = gestionnaire de l'ensemble des groupes de travail.* -*                gb_ids   = identifiants de groupes globaux.                  * -*                gb_count = nombre de ces groupes globaux.                    * -*                                                                             * -*  Description : Attend que toutes les tâches de tout groupe soient traitées. * +*  Description : Mène l'opération programmée.                                 *  *                                                                             *  *  Retour      : -                                                            *  *                                                                             * @@ -1257,80 +194,27 @@ void g_work_queue_wait_for_completion(GWorkQueue *queue, wgroup_id_t id)  *                                                                             *  ******************************************************************************/ -void g_work_queue_wait_for_all_completions(GWorkQueue *queue, const wgroup_id_t *gb_ids, size_t gb_count) +void g_generic_work_process(GGenericWork *work)  { -    size_t i;                               /* Boucle de parcours          */ - -    g_mutex_lock(&queue->mutex); - - wait_again: - -    /** -     * Attente d'éventuels groupes isolés. -     */ - -    while (queue->groups_count > gb_count) -        g_cond_wait(&queue->wait_all, &queue->mutex); - -    g_mutex_unlock(&queue->mutex); - -    /** -     * Attente des groupes principaux. -     */ - -    for (i = 0; i < gb_count; i++) -        g_work_queue_wait_for_completion(queue, gb_ids[i]); +    G_GENERIC_WORK_GET_CLASS(work)->run(work); -    /** -     * Si le groupe par défaut a généré de nouveaux groupes, on recommence ! -     */ - -    g_mutex_lock(&queue->mutex); - -    if (queue->groups_count > gb_count) -        goto wait_again; - -    g_mutex_unlock(&queue->mutex); - -} - - -/****************************************************************************** -*                                                                             * -*  Paramètres  : queue    = gestionnaire de l'ensemble des groupes de travail.* -*                id       = identifiant d'un groupe de travail.               * -*                callback = éventuelle fonction à appeler ou NULL.            * -*                data     = données devant accompagner l'appel.               * -*                                                                             * -*  Description : Modifie les conditions d'attente des fins d'exécutions.      * -*                                                                             * -*  Retour      : -                                                            * -*                                                                             * -*  Remarques   : -                                                            * -*                                                                             * -******************************************************************************/ +    g_mutex_lock(&work->mutex); -void g_work_queue_set_extra_wait_callback(GWorkQueue *queue, wgroup_id_t id, wait_for_incoming_works_cb callback, void *data) -{ -    GWorkGroup *group;                      /* Groupe de travail à traiter */ +    work->completed = true; -    group = g_work_queue_find_group_for_id(queue, id); +    g_cond_signal(&work->cond); +    g_mutex_unlock(&work->mutex); -    if (group != NULL) -    { -        g_work_group_set_extra_wait_callback(group, callback, data); -        g_object_unref(G_OBJECT(group)); -    } +    g_signal_emit_by_name(work, "work-completed");  }  /******************************************************************************  *                                                                             * -*  Paramètres  : queue    = gestionnaire de l'ensemble des groupes de travail.* -*                id       = identifiant d'un groupe de travail.               * +*  Paramètres  : work = travail à surveiller.                                 *  *                                                                             * -*  Description : Force un réveil d'une attente en cours pour la confirmer.    * +*  Description : Attend la fin de l'exécution d'une tâche donnée.             *  *                                                                             *  *  Retour      : -                                                            *  *                                                                             * @@ -1338,16 +222,13 @@ void g_work_queue_set_extra_wait_callback(GWorkQueue *queue, wgroup_id_t id, wai  *                                                                             *  ******************************************************************************/ -void g_work_queue_wake_up_waiters(GWorkQueue *queue, wgroup_id_t id) +void g_generic_work_wait_for_completion(GGenericWork *work)  { -    GWorkGroup *group;                      /* Groupe de travail à traiter */ +    g_mutex_lock(&work->mutex); -    group = g_work_queue_find_group_for_id(queue, id); +    while (!work->completed) +        g_cond_wait(&work->cond, &work->mutex); -    if (group != NULL) -    { -        g_work_group_wake_up_waiters(group); -        g_object_unref(G_OBJECT(group)); -    } +    g_mutex_unlock(&work->mutex);  } diff --git a/src/glibext/work.h b/src/glibext/work.h index 89eed12..1084942 100644 --- a/src/glibext/work.h +++ b/src/glibext/work.h @@ -1,8 +1,8 @@  /* Chrysalide - Outil d'analyse de fichiers binaires - * delayed.h - prototypes pour la gestion des travaux différés + * work.h - prototypes pour la gestion des travaux différés   * - * Copyright (C) 2009-2018 Cyrille Bagard + * Copyright (C) 2009-2024 Cyrille Bagard   *   *  This file is part of Chrysalide.   * @@ -21,107 +21,31 @@   */ -#ifndef _GLIBEXT_DELAYED_H -#define _GLIBEXT_DELAYED_H +#ifndef _GLIBEXT_WORK_H +#define _GLIBEXT_WORK_H -#include <glib-object.h> -#include <stdbool.h> -#include <stdint.h> +#include "helpers.h" -/* -------------------------- TACHE DIFFEREE DANS LE TEMPS -------------------------- */ +#define G_TYPE_GENERIC_WORK (g_generic_work_get_type()) +DECLARE_GTYPE(GGenericWork, g_generic_work, G, GENERIC_WORK); -#define G_TYPE_DELAYED_WORK               g_delayed_work_get_type() -#define G_DELAYED_WORK(obj)               (G_TYPE_CHECK_INSTANCE_CAST((obj), g_delayed_work_get_type(), GDelayedWork)) -#define G_IS_DELAYED_WORK(obj)            (G_TYPE_CHECK_INSTANCE_TYPE((obj), g_delayed_work_get_type())) -#define G_DELAYED_WORK_CLASS(klass)       (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_DELAYED_WORK, GDelayedWorkClass)) -#define G_IS_DELAYED_WORK_CLASS(klass)    (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_DELAYED_WORK)) -#define G_DELAYED_WORK_GET_CLASS(obj)     (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_DELAYED_WORK, GDelayedWorkClass)) +/* Intègre un travail dans une liste de tâches à effectuer. */ +void g_generic_work_add_to_list(GGenericWork *, GGenericWork **); -/* Travail différé (instance) */ -typedef struct _GDelayedWork GDelayedWork; +/* Supprime un travail d'une liste de tâches à effectuer. */ +void g_generic_work_remove_from_list(GGenericWork *, GGenericWork **); -/* Travail différé (classe) */ -typedef struct _GDelayedWorkClass GDelayedWorkClass; - - -/* Indique le type défini pour les travaux différés. */ -GType g_delayed_work_get_type(void); +/* Mène l'opération programmée. */ +void g_generic_work_process(GGenericWork *);  /* Attend la fin de l'exécution d'une tâche donnée. */ -void g_delayed_work_wait_for_completion(GDelayedWork *); - - - -/* ------------------------- TRAITEMENT DE TACHES DIFFEREES ------------------------- */ - - -#define G_TYPE_WORK_QUEUE               g_work_queue_get_type() -#define G_WORK_QUEUE(obj)               (G_TYPE_CHECK_INSTANCE_CAST((obj), g_work_queue_get_type(), GWorkQueue)) -#define G_IS_WORK_QUEUE(obj)            (G_TYPE_CHECK_INSTANCE_TYPE((obj), g_work_queue_get_type())) -#define G_WORK_QUEUE_CLASS(klass)       (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_WORK_QUEUE, GWorkQueueClass)) -#define G_IS_WORK_QUEUE_CLASS(klass)    (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_WORK_QUEUE)) -#define G_WORK_QUEUE_GET_CLASS(obj)     (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_WORK_QUEUE, GWorkQueueClass)) - - -/* Gestionnaire des travaux différés (instance) */ -typedef struct _GWorkQueue GWorkQueue; - -/* Gestionnaire des travaux différés (classe) */ -typedef struct _GWorkQueueClass GWorkQueueClass; - - -/** - * Identifiant unique pour groupe de travail. - * - * Le nombre de bits est forcé à 64 bits car glib-genmarshal ne reconnait - * pas explicitement le type 'unsigned long long'. - */ -typedef uint64_t wgroup_id_t; - - -/* Indique le type défini pour le gestionnaire des travaux différés. */ -GType g_work_queue_get_type(void); - -/* Créé un nouveau gestionnaire de tâches parallèles. */ -GWorkQueue *g_work_queue_new(void); - -/* Constitue un nouveau groupe de travail. */ -wgroup_id_t g_work_queue_define_work_group(GWorkQueue *); - -/* Constitue un nouveau petit groupe de travail. */ -wgroup_id_t g_work_queue_define_tiny_work_group(GWorkQueue *, guint); - -/* Dissout un groupe de travail existant. */ -void g_work_queue_delete_work_group(GWorkQueue *, wgroup_id_t); - -/* Place une nouvelle tâche en attente. */ -void g_work_queue_schedule_work(GWorkQueue *, GDelayedWork *, wgroup_id_t); - -/* Détermine si un groupe est vide de toute programmation. */ -bool g_work_queue_is_empty(GWorkQueue *, wgroup_id_t); - -/* Attend que toutes les tâches d'un groupe soient traitées. */ -void g_work_queue_wait_for_completion(GWorkQueue *, wgroup_id_t); - -/* Attend que toutes les tâches de tout groupe soient traitées. */ -void g_work_queue_wait_for_all_completions(GWorkQueue *, const wgroup_id_t *, size_t); - - -/* Etudie le besoin d'attendre d'avantage de prochaines tâches. */ -typedef bool (* wait_for_incoming_works_cb) (GWorkQueue *, wgroup_id_t, void *); - - -/* Modifie les conditions d'attente des fins d'exécutions. */ -void g_work_queue_set_extra_wait_callback(GWorkQueue *, wgroup_id_t, wait_for_incoming_works_cb, void *); - -/* Force un réveil d'une attente en cours pour la confirmer. */ -void g_work_queue_wake_up_waiters(GWorkQueue *, wgroup_id_t); +void g_generic_work_wait_for_completion(GGenericWork *); -#endif  /* _GLIBEXT_DELAYED_H */ +#endif  /* _GLIBEXT_WORK_H */ diff --git a/src/glibext/workgroup-int.h b/src/glibext/workgroup-int.h index 4f84e86..7224cf9 100644 --- a/src/glibext/workgroup-int.h +++ b/src/glibext/workgroup-int.h @@ -1,8 +1,8 @@  /* Chrysalide - Outil d'analyse de fichiers binaires - * delayed-int.h - définitions internes pour la gestion des travaux différés + * workgroup-int.h - définitions internes pour la gestion des travaux différés   * - * Copyright (C) 2009-2018 Cyrille Bagard + * Copyright (C) 2009-2024 Cyrille Bagard   *   *  This file is part of Chrysalide.   * @@ -21,55 +21,40 @@   */ -#ifndef _GLIBEXT_DELAYED_INT_H -#define _GLIBEXT_DELAYED_INT_H +#ifndef _GLIBEXT_WORKGROUP_INT_H +#define _GLIBEXT_WORKGROUP_INT_H -#include "delayed.h" +#include "workgroup.h" -#include "notifier.h" -#include "../common/dllist.h" - - -/* -------------------------- TACHE DIFFEREE DANS LE TEMPS -------------------------- */ - - -/* Traite un travail programmé. */ -typedef void (* run_task_fc) (GDelayedWork *, GtkStatusStack *); - - -/* Travail différé (instance) */ -struct _GDelayedWork +/* File de traitement pour un type donné (instance) */ +typedef struct _GWorkGroup  {      GObject parent;                         /* A laisser en premier        */ -    DL_LIST_ITEM(link);                     /* Lien vers les maillons      */ +    wgroup_id_t id;                         /* Identifiant de travaux menés*/ -    bool completed;                         /* Fin de la tâche ?           */ -    GMutex mutex;                           /* Accès à la variable         */ -    GCond cond;                             /* Attente de changement       */ +    GGenericWork *works;                    /* Tâches à mener à bien       */ +    GMutex mutex;                           /* Verrou pour l'accès         */ +    GCond cond;                             /* Réveil pour un traitement   */ +    GCond wait_cond;                        /* Réveil d'attente de fin     */ +    gint pending;                           /* Tâches en cours d'exécution */ -}; +    GThread **threads;                      /* Procédure de traitement     */ +    guint threads_count;                    /* Nombre de procédures        */ +    bool force_exit;                        /* Procédure d'arrêt           */ -/* Travail différé (classe) */ -struct _GDelayedWorkClass +} GWorkGroup; + +/* File de traitement pour un type donné (classe) */ +typedef struct _GWorkGroupClass  {      GObjectClass parent;                    /* A laisser en premier        */ -    run_task_fc run;                        /* Traitement externalisé      */ - -    /* Signaux */ - -    void (* work_completed) (GDelayedWork *); - -}; - - -#define delayed_work_list_add_tail(new, head) dl_list_add_tail(new, head, GDelayedWork, link) -#define delayed_work_list_del(item, head) dl_list_del(item, head, GDelayedWork, link) +} GWorkGroupClass; -#endif  /* _GLIBEXT_DELAYED_INT_H */ +#endif  /* _GLIBEXT_WORKGROUP_INT_H */ diff --git a/src/glibext/workgroup.c b/src/glibext/workgroup.c index 6b5ac35..c603d54 100644 --- a/src/glibext/workgroup.c +++ b/src/glibext/workgroup.c @@ -1,8 +1,8 @@  /* Chrysalide - Outil d'analyse de fichiers binaires - * delayed.c - gestion des travaux différés + * workgroup.c - gestion des travaux différés   * - * Copyright (C) 2009-2018 Cyrille Bagard + * Copyright (C) 2009-2024 Cyrille Bagard   *   *  This file is part of Chrysalide.   * @@ -21,88 +21,21 @@   */ -#include "delayed.h" +#include "workgroup.h"  #include <assert.h>  #include <inttypes.h>  #include <malloc.h>  #include <stdio.h> -#include <string.h> -#include "delayed-int.h" +#include "workgroup-int.h" +#include "../common/dllist.h"  #include "../core/nproc.h" -#ifdef INCLUDE_GTK_SUPPORT -#   include "../gui/core/global.h" -#endif -/* -------------------------- TACHE DIFFEREE DANS LE TEMPS -------------------------- */ - - -/* Initialise la classe des travaux différés. */ -static void g_delayed_work_class_init(GDelayedWorkClass *); - -/* Initialise une instance de travail différé. */ -static void g_delayed_work_init(GDelayedWork *); - -/* Supprime toutes les références externes. */ -static void g_delayed_work_dispose(GDelayedWork *); - -/* Procède à la libération totale de la mémoire. */ -static void g_delayed_work_finalize(GDelayedWork *); - -/* Mène l'opération programmée. */ -static void g_delayed_work_process(GDelayedWork *, GtkStatusStack *); - - - -/* -------------------------- THREAD DE TRAITEMENTS DEDIES -------------------------- */ - - -#define G_TYPE_WORK_GROUP               g_work_group_get_type() -#define G_WORK_GROUP(obj)               (G_TYPE_CHECK_INSTANCE_CAST((obj), g_work_group_get_type(), GWorkGroup)) -#define G_IS_WORK_GROUP(obj)            (G_TYPE_CHECK_INSTANCE_TYPE((obj), g_work_group_get_type())) -#define G_WORK_GROUP_CLASS(klass)       (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_WORK_GROUP, GWorkGroupClass)) -#define G_IS_WORK_GROUP_CLASS(klass)    (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_WORK_GROUP)) -#define G_WORK_GROUP_GET_CLASS(obj)     (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_WORK_GROUP, GWorkGroupClass)) - - -/* File de traitement pour un type donné (instance) */ -typedef struct _GWorkGroup -{ -    GObject parent;                         /* A laisser en premier        */ - -    wgroup_id_t id;                         /* Identifiant de travaux menés*/ - -    GDelayedWork *works;                    /* Tâches à mener à bien       */ -    GMutex mutex;                           /* Verrou pour l'accès         */ -    GCond cond;                             /* Réveil pour un traitement   */ -    GCond wait_cond;                        /* Réveil d'attente de fin     */ -    gint pending;                           /* Tâches en cours d'exécution */ - -    GThread **threads;                      /* Procédure de traitement     */ -    guint threads_count;                    /* Nombre de procédures        */ -    bool force_exit;                        /* Procédure d'arrêt           */ - -    wait_for_incoming_works_cb callback;    /* Encadre les attentes de fin */ -    void *data;                             /* Données à associer          */ - -} GWorkGroup; - -/* File de traitement pour un type donné (classe) */ -typedef struct _GWorkGroupClass -{ -    GObjectClass parent;                    /* A laisser en premier        */ - -} GWorkGroupClass; - - -/* Indique le type défini pour les groupes de travail. */ -static GType g_work_group_get_type(void); -  /* Initialise la classe des groupes de travail. */  static void g_work_group_class_init(GWorkGroupClass *); @@ -115,237 +48,9 @@ static void g_work_group_dispose(GWorkGroup *);  /* Procède à la libération totale de la mémoire. */  static void g_work_group_finalize(GWorkGroup *); -/* Crée un nouveau thread dédié à un type de travaux donné. */ -static GWorkGroup *g_work_group_new(wgroup_id_t, const guint *); - -/* Fournit l'identifiant associé à un groupe de travail. */ -static wgroup_id_t g_work_group_get_id(const GWorkGroup *); - -/* Place une nouvelle tâche en attente dans une file dédiée. */ -static void g_work_group_schedule(GWorkGroup *, GDelayedWork *); -  /* Assure le traitement en différé. */  static void *g_work_group_process(GWorkGroup *); -/* Détermine si le groupe est vide de toute programmation. */ -static bool g_work_group_is_empty(GWorkGroup *); - -/* Attend que toutes les tâches d'un groupe soient traitées. */ -static void g_work_group_wait_for_completion(GWorkGroup *, GWorkQueue *); - -/* Modifie les conditions d'attente des fins d'exécutions. */ -static void g_work_group_set_extra_wait_callback(GWorkGroup *, wait_for_incoming_works_cb, void *); - -/* Force un réveil d'une attente en cours pour la confirmer. */ -static void g_work_group_wake_up_waiters(GWorkGroup *); - - - -/* ------------------------- TRAITEMENT DE TACHES DIFFEREES ------------------------- */ - - -/* Gestionnaire des travaux différés (instance) */ -struct _GWorkQueue -{ -    GObject parent;                         /* A laisser en premier        */ - -    wgroup_id_t generator;                  /* Générateur d'identifiants   */ - -    GWorkGroup **groups;                    /* Files de traitement         */ -    size_t groups_count;                    /* Nombre de files internes    */ -    GMutex mutex;                           /* Verrou pour l'accès         */ -    GCond wait_all;                         /* Réveil d'attente globale    */ - -}; - -/* Gestionnaire des travaux différés (classe) */ -struct _GWorkQueueClass -{ -    GObjectClass parent;                    /* A laisser en premier        */ - -}; - - -/* Initialise la classe des travaux différés. */ -static void g_work_queue_class_init(GWorkQueueClass *); - -/* Initialise une instance de gestionnaire de travaux différés. */ -static void g_work_queue_init(GWorkQueue *); - -/* Supprime toutes les références externes. */ -static void g_work_queue_dispose(GWorkQueue *); - -/* Procède à la libération totale de la mémoire. */ -static void g_work_queue_finalize(GWorkQueue *); - -/* Donne l'assurance de l'existence d'un groupe de travail. */ -static bool g_work_queue_ensure_group_exists(GWorkQueue *, wgroup_id_t, const guint *); - -/* Fournit le groupe de travail correspondant à un identifiant. */ -static GWorkGroup *g_work_queue_find_group_for_id(GWorkQueue *, wgroup_id_t); - - - -/* ---------------------------------------------------------------------------------- */ -/*                            TACHE DIFFEREE DANS LE TEMPS                            */ -/* ---------------------------------------------------------------------------------- */ - - -/* Indique le type défini pour les travaux différés. */ -G_DEFINE_TYPE(GDelayedWork, g_delayed_work, G_TYPE_OBJECT); - - -/****************************************************************************** -*                                                                             * -*  Paramètres  : klass = classe à initialiser.                                * -*                                                                             * -*  Description : Initialise la classe des travaux différés.                   * -*                                                                             * -*  Retour      : -                                                            * -*                                                                             * -*  Remarques   : -                                                            * -*                                                                             * -******************************************************************************/ - -static void g_delayed_work_class_init(GDelayedWorkClass *klass) -{ -    GObjectClass *object;                   /* Autre version de la classe  */ - -    object = G_OBJECT_CLASS(klass); - -    object->dispose = (GObjectFinalizeFunc/* ! */)g_delayed_work_dispose; -    object->finalize = (GObjectFinalizeFunc)g_delayed_work_finalize; - -    g_signal_new("work-completed", -                 G_TYPE_DELAYED_WORK, -                 G_SIGNAL_RUN_LAST, -                 G_STRUCT_OFFSET(GDelayedWorkClass, work_completed), -                 NULL, NULL, -                 g_cclosure_marshal_VOID__VOID, -                 G_TYPE_NONE, 0); - -} - - -/****************************************************************************** -*                                                                             * -*  Paramètres  : work = instance à initialiser.                               * -*                                                                             * -*  Description : Initialise une instance de travail différé.                  * -*                                                                             * -*  Retour      : -                                                            * -*                                                                             * -*  Remarques   : -                                                            * -*                                                                             * -******************************************************************************/ - -static void g_delayed_work_init(GDelayedWork *work) -{ -    work->completed = false; -    g_mutex_init(&work->mutex); -    g_cond_init(&work->cond); - -} - - -/****************************************************************************** -*                                                                             * -*  Paramètres  : work = instance d'objet GLib à traiter.                      * -*                                                                             * -*  Description : Supprime toutes les références externes.                     * -*                                                                             * -*  Retour      : -                                                            * -*                                                                             * -*  Remarques   : -                                                            * -*                                                                             * -******************************************************************************/ - -static void g_delayed_work_dispose(GDelayedWork *work) -{ -    g_mutex_clear(&work->mutex); -    g_cond_clear(&work->cond); - -    G_OBJECT_CLASS(g_delayed_work_parent_class)->dispose(G_OBJECT(work)); - -} - - -/****************************************************************************** -*                                                                             * -*  Paramètres  : work = instance d'objet GLib à traiter.                      * -*                                                                             * -*  Description : Procède à la libération totale de la mémoire.                * -*                                                                             * -*  Retour      : -                                                            * -*                                                                             * -*  Remarques   : -                                                            * -*                                                                             * -******************************************************************************/ - -static void g_delayed_work_finalize(GDelayedWork *work) -{ -    G_OBJECT_CLASS(g_delayed_work_parent_class)->finalize(G_OBJECT(work)); - -} - - -/****************************************************************************** -*                                                                             * -*  Paramètres  : work   = travail à effectuer.                                * -*                status = barre de statut à tenir informée.                   * -*                                                                             * -*  Description : Mène l'opération programmée.                                 * -*                                                                             * -*  Retour      : -                                                            * -*                                                                             * -*  Remarques   : -                                                            * -*                                                                             * -******************************************************************************/ - -static void g_delayed_work_process(GDelayedWork *work, GtkStatusStack *status) -{ -    G_DELAYED_WORK_GET_CLASS(work)->run(work, status); - -    g_mutex_lock(&work->mutex); - -    work->completed = true; - -    g_cond_signal(&work->cond); -    g_mutex_unlock(&work->mutex); - -    g_signal_emit_by_name(work, "work-completed"); - -} - - -/****************************************************************************** -*                                                                             * -*  Paramètres  : work = travail à surveiller.                                 * -*                                                                             * -*  Description : Attend la fin de l'exécution d'une tâche donnée.             * -*                                                                             * -*  Retour      : -                                                            * -*                                                                             * -*  Remarques   : -                                                            * -*                                                                             * -******************************************************************************/ - -void g_delayed_work_wait_for_completion(GDelayedWork *work) -{ -    g_mutex_lock(&work->mutex); - -    while (!work->completed) -        g_cond_wait(&work->cond, &work->mutex); - -    g_mutex_unlock(&work->mutex); - -} - - - -/* ---------------------------------------------------------------------------------- */ -/*                           THREADS DES TRAITEMENTS DEDIES                           */ -/* ---------------------------------------------------------------------------------- */  /* Indique le type défini pour les groupes de travail. */ @@ -390,7 +95,7 @@ static void g_work_group_class_init(GWorkGroupClass *klass)  static void g_work_group_init(GWorkGroup *group)  { -    group->works = NULL; +    DL_LIST_HEAD_INIT(group->works);      g_mutex_init(&group->mutex);      g_cond_init(&group->cond); @@ -402,15 +107,12 @@ static void g_work_group_init(GWorkGroup *group)      group->threads_count = 0;      group->force_exit = false; -    group->callback = NULL; -    group->data = NULL; -  }  /******************************************************************************  *                                                                             * -*  Paramètres  : queue = instance d'objet GLib à traiter.                     * +*  Paramètres  : group = instance d'objet GLib à traiter.                     *  *                                                                             *  *  Description : Supprime toutes les références externes.                     *  *                                                                             * @@ -423,7 +125,7 @@ static void g_work_group_init(GWorkGroup *group)  static void g_work_group_dispose(GWorkGroup *group)  {      guint i;                                /* Boucle de parcours          */ -    GDelayedWork *work;                     /* Travail à oublier           */ +    GGenericWork *work;                     /* Travail à oublier           */      group->force_exit = true; @@ -444,9 +146,9 @@ static void g_work_group_dispose(GWorkGroup *group)      while (!dl_list_empty(group->works))      {          work = group->works; -        delayed_work_list_del(work, &group->works); +        g_generic_work_remove_from_list(work, &group->works); -        g_object_unref(G_OBJECT(work)); +        unref_object(work);      } @@ -484,7 +186,7 @@ static void g_work_group_finalize(GWorkGroup *group)  /******************************************************************************  *                                                                             *  *  Paramètres  : id    = identifiant accordé au nouveau groupe.               * -*                count = quantité de threads à allouer.                       * +*                count = quantité de threads à allouer (0 pour un défaut).    *  *                                                                             *  *  Description : Crée un nouveau thread dédié à un type de travaux donné.     *  *                                                                             * @@ -494,33 +196,47 @@ static void g_work_group_finalize(GWorkGroup *group)  *                                                                             *  ******************************************************************************/ -static GWorkGroup *g_work_group_new(wgroup_id_t id, const guint *count) +GWorkGroup *g_work_group_new(wgroup_id_t id, guint count)  { -    GWorkGroup *result;                    /* Traiteur à retourner        */ +    GWorkGroup *result;                     /* Traiteur à retourner        */      guint i;                                /* Boucle de parcours          */ -    char name[16];                          /* Désignation humaine         */ +    int ret;                                /* Bilan d'un appel            */ +    char *name;                             /* Désignation humaine         */      result = g_object_new(G_TYPE_WORK_GROUP, NULL);      result->id = id; -    result->threads_count = get_max_online_threads(); +    if (count == 0) +        count = get_max_online_threads(); -    if (count != NULL && *count < result->threads_count) -        result->threads_count = *count; +    result->threads_count = count; -    result->threads = (GThread **)calloc(result->threads_count, sizeof(GThread *)); +    result->threads = calloc(result->threads_count, sizeof(GThread *));      for (i = 0; i < result->threads_count; i++)      { -        snprintf(name, sizeof(name), "wgrp_%" PRIu64 "-%u", id, i); +        /** +         * La documentation précise : +         * +         *    Some systems restrict the length of name to 16 bytes. +         * +         * On laisse ces systèmes tronquer. +         */ + +        ret = asprintf(&name, "wgrp_%" PRIu64 "-%u", id, i); +        if (ret == -1) goto naming_error;          result->threads[i] = g_thread_new(name, (GThreadFunc)g_work_group_process, result); + +        free(name); +          if (!result->threads[i])              goto start_error;      } + naming_error:   start_error:      result->threads_count = i; @@ -544,7 +260,7 @@ static GWorkGroup *g_work_group_new(wgroup_id_t id, const guint *count)  *                                                                             *  ******************************************************************************/ -static wgroup_id_t g_work_group_get_id(const GWorkGroup *group) +wgroup_id_t g_work_group_get_id(const GWorkGroup *group)  {      return group->id; @@ -564,13 +280,14 @@ static wgroup_id_t g_work_group_get_id(const GWorkGroup *group)  *                                                                             *  ******************************************************************************/ -static void g_work_group_schedule(GWorkGroup *group, GDelayedWork *work) +void g_work_group_schedule(GWorkGroup *group, GGenericWork *work)  {      g_mutex_lock(&group->mutex);      g_atomic_int_inc(&group->pending); -    delayed_work_list_add_tail(work, &group->works); +    ref_object(work); +    g_generic_work_add_to_list(work, &group->works);      g_cond_signal(&group->cond); @@ -593,8 +310,7 @@ static void g_work_group_schedule(GWorkGroup *group, GDelayedWork *work)  static void *g_work_group_process(GWorkGroup *group)  { -    GDelayedWork *work;                     /* Traitement à mener          */ -    GtkStatusStack *status;                 /* Zone d'info éventuelle      */ +    GGenericWork *work;                     /* Traitement à mener          */      while (1)      { @@ -610,18 +326,13 @@ static void *g_work_group_process(GWorkGroup *group)          }          work = group->works; -        delayed_work_list_del(work, &group->works); +        g_generic_work_remove_from_list(work, &group->works);          g_mutex_unlock(&group->mutex); -#ifdef INCLUDE_GTK_SUPPORT -        status = get_global_status(); -#else -        status = NULL; -#endif -        g_delayed_work_process(work, status); +        g_generic_work_process(work); -        g_object_unref(G_OBJECT(work)); +        unref_object(work);          /**           * Verrou ou pas verrou ? @@ -687,7 +398,7 @@ static void *g_work_group_process(GWorkGroup *group)  *                                                                             *  ******************************************************************************/ -static bool g_work_group_is_empty(GWorkGroup *group) +bool g_work_group_is_empty(GWorkGroup *group)  {      bool result;                            /* Etat à retourner            */ @@ -716,7 +427,6 @@ static bool g_work_group_is_empty(GWorkGroup *group)  /******************************************************************************  *                                                                             *  *  Paramètres  : group = groupe dont les conclusions sont attendues.          * -*                queue = queue d'appartenance pour les appels externes.       *  *                                                                             *  *  Description : Attend que toutes les tâches d'un groupe soient traitées.    *  *                                                                             * @@ -726,17 +436,8 @@ static bool g_work_group_is_empty(GWorkGroup *group)  *                                                                             *  ******************************************************************************/ -static void g_work_group_wait_for_completion(GWorkGroup *group, GWorkQueue *queue) +void g_work_group_wait_for_completion(GWorkGroup *group)  { -    wait_for_incoming_works_cb callback;    /* Procédure complémentaire    */ - -    bool no_extra_check(GWorkQueue *_q, wgroup_id_t _id, void *_data) -    { -        return false; -    } - -    callback = group->callback != NULL ? group->callback : no_extra_check; -      g_mutex_lock(&group->mutex);      /** @@ -746,7 +447,7 @@ static void g_work_group_wait_for_completion(GWorkGroup *group, GWorkQueue *queu       *  - rien n'indique que de nouvelles tâches supplémentaires vont arriver.       */ -    while ((g_atomic_int_get(&group->pending) > 0 || callback(queue, group->id, group->data)) +    while ((g_atomic_int_get(&group->pending) > 0)             && !group->force_exit)      {          g_cond_wait(&group->wait_cond, &group->mutex); @@ -759,456 +460,43 @@ static void g_work_group_wait_for_completion(GWorkGroup *group, GWorkQueue *queu  /******************************************************************************  *                                                                             * -*  Paramètres  : group    = groupe dont les paramètres sont à modifier.       * -*                callback = éventuelle fonction à appeler ou NULL.            * -*                data     = données devant accompagner l'appel.               * +*  Paramètres  : group = groupe dont les conclusions sont attendues.          * +*                rel   = durée relative à patienter au max. en microsecondes. *  *                                                                             * -*  Description : Modifie les conditions d'attente des fins d'exécutions.      * +*  Description : Attend que toutes les tâches d'un groupe soient traitées.    *  *                                                                             * -*  Retour      : -                                                            * +*  Retour      : Bilan de l'attente : false en cas d'expiration, true sinon.  *  *                                                                             * -*  Remarques   : -                                                            * +*  Remarques   : Cette fonction est originellement dédiée à un usage Python.  *  *                                                                             *  ******************************************************************************/ -static void g_work_group_set_extra_wait_callback(GWorkGroup *group, wait_for_incoming_works_cb callback, void *data) +bool g_work_group_wait_timed_for_completion(GWorkGroup *group, gint64 rel)  { -    group->callback = callback; -    group->data = data; +    bool result;                            /* Bilan d'attente à renvoyer  */ +    gint64 end_time;                        /* Borne de fin de l'attente   */ -} +    result = true; +    g_mutex_lock(&group->mutex); -/****************************************************************************** -*                                                                             * -*  Paramètres  : queue    = gestionnaire de l'ensemble des groupes de travail.* -*                id       = identifiant d'un groupe de travail.               * -*                                                                             * -*  Description : Force un réveil d'une attente en cours pour la confirmer.    * -*                                                                             * -*  Retour      : -                                                            * -*                                                                             * -*  Remarques   : -                                                            * -*                                                                             * -******************************************************************************/ +    end_time = g_get_monotonic_time() + rel; -static void g_work_group_wake_up_waiters(GWorkGroup *group) -{      /** -     * Concernant la pose du verrou, se référer aux commentaires de la -     * fonction g_work_group_process(). +     * On attend que : +     *  - la liste des tâches programmées soit vide. +     *  - il n'existe plus de tâche en cours. +     *  - rien n'indique que de nouvelles tâches supplémentaires vont arriver.       */ -    g_mutex_lock(&group->mutex); - -    g_cond_broadcast(&group->wait_cond); - -    g_mutex_unlock(&group->mutex); - -} - - - -/* ---------------------------------------------------------------------------------- */ -/*                           TRAITEMENT DE TACHES DIFFEREES                           */ -/* ---------------------------------------------------------------------------------- */ - - -/* Indique le type défini pour le gestionnaire des travaux différés. */ -G_DEFINE_TYPE(GWorkQueue, g_work_queue, G_TYPE_OBJECT); - - -/****************************************************************************** -*                                                                             * -*  Paramètres  : klass = classe à initialiser.                                * -*                                                                             * -*  Description : Initialise la classe des travaux différés.                   * -*                                                                             * -*  Retour      : -                                                            * -*                                                                             * -*  Remarques   : -                                                            * -*                                                                             * -******************************************************************************/ - -static void g_work_queue_class_init(GWorkQueueClass *klass) -{ -    GObjectClass *object;                   /* Autre version de la classe  */ - -    object = G_OBJECT_CLASS(klass); - -    object->dispose = (GObjectFinalizeFunc/* ! */)g_work_queue_dispose; -    object->finalize = (GObjectFinalizeFunc)g_work_queue_finalize; - -} - - -/****************************************************************************** -*                                                                             * -*  Paramètres  : queue = instance à initialiser.                              * -*                                                                             * -*  Description : Initialise une instance de gestionnaire de travaux différés. * -*                                                                             * -*  Retour      : -                                                            * -*                                                                             * -*  Remarques   : -                                                            * -*                                                                             * -******************************************************************************/ - -static void g_work_queue_init(GWorkQueue *queue) -{ -    queue->generator = 0; - -    queue->groups = NULL; -    queue->groups_count = 0; -    g_mutex_init(&queue->mutex); -    g_cond_init(&queue->wait_all); - -} - - -/****************************************************************************** -*                                                                             * -*  Paramètres  : queue = instance d'objet GLib à traiter.                     * -*                                                                             * -*  Description : Supprime toutes les références externes.                     * -*                                                                             * -*  Retour      : -                                                            * -*                                                                             * -*  Remarques   : -                                                            * -*                                                                             * -******************************************************************************/ - -static void g_work_queue_dispose(GWorkQueue *queue) -{ -    size_t i;                               /* Boucle de parcours          */ - -    g_mutex_lock(&queue->mutex); - -    for (i = 0; i < queue->groups_count; i++) -        g_clear_object(&queue->groups[i]); - -    g_mutex_unlock(&queue->mutex); - -    g_mutex_clear(&queue->mutex); -    g_cond_clear(&queue->wait_all); - -    G_OBJECT_CLASS(g_work_queue_parent_class)->dispose(G_OBJECT(queue)); - -} - - -/****************************************************************************** -*                                                                             * -*  Paramètres  : queue = instance d'objet GLib à traiter.                     * -*                                                                             * -*  Description : Procède à la libération totale de la mémoire.                * -*                                                                             * -*  Retour      : -                                                            * -*                                                                             * -*  Remarques   : -                                                            * -*                                                                             * -******************************************************************************/ - -static void g_work_queue_finalize(GWorkQueue *queue) -{ -    if (queue->groups != NULL) -        free(queue->groups); - -    G_OBJECT_CLASS(g_work_queue_parent_class)->finalize(G_OBJECT(queue)); - -} - - -/****************************************************************************** -*                                                                             * -*  Paramètres  : -                                                            * -*                                                                             * -*  Description : Créé un nouveau gestionnaire de tâches parallèles.           * -*                                                                             * -*  Retour      : Gestionnaire de traitements mis en place.                    * -*                                                                             * -*  Remarques   : -                                                            * -*                                                                             * -******************************************************************************/ - -GWorkQueue *g_work_queue_new(void) -{ -    GWorkQueue *result;                     /* Instance à retourner        */ - -    result = g_object_new(G_TYPE_WORK_QUEUE, NULL); - -    return result; - -} - - -/****************************************************************************** -*                                                                             * -*  Paramètres  : queue = gestionnaire de l'ensemble des groupes de travail.   * -*                id    = identifiant d'un groupe de travail.                  * -*                count = quantité de threads à allouer.                       * -*                                                                             * -*  Description : Donne l'assurance de l'existence d'un groupe de travail.     * -*                                                                             * -*  Retour      : true si un nouveau groupe a été constitué, false sinon.      * -*                                                                             * -*  Remarques   : Le verrou d'accès doit être posé par l'appelant.             * -*                                                                             * -******************************************************************************/ - -static bool g_work_queue_ensure_group_exists(GWorkQueue *queue, wgroup_id_t id, const guint *count) -{ -    bool found;                             /* Bilan des recherches        */ -    size_t i;                               /* Boucle de parcours          */ -    GWorkGroup *group;                      /* Groupe à consulter          */ - -    assert(!g_mutex_trylock(&queue->mutex)); - -    found = false; - -    for (i = 0; i < queue->groups_count && !found; i++) -    { -        group = queue->groups[i]; -        found = (g_work_group_get_id(group) == id); -    } - -    if (!found) -    { -        queue->groups_count++; -        queue->groups = (GWorkGroup **)realloc(queue->groups, -                                               queue->groups_count * sizeof(GWorkGroup *)); - -        group = g_work_group_new(id, count); -        queue->groups[queue->groups_count - 1] = group; - -    } - -    return !found; - -} - - -/****************************************************************************** -*                                                                             * -*  Paramètres  : queue = gestionnaire de l'ensemble des groupes de travail.   * -*                                                                             * -*  Description : Constitue un nouveau groupe de travail.                      * -*                                                                             * -*  Retour      : Nouvel identifiant unique d'un nouveau groupe de travail.    * -*                                                                             * -*  Remarques   : -                                                            * -*                                                                             * -******************************************************************************/ - -wgroup_id_t g_work_queue_define_work_group(GWorkQueue *queue) -{ -    wgroup_id_t result;                     /* Valeur à retourner          */ -    bool created;                           /* Bilan d'une tentative       */ - -    g_mutex_lock(&queue->mutex); - -    do -    { -        result = queue->generator++; -        created = g_work_queue_ensure_group_exists(queue, result, NULL); -    } -    while (!created); - -    g_mutex_unlock(&queue->mutex); - -    return result; - -} - - -/****************************************************************************** -*                                                                             * -*  Paramètres  : queue = gestionnaire de l'ensemble des groupes de travail.   * -*                count = quantité de threads à allouer.                       * -*                                                                             * -*  Description : Constitue un nouveau petit groupe de travail.                * -*                                                                             * -*  Retour      : Nouvel identifiant unique d'un nouveau groupe de travail.    * -*                                                                             * -*  Remarques   : -                                                            * -*                                                                             * -******************************************************************************/ - -wgroup_id_t g_work_queue_define_tiny_work_group(GWorkQueue *queue, guint count) -{ -    wgroup_id_t result;                     /* Valeur à retourner          */ -    bool created;                           /* Bilan d'une tentative       */ - -    g_mutex_lock(&queue->mutex); - -    do -    { -        result = queue->generator++; -        created = g_work_queue_ensure_group_exists(queue, result, &count); -    } -    while (!created); - -    g_mutex_unlock(&queue->mutex); - -    return result; - -} - - -/****************************************************************************** -*                                                                             * -*  Paramètres  : queue = gestionnaire de l'ensemble des groupes de travail.   * -*                id    = identifiant d'un groupe de travail.                  * -*                                                                             * -*  Description : Dissout un groupe de travail existant.                       * -*                                                                             * -*  Retour      : -                                                            * -*                                                                             * -*  Remarques   : -                                                            * -*                                                                             * -******************************************************************************/ - -void g_work_queue_delete_work_group(GWorkQueue *queue, wgroup_id_t id) -{ -    size_t i;                               /* Boucle de parcours          */ -    GWorkGroup *group;                      /* Groupe de travail manipulé  */ -#ifndef NDEBUG -    bool found;                             /* Repérage du groupe visé     */ -#endif - -#ifndef NDEBUG -    found = false; -#endif - -    g_mutex_lock(&queue->mutex); - -    for (i = 0; i < queue->groups_count; i++) -    { -        group = queue->groups[i]; - -        if (g_work_group_get_id(group) == id) -        { -            g_object_unref(G_OBJECT(group)); - -            memmove(&queue->groups[i], &queue->groups[i + 1], -                    (queue->groups_count - i - 1) * sizeof(GWorkGroup *)); - -            queue->groups_count--; -            queue->groups = (GWorkGroup **)realloc(queue->groups, -                                                   queue->groups_count * sizeof(GWorkGroup *)); - -#ifndef NDEBUG -            found = true; -#endif - -            break; - -        } - -    } - -    assert(found); - -    g_cond_broadcast(&queue->wait_all); - -    g_mutex_unlock(&queue->mutex); - -} - - -/****************************************************************************** -*                                                                             * -*  Paramètres  : queue = gestionnaire des actions à mener.                    * -*                work  = nouvelle tâche à programmer, puis effectuer.         * -*                id    = identifiant du groupe de travail d'affectation.      * -*                                                                             * -*  Description : Place une nouvelle tâche en attente.                         * -*                                                                             * -*  Retour      : -                                                            * -*                                                                             * -*  Remarques   : -                                                            * -*                                                                             * -******************************************************************************/ - -void g_work_queue_schedule_work(GWorkQueue *queue, GDelayedWork *work, wgroup_id_t id) -{ -    GWorkGroup *group;                      /* Groupe de travail à attendre*/ - -    group = g_work_queue_find_group_for_id(queue, id); -    assert(group != NULL); - -    g_work_group_schedule(group, work); - -    g_object_unref(G_OBJECT(group)); - -} - - -/****************************************************************************** -*                                                                             * -*  Paramètres  : queue = gestionnaire de l'ensemble des groupes de travail.   * -*                id    = identifiant d'un groupe de travail.                  * -*                                                                             * -*  Description : Fournit le groupe de travail correspondant à un identifiant. * -*                                                                             * -*  Retour      : Eventuel groupe existant trouvé ou NULL si aucun.            * -*                                                                             * -*  Remarques   : -                                                            * -*                                                                             * -******************************************************************************/ - -static GWorkGroup *g_work_queue_find_group_for_id(GWorkQueue *queue, wgroup_id_t id) -{ -    GWorkGroup *result;                     /* Trouvaille à retourner      */ -    size_t i;                               /* Boucle de parcours          */ - -    result = NULL; - -    g_mutex_lock(&queue->mutex); - -    for (i = 0; i < queue->groups_count; i++) -        if (g_work_group_get_id(queue->groups[i]) == id) -        { -            result = queue->groups[i]; -            g_object_ref(G_OBJECT(result)); -            break; -        } - -    g_mutex_unlock(&queue->mutex); - -    return result; - -} - - -/****************************************************************************** -*                                                                             * -*  Paramètres  : queue = gestionnaire de l'ensemble des groupes de travail.   * -*                id    = identifiant d'un groupe de travail.                  * -*                                                                             * -*  Description : Détermine si un groupe est vide de toute programmation.      * -*                                                                             * -*  Retour      : Etat du groupe de travail.                                   * -*                                                                             * -*  Remarques   : -                                                            * -*                                                                             * -******************************************************************************/ - -bool g_work_queue_is_empty(GWorkQueue *queue, wgroup_id_t id) -{ -    bool result;                            /* Etat à retourner            */ -    GWorkGroup *group;                      /* Groupe de travail à attendre*/ - -    group = g_work_queue_find_group_for_id(queue, id); - -    if (group != NULL) +    while ((g_atomic_int_get(&group->pending) > 0) +           && !group->force_exit)      { -        result = g_work_group_is_empty(group); -        g_object_unref(G_OBJECT(group)); +        result = g_cond_wait_until(&group->wait_cond, &group->mutex, end_time); +        if (!result) break;      } -    else -        result = true; +    g_mutex_unlock(&group->mutex);      return result; @@ -1217,39 +505,9 @@ bool g_work_queue_is_empty(GWorkQueue *queue, wgroup_id_t id)  /******************************************************************************  *                                                                             * -*  Paramètres  : queue = gestionnaire de l'ensemble des groupes de travail.   * -*                id    = identifiant d'un groupe de travail.                  * -*                                                                             * -*  Description : Attend que toutes les tâches d'un groupe soient traitées.    * -*                                                                             * -*  Retour      : -                                                            * -*                                                                             * -*  Remarques   : -                                                            * -*                                                                             * -******************************************************************************/ - -void g_work_queue_wait_for_completion(GWorkQueue *queue, wgroup_id_t id) -{ -    GWorkGroup *group;                      /* Groupe de travail à attendre*/ - -    group = g_work_queue_find_group_for_id(queue, id); - -    if (group != NULL) -    { -        g_work_group_wait_for_completion(group, queue); -        g_object_unref(G_OBJECT(group)); -    } - -} - - -/****************************************************************************** -*                                                                             * -*  Paramètres  : queue    = gestionnaire de l'ensemble des groupes de travail.* -*                gb_ids   = identifiants de groupes globaux.                  * -*                gb_count = nombre de ces groupes globaux.                    * +*  Paramètres  : group = groupes de travail à manipuler.                      *  *                                                                             * -*  Description : Attend que toutes les tâches de tout groupe soient traitées. * +*  Description : Force un réveil d'une attente en cours pour la confirmer.    *  *                                                                             *  *  Retour      : -                                                            *  *                                                                             * @@ -1257,97 +515,17 @@ void g_work_queue_wait_for_completion(GWorkQueue *queue, wgroup_id_t id)  *                                                                             *  ******************************************************************************/ -void g_work_queue_wait_for_all_completions(GWorkQueue *queue, const wgroup_id_t *gb_ids, size_t gb_count) +void g_work_group_wake_up_waiters(GWorkGroup *group)  { -    size_t i;                               /* Boucle de parcours          */ - -    g_mutex_lock(&queue->mutex); - - wait_again: - -    /** -     * Attente d'éventuels groupes isolés. -     */ - -    while (queue->groups_count > gb_count) -        g_cond_wait(&queue->wait_all, &queue->mutex); - -    g_mutex_unlock(&queue->mutex); -      /** -     * Attente des groupes principaux. -     */ - -    for (i = 0; i < gb_count; i++) -        g_work_queue_wait_for_completion(queue, gb_ids[i]); - -    /** -     * Si le groupe par défaut a généré de nouveaux groupes, on recommence ! +     * Concernant la pose du verrou, se référer aux commentaires de la +     * fonction g_work_group_process().       */ -    g_mutex_lock(&queue->mutex); - -    if (queue->groups_count > gb_count) -        goto wait_again; - -    g_mutex_unlock(&queue->mutex); - -} - - -/****************************************************************************** -*                                                                             * -*  Paramètres  : queue    = gestionnaire de l'ensemble des groupes de travail.* -*                id       = identifiant d'un groupe de travail.               * -*                callback = éventuelle fonction à appeler ou NULL.            * -*                data     = données devant accompagner l'appel.               * -*                                                                             * -*  Description : Modifie les conditions d'attente des fins d'exécutions.      * -*                                                                             * -*  Retour      : -                                                            * -*                                                                             * -*  Remarques   : -                                                            * -*                                                                             * -******************************************************************************/ - -void g_work_queue_set_extra_wait_callback(GWorkQueue *queue, wgroup_id_t id, wait_for_incoming_works_cb callback, void *data) -{ -    GWorkGroup *group;                      /* Groupe de travail à traiter */ - -    group = g_work_queue_find_group_for_id(queue, id); - -    if (group != NULL) -    { -        g_work_group_set_extra_wait_callback(group, callback, data); -        g_object_unref(G_OBJECT(group)); -    } - -} - - -/****************************************************************************** -*                                                                             * -*  Paramètres  : queue    = gestionnaire de l'ensemble des groupes de travail.* -*                id       = identifiant d'un groupe de travail.               * -*                                                                             * -*  Description : Force un réveil d'une attente en cours pour la confirmer.    * -*                                                                             * -*  Retour      : -                                                            * -*                                                                             * -*  Remarques   : -                                                            * -*                                                                             * -******************************************************************************/ - -void g_work_queue_wake_up_waiters(GWorkQueue *queue, wgroup_id_t id) -{ -    GWorkGroup *group;                      /* Groupe de travail à traiter */ +    g_mutex_lock(&group->mutex); -    group = g_work_queue_find_group_for_id(queue, id); +    g_cond_broadcast(&group->wait_cond); -    if (group != NULL) -    { -        g_work_group_wake_up_waiters(group); -        g_object_unref(G_OBJECT(group)); -    } +    g_mutex_unlock(&group->mutex);  } diff --git a/src/glibext/workgroup.h b/src/glibext/workgroup.h index 89eed12..f40155e 100644 --- a/src/glibext/workgroup.h +++ b/src/glibext/workgroup.h @@ -1,8 +1,8 @@  /* Chrysalide - Outil d'analyse de fichiers binaires - * delayed.h - prototypes pour la gestion des travaux différés + * workgroup.h - prototypes pour la gestion des travaux différés   * - * Copyright (C) 2009-2018 Cyrille Bagard + * Copyright (C) 2009-2024 Cyrille Bagard   *   *  This file is part of Chrysalide.   * @@ -21,58 +21,22 @@   */ -#ifndef _GLIBEXT_DELAYED_H -#define _GLIBEXT_DELAYED_H +#ifndef _GLIBEXT_WORKGROUP_H +#define _GLIBEXT_WORKGROUP_H -#include <glib-object.h>  #include <stdbool.h>  #include <stdint.h> +#include "helpers.h" +#include "work.h" -/* -------------------------- TACHE DIFFEREE DANS LE TEMPS -------------------------- */ -#define G_TYPE_DELAYED_WORK               g_delayed_work_get_type() -#define G_DELAYED_WORK(obj)               (G_TYPE_CHECK_INSTANCE_CAST((obj), g_delayed_work_get_type(), GDelayedWork)) -#define G_IS_DELAYED_WORK(obj)            (G_TYPE_CHECK_INSTANCE_TYPE((obj), g_delayed_work_get_type())) -#define G_DELAYED_WORK_CLASS(klass)       (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_DELAYED_WORK, GDelayedWorkClass)) -#define G_IS_DELAYED_WORK_CLASS(klass)    (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_DELAYED_WORK)) -#define G_DELAYED_WORK_GET_CLASS(obj)     (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_DELAYED_WORK, GDelayedWorkClass)) +#define G_TYPE_WORK_GROUP (g_work_group_get_type()) - -/* Travail différé (instance) */ -typedef struct _GDelayedWork GDelayedWork; - -/* Travail différé (classe) */ -typedef struct _GDelayedWorkClass GDelayedWorkClass; - - -/* Indique le type défini pour les travaux différés. */ -GType g_delayed_work_get_type(void); - -/* Attend la fin de l'exécution d'une tâche donnée. */ -void g_delayed_work_wait_for_completion(GDelayedWork *); - - - -/* ------------------------- TRAITEMENT DE TACHES DIFFEREES ------------------------- */ - - -#define G_TYPE_WORK_QUEUE               g_work_queue_get_type() -#define G_WORK_QUEUE(obj)               (G_TYPE_CHECK_INSTANCE_CAST((obj), g_work_queue_get_type(), GWorkQueue)) -#define G_IS_WORK_QUEUE(obj)            (G_TYPE_CHECK_INSTANCE_TYPE((obj), g_work_queue_get_type())) -#define G_WORK_QUEUE_CLASS(klass)       (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_WORK_QUEUE, GWorkQueueClass)) -#define G_IS_WORK_QUEUE_CLASS(klass)    (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_WORK_QUEUE)) -#define G_WORK_QUEUE_GET_CLASS(obj)     (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_WORK_QUEUE, GWorkQueueClass)) - - -/* Gestionnaire des travaux différés (instance) */ -typedef struct _GWorkQueue GWorkQueue; - -/* Gestionnaire des travaux différés (classe) */ -typedef struct _GWorkQueueClass GWorkQueueClass; +DECLARE_GTYPE(GWorkGroup, g_work_group, G, WORK_GROUP);  /** @@ -83,45 +47,33 @@ typedef struct _GWorkQueueClass GWorkQueueClass;   */  typedef uint64_t wgroup_id_t; +/** + * Marque de non initialisation. + */ +#define INVALID_GROUP_ID 0 -/* Indique le type défini pour le gestionnaire des travaux différés. */ -GType g_work_queue_get_type(void); - -/* Créé un nouveau gestionnaire de tâches parallèles. */ -GWorkQueue *g_work_queue_new(void); - -/* Constitue un nouveau groupe de travail. */ -wgroup_id_t g_work_queue_define_work_group(GWorkQueue *); -/* Constitue un nouveau petit groupe de travail. */ -wgroup_id_t g_work_queue_define_tiny_work_group(GWorkQueue *, guint); +/* Crée un nouveau thread dédié à un type de travaux donné. */ +GWorkGroup *g_work_group_new(wgroup_id_t, guint); -/* Dissout un groupe de travail existant. */ -void g_work_queue_delete_work_group(GWorkQueue *, wgroup_id_t); +/* Fournit l'identifiant associé à un groupe de travail. */ +wgroup_id_t g_work_group_get_id(const GWorkGroup *); -/* Place une nouvelle tâche en attente. */ -void g_work_queue_schedule_work(GWorkQueue *, GDelayedWork *, wgroup_id_t); +/* Place une nouvelle tâche en attente dans une file dédiée. */ +void g_work_group_schedule(GWorkGroup *, GGenericWork *); -/* Détermine si un groupe est vide de toute programmation. */ -bool g_work_queue_is_empty(GWorkQueue *, wgroup_id_t); +/* Détermine si le groupe est vide de toute programmation. */ +bool g_work_group_is_empty(GWorkGroup *);  /* Attend que toutes les tâches d'un groupe soient traitées. */ -void g_work_queue_wait_for_completion(GWorkQueue *, wgroup_id_t); +void g_work_group_wait_for_completion(GWorkGroup *); -/* Attend que toutes les tâches de tout groupe soient traitées. */ -void g_work_queue_wait_for_all_completions(GWorkQueue *, const wgroup_id_t *, size_t); - - -/* Etudie le besoin d'attendre d'avantage de prochaines tâches. */ -typedef bool (* wait_for_incoming_works_cb) (GWorkQueue *, wgroup_id_t, void *); - - -/* Modifie les conditions d'attente des fins d'exécutions. */ -void g_work_queue_set_extra_wait_callback(GWorkQueue *, wgroup_id_t, wait_for_incoming_works_cb, void *); +/* Attend que toutes les tâches d'un groupe soient traitées. */ +bool g_work_group_wait_timed_for_completion(GWorkGroup *, gint64);  /* Force un réveil d'une attente en cours pour la confirmer. */ -void g_work_queue_wake_up_waiters(GWorkQueue *, wgroup_id_t); +void g_work_group_wake_up_waiters(GWorkGroup *); -#endif  /* _GLIBEXT_DELAYED_H */ +#endif  /* _GLIBEXT_WORKGROUP_H */ diff --git a/src/glibext/workqueue-int.h b/src/glibext/workqueue-int.h index 4f84e86..40afa19 100644 --- a/src/glibext/workqueue-int.h +++ b/src/glibext/workqueue-int.h @@ -1,8 +1,8 @@  /* Chrysalide - Outil d'analyse de fichiers binaires - * delayed-int.h - définitions internes pour la gestion des travaux différés + * workqueue-int.h - définitions internes pour la gestion des travaux différés   * - * Copyright (C) 2009-2018 Cyrille Bagard + * Copyright (C) 2009-2024 Cyrille Bagard   *   *  This file is part of Chrysalide.   * @@ -21,55 +21,35 @@   */ -#ifndef _GLIBEXT_DELAYED_INT_H -#define _GLIBEXT_DELAYED_INT_H +#ifndef _GLIBEXT_WORKQUEUE_INT_H +#define _GLIBEXT_WORKQUEUE_INT_H -#include "delayed.h" +#include "workqueue.h" -#include "notifier.h" -#include "../common/dllist.h" - - -/* -------------------------- TACHE DIFFEREE DANS LE TEMPS -------------------------- */ - - -/* Traite un travail programmé. */ -typedef void (* run_task_fc) (GDelayedWork *, GtkStatusStack *); - - -/* Travail différé (instance) */ -struct _GDelayedWork +/* Gestionnaire des travaux différés (instance) */ +struct _GWorkQueue  {      GObject parent;                         /* A laisser en premier        */ -    DL_LIST_ITEM(link);                     /* Lien vers les maillons      */ +    wgroup_id_t generator;                  /* Générateur d'identifiants   */ -    bool completed;                         /* Fin de la tâche ?           */ -    GMutex mutex;                           /* Accès à la variable         */ -    GCond cond;                             /* Attente de changement       */ +    GWorkGroup **groups;                    /* Files de traitement         */ +    size_t groups_count;                    /* Nombre de files internes    */ +    GMutex mutex;                           /* Verrou pour l'accès         */ +    GCond wait_all;                         /* Réveil d'attente globale    */  }; -/* Travail différé (classe) */ -struct _GDelayedWorkClass +/* Gestionnaire des travaux différés (classe) */ +struct _GWorkQueueClass  {      GObjectClass parent;                    /* A laisser en premier        */ -    run_task_fc run;                        /* Traitement externalisé      */ - -    /* Signaux */ - -    void (* work_completed) (GDelayedWork *); -  }; -#define delayed_work_list_add_tail(new, head) dl_list_add_tail(new, head, GDelayedWork, link) -#define delayed_work_list_del(item, head) dl_list_del(item, head, GDelayedWork, link) - - -#endif  /* _GLIBEXT_DELAYED_INT_H */ +#endif  /* _GLIBEXT_WORKQUEUE_INT_H */ diff --git a/src/glibext/workqueue.c b/src/glibext/workqueue.c index 6b5ac35..fe7f1bb 100644 --- a/src/glibext/workqueue.c +++ b/src/glibext/workqueue.c @@ -1,8 +1,8 @@  /* Chrysalide - Outil d'analyse de fichiers binaires - * delayed.c - gestion des travaux différés + * workqueue.c - gestion des travaux différés   * - * Copyright (C) 2009-2018 Cyrille Bagard + * Copyright (C) 2009-2024 Cyrille Bagard   *   *  This file is part of Chrysalide.   * @@ -21,149 +21,15 @@   */ -#include "delayed.h" +#include "workqueue.h"  #include <assert.h> -#include <inttypes.h>  #include <malloc.h> -#include <stdio.h> -#include <string.h> -#include "delayed-int.h" -#include "../core/nproc.h" -#ifdef INCLUDE_GTK_SUPPORT -#   include "../gui/core/global.h" -#endif - - - -/* -------------------------- TACHE DIFFEREE DANS LE TEMPS -------------------------- */ - - -/* Initialise la classe des travaux différés. */ -static void g_delayed_work_class_init(GDelayedWorkClass *); - -/* Initialise une instance de travail différé. */ -static void g_delayed_work_init(GDelayedWork *); - -/* Supprime toutes les références externes. */ -static void g_delayed_work_dispose(GDelayedWork *); - -/* Procède à la libération totale de la mémoire. */ -static void g_delayed_work_finalize(GDelayedWork *); - -/* Mène l'opération programmée. */ -static void g_delayed_work_process(GDelayedWork *, GtkStatusStack *); - - - -/* -------------------------- THREAD DE TRAITEMENTS DEDIES -------------------------- */ - - -#define G_TYPE_WORK_GROUP               g_work_group_get_type() -#define G_WORK_GROUP(obj)               (G_TYPE_CHECK_INSTANCE_CAST((obj), g_work_group_get_type(), GWorkGroup)) -#define G_IS_WORK_GROUP(obj)            (G_TYPE_CHECK_INSTANCE_TYPE((obj), g_work_group_get_type())) -#define G_WORK_GROUP_CLASS(klass)       (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_WORK_GROUP, GWorkGroupClass)) -#define G_IS_WORK_GROUP_CLASS(klass)    (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_WORK_GROUP)) -#define G_WORK_GROUP_GET_CLASS(obj)     (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_WORK_GROUP, GWorkGroupClass)) - - -/* File de traitement pour un type donné (instance) */ -typedef struct _GWorkGroup -{ -    GObject parent;                         /* A laisser en premier        */ - -    wgroup_id_t id;                         /* Identifiant de travaux menés*/ - -    GDelayedWork *works;                    /* Tâches à mener à bien       */ -    GMutex mutex;                           /* Verrou pour l'accès         */ -    GCond cond;                             /* Réveil pour un traitement   */ -    GCond wait_cond;                        /* Réveil d'attente de fin     */ -    gint pending;                           /* Tâches en cours d'exécution */ - -    GThread **threads;                      /* Procédure de traitement     */ -    guint threads_count;                    /* Nombre de procédures        */ -    bool force_exit;                        /* Procédure d'arrêt           */ - -    wait_for_incoming_works_cb callback;    /* Encadre les attentes de fin */ -    void *data;                             /* Données à associer          */ - -} GWorkGroup; - -/* File de traitement pour un type donné (classe) */ -typedef struct _GWorkGroupClass -{ -    GObjectClass parent;                    /* A laisser en premier        */ - -} GWorkGroupClass; - - -/* Indique le type défini pour les groupes de travail. */ -static GType g_work_group_get_type(void); - -/* Initialise la classe des groupes de travail. */ -static void g_work_group_class_init(GWorkGroupClass *); - -/* Initialise une instance de groupe de travail. */ -static void g_work_group_init(GWorkGroup *); +#include "workqueue-int.h" -/* Supprime toutes les références externes. */ -static void g_work_group_dispose(GWorkGroup *); - -/* Procède à la libération totale de la mémoire. */ -static void g_work_group_finalize(GWorkGroup *); - -/* Crée un nouveau thread dédié à un type de travaux donné. */ -static GWorkGroup *g_work_group_new(wgroup_id_t, const guint *); - -/* Fournit l'identifiant associé à un groupe de travail. */ -static wgroup_id_t g_work_group_get_id(const GWorkGroup *); - -/* Place une nouvelle tâche en attente dans une file dédiée. */ -static void g_work_group_schedule(GWorkGroup *, GDelayedWork *); - -/* Assure le traitement en différé. */ -static void *g_work_group_process(GWorkGroup *); - -/* Détermine si le groupe est vide de toute programmation. */ -static bool g_work_group_is_empty(GWorkGroup *); - -/* Attend que toutes les tâches d'un groupe soient traitées. */ -static void g_work_group_wait_for_completion(GWorkGroup *, GWorkQueue *); - -/* Modifie les conditions d'attente des fins d'exécutions. */ -static void g_work_group_set_extra_wait_callback(GWorkGroup *, wait_for_incoming_works_cb, void *); - -/* Force un réveil d'une attente en cours pour la confirmer. */ -static void g_work_group_wake_up_waiters(GWorkGroup *); - - - -/* ------------------------- TRAITEMENT DE TACHES DIFFEREES ------------------------- */ - - -/* Gestionnaire des travaux différés (instance) */ -struct _GWorkQueue -{ -    GObject parent;                         /* A laisser en premier        */ - -    wgroup_id_t generator;                  /* Générateur d'identifiants   */ - -    GWorkGroup **groups;                    /* Files de traitement         */ -    size_t groups_count;                    /* Nombre de files internes    */ -    GMutex mutex;                           /* Verrou pour l'accès         */ -    GCond wait_all;                         /* Réveil d'attente globale    */ - -}; - -/* Gestionnaire des travaux différés (classe) */ -struct _GWorkQueueClass -{ -    GObjectClass parent;                    /* A laisser en premier        */ - -};  /* Initialise la classe des travaux différés. */ @@ -179,641 +45,13 @@ static void g_work_queue_dispose(GWorkQueue *);  static void g_work_queue_finalize(GWorkQueue *);  /* Donne l'assurance de l'existence d'un groupe de travail. */ -static bool g_work_queue_ensure_group_exists(GWorkQueue *, wgroup_id_t, const guint *); +static bool g_work_queue_ensure_group_exists(GWorkQueue *, wgroup_id_t, guint);  /* Fournit le groupe de travail correspondant à un identifiant. */  static GWorkGroup *g_work_queue_find_group_for_id(GWorkQueue *, wgroup_id_t); -/* ---------------------------------------------------------------------------------- */ -/*                            TACHE DIFFEREE DANS LE TEMPS                            */ -/* ---------------------------------------------------------------------------------- */ - - -/* Indique le type défini pour les travaux différés. */ -G_DEFINE_TYPE(GDelayedWork, g_delayed_work, G_TYPE_OBJECT); - - -/****************************************************************************** -*                                                                             * -*  Paramètres  : klass = classe à initialiser.                                * -*                                                                             * -*  Description : Initialise la classe des travaux différés.                   * -*                                                                             * -*  Retour      : -                                                            * -*                                                                             * -*  Remarques   : -                                                            * -*                                                                             * -******************************************************************************/ - -static void g_delayed_work_class_init(GDelayedWorkClass *klass) -{ -    GObjectClass *object;                   /* Autre version de la classe  */ - -    object = G_OBJECT_CLASS(klass); - -    object->dispose = (GObjectFinalizeFunc/* ! */)g_delayed_work_dispose; -    object->finalize = (GObjectFinalizeFunc)g_delayed_work_finalize; - -    g_signal_new("work-completed", -                 G_TYPE_DELAYED_WORK, -                 G_SIGNAL_RUN_LAST, -                 G_STRUCT_OFFSET(GDelayedWorkClass, work_completed), -                 NULL, NULL, -                 g_cclosure_marshal_VOID__VOID, -                 G_TYPE_NONE, 0); - -} - - -/****************************************************************************** -*                                                                             * -*  Paramètres  : work = instance à initialiser.                               * -*                                                                             * -*  Description : Initialise une instance de travail différé.                  * -*                                                                             * -*  Retour      : -                                                            * -*                                                                             * -*  Remarques   : -                                                            * -*                                                                             * -******************************************************************************/ - -static void g_delayed_work_init(GDelayedWork *work) -{ -    work->completed = false; -    g_mutex_init(&work->mutex); -    g_cond_init(&work->cond); - -} - - -/****************************************************************************** -*                                                                             * -*  Paramètres  : work = instance d'objet GLib à traiter.                      * -*                                                                             * -*  Description : Supprime toutes les références externes.                     * -*                                                                             * -*  Retour      : -                                                            * -*                                                                             * -*  Remarques   : -                                                            * -*                                                                             * -******************************************************************************/ - -static void g_delayed_work_dispose(GDelayedWork *work) -{ -    g_mutex_clear(&work->mutex); -    g_cond_clear(&work->cond); - -    G_OBJECT_CLASS(g_delayed_work_parent_class)->dispose(G_OBJECT(work)); - -} - - -/****************************************************************************** -*                                                                             * -*  Paramètres  : work = instance d'objet GLib à traiter.                      * -*                                                                             * -*  Description : Procède à la libération totale de la mémoire.                * -*                                                                             * -*  Retour      : -                                                            * -*                                                                             * -*  Remarques   : -                                                            * -*                                                                             * -******************************************************************************/ - -static void g_delayed_work_finalize(GDelayedWork *work) -{ -    G_OBJECT_CLASS(g_delayed_work_parent_class)->finalize(G_OBJECT(work)); - -} - - -/****************************************************************************** -*                                                                             * -*  Paramètres  : work   = travail à effectuer.                                * -*                status = barre de statut à tenir informée.                   * -*                                                                             * -*  Description : Mène l'opération programmée.                                 * -*                                                                             * -*  Retour      : -                                                            * -*                                                                             * -*  Remarques   : -                                                            * -*                                                                             * -******************************************************************************/ - -static void g_delayed_work_process(GDelayedWork *work, GtkStatusStack *status) -{ -    G_DELAYED_WORK_GET_CLASS(work)->run(work, status); - -    g_mutex_lock(&work->mutex); - -    work->completed = true; - -    g_cond_signal(&work->cond); -    g_mutex_unlock(&work->mutex); - -    g_signal_emit_by_name(work, "work-completed"); - -} - - -/****************************************************************************** -*                                                                             * -*  Paramètres  : work = travail à surveiller.                                 * -*                                                                             * -*  Description : Attend la fin de l'exécution d'une tâche donnée.             * -*                                                                             * -*  Retour      : -                                                            * -*                                                                             * -*  Remarques   : -                                                            * -*                                                                             * -******************************************************************************/ - -void g_delayed_work_wait_for_completion(GDelayedWork *work) -{ -    g_mutex_lock(&work->mutex); - -    while (!work->completed) -        g_cond_wait(&work->cond, &work->mutex); - -    g_mutex_unlock(&work->mutex); - -} - - - -/* ---------------------------------------------------------------------------------- */ -/*                           THREADS DES TRAITEMENTS DEDIES                           */ -/* ---------------------------------------------------------------------------------- */ - - -/* Indique le type défini pour les groupes de travail. */ -G_DEFINE_TYPE(GWorkGroup, g_work_group, G_TYPE_OBJECT); - - -/****************************************************************************** -*                                                                             * -*  Paramètres  : klass = classe à initialiser.                                * -*                                                                             * -*  Description : Initialise la classe des groupes de travail.                 * -*                                                                             * -*  Retour      : -                                                            * -*                                                                             * -*  Remarques   : -                                                            * -*                                                                             * -******************************************************************************/ - -static void g_work_group_class_init(GWorkGroupClass *klass) -{ -    GObjectClass *object;                   /* Autre version de la classe  */ - -    object = G_OBJECT_CLASS(klass); - -    object->dispose = (GObjectFinalizeFunc/* ! */)g_work_group_dispose; -    object->finalize = (GObjectFinalizeFunc)g_work_group_finalize; - -} - - -/****************************************************************************** -*                                                                             * -*  Paramètres  : group = instance à initialiser.                              * -*                                                                             * -*  Description : Initialise une instance de groupe de travail.                * -*                                                                             * -*  Retour      : -                                                            * -*                                                                             * -*  Remarques   : -                                                            * -*                                                                             * -******************************************************************************/ - -static void g_work_group_init(GWorkGroup *group) -{ -    group->works = NULL; - -    g_mutex_init(&group->mutex); -    g_cond_init(&group->cond); -    g_cond_init(&group->wait_cond); - -    g_atomic_int_set(&group->pending, 0); - -    group->threads = NULL; -    group->threads_count = 0; -    group->force_exit = false; - -    group->callback = NULL; -    group->data = NULL; - -} - - -/****************************************************************************** -*                                                                             * -*  Paramètres  : queue = instance d'objet GLib à traiter.                     * -*                                                                             * -*  Description : Supprime toutes les références externes.                     * -*                                                                             * -*  Retour      : -                                                            * -*                                                                             * -*  Remarques   : -                                                            * -*                                                                             * -******************************************************************************/ - -static void g_work_group_dispose(GWorkGroup *group) -{ -    guint i;                                /* Boucle de parcours          */ -    GDelayedWork *work;                     /* Travail à oublier           */ - -    group->force_exit = true; - -    /** -     * Concernant la pose du verrou, se référer aux commentaires de la -     * fonction g_work_group_process(). -     */ - -    g_mutex_lock(&group->mutex); - -    g_cond_broadcast(&group->cond); - -    g_mutex_unlock(&group->mutex); - -    for (i = 0; i < group->threads_count; i++) -        g_thread_join(group->threads[i]); - -    while (!dl_list_empty(group->works)) -    { -        work = group->works; -        delayed_work_list_del(work, &group->works); - -        g_object_unref(G_OBJECT(work)); - -    } - -    g_mutex_clear(&group->mutex); -    g_cond_clear(&group->cond); -    g_cond_clear(&group->wait_cond); - -    G_OBJECT_CLASS(g_work_group_parent_class)->dispose(G_OBJECT(group)); - -} - - -/****************************************************************************** -*                                                                             * -*  Paramètres  : group = instance d'objet GLib à traiter.                     * -*                                                                             * -*  Description : Procède à la libération totale de la mémoire.                * -*                                                                             * -*  Retour      : -                                                            * -*                                                                             * -*  Remarques   : -                                                            * -*                                                                             * -******************************************************************************/ - -static void g_work_group_finalize(GWorkGroup *group) -{ -    if (group->threads != NULL) -        free(group->threads); - -    G_OBJECT_CLASS(g_work_group_parent_class)->finalize(G_OBJECT(group)); - -} - - -/****************************************************************************** -*                                                                             * -*  Paramètres  : id    = identifiant accordé au nouveau groupe.               * -*                count = quantité de threads à allouer.                       * -*                                                                             * -*  Description : Crée un nouveau thread dédié à un type de travaux donné.     * -*                                                                             * -*  Retour      : Structure associée au thread mise en place.                  * -*                                                                             * -*  Remarques   : -                                                            * -*                                                                             * -******************************************************************************/ - -static GWorkGroup *g_work_group_new(wgroup_id_t id, const guint *count) -{ -    GWorkGroup *result;                    /* Traiteur à retourner        */ -    guint i;                                /* Boucle de parcours          */ -    char name[16];                          /* Désignation humaine         */ - -    result = g_object_new(G_TYPE_WORK_GROUP, NULL); - -    result->id = id; - -    result->threads_count = get_max_online_threads(); - -    if (count != NULL && *count < result->threads_count) -        result->threads_count = *count; - -    result->threads = (GThread **)calloc(result->threads_count, sizeof(GThread *)); - -    for (i = 0; i < result->threads_count; i++) -    { -        snprintf(name, sizeof(name), "wgrp_%" PRIu64 "-%u", id, i); - -        result->threads[i] = g_thread_new(name, (GThreadFunc)g_work_group_process, result); -        if (!result->threads[i]) -            goto start_error; - -    } - - start_error: - -    result->threads_count = i; - -    assert(i > 0); - -    return result; - -} - - -/****************************************************************************** -*                                                                             * -*  Paramètres  : group = gestionnaire des actions à mener.                    * -*                                                                             * -*  Description : Fournit l'identifiant associé à un groupe de travail.        * -*                                                                             * -*  Retour      : Identifiant unique attribué au groupe de travail.            * -*                                                                             * -*  Remarques   : -                                                            * -*                                                                             * -******************************************************************************/ - -static wgroup_id_t g_work_group_get_id(const GWorkGroup *group) -{ -    return group->id; - -} - - -/****************************************************************************** -*                                                                             * -*  Paramètres  : group = gestionnaire des actions à mener.                    * -*                work  = nouvelle tâche à programmer, puis effectuer.         * -*                                                                             * -*  Description : Place une nouvelle tâche en attente dans une file dédiée.    * -*                                                                             * -*  Retour      : -                                                            * -*                                                                             * -*  Remarques   : -                                                            * -*                                                                             * -******************************************************************************/ - -static void g_work_group_schedule(GWorkGroup *group, GDelayedWork *work) -{ -    g_mutex_lock(&group->mutex); - -    g_atomic_int_inc(&group->pending); - -    delayed_work_list_add_tail(work, &group->works); - -    g_cond_signal(&group->cond); - -    g_mutex_unlock(&group->mutex); - -} - - -/****************************************************************************** -*                                                                             * -*  Paramètres  : group = gestionnaire des actions à mener.                    * -*                                                                             * -*  Description : Assure le traitement en différé.                             * -*                                                                             * -*  Retour      : Bilan de l'opération.                                        * -*                                                                             * -*  Remarques   : -                                                            * -*                                                                             * -******************************************************************************/ - -static void *g_work_group_process(GWorkGroup *group) -{ -    GDelayedWork *work;                     /* Traitement à mener          */ -    GtkStatusStack *status;                 /* Zone d'info éventuelle      */ - -    while (1) -    { -        g_mutex_lock(&group->mutex); - -        while (dl_list_empty(group->works) && !group->force_exit) -            g_cond_wait(&group->cond, &group->mutex); - -        if (group->force_exit) -        { -            g_mutex_unlock(&group->mutex); -            break; -        } - -        work = group->works; -        delayed_work_list_del(work, &group->works); - -        g_mutex_unlock(&group->mutex); - -#ifdef INCLUDE_GTK_SUPPORT -        status = get_global_status(); -#else -        status = NULL; -#endif -        g_delayed_work_process(work, status); - -        g_object_unref(G_OBJECT(work)); - -        /** -         * Verrou ou pas verrou ? -         * -         * La documentation de la GLib indique que ce n'est pas nécessaire : -         * -         *    ''' -         *    It is good practice to lock the same mutex as the waiting threads -         *    while calling this function, though not required. -         *    ''' -         * -         * Ce conseil se trouve verbatim à l'adresse : -         * -         *    https://developer.gnome.org/glib/stable/glib-Threads.html#g-cond-broadcast -         * -         * Dans la pratique, il peut arriver que l'attente de la fonction -         * g_work_group_wait_for_completion() ne soit jamais interrompue. -         * -         * La documentation POSIX est un peu plus orientée : -         * -         *    ''' -         *    The pthread_cond_broadcast() functions may be called by a thread -         *    whether or not it currently owns the mutex that threads calling -         *    pthread_cond_wait() have associated with the condition variable -         *    during their waits; however, if predictable scheduling behavior is -         *    required, then that mutex shall be locked by the thread calling -         *    pthread_cond_broadcast(). -         *    ''' -         * -         * Ce passage complet est consultable à l'adresse : -         * -         *    http://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_cond_broadcast.html -         * -         * La page de manuel pthread_cond_broadcast(3) est quant à elle plus -         * directrice : aucun complément d'information sur le sujet n'est fourni -         * et les exemples associés utilisent implicement un verrou pendant -         * sont appel. -         */ - -        g_mutex_lock(&group->mutex); - -        if (g_atomic_int_dec_and_test(&group->pending)) -            g_cond_broadcast(&group->wait_cond); - -        g_mutex_unlock(&group->mutex); - -    } - -    return NULL; - -} - - -/****************************************************************************** -*                                                                             * -*  Paramètres  : group = gestionnaire des actions à consulter.                * -*                                                                             * -*  Description : Détermine si le groupe est vide de toute programmation.      * -*                                                                             * -*  Retour      : Etat du groupe de travail.                                   * -*                                                                             * -*  Remarques   : -                                                            * -*                                                                             * -******************************************************************************/ - -static bool g_work_group_is_empty(GWorkGroup *group) -{ -    bool result;                            /* Etat à retourner            */ - -    /** -     * Pour que le résultat soit exploitable, il ne doit pas varier -     * en dehors de la zone couverte par le verrou du groupe avant -     * son utilisation par l'appelant. -     * -     * Il doit donc logiquement y avoir un autre verrou en amont et, -     * comme à priori on ne devrait pas bloquer les groupes principaux -     * pour un traitement particulier, cette procédure ne devrait concerner -     * que des groupes dynamiques. -     */ - -    g_mutex_lock(&group->mutex); - -    result = dl_list_empty(group->works); - -    g_mutex_unlock(&group->mutex); - -    return result; - -} - - -/****************************************************************************** -*                                                                             * -*  Paramètres  : group = groupe dont les conclusions sont attendues.          * -*                queue = queue d'appartenance pour les appels externes.       * -*                                                                             * -*  Description : Attend que toutes les tâches d'un groupe soient traitées.    * -*                                                                             * -*  Retour      : -                                                            * -*                                                                             * -*  Remarques   : -                                                            * -*                                                                             * -******************************************************************************/ - -static void g_work_group_wait_for_completion(GWorkGroup *group, GWorkQueue *queue) -{ -    wait_for_incoming_works_cb callback;    /* Procédure complémentaire    */ - -    bool no_extra_check(GWorkQueue *_q, wgroup_id_t _id, void *_data) -    { -        return false; -    } - -    callback = group->callback != NULL ? group->callback : no_extra_check; - -    g_mutex_lock(&group->mutex); - -    /** -     * On attend que : -     *  - la liste des tâches programmées soit vide. -     *  - il n'existe plus de tâche en cours. -     *  - rien n'indique que de nouvelles tâches supplémentaires vont arriver. -     */ - -    while ((g_atomic_int_get(&group->pending) > 0 || callback(queue, group->id, group->data)) -           && !group->force_exit) -    { -        g_cond_wait(&group->wait_cond, &group->mutex); -    } - -    g_mutex_unlock(&group->mutex); - -} - - -/****************************************************************************** -*                                                                             * -*  Paramètres  : group    = groupe dont les paramètres sont à modifier.       * -*                callback = éventuelle fonction à appeler ou NULL.            * -*                data     = données devant accompagner l'appel.               * -*                                                                             * -*  Description : Modifie les conditions d'attente des fins d'exécutions.      * -*                                                                             * -*  Retour      : -                                                            * -*                                                                             * -*  Remarques   : -                                                            * -*                                                                             * -******************************************************************************/ - -static void g_work_group_set_extra_wait_callback(GWorkGroup *group, wait_for_incoming_works_cb callback, void *data) -{ -    group->callback = callback; -    group->data = data; - -} - - -/****************************************************************************** -*                                                                             * -*  Paramètres  : queue    = gestionnaire de l'ensemble des groupes de travail.* -*                id       = identifiant d'un groupe de travail.               * -*                                                                             * -*  Description : Force un réveil d'une attente en cours pour la confirmer.    * -*                                                                             * -*  Retour      : -                                                            * -*                                                                             * -*  Remarques   : -                                                            * -*                                                                             * -******************************************************************************/ - -static void g_work_group_wake_up_waiters(GWorkGroup *group) -{ -    /** -     * Concernant la pose du verrou, se référer aux commentaires de la -     * fonction g_work_group_process(). -     */ - -    g_mutex_lock(&group->mutex); - -    g_cond_broadcast(&group->wait_cond); - -    g_mutex_unlock(&group->mutex); - -} - - - -/* ---------------------------------------------------------------------------------- */ -/*                           TRAITEMENT DE TACHES DIFFEREES                           */ -/* ---------------------------------------------------------------------------------- */ - -  /* Indique le type défini pour le gestionnaire des travaux différés. */  G_DEFINE_TYPE(GWorkQueue, g_work_queue, G_TYPE_OBJECT); @@ -946,7 +184,7 @@ GWorkQueue *g_work_queue_new(void)  *                                                                             *  *  Paramètres  : queue = gestionnaire de l'ensemble des groupes de travail.   *  *                id    = identifiant d'un groupe de travail.                  * -*                count = quantité de threads à allouer.                       * +*                count = quantité de threads à allouer (0 pour un défaut).    *  *                                                                             *  *  Description : Donne l'assurance de l'existence d'un groupe de travail.     *  *                                                                             * @@ -956,7 +194,7 @@ GWorkQueue *g_work_queue_new(void)  *                                                                             *  ******************************************************************************/ -static bool g_work_queue_ensure_group_exists(GWorkQueue *queue, wgroup_id_t id, const guint *count) +static bool g_work_queue_ensure_group_exists(GWorkQueue *queue, wgroup_id_t id, guint count)  {      bool found;                             /* Bilan des recherches        */      size_t i;                               /* Boucle de parcours          */ @@ -975,8 +213,7 @@ static bool g_work_queue_ensure_group_exists(GWorkQueue *queue, wgroup_id_t id,      if (!found)      {          queue->groups_count++; -        queue->groups = (GWorkGroup **)realloc(queue->groups, -                                               queue->groups_count * sizeof(GWorkGroup *)); +        queue->groups = realloc(queue->groups, queue->groups_count * sizeof(GWorkGroup *));          group = g_work_group_new(id, count);          queue->groups[queue->groups_count - 1] = group; @@ -991,6 +228,7 @@ static bool g_work_queue_ensure_group_exists(GWorkQueue *queue, wgroup_id_t id,  /******************************************************************************  *                                                                             *  *  Paramètres  : queue = gestionnaire de l'ensemble des groupes de travail.   * +*                count = quantité de threads à allouer (0 pour un défaut).    *  *                                                                             *  *  Description : Constitue un nouveau groupe de travail.                      *  *                                                                             * @@ -1000,7 +238,7 @@ static bool g_work_queue_ensure_group_exists(GWorkQueue *queue, wgroup_id_t id,  *                                                                             *  ******************************************************************************/ -wgroup_id_t g_work_queue_define_work_group(GWorkQueue *queue) +wgroup_id_t g_work_queue_define_group(GWorkQueue *queue, guint count)  {      wgroup_id_t result;                     /* Valeur à retourner          */      bool created;                           /* Bilan d'une tentative       */ @@ -1009,42 +247,13 @@ wgroup_id_t g_work_queue_define_work_group(GWorkQueue *queue)      do      { -        result = queue->generator++; -        created = g_work_queue_ensure_group_exists(queue, result, NULL); -    } -    while (!created); +        result = ++queue->generator; -    g_mutex_unlock(&queue->mutex); +        if (result == INVALID_GROUP_ID) +            continue; -    return result; - -} - - -/****************************************************************************** -*                                                                             * -*  Paramètres  : queue = gestionnaire de l'ensemble des groupes de travail.   * -*                count = quantité de threads à allouer.                       * -*                                                                             * -*  Description : Constitue un nouveau petit groupe de travail.                * -*                                                                             * -*  Retour      : Nouvel identifiant unique d'un nouveau groupe de travail.    * -*                                                                             * -*  Remarques   : -                                                            * -*                                                                             * -******************************************************************************/ +        created = g_work_queue_ensure_group_exists(queue, result, count); -wgroup_id_t g_work_queue_define_tiny_work_group(GWorkQueue *queue, guint count) -{ -    wgroup_id_t result;                     /* Valeur à retourner          */ -    bool created;                           /* Bilan d'une tentative       */ - -    g_mutex_lock(&queue->mutex); - -    do -    { -        result = queue->generator++; -        created = g_work_queue_ensure_group_exists(queue, result, &count);      }      while (!created); @@ -1068,7 +277,7 @@ wgroup_id_t g_work_queue_define_tiny_work_group(GWorkQueue *queue, guint count)  *                                                                             *  ******************************************************************************/ -void g_work_queue_delete_work_group(GWorkQueue *queue, wgroup_id_t id) +void g_work_queue_delete_group(GWorkQueue *queue, wgroup_id_t id)  {      size_t i;                               /* Boucle de parcours          */      GWorkGroup *group;                      /* Groupe de travail manipulé  */ @@ -1088,14 +297,13 @@ void g_work_queue_delete_work_group(GWorkQueue *queue, wgroup_id_t id)          if (g_work_group_get_id(group) == id)          { -            g_object_unref(G_OBJECT(group)); +            unref_object(group);              memmove(&queue->groups[i], &queue->groups[i + 1],                      (queue->groups_count - i - 1) * sizeof(GWorkGroup *));              queue->groups_count--; -            queue->groups = (GWorkGroup **)realloc(queue->groups, -                                                   queue->groups_count * sizeof(GWorkGroup *)); +            queue->groups = realloc(queue->groups, queue->groups_count * sizeof(GWorkGroup *));  #ifndef NDEBUG              found = true; @@ -1124,22 +332,31 @@ void g_work_queue_delete_work_group(GWorkQueue *queue, wgroup_id_t id)  *                                                                             *  *  Description : Place une nouvelle tâche en attente.                         *  *                                                                             * -*  Retour      : -                                                            * +*  Retour      : Bilan, qui correspond à l'existence du groupe ciblé.         *  *                                                                             *  *  Remarques   : -                                                            *  *                                                                             *  ******************************************************************************/ -void g_work_queue_schedule_work(GWorkQueue *queue, GDelayedWork *work, wgroup_id_t id) +bool g_work_queue_schedule(GWorkQueue *queue, GGenericWork *work, wgroup_id_t id)  { +    bool result;                            /* Bilan à retourner           */      GWorkGroup *group;                      /* Groupe de travail à attendre*/      group = g_work_queue_find_group_for_id(queue, id);      assert(group != NULL); -    g_work_group_schedule(group, work); +    result = (group != NULL); -    g_object_unref(G_OBJECT(group)); +    if (result) +    { +        g_work_group_schedule(group, work); + +        unref_object(group); + +    } + +    return result;  } @@ -1170,7 +387,7 @@ static GWorkGroup *g_work_queue_find_group_for_id(GWorkQueue *queue, wgroup_id_t          if (g_work_group_get_id(queue->groups[i]) == id)          {              result = queue->groups[i]; -            g_object_ref(G_OBJECT(result)); +            ref_object(result);              break;          } @@ -1204,7 +421,7 @@ bool g_work_queue_is_empty(GWorkQueue *queue, wgroup_id_t id)      if (group != NULL)      {          result = g_work_group_is_empty(group); -        g_object_unref(G_OBJECT(group)); +        unref_object(group);      }      else @@ -1236,8 +453,8 @@ void g_work_queue_wait_for_completion(GWorkQueue *queue, wgroup_id_t id)      if (group != NULL)      { -        g_work_group_wait_for_completion(group, queue); -        g_object_unref(G_OBJECT(group)); +        g_work_group_wait_for_completion(group); +        unref_object(group);      }  } @@ -1245,6 +462,40 @@ void g_work_queue_wait_for_completion(GWorkQueue *queue, wgroup_id_t id)  /******************************************************************************  *                                                                             * +*  Paramètres  : queue = gestionnaire de l'ensemble des groupes de travail.   * +*                id    = identifiant d'un groupe de travail.                  * +*                rel   = durée relative à patienter au max. en microsecondes. * +*                                                                             * +*  Description : Attend que toutes les tâches d'un groupe soient traitées.    * +*                                                                             * +*  Retour      : Bilan de l'attente : false en cas d'expiration, true sinon.  * +*                                                                             * +*  Remarques   : Cette fonction est originellement dédiée à un usage Python.  * +*                                                                             * +******************************************************************************/ + +bool g_work_queue_wait_timed_for_completion(GWorkQueue *queue, wgroup_id_t id, gint64 rel) +{ +    bool result;                            /* Bilan d'attente à renvoyer  */ +    GWorkGroup *group;                      /* Groupe de travail à attendre*/ + +    group = g_work_queue_find_group_for_id(queue, id); + +    if (group != NULL) +    { +        result = g_work_group_wait_timed_for_completion(group, rel); +        unref_object(group); +    } +    else +        result = true; + +    return result; + +} + + +/****************************************************************************** +*                                                                             *  *  Paramètres  : queue    = gestionnaire de l'ensemble des groupes de travail.*  *                gb_ids   = identifiants de groupes globaux.                  *  *                gb_count = nombre de ces groupes globaux.                    * @@ -1299,36 +550,6 @@ void g_work_queue_wait_for_all_completions(GWorkQueue *queue, const wgroup_id_t  *                                                                             *  *  Paramètres  : queue    = gestionnaire de l'ensemble des groupes de travail.*  *                id       = identifiant d'un groupe de travail.               * -*                callback = éventuelle fonction à appeler ou NULL.            * -*                data     = données devant accompagner l'appel.               * -*                                                                             * -*  Description : Modifie les conditions d'attente des fins d'exécutions.      * -*                                                                             * -*  Retour      : -                                                            * -*                                                                             * -*  Remarques   : -                                                            * -*                                                                             * -******************************************************************************/ - -void g_work_queue_set_extra_wait_callback(GWorkQueue *queue, wgroup_id_t id, wait_for_incoming_works_cb callback, void *data) -{ -    GWorkGroup *group;                      /* Groupe de travail à traiter */ - -    group = g_work_queue_find_group_for_id(queue, id); - -    if (group != NULL) -    { -        g_work_group_set_extra_wait_callback(group, callback, data); -        g_object_unref(G_OBJECT(group)); -    } - -} - - -/****************************************************************************** -*                                                                             * -*  Paramètres  : queue    = gestionnaire de l'ensemble des groupes de travail.* -*                id       = identifiant d'un groupe de travail.               *  *                                                                             *  *  Description : Force un réveil d'une attente en cours pour la confirmer.    *  *                                                                             * @@ -1347,7 +568,7 @@ void g_work_queue_wake_up_waiters(GWorkQueue *queue, wgroup_id_t id)      if (group != NULL)      {          g_work_group_wake_up_waiters(group); -        g_object_unref(G_OBJECT(group)); +        unref_object(group);      }  } diff --git a/src/glibext/workqueue.h b/src/glibext/workqueue.h index 89eed12..963d86a 100644 --- a/src/glibext/workqueue.h +++ b/src/glibext/workqueue.h @@ -1,8 +1,8 @@  /* Chrysalide - Outil d'analyse de fichiers binaires - * delayed.h - prototypes pour la gestion des travaux différés + * workqueue.h - prototypes pour la gestion des travaux différés   * - * Copyright (C) 2009-2018 Cyrille Bagard + * Copyright (C) 2009-2024 Cyrille Bagard   *   *  This file is part of Chrysalide.   * @@ -21,86 +21,34 @@   */ -#ifndef _GLIBEXT_DELAYED_H -#define _GLIBEXT_DELAYED_H +#ifndef _GLIBEXT_WORKQUEUE_H +#define _GLIBEXT_WORKQUEUE_H -#include <glib-object.h>  #include <stdbool.h> -#include <stdint.h> +#include "helpers.h" +#include "workgroup.h" -/* -------------------------- TACHE DIFFEREE DANS LE TEMPS -------------------------- */ -#define G_TYPE_DELAYED_WORK               g_delayed_work_get_type() -#define G_DELAYED_WORK(obj)               (G_TYPE_CHECK_INSTANCE_CAST((obj), g_delayed_work_get_type(), GDelayedWork)) -#define G_IS_DELAYED_WORK(obj)            (G_TYPE_CHECK_INSTANCE_TYPE((obj), g_delayed_work_get_type())) -#define G_DELAYED_WORK_CLASS(klass)       (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_DELAYED_WORK, GDelayedWorkClass)) -#define G_IS_DELAYED_WORK_CLASS(klass)    (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_DELAYED_WORK)) -#define G_DELAYED_WORK_GET_CLASS(obj)     (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_DELAYED_WORK, GDelayedWorkClass)) +#define G_TYPE_WORK_QUEUE (g_work_queue_get_type()) +DECLARE_GTYPE(GWorkQueue, g_work_queue, G, WORK_QUEUE); -/* Travail différé (instance) */ -typedef struct _GDelayedWork GDelayedWork; - -/* Travail différé (classe) */ -typedef struct _GDelayedWorkClass GDelayedWorkClass; - - -/* Indique le type défini pour les travaux différés. */ -GType g_delayed_work_get_type(void); - -/* Attend la fin de l'exécution d'une tâche donnée. */ -void g_delayed_work_wait_for_completion(GDelayedWork *); - - - -/* ------------------------- TRAITEMENT DE TACHES DIFFEREES ------------------------- */ - - -#define G_TYPE_WORK_QUEUE               g_work_queue_get_type() -#define G_WORK_QUEUE(obj)               (G_TYPE_CHECK_INSTANCE_CAST((obj), g_work_queue_get_type(), GWorkQueue)) -#define G_IS_WORK_QUEUE(obj)            (G_TYPE_CHECK_INSTANCE_TYPE((obj), g_work_queue_get_type())) -#define G_WORK_QUEUE_CLASS(klass)       (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_WORK_QUEUE, GWorkQueueClass)) -#define G_IS_WORK_QUEUE_CLASS(klass)    (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_WORK_QUEUE)) -#define G_WORK_QUEUE_GET_CLASS(obj)     (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_WORK_QUEUE, GWorkQueueClass)) - - -/* Gestionnaire des travaux différés (instance) */ -typedef struct _GWorkQueue GWorkQueue; - -/* Gestionnaire des travaux différés (classe) */ -typedef struct _GWorkQueueClass GWorkQueueClass; - - -/** - * Identifiant unique pour groupe de travail. - * - * Le nombre de bits est forcé à 64 bits car glib-genmarshal ne reconnait - * pas explicitement le type 'unsigned long long'. - */ -typedef uint64_t wgroup_id_t; - - -/* Indique le type défini pour le gestionnaire des travaux différés. */ -GType g_work_queue_get_type(void);  /* Créé un nouveau gestionnaire de tâches parallèles. */  GWorkQueue *g_work_queue_new(void);  /* Constitue un nouveau groupe de travail. */ -wgroup_id_t g_work_queue_define_work_group(GWorkQueue *); - -/* Constitue un nouveau petit groupe de travail. */ -wgroup_id_t g_work_queue_define_tiny_work_group(GWorkQueue *, guint); +wgroup_id_t g_work_queue_define_group(GWorkQueue *, guint);  /* Dissout un groupe de travail existant. */ -void g_work_queue_delete_work_group(GWorkQueue *, wgroup_id_t); +void g_work_queue_delete_group(GWorkQueue *, wgroup_id_t);  /* Place une nouvelle tâche en attente. */ -void g_work_queue_schedule_work(GWorkQueue *, GDelayedWork *, wgroup_id_t); +bool g_work_queue_schedule(GWorkQueue *, GGenericWork *, wgroup_id_t);  /* Détermine si un groupe est vide de toute programmation. */  bool g_work_queue_is_empty(GWorkQueue *, wgroup_id_t); @@ -108,20 +56,15 @@ bool g_work_queue_is_empty(GWorkQueue *, wgroup_id_t);  /* Attend que toutes les tâches d'un groupe soient traitées. */  void g_work_queue_wait_for_completion(GWorkQueue *, wgroup_id_t); +/* Attend que toutes les tâches d'un groupe soient traitées. */ +bool g_work_queue_wait_timed_for_completion(GWorkQueue *, wgroup_id_t, gint64); +  /* Attend que toutes les tâches de tout groupe soient traitées. */  void g_work_queue_wait_for_all_completions(GWorkQueue *, const wgroup_id_t *, size_t); - -/* Etudie le besoin d'attendre d'avantage de prochaines tâches. */ -typedef bool (* wait_for_incoming_works_cb) (GWorkQueue *, wgroup_id_t, void *); - - -/* Modifie les conditions d'attente des fins d'exécutions. */ -void g_work_queue_set_extra_wait_callback(GWorkQueue *, wgroup_id_t, wait_for_incoming_works_cb, void *); -  /* Force un réveil d'une attente en cours pour la confirmer. */  void g_work_queue_wake_up_waiters(GWorkQueue *, wgroup_id_t); -#endif  /* _GLIBEXT_DELAYED_H */ +#endif  /* _GLIBEXT_WORKQUEUE_H */ diff --git a/src/gtkext/Makefile.am b/src/gtkext/Makefile.am index c9445e6..c6908dd 100644 --- a/src/gtkext/Makefile.am +++ b/src/gtkext/Makefile.am @@ -13,15 +13,11 @@ libgtkext_la_SOURCES =						\  	gtkblockdisplay.h gtkblockdisplay.c		\  	gtkdockable-int.h						\  	gtkdockable.h gtkdockable.c				\ -	gtkdockstation.h gtkdockstation.c		\  	gtkgraphdisplay.h gtkgraphdisplay.c		\ -	gtkstatusstack.h gtkstatusstack.c		\  	hexdisplay.h hexdisplay.c				\  	named-int.h								\  	named.h named.c							\ -	resources.h resources.c					\  	support.h support.c						\ -	tiledgrid.h tiledgrid.c					\  	tmgt.h tmgt.c  libgtkext_la_LIBADD = 						\ @@ -30,9 +26,19 @@ libgtkext_la_LIBADD = 						\  libgtkext_la_CFLAGS = $(LIBGTK_CFLAGS) $(LIBXML_CFLAGS) +IMG_PATH = ../../data/images +  RES_FILES =									\ +	grid.ui									\ +	dockstation.ui							\  	hexview.css								\ -	hexview.ui +	hexview.ui								\ +	launcher.ui								\ +	statusstack.ui							\ +	$(IMG_PATH)/nolock-symbolic.svg			\ +	$(IMG_PATH)/locked-symbolic.svg			\ +	$(IMG_PATH)/unlocked-symbolic.svg		\ +	tweak.ui  libgtkext4_la_SOURCES =						\  	area-int.h								\ @@ -41,19 +47,36 @@ libgtkext4_la_SOURCES =						\  	bufferview.h bufferview.c				\  	contentview-int.h						\  	contentview.h contentview.c				\ +	dockstation-int.h						\ +	dockstation.h dockstation.c				\ +	grid-int.h								\ +	grid.h grid.c							\ +	helpers.h								\  	hexview-int.h							\  	hexview.h hexview.c						\ -	resources.h resources.c +	launcher-int.h							\ +	launcher.h launcher.c					\ +	panel-int.h								\ +	panel.h panel.c							\ +	resources.h resources.c					\ +	statusstack-int.h						\ +	statusstack.h statusstack.c				\ +	tweak-int.h								\ +	tweak.h tweak.c  libgtkext4_la_CFLAGS = $(LIBGTK4_CFLAGS) +libgtkext4_la_LIBADD = 						\ +	bindings/libgtkextbindings.la +  devdir = $(includedir)/chrysalide/$(subdir:src/%=core/%) -dev_HEADERS = $(libgtkext_la_SOURCES:%c=) +dev_HEADERS = $(libgtkext4_la_SOURCES:%c=)  #SUBDIRS = graph +SUBDIRS = bindings  resources.c: gresource.xml $(RES_FILES) diff --git a/src/gtkext/area.c b/src/gtkext/area.c index 3c59a59..3c573b2 100644 --- a/src/gtkext/area.c +++ b/src/gtkext/area.c @@ -85,6 +85,8 @@ static void gtk_composing_area_class_init(GtkComposingAreaClass *class)      widget = GTK_WIDGET_CLASS(class); +    gtk_widget_class_set_css_name(widget, "comparea"); +      widget->snapshot = gtk_composing_area_snapshot;  } diff --git a/src/gtkext/bindings/Makefile.am b/src/gtkext/bindings/Makefile.am new file mode 100644 index 0000000..71e770d --- /dev/null +++ b/src/gtkext/bindings/Makefile.am @@ -0,0 +1,42 @@ + +EXTRA_DIST = \ +	generated-enums.c.template \ +	generated-enums.h.template + + +noinst_LTLIBRARIES  = libgtkextbindings.la + + +nodist_libgtkextbindings_la_SOURCES = \ +	grid-enums.h grid-enums.c + +libgtkextbindings_la_CFLAGS = $(LIBGTK4_CFLAGS) + + +BUILT_SOURCES = $(nodist_libgtkextbindings_la_SOURCES) +CLEANFILES = $(nodist_libgtkextbindings_la_SOURCES) + + +devdir = $(includedir)/chrysalide/$(subdir:src/%=core/%) + +dev_HEADERS = $(nodist_libgtkextbindings_la_SOURCES:%c=) + + +grid-enums.c: ../../gtkext/grid.h generated-enums.c.template +	$(AM_V_GEN)$(GLIB_MKENUMS) \ +		--fhead "#include \"$(subst .c,.h,$@)\"\n" \ +		--template=$(srcdir)/generated-enums.c.template \ +		--output=$(srcdir)/$@ \ +		$< + +grid-enums.h: ../../gtkext/grid.h generated-enums.h.template +	$(AM_V_GEN)$(GLIB_MKENUMS) \ +		--fhead "#ifndef _GTKEXT_BINDINGS_GRID_ENUM_H\n" \ +		--fhead "#define _GTKEXT_BINDINGS_GRID_ENUM_H\n" \ +		--fhead "\n" \ +		--fhead "#include \"$<\"\n" \ +		--fhead "\n" \ +		--ftail "#endif  /* _GTKEXT_BINDINGS_GRID_ENUM_H */\n" \ +		--template=$(srcdir)/generated-enums.h.template \ +		--output=$(srcdir)/$@ \ +		$< diff --git a/src/gtkext/bindings/generated-enums.c.template b/src/gtkext/bindings/generated-enums.c.template new file mode 100644 index 0000000..8f54149 --- /dev/null +++ b/src/gtkext/bindings/generated-enums.c.template @@ -0,0 +1,41 @@ +// SPDX-License-Identifier: LGPL-2.1-or-later +// SPDX-FileCopyrightText: 2023 Bartosz Golaszewski <bartosz.golaszewski@linaro.org> + +/*** BEGIN file-header ***/ + +/*** END file-header ***/ + +/*** BEGIN file-production ***/ + +/* Enumerations de "@filename@" */ + +/*** END file-production ***/ + +/*** BEGIN value-header ***/ + +GType @enum_name@_get_type(void) +{ +	static gsize static_g_@type@_type_id; + +	if (g_once_init_enter(&static_g_@type@_type_id)) { +		static const G@Type@Value values[] = { +/*** END value-header ***/ + +/*** BEGIN value-production ***/ +			{@VALUENAME@, "@VALUENAME@", "@valuenick@"}, +/*** END value-production ***/ + +/*** BEGIN value-tail ***/ +			{ 0, NULL, NULL } +		}; + +		GType g_@type@_type_id = g_@type@_register_static( +				g_intern_static_string("@EnumName@"), values); + +		g_once_init_leave (&static_g_@type@_type_id, g_@type@_type_id); +	} + +	return static_g_@type@_type_id; +} + +/*** END value-tail ***/ diff --git a/src/gtkext/bindings/generated-enums.h.template b/src/gtkext/bindings/generated-enums.h.template new file mode 100644 index 0000000..58c772d --- /dev/null +++ b/src/gtkext/bindings/generated-enums.h.template @@ -0,0 +1,23 @@ +// SPDX-License-Identifier: LGPL-2.1-or-later +// SPDX-FileCopyrightText: 2023-2024 Bartosz Golaszewski <bartosz.golaszewski@linaro.org> + +/*** BEGIN file-header ***/ + +G_BEGIN_DECLS + +/*** END file-header ***/ + +/*** BEGIN file-production ***/ + +/*** END file-production ***/ + +/*** BEGIN value-header ***/ +GType @enum_name@_get_type(void) G_GNUC_CONST; +#define @ENUMPREFIX@_@ENUMSHORT@_TYPE (@enum_name@_get_type()) +/*** END value-header ***/ + +/*** BEGIN file-tail ***/ + +G_END_DECLS + +/*** END file-tail ***/ diff --git a/src/gtkext/bufferview.c b/src/gtkext/bufferview.c index 4a700c3..13c2632 100644 --- a/src/gtkext/bufferview.c +++ b/src/gtkext/bufferview.c @@ -33,10 +33,10 @@  /* ------------------------- BASES D'UN COMPOSANT GRAPHIQUE ------------------------- */ -/* Procède à l'initialisation de l'afficheur de tampons. */ +/* Initialise la classe des afficheurs de tampons. */  static void gtk_buffer_view_class_init(GtkBufferViewClass *); -/* Procède à l'initialisation de l'afficheur de tampons. */ +/* Initialise une instance d'afficheur de tampons. */  static void gtk_buffer_view_init(GtkBufferView *);  /* Supprime toutes les références externes. */ @@ -72,7 +72,7 @@ G_DEFINE_TYPE(GtkBufferView, gtk_buffer_view, GTK_TYPE_CONTENT_VIEW);  *                                                                             *  *  Paramètres  : class = classe GTK à initialiser.                            *  *                                                                             * -*  Description : Procède à l'initialisation de l'afficheur de tampons.        * +*  Description : Initialise la classe des afficheurs de tampons.              *  *                                                                             *  *  Retour      : -                                                            *  *                                                                             * @@ -146,9 +146,9 @@ static void gtk_buffer_view_class_init(GtkBufferViewClass *class)  /******************************************************************************  *                                                                             * -*  Paramètres  : display = composant GTK à initialiser.                       * +*  Paramètres  : view = composant GTK à initialiser.                          *  *                                                                             * -*  Description : Procède à l'initialisation de l'afficheur de tampons.        * +*  Description : Initialise une instance d'afficheur de tampons.              *  *                                                                             *  *  Retour      : -                                                            *  *                                                                             * @@ -168,7 +168,7 @@ static void gtk_buffer_view_init(GtkBufferView *view)  /******************************************************************************  *                                                                             * -*  Paramètres  : display = instance d'objet GLib à traiter.                   * +*  Paramètres  : view = instance d'objet GLib à traiter.                      *  *                                                                             *  *  Description : Supprime toutes les références externes.                     *  *                                                                             * @@ -208,7 +208,7 @@ static void gtk_buffer_view_dispose(GtkBufferView *view)  /******************************************************************************  *                                                                             * -*  Paramètres  : display = instance d'objet Gtk à traiter.                    * +*  Paramètres  : view = instance d'objet Gtk à traiter.                       *  *                                                                             *  *  Description : Procède à la libération totale de la mémoire.                *  *                                                                             * @@ -279,9 +279,9 @@ GBufferView *gtk_buffer_view_get_view(const GtkBufferView *view)  /******************************************************************************  *                                                                             * -*  Paramètres  : widget = composant GTK à examiner.                           * -*                width  = largeur affectée au composant graphique.            * -*                height = hauteur affectée au composant graphique.            * +*  Paramètres  : widget   = composant GTK à examiner.                         * +*                width    = largeur affectée au composant graphique.          * +*                height   = hauteur affectée au composant graphique.          *  *                baseline = ligne de base affectée au composant graphique.    *  *                                                                             *  *  Description : Prend acte de la taille allouée au composant d'affichage.    * diff --git a/src/gtkext/dockstation-int.h b/src/gtkext/dockstation-int.h new file mode 100644 index 0000000..17ed828 --- /dev/null +++ b/src/gtkext/dockstation-int.h @@ -0,0 +1,68 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * dockstation.h - prototypes internes pour la manipulation et l'affichage de composants rassemblés + * + * Copyright (C) 2024 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 _GTKEXT_DOCKSTATION_INT_H +#define _GTKEXT_DOCKSTATION_INT_H + + +#include "dockstation.h" + + + +/* Station de réception pour concentration d'éléments (instance) */ +struct _GtkDockStation +{ +    GtkBox parent;                          /* A laisser en premier        */ + +    GtkOrientation orientation;             /* Spécification d'orientation */ + +    GtkWidget *tabs;                        /* Bascule entre panneaux      */ +    GtkWidget *toolbar;                     /* Boutons d'action            */ +    GtkWidget *sep1;                        /* Séparateur #1               */ +    GtkStack *stack;                        /* Pile de panneaux affichés   */ +    GtkWidget *sep2;                        /* Séparateur #2               */ + +    GtkTiledPanel *def_panel;               /* Eventuel panneau à maintenir*/ + +}; + +/* Station de réception pour concentration d'éléments (classe) */ +struct _GtkDockStationClass +{ +    GtkBoxClass parent;                     /* A laisser en premier        */ + +    /* Signaux */ + +    void (* panel_docked) (GtkDockStation *, GtkTiledPanel *); +    void (* panel_undocked) (GtkDockStation *, GtkTiledPanel *); + +    void (* switch_widget) (GtkDockStation *, GtkWidget *); + +    void (* menu_requested) (GtkDockStation *, GtkWidget *); +    void (* close_requested) (GtkDockStation *, GtkWidget *); + +}; + + + +#endif  /* _GTKEXT_DOCKSTATION_INT_H */ diff --git a/src/gtkext/dockstation.c b/src/gtkext/dockstation.c new file mode 100644 index 0000000..80bae75 --- /dev/null +++ b/src/gtkext/dockstation.c @@ -0,0 +1,1052 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * dockstation.c - manipulation et l'affichage de composants rassemblés + * + * Copyright (C) 2012-2024 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 "dockstation.h" + + +#include "dockstation-int.h" + + + +/* --------------------------- INTERFACE DU COMPOSANT GTK --------------------------- */ + + +/* Liste des propriétés */ + +typedef enum _DockStationProperty { + +    PROP_0,                                 /* Réservé                     */ + +    /* Interface GtkOrientable */ +    PROP_ORIENTATION, + +    N_PROPERTIES = PROP_ORIENTATION + +} DockStationProperty; + +//static GParamSpec *_dock_station_properties[N_PROPERTIES] = { NULL, }; + + +/* Procède à l'initialisation de l'afficheur concentré. */ +static void gtk_dock_station_class_init(GtkDockStationClass *); + +/* Procède à l'initialisation du support d'affichage concentré. */ +static void gtk_dock_station_init(GtkDockStation *); + +/* Supprime toutes les références externes. */ +static void gtk_dock_station_dispose(GObject *); + +/* Procède à la libération totale de la mémoire. */ +static void gtk_dock_station_finalize(GObject *); + + + +/* --------------------- IMPLEMENTATION DES FONCTIONS DE CLASSE --------------------- */ + + +/* Met à jour une propriété d'instance GObject. */ +static void gtk_dock_station_set_property(GObject *, guint, const GValue *, GParamSpec *); + +/* Fournit la valeur d'une propriété d'instance GObject. */ +static void gtk_dock_station_get_property(GObject *, guint, GValue *, GParamSpec *); + + + +/* ---------------------------------------------------------------------------------- */ +/*                             INTERFACE DU COMPOSANT GTK                             */ +/* ---------------------------------------------------------------------------------- */ + + +/* Détermine le type du composant d'affichage concentré. */ +G_DEFINE_TYPE(GtkDockStation, gtk_dock_station, GTK_TYPE_GRID) + + +/****************************************************************************** +*                                                                             * +*  Paramètres  : class = classe GTK à initialiser.                            * +*                                                                             * +*  Description : Procède à l'initialisation de l'afficheur concentré.         * +*                                                                             * +*  Retour      : -                                                            * +*                                                                             * +*  Remarques   : -                                                            * +*                                                                             * +******************************************************************************/ + +static void gtk_dock_station_class_init(GtkDockStationClass *class) +{ +    GObjectClass *object;                   /* Autre version de la classe  */ +    GtkWidgetClass *widget;                 /* Classe de haut niveau       */ + +    object = G_OBJECT_CLASS(class); + +    object->dispose = gtk_dock_station_dispose; +    object->finalize = gtk_dock_station_finalize; +    object->set_property = gtk_dock_station_set_property; +    object->get_property = gtk_dock_station_get_property; + +    //g_object_class_install_properties(object, N_PROPERTIES, _dock_station_properties); +    g_object_class_override_property(object, PROP_ORIENTATION, "orientation"); + +    widget = GTK_WIDGET_CLASS(class); + +    gtk_widget_class_set_template_from_resource(widget, "/re/chrysalide/framework/gtkext/dockstation.ui"); + +    //gtk_widget_class_bind_template_callback_full(widget, BUILDER_CB(gtk_status_stack_on_zoom_icon_press)); + +    gtk_widget_class_bind_template_child(widget, GtkDockStation, tabs); +    gtk_widget_class_bind_template_child(widget, GtkDockStation, toolbar); +    gtk_widget_class_bind_template_child(widget, GtkDockStation, sep1); +    gtk_widget_class_bind_template_child(widget, GtkDockStation, stack); +    gtk_widget_class_bind_template_child(widget, GtkDockStation, sep2); + +    g_signal_new("panel-docked", +                 GTK_TYPE_DOCK_STATION, +                 G_SIGNAL_RUN_LAST, +                 G_STRUCT_OFFSET(GtkDockStationClass, panel_docked), +                 NULL, NULL, +                 g_cclosure_marshal_VOID__OBJECT, +                 G_TYPE_NONE, 1, GTK_TYPE_WIDGET); + +    g_signal_new("panel-undocked", +                 GTK_TYPE_DOCK_STATION, +                 G_SIGNAL_RUN_LAST, +                 G_STRUCT_OFFSET(GtkDockStationClass, panel_undocked), +                 NULL, NULL, +                 g_cclosure_marshal_VOID__OBJECT, +                 G_TYPE_NONE, 1, GTK_TYPE_WIDGET); + +    /* +    g_signal_new("switch-widget", +                 GTK_TYPE_DOCK_STATION, +                 G_SIGNAL_RUN_LAST, +                 G_STRUCT_OFFSET(GtkDockStationClass, switch_widget), +                 NULL, NULL, +                 g_cclosure_marshal_VOID__OBJECT, +                 G_TYPE_NONE, 1, GTK_TYPE_WIDGET); + +    g_signal_new("menu-requested", +                 GTK_TYPE_DOCK_STATION, +                 G_SIGNAL_RUN_LAST, +                 G_STRUCT_OFFSET(GtkDockStationClass, menu_requested), +                 NULL, NULL, +                 g_cclosure_marshal_VOID__OBJECT, +                 G_TYPE_NONE, 1, GTK_TYPE_WIDGET); + +    g_signal_new("close-requested", +                 GTK_TYPE_DOCK_STATION, +                 G_SIGNAL_RUN_LAST, +                 G_STRUCT_OFFSET(GtkDockStationClass, close_requested), +                 NULL, NULL, +                 g_cclosure_marshal_VOID__OBJECT, +                 G_TYPE_NONE, 1, GTK_TYPE_WIDGET); +    */ + +} + + +/****************************************************************************** +*                                                                             * +*  Paramètres  : station = composant GTK à initialiser.                       * +*                                                                             * +*  Description : Procède à l'initialisation du support d'affichage concentré. * +*                                                                             * +*  Retour      : -                                                            * +*                                                                             * +*  Remarques   : -                                                            * +*                                                                             * +******************************************************************************/ + +static void gtk_dock_station_init(GtkDockStation *station) +{ +    gtk_widget_init_template(GTK_WIDGET(station)); + +    station->orientation = GTK_ORIENTATION_HORIZONTAL; + +    station->def_panel = NULL; + +} + + +/****************************************************************************** +*                                                                             * +*  Paramètres  : object = instance d'objet GLib à traiter.                    * +*                                                                             * +*  Description : Supprime toutes les références externes.                     * +*                                                                             * +*  Retour      : -                                                            * +*                                                                             * +*  Remarques   : -                                                            * +*                                                                             * +******************************************************************************/ + +static void gtk_dock_station_dispose(GObject *object) +{ +    GtkDockStation *station;                /* Version spécialisée         */ + +    station = GTK_DOCK_STATION(object); + +    gtk_widget_dispose_template(GTK_WIDGET(object), GTK_TYPE_DOCK_STATION); + +    g_clear_object(&station->def_panel); + +    G_OBJECT_CLASS(gtk_dock_station_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 gtk_dock_station_finalize(GObject *object) +{ +    G_OBJECT_CLASS(gtk_dock_station_parent_class)->finalize(object); + +} + + +/****************************************************************************** +*                                                                             * +*  Paramètres  : -                                                            * +*                                                                             * +*  Description : Crée un nouveau composant pour support d'affichage concentré.* +*                                                                             * +*  Retour      : -                                                            * +*                                                                             * +*  Remarques   : -                                                            * +*                                                                             * +******************************************************************************/ + +GtkWidget *gtk_dock_station_new(void) +{ +    GtkWidget *result;                      /* Instance à retourner        */ + +    result = g_object_new(GTK_TYPE_DOCK_STATION, NULL); + +    return result; + +} + + +/****************************************************************************** +*                                                                             * +*  Paramètres  : station = station d'accueil pour panneaux à compléter.       * +*                panel   = nouveau panneau à afficher.                        * +*                                                                             * +*  Description : Ajoute un panneau à un groupe de tuiles.                     * +*                                                                             * +*  Retour      : -                                                            * +*                                                                             * +*  Remarques   : -                                                            * +*                                                                             * +******************************************************************************/ + +void gtk_dock_station_add_panel(GtkDockStation *station, GtkTiledPanel *panel) +{ +    GtkStackPage *page;                     /* Nouvelle page insérée       */ + +    page = gtk_stack_add_child(station->stack, GTK_WIDGET(panel)); + +    if (0)  // TODO +        gtk_stack_page_set_title(page, "settings"); + +    else +        gtk_stack_page_set_icon_name(page, "logs-symbolic"); + +    gtk_stack_set_visible_child(station->stack, GTK_WIDGET(panel)); + + +    g_signal_emit_by_name(station, "panel-docked", panel); + + +} + + +/****************************************************************************** +*                                                                             * +*  Paramètres  : station = station d'accueil pour panneaux à compléter.       * +*                panel   = nouveau panneau à afficher.                        * +*                                                                             * +*  Description : Ajoute un panneau à conserver à un groupe de tuiles.         * +*                                                                             * +*  Retour      : -                                                            * +*                                                                             * +*  Remarques   : -                                                            * +*                                                                             * +******************************************************************************/ + +void gtk_dock_station_keep_panel(GtkDockStation *station, GtkTiledPanel *panel) +{ +    bool visible;                           /* Visibilité des barres       */ + +    g_clear_object(&station->def_panel); + +    if (panel != NULL) +    { +        station->def_panel = panel; +        ref_object(panel); + +        if (gtk_stack_get_page(station->stack, GTK_WIDGET(panel)) == NULL) +            gtk_dock_station_add_panel(station, panel); + +    } + +    visible = (station->def_panel == NULL); + +    gtk_widget_set_visible(station->tabs, visible); +    gtk_widget_set_visible(station->toolbar, visible); +    gtk_widget_set_visible(station->sep1, visible); +    gtk_widget_set_visible(station->sep2, visible && station->orientation == GTK_ORIENTATION_HORIZONTAL); + +} + + +/****************************************************************************** +*                                                                             * +*  Paramètres  : station = station d'accueil pour panneaux à consulter.       * +*                                                                             * +*  Description : Indique si la station d'accueil contient au moins un panneau.* +*                                                                             * +*  Retour      : true si aucun panneau n'est intégré, false sinon.            * +*                                                                             * +*  Remarques   : -                                                            * +*                                                                             * +******************************************************************************/ + +bool gtk_dock_station_is_empty(const GtkDockStation *station) +{ +    bool result;                            /* Bilan à retourner           */ +    GtkSelectionModel *model;               /* Modèle pour la pile         */ +    guint count;                            /* Nombre de panneaux présents */ + +    model = gtk_stack_get_pages(station->stack); + +    count = g_list_model_get_n_items(G_LIST_MODEL(model)); + +    result = (count == 0); + +    unref_object(model); + +    return result; + +} + + +/****************************************************************************** +*                                                                             * +*  Paramètres  : station = station d'accueil pour panneaux à manipuler.       * +*                main      = panneau principal visé par l'opération.          * +*                activated = nature du changement de statut : ajout, retrait ?* +*                                                                             * +*  Description : Note un ajout ou un retrait de panneau principal.            * +*                                                                             * +*  Retour      : -                                                            * +*                                                                             * +*  Remarques   : -                                                            * +*                                                                             * +******************************************************************************/ + +void gtk_dock_station_notify_new_main_panel_state(const GtkDockStation *station, GtkTiledPanel *main, bool activated) +{ +    GListModel *list;                       /* Liste de pages à parcourir  */ +    guint count;                            /* Nombre de pages             */ +    guint i;                                /* Boucle de parcours          */ +    GtkStackPage *page;                     /* Page à consulter            */ +    GtkWidget *panel;                       /* Panneau intégré             */ + +    list = G_LIST_MODEL(gtk_stack_get_pages(station->stack)); + +    count = g_list_model_get_n_items(list); + +    for (i = 0; i < count; i++) +    { +        page = GTK_STACK_PAGE(g_list_model_get_object(list, i)); +        if (page == NULL) continue; + +        panel = gtk_stack_page_get_child(page); + +        gtk_tiled_panel_notify_new_main_panel_state(GTK_TILED_PANEL(panel), main, activated); + +        unref_object(page); + +    } + +    unref_object(list); + +} + + + +/* ---------------------------------------------------------------------------------- */ +/*                       IMPLEMENTATION DES FONCTIONS DE CLASSE                       */ +/* ---------------------------------------------------------------------------------- */ + + +/****************************************************************************** +*                                                                             * +*  Paramètres  : object  = instance d'objet GLib à mamnipuler.                * +*                prop_id = identifiant de la propriété visée.                 * +*                value   = valeur à prendre en compte.                        * +*                pspec   = définition de la propriété.                        * +*                                                                             * +*  Description : Met à jour une propriété d'instance GObject.                 * +*                                                                             * +*  Retour      : -                                                            * +*                                                                             * +*  Remarques   : -                                                            * +*                                                                             * +******************************************************************************/ + +static void gtk_dock_station_set_property(GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) +{ +    GtkDockStation *station;                /* Version spécialisée         */ +    GtkOrientation orientation;             /* Spécification d'orientation */ +    GtkLayoutManager *layout;               /* Gestionnaire de disposition */ +    GtkLayoutChild *child_layout;           /* Disposition de composant    */ + +    station = GTK_DOCK_STATION(object); + +    switch (prop_id) +    { +        case PROP_ORIENTATION: + +            orientation = g_value_get_enum(value); + +            if (station->orientation != orientation) +            { +                station->orientation = orientation; + +                gtk_orientable_set_orientation(GTK_ORIENTABLE(station->tabs), orientation); +                gtk_orientable_set_orientation(GTK_ORIENTABLE(station->toolbar), orientation); + +                layout = gtk_widget_get_layout_manager(GTK_WIDGET(object)); + +                if (orientation == GTK_ORIENTATION_VERTICAL) +                { +                    g_object_set(G_OBJECT(station->tabs), +                                 "halign", GTK_ALIGN_START, +                                 "valign", GTK_ALIGN_CENTER, +                                 NULL); + +                    g_object_set(G_OBJECT(station->toolbar), +                                 "halign", GTK_ALIGN_END, +                                 "valign", GTK_ALIGN_CENTER, +                                 NULL); + +                    child_layout = gtk_layout_manager_get_layout_child(layout, station->toolbar); + +                    g_object_set(G_OBJECT(child_layout), +                                 "column", 1, +                                 "row", 0, +                                 NULL); + +                    child_layout = gtk_layout_manager_get_layout_child(layout, station->sep1); + +                    g_object_set(G_OBJECT(child_layout), +                                 "column", 0, +                                 "row", 1, +                                 "column-span", 2, +                                 NULL); + +                    gtk_widget_set_visible(station->sep2, FALSE); + +                    child_layout = gtk_layout_manager_get_layout_child(layout, GTK_WIDGET(station->stack)); + +                    g_object_set(G_OBJECT(child_layout), +                                 "column", 0, +                                 "row", 2, +                                 "column-span", 2, +                                 NULL); + +                } +                else +                { +                    g_object_set(G_OBJECT(station->tabs), +                                 "halign", GTK_ALIGN_START, +                                 "valign", GTK_ALIGN_START, +                                 NULL); + +                    g_object_set(G_OBJECT(station->toolbar), +                                 "halign", GTK_ALIGN_END, +                                 "valign", GTK_ALIGN_START, +                                 NULL); + +                    child_layout = gtk_layout_manager_get_layout_child(layout, station->sep1); + +                    g_object_set(G_OBJECT(child_layout), +                                 "column", 1, +                                 "row", 0, +                                 "column-span", 1, +                                 NULL); + +                    child_layout = gtk_layout_manager_get_layout_child(layout, GTK_WIDGET(station->stack)); + +                    g_object_set(G_OBJECT(child_layout), +                                 "column", 2, +                                 "row", 0, +                                 "column-span", 1, +                                 NULL); + +                    gtk_widget_set_visible(station->sep2, TRUE); + +                    child_layout = gtk_layout_manager_get_layout_child(layout, station->sep2); + +                    g_object_set(G_OBJECT(child_layout), +                                 "column", 3, +                                 "row", 0, +                                 NULL); + +                    child_layout = gtk_layout_manager_get_layout_child(layout, station->toolbar); + +                    g_object_set(G_OBJECT(child_layout), +                                 "column", 4, +                                 "row", 0, +                                 NULL); + +                } + +                g_object_notify_by_pspec(object, pspec); + +            } + +            break; + +        default: +            G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec); +            break; + +    } + +} + + +/****************************************************************************** +*                                                                             * +*  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_dock_station_get_property(GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) +{ +    GtkDockStation *station;                /* Version spécialisée         */ + +    station = GTK_DOCK_STATION(object); + +    switch (prop_id) +    { +        case PROP_ORIENTATION: +            g_value_set_enum(value, station->orientation); +            break; + +        default: +            G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec); +            break; + +    } + +} + + + + + + + + + + + + + + + + + + + + +#if 0 + +#include <malloc.h> +#include <string.h> + + +#include "easygtk.h" +#include "../core/params.h" +#include "../common/extstr.h" +#include "../glibext/chrysamarshal.h" + + + +/* Procède à l'initialisation de l'afficheur concentré. */ +static void gtk_dock_station_class_init(GtkDockStationClass *); + +/* Procède à l'initialisation du support d'affichage concentré. */ +static void gtk_dock_station_init(GtkDockStation *); + +/* Met à jour le titre du support de panneaux concentrés. */ +static gboolean gtk_dock_station_switch_panel(GtkNotebook *, gpointer *, guint, GtkDockStation *); + + + + +/* Révèle ou cache la zone de recherches. */ +static void on_toggle_revealer(GtkToggleButton *, GtkDockStation *); + +/* Demande l'apparition d'un menu pour inclure des composants. */ +static void on_click_for_menu(GtkButton *, GtkDockStation *); + +/* Demande la disparition du composant courant. */ +static void on_click_for_close(GtkButton *, GtkDockStation *); + + + + + + +/* Détermine le type du composant d'affichage concentré. */ +G_DEFINE_TYPE(GtkDockStation, gtk_dock_station, GTK_TYPE_NOTEBOOK) + + +/****************************************************************************** +*                                                                             * +*  Paramètres  : class = classe GTK à initialiser.                            * +*                                                                             * +*  Description : Procède à l'initialisation de l'afficheur concentré.         * +*                                                                             * +*  Retour      : -                                                            * +*                                                                             * +*  Remarques   : -                                                            * +*                                                                             * +******************************************************************************/ + +static void gtk_dock_station_class_init(GtkDockStationClass *class) +{ +    g_signal_new("dock-widget", +                 GTK_TYPE_DOCK_STATION, +                 G_SIGNAL_RUN_LAST, +                 G_STRUCT_OFFSET(GtkDockStationClass, dock_widget), +                 NULL, NULL, +                 g_cclosure_marshal_VOID__OBJECT, +                 G_TYPE_NONE, 1, GTK_TYPE_WIDGET); + +    g_signal_new("undock-widget", +                 GTK_TYPE_DOCK_STATION, +                 G_SIGNAL_RUN_LAST, +                 G_STRUCT_OFFSET(GtkDockStationClass, undock_widget), +                 NULL, NULL, +                 g_cclosure_marshal_VOID__OBJECT, +                 G_TYPE_NONE, 1, GTK_TYPE_WIDGET); + +    g_signal_new("switch-widget", +                 GTK_TYPE_DOCK_STATION, +                 G_SIGNAL_RUN_LAST, +                 G_STRUCT_OFFSET(GtkDockStationClass, switch_widget), +                 NULL, NULL, +                 g_cclosure_marshal_VOID__OBJECT, +                 G_TYPE_NONE, 1, GTK_TYPE_WIDGET); + +    g_signal_new("menu-requested", +                 GTK_TYPE_DOCK_STATION, +                 G_SIGNAL_RUN_LAST, +                 G_STRUCT_OFFSET(GtkDockStationClass, menu_requested), +                 NULL, NULL, +                 g_cclosure_marshal_VOID__OBJECT, +                 G_TYPE_NONE, 1, GTK_TYPE_WIDGET); + +    g_signal_new("close-requested", +                 GTK_TYPE_DOCK_STATION, +                 G_SIGNAL_RUN_LAST, +                 G_STRUCT_OFFSET(GtkDockStationClass, close_requested), +                 NULL, NULL, +                 g_cclosure_marshal_VOID__OBJECT, +                 G_TYPE_NONE, 1, GTK_TYPE_WIDGET); + +} + + +/****************************************************************************** +*                                                                             * +*  Paramètres  : station = composant GTK à initialiser.                       * +*                                                                             * +*  Description : Procède à l'initialisation du support d'affichage concentré. * +*                                                                             * +*  Retour      : -                                                            * +*                                                                             * +*  Remarques   : -                                                            * +*                                                                             * +******************************************************************************/ + +static void gtk_dock_station_init(GtkDockStation *station) +{ +    GtkNotebook *notebook;                  /* Autre version du composant  */ +    GtkWidget *hbox;                        /* Division supérieure         */ +    GtkWidget *button;                      /* Bouton de contrôle          */ + +    notebook = GTK_NOTEBOOK(station); + +    gtk_notebook_set_show_border(notebook, FALSE); +    gtk_notebook_set_scrollable(notebook, TRUE); + +    /* Définition de la zone de contrôle */ + +    hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0); +    gtk_widget_set_valign(hbox, GTK_ALIGN_CENTER); +    gtk_widget_set_margin_end(hbox, 8); +    gtk_widget_show(hbox); + +    button = qck_create_toggle_button_with_named_img(G_OBJECT(station), "search", +                                                     "edit-find-symbolic", GTK_ICON_SIZE_MENU, NULL, +                                                     G_CALLBACK(on_toggle_revealer), station); +    gtk_button_set_relief(GTK_BUTTON(button), GTK_RELIEF_NONE); +    gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, FALSE, 0); + +    button = qck_create_button_with_named_img(G_OBJECT(station), "menu", +                                              "go-down-symbolic", GTK_ICON_SIZE_MENU, NULL, +                                              G_CALLBACK(on_click_for_menu), station); +    gtk_button_set_relief(GTK_BUTTON(button), GTK_RELIEF_NONE); +    gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, FALSE, 0); + +    button = qck_create_button_with_named_img(G_OBJECT(station), "close", +                                              "window-close-symbolic", GTK_ICON_SIZE_MENU, NULL, +                                              G_CALLBACK(on_click_for_close), station); +    gtk_button_set_relief(GTK_BUTTON(button), GTK_RELIEF_NONE); +    gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, FALSE, 0); + +    gtk_notebook_set_action_widget(notebook, hbox, GTK_PACK_END); + +    g_signal_connect(notebook, "switch-page", +                     G_CALLBACK(gtk_dock_station_switch_panel), station); + +} + + +/****************************************************************************** +*                                                                             * +*  Paramètres  : -                                                            * +*                                                                             * +*  Description : Crée un nouveau composant pour support d'affichage concentré.* +*                                                                             * +*  Retour      : -                                                            * +*                                                                             * +*  Remarques   : -                                                            * +*                                                                             * +******************************************************************************/ + +GtkWidget *gtk_dock_station_new(void) +{ +    return g_object_new(GTK_TYPE_DOCK_STATION, NULL); + +} + + +/****************************************************************************** +*                                                                             * +*  Paramètres  : notebook = support à l'origine de la mise à jour.            * +*                page     = onglet mis en avant.                              * +*                index    = indice de l'onglet actuellement actif.            * +*                station  = conteneur de gestion supérieur.                   * +*                                                                             * +*  Description : Met à jour le titre du support de panneaux concentrés.       * +*                                                                             * +*  Retour      : TRUE ?                                                       * +*                                                                             * +*  Remarques   : -                                                            * +*                                                                             * +******************************************************************************/ + +static gboolean gtk_dock_station_switch_panel(GtkNotebook *notebook, gpointer *page, guint index, GtkDockStation *station) +{ +    GtkWidget *widget;                      /* Panneau concerné            */ +    GtkDockable *dockable;                  /* Elément encapsulé           */ +    GtkWidget *button;                      /* Bouton de contrôle          */ + +    widget = gtk_notebook_get_nth_page(notebook, index); + +    dockable = GTK_DOCKABLE(g_object_get_data(G_OBJECT(widget), "dockable")); + +    /* Mise à jour des boutons utilisables */ + +    button = GTK_WIDGET(g_object_get_data(G_OBJECT(station), "search")); + +    if (gtk_dockable_can_search(dockable)) +        gtk_widget_show(button); +    else +        gtk_widget_hide(button); + +    /* Remontée du changement d'onglet */ + +    g_signal_emit_by_name(station, "switch-widget", widget); + +    return TRUE; + +} + + +/****************************************************************************** +*                                                                             * +*  Paramètres  : station  = plateforme GTK à compléter.                       * +*                dockable = nouvel élément à intégrer.                        * +*                                                                             * +*  Description : Ajoute un paquet d'informations à l'affichage centralisé.    * +*                                                                             * +*  Retour      : -                                                            * +*                                                                             * +*  Remarques   : -                                                            * +*                                                                             * +******************************************************************************/ +#include "gtkdisplaypanel.h" +#include "../gui/panels/history.h" +void gtk_dock_station_add_dockable(GtkDockStation *station, GtkDockable *dockable) +{ +    GtkWidget *widget;                      /* Composant GTK à intégrer    */ +    char *name;                             /* Nom à donner à l'onglet     */ +    char *desc;                             /* Description à y associer    */ +    int max;                                /* Taille maximale des titres  */ +    GtkWidget *label;                       /* Etiquette d'onglet          */ +    GtkNotebook *notebook;                  /* Autre version du composant  */ + + + + + + + +    /* Récupération des éléments utiles */ + +    widget = gtk_dockable_build_widget(dockable); + +    //widget = gtk_button_new_with_label("123"); +    gtk_widget_show(widget); + + +    g_object_set_data(G_OBJECT(widget), "dockable", dockable); + +    name = gtk_dockable_get_name(dockable); +    desc = gtk_dockable_get_desc(dockable); + +    /* Mise en place de la page */ + +    if (!g_generic_config_get_value(get_main_configuration(), MPK_ELLIPSIS_TAB, &max)) +        max = -1; + +    name = ellipsis(name, max); +    label = qck_create_label(NULL, NULL, name); +    free(name); + +    notebook = GTK_NOTEBOOK(station); + +    if (gtk_notebook_get_n_pages(notebook) > 0) +    g_signal_handlers_disconnect_by_func(notebook, +                                         G_CALLBACK(gtk_dock_station_switch_panel), station); + +    gtk_notebook_append_page(notebook, widget, label); + +    gtk_widget_set_tooltip_text(label, desc); + +    free(desc); + +    if (gtk_notebook_get_n_pages(notebook) > 1) +    g_signal_connect(notebook, "switch-page", +                     G_CALLBACK(gtk_dock_station_switch_panel), station); + +    /* Lancement des mises à jour */ + +    if (gtk_notebook_get_n_pages(notebook) > 1) +        gtk_notebook_set_current_page(notebook, -1); + +    //g_signal_emit_by_name(station, "dock-widget", widget); + +} + + +/****************************************************************************** +*                                                                             * +*  Paramètres  : station = plateforme GTK à compléter.                        * +*                widget  = nouvel élément à intégrer.                         * +*                                                                             * +*  Description : Change le contenu de l'onglet courant uniquement.            * +*                                                                             * +*  Retour      : -                                                            * +*                                                                             * +*  Remarques   : -                                                            * +*                                                                             * +******************************************************************************/ + +void gtk_dock_panel_change_active_widget(GtkDockStation *station, GtkWidget *widget) +{ +    GtkNotebook *notebook;                  /* Autre version du composant  */ +    gint index;                             /* Indice de l'onglet actif    */ +    GtkWidget *old;                         /* Ancien composant            */ +    GtkWidget *label;                       /* Etiquette d'onglet          */ +    char *str;                              /* Titre des prochaines fois   */ + +    notebook = GTK_NOTEBOOK(station); + +    index = gtk_notebook_get_current_page(notebook); + +    g_signal_handlers_disconnect_by_func(notebook, +                                         G_CALLBACK(gtk_dock_station_switch_panel), station); + +    old = gtk_notebook_get_nth_page(notebook, index); +    label = gtk_notebook_get_tab_label(notebook, old); + +    g_object_ref(G_OBJECT(label)); +    str = g_object_get_data(G_OBJECT(old), "title"); + +    gtk_notebook_remove_page(notebook, index); +    gtk_notebook_insert_page(notebook, widget, label, index); + +    g_object_unref(G_OBJECT(label)); +    g_object_set_data(G_OBJECT(widget), "title", str); + +    gtk_notebook_set_current_page(notebook, index); + +    g_signal_connect(notebook, "switch-page", +                     G_CALLBACK(gtk_dock_station_switch_panel), station); + +} + + +/****************************************************************************** +*                                                                             * +*  Paramètres  : station = plateforme GTK à compléter.                        * +*                dockable = élément existant à retirer.                       * +*                                                                             * +*  Description : Retire un paquet d'informations de l'affichage centralisé.   * +*                                                                             * +*  Retour      : -                                                            * +*                                                                             * +*  Remarques   : -                                                            * +*                                                                             * +******************************************************************************/ + +void gtk_dock_station_remove_dockable(GtkDockStation *station, GtkDockable *dockable) +{ +    GtkNotebook *notebook;                  /* Autre version du composant  */ +    GtkWidget *widget;                      /* Composant GTK à retirer     */ +    gint index;                             /* Indice de l'onglet visé     */ + +    notebook = GTK_NOTEBOOK(station); + +    widget = gtk_dockable_decompose(dockable, NULL); + +    index = gtk_notebook_page_num(notebook, widget); + +    gtk_notebook_remove_page(notebook, index); + +} + + +/****************************************************************************** +*                                                                             * +*  Paramètres  : button  = bouton à l'origine de la procédure.                * +*                station = station d'accueil pour différents composants.      * +*                                                                             * +*  Description : Révèle ou cache la zone de recherches.                       * +*                                                                             * +*  Retour      : -                                                            * +*                                                                             * +*  Remarques   : -                                                            * +*                                                                             * +******************************************************************************/ + +static void on_toggle_revealer(GtkToggleButton *button, GtkDockStation *station) +{ +    GtkNotebook *notebook;                  /* Autre version du composant  */ +    gint index;                             /* Indice de l'onglet courant  */ +    GtkWidget *widget;                      /* Panneau concerné            */ +    GtkDockable *dockable;                  /* Elément encapsulé           */ + +    notebook = GTK_NOTEBOOK(station); + +    index = gtk_notebook_get_current_page(notebook); +    widget = gtk_notebook_get_nth_page(notebook, index); + +    dockable = GTK_DOCKABLE(g_object_get_data(G_OBJECT(widget), "dockable")); + +    gtk_dockable_toggle_revealer(dockable, widget, gtk_toggle_button_get_active(button)); + +} + + +/****************************************************************************** +*                                                                             * +*  Paramètres  : button  = bouton à l'origine de la procédure.                * +*                station = station d'accueil pour différents composants.      * +*                                                                             * +*  Description : Demande l'apparition d'un menu pour inclure des composants.  * +*                                                                             * +*  Retour      : -                                                            * +*                                                                             * +*  Remarques   : -                                                            * +*                                                                             * +******************************************************************************/ + +static void on_click_for_menu(GtkButton *button, GtkDockStation *station) +{ +    g_signal_emit_by_name(station, "menu-requested", button); + +} + + +/****************************************************************************** +*                                                                             * +*  Paramètres  : button  = bouton à l'origine de la procédure.                * +*                station = station d'accueil pour différents composants.      * +*                                                                             * +*  Description : Demande la disparition du composant courant.                 * +*                                                                             * +*  Retour      : -                                                            * +*                                                                             * +*  Remarques   : -                                                            * +*                                                                             * +******************************************************************************/ + +static void on_click_for_close(GtkButton *button, GtkDockStation *station) +{ +    g_signal_emit_by_name(station, "close-requested", button); + +} + + +#endif + diff --git a/src/gtkext/gtkdockstation.h b/src/gtkext/dockstation.h index f286c1c..e4c849f 100644 --- a/src/gtkext/gtkdockstation.h +++ b/src/gtkext/dockstation.h @@ -1,8 +1,8 @@  /* Chrysalide - Outil d'analyse de fichiers binaires - * gtkdockstation.h - prototypes pour la manipulation et l'affichage de composants rassemblés + * dockstation.h - prototypes pour la manipulation et l'affichage de composants rassemblés   * - * Copyright (C) 2012-2018 Cyrille Bagard + * Copyright (C) 2012-2024 Cyrille Bagard   *   *  This file is part of Chrysalide.   * @@ -21,13 +21,46 @@   */ -#ifndef _GTKEXT_GTKDOCKSTATION_H -#define _GTKEXT_GTKDOCKSTATION_H +#ifndef _GTKEXT_DOCKSTATION_H +#define _GTKEXT_DOCKSTATION_H  #include <gtk/gtk.h> +#include "panel.h" +#include "../glibext/helpers.h" + + + +#define GTK_TYPE_DOCK_STATION (gtk_dock_station_get_type()) + +DECLARE_GTYPE(GtkDockStation, gtk_dock_station, GTK, DOCK_STATION); + + +/* Crée un nouveau composant pour support d'affichage concentré. */ +GtkWidget *gtk_dock_station_new(void); + +/* Ajoute un panneau à un groupe de tuiles. */ +void gtk_dock_station_add_panel(GtkDockStation *, GtkTiledPanel *); + +/* Ajoute un panneau à conserver à un groupe de tuiles. */ +void gtk_dock_station_keep_panel(GtkDockStation *, GtkTiledPanel *); + +/* Indique si la station d'accueil contient au moins un panneau. */ +bool gtk_dock_station_is_empty(const GtkDockStation *); + +/* Note un ajout ou un retrait de panneau principal. */ +void gtk_dock_station_notify_new_main_panel_state(const GtkDockStation *, GtkTiledPanel *, bool); + + + + +#if 0 + +#include <gtk/gtk.h> + +  #include "gtkdockable.h" @@ -76,9 +109,6 @@ struct _GtkDockStationClass  /* Détermine le type du composant d'affichage concentré. */  GType gtk_dock_station_get_type(void); -/* Crée un nouveau composant pour support d'affichage concentré. */ -GtkWidget *gtk_dock_station_new(void); -  /* Ajoute un paquet d'informations à l'affichage centralisé. */  void gtk_dock_station_add_dockable(GtkDockStation *, GtkDockable *); @@ -92,6 +122,7 @@ void gtk_dock_station_remove_dockable(GtkDockStation *, GtkDockable *);  //G_END_DECLS +#endif -#endif  /* _GTKEXT_GTKDOCKSTATION_H */ +#endif  /* _GTKEXT_DOCKSTATION_H */ diff --git a/src/gtkext/dockstation.ui b/src/gtkext/dockstation.ui new file mode 100644 index 0000000..4d25134 --- /dev/null +++ b/src/gtkext/dockstation.ui @@ -0,0 +1,80 @@ +<?xml version="1.0" encoding="UTF-8"?> +<interface> +    <template class="GtkDockStation" parent="GtkGrid"> +        <property name="orientation">horizontal</property> + +        <child> +            <object class="GtkStackSwitcher" id="tabs"> +                <property name="orientation">horizontal</property> +                <property name="halign">start</property> +                <property name="valign">start</property> +                <property name="margin-start">2</property> +                <property name="margin-top">2</property> +                <property name="margin-end">2</property> +                <property name="margin-bottom">2</property> +                <property name="stack">stack</property> +                <layout> +                    <property name="column">0</property> +                    <property name="row">0</property> +                </layout> +            </object> +        </child> + +        <child> +            <object class="GtkBox" id="toolbar"> +                <property name="orientation">horizontal</property> +                <property name="halign">end</property> +                <property name="valign">start</property> + +                <child> +                    <object class="GtkButton"> +                        <property name="icon-name">window-close-symbolic</property> +                        <style> +                            <class name="circular"/> +                            <class name="flat"/> +                            <class name="control-button"/> +                        </style> +                    </object> +                </child> + +                <layout> +                    <property name="column">4</property> +                    <property name="row">0</property> +                </layout> +            </object> +        </child> + +        <child> +            <object class="GtkSeparator" id="sep1"> +                <property name="orientation">horizontal</property> +                <layout> +                    <property name="column">1</property> +                    <property name="row">0</property> +                    <property name="column-span">1</property> +                </layout> +            </object> +        </child> + +        <child> +            <object class="GtkStack" id="stack"> +                <property name="hexpand">true</property> +                <layout> +                    <property name="column">2</property> +                    <property name="row">0</property> +                    <property name="column-span">1</property> +                </layout> +            </object> +        </child> + +        <child> +            <object class="GtkSeparator" id="sep2"> +                <property name="orientation">horizontal</property> +                <layout> +                    <property name="column">3</property> +                    <property name="row">0</property> +                </layout> +            </object> +        </child> + +    </template> +</interface> diff --git a/src/gtkext/gresource.xml b/src/gtkext/gresource.xml index 225b2a4..26943a6 100644 --- a/src/gtkext/gresource.xml +++ b/src/gtkext/gresource.xml @@ -1,7 +1,17 @@  <?xml version="1.0" encoding="UTF-8"?>  <gresources>      <gresource prefix="/re/chrysalide/framework/gtkext"> +        <file compressed="true">dockstation.ui</file> +        <file compressed="true">grid.ui</file>          <file compressed="true">hexview.css</file>          <file compressed="true">hexview.ui</file> +        <file compressed="true">launcher.ui</file> +        <file compressed="true">statusstack.ui</file> +        <file compressed="true">tweak.ui</file> +    </gresource> +    <gresource prefix="/re/chrysalide/framework/gui/icons/scalable/actions"> +        <file compressed="true" alias="nolock-symbolic.svg">../../data/images/nolock-symbolic.svg</file> +        <file compressed="true" alias="locked-symbolic.svg">../../data/images/locked-symbolic.svg</file> +        <file compressed="true" alias="unlocked-symbolic.svg">../../data/images/unlocked-symbolic.svg</file>      </gresource>  </gresources> diff --git a/src/gtkext/grid-int.h b/src/gtkext/grid-int.h new file mode 100644 index 0000000..8a2702b --- /dev/null +++ b/src/gtkext/grid-int.h @@ -0,0 +1,81 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * grid-int.h - prototypes interne pour un composant d'affichage avec des chemins vers les composants contenus + * + * Copyright (C) 2024 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 _GTKEXT_GRID_INT_H +#define _GTKEXT_GRID_INT_H + + +#include "dockstation.h" +#include "grid.h" + + + +/* Conteneur pour un affichage en tuiles nommées (instance) */ +struct _GtkTilingGrid +{ +    GtkGrid parent;                         /* A laisser en premier        */ + +    GSettings *settings;                    /* Configuration du conteneur  */ + +    LayoutReachOptions layout;              /* Disposition générale        */ + +    bool visible[TGB_COUNT];                /* Visibilités souhaitées      */ + +    GtkRevealer *top;                       /* Zone d'accueil #1           */ +    GtkWidget *top_handle;                  /* Poignée de redimensionnement*/ +    GtkDockStation *top_station;            /* Station entière             */ + +    GtkRevealer *left;                      /* Zone d'accueil #2           */ +    GtkWidget *left_handle;                 /* Poignée de redimensionnement*/ +    GtkDockStation *left_station;           /* Station entière             */ + +    GtkDockStation *main_station;           /* Zone d'accueil #3           */ + +    GtkRevealer *right;                     /* Zone d'accueil #4           */ +    GtkWidget *right_handle;                /* Poignée de redimensionnement*/ +    GtkDockStation *right_station;          /* Station entière             */ + +    GtkRevealer *bottom;                    /* Zone d'accueil #5           */ +    GtkWidget *bottom_handle;               /* Poignée de redimensionnement*/ +    GtkDockStation *bottom_station;         /* Station entière             */ + +    GtkGesture *tpad_gesture[TGB_COUNT];    /* Gestionnaires du touchpad   */ + +    bool panning;                           /* Redimensionnement en cours  */ + +}; + +/* Conteneur pour un affichage en tuiles nommées (classe) */ +struct _GtkTilingGridClass +{ +    GtkGridClass parent;                    /* A laisser en premier        */ + +    /* Signaux */ + +    void (* station_created) (GtkTilingGrid *, GtkDockStation *, gpointer); + +}; + + + +#endif  /* _GTKEXT_GRID_INT_H */ diff --git a/src/gtkext/grid.c b/src/gtkext/grid.c new file mode 100644 index 0000000..eb3cdf9 --- /dev/null +++ b/src/gtkext/grid.c @@ -0,0 +1,1128 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * grid.c - composant d'affichage avec des chemins vers les composants contenus + * + * Copyright (C) 2018-2024 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 "grid.h" + + +#include <assert.h> +#include <malloc.h> +#include <string.h> + + +#include "grid-int.h" +#include "helpers.h" +#include "bindings/grid-enums.h" + + + +/* --------------------------- INTERFACE DU COMPOSANT GTK --------------------------- */ + + +/* Liste des propriétés */ + +typedef enum _TilingGridProperty { + +    PROP_0,                                 /* Réservé                     */ + +    PROP_LAYOUT,                            /* Disposition générale        */ + +    PROP_EMPTY_TOP,                         /* Vide de la zone supérieure  */ +    PROP_EMPTY_LEFT,                        /* Vide de la zone de gauche   */ +    PROP_EMPTY_RIGHT,                       /* Vide de la zone de droite   */ +    PROP_EMPTY_BOTTOM,                      /* Vide de la zone inférieure  */ + +    PROP_VISIBLE_TOP,                       /* Visibilité de zone sup.     */ +    PROP_VISIBLE_LEFT,                      /* Visibilité de zone de gauche*/ +    PROP_VISIBLE_RIGHT,                     /* Visibilité de zone de droite*/ +    PROP_VISIBLE_BOTTOM,                    /* Visibilité de zone inf.     */ + +    N_PROPERTIES + +} TilingGridProperty; + +static GParamSpec *_tiling_grid_properties[N_PROPERTIES] = { NULL, }; + + +/* Initialise la classe des conteneurs d'affichage en tuiles. */ +static void gtk_tiling_grid_class_init(GtkTilingGridClass *); + +/* Initialise une instance de conteneur d'affichage en tuiles. */ +static void gtk_tiling_grid_init(GtkTilingGrid *); + +/* Supprime toutes les références externes. */ +static void gtk_tiling_grid_dispose(GObject *); + +/* Procède à la libération totale de la mémoire. */ +static void gtk_tiling_grid_finalize(GObject *); + +/* Réagit à une intégration ou à un retrait de panneau. */ +static void gtk_tiling_grid_on_panel_un_docked(GtkDockStation *, GtkTiledPanel *, GtkTilingGrid *); + + + +/* -------------------- REDIMENSIONNEMENT DE ZONES POUR PANNEAUX -------------------- */ + + +/* Initie un redimensionnement par drag-and-drop. */ +static void gtk_tiling_grid_on_gesture_drag_begin(GtkGestureDrag *, double, double, GtkTilingGrid *); + +/* Applique l'effet d'un redimensionnement drag-and-drop donné. */ +static void gtk_tiling_grid_on_gesture_drag_update(GtkTilingGrid *, TilingGridBorder, double, double); + +/* Actualise l'effet d'un redimensionnement drag-and-drop. */ +static void gtk_tiling_grid_on_top_gesture_drag_update(GtkGestureDrag *, double, double, GtkTilingGrid *); + +/* Actualise l'effet d'un redimensionnement drag-and-drop. */ +static void gtk_tiling_grid_on_left_gesture_drag_update(GtkGestureDrag *, double, double, GtkTilingGrid *); + +/* Actualise l'effet d'un redimensionnement drag-and-drop. */ +static void gtk_tiling_grid_on_right_gesture_drag_update(GtkGestureDrag *, double, double, GtkTilingGrid *); + +/* Actualise l'effet d'un redimensionnement drag-and-drop. */ +static void gtk_tiling_grid_on_bottom_gesture_drag_update(GtkGestureDrag *, double, double, GtkTilingGrid *); + +/* Clôture un drag-and-drop de redimensionnement. */ +static void gtk_tiling_grid_on_gesture_drag_end(GtkGestureDrag *, double, double, GtkTilingGrid *); + + + +/* --------------------- IMPLEMENTATION DES FONCTIONS DE CLASSE --------------------- */ + + +/* Met à jour une propriété d'instance GObject. */ +static void gtk_tiling_grid_set_property(GObject *, guint, const GValue *, GParamSpec *); + +/* Fournit la valeur d'une propriété d'instance GObject. */ +static void gtk_tiling_grid_get_property(GObject *, guint, GValue *, GParamSpec *); + + + +/* ---------------------------------------------------------------------------------- */ +/*                             INTERFACE DU COMPOSANT GTK                             */ +/* ---------------------------------------------------------------------------------- */ + + +/* Détermine le type du conteneur d'affichage en tuiles nommées. */ +G_DEFINE_TYPE(GtkTilingGrid, gtk_tiling_grid, GTK_TYPE_GRID) + + +/****************************************************************************** +*                                                                             * +*  Paramètres  : class = classe GTK à initialiser.                            * +*                                                                             * +*  Description : Initialise la classe des conteneurs d'affichage en tuiles.   * +*                                                                             * +*  Retour      : -                                                            * +*                                                                             * +*  Remarques   : -                                                            * +*                                                                             * +******************************************************************************/ + +static void gtk_tiling_grid_class_init(GtkTilingGridClass *class) +{ +    GObjectClass *object;                   /* Autre version de la classe  */ +    GtkWidgetClass *widget;                 /* Classe de haut niveau       */ + +    object = G_OBJECT_CLASS(class); + +    object->dispose = gtk_tiling_grid_dispose; +    object->finalize = gtk_tiling_grid_finalize; +    object->set_property = gtk_tiling_grid_set_property; +    object->get_property = gtk_tiling_grid_get_property; + +    _tiling_grid_properties[PROP_LAYOUT] = +        g_param_spec_flags("layout", NULL, NULL, +                           LAYOUT_REACH_OPTIONS_TYPE, +                           LRO_NONE, +                           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_EXPLICIT_NOTIFY); + +    _tiling_grid_properties[PROP_EMPTY_TOP] = +        g_param_spec_boolean("empty-top", NULL, NULL, +                             TRUE, +                             G_PARAM_READABLE | G_PARAM_STATIC_STRINGS | G_PARAM_EXPLICIT_NOTIFY); + +    _tiling_grid_properties[PROP_EMPTY_LEFT] = +        g_param_spec_boolean("empty-left", NULL, NULL, +                             TRUE, +                             G_PARAM_READABLE | G_PARAM_STATIC_STRINGS | G_PARAM_EXPLICIT_NOTIFY); + +    _tiling_grid_properties[PROP_EMPTY_RIGHT] = +        g_param_spec_boolean("empty-right", NULL, NULL, +                             TRUE, +                             G_PARAM_READABLE | G_PARAM_STATIC_STRINGS | G_PARAM_EXPLICIT_NOTIFY); + +    _tiling_grid_properties[PROP_EMPTY_BOTTOM] = +        g_param_spec_boolean("empty-bottom", NULL, NULL, +                             TRUE, +                             G_PARAM_READABLE | G_PARAM_STATIC_STRINGS | G_PARAM_EXPLICIT_NOTIFY); + +    /** +     * La valeur initiale des champs suivants est à maintenir synchronisée avec +     * les initialisations de gtk_tiling_grid_init(). +     */ + +    _tiling_grid_properties[PROP_VISIBLE_TOP] = +        g_param_spec_boolean("visible-top", NULL, NULL, +                             TRUE, +                             G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_EXPLICIT_NOTIFY); + +    _tiling_grid_properties[PROP_VISIBLE_LEFT] = +        g_param_spec_boolean("visible-left", NULL, NULL, +                             TRUE, +                             G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_EXPLICIT_NOTIFY); + +    _tiling_grid_properties[PROP_VISIBLE_RIGHT] = +        g_param_spec_boolean("visible-right", NULL, NULL, +                             TRUE, +                             G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_EXPLICIT_NOTIFY); + +    _tiling_grid_properties[PROP_VISIBLE_BOTTOM] = +        g_param_spec_boolean("visible-bottom", NULL, NULL, +                             TRUE, +                             G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_EXPLICIT_NOTIFY); + +    g_object_class_install_properties(object, N_PROPERTIES, _tiling_grid_properties); + +    widget = GTK_WIDGET_CLASS(class); + +    g_type_ensure(GTK_TYPE_DOCK_STATION); + +    gtk_widget_class_set_template_from_resource(widget, "/re/chrysalide/framework/gtkext/grid.ui"); + +    gtk_widget_class_bind_template_callback_full(widget, BUILDER_CB(gtk_tiling_grid_on_panel_un_docked)); +    gtk_widget_class_bind_template_callback_full(widget, BUILDER_CB(gtk_tiling_grid_on_gesture_drag_begin)); +    gtk_widget_class_bind_template_callback_full(widget, BUILDER_CB(gtk_tiling_grid_on_top_gesture_drag_update)); +    gtk_widget_class_bind_template_callback_full(widget, BUILDER_CB(gtk_tiling_grid_on_left_gesture_drag_update)); +    gtk_widget_class_bind_template_callback_full(widget, BUILDER_CB(gtk_tiling_grid_on_right_gesture_drag_update)); +    gtk_widget_class_bind_template_callback_full(widget, BUILDER_CB(gtk_tiling_grid_on_bottom_gesture_drag_update)); +    gtk_widget_class_bind_template_callback_full(widget, BUILDER_CB(gtk_tiling_grid_on_gesture_drag_end)); + +    gtk_widget_class_bind_template_child(widget, GtkTilingGrid, top); +    gtk_widget_class_bind_template_child(widget, GtkTilingGrid, top_handle); +    gtk_widget_class_bind_template_child(widget, GtkTilingGrid, top_station); +    gtk_widget_class_bind_template_child(widget, GtkTilingGrid, left); +    gtk_widget_class_bind_template_child(widget, GtkTilingGrid, left_handle); +    gtk_widget_class_bind_template_child(widget, GtkTilingGrid, left_station); +    gtk_widget_class_bind_template_child(widget, GtkTilingGrid, main_station); +    gtk_widget_class_bind_template_child(widget, GtkTilingGrid, right); +    gtk_widget_class_bind_template_child(widget, GtkTilingGrid, right_handle); +    gtk_widget_class_bind_template_child(widget, GtkTilingGrid, right_station); +    gtk_widget_class_bind_template_child(widget, GtkTilingGrid, bottom); +    gtk_widget_class_bind_template_child(widget, GtkTilingGrid, bottom_handle); +    gtk_widget_class_bind_template_child(widget, GtkTilingGrid, bottom_station); + + +    ///////////// + +    g_signal_new("station-created", +                 GTK_TYPE_TILING_GRID, +                 G_SIGNAL_RUN_LAST, +                 G_STRUCT_OFFSET(GtkTilingGridClass, station_created), +                 NULL, NULL, +                 g_cclosure_marshal_VOID__OBJECT, +                 G_TYPE_NONE, 1, GTK_TYPE_WIDGET/*DOCK_STATION FIXME */); + +} + + +/****************************************************************************** +*                                                                             * +*  Paramètres  : grid = instance GTK à initialiser.                           * +*                                                                             * +*  Description : Initialise une instance de conteneur d'affichage en tuiles.  * +*                                                                             * +*  Retour      : -                                                            * +*                                                                             * +*  Remarques   : -                                                            * +*                                                                             * +******************************************************************************/ + +static void gtk_tiling_grid_init(GtkTilingGrid *grid) +{ +    gtk_widget_init_template(GTK_WIDGET(grid)); + +    grid->settings = g_settings_new_with_path("re.chrysalide.framework.tiledgrid", +                                              "/re/chrysalide/framework/gui/tiles/"); + +    g_settings_bind(grid->settings, "layout", +                    grid, "layout", +                    G_SETTINGS_BIND_DEFAULT); + +    /** +     * L'initialisation des champs suivants est à maintenir synchronisée avec +     * les valeurs initiales de gtk_tiling_grid_class_init(). +     */ + +    grid->visible[TGB_TOP] = true; +    grid->visible[TGB_LEFT] = true; +    grid->visible[TGB_RIGHT] = true; +    grid->visible[TGB_BOTTOM] = true; + +    g_settings_bind(grid->settings, "top-request", +                    grid->top_station, "height-request", +                    G_SETTINGS_BIND_DEFAULT); + +    g_settings_bind(grid->settings, "top-visibility", +                    grid, "visible-top", +                    G_SETTINGS_BIND_DEFAULT); + +    g_settings_bind(grid->settings, "left-request", +                    grid->left_station, "width-request", +                    G_SETTINGS_BIND_DEFAULT); + +    g_settings_bind(grid->settings, "left-visibility", +                    grid, "visible-left", +                    G_SETTINGS_BIND_DEFAULT); + +    g_settings_bind(grid->settings, "right-request", +                    grid->right_station, "width-request", +                    G_SETTINGS_BIND_DEFAULT); + +    g_settings_bind(grid->settings, "right-visibility", +                    grid, "visible-right", +                    G_SETTINGS_BIND_DEFAULT); + +    g_settings_bind(grid->settings, "bottom-request", +                    grid->bottom_station, "height-request", +                    G_SETTINGS_BIND_DEFAULT); + +    g_settings_bind(grid->settings, "bottom-visibility", +                    grid, "visible-bottom", +                    G_SETTINGS_BIND_DEFAULT); + +    gtk_widget_set_cursor_from_name(grid->top_handle, "row-resize"); +    gtk_widget_set_cursor_from_name(grid->left_handle, "col-resize"); +    gtk_widget_set_cursor_from_name(grid->right_handle, "col-resize"); +    gtk_widget_set_cursor_from_name(grid->bottom_handle, "row-resize"); + +} + + +/****************************************************************************** +*                                                                             * +*  Paramètres  : object = instance d'objet GLib à traiter.                    * +*                                                                             * +*  Description : Supprime toutes les références externes.                     * +*                                                                             * +*  Retour      : -                                                            * +*                                                                             * +*  Remarques   : -                                                            * +*                                                                             * +******************************************************************************/ + +static void gtk_tiling_grid_dispose(GObject *object) +{ +    GtkTilingGrid *grid;                    /* Version spécialisée         */ + +    gtk_widget_dispose_template(GTK_WIDGET(object), GTK_TYPE_DOCK_STATION); + +    grid = GTK_TILING_GRID(object); + +    g_clear_object(&grid->settings); + +    G_OBJECT_CLASS(gtk_tiling_grid_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 gtk_tiling_grid_finalize(GObject *object) +{ +    G_OBJECT_CLASS(gtk_tiling_grid_parent_class)->finalize(object); + +} + + +/****************************************************************************** +*                                                                             * +*  Paramètres  : -                                                            * +*                                                                             * +*  Description : Crée une nouvelle instance de conteneur avec tuiles.         * +*                                                                             * +*  Retour      : Composant GTK mis en place.                                  * +*                                                                             * +*  Remarques   : -                                                            * +*                                                                             * +******************************************************************************/ + +GtkWidget *gtk_tiling_grid_new(void) +{ +    GtkWidget *result;                      /* Instance à retourner        */ + +    result = g_object_new(GTK_TYPE_TILING_GRID, NULL); + +    return result; + +} + + +/****************************************************************************** +*                                                                             * +*  Paramètres  : grid    = zone d'affichage en tuiles à manipuler.            * +*                border  = sélection de la zone à considérer.                 * +*                visible = nouveau statut de visibilité à appliquer.          * +*                                                                             * +*  Description : Affiche ou masque une zone du conteneur en tuiles.           * +*                                                                             * +*  Retour      : -                                                            * +*                                                                             * +*  Remarques   : -                                                            * +*                                                                             * +******************************************************************************/ + +void gtk_tiling_grid_set_visible(GtkTilingGrid *grid, TilingGridBorder border, bool visible) +{ +    GtkRevealer *revealer;                  /* Cible visée par l'opération */ +    GtkDockStation *station;                /* Apport d'une contrainte     */ + +    if (grid->visible[border] != visible) +    { +        grid->visible[border] = visible; + +        switch (border) +        { +            case TGB_TOP: +                revealer = grid->top; +                station = grid->top_station; +                break; + +            case TGB_LEFT: +                revealer = grid->left; +                station = grid->left_station; +                break; + +            case TGB_RIGHT: +                revealer = grid->right; +                station = grid->right_station; +                break; + +            case TGB_BOTTOM: +                revealer = grid->bottom; +                station = grid->bottom_station; +                break; + +        } + +        gtk_revealer_set_reveal_child(revealer, visible && !gtk_dock_station_is_empty(station)); + +        g_object_notify_by_pspec(G_OBJECT(grid), _tiling_grid_properties[PROP_VISIBLE_TOP + border]); + +    } + +} + + +/****************************************************************************** +*                                                                             * +*  Paramètres  : grid   = zone d'affichage en tuiles à manipuler.             * +*                border = sélection de la zone à considérer.                  * +*                                                                             * +*  Description : Fournit la visibilité d'une zone du conteneur en tuiles.     * +*                                                                             * +*  Retour      : Visibilité de la zone considérée.                            * +*                                                                             * +*  Remarques   : -                                                            * +*                                                                             * +******************************************************************************/ + +bool gtk_tiling_grid_get_visible(GtkTilingGrid *grid, TilingGridBorder border) +{ +    bool result;                            /* Statut à retourner          */ + +    result = grid->visible[border]; + +    return result; + +} + + +/****************************************************************************** +*                                                                             * +*  Paramètres  : grid  = zone d'affichage en tuiles à manipuler.              * +*                panel = nouveau panneau à afficher.                          * +*                keep  = indique si le panneau est à conserver présent.       * +*                                                                             * +*  Description : Ajoute un panneau à un conteneur en tuiles.                  * +*                                                                             * +*  Retour      : -                                                            * +*                                                                             * +*  Remarques   : -                                                            * +*                                                                             * +******************************************************************************/ + +void gtk_tiling_grid_add_panel(GtkTilingGrid *grid, GtkTiledPanel *panel, bool keep) +{ +    char *path;                             /* Chemin visé par le panneau  */ +    bool static_path;                       /* Nature du chemin à traiter  */ + +    path = gtk_tiled_panel_get_path(panel); + +    static_path = (path == NULL); + +    if (static_path) +        path = ""; + +    switch (path[0]) +    { +        case 'N': +            if (keep) +                gtk_dock_station_keep_panel(grid->top_station, panel); +            else +                gtk_dock_station_add_panel(grid->top_station, panel); +            break; + +        case 'W': +            if (keep) +                gtk_dock_station_keep_panel(grid->left_station, panel); +            else +                gtk_dock_station_add_panel(grid->left_station, panel); +            break; + +        case '\0': +        case 'M': +            if (keep) +                gtk_dock_station_keep_panel(grid->main_station, panel); +            else +                gtk_dock_station_add_panel(grid->main_station, panel); +            break; + +        case 'E': +            if (keep) +                gtk_dock_station_keep_panel(grid->right_station, panel); +            else +                gtk_dock_station_add_panel(grid->right_station, panel); +            break; + +        case 'S': +            if (keep) +                gtk_dock_station_keep_panel(grid->bottom_station, panel); +            else +                gtk_dock_station_add_panel(grid->bottom_station, panel); +            break; + +        default: +            break; + +    } + +    if (!static_path) +        free(path); + +} + + +/****************************************************************************** +*                                                                             * +*  Paramètres  : grid      = zone d'affichage en tuiles à manipuler.          * +*                main      = panneau principal visé par l'opération.          * +*                activated = nature du changement de statut : ajout, retrait ?* +*                                                                             * +*  Description : Note un ajout ou un retrait de panneau principal.            * +*                                                                             * +*  Retour      : -                                                            * +*                                                                             * +*  Remarques   : -                                                            * +*                                                                             * +******************************************************************************/ + +void gtk_tiling_grid_notify_new_main_panel_state(const GtkTilingGrid *grid, GtkTiledPanel *main, bool activated) +{ +    gtk_dock_station_notify_new_main_panel_state(grid->top_station, main, activated); + +    gtk_dock_station_notify_new_main_panel_state(grid->left_station, main, activated); + +    gtk_dock_station_notify_new_main_panel_state(grid->main_station, main, activated); + +    gtk_dock_station_notify_new_main_panel_state(grid->right_station, main, activated); + +    gtk_dock_station_notify_new_main_panel_state(grid->bottom_station, main, activated); + +} + + +/****************************************************************************** +*                                                                             * +*  Paramètres  : station = plateforme GTK ayant connu un changement.          * +*                widget  = nouvel élément à intégrer.                         * +*                grid    = gestionnaire de placement en tuile concerné.       * +*                                                                             * +*  Description : Réagit à une intégration ou à un retrait de panneau.         * +*                                                                             * +*  Retour      : -                                                            * +*                                                                             * +*  Remarques   : -                                                            * +*                                                                             * +******************************************************************************/ + +static void gtk_tiling_grid_on_panel_un_docked(GtkDockStation *station, GtkTiledPanel *panel, GtkTilingGrid *grid) +{ +    TilingGridBorder border;                /* Aire concernée par l'action */ +    GtkRevealer *revealer;                  /* Cible visée par l'opération */ +    bool new_state;                         /* Nouveau statut d'affichage  */ + +    if (station == grid->top_station) +    { +        border = TGB_TOP; +        revealer = grid->top; +    } + +    else if (station == grid->left_station) +    { +        border = TGB_LEFT; +        revealer = grid->left; +    } + +    else if (station == grid->right_station) +    { +        border = TGB_RIGHT; +        revealer = grid->right; +    } + +    else if (station == grid->bottom_station) +    { +        border = TGB_BOTTOM; +        revealer = grid->bottom; +    } + +    else +        assert(false); + +    new_state = grid->visible[border] && !gtk_dock_station_is_empty(station); + +    if (gtk_revealer_get_reveal_child(revealer) != new_state) +        gtk_revealer_set_reveal_child(revealer, new_state); + +    /** +     * On ne sait pas si l'état a réellement changé, mais on avertit +     * d'une mise à jour quand même, au cas où. +     */ + +    g_object_notify_by_pspec(G_OBJECT(grid), _tiling_grid_properties[PROP_EMPTY_TOP + border]); + +} + + + +/* ---------------------------------------------------------------------------------- */ +/*                      REDIMENSIONNEMENT DE ZONES POUR PANNEAUX                      */ +/* ---------------------------------------------------------------------------------- */ + + +/****************************************************************************** +*                                                                             * +*  Paramètres  : gesture = encadrement de déplacement à l'origine de l'appel. * +*                start_x = pointe de départ sur l'axe des abscisses.          * +*                start_y = pointe de départ sur l'axe des ordonnées.          * +*                grid    = gestionnaire de placement en tuile concerné.       * +*                                                                             * +*  Description : Initie un redimensionnement par drag-and-drop.               * +*                                                                             * +*  Retour      : -                                                            * +*                                                                             * +*  Remarques   : -                                                            * +*                                                                             * +******************************************************************************/ + +static void gtk_tiling_grid_on_gesture_drag_begin(GtkGestureDrag *gesture, double start_x, double start_y, GtkTilingGrid *grid) +{ +    gtk_gesture_set_state(GTK_GESTURE(gesture), GTK_EVENT_SEQUENCE_CLAIMED); + +    grid->panning = true; + +} + + +/****************************************************************************** +*                                                                             * +*  Paramètres  : grid     = zone d'affichage en tuiles à manipuler.           * +*                border   = sélection de la zone à considérer.                * +*                offset_x = déplacement sur l'axe des abscisses.              * +*                offset_y = déplacement sur l'axe des ordonnées.              * +*                                                                             * +*  Description : Applique l'effet d'un redimensionnement drag-and-drop donné. * +*                                                                             * +*  Retour      : -                                                            * +*                                                                             * +*  Remarques   : -                                                            * +*                                                                             * +******************************************************************************/ + +static void gtk_tiling_grid_on_gesture_drag_update(GtkTilingGrid *grid, TilingGridBorder border, double offset_x, double offset_y) +{ +    GtkDockStation *station;                /* Station entière             */ +    int request;                            /* Taille requise              */ + +    /* Sélection de la poignée adaptée */ + +    switch (border) +    { +        case TGB_TOP: +            station = grid->top_station; +            break; + +        case TGB_LEFT: +            station = grid->left_station; +            break; + +        case TGB_RIGHT: +            station = grid->right_station; +            break; + +        case TGB_BOTTOM: +            station = grid->bottom_station; +            break; + +    } + +    /* Détermination d'une nouvelle position et application */ + +    switch (border) +    { +        case TGB_TOP: +        case TGB_BOTTOM: +            g_object_get(G_OBJECT(station), "height-request", &request, NULL); +            break; + +        case TGB_LEFT: +        case TGB_RIGHT: +            g_object_get(G_OBJECT(station), "width-request", &request, NULL); +            break; + +    } + +    switch (border) +    { +        case TGB_TOP: +            request += offset_y; +            break; + +        case TGB_LEFT: +            request += offset_x; +            break; + +        case TGB_RIGHT: +            request += -offset_x; +            break; + +        case TGB_BOTTOM: +            request += -offset_y; +            break; + +    } + +    if (request > 0) +    { +        switch (border) +        { +            case TGB_TOP: +            case TGB_BOTTOM: +                g_object_set(G_OBJECT(station), "height-request", request, NULL); +                break; + +            case TGB_LEFT: +            case TGB_RIGHT: +                g_object_set(G_OBJECT(station), "width-request", request, NULL); +                break; + +        } + +    } + +} + + +/****************************************************************************** +*                                                                             * +*  Paramètres  : gesture = encadrement de déplacement à l'origine de l'appel. * +*                offset_x = déplacement sur l'axe des abscisses.              * +*                offset_y = déplacement sur l'axe des ordonnées.              * +*                grid    = gestionnaire de placement en tuile concerné.       * +*                                                                             * +*  Description : Actualise l'effet d'un redimensionnement drag-and-drop.      * +*                                                                             * +*  Retour      : -                                                            * +*                                                                             * +*  Remarques   : -                                                            * +*                                                                             * +******************************************************************************/ + +static void gtk_tiling_grid_on_top_gesture_drag_update(GtkGestureDrag *gesture, double offset_x, double offset_y, GtkTilingGrid *grid) +{ +    gtk_tiling_grid_on_gesture_drag_update(grid, TGB_TOP, offset_x, offset_y); + +} + + +/****************************************************************************** +*                                                                             * +*  Paramètres  : gesture = encadrement de déplacement à l'origine de l'appel. * +*                offset_x = déplacement sur l'axe des abscisses.              * +*                offset_y = déplacement sur l'axe des ordonnées.              * +*                grid    = gestionnaire de placement en tuile concerné.       * +*                                                                             * +*  Description : Actualise l'effet d'un redimensionnement drag-and-drop.      * +*                                                                             * +*  Retour      : -                                                            * +*                                                                             * +*  Remarques   : -                                                            * +*                                                                             * +******************************************************************************/ + +static void gtk_tiling_grid_on_left_gesture_drag_update(GtkGestureDrag *gesture, double offset_x, double offset_y, GtkTilingGrid *grid) +{ +    gtk_tiling_grid_on_gesture_drag_update(grid, TGB_LEFT, offset_x, offset_y); + +} + + +/****************************************************************************** +*                                                                             * +*  Paramètres  : gesture = encadrement de déplacement à l'origine de l'appel. * +*                offset_x = déplacement sur l'axe des abscisses.              * +*                offset_y = déplacement sur l'axe des ordonnées.              * +*                grid    = gestionnaire de placement en tuile concerné.       * +*                                                                             * +*  Description : Actualise l'effet d'un redimensionnement drag-and-drop.      * +*                                                                             * +*  Retour      : -                                                            * +*                                                                             * +*  Remarques   : -                                                            * +*                                                                             * +******************************************************************************/ + +static void gtk_tiling_grid_on_right_gesture_drag_update(GtkGestureDrag *gesture, double offset_x, double offset_y, GtkTilingGrid *grid) +{ +    gtk_tiling_grid_on_gesture_drag_update(grid, TGB_RIGHT, offset_x, offset_y); + +} + + +/****************************************************************************** +*                                                                             * +*  Paramètres  : gesture = encadrement de déplacement à l'origine de l'appel. * +*                offset_x = déplacement sur l'axe des abscisses.              * +*                offset_y = déplacement sur l'axe des ordonnées.              * +*                grid    = gestionnaire de placement en tuile concerné.       * +*                                                                             * +*  Description : Actualise l'effet d'un redimensionnement drag-and-drop.      * +*                                                                             * +*  Retour      : -                                                            * +*                                                                             * +*  Remarques   : -                                                            * +*                                                                             * +******************************************************************************/ + +static void gtk_tiling_grid_on_bottom_gesture_drag_update(GtkGestureDrag *gesture, double offset_x, double offset_y, GtkTilingGrid *grid) +{ +    gtk_tiling_grid_on_gesture_drag_update(grid, TGB_BOTTOM, offset_x, offset_y); + +} + + +/****************************************************************************** +*                                                                             * +*  Paramètres  : gesture = encadrement de déplacement à l'origine de l'appel. * +*                offset_x = déplacement final sur l'axe des abscisses.        * +*                offset_y = déplacement final sur l'axe des ordonnées.        * +*                grid    = gestionnaire de placement en tuile concerné.       * +*                                                                             * +*  Description : Clôture un drag-and-drop de redimensionnement.               * +*                                                                             * +*  Retour      : -                                                            * +*                                                                             * +*  Remarques   : -                                                            * +*                                                                             * +******************************************************************************/ + +static void gtk_tiling_grid_on_gesture_drag_end(GtkGestureDrag *gesture, double offset_x, double offset_y, GtkTilingGrid *grid) +{ +    if (!grid->panning) +        gtk_gesture_set_state(GTK_GESTURE(gesture), GTK_EVENT_SEQUENCE_DENIED); +    else +        grid->panning = false; + +} + + + +/* ---------------------------------------------------------------------------------- */ +/*                       IMPLEMENTATION DES FONCTIONS DE CLASSE                       */ +/* ---------------------------------------------------------------------------------- */ + + +/****************************************************************************** +*                                                                             * +*  Paramètres  : object  = instance d'objet GLib à mamnipuler.                * +*                prop_id = identifiant de la propriété visée.                 * +*                value   = valeur à prendre en compte.                        * +*                pspec   = définition de la propriété.                        * +*                                                                             * +*  Description : Met à jour une propriété d'instance GObject.                 * +*                                                                             * +*  Retour      : -                                                            * +*                                                                             * +*  Remarques   : -                                                            * +*                                                                             * +******************************************************************************/ + +static void gtk_tiling_grid_set_property(GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) +{ +    GtkTilingGrid *grid;                    /* Version spécialisée         */ + +    grid = GTK_TILING_GRID(object); + +    switch (prop_id) +    { +        case PROP_LAYOUT: +            if (grid->layout != g_value_get_flags(value)) +            { +                grid->layout = g_value_get_flags(value); + +                apply_tiling_grid_layout(GTK_GRID(grid), grid->layout, (GtkWidget *[]) { +                        GTK_WIDGET(grid->top), GTK_WIDGET(grid->left), +                        GTK_WIDGET(grid->right), GTK_WIDGET(grid->bottom) +                    }); + +                g_object_notify_by_pspec(object, pspec); + +            } +            break; + +            gtk_tiling_grid_set_visible(grid, TGB_TOP, g_value_get_boolean(value)); +            break; + +        case PROP_VISIBLE_TOP: +            gtk_tiling_grid_set_visible(grid, TGB_TOP, g_value_get_boolean(value)); +            break; + +        case PROP_VISIBLE_LEFT: +            gtk_tiling_grid_set_visible(grid, TGB_LEFT, g_value_get_boolean(value)); +            break; + +        case PROP_VISIBLE_RIGHT: +            gtk_tiling_grid_set_visible(grid, TGB_RIGHT, g_value_get_boolean(value)); +            break; + +        case PROP_VISIBLE_BOTTOM: +            gtk_tiling_grid_set_visible(grid, TGB_BOTTOM, g_value_get_boolean(value)); +            break; + +        default: +            G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec); +            break; + +    } + +} + + +/****************************************************************************** +*                                                                             * +*  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_tiling_grid_get_property(GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) +{ +    GtkTilingGrid *grid;                    /* Version spécialisée         */ + +    grid = GTK_TILING_GRID(object); + +    switch (prop_id) +    { +        case PROP_EMPTY_TOP: +            g_value_set_boolean(value, gtk_dock_station_is_empty(grid->top_station)); +            break; + +        case PROP_EMPTY_LEFT: +            g_value_set_boolean(value, gtk_dock_station_is_empty(grid->left_station)); +            break; + +        case PROP_EMPTY_RIGHT: +            g_value_set_boolean(value, gtk_dock_station_is_empty(grid->right_station)); +            break; + +        case PROP_EMPTY_BOTTOM: +            g_value_set_boolean(value, gtk_dock_station_is_empty(grid->bottom_station)); +            break; + +        case PROP_VISIBLE_TOP: +            g_value_set_boolean(value, gtk_tiling_grid_get_visible(grid, TGB_TOP)); +            break; + +        case PROP_VISIBLE_LEFT: +            g_value_set_boolean(value, gtk_tiling_grid_get_visible(grid, TGB_LEFT)); +            break; + +        case PROP_VISIBLE_RIGHT: +            g_value_set_boolean(value, gtk_tiling_grid_get_visible(grid, TGB_RIGHT)); +            break; + +        case PROP_VISIBLE_BOTTOM: +            g_value_set_boolean(value, gtk_tiling_grid_get_visible(grid, TGB_BOTTOM)); +            break; + +        default: +            G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec); +            break; + +    } + +} + + + +/* ---------------------------------------------------------------------------------- */ +/*                       FORME GENERIQUE DE MISE EN DISPOSITION                       */ +/* ---------------------------------------------------------------------------------- */ + + +/****************************************************************************** +*                                                                             * +*  Paramètres  : grid    = composant GTK dont le contenu est à arranger.      * +*                options = options de mise en place.                          * +*                panels  = liste organisée de composants à déplacer.          * +*                                                                             * +*  Description : Met en place une disposition particulière de panneaux.       * +*                                                                             * +*  Retour      : -                                                            * +*                                                                             * +*  Remarques   : -                                                            * +*                                                                             * +******************************************************************************/ + +void apply_tiling_grid_layout(GtkGrid *grid, LayoutReachOptions options, GtkWidget *panels[TGB_COUNT]) +{ +    int top_panel_span;                     /* Etendue d'un composant #1   */ +    int left_panel_span;                    /* Etendue d'un composant #2   */ +    int right_panel_span;                   /* Etendue d'un composant #3   */ +    int bottom_panel_span;                  /* Etendue d'un composant #4   */ +    int top_panel_column;                   /* Position de composant #1    */ +    int left_panel_row;                     /* Position de composant #2    */ +    int right_panel_row;                    /* Position de composant #3    */ +    int bottom_panel_column;                /* Position de composant #4    */ +    GtkLayoutManager *layout;               /* Gestionnaire de disposition */ +    GtkGridLayoutChild *top_panel_layout;   /* Disposition de composant #1 */ +    GtkGridLayoutChild *left_panel_layout;  /* Disposition de composant #2 */ +    GtkGridLayoutChild *right_panel_layout; /* Disposition de composant #3 */ +    GtkGridLayoutChild *bottom_panel_layout;/* Disposition de composant #4 */ + +    /* Calcul des placements */ + +    top_panel_span = 3; +    left_panel_span = 3; +    right_panel_span = 3; +    bottom_panel_span = 3; + +    if (options & LRO_LEFT_TOP_REACH) +    { +        top_panel_column = 1; +        top_panel_span--; +        left_panel_row = 0; +    } +    else +    { +        top_panel_column = 0; +        left_panel_row = 1; +        left_panel_span--; +    } + +    if (options & LRO_LEFT_BOTTOM_REACH) +    { +        bottom_panel_column = 1; +        bottom_panel_span--; +    } +    else +    { +        left_panel_span--; +        bottom_panel_column = 0; +    } + +    if (options & LRO_RIGHT_TOP_REACH) +    { +        top_panel_span--; +        right_panel_row = 0; +    } +    else +    { +        right_panel_row = 1; +        right_panel_span--; +    } + +    if (options & LRO_RIGHT_BOTTOM_REACH) +        bottom_panel_span--; +    else +        right_panel_span--; + +    /* Mise en application des contraintes */ + +    layout = gtk_widget_get_layout_manager(GTK_WIDGET(grid)); + +    top_panel_layout = GTK_GRID_LAYOUT_CHILD(gtk_layout_manager_get_layout_child(layout, panels[TGB_TOP])); +    left_panel_layout = GTK_GRID_LAYOUT_CHILD(gtk_layout_manager_get_layout_child(layout, panels[TGB_LEFT])); +    right_panel_layout = GTK_GRID_LAYOUT_CHILD(gtk_layout_manager_get_layout_child(layout, panels[TGB_RIGHT])); +    bottom_panel_layout = GTK_GRID_LAYOUT_CHILD(gtk_layout_manager_get_layout_child(layout, panels[TGB_BOTTOM])); + +    g_object_set(G_OBJECT(top_panel_layout), +                 "column", top_panel_column, +                 "column-span", top_panel_span, +                 NULL); + +    g_object_set(G_OBJECT(left_panel_layout), +                 "row", left_panel_row, +                 "row-span", left_panel_span, +                 NULL); + +    g_object_set(G_OBJECT(right_panel_layout), +                 "row", right_panel_row, +                 "row-span", right_panel_span, +                 NULL); + +    g_object_set(G_OBJECT(bottom_panel_layout), +                 "column", bottom_panel_column, +                 "column-span", bottom_panel_span, +                 NULL); + +    gtk_layout_manager_layout_changed(layout); + +} diff --git a/src/gtkext/tiledgrid.h b/src/gtkext/grid.h index 539e248..fd98035 100644 --- a/src/gtkext/tiledgrid.h +++ b/src/gtkext/grid.h @@ -2,7 +2,7 @@  /* Chrysalide - Outil d'analyse de fichiers binaires   * tiledgrid.h - prototypes pour un composant d'affichage avec des chemins vers les composants contenus   * - * Copyright (C) 2018-2019 Cyrille Bagard + * Copyright (C) 2018-2024 Cyrille Bagard   *   *  This file is part of Chrysalide.   * @@ -21,10 +21,81 @@   */ -#ifndef _GTKEXT_TILEDGRID_H -#define _GTKEXT_TILEDGRID_H +#ifndef _GTKEXT_GRID_H +#define _GTKEXT_GRID_H +#include <stdbool.h> +#include <gtk/gtk.h> + + +#include "panel.h" +#include "../glibext/helpers.h" + + + +#define GTK_TYPE_TILING_GRID (gtk_tiling_grid_get_type()) + +DECLARE_GTYPE(GtkTilingGrid, gtk_tiling_grid, GTK, TILING_GRID); + + +/* Crée une nouvelle instance de conteneur avec tuiles. */ +GtkWidget *gtk_tiling_grid_new(void); + +/* Liste des zones de bordure */ +typedef enum _TilingGridBorder              /*< skip (glib-mkenums)       >*/ +{ +    TGB_TOP,                                /* Zone supérieure             */ +    TGB_LEFT,                               /* Zone de gauche              */ +    TGB_RIGHT,                              /* Zone de droite              */ +    TGB_BOTTOM,                             /* Zone inférieure             */ + +} TilingGridBorder; + +/** + * Fixe le nombre de combinaisons sans le rendre visible dans l'énumération. + */ +#define TGB_COUNT (TGB_BOTTOM + 1) + +/* Affiche ou masque une zone du conteneur en tuiles. */ +void gtk_tiling_grid_set_visible(GtkTilingGrid *, TilingGridBorder, bool); + +/* Fournit la visibilité d'une zone du conteneur en tuiles. */ +bool gtk_tiling_grid_get_visible(GtkTilingGrid *, TilingGridBorder); + +/* Ajoute un panneau à un conteneur en tuiles. */ +void gtk_tiling_grid_add_panel(GtkTilingGrid *, GtkTiledPanel *, bool); + +/* Note un ajout ou un retrait de panneau principal. */ +void gtk_tiling_grid_notify_new_main_panel_state(const GtkTilingGrid *, GtkTiledPanel *, bool); + + + +/* --------------------- FORME GENERIQUE DE MISE EN DISPOSITION --------------------- */ + + +/* Options de dispositions cumulables */ +typedef enum _LayoutReachOptions            /*< flags (glib-mkenums)      >*/ +{ +    LRO_NONE                = (0 << 0),     /* Aucune atteinte des bords   */ +    LRO_LEFT_TOP_REACH      = (1 << 0),     /* Atteinte du bord haut à G.  */ +    LRO_LEFT_BOTTOM_REACH   = (1 << 1),     /* Atteinte du bord bas à G.   */ +    LRO_RIGHT_TOP_REACH     = (1 << 2),     /* Atteinte du bord haut à D.  */ +    LRO_RIGHT_BOTTOM_REACH  = (1 << 3),     /* Atteinte du bord bas à D.   */ + +} LayoutReachOptions; + +/* Met en place une disposition particulière de panneaux. */ +void apply_tiling_grid_layout(GtkGrid *, LayoutReachOptions, GtkWidget *[TGB_COUNT]); + + + + + + + +#if 0 +  #include <gtk/gtk.h> @@ -81,5 +152,7 @@ void gtk_tiled_grid_restore_positions(const GtkTiledGrid *, GGenConfig *);  void gtk_tiled_grid_save_positions(const GtkTiledGrid *, GGenConfig *); +#endif + -#endif  /* _GTKEXT_TILEDGRID_H */ +#endif  /* _GTKEXT_GRID_H */ diff --git a/src/gtkext/grid.ui b/src/gtkext/grid.ui new file mode 100644 index 0000000..b14ced2 --- /dev/null +++ b/src/gtkext/grid.ui @@ -0,0 +1,217 @@ +<?xml version="1.0" encoding="UTF-8"?> +<interface> +    <template class="GtkTilingGrid" parent="GtkGrid"> + +        <!-- Zone supérieure --> + +        <child> +            <object class="GtkRevealer" id="top"> +                <property name="transition-type">slide-up</property> +                <property name="reveal-child">false</property> + +                <child> +                    <object class="GtkBox"> +                        <property name="orientation">vertical</property> + +                        <child> +                            <object class="GtkDockStation" id="top_station"> +                                <property name="orientation">vertical</property> +                                <property name="hexpand">true</property> +                                <property name="vexpand">false</property> +                                <property name="height-request">30</property> +                                <signal name="panel-docked" handler="gtk_tiling_grid_on_panel_un_docked"/> +                                <signal name="panel-undocked" handler="gtk_tiling_grid_on_panel_un_docked"/> +                            </object> +                        </child> + +                        <child> +                            <object class="GtkSeparator" id="top_handle"> +                                <property name="orientation">vertical</property> +                                <property name="height-request">5</property> + +                                <child> +                                    <object class="GtkGestureDrag"> +                                        <property name="propagation-phase">capture</property> +                                        <signal name="drag-begin" handler="gtk_tiling_grid_on_gesture_drag_begin"/> +                                        <signal name="drag-update" handler="gtk_tiling_grid_on_top_gesture_drag_update"/> +                                        <signal name="drag-end" handler="gtk_tiling_grid_on_gesture_drag_end"/> +                                    </object> +                                </child> + +                            </object> +                        </child> + +                    </object> +                </child> + +                <layout> +                    <property name="column">0</property> +                    <property name="row">0</property> +                    <property name="column-span">3</property> +                </layout> +            </object> +        </child> + +        <!-- Zone de gauche --> + +        <child> +            <object class="GtkRevealer" id="left"> +                <property name="transition-type">slide-right</property> +                <property name="reveal-child">false</property> + +                <child> +                    <object class="GtkBox"> +                        <property name="orientation">horizontal</property> + +                        <child> +                            <object class="GtkDockStation" id="left_station"> +                                <property name="orientation">vertical</property> +                                <property name="hexpand">false</property> +                                <property name="vexpand">true</property> +                                <property name="width-request">300</property> +                                <signal name="panel-docked" handler="gtk_tiling_grid_on_panel_un_docked"/> +                                <signal name="panel-undocked" handler="gtk_tiling_grid_on_panel_un_docked"/> +                            </object> +                        </child> + +                        <child> +                            <object class="GtkSeparator" id="left_handle"> +                                <property name="orientation">horizontal</property> +                                <property name="width-request">5</property> + +                                <child> +                                    <object class="GtkGestureDrag"> +                                        <property name="propagation-phase">capture</property> +                                        <signal name="drag-begin" handler="gtk_tiling_grid_on_gesture_drag_begin"/> +                                        <signal name="drag-update" handler="gtk_tiling_grid_on_left_gesture_drag_update"/> +                                        <signal name="drag-end" handler="gtk_tiling_grid_on_gesture_drag_end"/> +                                    </object> +                                </child> + +                            </object> +                        </child> + +                    </object> +                </child> + +                <layout> +                    <property name="column">0</property> +                    <property name="row">1</property> +                </layout> +            </object> +        </child> + +        <!-- Zone centrale --> + +        <child> +            <object class="GtkDockStation" id="main_station"> +                <property name="hexpand">true</property> +                <property name="vexpand">true</property> +                <layout> +                    <property name="column">1</property> +                    <property name="row">1</property> +                </layout> +            </object> +        </child> + +        <!-- Zone de droite --> + +        <child> +            <object class="GtkRevealer" id="right"> +                <property name="transition-type">slide-left</property> +                <property name="reveal-child">false</property> + +                <child> +                    <object class="GtkBox"> +                        <property name="orientation">horizontal</property> + +                        <child> +                            <object class="GtkSeparator" id="right_handle"> +                                <property name="orientation">horizontal</property> +                                <property name="width-request">5</property> + +                                <child> +                                    <object class="GtkGestureDrag"> +                                        <property name="propagation-phase">capture</property> +                                        <signal name="drag-begin" handler="gtk_tiling_grid_on_gesture_drag_begin"/> +                                        <signal name="drag-update" handler="gtk_tiling_grid_on_right_gesture_drag_update"/> +                                        <signal name="drag-end" handler="gtk_tiling_grid_on_gesture_drag_end"/> +                                    </object> +                                </child> + +                            </object> +                        </child> + +                        <child> +                            <object class="GtkDockStation" id="right_station"> +                                <property name="orientation">vertical</property> +                                <property name="hexpand">false</property> +                                <property name="vexpand">true</property> +                                <property name="width-request">300</property> +                                <signal name="panel-docked" handler="gtk_tiling_grid_on_panel_un_docked"/> +                                <signal name="panel-undocked" handler="gtk_tiling_grid_on_panel_un_docked"/> +                            </object> +                        </child> + +                    </object> +                </child> + +                <layout> +                    <property name="column">2</property> +                    <property name="row">1</property> +                </layout> +            </object> +        </child> + +        <!-- Zone inférieure --> + +        <child> +            <object class="GtkRevealer" id="bottom"> +                <property name="transition-type">slide-up</property> +                <property name="reveal-child">false</property> + +                <child> +                    <object class="GtkBox"> +                        <property name="orientation">vertical</property> + +                        <child> +                            <object class="GtkSeparator" id="bottom_handle"> +                                <property name="orientation">vertical</property> +                                <property name="height-request">5</property> + +                                <child> +                                    <object class="GtkGestureDrag"> +                                        <property name="propagation-phase">capture</property> +                                        <signal name="drag-begin" handler="gtk_tiling_grid_on_gesture_drag_begin"/> +                                        <signal name="drag-update" handler="gtk_tiling_grid_on_bottom_gesture_drag_update"/> +                                        <signal name="drag-end" handler="gtk_tiling_grid_on_gesture_drag_end"/> +                                    </object> +                                </child> + +                            </object> +                        </child> + +                        <child> +                            <object class="GtkDockStation" id="bottom_station"> +                                <property name="orientation">horizontal</property> +                                <property name="hexpand">true</property> +                                <property name="vexpand">false</property> +                                <property name="height-request">250</property> +                                <signal name="panel-docked" handler="gtk_tiling_grid_on_panel_un_docked"/> +                                <signal name="panel-undocked" handler="gtk_tiling_grid_on_panel_un_docked"/> +                            </object> +                        </child> + +                    </object> +                </child> + +                <layout> +                    <property name="column">0</property> +                    <property name="row">2</property> +                    <property name="column-span">3</property> +                </layout> +            </object> +        </child> + +    </template> +</interface> diff --git a/src/gtkext/gtkdockstation.c b/src/gtkext/gtkdockstation.c deleted file mode 100644 index 1757542..0000000 --- a/src/gtkext/gtkdockstation.c +++ /dev/null @@ -1,467 +0,0 @@ - -/* Chrysalide - Outil d'analyse de fichiers binaires - * gtkdockstation.c - manipulation et l'affichage de composants rassemblés - * - * Copyright (C) 2012-2019 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 "gtkdockstation.h" - - -#include <malloc.h> -#include <string.h> - - -#include "easygtk.h" -#include "../core/params.h" -#include "../common/extstr.h" -#include "../glibext/chrysamarshal.h" - - - -/* Procède à l'initialisation de l'afficheur concentré. */ -static void gtk_dock_station_class_init(GtkDockStationClass *); - -/* Procède à l'initialisation du support d'affichage concentré. */ -static void gtk_dock_station_init(GtkDockStation *); - -/* Met à jour le titre du support de panneaux concentrés. */ -static gboolean gtk_dock_station_switch_panel(GtkNotebook *, gpointer *, guint, GtkDockStation *); - - - - -/* Révèle ou cache la zone de recherches. */ -static void on_toggle_revealer(GtkToggleButton *, GtkDockStation *); - -/* Demande l'apparition d'un menu pour inclure des composants. */ -static void on_click_for_menu(GtkButton *, GtkDockStation *); - -/* Demande la disparition du composant courant. */ -static void on_click_for_close(GtkButton *, GtkDockStation *); - - - - - - -/* Détermine le type du composant d'affichage concentré. */ -G_DEFINE_TYPE(GtkDockStation, gtk_dock_station, GTK_TYPE_NOTEBOOK) - - -/****************************************************************************** -*                                                                             * -*  Paramètres  : class = classe GTK à initialiser.                            * -*                                                                             * -*  Description : Procède à l'initialisation de l'afficheur concentré.         * -*                                                                             * -*  Retour      : -                                                            * -*                                                                             * -*  Remarques   : -                                                            * -*                                                                             * -******************************************************************************/ - -static void gtk_dock_station_class_init(GtkDockStationClass *class) -{ -    g_signal_new("dock-widget", -                 GTK_TYPE_DOCK_STATION, -                 G_SIGNAL_RUN_LAST, -                 G_STRUCT_OFFSET(GtkDockStationClass, dock_widget), -                 NULL, NULL, -                 g_cclosure_marshal_VOID__OBJECT, -                 G_TYPE_NONE, 1, GTK_TYPE_WIDGET); - -    g_signal_new("undock-widget", -                 GTK_TYPE_DOCK_STATION, -                 G_SIGNAL_RUN_LAST, -                 G_STRUCT_OFFSET(GtkDockStationClass, undock_widget), -                 NULL, NULL, -                 g_cclosure_marshal_VOID__OBJECT, -                 G_TYPE_NONE, 1, GTK_TYPE_WIDGET); - -    g_signal_new("switch-widget", -                 GTK_TYPE_DOCK_STATION, -                 G_SIGNAL_RUN_LAST, -                 G_STRUCT_OFFSET(GtkDockStationClass, switch_widget), -                 NULL, NULL, -                 g_cclosure_marshal_VOID__OBJECT, -                 G_TYPE_NONE, 1, GTK_TYPE_WIDGET); - -    g_signal_new("menu-requested", -                 GTK_TYPE_DOCK_STATION, -                 G_SIGNAL_RUN_LAST, -                 G_STRUCT_OFFSET(GtkDockStationClass, menu_requested), -                 NULL, NULL, -                 g_cclosure_marshal_VOID__OBJECT, -                 G_TYPE_NONE, 1, GTK_TYPE_WIDGET); - -    g_signal_new("close-requested", -                 GTK_TYPE_DOCK_STATION, -                 G_SIGNAL_RUN_LAST, -                 G_STRUCT_OFFSET(GtkDockStationClass, close_requested), -                 NULL, NULL, -                 g_cclosure_marshal_VOID__OBJECT, -                 G_TYPE_NONE, 1, GTK_TYPE_WIDGET); - -} - - -/****************************************************************************** -*                                                                             * -*  Paramètres  : station = composant GTK à initialiser.                       * -*                                                                             * -*  Description : Procède à l'initialisation du support d'affichage concentré. * -*                                                                             * -*  Retour      : -                                                            * -*                                                                             * -*  Remarques   : -                                                            * -*                                                                             * -******************************************************************************/ - -static void gtk_dock_station_init(GtkDockStation *station) -{ -    GtkNotebook *notebook;                  /* Autre version du composant  */ -    GtkWidget *hbox;                        /* Division supérieure         */ -    GtkWidget *button;                      /* Bouton de contrôle          */ - -    notebook = GTK_NOTEBOOK(station); - -    gtk_notebook_set_show_border(notebook, FALSE); -    gtk_notebook_set_scrollable(notebook, TRUE); - -    /* Définition de la zone de contrôle */ - -    hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0); -    gtk_widget_set_valign(hbox, GTK_ALIGN_CENTER); -    gtk_widget_set_margin_end(hbox, 8); -    gtk_widget_show(hbox); - -    button = qck_create_toggle_button_with_named_img(G_OBJECT(station), "search", -                                                     "edit-find-symbolic", GTK_ICON_SIZE_MENU, NULL, -                                                     G_CALLBACK(on_toggle_revealer), station); -    gtk_button_set_relief(GTK_BUTTON(button), GTK_RELIEF_NONE); -    gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, FALSE, 0); - -    button = qck_create_button_with_named_img(G_OBJECT(station), "menu", -                                              "go-down-symbolic", GTK_ICON_SIZE_MENU, NULL, -                                              G_CALLBACK(on_click_for_menu), station); -    gtk_button_set_relief(GTK_BUTTON(button), GTK_RELIEF_NONE); -    gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, FALSE, 0); - -    button = qck_create_button_with_named_img(G_OBJECT(station), "close", -                                              "window-close-symbolic", GTK_ICON_SIZE_MENU, NULL, -                                              G_CALLBACK(on_click_for_close), station); -    gtk_button_set_relief(GTK_BUTTON(button), GTK_RELIEF_NONE); -    gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, FALSE, 0); - -    gtk_notebook_set_action_widget(notebook, hbox, GTK_PACK_END); - -    g_signal_connect(notebook, "switch-page", -                     G_CALLBACK(gtk_dock_station_switch_panel), station); - -} - - -/****************************************************************************** -*                                                                             * -*  Paramètres  : -                                                            * -*                                                                             * -*  Description : Crée un nouveau composant pour support d'affichage concentré.* -*                                                                             * -*  Retour      : -                                                            * -*                                                                             * -*  Remarques   : -                                                            * -*                                                                             * -******************************************************************************/ - -GtkWidget *gtk_dock_station_new(void) -{ -    return g_object_new(GTK_TYPE_DOCK_STATION, NULL); - -} - - -/****************************************************************************** -*                                                                             * -*  Paramètres  : notebook = support à l'origine de la mise à jour.            * -*                page     = onglet mis en avant.                              * -*                index    = indice de l'onglet actuellement actif.            * -*                station  = conteneur de gestion supérieur.                   * -*                                                                             * -*  Description : Met à jour le titre du support de panneaux concentrés.       * -*                                                                             * -*  Retour      : TRUE ?                                                       * -*                                                                             * -*  Remarques   : -                                                            * -*                                                                             * -******************************************************************************/ - -static gboolean gtk_dock_station_switch_panel(GtkNotebook *notebook, gpointer *page, guint index, GtkDockStation *station) -{ -    GtkWidget *widget;                      /* Panneau concerné            */ -    GtkDockable *dockable;                  /* Elément encapsulé           */ -    GtkWidget *button;                      /* Bouton de contrôle          */ - -    widget = gtk_notebook_get_nth_page(notebook, index); - -    dockable = GTK_DOCKABLE(g_object_get_data(G_OBJECT(widget), "dockable")); - -    /* Mise à jour des boutons utilisables */ - -    button = GTK_WIDGET(g_object_get_data(G_OBJECT(station), "search")); - -    if (gtk_dockable_can_search(dockable)) -        gtk_widget_show(button); -    else -        gtk_widget_hide(button); - -    /* Remontée du changement d'onglet */ - -    g_signal_emit_by_name(station, "switch-widget", widget); - -    return TRUE; - -} - - -/****************************************************************************** -*                                                                             * -*  Paramètres  : station  = plateforme GTK à compléter.                       * -*                dockable = nouvel élément à intégrer.                        * -*                                                                             * -*  Description : Ajoute un paquet d'informations à l'affichage centralisé.    * -*                                                                             * -*  Retour      : -                                                            * -*                                                                             * -*  Remarques   : -                                                            * -*                                                                             * -******************************************************************************/ -#include "gtkdisplaypanel.h" -#include "../gui/panels/history.h" -void gtk_dock_station_add_dockable(GtkDockStation *station, GtkDockable *dockable) -{ -    GtkWidget *widget;                      /* Composant GTK à intégrer    */ -    char *name;                             /* Nom à donner à l'onglet     */ -    char *desc;                             /* Description à y associer    */ -    int max;                                /* Taille maximale des titres  */ -    GtkWidget *label;                       /* Etiquette d'onglet          */ -    GtkNotebook *notebook;                  /* Autre version du composant  */ - - - - - - - -    /* Récupération des éléments utiles */ - -    widget = gtk_dockable_build_widget(dockable); - -    //widget = gtk_button_new_with_label("123"); -    gtk_widget_show(widget); - - -    g_object_set_data(G_OBJECT(widget), "dockable", dockable); - -    name = gtk_dockable_get_name(dockable); -    desc = gtk_dockable_get_desc(dockable); - -    /* Mise en place de la page */ - -    if (!g_generic_config_get_value(get_main_configuration(), MPK_ELLIPSIS_TAB, &max)) -        max = -1; - -    name = ellipsis(name, max); -    label = qck_create_label(NULL, NULL, name); -    free(name); - -    notebook = GTK_NOTEBOOK(station); - -    if (gtk_notebook_get_n_pages(notebook) > 0) -    g_signal_handlers_disconnect_by_func(notebook, -                                         G_CALLBACK(gtk_dock_station_switch_panel), station); - -    gtk_notebook_append_page(notebook, widget, label); - -    gtk_widget_set_tooltip_text(label, desc); - -    free(desc); - -    if (gtk_notebook_get_n_pages(notebook) > 1) -    g_signal_connect(notebook, "switch-page", -                     G_CALLBACK(gtk_dock_station_switch_panel), station); - -    /* Lancement des mises à jour */ - -    if (gtk_notebook_get_n_pages(notebook) > 1) -        gtk_notebook_set_current_page(notebook, -1); - -    //g_signal_emit_by_name(station, "dock-widget", widget); - -} - - -/****************************************************************************** -*                                                                             * -*  Paramètres  : station = plateforme GTK à compléter.                        * -*                widget  = nouvel élément à intégrer.                         * -*                                                                             * -*  Description : Change le contenu de l'onglet courant uniquement.            * -*                                                                             * -*  Retour      : -                                                            * -*                                                                             * -*  Remarques   : -                                                            * -*                                                                             * -******************************************************************************/ - -void gtk_dock_panel_change_active_widget(GtkDockStation *station, GtkWidget *widget) -{ -    GtkNotebook *notebook;                  /* Autre version du composant  */ -    gint index;                             /* Indice de l'onglet actif    */ -    GtkWidget *old;                         /* Ancien composant            */ -    GtkWidget *label;                       /* Etiquette d'onglet          */ -    char *str;                              /* Titre des prochaines fois   */ - -    notebook = GTK_NOTEBOOK(station); - -    index = gtk_notebook_get_current_page(notebook); - -    g_signal_handlers_disconnect_by_func(notebook, -                                         G_CALLBACK(gtk_dock_station_switch_panel), station); - -    old = gtk_notebook_get_nth_page(notebook, index); -    label = gtk_notebook_get_tab_label(notebook, old); - -    g_object_ref(G_OBJECT(label)); -    str = g_object_get_data(G_OBJECT(old), "title"); - -    gtk_notebook_remove_page(notebook, index); -    gtk_notebook_insert_page(notebook, widget, label, index); - -    g_object_unref(G_OBJECT(label)); -    g_object_set_data(G_OBJECT(widget), "title", str); - -    gtk_notebook_set_current_page(notebook, index); - -    g_signal_connect(notebook, "switch-page", -                     G_CALLBACK(gtk_dock_station_switch_panel), station); - -} - - -/****************************************************************************** -*                                                                             * -*  Paramètres  : station = plateforme GTK à compléter.                        * -*                dockable = élément existant à retirer.                       * -*                                                                             * -*  Description : Retire un paquet d'informations de l'affichage centralisé.   * -*                                                                             * -*  Retour      : -                                                            * -*                                                                             * -*  Remarques   : -                                                            * -*                                                                             * -******************************************************************************/ - -void gtk_dock_station_remove_dockable(GtkDockStation *station, GtkDockable *dockable) -{ -    GtkNotebook *notebook;                  /* Autre version du composant  */ -    GtkWidget *widget;                      /* Composant GTK à retirer     */ -    gint index;                             /* Indice de l'onglet visé     */ - -    notebook = GTK_NOTEBOOK(station); - -    widget = gtk_dockable_decompose(dockable, NULL); - -    index = gtk_notebook_page_num(notebook, widget); - -    gtk_notebook_remove_page(notebook, index); - -} - - -/****************************************************************************** -*                                                                             * -*  Paramètres  : button  = bouton à l'origine de la procédure.                * -*                station = station d'accueil pour différents composants.      * -*                                                                             * -*  Description : Révèle ou cache la zone de recherches.                       * -*                                                                             * -*  Retour      : -                                                            * -*                                                                             * -*  Remarques   : -                                                            * -*                                                                             * -******************************************************************************/ - -static void on_toggle_revealer(GtkToggleButton *button, GtkDockStation *station) -{ -    GtkNotebook *notebook;                  /* Autre version du composant  */ -    gint index;                             /* Indice de l'onglet courant  */ -    GtkWidget *widget;                      /* Panneau concerné            */ -    GtkDockable *dockable;                  /* Elément encapsulé           */ - -    notebook = GTK_NOTEBOOK(station); - -    index = gtk_notebook_get_current_page(notebook); -    widget = gtk_notebook_get_nth_page(notebook, index); - -    dockable = GTK_DOCKABLE(g_object_get_data(G_OBJECT(widget), "dockable")); - -    gtk_dockable_toggle_revealer(dockable, widget, gtk_toggle_button_get_active(button)); - -} - - -/****************************************************************************** -*                                                                             * -*  Paramètres  : button  = bouton à l'origine de la procédure.                * -*                station = station d'accueil pour différents composants.      * -*                                                                             * -*  Description : Demande l'apparition d'un menu pour inclure des composants.  * -*                                                                             * -*  Retour      : -                                                            * -*                                                                             * -*  Remarques   : -                                                            * -*                                                                             * -******************************************************************************/ - -static void on_click_for_menu(GtkButton *button, GtkDockStation *station) -{ -    g_signal_emit_by_name(station, "menu-requested", button); - -} - - -/****************************************************************************** -*                                                                             * -*  Paramètres  : button  = bouton à l'origine de la procédure.                * -*                station = station d'accueil pour différents composants.      * -*                                                                             * -*  Description : Demande la disparition du composant courant.                 * -*                                                                             * -*  Retour      : -                                                            * -*                                                                             * -*  Remarques   : -                                                            * -*                                                                             * -******************************************************************************/ - -static void on_click_for_close(GtkButton *button, GtkDockStation *station) -{ -    g_signal_emit_by_name(station, "close-requested", button); - -} diff --git a/src/gtkext/gtkstatusstack.c b/src/gtkext/gtkstatusstack.c deleted file mode 100644 index fe4e4d5..0000000 --- a/src/gtkext/gtkstatusstack.c +++ /dev/null @@ -1,1121 +0,0 @@ - -/* Chrysalide - Outil d'analyse de fichiers binaires - * gtkstatusstack.c - empilement d'informations de statut - * - * Copyright (C) 2015-2019 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 "gtkstatusstack.h" - - -#include <assert.h> -#include <inttypes.h> -#include <malloc.h> -#include <string.h> - - -#include <i18n.h> - - -#include "easygtk.h" -#include "../gui/agroup.h" -#include "../format/format.h" - - - -/* ------------------------- GESTION EXTERIEURE DE LA BARRE ------------------------- */ - - -/* Navigation au sein d'assemblage */ -typedef struct _assembly_info assembly_info; - -/* Mémorisation des progressions */ -typedef struct _progress_info progress_info; - - -/* Abstration d'une gestion de barre de statut (instance) */ -struct _GtkStatusStack -{ -    GtkBox parent;                          /* A laisser en premier        */ - -    GtkStack *main;                         /* Pile d'informations associée*/ - -    GSourceFunc def_source;                 /* Appel en fin d'activité     */ - -    GObject *asm_ref;                       /* Espace de référencements #1 */ -    assembly_info *asm_info;                /* Informations courantes #1   */ - -    GObject *prog_ref;                      /* Espace de référencements #2 */ -    progress_info *prog_info;               /* Informations courantes #2   */ - -}; - -/* Abstration d'une gestion de barre de statut (classe) */ -struct _GtkStatusStackClass -{ -    GtkBoxClass parent;                     /* A laisser en premier        */ - -}; - - -/* Initialise la classe des barres de statut améliorées. */ -static void gtk_status_stack_class_init(GtkStatusStackClass *); - -/* Initialise une instance de barre de statut améliorée. */ -static void gtk_status_stack_init(GtkStatusStack *); - -/* Supprime toutes les références externes. */ -static void gtk_status_stack_dispose(GtkStatusStack *); - -/* Procède à la libération totale de la mémoire. */ -static void gtk_status_stack_finalize(GtkStatusStack *); - - - -/* -------------------- STATUT DES INFORMATIONS DE DESASSEMBLAGE -------------------- */ - - -/* Navigation au sein d'assemblage */ -struct _assembly_info -{ -    bool reset;                             /* Réinitialisation            */ - -    mrange_t current;                       /* Emplacement correspondant   */ - -    char *segment;                          /* Segment d'appartenance      */ - -    VMPA_BUFFER(phys);                      /* Localisation physique       */ -    VMPA_BUFFER(virt);                      /* Localisation virtuelle      */ - -    char *symbol;                           /* Eventuel symbole concerné   */ - -    const char *encoding;                   /* Encodage de l'instruction   */ -    phys_t size;                            /* Taille de l'instruction     */ - -}; - - -/* Supprime l'empreinte mémoire d'informations d'assemblage. */ -static void reset_assembly_info(assembly_info *); - -/* Construit une barre d'état pour language d'assemblage. */ -static GtkWidget *build_assembly_status_stack(GtkStatusStack *); - -/* Réagit à un redimensionnement de la barre de désassemblage. */ -static void on_size_allocate_for_asm_status(GtkWidget *, GdkRectangle *, GObject *); - -/* Réagit à un clic sur l'icône de zoom. */ -static void on_zoom_icon_press(GtkEntry *, GtkEntryIconPosition, GdkEventButton *, GtkStatusStack *); - -/* S'assure de l'affichage à jour de la partie "assemblage". */ -static gboolean gtk_status_stack_show_current_location(GtkStatusStack *); - - - -/* -------------------------- STATUT DES SUIVIS D'ACTIVITE -------------------------- */ - - -/* Informations de progression */ -typedef struct _progress_status -{ -    activity_id_t id;                       /* Identifiant unique          */ - -    char *message;                          /* Indication à faire valoir   */ - -    unsigned long current;                  /* Position courante           */ -    unsigned long max;                      /* Couverture à parcourir      */ - -    double last_updated;                    /* Dernière valeur poussée     */ - -} progress_status; - -/* Mémorisation des progressions */ -struct _progress_info -{ -    activity_id_t generator;                /* Générateur de séquence      */ - -    progress_status *statuses;              /* Statuts de progression      */ -    size_t count;                           /* Nombre de ces statuts       */ -    GMutex access;                          /* Accès à la pile             */ - -    guint tag;                              /* Identifiant de mise à jour  */ - -}; - - -#define PROGRESS_SIZE 200 - - -/* Supprime l'empreinte mémoire d'informations d'activité. */ -static void reset_progress_info(progress_info *); - -/* Construit une barre d'état pour un suivi d'activité. */ -static GtkWidget *build_progress_status_stack(GtkStatusStack *); - -/* S'assure de l'affichage à jour de la partie "activité". */ -static gboolean gtk_status_stack_show_current_activity(GtkStatusStack *); - - - -/* ---------------------------------------------------------------------------------- */ -/*                           GESTION EXTERIEURE DE LA BARRE                           */ -/* ---------------------------------------------------------------------------------- */ - - -/* Détermine le type de la barre de statut améliorée. */ -G_DEFINE_TYPE(GtkStatusStack, gtk_status_stack, GTK_TYPE_BOX) - - -/****************************************************************************** -*                                                                             * -*  Paramètres  : klass = classe GTK à initialiser.                            * -*                                                                             * -*  Description : Initialise la classe des barres de statut améliorées.        * -*                                                                             * -*  Retour      : -                                                            * -*                                                                             * -*  Remarques   : -                                                            * -*                                                                             * -******************************************************************************/ - -static void gtk_status_stack_class_init(GtkStatusStackClass *klass) -{ -    GObjectClass *object;                   /* Autre version de la classe  */ - -    object = G_OBJECT_CLASS(klass); - -    object->dispose = (GObjectFinalizeFunc/* ! */)gtk_status_stack_dispose; -    object->finalize = (GObjectFinalizeFunc)gtk_status_stack_finalize; - -} - - -/****************************************************************************** -*                                                                             * -*  Paramètres  : stack = instance GTK à initialiser.                          * -*                                                                             * -*  Description : Initialise une instance de barre de statut améliorée.        * -*                                                                             * -*  Retour      : -                                                            * -*                                                                             * -*  Remarques   : -                                                            * -*                                                                             * -******************************************************************************/ - -static void gtk_status_stack_init(GtkStatusStack *stack) -{ -    GtkWidget *layer;                       /* Couche à empiler            */ - -    gtk_orientable_set_orientation(GTK_ORIENTABLE(stack), GTK_ORIENTATION_HORIZONTAL); - -    stack->main = GTK_STACK(gtk_stack_new()); -    gtk_widget_show(GTK_WIDGET(stack->main)); -    gtk_box_pack_start(GTK_BOX(stack), GTK_WIDGET(stack->main), TRUE, TRUE, 8); - -    stack->def_source = (GSourceFunc)gtk_status_stack_show_current_location; - -    layer = build_assembly_status_stack(stack); -    gtk_stack_add_named(stack->main, layer, "asm_info"); - -    stack->asm_ref = G_OBJECT(layer); -    stack->asm_info = (assembly_info *)calloc(1, sizeof(assembly_info)); - -    reset_assembly_info(stack->asm_info); - -    layer = build_progress_status_stack(stack); -    gtk_stack_add_named(stack->main, layer, "prog_info"); - -    stack->prog_ref = G_OBJECT(layer); -    stack->prog_info = (progress_info *)calloc(1, sizeof(progress_info)); - -    reset_progress_info(stack->prog_info); - -    gtk_status_stack_reset_current_location(stack); - -} - - -/****************************************************************************** -*                                                                             * -*  Paramètres  : view = instance d'objet GLib à traiter.                      * -*                                                                             * -*  Description : Supprime toutes les références externes.                     * -*                                                                             * -*  Retour      : -                                                            * -*                                                                             * -*  Remarques   : -                                                            * -*                                                                             * -******************************************************************************/ - -static void gtk_status_stack_dispose(GtkStatusStack *stack) -{ -    G_OBJECT_CLASS(gtk_status_stack_parent_class)->dispose(G_OBJECT(stack)); - -} - - -/****************************************************************************** -*                                                                             * -*  Paramètres  : view = instance d'objet GLib à traiter.                      * -*                                                                             * -*  Description : Procède à la libération totale de la mémoire.                * -*                                                                             * -*  Retour      : -                                                            * -*                                                                             * -*  Remarques   : -                                                            * -*                                                                             * -******************************************************************************/ - -static void gtk_status_stack_finalize(GtkStatusStack *stack) -{ -    reset_assembly_info(stack->asm_info); -    free(stack->asm_info); - -    reset_progress_info(stack->prog_info); -    free(stack->prog_info); - -    G_OBJECT_CLASS(gtk_status_stack_parent_class)->finalize(G_OBJECT(stack)); - -} - - -/****************************************************************************** -*                                                                             * -*  Paramètres  : -                                                            * -*                                                                             * -*  Description : Crée une nouvelle instance de barre de statut.               * -*                                                                             * -*  Retour      : Composant GTK mis en place.                                  * -*                                                                             * -*  Remarques   : -                                                            * -*                                                                             * -******************************************************************************/ - -GtkStatusStack *gtk_status_stack_new(void) -{ -    GtkStatusStack *result;                 /* Instance à retourner        */ - -    result = g_object_new(GTK_TYPE_STATUS_STACK, NULL); - -    return result; - -} - - - -/* ---------------------------------------------------------------------------------- */ -/*                      STATUT DES INFORMATIONS DE DESASSEMBLAGE                      */ -/* ---------------------------------------------------------------------------------- */ - - -/****************************************************************************** -*                                                                             * -*  Paramètres  : info = informations à réinitialiser.                         * -*                                                                             * -*  Description : Supprime l'empreinte mémoire d'informations d'assemblage.    * -*                                                                             * -*  Retour      : -                                                            * -*                                                                             * -*  Remarques   : -                                                            * -*                                                                             * -******************************************************************************/ - -static void reset_assembly_info(assembly_info *info) -{ -    info->reset = true; - -    if (info->segment != NULL) -    { -        free(info->segment); -        info->segment = NULL; -    } - -    if (info->symbol != NULL) -    { -        free(info->symbol); -        info->symbol = NULL; -    } - -} - - -/****************************************************************************** -*                                                                             * -*  Paramètres  : stack = composant global en cours de construction.           * -*                                                                             * -*  Description : Construit une barre d'état pour language d'assemblage.       * -*                                                                             * -*  Retour      : Composant GTK mis en place.                                  * -*                                                                             * -*  Remarques   : -                                                            * -*                                                                             * -******************************************************************************/ - -static GtkWidget *build_assembly_status_stack(GtkStatusStack *stack) -{ -    GtkWidget *result;                      /* Support à retourner         */ -    GObject *ref;                           /* Espace de référencements    */ -    GtkWidget *hbox;                        /* Sous-division horizontale   */ -    GtkWidget *label;                       /* Etiquette pour impression   */ -    GtkWidget *zoom;                        /* Sélection du zoom courant   */ - -    result = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0); -    gtk_widget_show(result); - -    ref = G_OBJECT(result); - -    g_signal_connect(result, "size-allocate", G_CALLBACK(on_size_allocate_for_asm_status), ref); - -    /* Première partie : navigation */ - -    hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 16); -    gtk_widget_show(hbox); -    gtk_box_pack_start(GTK_BOX(result), hbox, TRUE, TRUE, 8); - -    label = qck_create_label(ref, "segment", NULL); -    gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0); - -    label = qck_create_label(ref, "phys", NULL); -    gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0); - -    label = qck_create_label(ref, "virt", NULL); -    gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0); - -    label = qck_create_label(ref, "offset", NULL); -    gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0); - -    /* Seconde partie : architecture */ - -    hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 8); -    g_object_set_data(ref, "arch_box", hbox); -    gtk_widget_show(hbox); -    gtk_box_pack_start(GTK_BOX(result), hbox, FALSE, TRUE, 8); - -    label = qck_create_label(ref, "arch", NULL); -    gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0); - -    label = qck_create_label(ref, "size", NULL); -    gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0); - -    /* Troisième partie : affichage */ - -    hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 8); -    gtk_widget_show(hbox); -    gtk_box_pack_start(GTK_BOX(result), hbox, FALSE, FALSE, 8); - -    zoom = qck_create_entry(ref, "zoom", "100%"); -    gtk_entry_set_icon_from_icon_name(GTK_ENTRY(zoom), GTK_ENTRY_ICON_SECONDARY, "go-up-symbolic"); - -    g_signal_connect(zoom, "focus-in-event", G_CALLBACK(track_focus_change_in_text_area), NULL); -    g_signal_connect(zoom, "focus-out-event", G_CALLBACK(track_focus_change_in_text_area), NULL); -    g_signal_connect(zoom, "icon-press", G_CALLBACK(on_zoom_icon_press), stack); - -    gtk_box_pack_start(GTK_BOX(hbox), zoom, FALSE, TRUE, 0); - -    return result; - -} - - -/****************************************************************************** -*                                                                             * -*  Paramètres  : widget     = composant graphique qui vient d'évoluer.        * -*                allocation = espace réservé pour le composant visé.          * -*                ref        = espace de référencement global.                 * -*                                                                             * -*  Description : Réagit à un redimensionnement de la barre de désassemblage.  * -*                                                                             * -*  Retour      : -                                                            * -*                                                                             * -*  Remarques   : -                                                            * -*                                                                             * -******************************************************************************/ - -static void on_size_allocate_for_asm_status(GtkWidget *widget, GdkRectangle *allocation, GObject *ref) -{ -    GtkWidget *hbox;                        /* Sous-division horizontale   */ - -    hbox = GTK_WIDGET(g_object_get_data(ref, "arch_box")); - -    gtk_widget_set_size_request(hbox, (allocation->width * 40) / 100, -1); - -    /** -     * On intervient après que le containeur soit passé collecter les tailles -     * de ses enfants lors de son redimensionnement. -     * -     * Donc on force un prise en compte des changements. -     */ -    gtk_container_check_resize(GTK_CONTAINER(widget)); - -} - - -/****************************************************************************** -*                                                                             * -*  Paramètres  : entry    = zone de texte visée par la procédure.             * -*                icon_pos = position de l'image associée à l'entrée.          * -*                event    = informations liées à l'événement.                 * -*                stack    = composant graphique de gestion des statuts.       * -*                                                                             * -*  Description : Réagit à un clic sur l'icône de zoom.                        * -*                                                                             * -*  Retour      : -                                                            * -*                                                                             * -*  Remarques   : -                                                            * -*                                                                             * -******************************************************************************/ - -static void on_zoom_icon_press(GtkEntry *entry, GtkEntryIconPosition icon_pos, GdkEventButton *event, GtkStatusStack *stack) -{ -    GtkWidget *popup;                       /* Popup à faire surgir        */ -    GdkRectangle rect;                      /* Zone précise à cibler       */ - -    if (event->button != GDK_BUTTON_PRIMARY) -        return; - -    popup = gtk_popover_new(GTK_WIDGET(entry)); - -    gtk_entry_get_icon_area(entry, GTK_ENTRY_ICON_SECONDARY, &rect); -    gtk_popover_set_pointing_to(GTK_POPOVER(popup), &rect); - -    gtk_widget_show(popup); - -} - - -/****************************************************************************** -*                                                                             * -*  Paramètres  : stack    = barre de statut à actualiser.                     * -*                range    = emplacement à mettre en valeur.                   * -*                segment  = zone de binaire d'appartenance.                   * -*                symbol   = éventuelle position par rapport à un symbole.     * -*                encoding = encodage d'une éventuelle instruction ou NULL.    * -*                                                                             * -*  Description : Actualise les informations liées une position d'assemblage.  * -*                                                                             * -*  Retour      : -                                                            * -*                                                                             * -*  Remarques   : -                                                            * -*                                                                             * -******************************************************************************/ - -void gtk_status_stack_update_current_location(GtkStatusStack *stack, const mrange_t *range, const char *segment, const char *symbol, const char *encoding) -{ -    assembly_info *info;                    /* Informations à constituer   */ -    const vmpa2t *addr;                     /* Localisation de départ      */ -    phys_t size;                            /* Taille de l'emplacement     */ - -    info = stack->asm_info; - -    /* Bascule vers une zone courante nouvelle ? */ - -    addr = get_mrange_addr(range); -    size = get_mrange_length(range); - -    if (cmp_mrange(&info->current, range) == 0 -        && info->size == size -        && info->encoding == encoding) -        goto useless; - -    /* Réinitialisation */ - -    reset_assembly_info(info); - -    copy_mrange(&info->current, range); - -    /* Zone d'appartenance */ - -    info->segment = strdup(segment); - -    /* Adresses de base */ - -    vmpa2_phys_to_string(addr, MDS_UNDEFINED, info->phys, NULL); - -    vmpa2_virt_to_string(addr, MDS_UNDEFINED, info->virt, NULL); - -    info->encoding = encoding; -    info->size = size; - -    /* Symbole concerné */ - -    if (symbol != NULL) -        info->symbol = strdup(symbol); - -    /* Nettoyage et conclusion */ - -    info->reset = false; - -    gtk_status_stack_show_current_location(stack); - - useless: - -    ; - -} - - -/****************************************************************************** -*                                                                             * -*  Paramètres  : stack = barre de statut à actualiser.                        * -*                                                                             * -*  Description : Réinitialise les informations associées une position.        * -*                                                                             * -*  Retour      : -                                                            * -*                                                                             * -*  Remarques   : -                                                            * -*                                                                             * -******************************************************************************/ - -void gtk_status_stack_reset_current_location(GtkStatusStack *stack) -{ -    assembly_info *info;                    /* Informations à constituer   */ - -    info = stack->asm_info; - -    reset_assembly_info(info); - -    gtk_status_stack_show_current_location(stack); - -} - - -/****************************************************************************** -*                                                                             * -*  Paramètres  : stack = pile de statuts à manipuler.                         * -*                                                                             * -*  Description : S'assure de l'affichage à jour de la partie "assemblage".    * -*                                                                             * -*  Retour      : G_SOURCE_REMOVE pour une exécution unique.                   * -*                                                                             * -*  Remarques   : -                                                            * -*                                                                             * -******************************************************************************/ - -static gboolean gtk_status_stack_show_current_location(GtkStatusStack *stack) -{ -    GObject *ref;                           /* Espace de référencements    */ -    assembly_info *info;                    /* Informations à consulter    */ -    GtkLabel *label;                        /* Etiquette à actualiser      */ -    char raw_pos[6 + VMPA_MAX_LEN + 1];     /* Formatage final en direct   */ -    char *content;                          /* Contenu dynamique           */ - -    stack->def_source = (GSourceFunc)gtk_status_stack_show_current_location; - -    gtk_stack_set_visible_child_name(stack->main, "asm_info"); - -    ref = stack->asm_ref; -    info = stack->asm_info; - -    /* Première partie : navigation */ - -    if (info->reset) -    { -        label = GTK_LABEL(g_object_get_data(ref, "segment")); -        gtk_label_set_text(label, NULL); - -        label = GTK_LABEL(g_object_get_data(ref, "phys")); -        gtk_label_set_text(label, NULL); - -        label = GTK_LABEL(g_object_get_data(ref, "virt")); -        gtk_label_set_text(label, NULL); - -        label = GTK_LABEL(g_object_get_data(ref, "offset")); -        gtk_label_set_text(label, NULL); - -    } -    else -    { -        label = GTK_LABEL(g_object_get_data(ref, "segment")); -        gtk_label_set_text(label, info->segment); - -        snprintf(raw_pos, sizeof(raw_pos), "phys: %s", info->phys); - -        label = GTK_LABEL(g_object_get_data(ref, "phys")); -        gtk_label_set_text(label, raw_pos); - -        snprintf(raw_pos, sizeof(raw_pos), "virt: %s", info->virt); - -        label = GTK_LABEL(g_object_get_data(ref, "virt")); -        gtk_label_set_text(label, raw_pos); - -        label = GTK_LABEL(g_object_get_data(ref, "offset")); -        gtk_label_set_text(label, info->symbol != NULL ? info->symbol : ""); - -    } - -    /* Seconde partie : architecture */ - -    if (info->reset || info->encoding == NULL || info->size == VMPA_NO_PHYSICAL) -    { -        label = GTK_LABEL(g_object_get_data(ref, "arch")); -        gtk_label_set_text(label, NULL); - -        label = GTK_LABEL(g_object_get_data(ref, "size")); -        gtk_label_set_text(label, NULL); - -    } -    else -    { -        label = GTK_LABEL(g_object_get_data(ref, "arch")); -        gtk_label_set_text(label, info->encoding); - -        if (info->size > 1) -            asprintf(&content, "%" PRIu64 " %s", (uint64_t)info->size, _("bytes")); -        else -            asprintf(&content, "%" PRIu64 " %s", (uint64_t)info->size, _("byte")); - -        label = GTK_LABEL(g_object_get_data(ref, "size")); -        gtk_label_set_text(label, content); - -        free(content); - -    } - -    return G_SOURCE_REMOVE; - -} - - - -/* ---------------------------------------------------------------------------------- */ -/*                            STATUT DES SUIVIS D'ACTIVITE                            */ -/* ---------------------------------------------------------------------------------- */ - - -/****************************************************************************** -*                                                                             * -*  Paramètres  : info = informations à réinitialiser.                         * -*                                                                             * -*  Description : Supprime l'empreinte mémoire d'informations d'activité.      * -*                                                                             * -*  Retour      : -                                                            * -*                                                                             * -*  Remarques   : -                                                            * -*                                                                             * -******************************************************************************/ - -static void reset_progress_info(progress_info *info) -{ -    size_t i;                               /* Boucle de parcours          */ - -    if (info->tag != 0) -        g_source_remove(info->tag); - -    info->tag = 0; - -    for (i = 0; i < info->count; i++) -    { -        if (info->statuses[i].message != NULL) -            free(info->statuses[i].message); -    } - -    if (info->statuses != NULL) -    { -        free(info->statuses); -        info->statuses = NULL; -    } - -    info->count = 0; - -    g_mutex_init(&info->access); - -} - - -/****************************************************************************** -*                                                                             * -*  Paramètres  : stack = composant global en cours de construction.           * -*                                                                             * -*  Description : Construit une barre d'état pour un suivi d'activité.         * -*                                                                             * -*  Retour      : Composant GTK mis en place.                                  * -*                                                                             * -*  Remarques   : -                                                            * -*                                                                             * -******************************************************************************/ - -static GtkWidget *build_progress_status_stack(GtkStatusStack *stack) -{ -    GtkWidget *result;                      /* Support à retourner         */ -    GObject *ref;                           /* Espace de référencements    */ -    GtkWidget *progress;                    /* Barre de progression        */ -    GtkWidget *label;                       /* Désignation de l'activité   */ - -    result = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0); -    gtk_widget_show(result); - -    ref = G_OBJECT(result); - -    progress = gtk_progress_bar_new(); -    g_object_set_data(ref, "progress", progress); -    gtk_widget_set_size_request(progress, PROGRESS_SIZE, -1); -    gtk_widget_set_valign(progress, GTK_ALIGN_CENTER); -    gtk_widget_show(progress); -    gtk_box_pack_start(GTK_BOX(result), progress, FALSE, TRUE, 8); - -    label = qck_create_label(ref, "message", NULL); -    gtk_box_pack_start(GTK_BOX(result), label, TRUE, TRUE, 0); - -    return result; - -} - - -/****************************************************************************** -*                                                                             * -*  Paramètres  : stack = barre de statut à actualiser.                        * -*                msg   = nouveau message de statut à copier.                  * -*                max   = taille de la plage à parcourir.                      * -*                                                                             * -*  Description : Démarre le suivi d'une nouvelle activité.                    * -*                                                                             * -*  Retour      : -                                                            * -*                                                                             * -*  Remarques   : -                                                            * -*                                                                             * -******************************************************************************/ - -activity_id_t gtk_status_stack_add_activity(GtkStatusStack *stack, const char *msg, unsigned long max) -{ -    activity_id_t result;                   /* Numéro unique à renvoyer    */ -    progress_info *info;                    /* Informations à consulter    */ -    size_t new;                             /* Indice de l'activité créée  */ - -    if (stack == NULL) return NO_ACTIVITY_ID; - -    info = stack->prog_info; - -    g_mutex_lock(&info->access); - -    result = ++info->generator; - -    new = info->count++; - -    info->statuses = (progress_status *)realloc(info->statuses, -                                                info->count * sizeof(progress_status)); - -    info->statuses[new].id = result; - -    /* Intitulé */ - -    if (msg == NULL) -        info->statuses[new].message = NULL; -    else -        info->statuses[new].message = strdup(msg); - -    /* Valeur */ - -    info->statuses[new].current = 0; -    info->statuses[new].max = max; -    info->statuses[new].last_updated = 0; - -    /* Actualisation */ - -    if (info->tag != 0) -        g_source_remove(info->tag); - -    info->tag = g_idle_add((GSourceFunc)gtk_status_stack_show_current_activity, stack); - -    g_mutex_unlock(&info->access); - -    return result; - -} - - -/****************************************************************************** -*                                                                             * -*  Paramètres  : stack = barre de statut à actualiser.                        * -*                id    = identifiant de l'activité à cibler.                  * -*                extra = nouvelle échéance supplémentaire des traitements.    * -*                                                                             * -*  Description : Etend la portée des travaux d'une nouvelle activité.         * -*                                                                             * -*  Retour      : -                                                            * -*                                                                             * -*  Remarques   : -                                                            * -*                                                                             * -******************************************************************************/ - -void gtk_status_stack_extend_activity(GtkStatusStack *stack, activity_id_t id, unsigned long extra) -{ -    progress_info *info;                    /* Informations à consulter    */ -    size_t i;                               /* Boucle de parcours          */ - -    if (stack == NULL) return; - -    info = stack->prog_info; - -    g_mutex_lock(&info->access); - -    for (i = 0; i < info->count; i++) -        if (info->statuses[i].id == id) -            break; - -    assert(i < info->count); - -    info->statuses[i].max += extra; - -    g_mutex_unlock(&info->access); - -} - - -/****************************************************************************** -*                                                                             * -*  Paramètres  : stack = barre de statut à actualiser.                        * -*                id    = identifiant de l'activité à cibler.                  * -*                msg   = nouveau message de statut à copier.                  * -*                                                                             * -*  Description : Actualise les informations concernant une activité.          * -*                                                                             * -*  Retour      : -                                                            * -*                                                                             * -*  Remarques   : -                                                            * -*                                                                             * -******************************************************************************/ - -void gtk_status_stack_update_activity(GtkStatusStack *stack, activity_id_t id, const char *msg) -{ -    progress_info *info;                    /* Informations à consulter    */ -    size_t i;                               /* Boucle de parcours          */ -    bool msg_changed;                       /* Changement d'intitulé       */ - -    if (stack == NULL) return; - -    info = stack->prog_info; - -    g_mutex_lock(&info->access); - -    for (i = 0; i < info->count; i++) -        if (info->statuses[i].id == id) -            break; - -    assert(i < info->count); - -    /* Intitulé */ - -    if (info->statuses[i].message != NULL) -    { -        if (msg == NULL) -            msg_changed = true; -        else -            msg_changed = (strcmp(info->statuses[i].message, msg) != 0); - -        free(info->statuses[i].message); - -    } -    else -        msg_changed = (msg != NULL); - -    if (msg == NULL) -        info->statuses[i].message = NULL; -    else -        info->statuses[i].message = strdup(msg); - -    /* On n'actualise que le sommet de la pile */ - -    if ((i + 1) == info->count && msg_changed) -    { -        if (info->tag != 0) -            g_source_remove(info->tag); - -        info->tag = g_idle_add((GSourceFunc)gtk_status_stack_show_current_activity, stack); - -    } - -    g_mutex_unlock(&info->access); - -} - - -/****************************************************************************** -*                                                                             * -*  Paramètres  : stack = barre de statut à actualiser.                        * -*                id    = identifiant de l'activité à cibler.                  * -*                inc   = nouvelle valeur pour une progression donnée.         * -*                                                                             * -*  Description : Actualise la progression d'une activité.                     * -*                                                                             * -*  Retour      : -                                                            * -*                                                                             * -*  Remarques   : -                                                            * -*                                                                             * -******************************************************************************/ - -void gtk_status_stack_update_activity_value(GtkStatusStack *stack, activity_id_t id, unsigned long inc) -{ -    progress_info *info;                    /* Informations à consulter    */ -    size_t i;                               /* Boucle de parcours          */ -    progress_status *status;                /* Raccourci de confort        */ -    double new;                             /* Nouvelle progression        */ - -    if (stack == NULL) return; - -    info = stack->prog_info; - -    g_mutex_lock(&info->access); - -    for (i = 0; i < info->count; i++) -        if (info->statuses[i].id == id) -            break; - -    assert(i < info->count); - -    status = &info->statuses[i]; - -    /* Valeur */ - -    status->current += inc; - -    new = (status->current * 1.0) / status->max; - -    /* On n'actualise que le sommet de la pile */ - -    if ((i + 1) == info->count && (new - status->last_updated) > (1.0 / PROGRESS_SIZE)) -    { -        status->last_updated = new; - -        if (info->tag != 0) -            g_source_remove(info->tag); - -        info->tag = g_idle_add((GSourceFunc)gtk_status_stack_show_current_activity, stack); - -    } - -    g_mutex_unlock(&info->access); - -} - - -/****************************************************************************** -*                                                                             * -*  Paramètres  : stack = barre de statut à actualiser.                        * -*                                                                             * -*  Description : Met fin au suivi d'une activité donnée.                      * -*                                                                             * -*  Retour      : -                                                            * -*                                                                             * -*  Remarques   : -                                                            * -*                                                                             * -******************************************************************************/ - -void gtk_status_stack_remove_activity(GtkStatusStack *stack, activity_id_t id) -{ -    progress_info *info;                    /* Informations à consulter    */ -    size_t i;                               /* Boucle de parcours          */ - -    if (stack == NULL) return; - -    info = stack->prog_info; - -    g_mutex_lock(&info->access); - -    for (i = 0; i < info->count; i++) -        if (info->statuses[i].id == id) -            break; - -    assert(i < info->count); - -    if (info->tag != 0) -        g_source_remove(info->tag); - -    if (info->statuses[i].message != NULL) -        free(info->statuses[i].message); - -    if (info->count == 1) -    { -        free(info->statuses); -        info->statuses = NULL; -    } -    else -    { -        memmove(&info->statuses[i], &info->statuses[i + 1], -                (info->count - i - 1) * sizeof(progress_status)); - -        info->statuses = (progress_status *)realloc(info->statuses, -                                                    (info->count - 1) * sizeof(progress_status)); - -    } - -    info->count--; - -    if (info->count == 0) -    { -        info->tag = 0; -        g_idle_add(stack->def_source, stack); -    } -    else -        info->tag = g_idle_add((GSourceFunc)gtk_status_stack_show_current_activity, stack); - -    g_mutex_unlock(&info->access); - -} - - -/****************************************************************************** -*                                                                             * -*  Paramètres  : stack = pile de statuts à manipuler.                         * -*                                                                             * -*  Description : S'assure de l'affichage à jour de la partie "activité".      * -*                                                                             * -*  Retour      : G_SOURCE_REMOVE pour une exécution unique.                   * -*                                                                             * -*  Remarques   : -                                                            * -*                                                                             * -******************************************************************************/ - -static gboolean gtk_status_stack_show_current_activity(GtkStatusStack *stack) -{ -    GObject *ref;                           /* Espace de référencements    */ -    progress_info *info;                    /* Informations à consulter    */ -    progress_status *last;                  /* Dernier statut à traiter    */ -    GtkProgressBar *progress;               /* Barre de progression        */ -    GtkLabel *label;                        /* Désignation de l'activité   */ - -    if (!g_source_is_destroyed(g_main_current_source())) -    { -        gtk_stack_set_visible_child_name(stack->main, "prog_info"); - -        ref = stack->prog_ref; -        info = stack->prog_info; - -        g_mutex_lock(&info->access); - -        info->tag = 0; - -        if (info->count > 0) -        { -            last = &info->statuses[info->count - 1]; - -            progress = GTK_PROGRESS_BAR(g_object_get_data(ref, "progress")); -            gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(progress), (last->current * 1.0) / last->max); - -            label = GTK_LABEL(g_object_get_data(ref, "message")); -            gtk_label_set_text(label, last->message); - -        } - -        g_mutex_unlock(&info->access); - -    } - -    return G_SOURCE_REMOVE; - -} diff --git a/src/gtkext/helpers.h b/src/gtkext/helpers.h new file mode 100644 index 0000000..3f8b3cd --- /dev/null +++ b/src/gtkext/helpers.h @@ -0,0 +1,43 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * helpers.h - prototypes pour la simplification des interactions de base avec GTK + * + * Copyright (C) 2024 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 _GTKEXT_HELPERS_H +#define _GTKEXT_HELPERS_H + + +#include <assert.h> +#include <glib-object.h> + + + +/** + * Facilités de transmission de paramètres pour les fonctions de type + * gtk_widget_class_bind_template_callback_full() et gtk_builder_cscope_add_callback_symbol(). + */ + +#define BUILDER_CB(cb) \ +    #cb, G_CALLBACK(cb) + + + +#endif  /* _GTKEXT_HELPERS_H */ diff --git a/src/gtkext/hexview.c b/src/gtkext/hexview.c index 7363079..95b592e 100644 --- a/src/gtkext/hexview.c +++ b/src/gtkext/hexview.c @@ -37,17 +37,33 @@  /* ------------------------- BASES D'UN COMPOSANT GRAPHIQUE ------------------------- */ -/* Procède à l'initialisation de l'afficheur générique. */ +/* Liste des propriétés */ + +typedef enum _HexViewProperty { + +    PROP_0,                                 /* Réservé                     */ + +    PROP_SHOW_OFFSETS,                      /* Affichage des positions     */ +    PROP_CONTENT,                           /* Contenu binaire affiché     */ + +    N_PROPERTIES + +} HexViewProperty; + +static GParamSpec *_hex_view_properties[N_PROPERTIES] = { NULL, }; + + +/* Initialise la classe des afficheurs de tampons bruts. */  static void gtk_hex_view_class_init(GtkHexViewClass *); -/* Procède à l'initialisation de l'afficheur générique. */ +/* Initialise une instance d'afficheur de tampons bruts. */  static void gtk_hex_view_init(GtkHexView *);  /* Supprime toutes les références externes. */ -static void gtk_hex_view_dispose(GtkHexView *); +static void gtk_hex_view_dispose(GObject *);  /* Procède à la libération totale de la mémoire. */ -static void gtk_hex_view_finalize(GtkHexView *); +static void gtk_hex_view_finalize(GObject *);  /* Procède à l'actualisation de l'affichage d'un sous-composant. */  static void gtk_hex_view_dispatch_sub_snapshot(GtkWidget *, GtkSnapshot *, GtkWidget *); @@ -57,14 +73,14 @@ static void gtk_hex_view_populate_cache(GtkHexView *); -void demo_snapshot (GtkWidget *widget, GtkSnapshot *snapshot, GtkWidget *parent); - - - +/* --------------------- IMPLEMENTATION DES FONCTIONS DE CLASSE --------------------- */ -/* --------------------- IMPLEMENTATION DES FONCTIONS DE CLASSE --------------------- */ +/* Met à jour une propriété d'instance GObject. */ +static void gtk_hex_view_set_property(GObject *, guint, const GValue *, GParamSpec *); +/* Fournit la valeur d'une propriété d'instance GObject. */ +static void gtk_hex_view_get_property(GObject *, guint, GValue *, GParamSpec *);  /* Prend acte de la taille allouée au composant d'affichage. */  static void gtk_hex_view_size_allocate(GtkWidget *, int, int, int); @@ -90,7 +106,7 @@ G_DEFINE_TYPE(GtkHexView, gtk_hex_view, GTK_TYPE_BUFFER_VIEW);  *                                                                             *  *  Paramètres  : class = classe GTK à initialiser.                            *  *                                                                             * -*  Description : Procède à l'initialisation de l'afficheur générique.         * +*  Description : Initialise la classe des afficheurs de tampons bruts.        *  *                                                                             *  *  Retour      : -                                                            *  *                                                                             * @@ -105,12 +121,26 @@ static void gtk_hex_view_class_init(GtkHexViewClass *class)      object = G_OBJECT_CLASS(class); -    object->dispose = (GObjectFinalizeFunc/* ! */)gtk_hex_view_dispose; -    object->finalize = (GObjectFinalizeFunc)gtk_hex_view_finalize; +    object->dispose = gtk_hex_view_dispose; +    object->finalize = gtk_hex_view_finalize; +    object->set_property = gtk_hex_view_set_property; +    object->get_property = gtk_hex_view_get_property; + +    _hex_view_properties[PROP_SHOW_OFFSETS] = +        g_param_spec_boolean("show-offsets", NULL, NULL, +                             TRUE, +                             G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); + +    _hex_view_properties[PROP_CONTENT] = +        g_param_spec_object("content", NULL, NULL, +                            G_TYPE_BIN_CONTENT, +                            G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_EXPLICIT_NOTIFY); + +    g_object_class_install_properties(object, N_PROPERTIES, _hex_view_properties);      widget = GTK_WIDGET_CLASS(class); -    gtk_widget_class_set_css_name(widget, "GtkHexView"); +    gtk_widget_class_set_css_name(widget, "hexview");      g_type_ensure(GTK_TYPE_COMPOSING_AREA); @@ -131,7 +161,7 @@ static void gtk_hex_view_class_init(GtkHexViewClass *class)  *                                                                             *  *  Paramètres  : view = composant GTK à initialiser.                          *  *                                                                             * -*  Description : Procède à l'initialisation de l'afficheur générique.         * +*  Description : Initialise une instance d'afficheur de tampons bruts.        *  *                                                                             *  *  Retour      : -                                                            *  *                                                                             * @@ -167,12 +197,14 @@ static void gtk_hex_view_init(GtkHexView *view)      view->generator = NULL; +    gtk_hex_view_create(view, NULL); +  }  /******************************************************************************  *                                                                             * -*  Paramètres  : view = instance d'objet GLib à traiter.                      * +*  Paramètres  : object = instance d'objet GLib à traiter.                    *  *                                                                             *  *  Description : Supprime toutes les références externes.                     *  *                                                                             * @@ -182,20 +214,24 @@ static void gtk_hex_view_init(GtkHexView *view)  *                                                                             *  ******************************************************************************/ -static void gtk_hex_view_dispose(GtkHexView *view) +static void gtk_hex_view_dispose(GObject *object)  { -    gtk_widget_dispose_template(GTK_WIDGET(view), GTK_TYPE_HEX_VIEW); +    GtkHexView *view;                       /* Version spécialisée         */ + +    gtk_widget_dispose_template(GTK_WIDGET(object), GTK_TYPE_HEX_VIEW); + +    view = GTK_HEX_VIEW(object);      g_clear_object(&view->generator); -    G_OBJECT_CLASS(gtk_hex_view_parent_class)->dispose(G_OBJECT(view)); +    G_OBJECT_CLASS(gtk_hex_view_parent_class)->dispose(object);  }  /******************************************************************************  *                                                                             * -*  Paramètres  : view = instance d'objet GLib à traiter.                      * +*  Paramètres  : object = instance d'objet GLib à traiter.                    *  *                                                                             *  *  Description : Procède à la libération totale de la mémoire.                *  *                                                                             * @@ -205,9 +241,9 @@ static void gtk_hex_view_dispose(GtkHexView *view)  *                                                                             *  ******************************************************************************/ -static void gtk_hex_view_finalize(GtkHexView *view) +static void gtk_hex_view_finalize(GObject *object)  { -    G_OBJECT_CLASS(gtk_hex_view_parent_class)->finalize(G_OBJECT(view)); +    G_OBJECT_CLASS(gtk_hex_view_parent_class)->finalize(object);  } @@ -263,13 +299,43 @@ bool gtk_hex_view_create(GtkHexView *view, GBinContent *content)      parent = GTK_BUFFER_VIEW(view); -    cache = g_buffer_cache_new(1, 2); +    cache = g_buffer_cache_new(1 /* opt_count */, 2 /* reg_count */);      parent->view = g_buffer_view_new(cache, parent->style);      unref_object(cache); -    view->generator = g_hex_generator_new(content); + + +    gtk_hex_view_set_content(view, content); + + + +    return result; + +} + + +/****************************************************************************** +*                                                                             * +*  Paramètres  : view = composant d'affichage à consulter.                    * +*                                                                             * +*  Description : Fournit le contenu associé au composant d'affichage.         * +*                                                                             * +*  Retour      : Contenu dans lequel puise le générateur pour les lignes.     * +*                                                                             * +*  Remarques   : -                                                            * +*                                                                             * +******************************************************************************/ + +GBinContent *gtk_hex_view_get_content(const GtkHexView *view) +{ +    GBinContent *result;                    /* Référence à retourner       */ + +    if (view->generator != NULL) +        result = g_hex_generator_get_content(view->generator); +    else +        result = NULL;      return result; @@ -278,6 +344,61 @@ bool gtk_hex_view_create(GtkHexView *view, GBinContent *content)  /******************************************************************************  *                                                                             * +*  Paramètres  : view    = composant d'affichage à modifier.                  * +*                content = nouveau contenu pour source de génération.         * +*                                                                             * +*  Description : Définit le contenu associé au composant d'affichage.         * +*                                                                             * +*  Retour      : -                                                            * +*                                                                             * +*  Remarques   : -                                                            * +*                                                                             * +******************************************************************************/ + +void gtk_hex_view_set_content(GtkHexView *view, GBinContent *content) +{ +    GBinContent *old;                       /* Ancienne valeur             */ +    GBufferCache *cache;                    /* Tampon à représenter        */ + +    old = gtk_hex_view_get_content(view); + +    assert((old == NULL && view->generator == NULL) || (old != NULL && view->generator != NULL)); + +    if (old != content) +    { +        if (view->generator != NULL) +        { +            cache = g_buffer_view_get_cache(GTK_BUFFER_VIEW(view)->view); + +            g_buffer_cache_wlock(cache); + +            g_buffer_cache_truncate(cache, 0); + +            g_buffer_cache_wunlock(cache); + +            unref_object(cache); + +            g_clear_object(&view->generator); + +        } + +        if (content != NULL) +            view->generator = g_hex_generator_new(content); + +        g_object_notify_by_pspec(G_OBJECT(view), _hex_view_properties[PROP_CONTENT]); + +        assert(content != NULL); +        gtk_widget_queue_resize(GTK_WIDGET(view)); + +    } + +    g_clear_object(&old); + +} + + +/****************************************************************************** +*                                                                             *  *  Paramètres  : widget   = composant GTK à redessiner.                       *  *                snapshot = gestionnaire de noeuds de rendu à solliciter.     *  *                parent   = composant GTK parent et cadre de l'appel.         * @@ -380,67 +501,108 @@ static void gtk_hex_view_populate_cache(GtkHexView *view)      /* Mise à jour de l'affichage ? */ +    /*      if (needed != count)          gtk_widget_queue_resize(GTK_WIDGET(view)); +    */  } +/* ---------------------------------------------------------------------------------- */ +/*                       IMPLEMENTATION DES FONCTIONS DE CLASSE                       */ +/* ---------------------------------------------------------------------------------- */ +/****************************************************************************** +*                                                                             * +*  Paramètres  : object  = instance d'objet GLib à mamnipuler.                * +*                prop_id = identifiant de la propriété visée.                 * +*                value   = valeur à prendre en compte.                        * +*                pspec   = définition de la propriété.                        * +*                                                                             * +*  Description : Met à jour une propriété d'instance GObject.                 * +*                                                                             * +*  Retour      : -                                                            * +*                                                                             * +*  Remarques   : -                                                            * +*                                                                             * +******************************************************************************/ - -void demo_snapshot (GtkWidget *widget, GtkSnapshot *snapshot, GtkWidget *parent) +static void gtk_hex_view_set_property(GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec)  { -  GdkRGBA red, green, yellow, blue; -  float w, h; - -  gdk_rgba_parse (&red, "red"); -  gdk_rgba_parse (&green, "green"); -  gdk_rgba_parse (&yellow, "yellow"); -  gdk_rgba_parse (&blue, "blue"); +    GtkHexView *view;                       /* Version spécialisée         */ +    GObject *content;                       /* Contenu sous forme simple   */ -  w = gtk_widget_get_width (widget) / 2.0; -  h = gtk_widget_get_height (widget) / 2.0; +    view = GTK_HEX_VIEW(object); -  h /= 2.0; +    switch (prop_id) +    { +        case PROP_SHOW_OFFSETS: +            g_display_options_set(GTK_CONTENT_VIEW(view)->options, HCO_OFFSET, g_value_get_boolean(value)); +            gtk_widget_set_visible(view->offsets, g_value_get_boolean(value)); +            break; -  gtk_snapshot_append_color (snapshot, &red, -                             &GRAPHENE_RECT_INIT(0, 0, w, h)); -  gtk_snapshot_append_color (snapshot, &green, -                             &GRAPHENE_RECT_INIT(w, 0, w, h)); -  gtk_snapshot_append_color (snapshot, &yellow, -                             &GRAPHENE_RECT_INIT(0, h, w, h)); -  gtk_snapshot_append_color (snapshot, &blue, -                             &GRAPHENE_RECT_INIT(w, h, w, h)); +        case PROP_CONTENT: +            content = g_value_get_object(value); +            gtk_hex_view_set_content(view, G_BIN_CONTENT(content)); +            break; +        default: +            G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec); +            break; +    }  } +/****************************************************************************** +*                                                                             * +*  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_hex_view_get_property(GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) +{ +    GtkHexView *view;                       /* Version spécialisée         */ +    view = GTK_HEX_VIEW(object); +    switch (prop_id) +    { +        case PROP_SHOW_OFFSETS: +            g_value_set_boolean(value, gtk_widget_get_visible(view->offsets)); +            break; +        case PROP_CONTENT: +            g_value_take_object(value, gtk_hex_view_get_content(view)); +            break; +        default: +            G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec); +            break; +    } - - - - -/* ---------------------------------------------------------------------------------- */ -/*                       IMPLEMENTATION DES FONCTIONS DE CLASSE                       */ -/* ---------------------------------------------------------------------------------- */ +}  /******************************************************************************  *                                                                             * -*  Paramètres  : widget = composant GTK à examiner.                           * -*                width  = largeur affectée au composant graphique.            * -*                height = hauteur affectée au composant graphique.            * +*  Paramètres  : widget   = composant GTK à examiner.                         * +*                width    = largeur affectée au composant graphique.          * +*                height   = hauteur affectée au composant graphique.          *  *                baseline = ligne de base affectée au composant graphique.    *  *                                                                             *  *  Description : Prend acte de la taille allouée au composant d'affichage.    * @@ -467,7 +629,13 @@ static void gtk_hex_view_size_allocate(GtkWidget *widget, int width, int height,      final_widths = alloca(_CHILDREN_COUNT * sizeof(int));      for (i = 0; i < _CHILDREN_COUNT; i++) -        gtk_widget_measure(view->children[i], GTK_ORIENTATION_HORIZONTAL, -1, &min_widths[i], NULL, NULL, NULL); +    { +        if (!gtk_widget_get_visible(view->children[i])) +            min_widths[i] = 0; +        else +            gtk_widget_measure(view->children[i], GTK_ORIENTATION_HORIZONTAL, -1, &min_widths[i], NULL, NULL, NULL); + +    }      /* Passe 1 : tentative sans défilement vertical */ @@ -491,7 +659,10 @@ static void gtk_hex_view_size_allocate(GtkWidget *widget, int width, int height,          for (i = 0; i < _CHILDREN_COUNT; i++)          { -            final_widths[i] += min_widths[i]; +            if (!gtk_widget_get_visible(view->children[i])) +                final_widths[i] = 0; +            else +                final_widths[i] += min_widths[i];              g_width_tracker_set_column_min_width(tracker, i, final_widths[i]); @@ -531,17 +702,6 @@ static GtkSizeRequestMode gtk_hex_view_get_request_mode(GtkWidget *widget)  } - - - - - - - - - - -  /******************************************************************************  *                                                                             *  *  Paramètres  : widget       = composant GTK à examiner.                     * @@ -580,8 +740,12 @@ static void gtk_hex_view_measure(GtkWidget *widget, GtkOrientation orientation,          for (i = 0; i < _CHILDREN_COUNT; i++)          { +            if (!gtk_widget_get_visible(view->children[i])) +                continue; +              gtk_widget_measure(view->children[i], GTK_ORIENTATION_HORIZONTAL, -1, &min, NULL, NULL, NULL);              requested += min; +          }          for_size -= requested; @@ -593,11 +757,14 @@ static void gtk_hex_view_measure(GtkWidget *widget, GtkOrientation orientation,                                                                  GTK_BUFFER_VIEW(view)->style,                                                                  for_size); -            if (minimum != NULL) *minimum = 0; +            if (minimum != NULL) *minimum = requested;              if (natural != NULL) *natural = requested;              for (i = 0; i < _CHILDREN_COUNT; i++)              { +                if (!gtk_widget_get_visible(view->children[i])) +                    continue; +                  gtk_widget_measure(view->children[i], GTK_ORIENTATION_VERTICAL, -1, &min, &nat, NULL, NULL);                  if (minimum != NULL && min > *minimum) diff --git a/src/gtkext/hexview.h b/src/gtkext/hexview.h index 2199786..0d2cd5a 100644 --- a/src/gtkext/hexview.h +++ b/src/gtkext/hexview.h @@ -41,6 +41,12 @@ DECLARE_GTYPE(GtkHexView, gtk_hex_view, GTK, HEX_VIEW);  /* Crée un composant d'affichage d'octets bruts et imprimables. */  GtkHexView *gtk_hex_view_new(GBinContent *); +/* Fournit le contenu associé au composant d'affichage. */ +GBinContent *gtk_hex_view_get_content(const GtkHexView *); + +/* Définit le contenu associé au composant d'affichage. */ +void gtk_hex_view_set_content(GtkHexView *, GBinContent *); +  #endif  /* _GTKEXT_HEXVIEW_H */ diff --git a/src/gtkext/hexview.ui b/src/gtkext/hexview.ui index ae4586c..9b42936 100644 --- a/src/gtkext/hexview.ui +++ b/src/gtkext/hexview.ui @@ -1,27 +1,29 @@ +<?xml version="1.0" encoding="UTF-8"?>  <interface> -  <template class="GtkHexView" parent="GtkBufferView"> -    <property name="css-name">GtkHexView</property> -    <child> -      <object class="GtkComposingArea" id="offsets"> -        <style> -          <class name="gutter"/> -        </style> -      </object> -    </child> -    <child> -      <object class="GtkComposingArea" id="hex"> -        <property name="hexpand">true</property> -        <style> -          <class name="custom-view"/> -        </style> -      </object> -    </child> -    <child> -      <object class="GtkComposingArea" id="ascii"> -        <style> -          <class name="custom-view"/> -        </style> -      </object> -    </child> -  </template> + +    <template class="GtkHexView" parent="GtkBufferView"> +        <child> +            <object class="GtkComposingArea" id="offsets"> +                <style> +                    <class name="gutter"/> +                </style> +            </object> +        </child> +        <child> +            <object class="GtkComposingArea" id="hex"> +                <property name="hexpand">true</property> +                <style> +                    <class name="custom-view"/> +                </style> +            </object> +        </child> +        <child> +            <object class="GtkComposingArea" id="ascii"> +                <style> +                    <class name="custom-view"/> +                </style> +            </object> +        </child> +    </template> +  </interface> diff --git a/src/gtkext/launcher-int.h b/src/gtkext/launcher-int.h new file mode 100644 index 0000000..07152f0 --- /dev/null +++ b/src/gtkext/launcher-int.h @@ -0,0 +1,56 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * tweak-int.h - définitions internes pour un lanceur de panneau majeur + * + * 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 _GTKEXT_LAUNCHER_INT_H +#define _GTKEXT_LAUNCHER_INT_H + + +#include "launcher.h" + + + +/* Elément de lancement d'un panneau majeur pour l'interface (instance) */ +struct _GtkPanelLauncher +{ +    GtkListBoxRow parent;                   /* A laisser en premier        */ + +    GtkImage *icon;                         /* Eventuelle image            */ +    GtkLabel *title;                        /* Etiquette associée          */ +    GtkLabel *desc;                         /* Description du panneau      */ + +}; + +/* Elément de lancement d'un panneau majeur pour l'interface (classe) */ +struct _GtkPanelLauncherClass +{ +    GtkListBoxRowClass parent;              /* A laisser en premier        */ + +}; + + +/* Met en place un nouveau lanceur de panneau majeur. */ +bool gtk_panel_launcher_create(GtkPanelLauncher *, const char *, const char *, const char *); + + + +#endif  /* _GTKEXT_LAUNCHER_INT_H */ diff --git a/src/gtkext/launcher.c b/src/gtkext/launcher.c new file mode 100644 index 0000000..5bb850b --- /dev/null +++ b/src/gtkext/launcher.c @@ -0,0 +1,211 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * launcher.c - lanceur de panneau majeur + * + * 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/>. + */ + + +#include "launcher.h" + + +#include <malloc.h> +#include <string.h> + + +#include "helpers.h" +#include "launcher-int.h" +#include "../common/extstr.h" + + + +/* Initialise la classe des sections d'éléments paramétrables. */ +static void gtk_panel_launcher_class_init(GtkPanelLauncherClass *); + +/* Initialise une instance de lanceur de panneau majeur. */ +static void gtk_panel_launcher_init(GtkPanelLauncher *); + +/* Supprime toutes les références externes. */ +static void gtk_panel_launcher_dispose(GObject *); + +/* Procède à la libération totale de la mémoire. */ +static void gtk_panel_launcher_finalize(GObject *); + + + +/* Détermine le type du composant d'affichage générique. */ +G_DEFINE_TYPE(GtkPanelLauncher, gtk_panel_launcher, GTK_TYPE_LIST_BOX_ROW); + + +/****************************************************************************** +*                                                                             * +*  Paramètres  : class = classe GTK à initialiser.                            * +*                                                                             * +*  Description : Initialise la classe des sections d'éléments paramétrables.  * +*                                                                             * +*  Retour      : -                                                            * +*                                                                             * +*  Remarques   : -                                                            * +*                                                                             * +******************************************************************************/ + +static void gtk_panel_launcher_class_init(GtkPanelLauncherClass *class) +{ +    GObjectClass *object;                   /* Plus haut niveau équivalent */ +    GtkWidgetClass *widget;                 /* Classe de haut niveau       */ + +    object = G_OBJECT_CLASS(class); + +    object->dispose = gtk_panel_launcher_dispose; +    object->finalize = gtk_panel_launcher_finalize; + +    widget = GTK_WIDGET_CLASS(class); + +    gtk_widget_class_set_template_from_resource(widget, "/re/chrysalide/framework/gtkext/launcher.ui"); + +    gtk_widget_class_bind_template_child(widget, GtkPanelLauncher, icon); +    gtk_widget_class_bind_template_child(widget, GtkPanelLauncher, title); +    gtk_widget_class_bind_template_child(widget, GtkPanelLauncher, desc); + +} + + +/****************************************************************************** +*                                                                             * +*  Paramètres  : launcher = composant GTK à initialiser.                      * +*                                                                             * +*  Description : Initialise une instance de lanceur de panneau majeur.        * +*                                                                             * +*  Retour      : -                                                            * +*                                                                             * +*  Remarques   : -                                                            * +*                                                                             * +******************************************************************************/ + +static void gtk_panel_launcher_init(GtkPanelLauncher *launcher) +{ +    gtk_widget_init_template(GTK_WIDGET(launcher)); + +} + + +/****************************************************************************** +*                                                                             * +*  Paramètres  : object = instance d'objet GLib à traiter.                    * +*                                                                             * +*  Description : Supprime toutes les références externes.                     * +*                                                                             * +*  Retour      : -                                                            * +*                                                                             * +*  Remarques   : -                                                            * +*                                                                             * +******************************************************************************/ + +static void gtk_panel_launcher_dispose(GObject *object) +{ +    gtk_widget_dispose_template(GTK_WIDGET(object), GTK_TYPE_PANEL_LAUNCHER); + +    G_OBJECT_CLASS(gtk_panel_launcher_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 gtk_panel_launcher_finalize(GObject *object) +{ +    G_OBJECT_CLASS(gtk_panel_launcher_parent_class)->finalize(object); + +} + + +/****************************************************************************** +*                                                                             * +*  Paramètres  : icon  = désignation de l'image de représentation.            * +*                title = titre principal à afficher.                          * +*                desc  = description du panneau ciblé.                        * +*                                                                             * +*  Description : Crée un nouveau lanceur de panneau majeur.                   * +*                                                                             * +*  Retour      : Composant GTK mis en place.                                  * +*                                                                             * +*  Remarques   : -                                                            * +*                                                                             * +******************************************************************************/ + +GtkPanelLauncher *gtk_panel_launcher_new(const char *icon, const char *title, const char *desc) +{ +    GtkPanelLauncher *result;               /* Instance à retourner        */ + +    result = g_object_new(GTK_TYPE_PANEL_LAUNCHER, NULL); + +    if (!gtk_panel_launcher_create(result, icon, title, desc)) +        g_clear_object(&result); + +    return result; + +} + + +/****************************************************************************** +*                                                                             * +*  Paramètres  : launcher = lanceur à initialiser pleinement.                 * +*                icon     = désignation de l'image de représentation.         * +*                title    = titre principal à afficher.                       * +*                desc     = description du panneau ciblé.                     * +*                                                                             * +*  Description : Met en place un nouveau lanceur de panneau majeur.           * +*                                                                             * +*  Retour      : Bilan de l'opération.                                        * +*                                                                             * +*  Remarques   : -                                                            * +*                                                                             * +******************************************************************************/ + +bool gtk_panel_launcher_create(GtkPanelLauncher *launcher, const char *icon, const char *title, const char *desc) +{ +    bool result;                            /* Bilan à retourner           */ +    char *bold;                             /* Titre sublimé               */ + +    result = true; + +    gtk_image_set_from_icon_name(launcher->icon, icon); + +    bold = strdup(title); +    bold = strprep(bold, "<b>"); +    bold = stradd(bold, "</b>"); + +    gtk_label_set_label(launcher->title, bold); + +    free(bold); + +    gtk_label_set_label(launcher->desc, desc); + +    return result; + +} diff --git a/src/gtkext/launcher.h b/src/gtkext/launcher.h new file mode 100644 index 0000000..3857216 --- /dev/null +++ b/src/gtkext/launcher.h @@ -0,0 +1,45 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * launcher.h - prototypes pour pour un lanceur de panneau majeur + * + * 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 _GTKEXT_LAUNCHER_H +#define _GTKEXT_LAUNCHER_H + + +#include <gtk/gtk.h> + + +#include "../glibext/helpers.h" + + + +#define GTK_TYPE_PANEL_LAUNCHER (gtk_panel_launcher_get_type()) + +DECLARE_GTYPE(GtkPanelLauncher, gtk_panel_launcher, GTK, PANEL_LAUNCHER); + + +/* Crée un nouveau lanceur de panneau majeur. */ +GtkPanelLauncher *gtk_panel_launcher_new(const char *, const char *, const char *); + + + +#endif  /* _GTKEXT_LAUNCHER_H */ diff --git a/src/gtkext/launcher.ui b/src/gtkext/launcher.ui new file mode 100644 index 0000000..f6f4fec --- /dev/null +++ b/src/gtkext/launcher.ui @@ -0,0 +1,76 @@ +<?xml version="1.0" encoding="UTF-8"?> +<interface> +    <template class="GtkPanelLauncher" parent="GtkListBoxRow"> + +        <property name="child"> + +            <object class="GtkGrid"> +                <property name="margin-bottom">12</property> +                <property name="margin-end">12</property> +                <property name="margin-start">12</property> +                <property name="margin-top">12</property> +                <property name="column-spacing">12</property> + +                <child> +                    <object class="GtkImage" id="icon"> +                        <property name="icon-name"></property> +                        <property name="pixel-size">48</property> +                        <layout> +                            <property name="column">0</property> +                            <property name="row">0</property> +                            <property name="row-span">2</property> +                        </layout> +                        <style> +                            <class name="icon-dropshadow"/> +                        </style> +                    </object> +                </child> + +                <child> +                    <object class="GtkLabel" id="title"> +                        <property name="label"></property> +                        <property name="use-markup">TRUE</property> +                        <property name="xalign">0</property> +                        <layout> +                            <property name="column">1</property> +                            <property name="row">0</property> +                        </layout> +                    </object> +                </child> + +                <child> +                    <object class="GtkLabel" id="desc"> +                        <property name="label"></property> +                        <property name="hexpand">true</property> +                        <property name="xalign">0</property> +                        <layout> +                            <property name="column">1</property> +                            <property name="row">1</property> +                        </layout> +                        <style> +                            <class name="dim-label"/> +                        </style> +                    </object> +                </child> + +                <child> +                    <object class="GtkImage"> +                        <property name="icon-name">go-next-symbolic</property> +                        <property name="margin-start">12</property> +                        <layout> +                            <property name="column">2</property> +                            <property name="row">0</property> +                            <property name="row-span">2</property> +                        </layout> +                        <style> +                            <class name="icon-dropshadow"/> +                        </style> +                    </object> +                </child> + +            </object> + +        </property> + +    </template> +</interface> diff --git a/src/gui/panel-int.h b/src/gtkext/panel-int.h index d54dc16..5398e51 100644 --- a/src/gui/panel-int.h +++ b/src/gtkext/panel-int.h @@ -2,7 +2,7 @@  /* Chrysalide - Outil d'analyse de fichiers binaires   * panel-int.h - prototypes pour les définitions internes liées aux panneaux d'affichage   * - * Copyright (C) 2019 Cyrille Bagard + * Copyright (C) 2019-2024 Cyrille Bagard   *   *  This file is part of Chrysalide.   * @@ -22,13 +22,52 @@   */ -#ifndef _GUI_PANELS_PANEL_INT_H -#define _GUI_PANELS_PANEL_INT_H +#ifndef _GTKEXT_PANEL_INT_H +#define _GTKEXT_PANEL_INT_H  #include "panel.h" + +/* Indique l'emplacement par défaut pour un affichage. */ +typedef char * (* get_tiled_panel_path) (const GtkTiledPanel *); + +/* Fournit les composants adaptés pour la barre de titre. */ +typedef GListStore * (* get_tiled_panel_widgets_cb) (const GtkTiledPanel *, bool); + +/* Note un ajout ou un retrait de panneau principal. */ +typedef void (* notify_tiled_panel_state_cb) (GtkTiledPanel *, GtkTiledPanel *, bool); + + +/* Elément réactif pour panneaux de l'éditeur (instance) */ +struct _GtkTiledPanel +{ +    GtkBox parent;                          /* A laisser en premier        */ + +}; + +/* Elément réactif pour panneaux de l'éditeur (classe) */ +struct _GtkTiledPanelClass +{ +    GtkBoxClass parent;                     /* A laisser en premier        */ + +    get_tiled_panel_path get_default_path;  /* Localisation de l'affichage */ +    get_tiled_panel_widgets_cb get_widgets; /* Récupération de composants  */ + +    notify_tiled_panel_state_cb notify;     /* Note d'un ajout ou retrait  */ + +}; + + + + + + + + +#if 0 +  #include <gtk/gtk.h> @@ -134,5 +173,8 @@ void g_panel_item_switch_to_updating_mask(GPanelItem *);  void g_panel_item_switch_to_updated_content(GPanelItem *); +#endif + + -#endif  /* _GUI_PANELS_PANEL_INT_H */ +#endif  /* _GTKEXT_PANEL_INT_H */ diff --git a/src/gui/panel.c b/src/gtkext/panel.c index 5b21620..f63cfa1 100644 --- a/src/gui/panel.c +++ b/src/gtkext/panel.c @@ -2,7 +2,7 @@  /* Chrysalide - Outil d'analyse de fichiers binaires   * panel.c - gestion des éléments réactifs spécifiques aux panneaux   * - * Copyright (C) 2019 Cyrille Bagard + * Copyright (C) 2019-2024 Cyrille Bagard   *   *  This file is part of Chrysalide.   * @@ -25,6 +25,206 @@  #include "panel.h" +#include "panel-int.h" + + + + + +/* Initialise la classe des panneaux graphiques de l'éditeur. */ +static void gtk_tiled_panel_class_init(GtkTiledPanelClass *); + +/* Initialise une instance de panneau graphique pour l'éditeur. */ +static void gtk_tiled_panel_init(GtkTiledPanel *); + +/* Supprime toutes les références externes. */ +static void gtk_tiled_panel_dispose(GtkTiledPanel *); + +/* Procède à la libération totale de la mémoire. */ +static void gtk_tiled_panel_finalize(GtkTiledPanel *); + + + + + + + + +/* Détermine le type du conteneur d'affichage en tuiles nommées. */ +G_DEFINE_TYPE(GtkTiledPanel, gtk_tiled_panel, GTK_TYPE_BOX) + + +/****************************************************************************** +*                                                                             * +*  Paramètres  : klass = classe GTK à initialiser.                            * +*                                                                             * +*  Description : Initialise la classe des panneaux graphiques de l'éditeur.   * +*                                                                             * +*  Retour      : -                                                            * +*                                                                             * +*  Remarques   : -                                                            * +*                                                                             * +******************************************************************************/ + +static void gtk_tiled_panel_class_init(GtkTiledPanelClass *klass) +{ +    GObjectClass *object;                   /* Autre version de la classe  */ + +    object = G_OBJECT_CLASS(klass); + +    object->dispose = (GObjectFinalizeFunc/* ! */)gtk_tiled_panel_dispose; +    object->finalize = (GObjectFinalizeFunc)gtk_tiled_panel_finalize; + +} + + +/****************************************************************************** +*                                                                             * +*  Paramètres  : panel = instance GTK à initialiser.                          * +*                                                                             * +*  Description : Initialise une instance de panneau graphique pour l'éditeur. * +*                                                                             * +*  Retour      : -                                                            * +*                                                                             * +*  Remarques   : -                                                            * +*                                                                             * +******************************************************************************/ + +static void gtk_tiled_panel_init(GtkTiledPanel *panel) +{ + +} + + +/****************************************************************************** +*                                                                             * +*  Paramètres  : panel = instance d'objet GLib à traiter.                     * +*                                                                             * +*  Description : Supprime toutes les références externes.                     * +*                                                                             * +*  Retour      : -                                                            * +*                                                                             * +*  Remarques   : -                                                            * +*                                                                             * +******************************************************************************/ + +static void gtk_tiled_panel_dispose(GtkTiledPanel *panel) +{ +    G_OBJECT_CLASS(gtk_tiled_panel_parent_class)->dispose(G_OBJECT(panel)); + +} + + +/****************************************************************************** +*                                                                             * +*  Paramètres  : panel = instance d'objet GLib à traiter.                     * +*                                                                             * +*  Description : Procède à la libération totale de la mémoire.                * +*                                                                             * +*  Retour      : -                                                            * +*                                                                             * +*  Remarques   : -                                                            * +*                                                                             * +******************************************************************************/ + +static void gtk_tiled_panel_finalize(GtkTiledPanel *panel) +{ +    G_OBJECT_CLASS(gtk_tiled_panel_parent_class)->finalize(G_OBJECT(panel)); + +} + + +/****************************************************************************** +*                                                                             * +*  Paramètres  : panel = panneau graphique à consulter.                       * +*                                                                             * +*  Description : Indique l'emplacement attendu pour un affichage.             * +*                                                                             * +*  Retour      : Chemin représenté ou NULL pour l'emplacement "M" par défaut. * +*                                                                             * +*  Remarques   : -                                                            * +*                                                                             * +******************************************************************************/ + +char *gtk_tiled_panel_get_path(const GtkTiledPanel *panel) +{ +    char *result;                           /* Chemin à retourner          */ +    GtkTiledPanelClass *class;              /* Classe à actionner          */ + +    class = GTK_TILED_PANEL_GET_CLASS(panel); + +    if (class->get_default_path != NULL) +        result = class->get_default_path(panel); +    else +        result = NULL; + +    return result; + +} + + +/****************************************************************************** +*                                                                             * +*  Paramètres  : panel = panneau graphique à consulter.                       * +*                left  = indication quant au côté ciblé.                      * +*                                                                             * +*  Description : Fournit les composants adaptés pour la barre de titre.       * +*                                                                             * +*  Retour      : Liste de Composants GTK mis en place.                        * +*                                                                             * +*  Remarques   : -                                                            * +*                                                                             * +******************************************************************************/ + +GListStore *gtk_tiled_panel_get_title_widgets(const GtkTiledPanel *panel, bool left) +{ +    GListStore *result;                     /* Composant(s) à retourner    */ +    GtkTiledPanelClass *class;              /* Classe à actionner          */ + +    class = GTK_TILED_PANEL_GET_CLASS(panel); + +    if (class->get_widgets != NULL) +        result = class->get_widgets(panel, left); +    else +        result = NULL; + +    return result; + +} + + +/****************************************************************************** +*                                                                             * +*  Paramètres  : panel     = panneau graphique à manipuler.                   * +*                main      = panneau principal visé par l'opération.          * +*                activated = nature du changement de statut : ajout, retrait ?* +*                                                                             * +*  Description : Note un ajout ou un retrait de panneau principal.            * +*                                                                             * +*  Retour      : -                                                            * +*                                                                             * +*  Remarques   : -                                                            * +*                                                                             * +******************************************************************************/ + +void gtk_tiled_panel_notify_new_main_panel_state(GtkTiledPanel *panel, GtkTiledPanel *main, bool activated) +{ +    GtkTiledPanelClass *class;              /* Classe à actionner          */ + +    class = GTK_TILED_PANEL_GET_CLASS(panel); + +    if (class->notify != NULL) +        class->notify(panel, main, activated); + +} + + + + + + +#if 0 +  #include <assert.h>  #include <stdio.h>  #include <string.h> @@ -859,7 +1059,7 @@ void g_panel_item_set_dock_at_startup(GPanelItem *item, bool status)  bool g_panel_item_is_docked(const GPanelItem *item)  { -    bool result;                            /* Status à retourner          */ +    bool result;                            /* Statut à retourner          */      result = item->docked; @@ -1117,3 +1317,5 @@ void g_panel_item_switch_to_updated_content(GPanelItem *item)      g_atomic_int_dec_and_test(&item->switched);  } + +#endif diff --git a/src/gui/panel.h b/src/gtkext/panel.h index de8d2bf..9b00657 100644 --- a/src/gui/panel.h +++ b/src/gtkext/panel.h @@ -2,7 +2,7 @@  /* Chrysalide - Outil d'analyse de fichiers binaires   * panel.h - prototypes pour la gestion des éléments réactifs spécifiques aux panneaux   * - * Copyright (C) 2019 Cyrille Bagard + * Copyright (C) 2019-2024 Cyrille Bagard   *   *  This file is part of Chrysalide.   * @@ -22,10 +22,38 @@   */ -#ifndef _GUI_PANELS_PANEL_H -#define _GUI_PANELS_PANEL_H +#ifndef _GTKEXT_PANEL_H +#define _GTKEXT_PANEL_H +#include <gtk/gtk.h> + + +#include "../glibext/helpers.h" + + + +#define GTK_TYPE_TILED_PANEL (gtk_tiled_panel_get_type()) + +DECLARE_GTYPE(GtkTiledPanel, gtk_tiled_panel, GTK, TILED_PANEL); + + +/* Indique l'emplacement attendu pour un affichage. */ +char *gtk_tiled_panel_get_path(const GtkTiledPanel *); + +/* Fournit les composants adaptés pour la barre de titre. */ +GListStore *gtk_tiled_panel_get_title_widgets(const GtkTiledPanel *, bool); + +/* Note un ajout ou un retrait de panneau principal. */ +void gtk_tiled_panel_notify_new_main_panel_state(GtkTiledPanel *, GtkTiledPanel *, bool); + + + + + + +#if 0 +  #include <stdbool.h>  #include <gtk/gtk.h> @@ -108,5 +136,7 @@ bool g_panel_item_is_docked(const GPanelItem *);  void g_panel_item_undock(GPanelItem *); +#endif + -#endif  /* _GUI_PANELS_PANEL_H */ +#endif  /* _GTKEXT_PANEL_H */ diff --git a/src/gtkext/statusstack-int.h b/src/gtkext/statusstack-int.h new file mode 100644 index 0000000..721b982 --- /dev/null +++ b/src/gtkext/statusstack-int.h @@ -0,0 +1,106 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * statusstack-int.h - définitions internes pour l'empilement d'informations de statut + * + * Copyright (C) 2024 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 _GTKEXT_STATUSSTACK_INT_H +#define _GTKEXT_STATUSSTACK_INT_H + + +#include "statusstack.h" +#include "../glibext/secstorage.h" + + + +/* Navigation au sein d'assemblage */ +typedef struct _navigation_info_t navigation_info_t; + +/* Mémorisation des progressions au sein d'activités */ +typedef struct _activity_info_t activity_info_t; + + +#define NETWORK_UPDATE_COUNT 10 +#define NETWORK_UPDATE_INTERVAL (1000 / NETWORK_UPDATE_COUNT) + + +/* Gestion de barre de statut adaptable (instance) */ +struct _GtkStatusStack +{ +    GtkBox parent;                          /* A laisser en premier        */ + +    GtkStack *main;                         /* Pile d'informations associée*/ + +    GSourceFunc def_source;                 /* Appel en fin d'activité     */ + +    /* Message simple par défaut */ + +    GtkLabel *def_label;                    /* Afficheur de message        */ + +    char *msg;                              /* Contenu associé             */ + +    /* Navigation */ + +    GtkLabel *nav_segment;                  /* Désignation du segment      */ +    GtkLabel *nav_phys;                     /* Adresse physique            */ +    GtkLabel *nav_virt;                     /* Adresse virtuelle           */ +    GtkLabel *nav_offset;                   /* Position dans le binaire    */ +    GtkLabel *nav_format;                   /* Architecture du binaire     */ +    GtkLabel *nav_details;                  /* Détails sur l'architecture  */ +    GtkEntry *zoom;                         /* Degré de zoom courant       */ + +    navigation_info_t *nav_info;            /* Informations brutes liées   */ + +    /* Activité */ + +    GtkLabel *activity_message;             /* Nature de l'activité        */ +    GtkProgressBar *activity_progress;      /* Barre de progression        */ + +    activity_info_t *activity_info;         /* Informations brutes liées   */ + +    /* Tronc commun */ + +    GSecretStorage *storage;                /* Stockage des secrets        */ +    GtkToggleButton *lock_update;           /* Activation des accès        */ + +    GtkLabel *net_recv_speed;               /* Débit en réception          */ +    GtkLabel *net_send_speed;               /* Débit en émission           */ + +    size_t last_bytes_received[NETWORK_UPDATE_COUNT]; /* Octets reçus      */ +    size_t last_bytes_sent[NETWORK_UPDATE_COUNT]; /* Octets émis           */ +    gint64 last_timestamps[NETWORK_UPDATE_COUNT]; /* Dates des mesures     */ +    size_t next_index;                      /* Indice d'écriture           */ + +    guint network_update_tag;               /* Identifiant de mise à jour  */ + +    GtkToggleButton *bottom_toggler;        /* Bascule de panneaux inf.    */ + +}; + +/* Gestion de barre de statut adaptable (classe) */ +struct _GtkStatusStackClass +{ +    GtkBoxClass parent;                     /* A laisser en premier        */ + +}; + + + +#endif  /* _GTKEXT_STATUSSTACK_INT_H */ diff --git a/src/gtkext/statusstack.c b/src/gtkext/statusstack.c new file mode 100644 index 0000000..92c296a --- /dev/null +++ b/src/gtkext/statusstack.c @@ -0,0 +1,1383 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * statusstack.c - empilement d'informations de statut + * + * Copyright (C) 2015-2024 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 "statusstack.h" + + +#include <assert.h> +#include <malloc.h> +#include <string.h> + + +#include <i18n.h> + + +#include "helpers.h" +#include "statusstack-int.h" +#include "../core/global.h" + + + +/* -------------------------- GESTION GENERALE DES STATUTS -------------------------- */ + + +/* Liste des propriétés */ + +typedef enum _StatusStackProperty { + +    PROP_0,                                 /* Réservé                     */ + +    PROP_SHOW_BOTTOM,                       /* Affichage de la zone inf.   */ + +    N_PROPERTIES + +} StatusStackProperty; + +static GParamSpec *_status_stack_properties[N_PROPERTIES] = { NULL, }; + + +/* Source d'affichage par défaut */ +#define gtk_status_stack_default_source gtk_status_stack_show_simple_message + + +/* Initialise la classe des barres de statut améliorées. */ +static void gtk_status_stack_class_init(GtkStatusStackClass *); + +/* Initialise une instance de barre de statut améliorée. */ +static void gtk_status_stack_init(GtkStatusStack *); + +/* Supprime toutes les références externes. */ +static void gtk_status_stack_dispose(GtkStatusStack *); + +/* Procède à la libération totale de la mémoire. */ +static void gtk_status_stack_finalize(GtkStatusStack *); + +/* Note le changement de verrouillage du stockage sécurisé. */ +static void gtk_status_stack_on_secret_storage_lock_update(GSecretStorage *, GtkStatusStack *); + +/* Met à jour dans la barre les débits réseau observés. */ +static gboolean gtk_status_stack_update_network_stats(GtkStatusStack *); + + + +/* --------------------- IMPLEMENTATION DES FONCTIONS DE CLASSE --------------------- */ + + +/* Met à jour une propriété d'instance GObject. */ +static void gtk_status_stack_set_property(GObject *, guint, const GValue *, GParamSpec *); + +/* Fournit la valeur d'une propriété d'instance GObject. */ +static void gtk_status_stack_get_property(GObject *, guint, GValue *, GParamSpec *); + + + +/* ----------------------- MISE EN AVANT DES MESSAGES SIMPLES ----------------------- */ + + +/* S'assure de l'affichage à jour de la partie "default". */ +static gboolean gtk_status_stack_show_simple_message(gpointer); + + + +/* -------------------- STATUT DES INFORMATIONS DE DESASSEMBLAGE -------------------- */ + + +/* Navigation au sein d'assemblage */ +struct _navigation_info_t +{ +    char *segment;                          /* Segment d'appartenance      */ + +    mrange_t current;                       /* Emplacement correspondant   */ + +    VMPA_BUFFER(phys);                      /* Localisation physique       */ +    VMPA_BUFFER(virt);                      /* Localisation virtuelle      */ + +    char *symbol;                           /* Eventuel symbole concerné   */ + +    char *format;                           /* Architecture et format      */ +    char *details;                          /* Encodage de l'instruction   */ + +}; + + +/* Met en place le suivi d'informations de navigation. */ +static void init_navigation_info(navigation_info_t *); + +/* Supprime l'empreinte mémoire d'informations de navigation. */ +static void fini_navigation_info(navigation_info_t *); + +/* S'assure de l'affichage à jour de la partie "navigation". */ +static gboolean gtk_status_stack_show_current_location(gpointer); + +/* Réagit à un clic sur l'icône de zoom. */ +static void gtk_status_stack_on_zoom_icon_press(GtkEntry *, GtkEntryIconPosition, GtkStatusStack *); + + + +/* -------------------------- STATUT DES SUIVIS D'ACTIVITE -------------------------- */ + + +/* Informations de progression */ +typedef struct _activity_status_t +{ +    activity_id_t id;                       /* Identifiant unique          */ + +    char *message;                          /* Indication à faire valoir   */ + +    unsigned long current;                  /* Position courante           */ +    unsigned long max;                      /* Couverture à parcourir      */ + +    double last_updated;                    /* Dernière valeur poussée     */ + +} activity_status_t; + + +/* Mémorisation des progressions au sein d'activités */ +struct _activity_info_t +{ +    GMutex access;                          /* Accès à la pile             */ + +    activity_id_t generator;                /* Générateur de séquence      */ + +    activity_status_t *statuses;            /* Statuts de progression      */ +    size_t count;                           /* Nombre de ces statuts       */ + +    guint tag;                              /* Identifiant de mise à jour  */ + +}; + + +/* Met en place le suivi d'informations d'activité. */ +static void init_activity_info(activity_info_t *); + +/* Supprime l'empreinte mémoire d'informations d'activité. */ +static void fini_activity_info(activity_info_t *); + +/* Recherche les indications de statut d'une activité donnée. */ +static activity_status_t *find_activity_status_by_id(activity_info_t *, activity_id_t); + +/* S'assure de l'affichage à jour de la partie "activité". */ +static gboolean gtk_status_stack_show_current_activity(gpointer); + + + +/* ---------------------------------------------------------------------------------- */ +/*                            GESTION GENERALE DES STATUTS                            */ +/* ---------------------------------------------------------------------------------- */ + + +/* Détermine le type du composant d'affichage générique. */ +G_DEFINE_TYPE(GtkStatusStack, gtk_status_stack, GTK_TYPE_BOX); + + +/****************************************************************************** +*                                                                             * +*  Paramètres  : class = classe GTK à initialiser.                            * +*                                                                             * +*  Description : Initialise la classe des barres de statut améliorées.        * +*                                                                             * +*  Retour      : -                                                            * +*                                                                             * +*  Remarques   : -                                                            * +*                                                                             * +******************************************************************************/ + +static void gtk_status_stack_class_init(GtkStatusStackClass *class) +{ +    GObjectClass *object;                   /* Plus haut niveau équivalent */ +    GtkWidgetClass *widget;                 /* Classe de haut niveau       */ + +    object = G_OBJECT_CLASS(class); + +    object->dispose = (GObjectFinalizeFunc/* ! */)gtk_status_stack_dispose; +    object->finalize = (GObjectFinalizeFunc)gtk_status_stack_finalize; +    object->set_property = gtk_status_stack_set_property; +    object->get_property = gtk_status_stack_get_property; + +    _status_stack_properties[PROP_SHOW_BOTTOM] = +        g_param_spec_boolean("show-bottom", NULL, NULL, +                             TRUE, +                             G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); + +    g_object_class_install_properties(object, N_PROPERTIES, _status_stack_properties); + +    widget = GTK_WIDGET_CLASS(class); + +    gtk_widget_class_set_template_from_resource(widget, "/re/chrysalide/framework/gtkext/statusstack.ui"); + +    gtk_widget_class_bind_template_callback_full(widget, BUILDER_CB(gtk_status_stack_on_zoom_icon_press)); + +    gtk_widget_class_bind_template_child(widget, GtkStatusStack, main); + +    gtk_widget_class_bind_template_child(widget, GtkStatusStack, def_label); + +    gtk_widget_class_bind_template_child(widget, GtkStatusStack, nav_segment); +    gtk_widget_class_bind_template_child(widget, GtkStatusStack, nav_phys); +    gtk_widget_class_bind_template_child(widget, GtkStatusStack, nav_virt); +    gtk_widget_class_bind_template_child(widget, GtkStatusStack, nav_offset); +    gtk_widget_class_bind_template_child(widget, GtkStatusStack, nav_format); +    gtk_widget_class_bind_template_child(widget, GtkStatusStack, nav_details); +    gtk_widget_class_bind_template_child(widget, GtkStatusStack, zoom); + +    gtk_widget_class_bind_template_child(widget, GtkStatusStack, activity_message); +    gtk_widget_class_bind_template_child(widget, GtkStatusStack, activity_progress); + +    gtk_widget_class_bind_template_child(widget, GtkStatusStack, lock_update); + +    gtk_widget_class_bind_template_child(widget, GtkStatusStack, net_recv_speed); +    gtk_widget_class_bind_template_child(widget, GtkStatusStack, net_send_speed); + +    gtk_widget_class_bind_template_child(widget, GtkStatusStack, bottom_toggler); + +} + + +/****************************************************************************** +*                                                                             * +*  Paramètres  : stack = composant GTK à initialiser.                         * +*                                                                             * +*  Description : Initialise une instance de barre de statut améliorée.        * +*                                                                             * +*  Retour      : -                                                            * +*                                                                             * +*  Remarques   : -                                                            * +*                                                                             * +******************************************************************************/ + +static void gtk_status_stack_init(GtkStatusStack *stack) +{ +    gtk_widget_init_template(GTK_WIDGET(stack)); + +    stack->def_source = gtk_status_stack_default_source; + +    stack->msg = NULL; + +    stack->nav_info = calloc(1, sizeof(navigation_info_t)); +    init_navigation_info(stack->nav_info); + +    stack->activity_info = calloc(1, sizeof(activity_info_t)); +    init_activity_info(stack->activity_info); + +    /* Suivi des évolutions relatives au stockage sécurisé */ + +    stack->storage = get_secret_storage(); + +    g_signal_connect(stack->storage, "lock-update", +                     G_CALLBACK(gtk_status_stack_on_secret_storage_lock_update), stack); + +    gtk_status_stack_on_secret_storage_lock_update(stack->storage, stack); + +    /* Suivi des débits de connexion */ + +    stack->next_index = 0; + +    stack->network_update_tag = g_timeout_add(NETWORK_UPDATE_INTERVAL, +                                              G_SOURCE_FUNC(gtk_status_stack_update_network_stats), stack); + +    /* Premier affichage... */ + +    gtk_status_stack_reset_to_default(stack); + +} + + +/****************************************************************************** +*                                                                             * +*  Paramètres  : stack = instance d'objet GLib à traiter.                     * +*                                                                             * +*  Description : Supprime toutes les références externes.                     * +*                                                                             * +*  Retour      : -                                                            * +*                                                                             * +*  Remarques   : -                                                            * +*                                                                             * +******************************************************************************/ + +static void gtk_status_stack_dispose(GtkStatusStack *stack) +{ +    if (stack->storage != NULL) +        g_signal_handlers_disconnect_by_func(stack->storage, +                                             gtk_status_stack_on_secret_storage_lock_update, stack); + +    g_clear_object(&stack->storage); + +    g_source_remove(stack->network_update_tag); + +    gtk_widget_dispose_template(GTK_WIDGET(stack), GTK_TYPE_STATUS_STACK); + +    G_OBJECT_CLASS(gtk_status_stack_parent_class)->dispose(G_OBJECT(stack)); + +} + + +/****************************************************************************** +*                                                                             * +*  Paramètres  : stack = instance d'objet GLib à traiter.                     * +*                                                                             * +*  Description : Procède à la libération totale de la mémoire.                * +*                                                                             * +*  Retour      : -                                                            * +*                                                                             * +*  Remarques   : -                                                            * +*                                                                             * +******************************************************************************/ + +static void gtk_status_stack_finalize(GtkStatusStack *stack) +{ +    if (stack->msg != NULL) +        free(stack->msg); + +    fini_navigation_info(stack->nav_info); +    free(stack->nav_info); + +    fini_activity_info(stack->activity_info); +    free(stack->activity_info); + +    G_OBJECT_CLASS(gtk_status_stack_parent_class)->finalize(G_OBJECT(stack)); + +} + + +/****************************************************************************** +*                                                                             * +*  Paramètres  : -                                                            * +*                                                                             * +*  Description : Crée une nouvelle instance de barre de statut.               * +*                                                                             * +*  Retour      : Composant GTK mis en place.                                  * +*                                                                             * +*  Remarques   : -                                                            * +*                                                                             * +******************************************************************************/ + +GtkStatusStack *gtk_status_stack_new(void) +{ +    GtkStatusStack *result;                 /* Instance à retourner        */ + +    result = g_object_new(GTK_TYPE_STATUS_STACK, NULL); + +    return result; + +} + + +/****************************************************************************** +*                                                                             * +*  Paramètres  : stack = barre de statut à actualiser.                        * +*                                                                             * +*  Description : Réinitialise la barre de statut à son stade par défaut.      * +*                                                                             * +*  Retour      : -                                                            * +*                                                                             * +*  Remarques   : -                                                            * +*                                                                             * +******************************************************************************/ + +void gtk_status_stack_reset_to_default(GtkStatusStack *stack) +{ +    /** +     * Une amélioration possible serait de passer à g_idle_add_once(), +     * et de s'affranchir des retours G_SOURCE_REMOVE systématiques, +     * mais la fonction n'est disponible qu'à partir de la GLib 2.74. +     */ + +    g_idle_add(stack->def_source, stack); + +} + + +/****************************************************************************** +*                                                                             * +*  Paramètres  : storage = gardien des secrets impliqué.                      * +*                stack   = barre de statut à actualiser.                      * +*                                                                             * +*  Description : Note le changement de verrouillage du stockage sécurisé.     * +*                                                                             * +*  Retour      : -                                                            * +*                                                                             * +*  Remarques   : -                                                            * +*                                                                             * +******************************************************************************/ + +static void gtk_status_stack_on_secret_storage_lock_update(GSecretStorage *storage, GtkStatusStack *stack) +{ +    if (!g_secret_storage_has_key(stack->storage)) +    { +        gtk_widget_set_sensitive(GTK_WIDGET(stack->lock_update), false); +        gtk_button_set_icon_name(GTK_BUTTON(stack->lock_update), "nolock-symbolic"); +    } +    else +    { +        gtk_widget_set_sensitive(GTK_WIDGET(stack->lock_update), true); + +        if (g_secret_storage_is_locked(stack->storage)) +            gtk_button_set_icon_name(GTK_BUTTON(stack->lock_update), "locked-symbolic"); +        else +            gtk_button_set_icon_name(GTK_BUTTON(stack->lock_update), "unlocked-symbolic"); + +    } + +} + + +/****************************************************************************** +*                                                                             * +*  Paramètres  : stack = barre de statut à actualiser.                        * +*                                                                             * +*  Description : Met à jour dans la barre les débits réseau observés.         * +*                                                                             * +*  Retour      : G_SOURCE_CONTINUE pour poursuivre les mises à jour.          * +*                                                                             * +*  Remarques   : -                                                            * +*                                                                             * +******************************************************************************/ + +static gboolean gtk_status_stack_update_network_stats(GtkStatusStack *stack) +{ +    gboolean result;                        /* Indication à retourner      */ +    gint64 timestamp;                       /* Position temporelle         */ +    size_t received;                        /* Quantité d'octets reçus     */ +    size_t sent;                            /* Quantité d'octets émis      */ +    gint64 diff_time;                       /* Différentiel de temps       */ +    size_t diff_bytes;                      /* Différentiel de volume      */ +    double speed;                           /* Débit de transfert constaté */ +    size_t i;                               /* Boucle de parcours          */ +    char *value;                            /* Valeur à afficher           */ + +    const char *units[] = { _("b/s"), _("kb/s"), _("Mb/s"), _("Gb/s"), _("Tb/s") }; + +    result = G_SOURCE_CONTINUE; + +    /* Mémorisation des données */ + +    timestamp = g_get_monotonic_time(); + +    get_network_stats(&received, &sent); + +    if (stack->next_index < NETWORK_UPDATE_COUNT) +    { +        stack->last_bytes_received[stack->next_index] = received; +        stack->last_bytes_sent[stack->next_index] = sent; +        stack->last_timestamps[stack->next_index] = timestamp; + +        stack->next_index++; + +    } +    else +    { +        memcpy(stack->last_bytes_received, stack->last_bytes_received + 1, +               (NETWORK_UPDATE_COUNT - 1) * sizeof(size_t)); + +        memcpy(stack->last_bytes_sent, stack->last_bytes_sent + 1, +               (NETWORK_UPDATE_COUNT - 1) * sizeof(size_t)); + +        memcpy(stack->last_timestamps, stack->last_timestamps + 1, +               (NETWORK_UPDATE_COUNT - 1) * sizeof(gint64)); + +        stack->last_bytes_received[NETWORK_UPDATE_COUNT - 1] = received; +        stack->last_bytes_sent[NETWORK_UPDATE_COUNT - 1] = sent; +        stack->last_timestamps[NETWORK_UPDATE_COUNT - 1] = timestamp; + +    } + +    if (stack->next_index < NETWORK_UPDATE_COUNT) +        goto done; + +    diff_time = stack->last_timestamps[NETWORK_UPDATE_COUNT - 1] - stack->last_timestamps[0]; + +    /* Débit de réception */ + +    diff_bytes = stack->last_bytes_received[NETWORK_UPDATE_COUNT - 1] - stack->last_bytes_received[0]; + +    speed = (diff_bytes * 1000000) / diff_time; + +    for (i = 0; i < G_N_ELEMENTS(units); i++) +    { +        if (speed < 1024) +            break; + +        speed /= 1024; + +    } + +    if (i == 0) +        asprintf(&value, "%d %s", (int)speed, units[i]); +    else +        asprintf(&value, "%.1f %s", speed, units[i]); + +    gtk_label_set_label(stack->net_recv_speed, value); + +    free(value); + +    /* Débit de émission */ + +    diff_bytes = stack->last_bytes_sent[NETWORK_UPDATE_COUNT - 1] - stack->last_bytes_sent[0]; + +    speed = (diff_bytes * 1000000) / diff_time; + +    for (i = 0; i < G_N_ELEMENTS(units); i++) +    { +        if (speed < 1024) +            break; + +        speed /= 1024; + +    } + +    if (i == 0) +        asprintf(&value, "%d %s", (int)speed, units[i]); +    else +        asprintf(&value, "%.1f %s", speed, units[i]); + +    gtk_label_set_label(stack->net_send_speed, value); + +    free(value); + + done: + +    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 à prendre en compte.                        * +*                pspec   = définition de la propriété.                        * +*                                                                             * +*  Description : Met à jour une propriété d'instance GObject.                 * +*                                                                             * +*  Retour      : -                                                            * +*                                                                             * +*  Remarques   : -                                                            * +*                                                                             * +******************************************************************************/ + +static void gtk_status_stack_set_property(GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) +{ +    GtkStatusStack *stack;                  /* Version spécialisée         */ + +    stack = GTK_STATUS_STACK(object); + +    switch (prop_id) +    { +        case PROP_SHOW_BOTTOM: +            gtk_toggle_button_set_active(stack->bottom_toggler, g_value_get_boolean(value)); +            break; + +        default: +            G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec); +            break; + +    } + +} + + +/****************************************************************************** +*                                                                             * +*  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_status_stack_get_property(GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) +{ +    GtkStatusStack *stack;                  /* Version spécialisée         */ + +    stack = GTK_STATUS_STACK(object); + +    switch (prop_id) +    { +        case PROP_SHOW_BOTTOM: +            g_value_set_boolean(value, gtk_toggle_button_get_active(stack->bottom_toggler)); +            break; + +        default: +            G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec); +            break; + +    } + +} + + + +/* ---------------------------------------------------------------------------------- */ +/*                         MISE EN AVANT DES MESSAGES SIMPLES                         */ +/* ---------------------------------------------------------------------------------- */ + + +/****************************************************************************** +*                                                                             * +*  Paramètres  : stack = barre de statut à actualiser.                        * +*                msg   = simple message à faire paraître.                     * +*                                                                             * +*  Description : Inscrit un message simple dans la barre de statut.           * +*                                                                             * +*  Retour      : -                                                            * +*                                                                             * +*  Remarques   : -                                                            * +*                                                                             * +******************************************************************************/ + +void gtk_status_stack_display_message(GtkStatusStack *stack, const char *msg) +{ +    if (stack->msg != NULL) +        free(stack->msg); + +    if (msg != NULL) +        stack->msg = strdup(msg); +    else +        stack->msg = NULL; + +    gtk_status_stack_show_simple_message(stack); + +} + + +/****************************************************************************** +*                                                                             * +*  Paramètres  : data = pile de statuts à manipuler.                          * +*                                                                             * +*  Description : S'assure de l'affichage à jour de la partie "default".       * +*                                                                             * +*  Retour      : G_SOURCE_REMOVE pour une exécution unique.                   * +*                                                                             * +*  Remarques   : -                                                            * +*                                                                             * +******************************************************************************/ + +static gboolean gtk_status_stack_show_simple_message(gpointer data) +{ +    GtkStatusStack *stack;                  /* Version spécialisée         */ + +    stack = GTK_STATUS_STACK(data); + +    stack->def_source = gtk_status_stack_show_simple_message; + +    gtk_label_set_text(stack->def_label, stack->msg != NULL ? stack->msg : ""); + +    gtk_stack_set_visible_child_name(stack->main, "default"); + +    return G_SOURCE_REMOVE; + +} + + + +/* ---------------------------------------------------------------------------------- */ +/*                      STATUT DES INFORMATIONS DE DESASSEMBLAGE                      */ +/* ---------------------------------------------------------------------------------- */ + + +/****************************************************************************** +*                                                                             * +*  Paramètres  : info = informations à initialiser.                           * +*                                                                             * +*  Description : Met en place le suivi d'informations de navigation.          * +*                                                                             * +*  Retour      : -                                                            * +*                                                                             * +*  Remarques   : -                                                            * +*                                                                             * +******************************************************************************/ + +static void init_navigation_info(navigation_info_t *info) +{ +    info->segment = NULL; + +    info->symbol = NULL; + +    info->format = NULL; +    info->details = NULL; + +} + + +/****************************************************************************** +*                                                                             * +*  Paramètres  : info = informations à libérer de la mémoire.                 * +*                                                                             * +*  Description : Supprime l'empreinte mémoire d'informations de navigation.   * +*                                                                             * +*  Retour      : -                                                            * +*                                                                             * +*  Remarques   : -                                                            * +*                                                                             * +******************************************************************************/ + +static void fini_navigation_info(navigation_info_t *info) +{ +    if (info->segment != NULL) +        free(info->segment); + +    if (info->symbol != NULL) +        free(info->symbol); + +    if (info->format != NULL) +        free(info->format); + +    if (info->details != NULL) +        free(info->details); + +} + + +/****************************************************************************** +*                                                                             * +*  Paramètres  : stack   = barre de statut à actualiser.                      * +*                range   = emplacement à mettre en valeur.                    * +*                segment = zone de binaire d'appartenance.                    * +*                symbol  = éventuelle position par rapport à un symbole.      * +*                format  = format du binaire manipulé                         * +*                details = détails supplémentaires (liés à l'encodage ?)      * +*                                                                             * +*  Description : Actualise les informations liées une position d'assemblage.  * +*                                                                             * +*  Retour      : -                                                            * +*                                                                             * +*  Remarques   : -                                                            * +*                                                                             * +******************************************************************************/ + +void gtk_status_stack_update_current_location(GtkStatusStack *stack, const mrange_t *range, const char *segment, const char *symbol, const char *format, const char *details) +{ +    navigation_info_t *info;                /* Informations à constituer   */ +    const vmpa2t *addr;                     /* Localisation de départ      */ + +    info = stack->nav_info; + +    if (cmp_mrange(&info->current, range) == 0) +        goto useless; + +    /* Zone d'appartenance */ + +    if (segment != NULL) +        info->segment = strdup(segment); +    else +        info->segment = NULL; + +    /* Adresses de base */ + +    copy_mrange(&info->current, range); + +    addr = get_mrange_addr(range); + +    vmpa2_phys_to_string(addr, MDS_UNDEFINED, info->phys, NULL); + +    vmpa2_virt_to_string(addr, MDS_UNDEFINED, info->virt, NULL); + +    /* Symbole concerné */ + +    if (symbol != NULL) +        info->symbol = strdup(symbol); +    else +        info->symbol = NULL; + +    /* Architecture & format */ + +    info->format = strdup(format); + +    if (details != NULL) +        info->details = strdup(details); +    else +        info->details = NULL; + +    /* Nettoyage et conclusion */ + +    gtk_status_stack_show_current_location(stack); + + useless: + +    ; + +} + + +/****************************************************************************** +*                                                                             * +*  Paramètres  : data = pile de statuts à manipuler.                          * +*                                                                             * +*  Description : S'assure de l'affichage à jour de la partie "navigation".    * +*                                                                             * +*  Retour      : G_SOURCE_REMOVE pour une exécution unique.                   * +*                                                                             * +*  Remarques   : -                                                            * +*                                                                             * +******************************************************************************/ + +static gboolean gtk_status_stack_show_current_location(gpointer data) +{ +    GtkStatusStack *stack;                  /* Version spécialisée         */ +    navigation_info_t *info;                /* Informations à constituer   */ +    char raw_pos[6 + VMPA_MAX_LEN + 1];     /* Formatage final en direct   */ + +    stack = GTK_STATUS_STACK(data); + +    stack->def_source = gtk_status_stack_show_current_location; + +    info = stack->nav_info; + +    /* Première partie : navigation */ + +    gtk_label_set_text(stack->nav_segment, info->segment != NULL ? info->segment : ""); + +    snprintf(raw_pos, sizeof(raw_pos), "phys: %s", info->phys); + +    gtk_label_set_text(stack->nav_phys, raw_pos); + +    snprintf(raw_pos, sizeof(raw_pos), "virt: %s", info->virt); + +    gtk_label_set_text(stack->nav_virt, raw_pos); + +    gtk_label_set_text(stack->nav_offset, info->symbol != NULL ? info->symbol : ""); + +    /* Seconde partie : format & architecture */ + +    gtk_label_set_text(stack->nav_format, info->format); + +    gtk_label_set_text(stack->nav_details, info->details != NULL ? info->details : ""); + +    /* Conclusion */ + +    gtk_stack_set_visible_child_name(stack->main, "navigation"); + +    return G_SOURCE_REMOVE; + +} + + +/****************************************************************************** +*                                                                             * +*  Paramètres  : entry    = zone de texte visée par la procédure.             * +*                icon_pos = position de l'image associée à l'entrée.          * +*                stack    = composant graphique de gestion des statuts.       * +*                                                                             * +*  Description : Réagit à un clic sur l'icône de zoom.                        * +*                                                                             * +*  Retour      : -                                                            * +*                                                                             * +*  Remarques   : -                                                            * +*                                                                             * +******************************************************************************/ + +static void gtk_status_stack_on_zoom_icon_press(GtkEntry *entry, GtkEntryIconPosition icon_pos, GtkStatusStack *stack) +{ +#if 0 +    GtkWidget *popup;                       /* Popup à faire surgir        */ +    GdkRectangle rect;                      /* Zone précise à cibler       */ + +    popup = gtk_popover_new(); + +    gtk_entry_get_icon_area(entry, GTK_ENTRY_ICON_SECONDARY, &rect); +    gtk_popover_set_pointing_to(GTK_POPOVER(popup), &rect); + +    gtk_widget_show(popup); +#endif +} + + +/* ---------------------------------------------------------------------------------- */ +/*                            STATUT DES SUIVIS D'ACTIVITE                            */ +/* ---------------------------------------------------------------------------------- */ + + +/****************************************************************************** +*                                                                             * +*  Paramètres  : info = informations à initialiser.                           * +*                                                                             * +*  Description : Met en place le suivi d'informations d'activité.             * +*                                                                             * +*  Retour      : -                                                            * +*                                                                             * +*  Remarques   : -                                                            * +*                                                                             * +******************************************************************************/ + +static void init_activity_info(activity_info_t *info) +{ +    g_mutex_init(&info->access); + +    info->generator = NO_ACTIVITY_ID; + +    info->statuses = NULL; +    info->count = 0; + +    info->tag = 0; + +} + + +/****************************************************************************** +*                                                                             * +*  Paramètres  : info = informations à libérer de la mémoire.                 * +*                                                                             * +*  Description : Supprime l'empreinte mémoire d'informations d'activité.      * +*                                                                             * +*  Retour      : -                                                            * +*                                                                             * +*  Remarques   : -                                                            * +*                                                                             * +******************************************************************************/ + +static void fini_activity_info(activity_info_t *info) +{ +    size_t i;                               /* Boucle de parcours          */ + +    if (info->tag != 0) +        g_source_remove(info->tag); + +    info->tag = 0; + +    for (i = 0; i < info->count; i++) +    { +        if (info->statuses[i].message != NULL) +            free(info->statuses[i].message); +    } + +    if (info->statuses != NULL) +    { +        free(info->statuses); +        info->statuses = NULL; +    } + +    info->count = 0; + +    g_mutex_clear(&info->access); + +} + + +/****************************************************************************** +*                                                                             * +*  Paramètres  : info = informations relatives aux activités à consulter.     * +*                id   = identifiant de l'activité à cibler.                   * +*                                                                             * +*  Description : Recherche les indications de statut d'une activité donnée.   * +*                                                                             * +*  Retour      : Structure d'encadrement trouvée ou NULL.                     * +*                                                                             * +*  Remarques   : -                                                            * +*                                                                             * +******************************************************************************/ + +static activity_status_t *find_activity_status_by_id(activity_info_t *info, activity_id_t id) +{ +    activity_status_t *result;              /* Statut trouvé à renvoyer    */ +    size_t i;                               /* Boucle de parcours          */ + +    result = NULL; + +    assert(!g_mutex_trylock(&info->access)); + +    for (i = 0; i < info->count; i++) +        if (info->statuses[i].id == id) +        { +            result = info->statuses + i; +            break; +        } + +    return result; + +} + + +/****************************************************************************** +*                                                                             * +*  Paramètres  : stack = barre de statut à actualiser.                        * +*                msg   = nouveau message de statut à copier.                  * +*                max   = taille de la plage à parcourir.                      * +*                                                                             * +*  Description : Démarre le suivi d'une nouvelle activité.                    * +*                                                                             * +*  Retour      : -                                                            * +*                                                                             * +*  Remarques   : -                                                            * +*                                                                             * +******************************************************************************/ + +activity_id_t gtk_status_stack_add_activity(GtkStatusStack *stack, const char *msg, unsigned long max) +{ +    activity_id_t result;                   /* Numéro unique à renvoyer    */ +    activity_info_t *info;                  /* Informations à consulter    */ +    activity_status_t *new;                 /* Nouveau suivi d'activité    */ + +    info = stack->activity_info; + +    g_mutex_lock(&info->access); + +    while (1) +    { +        result = ++info->generator; + +        if (find_activity_status_by_id(info, result) == NULL) +            break; + +    } +    while (0); + +    info->statuses = realloc(info->statuses, ++info->count * sizeof(activity_status_t)); + +    new = info->statuses + info->count - 1; + +    /* Identifiant */ + +    new->id = result; + +    /* Intitulé */ + +    if (msg == NULL) +        new->message = NULL; +    else +        new->message = strdup(msg); + +    /* Valeur */ + +    new->current = 0; +    new->max = max; +    new->last_updated = 0; + +    /* Actualisation */ + +    if (info->tag != 0) +        g_source_remove(info->tag); + +    info->tag = g_idle_add(gtk_status_stack_show_current_activity, stack); + +    g_mutex_unlock(&info->access); + +    return result; + +} + + +/****************************************************************************** +*                                                                             * +*  Paramètres  : stack = barre de statut à actualiser.                        * +*                id    = identifiant de l'activité à cibler.                  * +*                msg   = nouveau message de statut à copier.                  * +*                                                                             * +*  Description : Actualise les informations concernant une activité.          * +*                                                                             * +*  Retour      : -                                                            * +*                                                                             * +*  Remarques   : -                                                            * +*                                                                             * +******************************************************************************/ + +void gtk_status_stack_update_activity_message(GtkStatusStack *stack, activity_id_t id, const char *msg) +{ +    activity_info_t *info;                  /* Informations à consulter    */ +    activity_status_t *status;              /* Suivi d'activité à traiter  */ +    bool msg_changed;                       /* Changement d'intitulé       */ + +    info = stack->activity_info; + +    g_mutex_lock(&info->access); + +    status = find_activity_status_by_id(info, id); + +    assert(status != NULL); + +    if (status == NULL) +        goto exit; + +    /* Intitulé */ + +    if (status->message != NULL) +    { +        if (msg == NULL) +            msg_changed = true; +        else +            msg_changed = (strcmp(status->message, msg) != 0); + +        free(status->message); + +    } +    else +        msg_changed = (msg != NULL); + +    if (msg == NULL) +        status->message = NULL; +    else +        status->message = strdup(msg); + +    /* On n'actualise que le sommet de la pile */ + +    if ((status - info->statuses + 1) == info->count && msg_changed) +    { +        if (info->tag != 0) +            g_source_remove(info->tag); + +        info->tag = g_idle_add(gtk_status_stack_show_current_activity, stack); + +    } + + exit: + +    g_mutex_unlock(&info->access); + +} + + +/****************************************************************************** +*                                                                             * +*  Paramètres  : stack = barre de statut à actualiser.                        * +*                id    = identifiant de l'activité à cibler.                  * +*                inc   = nouvelle valeur pour une progression donnée.         * +*                                                                             * +*  Description : Actualise la progression d'une activité.                     * +*                                                                             * +*  Retour      : -                                                            * +*                                                                             * +*  Remarques   : -                                                            * +*                                                                             * +******************************************************************************/ + +void gtk_status_stack_update_activity_value(GtkStatusStack *stack, activity_id_t id, unsigned long inc) +{ +    activity_info_t *info;                  /* Informations à consulter    */ +    activity_status_t *status;              /* Suivi d'activité à traiter  */ +    double new;                             /* Nouvelle progression        */ + +    info = stack->activity_info; + +    g_mutex_lock(&info->access); + +    status = find_activity_status_by_id(info, id); + +    assert(status != NULL); + +    if (status == NULL) +        goto exit; + +    /* Valeur */ + +    status->current += inc; + +    new = (status->current * 1.0) / status->max; + +    /* On n'actualise que le sommet de la pile */ + +    if ((status - info->statuses + 1) == info->count && (new - status->last_updated) > 0.1) +    { +        status->last_updated = new; + +        if (info->tag != 0) +            g_source_remove(info->tag); + +        info->tag = g_idle_add(gtk_status_stack_show_current_activity, stack); + +    } + + exit: + +    g_mutex_unlock(&info->access); + +} + + +/****************************************************************************** +*                                                                             * +*  Paramètres  : stack = barre de statut à actualiser.                        * +*                id    = identifiant de l'activité à cibler.                  * +*                extra = nouvelle échéance supplémentaire des traitements.    * +*                                                                             * +*  Description : Etend la portée des travaux d'une nouvelle activité.         * +*                                                                             * +*  Retour      : -                                                            * +*                                                                             * +*  Remarques   : -                                                            * +*                                                                             * +******************************************************************************/ + +void gtk_status_stack_extend_activity_max(GtkStatusStack *stack, activity_id_t id, unsigned long extra) +{ +    activity_info_t *info;                  /* Informations à consulter    */ +    activity_status_t *status;              /* Suivi d'activité à traiter  */ + +    info = stack->activity_info; + +    g_mutex_lock(&info->access); + +    status = find_activity_status_by_id(info, id); + +    assert(status != NULL); + +    if (status == NULL) +        goto exit; + +    /* Valeur */ + +    status->max += extra; + +    /* On n'actualise que le sommet de la pile */ + +    if ((status - info->statuses + 1) == info->count) +    { +        if (info->tag != 0) +            g_source_remove(info->tag); + +        info->tag = g_idle_add(gtk_status_stack_show_current_activity, stack); + +    } + + exit: + +    g_mutex_unlock(&info->access); + +} + + +/****************************************************************************** +*                                                                             * +*  Paramètres  : stack = barre de statut à actualiser.                        * +*                                                                             * +*  Description : Met fin au suivi d'une activité donnée.                      * +*                                                                             * +*  Retour      : -                                                            * +*                                                                             * +*  Remarques   : -                                                            * +*                                                                             * +******************************************************************************/ + +void gtk_status_stack_remove_activity(GtkStatusStack *stack, activity_id_t id) +{ +    activity_info_t *info;                  /* Informations à consulter    */ +    activity_status_t *status;              /* Suivi d'activité à traiter  */ +    bool is_last;                           /* Dernière position ?         */ + +    info = stack->activity_info; + +    g_mutex_lock(&info->access); + +    status = find_activity_status_by_id(info, id); + +    assert(status != NULL); + +    if (status == NULL) +        goto exit; + +    is_last = ((status - info->statuses + 1) == info->count); + +    /* Suppression des données */ + +    if (is_last) +    { +        if (info->tag != 0) +            g_source_remove(info->tag); +    } + +    if (status->message != NULL) +        free(status->message); + +    /* Réajustement des enregistrements */ + +    if (!is_last) +        memmove(status, status + 1, +                (((info->statuses + info->count) - status) - 1) * sizeof(activity_status_t)); + +    info->statuses = realloc(info->statuses, --info->count * sizeof(activity_status_t)); + +    /* Bascule vers un autre affichage ou actualisation ? */ + +    if (info->count == 0) +    { +        info->tag = 0; +        gtk_status_stack_reset_to_default(stack); +    } +    else if (is_last) +        info->tag = g_idle_add(gtk_status_stack_show_current_activity, stack); + + exit: + +    g_mutex_unlock(&info->access); + +} + + +/****************************************************************************** +*                                                                             * +*  Paramètres  : data = pile de statuts à manipuler.                          * +*                                                                             * +*  Description : S'assure de l'affichage à jour de la partie "activité".      * +*                                                                             * +*  Retour      : G_SOURCE_REMOVE pour une exécution unique.                   * +*                                                                             * +*  Remarques   : -                                                            * +*                                                                             * +******************************************************************************/ + +static gboolean gtk_status_stack_show_current_activity(gpointer data) +{ +    GtkStatusStack *stack;                  /* Version spécialisée         */ +    activity_info_t *info;                  /* Informations à consulter    */ +    activity_status_t *last;                /* Dernier statut à traiter    */ + +    stack = GTK_STATUS_STACK(data); + +    info = stack->activity_info; + +    g_mutex_lock(&info->access); + +    if (!g_source_is_destroyed(g_main_current_source())) +    { +        if (info->count > 0) +        { +            last = &info->statuses[info->count - 1]; + +            gtk_label_set_text(stack->activity_message, last->message); + +            gtk_progress_bar_set_fraction(stack->activity_progress, (last->current * 1.0) / last->max); + +            gtk_stack_set_visible_child_name(stack->main, "activity"); + +        } + +        info->tag = 0; + +    } + +    g_mutex_unlock(&info->access); + +    return G_SOURCE_REMOVE; + +} diff --git a/src/gtkext/gtkstatusstack.h b/src/gtkext/statusstack.h index f419014..96d008c 100644 --- a/src/gtkext/gtkstatusstack.h +++ b/src/gtkext/statusstack.h @@ -1,8 +1,8 @@  /* Chrysalide - Outil d'analyse de fichiers binaires - * gtkstatusstack.h - prototypes pour un empilement d'informations de statut + * statusstack.h - prototypes pour l'empilement d'informations de statut   * - * Copyright (C) 2015-2019 Cyrille Bagard + * Copyright (C) 2015-2024 Cyrille Bagard   *   *  This file is part of Chrysalide.   * @@ -21,40 +21,39 @@   */ -#ifndef _GTKEXT_GTKSTATUSSTACK_H -#define _GTKEXT_GTKSTATUSSTACK_H +#ifndef _GTKEXT_STATUSSTACK_H +#define _GTKEXT_STATUSSTACK_H  #include <gtk/gtk.h>  #include "../arch/vmpa.h" +#include "../glibext/helpers.h" -/* ------------------------- GESTION EXTERIEURE DE LA BARRE ------------------------- */ +/* -------------------------- GESTION GENERALE DES STATUTS -------------------------- */ -#define GTK_TYPE_STATUS_STACK            (gtk_status_stack_get_type()) -#define GTK_STATUS_STACK(obj)            (G_TYPE_CHECK_INSTANCE_CAST(obj, GTK_TYPE_STATUS_STACK, GtkStatusStack)) -#define GTK_STATUS_STACK_CLASS(klass)    (G_LOADED_BINARY_GET_CLASS(klass, GTK_TYPE_STATUS_STACK, GtkStatusStackClass)) -#define GTK_IS_STATUS_STACK(obj)         (G_TYPE_CHECK_INSTANCE_TYPE(obj, GTK_TYPE_STATUS_STACK)) -#define GTK_IS_STATUS_STACK_CLASS(obj)   (G_TYPE_CHECK_INSTANCE_TYPE(obj, GTK_TYPE_STATUS_STACK)) -#define GTK_STATUS_STACK_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS((obj), GTK_TYPE_STATUS_STACK, GtkStatusStackClass)) +#define GTK_TYPE_STATUS_STACK (gtk_status_stack_get_type()) +DECLARE_GTYPE(GtkStatusStack, gtk_status_stack, GTK, STATUS_STACK); -/* Abstration d'une gestion de barre de statut (instance) */ -typedef struct _GtkStatusStack GtkStatusStack; -/* Abstration d'une gestion de barre de statut (classe) */ -typedef struct _GtkStatusStackClass GtkStatusStackClass; +/* Crée une nouvelle instance de barre de statut. */ +GtkStatusStack *gtk_status_stack_new(void); +/* Réinitialise la barre de statut à son stade par défaut. */ +void gtk_status_stack_reset_to_default(GtkStatusStack *); -/* Détermine le type de la barre de statut améliorée. */ -GType gtk_status_stack_get_type(void); -/* Crée une nouvelle instance de barre de statut. */ -GtkStatusStack *gtk_status_stack_new(void); + +/* ----------------------- MISE EN AVANT DES MESSAGES SIMPLES ----------------------- */ + + +/* Inscrit un message simple dans la barre de statut. */ +void gtk_status_stack_display_message(GtkStatusStack *, const char *); @@ -62,10 +61,7 @@ GtkStatusStack *gtk_status_stack_new(void);  /* Actualise les informations liées une position d'assemblage. */ -void gtk_status_stack_update_current_location(GtkStatusStack *, const mrange_t *, const char *, const char *, const char *); - -/* Réinitialise les informations associées une position. */ -void gtk_status_stack_reset_current_location(GtkStatusStack *); +void gtk_status_stack_update_current_location(GtkStatusStack *, const mrange_t *, const char *, const char *, const char *, const char *); @@ -82,18 +78,18 @@ typedef unsigned long activity_id_t;  /* Démarre le suivi d'une nouvelle activité. */  activity_id_t gtk_status_stack_add_activity(GtkStatusStack *, const char *, unsigned long); -/* Etend la portée des travaux d'une nouvelle activité. */ -void gtk_status_stack_extend_activity(GtkStatusStack *, activity_id_t, unsigned long); -  /* Actualise les informations concernant une activité. */ -void gtk_status_stack_update_activity(GtkStatusStack *, activity_id_t, const char *); +void gtk_status_stack_update_activity_message(GtkStatusStack *, activity_id_t, const char *);  /* Actualise la progression d'une activité. */  void gtk_status_stack_update_activity_value(GtkStatusStack *, activity_id_t, unsigned long); +/* Etend la portée des travaux d'une nouvelle activité. */ +void gtk_status_stack_extend_activity_max(GtkStatusStack *, activity_id_t, unsigned long); +  /* Met fin au suivi d'une activité donnée. */  void gtk_status_stack_remove_activity(GtkStatusStack *, activity_id_t); -#endif  /* _GTKEXT_GTKSTATUSSTACK_H */ +#endif  /* _GTKEXT_STATUSSTACK_H */ diff --git a/src/gtkext/statusstack.ui b/src/gtkext/statusstack.ui new file mode 100644 index 0000000..0b7cd6d --- /dev/null +++ b/src/gtkext/statusstack.ui @@ -0,0 +1,214 @@ +<?xml version="1.0" encoding="UTF-8"?> +<interface> +    <template class="GtkStatusStack" parent="GtkBox"> + +        <!--property name="show-bottom" bind-source="bottom_toggler" bind-property="active" bind-flags="bidirectional|sync-create"/--> + +        <child> +            <object class="GtkStack" id="main"> +                <property name="margin-start">8</property> +                <property name="margin-end">8</property> +                <property name="hexpand">true</property> + +                <!-- Vide par défaut --> +                <child> +                    <object class="GtkStackPage"> +                        <property name="name">default</property> +                        <property name="child"> + +                            <object class="GtkLabel" id="def_label"> +                                <property name="hexpand">true</property> +                                <property name="halign">fill</property> +                                <property name="valign">baseline</property> +                                <property name="xalign">0</property> +                                <property name="label"></property> +                                <style> +                                    <class name="dim-label"/> +                                </style> +                            </object> + +                        </property> +                    </object> +                </child> + +                <!-- Informations pendant une navigation dans du contenu --> +                <child> +                    <object class="GtkStackPage"> +                        <property name="name">navigation</property> +                        <property name="child"> + +                            <object class="GtkBox"> +                                <property name="orientation">horizontal</property> +                                <property name="hexpand">true</property> +                                <property name="halign">fill</property> +                                <property name="valign">center</property> + +                                <!-- Première partie : navigation --> + +                                <child> +                                    <object class="GtkLabel" id="nav_segment"> +                                        <property name="xalign">0</property> +                                        <property name="label">-</property> +                                    </object> +                                </child> + +                                <child> +                                    <object class="GtkLabel" id="nav_phys"> +                                        <property name="xalign">0</property> +                                        <property name="label">-</property> +                                    </object> +                                </child> + +                                <child> +                                    <object class="GtkLabel" id="nav_virt"> +                                        <property name="xalign">0</property> +                                        <property name="label">-</property> +                                    </object> +                                </child> + +                                <child> +                                    <object class="GtkLabel" id="nav_offset"> +                                        <property name="xalign">0</property> +                                        <property name="hexpand">true</property> +                                        <property name="halign">fill</property> +                                        <property name="label">-</property> +                                    </object> +                                </child> + +                                <!-- Seconde partie : architecture --> + +                                <child> +                                    <object class="GtkLabel" id="nav_format"> +                                        <property name="xalign">0</property> +                                        <property name="label">-</property> +                                    </object> +                                </child> + +                                <child> +                                    <object class="GtkLabel" id="nav_details"> +                                        <property name="xalign">0</property> +                                        <property name="label">-</property> +                                    </object> +                                </child> + +                                <!-- Troisième partie : affichage --> + +                                <child> +                                    <object class="GtkEntry" id="zoom"> +                                        <property name="secondary-icon-name">go-up-symbolic</property> +                                        <signal name="icon-press" handler="gtk_status_stack_on_zoom_icon_press"/> +                                    </object> +                                </child> + +                            </object> + +                        </property> +                    </object> +                </child> + +                <!-- Informations liées à une activité en cours --> +                <child> +                    <object class="GtkStackPage"> +                        <property name="name">activity</property> +                        <property name="child"> + +                            <object class="GtkBox"> +                                <property name="orientation">horizontal</property> +                                <property name="hexpand">true</property> +                                <property name="halign">fill</property> +                                <property name="valign">center</property> + +                                <child> +                                    <object class="GtkLabel" id="activity_message"> +                                        <property name="xalign">0</property> +                                        <property name="margin-end">8</property> +                                        <property name="label">-</property> +                                    </object> +                                </child> + +                                <child> +                                    <object class="GtkProgressBar" id="activity_progress"> +                                        <property name="hexpand">true</property> +                                        <property name="halign">fill</property> +                                        <property name="valign">center</property> +                                        <property name="fraction">0</property> +                                    </object> +                                </child> + +                            </object> + +                        </property> +                    </object> +                </child> + +                <property name="visible-child-name">default</property> +            </object> +        </child> + +        <!-- Tronc commun --> + +        <child> +            <object class="GtkSeparator"> +                <property name="orientation">vertical</property> +            </object> +        </child> + +        <child> +            <object class="GtkToggleButton" id="lock_update"> +                <property name="sensitive">false</property> +                <property name="has-frame">false</property> +                <property name="icon-name">nolock-symbolic</property> +            </object> +        </child> + +        <child> +            <object class="GtkSeparator"> +                <property name="orientation">vertical</property> +            </object> +        </child> + +        <child> +            <object class="GtkImage"> +                <property name="margin-start">8</property> +                <property name="icon-name">pan-down-symbolic</property> +            </object> +        </child> +        <child> +            <object class="GtkLabel" id="net_recv_speed"> +                <property name="margin-start">8</property> +                <property name="margin-end">8</property> +                <property name="xalign">0</property> +                <property name="label">0 b/s</property> +            </object> +        </child> + +        <child> +            <object class="GtkImage"> +                <property name="icon-name">pan-up-symbolic</property> +            </object> +        </child> +        <child> +            <object class="GtkLabel" id="net_send_speed"> +                <property name="margin-start">8</property> +                <property name="margin-end">8</property> +                <property name="xalign">0</property> +                <property name="label">0 b/s</property> +            </object> +        </child> + +        <child> +            <object class="GtkSeparator"> +                <property name="orientation">vertical</property> +            </object> +        </child> + +        <child> +            <object class="GtkToggleButton" id="bottom_toggler"> +                <property name="has-frame">false</property> +                <property name="icon-name">dock-station-bottom-symbolic</property> +                <property name="action-name">win.toggle-bottom</property> +            </object> +        </child> + +    </template> +</interface> diff --git a/src/gtkext/tiledgrid.c b/src/gtkext/tiledgrid.c deleted file mode 100644 index 22b2680..0000000 --- a/src/gtkext/tiledgrid.c +++ /dev/null @@ -1,1143 +0,0 @@ - -/* Chrysalide - Outil d'analyse de fichiers binaires - * tiledgrid.c - composant d'affichage avec des chemins vers les composants contenus - * - * Copyright (C) 2018-2019 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 "tiledgrid.h" - - -#include <assert.h> -#include <ctype.h> -#include <malloc.h> -#include <string.h> - - -#include "../core/logs.h" - - - -/* -------------------------- GESTION DES TUILES AFFICHEES -------------------------- */ - - -/* Informations concernant une tuile */ -typedef struct _grid_tile_t -{ -    struct _grid_tile_t *parent;            /* Tuile parente               */ - -    GtkWidget *widget;                      /* Support d'affichage         */ - -    char *path;                             /* Chemin d'accès              */ - -    struct _grid_tile_t *children[2];       /* Tuiles encastrées ou 2xNULL */ - -} grid_tile_t; - - -#define IS_LEAF_TILE(t)                                 \ -    ({                                                  \ -        bool __result;                                  \ -        __result = GTK_IS_DOCK_STATION((t)->widget);    \ -        assert(__result || GTK_IS_PANED((t)->widget));  \ -        __result;                                       \ -    }) - - -/* Valide un chemin d'accès à une tuile. */ -static bool is_valid_tile_path(const char *); - -/* Crée une tuile finale d'affichage de panneaux. */ -static grid_tile_t *create_leaf_tile(const char *, GtkTiledGrid *); - -/* Crée une tuile intermédiaire d'affichage de panneaux. */ -static grid_tile_t *create_inter_tile(grid_tile_t *, bool, grid_tile_t *, grid_tile_t *); - -/* Supprime une tuile de la mémoire. */ -static void delete_tile(grid_tile_t *); - -/* Calcule la taille comme entre un chemin et celui d'une tuile. */ -static size_t compute_tile_score(const grid_tile_t *, const char *); - -/* Indique la tuile adaptée pour un chemin donné. */ -static grid_tile_t *find_suitable_tile(grid_tile_t **, const char *, GtkTiledGrid *); - -/* Découpe une tuile pour y insérer une zone. */ -static grid_tile_t *split_tile(grid_tile_t **, const char *, char, GtkTiledGrid *); - -/* Tente de mettre la main sur une station d'accueil. */ -static grid_tile_t *find_tile_for_widget(grid_tile_t *, GtkWidget *); - -/* Retire une moitié de tuile vide au plein profit de l'autre. */ -static void collapse_tile(grid_tile_t *, grid_tile_t *); - - - -/* --------------------------- INTERFACE DU COMPOSANT GTK --------------------------- */ - - -/* Conteneur pour un affichage en tuiles nommées (instance) */ -struct _GtkTiledGrid -{ -    GtkBin parent;                          /* A laisser en premier        */ - -    grid_tile_t *tiles;                     /* Tuiles représentées         */ - -    GPanelItem *def_panel;                  /* Panneau principal par défaut*/ - -}; - -/* Conteneur pour un affichage en tuiles nommées (classe) */ -struct _GtkTiledGridClass -{ -    GtkBinClass parent;                     /* A laisser en premier        */ - -    /* Signaux */ - -    void (* station_created) (GtkTiledGrid *, GtkDockStation *, gpointer); - -}; - - -/* Initialise la classe des conteneurs d'affichage en tuiles. */ -static void gtk_tiled_grid_class_init(GtkTiledGridClass *); - -/* Initialise une instance de conteneur d'affichage en tuiles. */ -static void gtk_tiled_grid_init(GtkTiledGrid *); - -/* Supprime toutes les références externes. */ -static void gtk_tiled_grid_dispose(GtkTiledGrid *); - -/* Procède à la libération totale de la mémoire. */ -static void gtk_tiled_grid_finalize(GtkTiledGrid *); - - - -/* ---------------------------------------------------------------------------------- */ -/*                            GESTION DES TUILES AFFICHEES                            */ -/* ---------------------------------------------------------------------------------- */ - - -/****************************************************************************** -*                                                                             * -*  Paramètres  : path = chemin destiné à sélectionner une tuile.              * -*                                                                             * -*  Description : Valide un chemin d'accès à une tuile.                        * -*                                                                             * -*  Retour      : true si le chemin est utilisable, false sinon.               * -*                                                                             * -*  Remarques   : -                                                            * -*                                                                             * -******************************************************************************/ - -static bool is_valid_tile_path(const char *path) -{ -    bool result;                            /* Bilan à retourner           */ -    size_t len;                             /* Taille du chemin            */ -    size_t i;                               /* Boucle de parcours          */ -    char c;                                 /* Caractère de chemin analysé */ - -    /** -     * M[NESWnesw]* -     */ - -    len = strlen(path); - -    result = (len >= 1); - -    if (result) -        result = (path[0] == 'M'); - -    for (i = 1; i < len && result; i++) -    { -        c = path[i]; - -        if (c == '\0') -            break; - -        result = (c == 'N' || c == 'n' -                  || c == 'E' || c == 'e' -                  || c == 'S' || c == 's' -                  || c == 'W' || c == 'w'); - -    } - -    return result; - -} - - -/****************************************************************************** -*                                                                             * -*  Paramètres  : path  = chemin d'accès à la future tuile.                    * -*  Paramètres  : tgrid = conteneur d'affichage en tuiles à manipuler.         * -*                                                                             * -*  Description : Crée une tuile finale d'affichage de panneaux.               * -*                                                                             * -*  Retour      : Structure mise en place.                                     * -*                                                                             * -*  Remarques   : -                                                            * -*                                                                             * -******************************************************************************/ - -static grid_tile_t *create_leaf_tile(const char *path, GtkTiledGrid *tgrid) -{ -    grid_tile_t *result;                    /* Structure à retourner       */ - -    result = (grid_tile_t *)malloc(sizeof(grid_tile_t)); - -    result->parent = NULL; - -    result->widget = gtk_dock_station_new(); -    gtk_widget_show(result->widget); - -    result->path = strdup(path); - -    result->children[0] = NULL; -    result->children[1] = NULL; - -    g_signal_emit_by_name(tgrid, "station-created", result->widget); - -    return result; - -} - - -/****************************************************************************** -*                                                                             * -*  Paramètres  : parent = tuile parente ou NULL si aucune.                    * -*                horiz  = indique le type d'orientation désiré.               * -*                first  = première tuile à intégrer.                          * -*                second = seconde tuile à intégrer.                           * -*                                                                             * -*  Description : Crée une tuile intermédiaire d'affichage de panneaux.        * -*                                                                             * -*  Retour      : Structure mise en place.                                     * -*                                                                             * -*  Remarques   : -                                                            * -*                                                                             * -******************************************************************************/ - -static grid_tile_t *create_inter_tile(grid_tile_t *parent, bool horiz, grid_tile_t *first, grid_tile_t *second) -{ -    grid_tile_t *result;                    /* Structure à retourner       */ -    GtkWidget *container;                   /* Conteneur à vider           */ - -    result = (grid_tile_t *)malloc(sizeof(grid_tile_t)); - -    result->parent = parent; - -    if (horiz) -        result->widget = gtk_paned_new(GTK_ORIENTATION_HORIZONTAL); -    else -        result->widget = gtk_paned_new(GTK_ORIENTATION_VERTICAL); - -    gtk_widget_show(result->widget); - -    result->path = NULL; - -    result->children[0] = first; -    result->children[1] = second; - -    /* Changement de propriétaire */ - -    container = gtk_widget_get_parent(first->widget); - -    if (container != NULL) -        gtk_container_remove(GTK_CONTAINER(container), first->widget); - -    g_object_ref(G_OBJECT(first->widget)); -    gtk_paned_pack1(GTK_PANED(result->widget), first->widget, TRUE, FALSE); - -    container = gtk_widget_get_parent(second->widget); - -    if (container != NULL) -        gtk_container_remove(GTK_CONTAINER(container), second->widget); - -    g_object_ref(G_OBJECT(second->widget)); -    gtk_paned_pack2(GTK_PANED(result->widget), second->widget, TRUE, FALSE); - -    return result; - -} - - -/****************************************************************************** -*                                                                             * -*  Paramètres  : tile = tuile à supprimer.                                    * -*                                                                             * -*  Description : Supprime une tuile de la mémoire.                            * -*                                                                             * -*  Retour      : -                                                            * -*                                                                             * -*  Remarques   : -                                                            * -*                                                                             * -******************************************************************************/ - -static void delete_tile(grid_tile_t *tile) -{ -    if (!IS_LEAF_TILE(tile)) -    { -        delete_tile(tile->children[0]); -        delete_tile(tile->children[1]); -    } - -    else -        free(tile->path); - -    g_object_unref(G_OBJECT(tile->widget)); - -    free(tile); - -} - - -/****************************************************************************** -*                                                                             * -*  Paramètres  : tile = tuile à analyser.                                     * -*                path = chemin final complet recherché.                       * -*                                                                             * -*  Description : Calcule la taille comme entre un chemin et celui d'une tuile.* -*                                                                             * -*  Retour      : Quantité de caractères communs.                              * -*                                                                             * -*  Remarques   : -                                                            * -*                                                                             * -******************************************************************************/ - -static size_t compute_tile_score(const grid_tile_t *tile, const char *path) -{ -    size_t result;                          /* Nombre de points à renvoyer */ -    size_t max;                             /* Taille du chemin de la tuile*/ -    size_t i;                               /* Boucle de parcours          */ -    size_t score_0;                         /* Score du sous-élément #1    */ -    size_t score_1;                         /* Score du sous-élément #2    */ - -    if (IS_LEAF_TILE(tile)) -    { -        max = strlen(tile->path); - -        if (strlen(path) < max) -            result = 0; - -        else -        { -            result = 0; - -            for (i = 0; i < max; i++) -            { -                if (tolower((unsigned char)tile->path[i]) == tolower((unsigned char)path[i])) -                    result++; -                else -                    break; -            } - -        } - -    } -    else -    { -        score_0 = compute_tile_score(tile->children[0], path); -        score_1 = compute_tile_score(tile->children[1], path); - -        result = score_0 > score_1 ? score_0 : score_1; - -    } - -    return result; - -} - - -/****************************************************************************** -*                                                                             * -*  Paramètres  : tile  = tuile ou NULL si aucune. [OUT]                       * -*                path  = chemin d'accès à la tuile visée.                     * -*                tgrid = conteneur d'affichage en tuiles à manipuler.         * -*                                                                             * -*  Description : Indique la tuile adaptée pour un chemin donné.               * -*                                                                             * -*  Retour      : Structure d'acceuil à disposition.                           * -*                                                                             * -*  Remarques   : -                                                            * -*                                                                             * -******************************************************************************/ - -static grid_tile_t *find_suitable_tile(grid_tile_t **tile, const char *path, GtkTiledGrid *tgrid) -{ -    grid_tile_t *result;                    /* Structure à renvoyer        */ -    size_t best_len;                        /* Taille du chemin associé    */ -    size_t score_0;                         /* Score du sous-élément #1    */ -    size_t score_1;                         /* Score du sous-élément #2    */ -    char *sub_path;                         /* Nouvelle tentative d'accès  */ -    grid_tile_t **best;                     /* Direction à prendre         */ -    unsigned char next;                     /* Prochaine étape             */ - -    /* Cas d'école : appel initial */ -    if (*tile == NULL) -    { -        assert(path[0] == 'M' && path[1] == '\0'); - -        result = create_leaf_tile("M", tgrid); -        *tile = result; - -    } - -    else -    { -        if (IS_LEAF_TILE(*tile)) -        { -            best_len = compute_tile_score(*tile, path); - -            assert(best_len > 0); - -            if (path[best_len] == '\0') -                result = *tile; - -            else -                result = split_tile(tile, path, path[best_len], tgrid); - -        } - -        else -        { -            score_0 = compute_tile_score((*tile)->children[0], path); -            score_1 = compute_tile_score((*tile)->children[1], path); - -            assert(score_0 > 0 || score_0 > 0); - -            if (score_0 == score_1) -            { -                sub_path = strndup(path, score_0); - -                score_0 = compute_tile_score((*tile)->children[0], sub_path); -                score_1 = compute_tile_score((*tile)->children[1], sub_path); - -                free(sub_path); - -            } - -            if (score_0 == score_1) -                result = split_tile(tile, path, path[score_0], tgrid); - -            else -            { -                if (score_0 > score_1) -                { -                    best = &(*tile)->children[0]; -                    best_len = score_0; -                } -                else -                { -                    best = &(*tile)->children[1]; -                    best_len = score_1; -                } - -                /** -                 * Si on vient de tomber une feuille, trois cas de figure : -                 *    - soit c'est elle qui est visée. -                 *    - soit on veut la diviser. -                 *    - soit on veut la diviser en englobant ses voisines. -                 */ - -                if (IS_LEAF_TILE(*best)) -                { -                    assert(best_len <= strlen(path)); - -                    next = path[best_len]; - -                    /* Premier cas */ -                    if (next == '\0') -                        result = *best; - -                    else -                    { -                        /* Second cas */ -                        if (islower(next)) -                            result = find_suitable_tile(best, path, tgrid); - -                        /* Troisième cas */ -                        else -                            result = split_tile(tile, path, next, tgrid); - -                    } - -                } - -                else -                    result = find_suitable_tile(best, path, tgrid); - -            } - -        } - -    } - -    assert(IS_LEAF_TILE(result)); - -    return result; - -} - - -/****************************************************************************** -*                                                                             * -*  Paramètres  : tile     = tuile à découper en deux. [OUT]                   * -*                path     = chemin d'accès à la future tuile.                 * -*                endpoint = désignation de la zone représentée.               * -*                tgrid    = conteneur d'affichage en tuiles à manipuler.      * -*                                                                             * -*  Description : Découpe une tuile pour y insérer une zone.                   * -*                                                                             * -*  Retour      : Structure fille mise en place.                               * -*                                                                             * -*  Remarques   : -                                                            * -*                                                                             * -******************************************************************************/ - -static grid_tile_t *split_tile(grid_tile_t **tile, const char *path, char endpoint, GtkTiledGrid *tgrid) -{ -    grid_tile_t *result;                    /* Création à retourner        */ -    GtkWidget *container;                   /* Conteneur à vider           */ -    grid_tile_t *new;                       /* Nouvelle tuile intermédiaire*/ - -    container = gtk_widget_get_parent((*tile)->widget); - -    /* Création */ - -    result = create_leaf_tile(path, tgrid); - -    /* Encapsulation */ - -    switch (endpoint) -    { -        case 'N': -        case 'n': -            new = create_inter_tile((*tile)->parent, false, result, *tile); -            break; - -        case 'E': -        case 'e': -            new = create_inter_tile((*tile)->parent, true, *tile, result); -            break; - -        case 'S': -        case 's': -            new = create_inter_tile((*tile)->parent, false, *tile, result); -            break; - -        case 'W': -        case 'w': -            new = create_inter_tile((*tile)->parent, true, result, *tile); -            break; - -        default: -            assert(false); -            new = NULL; -            break; - -    } - -    /* Connexions */ - -    *tile = new; - -    result->parent = new; - -    if (container != NULL) -    { -        g_object_ref(G_OBJECT(new->widget)); -        gtk_container_add(GTK_CONTAINER(container), new->widget); -    } - -    return result; - -} - - -/****************************************************************************** -*                                                                             * -*  Paramètres  : tile = tuile parente, prochaine victime de promotion.        * -*                side = côté de tuile amené à disparaître.                    * -*                                                                             * -*  Description : Retire une moitié de tuile vide au plein profit de l'autre.  * -*                                                                             * -*  Retour      : -                                                            * -*                                                                             * -*  Remarques   : -                                                            * -*                                                                             * -******************************************************************************/ - -static void collapse_tile(grid_tile_t *tile, grid_tile_t *side) -{ -    grid_tile_t *promoted;                  /* Tuile à faire remonter      */ -    GtkWidget *container;                   /* Conteneur à vider           */ - -    assert(!IS_LEAF_TILE(tile)); - -    /* Sélection du remplaçant */ - -    if (side == tile->children[0]) -        promoted = tile->children[1]; -    else -        promoted = tile->children[0]; - -    /* Etablissement d'une place nette */ - -    gtk_container_remove(GTK_CONTAINER(tile->widget), promoted->widget); - -    container = gtk_widget_get_parent(tile->widget); -    gtk_container_remove(GTK_CONTAINER(container), tile->widget); - -    delete_tile(side); - -    /* Promotion effective */ - -    tile->widget = promoted->widget; - -    tile->path = promoted->path; - -    tile->children[0] = promoted->children[0]; -    tile->children[1] = promoted->children[1]; - -    g_object_ref(G_OBJECT(promoted->widget)); -    gtk_container_add(GTK_CONTAINER(container), tile->widget); - -    free(promoted); - -} - - -/****************************************************************************** -*                                                                             * -*  Paramètres  : tile   = point de départ des recherches locales.             * -*                widget = composant graphique à retrouver.                    * -*                                                                             * -*  Description : Tente de mettre la main sur une station d'accueil.           * -*                                                                             * -*  Retour      : Eventuelle tuile trouvée ou NULL.                            * -*                                                                             * -*  Remarques   : -                                                            * -*                                                                             * -******************************************************************************/ - -static grid_tile_t *find_tile_for_widget(grid_tile_t *tile, GtkWidget *widget) -{ -    grid_tile_t *result;                    /* Tuile à retourner           */ - -    if (IS_LEAF_TILE(tile)) -        result = tile->widget == widget ? tile : NULL; - -    else -    { -        result = find_tile_for_widget(tile->children[0], widget); - -        if (result == NULL) -            result = find_tile_for_widget(tile->children[1], widget); - -    } - -    return result; - -} - - - -/* ---------------------------------------------------------------------------------- */ -/*                             INTERFACE DU COMPOSANT GTK                             */ -/* ---------------------------------------------------------------------------------- */ - - -/* Détermine le type du conteneur d'affichage en tuiles nommées. */ -G_DEFINE_TYPE(GtkTiledGrid, gtk_tiled_grid, GTK_TYPE_BIN) - - -/****************************************************************************** -*                                                                             * -*  Paramètres  : klass = classe GTK à initialiser.                            * -*                                                                             * -*  Description : Initialise la classe des conteneurs d'affichage en tuiles.   * -*                                                                             * -*  Retour      : -                                                            * -*                                                                             * -*  Remarques   : -                                                            * -*                                                                             * -******************************************************************************/ - -static void gtk_tiled_grid_class_init(GtkTiledGridClass *klass) -{ -    GObjectClass *object;                   /* Autre version de la classe  */ - -    object = G_OBJECT_CLASS(klass); - -    object->dispose = (GObjectFinalizeFunc/* ! */)gtk_tiled_grid_dispose; -    object->finalize = (GObjectFinalizeFunc)gtk_tiled_grid_finalize; - -    g_signal_new("station-created", -                 GTK_TYPE_TILED_GRID, -                 G_SIGNAL_RUN_LAST, -                 G_STRUCT_OFFSET(GtkTiledGridClass, station_created), -                 NULL, NULL, -                 g_cclosure_marshal_VOID__OBJECT, -                 G_TYPE_NONE, 1, GTK_TYPE_DOCK_STATION); - -} - - -/****************************************************************************** -*                                                                             * -*  Paramètres  : tgrid = instance GTK à initialiser.                          * -*                                                                             * -*  Description : Initialise une instance de conteneur d'affichage en tuiles.  * -*                                                                             * -*  Retour      : -                                                            * -*                                                                             * -*  Remarques   : -                                                            * -*                                                                             * -******************************************************************************/ - -static void gtk_tiled_grid_init(GtkTiledGrid *tgrid) -{ -    tgrid->tiles = NULL; - -    tgrid->def_panel = NULL; - -} - - -/****************************************************************************** -*                                                                             * -*  Paramètres  : tgrid = instance d'objet GLib à traiter.                     * -*                                                                             * -*  Description : Supprime toutes les références externes.                     * -*                                                                             * -*  Retour      : -                                                            * -*                                                                             * -*  Remarques   : -                                                            * -*                                                                             * -******************************************************************************/ - -static void gtk_tiled_grid_dispose(GtkTiledGrid *tgrid) -{ -    if (tgrid->tiles != NULL) -    { -        delete_tile(tgrid->tiles); -        tgrid->tiles = NULL; -    } - -    g_clear_object(&tgrid->def_panel); - -    G_OBJECT_CLASS(gtk_tiled_grid_parent_class)->dispose(G_OBJECT(tgrid)); - -} - - -/****************************************************************************** -*                                                                             * -*  Paramètres  : tgrid = instance d'objet GLib à traiter.                     * -*                                                                             * -*  Description : Procède à la libération totale de la mémoire.                * -*                                                                             * -*  Retour      : -                                                            * -*                                                                             * -*  Remarques   : -                                                            * -*                                                                             * -******************************************************************************/ - -static void gtk_tiled_grid_finalize(GtkTiledGrid *tgrid) -{ -    G_OBJECT_CLASS(gtk_tiled_grid_parent_class)->finalize(G_OBJECT(tgrid)); - -} - - -/****************************************************************************** -*                                                                             * -*  Paramètres  : -                                                            * -*                                                                             * -*  Description : Crée une nouvelle instance de conteneur avec tuiles.         * -*                                                                             * -*  Retour      : Composant GTK mis en place.                                  * -*                                                                             * -*  Remarques   : -                                                            * -*                                                                             * -******************************************************************************/ - -GtkWidget *gtk_tiled_grid_new(void) -{ -    return g_object_new(GTK_TYPE_TILED_GRID, NULL); - -} - - -/****************************************************************************** -*                                                                             * -*  Paramètres  : tgrid = conteneur d'affichage en tuiles à consulter.         * -*                                                                             * -*  Description : Donne le panneau fourni par défaut pour la zone principale.  * -*                                                                             * -*  Retour      : Panneau d'affichage par défault ou NULL.                     * -*                                                                             * -*  Remarques   : -                                                            * -*                                                                             * -******************************************************************************/ - -GPanelItem *gtk_tiled_grid_get_default_main_panel(const GtkTiledGrid *tgrid) -{ -    GPanelItem *result;                     /* Panneau à retourner         */ - -    result = tgrid->def_panel; - -    if (result != NULL) -        g_object_ref(G_OBJECT(result)); - -    return result; - -} - - -/****************************************************************************** -*                                                                             * -*  Paramètres  : tgrid = conteneur d'affichage en tuiles à modifier.          * -*                panel = panneau d'affichage par défault ou NULL.             * -*                                                                             * -*  Description : Fournit le panneau par défaut pour la zone principale.       * -*                                                                             * -*  Retour      : -                                                            * -*                                                                             * -*  Remarques   : -                                                            * -*                                                                             * -******************************************************************************/ - -void gtk_tiled_grid_set_default_main_panel(GtkTiledGrid *tgrid, GPanelItem *panel) -{ -    GtkWidget *widget;                      /* Composant GTK à retirer     */ -    GtkWidget *parent;                      /* Conteneur à vider           */ -    grid_tile_t *tile;                      /* Première tuile d'accueil    */ - -    if (tgrid->def_panel != NULL) -    { -        widget = gtk_dockable_build_widget(GTK_DOCKABLE(tgrid->def_panel)); - -        parent = gtk_widget_get_parent(widget); - -        if (parent != NULL) -            gtk_container_remove(GTK_CONTAINER(parent), widget); - -        g_object_unref(G_OBJECT(widget)); - -        g_object_unref(G_OBJECT(tgrid->def_panel)); - -    } - -    tgrid->def_panel = panel; - -    if (panel != NULL) -    { -        g_object_ref(G_OBJECT(panel)); - -        if (tgrid->tiles == NULL) -            gtk_tiled_grid_add(tgrid, panel); - -        else -        { -            tile = find_suitable_tile(&tgrid->tiles, "M", tgrid); - -            if (gtk_notebook_get_n_pages(GTK_NOTEBOOK(tile->widget)) == 0) -                gtk_tiled_grid_add(tgrid, panel); - -        } - -    } - -} - - -/****************************************************************************** -*                                                                             * -*  Paramètres  : tgrid = conteneur d'affichage en tuiles à modifier.          * -*                panel = panneau d'affichage à intégrer.                      * -*                                                                             * -*  Description : Incorpore un nouveau panneau dans le conteneur en tuiles.    * -*                                                                             * -*  Retour      : -                                                            * -*                                                                             * -*  Remarques   : -                                                            * -*                                                                             * -******************************************************************************/ - -void gtk_tiled_grid_add(GtkTiledGrid *tgrid, GPanelItem *panel) -{ -    char *path;                             /* Chemin d'accès              */ -    char *name;                             /* Nom à donner à l'onglet     */ -    grid_tile_t *tile;                      /* Tuile d'accueil             */ - -    path = gtk_panel_item_class_get_path(G_PANEL_ITEM_GET_CLASS(panel)); - -    if (!is_valid_tile_path(path)) -    { -        name = gtk_dockable_get_name(GTK_DOCKABLE(panel)); -        log_variadic_message(LMT_ERROR, _("Invalid path '%s' for panel '%s'"), path, name); -        free(name); -    } - -    else -    { -        tile = find_suitable_tile(&tgrid->tiles, path, tgrid); -        assert(tile != NULL); - -        gtk_dock_station_add_dockable(GTK_DOCK_STATION(tile->widget), GTK_DOCKABLE(panel)); - -        g_panel_item_set_dock_at_startup(panel, true); - -        /* Si c'est la toute première fois... */ -        if (gtk_widget_get_parent(tile->widget) == NULL) -        { -            assert(tile == tgrid->tiles); -            assert(tile->path[0] == 'M' && tile->path[1] == '\0'); -            g_object_ref(G_OBJECT(tile->widget)); -            gtk_container_add(GTK_CONTAINER(tgrid), tile->widget); -        } - -        /* Si on n'a plus besoin du panneau par défaut */ -        if (tgrid->def_panel != NULL && tile->path[0] == 'M' && tile->path[1] == '\0') -        { -            /* Si ce n'est pas le panneau qu'on vient de rajouter...*/ -            if (panel != tgrid->def_panel) -            { -                /* Enfin : si ce panneau par défaut est réellement en place */ -                if (g_panel_item_is_docked(tgrid->def_panel)) -                    gtk_tiled_grid_remove(tgrid, tgrid->def_panel); - -            } - -        } - -    } - -    free(path); - -} - - -/****************************************************************************** -*                                                                             * -*  Paramètres  : tgrid = conteneur d'affichage en tuiles à modifier.          * -*                panel = panneau d'affichage à supprimer.                     * -*                                                                             * -*  Description : Retire un panneau dans le conteneur en tuiles.               * -*                                                                             * -*  Retour      : -                                                            * -*                                                                             * -*  Remarques   : -                                                            * -*                                                                             * -******************************************************************************/ - -void gtk_tiled_grid_remove(GtkTiledGrid *tgrid, GPanelItem *panel) -{ -    GtkWidget *station;                     /* Support courant             */ -    grid_tile_t *tile;                      /* Tuile d'accueil             */ - -    assert(g_panel_item_is_docked(panel)); - -    gtk_dockable_decompose(GTK_DOCKABLE(panel), &station); - -    tile = find_tile_for_widget(tgrid->tiles, station); -    assert(tile != NULL); - -    gtk_dock_station_remove_dockable(GTK_DOCK_STATION(station), GTK_DOCKABLE(panel)); - -    g_panel_item_set_dock_at_startup(panel, false); - -    if (gtk_notebook_get_n_pages(GTK_NOTEBOOK(station)) == 0) -    { -        /* Si le panneau par défaut devient nécessaire */ -        if (tgrid->def_panel != NULL && tile->path[0] == 'M' && tile->path[1] == '\0') -            gtk_tiled_grid_add(tgrid, tgrid->def_panel); - -        else -        { -            /* La racine est concernée ! */ -            if (tile->parent == NULL) -            { -                assert(tile == tgrid->tiles); - -                g_object_ref(G_OBJECT(tile->widget)); -                gtk_container_remove(GTK_CONTAINER(tgrid), tile->widget); - -                delete_tile(tile); -                tgrid->tiles = NULL; - -            } - -            else -                collapse_tile(tile->parent, tile); - -        } - -    } - -} - - -/****************************************************************************** -*                                                                             * -*  Paramètres  : tgrid   = conteneur d'affichage en tuiles à consulter.       * -*                station = station d'accueil à retrouver.                     * -*                                                                             * -*  Description : Indique le chemin correspondant à une station intégrée.      * -*                                                                             * -*  Retour      : Copie de chemin trouvé, à libérer ensuite, ou NULL si échec. * -*                                                                             * -*  Remarques   : -                                                            * -*                                                                             * -******************************************************************************/ - -char *gtk_tiled_grid_get_path_for_station(const GtkTiledGrid *tgrid, GtkDockStation *station) -{ -    char *result;                           /* Chemin d'accès à renvoyer   */ -    grid_tile_t *tile;                      /* Tuile d'accueil             */ - -    tile = find_tile_for_widget(tgrid->tiles, GTK_WIDGET(station)); - -    if (tile == NULL) -        result = NULL; - -    else -        result = strdup(tile->path); - -    return result; - -} - - -/****************************************************************************** -*                                                                             * -*  Paramètres  : tgrid  = conteneur d'affichage en tuiles à mettre à jour.    * -*                config = configuration à consulter.                          * -*                                                                             * -*  Description : Replace les positions des séparateurs de tuiles.             * -*                                                                             * -*  Retour      : -                                                            * -*                                                                             * -*  Remarques   : -                                                            * -*                                                                             * -******************************************************************************/ - -void gtk_tiled_grid_restore_positions(const GtkTiledGrid *tgrid, GGenConfig *config) -{ - -    void visit_tiles_for_restoring(grid_tile_t *tile, const char *vpath) -    { -        GtkOrientation orientation;         /* Direction de la tuile       */ -        char hint;                          /* Inutile donc indispensable  */ -        char *key;                          /* Clef d'accès à un paramètre */ -        gint position;                      /* Nouvelle position de barre  */ -        size_t i;                           /* Boucle de parcours          */ -        char *child_key;                    /* Clef d'accès des suivants   */ - -        if (!IS_LEAF_TILE(tile)) -        { -            orientation = gtk_orientable_get_orientation(GTK_ORIENTABLE(tile->widget)); - -            hint = orientation == GTK_ORIENTATION_HORIZONTAL ? 'h' : 'v'; - -            asprintf(&key, "%s%c", vpath, hint); - -            if (g_generic_config_get_value(config, key, &position)) -                gtk_paned_set_position(GTK_PANED(tile->widget), position); - -            for (i = 0; i < 2; i++) -            { -                asprintf(&child_key, "%s%zu", key, i); - -                visit_tiles_for_restoring(tile->children[i], child_key); - -                free(child_key); - -            } - -            free(key); - -        } - -    } - - -    visit_tiles_for_restoring(tgrid->tiles, "gui.panels.positions.R"); - -} - - -/****************************************************************************** -*                                                                             * -*  Paramètres  : tgrid  = conteneur d'affichage en tuiles à consulter.        * -*                config = configuration à mettre à jour.                      * -*                                                                             * -*  Description : Sauvegarde les positions des séparateurs de tuiles.          * -*                                                                             * -*  Retour      : -                                                            * -*                                                                             * -*  Remarques   : -                                                            * -*                                                                             * -******************************************************************************/ - -void gtk_tiled_grid_save_positions(const GtkTiledGrid *tgrid, GGenConfig *config) -{ - -    void visit_tiles_for_saving(grid_tile_t *tile, const char *vpath) -    { -        GtkOrientation orientation;         /* Direction de la tuile       */ -        char hint;                          /* Inutile donc indispensable  */ -        char *key;                          /* Clef d'accès à un paramètre */ -        gint position;                      /* Nouvelle position de barre  */ -        size_t i;                           /* Boucle de parcours          */ -        char *child_key;                    /* Clef d'accès des suivants   */ - -        if (!IS_LEAF_TILE(tile)) -        { -            orientation = gtk_orientable_get_orientation(GTK_ORIENTABLE(tile->widget)); - -            hint = orientation == GTK_ORIENTATION_HORIZONTAL ? 'h' : 'v'; - -            asprintf(&key, "%s%c", vpath, hint); - -            position = gtk_paned_get_position(GTK_PANED(tile->widget)); -            g_generic_config_create_or_udpdate_param(config, key, CPT_INTEGER, -1, position); - -            for (i = 0; i < 2; i++) -            { -                asprintf(&child_key, "%s%zu", key, i); - -                visit_tiles_for_saving(tile->children[i], child_key); - -                free(child_key); - -            } - -            free(key); - -        } - -    } - - -    visit_tiles_for_saving(tgrid->tiles, "gui.panels.positions.R"); - -} diff --git a/src/gtkext/tweak-int.h b/src/gtkext/tweak-int.h new file mode 100644 index 0000000..0d2c213 --- /dev/null +++ b/src/gtkext/tweak-int.h @@ -0,0 +1,65 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * tweak-int.h - définitions internes pour une section d'éléments à paramétrer + * + * 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 _GTKEXT_TWEAK_INT_H +#define _GTKEXT_TWEAK_INT_H + + +#include "tweak.h" + + + +/* Section de paramétrage pour liste d'éléments à configurer (instance) */ +struct _GtkTweakSection +{ +    GtkListBoxRow parent;                   /* A laisser en premier        */ + +    GtkImage *icon;                         /* Eventuelle image            */ +    GtkLabel *label;                        /* Etiquette associée          */ +    GtkWidget *next;                        /* Eventuelle progression      */ + +    char *category;                         /* Groupe de rassemblement     */ + +    union +    { +        GType panel;                        /* Accès à la page de config.  */ +        char *sub;                          /* Sous-ensemble à presenter   */ +    }; +    bool has_sub_section;                   /* Choix du champ valide       */ + +}; + +/* Section de paramétrage pour liste d'éléments à configurer (classe) */ +struct _GtkTweakSectionClass +{ +    GtkListBoxRowClass parent;              /* A laisser en premier        */ + +}; + + +/* Met en place une nouvelle section de configuration. */ +bool gtk_tweak_section_create(GtkTweakSection *, const tweak_info_t *); + + + +#endif  /* _GTKEXT_TWEAK_INT_H */ diff --git a/src/gtkext/tweak.c b/src/gtkext/tweak.c new file mode 100644 index 0000000..b03cf17 --- /dev/null +++ b/src/gtkext/tweak.c @@ -0,0 +1,319 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * tweak.c - section d'éléments à paramétrer + * + * 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/>. + */ + + +#include "tweak.h" + + +#include <assert.h> +#include <malloc.h> +#include <string.h> + + +#include "helpers.h" +#include "tweak-int.h" + + + +/* Initialise la classe des sections d'éléments paramétrables. */ +static void gtk_tweak_section_class_init(GtkTweakSectionClass *); + +/* Initialise une instance de section d'éléments paramétrables. */ +static void gtk_tweak_section_init(GtkTweakSection *); + +/* Supprime toutes les références externes. */ +static void gtk_tweak_section_dispose(GtkTweakSection *); + +/* Procède à la libération totale de la mémoire. */ +static void gtk_tweak_section_finalize(GtkTweakSection *); + + + +/* Détermine le type du composant d'affichage générique. */ +G_DEFINE_TYPE(GtkTweakSection, gtk_tweak_section, GTK_TYPE_LIST_BOX_ROW); + + +/****************************************************************************** +*                                                                             * +*  Paramètres  : class = classe GTK à initialiser.                            * +*                                                                             * +*  Description : Initialise la classe des sections d'éléments paramétrables.  * +*                                                                             * +*  Retour      : -                                                            * +*                                                                             * +*  Remarques   : -                                                            * +*                                                                             * +******************************************************************************/ + +static void gtk_tweak_section_class_init(GtkTweakSectionClass *class) +{ +    GObjectClass *object;                   /* Plus haut niveau équivalent */ +    GtkWidgetClass *widget;                 /* Classe de haut niveau       */ + +    object = G_OBJECT_CLASS(class); + +    object->dispose = (GObjectFinalizeFunc/* ! */)gtk_tweak_section_dispose; +    object->finalize = (GObjectFinalizeFunc)gtk_tweak_section_finalize; + +    widget = GTK_WIDGET_CLASS(class); + +    gtk_widget_class_set_template_from_resource(widget, "/re/chrysalide/framework/gtkext/tweak.ui"); + +    gtk_widget_class_bind_template_child(widget, GtkTweakSection, icon); +    gtk_widget_class_bind_template_child(widget, GtkTweakSection, label); +    gtk_widget_class_bind_template_child(widget, GtkTweakSection, next); + +} + + +/****************************************************************************** +*                                                                             * +*  Paramètres  : section = composant GTK à initialiser.                       * +*                                                                             * +*  Description : Initialise une instance de section d'éléments paramétrables. * +*                                                                             * +*  Retour      : -                                                            * +*                                                                             * +*  Remarques   : -                                                            * +*                                                                             * +******************************************************************************/ + +static void gtk_tweak_section_init(GtkTweakSection *section) +{ +    gtk_widget_init_template(GTK_WIDGET(section)); + +    section->category = NULL; + +    section->sub = NULL; +    section->has_sub_section = true; + +} + + +/****************************************************************************** +*                                                                             * +*  Paramètres  : section = instance d'objet GLib à traiter.                   * +*                                                                             * +*  Description : Supprime toutes les références externes.                     * +*                                                                             * +*  Retour      : -                                                            * +*                                                                             * +*  Remarques   : -                                                            * +*                                                                             * +******************************************************************************/ + +static void gtk_tweak_section_dispose(GtkTweakSection *section) +{ +    gtk_widget_dispose_template(GTK_WIDGET(section), GTK_TYPE_TWEAK_SECTION); + +    G_OBJECT_CLASS(gtk_tweak_section_parent_class)->dispose(G_OBJECT(section)); + +} + + +/****************************************************************************** +*                                                                             * +*  Paramètres  : section = instance d'objet GLib à traiter.                   * +*                                                                             * +*  Description : Procède à la libération totale de la mémoire.                * +*                                                                             * +*  Retour      : -                                                            * +*                                                                             * +*  Remarques   : -                                                            * +*                                                                             * +******************************************************************************/ + +static void gtk_tweak_section_finalize(GtkTweakSection *section) +{ +    if (section->category != NULL) +        free(section->category); + +    if (section->has_sub_section && section->sub != NULL) +        free(section->sub); + +    G_OBJECT_CLASS(gtk_tweak_section_parent_class)->finalize(G_OBJECT(section)); + +} + + +/****************************************************************************** +*                                                                             * +*  Paramètres  : info = informations associées à la section.                  * +*                                                                             * +*  Description : Crée une nouvelle section de configuration.                  * +*                                                                             * +*  Retour      : Composant GTK mis en place.                                  * +*                                                                             * +*  Remarques   : -                                                            * +*                                                                             * +******************************************************************************/ + +GtkTweakSection *gtk_tweak_section_new(const tweak_info_t *info) +{ +    GtkTweakSection *result;                 /* Instance à retourner        */ + +    result = g_object_new(GTK_TYPE_TWEAK_SECTION, NULL); + +    if (!gtk_tweak_section_create(result, info)) +        g_clear_object(&result); + +    return result; + +} + + +/****************************************************************************** +*                                                                             * +*  Paramètres  : section = section à initialiser pleinement.                  * +*                info    = informations associées à la section.               * +*                                                                             * +*  Description : Met en place une nouvelle section de configuration.          * +*                                                                             * +*  Retour      : Bilan de l'opération.                                        * +*                                                                             * +*  Remarques   : -                                                            * +*                                                                             * +******************************************************************************/ + +bool gtk_tweak_section_create(GtkTweakSection *section, const tweak_info_t *info) +{ +    bool result;                            /* Bilan à retourner           */ + +    result = true; + +    gtk_image_set_from_icon_name(section->icon, info->image); +    gtk_label_set_label(section->label, info->label); + +    gtk_widget_set_visible(section->next, info->has_sub_section); + +    section->category = strdup(info->category); + +    if (info->has_sub_section) +    { +        section->sub = strdup(info->sub); +        section->has_sub_section = true; +    } +    else +    { +        section->panel = info->panel; +        section->has_sub_section = false; +    } + +    return result; + +} + + +/****************************************************************************** +*                                                                             * +*  Paramètres  : section = section à consulter.                               * +*                                                                             * +*  Description : Fournit l'étiquette associée à une section de configuration. * +*                                                                             * +*  Retour      : Désignation humaine de la section.                           * +*                                                                             * +*  Remarques   : -                                                            * +*                                                                             * +******************************************************************************/ + +const char *gtk_tweak_section_get_label(const GtkTweakSection *section) +{ +    const char *result;                     /* Texte à retourner           */ + +    result = gtk_label_get_text(section->label); + +    return result; + +} + + +/****************************************************************************** +*                                                                             * +*  Paramètres  : section = section à consulter.                               * +*                                                                             * +*  Description : Indique si la section renvoie vers une sous-section.         * +*                                                                             * +*  Retour      : Bilan de la consultation.                                    * +*                                                                             * +*  Remarques   : -                                                            * +*                                                                             * +******************************************************************************/ + +bool gtk_tweak_section_has_sub_section(const GtkTweakSection *section) +{ +    bool result;                            /* Statut à retourner          */ + +    result = section->has_sub_section; + +    return result; + +} + + +/****************************************************************************** +*                                                                             * +*  Paramètres  : section = section à consulter.                               * +*                                                                             * +*  Description : Fournit le type d'un éventuel panneau de configuration lié.  * +*                                                                             * +*  Retour      : Bilan de la consultation.                                    * +*                                                                             * +*  Remarques   : -                                                            * +*                                                                             * +******************************************************************************/ + +GType gtk_tweak_section_get_panel(const GtkTweakSection *section) +{ +    GType result;                           /* Type d'objet à retourner    */ + +    assert(!section->has_sub_section); + +    result = section->panel; + +    return result; + +} + + +/****************************************************************************** +*                                                                             * +*  Paramètres  : section = section à consulter.                               * +*                                                                             * +*  Description : Fournit la désignation d'une éventuelle sous-section liée.   * +*                                                                             * +*  Retour      : Désignation associée à la sous-section.                      * +*                                                                             * +*  Remarques   : -                                                            * +*                                                                             * +******************************************************************************/ + +const char *gtk_tweak_section_get_sub_section(const GtkTweakSection *section) +{ +    const char *result;                     /* Désignation à renvoyer      */ + +    assert(section->has_sub_section); + +    result = section->sub; + +    return result; + +} diff --git a/src/gtkext/tweak.h b/src/gtkext/tweak.h new file mode 100644 index 0000000..8c44844 --- /dev/null +++ b/src/gtkext/tweak.h @@ -0,0 +1,90 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * tweak.h - prototypes pour pour une section d'éléments à paramétrer + * + * 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 _GTKEXT_TWEAK_H +#define _GTKEXT_TWEAK_H + + +#include <stdbool.h> +#include <gtk/gtk.h> + + +#include "../glibext/helpers.h" + + + +/* Définition d'une section de configuration */ +typedef struct _tweak_info_t +{ +    const char *parent;                     /* Ensemble d'appartenance     */ + +    const char *category;                   /* Groupe de rassemblement     */ + +    const char *image;                      /* Eventuelle image associée   */ +    const char *key;                        /* Désignation de la section   */ +    const char *label;                      /* Désignation humaine         */ + +    union +    { +        GType panel;                        /* Accès à la page de config.  */ +        const char *sub;                    /* Sous-ensemble à presenter   */ +    }; +    bool has_sub_section;                   /* Choix du champ valide       */ + +} tweak_info_t; + + +#define TWEAK_SIMPLE_DEF(p, c, i, k, l, t)  \ +    {                                       \ +        .parent = p,                        \ +        .category = c,                      \ +        .image = i,                         \ +        .key = k,                           \ +        .label = l,                         \ +        .panel = t,                         \ +        .has_sub_section = false,           \ +    } + +#define GTK_TYPE_TWEAK_SECTION (gtk_tweak_section_get_type()) + +DECLARE_GTYPE(GtkTweakSection, gtk_tweak_section, GTK, TWEAK_SECTION); + + +/* Crée une nouvelle section de configuration. */ +GtkTweakSection *gtk_tweak_section_new(const tweak_info_t *); + +/* Fournit l'étiquette associée à une section de configuration. */ +const char *gtk_tweak_section_get_label(const GtkTweakSection *); + +/* Indique si la section renvoie vers une sous-section. */ +bool gtk_tweak_section_has_sub_section(const GtkTweakSection *); + +/* Fournit le type d'un éventuel panneau de configuration lié. */ +GType gtk_tweak_section_get_panel(const GtkTweakSection *); + +/* Fournit la désignation d'une éventuelle sous-section liée. */ +const char *gtk_tweak_section_get_sub_section(const GtkTweakSection *); + + + +#endif  /* _GTKEXT_TWEAK_H */ diff --git a/src/gtkext/tweak.ui b/src/gtkext/tweak.ui new file mode 100644 index 0000000..576e25e --- /dev/null +++ b/src/gtkext/tweak.ui @@ -0,0 +1,46 @@ +<?xml version="1.0" encoding="UTF-8"?> +<interface> +    <template class="GtkTweakSection" parent="GtkListBoxRow"> + +        <property name="child"> + +            <object class="GtkBox"> +                <property name="orientation">horizontal</property> +                <property name="margin-top">14</property> +                <property name="margin-bottom">14</property> + +                <child> +                    <object class="GtkImage" id="icon"> +                        <property name="icon-name">security-high-symbolic</property> +                        <property name="margin-start">12</property> +                        <property name="margin-end">12</property> +                        <style> +                            <class name="icon-dropshadow"/> +                        </style> +                    </object> +                </child> + +                <child> +                    <object class="GtkLabel" id="label"> +                        <property name="xalign">0</property> +                        <property name="label" translatable="yes">Security</property> +                        <property name="hexpand">true</property> +                    </object> +                </child> + +                <child> +                    <object class="GtkImage" id="next"> +                        <property name="icon-name">go-next-symbolic</property> +                        <property name="margin-start">12</property> +                        <property name="margin-end">12</property> +                        <style> +                            <class name="icon-dropshadow"/> +                        </style> +                    </object> +                </child> + +            </object> +        </property> + +    </template> +</interface> diff --git a/src/gui/Makefile.am b/src/gui/Makefile.am index f4a682c..be70445 100644 --- a/src/gui/Makefile.am +++ b/src/gui/Makefile.am @@ -12,15 +12,12 @@ libgui_la_SOURCES =						\  	item-int.h							\  	item.h item.c						\  	menubar.h menubar.c					\ -	panel-int.h							\ -	panel.h panel.c						\  	resources.h resources.c				\  	status.h status.c					\  	theme.h theme.c  libgui_la_LIBADD =						\  	core/libguicore.la					\ -	dialogs/libguidialogs.la			\  	menus/libguimenus.la				\  	panels/libguipanels.la				\  	tb/libguitb.la @@ -28,10 +25,15 @@ libgui_la_LIBADD =						\  libgui_la_CFLAGS = $(LIBGTK_CFLAGS) $(LIBXML_CFLAGS) -libgui4_la_SOURCES = +libgui4_la_SOURCES =						\ +	resources.h resources.c					\ +	window-int.h							\ +	window.h window.c -libgui4_la_LIBADD =						\ -	core/libguicore4.la +libgui4_la_LIBADD =							\ +	core/libguicore4.la						\ +	dialogs/libguidialogs.la				\ +	panels/libguipanels4.la  libgui4_la_CFLAGS = $(LIBGTK4_CFLAGS) @@ -41,10 +43,14 @@ devdir = $(includedir)/chrysalide/$(subdir:src/%=core/%)  dev_HEADERS = $(libgui_la_SOURCES:%c=) -SUBDIRS = core # dialogs menus panels tb +SUBDIRS = core dialogs panels # menus panels tb -resources.c: gresource.xml $(UI_FILES) +RES_FILES = 								\ +	style.css								\ +	window.ui + +resources.c: gresource.xml $(RES_FILES)  	glib-compile-resources --target=$@ --sourcedir=$(srcdir) --generate-source --c-name gui gresource.xml  resources.h: gresource.xml @@ -53,4 +59,4 @@ resources.h: gresource.xml  CLEANFILES = resources.h resources.c -EXTRA_DIST = gresource.xml $(UI_FILES) +EXTRA_DIST = gresource.xml $(RES_FILES) diff --git a/src/gui/core/Makefile.am b/src/gui/core/Makefile.am index 96ef578..a854977 100644 --- a/src/gui/core/Makefile.am +++ b/src/gui/core/Makefile.am @@ -15,7 +15,6 @@ RES_FILES =								\  libguicore_la_SOURCES =					\  	global.h global.c					\  	items.h items.c						\ -	panels.h panels.c					\  	resources.h resources.c				\  	theme.h theme.c @@ -24,7 +23,9 @@ libguicore_la_CFLAGS = $(LIBGTK_CFLAGS) $(LIBXML_CFLAGS)  libguicore4_la_SOURCES =					\  	core.h core.c							\ -	logs.h logs.c +	logs.h logs.c							\ +	nox.h nox.c								\ +	panels.h panels.c  libguicore4_la_CFLAGS = $(LIBGTK_CFLAGS) $(LIBXML_CFLAGS) diff --git a/src/gui/core/core.c b/src/gui/core/core.c index 2d47dc9..57a398a 100644 --- a/src/gui/core/core.c +++ b/src/gui/core/core.c @@ -2,7 +2,7 @@  /* Chrysalide - Outil d'analyse de fichiers binaires   * core.c - chargement et le déchargement du tronc commun pour l'éditeur graphique   * - * Copyright (C) 2016-2019 Cyrille Bagard + * Copyright (C) 2016-2025 Cyrille Bagard   *   *  This file is part of Chrysalide.   * @@ -24,6 +24,7 @@  #include "core.h" +#include "panels.h"  #include "../../glibext/linetoken.h" @@ -32,6 +33,7 @@  static AvailableGuiComponent __loaded = AGC_NONE; +  /******************************************************************************  *                                                                             *  *  Paramètres  : flags = liste d'éléments à charger.                          * @@ -59,6 +61,15 @@ bool load_gui_components(AvailableGuiComponent flags)      } +    if ((flags & AGC_PANELS) != 0 && (__loaded & AGC_PANELS) == 0) +    { +        result = load_main_framework_panel_definitions(); +        if (!result) goto done; + +        __loaded |= AGC_PANELS; + +    } +   done:      return result; @@ -80,6 +91,14 @@ bool load_gui_components(AvailableGuiComponent flags)  void unload_gui_components(AvailableGuiComponent flags)  { +    if ((flags & AGC_PANELS) != 0 && (__loaded & AGC_PANELS) == 0) +    { +        unload_all_framework_panel_definitions(); + +        __loaded &= ~AGC_PANELS; + +    } +      if ((flags & AGC_BUFFER_FEATURES) != 0 && (__loaded & AGC_BUFFER_FEATURES) == 0)      {          exit_segment_content_hash_table(); @@ -87,7 +106,6 @@ void unload_gui_components(AvailableGuiComponent flags)          __loaded &= ~AGC_BUFFER_FEATURES;      } -  } diff --git a/src/gui/core/core.h b/src/gui/core/core.h index bcb5433..19647ce 100644 --- a/src/gui/core/core.h +++ b/src/gui/core/core.h @@ -34,6 +34,7 @@ typedef enum _AvailableGuiComponent  {      AGC_NONE            = (0 << 0),         /* Statut initial              */      AGC_BUFFER_FEATURES = (1 << 0),         /* Tampons de bribes de texte  */ +    AGC_PANELS          = (1 << 1),         /* Panneaux graphiques de base */  } AvailableGuiComponent; diff --git a/src/gui/core/logs.c b/src/gui/core/logs.c index 59910f1..cdb2a0d 100644 --- a/src/gui/core/logs.c +++ b/src/gui/core/logs.c @@ -24,6 +24,14 @@  #include "logs.h" +#include <assert.h> + + +#include "panels.h" +#include "../panels/logs.h" +#include "../../glibext/log.h" + +  /******************************************************************************  *                                                                             * @@ -38,26 +46,20 @@  *                                                                             *  ******************************************************************************/ -void do_log_message_alt2(LogMessageType type, const char *msg) +void do_log_message_alt(LogMessageType type, const char *msg)  { -#if 0 - -#ifdef INCLUDE_GTK_SUPPORT - -    GEditorItem *item;                      /* Eventuel affichage présent  */ +    GLogEntry *entry;                       /* Nouvel élément de journal   */ +    GtkTiledPanel *panel;                   /* Panneau de journalisation   */ -    item = find_editor_item_by_type(G_TYPE_LOG_PANEL); +    entry = g_log_entry_new(type, msg); -    if (item != NULL) -    { -        g_log_panel_add_message(G_LOG_PANEL(item), type, msg); -        g_object_unref(G_OBJECT(item)); -    } +    panel = get_framework_panel_singleton(GTK_TYPE_LOGS_PANEL); +    assert(panel != NULL); -#endif +    g_log_panel_add_message(GTK_LOGS_PANEL(panel), entry); -#endif +    unref_object(panel); -    printf("[log GUI] [%u] %s\n", type, msg); +    unref_object(entry);  } diff --git a/src/gui/core/nox.c b/src/gui/core/nox.c new file mode 100644 index 0000000..7f3ae1f --- /dev/null +++ b/src/gui/core/nox.c @@ -0,0 +1,48 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * nox.c - indication de présence ou d'absence de support graphique + * + * Copyright (C) 2024 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 "nox.h" + + + +/****************************************************************************** +*                                                                             * +*  Paramètres  : -                                                            * +*                                                                             * +*  Description : Indique la présence ou l'absence d'un affichage graphique.   * +*                                                                             * +*  Retour      : Statut à transmettre.                                        * +*                                                                             * +*  Remarques   : -                                                            * +*                                                                             * +******************************************************************************/ + +bool _run_in_nox_mode(void) +{ +    bool result;                            /* Statut à retournr           */ + +    result = false; + +    return result; + +} diff --git a/src/gui/core/nox.h b/src/gui/core/nox.h new file mode 100644 index 0000000..e03b365 --- /dev/null +++ b/src/gui/core/nox.h @@ -0,0 +1,37 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * nox.h - prototypes pour l'indication de présence ou d'absence de support graphique + * + * Copyright (C) 2024 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 _GUI_CORE_NOX_H +#define _GUI_CORE_NOX_H + + +#include <stdbool.h> + + + +/* Indique la présence ou l'absence d'un affichage graphique. */ +bool _run_in_nox_mode(void); + + + +#endif  /* _GUI_CORE_NOX_H */ diff --git a/src/gui/core/panels.c b/src/gui/core/panels.c index 1b6f604..9fca411 100644 --- a/src/gui/core/panels.c +++ b/src/gui/core/panels.c @@ -1,8 +1,8 @@  /* Chrysalide - Outil d'analyse de fichiers binaires - * panels.c - gestion d'ensemble de tous les panneaux pour l'éditeur + * panels.c - gestion d'ensemble de tous les panneaux graphiques du framework   * - * Copyright (C) 2016-2019 Cyrille Bagard + * Copyright (C) 2016-2025 Cyrille Bagard   *   *  This file is part of Chrysalide.   * @@ -27,35 +27,100 @@  #include <assert.h>  #include <malloc.h> +#include <string.h> -#include "items.h" -#include "../panel-int.h" -#include "../panels/bintree.h" -#include "../panels/bookmarks.h" -#include "../panels/errors.h" -#include "../panels/glance.h" -#include "../panels/history.h" -#include "../panels/log.h" -#include "../panels/regedit.h" -#include "../panels/strings.h" -#include "../panels/symbols.h" +#include <i18n.h> + + +#include "../panels/binary.h" +#include "../panels/binary-params.h" +#include "../panels/logs.h"  #include "../panels/welcome.h" -#include "../../core/params.h" +#include "../../gtkext/launcher.h" + + + +/* Définition générique complète d'un panneau */ +typedef struct _ext_panel_info_t +{ +    /* Début des champs copiés de panel_info_t */ + +    char *category;                         /* Groupe de rassemblement     */ + +    char *image;                            /* Eventuelle image associée   */ +    char *title;                            /* Désignation humaine         */ +    char *desc;                             /* Description humaine         */ + +    FrameworkPanelPersonality personality;  /* Comportement attendu        */ + +    GType panel_type;                       /* Type du panneau représenté  */ +    GType params_type;                      /* Composant de paramètre      */ + +    /* Fin des champs copiés de panel_info_t */ + +    GtkTiledPanel *singleton;               /* Conservation des allocations*/ +} ext_panel_info_t;  /* Liste des panneaux disponibles */ -static GType *_panels_list = NULL; +static ext_panel_info_t **_panels_list = NULL;  static size_t _panels_count = 0; +/* Copie une définition basique de panneau graphqiue. */ +static ext_panel_info_t *copy_panel_info(const panel_info_t *); + +/* Efface une définition étendue de panneau graphique. */ +static void delete_panel_info(ext_panel_info_t *); + +  /******************************************************************************  *                                                                             * -*  Paramètres  : -                                                            * +*  Paramètres  : info = information de base à copier.                         * +*                                                                             * +*  Description : Copie une définition basique de panneau graphqiue.           * +*                                                                             * +*  Retour      : Structure mémorisant l'ensemble des informations.            * +*                                                                             * +*  Remarques   : -                                                            * +*                                                                             * +******************************************************************************/ + +static ext_panel_info_t *copy_panel_info(const panel_info_t *info) +{ +    ext_panel_info_t *result;               /* Structure à retourner       */ + +    result = calloc(1, sizeof(ext_panel_info_t)); + +    if (info->category != NULL) +        result->category = strdup(info->category); + +    if (info->image != NULL) +        result->image = strdup(info->image); + +    result->title = strdup(info->title); + +    if (info->desc != NULL) +        result->desc = strdup(info->desc); + +    result->personality = info->personality; + +    result->panel_type = info->panel_type; +    result->params_type = info->params_type; + +    return result; + +} + + +/******************************************************************************  *                                                                             * -*  Description : Charge les principaux panneaux de l'éditeur.                 * +*  Paramètres  : info = informations à supprimer de la mémoire.               * +*                                                                             * +*  Description : Efface une définition étendue de panneau graphique.          *  *                                                                             *  *  Retour      : -                                                            *  *                                                                             * @@ -63,38 +128,132 @@ static size_t _panels_count = 0;  *                                                                             *  ******************************************************************************/ -void load_main_panels(void) +static void delete_panel_info(ext_panel_info_t *info)  { -    GGenConfig *config;                     /* Configuration globale       */ -    GPanelItem *panel;                      /* Panneau à précharger        */ +    if (info->category != NULL) +        free(info->category); + +    if (info->image != NULL) +        free(info->image); + +    free(info->title); + +    if (info->desc != NULL) +        free(info->desc); + +    if (info->singleton != NULL) +    { +        assert(info->personality & FPP_SINGLETON); +        unref_object(info->singleton); +    } + +    free(info); + +} -    config = get_main_configuration(); -    register_panel_item(G_TYPE_LOG_PANEL, config); +/****************************************************************************** +*                                                                             * +*  Paramètres  : -                                                            * +*                                                                             * +*  Description : Charge les définitions des principaux panneaux du framework. * +*                                                                             * +*  Retour      : Bilan de l'opération.                                        * +*                                                                             * +*  Remarques   : -                                                            * +*                                                                             * +******************************************************************************/ + +bool load_main_framework_panel_definitions(void) +{ +    bool result;                            /* Bilan à retourner           */ +    panel_info_t info;                      /* Infos d'enregistrement      */      /* Chargement du panneau de rapport au plus tôt */ -    panel = g_panel_item_new(G_TYPE_LOG_PANEL, NULL); -    g_object_unref(G_OBJECT(panel)); - -    register_panel_item(G_TYPE_WELCOME_PANEL, config); -    register_panel_item(G_TYPE_REGEDIT_PANEL, config); -    register_panel_item(G_TYPE_SYMBOLS_PANEL, config); -    register_panel_item(G_TYPE_HISTORY_PANEL, config); -    register_panel_item(G_TYPE_STRINGS_PANEL, config); -    register_panel_item(G_TYPE_GLANCE_PANEL, config); -    register_panel_item(G_TYPE_BOOKMARKS_PANEL, config); -    register_panel_item(G_TYPE_BINTREE_PANEL, config); -    register_panel_item(G_TYPE_ERROR_PANEL, config); + +    info.category = NULL; + +    info.image = NULL; +    info.title = _("Logs"); +    info.desc = NULL; + +    info.personality = FPP_SINGLETON; + +    info.panel_type = GTK_TYPE_LOGS_PANEL; +    info.params_type = G_TYPE_INVALID; + +    result = register_framework_panel_definition(&info); +    if (!result) goto done; + +    /* Chargements des panneaux restants */ + +    info.category = "Main"; + +    info.image = "binfile-symbolic"; +    info.title = _("Binary analysis"); +    info.desc = _("Load a binary content and parse its format if recognized"); + +    info.personality = FPP_MAIN_PANEL; + +    info.panel_type = GTK_TYPE_BINARY_PANEL; +    info.params_type = GTK_TYPE_BINARY_PARAMETERS; + +    result = register_framework_panel_definition(&info); +    if (!result) goto done; + +    /* --- */ + +    info.category = NULL; + +    info.image = NULL; +    info.title = _("Welcome"); +    info.desc = NULL; + +    info.personality = FPP_MAIN_PANEL | FPP_SINGLETON; + +    info.panel_type = GTK_TYPE_WELCOME_PANEL; +    info.params_type = G_TYPE_INVALID; + +    result = register_framework_panel_definition(&info); +    if (!result) goto done; + + done: + +    return result; + +} + + +/****************************************************************************** +*                                                                             * +*  Paramètres  : -                                                            * +*                                                                             * +*  Description : Décharge tous les panneaux graphiques du framework.          * +*                                                                             * +*  Retour      : -                                                            * +*                                                                             * +*  Remarques   : -                                                            * +*                                                                             * +******************************************************************************/ + +void unload_all_framework_panel_definitions(void) +{ +    size_t i;                               /* Boucle de parcours          */ + +    for (i = 0; i < _panels_count; i++) +        delete_panel_info(_panels_list[i]); + +    _panels_list = NULL; +    _panels_count = 0;  }  /******************************************************************************  *                                                                             * -*  Paramètres  : type   = type du composant à présenter à l'affichage.        * -*                config = configuration à compléter.                          * +*  Paramètres  : info = information de base à copier.                         *  *                                                                             * -*  Description : Enregistre un panneau comme partie intégrante de l'éditeur.  * +*  Description : Enregistre la définition d'un panneau graphique.             *  *                                                                             *  *  Retour      : -                                                            *  *                                                                             * @@ -102,71 +261,199 @@ void load_main_panels(void)  *                                                                             *  ******************************************************************************/ -void register_panel_item(GType type, GGenConfig *config) +bool register_framework_panel_definition(const panel_info_t *info)  { -    GPanelItemClass *class;                 /* Classe associée au type     */ -#ifndef NDEBUG -    bool status;                            /* Bilan de mise en place      */ -#endif +    bool result;                            /* Bilan à retourner           */ +    size_t i;                               /* Boucle de parcours          */ +    ext_panel_info_t *ext_info;             /* Informations conservées     */ + +    result = false; + +    /* Validation */ + +    for (i = 0; i < _panels_count; i++) +        if (_panels_list[i]->panel_type == info->panel_type) +            break; -    _panels_list = realloc(_panels_list, ++_panels_count * sizeof(GType)); +    if (i < _panels_count) +        goto done; -    _panels_list[_panels_count - 1] = type; +    /* Enregistrement */ -    class = g_type_class_ref(type); +    ext_info = copy_panel_info(info); -#ifndef NDEBUG -    status = gtk_panel_item_class_setup_configuration(class, config); -    assert(status); -#else -    gtk_panel_item_class_setup_configuration(class, config); -#endif +    _panels_list = realloc(_panels_list, ++_panels_count * sizeof(ext_panel_info_t *)); -    g_type_class_unref(class); +    _panels_list[_panels_count - 1] = ext_info; + +    result = true; + + done: + +    return result;  }  /******************************************************************************  *                                                                             * -*  Paramètres  : skip   = saute le panneau d'accueil lors du parcours ?       * -*                handle = routine à appeler pour chaque panneau.              * -*                data   = données fournies pour accompagner cet appel.        * +*  Paramètres  : target = type de définition de panneau recherchée.           *  *                                                                             * -*  Description : Effectue le parcours de tous les panneaux chargés.           * +*  Description : Récupère les particularités d'un panneau graphique.          *  *                                                                             * -*  Retour      : true si le parcours a été total, false sinon.                * +*  Retour      : Détails du comportement associé au panneau visé.             *  *                                                                             *  *  Remarques   : -                                                            *  *                                                                             *  ******************************************************************************/ -bool _browse_all_item_panels(bool skip, handle_panel_item_fc handle, void *data) +FrameworkPanelPersonality get_framework_panel_personality(GType target)  { -    bool result;                            /* Résultat à renvoyer         */ -    GType type;                             /* Type de panneau à traiter   */ +    FrameworkPanelPersonality result;       /* Propriétées à retourner     */      size_t i;                               /* Boucle de parcours          */ -    GPanelItemClass *class;                 /* Classe associée au type     */ +    ext_panel_info_t *info;                 /* Informations conservées     */ -    result = true; +    result = FPP_NONE; + +    for (i = 0; i < _panels_count; i++) +    { +        info = _panels_list[i]; + +        if (info->panel_type == target) +        { +            result = info->personality; +            break; +        } + +    } + +    return result; + +} + + +/****************************************************************************** +*                                                                             * +*  Paramètres  : target = type de définition de panneau recherchée.           * +*                                                                             * +*  Description : Met en place (au besoin) un panneau graphique unique.        * +*                                                                             * +*  Retour      : Instance de définition identifiée ou NULL en cas d'échec.    * +*                                                                             * +*  Remarques   : -                                                            * +*                                                                             * +******************************************************************************/ + +GtkTiledPanel *get_framework_panel_singleton(GType target) +{ +    GtkTiledPanel *result;                  /* Instance à renvoyer         */ +    size_t i;                               /* Boucle de parcours          */ +    ext_panel_info_t *info;                 /* Informations conservées     */ + +    result = NULL; + +    for (i = 0; i < _panels_count; i++) +    { +        info = _panels_list[i]; + +        if (info->panel_type == target) +        { +            if (info->singleton == NULL) +                info->singleton = g_object_new(target, NULL); + +            result = info->singleton; +            ref_object(result); +            break; + +        } + +    } + +    return result; + +} + + +/****************************************************************************** +*                                                                             * +*  Paramètres  : list = liste à compléter.                                    * +*                                                                             * +*  Description : Intègre une définition de panneau enregistrée.               * +*                                                                             * +*  Retour      : true pour un parcours complet de la liste des définitions.   * +*                                                                             * +*  Remarques   : -                                                            * +*                                                                             * +******************************************************************************/ + +void populate_framework_panel_launcher_list(GtkListBox *list) +{ +    size_t i;                               /* Boucle de parcours          */ +    ext_panel_info_t *info;                 /* Informations conservées     */ +    GtkPanelLauncher *launcher;             /* Lanceur à intégrer          */      for (i = 0; i < _panels_count; i++)      { -        type = _panels_list[i]; +        info = _panels_list[i]; -        if (skip && type == G_TYPE_WELCOME_PANEL) +        if (info->category == NULL)              continue; -        class = g_type_class_ref(type); +        launcher = gtk_panel_launcher_new(info->image, info->title, info->desc); + +        g_object_set_data(G_OBJECT(launcher), "panel_type", GSIZE_TO_POINTER(info->panel_type)); + +        gtk_list_box_append(list, GTK_WIDGET(launcher)); -        result = handle(class, data); +    } + +} -        g_type_class_unref(class); -        if (!result) break; +/****************************************************************************** +*                                                                             * +*  Paramètres  : row = lanceur sélectionné.                                   * +*                                                                             * +*  Description : Fournit un composant d'édition de paramètres de panneau.     * +*                                                                             * +*  Retour      : Composant d'édition de paramètres ou NULL.                   * +*                                                                             * +*  Remarques   : -                                                            * +*                                                                             * +******************************************************************************/ + +GtkWidget *get_framework_panel_parameters(GtkListBoxRow *row) +{ +    GtkWidget *result;                      /* Composant à retourner       */ +    gpointer *data;                         /* Valeur incrustée            */ +    GType target;                           /* Type de panneau recherché   */ +    ext_panel_info_t *info;                 /* Informations conservées     */ +    size_t i;                               /* Boucle de parcours          */ + +    data = g_object_get_data(G_OBJECT(row), "panel_type"); +    assert(data != NULL); + +    target = GPOINTER_TO_SIZE(data); + +    info = NULL; + +    for (i = 0; i < _panels_count; i++) +    { +        info = _panels_list[i]; + +        if (info->panel_type == target) +            break;      } +    assert(info != NULL); +    assert(i < _panels_count); + +    if (info->params_type == G_TYPE_INVALID) +        result = NULL; +    else +        result = g_object_new(info->params_type, NULL); +      return result;  } diff --git a/src/gui/core/panels.h b/src/gui/core/panels.h index 3846038..e17ef8a 100644 --- a/src/gui/core/panels.h +++ b/src/gui/core/panels.h @@ -1,8 +1,8 @@  /* Chrysalide - Outil d'analyse de fichiers binaires - * panels.h - prototypes pour la gestion d'ensemble de tous les panneaux pour l'éditeur + * panels.h - prototypes pour la gestion d'ensemble de tous les panneaux graphiques du framework   * - * Copyright (C) 2016-2019 Cyrille Bagard + * Copyright (C) 2016-2025 Cyrille Bagard   *   *  This file is part of Chrysalide.   * @@ -26,28 +26,62 @@  #define _GUI_CORE_PANELS_H +#include <glib-object.h>  #include <stdbool.h> +#include <gtk/gtk.h> -#include "../panel.h" -#include "../../glibext/configuration.h" +#include "../../gtkext/panel.h" -/* Charge les principaux panneaux de l'éditeur. */ -void load_main_panels(void); +/* Types de panneaux pour éditeur */ +typedef enum _FrameworkPanelPersonality +{ +    FPP_NONE        = (0 << 0),             /* Pas de particularité        */ -/* Enregistre un panneau comme partie intégrante de l'éditeur. */ -void register_panel_item(GType, GGenConfig *); +    FPP_MAIN_PANEL  = (1 << 0),             /* Panneau principal           */ +    FPP_SINGLETON   = (1 << 1),             /* Instance unique             */ -/* Réalise un traitement sur un panneau de l'éditeur. */ -typedef bool (* handle_panel_item_fc) (GPanelItemClass *, void *); +} FrameworkPanelPersonality; -/* Effectue le parcours de tous les panneaux chargés. */ -bool _browse_all_item_panels(bool, handle_panel_item_fc, void *); +/* Définition générique d'un panneau */ +typedef struct _panel_info_t +{ +    const char *category;                   /* Groupe de rassemblement     */ -#define browse_all_item_panels(h, d) \ -    _browse_all_item_panels(false, h, d) +    const char *image;                      /* Eventuelle image associée   */ +    const char *title;                      /* Désignation humaine         */ +    const char *desc;                       /* Description humaine         */ + +    FrameworkPanelPersonality personality;  /* Comportement attendu        */ + +    GType panel_type;                       /* Type du panneau représenté  */ +    GType params_type;                      /* Composant de paramètre      */ + +} panel_info_t; + + +/* Charge les définitions des principaux panneaux du framework. */ +bool load_main_framework_panel_definitions(void); + +/* Décharge tous les panneaux graphiques du framework. */ +void unload_all_framework_panel_definitions(void); + +/* Enregistre la définition d'un panneau graphique. */ +bool register_framework_panel_definition(const panel_info_t *); + +/* Récupère les particularités d'un panneau graphique. */ +FrameworkPanelPersonality get_framework_panel_personality(GType); + +/* Met en place (au besoin) un panneau graphique unique. */ +GtkTiledPanel *get_framework_panel_singleton(GType); + +/* Intègre une définition de panneau enregistrée. */ +void populate_framework_panel_launcher_list(GtkListBox *); + +/* Fournit un composant d'édition de paramètres de panneau. */ +GtkWidget *get_framework_panel_parameters(GtkListBoxRow *); diff --git a/src/gui/dialogs/Makefile.am b/src/gui/dialogs/Makefile.am index 5716f14..3492f63 100644 --- a/src/gui/dialogs/Makefile.am +++ b/src/gui/dialogs/Makefile.am @@ -3,35 +3,43 @@ BUILT_SOURCES = resources.h resources.c  noinst_LTLIBRARIES  = libguidialogs.la -UI_FILES =								\ -	about.ui							\ -	bookmark.ui							\ -	export_graph.ui						\ -	identity.ui							\ -	loading.ui							\ -	preferences.ui						\ -	prefs_fgraph.ui						\ -	prefs_labels.ui						\ -	snapshots.ui						\ -	storage.ui - -libguidialogs_la_SOURCES =				\ -	about.h about.c						\ -	bookmark.h bookmark.c				\ -	export_disass.h export_disass.c		\ -	export_graph.h export_graph.c		\ -	goto.h goto.c						\ -	gotox.h gotox.c						\ -	identity.h identity.c				\ -	loading.h loading.c					\ -	preferences.h preferences.c			\ -	prefs_fgraph.h prefs_fgraph.c		\ -	prefs_labels.h prefs_labels.c		\ -	resources.h resources.c				\ -	snapshots.h snapshots.c				\ -	storage.h storage.c - -libguidialogs_la_CFLAGS = $(LIBGTK_CFLAGS) $(LIBXML_CFLAGS) + +UI_FILES =									\ +	about.css								\ +	about.ui								\ +	preferences.ui +# bookmark.ui							\ +# export_graph.ui						\ +# identity.ui							\ +# loading.ui							\ +# prefs_fgraph.ui						\ +# prefs_labels.ui						\ +# snapshots.ui						\ +# storage.ui + +libguidialogs_la_SOURCES =					\ +	about-int.h								\ +	about.h about.c							\ +	preferences-int.h						\ +	preferences.h preferences.c				\ +	resources.h resources.c +# bookmark.h bookmark.c				\ +# export_disass.h export_disass.c		\ +# export_graph.h export_graph.c		\ +# goto.h goto.c						\ +# gotox.h gotox.c						\ +# identity.h identity.c				\ +# loading.h loading.c					\ +# 			\ +# prefs_fgraph.h prefs_fgraph.c		\ +# prefs_labels.h prefs_labels.c		\ +# snapshots.h snapshots.c				\ +# storage.h storage.c + +libguidialogs_la_LIBADD =					\ +	prefs/libguidialogsprefs.la + +libguidialogs_la_CFLAGS = $(LIBGTK4_CFLAGS)  devdir = $(includedir)/chrysalide/$(subdir:src/%=core/%) @@ -39,6 +47,9 @@ devdir = $(includedir)/chrysalide/$(subdir:src/%=core/%)  dev_HEADERS = $(libguidialogs_la_SOURCES:%c=) +SUBDIRS = prefs + +  resources.c: gresource.xml $(UI_FILES)  	glib-compile-resources --target=$@ --sourcedir=$(srcdir) --generate-source --c-name gui_dialogs gresource.xml diff --git a/src/gui/dialogs/about-int.h b/src/gui/dialogs/about-int.h new file mode 100644 index 0000000..96a470e --- /dev/null +++ b/src/gui/dialogs/about-int.h @@ -0,0 +1,55 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * about-int.h - définitions internes pour la boîte de dialogue d'information sur le programme + * + * Copyright (C) 2024 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 _GUI_DIALOGS_ABOUT_INT_H +#define _GUI_DIALOGS_ABOUT_INT_H + + +#include <stdbool.h> + + +#include "about.h" + + + +/* Boîte "A propos de" dédiée à l'application (instance) */ +struct _GtkAppAboutDialog +{ +    GtkWindow parent;                       /* A laisser en premier        */ + +}; + +/* Boîte "A propos de" dédiée à l'application (classe) */ +struct _GtkAppAboutDialogClass +{ +    GtkWindowClass parent;                  /* A laisser en premier        */ + +}; + + +/* Met en place la fenêtre d'informations sur le logiciel. */ +bool gtk_app_about_dialog_create(GtkAppAboutDialog *, GtkWindow *); + + + +#endif  /* _GUI_DIALOGS_ABOUT_INT_H */ diff --git a/src/gui/dialogs/about.c b/src/gui/dialogs/about.c index 574c7f2..1dca752 100644 --- a/src/gui/dialogs/about.c +++ b/src/gui/dialogs/about.c @@ -2,7 +2,7 @@  /* Chrysalide - Outil d'analyse de fichiers binaires   * about.h - boîte de dialogue d'information sur le programme   * - * Copyright (C) 2015-2020 Cyrille Bagard + * Copyright (C) 2015-2024 Cyrille Bagard   *   *  This file is part of Chrysalide.   * @@ -33,143 +33,168 @@  #include <config.h> -#include "../../gtkext/easygtk.h" +#include "about-int.h" -/* Réagit à l'appui d'une touche sur la fenêtre 'A propos'. */ -static gboolean close_about_window_on_escape(GtkWidget *, GdkEventKey *, gpointer); +/* Procède à l'initialisation de la boîte "A propos de". */ +static void gtk_app_about_dialog_class_init(GtkAppAboutDialogClass *); -/* Dessine un fond adapté pour la fenêtre sans toucher au thème. */ -static gboolean draw_black_background(GtkWidget *, cairo_t *, gpointer); +/* Procède à l'initialisation de la boîte "A propos de". */ +static void gtk_app_about_dialog_init(GtkAppAboutDialog *); +/* Supprime toutes les références externes. */ +static void gtk_app_about_dialog_dispose(GObject *); + +/* Procède à la libération totale de la mémoire. */ +static void gtk_app_about_dialog_finalize(GObject *); + + + +/* Détermine le type du composant d'affichage générique. */ +G_DEFINE_TYPE(GtkAppAboutDialog, gtk_app_about_dialog, GTK_TYPE_WINDOW);  /******************************************************************************  *                                                                             * -*  Paramètres  : parent = fenêtre parente à surpasser.                        * -*                outb   = constructeur à détruire après usage. [OUT]          * +*  Paramètres  : class = classe GTK à initialiser.                            *  *                                                                             * -*  Description : Construit la fenêtre d'informations sur le logiciel.         * +*  Description : Procède à l'initialisation de la boîte "A propos de".        *  *                                                                             * -*  Retour      : Adresse de la fenêtre mise en place.                         * +*  Retour      : -                                                            *  *                                                                             *  *  Remarques   : -                                                            *  *                                                                             *  ******************************************************************************/ -GtkWidget *create_about_dialog(GtkWindow *parent, GtkBuilder **outb) +static void gtk_app_about_dialog_class_init(GtkAppAboutDialogClass *class)  { -    GtkWidget *result;                      /* Fenêtre à renvoyer          */ -    GtkBuilder *builder;                    /* Constructeur utilisé        */ -    unsigned int revision;                  /* Numéro de révision          */ -    unsigned int max;                       /* Nbre. de boucles à effectuer*/ -    unsigned int i;                         /* Boucle de parcours          */ -    unsigned int level;                     /* Unité la plus importante    */ -    char buffer[64];                        /* Nom d'image à forger        */ -    GtkImage *img;                          /* Composant d'affichage       */ +    GObjectClass *object;                   /* Plus haut niveau équivalent */ +    GtkWidgetClass *widget;                 /* Classe de haut niveau       */ -    builder = gtk_builder_new_from_resource("/org/chrysalide/gui/dialogs/about.ui"); -    *outb = builder; +    object = G_OBJECT_CLASS(class); -    result = GTK_WIDGET(gtk_builder_get_object(builder, "window")); +    object->dispose = gtk_app_about_dialog_dispose; +    object->finalize = gtk_app_about_dialog_finalize; -    gtk_window_set_transient_for(GTK_WINDOW(result), parent); +    widget = GTK_WIDGET_CLASS(class); -    /* Numéro de révision */ +    gtk_widget_class_set_css_name(widget, "aboutdialog"); -    revision = REVISION; -    max = log(revision) / log(10); +    gtk_widget_class_add_binding_action(widget, GDK_KEY_Escape, 0, "window.close", NULL); -    assert(max <= 6); +    gtk_widget_class_set_template_from_resource(widget, "/re/chrysalide/framework/gui/dialogs/about.ui"); -    for (i = 0; i <= max; i++) -    { -        snprintf(buffer, 64, "revision_%u", i); +} -        img = GTK_IMAGE(gtk_builder_get_object(builder, buffer)); -        level = pow(10, max - i); +/****************************************************************************** +*                                                                             * +*  Paramètres  : dialog = composant GTK à initialiser.                        * +*                                                                             * +*  Description : Procède à l'initialisation de la boîte "A propos de".        * +*                                                                             * +*  Retour      : -                                                            * +*                                                                             * +*  Remarques   : -                                                            * +*                                                                             * +******************************************************************************/ -        snprintf(buffer, 64, "/org/chrysalide/gui/dialogs/about/revision_%u.png", revision / level); +static void gtk_app_about_dialog_init(GtkAppAboutDialog *dialog) +{ +    gtk_widget_init_template(GTK_WIDGET(dialog)); -        gtk_image_set_from_resource(img, buffer); +} -        revision %= level; -    } +/****************************************************************************** +*                                                                             * +*  Paramètres  : object = instance d'objet GLib à traiter.                    * +*                                                                             * +*  Description : Supprime toutes les références externes.                     * +*                                                                             * +*  Retour      : -                                                            * +*                                                                             * +*  Remarques   : -                                                            * +*                                                                             * +******************************************************************************/ -    /* Connexion des signaux */ +static void gtk_app_about_dialog_dispose(GObject *object) +{ +    gtk_widget_dispose_template(GTK_WIDGET(object), GTK_TYPE_APP_ABOUT_DIALOG); -    gtk_builder_add_callback_symbols(builder, -                                     BUILDER_CALLBACK(close_about_window_on_escape), -                                     BUILDER_CALLBACK(draw_black_background), -                                     NULL); +    G_OBJECT_CLASS(gtk_app_about_dialog_parent_class)->dispose(object); -    gtk_builder_connect_signals(builder, builder); +} -    return result; + +/****************************************************************************** +*                                                                             * +*  Paramètres  : object = instance d'objet GLib à traiter.                    * +*                                                                             * +*  Description : Procède à la libération totale de la mémoire.                * +*                                                                             * +*  Retour      : -                                                            * +*                                                                             * +*  Remarques   : -                                                            * +*                                                                             * +******************************************************************************/ + +static void gtk_app_about_dialog_finalize(GObject *object) +{ +    G_OBJECT_CLASS(gtk_app_about_dialog_parent_class)->finalize(object);  }  /******************************************************************************  *                                                                             * -*  Paramètres  : widget = fenêtre visée par la procédure.                     * -*                event  = informations liées à l'événement.                   * -*                dummy  = donnée non utilisée ici.                            * +*  Paramètres  : parent = fenêtre parente à surpasser.                        *  *                                                                             * -*  Description : Réagit à l'appui d'une touche sur la fenêtre 'A propos'.     * +*  Description : Construit la fenêtre d'informations sur le logiciel.         *  *                                                                             * -*  Retour      : TRUE pour interrompre la propagation, FALSE autrement.       * +*  Retour      : Adresse de la fenêtre mise en place.                         *  *                                                                             *  *  Remarques   : -                                                            *  *                                                                             *  ******************************************************************************/ -static gboolean close_about_window_on_escape(GtkWidget *widget, GdkEventKey *event, gpointer dummy) +GtkWindow *gtk_app_about_dialog_new(GtkWindow *parent)  { -    gboolean result;                        /* Ordre à retourner           */ +    GtkWindow *result;                      /* Boite de dialogue à renvoyer*/ + +    result = g_object_new(GTK_TYPE_APP_ABOUT_DIALOG, NULL); -    if (event->keyval == GDK_KEY_Escape) -    { -        gtk_widget_destroy(widget); -        result = TRUE; -    } -    else result = FALSE; +    if (!gtk_app_about_dialog_create(GTK_APP_ABOUT_DIALOG(result), parent)) +        g_clear_object(&result);      return result;  } +  /******************************************************************************  *                                                                             * -*  Paramètres  : widget = fenêtre visée par la procédure.                     * -*                event  = informations liées à l'événement.                   * -*                dummy  = donnée non utilisée ici.                            * +*  Paramètres  : dialog = boîte de dialogue à initialiser pleinement.         * +*                parent = fenêtre parente à surpasser.                        *  *                                                                             * -*  Description : Dessine un fond adapté pour la fenêtre sans toucher au thème.* +*  Description : Met en place la fenêtre d'informations sur le logiciel.      *  *                                                                             * -*  Retour      : TRUE pour interrompre la propagation, FALSE autrement.       * +*  Retour      : Bilan de l'opération.                                        *  *                                                                             *  *  Remarques   : -                                                            *  *                                                                             *  ******************************************************************************/ -static gboolean draw_black_background(GtkWidget *widget, cairo_t *cr, gpointer dummy) +bool gtk_app_about_dialog_create(GtkAppAboutDialog *dialog, GtkWindow *parent)  { -    int width;                              /* Largeur du composant        */ -    int height;                             /* Hauteur du composant        */ +    bool result;                            /* Bilan à retourner           */ -    width = gtk_widget_get_allocated_width(widget); -    height = gtk_widget_get_allocated_height(widget); +    result = true; -    cairo_set_source_rgb(cr, 0.0, 0.0, 0.0); +    gtk_window_set_transient_for(GTK_WINDOW(dialog), parent); -    cairo_rectangle(cr, 0, 0, width, height); -    cairo_fill(cr); - -    return FALSE; +    return result;  } diff --git a/src/gui/dialogs/about.css b/src/gui/dialogs/about.css new file mode 100644 index 0000000..af3fa97 --- /dev/null +++ b/src/gui/dialogs/about.css @@ -0,0 +1,9 @@ + +aboutdialog > box { + +    background-color: black; + +    background-image: url('resource:///re/chrysalide/framework/gui/dialogs/about/bg.png'); +    background-repeat: no-repeat; + +} diff --git a/src/gui/dialogs/about.h b/src/gui/dialogs/about.h index f119f67..e569ad3 100644 --- a/src/gui/dialogs/about.h +++ b/src/gui/dialogs/about.h @@ -2,7 +2,7 @@  /* Chrysalide - Outil d'analyse de fichiers binaires   * about.h - prototypes pour la boîte de dialogue d'information sur le programme   * - * Copyright (C) 2015-2020 Cyrille Bagard + * Copyright (C) 2015-2024 Cyrille Bagard   *   *  This file is part of Chrysalide.   * @@ -28,9 +28,17 @@  #include <gtk/gtk.h> +#include "../../glibext/helpers.h" + + + +#define GTK_TYPE_APP_ABOUT_DIALOG (gtk_app_about_dialog_get_type()) + +DECLARE_GTYPE(GtkAppAboutDialog, gtk_app_about_dialog, GTK, APP_ABOUT_DIALOG); +  /* Construit la fenêtre d'informations sur le logiciel. */ -GtkWidget *create_about_dialog(GtkWindow *, GtkBuilder **); +GtkWindow *gtk_app_about_dialog_new(GtkWindow *); diff --git a/src/gui/dialogs/about.ui b/src/gui/dialogs/about.ui index 0170508..7b519d2 100644 --- a/src/gui/dialogs/about.ui +++ b/src/gui/dialogs/about.ui @@ -1,151 +1,28 @@  <?xml version="1.0" encoding="UTF-8"?> -<!-- Generated with glade 3.37.0 -->  <interface> -  <requires lib="gtk+" version="3.12"/> -  <object class="GtkWindow" id="window"> -    <property name="width-request">350</property> -    <property name="height-request">430</property> -    <property name="can-focus">False</property> -    <property name="border-width">0</property> -    <property name="title" translatable="yes">About</property> -    <property name="resizable">False</property> -    <property name="modal">True</property> -    <property name="window-position">center-on-parent</property> -    <property name="default-width">350</property> -    <property name="default-height">430</property> -    <property name="type-hint">dialog</property> -    <signal name="key-press-event" handler="close_about_window_on_escape" swapped="no"/> -    <child> -      <object class="GtkFixed"> -        <property name="visible">True</property> -        <property name="can-focus">False</property> -        <signal name="draw" handler="draw_black_background" swapped="no"/> -        <child> -          <object class="GtkLabel"> -            <property name="width-request">350</property> -            <property name="height-request">20</property> -            <property name="visible">True</property> -            <property name="can-focus">False</property> -            <property name="margin-bottom">10</property> -            <property name="label" translatable="yes"><span fgcolor='white'>Copyright (C) 2008-2020 Cyrille Bagard</span></property> -            <property name="use-markup">True</property> -          </object> -          <packing> -            <property name="y">400</property> -          </packing> -        </child> -        <child> -          <object class="GtkImage" id="logo"> -            <property name="width-request">330</property> -            <property name="height-request">300</property> -            <property name="visible">True</property> -            <property name="can-focus">False</property> -            <property name="resource">/org/chrysalide/gui/dialogs/about/chrysalide-full.png</property> -          </object> -          <packing> -            <property name="x">10</property> -            <property name="y">10</property> -          </packing> -        </child> -        <child> -          <object class="GtkImage" id="text"> -            <property name="width-request">253</property> -            <property name="height-request">42</property> -            <property name="visible">True</property> -            <property name="can-focus">False</property> -            <property name="resource">/org/chrysalide/gui/dialogs/about/chrysalide_text.png</property> -          </object> -          <packing> -            <property name="x">48</property> -            <property name="y">324</property> -          </packing> -        </child> -        <child> -          <object class="GtkImage" id="revision"> -            <property name="width-request">14</property> -            <property name="height-request">18</property> -            <property name="visible">True</property> -            <property name="can-focus">False</property> -            <property name="resource">/org/chrysalide/gui/dialogs/about/revision.png</property> -          </object> -          <packing> -            <property name="x">149</property> -            <property name="y">360</property> -          </packing> -        </child> -        <child> -          <object class="GtkImage" id="revision_0"> -            <property name="width-request">14</property> -            <property name="height-request">18</property> -            <property name="visible">True</property> -            <property name="can-focus">False</property> -          </object> -          <packing> -            <property name="x">163</property> -            <property name="y">360</property> -          </packing> -        </child> -        <child> -          <object class="GtkImage" id="revision_1"> -            <property name="width-request">14</property> -            <property name="height-request">18</property> -            <property name="visible">True</property> -            <property name="can-focus">False</property> -          </object> -          <packing> -            <property name="x">177</property> -            <property name="y">360</property> -          </packing> -        </child> -        <child> -          <object class="GtkImage" id="revision_2"> -            <property name="width-request">14</property> -            <property name="height-request">18</property> -            <property name="visible">True</property> -            <property name="can-focus">False</property> -          </object> -          <packing> -            <property name="x">191</property> -            <property name="y">360</property> -          </packing> -        </child> -        <child> -          <object class="GtkImage" id="revision_3"> -            <property name="width-request">14</property> -            <property name="height-request">18</property> -            <property name="visible">True</property> -            <property name="can-focus">False</property> -          </object> -          <packing> -            <property name="x">205</property> -            <property name="y">360</property> -          </packing> -        </child> -        <child> -          <object class="GtkImage" id="revision_4"> -            <property name="width-request">14</property> -            <property name="height-request">18</property> -            <property name="visible">True</property> -            <property name="can-focus">False</property> -          </object> -          <packing> -            <property name="x">219</property> -            <property name="y">360</property> -          </packing> -        </child> -        <child> -          <object class="GtkImage" id="revision_5"> -            <property name="width-request">14</property> -            <property name="height-request">18</property> -            <property name="visible">True</property> -            <property name="can-focus">False</property> -          </object> -          <packing> -            <property name="x">233</property> -            <property name="y">360</property> -          </packing> -        </child> -      </object> -    </child> -  </object> + +    <template class="GtkAppAboutDialog" parent="GtkWindow"> +        <property name="title" translatable="yes">About</property> +        <property name="default-width">350</property> +        <property name="default-height">430</property> +        <property name="modal">true</property> +        <property name="resizable">false</property> + +        <child> +            <object class="GtkBox"> +                <property name="orientation">vertical</property> + +                <child> +                    <object class="GtkLabel"> +                        <property name="margin-top">368</property> +                        <property name="margin-bottom">10</property> +                        <property name="label" translatable="yes"><span fgcolor='white'>Copyright (C) 2008-2025 Cyrille Bagard</span></property> +                        <property name="use-markup">True</property> +                    </object> +                </child> + +            </object> +        </child> + +    </template>  </interface> diff --git a/src/gui/dialogs/gresource.xml b/src/gui/dialogs/gresource.xml index 0e12ef2..966d9c8 100644 --- a/src/gui/dialogs/gresource.xml +++ b/src/gui/dialogs/gresource.xml @@ -1,30 +1,8 @@  <?xml version="1.0" encoding="UTF-8"?>  <gresources> -    <gresource prefix="/org/chrysalide/gui/dialogs"> +    <gresource prefix="/re/chrysalide/framework/gui/dialogs"> +        <file compressed="true">about.css</file>          <file compressed="true">about.ui</file> -        <file compressed="true">bookmark.ui</file> -        <file compressed="true">export_graph.ui</file> -        <file compressed="true">identity.ui</file> -        <file compressed="true">loading.ui</file>          <file compressed="true">preferences.ui</file> -        <file compressed="true">prefs_fgraph.ui</file> -        <file compressed="true">prefs_labels.ui</file> -        <file compressed="true">snapshots.ui</file> -        <file compressed="true">storage.ui</file> -    </gresource> -    <gresource prefix="/org/chrysalide/gui/dialogs/about"> -      <file compressed="true" alias="chrysalide-full.png">../../../pixmaps/chrysalide-full.png</file> -      <file compressed="true" alias="chrysalide_text.png">../../../pixmaps/chrysalide_text.png</file> -      <file compressed="true" alias="revision.png">../../../pixmaps/revision.png</file> -      <file compressed="true" alias="revision_0.png">../../../pixmaps/revision_0.png</file> -      <file compressed="true" alias="revision_1.png">../../../pixmaps/revision_1.png</file> -      <file compressed="true" alias="revision_2.png">../../../pixmaps/revision_2.png</file> -      <file compressed="true" alias="revision_3.png">../../../pixmaps/revision_3.png</file> -      <file compressed="true" alias="revision_4.png">../../../pixmaps/revision_4.png</file> -      <file compressed="true" alias="revision_5.png">../../../pixmaps/revision_5.png</file> -      <file compressed="true" alias="revision_6.png">../../../pixmaps/revision_6.png</file> -      <file compressed="true" alias="revision_7.png">../../../pixmaps/revision_7.png</file> -      <file compressed="true" alias="revision_8.png">../../../pixmaps/revision_8.png</file> -      <file compressed="true" alias="revision_9.png">../../../pixmaps/revision_9.png</file>      </gresource>  </gresources> diff --git a/src/gui/dialogs/preferences-int.h b/src/gui/dialogs/preferences-int.h new file mode 100644 index 0000000..806f5f6 --- /dev/null +++ b/src/gui/dialogs/preferences-int.h @@ -0,0 +1,62 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * preferences-int.h - définitions internes pour la boîte de dialogue d'édition des préférences de l'utilisateur + * + * 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 _GUI_DIALOGS_PREFERENCES_INT_H +#define _GUI_DIALOGS_PREFERENCES_INT_H + + +#include <stdbool.h> + + +#include "preferences.h" + + + +/* Fenêtre d'édition générale de la configuration (instance) */ +struct _GtkPreferencesDialog +{ +    GtkWindow parent;                       /* A laisser en premier        */ + +    GtkLabel *side_title;                   /* Titre principal             */ +    GtkScrolledWindow *side_content;        /* Liste des sections          */ +    GtkLabel *main_title;                   /* Titre de section            */ +    GtkScrolledWindow *main_content;        /* Page de configuration       */ + +    GHashTable *navigations;                /* Liste de sections en place  */ + +}; + +/* Fenêtre d'édition générale de la configuration (classe) */ +struct _GtkPreferencesDialogClass +{ +    GtkWindowClass parent;                  /* A laisser en premier        */ + +}; + + +/* Met en place la boîte de dialogue pour les préférences. */ +bool gtk_preferences_dialog_create(GtkPreferencesDialog *, GtkWindow *); + + + +#endif  /* _GUI_DIALOGS_PREFERENCES_INT_H */ diff --git a/src/gui/dialogs/preferences.c b/src/gui/dialogs/preferences.c index 4a3fb7c..0369241 100644 --- a/src/gui/dialogs/preferences.c +++ b/src/gui/dialogs/preferences.c @@ -1,8 +1,8 @@  /* Chrysalide - Outil d'analyse de fichiers binaires - * preferences.c - (re)définition de l'identité de l'utilisateur + * preferences.c - boîte de dialogue d'édition des préférences de l'utilisateur   * - * Copyright (C) 2019 Cyrille Bagard + * Copyright (C) 2019-2025 Cyrille Bagard   *   *  This file is part of Chrysalide.   * @@ -24,129 +24,105 @@  #include "preferences.h" -#include <i18n.h> +#include <assert.h> +#include <math.h> +#include <stdio.h> +#include <gdk/gdkkeysyms.h> -#include "prefs_fgraph.h" -#include "prefs_labels.h" -#include "../../core/params.h" -#include "../../gtkext/easygtk.h" +#include <config.h> +#include "preferences-int.h" +#include "prefs/appearance.h" +#include "prefs/security.h" +#include "../../common/cpp.h" +#include "../../gtkext/tweak.h" +#include "../../plugins/pglist.h" +#include "../../plugins/tweakable.h" -/* Constructeur de panneau de paramétrage */ -typedef GtkWidget * (* prefs_panel_creation_cb) (GtkBuilder **); -/* Chargement de la configuration */ -typedef void (* prefs_config_update_cb) (GtkBuilder *, GGenConfig *); -/* Description d'un noeud de préférences */ -typedef struct _pref_node_desc_t -{ -    prefs_panel_creation_cb create;         /* Procédure de création       */ -    prefs_config_update_cb load;            /* Procédure de chargement     */ -    prefs_config_update_cb store;           /* Procédure d'enregistrement  */ - -    const char *name;                       /* Désignation interne         */ -    const char *title;                      /* Désignation humaine         */ - -    GtkBuilder *builder;                    /* Constructeur GTK            */ -    GtkWidget *panel;                       /* Panneau GTK                 */ - -    struct _pref_node_desc_t *children;     /* Sous-arborescence           */ - -} pref_node_desc_t; - - -#define PREF_NODE_NULL_ENTRY { .title = NULL } +/* --------------------------- BASES DE BOITE DE DIALOGUE --------------------------- */ -/* Liste des paramétrages à afficher */ -static pref_node_desc_t _prefs_nodes[] = { +/* Procède à l'initialisation de la fenêtre des paramètres. */ +static void gtk_preferences_dialog_class_init(GtkPreferencesDialogClass *); -    { -        .create = NULL, - -        .title = "Analysis", +/* Procède à l'initialisation de la fenêtre des paramètres. */ +static void gtk_preferences_dialog_init(GtkPreferencesDialog *); -        .children = (pref_node_desc_t []){ +/* Supprime toutes les références externes. */ +static void gtk_preferences_dialog_dispose(GObject *); -            { -                .create = create_labels_preferences, -                .load = load_labels_configuration, -                .store = store_labels_configuration, +/* Procède à la libération totale de la mémoire. */ +static void gtk_preferences_dialog_finalize(GObject *); -                .name = "labels", -                .title = "Colored labels", +/* Fournit la liste de section désignée par un nom. */ +static GtkListBox *gtk_preferences_dialog_get_navigation(GtkPreferencesDialog *, const char *, bool); -            }, +/* Réagit à un changement de sélection dans les sections. */ +static void gtk_preferences_dialog_on_row_selected(GtkListBox *, GtkListBoxRow *, GtkPreferencesDialog *); -            PREF_NODE_NULL_ENTRY -        } -    }, +/* --------------------- IMPLEMENTATION DES FONCTIONS DE CLASSE --------------------- */ -    { -        .create = NULL, -        .title = "Editor", -        .children = (pref_node_desc_t []){ -            { -                .create = create_fgraph_preferences, -                .load = load_fgraph_configuration, -                .store = store_fgraph_configuration, -                .name = "fgraph", -                .title = "Function graph", +/* ---------------------------------------------------------------------------------- */ +/*                             BASES DE BOITE DE DIALOGUE                             */ +/* ---------------------------------------------------------------------------------- */ -            }, - -            PREF_NODE_NULL_ENTRY - -        } -    }, +/* Détermine le type du composant d'affichage générique. */ +G_DEFINE_TYPE(GtkPreferencesDialog, gtk_preferences_dialog, GTK_TYPE_WINDOW); -    PREF_NODE_NULL_ENTRY - -}; +/****************************************************************************** +*                                                                             * +*  Paramètres  : class = classe GTK à initialiser.                            * +*                                                                             * +*  Description : Procède à l'initialisation de la fenêtre des paramètres.     * +*                                                                             * +*  Retour      : -                                                            * +*                                                                             * +*  Remarques   : -                                                            * +*                                                                             * +******************************************************************************/ -/* Eléments de la liste de sections */ -typedef enum _PrefListItem +static void gtk_preferences_dialog_class_init(GtkPreferencesDialogClass *class)  { -    PLI_TITLE,                              /* Etiquette de la section     */ -    PLI_PANEL,                              /* Panneau graphique associé   */ +    GObjectClass *object;                   /* Plus haut niveau équivalent */ +    GtkWidgetClass *widget;                 /* Classe de haut niveau       */ -} PrefListItem; +    object = G_OBJECT_CLASS(class); +    object->dispose = gtk_preferences_dialog_dispose; +    object->finalize = gtk_preferences_dialog_finalize; -/* Ajoute un panneau de paramétrage à la boîte de dialogue. */ -static void add_preferences_node(GtkTreeStore *, GtkTreeIter *, GGenConfig *, GtkStack *, pref_node_desc_t *); +    widget = GTK_WIDGET_CLASS(class); -/* Affiche le panneau correspondant au noeud sélectionné. */ -static void on_prefs_selection_changed(GtkTreeSelection *, GtkBuilder *); +    gtk_widget_class_set_template_from_resource(widget, "/re/chrysalide/framework/gui/dialogs/preferences.ui"); -/* Lance la sauvegarde d'éléments de paramétrage. */ -static void store_preferences_node(GGenConfig *, pref_node_desc_t *); +    gtk_widget_class_bind_template_child(widget, GtkPreferencesDialog, side_title); +    gtk_widget_class_bind_template_child(widget, GtkPreferencesDialog, side_content); +    gtk_widget_class_bind_template_child(widget, GtkPreferencesDialog, main_title); +    gtk_widget_class_bind_template_child(widget, GtkPreferencesDialog, main_content); -/* Sauvegarde l'ensemble des paramètres de configuration. */ -static void on_prefs_apply_button_clicked(GtkButton *, GtkBuilder *); +    /* Active une action native (cf. https://docs.gtk.org/gtk4/class.Window.html#actions) */ +    gtk_widget_class_add_binding_action(widget, GDK_KEY_Escape, 0 /* GDK 4.14 : GDK_NO_MODIFIER_MASK */, "window.close", NULL); +}  /******************************************************************************  *                                                                             * -*  Paramètres  : store  = arborescence des sections à compléter.              * -*                parent = point d'insertion du parent.                        * -*                config = configuration globale à charger.                    * -*                stack  = pile de composants GTK à constituer.                * -*                node   = noeud de description courant à traiter.             * +*  Paramètres  : dialog = composant GTK à initialiser.                        *  *                                                                             * -*  Description : Ajoute un panneau de paramétrage à la boîte de dialogue.     * +*  Description : Procède à l'initialisation de la fenêtre des paramètres.     *  *                                                                             *  *  Retour      : -                                                            *  *                                                                             * @@ -154,95 +130,152 @@ static void on_prefs_apply_button_clicked(GtkButton *, GtkBuilder *);  *                                                                             *  ******************************************************************************/ -static void add_preferences_node(GtkTreeStore *store, GtkTreeIter *parent, GGenConfig *config, GtkStack *stack, pref_node_desc_t *node) +static void gtk_preferences_dialog_init(GtkPreferencesDialog *dialog)  { -    GtkTreeIter iter;                       /* Point d'insertion           */ -    pref_node_desc_t *child;                /* Sous-élément à traiter      */ +    size_t i;                               /* Boucle de parcours          */ +    const tweak_info_t *info;               /* Informations à considérer   */ +    GtkListBox *navigation;                 /* Liste de sections à afficher*/ +    GtkTweakSection *section;               /* Nouvelle section à présenter*/ +    tweak_info_t *dyn_infos;                /* Informations supplémentaires*/ +    size_t dyn_count;                       /* Quantité de ces informations*/ + +    tweak_info_t infos[] = { +        TWEAK_SIMPLE_DEF("root", "Basics", +                         "security-high-symbolic", "appearance", "Appearance", GTK_TYPE_APPEARANCE_TWEAK_PANEL), +        TWEAK_SIMPLE_DEF("root", "Basics", +                         "security-high-symbolic", "security", "Security", GTK_TYPE_SECURITY_TWEAK_PANEL), +    }; + +    gtk_widget_init_template(GTK_WIDGET(dialog)); -    if (node->create == NULL) +    dialog->navigations = g_hash_table_new_full(g_str_hash, g_str_equal, free, g_object_unref); + +    /* Chargement des sections fixes */ + +    for (i = 0; i < ARRAY_SIZE(infos); i++)      { -        node->builder = NULL; -        node->panel = NULL; +        info = &infos[i]; + +        navigation = gtk_preferences_dialog_get_navigation(dialog, info->parent, true); +        assert(navigation != NULL); + +        section = gtk_tweak_section_new(info); + +        gtk_list_box_append(navigation, GTK_WIDGET(section)); +      } -    else + +    /* Chargement des sections dynamiques */ + +    dyn_infos = get_tweakable_plugins_info(&dyn_count); + +    for (i = 0; i < dyn_count; i++)      { -        node->panel = node->create(&node->builder); +        info = &dyn_infos[i]; -        node->load(node->builder, config); +        navigation = gtk_preferences_dialog_get_navigation(dialog, info->parent, true); +        assert(navigation != NULL); -        gtk_widget_show(node->panel); +        section = gtk_tweak_section_new(info); -        gtk_stack_add_named(stack, node->panel, node->name); +        gtk_list_box_append(navigation, GTK_WIDGET(section));      } -    gtk_tree_store_append(store, &iter, parent); +    if (dyn_infos != NULL) +        free(dyn_infos); + +    /* Affichage de la liste racine */ -    gtk_tree_store_set(store, &iter, -                       PLI_TITLE, _(node->title), -                       PLI_PANEL, node->panel, -                       -1); +    navigation = gtk_preferences_dialog_get_navigation(dialog, "root", false); +    assert(navigation != NULL); -    if (node->children != NULL) -        for (child = node->children; child->title != NULL; child++) -            add_preferences_node(store, &iter, config, stack, child); +    g_signal_connect(navigation, "row-selected", +                     G_CALLBACK(gtk_preferences_dialog_on_row_selected), dialog); + +    gtk_scrolled_window_set_child(dialog->side_content, GTK_WIDGET(navigation)); + +    unref_object(navigation);  }  /******************************************************************************  *                                                                             * -*  Paramètres  : parent = fenêtre principale de l'éditeur.                    * -*                outb   = constructeur à détruire après usage. [OUT]          * +*  Paramètres  : object = instance d'objet GLib à traiter.                    *  *                                                                             * -*  Description : Propose une boîte de dialogue pour la configuration générale.* +*  Description : Supprime toutes les références externes.                     *  *                                                                             * -*  Retour      : Adresse de la fenêtre mise en place.                         * +*  Retour      : -                                                            *  *                                                                             *  *  Remarques   : -                                                            *  *                                                                             *  ******************************************************************************/ -GtkWidget *create_preferences_dialog(GtkWindow *parent, GtkBuilder **outb) +static void gtk_preferences_dialog_dispose(GObject *object)  { -    GtkWidget *result;                      /* Fenêtre à renvoyer          */ -    GtkBuilder *builder;                    /* Constructeur utilisé        */ -    GGenConfig *config;                     /* Configuration globale       */ -    GtkStack *stack;                        /* Pile à mettre à jour        */ -    GtkTreeStore *store;                    /* Arborescence des sections   */ -    pref_node_desc_t *iter;                 /* Boucle de parcours          */ -    GtkTreeView *treeview;                  /* Arborescence principale     */ +    GtkPreferencesDialog *dialog;           /* Version spécialisée         */ + +    dialog = GTK_PREFERENCES_DIALOG(object); -    builder = gtk_builder_new_from_resource("/org/chrysalide/gui/dialogs/preferences.ui"); -    *outb = builder; +    if (dialog->navigations != NULL) +    { +        /** +         * Cf. documentation de g_hash_table_new_full(). +         */ +        g_hash_table_remove_all(dialog->navigations); -    result = GTK_WIDGET(gtk_builder_get_object(builder, "window")); +        g_hash_table_unref(dialog->navigations); +        dialog->navigations = NULL; -    gtk_window_set_transient_for(GTK_WINDOW(result), parent); +    } -    /* Intégration des différentes sections */ +    gtk_widget_dispose_template(GTK_WIDGET(dialog), GTK_TYPE_PREFERENCES_DIALOG); + +    G_OBJECT_CLASS(gtk_preferences_dialog_parent_class)->dispose(object); + +} -    config = get_main_configuration(); -    stack = GTK_STACK(gtk_builder_get_object(builder, "stack")); +/****************************************************************************** +*                                                                             * +*  Paramètres  : object = instance d'objet GLib à traiter.                    * +*                                                                             * +*  Description : Procède à la libération totale de la mémoire.                * +*                                                                             * +*  Retour      : -                                                            * +*                                                                             * +*  Remarques   : -                                                            * +*                                                                             * +******************************************************************************/ -    store = GTK_TREE_STORE(gtk_builder_get_object(builder, "pref_list")); +static void gtk_preferences_dialog_finalize(GObject *object) +{ +    G_OBJECT_CLASS(gtk_preferences_dialog_parent_class)->finalize(object); -    for (iter = _prefs_nodes; iter->title != NULL; iter++) -        add_preferences_node(store, NULL, config, stack, iter); +} -    treeview = GTK_TREE_VIEW(gtk_builder_get_object(builder, "treeview")); -    gtk_tree_view_expand_all(treeview); +/****************************************************************************** +*                                                                             * +*  Paramètres  : parent = fenêtre parente à surpasser.                        * +*                                                                             * +*  Description : Construit une boîte de dialogue pour les préférences.        * +*                                                                             * +*  Retour      : Adresse de la fenêtre mise en place.                         * +*                                                                             * +*  Remarques   : -                                                            * +*                                                                             * +******************************************************************************/ -    /* Connexion des signaux */ +GtkWindow *gtk_preferences_dialog_new(GtkWindow *parent) +{ +    GtkWindow *result;                      /* Boite de dialogue à renvoyer*/ -    gtk_builder_add_callback_symbols(builder, -                                     BUILDER_CALLBACK(on_prefs_selection_changed), -                                     BUILDER_CALLBACK(on_prefs_apply_button_clicked), -                                     NULL); +    result = g_object_new(GTK_TYPE_PREFERENCES_DIALOG, NULL); -    gtk_builder_connect_signals(builder, builder); +    if (!gtk_preferences_dialog_create(GTK_PREFERENCES_DIALOG(result), parent)) +        g_clear_object(&result);      return result; @@ -251,79 +284,85 @@ GtkWidget *create_preferences_dialog(GtkWindow *parent, GtkBuilder **outb)  /******************************************************************************  *                                                                             * -*  Paramètres  : selection = sélection courante de l'arborescence des options.* -*                builder = constructeur GTK avec toutes les références.       * +*  Paramètres  : dialog = boîte de dialogue à initialiser pleinement.         * +*                parent = fenêtre parente à surpasser.                        *  *                                                                             * -*  Description : Affiche le panneau correspondant au noeud sélectionné.       * +*  Description : Met en place la boîte de dialogue pour les préférences.      *  *                                                                             * -*  Retour      : -                                                            * +*  Retour      : Bilan de l'opération.                                        *  *                                                                             *  *  Remarques   : -                                                            *  *                                                                             *  ******************************************************************************/ -static void on_prefs_selection_changed(GtkTreeSelection *selection, GtkBuilder *builder) +bool gtk_preferences_dialog_create(GtkPreferencesDialog *dialog, GtkWindow *parent)  { -    GtkTreeModel *model;                    /* Gestionnaire de données     */ -    GtkTreeIter iter;                       /* Position courante           */ -    GtkWidget *panel;                       /* Panneau à mettre en avant   */ -    GtkStack *stack;                        /* Pile à mettre à jour        */ - -    if (gtk_tree_selection_get_selected(selection, &model, &iter)) -    { -        gtk_tree_model_get(model, &iter, PLI_PANEL, &panel, -1); +    bool result;                            /* Bilan à retourner           */ -        stack = GTK_STACK(gtk_builder_get_object(builder, "stack")); +    result = true; -        if (panel == NULL) -            gtk_stack_set_visible_child_name(stack, "empty"); - -        else -        { -            gtk_stack_set_visible_child(stack, panel); +    gtk_window_set_transient_for(GTK_WINDOW(dialog), parent); -            g_object_unref(G_OBJECT(panel)); - -        } - -    } +    return result;  }  /******************************************************************************  *                                                                             * -*  Paramètres  : config = configuration globale à actualiser.                 * -*                node   = noeud de description courant à traiter.             * +*  Paramètres  : dialog = boîte de dialogue à initialiser pleinement.         * +*                key    = désignation de la liste à fournir.                  * +*                create = autorisation d'une création si besoin est.          *  *                                                                             * -*  Description : Lance la sauvegarde d'éléments de paramétrage.               * +*  Description : Fournit la liste de section désignée par un nom.             *  *                                                                             * -*  Retour      : -                                                            * +*  Retour      : Composant graphique à utiliser.                              *  *                                                                             *  *  Remarques   : -                                                            *  *                                                                             *  ******************************************************************************/ -static void store_preferences_node(GGenConfig *config, pref_node_desc_t *node) +static GtkListBox *gtk_preferences_dialog_get_navigation(GtkPreferencesDialog *dialog, const char *key, bool create)  { -    pref_node_desc_t *child;                /* Sous-élément à traiter      */ +    GtkListBox *result;                     /* Instance à retourner        */ +#ifndef NDEBUG +    gboolean status;                        /* Bilan d'une insertion       */ +#endif -    if (node->create != NULL) -        node->store(node->builder, config); +    result = g_hash_table_lookup(dialog->navigations, key); -    if (node->children != NULL) -        for (child = node->children; child->title != NULL; child++) -            store_preferences_node(config, child); +    if (result == NULL && create) +    { +        result = GTK_LIST_BOX(gtk_list_box_new()); +        g_object_ref_sink(G_OBJECT(result)); + +        gtk_list_box_set_selection_mode(result, GTK_SELECTION_BROWSE); +        gtk_widget_add_css_class(GTK_WIDGET(result), "navigation-sidebar"); + +#ifndef NDEBUG +        status = g_hash_table_insert(dialog->navigations, strdup(key), result); +        assert(status); +#else +        g_hash_table_insert(dialog->navigations, key, result); +#endif + +    } + +    if (result != NULL) +        ref_object(result); + +    return result;  }  /******************************************************************************  *                                                                             * -*  Paramètres  : button  = bouton GTK à l'origine de l'opération.             * -*                builder = constructeur GTK avec toutes les références.       * +*  Paramètres  : navigation = liste concernée par l'événement.                * +*                selected   = élément sélectionné (voire NULL).               * +*                dialog     = boîte de dialogue à initialiser pleinement.     *  *                                                                             * -*  Description : Sauvegarde l'ensemble des paramètres de configuration.       * +*  Description : Réagit à un changement de sélection dans les sections.       *  *                                                                             *  *  Retour      : -                                                            *  *                                                                             * @@ -331,14 +370,41 @@ static void store_preferences_node(GGenConfig *config, pref_node_desc_t *node)  *                                                                             *  ******************************************************************************/ -static void on_prefs_apply_button_clicked(GtkButton *button, GtkBuilder *builder) +static void gtk_preferences_dialog_on_row_selected(GtkListBox *navigation, GtkListBoxRow *selected, GtkPreferencesDialog *dialog)  { -    GGenConfig *config;                     /* Configuration globale       */ -    pref_node_desc_t *iter;                 /* Boucle de parcours          */ +    GtkTweakSection *section;               /* Nature réelle sélectionnée  */ +    GType type;                             /* Type de panneau de config.  */ +    GtkWidget *panel;                       /* Nouveau panneau à présenter */ + +    if (selected != NULL) +    { +        if (!gtk_tweak_section_has_sub_section(GTK_TWEAK_SECTION(selected))) +        { +            section = GTK_TWEAK_SECTION(selected); + +            gtk_label_set_text(dialog->main_title, gtk_tweak_section_get_label(section)); + +            type = gtk_tweak_section_get_panel(section); +            panel = g_object_new(type, NULL); -    config = get_main_configuration(); +            gtk_scrolled_window_set_child(dialog->main_content, panel); -    for (iter = _prefs_nodes; iter->title != NULL; iter++) -        store_preferences_node(config, iter); +        } + +        else +        { + +            // TODO + +        } + +    }  } + + + +/* ---------------------------------------------------------------------------------- */ +/*                       IMPLEMENTATION DES FONCTIONS DE CLASSE                       */ +/* ---------------------------------------------------------------------------------- */ + diff --git a/src/gui/dialogs/preferences.h b/src/gui/dialogs/preferences.h index d04af72..e291ea8 100644 --- a/src/gui/dialogs/preferences.h +++ b/src/gui/dialogs/preferences.h @@ -1,8 +1,8 @@  /* Chrysalide - Outil d'analyse de fichiers binaires - * preferences.h - prototypes pour la (re)définition de l'identité de l'utilisateur + * preferences.h - prototypes pour la boîte de dialogue d'édition des préférences de l'utilisateur   * - * Copyright (C) 2019 Cyrille Bagard + * Copyright (C) 2019-2025 Cyrille Bagard   *   *  This file is part of Chrysalide.   * @@ -28,9 +28,17 @@  #include <gtk/gtk.h> +#include "../../glibext/helpers.h" -/* Propose une boîte de dialogue pour la configuration générale. */ -GtkWidget *create_preferences_dialog(GtkWindow *, GtkBuilder **); + + +#define GTK_TYPE_PREFERENCES_DIALOG (gtk_preferences_dialog_get_type()) + +DECLARE_GTYPE(GtkPreferencesDialog, gtk_preferences_dialog, GTK, PREFERENCES_DIALOG); + + +/* Construit une boîte de dialogue pour les préférences. */ +GtkWindow *gtk_preferences_dialog_new(GtkWindow *); diff --git a/src/gui/dialogs/preferences.ui b/src/gui/dialogs/preferences.ui index 251ef46..950242a 100644 --- a/src/gui/dialogs/preferences.ui +++ b/src/gui/dialogs/preferences.ui @@ -1,156 +1,111 @@  <?xml version="1.0" encoding="UTF-8"?> -<!-- Generated with glade 3.21.0 -->  <interface> -  <requires lib="gtk+" version="3.20"/> -  <object class="GtkTreeStore" id="pref_list"> -    <columns> -      <!-- column-name title --> -      <column type="gchararray"/> -      <!-- column-name panel --> -      <column type="GObject"/> -    </columns> -  </object> -  <object class="GtkDialog" id="window"> -    <property name="can_focus">False</property> -    <property name="title" translatable="yes">General preferences</property> -    <property name="modal">True</property> -    <property name="default_width">800</property> -    <property name="default_height">500</property> -    <property name="type_hint">dialog</property> -    <child internal-child="vbox"> -      <object class="GtkBox"> -        <property name="can_focus">False</property> -        <property name="orientation">vertical</property> -        <property name="spacing">2</property> -        <child internal-child="action_area"> -          <object class="GtkButtonBox"> -            <property name="can_focus">False</property> -            <property name="margin_left">8</property> -            <property name="margin_right">8</property> -            <property name="margin_top">8</property> -            <property name="margin_bottom">8</property> -            <property name="layout_style">end</property> -            <child> -              <object class="GtkButton" id="button1"> -                <property name="label">gtk-cancel</property> -                <property name="visible">True</property> -                <property name="can_focus">True</property> -                <property name="receives_default">True</property> -                <property name="use_stock">True</property> -              </object> -              <packing> -                <property name="expand">True</property> -                <property name="fill">True</property> -                <property name="position">0</property> -              </packing> -            </child> -            <child> -              <object class="GtkButton" id="button2"> -                <property name="label">gtk-apply</property> -                <property name="visible">True</property> -                <property name="can_focus">True</property> -                <property name="receives_default">True</property> -                <property name="use_stock">True</property> -                <signal name="clicked" handler="on_prefs_apply_button_clicked" swapped="no"/> -              </object> -              <packing> -                <property name="expand">True</property> -                <property name="fill">True</property> -                <property name="position">1</property> -              </packing> -            </child> -          </object> -          <packing> -            <property name="expand">False</property> -            <property name="fill">False</property> -            <property name="position">0</property> -          </packing> + +    <template class="GtkPreferencesDialog" parent="GtkWindow"> + +        <property name="default-width">980</property> +        <property name="default-height">640</property> +        <property name="modal">true</property> +        <property name="resizable">true</property> + +        <child type="titlebar"> +            <object class="GtkBox"> +                <child> +                    <object class="GtkHeaderBar" id="sidebar-header"> +                        <property name="decoration-layout">:</property> + +                        <property name="title-widget"> +                            <object class="GtkLabel" id="side_title"> +                                <property name="label" translatable="yes">Parameters</property> +                                <property name="single-line-mode">True</property> +                                <property name="ellipsize">end</property> +                                <property name="width-chars">5</property> +                                <style> +                                    <class name="title"/> +                                </style> +                            </object> +                        </property> + +                        <child type="start"> +                            <object class="GtkToggleButton"> +                                <property name="icon-name">edit-find-symbolic</property> +                                <property name="valign">center</property> +                            </object> +                        </child> +                    </object> +                </child> + +                <!-- Séparation centrale --> +                <child> +                    <object class="GtkSeparator"> +                        <property name="orientation">vertical</property> +                        <property name="css-name">sidebar</property> +                    </object> +                </child> + +                <child> +                    <object class="GtkHeaderBar" id="main-header"> +                        <property name="hexpand">1</property> + +                        <property name="title-widget"> +                            <object class="GtkLabel" id="main_title"> +                                <property name="label" translatable="yes"></property> +                                <property name="single-line-mode">True</property> +                                <property name="ellipsize">end</property> +                                <property name="width-chars">5</property> +                                <style> +                                    <class name="title"/> +                                </style> +                            </object> +                        </property> + +                    </object> +                </child> +            </object>          </child> +          <child> -          <object class="GtkPaned"> -            <property name="visible">True</property> -            <property name="can_focus">True</property> -            <property name="position">200</property> -            <property name="wide_handle">True</property> -            <child> -              <object class="GtkScrolledWindow"> -                <property name="visible">True</property> -                <property name="can_focus">True</property> -                <property name="margin_left">8</property> -                <property name="margin_right">8</property> -                <property name="margin_top">8</property> -                <property name="shadow_type">in</property> +            <object class="GtkBox">                  <child> -                  <object class="GtkTreeView" id="treeview"> -                    <property name="visible">True</property> -                    <property name="can_focus">True</property> -                    <property name="model">pref_list</property> -                    <property name="headers_visible">False</property> -                    <child internal-child="selection"> -                      <object class="GtkTreeSelection"> -                        <signal name="changed" handler="on_prefs_selection_changed" swapped="no"/> -                      </object> -                    </child> -                    <child> -                      <object class="GtkTreeViewColumn"> -                        <property name="title" translatable="yes">column</property> -                        <child> -                          <object class="GtkCellRendererText"/> -                          <attributes> -                            <attribute name="text">0</attribute> -                          </attributes> -                        </child> -                      </object> -                    </child> -                  </object> +                    <object class="GtkScrolledWindow" id="side_content"> +                        <property name="hexpand">false</property> +                        <property name="vexpand">true</property> +                        <property name="hscrollbar-policy">never</property> +                        <property name="vscrollbar-policy">automatic</property> +                    </object> +                </child> + +                <!-- Séparation centrale --> +                <child> +                    <object class="GtkSeparator"> +                        <property name="orientation">vertical</property> +                        <property name="css-name">sidebar</property> +                    </object>                  </child> -              </object> -              <packing> -                <property name="resize">False</property> -                <property name="shrink">True</property> -              </packing> -            </child> -            <child> -              <object class="GtkStack" id="stack"> -                <property name="visible">True</property> -                <property name="can_focus">False</property> -                <property name="margin_left">8</property> -                <property name="margin_right">8</property> -                <property name="margin_top">8</property> +                  <child> -                  <object class="GtkBox"> -                    <property name="visible">True</property> -                    <property name="can_focus">False</property> -                    <property name="orientation">vertical</property> -                    <child> -                      <placeholder/> -                    </child> -                  </object> -                  <packing> -                    <property name="name">empty</property> -                  </packing> +                    <object class="GtkScrolledWindow" id="main_content"> +                        <property name="hexpand">1</property> +                        <property name="vexpand">1</property> +                        <property name="hscrollbar-policy">never</property> +                        <property name="vscrollbar-policy">automatic</property> +                    </object>                  </child> -              </object> -              <packing> -                <property name="resize">True</property> -                <property name="shrink">True</property> -              </packing> -            </child> -          </object> -          <packing> -            <property name="expand">True</property> -            <property name="fill">True</property> -            <property name="position">1</property> -          </packing> +            </object>          </child> -      </object> -    </child> -    <action-widgets> -      <action-widget response="-6">button1</action-widget> -      <action-widget response="-10">button2</action-widget> -    </action-widgets> -    <child> -      <placeholder/> -    </child> -  </object> + +        <object class="GtkSizeGroup"> +            <widgets> +                <widget name="sidebar-header"/> +                <widget name="side_content"/> +            </widgets> +        </object> +        <object class="GtkSizeGroup"> +            <widgets> +                <widget name="main-header"/> +                <widget name="main_content"/> +            </widgets> +        </object> + +    </template>  </interface> diff --git a/src/gui/dialogs/prefs/Makefile.am b/src/gui/dialogs/prefs/Makefile.am new file mode 100644 index 0000000..50bc3c8 --- /dev/null +++ b/src/gui/dialogs/prefs/Makefile.am @@ -0,0 +1,34 @@ + +BUILT_SOURCES = resources.h resources.c + +noinst_LTLIBRARIES  = libguidialogsprefs.la + +UI_FILES =									\ +	appearance.ui							\ +	security.ui + +libguidialogsprefs_la_SOURCES =				\ +	appearance-int.h						\ +	appearance.h appearance.c				\ +	resources.h resources.c					\ +	security-int.h							\ +	security.h security.c + +libguidialogsprefs_la_CFLAGS = $(LIBGTK4_CFLAGS) + + +devdir = $(includedir)/chrysalide/$(subdir:src/%=core/%) + +dev_HEADERS = $(libguidialogsprefs_la_SOURCES:%c=) + + +resources.c: gresource.xml $(UI_FILES) +	glib-compile-resources --target=$@ --sourcedir=$(srcdir) --generate-source --c-name gui_dialogs_prefs gresource.xml + +resources.h: gresource.xml +	glib-compile-resources --target=$@ --sourcedir=$(srcdir) --generate-header --c-name gui_dialogs_prefs gresource.xml + + +CLEANFILES = resources.h resources.c + +EXTRA_DIST = gresource.xml $(UI_FILES) diff --git a/src/gui/dialogs/prefs/appearance-int.h b/src/gui/dialogs/prefs/appearance-int.h new file mode 100644 index 0000000..886a562 --- /dev/null +++ b/src/gui/dialogs/prefs/appearance-int.h @@ -0,0 +1,64 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * appearance-int.h - définitions internes pour la configuration des paramètres liés aux apparences + * + * 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 _GUI_DIALOGS_PREFS_APPEARANCE_INT_H +#define _GUI_DIALOGS_PREFS_APPEARANCE_INT_H + + +#include "appearance.h" + + + +/* Composant d'édition des paramètres liés aux apparences (instance) */ +struct _GtkAppearanceTweakPanel +{ +    GtkBox parent;                          /* A laisser en premier        */ + +    /* Disposition des panneaux */ + +    GSettings *tiles_settings;              /* Configuration sollicitée    */ + +    GtkWidget *layout_preview;              /* Zone d'aperçu de dispositon*/ + +    GtkWidget *top_panel;                   /* Composant d'aperçu #1       */ +    GtkWidget *left_panel;                  /* Composant d'aperçu #2       */ +    GtkWidget *right_panel;                 /* Composant d'aperçu #3       */ +    GtkWidget *bottom_panel;                /* Composant d'aperçu #4       */ + +    GtkCheckButton *left_top_reach;         /* Paramètre de disposition #1 */ +    GtkCheckButton *left_bottom_reach;      /* Paramètre de disposition #2 */ +    GtkCheckButton *right_top_reach;        /* Paramètre de disposition #3 */ +    GtkCheckButton *right_bottom_reach;     /* Paramètre de disposition #4 */ + +}; + +/* Composant d'édition des paramètres liés aux apparences (classe) */ +struct _GtkAppearanceTweakPanelClass +{ +    GtkBoxClass parent;                     /* A laisser en premier        */ + +}; + + + +#endif  /* _GUI_DIALOGS_PREFS_APPEARANCE_INT_H */ diff --git a/src/gui/dialogs/prefs/appearance.c b/src/gui/dialogs/prefs/appearance.c new file mode 100644 index 0000000..a8585fa --- /dev/null +++ b/src/gui/dialogs/prefs/appearance.c @@ -0,0 +1,251 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * appearance.c - configuration des paramètres liés aux apparences + * + * 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/>. + */ + + +#include "appearance.h" + + +#include "appearance-int.h" +#include "../../../gtkext/grid.h" +#include "../../../gtkext/helpers.h" + + + +/* Procède à l'initialisation de classe des configurations. */ +static void gtk_appearance_tweak_panel_class_init(GtkAppearanceTweakPanelClass *); + +/* Procède à l'initialisation des configurations de sécurité. */ +static void gtk_appearance_tweak_panel_init(GtkAppearanceTweakPanel *); + +/* Supprime toutes les références externes. */ +static void gtk_appearance_tweak_panel_dispose(GObject *); + +/* Procède à la libération totale de la mémoire. */ +static void gtk_appearance_tweak_panel_finalize(GObject *); + +/* Réagit à un changement de paramètre de configuration. */ +static void gtk_appearance_tweak_panel_on_tiles_settings_changed(GSettings *, const gchar *, GtkAppearanceTweakPanel *); + +/* Change la disposition des panneaux de la fenêtre principale. */ +static void gtk_appearance_tweak_panel_on_panel_reach_toggled(GtkCheckButton *, GtkAppearanceTweakPanel *); + + +/* Indique le type du composant de configuration des notes. */ +G_DEFINE_TYPE(GtkAppearanceTweakPanel, gtk_appearance_tweak_panel, GTK_TYPE_BOX); + + +/****************************************************************************** +*                                                                             * +*  Paramètres  : class = classe GTK à initialiser.                            * +*                                                                             * +*  Description : Procède à l'initialisation de classe des configurations.     * +*                                                                             * +*  Retour      : -                                                            * +*                                                                             * +*  Remarques   : -                                                            * +*                                                                             * +******************************************************************************/ + +static void gtk_appearance_tweak_panel_class_init(GtkAppearanceTweakPanelClass *class) +{ +    GObjectClass *object;                   /* Plus haut niveau équivalent */ +    GtkWidgetClass *widget;                 /* Classe de haut niveau       */ + +    object = G_OBJECT_CLASS(class); + +    object->dispose = gtk_appearance_tweak_panel_dispose; +    object->finalize = gtk_appearance_tweak_panel_finalize; + +    widget = GTK_WIDGET_CLASS(class); + +    gtk_widget_class_set_template_from_resource(widget, "/re/chrysalide/framework/gui/dialogs/prefs/appearance.ui"); + +    gtk_widget_class_bind_template_callback_full(widget, BUILDER_CB(gtk_appearance_tweak_panel_on_panel_reach_toggled)); + +    gtk_widget_class_bind_template_child(widget, GtkAppearanceTweakPanel, layout_preview); + +    gtk_widget_class_bind_template_child(widget, GtkAppearanceTweakPanel, top_panel); +    gtk_widget_class_bind_template_child(widget, GtkAppearanceTweakPanel, left_panel); +    gtk_widget_class_bind_template_child(widget, GtkAppearanceTweakPanel, right_panel); +    gtk_widget_class_bind_template_child(widget, GtkAppearanceTweakPanel, bottom_panel); + +    gtk_widget_class_bind_template_child(widget, GtkAppearanceTweakPanel, left_top_reach); +    gtk_widget_class_bind_template_child(widget, GtkAppearanceTweakPanel, left_bottom_reach); +    gtk_widget_class_bind_template_child(widget, GtkAppearanceTweakPanel, right_top_reach); +    gtk_widget_class_bind_template_child(widget, GtkAppearanceTweakPanel, right_bottom_reach); + +} + + +/****************************************************************************** +*                                                                             * +*  Paramètres  : panel = composant GTK à initialiser.                         * +*                                                                             * +*  Description : Procède à l'initialisation des configurations de sécurité.   * +*                                                                             * +*  Retour      : -                                                            * +*                                                                             * +*  Remarques   : -                                                            * +*                                                                             * +******************************************************************************/ + +static void gtk_appearance_tweak_panel_init(GtkAppearanceTweakPanel *panel) +{ +    LayoutReachOptions options;             /* Détails de disposition      */ + +    gtk_widget_init_template(GTK_WIDGET(panel)); + +    panel->tiles_settings = g_settings_new_with_path("re.chrysalide.framework.tiledgrid", +                                                     "/re/chrysalide/framework/gui/tiles/"); + +    options = g_settings_get_flags(panel->tiles_settings, "layout"); + +    gtk_check_button_set_active(panel->left_top_reach, options & LRO_LEFT_TOP_REACH); +    gtk_check_button_set_active(panel->left_bottom_reach, options & LRO_LEFT_BOTTOM_REACH); +    gtk_check_button_set_active(panel->right_top_reach, options & LRO_RIGHT_TOP_REACH); +    gtk_check_button_set_active(panel->right_bottom_reach, options & LRO_RIGHT_BOTTOM_REACH); + +    gtk_appearance_tweak_panel_on_tiles_settings_changed(panel->tiles_settings, "layout", panel); + +    g_signal_connect(panel->tiles_settings, "changed", +                     G_CALLBACK(gtk_appearance_tweak_panel_on_tiles_settings_changed), panel); + +} + + +/****************************************************************************** +*                                                                             * +*  Paramètres  : object = instance d'objet GLib à traiter.                    * +*                                                                             * +*  Description : Supprime toutes les références externes.                     * +*                                                                             * +*  Retour      : -                                                            * +*                                                                             * +*  Remarques   : -                                                            * +*                                                                             * +******************************************************************************/ + +static void gtk_appearance_tweak_panel_dispose(GObject *object) +{ +    GtkAppearanceTweakPanel *panel;         /* Version spécialisée         */ + +    gtk_widget_dispose_template(GTK_WIDGET(object), GTK_TYPE_APPEARANCE_TWEAK_PANEL); + +    panel = GTK_APPEARANCE_TWEAK_PANEL(object); + +    g_clear_object(&panel->tiles_settings); + +    G_OBJECT_CLASS(gtk_appearance_tweak_panel_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 gtk_appearance_tweak_panel_finalize(GObject *object) +{ +    G_OBJECT_CLASS(gtk_appearance_tweak_panel_parent_class)->finalize(object); + +} + + +/****************************************************************************** +*                                                                             * +*  Paramètres  : settings = ensemble de paramètres connaissant une évolution. * +*                key      = identifiant du paramètre ayant changé.            * +*                panel    = panneau de paramétrage concerné par l'appel.      * +*                                                                             * +*  Description : Réagit à un changement de paramètre de configuration.        * +*                                                                             * +*  Retour      : -                                                            * +*                                                                             * +*  Remarques   : -                                                            * +*                                                                             * +******************************************************************************/ + +static void gtk_appearance_tweak_panel_on_tiles_settings_changed(GSettings *settings, const gchar *key, GtkAppearanceTweakPanel *panel) +{ +    LayoutReachOptions options;             /* Détails de disposition      */ + +    if (strcmp(key, "layout") == 0) +    { +        options = g_settings_get_flags(panel->tiles_settings, "layout"); + +        apply_tiling_grid_layout(GTK_GRID(panel->layout_preview), options, (GtkWidget *[]) { +                panel->top_panel, panel->left_panel, panel->right_panel, panel->bottom_panel +            }); + +    } + +} + + +/****************************************************************************** +*                                                                             * +*  Paramètres  : button = composant radio dont l'état vient de basculer.      * +*                panel  = panneau d'édition des préférences courant.          * +*                                                                             * +*  Description : Change la disposition des panneaux de la fenêtre principale. * +*                                                                             * +*  Retour      : -                                                            * +*                                                                             * +*  Remarques   : -                                                            * +*                                                                             * +******************************************************************************/ + +static void gtk_appearance_tweak_panel_on_panel_reach_toggled(GtkCheckButton *button, GtkAppearanceTweakPanel *panel) +{ +    gboolean left_top_reach;                /* Paramètre de disposition #1 */ +    gboolean left_bottom_reach;             /* Paramètre de disposition #2 */ +    gboolean right_top_reach;               /* Paramètre de disposition #3 */ +    gboolean right_bottom_reach;            /* Paramètre de disposition #4 */ +    LayoutReachOptions options;             /* Options à appliquer         */ + +    /* Récupération des indications */ + +    left_top_reach = gtk_check_button_get_active(panel->left_top_reach); +    left_bottom_reach = gtk_check_button_get_active(panel->left_bottom_reach); +    right_top_reach = gtk_check_button_get_active(panel->right_top_reach); +    right_bottom_reach = gtk_check_button_get_active(panel->right_bottom_reach); + +    /* Conversion et application */ + +    options = LRO_NONE; + +    if (left_top_reach) options |= LRO_LEFT_TOP_REACH; +    if (left_bottom_reach) options |= LRO_LEFT_BOTTOM_REACH; +    if (right_top_reach) options |= LRO_RIGHT_TOP_REACH; +    if (right_bottom_reach) options |= LRO_RIGHT_BOTTOM_REACH; + +    g_settings_set_flags(panel->tiles_settings, "layout", options); + +} diff --git a/src/gui/dialogs/prefs/appearance.h b/src/gui/dialogs/prefs/appearance.h new file mode 100644 index 0000000..916b194 --- /dev/null +++ b/src/gui/dialogs/prefs/appearance.h @@ -0,0 +1,41 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * appearance.h - prototypes pour la configuration des paramètres liés aux apparences + * + * 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 _GUI_DIALOGS_PREFS_APPEARANCE_H +#define _GUI_DIALOGS_PREFS_APPEARANCE_H + + +#include <gtk/gtk.h> + + +#include "../../../glibext/helpers.h" + + + +#define GTK_TYPE_APPEARANCE_TWEAK_PANEL (gtk_appearance_tweak_panel_get_type()) + +DECLARE_GTYPE(GtkAppearanceTweakPanel, gtk_appearance_tweak_panel, GTK, APPEARANCE_TWEAK_PANEL); + + + +#endif  /* _GUI_DIALOGS_PREFS_APPEARANCE_H */ diff --git a/src/gui/dialogs/prefs/appearance.ui b/src/gui/dialogs/prefs/appearance.ui new file mode 100644 index 0000000..3410115 --- /dev/null +++ b/src/gui/dialogs/prefs/appearance.ui @@ -0,0 +1,184 @@ +<?xml version="1.0" encoding="UTF-8"?> +<interface> + +    <template class="GtkAppearanceTweakPanel" parent="GtkBox"> + +        <property name="orientation">vertical</property> +        <property name="margin-start">20</property> +        <property name="margin-end">20</property> +        <property name="margin-top">20</property> +        <property name="margin-bottom">20</property> +        <property name="spacing">10</property> + +        <!-- Disposition des panneaux --> + +        <child> +            <object class="GtkLabel"> +                <property name="label">Layout</property> +                <property name="use-markup">true</property> +                <property name="xalign">0</property> +                <style> +                    <class name="heading"/> +                </style> +            </object> +        </child> + +        <child> +            <object class="GtkLabel"> +                <property name="label">Layout defines the global panel organization of the main window.</property> +                <property name="wrap">true</property> +                <property name="use-markup">true</property> +                <property name="xalign">0</property> +                <style> +                    <class name="dim-label"/> +                </style> +            </object> +        </child> + + +        <child> +            <object class="GtkBox"> +                <property name="orientation">horizontal</property> + +                <!-- Aperçu --> + +                <child> +                    <object class="GtkGrid" id="layout_preview"> +                        <property name="margin-start">20</property> +                        <property name="margin-end">20</property> +                        <property name="margin-top">10</property> +                        <property name="margin-bottom">10</property> +                        <property name="row-spacing">5</property> +                        <property name="column-spacing">5</property> +                        <property name="hexpand">false</property> +                        <property name="vexpand">false</property> +                        <property name="height-request">200</property> +                        <property name="width-request">300</property> + +                        <child> +                            <object class="GtkFrame" id="top_panel"> +                                <property name="hexpand">true</property> +                                <property name="vexpand">false</property> +                                <property name="height-request">20</property> +                                <layout> +                                    <property name="column">0</property> +                                    <property name="row">0</property> +                                    <property name="column-span">3</property> +                                </layout> +                                <style> +                                    <class name="view"/> +                                </style> +                            </object> +                        </child> + +                        <child> +                            <object class="GtkFrame" id="left_panel"> +                                <property name="hexpand">false</property> +                                <property name="vexpand">true</property> +                                <property name="width-request">50</property> +                                <layout> +                                    <property name="column">0</property> +                                    <property name="row">1</property> +                                </layout> +                                <style> +                                    <class name="view"/> +                                </style> +                            </object> +                        </child> + +                        <child> +                            <object class="GtkFrame"> +                                <property name="hexpand">true</property> +                                <property name="vexpand">true</property> +                                <layout> +                                    <property name="column">1</property> +                                    <property name="row">1</property> +                                </layout> +                                <style> +                                    <class name="view"/> +                                </style> +                            </object> +                        </child> + +                        <child> +                            <object class="GtkFrame" id="right_panel"> +                                <property name="hexpand">false</property> +                                <property name="vexpand">true</property> +                                <property name="width-request">50</property> +                                <layout> +                                    <property name="column">2</property> +                                    <property name="row">1</property> +                                </layout> +                                <style> +                                    <class name="view"/> +                                </style> +                            </object> +                        </child> + +                        <child> +                            <object class="GtkFrame" id="bottom_panel"> +                                <property name="hexpand">true</property> +                                <property name="vexpand">false</property> +                                <property name="height-request">50</property> +                                <layout> +                                    <property name="column">0</property> +                                    <property name="row">2</property> +                                    <property name="column-span">3</property> +                                </layout> +                                <style> +                                    <class name="view"/> +                                </style> +                            </object> +                        </child> + +                    </object> +                </child> + +                <!-- Options --> + +                <child> +                    <object class="GtkBox"> +                        <property name="orientation">vertical</property> +                        <property name="valign">center</property> +                        <property name="spacing">10</property> + +                        <child> +                            <object class="GtkCheckButton" id="left_top_reach"> +                                <property name="label">Left panels reach the top of the window</property> +                                <property name="active">false</property> +                                <signal name="toggled" handler="gtk_appearance_tweak_panel_on_panel_reach_toggled"/> +                            </object> +                        </child> + +                        <child> +                            <object class="GtkCheckButton" id="left_bottom_reach"> +                                <property name="label">Left panels reach the bottom of the window</property> +                                <property name="active">false</property> +                                <signal name="toggled" handler="gtk_appearance_tweak_panel_on_panel_reach_toggled"/> +                            </object> +                        </child> + +                        <child> +                            <object class="GtkCheckButton" id="right_top_reach"> +                                <property name="label">Right panels reach the top of the window</property> +                                <property name="active">false</property> +                                <signal name="toggled" handler="gtk_appearance_tweak_panel_on_panel_reach_toggled"/> +                            </object> +                        </child> + +                        <child> +                            <object class="GtkCheckButton" id="right_bottom_reach"> +                                <property name="label">Right panels reach the bottom of the window</property> +                                <property name="active">false</property> +                                <signal name="toggled" handler="gtk_appearance_tweak_panel_on_panel_reach_toggled"/> +                            </object> +                        </child> + +                    </object> +                </child> + +            </object> +        </child> + +    </template> +</interface> diff --git a/src/gui/dialogs/prefs/gresource.xml b/src/gui/dialogs/prefs/gresource.xml new file mode 100644 index 0000000..ad0f97f --- /dev/null +++ b/src/gui/dialogs/prefs/gresource.xml @@ -0,0 +1,7 @@ +<?xml version="1.0" encoding="UTF-8"?> +<gresources> +    <gresource prefix="/re/chrysalide/framework/gui/dialogs/prefs"> +        <file compressed="true">appearance.ui</file> +        <file compressed="true">security.ui</file> +    </gresource> +</gresources> diff --git a/src/gui/dialogs/prefs/security-int.h b/src/gui/dialogs/prefs/security-int.h new file mode 100644 index 0000000..be7867c --- /dev/null +++ b/src/gui/dialogs/prefs/security-int.h @@ -0,0 +1,64 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * security-int.h - définitions internes pour la configuration des paramètres liés à la sécurité + * + * 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 _GUI_DIALOGS_PREFS_SECURITY_INT_H +#define _GUI_DIALOGS_PREFS_SECURITY_INT_H + + +#include "security.h" +#include "../../../glibext/secstorage.h" + + + +/* Composant d'édition des paramètres de sécurité (instance) */ +struct _GtkSecurityTweakPanel +{ +    GtkBox parent;                          /* A laisser en premier        */ + +    /* Stockage sécurisé */ + +    GSecretStorage *storage;                /* Stockage des secrets        */ + +    GtkWidget *current_primary_passwd;      /* Mot de passe courant        */ + +    GtkWidget *new_primary_passwd;          /* Nouveau mot de passe        */ +    GtkWidget *new_primary_passwd_lbl;      /* Etiquette associée          */ +    GtkWidget *new_primary_passwd_2;        /* Nouveau mot de passe (#2)   */ +    GtkWidget *new_primary_passwd_2_lbl;    /* Etiquette associée (#2)     */ + +    GtkWidget *set_password;                /* Bouton de définition de mdp */ +    GtkWidget *change_password;             /* Bouton de changement de mdp */ +    GtkWidget *remove_password;             /* Bouton de suppression de mdp*/ + +}; + +/* Composant d'édition des paramètres de sécurité (classe) */ +struct _GtkSecurityTweakPanelClass +{ +    GtkBoxClass parent;                     /* A laisser en premier        */ + +}; + + + +#endif  /* _GUI_DIALOGS_PREFS_SECURITY_INT_H */ diff --git a/src/gui/dialogs/prefs/security.c b/src/gui/dialogs/prefs/security.c new file mode 100644 index 0000000..2b82339 --- /dev/null +++ b/src/gui/dialogs/prefs/security.c @@ -0,0 +1,400 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * security.c - configuration des paramètres liés à la sécurité + * + * 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/>. + */ + + +#include "security.h" + + +#include <i18n.h> + + +#include "security-int.h" +#include "../../../core/global.h" +#include "../../../core/logs.h" +#include "../../../gtkext/helpers.h" + + + +/* ---------------------- GESTION DE L'ENSEMBLE DES PARAMETRES ---------------------- */ + + +/* Procède à l'initialisation de classe des configurations. */ +static void gtk_security_tweak_panel_class_init(GtkSecurityTweakPanelClass *); + +/* Procède à l'initialisation des configurations de sécurité. */ +static void gtk_security_tweak_panel_init(GtkSecurityTweakPanel *); + +/* Supprime toutes les références externes. */ +static void gtk_security_tweak_panel_dispose(GObject *); + +/* Procède à la libération totale de la mémoire. */ +static void gtk_security_tweak_panel_finalize(GObject *); + + + +/* ---------------------- CONSERVATION SECURISEE DE PARAMETRES ---------------------- */ + + +/* Initalise la partie relative au stockage sécurisé. */ +static void gtk_security_tweak_panel_init_secret_storage(GtkSecurityTweakPanel *); + +/* Supprime toutes les références externes. */ +static void gtk_security_tweak_panel_dispose_secret_storage(GtkSecurityTweakPanel *); + +/* Note le changement de verrouillage du stockage sécurisé. */ +static void gtk_security_tweak_panel_on_secret_storage_lock_update(GSecretStorage *, GtkSecurityTweakPanel *); + +/* Réagit à un changement dans l'édition d'un mot de passe. */ +static void gtk_security_tweak_panel_on_new_passwords_changed(GtkEditable *, GtkSecurityTweakPanel *); + +/* Réagit à une demande de création de mot de passe. */ +static void gtk_security_tweak_panel_on_set_password_clicked(GtkButton *, GtkSecurityTweakPanel *); + +/* Réagit à une demande de changement de mot de passe. */ +static void gtk_security_tweak_panel_on_change_password_clicked(GtkButton *, GtkSecurityTweakPanel *); + +/* Réagit à une demande de suppression de mot de passe. */ +static void gtk_security_tweak_panel_on_remove_password_clicked(GtkButton *, GtkSecurityTweakPanel *); + + + +/* ---------------------------------------------------------------------------------- */ +/*                        GESTION DE L'ENSEMBLE DES PARAMETRES                        */ +/* ---------------------------------------------------------------------------------- */ + + +/* Indique le type du composant d'édition des paramètres de sécurité. */ +G_DEFINE_TYPE(GtkSecurityTweakPanel, gtk_security_tweak_panel, GTK_TYPE_BOX); + + +/****************************************************************************** +*                                                                             * +*  Paramètres  : class = classe GTK à initialiser.                            * +*                                                                             * +*  Description : Procède à l'initialisation de classe des configurations.     * +*                                                                             * +*  Retour      : -                                                            * +*                                                                             * +*  Remarques   : -                                                            * +*                                                                             * +******************************************************************************/ + +static void gtk_security_tweak_panel_class_init(GtkSecurityTweakPanelClass *class) +{ +    GObjectClass *object;                   /* Plus haut niveau équivalent */ +    GtkWidgetClass *widget;                 /* Classe de haut niveau       */ + +    object = G_OBJECT_CLASS(class); + +    object->dispose = gtk_security_tweak_panel_dispose; +    object->finalize = gtk_security_tweak_panel_finalize; + +    widget = GTK_WIDGET_CLASS(class); + +    gtk_widget_class_set_template_from_resource(widget, "/re/chrysalide/framework/gui/dialogs/prefs/security.ui"); + +    /* Stockage sécurisé */ + +    gtk_widget_class_bind_template_callback_full(widget, BUILDER_CB(gtk_security_tweak_panel_on_new_passwords_changed)); +    gtk_widget_class_bind_template_callback_full(widget, BUILDER_CB(gtk_security_tweak_panel_on_set_password_clicked)); +    gtk_widget_class_bind_template_callback_full(widget, BUILDER_CB(gtk_security_tweak_panel_on_change_password_clicked)); +    gtk_widget_class_bind_template_callback_full(widget, BUILDER_CB(gtk_security_tweak_panel_on_remove_password_clicked)); + +    gtk_widget_class_bind_template_child(widget, GtkSecurityTweakPanel, current_primary_passwd); +    gtk_widget_class_bind_template_child(widget, GtkSecurityTweakPanel, new_primary_passwd); +    gtk_widget_class_bind_template_child(widget, GtkSecurityTweakPanel, new_primary_passwd_lbl); +    gtk_widget_class_bind_template_child(widget, GtkSecurityTweakPanel, new_primary_passwd_2); +    gtk_widget_class_bind_template_child(widget, GtkSecurityTweakPanel, new_primary_passwd_2_lbl); +    gtk_widget_class_bind_template_child(widget, GtkSecurityTweakPanel, set_password); +    gtk_widget_class_bind_template_child(widget, GtkSecurityTweakPanel, change_password); +    gtk_widget_class_bind_template_child(widget, GtkSecurityTweakPanel, remove_password); + +} + + +/****************************************************************************** +*                                                                             * +*  Paramètres  : panel = composant GTK à initialiser.                         * +*                                                                             * +*  Description : Procède à l'initialisation des configurations de sécurité.   * +*                                                                             * +*  Retour      : -                                                            * +*                                                                             * +*  Remarques   : -                                                            * +*                                                                             * +******************************************************************************/ + +static void gtk_security_tweak_panel_init(GtkSecurityTweakPanel *panel) +{ +    gtk_widget_init_template(GTK_WIDGET(panel)); + +    gtk_security_tweak_panel_init_secret_storage(panel); + +} + + +/****************************************************************************** +*                                                                             * +*  Paramètres  : object = instance d'objet GLib à traiter.                    * +*                                                                             * +*  Description : Supprime toutes les références externes.                     * +*                                                                             * +*  Retour      : -                                                            * +*                                                                             * +*  Remarques   : -                                                            * +*                                                                             * +******************************************************************************/ + +static void gtk_security_tweak_panel_dispose(GObject *object) +{ +    GtkSecurityTweakPanel *panel;           /* Version spécialisée         */ + +    panel = GTK_SECURITY_TWEAK_PANEL(object); + +    gtk_security_tweak_panel_dispose_secret_storage(panel); + +    gtk_widget_dispose_template(GTK_WIDGET(panel), GTK_TYPE_SECURITY_TWEAK_PANEL); + +    G_OBJECT_CLASS(gtk_security_tweak_panel_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 gtk_security_tweak_panel_finalize(GObject *object) +{ +    G_OBJECT_CLASS(gtk_security_tweak_panel_parent_class)->finalize(object); + +} + + + +/* ---------------------------------------------------------------------------------- */ +/*                        CONSERVATION SECURISEE DE PARAMETRES                        */ +/* ---------------------------------------------------------------------------------- */ + + +/****************************************************************************** +*                                                                             * +*  Paramètres  : panel = composant GTK à initialiser.                         * +*                                                                             * +*  Description : Initalise la partie relative au stockage sécurisé.           * +*                                                                             * +*  Retour      : -                                                            * +*                                                                             * +*  Remarques   : -                                                            * +*                                                                             * +******************************************************************************/ + +static void gtk_security_tweak_panel_init_secret_storage(GtkSecurityTweakPanel *panel) +{ +    panel->storage = get_secret_storage(); + +    g_signal_connect(panel->storage, "lock-update", +                     G_CALLBACK(gtk_security_tweak_panel_on_secret_storage_lock_update), panel); + +    gtk_security_tweak_panel_on_secret_storage_lock_update(panel->storage, panel); + +} + + +/****************************************************************************** +*                                                                             * +*  Paramètres  : panel = instance d'objet GLib à traiter.                     * +*                                                                             * +*  Description : Supprime toutes les références externes.                     * +*                                                                             * +*  Retour      : -                                                            * +*                                                                             * +*  Remarques   : -                                                            * +*                                                                             * +******************************************************************************/ + +static void gtk_security_tweak_panel_dispose_secret_storage(GtkSecurityTweakPanel *panel) +{ +    if (panel->storage != NULL) +        g_signal_handlers_disconnect_by_func(panel->storage, +                                             gtk_security_tweak_panel_on_secret_storage_lock_update, panel); + +    g_clear_object(&panel->storage); + +} + + +/****************************************************************************** +*                                                                             * +*  Paramètres  : storage = gardien des secrets impliqué.                      * +*                panel   = support de la partie relative au stockage sécurisé.* +*                                                                             * +*  Description : Note le changement de verrouillage du stockage sécurisé.     * +*                                                                             * +*  Retour      : -                                                            * +*                                                                             * +*  Remarques   : -                                                            * +*                                                                             * +******************************************************************************/ + +static void gtk_security_tweak_panel_on_secret_storage_lock_update(GSecretStorage *storage, GtkSecurityTweakPanel *panel) +{ +    bool has_key;                           /* Existence d'une clef ?      */ + +    has_key = g_secret_storage_has_key(panel->storage); + +    gtk_widget_set_visible(panel->new_primary_passwd, has_key); +    gtk_widget_set_visible(panel->new_primary_passwd_lbl, has_key); + +    gtk_widget_set_visible(panel->new_primary_passwd_2, has_key); +    gtk_widget_set_visible(panel->new_primary_passwd_2_lbl, has_key); + +    gtk_widget_set_visible(panel->set_password, !has_key); +    gtk_widget_set_visible(panel->change_password, has_key); +    gtk_widget_set_visible(panel->remove_password, has_key); + +} + + +/****************************************************************************** +*                                                                             * +*  Paramètres  : editable = zone de saisie bouton GTK concerné par l'appel.   * +*                panel    = support de la partie liée au stockage sécurisé.   * +*                                                                             * +*  Description : Réagit à un changement dans l'édition d'un mot de passe.     * +*                                                                             * +*  Retour      : -                                                            * +*                                                                             * +*  Remarques   : -                                                            * +*                                                                             * +******************************************************************************/ + +static void gtk_security_tweak_panel_on_new_passwords_changed(GtkEditable *editable, GtkSecurityTweakPanel *panel) +{ +    const char *new_passwd;                 /* Nouveau mot de passe #1     */ +    const char *new_passwd_2;               /* Nouveau mot de passe #2     */ +    bool status;                            /* Bilan de l'opération        */ + +    new_passwd = gtk_editable_get_text(GTK_EDITABLE(panel->new_primary_passwd)); + +    new_passwd_2 = gtk_editable_get_text(GTK_EDITABLE(panel->new_primary_passwd_2)); + +    status = (strcmp(new_passwd, new_passwd_2) == 0); + +    gtk_widget_set_sensitive(panel->change_password, status); + +} + + +/****************************************************************************** +*                                                                             * +*  Paramètres  : button = bouton GTK concerné par l'appel.                    * +*                panel  = support de la partie relative au stockage sécurisé. * +*                                                                             * +*  Description : Réagit à une demande de création de mot de passe.            * +*                                                                             * +*  Retour      : -                                                            * +*                                                                             * +*  Remarques   : -                                                            * +*                                                                             * +******************************************************************************/ + +static void gtk_security_tweak_panel_on_set_password_clicked(GtkButton *button, GtkSecurityTweakPanel *panel) +{ +    const char *passwd;                     /* Mot de passe à considérer   */ +    bool status;                            /* Bilan de l'opération        */ + +    passwd = gtk_editable_get_text(GTK_EDITABLE(panel->current_primary_passwd)); + +    status = g_secret_storage_set_password(panel->storage, passwd); + +    log_variadic_message(LMT_INFO, _("Setting password for secret storage: %s"), +                         status ? _("success") : _("failed")); + +} + + +/****************************************************************************** +*                                                                             * +*  Paramètres  : button = bouton GTK concerné par l'appel.                    * +*                panel  = support de la partie relative au stockage sécurisé. * +*                                                                             * +*  Description : Réagit à une demande de changement de mot de passe.          * +*                                                                             * +*  Retour      : -                                                            * +*                                                                             * +*  Remarques   : -                                                            * +*                                                                             * +******************************************************************************/ + +static void gtk_security_tweak_panel_on_change_password_clicked(GtkButton *button, GtkSecurityTweakPanel *panel) +{ +    const char *old_passwd;                 /* Ancien mot de passe         */ +    const char *new_passwd;                 /* Nouveau mot de passe        */ +    bool status;                            /* Bilan de l'opération        */ + +    old_passwd = gtk_editable_get_text(GTK_EDITABLE(panel->current_primary_passwd)); + +    new_passwd = gtk_editable_get_text(GTK_EDITABLE(panel->new_primary_passwd)); + +    status = g_secret_storage_change_password(panel->storage, old_passwd, new_passwd); + +    log_variadic_message(LMT_INFO, _("Changed password for secret storage: %s"), +                         status ? _("success") : _("failed")); + +} + + +/****************************************************************************** +*                                                                             * +*  Paramètres  : button = bouton GTK concerné par l'appel.                    * +*                panel  = support de la partie relative au stockage sécurisé. * +*                                                                             * +*  Description : Réagit à une demande de suppression de mot de passe.         * +*                                                                             * +*  Retour      : -                                                            * +*                                                                             * +*  Remarques   : -                                                            * +*                                                                             * +******************************************************************************/ + +static void gtk_security_tweak_panel_on_remove_password_clicked(GtkButton *button, GtkSecurityTweakPanel *panel) +{ +    const char *passwd;                     /* Mot de passe à considérer   */ +    bool status;                            /* Bilan de l'opération        */ + +    passwd = gtk_editable_get_text(GTK_EDITABLE(panel->current_primary_passwd)); + +    status = g_secret_storage_remove_password(panel->storage, passwd); + +    log_variadic_message(LMT_INFO, _("Removed password for secret storage: %s"), +                         status ? _("success") : _("failed")); + +} diff --git a/src/gui/dialogs/prefs/security.h b/src/gui/dialogs/prefs/security.h new file mode 100644 index 0000000..206a123 --- /dev/null +++ b/src/gui/dialogs/prefs/security.h @@ -0,0 +1,41 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * security.h - prototypes pour la configuration des paramètres liés à la sécurité + * + * 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 _GUI_DIALOGS_PREFS_SECURITY_H +#define _GUI_DIALOGS_PREFS_SECURITY_H + + +#include <gtk/gtk.h> + + +#include "../../../glibext/helpers.h" + + + +#define GTK_TYPE_SECURITY_TWEAK_PANEL (gtk_security_tweak_panel_get_type()) + +DECLARE_GTYPE(GtkSecurityTweakPanel, gtk_security_tweak_panel, GTK, SECURITY_TWEAK_PANEL); + + + +#endif  /* _GUI_DIALOGS_PREFS_SECURITY_H */ diff --git a/src/gui/dialogs/prefs/security.ui b/src/gui/dialogs/prefs/security.ui new file mode 100644 index 0000000..ccf2d39 --- /dev/null +++ b/src/gui/dialogs/prefs/security.ui @@ -0,0 +1,170 @@ +<?xml version="1.0" encoding="UTF-8"?> +<interface> + +    <template class="GtkSecurityTweakPanel" parent="GtkBox"> + +        <property name="orientation">vertical</property> + +        <!-- Conservation de paramètres sécurisée --> +        <child> +            <object class="GtkGrid"> +                <property name="margin-start">20</property> +                <property name="margin-end">20</property> +                <property name="margin-top">20</property> +                <property name="margin-bottom">20</property> +                <property name="row-spacing">10</property> +                <property name="column-spacing">10</property> + +                <child> +                    <object class="GtkLabel"> +                        <property name="label">Secret storage</property> +                        <property name="use-markup">true</property> +                        <property name="xalign">0</property> +                        <layout> +                            <property name="column">0</property> +                            <property name="row">0</property> +                            <property name="column-span">2</property> +                        </layout> +                        <style> +                            <class name="heading"/> +                        </style> +                    </object> +                </child> + +                <child> +                    <object class="GtkLabel"> +                        <property name="label">Configuration may handle sensitive data (such as passwords or API keys) which can be saved in plain text or stored encrypted using a Primary Password. + +If encryption is activated, entering the Primary Password will be asked on need once per session.</property> +                        <property name="wrap">true</property> +                        <property name="xalign">0</property> +                        <layout> +                            <property name="column">0</property> +                            <property name="row">1</property> +                            <property name="column-span">2</property> +                        </layout> +                        <style> +                            <class name="dim-label"/> +                        </style> +                    </object> +                </child> + +                <!-- Mot de passe courant --> + +                <child> +                    <object class="GtkLabel"> +                        <property name="label">Enter current password:</property> +                        <property name="xalign">0</property> +                        <layout> +                            <property name="column">0</property> +                            <property name="row">2</property> +                        </layout> +                    </object> +                </child> + +                <child> +                    <object class="GtkPasswordEntry" id="current_primary_passwd"> +                        <property name="hexpand">true</property> +                        <property name="show-peek-icon">true</property> +                        <layout> +                            <property name="column">1</property> +                            <property name="row">2</property> +                        </layout> +                    </object> +                </child> + +                <!-- Nouveau mot de passe --> + +                <child> +                    <object class="GtkLabel" id="new_primary_passwd_lbl"> +                        <property name="label">Enter new password:</property> +                        <property name="xalign">0</property> +                        <layout> +                            <property name="column">0</property> +                            <property name="row">3</property> +                        </layout> +                    </object> +                </child> + +                <child> +                    <object class="GtkPasswordEntry" id="new_primary_passwd"> +                        <property name="hexpand">true</property> +                        <property name="show-peek-icon">true</property> +                        <signal name="changed" handler="gtk_security_tweak_panel_on_new_passwords_changed"/> +                        <layout> +                            <property name="column">1</property> +                            <property name="row">3</property> +                        </layout> +                    </object> +                </child> + +                <!-- Confirmation de mot de passe --> + +                <child> +                    <object class="GtkLabel" id="new_primary_passwd_2_lbl"> +                        <property name="label">Re-enter new password:</property> +                        <property name="xalign">0</property> +                        <layout> +                            <property name="column">0</property> +                            <property name="row">4</property> +                        </layout> +                    </object> +                </child> + +                <child> +                    <object class="GtkPasswordEntry" id="new_primary_passwd_2"> +                        <property name="hexpand">true</property> +                        <property name="show-peek-icon">true</property> +                        <signal name="changed" handler="gtk_security_tweak_panel_on_new_passwords_changed"/> +                        <layout> +                            <property name="column">1</property> +                            <property name="row">4</property> +                        </layout> +                    </object> +                </child> + +                <!-- Boutons de contrôle --> + +                <child> +                    <object class="GtkBox"> +                        <property name="halign">center</property> +                        <property name="homogeneous">true</property> +                        <property name="spacing">8</property> +                        <layout> +                            <property name="column">0</property> +                            <property name="row">5</property> +                            <property name="column-span">2</property> +                        </layout> + +                        <child> +                            <object class="GtkButton" id="set_password"> +                                <property name="label">Set</property> +                                <signal name="clicked" handler="gtk_security_tweak_panel_on_set_password_clicked"/> +                            </object> +                        </child> + +                        <child> +                            <object class="GtkButton" id="change_password"> +                                <property name="label">Change</property> +                                <signal name="clicked" handler="gtk_security_tweak_panel_on_change_password_clicked"/> +                            </object> +                        </child> + +                        <child> +                            <object class="GtkButton" id="remove_password"> +                                <property name="label">Remove</property> +                                <signal name="clicked" handler="gtk_security_tweak_panel_on_remove_password_clicked"/> +                                <style> +                                    <class name="destructive-action"/> +                                </style> +                            </object> +                        </child> + +                    </object> +                </child> + +            </object> +        </child> + +    </template> +</interface> diff --git a/src/gui/gresource.xml b/src/gui/gresource.xml index 011281d..91d9bc9 100644 --- a/src/gui/gresource.xml +++ b/src/gui/gresource.xml @@ -1,6 +1,10 @@  <?xml version="1.0" encoding="UTF-8"?>  <gresources> -    <gresource prefix="/org/chrysalide/gui"> -        <file compressed="true">editor.ui</file> +    <gresource prefix="/re/chrysalide/framework/gui"> +        <file compressed="true">style.css</file> +        <file compressed="true">window.ui</file> +    </gresource> +    <gresource prefix="/re/chrysalide/framework/images"> +        <file compressed="true" alias="chrysalide-logo.svg">../../pixmaps/chrysalide-logo.svg</file>      </gresource>  </gresources> diff --git a/src/gui/panels/Makefile.am b/src/gui/panels/Makefile.am index 83e173b..ecff6c7 100644 --- a/src/gui/panels/Makefile.am +++ b/src/gui/panels/Makefile.am @@ -3,7 +3,7 @@ DEFAULT_INCLUDES = -idirafter. -I$(top_builddir)  BUILT_SOURCES = resources.h resources.c -noinst_LTLIBRARIES  = libguipanels.la +noinst_LTLIBRARIES  = libguipanels4.la # libguipanels.la  UI_FILES =								\  	bintree.ui							\ @@ -11,11 +11,9 @@ UI_FILES =								\  	errors.ui							\  	glance.ui							\  	history.ui							\ -	log.ui								\  	regedit.ui							\  	strings.ui							\ -	symbols.ui							\ -	welcome.ui +	symbols.ui  libguipanels_la_SOURCES =				\  	bintree.h bintree.c					\ @@ -23,25 +21,50 @@ libguipanels_la_SOURCES =				\  	errors.h errors.c					\  	glance.h glance.c					\  	history.h history.c					\ -	log.h log.c							\  	regedit.h regedit.c					\  	resources.h resources.c				\  	strings.h strings.c					\  	symbols.h symbols.c					\  	updating-int.h						\  	updating.h updating.c				\ -	view.h view.c						\ -	welcome.h welcome.c +	view.h view.c  libguipanels_la_CFLAGS = $(LIBGTK_CFLAGS) $(LIBXML_CFLAGS) +IMG_PATH = ../../../data/images + +RES_FILES =									\ +	binary.ui								\ +	binary-params.ui						\ +	$(IMG_PATH)/binfile-symbolic.svg		\ +	logs.ui									\ +	logs-col-icon.ui						\ +	logs-col-message.ui						\ +	welcome.ui								\ +	welcome-hints.txt						\ +	$(IMG_PATH)/tipoftheday-symbolic.svg + +libguipanels4_la_SOURCES =					\ +	binary-int.h							\ +	binary.h binary.c						\ +	binary-params-int.h						\ +	binary-params.h binary-params.c			\ +	logs-int.h								\ +	logs.h logs.c							\ +	resources.h resources.c					\ +	welcome-int.h						 	\ +	welcome.h welcome.c + +libguipanels4_la_CFLAGS = $(LIBGTK4_CFLAGS) + +  devdir = $(includedir)/chrysalide/$(subdir:src/%=core/%)  dev_HEADERS = $(libguipanels_la_SOURCES:%c=) -resources.c: gresource.xml $(UI_FILES) +resources.c: gresource.xml $(RES_FILES)  	glib-compile-resources --target=$@ --sourcedir=$(srcdir) --generate-source --c-name gui_panels gresource.xml  resources.h: gresource.xml @@ -50,4 +73,4 @@ resources.h: gresource.xml  CLEANFILES = resources.h resources.c -EXTRA_DIST = gresource.xml $(UI_FILES) +EXTRA_DIST = gresource.xml $(RES_FILES) diff --git a/src/gui/panels/binary-int.h b/src/gui/panels/binary-int.h new file mode 100644 index 0000000..5116f5c --- /dev/null +++ b/src/gui/panels/binary-int.h @@ -0,0 +1,52 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * binary-int.h - prototypes internes pour le panneau d'affichage de contenus d'un binaire, bruts ou non + * + * Copyright (C) 2024 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 this program; if not, write to the Free Software + *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA + */ + + +#ifndef _GUI_PANELS_BINARY_INT_H +#define _GUI_PANELS_BINARY_INT_H + + +#include "binary.h" +#include "../../gtkext/panel-int.h" + + + +/* Panneau d'accueil par défaut (instance) */ +struct _GtkBinaryPanel +{ +    GtkTiledPanel parent;                   /* A laisser en premier        */ + +    GtkScrolledWindow *hex_scroll;          /* Défilement pour contenu #0  */ + +}; + +/* Panneau d'accueil par défaut (classe) */ +struct _GtkBinaryPanelClass +{ +    GtkTiledPanelClass parent;              /* A laisser en premier        */ + +}; + + + +#endif  /* _GUI_PANELS_BINARY_INT_H */ diff --git a/src/gui/panels/binary-params-int.h b/src/gui/panels/binary-params-int.h new file mode 100644 index 0000000..0fbef24 --- /dev/null +++ b/src/gui/panels/binary-params-int.h @@ -0,0 +1,50 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * binary-params-int.h - définitions internes pour l'édition des paramètres initiaux d'un chargement de binaire + * + * 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 _GUI_PANELS_BINARY_PARAMS_INT_H +#define _GUI_PANELS_BINARY_PARAMS_INT_H + + +#include "binary-params.h" + + + +/* Composant pour les paramètres de chargement d'un binaire (instance) */ +struct _GtkBinaryParameters +{ +    GtkGrid parent;                         /* A laisser en premier        */ + +    GtkEntry *filename;                     /* CHemin d'un binaire         */ + +}; + +/* Composant pour les paramètres de chargement d'un binaire (classe) */ +struct _GtkBinaryParametersClass +{ +    GtkGridClass parent;                    /* A laisser en premier        */ + +}; + + + +#endif  /* _GUI_PANELS_BINARY_PARAMS_INT_H */ diff --git a/src/gui/panels/binary-params.c b/src/gui/panels/binary-params.c new file mode 100644 index 0000000..1059761 --- /dev/null +++ b/src/gui/panels/binary-params.c @@ -0,0 +1,178 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * binary-params.c - édition des paramètres initiaux d'un chargement de binaire + * + * 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/>. + */ + + +#include "binary-params.h" + + +#include "binary.h" +#include "binary-params-int.h" +#include "../window.h" +#include "../../analysis/contents/file.h" +#include "../../gtkext/helpers.h" + + + +/* Initialise la classe des composants d'édition de paramètres. */ +static void gtk_binary_parameters_class_init(GtkBinaryParametersClass *); + +/* Initialise une instance de composant d'édition de paramètres. */ +static void gtk_binary_parameters_init(GtkBinaryParameters *); + +/* Supprime toutes les références externes. */ +static void gtk_binary_parameters_dispose(GObject *); + +/* Procède à la libération totale de la mémoire. */ +static void gtk_binary_parameters_finalize(GObject *); + +/* Ouvre une boîte de dialogue pour récupérer un fichier. */ +static void gtk_binary_parameters_on_new_file_entry_icon_release(GtkEntry *, GtkEntryIconPosition, GtkBinaryParameters *); + + + +/* Détermine le type du composant d'édition des paramètres de chargement. */ +G_DEFINE_TYPE(GtkBinaryParameters, gtk_binary_parameters, GTK_TYPE_GRID); + + +/****************************************************************************** +*                                                                             * +*  Paramètres  : class = classe GTK à initialiser.                            * +*                                                                             * +*  Description : Initialise la classe des composants d'édition de paramètres. * +*                                                                             * +*  Retour      : -                                                            * +*                                                                             * +*  Remarques   : -                                                            * +*                                                                             * +******************************************************************************/ + +static void gtk_binary_parameters_class_init(GtkBinaryParametersClass *class) +{ +    GObjectClass *object;                   /* Plus haut niveau équivalent */ +    GtkWidgetClass *widget;                 /* Classe de haut niveau       */ + +    object = G_OBJECT_CLASS(class); + +    object->dispose = gtk_binary_parameters_dispose; +    object->finalize = gtk_binary_parameters_finalize; + +    widget = GTK_WIDGET_CLASS(class); + +    gtk_widget_class_set_template_from_resource(widget, "/re/chrysalide/framework/gui/panels/binary-params.ui"); + +    gtk_widget_class_bind_template_callback_full(widget, BUILDER_CB(gtk_binary_parameters_on_new_file_entry_icon_release)); + +    gtk_widget_class_bind_template_child(widget, GtkBinaryParameters, filename); + +} + + +/****************************************************************************** +*                                                                             * +*  Paramètres  : params = composant GTK à initialiser.                        * +*                                                                             * +*  Description : Initialise une instance de composant d'édition de paramètres.* +*                                                                             * +*  Retour      : -                                                            * +*                                                                             * +*  Remarques   : -                                                            * +*                                                                             * +******************************************************************************/ + +static void gtk_binary_parameters_init(GtkBinaryParameters *params) +{ +    gtk_widget_init_template(GTK_WIDGET(params)); + +} + + +/****************************************************************************** +*                                                                             * +*  Paramètres  : object = instance d'objet GLib à traiter.                    * +*                                                                             * +*  Description : Supprime toutes les références externes.                     * +*                                                                             * +*  Retour      : -                                                            * +*                                                                             * +*  Remarques   : -                                                            * +*                                                                             * +******************************************************************************/ + +static void gtk_binary_parameters_dispose(GObject *object) +{ +    gtk_widget_dispose_template(GTK_WIDGET(object), GTK_TYPE_BINARY_PARAMETERS); + +    G_OBJECT_CLASS(gtk_binary_parameters_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 gtk_binary_parameters_finalize(GObject *object) +{ +    G_OBJECT_CLASS(gtk_binary_parameters_parent_class)->finalize(object); + +} + + +/****************************************************************************** +*                                                                             * +*  Paramètres  : entry    = zone de saisie concernée par l'appel.             * +*                icon_pos = position de l'icone incrustée dans la zone.       * +*                params   = composant d'édition des paramètres.               * +*                                                                             * +*  Description : Ouvre une boîte de dialogue pour récupérer un fichier.       * +*                                                                             * +*  Retour      : -                                                            * +*                                                                             * +*  Remarques   : -                                                            * +*                                                                             * +******************************************************************************/ + +static void gtk_binary_parameters_on_new_file_entry_icon_release(GtkEntry *entry, GtkEntryIconPosition icon_pos, GtkBinaryParameters *params) +{ +    GtkRoot *root;                          /* Racine du composant         */ +    GBinContent *content;                   /* Contenu binaire à afficher  */ +    GtkTiledPanel *tiled;                   /* Panneau d'affichage complet */ + +    root = gtk_widget_get_root(GTK_WIDGET(entry)); + +    content = g_file_content_new("/bin/id"); + +    tiled = gtk_binary_panel_new_for_content(content); + +    unref_object(content); + +    gtk_framework_window_add(GTK_FRAMEWORK_WINDOW(root), tiled); + +} diff --git a/src/gui/panels/binary-params.h b/src/gui/panels/binary-params.h new file mode 100644 index 0000000..450da25 --- /dev/null +++ b/src/gui/panels/binary-params.h @@ -0,0 +1,41 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * binary-params.h - prototypes pour l'édition des paramètres initiaux d'un chargement de binaire + * + * 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 _GUI_PANELS_BINARY_PARAMS_H +#define _GUI_PANELS_BINARY_PARAMS_H + + +#include <gtk/gtk.h> + + +#include "../../glibext/helpers.h" + + + +#define GTK_TYPE_BINARY_PARAMETERS (gtk_binary_parameters_get_type()) + +DECLARE_GTYPE(GtkBinaryParameters, gtk_binary_parameters, GTK, BINARY_PARAMETERS); + + + +#endif  /* _GUI_PANELS_BINARY_PARAMS_H */ diff --git a/src/gui/panels/binary-params.ui b/src/gui/panels/binary-params.ui new file mode 100644 index 0000000..dcbaf7c --- /dev/null +++ b/src/gui/panels/binary-params.ui @@ -0,0 +1,42 @@ +<?xml version="1.0" encoding="UTF-8"?> +<interface> + +    <template class="GtkBinaryParameters" parent="GtkGrid"> +        <property name="margin-bottom">12</property> +        <property name="margin-end">12</property> +        <property name="margin-start">12</property> +        <property name="margin-top">12</property> +        <property name="column-spacing">12</property> +        <property name="row-spacing">8</property> + +        <child> +            <object class="GtkLabel"> +                <property name="label">Load and analyze a new file:</property> +                <property name="xalign">0</property> +                <layout> +                    <property name="column">0</property> +                    <property name="row">0</property> +                </layout> +            </object> +        </child> + +        <child> +            <object class="GtkEntry" id="filename"> +                <property name="secondary-icon-name">document-open-symbolic</property> +                <property name="placeholder-text">File location</property> +                <property name="hexpand">TRUE</property> +                <property name="hexpand-set">TRUE</property> +                <layout> +                    <property name="column">0</property> +                    <property name="row">1</property> +                </layout> +                <style> +                    <class name="background"/> +                </style> +                <signal name="icon-release" handler="gtk_binary_parameters_on_new_file_entry_icon_release"/> +            </object> +        </child> + +    </template> + +</interface> diff --git a/src/gui/panels/binary.c b/src/gui/panels/binary.c new file mode 100644 index 0000000..f58c06b --- /dev/null +++ b/src/gui/panels/binary.c @@ -0,0 +1,195 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * binary.c - panneau d'affichage de contenus d'un binaire, bruts ou non + * + * Copyright (C) 2024 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 this program; if not, write to the Free Software + *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA + */ + + +#include "binary.h" + + +#include "binary-int.h" +#include "../../gtkext/helpers.h" +#include "../../gtkext/hexview.h" + + + +/* ------------------------- COEUR D'UN PANNEAU D'AFFICHAGE ------------------------- */ + + +/* Initialise la classe des panneaux pour binaires. */ +static void gtk_binary_panel_class_init(GtkBinaryPanelClass *); + +/* Initialise une instance de panneau pour binaire. */ +static void gtk_binary_panel_init(GtkBinaryPanel *); + +/* Supprime toutes les références externes. */ +static void gtk_binary_panel_dispose(GObject *); + +/* Procède à la libération totale de la mémoire. */ +static void gtk_binary_panel_finalize(GObject *); + + + +/* --------------------- IMPLEMENTATION DES FONCTIONS DE CLASSE --------------------- */ + + + + + + +/* ---------------------------------------------------------------------------------- */ +/*                           COEUR D'UN PANNEAU D'AFFICHAGE                           */ +/* ---------------------------------------------------------------------------------- */ + + +/* Indique le type défini pour un panneau d'affichage de contenus d'un binaire. */ +G_DEFINE_TYPE(GtkBinaryPanel, gtk_binary_panel, GTK_TYPE_TILED_PANEL); + + +/****************************************************************************** +*                                                                             * +*  Paramètres  : class = classe à initialiser.                                * +*                                                                             * +*  Description : Initialise la classe des panneaux pour binaires.             * +*                                                                             * +*  Retour      : -                                                            * +*                                                                             * +*  Remarques   : -                                                            * +*                                                                             * +******************************************************************************/ + +static void gtk_binary_panel_class_init(GtkBinaryPanelClass *class) +{ +    GObjectClass *object;                   /* Autre version de la classe  */ +    GtkWidgetClass *widget;                 /* Classe de haut niveau       */ + +    object = G_OBJECT_CLASS(class); + +    object->dispose = gtk_binary_panel_dispose; +    object->finalize = gtk_binary_panel_finalize; + +    widget = GTK_WIDGET_CLASS(class); + +    gtk_widget_class_set_template_from_resource(widget, "/re/chrysalide/framework/gui/panels/binary.ui"); + +    gtk_widget_class_bind_template_child(widget, GtkBinaryPanel, hex_scroll); + +} + + +/****************************************************************************** +*                                                                             * +*  Paramètres  : panel = instance à initialiser.                              * +*                                                                             * +*  Description : Initialise une instance de panneau pour binaire.             * +*                                                                             * +*  Retour      : -                                                            * +*                                                                             * +*  Remarques   : -                                                            * +*                                                                             * +******************************************************************************/ + +static void gtk_binary_panel_init(GtkBinaryPanel *panel) +{ +    gtk_widget_init_template(GTK_WIDGET(panel)); + +} + + +/****************************************************************************** +*                                                                             * +*  Paramètres  : object = instance d'objet GLib à traiter.                    * +*                                                                             * +*  Description : Supprime toutes les références externes.                     * +*                                                                             * +*  Retour      : -                                                            * +*                                                                             * +*  Remarques   : -                                                            * +*                                                                             * +******************************************************************************/ + +static void gtk_binary_panel_dispose(GObject *object) +{ +    gtk_widget_dispose_template(GTK_WIDGET(object), GTK_TYPE_BINARY_PANEL); + +    G_OBJECT_CLASS(gtk_binary_panel_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 gtk_binary_panel_finalize(GObject *object) +{ +    G_OBJECT_CLASS(gtk_binary_panel_parent_class)->finalize(object); + +} + + +/****************************************************************************** +*                                                                             * +*  Paramètres  : content = contenu brut à exposer.                            * +*                                                                             * +*  Description : Crée une nouvelle instance de panneau pour binaire.          * +*                                                                             * +*  Retour      : Composant GTK mis en place.                                  * +*                                                                             * +*  Remarques   : -                                                            * +*                                                                             * +******************************************************************************/ + +GtkTiledPanel *gtk_binary_panel_new_for_content(GBinContent *content) +{ +    GtkTiledPanel *result;                  /* Instance à retourner        */ +    GtkHexView *view;                       /* Composant d'affichage       */ + +    result = g_object_new(GTK_TYPE_BINARY_PANEL, NULL); + +    view = gtk_hex_view_new(content); +    gtk_scrolled_window_set_child(GTK_BINARY_PANEL(result)->hex_scroll, GTK_WIDGET(view)); + +    return result; + +} + + + +/* ---------------------------------------------------------------------------------- */ +/*                       IMPLEMENTATION DES FONCTIONS DE CLASSE                       */ +/* ---------------------------------------------------------------------------------- */ + + + + + + + + diff --git a/src/gui/panels/binary.h b/src/gui/panels/binary.h new file mode 100644 index 0000000..26f8a7d --- /dev/null +++ b/src/gui/panels/binary.h @@ -0,0 +1,48 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * binary.h - prototypes pour le panneau d'accueil par défaut + * + * Copyright (C) 2012-2024 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 this program; if not, write to the Free Software + *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA + */ + + +#ifndef _GUI_PANELS_BINARY_H +#define _GUI_PANELS_BINARY_H + + +#include <gtk/gtk.h> + + +#include "../../analysis/content.h" +#include "../../glibext/helpers.h" +#include "../../gtkext/panel.h" + + + +#define GTK_TYPE_BINARY_PANEL (gtk_binary_panel_get_type()) + +DECLARE_GTYPE(GtkBinaryPanel, gtk_binary_panel, GTK, BINARY_PANEL); + + +/* Crée une nouvelle instance de panneau pour binaire. */ +GtkTiledPanel *gtk_binary_panel_new_for_content(GBinContent *); + + + +#endif  /* _GUI_PANELS_BINARY_H */ diff --git a/src/gui/panels/binary.ui b/src/gui/panels/binary.ui new file mode 100644 index 0000000..a34c409 --- /dev/null +++ b/src/gui/panels/binary.ui @@ -0,0 +1,16 @@ +<?xml version="1.0" encoding="UTF-8"?> +<interface> + +    <template class="GtkBinaryPanel" parent="GtkTiledPanel"> +        <child> +            <object class="GtkScrolledWindow" id="hex_scroll"> +                <property name="hscrollbar-policy">automatic</property> +                <property name="vscrollbar-policy">automatic</property> +                <property name="hexpand">TRUE</property> +                <property name="vexpand">TRUE</property> +                <property name="has-frame">0</property> +            </object> +        </child> +    </template> + +</interface> diff --git a/src/gui/panels/gresource.xml b/src/gui/panels/gresource.xml index d996ef1..2765b25 100644 --- a/src/gui/panels/gresource.xml +++ b/src/gui/panels/gresource.xml @@ -1,20 +1,16 @@  <?xml version="1.0" encoding="UTF-8"?>  <gresources> -    <gresource prefix="/org/chrysalide/gui/panels"> -        <file compressed="true">../../../pixmaps/tbutton_list_view.png</file> -        <file compressed="true">../../../pixmaps/tbutton_tree_view.png</file> -        <file compressed="true">../../../pixmaps/tbutton_collapse.png</file> -        <file compressed="true">../../../pixmaps/tbutton_expand.png</file> -        <file compressed="true">../../../pixmaps/symbol_class_classic.png</file> -        <file compressed="true">bintree.ui</file> -        <file compressed="true">bookmarks.ui</file> -        <file compressed="true">errors.ui</file> -        <file compressed="true">glance.ui</file> -        <file compressed="true">history.ui</file> -        <file compressed="true">log.ui</file> -        <file compressed="true">regedit.ui</file> -        <file compressed="true">strings.ui</file> -        <file compressed="true">symbols.ui</file> +    <gresource prefix="/re/chrysalide/framework/gui/panels"> +        <file compressed="true">binary.ui</file> +        <file compressed="true">binary-params.ui</file> +        <file compressed="true">logs.ui</file> +        <file compressed="true">logs-col-icon.ui</file> +        <file compressed="true">logs-col-message.ui</file>          <file compressed="true">welcome.ui</file> +        <file compressed="true">welcome-hints.txt</file> +    </gresource> +    <gresource prefix="/re/chrysalide/framework/gui/icons/scalable/actions"> +        <file compressed="true" alias="binfile-symbolic.svg">../../../data/images/binfile-symbolic.svg</file> +        <file compressed="true" alias="tipoftheday-symbolic.svg">../../../data/images/tipoftheday-symbolic.svg</file>      </gresource>  </gresources> diff --git a/src/gui/panels/log.c b/src/gui/panels/log.c deleted file mode 100644 index d11fbd2..0000000 --- a/src/gui/panels/log.c +++ /dev/null @@ -1,451 +0,0 @@ - -/* Chrysalide - Outil d'analyse de fichiers binaires - * log.c - panneau d'affichage des messages système - * - * Copyright (C) 2012-2019 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 this program; if not, write to the Free Software - *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA - */ - - -#include "log.h" - - -#include <malloc.h> -#include <stdarg.h> -#include <stdio.h> -#include <string.h> -#include <gtk/gtk.h> - - -#include "../panel-int.h" -#include "../core/panels.h" -#include "../../gtkext/easygtk.h" -#include "../../gtkext/named.h" - - - -/* Colonnes de la liste des messages */ -typedef enum _LogColumn -{ -    LGC_PICTURE,                            /* Image de représentation     */ -    LGC_STRING,                             /* Chaîne de caractères        */ - -    LGC_COUNT                               /* Nombre de colonnes          */ - -} LogColumn; - - -/* Paramètres à transmettre pour un affichage */ -typedef struct _log_data -{ -    GPanelItem *item;                       /* Intermédiaire mis en place  */ -    LogMessageType type;                    /* Type de message à afficher  */ -    char *msg;                              /* Contenu du message          */ - -} log_data; - - -/* Panneau d'accueil (instance) */ -struct _GLogPanel -{ -    GPanelItem parent;                      /* A laisser en premier        */ - -}; - - -/* Panneau d'accueil (classe) */ -struct _GLogPanelClass -{ -    GPanelItemClass parent;                 /* A laisser en premier        */ - -}; - - -/* Initialise la classe des panneaux d'affichage des messages. */ -static void g_log_panel_class_init(GLogPanelClass *); - -/* Initialise une instance de panneau d'affichage des messages. */ -static void g_log_panel_init(GLogPanel *); - -/* Supprime toutes les références externes. */ -static void g_log_panel_dispose(GLogPanel *); - -/* Procède à la libération totale de la mémoire. */ -static void g_log_panel_finalize(GLogPanel *); - -/* Fournit le nom interne attribué à l'élément réactif. */ -static char *g_log_panel_class_get_key(const GLogPanelClass *); - -/* Fournit une indication sur la personnalité du panneau. */ -static PanelItemPersonality g_log_panel_class_get_personality(const GLogPanelClass *); - -/* Indique le chemin initial de la localisation d'un panneau. */ -static char *g_log_panel_class_get_path(const GLogPanelClass *); - -/* Indique la définition d'un éventuel raccourci clavier. */ -static char *g_log_panel_class_get_key_bindings(const GLogPanelClass *); - -/* Affiche un message dans le journal des messages système. */ -static gboolean log_message(log_data *); - - - -/* Indique le type défini pour un panneau d'affichage de messages. */ -G_DEFINE_TYPE(GLogPanel, g_log_panel, G_TYPE_PANEL_ITEM); - - -/****************************************************************************** -*                                                                             * -*  Paramètres  : class = classe à initialiser.                                * -*                                                                             * -*  Description : Initialise la classe des panneaux d'affichage des messages.  * -*                                                                             * -*  Retour      : -                                                            * -*                                                                             * -*  Remarques   : -                                                            * -*                                                                             * -******************************************************************************/ - -static void g_log_panel_class_init(GLogPanelClass *class) -{ -    GObjectClass *object;                   /* Autre version de la classe  */ -    GEditorItemClass *item;                 /* Encore une autre vision...  */ -    GPanelItemClass *panel;                 /* Version parente de la classe*/ - -    object = G_OBJECT_CLASS(class); - -    object->dispose = (GObjectFinalizeFunc/* ! */)g_log_panel_dispose; -    object->finalize = (GObjectFinalizeFunc)g_log_panel_finalize; - -    item = G_EDITOR_ITEM_CLASS(class); - -    item->get_key = (get_item_key_fc)g_log_panel_class_get_key; - -    panel = G_PANEL_ITEM_CLASS(class); - -    panel->get_personality = (get_panel_personality_fc)g_log_panel_class_get_personality; -    panel->get_path = (get_panel_path_fc)g_log_panel_class_get_path; -    panel->get_bindings = (get_panel_bindings_fc)g_log_panel_class_get_key_bindings; - -} - - -/****************************************************************************** -*                                                                             * -*  Paramètres  : panel = instance à initialiser.                              * -*                                                                             * -*  Description : Initialise une instance de panneau d'affichage des messages. * -*                                                                             * -*  Retour      : -                                                            * -*                                                                             * -*  Remarques   : -                                                            * -*                                                                             * -******************************************************************************/ - -static void g_log_panel_init(GLogPanel *panel) -{ -    GPanelItem *pitem;                      /* Version parente du panneau  */ - -    /* Eléments de base */ - -    pitem = G_PANEL_ITEM(panel); - -    pitem->widget = G_NAMED_WIDGET(gtk_built_named_widget_new_for_panel(_("Messages"), -                                                                        _("Misc information"), -                                                                        PANEL_LOG_ID)); - -} - - -/****************************************************************************** -*                                                                             * -*  Paramètres  : panel = instance d'objet GLib à traiter.                     * -*                                                                             * -*  Description : Supprime toutes les références externes.                     * -*                                                                             * -*  Retour      : -                                                            * -*                                                                             * -*  Remarques   : -                                                            * -*                                                                             * -******************************************************************************/ - -static void g_log_panel_dispose(GLogPanel *panel) -{ -    G_OBJECT_CLASS(g_log_panel_parent_class)->dispose(G_OBJECT(panel)); - -} - - -/****************************************************************************** -*                                                                             * -*  Paramètres  : panel = instance d'objet GLib à traiter.                     * -*                                                                             * -*  Description : Procède à la libération totale de la mémoire.                * -*                                                                             * -*  Retour      : -                                                            * -*                                                                             * -*  Remarques   : -                                                            * -*                                                                             * -******************************************************************************/ - -static void g_log_panel_finalize(GLogPanel *panel) -{ -    G_OBJECT_CLASS(g_log_panel_parent_class)->finalize(G_OBJECT(panel)); - -} - - -/****************************************************************************** -*                                                                             * -*  Paramètres  : class = classe à consulter.                                  * -*                                                                             * -*  Description : Fournit le nom interne attribué à l'élément réactif.         * -*                                                                             * -*  Retour      : Désignation (courte) de l'élément de l'éditeur.              * -*                                                                             * -*  Remarques   : -                                                            * -*                                                                             * -******************************************************************************/ - -static char *g_log_panel_class_get_key(const GLogPanelClass *class) -{ -    char *result;                           /* Description à renvoyer      */ - -    result = strdup(PANEL_LOG_ID); - -    return result; - -} - - -/****************************************************************************** -*                                                                             * -*  Paramètres  : class = classe à consulter.                                  * -*                                                                             * -*  Description : Fournit une indication sur la personnalité du panneau.       * -*                                                                             * -*  Retour      : Identifiant lié à la nature unique du panneau.               * -*                                                                             * -*  Remarques   : -                                                            * -*                                                                             * -******************************************************************************/ - -static PanelItemPersonality g_log_panel_class_get_personality(const GLogPanelClass *class) -{ -    PanelItemPersonality result;            /* Personnalité à retourner    */ - -    result = PIP_PERSISTENT_SINGLETON; - -    return result; - -} - - -/****************************************************************************** -*                                                                             * -*  Paramètres  : class = classe à consulter.                                  * -*                                                                             * -*  Description : Indique le chemin initial de la localisation d'un panneau.   * -*                                                                             * -*  Retour      : Chemin fixé associé à la position initiale.                  * -*                                                                             * -*  Remarques   : -                                                            * -*                                                                             * -******************************************************************************/ - -static char *g_log_panel_class_get_path(const GLogPanelClass *class) -{ -    char *result;                           /* Emplacement à retourner     */ - -    result = strdup("Ms"); - -    return result; - -} - - -/****************************************************************************** -*                                                                             * -*  Paramètres  : class = classe à consulter.                                  * -*                                                                             * -*  Description : Indique la définition d'un éventuel raccourci clavier.       * -*                                                                             * -*  Retour      : Description d'un raccourci ou NULL si aucun de défini.       * -*                                                                             * -*  Remarques   : -                                                            * -*                                                                             * -******************************************************************************/ - -static char *g_log_panel_class_get_key_bindings(const GLogPanelClass *class) -{ -    char *result;                           /* Emplacement à retourner     */ - -    result = strdup("<Shift>F1"); - -    return result; - -} - - -/****************************************************************************** -*                                                                             * -*  Paramètres  : -                                                            * -*                                                                             * -*  Description : Crée un panneau d'affichage des messages système.            * -*                                                                             * -*  Retour      : Adresse de la structure mise en place.                       * -*                                                                             * -*  Remarques   : -                                                            * -*                                                                             * -******************************************************************************/ - -GPanelItem *g_log_panel_new(void) -{ -    GPanelItem *result;                     /* Structure à retourner       */ - -    result = g_object_new(G_TYPE_LOG_PANEL, NULL); - -    return result; - -} - - -/****************************************************************************** -*                                                                             * -*  Paramètres  : panel = instance d'objet GLib à traiter.                     * -*                type  = espèce du message à ajouter.                         * -*                msg   = message à faire apparaître à l'écran.                * -*                                                                             * -*  Description : Affiche un message dans le journal des messages système.     * -*                                                                             * -*  Retour      : -                                                            * -*                                                                             * -*  Remarques   : -                                                            * -*                                                                             * -******************************************************************************/ - -void g_log_panel_add_message(GLogPanel *panel, LogMessageType type, const char *msg) -{ -    log_data *data;                         /* Paramètres à joindre        */ - -    data = calloc(1, sizeof(log_data)); - -    data->item = G_PANEL_ITEM(panel); -    data->type = type; -    data->msg = strdup(msg); - -    g_object_ref(G_OBJECT(data->item)); - -    g_main_context_invoke(NULL, (GSourceFunc)log_message, data); - -} - - -/****************************************************************************** -*                                                                             * -*  Paramètres  : data = paramètres destinés à l'affichage d'un message.       * -*                                                                             * -*  Description : Affiche un message dans le journal des messages système.     * -*                                                                             * -*  Retour      : -                                                            * -*                                                                             * -*  Remarques   : Cette fonction, et c'est tout son intérêt, est toujours      * -*                exécutée dans le contexte GTK principal.                     * -*                                                                             * -******************************************************************************/ - -static gboolean log_message(log_data *data) -{ -    GtkBuilder *builder;                    /* Constructeur utilisé        */ -    GtkListStore *store;                    /* Modèle de gestion           */ -    GtkTreeIter iter;                       /* Point d'insertion           */ -    GtkTreeView *treeview;                  /* Affichage de la liste       */ - -    builder = gtk_built_named_widget_get_builder(GTK_BUILT_NAMED_WIDGET(G_PANEL_ITEM(data->item)->widget)); - -    /* Mise en place du message */ - -    store = GTK_LIST_STORE(gtk_builder_get_object(builder, "store")); - -    gtk_list_store_append(store, &iter); - -    switch (data->type) -    { -        case LMT_INFO: -            gtk_list_store_set(store, &iter, -                               LGC_PICTURE, "gtk-info", -                               LGC_STRING, data->msg, -                               -1); -            break; - -        case LMT_PROCESS: -            gtk_list_store_set(store, &iter, -                               LGC_PICTURE, "gtk-execute", -                               LGC_STRING, data->msg, -                               -1); -            break; - -        case LMT_WARNING: -            gtk_list_store_set(store, &iter, -                               LGC_PICTURE, "gtk-dialog-warning", -                               LGC_STRING, data->msg, -                               -1); -            break; - -        case LMT_BAD_BINARY: -            gtk_list_store_set(store, &iter, -                               LGC_PICTURE, "gtk-dialog-warning", -                               LGC_STRING, data->msg, -                               -1); -            break; - -        case LMT_ERROR: -        case LMT_EXT_ERROR: -            gtk_list_store_set(store, &iter, -                               LGC_PICTURE, "gtk-dialog-error", -                               LGC_STRING, data->msg, -                               -1); -            break; - -        default: -            gtk_list_store_set(store, &iter, -                               LGC_STRING, data->msg, -                               -1); -            break; - -    } - -    /* Défilement pour pointer à l'affichage */ - -    treeview = GTK_TREE_VIEW(gtk_builder_get_object(builder, "treeview")); - -    scroll_to_treeview_iter(treeview, GTK_TREE_MODEL(store), &iter); - -    g_object_unref(G_OBJECT(builder)); - -    /* Nettoyage de la mémoire */ - -    g_object_unref(G_OBJECT(data->item)); - -    free(data->msg); - -    free(data); - -    return G_SOURCE_REMOVE; - -} diff --git a/src/gui/panels/log.h b/src/gui/panels/log.h deleted file mode 100644 index 4d155a2..0000000 --- a/src/gui/panels/log.h +++ /dev/null @@ -1,67 +0,0 @@ - -/* Chrysalide - Outil d'analyse de fichiers binaires - * log.h - prototypes pour le panneau d'affichage des messages système - * - * Copyright (C) 2012-2019 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 this program; if not, write to the Free Software - *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA - */ - - -#ifndef _GUI_PANELS_LOG_H -#define _GUI_PANELS_LOG_H - - -#include <i18n.h> - - -#include "../panel.h" -#include "../../core/logs.h" - - - -#define PANEL_LOG_ID "log" - - -#define G_TYPE_LOG_PANEL               g_log_panel_get_type() -#define G_LOG_PANEL(obj)               (G_TYPE_CHECK_INSTANCE_CAST((obj), g_log_panel_get_type(), GLogPanel)) -#define G_IS_LOG_PANEL(obj)            (G_TYPE_CHECK_INSTANCE_TYPE((obj), g_log_panel_get_type())) -#define G_LOG_PANEL_CLASS(klass)       (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_LOG_PANEL, GLogPanelClass)) -#define G_IS_LOG_PANEL_CLASS(klass)    (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_LOG_PANEL)) -#define G_LOG_PANEL_GET_CLASS(obj)     (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_LOG_PANEL, GLogPanelClass)) - - -/* Panneau d'affichage de messages (instance) */ -typedef struct _GLogPanel GLogPanel; - -/* Panneau d'affichage de messages (classe) */ -typedef struct _GLogPanelClass GLogPanelClass; - - - -/* Indique le type défini pour un panneau d'affichage de messages. */ -GType g_log_panel_get_type(void); - -/* Crée un panneau d'affichage des messages système. */ -GPanelItem *g_log_panel_new(void); - -/* Affiche un message dans le journal des messages système. */ -void g_log_panel_add_message(GLogPanel *, LogMessageType, const char *); - - - -#endif  /* _GUI_PANELS_LOG_H */ diff --git a/src/gui/panels/log.ui b/src/gui/panels/log.ui deleted file mode 100644 index 4ffe96c..0000000 --- a/src/gui/panels/log.ui +++ /dev/null @@ -1,59 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- Generated with glade 3.21.0 --> -<interface> -  <requires lib="gtk+" version="3.20"/> -  <object class="GtkListStore" id="store"> -    <columns> -      <!-- column-name picture --> -      <column type="gchararray"/> -      <!-- column-name string --> -      <column type="gchararray"/> -    </columns> -  </object> -  <object class="GtkOffscreenWindow"> -    <property name="can_focus">False</property> -    <child> -      <object class="GtkScrolledWindow" id="box"> -        <property name="visible">True</property> -        <property name="can_focus">True</property> -        <property name="shadow_type">in</property> -        <child> -          <object class="GtkTreeView" id="treeview"> -            <property name="visible">True</property> -            <property name="can_focus">True</property> -            <property name="model">store</property> -            <property name="headers_visible">False</property> -            <child internal-child="selection"> -              <object class="GtkTreeSelection"/> -            </child> -            <child> -              <object class="GtkTreeViewColumn"> -                <property name="title" translatable="yes">picture</property> -                <child> -                  <object class="GtkCellRendererPixbuf"/> -                  <attributes> -                    <attribute name="stock-id">0</attribute> -                  </attributes> -                </child> -              </object> -            </child> -            <child> -              <object class="GtkTreeViewColumn"> -                <property name="title" translatable="yes">string</property> -                <child> -                  <object class="GtkCellRendererText"/> -                  <attributes> -                    <attribute name="markup">1</attribute> -                  </attributes> -                </child> -              </object> -            </child> -          </object> -        </child> -      </object> -    </child> -    <child type="titlebar"> -      <placeholder/> -    </child> -  </object> -</interface> diff --git a/src/gui/panels/logs-col-icon.ui b/src/gui/panels/logs-col-icon.ui new file mode 100644 index 0000000..6463e84 --- /dev/null +++ b/src/gui/panels/logs-col-icon.ui @@ -0,0 +1,17 @@ +<?xml version="1.0" encoding="UTF-8"?> +<interface> + +    <template class="GtkListItem"> +        <property name="child"> +            <object class="GtkImage"> +                <binding name="icon-name"> +                    <lookup name="icon-name" type="GLogEntry"> +                        <lookup name="item">GtkListItem</lookup> +                    </lookup> +                </binding> +            </object> +        </property> + +    </template> + +</interface> diff --git a/src/gui/panels/logs-col-message.ui b/src/gui/panels/logs-col-message.ui new file mode 100644 index 0000000..49839e4 --- /dev/null +++ b/src/gui/panels/logs-col-message.ui @@ -0,0 +1,19 @@ +<?xml version="1.0" encoding="UTF-8"?> +<interface> + +    <template class="GtkListItem"> +        <property name="child"> +            <object class="GtkLabel"> +                <property name="xalign">0</property> +                <property name="use-markup">true</property> +                <binding name="label"> +                    <lookup name="message" type="GLogEntry"> +                        <lookup name="item">GtkListItem</lookup> +                    </lookup> +                </binding> +            </object> +        </property> + +    </template> + +</interface> diff --git a/src/gui/panels/logs-int.h b/src/gui/panels/logs-int.h new file mode 100644 index 0000000..692c1b4 --- /dev/null +++ b/src/gui/panels/logs-int.h @@ -0,0 +1,53 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * logs-int.h - prototypes internes pour le panneau d'affichage des messages système + * + * 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 this program; if not, write to the Free Software + *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA + */ + + +#ifndef _GUI_PANELS_LOGS_INT_H +#define _GUI_PANELS_LOGS_INT_H + + +#include "logs.h" +#include "../../gtkext/panel-int.h" + + + +/* Panneau d'affichage de messages (instance) */ +struct _GtkLogsPanel +{ +    GtkTiledPanel parent;                   /* A laisser en premier        */ + +    GListStore *store;                      /* Liste des eléments conservés*/ +    GtkWidget *list;                        /* Composant d'affichage       */ + +}; + +/* Panneau d'affichage de messages (classe) */ +struct _GtkLogsPanelClass +{ +    GtkTiledPanelClass parent;              /* A laisser en premier        */ + +}; + + + +#endif  /* _GUI_PANELS_LOGS_INT_H */ diff --git a/src/gui/panels/logs.c b/src/gui/panels/logs.c new file mode 100644 index 0000000..399c4c0 --- /dev/null +++ b/src/gui/panels/logs.c @@ -0,0 +1,227 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * logs.c - panneau d'affichage des messages système + * + * Copyright (C) 2012-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 this program; if not, write to the Free Software + *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA + */ + + +#include "logs.h" + + +#include <assert.h> +#include <string.h> + + +#include "logs-int.h" +#include "../../gtkext/helpers.h" + + + +/* ------------------------- COEUR D'UN PANNEAU D'AFFICHAGE ------------------------- */ + + +/* Initialise la classe des panneaux d'affichage des journaux. */ +static void gtk_logs_panel_class_init(GtkLogsPanelClass *); + +/* Initialise une instance de panneau d'affichage des journaux. */ +static void gtk_logs_panel_init(GtkLogsPanel *); + +/* Supprime toutes les références externes. */ +static void gtk_logs_panel_dispose(GObject *); + +/* Procède à la libération totale de la mémoire. */ +static void gtk_logs_panel_finalize(GObject *); + + + +/* --------------------- IMPLEMENTATION DES FONCTIONS DE CLASSE --------------------- */ + + +/* Indique l'emplacement par défaut pour un affichage. */ +static char *gtk_logs_panel_get_default_path(const GtkTiledPanel *); + + + +/* ---------------------------------------------------------------------------------- */ +/*                           COEUR D'UN PANNEAU D'AFFICHAGE                           */ +/* ---------------------------------------------------------------------------------- */ + + +/* Indique le type défini pour un panneau d'accueil. */ +G_DEFINE_TYPE(GtkLogsPanel, gtk_logs_panel, GTK_TYPE_TILED_PANEL); + + +/****************************************************************************** +*                                                                             * +*  Paramètres  : class = classe à initialiser.                                * +*                                                                             * +*  Description : Initialise la classe des panneaux d'affichage des journaux.  * +*                                                                             * +*  Retour      : -                                                            * +*                                                                             * +*  Remarques   : -                                                            * +*                                                                             * +******************************************************************************/ + +static void gtk_logs_panel_class_init(GtkLogsPanelClass *class) +{ +    GObjectClass *object;                   /* Autre version de la classe  */ +    GtkWidgetClass *widget;                 /* Classe de haut niveau       */ +    GtkTiledPanelClass *panel;              /* Classe parente              */ + +    object = G_OBJECT_CLASS(class); + +    object->dispose = gtk_logs_panel_dispose; +    object->finalize = gtk_logs_panel_finalize; + +    widget = GTK_WIDGET_CLASS(class); + +    g_type_ensure(G_TYPE_LOG_ENTRY); + +    gtk_widget_class_set_template_from_resource(widget, "/re/chrysalide/framework/gui/panels/logs.ui"); + +    //gtk_widget_class_bind_template_callback_full(widget, BUILDER_CB(gtk_logs_panel_on_selected_rows_changed)); + +    gtk_widget_class_bind_template_child(widget, GtkLogsPanel, store); +    gtk_widget_class_bind_template_child(widget, GtkLogsPanel, list); + +    panel = GTK_TILED_PANEL_CLASS(class); + +    panel->get_default_path = gtk_logs_panel_get_default_path; + +} + + +/****************************************************************************** +*                                                                             * +*  Paramètres  : panel = instance à initialiser.                              * +*                                                                             * +*  Description : Initialise une instance de panneau d'affichage des journaux. * +*                                                                             * +*  Retour      : -                                                            * +*                                                                             * +*  Remarques   : -                                                            * +*                                                                             * +******************************************************************************/ + +static void gtk_logs_panel_init(GtkLogsPanel *panel) +{ +    GtkWidget *headers;                     /* Composant à cacher          */ + +    gtk_widget_init_template(GTK_WIDGET(panel)); + +    /** +     * Retrait des entêtes de colonne de l'affichage. +     */ + +    headers = gtk_widget_get_first_child(panel->list); + +    gtk_widget_set_visible(headers, FALSE); + +} + + +/****************************************************************************** +*                                                                             * +*  Paramètres  : object = instance d'objet GLib à traiter.                    * +*                                                                             * +*  Description : Supprime toutes les références externes.                     * +*                                                                             * +*  Retour      : -                                                            * +*                                                                             * +*  Remarques   : -                                                            * +*                                                                             * +******************************************************************************/ + +static void gtk_logs_panel_dispose(GObject *object) +{ +    gtk_widget_dispose_template(GTK_WIDGET(object), GTK_TYPE_LOGS_PANEL); + +    G_OBJECT_CLASS(gtk_logs_panel_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 gtk_logs_panel_finalize(GObject *object) +{ +    G_OBJECT_CLASS(gtk_logs_panel_parent_class)->finalize(object); + +} + + +/****************************************************************************** +*                                                                             * +*  Paramètres  : panel = instance d'objet GLib à traiter.                     * +*                entry = élément de journalisation à intégrer.                * +*                                                                             * +*  Description : Affiche un message dans le journal des messages système.     * +*                                                                             * +*  Retour      : -                                                            * +*                                                                             * +*  Remarques   : -                                                            * +*                                                                             * +******************************************************************************/ + +void g_log_panel_add_message(GtkLogsPanel *panel, GLogEntry *entry) +{ +    g_list_store_append(panel->store, entry); + +} + + + +/* ---------------------------------------------------------------------------------- */ +/*                       IMPLEMENTATION DES FONCTIONS DE CLASSE                       */ +/* ---------------------------------------------------------------------------------- */ + + +/****************************************************************************** +*                                                                             * +*  Paramètres  : panel = panneau graphique à consulter.                       * +*                                                                             * +*  Description : Indique l'emplacement par défaut pour un affichage.          * +*                                                                             * +*  Retour      : Chemin représenté ou NULL pour l'emplacement "M" par défaut. * +*                                                                             * +*  Remarques   : -                                                            * +*                                                                             * +******************************************************************************/ + +static char *gtk_logs_panel_get_default_path(const GtkTiledPanel *panel) +{ +    char *result;                           /* Chemin à retourner          */ + +    result = strdup("S"); + +    return result; + +} diff --git a/src/gui/panels/logs.h b/src/gui/panels/logs.h new file mode 100644 index 0000000..a8b902b --- /dev/null +++ b/src/gui/panels/logs.h @@ -0,0 +1,47 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * logs.h - prototypes pour le panneau d'affichage des messages système + * + * Copyright (C) 2012-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 this program; if not, write to the Free Software + *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA + */ + + +#ifndef _GUI_PANELS_LOGS_H +#define _GUI_PANELS_LOGS_H + + +#include <gtk/gtk.h> + + +#include "../../glibext/helpers.h" +#include "../../glibext/log.h" + + + +#define GTK_TYPE_LOGS_PANEL (gtk_logs_panel_get_type()) + +DECLARE_GTYPE(GtkLogsPanel, gtk_logs_panel, GTK, LOGS_PANEL); + + +/* Affiche un message dans le journal des messages système. */ +void g_log_panel_add_message(GtkLogsPanel *, GLogEntry *); + + + +#endif  /* _GUI_PANELS_LOGS_H */ diff --git a/src/gui/panels/logs.ui b/src/gui/panels/logs.ui new file mode 100644 index 0000000..ba920cd --- /dev/null +++ b/src/gui/panels/logs.ui @@ -0,0 +1,58 @@ +<?xml version="1.0" encoding="UTF-8"?> +<interface> + +    <object class="GtkNoSelection" id="noselection"> +        <property name="model"> +            <object class="GListStore" id="store"> +                <property name="item-type">GLogEntry</property> +            </object> +        </property> +    </object> + +    <template class="GtkLogsPanel" parent="GtkTiledPanel"> + +        <child> +            <object class="GtkScrolledWindow"> +                <property name="hscrollbar-policy">automatic</property> +                <property name="vscrollbar-policy">automatic</property> +                <property name="hexpand">true</property> +                <property name="vexpand">true</property> +                <property name="has-frame">0</property> + +                <child> +                    <object class="GtkColumnView" id="list"> +                        <property name="vexpand">true</property> +                        <property name="model">noselection</property> + +                        <child> +                            <object class="GtkColumnViewColumn"> +                                <property name="title"></property> +                                <property name="factory"> +                                    <object class="GtkBuilderListItemFactory"> +                                        <property name="resource">/re/chrysalide/framework/gui/panels/logs-col-icon.ui</property> +                                    </object> +                                </property> +                            </object> +                        </child> + +                        <child> +                            <object class="GtkColumnViewColumn"> +                                <property name="expand">true</property> +                                <property name="title">Message</property> +                                <property name="factory"> +                                    <object class="GtkBuilderListItemFactory"> +                                        <property name="resource">/re/chrysalide/framework/gui/panels/logs-col-message.ui</property> +                                    </object> +                                </property> +                            </object> +                        </child> + +                    </object> +                </child> + +            </object> +        </child> + +    </template> + +</interface> diff --git a/src/gui/panels/welcome-hints.txt b/src/gui/panels/welcome-hints.txt new file mode 100644 index 0000000..a35ea64 --- /dev/null +++ b/src/gui/panels/welcome-hints.txt @@ -0,0 +1,23 @@ +Chrysalide's GUI offers launchers at startup in order to run main activities quickly. + +Once an activity is selected, options get displayed and allow some tunning before starting new processes. + +Such options are usually saved between runs. + + +There is no need to install Chrysalide on your system if you only want to give it a try. + +Just compile the source code and run the program from there. + + +Chrysalide can be used in external Python scripts by setting PYTHONPATH to the directory containing the 'pychrysalide.so' file. For instance: + +  cd plugins/pychrysa/.libs/ +  export PYTHONPATH=$PWD + +Then run the interpreter suitable to your configuration (debug or release): + +  python3-dbg -c 'import pychrysalide ; print(pychrysalide.mod_version())' + + +All the configuration files for Chrysalide are located in $HOME/.config/chrysalide/.
\ No newline at end of file diff --git a/src/gui/panels/welcome-int.h b/src/gui/panels/welcome-int.h new file mode 100644 index 0000000..206bc2c --- /dev/null +++ b/src/gui/panels/welcome-int.h @@ -0,0 +1,61 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * welcome-int.h - prototypes internes pour le panneau d'accueil par défaut + * + * Copyright (C) 2024 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 this program; if not, write to the Free Software + *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA + */ + + +#ifndef _GUI_PANELS_WELCOME_INT_H +#define _GUI_PANELS_WELCOME_INT_H + + +#include "welcome.h" +#include "../../gtkext/panel-int.h" + + + +/* Panneau d'accueil par défaut (instance) */ +struct _GtkWelcomePanel +{ +    GtkTiledPanel parent;                   /* A laisser en premier        */ + +    GtkListBox *list;                       /* Liste de lanceurs           */ +    GtkStack *properties;                   /* Premières propriétés        */ + +    GtkWidget *def_child;                   /* Contenu par défaut          */ +    GtkLabel *hints;                        /* Affichage d'astuces du jour */ +    GtkWidget *other_child;                 /* Autre contenu, alternatif   */ + +    gchar **raw_hints;                      /* Liste d'astuces             */ +    guint raw_count;                        /* Taille de cette liste       */ +    guint cur_hint;                         /* Position dans le parcours   */ + +}; + +/* Panneau d'accueil par défaut (classe) */ +struct _GtkWelcomePanelClass +{ +    GtkTiledPanelClass parent;              /* A laisser en premier        */ + +}; + + + +#endif  /* _GUI_PANELS_WELCOME_INT_H */ diff --git a/src/gui/panels/welcome.c b/src/gui/panels/welcome.c index 60593d1..6e8763b 100644 --- a/src/gui/panels/welcome.c +++ b/src/gui/panels/welcome.c @@ -2,7 +2,7 @@  /* Chrysalide - Outil d'analyse de fichiers binaires   * welcome.c - panneau d'accueil par défaut   * - * Copyright (C) 2012-2019 Cyrille Bagard + * Copyright (C) 2012-2024 Cyrille Bagard   *   *  This file is part of Chrysalide.   * @@ -26,130 +26,63 @@  #include <assert.h> -#include <malloc.h> -#include <stdbool.h> -#include <stdlib.h> -#include <string.h> -#include <i18n.h> - - -#include "../panel-int.h" -#include "../core/global.h" -#include "../../common/cpp.h" -#include "../../common/io.h" -#include "../../common/net.h" +#include "welcome-int.h" +#include "../core/panels.h"  #include "../../common/shuffle.h" -#include "../../core/global.h" -#include "../../core/params.h" -#include "../../core/paths.h" -#include "../../gtkext/easygtk.h" -#include "../../gtkext/named.h" - - - -/* Panneau d'accueil par défaut (instance) */ -struct _GWelcomePanel -{ -    GPanelItem parent;                      /* A laisser en premier        */ +#include "../../gtkext/helpers.h" -    cairo_surface_t *background;            /* Fond pour astuces           */ -    char **tips;                            /* Liste de toutes les astuces */ -    size_t count;                           /* Quantité d'astuces          */ -    size_t current;                         /* Indice de l'astuce courante */ - -    bool uorigin;                           /* Origine de l'affichage      */ - -    gulong sig_id;                          /* Connexion par signal        */ - -}; - -/* Panneau d'accueil par défaut (classe) */ -struct _GWelcomePanelClass -{ -    GPanelItemClass parent;                 /* A laisser en premier        */ -}; - - -/* Colonnes de la liste des messages */ -typedef enum _RecentProjectColumn -{ -    RPC_VALID,                              /* Validité de l'entrée        */ -    RPC_FULLPATH,                           /* Chemin d'accès à un projet  */ - -    RPC_COUNT                               /* Nombre de colonnes          */ - -} RecentProjectColumn; +/* ------------------------- COEUR D'UN PANNEAU D'AFFICHAGE ------------------------- */  /* Initialise la classe des panneaux d'accueil par défaut. */ -static void g_welcome_panel_class_init(GWelcomePanelClass *); +static void gtk_welcome_panel_class_init(GtkWelcomePanelClass *);  /* Initialise une instance de panneau d'accueil par défaut. */ -static void g_welcome_panel_init(GWelcomePanel *); +static void gtk_welcome_panel_init(GtkWelcomePanel *);  /* Supprime toutes les références externes. */ -static void g_welcome_panel_dispose(GWelcomePanel *); +static void gtk_welcome_panel_dispose(GObject *);  /* Procède à la libération totale de la mémoire. */ -static void g_welcome_panel_finalize(GWelcomePanel *); +static void gtk_welcome_panel_finalize(GObject *); -/* Fournit le nom interne attribué à l'élément réactif. */ -static char *g_welcome_panel_class_get_key(const GWelcomePanelClass *); +/* Réagit à un changement de sélection de la liste de panneaux. */ +static void gtk_welcome_panel_on_selected_rows_changed(GtkListBox *, GtkWelcomePanel *); -/* Fournit une indication sur la personnalité du panneau. */ -static PanelItemPersonality g_welcome_panel_class_get_personality(const GWelcomePanelClass *); +/* Réagit à une demande d'affichage de l'astuce précédente. */ +static void gtk_welcome_panel_on_prev_hint_clicked(GtkButton *, GtkWelcomePanel *); -/* Indique le chemin initial de la localisation d'un panneau. */ -static char *g_welcome_panel_class_get_path(const GWelcomePanelClass *); +/* Réagit à une demande d'affichage de l'astuce suivante. */ +static void gtk_welcome_panel_on_next_hint_clicked(GtkButton *, GtkWelcomePanel *); -/* Place un panneau dans l'ensemble affiché. */ -static void g_welcome_panel_dock(GWelcomePanel *); -/* Charge l'ensemble des astuces. */ -static void g_welcome_panel_load_tips(GWelcomePanel *); -/* Assure le dessin du fond de la bulle d'astuce. */ -static gboolean on_tip_background_draw(GtkWidget *, cairo_t *, GWelcomePanel *); +/* --------------------- IMPLEMENTATION DES FONCTIONS DE CLASSE --------------------- */ -/* Réagit à la demande d'étude d'un nouveau binaire. */ -static void on_new_binary_clicked(GtkButton *, GWelcomePanel *); -/* Actualise au besoin la liste des projets récents. */ -static void on_recent_list_changed(GtkRecentManager *, GWelcomePanel *); -/* Recharge une liste à jour des projets récents. */ -static void g_welcome_panel_reload_project_list(GWelcomePanel *, GtkRecentManager *); -/* Réagit à une sélection décidée d'un projet particulier. */ -static void on_row_activated_for_projects(GtkTreeView *, GtkTreePath *, GtkTreeViewColumn *, GWelcomePanel *); -/* Enregistre les conditions d'affichage du panneau d'accueil. */ -static void on_startup_toggled(GtkToggleButton *, GWelcomePanel *); -/* Consulte les versions existantes et affiche une conclusion. */ -static void g_welcome_panel_check_version(GWelcomePanel *); -/* Affiche l'astuce précédente dans la liste globale. */ -static void on_tip_previous_clicked(GtkButton *, GWelcomePanel *); -/* Affiche l'astuce suivante dans la liste globale. */ -static void on_tip_next_clicked(GtkButton *, GWelcomePanel *); -/* Actualise l'affichage des astuces. */ -static void g_welcome_panel_refresh_tip(GWelcomePanel *); +/* ---------------------------------------------------------------------------------- */ +/*                           COEUR D'UN PANNEAU D'AFFICHAGE                           */ +/* ---------------------------------------------------------------------------------- */  /* Indique le type défini pour un panneau d'accueil. */ -G_DEFINE_TYPE(GWelcomePanel, g_welcome_panel, G_TYPE_PANEL_ITEM); +G_DEFINE_TYPE(GtkWelcomePanel, gtk_welcome_panel, GTK_TYPE_TILED_PANEL);  /******************************************************************************  *                                                                             * -*  Paramètres  : klass = classe à initialiser.                                * +*  Paramètres  : class = classe à initialiser.                                *  *                                                                             *  *  Description : Initialise la classe des panneaux d'accueil par défaut.      *  *                                                                             * @@ -159,28 +92,28 @@ G_DEFINE_TYPE(GWelcomePanel, g_welcome_panel, G_TYPE_PANEL_ITEM);  *                                                                             *  ******************************************************************************/ -static void g_welcome_panel_class_init(GWelcomePanelClass *klass) +static void gtk_welcome_panel_class_init(GtkWelcomePanelClass *class)  {      GObjectClass *object;                   /* Autre version de la classe  */ -    GEditorItemClass *item;                 /* Encore une autre vision...  */ -    GPanelItemClass *panel;                 /* Version parente de classe   */ +    GtkWidgetClass *widget;                 /* Classe de haut niveau       */ -    object = G_OBJECT_CLASS(klass); +    object = G_OBJECT_CLASS(class); -    object->dispose = (GObjectFinalizeFunc/* ! */)g_welcome_panel_dispose; -    object->finalize = (GObjectFinalizeFunc)g_welcome_panel_finalize; +    object->dispose = gtk_welcome_panel_dispose; +    object->finalize = gtk_welcome_panel_finalize; -    item = G_EDITOR_ITEM_CLASS(klass); +    widget = GTK_WIDGET_CLASS(class); -    item->get_key = (get_item_key_fc)g_welcome_panel_class_get_key; +    gtk_widget_class_set_template_from_resource(widget, "/re/chrysalide/framework/gui/panels/welcome.ui"); -    panel = G_PANEL_ITEM_CLASS(klass); +    gtk_widget_class_bind_template_callback_full(widget, BUILDER_CB(gtk_welcome_panel_on_selected_rows_changed)); +    gtk_widget_class_bind_template_callback_full(widget, BUILDER_CB(gtk_welcome_panel_on_prev_hint_clicked)); +    gtk_widget_class_bind_template_callback_full(widget, BUILDER_CB(gtk_welcome_panel_on_next_hint_clicked)); -    panel->get_personality = (get_panel_personality_fc)g_welcome_panel_class_get_personality; -    panel->dock_at_startup = gtk_panel_item_class_return_false; -    panel->get_path = (get_panel_path_fc)g_welcome_panel_class_get_path; - -    panel->ack_dock = (ack_undock_process_fc)g_welcome_panel_dock; +    gtk_widget_class_bind_template_child(widget, GtkWelcomePanel, list); +    gtk_widget_class_bind_template_child(widget, GtkWelcomePanel, properties); +    gtk_widget_class_bind_template_child(widget, GtkWelcomePanel, def_child); +    gtk_widget_class_bind_template_child(widget, GtkWelcomePanel, hints);  } @@ -197,93 +130,81 @@ static void g_welcome_panel_class_init(GWelcomePanelClass *klass)  *                                                                             *  ******************************************************************************/ -static void g_welcome_panel_init(GWelcomePanel *panel) +static void gtk_welcome_panel_init(GtkWelcomePanel *panel)  { -    GPanelItem *pitem;                      /* Version parente du panneau  */ -    GtkBuilder *builder;                    /* Constructeur utilisé        */ -    GtkTreeView *treeview;                  /* Affichage de la liste       */ -    GtkCellRenderer *renderer;              /* Moteur de rendu de colonne  */ -    GtkTreeViewColumn *column;              /* Colonne de la liste         */ -    GtkToggleButton *button;                /* Bouton à bascule à traiter  */ -    bool state;                             /* Etat de la coche à définir  */ -    gchar *filename;                        /* Chemin d'accès à une image  */ -    GtkRecentManager *manager;              /* Gestionnaire global         */ - -    /* Eléments de base */ - -    pitem = G_PANEL_ITEM(panel); - -    pitem->widget = G_NAMED_WIDGET(gtk_built_named_widget_new_for_panel(_("Welcome"), -                                                                        _("Welcome panel"), -                                                                        PANEL_WELCOME_ID)); - -    panel->uorigin = !gtk_panel_item_class_dock_at_startup(G_PANEL_ITEM_GET_CLASS(pitem)); +    GBytes *bytes;                          /* Données brutes de ressource */ +    const gchar *data;                      /* Données brutes natives      */ +    int min;                                /* Taille à gauche minimale    */ +    GtkConstraintLayout *layout;            /* Disposition fixant la taille*/ +    GtkConstraint *constraint;              /* Contrainte à considérer     */ -    /* Représentation graphique */ +    gtk_widget_init_template(GTK_WIDGET(panel)); -    builder = gtk_built_named_widget_get_builder(GTK_BUILT_NAMED_WIDGET(pitem->widget)); +    panel->other_child = NULL; -    /* Liste des projets récents */ +    /* Chargement des astuces */ -    treeview = GTK_TREE_VIEW(gtk_builder_get_object(builder, "treeview")); +    bytes = g_resources_lookup_data("/re/chrysalide/framework/gui/panels/welcome-hints.txt", +                                    G_RESOURCE_LOOKUP_FLAGS_NONE, NULL); +    assert(bytes != NULL); -    column = gtk_tree_view_column_new(); -    gtk_tree_view_append_column(treeview, column); -    gtk_tree_view_set_expander_column(treeview, column); +    data = g_bytes_get_data(bytes, NULL); -    renderer = gtk_cell_renderer_text_new(); -    gtk_tree_view_column_pack_start(column, renderer, TRUE); -    gtk_tree_view_column_add_attribute(column, renderer, "markup", RPC_FULLPATH); +    panel->raw_hints = g_strsplit(data, "\n\n\n", -1); -    /* Affichage au démarrage ? */ +    g_bytes_unref(bytes); -    button = GTK_TOGGLE_BUTTON(gtk_builder_get_object(builder, "startup")); +    panel->raw_count = g_strv_length(panel->raw_hints); +    assert(panel->raw_count > 0); -    g_generic_config_get_value(get_main_configuration(), MPK_WELCOME_STARTUP, &state); +    panel->cur_hint = 0; -    gtk_toggle_button_set_active(button, state); +    /* Constitution de la liste des démarreurs */ -    /* Chargement de l'image de fond */ +    populate_framework_panel_launcher_list(panel->list); -    filename = find_pixmap_file("tipoftheday.png"); +    /* Dimensionnement de la zone d'astuces */ -    panel->background = cairo_image_surface_create_from_png(filename); +    gtk_widget_measure(GTK_WIDGET(panel->list), GTK_ORIENTATION_HORIZONTAL, -1, &min, NULL, NULL, NULL); -    g_free(filename); +    if (min > 150) +        min -= 150; -    /* Connexion des signaux */ +    layout = GTK_CONSTRAINT_LAYOUT(gtk_widget_get_layout_manager(GTK_WIDGET(panel->hints))); -    gtk_builder_add_callback_symbols(builder, -                                     BUILDER_CALLBACK(on_tip_background_draw), -                                     BUILDER_CALLBACK(on_new_binary_clicked), -                                     BUILDER_CALLBACK(on_row_activated_for_projects), -                                     BUILDER_CALLBACK(on_startup_toggled), -                                     BUILDER_CALLBACK(on_tip_previous_clicked), -                                     BUILDER_CALLBACK(on_tip_next_clicked), -                                     NULL); +    gtk_constraint_layout_remove_all_constraints(layout); -    gtk_builder_connect_signals(builder, panel); +    constraint = gtk_constraint_new_constant(NULL, +                                             GTK_CONSTRAINT_ATTRIBUTE_LEFT, +                                             GTK_CONSTRAINT_RELATION_EQ, +                                             0, +                                             GTK_CONSTRAINT_STRENGTH_REQUIRED); +    gtk_constraint_layout_add_constraint(layout, constraint); -    g_object_unref(G_OBJECT(builder)); +    constraint = gtk_constraint_new_constant(NULL, +                                             GTK_CONSTRAINT_ATTRIBUTE_TOP, +                                             GTK_CONSTRAINT_RELATION_EQ, +                                             0, +                                             GTK_CONSTRAINT_STRENGTH_REQUIRED); +    gtk_constraint_layout_add_constraint(layout, constraint); -    /* Actualisation du contenu du panneau */ +    constraint = gtk_constraint_new_constant(NULL, +                                             GTK_CONSTRAINT_ATTRIBUTE_RIGHT, +                                             GTK_CONSTRAINT_RELATION_EQ, +                                             min, +                                             GTK_CONSTRAINT_STRENGTH_REQUIRED); +    gtk_constraint_layout_add_constraint(layout, constraint); -    manager = get_project_manager(); +    /* Premier affichage */ -    panel->sig_id = g_signal_connect(manager, "changed", G_CALLBACK(on_recent_list_changed), panel); - -    g_welcome_panel_reload_project_list(panel, manager); - -    g_welcome_panel_load_tips(panel); - -    g_welcome_panel_check_version(panel); +    gtk_label_set_markup(panel->hints, panel->raw_hints[panel->cur_hint]);  }  /******************************************************************************  *                                                                             * -*  Paramètres  : panel = instance d'objet GLib à traiter.                     * +*  Paramètres  : object = instance d'objet GLib à traiter.                    *  *                                                                             *  *  Description : Supprime toutes les références externes.                     *  *                                                                             * @@ -293,27 +214,24 @@ static void g_welcome_panel_init(GWelcomePanel *panel)  *                                                                             *  ******************************************************************************/ -static void g_welcome_panel_dispose(GWelcomePanel *panel) +static void gtk_welcome_panel_dispose(GObject *object)  { -    GtkRecentManager *manager;              /* Gestionnaire global         */ +    GtkWelcomePanel *panel;                 /* Version spécialisée         */ -    if (panel->sig_id > 0) -    { -        manager = get_project_manager(); +    gtk_widget_dispose_template(GTK_WIDGET(object), GTK_TYPE_WELCOME_PANEL); -        g_signal_handler_disconnect(manager, panel->sig_id); -        panel->sig_id = 0; +    panel = GTK_WELCOME_PANEL(object); -    } +    g_clear_object(&panel->other_child); -    G_OBJECT_CLASS(g_welcome_panel_parent_class)->dispose(G_OBJECT(panel)); +    G_OBJECT_CLASS(gtk_welcome_panel_parent_class)->dispose(object);  }  /******************************************************************************  *                                                                             * -*  Paramètres  : panel = instance d'objet GLib à traiter.                     * +*  Paramètres  : object = instance d'objet GLib à traiter.                    *  *                                                                             *  *  Description : Procède à la libération totale de la mémoire.                *  *                                                                             * @@ -323,133 +241,25 @@ static void g_welcome_panel_dispose(GWelcomePanel *panel)  *                                                                             *  ******************************************************************************/ -static void g_welcome_panel_finalize(GWelcomePanel *panel) +static void gtk_welcome_panel_finalize(GObject *object)  { -    cairo_surface_destroy(panel->background); +    GtkWelcomePanel *panel;                 /* Version spécialisée         */ -    free(panel->tips); +    panel = GTK_WELCOME_PANEL(object); -    G_OBJECT_CLASS(g_welcome_panel_parent_class)->finalize(G_OBJECT(panel)); +    g_strfreev(panel->raw_hints); -} - - -/****************************************************************************** -*                                                                             * -*  Paramètres  : class = classe à consulter.                                  * -*                                                                             * -*  Description : Fournit le nom interne attribué à l'élément réactif.         * -*                                                                             * -*  Retour      : Désignation (courte) de l'élément de l'éditeur.              * -*                                                                             * -*  Remarques   : -                                                            * -*                                                                             * -******************************************************************************/ - -static char *g_welcome_panel_class_get_key(const GWelcomePanelClass *class) -{ -    char *result;                           /* Description à renvoyer      */ - -    result = strdup(PANEL_WELCOME_ID); - -    return result; +    G_OBJECT_CLASS(gtk_welcome_panel_parent_class)->finalize(object);  }  /******************************************************************************  *                                                                             * -*  Paramètres  : class = classe à consulter.                                  * -*                                                                             * -*  Description : Fournit une indication sur la personnalité du panneau.       * +*  Paramètres  : box   = liste GTK concernée par l'appel.                     * +*                panel = panneau d'accueil lié à la liste.                    *  *                                                                             * -*  Retour      : Identifiant lié à la nature unique du panneau.               * -*                                                                             * -*  Remarques   : -                                                            * -*                                                                             * -******************************************************************************/ - -static PanelItemPersonality g_welcome_panel_class_get_personality(const GWelcomePanelClass *class) -{ -    PanelItemPersonality result;            /* Personnalité à retourner    */ - -    result = PIP_PERSISTENT_SINGLETON; - -    return result; - -} - - -/****************************************************************************** -*                                                                             * -*  Paramètres  : class = classe à consulter.                                  * -*                                                                             * -*  Description : Indique le chemin initial de la localisation d'un panneau.   * -*                                                                             * -*  Retour      : Chemin fixé associé à la position initiale.                  * -*                                                                             * -*  Remarques   : -                                                            * -*                                                                             * -******************************************************************************/ - -static char *g_welcome_panel_class_get_path(const GWelcomePanelClass *class) -{ -    char *result;                           /* Emplacement à retourner     */ - -    result = strdup("M"); - -    return result; - -} - - -/****************************************************************************** -*                                                                             * -*  Paramètres  : -                                                            * -*                                                                             * -*  Description : Crée un panneau d'accueil par défaut.                        * -*                                                                             * -*  Retour      : Adresse de la structure mise en place.                       * -*                                                                             * -*  Remarques   : -                                                            * -*                                                                             * -******************************************************************************/ - -GPanelItem *g_welcome_panel_new(void) -{ -    GPanelItem *result;                     /* Structure à retourner       */ - -    result = g_object_new(G_TYPE_WELCOME_PANEL, NULL); - -    return result; - -} - - -/****************************************************************************** -*                                                                             * -*  Paramètres  : panel = composant à présenter à l'affichage.                 * -*                                                                             * -*  Description : Place un panneau dans l'ensemble affiché.                    * -*                                                                             * -*  Retour      : -                                                            * -*                                                                             * -*  Remarques   : -                                                            * -*                                                                             * -******************************************************************************/ - -static void g_welcome_panel_dock(GWelcomePanel *panel) -{ -    g_welcome_panel_set_user_origin(panel, true); - -} - - -/****************************************************************************** -*                                                                             * -*  Paramètres  : panel = panneau d'accueil à mettre à jour.                   * -*                                                                             * -*  Description : Charge l'ensemble des astuces.                               * +*  Description : Réagit à un changement de sélection de la liste de panneaux. *  *                                                                             *  *  Retour      : -                                                            *  *                                                                             * @@ -457,414 +267,58 @@ static void g_welcome_panel_dock(GWelcomePanel *panel)  *                                                                             *  ******************************************************************************/ -static void g_welcome_panel_load_tips(GWelcomePanel *panel) +static void gtk_welcome_panel_on_selected_rows_changed(GtkListBox *box, GtkWelcomePanel *panel)  { -    size_t i;                               /* Boucle de parcours          */ - -    char *tips[] = { - -        _("There is no need to install Chrysalide on your system if you only want to give it a try.\n\n" -          "Just compile the source code and run the program from there."), - -        _("Chrysalide can be used in external Python scripts by setting PYTHONPATH to the directory " -          "containing the 'pychrysalide.so' file. For instance:\n\n" -          "  cd plugins/pychrysa/.libs/\n" -          "  export PYTHONPATH=$PWD\n\n" -          "Then run the interpreter suitable to your configuration (debug or release):\n\n" -          "  python3-dbg -c 'import pychrysalide ; print(pychrysalide.mod_version())'"), - -        _("All the configuration files for Chrysalide are located in $HOME/.config/chrysalide/."), - -        _("The behavior of the main menu bar is copied from the one of a well known browser " -          "with a fox mascot.\n\n" -          "To make the menu bar appear and disappear, just press and release the Alt key.") - -    }; - -    panel->count = ARRAY_SIZE(tips); - -    panel->tips = (char **)calloc(panel->count, sizeof(char *)); - -    for (i = 0; i < panel->count; i++) -        panel->tips[i] = tips[i]; - -    shuffle(panel->tips, panel->count, sizeof(char *)); - -    panel->current = 0; - -    g_welcome_panel_refresh_tip(panel); - -} - - -/****************************************************************************** -*                                                                             * -*  Paramètres  : widget = composant graphique à redessiner.                   * -*                cr     = contexte graphique à utiliser.                      * -*                panel  = panneau associé comportant des informations utiles. * -*                                                                             * -*  Description : Assure le dessin du fond de la bulle d'astuce.               * -*                                                                             * -*  Retour      : FALSE pour poursuivre la propagation de l'événement.         * -*                                                                             * -*  Remarques   : -                                                            * -*                                                                             * -******************************************************************************/ +    GtkListBoxRow *row;                     /* Ligne sélectionnée          */ +    GtkWidget *new;                         /* Nouvelles propriétés        */ -static gboolean on_tip_background_draw(GtkWidget *widget, cairo_t *cr, GWelcomePanel *panel) -{ -    int wgt_width;                          /* Largeur disponible totale   */ -    int wgt_height;                         /* Hauteur disponible totale   */ -    int img_width;                          /* Largeur de l'image de fond  */ -    int img_height;                         /* Hauteur de l'image de fond  */ -    double scale;                           /* Echelle à appliquer         */ +    row = gtk_list_box_get_selected_row(box); -    if (cairo_surface_status(panel->background) == CAIRO_STATUS_SUCCESS) +    /** +     * Perte de sélection : bascule sur les informations d'accueil. +     */ +    if (row == NULL)      { -        wgt_width = gtk_widget_get_allocated_width(widget); -        wgt_height = gtk_widget_get_allocated_height(widget); - -        img_width = cairo_image_surface_get_width(panel->background); -        img_height = cairo_image_surface_get_height(panel->background); +        assert(panel->other_child != NULL); -        scale = wgt_height / (2.0 * img_height); +        gtk_stack_set_visible_child(panel->properties, panel->def_child); -        cairo_scale(cr, scale, scale); - -        cairo_set_source_surface(cr, panel->background, -                                 (wgt_width / scale) - img_width, -                                 ((wgt_height / scale) - img_height) / 2); - -        cairo_paint(cr); +        gtk_stack_remove(panel->properties, panel->other_child); +        panel->other_child = NULL;      } -    return FALSE; - -} - - -/****************************************************************************** -*                                                                             * -*  Paramètres  : button = bouton impliqué dans la procédure.                  * -*                panel  = panneau associé comportant des informations utiles. * -*                                                                             * -*  Description : Réagit à la demande d'étude d'un nouveau binaire.            * -*                                                                             * -*  Retour      : -                                                            * -*                                                                             * -*  Remarques   : -                                                            * -*                                                                             * -******************************************************************************/ - -static void on_new_binary_clicked(GtkButton *button, GWelcomePanel *panel) -{ -    GObject *ref;                           /* Espace de référencements    */ -    GtkMenuItem *item;                      /* Elément de menu simulé      */ - -    ref = G_OBJECT(get_editor_window()); - -    item = GTK_MENU_ITEM(g_object_get_data(ref, "mnu_project_add_binary")); - -    g_object_unref(ref); - -    gtk_menu_item_activate(item); - -} - - -/****************************************************************************** -*                                                                             * -*  Paramètres  : manager = gestion de fichiers récemment utilisés.            * -*                panel   = panneau associé comportant des informations utiles.* -*                                                                             * -*  Description : Actualise au besoin la liste des projets récents.            * -*                                                                             * -*  Retour      : -                                                            * -*                                                                             * -*  Remarques   : -                                                            * -*                                                                             * -******************************************************************************/ - -static void on_recent_list_changed(GtkRecentManager *manager, GWelcomePanel *panel) -{ -    g_welcome_panel_reload_project_list(panel, manager); - -} - - -/****************************************************************************** -*                                                                             * -*  Paramètres  : panel   = panneau comportant des informations utiles.        * -*                manager = gestion de fichiers récemment utilisés.            * -*                                                                             * -*  Description : Recharge une liste à jour des projets récents.               * -*                                                                             * -*  Retour      : -                                                            * -*                                                                             * -*  Remarques   : -                                                            * -*                                                                             * -******************************************************************************/ - -static void g_welcome_panel_reload_project_list(GWelcomePanel *panel, GtkRecentManager *manager) -{ -    GtkBuilder *builder;                    /* Constructeur utilisé        */ -    GtkListStore *store;                    /* Modèle de gestion           */ -    bool empty;                             /* Liste vide ?                */ -    GList *recents;                         /* Liste des fichiers récents  */ -    GList *recent;                          /* Elément à traiter           */ -    GtkRecentInfo *info;                    /* Informations sur l'élément  */ -    GtkTreeIter iter;                       /* Point d'insertion           */ - -    /* Réinitialisation */ - -    builder = gtk_built_named_widget_get_builder(GTK_BUILT_NAMED_WIDGET(G_PANEL_ITEM(panel)->widget)); - -    store = GTK_LIST_STORE(gtk_builder_get_object(builder, "store")); - -    gtk_list_store_clear(store); - -    empty = true; - -    /* Chargement */ - -    recents = gtk_recent_manager_get_items(manager); - -    if (recents != NULL) -    { -        for (recent = g_list_first(recents); recent != NULL; recent = g_list_next(recent)) -        { -            info = recent->data; - -            if (strcmp(gtk_recent_info_get_mime_type(info), "application/chrysalide.project") == 0) -            { -                gtk_list_store_append(store, &iter); - -                gtk_list_store_set(store, &iter, -                                   RPC_VALID, true, -                                   RPC_FULLPATH, gtk_recent_info_get_uri_display(info), -                                   -1); - -                empty = false; - -            } - -            gtk_recent_info_unref(info); - -        } - -        g_list_free(recents); - -    } - -    /* Indication par défaut */ -    if (empty) -    { -        gtk_list_store_append(store, &iter); - -        gtk_list_store_set(store, &iter, -                           RPC_VALID, false, -                           RPC_FULLPATH, _("<i>(No recent project)</i>"), -                           -1); - -    } - -    g_object_unref(G_OBJECT(builder)); - -} - - -/****************************************************************************** -*                                                                             * -*  Paramètres  : treeview = liste graphique concernée par la procédure.       * -*                path     = chemin d'accès à la ligne sélectionnée.           * -*                column   = colonne concernée par la sélection.               * -*                panel    = panneau associé avec des informations utiles.     * -*                                                                             * -*  Description : Réagit à une sélection décidée d'un projet particulier.      * -*                                                                             * -*  Retour      : -                                                            * -*                                                                             * -*  Remarques   : -                                                            * -*                                                                             * -******************************************************************************/ - -static void on_row_activated_for_projects(GtkTreeView *treeview, GtkTreePath *path, GtkTreeViewColumn *column, GWelcomePanel *panel) -{ -    GtkTreeModel *model;                    /* Modèle de gestion           */ -    GtkTreeIter iter;                       /* Point de la consultation    */ -    gboolean valid;                         /* Validité de l'entrée        */ -    gchar *filename;                        /* Chemin d'accès au projet    */ -    GStudyProject *project;                 /* Nouveau projet à ouvrir     */ - -    model = gtk_tree_view_get_model(treeview); - -    if (gtk_tree_model_get_iter(model, &iter, path)) +    /** +     * Bascule vers une nouvelle fenêtre. +     */ +    else      { -        gtk_tree_model_get(model, &iter, RPC_VALID, &valid, RPC_FULLPATH, &filename, -1); +        new = get_framework_panel_parameters(row); +        assert(new != NULL); -        if (valid) +        if (new != panel->other_child)          { -            project = g_study_project_open(filename, true); - -            if (project != NULL) -            { -                set_current_project(project); - -                push_project_into_recent_list(project); - -            } - -            g_free(filename); - -        } - -    } - -} - - -/****************************************************************************** -*                                                                             * -*  Paramètres  : button = bouton de défilement des astuces activé;            * -*                panel  = panneau associé comportant des informations utiles. * -*                                                                             * -*  Description : Enregistre les conditions d'affichage du panneau d'accueil.  * -*                                                                             * -*  Retour      : -                                                            * -*                                                                             * -*  Remarques   : -                                                            * -*                                                                             * -******************************************************************************/ - -static void on_startup_toggled(GtkToggleButton *button, GWelcomePanel *panel) -{ -    g_generic_config_set_value(get_main_configuration(), -                               MPK_WELCOME_STARTUP, gtk_toggle_button_get_active(button)); - -} - - -/****************************************************************************** -*                                                                             * -*  Paramètres  : panel = panneau d'accueil à mettre à jour.                   * -*                                                                             * -*  Description : Consulte les versions existantes et affiche une conclusion.  * -*                                                                             * -*  Retour      : -                                                            * -*                                                                             * -*  Remarques   : -                                                            * -*                                                                             * -******************************************************************************/ - -static void g_welcome_panel_check_version(GWelcomePanel *panel) -{ -    bool skip;                              /* Saut de la vérification     */ -    bool unknown;                           /* Impossibilité de comparaison*/ -    int current;                            /* Version courante            */ -    int sock;                               /* Canal de communication      */ -    bool status;                            /* Bilan d'une communication   */ -    char buffer[1024];                      /* Tampon de réception         */ -    size_t got;                             /* Quantité de données reçues  */ -    char *version;                          /* Version récupérée           */ -    int available;                          /* Version disponible          */ -    GtkBuilder *builder;                    /* Constructeur utilisé        */ -    GtkLabel *label;                        /* Etiquette à éditer          */ -    char *msg;                              /* Message à faire paraître    */ - -    g_generic_config_get_value(get_main_configuration(), MPK_WELCOME_CHECK, &skip); -    skip = !skip; - -    unknown = true; - -    current = atoi(VERSION); - -    if (skip) goto check_process; - -    /* Recherche en ligne */ +            gtk_stack_add_child(panel->properties, new); +            gtk_stack_set_visible_child(panel->properties, new); -    sock = connect_via_tcp("www.chrysalide.re", "80", NULL); -    if (sock == -1) goto check_process; +            if (panel->other_child != NULL) +                gtk_stack_remove(panel->properties, panel->other_child); -#define REQUEST "GET /version.last HTTP/1.1\r\nHost: www.chrysalide.re\r\n\r\n" - -    status = safe_send(sock, REQUEST, strlen(REQUEST), 0); -    if (!status) goto check_done; - -    status = recv_all(sock, buffer, sizeof(buffer), &got); -    if (!status) goto check_done; - -    version = strstr(buffer, "\r\n\r\n"); - -    if (version != NULL) -    { -        available = atoi(version + 4); - -        unknown = false; - -    } - - check_done: - -    close(sock); - - check_process: - -    /* Affichage */ - -    builder = gtk_built_named_widget_get_builder(GTK_BUILT_NAMED_WIDGET(G_PANEL_ITEM(panel)->widget)); - -    label = GTK_LABEL(gtk_builder_get_object(builder, "version")); - -    if (skip) -        asprintf(&msg, -                 "Your version is: <b>%d</b>\n\n"               \ -                 "Automatic version check is disabled.", -                 current); - -    else -    { -        if (unknown) -            asprintf(&msg, -                     "Your version is: <b>%d</b>\n\n"           \ -                     "Lastest available version is unknown.", -                     current); - -        else -        { -            if (current >= available) -                asprintf(&msg, -                         "Your version is: <b>%d</b>\n\n"       \ -                         "Lastest version is: <b>%d</b>\n\n"    \ -                         "Your software is <span color='green'><b>up-to-date</b></span>.", -                         current, available); - -            else -                asprintf(&msg, -                         "Your version is: <b>%d</b>\n\n"       \ -                         "Lastest version is: <b>%d</b>\n\n"    \ -                         "Your software is <span color='red'><b>outdated</b></span>.", -                         current, available); +            panel->other_child = new;          }      } -    gtk_label_set_markup(label, msg); - -    free(msg); - -    g_object_unref(G_OBJECT(builder)); -  }  /******************************************************************************  *                                                                             * -*  Paramètres  : button = bouton de défilement des astuces activé;            * -*                panel  = panneau associé comportant des informations utiles. * +*  Paramètres  : button = bouton GTK concerné par l'appel.                    * +*                panel  = panneau d'accueil lié à la liste.                   *  *                                                                             * -*  Description : Affiche l'astuce précédente dans la liste globale.           * +*  Description : Réagit à une demande d'affichage de l'astuce précédente.     *  *                                                                             *  *  Retour      : -                                                            *  *                                                                             * @@ -872,24 +326,24 @@ static void g_welcome_panel_check_version(GWelcomePanel *panel)  *                                                                             *  ******************************************************************************/ -static void on_tip_previous_clicked(GtkButton *button, GWelcomePanel *panel) +static void gtk_welcome_panel_on_prev_hint_clicked(GtkButton *button, GtkWelcomePanel *panel)  { -    if (panel->current > 0) -        panel->current--; +    if (panel->cur_hint > 0) +        panel->cur_hint--;      else -        panel->current = panel->count - 1; +        panel->cur_hint = panel->raw_count - 1; -    g_welcome_panel_refresh_tip(panel); +    gtk_label_set_markup(panel->hints, panel->raw_hints[panel->cur_hint]);  }  /******************************************************************************  *                                                                             * -*  Paramètres  : button = bouton de défilement des astuces activé;            * -*                panel  = panneau associé comportant des informations utiles. * +*  Paramètres  : button = bouton GTK concerné par l'appel.                    * +*                panel  = panneau d'accueil lié à la liste.                   *  *                                                                             * -*  Description : Affiche l'astuce suivante dans la liste globale.             * +*  Description : Réagit à une demande d'affichage de l'astuce suivante.       *  *                                                                             *  *  Retour      : -                                                            *  *                                                                             * @@ -897,82 +351,27 @@ static void on_tip_previous_clicked(GtkButton *button, GWelcomePanel *panel)  *                                                                             *  ******************************************************************************/ -static void on_tip_next_clicked(GtkButton *button, GWelcomePanel *panel) +static void gtk_welcome_panel_on_next_hint_clicked(GtkButton *button, GtkWelcomePanel *panel)  { -    if ((panel->current + 1) < panel->count) -        panel->current++; +    if ((panel->cur_hint + 1) < panel->raw_count) +        panel->cur_hint++;      else -        panel->current = 0; +        panel->cur_hint = 0; -    g_welcome_panel_refresh_tip(panel); +    gtk_label_set_markup(panel->hints, panel->raw_hints[panel->cur_hint]);  } -/****************************************************************************** -*                                                                             * -*  Paramètres  : panel = panneau associé comportant des informations utiles.  * -*                                                                             * -*  Description : Actualise l'affichage des astuces.                           * -*                                                                             * -*  Retour      : -                                                            * -*                                                                             * -*  Remarques   : -                                                            * -*                                                                             * -******************************************************************************/ -static void g_welcome_panel_refresh_tip(GWelcomePanel *panel) -{ -    GtkBuilder *builder;                    /* Constructeur utilisé        */ -    GtkLabel *label;                        /* Etiquette de présentation   */ +/* ---------------------------------------------------------------------------------- */ +/*                       IMPLEMENTATION DES FONCTIONS DE CLASSE                       */ +/* ---------------------------------------------------------------------------------- */ -    assert(panel->current < panel->count); -    builder = gtk_built_named_widget_get_builder(GTK_BUILT_NAMED_WIDGET(G_PANEL_ITEM(panel)->widget)); -    label = GTK_LABEL(gtk_builder_get_object(builder, "tip")); -    gtk_label_set_markup(label, panel->tips[panel->current]); -    g_object_unref(G_OBJECT(builder)); -} -/****************************************************************************** -*                                                                             * -*  Paramètres  : panel = panneau associé comportant des informations utiles.  * -*                                                                             * -*  Description : Indique l'origine de l'affichage du panneau d'accueil.       * -*                                                                             * -*  Retour      : true si l'affichage est le fait de l'utilisateur.            * -*                                                                             * -*  Remarques   : -                                                            * -*                                                                             * -******************************************************************************/ - -bool g_welcome_panel_get_user_origin(const GWelcomePanel *panel) -{ -    return panel->uorigin; - -} - - -/****************************************************************************** -*                                                                             * -*  Paramètres  : panel   = panneau associé comportant des informations utiles.* -*                uorigin = true si l'affichage est le fait de l'utilisateur.  * -*                                                                             * -*  Description : Détermine l'origine de l'affichage du panneau d'accueil.     * -*                                                                             * -*  Retour      : -                                                            * -*                                                                             * -*  Remarques   : -                                                            * -*                                                                             * -******************************************************************************/ - -void g_welcome_panel_set_user_origin(GWelcomePanel *panel, bool uorigin) -{ -    panel->uorigin = uorigin; - -} diff --git a/src/gui/panels/welcome.h b/src/gui/panels/welcome.h index 5cdd6a1..d9ea18d 100644 --- a/src/gui/panels/welcome.h +++ b/src/gui/panels/welcome.h @@ -2,7 +2,7 @@  /* Chrysalide - Outil d'analyse de fichiers binaires   * welcome.h - prototypes pour le panneau d'accueil par défaut   * - * Copyright (C) 2012-2019 Cyrille Bagard + * Copyright (C) 2012-2024 Cyrille Bagard   *   *  This file is part of Chrysalide.   * @@ -26,42 +26,17 @@  #define _GUI_PANELS_WELCOME_H -#include <i18n.h> +#include <gtk/gtk.h> -#include "../panel.h" +#include "../../glibext/helpers.h" +#include "../../gtkext/panel.h" -#define PANEL_WELCOME_ID "welcome" +#define GTK_TYPE_WELCOME_PANEL (gtk_welcome_panel_get_type()) - -#define G_TYPE_WELCOME_PANEL               g_welcome_panel_get_type() -#define G_WELCOME_PANEL(obj)               (G_TYPE_CHECK_INSTANCE_CAST((obj), g_welcome_panel_get_type(), GWelcomePanel)) -#define G_IS_WELCOME_PANEL(obj)            (G_TYPE_CHECK_INSTANCE_TYPE((obj), g_welcome_panel_get_type())) -#define G_WELCOME_PANEL_CLASS(klass)       (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_WELCOME_PANEL, GWelcomePanelClass)) -#define G_IS_WELCOME_PANEL_CLASS(klass)    (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_WELCOME_PANEL)) -#define G_WELCOME_PANEL_GET_CLASS(obj)     (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_WELCOME_PANEL, GWelcomePanelClass)) - - -/* Panneau d'accueil par défaut (instance) */ -typedef struct _GWelcomePanel GWelcomePanel; - -/* Panneau d'accueil par défaut (classe) */ -typedef struct _GWelcomePanelClass GWelcomePanelClass; - - -/* Indique le type défini pour un panneau d'accueil. */ -GType g_welcome_panel_get_type(void); - -/* Crée un panneau d'accueil par défaut. */ -GPanelItem *g_welcome_panel_new(void); - -/* Indique l'origine de l'affichage du panneau d'accueil. */ -bool g_welcome_panel_get_user_origin(const GWelcomePanel *); - -/* Détermine l'origine de l'affichage du panneau d'accueil. */ -void g_welcome_panel_set_user_origin(GWelcomePanel *, bool); +DECLARE_GTYPE(GtkWelcomePanel, gtk_welcome_panel, GTK, WELCOME_PANEL); diff --git a/src/gui/panels/welcome.ui b/src/gui/panels/welcome.ui index d016907..c545b1d 100644 --- a/src/gui/panels/welcome.ui +++ b/src/gui/panels/welcome.ui @@ -1,245 +1,168 @@  <?xml version="1.0" encoding="UTF-8"?> -<!-- Generated with glade 3.18.3 -->  <interface> -  <requires lib="gtk+" version="3.12"/> -  <object class="GtkImage" id="image1"> -    <property name="visible">True</property> -    <property name="can_focus">False</property> -    <property name="stock">gtk-new</property> -    <property name="icon_size">6</property> -  </object> -  <object class="GtkListStore" id="store"> -    <columns> -      <!-- column-name valid --> -      <column type="gboolean"/> -      <!-- column-name fullpath --> -      <column type="gchararray"/> -    </columns> -  </object> -  <object class="GtkOffscreenWindow" id="offscreenwindow1"> -    <property name="can_focus">False</property> -    <child> -      <object class="GtkBox" id="box"> -        <property name="visible">True</property> -        <property name="can_focus">False</property> -        <property name="homogeneous">True</property> -        <child> -          <object class="GtkBox" id="box2"> -            <property name="visible">True</property> -            <property name="can_focus">False</property> -            <property name="margin_left">8</property> -            <property name="margin_right">8</property> -            <property name="margin_top">8</property> -            <property name="margin_bottom">8</property> -            <property name="orientation">vertical</property> -            <property name="spacing">8</property> -            <child> -              <object class="GtkAlignment" id="alignment1"> -                <property name="visible">True</property> -                <property name="can_focus">False</property> -                <property name="halign">center</property> -                <property name="top_padding">180</property> -                <property name="bottom_padding">30</property> -                <child> -                  <object class="GtkButton" id="button1"> -                    <property name="label" translatable="yes">New binary...</property> -                    <property name="visible">True</property> -                    <property name="can_focus">True</property> -                    <property name="receives_default">True</property> -                    <property name="image">image1</property> -                    <property name="image_position">top</property> -                    <property name="always_show_image">True</property> -                    <signal name="clicked" handler="on_new_binary_clicked" swapped="no"/> -                  </object> -                </child> -              </object> -              <packing> -                <property name="expand">False</property> -                <property name="fill">True</property> -                <property name="position">0</property> -              </packing> -            </child> -            <child> -              <object class="GtkLabel" id="label1"> -                <property name="visible">True</property> -                <property name="can_focus">False</property> -                <property name="xalign">0</property> -                <property name="label" translatable="yes">Last projects:</property> -              </object> -              <packing> -                <property name="expand">False</property> -                <property name="fill">True</property> -                <property name="position">1</property> -              </packing> -            </child> -            <child> -              <object class="GtkTreeView" id="treeview"> -                <property name="height_request">250</property> -                <property name="visible">True</property> -                <property name="can_focus">True</property> -                <property name="margin_left">8</property> -                <property name="hexpand">True</property> -                <property name="model">store</property> -                <property name="headers_visible">False</property> -                <property name="rules_hint">True</property> -                <signal name="row-activated" handler="on_row_activated_for_projects" swapped="no"/> -                <child internal-child="selection"> -                  <object class="GtkTreeSelection" id="treeview-selection1"/> -                </child> -              </object> -              <packing> -                <property name="expand">False</property> -                <property name="fill">True</property> -                <property name="position">2</property> -              </packing> -            </child> -            <child> -              <object class="GtkCheckButton" id="startup"> -                <property name="label" translatable="yes">Show this panel at startup.</property> -                <property name="visible">True</property> -                <property name="can_focus">True</property> -                <property name="receives_default">False</property> -                <property name="halign">start</property> -                <property name="valign">end</property> -                <property name="vexpand">True</property> -                <property name="xalign">0</property> -                <property name="draw_indicator">True</property> -                <signal name="toggled" handler="on_startup_toggled" swapped="no"/> -              </object> -              <packing> -                <property name="expand">False</property> -                <property name="fill">True</property> -                <property name="position">3</property> -              </packing> -            </child> -          </object> -          <packing> -            <property name="expand">False</property> -            <property name="fill">True</property> -            <property name="position">0</property> -          </packing> -        </child> + +    <template class="GtkWelcomePanel" parent="GtkTiledPanel">          <child> -          <object class="GtkBox" id="box3"> -            <property name="visible">True</property> -            <property name="can_focus">False</property> -            <property name="margin_left">8</property> -            <property name="margin_right">8</property> -            <property name="margin_top">8</property> -            <property name="margin_bottom">8</property> -            <property name="orientation">vertical</property> -            <property name="spacing">8</property> -            <child> -              <object class="GtkBox" id="box4"> -                <property name="visible">True</property> -                <property name="can_focus">False</property> -                <property name="homogeneous">True</property> +            <object class="GtkScrolledWindow"> +                <property name="hscrollbar-policy">automatic</property> +                <property name="vscrollbar-policy">automatic</property> +                <property name="hexpand">TRUE</property> +                <property name="vexpand">TRUE</property> +                <property name="has-frame">0</property>                  <child> -                  <object class="GtkLabel" id="version"> -                    <property name="visible">True</property> -                    <property name="can_focus">False</property> -                    <property name="opacity">0.81999999977648264</property> -                    <property name="use_markup">True</property> -                  </object> -                  <packing> -                    <property name="expand">False</property> -                    <property name="fill">True</property> -                    <property name="position">0</property> -                  </packing> -                </child> -                <child> -                  <object class="GtkLabel" id="label3"> -                    <property name="visible">True</property> -                    <property name="can_focus">False</property> -                    <property name="opacity">0.81999999999999995</property> -                    <property name="label" translatable="yes">Get access to the online documentation and stay tuned by visiting the official website : <a href="http://chrysalide.re">chrysalide.re</a> - -You can also follow Chrysalide on Twitter : <a href="http://twitter.com/chrysalide_ref">@chrysalide_ref</a></property> -                    <property name="use_markup">True</property> -                    <property name="wrap">True</property> -                    <property name="track_visited_links">False</property> -                  </object> -                  <packing> -                    <property name="expand">False</property> -                    <property name="fill">True</property> -                    <property name="position">1</property> -                  </packing> -                </child> -              </object> -              <packing> -                <property name="expand">False</property> -                <property name="fill">True</property> -                <property name="position">0</property> -              </packing> -            </child> -            <child> -              <object class="GtkLabel" id="tip"> -                <property name="visible">True</property> -                <property name="can_focus">False</property> -                <property name="xalign">0</property> -                <property name="yalign">1</property> -                <property name="xpad">8</property> -                <property name="ypad">8</property> -                <property name="label" translatable="yes">label</property> -                <property name="wrap">True</property> -                <property name="selectable">True</property> -                <signal name="draw" handler="on_tip_background_draw" swapped="no"/> -              </object> -              <packing> -                <property name="expand">True</property> -                <property name="fill">True</property> -                <property name="position">1</property> -              </packing> -            </child> -            <child> -              <object class="GtkButtonBox" id="buttonbox1"> -                <property name="visible">True</property> -                <property name="can_focus">False</property> -                <property name="spacing">8</property> -                <property name="layout_style">end</property> -                <child> -                  <object class="GtkButton" id="button3"> -                    <property name="label" translatable="yes">Previous</property> -                    <property name="visible">True</property> -                    <property name="can_focus">True</property> -                    <property name="receives_default">True</property> -                    <signal name="clicked" handler="on_tip_previous_clicked" swapped="no"/> -                  </object> -                  <packing> -                    <property name="expand">True</property> -                    <property name="fill">True</property> -                    <property name="position">0</property> -                  </packing> -                </child> -                <child> -                  <object class="GtkButton" id="button2"> -                    <property name="label" translatable="yes">Next</property> -                    <property name="visible">True</property> -                    <property name="can_focus">True</property> -                    <property name="receives_default">True</property> -                    <signal name="clicked" handler="on_tip_next_clicked" swapped="no"/> -                  </object> -                  <packing> -                    <property name="expand">True</property> -                    <property name="fill">True</property> -                    <property name="position">1</property> -                  </packing> +                    <object class="GtkGrid"> +                        <property name="halign">center</property> +                        <property name="valign">center</property> +                        <property name="column-spacing">64</property> +                        <property name="column-homogeneous">TRUE</property> +                        <property name="margin-bottom">32</property> +                        <property name="margin-end">32</property> +                        <property name="margin-start">32</property> +                        <property name="margin-top">32</property> + +                        <!-- Launcher list --> +                        <child> +                            <object class="GtkListBox" id="list"> +                                <property name="halign">end</property> +                                <property name="valign">center</property> +                                <property name="selection-mode">GTK_SELECTION_SINGLE</property> +                                <property name="activate-on-single-click">0</property> + +                                <layout> +                                    <property name="column">0</property> +                                    <property name="row">0</property> +                                </layout> + +                                <style> +                                    <class name="boxed-list"/> +                                    <class name="frame"/> +                                </style> + +                                <signal name="selected-rows-changed" handler="gtk_welcome_panel_on_selected_rows_changed"/> + +                            </object> +                        </child> + +                        <!-- Hints / options --> +                        <child> +                            <object class="GtkStack" id="properties"> +                                <property name="halign">start</property> +                                <property name="valign">fill</property> + +                                <layout> +                                    <property name="column">1</property> +                                    <property name="row">0</property> +                                </layout> + +                                <child> + +                                    <object class="GtkStackPage"> +                                        <property name="name">default</property> +                                        <property name="title">Welcome</property> + +                                        <property name="child"> +                                            <object class="GtkGrid" id="def_child"> +                                                <property name="halign">start</property> +                                                <property name="valign">fill</property> +                                                <property name="column-spacing">16</property> +                                                <property name="column-homogeneous">FALSE</property> + +                                                <!-- Text --> + +                                                <child> +                                                    <object class="GtkLabel" id="hints"> +                                                        <property name="halign">start</property> +                                                        <property name="valign">fill</property> +                                                        <property name="xalign">0</property> +                                                        <property name="yalign">1</property> +                                                        <property name="vexpand">1</property> +                                                        <property name="width-request">50</property> +                                                        <property name="wrap">TRUE</property> + +                                                        <property name="layout-manager"> +                                                            <object class="GtkConstraintLayout"> +                                                                <!-- +                                                                <constraints> + +                                                                    <constraint target="super" target-attribute="left" +                                                                                relation="eq" +                                                                                constant="0" +                                                                                strength="required"/> + +                                                                    <constraint target="super" target-attribute="top" +                                                                                relation="eq" +                                                                                constant="0" +                                                                                strength="required"/> + +                                                                    <constraint target="super" target-attribute="right" +                                                                                relation="eq" +                                                                                constant="340" +                                                                                strength="required"/> + +                                                                </constraints> +                                                                --> +                                                            </object> +                                                        </property> + +                                                        <layout> +                                                            <property name="column">0</property> +                                                            <property name="row">0</property> +                                                        </layout> + +                                                    </object> +                                                </child> + +                                                <!-- Prev/Next buttons --> +                                                <child> +                                                    <object class="GtkBox"> +                                                        <property name="orientation">GTK_ORIENTATION_HORIZONTAL</property> +                                                        <property name="halign">fill</property> +                                                        <property name="valign">center</property> +                                                        <property name="homogeneous">TRUE</property> +                                                        <layout> +                                                            <property name="column">1</property> +                                                            <property name="row">1</property> +                                                        </layout> + +                                                        <child> +                                                            <object class="GtkButton"> +                                                                <property name="icon-name">go-previous-symbolic</property> +                                                                <property name="halign">end</property> +                                                                <signal name="clicked" handler="gtk_welcome_panel_on_prev_hint_clicked"/> +                                                            </object> +                                                        </child> + +                                                        <child> +                                                            <object class="GtkButton"> +                                                                <property name="icon-name">go-next-symbolic</property> +                                                                <property name="halign">start</property> +                                                                <signal name="clicked" handler="gtk_welcome_panel_on_next_hint_clicked"/> +                                                            </object> +                                                        </child> + +                                                        <style> +                                                            <class name="linked"/> +                                                        </style> + +                                                    </object> +                                                </child> + +                                                <style> +                                                    <class name="hints"/> +                                                </style> + +                                            </object> + +                                        </property> +                                    </object> +                                </child> + +                            </object> +                        </child> +                    </object>                  </child> -              </object> -              <packing> -                <property name="expand">False</property> -                <property name="fill">True</property> -                <property name="position">2</property> -              </packing> -            </child> -          </object> -          <packing> -            <property name="expand">False</property> -            <property name="fill">True</property> -            <property name="position">1</property> -          </packing> +            </object>          </child> -      </object> -    </child> -  </object> +    </template> +  </interface> diff --git a/src/gui/style.css b/src/gui/style.css new file mode 100644 index 0000000..dce41fa --- /dev/null +++ b/src/gui/style.css @@ -0,0 +1,71 @@ + +/* Extension de style */ + +.dim-label { + +    margin-bottom: 4px; + +} + + +.boxed-widget { + +    border-top-left-radius: 12px; +    border-top-right-radius: 12px; + +    border-bottom-left-radius: 12px; +    border-bottom-right-radius: 12px; + +} + + +list.boxed-list, list.boxed-list > row:first-child { + +    border-top-left-radius: 12px; +    border-top-right-radius: 12px; + +} + +list.boxed-list, list.boxed-list > row:last-child { + +    border-bottom-left-radius: 12px; +    border-bottom-right-radius: 12px; + +} + + +/* about.css */ + +@import url('resource:///re/chrysalide/framework/gui/dialogs/about.css'); + + +/* welcome.css */ + +grid.hints { + +    background-image: -gtk-icontheme('tipoftheday-symbolic'); +    background-position: right top; +    background-size: 200px auto; +    background-repeat: no-repeat; + +    min-height: 250px; + +} + +grid.hints > box { + +    min-width: 130px; + +} + + +/* dockstation.css */ + +.control-button { + +    min-height: 0; +    min-width: 0; + +    padding: 6px; + +} diff --git a/src/gui/window-int.h b/src/gui/window-int.h new file mode 100644 index 0000000..4f3dd57 --- /dev/null +++ b/src/gui/window-int.h @@ -0,0 +1,60 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * window.h - prototypes internes pour la construction d'une fenêtre graphique principale + * + * Copyright (C) 2024 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 _GUI_WINDOW_INT_H +#define _GUI_WINDOW_INT_H + + +#include "window.h" +#include "../gtkext/grid.h" + + + +/* Définition de l'application principale graphique (instance) */ +struct _GtkFrameworkWindow +{ +    GtkApplicationWindow parent;            /* A laisser en premier        */ + +    GSettings *settings;                    /* Paramètres globaux          */ + +    GtkTilingGrid *grid;                    /* Réceptacle de panneaux      */ +    GtkStatusStack *status;                 /* Barre de statut             */ + +    GtkTiledPanel *main;                    /* Panneau principal courant   */ + +}; + +/* Définition de l'application principale graphique (classe) */ +struct _GtkFrameworkWindowClass +{ +    GtkApplicationWindowClass parent;       /* A laisser en premier        */ + +}; + + +/* Met en place une fenêtre principale pour Chrysalide. */ +bool gtk_framework_window_create(GtkFrameworkWindow *, GtkApplication *); + + + +#endif  /* _GUI_WINDOW_INT_H */ diff --git a/src/gui/window.c b/src/gui/window.c new file mode 100644 index 0000000..e14ecf7 --- /dev/null +++ b/src/gui/window.c @@ -0,0 +1,621 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * window.c - construction d'une fenêtre graphique principale + * + * Copyright (C) 2024 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 this program; if not, write to the Free Software + *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA + */ + + +#include "window.h" + + +#include "window-int.h" +#include "core/panels.h" +#include "dialogs/about.h" +#include "dialogs/preferences.h" +#include "panels/logs.h" +#include "panels/welcome.h" +#include "../gtkext/grid.h" +#include "../gtkext/helpers.h" + + + +/* Initialise la classe des applications majeures de Chrysalide. */ +static void gtk_framework_window_class_init(GtkFrameworkWindowClass *); + +/* Initialise une application principale pour Chrysalide. */ +static void gtk_framework_window_init(GtkFrameworkWindow *); + +/* Supprime toutes les références externes. */ +static void gtk_framework_window_dispose(GObject *); + +/* Procède à la libération totale de la mémoire. */ +static void gtk_framework_window_finalize(GObject *); + +/* Bascule l'affichage d'un panneau de bordure. */ +static void gtk_framework_window_toggle_pannel_visibility(GtkFrameworkWindow *, TilingGridBorder); + +/* Réagit à une activation de bascule du panneau supérieur. */ +static void gtk_framework_window_activate_toggle_top(GSimpleAction *, GVariant *, gpointer); + +/* Réagit à une activation de bascule du panneau de gauche. */ +static void gtk_framework_window_activate_toggle_left(GSimpleAction *action, GVariant *, gpointer); + +/* Réagit à une activation de bascule du panneau de droite. */ +static void gtk_framework_window_activate_toggle_right(GSimpleAction *, GVariant *, gpointer); + +/* Réagit à une activation de bascule du panneau inférieur. */ +static void gtk_framework_window_activate_toggle_bottom(GSimpleAction *, GVariant *, gpointer); + +/* Réagit à une activation du menu "Préférences" de la fenetre. */ +static void gtk_framework_window_activate_preferences(GSimpleAction *, GVariant *, gpointer); + +/* Réagit à une activation du menu "A propos de" de la fenetre. */ +static void gtk_framework_window_activate_about(GSimpleAction *, GVariant *, gpointer); + + + +/* Indique le type défini pour une fenêtre graphique principale de Chrysalide. */ +G_DEFINE_TYPE(GtkFrameworkWindow, gtk_framework_window, GTK_TYPE_APPLICATION_WINDOW); + + +/****************************************************************************** +*                                                                             * +*  Paramètres  : class = classe à initialiser.                                * +*                                                                             * +*  Description : Initialise la classe des applications majeures de Chrysalide.* +*                                                                             * +*  Retour      : -                                                            * +*                                                                             * +*  Remarques   : -                                                            * +*                                                                             * +******************************************************************************/ + +static void gtk_framework_window_class_init(GtkFrameworkWindowClass *class) +{ +    GObjectClass *object;                   /* Plus haut niveau équivalent */ +    GtkWidgetClass *widget;                 /* Classe de haut niveau       */ + +    object = G_OBJECT_CLASS(class); + +    object->dispose = (GObjectFinalizeFunc/* ! */)gtk_framework_window_dispose; +    object->finalize = (GObjectFinalizeFunc)gtk_framework_window_finalize; + +    widget = GTK_WIDGET_CLASS(class); + +    g_type_ensure(GTK_TYPE_TILING_GRID); +    g_type_ensure(GTK_TYPE_STATUS_STACK); + +    gtk_widget_class_set_template_from_resource(widget, "/re/chrysalide/framework/gui/window.ui"); + +    gtk_widget_class_bind_template_child(widget, GtkFrameworkWindow, grid); +    gtk_widget_class_bind_template_child(widget, GtkFrameworkWindow, status); + +    /* Active une action native (cf. https://docs.gtk.org/gtk4/class.Window.html#actions) */ +    gtk_widget_class_add_binding_action(widget, GDK_KEY_Q, GDK_CONTROL_MASK, "window.close", NULL); + +    gtk_widget_class_add_binding_action(widget, GDK_KEY_comma, GDK_CONTROL_MASK, "win.preferences", NULL); + +} + + +/****************************************************************************** +*                                                                             * +*  Paramètres  : window = instance à initialiser.                             * +*                                                                             * +*  Description : Initialise une application principale pour Chrysalide.       * +*                                                                             * +*  Retour      : -                                                            * +*                                                                             * +*  Remarques   : -                                                            * +*                                                                             * +******************************************************************************/ + +static void gtk_framework_window_init(GtkFrameworkWindow *window) +{ +    GAction *action;                        /* Action mise en place        */ + +    static GActionEntry app_entries[] = { +        { "toggle-top", gtk_framework_window_activate_toggle_top, NULL, NULL, NULL }, +        { "toggle-left", gtk_framework_window_activate_toggle_left, NULL, NULL, NULL }, +        { "toggle-right", gtk_framework_window_activate_toggle_right, NULL, NULL, NULL }, +        { "toggle-bottom", gtk_framework_window_activate_toggle_bottom, NULL, NULL, NULL }, +        { "preferences", gtk_framework_window_activate_preferences, NULL, NULL, NULL }, +        { "about", gtk_framework_window_activate_about, NULL, NULL, NULL }, +    }; + +    gtk_widget_init_template(GTK_WIDGET(window)); + +    window->settings = g_settings_new(FRAMEWORK_WINDOW_ID); + +    g_settings_bind(window->settings, "window-width", G_OBJECT(window), "default-width", G_SETTINGS_BIND_DEFAULT); +    g_settings_bind(window->settings, "window-height", G_OBJECT(window), "default-height", G_SETTINGS_BIND_DEFAULT); +    g_settings_bind(window->settings, "window-maximized", G_OBJECT(window), "maximized", G_SETTINGS_BIND_DEFAULT); + +    window->main = NULL; + +    g_action_map_add_action_entries(G_ACTION_MAP(window), +                                    app_entries, G_N_ELEMENTS(app_entries), +                                    window); + +    /** +     * Définition de l'accès aux actions pour obtenir un effet de bord sur +     * l'accès aux boutons graphiques de déclenchement. +     */ + +    action = g_action_map_lookup_action(G_ACTION_MAP(window), "toggle-top"); + +    g_object_bind_property(G_OBJECT(window->grid), "empty-top", +                           G_OBJECT(action), "enabled", +                           G_BINDING_SYNC_CREATE | G_BINDING_INVERT_BOOLEAN); + +    action = g_action_map_lookup_action(G_ACTION_MAP(window), "toggle-left"); + +    g_object_bind_property(G_OBJECT(window->grid), "empty-left", +                           G_OBJECT(action), "enabled", +                           G_BINDING_SYNC_CREATE | G_BINDING_INVERT_BOOLEAN); + +    action = g_action_map_lookup_action(G_ACTION_MAP(window), "toggle-right"); + +    g_object_bind_property(G_OBJECT(window->grid), "empty-right", +                           G_OBJECT(action), "enabled", +                           G_BINDING_SYNC_CREATE | G_BINDING_INVERT_BOOLEAN); + +    action = g_action_map_lookup_action(G_ACTION_MAP(window), "toggle-bottom"); + +    g_object_bind_property(G_OBJECT(window->grid), "empty-bottom", +                           G_OBJECT(action), "enabled", +                           G_BINDING_SYNC_CREATE | G_BINDING_INVERT_BOOLEAN); + +} + + +/****************************************************************************** +*                                                                             * +*  Paramètres  : object = instance d'objet GLib à traiter.                    * +*                                                                             * +*  Description : Supprime toutes les références externes.                     * +*                                                                             * +*  Retour      : -                                                            * +*                                                                             * +*  Remarques   : -                                                            * +*                                                                             * +******************************************************************************/ + +static void gtk_framework_window_dispose(GObject *object) +{ +    GtkFrameworkWindow *window;             /* Version spécialisée         */ + +    window = GTK_FRAMEWORK_WINDOW(object); + +    gtk_widget_dispose_template(GTK_WIDGET(window), GTK_TYPE_FRAMEWORK_WINDOW); + +    g_clear_object(&window->settings); + +    g_clear_object(&window->main); + +    G_OBJECT_CLASS(gtk_framework_window_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 gtk_framework_window_finalize(GObject *object) +{ +    G_OBJECT_CLASS(gtk_framework_window_parent_class)->finalize(object); + +} + + +/****************************************************************************** +*                                                                             * +*  Paramètres  : app = application GTK de rattachement.                       * +*                                                                             * +*  Description : Crée une nouvelle application principale pour Chrysalide.    * +*                                                                             * +*  Retour      : Mécanismes mis en place.                                     * +*                                                                             * +*  Remarques   : -                                                            * +*                                                                             * +******************************************************************************/ + +GtkApplicationWindow *gtk_framework_window_new(GtkApplication *app) +{ +    GtkApplicationWindow *result;           /* Instance à retourner        */ + +    result = g_object_new(GTK_TYPE_FRAMEWORK_WINDOW, NULL); + +    if (!gtk_framework_window_create(GTK_FRAMEWORK_WINDOW(result), app)) +        g_clear_object(&result); + +    return result; + +} + + +/****************************************************************************** +*                                                                             * +*  Paramètres  : window = instance de fenêtre principale à remplir.           * +*                app    = application GTK de rattachement.                    * +*                                                                             * +*  Description : Met en place une fenêtre principale pour Chrysalide.         * +*                                                                             * +*  Retour      : Bilan de l'opération.                                        * +*                                                                             * +*  Remarques   : -                                                            * +*                                                                             * +******************************************************************************/ + +bool gtk_framework_window_create(GtkFrameworkWindow *window, GtkApplication *app) +{ +    bool result;                            /* Bilan à retourner           */ +    GtkTiledPanel *panel;                   /* Panneau d'affichage         */ +    GtkCssProvider *css;                    /* Feuille de style maison     */ + +    result = true; + +    gtk_window_set_application(GTK_WINDOW(window), app); + +    /* Inclusion d'un écran d'accueil */ + +    panel = get_framework_panel_singleton(GTK_TYPE_WELCOME_PANEL); + +    gtk_framework_window_add(window, panel); + +    if (1/* FIXME : first time */) +    { +        panel = get_framework_panel_singleton(GTK_TYPE_LOGS_PANEL); + +        gtk_framework_window_add(window, panel); + +    } + +    /* Chargement des extensions de thème */ + +    css = gtk_css_provider_new(); + +    gtk_css_provider_load_from_resource(css, "/re/chrysalide/framework/gtkext/hexview.css"); + +    gtk_style_context_add_provider_for_display(gtk_widget_get_display(GTK_WIDGET(window)), +                                               GTK_STYLE_PROVIDER(css), GTK_STYLE_PROVIDER_PRIORITY_APPLICATION); + +    unref_object(css); + +    css = gtk_css_provider_new(); + +    gtk_css_provider_load_from_resource(css, "/re/chrysalide/framework/gui/style.css"); + +    gtk_style_context_add_provider_for_display(gtk_widget_get_display(GTK_WIDGET(window)), +                                               GTK_STYLE_PROVIDER(css), GTK_STYLE_PROVIDER_PRIORITY_APPLICATION); + +    unref_object(css); + +    /* Fin des chargements */ + +    return result; + +} + + +/****************************************************************************** +*                                                                             * +*  Paramètres  : window = instance de fenêtre principale à manipuler.         * +*                border = sélection de la zone à considérer.                  * +*                                                                             * +*  Description : Bascule l'affichage d'un panneau de bordure.                 * +*                                                                             * +*  Retour      : -                                                            * +*                                                                             * +*  Remarques   : -                                                            * +*                                                                             * +******************************************************************************/ + +static void gtk_framework_window_toggle_pannel_visibility(GtkFrameworkWindow *window, TilingGridBorder border) +{ +    bool state;                             /* Etat courant à basculer     */ + +    state = gtk_tiling_grid_get_visible(window->grid, border); + +    state = !state; + +    gtk_tiling_grid_set_visible(window->grid, border, state); + +} + + +/****************************************************************************** +*                                                                             * +*  Paramètres  : action  = désignation de l'action concernée par l'appel.     * +*                unused  = adresse non utilisée ici.                          * +*                _window = instance de fenêtre principale à manipuler.        * +*                                                                             * +*  Description : Réagit à une activation de bascule du panneau supérieur.     * +*                                                                             * +*  Retour      : -                                                            * +*                                                                             * +*  Remarques   : -                                                            * +*                                                                             * +******************************************************************************/ + +static void gtk_framework_window_activate_toggle_top(GSimpleAction *action, GVariant *unused, gpointer _window) +{ +    gtk_framework_window_toggle_pannel_visibility(_window, TGB_TOP); + +} + + +/****************************************************************************** +*                                                                             * +*  Paramètres  : action  = désignation de l'action concernée par l'appel.     * +*                unused  = adresse non utilisée ici.                          * +*                _window = instance de fenêtre principale à manipuler.        * +*                                                                             * +*  Description : Réagit à une activation de bascule du panneau de gauche.     * +*                                                                             * +*  Retour      : -                                                            * +*                                                                             * +*  Remarques   : -                                                            * +*                                                                             * +******************************************************************************/ + +static void gtk_framework_window_activate_toggle_left(GSimpleAction *action, GVariant *unused, gpointer _window) +{ +    gtk_framework_window_toggle_pannel_visibility(_window, TGB_LEFT); + +} + + +/****************************************************************************** +*                                                                             * +*  Paramètres  : action  = désignation de l'action concernée par l'appel.     * +*                unused  = adresse non utilisée ici.                          * +*                _window = instance de fenêtre principale à manipuler.        * +*                                                                             * +*  Description : Réagit à une activation de bascule du panneau de droite.     * +*                                                                             * +*  Retour      : -                                                            * +*                                                                             * +*  Remarques   : -                                                            * +*                                                                             * +******************************************************************************/ + +static void gtk_framework_window_activate_toggle_right(GSimpleAction *action, GVariant *unused, gpointer _window) +{ +    gtk_framework_window_toggle_pannel_visibility(_window, TGB_RIGHT); + +} + + +/****************************************************************************** +*                                                                             * +*  Paramètres  : action  = désignation de l'action concernée par l'appel.     * +*                unused  = adresse non utilisée ici.                          * +*                _window = instance de fenêtre principale à manipuler.        * +*                                                                             * +*  Description : Réagit à une activation de bascule du panneau inférieur.     * +*                                                                             * +*  Retour      : -                                                            * +*                                                                             * +*  Remarques   : -                                                            * +*                                                                             * +******************************************************************************/ + +static void gtk_framework_window_activate_toggle_bottom(GSimpleAction *action, GVariant *unused, gpointer _window) +{ +    gtk_framework_window_toggle_pannel_visibility(_window, TGB_BOTTOM); + +} + + +/****************************************************************************** +*                                                                             * +*  Paramètres  : action  = désignation de l'action concernée par l'appel.     * +*                unused  = adresse non utilisée ici.                          * +*                _window = instance de fenêtre principale à manipuler.        * +*                                                                             * +*  Description : Réagit à une activation du menu "Préférences" de la fenetre. * +*                                                                             * +*  Retour      : -                                                            * +*                                                                             * +*  Remarques   : -                                                            * +*                                                                             * +******************************************************************************/ + +static void gtk_framework_window_activate_preferences(GSimpleAction *action, GVariant *unused, gpointer _window) +{ +    GtkFrameworkWindow *window;             /* Fenêtre principale associée */ +    GtkWindow *dialog;                      /* Boîte de dialogue à afficher*/ + +    window = _window; + +    dialog = gtk_preferences_dialog_new(GTK_WINDOW(window)); + +    gtk_window_present(dialog); + +} + + +/****************************************************************************** +*                                                                             * +*  Paramètres  : action  = désignation de l'action concernée par l'appel.     * +*                unused  = adresse non utilisée ici.                          * +*                _window = instance de fenêtre principale à manipuler.        * +*                                                                             * +*  Description : Réagit à une activation du menu "A propos de" de la fenetre. * +*                                                                             * +*  Retour      : -                                                            * +*                                                                             * +*  Remarques   : -                                                            * +*                                                                             * +******************************************************************************/ + +static void gtk_framework_window_activate_about(GSimpleAction *action, GVariant *unused, gpointer _window) +{ +    GtkFrameworkWindow *window;             /* Fenêtre principale associée */ +    GtkWindow *dialog;                      /* Boîte de dialogue à afficher*/ + +    window = _window; + +    dialog = gtk_app_about_dialog_new(GTK_WINDOW(window)); + +    gtk_window_present(dialog); + +} + + +/****************************************************************************** +*                                                                             * +*  Paramètres  : window = instance de fenêtre principale à consulter.         * +*                                                                             * +*  Description : Fournit une référence à la barre de statut intégrée.         * +*                                                                             * +*  Retour      : Composant GTK en place.                                      * +*                                                                             * +*  Remarques   : -                                                            * +*                                                                             * +******************************************************************************/ + +GtkStatusStack *gtk_framework_window_get_status_stack(const GtkFrameworkWindow *window) +{ +    GtkStatusStack *result;                 /* Instance à retourner        */ + +    result = window->status; +    ref_object(result); + +    return result; + +} + + + +/****************************************************************************** +*                                                                             * +*  Paramètres  : window = instance de fenêtre principale à remplir.           * +*                panel  = nouveau panneau à afficher.                         * +*                                                                             * +*  Description : Ajoute un panneau à la fenêtre principale de Chrysalide.     * +*                                                                             * +*  Retour      : -                                                            * +*                                                                             * +*  Remarques   : -                                                            * +*                                                                             * +******************************************************************************/ + +void gtk_framework_window_add(GtkFrameworkWindow *window, /* __steal */GtkTiledPanel *panel) +{ +    GtkWidget *bar;                         /* Barre de titre              */ +    GListStore *list;                       /* Liste éventuelle à intégrer */ +    guint count;                            /* Nombre d'élements présents  */ +    guint i;                                /* Boucle de parcours          */ +    GtkWidget *widget;                      /* Composant à intégrer        */ +    FrameworkPanelPersonality personality;  /* Propriétés du panneau       */ + + + +    gtk_tiling_grid_add_panel(window->grid, panel, G_OBJECT_TYPE(panel) == GTK_TYPE_WELCOME_PANEL); + + + + +    bar = gtk_window_get_titlebar(GTK_WINDOW(window)); + +    if (bar == NULL) ////////// REMME +    { +        bar = gtk_header_bar_new(); +        gtk_window_set_titlebar(GTK_WINDOW(window), bar); +    } ///////////////////////////// + +    list = gtk_tiled_panel_get_title_widgets(panel, false); + +    if (list != NULL) +    { +        count = g_list_model_get_n_items(G_LIST_MODEL(list)); + +        for (i = 0; i < count; i++) +        { +            widget = GTK_WIDGET(g_list_model_get_item(G_LIST_MODEL(list), i)); +            gtk_header_bar_pack_end(GTK_HEADER_BAR(bar), widget); +        } + +        unref_object(list); + +    } + +    /* Mise à jour des liens vers un panneau principal */ + +    personality = get_framework_panel_personality(G_OBJECT_TYPE(panel)); + +    if (personality & FPP_MAIN_PANEL) +        gtk_framework_window_notify_new_main_panel_state(window, panel, true); + +    else +    { +        if (window->main != NULL) +            gtk_tiled_panel_notify_new_main_panel_state(panel, window->main, true); +    } + +} + + +/****************************************************************************** +*                                                                             * +*  Paramètres  : window = instance de fenêtre principale à manipuler.         * +*                main      = panneau principal visé par l'opération.          * +*                activated = nature du changement de statut : ajout, retrait ?* +*                                                                             * +*  Description : Note un ajout ou un retrait de panneau principal.            * +*                                                                             * +*  Retour      : -                                                            * +*                                                                             * +*  Remarques   : -                                                            * +*                                                                             * +******************************************************************************/ + +void gtk_framework_window_notify_new_main_panel_state(GtkFrameworkWindow *window, GtkTiledPanel *main, bool activated) +{ +    if (activated) +    { +        g_clear_object(&window->main); + +        window->main = main; +        ref_object(main); + +    } + +    else +    { +        if (main == window->main) +            g_clear_object(&window->main); + +    } + +    gtk_tiling_grid_notify_new_main_panel_state(window->grid, main, activated); + +} diff --git a/src/gui/window.h b/src/gui/window.h new file mode 100644 index 0000000..077d51a --- /dev/null +++ b/src/gui/window.h @@ -0,0 +1,61 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * window.h - prototypes pour la construction d'une fenêtre graphique principale + * + * Copyright (C) 2024 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 _GUI_WINDOW_H +#define _GUI_WINDOW_H + + +#include <gtk/gtk.h> + + +#include "../glibext/helpers.h" +#include "../gtkext/panel.h" +#include "../gtkext/statusstack.h" + + + +/* Définition d'un identifiant unique */ +#define FRAMEWORK_WINDOW_ID "re.chrysalide.framework.gui" + + + +#define GTK_TYPE_FRAMEWORK_WINDOW (gtk_framework_window_get_type()) + +DECLARE_GTYPE(GtkFrameworkWindow, gtk_framework_window, GTK, FRAMEWORK_WINDOW); + + +/* Crée une nouvelle application principale pour Chrysalide. */ +GtkApplicationWindow *gtk_framework_window_new(GtkApplication *); + +/* Fournit une référence à la barre de statut intégrée. */ +GtkStatusStack *gtk_framework_window_get_status_stack(const GtkFrameworkWindow *); + +/* Ajoute un panneau à la fenêtre principale de Chrysalide. */ +void gtk_framework_window_add(GtkFrameworkWindow *, GtkTiledPanel *); + +/* Note un ajout ou un retrait de panneau principal. */ +void gtk_framework_window_notify_new_main_panel_state(GtkFrameworkWindow *, GtkTiledPanel *, bool); + + + +#endif  /* _GUI_WINDOW_H */ diff --git a/src/gui/window.ui b/src/gui/window.ui new file mode 100644 index 0000000..1c6a89a --- /dev/null +++ b/src/gui/window.ui @@ -0,0 +1,79 @@ +<?xml version="1.0" encoding="UTF-8"?> +<interface> + +    <menu id="main_menu_model"> +        <section> +            <item> +                <attribute name="label" translatable="yes">Preferences</attribute> +                <attribute name="action">win.preferences</attribute> +            </item> +            <item> +                <attribute name="label" translatable="yes">About</attribute> +                <attribute name="action">win.about</attribute> +            </item> +        </section> +    </menu> + +    <template class="GtkFrameworkWindow" parent="GtkApplicationWindow"> +        <property name="title" translatable="no">Chrysalide</property> +        <property name="default-width">800</property> +        <property name="default-height">600</property> +        <property name="icon-name">chrysalide-logo</property> + +        <child type="titlebar"> +            <object class="GtkHeaderBar"> + +                <child type="start"> +                    <object class="GtkToggleButton"> +                        <property name="icon-name">dock-station-left-symbolic</property> +                        <property name="action-name">win.toggle-left</property> +                        <property name="active" bind-source="grid" bind-property="visible-left" bind-flags="sync-create"/> +                    </object> +                </child> + +                <child type="end"> +                    <object class="GtkToggleButton"> +                        <property name="icon-name">dock-station-right-symbolic</property> +                        <property name="action-name">win.toggle-right</property> +                        <property name="active" bind-source="grid" bind-property="visible-right" bind-flags="sync-create"/> +                    </object> +                </child> + +                <child type="end"> +                    <object class="GtkMenuButton"> +                        <property name="icon-name">open-menu-symbolic</property> +                        <property name="menu-model">main_menu_model</property> +                    </object> +                </child> + +            </object> +        </child> + +        <child> +            <object class="GtkBox"> +                <property name="orientation">vertical</property> + +                <child> +                    <object class="GtkTilingGrid" id="grid"> +                        <property name="vexpand">TRUE</property> +                    </object> +                </child> + +                <child> +                    <object class="GtkSeparator"> +                        <property name="orientation">horizontal</property> +                    </object> +                </child> + +                <child> +                    <object class="GtkStatusStack" id="status"> +                        <property name="show-bottom" bind-source="grid" bind-property="visible-bottom" bind-flags="sync-create"/> +                    </object> +                </child> + +            </object> +        </child> + +    </template> + +</interface> diff --git a/src/plugins/Makefile.am b/src/plugins/Makefile.am index dd191fa..fa65484 100644 --- a/src/plugins/Makefile.am +++ b/src/plugins/Makefile.am @@ -1,13 +1,18 @@  noinst_LTLIBRARIES = libplugins.la -libplugins_la_SOURCES =					\ -	dt.h dt.c							\ -	pglist.h pglist.c					\ -	plugin-def.h						\ -	plugin-int.h						\ -	plugin.h plugin.c					\ -	self.h +libplugins_la_SOURCES =						\ +	manager-int.h							\ +	manager.h manager.c						\ +	native-int.h							\ +	native.h native.c						\ +	pglist.h pglist.c						\ +	plugin-def.h							\ +	plugin-int.h							\ +	plugin.h plugin.c						\ +	self.h									\ +	tweakable-int.h							\ +	tweakable.h tweakable.c  libplugins_la_CFLAGS = $(TOOLKIT_CFLAGS) $(LIBXML_CFLAGS) diff --git a/src/plugins/dt.c b/src/plugins/dt.c deleted file mode 100644 index 28b70bb..0000000 --- a/src/plugins/dt.c +++ /dev/null @@ -1,545 +0,0 @@ - -/* Chrysalide - Outil d'analyse de fichiers binaires - * dt.c - possibilité de créer de nouveaux types de façon dynamique - * - * Copyright (C) 2019 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 "dt.h" - - -#include <assert.h> -#include <malloc.h> -#include <string.h> - - -#include "pglist.h" - - - -/* ------------------------- MODULE DE GESTION DES NOUVEAUX ------------------------- */ - - -#define G_TYPE_DYNAMIC_TYPES            g_dynamic_types_get_type() -#define G_DYNAMIC_TYPES(obj)            (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_DYNAMIC_TYPES, GDynamicTypes)) -#define G_IS_DYNAMIC_TYPES(obj)         (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_DYNAMIC_TYPES)) -#define G_DYNAMIC_TYPES_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_DYNAMIC_TYPES, GDynamicTypesClass)) -#define G_IS_DYNAMIC_TYPES_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_DYNAMIC_TYPES)) -#define G_DYNAMIC_TYPES_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_DYNAMIC_TYPES, GDynamicTypesClass)) - - -/* Mémorisation des caractéristiques de type */ -typedef struct _type_dyn_info_t -{ -    GType type;                             /* Identifiant unique obtenu   */ - -    GClassInitFunc cinit;                   /* Phase d'initialisation #1   */ -    gconstpointer data;                     /* Eventuelles données utiles  */ - -    GInstanceInitFunc init;                 /* Phase d'initialisation #2   */ - -} type_dyn_info_t; - -/* Description de fichier binaire (instance) */ -typedef struct _GDynamicTypes -{ -    GObject parent;                         /* A laisser en premier        */ - -    type_dyn_info_t **info;                 /* Liste d'informations utiles */ -    size_t count;                           /* Taille de cette liste       */ - -} GDynamicTypes; - -/* Description de fichier binaire (classe) */ -typedef struct _GDynamicTypesClass -{ -    GObjectClass parent;                    /* A laisser en premier        */ - -} GDynamicTypesClass; - - -/* Indique le type défini pour une gestion de types dynamique. */ -static GType g_dynamic_types_get_type(void); - -/* Initialise la classe de gestion de types dynamique. */ -static void g_dynamic_types_class_init(GDynamicTypesClass *); - -/* Initialise une gestion de types dynamique. */ -static void g_dynamic_types_init(GDynamicTypes *); - -/* Procède à l'initialisation de l'interface de typage nouveau. */ -static void g_dynamic_types_interface_init(GTypePluginClass *); - -/* Supprime toutes les références externes. */ -static void g_dynamic_types_dispose(GDynamicTypes *); - -/* Procède à la libération totale de la mémoire. */ -static void g_dynamic_types_finalize(GDynamicTypes *); - -/* Crée un nouveau gestionnaire de nouveaux types. */ -static GDynamicTypes *g_dynamic_types_new(void); - -/* Marque une augmentation des utilisations. */ -static void g_dynamic_types_use(GDynamicTypes *); - -/* Marque une diminution des utilisations. */ -static void g_dynamic_types_unuse(GDynamicTypes *); - -/* Complète la définition d'un type dynamiquement. */ -static void g_dynamic_types_complete_type(GDynamicTypes *, GType, GTypeInfo *, GTypeValueTable *); - -/* Retrouve les informations concernant un type dynamique. */ -static type_dyn_info_t *g_dynamic_types_find(const GDynamicTypes *, GType); - -/* Fournit un identifiant GLib pour un nouveau type. */ -static GType g_dynamic_types_register_type(GDynamicTypes *, GType, const char *, GClassInitFunc, gconstpointer, GInstanceInitFunc); - - - -/* ----------------------- ACCOMPAGNEMENTS DES NOUVEAUX TYPES ----------------------- */ - - -/* Encadrement des nouveaux types dérivés */ -static GDynamicTypes *_chrysalide_dtypes = NULL; - - - -/* ---------------------------------------------------------------------------------- */ -/*                           MODULE DE GESTION DES NOUVEAUX                           */ -/* ---------------------------------------------------------------------------------- */ - -/* Indique le type défini pour une gestion de types dynamique. */ -G_DEFINE_TYPE_WITH_CODE(GDynamicTypes, g_dynamic_types, G_TYPE_OBJECT, -                        G_IMPLEMENT_INTERFACE(G_TYPE_TYPE_PLUGIN, g_dynamic_types_interface_init)); - - -/****************************************************************************** -*                                                                             * -*  Paramètres  : klass = classe à initialiser.                                * -*                                                                             * -*  Description : Initialise la classe de gestion de types dynamique.          * -*                                                                             * -*  Retour      : -                                                            * -*                                                                             * -*  Remarques   : -                                                            * -*                                                                             * -******************************************************************************/ - -static void g_dynamic_types_class_init(GDynamicTypesClass *klass) -{ -    GObjectClass *object;                   /* Autre version de la classe  */ - -    object = G_OBJECT_CLASS(klass); - -    object->dispose = (GObjectFinalizeFunc/* ! */)g_dynamic_types_dispose; -    object->finalize = (GObjectFinalizeFunc)g_dynamic_types_finalize; - -} - - -/****************************************************************************** -*                                                                             * -*  Paramètres  : types = instance à initialiser.                              * -*                                                                             * -*  Description : Initialise une gestion de types dynamique.                   * -*                                                                             * -*  Retour      : -                                                            * -*                                                                             * -*  Remarques   : -                                                            * -*                                                                             * -******************************************************************************/ - -static void g_dynamic_types_init(GDynamicTypes *types) -{ - -} - -/****************************************************************************** -*                                                                             * -*  Paramètres  : iface = interface GLib à initialiser.                        * -*                                                                             * -*  Description : Procède à l'initialisation de l'interface de typage nouveau. * -*                                                                             * -*  Retour      : -                                                            * -*                                                                             * -*  Remarques   : -                                                            * -*                                                                             * -******************************************************************************/ - -static void g_dynamic_types_interface_init(GTypePluginClass *iface) -{ -    iface->use_plugin = (GTypePluginUse)g_dynamic_types_use; -    iface->unuse_plugin = (GTypePluginUnuse)g_dynamic_types_unuse; -    iface->complete_type_info = (GTypePluginCompleteTypeInfo)g_dynamic_types_complete_type; - -} - -/****************************************************************************** -*                                                                             * -*  Paramètres  : types = instance d'objet GLib à traiter.                     * -*                                                                             * -*  Description : Supprime toutes les références externes.                     * -*                                                                             * -*  Retour      : -                                                            * -*                                                                             * -*  Remarques   : -                                                            * -*                                                                             * -******************************************************************************/ - -static void g_dynamic_types_dispose(GDynamicTypes *types) -{ -    size_t i;                               /* Boucle de parcours          */ -    type_dyn_info_t *info;                  /* Information à exploiter     */ -    gpointer g_class;                       /* Classe à oublier            */ - -    for (i = 0; i < types->count; i++) -    { -        info = types->info[i]; - -        if (info->type != G_TYPE_INVALID) -        { -            g_class = g_type_class_peek(info->type); -            g_type_class_unref(g_class); - -            info->type = G_TYPE_INVALID; - -        } - -    } - -    G_OBJECT_CLASS(g_dynamic_types_parent_class)->dispose(G_OBJECT(types)); - -} - - -/****************************************************************************** -*                                                                             * -*  Paramètres  : types = instance d'objet GLib à traiter.                     * -*                                                                             * -*  Description : Procède à la libération totale de la mémoire.                * -*                                                                             * -*  Retour      : -                                                            * -*                                                                             * -*  Remarques   : -                                                            * -*                                                                             * -******************************************************************************/ - -static void g_dynamic_types_finalize(GDynamicTypes *types) -{ -    size_t i;                               /* Boucle de parcours          */ - -    for (i = 0; i < types->count; i++) -        free(types->info[i]); - -    if (types->info != NULL) -        free(types->info); - -    G_OBJECT_CLASS(g_dynamic_types_parent_class)->finalize(G_OBJECT(types)); - -} - - -/****************************************************************************** -*                                                                             * -*  Paramètres  : -                                                            * -*                                                                             * -*  Description : Crée un nouveau gestionnaire de nouveaux types.              * -*                                                                             * -*  Retour      : Instance mise en place.                                      * -*                                                                             * -*  Remarques   : -                                                            * -*                                                                             * -******************************************************************************/ - -static GDynamicTypes *g_dynamic_types_new(void) -{ -    GDynamicTypes *result;                  /* Adresse à retourner         */ - -    result = g_object_new(G_TYPE_DYNAMIC_TYPES, NULL); - -    return result; - -} - - -/****************************************************************************** -*                                                                             * -*  Paramètres  : types = gestionnaire de types courant.                       * -*                                                                             * -*  Description : Marque une augmentation des utilisations.                    * -*                                                                             * -*  Retour      : -                                                            * -*                                                                             * -*  Remarques   : -                                                            * -*                                                                             * -******************************************************************************/ - -static void g_dynamic_types_use(GDynamicTypes *types) -{ - -} - - -/****************************************************************************** -*                                                                             * -*  Paramètres  : types = gestionnaire de types courant.                       * -*                                                                             * -*  Description : Marque une diminution des utilisations.                      * -*                                                                             * -*  Retour      : -                                                            * -*                                                                             * -*  Remarques   : -                                                            * -*                                                                             * -******************************************************************************/ - -static void g_dynamic_types_unuse(GDynamicTypes *types) -{ - -} - - -/****************************************************************************** -*                                                                             * -*  Paramètres  : types = gestionnaire de types courant.                       * -*                type  = nouveau type GLib à traiter.                         * -*                info  = information concernant ce type à constituer. [OUT]   * -*                table = table de valeur à éventuellement initialiser. [OUT]  * -*                                                                             * -*  Description : Complète la définition d'un type dynamiquement.              * -*                                                                             * -*  Retour      : -                                                            * -*                                                                             * -*  Remarques   : -                                                            * -*                                                                             * -******************************************************************************/ - -static void g_dynamic_types_complete_type(GDynamicTypes *types, GType type, GTypeInfo *info, GTypeValueTable *table) -{ -    type_dyn_info_t *nfo;                   /* Source d'inspiration        */ -    GType parent;                           /* Type parent du type         */ -    GTypeQuery query;                       /* Informations complémentaires*/ - -    /* Consultation */ - -    nfo = g_dynamic_types_find(types, type); -    assert(nfo != NULL); - -    parent = g_type_parent(type); -    g_type_query(parent, &query); - -    /* Définition */ - -    info->class_size = query.class_size; -    info->class_init = nfo->cinit; -    info->class_data = nfo->data; - -    info->instance_size = query.instance_size; -    info->instance_init = nfo->init; - -} - - -/****************************************************************************** -*                                                                             * -*  Paramètres  : parent = type GLib parent.                                   * -*                type   = identifiant du type GLib à considérer.              * -*                                                                             * -*  Description : Retrouve les informations concernant un type dynamique.      * -*                                                                             * -*  Retour      : Structure contenant les informations associées au type.      * -*                                                                             * -*  Remarques   : -                                                            * -*                                                                             * -******************************************************************************/ - -static type_dyn_info_t *g_dynamic_types_find(const GDynamicTypes *types, GType target) -{ -    type_dyn_info_t *result;                /* Informations à retourner    */ -    size_t i;                               /* Boucle de parcours          */ - -    result = NULL; - -    for (i = 0; i < types->count && result == NULL; i++) -        if (types->info[i]->type == target) -            result = types->info[i]; - -    return result; - -} - - -/****************************************************************************** -*                                                                             * -*  Paramètres  : parent = type GLib parent.                                   * -*                name   = désignation du nouveau type.                        * -*                cinit  = procédure d'initialisation de la classe associée.   * -*                data   = éventuelles données à associer à la future classe.  * -*                init   = procédure d'initialisation pour chaque instance.    * -*                                                                             * -*  Description : Fournit un identifiant GLib pour un nouveau type.            * -*                                                                             * -*  Retour      : identifiant d'un nouveau type valide, ou G_TYPE_INVALID.     * -*                                                                             * -*  Remarques   : -                                                            * -*                                                                             * -******************************************************************************/ - -static GType g_dynamic_types_register_type(GDynamicTypes *types, GType parent, const char *name, GClassInitFunc cinit, gconstpointer data, GInstanceInitFunc init) -{ -    GType result;                           /* Identifiant à retourner     */ -    type_dyn_info_t *new;                   /* Mémorisation de paramètres  */ - -    /* Création d'un nouveau type adapté */ - -    result = g_type_register_dynamic(parent, name, G_TYPE_PLUGIN(types), 0); - -    if (result == G_TYPE_INVALID) -        goto exit; - -    new = malloc(sizeof(type_dyn_info_t)); - -    new->type = result; - -    new->cinit = cinit; -    new->data = data; - -    new->init = init; - -    /* Inscription définitive */ - -    types->info = realloc(types->info, ++types->count * sizeof(type_dyn_info_t *)); - -    types->info[types->count - 1] = new; - - exit: - -    return result; - -} - - - -/* ---------------------------------------------------------------------------------- */ -/*                         ACCOMPAGNEMENTS DES NOUVEAUX TYPES                         */ -/* ---------------------------------------------------------------------------------- */ - - -/****************************************************************************** -*                                                                             * -*  Paramètres  : -                                                            * -*                                                                             * -*  Description : Lance le support de dérivations de types dans Chrysalide.    * -*                                                                             * -*  Retour      : Bilan de l'opération.                                        * -*                                                                             * -*  Remarques   : -                                                            * -*                                                                             * -******************************************************************************/ - -bool init_chrysalide_dynamic_types(void) -{ -    bool result;                            /* Bilan à retourner           */ - -    _chrysalide_dtypes = g_dynamic_types_new(); - -    result = (_chrysalide_dtypes != NULL); - -    return result; - -} - - -/****************************************************************************** -*                                                                             * -*  Paramètres  : -                                                            * -*                                                                             * -*  Description : Arrête le support de dérivations de types dans Chrysalide.   * -*                                                                             * -*  Retour      : -                                                            * -*                                                                             * -*  Remarques   : -                                                            * -*                                                                             * -******************************************************************************/ - -void exit_chrysalide_dynamic_types(void) -{ -    g_object_unref(G_OBJECT(_chrysalide_dtypes)); - -} - - -/****************************************************************************** -*                                                                             * -*  Paramètres  : parent = type GLib parent.                                   * -*                name   = désignation du nouveau type.                        * -*                cinit  = procédure d'initialisation de la classe associée.   * -*                data   = éventuelles données à associer à la future classe.  * -*                init   = procédure d'initialisation pour chaque instance.    * -*                                                                             * -*  Description : Fournit un identifiant GLib pour un nouveau type.            * -*                                                                             * -*  Retour      : Identifiant d'un nouveau type valide, ou G_TYPE_INVALID.     * -*                                                                             * -*  Remarques   : -                                                            * -*                                                                             * -******************************************************************************/ - -GType build_dynamic_type(GType parent, const char *name, GClassInitFunc cinit, gconstpointer data, GInstanceInitFunc init) -{ -    GType result;                           /* Identifiant à retourner     */ - -    result = g_type_from_name(name); - -    if (result == 0) -        result = g_dynamic_types_register_type(_chrysalide_dtypes, parent, name, cinit, data, init); - -    return result; - -} - - -/****************************************************************************** -*                                                                             * -*  Paramètres  : type = type d'instance à créer.                              * -*                                                                             * -*  Description : Crée un objet à partir d'un type, dynamique ou classique.    * -*                                                                             * -*  Retour      : Instance d'objet mise en place ou NULL en cas d'erreur.      * -*                                                                             * -*  Remarques   : -                                                            * -*                                                                             * -******************************************************************************/ - -gpointer create_object_from_type(GType type) -{ -    GObject *result;                        /* Instance à retourner        */ - -    result = NULL; - -    if (g_dynamic_types_find(_chrysalide_dtypes, type) != NULL) -        result = build_type_instance(type); - -    else -        result = g_object_new(type, NULL); - -    assert(result != NULL); - -    return result; - -} diff --git a/src/plugins/dt.h b/src/plugins/dt.h deleted file mode 100644 index 5c92593..0000000 --- a/src/plugins/dt.h +++ /dev/null @@ -1,50 +0,0 @@ - -/* Chrysalide - Outil d'analyse de fichiers binaires - * dt.h - prototypes pour la possibilité de créer de nouveaux types de façon dynamique - * - * Copyright (C) 2019 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 _PLUGINS_DT_H -#define _PLUGINS_DT_H - - -#include <glib-object.h> -#include <stdbool.h> - - - -/* ----------------------- ACCOMPAGNEMENTS DES NOUVEAUX TYPES ----------------------- */ - - -/* Lance le support de dérivations de types dans Chrysalide. */ -bool init_chrysalide_dynamic_types(void); - -/* Arrête le support de dérivations de types dans Chrysalide. */ -void exit_chrysalide_dynamic_types(void); - -/* Fournit un identifiant GLib pour un nouveau type. */ -GType build_dynamic_type(GType, const char *, GClassInitFunc, gconstpointer, GInstanceInitFunc); - -/* Crée un objet à partir d'un type, dynamique ou classique. */ -gpointer create_object_from_type(GType); - - - -#endif  /* _PLUGINS_PYCHRYSALIDE_DT_H */ diff --git a/src/plugins/manager-int.h b/src/plugins/manager-int.h new file mode 100644 index 0000000..dbd1d69 --- /dev/null +++ b/src/plugins/manager-int.h @@ -0,0 +1,54 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * manager-int.h - définitions internes propres aux interventions dans la gestion des extensions + * + * 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 _PLUGINS_MANAGER_INT_H +#define _PLUGINS_MANAGER_INT_H + + +#include "manager.h" + + + +/* -------------------- INTERVENTION DANS LA GESTION DE GREFFONS -------------------- */ + + +/* Accompagne la fin du chargement des modules natifs. */ +typedef void (* handle_native_plugins_cb) (GPluginManager *); + +/* Prend acte du chargement de l'ensemble des greffons. */ +typedef void (* handle_all_plugins_cb) (GPluginManager *); + + +/* Accompagnant dans la gestion des extensions (interface) */ +struct _GPluginManagerInterface +{ +    GTypeInterface base_iface;              /* A laisser en premier        */ + +    handle_native_plugins_cb handle_native; /* Greffons natifs chargés     */ +    handle_all_plugins_cb handle_all;       /* Ensemble des greffons chargé*/ + +}; + + + +#endif  /* _PLUGINS_MANAGER_INT_H */ diff --git a/src/plugins/manager.c b/src/plugins/manager.c new file mode 100644 index 0000000..381fbc1 --- /dev/null +++ b/src/plugins/manager.c @@ -0,0 +1,113 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * manager.c - intervention dans la gestion des extensions + * + * 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/>. + */ + + +#include "manager.h" + + +#include "manager-int.h" + + + +/* -------------------- INTERVENTION DANS LA GESTION DE GREFFONS -------------------- */ + + +/* Procède à l'initialisation de l'interface de gestion. */ +static void g_plugin_manager_default_init(GPluginManagerInterface *); + + + +/* ---------------------------------------------------------------------------------- */ +/*                      INTERVENTION DANS LA GESTION DE GREFFONS                      */ +/* ---------------------------------------------------------------------------------- */ + + +/* Détermine le type d'une interface pour l'intervention dans la gestion des greffons. */ +G_DEFINE_INTERFACE(GPluginManager, g_plugin_manager, G_TYPE_OBJECT) + + +/****************************************************************************** +*                                                                             * +*  Paramètres  : iface = interface GLib à initialiser.                        * +*                                                                             * +*  Description : Procède à l'initialisation de l'interface de gestion.        * +*                                                                             * +*  Retour      : -                                                            * +*                                                                             * +*  Remarques   : -                                                            * +*                                                                             * +******************************************************************************/ + +static void g_plugin_manager_default_init(GPluginManagerInterface *iface) +{ +    iface->handle_native = NULL; +    iface->handle_all = NULL; + +} + + +/****************************************************************************** +*                                                                             * +*  Paramètres  : manager = interface à manipuler.                             * +*                                                                             * +*  Description : Accompagne la fin du chargement des modules natifs.          * +*                                                                             * +*  Retour      : -                                                            * +*                                                                             * +*  Remarques   : -                                                            * +*                                                                             * +******************************************************************************/ + +void g_plugin_manager_handle_native_plugins_loaded_event(GPluginManager *manager) +{ +    GPluginManagerInterface *iface;         /* Interface utilisée          */ + +    iface = G_PLUGIN_MANAGER_GET_IFACE(manager); + +    if (iface->handle_native != NULL) +        iface->handle_native(manager); + +} + + +/****************************************************************************** +*                                                                             * +*  Paramètres  : manager = interface à manipuler.                             * +*                                                                             * +*  Description : Prend acte du chargement de l'ensemble des greffons.         * +*                                                                             * +*  Retour      : -                                                            * +*                                                                             * +*  Remarques   : -                                                            * +*                                                                             * +******************************************************************************/ + +void g_plugin_manager_handle_all_plugins_loaded_event(GPluginManager *manager) +{ +    GPluginManagerInterface *iface;         /* Interface utilisée          */ + +    iface = G_PLUGIN_MANAGER_GET_IFACE(manager); + +    if (iface->handle_all != NULL) +        iface->handle_all(manager); + +} diff --git a/src/plugins/manager.h b/src/plugins/manager.h new file mode 100644 index 0000000..2eb90a8 --- /dev/null +++ b/src/plugins/manager.h @@ -0,0 +1,61 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * manager.h - prototypes pour l'intervention dans la gestion des extensions + * + * 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 _PLUGINS_MANAGER_H +#define _PLUGINS_MANAGER_H + + +#include "../glibext/helpers.h" + + + +/* -------------------- INTERVENTION DANS LA GESTION DE GREFFONS -------------------- */ + + +#define G_TYPE_PLUGIN_MANAGER (g_plugin_manager_get_type()) + +DECLARE_INTERFACE(GPluginManager, g_plugin_manager, G, PLUGIN_MANAGER); + + +/* Accompagne la fin du chargement des modules natifs. */ +void g_plugin_manager_handle_native_plugins_loaded_event(GPluginManager *); + +/* Prend acte du chargement de l'ensemble des greffons. */ +void g_plugin_manager_handle_all_plugins_loaded_event(GPluginManager *); + + + +/* -------------------- SOLLICITATION DES FONCTIONNALITES CREEES -------------------- */ + + +#define notify_native_plugins_loaded() \ +    process_all_plugins_for(G_TYPE_PLUGIN_MANAGER, G_PLUGIN_MANAGER, \ +                            g_plugin_manager_handle_native_plugins_loaded_event) + +#define notify_all_plugins_loaded() \ +    process_all_plugins_for(G_TYPE_PLUGIN_MANAGER, G_PLUGIN_MANAGER, \ +                            g_plugin_manager_handle_all_plugins_loaded_event) + + + +#endif  /* _PLUGINS_MANAGER_H */ diff --git a/src/plugins/native-int.h b/src/plugins/native-int.h new file mode 100644 index 0000000..575994f --- /dev/null +++ b/src/plugins/native-int.h @@ -0,0 +1,73 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * native-int.h - prototypes pour les structures internes des greffons natifs + * + * 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 _PLUGINS_NATIVE_INT_H +#define _PLUGINS_NATIVE_INT_H + + +#include "native.h" + + +#include "plugin-int.h" + + + +/* Marqueur identifiable */ +#define CHRYSALIDE_PLUGIN_MAGIC 0xdeadc0de + + +/* Greffon natif pour Chrysalide (instance) */ +struct _GNativePlugin +{ +    GPluginModule parent;                   /* A laisser en premier        */ + +    /** +     * Le module porte le code et les données en mémoire. +     * +     * Les fonctions *_dispose() et *_finalize() accompagnant la libération des +     * greffons de la mémoire ne peuvent donc pas libérer ce module car elles +     * scieraient la branche sur laquelle elles se trouvent. +     * +     * Par ailleurs, même s'ils sont conservés dans chaque greffon, les modules +     * sont mis en place dans le code principal. C'est donc ce dernier qui les +     * libère, dans la fonction on_plugin_ref_toggle(). +     */ +    GModule *module;                        /* Structure de chargement GLib*/ + +}; + + +/* Greffon natif pour Chrysalide (classe) */ +struct _GNativePluginClass +{ +    GPluginModuleClass parent;              /* A laisser en premier        */ + +}; + + +/* Met en place un greffon natif. */ +bool g_native_plugin_create(GNativePlugin *, const char *, const char *, const char *, const char *, const char * const *, size_t, GModule *); + + + +#endif  /* _PLUGINS_NATIVE_INT_H */ diff --git a/src/plugins/native.c b/src/plugins/native.c new file mode 100644 index 0000000..de20abe --- /dev/null +++ b/src/plugins/native.c @@ -0,0 +1,295 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * native.c - interactions avec un greffon natif donné + * + * 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 this program; if not, write to the Free Software + *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA + */ + + +#include "native.h" + + +#include "native-int.h" +#include "../common/cpp.h" + + + +/* ------------------------- COMPOSITION DE NOUVEAU GREFFON ------------------------- */ + + +/* Initialise la classe des greffons natifs. */ +static void g_native_plugin_class_init(GNativePluginClass *); + +/* Initialise une instance de greffon natif. */ +static void g_native_plugin_init(GNativePlugin *); + +/* Supprime toutes les références externes. */ +static void g_native_plugin_dispose(GNativePlugin *); + +/* Procède à la libération totale de la mémoire. */ +static void g_native_plugin_finalize(GNativePlugin *); + + + +/* --------------------- IMPLEMENTATION DES FONCTIONS DE CLASSE --------------------- */ + + +/* Pointe le fichier contenant le greffon manipulé. */ +static char *g_native_plugin_get_filename(const GNativePlugin *); + +/* Fournit le nom brut associé au greffon. */ +static char *g_native_plugin_get_modname(const GNativePlugin *); + + + +/* ---------------------------------------------------------------------------------- */ +/*                           COMPOSITION DE NOUVEAU GREFFON                           */ +/* ---------------------------------------------------------------------------------- */ + + +/* Indique le type défini pour un greffon Python. */ +G_DEFINE_TYPE(GNativePlugin, g_native_plugin, G_TYPE_PLUGIN_MODULE); + + + +/****************************************************************************** +*                                                                             * +*  Paramètres  : class = classe à initialiser.                                * +*                                                                             * +*  Description : Initialise la classe des greffons natifs.                    * +*                                                                             * +*  Retour      : -                                                            * +*                                                                             * +*  Remarques   : -                                                            * +*                                                                             * +******************************************************************************/ + +static void g_native_plugin_class_init(GNativePluginClass *class) +{ +    GObjectClass *object;                   /* Autre version de la classe  */ +    GPluginModuleClass *plugin;             /* Version parente de la classe*/ + +    object = G_OBJECT_CLASS(class); + +    object->dispose = (GObjectFinalizeFunc/* ! */)g_native_plugin_dispose; +    object->finalize = (GObjectFinalizeFunc)g_native_plugin_finalize; + +    plugin = G_PLUGIN_MODULE_CLASS(class); + +    plugin->get_filename = (get_plugin_filename_fc)g_native_plugin_get_filename; +    plugin->get_modname = (get_plugin_modname_fc)g_native_plugin_get_modname; + +} + + +/****************************************************************************** +*                                                                             * +*  Paramètres  : plugin = instance à initialiser.                             * +*                                                                             * +*  Description : Initialise une instance de greffon natif.                    * +*                                                                             * +*  Retour      : -                                                            * +*                                                                             * +*  Remarques   : -                                                            * +*                                                                             * +******************************************************************************/ + +static void g_native_plugin_init(GNativePlugin *plugin) +{ +    plugin->module = NULL; + +} + + +/****************************************************************************** +*                                                                             * +*  Paramètres  : plugin = instance d'objet GLib à traiter.                    * +*                                                                             * +*  Description : Supprime toutes les références externes.                     * +*                                                                             * +*  Retour      : -                                                            * +*                                                                             * +*  Remarques   : -                                                            * +*                                                                             * +******************************************************************************/ + +static void g_native_plugin_dispose(GNativePlugin *plugin) +{ +    G_OBJECT_CLASS(g_native_plugin_parent_class)->dispose(G_OBJECT(plugin)); + +} + + +/****************************************************************************** +*                                                                             * +*  Paramètres  : plugin = instance d'objet GLib à traiter.                    * +*                                                                             * +*  Description : Procède à la libération totale de la mémoire.                * +*                                                                             * +*  Retour      : -                                                            * +*                                                                             * +*  Remarques   : -                                                            * +*                                                                             * +******************************************************************************/ + +static void g_native_plugin_finalize(GNativePlugin *plugin) +{ +    G_OBJECT_CLASS(g_native_plugin_parent_class)->finalize(G_OBJECT(plugin)); + +} + + +/****************************************************************************** +*                                                                             * +*  Paramètres  : plugin   = instance à initialiser pleinement.                * +*                name     = nom du greffon pour référence, principalement.    * +*                desc     = présentation éventuelle à destination humaine.    * +*                version  = indication de version éventuelle.                 * +*                url      = référence vers une ressource en ligne.            * +*                required = liste de dépendances éventuelles ou NULL.         * +*                count    = taille de cette liste.                            * +*                module   = extension vue du système.                         * +*                                                                             * +*  Description : Met en place un greffon natif.                               * +*                                                                             * +*  Retour      : Bilan de l'opération.                                        * +*                                                                             * +*  Remarques   : Le transfert de propriétée du module est total.              * +*                                                                             * +******************************************************************************/ + +bool g_native_plugin_create(GNativePlugin *plugin, const char *name, const char *desc, const char *version, const char *url, const char * const *required, size_t count, GModule *module) +{ +    bool result;                            /* Bilan à retourner           */ + +    result = g_plugin_module_create(G_PLUGIN_MODULE(plugin), name, desc, version, url, required, count); + +    if (result) +        plugin->module = module; + +    return result; + +} + + +/****************************************************************************** +*                                                                             * +*  Paramètres  : plugin = greffon à consulter.                                * +*                                                                             * +*  Description : Renvoie la structure opaque associée au module en mémoire.   * +*                                                                             * +*  Retour      : Structure de chargement côté GLib.                           * +*                                                                             * +*  Remarques   : -                                                            * +*                                                                             * +******************************************************************************/ + +GModule *g_native_plugin_get_module(const GNativePlugin *plugin) +{ +    GModule *result;                        /* Accès au module à renvoyer  */ + +    result = plugin->module; + +    return result; + +} + + + +/* ---------------------------------------------------------------------------------- */ +/*                       IMPLEMENTATION DES FONCTIONS DE CLASSE                       */ +/* ---------------------------------------------------------------------------------- */ + + +/****************************************************************************** +*                                                                             * +*  Paramètres  : plugin = greffon à consulter.                                * +*                                                                             * +*  Description : Pointe le fichier contenant le greffon manipulé.             * +*                                                                             * +*  Retour      : Chemin d'accès au greffon.                                   * +*                                                                             * +*  Remarques   : -                                                            * +*                                                                             * +******************************************************************************/ + +static char *g_native_plugin_get_filename(const GNativePlugin *plugin) +{ +    char *result;                           /* Chemin d'accès à renvoyer   */ + +    result = strdup(g_module_name(plugin->module)); + +    return result; + +} + + +/****************************************************************************** +*                                                                             * +*  Paramètres  : plugin = greffon à valider.                                  * +*                                                                             * +*  Description : Fournit le nom brut associé au greffon.                      * +*                                                                             * +*  Retour      : Désignation brute du greffon.                                * +*                                                                             * +*  Remarques   : -                                                            * +*                                                                             * +******************************************************************************/ + +static char *g_native_plugin_get_modname(const GNativePlugin *plugin) +{ +    char *result;                           /* Désignation brute à renvoyer*/ +    char *path;                             /* Chemin à traiter            */ +    char *filename;                         /* Nom de bibliothèque partagée*/ +    size_t length;                          /* Taille du nom               */ +    int ret;                                /* Bilan d'une comparaison     */ + +    path = g_native_plugin_get_filename(plugin); + +    filename = basename(path); + +    if (strncmp(filename, "lib", 3) == 0) +        filename += 3; + +    length = strlen(filename); + +#ifdef _WIN32 +#   define SHARED_SUFFIX ".dll" +#else +#   define SHARED_SUFFIX ".so" +#endif + +    if (length >= STATIC_STR_SIZE(SHARED_SUFFIX)) +    { +        ret = strncmp(&filename[length - STATIC_STR_SIZE(SHARED_SUFFIX)], +                      SHARED_SUFFIX, +                      STATIC_STR_SIZE(SHARED_SUFFIX)); + +        if (ret == 0) +            filename[length - STATIC_STR_SIZE(SHARED_SUFFIX)] = '\0'; + +    } + +    result = strdup(filename); + +    free(path); + +    return result; + +} diff --git a/src/plugins/native.h b/src/plugins/native.h new file mode 100644 index 0000000..18039c8 --- /dev/null +++ b/src/plugins/native.h @@ -0,0 +1,46 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * native.h - prototypes pour les interactions avec un greffon natif donné + * + * 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 this program; if not, write to the Free Software + *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA + */ + + +#ifndef _PLUGINS_NATIVE_H +#define _PLUGINS_NATIVE_H + + +#include <gmodule.h> + + +#include "../glibext/helpers.h" + + + +#define G_TYPE_NATIVE_PLUGIN (g_native_plugin_get_type()) + +DECLARE_GTYPE(GNativePlugin, g_native_plugin, G, NATIVE_PLUGIN); + + +/* Renvoie la structure opaque associée au module en mémoire. */ +GModule *g_native_plugin_get_module(const GNativePlugin *); + + + +#endif  /* _PLUGINS_NATIVE_H */ diff --git a/src/plugins/pglist.c b/src/plugins/pglist.c index 6b36d2f..3e107b8 100644 --- a/src/plugins/pglist.c +++ b/src/plugins/pglist.c @@ -30,19 +30,29 @@  #include <malloc.h>  #include <stdlib.h>  #include <string.h> +#include <unistd.h>  #include <i18n.h> -#include "dt.h" +#include "manager.h" +#include "native.h"  #include "plugin-int.h" +#include "../common/cpp.h"  #include "../common/extstr.h"  #include "../core/logs.h" +#include "../core/nox.h"  #include "../core/paths.h" +/** + * Prototype de la fonction de création, à garder synchronisé avec + * NATIVE_PLUGIN_ENTRYPOINT() (cf. native-int.h). + */ +typedef GPluginModule * (* get_plugin_instance_cb) (GModule *); +  /* Liste de l'ensemble des greffons */  static GPluginModule **_pg_list = NULL;  static size_t _pg_count = 0; @@ -60,6 +70,9 @@ static void browse_directory_for_plugins(const char *);  /* Suit les variations du compteur de références d'un greffon. */  static void on_plugin_ref_toggle(gpointer, GPluginModule *, gboolean); +/* Fournit le greffon répondant à un nom donné. */ +static GPluginModule *_find_plugin_by_name(const char *, size_t *); +  /****************************************************************************** @@ -82,8 +95,7 @@ bool init_all_plugins(bool load)      char *saveptr;                          /* Sauvegarde pour parcours    */      char *udir;                             /* Répertoire supplémentaire ? */ -    result = init_chrysalide_dynamic_types(); -    if (!result) goto exit; +    result = true;      g_rw_lock_init(&_pg_lock); @@ -107,8 +119,6 @@ bool init_all_plugins(bool load)      if (load)          load_remaning_plugins(); - exit: -      return result;  } @@ -129,64 +139,22 @@ bool init_all_plugins(bool load)  void exit_all_plugins(void)  {      size_t i;                               /* Boucle de parcours          */ -    const plugin_interface *pg_iface;       /* Définition du greffon       */      lock_plugin_list_for_reading(); -    if (_pg_list != NULL) +    for (i = 0; i < _pg_count; i++)      { -        for (i = 0; i < _pg_count; i++) -        { -            assert(_pg_list[i] != NULL); - -            /** -             * Si le greffon a conduit à la mise en place d'autres greffons, le -             * système de dépendances ne suffit pas pour le décompte des références : -             * le greffon voit à un instant T son compteur décroître ici ; à un -             * instant T+1, un greffon fils décrémente à son tour le compteur vers -             * le greffon principal. -             * -             * Le compteur du conteneur tombe alors à 0, et le code correspondant -             * est retiré. Lorsque que le flot d'exécution revient à la procédure -             * de sortie du second greffon, son code n'est plus en mémoire. -             * -             * On s'assure donc que les greffons qui génèrent d'autres greffons -             * sont bien traités en dernier. -             */ - -            pg_iface = g_plugin_module_get_interface(_pg_list[i]); - -            if (pg_iface != NULL && pg_iface->container) -                g_object_ref(_pg_list[i]); - -            g_object_unref(_pg_list[i]); - -        } - -        for (i = 0; i < _pg_count; i++) -        { -            if (_pg_list[i] == NULL) -                continue; - -            pg_iface = g_plugin_module_get_interface(_pg_list[i]); - -            if (pg_iface == NULL || !pg_iface->container) -                continue; - -            g_object_unref(_pg_list[i]); - -        } +        assert(_pg_list[i] != NULL); +        unref_object(_pg_list[i]); +    } +    if (_pg_list != NULL)          free(_pg_list); -    } -      unlock_plugin_list_for_reading();      g_rw_lock_clear(&_pg_lock); -    exit_chrysalide_dynamic_types(); -  } @@ -243,63 +211,95 @@ static int filter_dirs_or_mods(const struct dirent *entry)  *                                                                             *  *  Paramètres  : dir = répertoire à parcourir en quête de greffons (sans /).  *  *                                                                             * -*  Description : Part à la recherche de greffons sous forme de modules.       * +*  Description : Indique la version (NOX/UI) associée à un nom de fichier.    *  *                                                                             * -*  Retour      : -                                                            * +*  Retour      : true si la version complémentaire existe ou false.           *  *                                                                             *  *  Remarques   : -                                                            *  *                                                                             *  ******************************************************************************/ -static void browse_directory_for_plugins(const char *dir) +static bool check_for_plugin_versions(const char *dir, const char *filename, bool *is_nox, bool *is_ui)  { -    struct dirent **namelist;               /* Eléments trouvés            */ -    int ret;                                /* Bilan du parcours           */ -    char *filename;                         /* Elément à ausculter         */ -    GPluginModule *plugin;                  /* Greffon à intégrer ou pas   */ +    bool result;                            /* Bilan à renvoyer            */ +    size_t length;                          /* Taille du nom de fichier    */ +    char *alt_path;                         /* Autre chemin complet testé  */ +    int ret;                                /* Bilan d'une impression      */ -    ret = scandir(dir, &namelist, filter_dirs_or_mods, alphasort); -    if (ret < 0) -    { -        LOG_ERROR_N("scandir"); -        return; -    } +#ifdef _WIN32 +#   define SHARED_SUFFIX ".dll" +#else +#   define SHARED_SUFFIX ".so" +#endif +#define UI_SHARED_SUFFIX "ui" SHARED_SUFFIX + +    result = false; + +    /* Propriétés du fichier courant */ -    while (ret--) +    length = strlen(filename); + +    if (length < STATIC_STR_SIZE(UI_SHARED_SUFFIX)) +        *is_ui = false; + +    else +        *is_ui = (strcmp(filename + length - STATIC_STR_SIZE(UI_SHARED_SUFFIX), UI_SHARED_SUFFIX) == 0); + +    if (*is_ui) +        *is_nox = false; + +    else      { -        filename = (char *)calloc(strlen(dir) + 1 + strlen(namelist[ret]->d_name) + 1, sizeof(char)); +        if (length < STATIC_STR_SIZE(SHARED_SUFFIX)) +            *is_nox = false; -        strcpy(filename, dir); -        strcat(filename, G_DIR_SEPARATOR_S); -        strcat(filename, namelist[ret]->d_name); +        else +            *is_nox = (strcmp(filename + length - STATIC_STR_SIZE(SHARED_SUFFIX), SHARED_SUFFIX) == 0); -        if (namelist[ret]->d_type == DT_DIR) -            browse_directory_for_plugins(filename); +    } + +    /* Recherche d'une version alternative */ + +    if (*is_nox || *is_ui) +    { +        if (*is_nox) +            ret = asprintf(&alt_path, "%s%s%.*s%s", +                           dir, G_DIR_SEPARATOR_S, +                           (int)(length - STATIC_STR_SIZE(SHARED_SUFFIX)), filename, +                           UI_SHARED_SUFFIX);          else +            ret = asprintf(&alt_path, "%s%s%.*s%s", +                           dir, G_DIR_SEPARATOR_S, +                           (int)(length - STATIC_STR_SIZE(SHARED_SUFFIX)), filename, +                           SHARED_SUFFIX); + +        if (ret <= 0)          { -            plugin = g_plugin_module_new(filename); +            LOG_ERROR_N("asprintf"); +            goto exit; +        } -            if (plugin != NULL) -                register_plugin(plugin); +        ret = access(alt_path, R_OK | X_OK); -        } +        result = (ret == 0); -        free(filename); -        free(namelist[ret]); +        free(alt_path);      } -    free(namelist); + exit: + +    return result;  }  /******************************************************************************  *                                                                             * -*  Paramètres  : plugin = greffon à ajouter aux autres disponibles.           * +*  Paramètres  : dir = répertoire à parcourir en quête de greffons (sans /).  *  *                                                                             * -*  Description : Ajoute un greffon à la liste principale de greffons.         * +*  Description : Part à la recherche de greffons sous forme de modules.       *  *                                                                             *  *  Retour      : -                                                            *  *                                                                             * @@ -307,52 +307,91 @@ static void browse_directory_for_plugins(const char *dir)  *                                                                             *  ******************************************************************************/ -void _register_plugin(GPluginModule *plugin) +static void browse_directory_for_plugins(const char *dir)  { -    size_t i;                               /* Boucle de parcours          */ -    const plugin_interface *pg_iface;       /* Informations à consulter    */ -    const char *name;                       /* Désignation du greffon      */ - -    /** -     * L'appel sans verrou n'est fourni que pour les greffons -     * mettant en place des greffons en interne ! -     */ - -    /* Recherche d'un éventuel doublon */ +    struct dirent **namelist;               /* Eléments trouvés            */ +    int ret;                                /* Bilan d'un appel            */ +    int k;                                  /* Boucle de parcours          */ +    bool nox_mode;                          /* Absence de support graphique*/ +    char *filename;                         /* Elément à ausculter         */ +    bool is_nox;                            /* Chemin de version basique ? */ +    bool is_ui;                             /* Chemin de version graphique */ +    bool has_alt;                           /* Existence d'une alternative */ +    GModule *module;                        /* Abstration de manipulation  */ +    get_plugin_instance_cb get_instance;    /* Point d'entrée exporté      */ +    GPluginModule *plugin;                  /* Greffon à intégrer ou pas   */ -    pg_iface = g_plugin_module_get_interface(plugin); +    ret = scandir(dir, &namelist, filter_dirs_or_mods, alphasort); +    if (ret < 0) +    { +        LOG_ERROR_N("scandir"); +        return; +    } -    name = pg_iface->name; +    nox_mode = run_in_nox_mode(); -    for (i = 0; i < _pg_count; i++) +    for (k = ret; k--; )      { -        pg_iface = g_plugin_module_get_interface(_pg_list[i]); - -        if (strcmp(name, pg_iface->name) == 0) +        ret = asprintf(&filename, "%s%s%s", dir, G_DIR_SEPARATOR_S, namelist[k]->d_name); +        if (ret <= 0)          { -            log_variadic_message(LMT_ERROR, -                                 _("Plugin '%s' already registered!"), name); +            LOG_ERROR_N("asprintf"); +            continue; +        } -            break; +        if (namelist[k]->d_type == DT_DIR) +            browse_directory_for_plugins(filename); -        } +        else +        { +            has_alt = check_for_plugin_versions(dir, namelist[k]->d_name, &is_nox, &is_ui); -    } +            if ((nox_mode && is_nox) || (!nox_mode && ((is_nox && !has_alt) || is_ui))) +            { +                module = g_module_open(filename, G_MODULE_BIND_LAZY); +                if (module == NULL) +                { +                    log_variadic_message(LMT_ERROR,  +                                         _("Error while loading the plugin candidate '%s' : %s"), +                                         filename, g_module_error()); +                    goto next_file; +                } + +                get_instance = NULL; + +                if (!g_module_symbol(module, "get_chrysalide_plugin_instance", (gpointer *)&get_instance)) +                    log_variadic_message(LMT_ERROR, +                                         _("No '%s' entry in plugin candidate '%s'"), +                                         "<sym>", filename); + +                if (get_instance == NULL) +                    plugin = NULL; +                else +                    plugin = get_instance(module); + +                if (plugin != NULL) +                { +                    register_plugin(plugin); +                    unref_object(plugin); +                } + +                else +                    g_module_close(module); -    /* Ajout du greffon à la liste */ +            } +            else +                log_variadic_message(LMT_INFO, _("Skipping unsuitable file for plugin: %s"), filename); -    if (i == _pg_count) -    { -        _pg_list = (GPluginModule **)realloc(_pg_list, ++_pg_count * sizeof(GPluginModule)); +        } -        _pg_list[_pg_count - 1] = plugin; + next_file: -        g_object_add_toggle_ref(G_OBJECT(plugin), (GToggleNotify)on_plugin_ref_toggle, NULL); +        free(filename); +        free(namelist[k]);      } -    else -        /* FIXME : leak(plugin); */; +    free(namelist);  } @@ -373,24 +412,55 @@ void _register_plugin(GPluginModule *plugin)  static void on_plugin_ref_toggle(gpointer unused, GPluginModule *plugin, gboolean last)  { -    const plugin_interface *pg_iface;       /* Vitrine d'un greffon        */ +    const char *name;                       /* Désignation du greffon      */      size_t index;                           /* Indice du greffon           */      GPluginModule *same;                    /* Juste pour la récupération  */ +    GModule *module;                        /* Structure de chargement GLib*/      if (last)      {          assert(g_rw_lock_writer_trylock(&_pg_lock) == FALSE); -        pg_iface = g_plugin_module_get_interface(plugin); +        name = g_plugin_module_get_name(plugin); + +        /** +         * Les mécanismes de g_object_unref() prennent en compte la bascule d'un +         * compteur de références initialement à 2 avant appel pour déclencher +         * cet appel à on_plugin_ref_toggle() mis en place par g_object_add_toggle_ref(). +         * +         * Incrémenter ce compteur à nouveau, via get_plugin_by_name(), puis le +         * décrémenter ensuite via unref_object() va conduire à une nouvelle +         * bascule des statuts de suivi dans g_object_unref(). +         * +         * Il est ainsi impératif de rechercher une instance du greffon dans +         * la liste des extensions sans toucher au compteur de références. +         */ + +        same = _find_plugin_by_name(name, &index); -        same = get_plugin_by_name(pg_iface->name, &index);          assert(same != NULL); +        assert(same == plugin);          _pg_list[index] = NULL; -        g_object_remove_toggle_ref(G_OBJECT(plugin), (GToggleNotify)on_plugin_ref_toggle, NULL); +        /** +         * Suppression de la dernière référence. +         */ -        g_object_unref(G_OBJECT(same)); +        if (G_IS_NATIVE_PLUGIN(plugin)) +            module = g_native_plugin_get_module(G_NATIVE_PLUGIN(plugin)); +        else +            module = NULL; + +        g_object_remove_toggle_ref(G_OBJECT(same), (GToggleNotify)on_plugin_ref_toggle, NULL); + +        /** +         * Plus aucun code issu du greffon n'est désormais utile. Le module associé peut +         * être libéré de la mémoire. +         */ + +        if (module != NULL) +            g_module_close(module);      } @@ -411,9 +481,40 @@ static void on_plugin_ref_toggle(gpointer unused, GPluginModule *plugin, gboolea  void register_plugin(GPluginModule *plugin)  { +    size_t i;                               /* Boucle de parcours          */ +    const char *name;                       /* Désignation du greffon      */ +    const char *existing;                   /* Nom d'un greffon en place   */ +      g_rw_lock_writer_lock(&_pg_lock); -    _register_plugin(plugin); +    /* Recherche d'un éventuel doublon */ + +    name = g_plugin_module_get_name(plugin); + +    for (i = 0; i < _pg_count; i++) +    { +        existing = g_plugin_module_get_name(_pg_list[i]); + +        if (strcmp(name, existing) == 0) +        { +            log_variadic_message(LMT_ERROR, _("Plugin '%s' already registered!"), name); +            break; +        } + +    } + +    /* Ajout du greffon à la liste */ + +    if (i == _pg_count) +    { +        _pg_list = realloc(_pg_list, ++_pg_count * sizeof(GPluginModule)); + +        _pg_list[_pg_count - 1] = plugin; +        ref_object(plugin); + +        g_object_add_toggle_ref(G_OBJECT(plugin), (GToggleNotify)on_plugin_ref_toggle, NULL); + +    }      g_rw_lock_writer_unlock(&_pg_lock); @@ -481,13 +582,18 @@ void load_remaning_plugins(void)      /* Supprime les greffons non chargés */ -    for (i = 0; i < _pg_count; i++) +    for (i = 0; i < _pg_count;)      {          flags = g_plugin_module_get_flags(_pg_list[i]); -        if ((flags & PSF_LOADED) == 0) +        if (flags & PSF_LOADED) +            i++; + +        else          { -            g_object_unref(G_OBJECT(_pg_list[i])); +            unref_object(_pg_list[i]); + +            assert(_pg_list[i] == NULL);              memmove(&_pg_list[i], &_pg_list[i + 1], (_pg_count - i - 1) * sizeof(GPluginModule *));              _pg_count--; @@ -514,15 +620,16 @@ void load_remaning_plugins(void)  *                                                                             *  *  Retour      : Instance du greffon trouvé ou NULL si aucun.                 *  *                                                                             * -*  Remarques   : -                                                            * +*  Remarques   : Le compteur de référence d'un greffon trouvé n'est pas       * +*                modifié.                                                     *  *                                                                             *  ******************************************************************************/ -GPluginModule *get_plugin_by_name(const char *name, size_t *index) +static GPluginModule *_find_plugin_by_name(const char *name, size_t *index)  {      GPluginModule *result;                  /* Greffon trouvé à renvoyer   */      size_t i;                               /* Boucle de parcours          */ -    const plugin_interface *pg_iface;       /* Vitrine d'un greffon        */ +    const char *current;                    /* Nom du greffon courant      */      result = NULL; @@ -536,9 +643,9 @@ GPluginModule *get_plugin_by_name(const char *name, size_t *index)          /* Si on est en train de procéder à un nettoyage... */          if (_pg_list[i] == NULL) continue; -        pg_iface = g_plugin_module_get_interface(_pg_list[i]); +        current = g_plugin_module_get_name(_pg_list[i]); -        if (strcmp(pg_iface->name, name) == 0) +        if (strcmp(current, name) == 0)          {              result = _pg_list[i]; @@ -549,9 +656,6 @@ GPluginModule *get_plugin_by_name(const char *name, size_t *index)      } -    if (result != NULL) -        g_object_ref(G_OBJECT(result)); -      return result;  } @@ -559,33 +663,25 @@ GPluginModule *get_plugin_by_name(const char *name, size_t *index)  /******************************************************************************  *                                                                             * -*  Paramètres  : count = nombre de greffons trouvés. [OUT]                    * +*  Paramètres  : name  = désignation du greffon recherché.                    * +*                index = indice du greffon trouvé. [OUT]                      *  *                                                                             * -*  Description : Fournit la liste de l'ensemble des greffons.                 * +*  Description : Fournit le greffon répondant à un nom donné.                 *  *                                                                             * -*  Retour      : Liste de tous les greffons chargés.                          * +*  Retour      : Instance du greffon trouvé ou NULL si aucun.                 *  *                                                                             *  *  Remarques   : -                                                            *  *                                                                             *  ******************************************************************************/ -GPluginModule **get_all_plugins(size_t *count) +GPluginModule *get_plugin_by_name(const char *name, size_t *index)  { -    GPluginModule **result;                 /* Liste à retourner           */ -    size_t i;                               /* Boucle de parcours          */ - -    g_rw_lock_reader_lock(&_pg_lock); - -    result = malloc(_pg_count * sizeof(GPluginModule *)); -    *count = _pg_count; +    GPluginModule *result;                  /* Greffon trouvé à renvoyer   */ -    for (i = 0; i < _pg_count; i++) -    { -        result[i] = _pg_list[i]; -        g_object_ref(G_OBJECT(_pg_list[i])); -    } +    result = _find_plugin_by_name(name, index); -    g_rw_lock_reader_unlock(&_pg_lock); +    if (result != NULL) +        ref_object(result);      return result; @@ -594,48 +690,30 @@ GPluginModule **get_all_plugins(size_t *count)  /******************************************************************************  *                                                                             * -*  Paramètres  : action = fonctionnalité recherchée.                          * -*                count  = nombre de greffons trouvés. [OUT]                   * +*  Paramètres  : count = nombre de greffons trouvés. [OUT]                    *  *                                                                             * -*  Description : Fournit les greffons offrant le service demandé.             * +*  Description : Fournit la liste de l'ensemble des greffons.                 *  *                                                                             * -*  Retour      : Liste de greffons correspondants issue d'un tri interne.     * +*  Retour      : Liste de tous les greffons chargés.                          *  *                                                                             *  *  Remarques   : -                                                            *  *                                                                             *  ******************************************************************************/ -GPluginModule **get_all_plugins_for_action(PluginAction action, size_t *count) +GPluginModule **get_all_plugins(size_t *count)  {      GPluginModule **result;                 /* Liste à retourner           */ -    size_t i;                               /* Boucle de parcours #1       */ -    const plugin_interface *pg_iface;       /* Informations à consulter    */ -    size_t j;                               /* Boucle de parcours #2       */ - -    result = NULL; -    *count = 0; +    size_t i;                               /* Boucle de parcours          */      g_rw_lock_reader_lock(&_pg_lock); +    result = malloc(_pg_count * sizeof(GPluginModule *)); +    *count = _pg_count; +      for (i = 0; i < _pg_count; i++)      { -        pg_iface = g_plugin_module_get_interface(_pg_list[i]); - -        for (j = 0; j < pg_iface->actions_count; j++) -        { -            if (pg_iface->actions[j] == action) -            { -                result = realloc(result, ++(*count) * sizeof(GPluginModule *)); - -                result[*count - 1] = _pg_list[i]; -                g_object_ref(G_OBJECT(_pg_list[i])); - -                break; - -            } - -        } - +        result[i] = _pg_list[i]; +        ref_object(result[i]);      }      g_rw_lock_reader_unlock(&_pg_lock); diff --git a/src/plugins/pglist.h b/src/plugins/pglist.h index 83e9091..777b19c 100644 --- a/src/plugins/pglist.h +++ b/src/plugins/pglist.h @@ -52,9 +52,6 @@ void _lock_unlock_plugin_list_for_reading(bool lock);  #define unlock_plugin_list_for_reading() _lock_unlock_plugin_list_for_reading(false)  /* Ajoute un greffon à la liste principale de greffons. */ -void _register_plugin(GPluginModule *); - -/* Ajoute un greffon à la liste principale de greffons. */  void register_plugin(GPluginModule *);  /* Charge tous les greffons restant à charger. */ @@ -66,16 +63,74 @@ GPluginModule *get_plugin_by_name(const char *, size_t *);  /* Fournit la liste de l'ensemble des greffons. */  GPluginModule **get_all_plugins(size_t *); -/* Fournit les greffons offrant le service demandé. */ -GPluginModule **get_all_plugins_for_action(PluginAction, size_t *); -  /**   * Définitions des opérations appliquables à une catégories de greffons.   */ -#define process_all_plugins_for(a, f, ...)                  \ +#define process_all_plugins_for(tp, cst, fc)            \ +    do                                                  \ +    {                                                   \ +        size_t __count;                                 \ +        GPluginModule **__list;                         \ +        size_t __i;                                     \ +        GPluginModule *__pg;                            \ +        __list = get_all_plugins(&__count);             \ +        for (__i = 0; __i < __count; __i++)             \ +        {                                               \ +         __pg = __list[__i];                            \ +            if (G_TYPE_CHECK_INSTANCE_TYPE(__pg, tp))   \ +                fc(cst(__pg));                          \ +            unref_object(__pg);                         \ +        }                                               \ +        if (__list != NULL)                             \ +            free(__list);                               \ +    }                                                   \ +    while (0) + +#define accumulate_from_all_plugins(tp, cst, fc, atp, cnt)                      \ +    ({                                                                          \ +        atp *__acc_list;                                                        \ +        size_t __count;                                                         \ +        GPluginModule **__list;                                                 \ +        size_t __i;                                                             \ +        GPluginModule *__pg;                                                    \ +        size_t __tmp_count;                                                     \ +        atp *__tmp_list;                                                        \ +        *cnt = 0;                                                               \ +        __acc_list = NULL;                                                      \ +        __list = get_all_plugins(&__count);                                     \ +        for (__i = 0; __i < __count; __i++)                                     \ +        {                                                                       \ +            __pg = __list[__i];                                                 \ +            if (G_TYPE_CHECK_INSTANCE_TYPE(__pg, tp))                           \ +            {                                                                   \ +                __tmp_list = fc(cst(__pg), &__tmp_count);                       \ +                if (__tmp_list != NULL)                                         \ +                {                                                               \ +                    __acc_list = realloc(__acc_list,                            \ +                                         (*cnt + __tmp_count) * sizeof(atp));   \ +                    memcpy(&__acc_list[*cnt], __tmp_list,                       \ +                           __tmp_count * sizeof(atp));                          \ +                    *cnt += __tmp_count;                                        \ +                    free(__tmp_list);                                           \ +                }                                                               \ +            }                                                                   \ +            unref_object(__pg);                                                 \ +        }                                                                       \ +        if (__list != NULL)                                                     \ +            free(__list);                                                       \ +        __acc_list;                                                             \ +    }) + + + +#if 0 + +// TODO : REMME + +#define process_all_plugins_for_old__(a, f, ...)                  \      do                                                      \      {                                                       \          size_t __count;                                     \ @@ -114,11 +169,13 @@ GPluginModule **get_all_plugins_for_action(PluginAction, size_t *);  /* DPS_PG_MANAGEMENT */ +/*  #define notify_native_plugins_loaded() \ -    process_all_plugins_for(PGA_NATIVE_PLUGINS_LOADED, g_plugin_module_notify_plugins_loaded, NULL) +    process_all_plugins_for_old__(PGA_NATIVE_PLUGINS_LOADED, g_plugin_module_notify_plugins_loaded, NULL)  #define notify_all_plugins_loaded() \ -    process_all_plugins_for(PGA_ALL_PLUGINS_LOADED, g_plugin_module_notify_plugins_loaded, NULL) +    process_all_plugins_for_old__(PGA_ALL_PLUGINS_LOADED, g_plugin_module_notify_plugins_loaded, NULL) +*/  #define build_type_instance(t) \      process_plugins_while_null(PGA_TYPE_BUILDING, g_plugin_module_build_type_instance, t) @@ -126,44 +183,47 @@ GPluginModule **get_all_plugins_for_action(PluginAction, size_t *);  /* DPS_SETUP */  #define include_plugin_theme(d, r, c) \ -    process_all_plugins_for(PGA_GUI_THEME, g_plugin_module_include_theme, d, r, c) +    process_all_plugins_for_old__(PGA_GUI_THEME, g_plugin_module_include_theme, d, r, c)  /* DPS_RUNNING */  #define notify_panel_creation(i) \ -    process_all_plugins_for(PGA_PANEL_CREATION, g_plugin_module_notify_panel_creation, i) +    process_all_plugins_for_old__(PGA_PANEL_CREATION, g_plugin_module_notify_panel_creation, i)  #define notify_panel_docking(i, d) \ -    process_all_plugins_for(PGA_PANEL_DOCKING, g_plugin_module_notify_panel_docking, i, d) +    process_all_plugins_for_old__(PGA_PANEL_DOCKING, g_plugin_module_notify_panel_docking, i, d)  /* DPS_CONTENT */  #define handle_binary_content(a, c, i, s) \ -    process_all_plugins_for(a, g_plugin_module_handle_binary_content, c, i, s) +    process_all_plugins_for_old__(a, g_plugin_module_handle_binary_content, c, i, s)  #define handle_loaded_content(a, c, i, s) \ -    process_all_plugins_for(a, g_plugin_module_handle_loaded_content, c, i, s) +    process_all_plugins_for_old__(a, g_plugin_module_handle_loaded_content, c, i, s)  /* DPS_FORMAT */  #define handle_known_format_analysis(a, f, g, s) \ -    process_all_plugins_for(a, g_plugin_module_handle_known_format_analysis, f, g, s) +    process_all_plugins_for_old__(a, g_plugin_module_handle_known_format_analysis, f, g, s)  #define preload_binary_format(a, f, i, s) \ -    process_all_plugins_for(a, g_plugin_module_preload_binary_format, f, i, s) +    process_all_plugins_for_old__(a, g_plugin_module_preload_binary_format, f, i, s)  #define attach_debug_format(f) \ -    process_all_plugins_for(PGA_FORMAT_ATTACH_DEBUG, g_plugin_module_attach_debug_format, f) +    process_all_plugins_for_old__(PGA_FORMAT_ATTACH_DEBUG, g_plugin_module_attach_debug_format, f)  /* DPS_DISASSEMBLY */  #define process_disassembly_event(a, b, s, c) \ -    process_all_plugins_for(a, g_plugin_module_process_disassembly_event, b, s, c) +    process_all_plugins_for_old__(a, g_plugin_module_process_disassembly_event, b, s, c)  /* DPS_DETECTION */  #define detect_external_tools(a, cnt, v, n, c) \ -    process_all_plugins_for(a, g_plugin_module_detect_external_tools, cnt, v, n, c) +    process_all_plugins_for_old__(a, g_plugin_module_detect_external_tools, cnt, v, n, c) + + +#endif diff --git a/src/plugins/plugin-def.h b/src/plugins/plugin-def.h index 1118140..b5e0b51 100644 --- a/src/plugins/plugin-def.h +++ b/src/plugins/plugin-def.h @@ -35,18 +35,6 @@  /* ------------------------ IDENTIFICATION DE COMPATIBILITES ------------------------ */ -/* Version identifiant les définitions courantes */ -typedef uint32_t plugin_abi_version_t; - -#define DEFINE_PLUGIN_ABI_VERSION(maj, min, rev) \ -    (((maj & 0xff) << 24) | ((min & 0xff) << 16) | (rev & 0xffff)) - -#define GET_ABI_MAJ_VERSION(vs) ((vs >> 24) & 0xff) -#define GET_ABI_MIN_VERSION(vs) ((vs >> 16) & 0xff) -#define GET_ABI_REV_VERSION(vs) (vs & 0xffff) - -#define CURRENT_ABI_VERSION DEFINE_PLUGIN_ABI_VERSION(0, 3, 0) -  /* ------------------------- DEFINITION D'UN PROJET INTERNE ------------------------- */ @@ -232,14 +220,14 @@ typedef enum _PluginAction  /* ------------------------ PREMIER INTERFACAGE PROTOCOLAIRE ------------------------ */ -#define CHRYSALIDE_PLUGIN_MAGIC 0xdeadc0de1234abcdull +//#define CHRYSALIDE_PLUGIN_MAGIC 0xdeadc0de1234abcdull  /* Définition d'un greffon */  typedef struct _plugin_interface  {      uint64_t magic;                         /* Vérification a minima       */ -    plugin_abi_version_t abi_version;       /* Version du protocole utilisé*/ +    uint32_t /*plugin_abi_version_t*/ abi_version;       /* Version du protocole utilisé*/      /**       * Les champs suivants ne sont généralement pas alloués dynamiquement, diff --git a/src/plugins/plugin-int.h b/src/plugins/plugin-int.h index 3ba19dc..07b455a 100644 --- a/src/plugins/plugin-int.h +++ b/src/plugins/plugin-int.h @@ -37,21 +37,28 @@  #include "../common/bits.h" -/* Transfert de la conscience de soi. */ -typedef void (* pg_set_self_fc) (GPluginModule *); -/* Prend acte du [dé]chargement du greffon. */ +/* Pointe le fichier contenant le greffon manipulé. */ +typedef char * (* get_plugin_filename_fc) (const GPluginModule *); + +/* Fournit le nom brut associé au greffon. */ +typedef char * (* get_plugin_modname_fc) (const GPluginModule *); + +/* Prend acte de (l'|la dés)activation du greffon. */  typedef bool (* pg_management_fc) (GPluginModule *); + + + +/* Transfert de la conscience de soi. */ +typedef void (* pg_set_self_fc) (GPluginModule *); +  /* Accompagne la fin du chargement des modules natifs. */  typedef void (* pg_plugins_loaded_fc) (GPluginModule *, PluginAction);  /* Crée une instance à partir d'un type dynamique externe. */  typedef gpointer (* pg_build_instance_fc) (GPluginModule *, PluginAction, GType); -/* Fournit le nom brut associé au greffon. */ -typedef char * (* pg_get_modname_fc) (const GPluginModule *); -  #if 0  /* Procède à une opération liée à un contenu binaire. */ @@ -90,22 +97,47 @@ typedef void (* pg_detect_tools_fc) (const GPluginModule *, PluginAction, const  #endif +/* Marqueur identifiable */ +#define CHRYSALIDE_PLUGIN_MAGIC 0xdeadc0de + + +/* Version identifiant les définitions courantes */ +typedef uint32_t plugin_abi_version_t; + +#define DEFINE_PLUGIN_ABI_VERSION(maj, min, rev) \ +    (((maj & 0xff) << 24) | ((min & 0xff) << 16) | (rev & 0xffff)) + +#define GET_ABI_MAJ_VERSION(vs) ((vs >> 24) & 0xff) +#define GET_ABI_MIN_VERSION(vs) ((vs >> 16) & 0xff) +#define GET_ABI_REV_VERSION(vs) (vs & 0xffff) + +/** + * 0.3.0 : dernière version avec actions et fonctions associées + * 1.0.0 (04/01/25) : bascule en chargement d'objet et interfaces + */ +#define CURRENT_ABI_VERSION DEFINE_PLUGIN_ABI_VERSION(1, 0, 0) + +  /* Greffon pour Chrysalide (instance) */  struct _GPluginModule  {      GObject parent;                         /* A laisser en premier        */ -    char *filename;                         /* Fichier associé au greffon  */ -    GModule *module;                        /* Abstration de manipulation  */ +    uint32_t magic;                         /* Vérification a minima       */ +    plugin_abi_version_t abi_version;       /* Version du protocole utilisé*/ + +    char *name;                             /* Désignation humaine courte  */ +    char *desc;                             /* Description plus loquace    */ +    char *version;                          /* Version du greffon          */ +    char *url;                              /* Site Web associé            */ -    const plugin_interface *interface;      /* Déclaration d'interfaçage   */ +    char **required;                        /* Pré-chargements requis      */ +    size_t required_count;                  /* Quantité de ces dépendances */      PluginStatusFlags flags;                /* Fanion pour l'état courant  */      bitfield_t *dependencies;               /* Cartographie des dépendances*/ -    //GGenConfig *config;                     /* Configuration dédiée        */ -  }; @@ -114,6 +146,18 @@ struct _GPluginModuleClass  {      GObjectClass parent;                    /* A laisser en premier        */ +    get_plugin_filename_fc get_filename;    /* Obtention du chemin         */ +    get_plugin_modname_fc get_modname;      /* Fourniture du nom brut      */ + +    pg_management_fc enable;                /* Procédure d'activation      */ +    pg_management_fc disable;               /* Procédure d'extinction      */ + + + +    ///////////////////////////////////////////// + +#if 0 +      pg_management_fc init;                  /* Procédure d'initialisation  */      pg_management_fc manage;                /* Etape dans la vie du greffon*/      pg_management_fc exit;                  /* Procédure d'extinction      */ @@ -121,8 +165,6 @@ struct _GPluginModuleClass      pg_plugins_loaded_fc plugins_loaded;    /* Fin des chargements         */      pg_build_instance_fc build_instance;    /* Création d'objets           */ -    pg_get_modname_fc get_modname;          /* Fourniture du nom brut      */ -  #if 0  #ifdef INCLUDE_GTK_SUPPORT      pg_include_theme_fc include_theme;      /* Extension d'un thème        */ @@ -141,12 +183,28 @@ struct _GPluginModuleClass      pg_detect_tools_fc detect;              /* Lancement de détections     */  #endif +#endif + +    ///////////////////////////////////////////// +  }; -/* Met en place la configuration dédiée au greffon. */ -void g_plugin_module_create_config(GPluginModule *); + +#define STORE_PLUGIN_ABI(p)                     \ +    do                                          \ +    {                                           \ +        GPluginModule *_p;                      \ +        _p = G_PLUGIN_MODULE(p);                \ +        _p->magic = CHRYSALIDE_PLUGIN_MAGIC;    \ +        _p->abi_version = CURRENT_ABI_VERSION;  \ +    }                                           \ +    while (0); + + +/* Met en place un greffon. */ +bool g_plugin_module_create(GPluginModule *, const char *, const char *, const char *, const char *, const char * const *, size_t); diff --git a/src/plugins/plugin.c b/src/plugins/plugin.c index 5b3e475..dfdf3ed 100644 --- a/src/plugins/plugin.c +++ b/src/plugins/plugin.c @@ -30,14 +30,13 @@  #include <libgen.h>  #include <malloc.h>  #include <stdarg.h> -#include <stdbool.h>  #include <stdio.h>  #include <string.h> -#include "dt.h"  #include "pglist.h"  #include "plugin-int.h" +#include "../common/compiler.h"  #include "../common/extstr.h"  #include "../common/pathname.h"  #include "../common/xdg.h" @@ -56,19 +55,12 @@ static void g_plugin_module_dispose(GPluginModule *);  /* Procède à la libération totale de la mémoire. */  static void g_plugin_module_finalize(GPluginModule *); -/* Initialise la classe des greffons d'extension. */ -static void g_plugin_module_init_gclass(GPluginModuleClass *, GModule *); - -/* Fournit le nom brut associé au greffon. */ -static char *_g_plugin_module_get_modname(const GPluginModule *); -  /* Indique le type défini pour un greffon. */  G_DEFINE_TYPE(GPluginModule, g_plugin_module, G_TYPE_OBJECT); -  /******************************************************************************  *                                                                             *  *  Paramètres  : class = classe à initialiser.                                * @@ -84,16 +76,17 @@ G_DEFINE_TYPE(GPluginModule, g_plugin_module, G_TYPE_OBJECT);  static void g_plugin_module_class_init(GPluginModuleClass *class)  {      GObjectClass *object;                   /* Autre version de la classe  */ -    GPluginModuleClass *plugin;             /* Version parente de la classe*/      object = G_OBJECT_CLASS(class);      object->dispose = (GObjectFinalizeFunc/* ! */)g_plugin_module_dispose;      object->finalize = (GObjectFinalizeFunc)g_plugin_module_finalize; -    plugin = G_PLUGIN_MODULE_CLASS(class); +    class->get_filename = NULL; +    class->get_modname = NULL; -    plugin->get_modname = (pg_get_modname_fc)_g_plugin_module_get_modname; +    class->enable = NULL; +    class->disable = NULL;  } @@ -112,7 +105,17 @@ static void g_plugin_module_class_init(GPluginModuleClass *class)  static void g_plugin_module_init(GPluginModule *plugin)  { -    //plugin->config = NULL; +    plugin->name = NULL; +    plugin->desc = NULL; +    plugin->version = NULL; +    plugin->url = NULL; + +    plugin->required = NULL; +    plugin->required_count = 0; + +    plugin->flags = PSF_NONE; + +    plugin->dependencies = NULL;  } @@ -131,29 +134,29 @@ static void g_plugin_module_init(GPluginModule *plugin)  static void g_plugin_module_dispose(GPluginModule *plugin)  { -    const plugin_interface *pg_iface;       /* Définition du greffon       */      size_t i;                               /* Boucle de parcours          */ +    size_t index;                           /* Indice de greffon visé      */      GPluginModule *dependency;              /* Module nécessaire           */      GPluginModuleClass *class;              /* Classe de l'instance active */ -    pg_iface = g_plugin_module_get_interface(plugin); - -    if (pg_iface != NULL) +    if (plugin->dependencies != NULL)      {          lock_plugin_list_for_reading(); -        for (i = 0; i < pg_iface->required_count; i++) +        for (i = 0; i < plugin->required_count; i++)          { -            dependency = get_plugin_by_name(pg_iface->required[i], NULL); +            dependency = get_plugin_by_name(plugin->required[i], &index); -            /* Si le chargement a bien été complet avant la sortie... */ -            if (dependency != NULL) +            /* Si la dépendance a bien été pris en compte... */ +            if (test_in_bit_field(plugin->dependencies, index))              { +                assert(dependency != NULL); +                  /* Un coup pour l'appel à get_plugin_by_name(). */ -                g_object_unref(G_OBJECT(dependency)); +                unref_object(dependency);                  /* Un coup pour la dépendance */ -                g_object_unref(G_OBJECT(dependency)); +                unref_object(dependency);              } @@ -163,25 +166,13 @@ static void g_plugin_module_dispose(GPluginModule *plugin)      } -    class = G_PLUGIN_MODULE_GET_CLASS(plugin); - -    if (class->exit != NULL) -        class->exit(plugin); - -    /* -    if (plugin->config != NULL) +    if (plugin->flags & PSF_LOADED)      { -        g_generic_config_write(plugin->config); - -        g_clear_object(&plugin->config); +        class = G_PLUGIN_MODULE_GET_CLASS(plugin); -    } -    */ +        if (class->disable != NULL) +            class->disable(plugin); -    if (plugin->module != NULL) -    { -        g_module_close(plugin->module); -        plugin->module = NULL;      }      G_OBJECT_CLASS(g_plugin_module_parent_class)->dispose(G_OBJECT(plugin)); @@ -203,7 +194,25 @@ static void g_plugin_module_dispose(GPluginModule *plugin)  static void g_plugin_module_finalize(GPluginModule *plugin)  { -    free(plugin->filename); +    size_t i;                               /* Boucle de parcours          */ + +    if (plugin->name != NULL) +        free(plugin->name); + +    if (plugin->desc != NULL) +        free(plugin->desc); + +    if  (plugin->version != NULL) +        free(plugin->version); + +    if (plugin->url != NULL) +        free(plugin->url); + +    for (i = 0; i < plugin->required_count; i++) +        free(plugin->required[i]); + +    if (plugin->required != NULL) +        free(plugin->required);      if (plugin->dependencies != NULL)          delete_bit_field(plugin->dependencies); @@ -215,627 +224,173 @@ static void g_plugin_module_finalize(GPluginModule *plugin)  /******************************************************************************  *                                                                             * -*  Paramètres  : filename = nom du fichier à charger.                         * +*  Paramètres  : plugin   = instance à initialiser pleinement.                * +*                name     = nom du greffon pour référence, principalement.    * +*                desc     = présentation éventuelle à destination humaine.    * +*                version  = indication de version éventuelle.                 * +*                url      = référence vers une ressource en ligne.            * +*                required = liste de dépendances éventuelles ou NULL.         * +*                count    = taille de cette liste.                            *  *                                                                             * -*  Description : Crée un module pour un greffon donné.                        * +*  Description : Met en place un greffon.                                     *  *                                                                             * -*  Retour      : Adresse de la structure mise en place.                       * +*  Retour      : Bilan de l'opération.                                        *  *                                                                             *  *  Remarques   : -                                                            *  *                                                                             *  ******************************************************************************/ -GPluginModule *g_plugin_module_new(const gchar *filename) +bool g_plugin_module_create(GPluginModule *plugin, const char *name, const char *desc, const char *version, const char *url, const char * const *required, size_t count)  { -    GPluginModule *result;                  /* Structure à retourner       */ -    GModule *module;                        /* Abstration de manipulation  */ -    pg_set_self_fc set_self;                /* Copie du greffon            */ -    const plugin_interface *interface;      /* Déclaration d'interfaçage   */ -    plugin_abi_version_t current;           /* Version de l'ABI actuelle   */ -    bool valid;                             /* Statut de validité          */ -    size_t i;                               /* Boucle de parcours          */ -    uint32_t action;                        /* Identifiant d'une action    */ -    uint32_t category;                      /* Catégorie principale        */ -    uint32_t sub;                           /* Sous-catégorie visée        */ -    GType gtype;                            /* Nouveau type de greffon     */ - -    module = g_module_open(filename, G_MODULE_BIND_LAZY); -    if (module == NULL) -    { -        log_variadic_message(LMT_ERROR,  -                             _("Error while loading the plugin candidate '%s' : %s"), -                             filename, g_module_error()); -        goto bad_module; -    } - - -#define load_plugin_symbol(mod, sym, dest)                                          \ -    ({                                                                              \ -        bool __result;                                                              \ -        if (!g_module_symbol(mod, sym, (gpointer *)dest))                           \ -        {                                                                           \ -            log_variadic_message(LMT_ERROR,                                         \ -                                 _("No '%s' entry in plugin candidate '%s'"),       \ -                                 sym, filename);                                    \ -            __result = false;                                                       \ -        }                                                                           \ -        else __result = true;                                                       \ -        __result;                                                                   \ -    }) - - -    /* Récupération de la version d'ABI */ - -    if (!load_plugin_symbol(module, "chrysalide_plugin_set_self", &set_self)) -        goto no_self_setter; - -    if (!load_plugin_symbol(module, "_chrysalide_plugin", &interface)) -        goto no_interface; - -    current = CURRENT_ABI_VERSION; - -    if (current != interface->abi_version) -        goto wrong_abi; - -    /* Localisation des différents points d'entrée déclarés */ - +    bool result;                            /* Bilan à retourner           */ +    size_t i;                               /* Boucle de parcours #1       */ +    size_t k;                               /* Boucle de parcours #2       */ -#define check_plugin_symbol(mod, sym)                                           \ -    ({                                                                          \ -        bool __result;                                                          \ -        __result = g_module_symbol(mod, sym, (gpointer []) { NULL });           \ -        if (!__result)                                                          \ -            log_variadic_message(LMT_ERROR,                                     \ -                                 _("No '%s' entry in plugin candidate '%s'"),   \ -                                 sym, filename);                                \ -        __result;                                                               \ -    }) +    /* Validations préalables */ +    assert(name != NULL); -    valid = true; +    result = (name != NULL); -    for (i = 0; i < interface->actions_count && valid; i++) +    if (result && plugin->abi_version != CURRENT_ABI_VERSION)      { -        action = interface->actions[i]; -        category = MASK_PLUGIN_CATEGORY(action); -        sub = MASK_PLUGIN_SUB_CATEGORY(action); - -        switch (category) -        { -            case DPC_BASIC: - -                switch (sub) -                { -                    case DPS_NONE: -                        break; - -                    case DPS_PG_MANAGEMENT: - -                        switch (action) -                        { -                            case PGA_PLUGIN_INIT: -                                valid = check_plugin_symbol(module, "chrysalide_plugin_init"); -                                break; - -                            case PGA_PLUGIN_LOADED: -                                valid = check_plugin_symbol(module, "chrysalide_plugin_manage"); -                                break; - -                            case PGA_PLUGIN_EXIT: -                                valid = check_plugin_symbol(module, "chrysalide_plugin_exit"); -                                break; - -                            default: -                                log_variadic_message(LMT_WARNING, -                                                     _("Unknown action '0x%02x' in plugin '%s'..."), -                                                     interface->actions[i], filename); -                                break; - -                        } - -                        break; - -                    case DPS_CORE_MANAGEMENT: - -                        switch (action) -                        { -                            case PGA_NATIVE_PLUGINS_LOADED: -                            case PGA_ALL_PLUGINS_LOADED: -                                valid = check_plugin_symbol(module, "chrysalide_plugin_on_plugins_loaded"); -                                break; - -                            case PGA_TYPE_BUILDING: -                                valid = check_plugin_symbol(module, "chrysalide_plugin_build_type_instance"); -                                break; - -                            default: -                                log_variadic_message(LMT_WARNING, -                                                     _("Unknown action '0x%02x' in plugin '%s'..."), -                                                     interface->actions[i], filename); -                                break; - -                        } - -                        break; - -                    default: -                        log_variadic_message(LMT_WARNING, -                                             _("Unknown sub-category '0x%02x' in plugin '%s'..."), sub, filename); -                        break; - -                } - -                break; - -#if 0 - -            case DPC_GUI: - -                switch (sub) -                { -                    case DPS_SETUP: - -                        switch (action) -                        { -                            case PGA_GUI_THEME: -                                valid = check_plugin_symbol(module, "chrysalide_plugin_include_theme"); -                                break; - -                            default: -                                log_variadic_message(LMT_WARNING, -                                                     _("Unknown action '0x%02x' in plugin '%s'..."), -                                                     interface->actions[i], filename); -                                break; - -                        } - -                        break; - -                    case DPS_RUNNING: - -                        switch (action) -                        { -                            case PGA_PANEL_CREATION: -                                valid = check_plugin_symbol(module, "chrysalide_plugin_on_panel_creation"); -                                break; - -                            case PGA_PANEL_DOCKING: -                                valid = check_plugin_symbol(module, "chrysalide_plugin_on_panel_docking"); -                                break; - -                            default: -                                log_variadic_message(LMT_WARNING, -                                                     _("Unknown action '0x%02x' in plugin '%s'..."), -                                                     interface->actions[i], filename); -                                break; - -                        } - -                        break; - -                    default: -                        log_variadic_message(LMT_WARNING, -                                             _("Unknown sub-category '0x%02x' in plugin '%s'..."), sub, filename); -                        break; - -                } - -                break; - -            case DPC_BINARY_PROCESSING: - -                switch (sub) -                { -                    case DPS_CONTENT: - -                        switch (action) -                        { -                            case PGA_CONTENT_EXPLORER: -                            case PGA_CONTENT_RESOLVER: -                                valid = check_plugin_symbol(module, "chrysalide_plugin_handle_binary_content"); -                                break; - -                            case PGA_CONTENT_ANALYZED: -                                valid = check_plugin_symbol(module, "chrysalide_plugin_handle_loaded_content"); -                                break; - -                            default: -                                log_variadic_message(LMT_WARNING, -                                                     _("Unknown action '0x%02x' in plugin '%s'..."), -                                                     interface->actions[i], filename); -                                break; - -                        } +        result = false; -                        break; - -                    case DPS_FORMAT: +        log_variadic_message(LMT_ERROR, _("ABI mismatch detected: %08x (plugin) vs %08x (core)"), +                             plugin->abi_version, CURRENT_ABI_VERSION); -                        switch (action) -                        { -                            case PGA_FORMAT_ANALYSIS_STARTED: -                            case PGA_FORMAT_ANALYSIS_ENDED: -                            case PGA_FORMAT_POST_ANALYSIS_STARTED: -                            case PGA_FORMAT_POST_ANALYSIS_ENDED: -                                valid = check_plugin_symbol(module, "chrysalide_plugin_handle_binary_format_analysis"); -                                break; +    } -                            case PGA_FORMAT_PRELOAD: -                                valid = check_plugin_symbol(module, "chrysalide_plugin_preload_binary_format"); -                                break; +    /* Mémorisation des informations */ -                            case PGA_FORMAT_ATTACH_DEBUG: -                                valid = check_plugin_symbol(module, "chrysalide_plugin_attach_debug"); -                                break; +    if (result) +    { +        plugin->name = strdup(name); -                            default: -                                log_variadic_message(LMT_WARNING, -                                                     _("Unknown action '0x%02x' in plugin '%s'..."), -                                                     interface->actions[i], filename); -                                break; +        if (desc != NULL) +            plugin->desc = strdup(desc); -                        } +        if (version != NULL) +            plugin->version = strdup(version); -                        break; +        if (url != NULL) +            plugin->url = strdup(url); -                    case DPS_DISASSEMBLY: -                        valid = check_plugin_symbol(module, "chrysalide_plugin_process_disassembly_event"); -                        break; - -                    case DPS_DETECTION: -                        valid = check_plugin_symbol(module, "chrysalide_plugin_detect_external_tools"); -                        break; +        if (count > 0) +        { +            plugin->required = malloc(count * sizeof(char *)); +            plugin->required_count = 0; -                    default: -                        log_variadic_message(LMT_WARNING, -                                             _("Unknown sub-category '0x%02x' in plugin '%s'..."), sub, filename); +            for (i = 0; i < count; i++) +            { +                for (k = 0; k < plugin->required_count; k++) +                    if (strcmp(required[i], plugin->required[k]) == 0)                          break; -                } +                if (k < plugin->required_count) +                    continue; -#endif +                plugin->required[plugin->required_count++] = strdup(required[i]); -                break; +            } -            default: -                log_variadic_message(LMT_WARNING, -                                     _("Unknown category '0x%02x' in plugin '%s'..."), category, filename); -                break; +            plugin->required = realloc(plugin->required, plugin->required_count * sizeof(char *));          }      } -    if (!valid) -        goto missing_feature; - -    gtype = build_dynamic_type(G_TYPE_PLUGIN_MODULE, interface->gtp_name, -                               (GClassInitFunc)g_plugin_module_init_gclass, module, NULL); - -    if (gtype == G_TYPE_INVALID) -        goto no_instance; - -    result = g_object_new(gtype, NULL); - -    result->filename = strdup(filename); -    result->module = module; - -    result->interface = interface; - -    set_self(result); -      return result; - no_self_setter: - -    log_variadic_message(LMT_ERROR, _("Self pointer setter is missing for plugin '%s'"), filename); -    goto bad_plugin; - - no_interface: - -    log_variadic_message(LMT_ERROR, _("Main interface is missing for plugin '%s'"), filename); -    goto bad_plugin; - - wrong_abi: - -    log_variadic_message(LMT_ERROR, _("ABI mismatch detected! Plugin '%s' rejected"), filename); -    goto bad_plugin; - - missing_feature: - -    log_variadic_message(LMT_ERROR, _("An expected feature is missing for plugin '%s'"), filename); -    goto bad_plugin; - - no_instance: - -    log_variadic_message(LMT_ERROR, _("Unabled to create an instance of plugin '%s'"), filename); - - bad_plugin: - -    g_module_close(module); - - bad_module: - -    return NULL; -  }  /******************************************************************************  *                                                                             * -*  Paramètres  : class  = classe à initialiser.                               * -*                module = module représentant le greffon chargé en mémoire.   * +*  Paramètres  : plugin = greffon à consulter.                                *  *                                                                             * -*  Description : Initialise la classe des greffons d'extension.               * +*  Description : Indique le nom associé à un greffon.                         *  *                                                                             * -*  Retour      : -                                                            * +*  Retour      : Désignation interne de l'extension, pour référence(s).       *  *                                                                             *  *  Remarques   : -                                                            *  *                                                                             *  ******************************************************************************/ -static void g_plugin_module_init_gclass(GPluginModuleClass *class, GModule *module) +const char *g_plugin_module_get_name(const GPluginModule *plugin)  { -    const plugin_interface *interface;      /* Déclaration d'interfaçage   */ -    size_t i;                               /* Boucle de parcours          */ -    uint32_t action;                        /* Identifiant d'une action    */ -    uint32_t category;                      /* Catégorie principale        */ -    uint32_t sub;                           /* Sous-catégorie visée        */ - - -#undef load_plugin_symbol - -#define load_plugin_symbol(mod, sym, dest)                          \ -    ({                                                              \ -        bool __result;                                              \ -        __result = g_module_symbol(mod, sym, (gpointer *)dest);     \ -        assert(__result);                                           \ -        __result;                                                   \ -    }) - - -    load_plugin_symbol(module, "_chrysalide_plugin", &interface); - -    for (i = 0; i < interface->actions_count; i++) -    { -        action = interface->actions[i]; -        category = MASK_PLUGIN_CATEGORY(action); -        sub = MASK_PLUGIN_SUB_CATEGORY(action); - -        switch (category) -        { -            case DPC_BASIC: - -                switch (sub) -                { -                    case DPS_NONE: -                        break; - -                    case DPS_PG_MANAGEMENT: - -                        switch (action) -                        { -                            case PGA_PLUGIN_INIT: -                                load_plugin_symbol(module, "chrysalide_plugin_init", &class->init); -                                break; - -                            case PGA_PLUGIN_LOADED: -                                load_plugin_symbol(module, "chrysalide_plugin_manage", &class->manage); -                                break; - -                            case PGA_PLUGIN_EXIT: -                                load_plugin_symbol(module, "chrysalide_plugin_exit", &class->exit); -                                break; - -                            default: -                                assert(false); -                                break; - -                        } - -                        break; - -                    case DPS_CORE_MANAGEMENT: - -                        switch (action) -                        { -                            case PGA_NATIVE_PLUGINS_LOADED: -                            case PGA_ALL_PLUGINS_LOADED: -                                load_plugin_symbol(module, "chrysalide_plugin_on_plugins_loaded", -                                                   &class->plugins_loaded); -                                break; - -                            case PGA_TYPE_BUILDING: -                                load_plugin_symbol(module, "chrysalide_plugin_build_type_instance", -                                                   &class->build_instance); -                                break; - -                            default: -                                assert(false); -                                break; - -                        } - -                        break; - -                    default: -                        assert(false); -                        break; - -                } - -                break; -#if 0 -            case DPC_GUI: - -                switch (sub) -                { -                    case DPS_SETUP: - -                        switch (action) -                        { -                            case PGA_GUI_THEME: -#ifdef INCLUDE_GTK_SUPPORT -                                load_plugin_symbol(module, "chrysalide_plugin_include_theme", -                                                   &class->include_theme); -#endif -                                break; - -                            default: -                                assert(false); -                                break; - -                        } - -                        break; - -                    case DPS_RUNNING: - -                        switch (action) -                        { -                            case PGA_PANEL_CREATION: -#ifdef INCLUDE_GTK_SUPPORT -                                load_plugin_symbol(module, "chrysalide_plugin_on_panel_creation", -                                                   &class->notify_panel); -#endif -                                break; - -                            case PGA_PANEL_DOCKING: -#ifdef INCLUDE_GTK_SUPPORT -                                load_plugin_symbol(module, "chrysalide_plugin_on_panel_docking", -                                                   &class->notify_docking); -#endif -                                break; - -                            default: -                                assert(false); -                                break; - -                        } - -                        break; - -                    default: -                        assert(false); -                        break; +    const char *result;                     /* Valeur finale à renvoyer    */ -                } +    result = plugin->name; -                break; - -            case DPC_BINARY_PROCESSING: - -                switch (sub) -                { -                    case DPS_CONTENT: - -                        switch (action) -                        { -                            case PGA_CONTENT_EXPLORER: -                            case PGA_CONTENT_RESOLVER: -                                load_plugin_symbol(module, "chrysalide_plugin_handle_binary_content", -                                                   &class->handle_content); -                                break; - -                            case PGA_CONTENT_ANALYZED: -                                load_plugin_symbol(module, "chrysalide_plugin_handle_loaded_content", -                                                   &class->handle_loaded); -                                break; - -                            default: -                                assert(false); -                                break; - -                        } - -                        break; - -                    case DPS_FORMAT: - -                        switch (action) -                        { -                            case PGA_FORMAT_ANALYSIS_STARTED: -                            case PGA_FORMAT_ANALYSIS_ENDED: -                            case PGA_FORMAT_POST_ANALYSIS_STARTED: -                            case PGA_FORMAT_POST_ANALYSIS_ENDED: -                                load_plugin_symbol(module, "chrysalide_plugin_handle_binary_format_analysis", -                                                   &class->handle_fmt_analysis); -                                break; - -                            case PGA_FORMAT_PRELOAD: -                                load_plugin_symbol(module, "chrysalide_plugin_preload_binary_format", &class->preload_format); -                                break; - -                            case PGA_FORMAT_ATTACH_DEBUG: -                                load_plugin_symbol(module, "chrysalide_plugin_attach_debug", &class->attach_debug); -                                break; +    return result; -                            default: -                                assert(false); -                                break; +} -                        } -                        break; +/****************************************************************************** +*                                                                             * +*  Paramètres  : plugin = greffon à consulter.                                * +*                                                                             * +*  Description : Fournit une description fonctionnelle d'un greffon.          * +*                                                                             * +*  Retour      : Description textuelle associée à une extension ou NULL.      * +*                                                                             * +*  Remarques   : -                                                            * +*                                                                             * +******************************************************************************/ -                    case DPS_DISASSEMBLY: -                        load_plugin_symbol(module, "chrysalide_plugin_process_disassembly_event", &class->process_disass); -                        break; +const char *g_plugin_module_get_desc(const GPluginModule *plugin) +{ +    const char *result;                     /* Valeur finale à renvoyer    */ -                    case DPS_DETECTION: -                        load_plugin_symbol(module, "chrysalide_plugin_detect_external_tools", &class->detect); -                        break; +    result = plugin->desc; -                    default: -                        assert(false); -                        break; +    return result; -                } +} -#endif -                break; +/****************************************************************************** +*                                                                             * +*  Paramètres  : plugin = greffon à consulter.                                * +*                                                                             * +*  Description : Fournit la version d'un greffon et de ses fonctionnalités.   * +*                                                                             * +*  Retour      : Version sous forme de chaîne de caractères ou NULL.          * +*                                                                             * +*  Remarques   : -                                                            * +*                                                                             * +******************************************************************************/ -            default: -                assert(false); -                break; +const char *g_plugin_module_get_version(const GPluginModule *plugin) +{ +    const char *result;                     /* Valeur finale à renvoyer    */ -        } +    result = plugin->version; -    } +    return result;  }  /******************************************************************************  *                                                                             * -*  Paramètres  : plugin = greffon à valider.                                  * +*  Paramètres  : plugin = greffon à consulter.                                *  *                                                                             * -*  Description : Fournit le nom brut associé au greffon.                      * +*  Description : Fournit l'URL des ressources en ligne liées à un greffon.    *  *                                                                             * -*  Retour      : Désignation brute du greffon.                                * +*  Retour      : URL de renvoi associée à une extension ou NULL.              *  *                                                                             *  *  Remarques   : -                                                            *  *                                                                             *  ******************************************************************************/ -char *g_plugin_module_get_modname(const GPluginModule *plugin) +const char *g_plugin_module_get_url(const GPluginModule *plugin)  { -    char *result;                           /* Désignation brute à renvoyer*/ -    GPluginModuleClass *class;              /* Classe de l'instance active */ - -    class = G_PLUGIN_MODULE_GET_CLASS(plugin); - -    result = class->get_modname(plugin); +    const char *result;                     /* Valeur finale à renvoyer    */ -    /** -     * Tente une opération de la dernière chance. -     * -     * Dans le cas d'un module Python, la fonction de classe peut ne pas -     * trouver de support si l'extension Python n'est pas au point. -     */ -    if (result == NULL && class->get_modname != _g_plugin_module_get_modname) -        result = _g_plugin_module_get_modname(plugin); +    result = plugin->url;      return result; @@ -844,41 +399,24 @@ char *g_plugin_module_get_modname(const GPluginModule *plugin)  /******************************************************************************  *                                                                             * -*  Paramètres  : plugin = greffon à valider.                                  * +*  Paramètres  : plugin = greffon à consulter.                                * +*                count  = taille de la liste fournie. [OUT]                   *  *                                                                             * -*  Description : Fournit le nom brut associé au greffon.                      * +*  Description : Fournit la liste des dépendances d'un greffon donné.         *  *                                                                             * -*  Retour      : Désignation brute du greffon.                                * +*  Retour      : Liste des noms d'extensions requises pour une extension.     *  *                                                                             *  *  Remarques   : -                                                            *  *                                                                             *  ******************************************************************************/ -static char *_g_plugin_module_get_modname(const GPluginModule *plugin) +const char * const *g_plugin_module_get_requirements(const GPluginModule *plugin, size_t *count)  { -    char *result;                           /* Désignation brute à renvoyer*/ -    char *path;                             /* Chemin à traiter            */ -    char *filename;                         /* Nom de bibliothèque partagée*/ -    size_t length;                          /* Taille du nom               */ - -    path = strdup(g_plugin_module_get_filename(G_PLUGIN_MODULE(plugin))); - -    filename = basename(path); - -    if (strncmp(filename, "lib", 3) == 0) -        filename += 3; - -    length = strlen(filename); - -    if (length >= 3) -    { -        if (strncmp(&filename[length - 3], ".so", 3) == 0) -            filename[length - 3] = '\0'; -    } +    const char * const *result;             /* Valeur finale à renvoyer    */ -    result = strdup(filename); +    result = CONST_ARRAY_CAST(plugin->required, char); -    free(path); +    *count = plugin->required_count;      return result; @@ -889,7 +427,7 @@ static char *_g_plugin_module_get_modname(const GPluginModule *plugin)  *                                                                             *  *  Paramètres  : plugin = greffon à consulter.                                *  *                                                                             * -*  Description : Indique le fichier contenant le greffon manipulé.            * +*  Description : Pointe le fichier contenant le greffon manipulé.             *  *                                                                             *  *  Retour      : Chemin d'accès au greffon.                                   *  *                                                                             * @@ -897,28 +435,42 @@ static char *_g_plugin_module_get_modname(const GPluginModule *plugin)  *                                                                             *  ******************************************************************************/ -const char *g_plugin_module_get_filename(const GPluginModule *plugin) +char *g_plugin_module_get_filename(const GPluginModule *plugin)  { -    return plugin->filename; +    char *result;                           /* Chemin d'accès à renvoyer   */ +    GPluginModuleClass *class;              /* Classe de l'instance active */ + +    class = G_PLUGIN_MODULE_GET_CLASS(plugin); + +    result = class->get_filename(plugin); + +    return result;  }  /******************************************************************************  *                                                                             * -*  Paramètres  : plugin = greffon à consulter.                                * +*  Paramètres  : plugin = greffon à valider.                                  *  *                                                                             * -*  Description : Fournit la description du greffon dans son intégralité.      * +*  Description : Fournit le nom brut associé au greffon.                      *  *                                                                             * -*  Retour      : Interfaçage renseigné.                                       * +*  Retour      : Désignation brute du greffon.                                *  *                                                                             *  *  Remarques   : -                                                            *  *                                                                             *  ******************************************************************************/ -const plugin_interface *g_plugin_module_get_interface(const GPluginModule *plugin) +char *g_plugin_module_get_modname(const GPluginModule *plugin)  { -    return plugin->interface; +    char *result;                           /* Désignation brute à renvoyer*/ +    GPluginModuleClass *class;              /* Classe de l'instance active */ + +    class = G_PLUGIN_MODULE_GET_CLASS(plugin); + +    result = class->get_modname(plugin); + +    return result;  } @@ -979,7 +531,6 @@ void g_plugin_module_override_flags(GPluginModule *plugin, PluginStatusFlags fla  bool g_plugin_module_resolve_dependencies(GPluginModule *plugin, GPluginModule **list, size_t count)  {      bool result;                            /* Bilan à faire remonter      */ -    const plugin_interface *pg_iface;       /* Définition du greffon       */      bitfield_t *new;                        /* Nouvelle définition         */      size_t i;                               /* Boucle de parcours          */      GPluginModule *dependency;              /* Module nécessaire           */ @@ -997,15 +548,13 @@ bool g_plugin_module_resolve_dependencies(GPluginModule *plugin, GPluginModule *      if ((plugin->flags & (PSF_UNKNOW_DEP | PSF_DEP_LOOP)) == 0)      { -        pg_iface = g_plugin_module_get_interface(plugin); -          /* Collecte des dépendances */          new = dup_bit_field(plugin->dependencies); -        for (i = 0; i < pg_iface->required_count; i++) +        for (i = 0; i < plugin->required_count; i++)          { -            dependency = get_plugin_by_name(pg_iface->required[i], &index); +            dependency = get_plugin_by_name(plugin->required[i], &index);              if (dependency == NULL)                  plugin->flags |= PSF_UNKNOW_DEP; @@ -1015,7 +564,7 @@ bool g_plugin_module_resolve_dependencies(GPluginModule *plugin, GPluginModule *                  if (dependency->dependencies == NULL)                      dependency->dependencies = create_bit_field(count, false); -                set_in_bit_field(new, index, 1); +                set_in_bit_field(new, index);                  or_bit_field(new, dependency->dependencies);                  /** @@ -1023,7 +572,7 @@ bool g_plugin_module_resolve_dependencies(GPluginModule *plugin, GPluginModule *                   */                  if (test_in_bit_field(plugin->dependencies, index)) -                    g_object_unref(G_OBJECT(dependency)); +                    unref_object(dependency);              } @@ -1041,13 +590,14 @@ bool g_plugin_module_resolve_dependencies(GPluginModule *plugin, GPluginModule *          /* Vérification sanitaire */ -        dependency = get_plugin_by_name(pg_iface->name, &index); +        dependency = get_plugin_by_name(plugin->name, &index);          assert(dependency != NULL); +        assert(dependency == plugin);          if (test_in_bit_field(plugin->dependencies, index))              plugin->flags |= PSF_DEP_LOOP; -        g_object_unref(G_OBJECT(dependency)); +        unref_object(dependency);      } @@ -1075,12 +625,12 @@ bool g_plugin_module_load(GPluginModule *plugin, GPluginModule **list, size_t co  {      bool result;                            /* Bilan à retourner           */      PluginStatusFlags flags;                /* Fanions de greffon          */ -    const plugin_interface *pg_iface;       /* Définition du greffon       */      size_t i;                               /* Boucle de parcours          */      GPluginModule *dependency;              /* Module nécessaire           */ +    char *filename;                         /* Chemin d'accès au greffon   */      GPluginModuleClass *class;              /* Classe de l'instance active */ -    //GGenConfig *config;                     /* Configuration à charger     */ -    char *dir;                              /* Répertoire modifiable       */ +    char *tmp;                              /* Chaîne modifiable           */ +    char *dir;                              /* Pointeur vers répertoire    */      /* Si un essai précédent a déjà échoué ou réussi... */ @@ -1092,40 +642,41 @@ bool g_plugin_module_load(GPluginModule *plugin, GPluginModule **list, size_t co      /* Chargement des dépendances */ -    pg_iface = g_plugin_module_get_interface(plugin); -      result = true; -    for (i = 0; i < pg_iface->required_count && result; i++) +    filename = g_plugin_module_get_filename(plugin); + +    for (i = 0; i < plugin->required_count && result; i++)      { -        dependency = get_plugin_by_name(pg_iface->required[i], NULL); +        dependency = get_plugin_by_name(plugin->required[i], NULL);          assert(dependency != NULL);          result = g_plugin_module_load(dependency, list, count); -        g_object_unref(G_OBJECT(dependency)); +        unref_object(dependency);      }      if (!result)      { -        log_variadic_message(LMT_ERROR, -                             _("Some dependencies failed to load for plugin '%s'"), plugin->filename); +        log_variadic_message(LMT_ERROR, _("Some dependencies failed to load for plugin '%s'"), filename); + +        plugin->flags |= PSF_FAILURE;          goto failure; +      }      /* Chargement du greffon courant */      class = G_PLUGIN_MODULE_GET_CLASS(plugin); -    if (class->init != NULL) +    if (class->enable != NULL)      { -        result = class->init(plugin); +        result = class->enable(plugin);          if (!result)          { -            log_variadic_message(LMT_ERROR, -                                 _("Plugin '%s' failed to load itself..."), plugin->filename); +            log_variadic_message(LMT_ERROR, _("Plugin '%s' failed to load itself..."), filename);              plugin->flags |= PSF_FAILURE;              goto failure; @@ -1134,39 +685,23 @@ bool g_plugin_module_load(GPluginModule *plugin, GPluginModule **list, size_t co      } -    g_plugin_module_create_config(plugin); - -    result = g_plugin_module_manage(plugin, PGA_PLUGIN_LOADED); - -    if (!result) -    { -        log_variadic_message(LMT_ERROR, -                             _("Plugin '%s' failed to complete loading..."), plugin->filename); - -        plugin->flags |= PSF_FAILURE; -        goto failure; - -    } - -    /* -    config = g_plugin_module_get_config(plugin); -    g_generic_config_read(config); -    g_object_unref(G_OBJECT(config)); -    */ +    /* Message de bilan */ -    dir = strdup(plugin->filename); -    dir = dirname(dir); +    tmp = strdup(filename); +    dir = dirname(tmp);      log_variadic_message(LMT_PROCESS,                           _("Loaded the '<b>%s</b>' file as plugin from the '<b>%s</b>' directory"), -                         strrchr(plugin->filename, G_DIR_SEPARATOR) + 1, dir); +                         strrchr(filename, G_DIR_SEPARATOR) + 1, dir); -    free(dir); +    free(tmp);      plugin->flags |= PSF_LOADED;   failure: +    free(filename); +      return result;  } @@ -1203,7 +738,7 @@ char *g_plugin_module_build_config_filename(const GPluginModule *plugin, const c      suffix = stradd(suffix, G_DIR_SEPARATOR_S);      suffix = stradd(suffix, final); -    result = get_xdg_config_dir(suffix); +    result = get_xdg_config_dir(suffix, true);      free(suffix);      free(modname); @@ -1227,31 +762,6 @@ char *g_plugin_module_build_config_filename(const GPluginModule *plugin, const c  /******************************************************************************  *                                                                             * -*  Paramètres  : plugin = greffon à compléter.                                * -*                                                                             * -*  Description : Met en place la configuration dédiée au greffon.             * -*                                                                             * -*  Retour      : -                                                            * -*                                                                             * -*  Remarques   : -                                                            * -*                                                                             * -******************************************************************************/ - -void g_plugin_module_create_config(GPluginModule *plugin) -{ -    char *filename;                         /* Chemin d'accès particulier  */ - -    filename = g_plugin_module_build_config_filename(plugin, "config.xml", false); - -    //plugin->config = g_generic_config_new_from_file(filename); - -    free(filename); - -} - - -/****************************************************************************** -*                                                                             *  *  Paramètres  : plugin = greffon à consulter.                                *  *                                                                             *  *  Description : Fournit la configuration mise en place pour le greffon.      * @@ -1295,11 +805,11 @@ void g_plugin_module_log_simple_message(const GPluginModule *plugin, LogMessageT      size_t len;                             /* Taille tampon disponible    */      char *buffer;                           /* Tampon du msg reconstitué   */ -    len = 4 + strlen(plugin->interface->name) + 6 + strlen(msg) + 1; +    len = 4 + strlen(plugin->name) + 6 + strlen(msg) + 1;      buffer = calloc(len, sizeof(char));      strcpy(buffer, "<i>["); -    strcat(buffer, plugin->interface->name); +    strcat(buffer, plugin->name);      strcat(buffer, "]</i> ");      strcat(buffer, msg); @@ -1345,80 +855,12 @@ void g_plugin_module_log_variadic_message(const GPluginModule *plugin, LogMessag  } -/****************************************************************************** -*                                                                             * -*  Paramètres  : plugin = greffon à manipuler.                                * -*                action = type d'action attendue.                             * -*                                                                             * -*  Description : Encadre une étape de la vie d'un greffon.                    * -*                                                                             * -*  Retour      : Bilan de l'opération.                                        * -*                                                                             * -*  Remarques   : -                                                            * -*                                                                             * -******************************************************************************/ - -bool g_plugin_module_manage(GPluginModule *plugin, PluginAction action) -{ -    bool result;                            /* Bilan à faire remonter      */ -    GPluginModuleClass *class;              /* Classe de l'instance active */ -    const plugin_interface *pg_iface;       /* Informations à consulter    */ -    size_t i;                               /* Boucle de parcours          */ -    bool handle_action;                     /* Action supportée ?          */ - -    class = G_PLUGIN_MODULE_GET_CLASS(plugin); - -    if (class->manage == NULL) -        result = true; - -    else -    { -        handle_action = false; - -        pg_iface = g_plugin_module_get_interface(plugin); - -        for (i = 0; i < pg_iface->actions_count; i++) -            if (pg_iface->actions[i] == PGA_PLUGIN_LOADED) -            { -                handle_action = true; -                break; -            } - -        if (handle_action) -            result = class->manage(plugin/*, action*/); -        else -            result = true; - -    } - -    return result; - -} - -/****************************************************************************** -*                                                                             * -*  Paramètres  : plugin = greffon à manipuler.                                * -*                action = type d'action attendue.                             * -*                unused = variable non utilisé pour l'usage de __VA_ARGS__.   * -*                                                                             * -*  Description : Accompagne la fin du chargement des modules.                 * -*                                                                             * -*  Retour      : -                                                            * -*                                                                             * -*  Remarques   : -                                                            * -*                                                                             * -******************************************************************************/ -void g_plugin_module_notify_plugins_loaded(GPluginModule *plugin, PluginAction action, void *unused) -{ -    GPluginModuleClass *class;              /* Classe de l'instance active */ -    class = G_PLUGIN_MODULE_GET_CLASS(plugin); -    class->plugins_loaded(plugin, action); -} +#if 0  /****************************************************************************** @@ -1450,8 +892,6 @@ gpointer g_plugin_module_build_type_instance(GPluginModule *plugin, PluginAction -#if 0 -  #ifdef INCLUDE_GTK_SUPPORT diff --git a/src/plugins/plugin.h b/src/plugins/plugin.h index 5c473b2..a4cc388 100644 --- a/src/plugins/plugin.h +++ b/src/plugins/plugin.h @@ -52,6 +52,27 @@  DECLARE_GTYPE(GPluginModule, g_plugin_module, G, PLUGIN_MODULE); +/* Indique le nom associé à un greffon. */ +const char *g_plugin_module_get_name(const GPluginModule *); + +/* Fournit une description fonctionnelle d'un greffon. */ +const char *g_plugin_module_get_desc(const GPluginModule *); + +/* Fournit la version d'un greffon et de ses fonctionnalités. */ +const char *g_plugin_module_get_version(const GPluginModule *); + +/* Fournit l'URL des ressources en ligne liées à un greffon. */ +const char *g_plugin_module_get_url(const GPluginModule *); + +/* Fournit la liste des dépendances d'un greffon donné. */ +const char * const *g_plugin_module_get_requirements(const GPluginModule *, size_t *); + +/* Pointe le fichier contenant le greffon manipulé. */ +char *g_plugin_module_get_filename(const GPluginModule *); + +/* Fournit le nom brut associé au greffon. */ +char *g_plugin_module_get_modname(const GPluginModule *); +  /* Fanions indiquant le statut du greffon */  typedef enum _PluginStatusFlags  { @@ -66,19 +87,6 @@ typedef enum _PluginStatusFlags  #define BROKEN_PLUGIN_STATUS (PSF_UNKNOW_DEP | PSF_DEP_LOOP | PSF_FAILURE) - -/* Crée un module pour un greffon donné. */ -GPluginModule *g_plugin_module_new(const gchar *); - -/* Fournit le nom brut associé au greffon. */ -char *g_plugin_module_get_modname(const GPluginModule *); - -/* Indique le fichier contenant le greffon manipulé. */ -const char *g_plugin_module_get_filename(const GPluginModule *); - -/* Fournit la description du greffon dans son intégralité. */ -const plugin_interface *g_plugin_module_get_interface(const GPluginModule *); -  /* Fournit des indications sur l'état du greffon. */  PluginStatusFlags g_plugin_module_get_flags(const GPluginModule *); @@ -103,17 +111,12 @@ void g_plugin_module_log_simple_message(const GPluginModule *, LogMessageType, c  /* Présente dans le journal un message complexe. */  void g_plugin_module_log_variadic_message(const GPluginModule *, LogMessageType, const char *, ...); -/* Encadre une étape de la vie d'un greffon. */ -bool g_plugin_module_manage(GPluginModule *, PluginAction); -/* Accompagne la fin du chargement des modules natifs. */ -void g_plugin_module_notify_plugins_loaded(GPluginModule *, PluginAction, void *); +#if 0  /* Crée une instance à partir d'un type dynamique externe. */  gpointer g_plugin_module_build_type_instance(GPluginModule *, PluginAction, GType); -#if 0 -  #ifdef INCLUDE_GTK_SUPPORT  /* Complète une liste de resources pour thème. */ diff --git a/src/plugins/self.h b/src/plugins/self.h index 4d5ddb0..78a3fe6 100644 --- a/src/plugins/self.h +++ b/src/plugins/self.h @@ -1,8 +1,8 @@  /* Chrysalide - Outil d'analyse de fichiers binaires - * self.h - définitions pour inclusion dans les différents greffons + * self.h - définitions de fonctionnalités facilitant la mise en place d'extensions natives   * - * Copyright (C) 2020 Cyrille Bagard + * Copyright (C) 2020-2025 Cyrille Bagard   *   *  This file is part of Chrysalide.   * @@ -26,72 +26,55 @@  #define _PLUGINS_SELF_H -#ifndef _PLUGINS_PLUGIN_H -#   include "plugin.h" -#endif +#include <assert.h> +#include <malloc.h> + + +#include "plugin.h"  #include "../common/compiler.h" -/* Facilitations de déclarations */ +/* Symboles principaux */ + +#define PLUGIN_CORE_SELF                                                        \ +static GPluginModule *_this_plugin = NULL;                                      \ +static void chrysalide_plugin_set_self(GPluginModule *);                        \ +static void chrysalide_plugin_set_self(GPluginModule *plugin)                   \ +{                                                                               \ +    assert(_this_plugin == NULL);                                               \ +    _this_plugin = plugin;                                                      \ +};                                                                              \ +__private GPluginModule *_chrysalide_plugin_get_self(void);                     \ +__private GPluginModule *_chrysalide_plugin_get_self(void)                      \ +{                                                                               \ +    return _this_plugin;                                                        \ +}; + +#define NATIVE_PLUGIN_ENTRYPOINT(fc)                                            \ +PLUGIN_CORE_SELF;                                                               \ +G_MODULE_EXPORT GPluginModule *get_chrysalide_plugin_instance(GModule *);       \ +G_MODULE_EXPORT GPluginModule *get_chrysalide_plugin_instance(GModule *module)  \ +{                                                                               \ +    GPluginModule *result;                  /* Instance à retourner        */   \ +    result = fc(module);                                                        \ +    chrysalide_plugin_set_self(result);                                         \ +    return result;                                                              \ +} + + +/* Spécifications */  #define CHRYSALIDE_WEBSITE(p) "https://www.chrysalide.re/" p -#define EMPTY_PG_LIST(name)                         \ -    name = NULL,                                    \ -    name ## _count = 0                              \ - -#define BUILD_PG_LIST(name, lst)                    \ -    name = lst,                                     \ -    name ## _count = sizeof(lst) / sizeof(lst[0])   \ - -#define AL(...) BUILD_PG_LIST(.actions, ((plugin_action_t []){ __VA_ARGS__ })) - -#define RL(...) BUILD_PG_LIST(.required, ((char *[]){ __VA_ARGS__ })) - -#define NO_REQ EMPTY_PG_LIST(.required) - - -/* Composants d'interface */ - -#define PLUGIN_CORE_SELF                                                                    \ -static GPluginModule *_this_plugin = NULL;                                                  \ -G_MODULE_EXPORT void chrysalide_plugin_set_self(GPluginModule *p);                          \ -G_MODULE_EXPORT void chrysalide_plugin_set_self(GPluginModule *p) { _this_plugin = p; };    \ -__private GPluginModule *_chrysalide_plugin_get_self(void);                                 \ -__private GPluginModule *_chrysalide_plugin_get_self(void) { return _this_plugin; }; - -#define PLUGIN_CORE_PROPS(n, d, v, u, c)                        \ -                                                                \ -    .magic = CHRYSALIDE_PLUGIN_MAGIC,                           \ -    .abi_version = CURRENT_ABI_VERSION,                         \ -                                                                \ -    .gtp_name = "G" n "Plugin",                                 \ -    .name = n,                                                  \ -    .desc = d,                                                  \ -    .version = v,                                               \ -    .url = u,                                                   \ -                                                                \ -    .container = c - -#define DEFINE_CHRYSALIDE_PLUGIN(n, d, v, u, r, a)              \ -PLUGIN_CORE_SELF                                                \ -G_MODULE_EXPORT const plugin_interface _chrysalide_plugin = {   \ -    PLUGIN_CORE_PROPS(n, d, v, u, false),                       \ -    r,                                                          \ -    a,                                                          \ -} +#define NO_REQ NULL, 0 -#define DEFINE_CHRYSALIDE_CONTAINER_PLUGIN(n, d, v, u, r, a)    \ -PLUGIN_CORE_SELF                                                \ -G_MODULE_EXPORT const plugin_interface _chrysalide_plugin = {   \ -    PLUGIN_CORE_PROPS(n, d, v, u, true),                        \ -    r,                                                          \ -    a,                                                          \ -} +#define BUILD_PG_LIST(lst) lst, sizeof(lst) / sizeof(lst[0]) + +#define REQ_LIST(...) BUILD_PG_LIST((const char *[]){ __VA_ARGS__ }) -/* Manipulations accélérées */ +/* Journalisation */  __private GPluginModule *_chrysalide_plugin_get_self(void); diff --git a/src/plugins/tweakable-int.h b/src/plugins/tweakable-int.h new file mode 100644 index 0000000..776626f --- /dev/null +++ b/src/plugins/tweakable-int.h @@ -0,0 +1,50 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * tweakable-int.h - définitions internes propres aux participations aux mécanismes de configuration + * + * 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 _PLUGINS_TWEAKABLE_INT_H +#define _PLUGINS_TWEAKABLE_INT_H + + +#include "tweakable.h" + + + +/* ------------------- INTEGRATION DANS L'EDITION DES PREFERENCES ------------------- */ + + +/* Fournit une liste de sections de configuration. */ +typedef tweak_info_t * (* get_tweakable_plugin_info) (const GTweakablePlugin *, size_t *); + + +/* Greffon avec des compléments pour l'interface de configuration (interface) */ +struct _GTweakablePluginInterface +{ +    GTypeInterface base_iface;              /* A laisser en premier        */ + +    get_tweakable_plugin_info get_info;     /* Récupération de section(s)  */ + +}; + + + +#endif  /* _PLUGINS_TWEAKABLE_INT_H */ diff --git a/src/plugins/tweakable.c b/src/plugins/tweakable.c new file mode 100644 index 0000000..517c4a3 --- /dev/null +++ b/src/plugins/tweakable.c @@ -0,0 +1,98 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * tweakable.c - participation aux mécanismes de configuration + * + * 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/>. + */ + + +#include "tweakable.h" + + +#include "tweakable-int.h" + + + +/* ------------------- INTEGRATION DANS L'EDITION DES PREFERENCES ------------------- */ + + +/* Procède à l'initialisation de l'interface d'intervention. */ +static void g_tweakable_plugin_default_init(GTweakablePluginInterface *); + + + +/* ---------------------------------------------------------------------------------- */ +/*                     INTEGRATION DANS L'EDITION DES PREFERENCES                     */ +/* ---------------------------------------------------------------------------------- */ + + +/* Détermine le type d'une interface pour l'intervention dans la gestion des greffons. */ +G_DEFINE_INTERFACE(GTweakablePlugin, g_tweakable_plugin, G_TYPE_OBJECT) + + +/****************************************************************************** +*                                                                             * +*  Paramètres  : iface = interface GLib à initialiser.                        * +*                                                                             * +*  Description : Procède à l'initialisation de l'interface d'intervention.    * +*                                                                             * +*  Retour      : -                                                            * +*                                                                             * +*  Remarques   : -                                                            * +*                                                                             * +******************************************************************************/ + +static void g_tweakable_plugin_default_init(GTweakablePluginInterface *iface) +{ +    iface->get_info = NULL; + +} + + +/****************************************************************************** +*                                                                             * +*  Paramètres  : plugin = interface à manipuler.                              * +*                count  = taille de la liste renvoyée. [OUT]                  * +*                                                                             * +*  Description : Fournit une liste de sections de configuration.              * +*                                                                             * +*  Retour      : Définition(s) de section de configuration ou NULL.           * +*                                                                             * +*  Remarques   : -                                                            * +*                                                                             * +******************************************************************************/ + +tweak_info_t *g_tweakable_plugin_get_tweak_info(const GTweakablePlugin *plugin, size_t *count) +{ +    tweak_info_t *result;                   /* Liste à renvoyer            */ +    GTweakablePluginInterface *iface;       /* Interface utilisée          */ + +    iface = G_TWEAKABLE_PLUGIN_GET_IFACE(plugin); + +    if (iface->get_info != NULL) +        result = iface->get_info(plugin, count); + +    else +    { +        *count = 0; +        result = NULL; +    } + +    return result; + +} diff --git a/src/plugins/tweakable.h b/src/plugins/tweakable.h new file mode 100644 index 0000000..aea70b4 --- /dev/null +++ b/src/plugins/tweakable.h @@ -0,0 +1,62 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * tweakable.h - prototypes pour la participation aux mécanismes de configuration + * + * 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 _PLUGINS_TWEAKABLE_H +#define _PLUGINS_TWEAKABLE_H + + +#include "../glibext/helpers.h" +#include "../gtkext/tweak.h" + + + +/* ------------------- INTEGRATION DANS L'EDITION DES PREFERENCES ------------------- */ + + +#define G_TYPE_TWEAKABLE_PLUGIN (g_tweakable_plugin_get_type()) + +DECLARE_INTERFACE(GTweakablePlugin, g_tweakable_plugin, G, TWEAKABLE_PLUGIN); + + +/* Fournit une liste de sections de configuration. */ +tweak_info_t *g_tweakable_plugin_get_tweak_info(const GTweakablePlugin *, size_t *); + + + +/* -------------------- SOLLICITATION DES FONCTIONNALITES CREEES -------------------- */ + + +#define get_tweakable_plugins_info(c)                                               \ +    ({                                                                              \ +        tweak_info_t *__all_info;                                                   \ +        __all_info = accumulate_from_all_plugins(G_TYPE_TWEAKABLE_PLUGIN,           \ +                                                 G_TWEAKABLE_PLUGIN,                \ +                                                 g_tweakable_plugin_get_tweak_info, \ +                                                 tweak_info_t,                      \ +                                                 c);                                \ +        __all_info;                                                                 \ +    }) + + + +#endif  /* _PLUGINS_TWEAKABLE_H */ @@ -41,7 +41,9 @@  #include "analysis/scan/scanner.h"  #include "analysis/scan/patterns/backends/acism.h"  #include "analysis/scan/patterns/backends/bitap.h" -#include "analysis/scan/patterns/backends/hyperscan.h" +#ifdef INCLUDE_HS_SUPPORT +#   include "analysis/scan/patterns/backends/hyperscan.h" +#endif  #include "core/core.h"  #include "core/global.h"  #include "core/logs.h" @@ -93,7 +95,11 @@ static void show_rost_help(const char *name)      printf("\n"); +#ifdef INCLUDE_HS_SUPPORT      printf("\t-A --algorithm=NAME\tSelect one of the available algorithms for data: acism, bitmap, hyperscan (default: acsim).\n"); +#else +    printf("\t-A --algorithm=NAME\tSelect one of the available algorithms for data: acism, bitmap (default: acsim).\n"); +#endif      printf("\t-C --check-only\t\tValidate the rule syntax without performing a scan (discard the file/dir argument).\n");      printf("\t-j --print-json\t\tPrint matching strings in JSON format instead of simple text.\n");      printf("\t-s --print-strings\tPrint matching strings (default text format only).\n"); @@ -303,8 +309,10 @@ int main(int argc, char **argv)                      g_scan_options_set_backend_for_data(options, G_TYPE_ACISM_BACKEND);                  else if (strcmp(optarg, "bitmap") == 0)                      g_scan_options_set_backend_for_data(options, G_TYPE_BITAP_BACKEND); +#ifdef INCLUDE_HS_SUPPORT                  else if (strcmp(optarg, "hyperscan") == 0)                      g_scan_options_set_backend_for_data(options, G_TYPE_HYPERSCAN_BACKEND); +#endif                  else                      g_scan_options_set_backend_for_data(options, G_TYPE_INVALID);                  break; diff --git a/src/schemas/re.chrysalide.framework.gschema.xml b/src/schemas/re.chrysalide.framework.gschema.xml index 4a16f12..534f735 100644 --- a/src/schemas/re.chrysalide.framework.gschema.xml +++ b/src/schemas/re.chrysalide.framework.gschema.xml @@ -1,19 +1,106 @@  <schemalist gettext-domain="chrysalide"> -  <schema id="re.chrysalide.framework" path="/re/chrysalide/framework/"> -    <child schema="re.chrysalide.framework.mainapp" name="mainapp"/> -  </schema> - -  <schema id="re.chrysalide.framework.mainapp" path="/re/chrysalide/framework/mainapp/"> -    <key name="window-width" type="i"> -      <default>600</default> -    </key> -    <key name="window-height" type="i"> -      <default>400</default> -    </key> -    <key name="window-maximized" type="b"> -      <default>false</default> -    </key> -  </schema> +    <schema id="re.chrysalide.framework" path="/re/chrysalide/framework/"> +        <child schema="re.chrysalide.framework.paths" name="paths"/> +        <child schema="re.chrysalide.framework.gui" name="gui"/> +        <child schema="re.chrysalide.framework.tiledgrid" name="tiles"/> +        <child schema="re.chrysalide.framework.secstorage" name="secstorage"/> +    </schema> + +    <schema id="re.chrysalide.framework.paths" path="/re/chrysalide/framework/paths/"> +        <key name="tmp-work-dir" type="s"> +            <default>"/tmp/chrysalide"</default> +            <summary>Directory for temporary contents</summary> +            <description> +                Location of files created as cache and meant to get deleted when unused +            </description> +        </key> +    </schema> + +    <schema id="re.chrysalide.framework.gui" path="/re/chrysalide/framework/gui/"> +        <key name="window-width" type="i"> +            <default>600</default> +        </key> +        <key name="window-height" type="i"> +            <default>400</default> +        </key> +        <key name="window-maximized" type="b"> +            <default>false</default> +        </key> +    </schema> + +    <flags id="re.chrysalide.framework.tiledgrid.LayoutReachOptions"> +        <value nick="left-top-reach" value="1"/> +        <value nick="left-bottom-reach" value="2"/> +        <value nick="right-top-reach" value="4"/> +        <value nick="right-bottom-reach" value="8"/> +    </flags> + +    <schema id="re.chrysalide.framework.tiledgrid"> + +        <key name="layout" flags="re.chrysalide.framework.tiledgrid.LayoutReachOptions"> +            <default>["left-top-reach","right-top-reach"]</default> +            <summary>Main panel layout</summary> +            <description>Layout details describing the border panel locations</description> +        </key> + +        <key name="top-visibility" type="b"> +            <default>false</default> +            <summary>Top panel visibility</summary> +            <description>Visbility of the panel located at the top of a tiling grid</description> +        </key> + +        <key name="top-request" type="u"> +            <default>300</default> +            <summary>Top panel height</summary> +            <description>Height request for the panel located at the top of a tiling grid</description> +        </key> + +        <key name="left-visibility" type="b"> +            <default>false</default> +            <summary>Left panel visibility</summary> +            <description>Visbility of the panel located at the left of a tiling grid</description> +        </key> + +        <key name="left-request" type="u"> +            <default>300</default> +            <summary>Left panel height</summary> +            <description>Width request for the panel located at the left of a tiling grid</description> +        </key> + +        <key name="right-visibility" type="b"> +            <default>false</default> +            <summary>Right panel visibility</summary> +            <description>Visbility of the panel located at the right of a tiling grid</description> +        </key> + +        <key name="right-request" type="u"> +            <default>300</default> +            <summary>Right panel height</summary> +            <description>Width request for the panel located at the right of a tiling grid</description> +        </key> + +        <key name="bottom-visibility" type="b"> +            <default>false</default> +            <summary>Bottom panel visibility</summary> +            <description>Visbility of the panel located at the bottom of a tiling grid</description> +        </key> + +        <key name="bottom-request" type="u"> +            <default>250</default> +            <summary>Bottom panel height</summary> +            <description>Height request for the panel located at the bottom of a tiling grid</description> +        </key> + +    </schema> + +    <schema id="re.chrysalide.framework.secstorage" path="/re/chrysalide/framework/secstorage/"> +        <key name="salt" type="ay"> +            <default>[]</default> +        </key> +        <key name="master" type="ay"> +            <default>[]</default> +        </key> +    </schema>  </schemalist>  | 
