diff options
Diffstat (limited to 'src')
162 files changed, 10327 insertions, 7901 deletions
diff --git a/src/Makefile.am b/src/Makefile.am index c50af8f..5c4d1e3 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -78,7 +78,7 @@ libchrysacore4_la_SOURCES = libchrysacore4_la_LIBADD = \ analysis/libanalysis4.la \ - arch/libarch4.la \ + arch/libarch.la \ common/libcommon4.la \ core/libcore4.la \ format/libformat.la \ @@ -86,7 +86,7 @@ libchrysacore4_la_LIBADD = \ plugins/libplugins.la libchrysacore4_la_LDFLAGS = \ - $(TOOLKIT_LIBS) $(LIBSSL_LIBS) $(LIBJSONGLIB_LIBS) + $(TOOLKIT_LIBS) $(LIBSSL_LIBS) $(LIBJSONGLIB_LIBS) $(LIBZIP_LIBS) if BUILD_CURL_SUPPORT @@ -102,6 +102,7 @@ EXTRA_libchrysacoreui_la_DEPENDENCIES = libchrysacore4.la libchrysacoreui_la_SOURCES = libchrysacoreui_la_LIBADD = \ + arch/libarchui.la \ glibext/libglibextui.la \ gtkext/libgtkext4.la \ gui/libgui4.la 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 a3acc3b..c6ccb5b 100644 --- a/src/analysis/contents/memory.c +++ b/src/analysis/contents/memory.c @@ -35,9 +35,9 @@ #include "memory-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/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/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/arch/Makefile.am b/src/arch/Makefile.am index 6ee2690..127ca4c 100644 --- a/src/arch/Makefile.am +++ b/src/arch/Makefile.am @@ -1,43 +1,56 @@ -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 = \ +# instructions/libarchinstructions.la \ +# operands/libarchoperands.la + + +# instruction-int.h \ +# instruction.h instruction.c \ +# +# 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 = \ + 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 = 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/operand-int.h b/src/arch/operand-int.h index e6c1232..a83d135 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. * @@ -28,11 +28,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 +83,38 @@ 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; + +#define ARCH_OPERAND_EXTRA_DATA(mx) \ + \ + unsigned int reserved : GOBJECT_RESERVED_EXTRA_BITS; \ + \ + /** \ + * ArchOperandFlag \ + */ \ + unsigned int flags : mx; /* 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,6 +132,8 @@ struct _GArchOperandClass load_operand_fc load; /* Chargement depuis un tampon */ store_operand_fc store; /* Conservation dans un tampon */ +#endif + }; @@ -135,22 +141,36 @@ struct _GArchOperandClass * 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 _operand_extra_data_t +{ + ARCH_OPERAND_EXTRA_DATA(3); /* Informations pour l'opérande*/ -# define GET_ARCH_OP_EXTRA(op) (operand_extra_data_t *)&op->extra +} operand_extra_data_t; -#else -# define GET_ARCH_OP_EXTRA(op) GET_GOBJECT_EXTRA(G_OBJECT(op), 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 +210,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..4aacab7 --- /dev/null +++ b/src/arch/operand-ui.h @@ -0,0 +1,55 @@ + +/* 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..f2f356b 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_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_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_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..9dc3b2f 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 = $(TOOLKIT_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 = $(TOOLKIT_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..a6b4ae7 --- /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/disass.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..7ec5ebd 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_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_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_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..b68e60c --- /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/disass.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..adb700d 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_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_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_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..c5469e1 --- /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/disass.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..711f450 --- /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" + + + +/* 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..07e35c4 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_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_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_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..8a9b961 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" diff --git a/src/common/Makefile.am b/src/common/Makefile.am index 7925b66..d09b661 100644 --- a/src/common/Makefile.am +++ b/src/common/Makefile.am @@ -50,6 +50,7 @@ libcommon4_la_SOURCES = \ asm.h asm.c \ bits.h bits.c \ compiler.h \ + cpp.h \ datatypes.h \ dllist.h dllist.c \ entropy.h entropy.c \ @@ -57,7 +58,6 @@ libcommon4_la_SOURCES = \ extstr.h extstr.c \ fnv1a.h fnv1a.c \ io.h io.c \ - json.h json.c \ leb128.h leb128.c \ macros.h \ packed.h packed.c \ @@ -74,6 +74,13 @@ libcommon4_la_SOURCES += \ 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 @@ -82,6 +89,12 @@ 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 26f570f..27296f2 100644 --- a/src/common/bits.c +++ b/src/common/bits.c @@ -31,6 +31,7 @@ #include "asm.h" +#include "io.h" #include "leb128.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..9616db3 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,25 @@ /** + * 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) + + +/** * Détermine la taille de la plus longue chaîne de caractères * correspondant à un type donné. */ 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.h b/src/common/entropy.h index b677a77..cfd51ef 100644 --- a/src/common/entropy.h +++ b/src/common/entropy.h @@ -26,9 +26,10 @@ #include <stdbool.h> +#include <stddef.h> -#include "../arch/archbase.h" +#include "../common/datatypes.h" diff --git a/src/common/leb128.c b/src/common/leb128.c index 009aff6..7fae4d0 100644 --- a/src/common/leb128.c +++ b/src/common/leb128.c @@ -24,9 +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 + /****************************************************************************** * * @@ -133,7 +144,7 @@ bool load_uleb128(uleb128_t *value, int fd) unsigned int shift; /* Décalage à appliquer */ uint8_t byte; /* Octet à transposer */ - result = true; + result = false; *value = 0; @@ -142,7 +153,7 @@ bool load_uleb128(uleb128_t *value, int fd) while (true) { /* Encodage sur trop d'octets ? */ - if (shift > (7 * sizeof(uleb128_t))) + if (shift > (7 * MAX_LEB128_BYTES)) { result = false; break; @@ -153,6 +164,8 @@ bool load_uleb128(uleb128_t *value, int fd) *value |= ((byte & 0x7f) << shift); + result = true; + if ((byte & 0x80) == 0x00) break; @@ -207,7 +220,7 @@ bool store_uleb128(const uleb128_t *value, int fd) /****************************************************************************** * * * 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 non signé encodé au format LEB128. * * * @@ -217,26 +230,44 @@ bool store_uleb128(const uleb128_t *value, int fd) * * ******************************************************************************/ -bool pack_uleb128(const uleb128_t *value, packed_buffer_t *pbuf) +void *pack_uleb128(const uleb128_t *value, size_t *len) { - bool result; /* Bilan à retourner */ + uint8_t *result; /* Données à retourner */ uleb128_t tmp; /* Valeur modifiable */ - uint8_t byte; /* Octet à transposer */ + uint8_t *byte; /* Octet à transposer */ + + /* Calcul de la quantité d'octets nécessaires */ + + *len = 0; tmp = *value; do { - byte = (tmp & 0x7f); + 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 |= 0x80; - result = extend_packed_buffer(pbuf, &byte, sizeof(uint8_t), false); + byte++; } - while (result && tmp != 0); + while (tmp != 0); return result; @@ -246,7 +277,7 @@ 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. * * * @@ -256,19 +287,24 @@ bool pack_uleb128(const uleb128_t *value, packed_buffer_t *pbuf) * * ******************************************************************************/ -bool pack_leb128(const leb128_t *value, packed_buffer_t *pbuf) +void *pack_leb128(const leb128_t *value, size_t *len) { - - bool result; /* Bilan à retourner */ + 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) { @@ -291,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++; } @@ -306,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. * * * @@ -316,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; @@ -357,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. * * * @@ -367,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 0313f5c..cb712a3 100644 --- a/src/common/leb128.h +++ b/src/common/leb128.h @@ -30,7 +30,6 @@ #include "datatypes.h" -#include "packed.h" @@ -65,16 +64,16 @@ bool load_uleb128(uleb128_t *, int); 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/szbin.h b/src/common/szbin.h index 5891449..182739a 100644 --- a/src/common/szbin.h +++ b/src/common/szbin.h @@ -25,6 +25,7 @@ #define _COMMON_SZBIN_H +#include <assert.h> #include <malloc.h> #include <string.h> @@ -72,11 +73,22 @@ typedef struct _sized_binary_t 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 \ { \ - setup_sized_binary(sb, s); \ - memcpy((sb)->data, d, s); \ + size_t __size_once; \ + __size_once = s; \ + setup_sized_binary(sb, __size_once);\ + memcpy((sb)->data, d, __size_once); \ } \ while (0) @@ -97,6 +109,16 @@ typedef struct _sized_binary_t 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 \ { \ @@ -133,6 +155,11 @@ typedef struct _sized_binary_t }) + +/** + * Conservations et rechargements. + */ + #define load_sized_binary(sb, f) \ ({ \ uleb128_t __sz; \ @@ -149,6 +176,23 @@ typedef struct _sized_binary_t }) +#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; \ @@ -159,5 +203,82 @@ typedef struct _sized_binary_t }) +#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/core/Makefile.am b/src/core/Makefile.am index e1e3c4e..17fd2bf 100644 --- a/src/core/Makefile.am +++ b/src/core/Makefile.am @@ -22,7 +22,7 @@ libcore4_la_SOURCES = \ nproc.h nproc.c \ paths.h paths.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 9514ee1..8fe12f5 100644 --- a/src/core/core.c +++ b/src/core/core.c @@ -53,6 +53,8 @@ bool load_core_components(AvailableCoreComponent flags) 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; @@ -82,6 +84,8 @@ void unload_core_components(AvailableCoreComponent flags) { set_work_queue(NULL); + set_secret_storage(NULL); + __loaded &= ~ACC_GLOBAL_VARS; } diff --git a/src/core/core.h b/src/core/core.h index 7c50f6c..e5f0a60 100644 --- a/src/core/core.h +++ b/src/core/core.h @@ -32,9 +32,11 @@ /* Eléments à (dé)charger disponibles */ typedef enum _AvailableCoreComponent { - ACC_NONE = (0 << 0), /* Statut initial */ - ACC_GLOBAL_VARS = (1 << 0), /* Singletons globaux */ - ACC_SCAN_FEATURES = (1 << 0), /* Espace de noms pour scan */ + ACC_NONE = (0 << 0), /* Statut initial */ + ACC_GLOBAL_VARS = (1 << 0), /* Singletons globaux */ + ACC_SCAN_FEATURES = (1 << 1), /* Espace de noms pour scan */ + + ACC_ALL_COMPONENTS = (1 << 2) - 1 } AvailableCoreComponent; diff --git a/src/core/global.c b/src/core/global.c index d38656b..0275e09 100644 --- a/src/core/global.c +++ b/src/core/global.c @@ -36,6 +36,9 @@ static size_t _bytes_sent = 0; /* Gestionnaire de tâches parallèles */ static GWorkQueue *_queue = NULL; +/* Gardien des secrets avec support des stockages */ +static GSecretStorage *_storage = NULL; + /****************************************************************************** @@ -131,6 +134,49 @@ 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; + +} + + diff --git a/src/core/global.h b/src/core/global.h index b861ad8..f5d8a62 100644 --- a/src/core/global.h +++ b/src/core/global.h @@ -25,6 +25,7 @@ #define _CORE_GLOBAL_H +#include "../glibext/secstorage.h" #include "../glibext/workqueue.h" @@ -41,6 +42,12 @@ 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); + 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/format/program-int.h b/src/format/program-int.h index 1549a0a..8464fe4 100644 --- a/src/format/program-int.h +++ b/src/format/program-int.h @@ -36,7 +36,7 @@ typedef SourceEndian (* program_get_endian_fc) (const GProgramFormat *); /* Fournit l'emplacement d'une section donnée. */ -typedef bool (* get_range_by_name_fc) (const GProgramFormat *, const char *, mrange_t *); +typedef bool (* find_range_by_name_fc) (const GProgramFormat *, const char *, mrange_t *); /* Format de programme générique (instance) */ @@ -52,7 +52,7 @@ struct _GProgramFormatClass GKnownFormatClass parent; /* A laisser en premier */ program_get_endian_fc get_endian; /* Boutisme employé */ - get_range_by_name_fc get_range_by_name; /* Emplacement de sections */ + find_range_by_name_fc find_range_by_name; /* Emplacement de sections */ }; diff --git a/src/format/program.c b/src/format/program.c index d44f988..9b9df81 100644 --- a/src/format/program.c +++ b/src/format/program.c @@ -480,18 +480,18 @@ SourceEndian g_program_format_get_endianness(const GProgramFormat *format) * * ******************************************************************************/ -bool g_program_format_get_section_range_by_name(const GProgramFormat *format, const char *name, mrange_t *range) +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->get_range_by_name == NULL) + if (class->find_range_by_name == NULL) result = false; else - result = class->get_range_by_name(format, name, range); + result = class->find_range_by_name(format, name, range); return result; diff --git a/src/format/program.h b/src/format/program.h index 0eb26ae..12b095c 100644 --- a/src/format/program.h +++ b/src/format/program.h @@ -43,7 +43,7 @@ DECLARE_GTYPE(GProgramFormat, g_program_format, G, PROGRAM_FORMAT); SourceEndian g_program_format_get_endianness(const GProgramFormat *); /* Fournit l'emplacement d'une section donnée. */ -bool g_program_format_get_section_range_by_name(const GProgramFormat *, const char *, mrange_t *); +bool g_program_format_find_section_range_by_name(const GProgramFormat *, const char *, mrange_t *); diff --git a/src/glibext/Makefile.am b/src/glibext/Makefile.am index adbec4c..f946665 100644 --- a/src/glibext/Makefile.am +++ b/src/glibext/Makefile.am @@ -4,8 +4,6 @@ BUILT_SOURCES = chrysamarshal.h chrysamarshal.c resources.h resources.c noinst_LTLIBRARIES = libglibext.la libglibextui.la # libglibext_la_SOURCES = \ -# comparison-int.h \ -# comparison.h comparison.c \ # configuration-int.h \ # configuration.h configuration.c \ # gbinarycursor.h gbinarycursor.c \ @@ -13,7 +11,7 @@ noinst_LTLIBRARIES = libglibext.la libglibextui.la # glinecursor.h glinecursor.c \ # gnhash.h gnhash.c \ # notifier.h \ -# objhole.h \ +# \ # proto.h \ # seq.h seq.c \ # _signal.h signal.c \ @@ -40,9 +38,27 @@ noinst_LTLIBRARIES = libglibext.la libglibextui.la libglibext_la_SOURCES = \ chrysamarshal.h chrysamarshal.c \ + comparable-int.h \ + comparable.h comparable.c \ + hashable-int.h \ + hashable.h hashable.c \ helpers.h \ + 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 \ + 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 \ @@ -50,7 +66,7 @@ libglibext_la_SOURCES = \ workqueue-int.h \ workqueue.h workqueue.c -libglibext_la_CFLAGS = $(TOOLKIT_CFLAGS) +libglibext_la_CFLAGS = $(TOOLKIT_CFLAGS) $(LIBZIP_CFLAGS) RES_FILES = \ diff --git a/src/glibext/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 cfcc85b..6176245 100644 --- a/src/glibext/helpers.h +++ b/src/glibext/helpers.h @@ -29,6 +29,9 @@ #include <glib-object.h> +#include "../common/compiler.h" + + /** * Les définitions issues de <glib-2.80>/gobject/gtype.h fournissent des macros @@ -118,6 +121,31 @@ } +/** + * Définition sous condition d'une inclusion d'interface. Cette inclusion se réalise + * lorsque la fonction d'initialisation renseignée est définie. + * + * Cette version étendue de la macro G_IMPLEMENT_INTERFACE d'origine est principalement + * pour les raffinements d'objets en forme graphique. + */ + +#define G_IMPLEMENT_INTERFACE_IF_SYM(iface_tp_getter, iface_init) \ + do \ + { \ + extern GType iface_tp_getter(void) __weak; \ + extern void iface_init(GTypeInterface *, gpointer) __weak; \ + if (&iface_tp_getter != NULL && &iface_init != NULL) \ + { \ + GType iface_type = iface_tp_getter(); \ + const GInterfaceInfo implementation_info = { \ + (GInterfaceInitFunc)(void (*)(void))iface_init, NULL, NULL \ + }; \ + g_type_add_interface_static(g_define_type_id, iface_type, &implementation_info);\ + } \ + } \ + while (0); + + /** * Les principales fonctions incrémentant ou réduisant le nombre de références diff --git a/src/glibext/objhole-int.h b/src/glibext/objhole-int.h new file mode 100644 index 0000000..aa8a1f8 --- /dev/null +++ b/src/glibext/objhole-int.h @@ -0,0 +1,166 @@ + +/* 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 + + +/* 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..20bb2a8 --- /dev/null +++ b/src/glibext/objhole.c @@ -0,0 +1,191 @@ + +/* 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(GThickObject *); + +/* Procède à la libération totale de la mémoire. */ +static void g_thick_object_finalize(GThickObject *); + + + +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 = (GObjectFinalizeFunc/* ! */)g_thick_object_dispose; + object->finalize = (GObjectFinalizeFunc)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 : obj = instance d'objet GLib à traiter. * +* * +* Description : Supprime toutes les références externes. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_thick_object_dispose(GThickObject *obj) +{ + G_OBJECT_CLASS(g_thick_object_parent_class)->dispose(G_OBJECT(obj)); + +} + + +/****************************************************************************** +* * +* Paramètres : obj = instance d'objet GLib à traiter. * +* * +* Description : Procède à la libération totale de la mémoire. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_thick_object_finalize(GThickObject *obj) +{ + G_OBJECT_CLASS(g_thick_object_parent_class)->finalize(G_OBJECT(obj)); + +} + + +/****************************************************************************** +* * +* 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..c1e8cf1 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,20 @@ #define _GLIBEXT_OBJHOLE_H -#include <glib.h> -#include <glib-object.h> +#include "../glibext/helpers.h" -#include "../common/cpp.h" +#define G_TYPE_THICK_OBJECT (g_thick_object_get_type()) +DECLARE_GTYPE(GThickObject, g_thick_object, G, THICK_OBJECT); -/** - * 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; \ - }) - -#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. - */ - -#if __BYTE_ORDER == __LITTLE_ENDIAN - -# define HOLE_LOCK_BIT 31 - -#elif __BYTE_ORDER == __BIG_ENDIAN - -# define HOLE_LOCK_BIT 0 - -#else - -# error "Unknown byte order" - -#endif - - -/* 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) +/* Fournit la valeur courante de la zone de stockage d'un objet. */ +guint g_thick_object_get_extra(const GThickObject *); -#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..19881cf 100644 --- a/src/glibext/options/Makefile.am +++ b/src/glibext/options/Makefile.am @@ -3,6 +3,7 @@ noinst_LTLIBRARIES = libglibextoptions.la libglibextoptions_la_SOURCES = \ + disass.h \ hex.h hex.c libglibextoptions_la_CFLAGS = $(TOOLKIT_CFLAGS) diff --git a/src/glibext/options/disass.h b/src/glibext/options/disass.h new file mode 100644 index 0000000..e916083 --- /dev/null +++ b/src/glibext/options/disass.h @@ -0,0 +1,56 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * disass.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_DISASS_H +#define _GLIBEXT_OPTIONS_DISASS_H + + +#include "../helpers.h" + + + +/* Liste des colonnes en options */ +typedef enum _DisassColumnOptions +{ + ACO_OFFSET, /* Position */ + + ACO_COUNT + +} DisassColumnOptions; + + +#define ACO_ASSEMBLY (ACO_COUNT + 0) /* Code pour assembleur */ + + +#if 0 +#define G_TYPE_HEX_OPTIONS (g_hex_options_get_type()) + +DECLARE_GTYPE(GHexOptions, g_hex_options, G, HEX_OPTIONS); + + +/* Crée un groupe d'options pour le rendu d'hexadécimal. */ +GHexOptions *g_hex_options_new(void); +#endif + + +#endif /* _GLIBEXT_OPTIONS_HEX_H */ diff --git a/src/glibext/secstorage-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..b118aa6 --- /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; /* Gestion de stockage sécurisé*/ + + 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; /* Gestion de stockage sécurisé*/ + + 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/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..e4bac7a 100644 --- a/src/analysis/storage/storage-int.h +++ b/src/glibext/storage-int.h @@ -2,7 +2,7 @@ /* Chrysalide - Outil d'analyse de fichiers binaires * storage.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/gtkext/Makefile.am b/src/gtkext/Makefile.am index 2a2738a..839ee8f 100644 --- a/src/gtkext/Makefile.am +++ b/src/gtkext/Makefile.am @@ -26,10 +26,17 @@ libgtkext_la_LIBADD = \ libgtkext_la_CFLAGS = $(LIBGTK_CFLAGS) $(LIBXML_CFLAGS) +IMG_PATH = ../../data/images + RES_FILES = \ hexview.css \ hexview.ui \ - statusstack.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 \ @@ -45,17 +52,22 @@ libgtkext4_la_SOURCES = \ helpers.h \ hexview-int.h \ hexview.h hexview.c \ + launcher-int.h \ + launcher.h launcher.c \ panel-int.h \ panel.h panel.c \ resources.h resources.c \ - statusstack.h statusstack.c + statusstack-int.h \ + statusstack.h statusstack.c \ + tweak-int.h \ + tweak.h tweak.c libgtkext4_la_CFLAGS = $(LIBGTK4_CFLAGS) devdir = $(includedir)/chrysalide/$(subdir:src/%=core/%) -dev_HEADERS = $(libgtkext_la_SOURCES:%c=) +dev_HEADERS = $(libgtkext4_la_SOURCES:%c=) #SUBDIRS = graph diff --git a/src/gtkext/bufferview.c b/src/gtkext/bufferview.c index 6b8f17c..13c2632 100644 --- a/src/gtkext/bufferview.c +++ b/src/gtkext/bufferview.c @@ -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/gresource.xml b/src/gtkext/gresource.xml index 3bfd8c5..640985f 100644 --- a/src/gtkext/gresource.xml +++ b/src/gtkext/gresource.xml @@ -3,6 +3,13 @@ <gresource prefix="/re/chrysalide/framework/gtkext"> <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/hexview.c b/src/gtkext/hexview.c index 6df1140..5a8dd04 100644 --- a/src/gtkext/hexview.c +++ b/src/gtkext/hexview.c @@ -438,9 +438,9 @@ void demo_snapshot (GtkWidget *widget, GtkSnapshot *snapshot, GtkWidget *parent) /****************************************************************************** * * -* 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/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/gtkext/statusstack-int.h b/src/gtkext/statusstack-int.h index facc5af..2a9e99e 100644 --- a/src/gtkext/statusstack-int.h +++ b/src/gtkext/statusstack-int.h @@ -26,6 +26,7 @@ #include "statusstack.h" +#include "../glibext/secstorage.h" @@ -70,6 +71,9 @@ struct _GtkStatusStack /* 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 */ diff --git a/src/gtkext/statusstack.c b/src/gtkext/statusstack.c index 0d8ef62..76dbee8 100644 --- a/src/gtkext/statusstack.c +++ b/src/gtkext/statusstack.c @@ -53,6 +53,9 @@ 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 *); @@ -190,6 +193,8 @@ static void gtk_status_stack_class_init(GtkStatusStackClass *class) 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); @@ -220,6 +225,17 @@ static void gtk_status_stack_init(GtkStatusStack *stack) 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, @@ -242,6 +258,12 @@ static void gtk_status_stack_init(GtkStatusStack *stack) 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); @@ -322,6 +344,40 @@ void gtk_status_stack_reset(GtkStatusStack *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. * diff --git a/src/gtkext/statusstack.ui b/src/gtkext/statusstack.ui index 422f95d..8469e6e 100644 --- a/src/gtkext/statusstack.ui +++ b/src/gtkext/statusstack.ui @@ -1,3 +1,4 @@ +<?xml version="1.0" encoding="UTF-8"?> <interface> <template class="GtkStatusStack" parent="GtkBox"> @@ -148,6 +149,20 @@ </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> 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 42761c4..be70445 100644 --- a/src/gui/Makefile.am +++ b/src/gui/Makefile.am @@ -26,8 +26,6 @@ libgui_la_CFLAGS = $(LIBGTK_CFLAGS) $(LIBXML_CFLAGS) libgui4_la_SOURCES = \ - panel-int.h \ - panel.h panel.c \ resources.h resources.c \ window-int.h \ window.h window.c diff --git a/src/gui/core/core.c b/src/gui/core/core.c index 4a6809c..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. * @@ -63,7 +63,7 @@ bool load_gui_components(AvailableGuiComponent flags) if ((flags & AGC_PANELS) != 0 && (__loaded & AGC_PANELS) == 0) { - result = load_main_panels(); + result = load_main_framework_panel_definitions(); if (!result) goto done; __loaded |= AGC_PANELS; @@ -93,7 +93,7 @@ void unload_gui_components(AvailableGuiComponent flags) { if ((flags & AGC_PANELS) != 0 && (__loaded & AGC_PANELS) == 0) { - unload_all_panels(); + unload_all_framework_panel_definitions(); __loaded &= ~AGC_PANELS; diff --git a/src/gui/core/panels.c b/src/gui/core/panels.c index 69ab2aa..4c113b8 100644 --- a/src/gui/core/panels.c +++ b/src/gui/core/panels.c @@ -2,7 +2,7 @@ /* Chrysalide - Outil d'analyse de fichiers binaires * panels.c - gestion d'ensemble de tous les panneaux graphiques du framework * - * Copyright (C) 2016-2024 Cyrille Bagard + * Copyright (C) 2016-2025 Cyrille Bagard * * This file is part of Chrysalide. * @@ -25,25 +25,137 @@ #include "panels.h" +#include <assert.h> #include <malloc.h> +#include <string.h> + + +#include <i18n.h> #include "../panels/binary.h" +#include "../panels/binary-params.h" #include "../panels/welcome.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 GPanelItem **_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 : 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; + +} + + +/****************************************************************************** +* * +* Paramètres : info = informations à supprimer de la mémoire. * +* * +* Description : Efface une définition étendue de panneau graphique. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void delete_panel_info(ext_panel_info_t *info) +{ + 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); + +} + /****************************************************************************** * * * Paramètres : - * * * -* Description : Charge les principaux panneaux graphiques du framework. * +* Description : Charge les définitions des principaux panneaux du framework. * * * * Retour : Bilan de l'opération. * * * @@ -51,19 +163,45 @@ static size_t _panels_count = 0; * * ******************************************************************************/ -bool load_main_panels(void) +bool load_main_framework_panel_definitions(void) { bool result; /* Bilan à retourner */ - - result = true; + panel_info_t info; /* Infos d'enregistrement */ // TODO register_panel_item(G_TYPE_LOG_PANEL, config); /* Chargement du panneau de rapport au plus tôt */ // TODO panel = g_panel_item_new(G_TYPE_LOG_PANEL, NULL); - register_panel_item(g_binary_panel_new()); - register_panel_item(g_welcome_panel_new()); + 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; @@ -82,12 +220,12 @@ bool load_main_panels(void) * * ******************************************************************************/ -void unload_all_panels(void) +void unload_all_framework_panel_definitions(void) { size_t i; /* Boucle de parcours */ for (i = 0; i < _panels_count; i++) - unref_object(_panels_list[i]); + delete_panel_info(_panels_list[i]); _panels_list = NULL; _panels_count = 0; @@ -97,10 +235,9 @@ void unload_all_panels(void) /****************************************************************************** * * -* 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 : - * * * @@ -108,11 +245,36 @@ void unload_all_panels(void) * * ******************************************************************************/ -void register_panel_item(/* __steal */ GPanelItem *item) +bool register_framework_panel_definition(const panel_info_t *info) { - _panels_list = realloc(_panels_list, ++_panels_count * sizeof(GPanelItem *)); + bool result; /* Bilan à retourner */ + size_t i; /* Boucle de parcours */ + ext_panel_info_t *ext_info; /* Informations conservées */ + + result = false; - _panels_list[_panels_count - 1] = item; + /* Validation */ + + for (i = 0; i < _panels_count; i++) + if (_panels_list[i]->panel_type == info->panel_type) + break; + + if (i < _panels_count) + goto done; + + /* Enregistrement */ + + ext_info = copy_panel_info(info); + + _panels_list = realloc(_panels_list, ++_panels_count * sizeof(ext_panel_info_t *)); + + _panels_list[_panels_count - 1] = ext_info; + + result = true; + + done: + + return result; } @@ -121,7 +283,7 @@ void register_panel_item(/* __steal */ GPanelItem *item) * * * Paramètres : target = type de définition de panneau recherchée. * * * -* Description : Retrouve la définition d'un type de panneau. * +* Description : Met en place (au besoin) un panneau graphique unique. * * * * Retour : Instance de définition identifiée ou NULL en cas d'échec. * * * @@ -129,23 +291,27 @@ void register_panel_item(/* __steal */ GPanelItem *item) * * ******************************************************************************/ -GPanelItem *find_item_panel_by_type(GType target) +GtkTiledPanel *get_framework_panel_singleton(GType target) { - GPanelItem *result; /* Instance à renvoyer */ + GtkTiledPanel *result; /* Instance à renvoyer */ size_t i; /* Boucle de parcours */ - GPanelItem *item; /* Définition de panneau */ + ext_panel_info_t *info; /* Informations conservées */ result = NULL; for (i = 0; i < _panels_count; i++) { - item = _panels_list[i]; + info = _panels_list[i]; - if (G_OBJECT_TYPE(item) == target) + if (info->panel_type == target) { - result = item; + if (info->singleton == NULL) + info->singleton = g_object_new(target, NULL); + + result = info->singleton; ref_object(result); break; + } } @@ -157,39 +323,84 @@ GPanelItem *find_item_panel_by_type(GType target) /****************************************************************************** * * -* 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 : list = liste à compléter. * * * -* Description : Effectue le parcours de tous les panneaux chargés. * +* Description : Intègre une définition de panneau enregistrée. * * * -* Retour : true si le parcours a été total, false sinon. * +* Retour : true pour un parcours complet de la liste des définitions. * * * * Remarques : - * * * ******************************************************************************/ -bool browse_all_item_panels(bool skip, handle_panel_item_fc handle, void *data) +void populate_framework_panel_launcher_list(GtkListBox *list) { - bool result; /* Résultat à renvoyer */ size_t i; /* Boucle de parcours */ - GPanelItem *item; /* Définition de panneau */ - - result = true; + ext_panel_info_t *info; /* Informations conservées */ + GtkPanelLauncher *launcher; /* Lanceur à intégrer */ for (i = 0; i < _panels_count; i++) { - item = _panels_list[i]; + info = _panels_list[i]; - if (skip && G_OBJECT_TYPE(item) == G_TYPE_WELCOME_PANEL) + if (info->category == NULL) continue; - result = handle(item, data); + 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)); + + } + +} + + +/****************************************************************************** +* * +* 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); - if (!result) break; + 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 aaea9e6..4d0ce41 100644 --- a/src/gui/core/panels.h +++ b/src/gui/core/panels.h @@ -2,7 +2,7 @@ /* Chrysalide - Outil d'analyse de fichiers binaires * panels.h - prototypes pour la gestion d'ensemble de tous les panneaux graphiques du framework * - * Copyright (C) 2016-2024 Cyrille Bagard + * Copyright (C) 2016-2025 Cyrille Bagard * * This file is part of Chrysalide. * @@ -26,30 +26,59 @@ #define _GUI_CORE_PANELS_H +#include <glib-object.h> #include <stdbool.h> +#include <gtk/gtk.h> -#include "../panel.h" +#include "../../gtkext/panel.h" -/* Charge les principaux panneaux graphiques du framework. */ -bool load_main_panels(void); +/* Types de panneaux pour éditeur */ +typedef enum _FrameworkPanelPersonality +{ + FPP_NONE = (0 << 0), /* Pas de particularité */ + + FPP_MAIN_PANEL = (1 << 0), /* Panneau principal */ + FPP_SINGLETON = (1 << 1), /* Instance unique */ + +} FrameworkPanelPersonality; + +/* Définition générique d'un panneau */ +typedef struct _panel_info_t +{ + const char *category; /* Groupe de rassemblement */ + + 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_panels(void); +void unload_all_framework_panel_definitions(void); -/* Enregistre un panneau comme partie intégrante de l'éditeur. */ -void register_panel_item(/* __steal */ GPanelItem *); +/* Enregistre la définition d'un panneau graphique. */ +bool register_framework_panel_definition(const panel_info_t *); -/* Retrouve la définition d'un type de panneau. */ -GPanelItem *find_item_panel_by_type(GType); +/* Met en place (au besoin) un panneau graphique unique. */ +GtkTiledPanel *get_framework_panel_singleton(GType); -/* Réalise un traitement sur un panneau de l'éditeur. */ -typedef bool (* handle_panel_item_fc) (GPanelItem *, void *); +/* Intègre une définition de panneau enregistrée. */ +void populate_framework_panel_launcher_list(GtkListBox *); -/* Effectue le parcours de tous les panneaux chargés. */ -bool browse_all_item_panels(bool, handle_panel_item_fc, void *); +/* 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 5a77b99..e910c96 100644 --- a/src/gui/dialogs/Makefile.am +++ b/src/gui/dialogs/Makefile.am @@ -3,21 +3,23 @@ BUILT_SOURCES = resources.h resources.c noinst_LTLIBRARIES = libguidialogs.la -UI_FILES = \ - about.ui +UI_FILES = \ + about.ui \ + preferences.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-int.h \ - about.h about.c \ +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 \ @@ -26,12 +28,15 @@ libguidialogs_la_SOURCES = \ # 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 \ # snapshots.h snapshots.c \ # storage.h storage.c +libguidialogs_la_LIBADD = \ + prefs/libguidialogsprefs.la + libguidialogs_la_CFLAGS = $(LIBGTK4_CFLAGS) @@ -40,6 +45,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 index 382859b..616c73f 100644 --- a/src/gui/dialogs/about-int.h +++ b/src/gui/dialogs/about-int.h @@ -1,6 +1,6 @@ /* Chrysalide - Outil d'analyse de fichiers binaires - * about.h - définitions internes pour la boîte de dialogue d'information sur le programme + * about-int.h - définitions internes pour la boîte de dialogue d'information sur le programme * * Copyright (C) 2024 Cyrille Bagard * @@ -28,7 +28,7 @@ #include <stdbool.h> -#include "about-int.h" +#include "about.h" diff --git a/src/gui/dialogs/about.c b/src/gui/dialogs/about.c index 5c938ad..956918b 100644 --- a/src/gui/dialogs/about.c +++ b/src/gui/dialogs/about.c @@ -207,8 +207,8 @@ GtkWindow *gtk_app_about_dialog_new(GtkWindow *parent) /****************************************************************************** * * -* Paramètres : dialog = boîte de dialogue à initialiser pleinement. * -* content = contenu binaire à exposer de façon brute. * +* Paramètres : dialog = boîte de dialogue à initialiser pleinement. * +* parent = fenêtre parente à surpasser. * * * * Description : Met en place la fenêtre d'informations sur le logiciel. * * * diff --git a/src/gui/dialogs/about.ui b/src/gui/dialogs/about.ui index 892b468..989e53b 100644 --- a/src/gui/dialogs/about.ui +++ b/src/gui/dialogs/about.ui @@ -94,7 +94,7 @@ <object class="GtkLabel"> <property name="margin-top">22</property> <property name="margin-bottom">10</property> - <property name="label" translatable="yes"><span fgcolor='white'>Copyright (C) 2008-2024 Cyrille Bagard</span></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> diff --git a/src/gui/dialogs/gresource.xml b/src/gui/dialogs/gresource.xml index b9bc7e2..169f440 100644 --- a/src/gui/dialogs/gresource.xml +++ b/src/gui/dialogs/gresource.xml @@ -2,15 +2,7 @@ <gresources> <gresource prefix="/re/chrysalide/framework/gui/dialogs"> <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> 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..68e7fd9 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,104 @@ #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/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 +129,150 @@ 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", "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 +281,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 +367,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..fa1af96 --- /dev/null +++ b/src/gui/dialogs/prefs/Makefile.am @@ -0,0 +1,31 @@ + +BUILT_SOURCES = resources.h resources.c + +noinst_LTLIBRARIES = libguidialogsprefs.la + +UI_FILES = \ + security.ui + +libguidialogsprefs_la_SOURCES = \ + 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/gresource.xml b/src/gui/dialogs/prefs/gresource.xml new file mode 100644 index 0000000..7b18143 --- /dev/null +++ b/src/gui/dialogs/prefs/gresource.xml @@ -0,0 +1,6 @@ +<?xml version="1.0" encoding="UTF-8"?> +<gresources> + <gresource prefix="/re/chrysalide/framework/gui/dialogs/prefs"> + <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/panel-int.h b/src/gui/panel-int.h deleted file mode 100644 index 7e6f7e3..0000000 --- a/src/gui/panel-int.h +++ /dev/null @@ -1,71 +0,0 @@ - -/* 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-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_PANEL_INT_H -#define _GUI_PANEL_INT_H - - -#include "panel.h" - - - -/* Fournit une indication sur la personnalité du panneau. */ -typedef PanelItemPersonality (* get_panel_item_personality_cb) (const GPanelItem *); - -/* Fournit un composant pour lancer l'activité d'un panneau. */ -typedef GtkWidget * (* get_panel_item_widget_cb) (GPanelItem *); - -/* Fournit un composant représentant un panneau graphique. */ -typedef GtkTiledPanel * (* get_panel_item_panel_cb) (GPanelItem *, GtkWidget *); - - -/* Elément réactif pour panneaux de l'éditeur (instance) */ -struct _GPanelItem -{ - GObject parent; /* A laisser en premier */ - - GtkWidget *launcher; /* Eventuel lanceur associé */ - GtkWidget *properties; /* Propriétés de lancement */ - - GtkTiledPanel **panels; /* Instances complètes ouvertes*/ - size_t pcount; /* Quantité de ces instances */ - -}; - -/* Elément réactif pour panneaux de l'éditeur (classe) */ -struct _GPanelItemClass -{ - GObjectClass parent; /* A laisser en premier */ - - get_panel_item_personality_cb get_personality; /* Fourniture de nature */ - - get_panel_item_widget_cb get_launcher; /* Lancement d'une activité */ - get_panel_item_widget_cb get_properties;/* Préparation au lancement */ - get_panel_item_panel_cb get_panel; /* Panneau principal */ - -}; - - - -#endif /* _GUI_PANEL_INT_H */ diff --git a/src/gui/panel.c b/src/gui/panel.c deleted file mode 100644 index b361153..0000000 --- a/src/gui/panel.c +++ /dev/null @@ -1,1207 +0,0 @@ - -/* Chrysalide - Outil d'analyse de fichiers binaires - * panel.c - gestion des éléments réactifs spécifiques aux panneaux - * - * 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 this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - - -#include "panel.h" - - -#include "panel-int.h" - - - -/* ---------------------- MANIPULATIONS D'UN PANNEAU GRAPHIQUE ---------------------- */ - - - - - -/* Initialise la classe des panneaux graphiques de l'éditeur. */ -static void g_panel_item_class_init(GPanelItemClass *); - -/* Initialise une instance de panneau graphique pour l'éditeur. */ -static void g_panel_item_init(GPanelItem *); - -/* Supprime toutes les références externes. */ -static void g_panel_item_dispose(GPanelItem *); - -/* Procède à la libération totale de la mémoire. */ -static void g_panel_item_finalize(GPanelItem *); - - - - - -/* Indique le type défini pour un élément destiné à un panneau. */ -G_DEFINE_TYPE(GPanelItem, g_panel_item, G_TYPE_OBJECT); - - -/****************************************************************************** -* * -* Paramètres : class = classe à initialiser. * -* * -* Description : Initialise la classe des panneaux graphiques de l'éditeur. * -* * -* Retour : - * -* * -* Remarques : - * -* * -******************************************************************************/ - -static void g_panel_item_class_init(GPanelItemClass *class) -{ - GObjectClass *object; /* Autre version de la classe */ - - object = G_OBJECT_CLASS(class); - - object->dispose = (GObjectFinalizeFunc/* ! */)g_panel_item_dispose; - object->finalize = (GObjectFinalizeFunc)g_panel_item_finalize; - -} - - -/****************************************************************************** -* * -* Paramètres : item = instance à initialiser. * -* * -* Description : Initialise une instance de panneau graphique pour l'éditeur. * -* * -* Retour : - * -* * -* Remarques : - * -* * -******************************************************************************/ - -static void g_panel_item_init(GPanelItem *item) -{ - //item->docked = false; - - //item->widget = NULL; - //item->cached_widget = NULL; - - //item->filter = NULL; - - //g_atomic_int_set(&item->switched, 0); - -} - - -/****************************************************************************** -* * -* Paramètres : item = instance d'objet GLib à traiter. * -* * -* Description : Supprime toutes les références externes. * -* * -* Retour : - * -* * -* Remarques : - * -* * -******************************************************************************/ - -static void g_panel_item_dispose(GPanelItem *item) -{ - //g_clear_object(&item->widget); - //g_clear_object(&item->cached_widget); - - G_OBJECT_CLASS(g_panel_item_parent_class)->dispose(G_OBJECT(item)); - -} - - -/****************************************************************************** -* * -* Paramètres : item = instance d'objet GLib à traiter. * -* * -* Description : Procède à la libération totale de la mémoire. * -* * -* Retour : - * -* * -* Remarques : - * -* * -******************************************************************************/ - -static void g_panel_item_finalize(GPanelItem *item) -{ - G_OBJECT_CLASS(g_panel_item_parent_class)->finalize(G_OBJECT(item)); - -} - - -/****************************************************************************** -* * -* Paramètres : item = définition de panneau à consulter. * -* * -* Description : Fournit une indication sur la personnalité du panneau. * -* * -* Retour : Identifiant lié à la nature du panneau. * -* * -* Remarques : - * -* * -******************************************************************************/ - -PanelItemPersonality g_panel_item_get_personality(const GPanelItem *item) -{ - PanelItemPersonality result; /* Personnalité à retourner */ - GPanelItemClass *class; /* Classe à actionner */ - - class = G_PANEL_ITEM_GET_CLASS(item); - - result = class->get_personality(item); - - return result; - -} - - -/****************************************************************************** -* * -* Paramètres : item = définition de panneau à manipuler. * -* * -* Description : Fournit un composant pour lancer l'activité d'un panneau. * -* * -* Retour : Composant GTK (déjà ?) mis en place. * -* * -* Remarques : - * -* * -******************************************************************************/ - -GtkWidget *g_panel_item_get_launcher(GPanelItem *item) -{ - GtkWidget *result; /* Composant à retourner */ - GPanelItemClass *class; /* Classe à actionner */ - - if (item->launcher == NULL) - { - class = G_PANEL_ITEM_GET_CLASS(item); - item->launcher = class->get_launcher(item); - } - - result = item->launcher; - - if (result != NULL) - ref_object(result); - - return result; - -} - - -/****************************************************************************** -* * -* Paramètres : item = définition de panneau à manipuler. * -* * -* Description : Fournit un composant pour paramétrer l'activité d'un panneau.* -* * -* Retour : Composant GTK (déjà ?) mis en place. * -* * -* Remarques : - * -* * -******************************************************************************/ - -GtkWidget *g_panel_item_get_properties(GPanelItem *item) -{ - GtkWidget *result; /* Composant à retourner */ - GPanelItemClass *class; /* Classe à actionner */ - - if (item->properties == NULL) - { - class = G_PANEL_ITEM_GET_CLASS(item); - item->properties = class->get_properties(item); - } - - result = item->properties; - - if (result != NULL) - ref_object(result); - - return result; - -} - - -/****************************************************************************** -* * -* Paramètres : item = définition de panneau à manipuler. * -* * -* Description : Fournit un composant représentant un panneau graphique. * -* * -* Retour : Composant GTK (déjà ?) mis en place. * -* * -* Remarques : - * -* * -******************************************************************************/ - -GtkTiledPanel *g_panel_item_get_panel(GPanelItem *item) -{ - GtkTiledPanel *result; /* Composant à retourner */ - GPanelItemClass *class; /* Classe à actionner */ - - if (item->pcount == 0 /* || !singleton */) - { - class = G_PANEL_ITEM_GET_CLASS(item); - result = class->get_panel(item, item->properties); - - if (result != NULL) - { - item->panels = realloc(item->panels, ++item->pcount * sizeof(GtkTiledPanel *)); - item->panels[item->pcount - 1] = result; - } - - } - - else - result = item->panels[item->pcount - 1]; - - if (result != NULL) - ref_object(result); - - return result; - -} - - - - - - - - - - - - - -#if 0 - - -#include <assert.h> -#include <stdio.h> -#include <string.h> - - -#include "panel-int.h" -#include "core/global.h" -#include "core/items.h" -#include "../common/extstr.h" -#include "../core/params.h" -#include "../gtkext/gtkdockable-int.h" -#include "../gtkext/named.h" -#include "../plugins/dt.h" -#include "../plugins/pglist.h" - - - -/* ------------------------- COEUR DES PANNEAUX D'AFFICHAGE ------------------------- */ - - - - -/* ------------------------- COEUR D'UN PANNEAU D'AFFICHAGE ------------------------- */ - - -/* Construit la chaîne d'accès à un élément de configuration. */ -static char *gtk_panel_item_class_build_configuration_key(const GPanelItemClass *, const char *); - -/* Fournit le nom court du composant encapsulable. */ -static char *gtk_panel_item_get_name(const GPanelItem *); - -/* Fournit le nom long du composant encapsulable. */ -static char *gtk_panel_item_get_desc(const GPanelItem *); - -/* Détermine si un panneau peut être filtré. */ -static bool gtk_panel_item_can_search(const GPanelItem *); - -/* Fournit le composant graphique intégrable dans un ensemble. */ -static GtkWidget *gtk_panel_item_get_widget(GPanelItem *); - -/* Démarre l'actualisation du filtrage du contenu. */ -static void gtk_panel_item_update_filtered(GPanelItem *, const char *); - - - -/* ---------------------- MECANISMES DE MISE A JOUR DE PANNEAU ---------------------- */ - - -/* Présente une copie de l'affichage du composant rafraîchi. */ -static gboolean g_panel_item_draw_mask(GtkWidget *, cairo_t *, GPanelItem *); - - - -/* ---------------------------------------------------------------------------------- */ -/* COEUR DES PANNEAUX D'AFFICHAGE */ -/* ---------------------------------------------------------------------------------- */ - - - -/****************************************************************************** -* * -* Paramètres : class = classe à consulter. * -* * -* Description : Fournit une indication sur la personnalité du panneau. * -* * -* Retour : Identifiant lié à la nature unique du panneau. * -* * -* Remarques : - * -* * -******************************************************************************/ - -PanelItemPersonality gtk_panel_item_class_get_personality_singleton(const GPanelItemClass *class) -{ - PanelItemPersonality result; /* Personnalité à retourner */ - - result = PIP_SINGLETON; - - return result; - -} - - -/****************************************************************************** -* * -* Paramètres : class = classe à consulter. * -* * -* Description : Fournit une indication d'accroche du panneau au démarrage. * -* * -* Retour : true si le panneau doit être affiché de prime abord. * -* * -* Remarques : - * -* * -******************************************************************************/ - -bool gtk_panel_item_class_dock_at_startup(const GPanelItemClass *class) -{ - bool result; /* Statut à retourner */ - GGenConfig *config; /* Configuration courante */ - char *key; /* Clef d'accès à un paramètre */ -#ifndef NDEBUG - bool status; /* Bilan de consultation */ -#endif - - config = get_main_configuration(); - - key = gtk_panel_item_class_build_configuration_key(class, "dock_at_startup"); - -#ifndef NDEBUG - status = g_generic_config_get_value(config, key, &result); - assert(status); -#else - g_generic_config_get_value(config, key, &result); -#endif - - free(key); - - return result; - -} - - -/****************************************************************************** -* * -* Paramètres : class = classe associée à la consultation. * -* * -* Description : Renvoie false lors d'une consultation de la classe. * -* * -* Retour : false. * -* * -* Remarques : - * -* * -******************************************************************************/ - -bool gtk_panel_item_class_return_false(const GPanelItemClass *class) -{ - bool result; /* Statut à retourner */ - - result = false; - - return result; - -} - - -/****************************************************************************** -* * -* Paramètres : class = classe associée à la consultation. * -* * -* Description : Renvoie true lors d'une consultation de la classe. * -* * -* Retour : true. * -* * -* Remarques : - * -* * -******************************************************************************/ - -bool gtk_panel_item_class_return_true(const GPanelItemClass *class) -{ - bool result; /* Statut à retourner */ - - result = true; - - return result; - -} - - -/****************************************************************************** -* * -* Paramètres : class = classe à consulter. * -* * -* Description : Détermine si un panneau peut être filtré. * -* * -* Retour : Bilan de la consultation. * -* * -* Remarques : - * -* * -******************************************************************************/ - -bool gtk_panel_item_class_can_search(const GPanelItemClass *class) -{ - bool result; /* Statut à retourner */ - - result = class->can_search(class); - - 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 : - * -* * -******************************************************************************/ - -char *gtk_panel_item_class_get_path(const GPanelItemClass *class) -{ - char *result; /* Emplacement à retourner */ - GGenConfig *config; /* Configuration courante */ - char *key; /* Clef d'accès à un paramètre */ - const char *path; /* Nouveau chemin de placement */ -#ifndef NDEBUG - bool status; /* Statut de l'encapsulation */ -#endif - - config = get_main_configuration(); - - key = gtk_panel_item_class_build_configuration_key(class, "path"); - -#ifndef NDEBUG - status = g_generic_config_get_value(config, key, &path); - assert(status); -#else - g_generic_config_get_value(config, key, &path); -#endif - - free(key); - - result = strdup(path); - - 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 : - * -* * -******************************************************************************/ - -char *gtk_panel_item_class_get_key_bindings(const GPanelItemClass *class) -{ - char *result; /* Emplacement à retourner */ - - if (class->get_bindings != NULL) - result = class->get_bindings(class); - - else - result = NULL; - - return result; - -} - - -/****************************************************************************** -* * -* Paramètres : class = classe du type de panneau à traiter. * -* attrib = élément de configuration à inclure dans le résultat.* -* * -* Description : Construit la chaîne d'accès à un élément de configuration. * -* * -* Retour : Chaîne de caractères à libérer après usage. * -* * -* Remarques : - * -* * -******************************************************************************/ - -static char *gtk_panel_item_class_build_configuration_key(const GPanelItemClass *class, const char *attrib) -{ - char *result; /* Construction à renvoyer */ - const char *name; /* Nom court du panneau */ - - name = g_editor_item_class_get_key(G_EDITOR_ITEM_CLASS(class)); - - asprintf(&result, "gui.panels.%s.%s", attrib, name); - - result = strrpl(result, " ", "_"); - - result = strlower(result); - - return result; - -} - - -/****************************************************************************** -* * -* Paramètres : class = classe de panneau à consulter. * -* config = configuration à compléter. * -* * -* Description : Met en place les bases de la configuration d'un panneau. * -* * -* Retour : Bilan de l'opération. * -* * -* Remarques : - * -* * -******************************************************************************/ - -bool gtk_panel_item_class_setup_configuration(const GPanelItemClass *class, GGenConfig *config) -{ - bool result; /* Bilan à retourner */ - char *key; /* Clef d'accès à un paramètre */ - bool dock_at_startup; /* Affichage dès le départ ? */ - char *path; /* Localisation du panneau */ - - key = gtk_panel_item_class_build_configuration_key(class, "dock_at_startup"); - - dock_at_startup = class->dock_at_startup(class); - - result = g_generic_config_create_param_if_not_exist(config, key, CPT_BOOLEAN, dock_at_startup); - - free(key); - - if (!result) - goto exit; - - key = gtk_panel_item_class_build_configuration_key(class, "path"); - - path = class->get_path(class); - - result = g_generic_config_create_param_if_not_exist(config, key, CPT_STRING, path); - - free(path); - - free(key); - - exit: - - return result; - -} - - -/****************************************************************************** -* * -* Paramètres : type = type de panneau à mettre en place. * -* path = emplacement d'affichage ou NULL. * -* * -* Description : Crée un élément de panneau réactif. * -* * -* Retour : Adresse de la structure mise en place. * -* * -* Remarques : - * -* * -******************************************************************************/ - -GPanelItem *g_panel_item_new(GType type, const char *path) -{ - GPanelItem *result; /* Structure à retourner */ - GPanelItemClass *class; /* Classe associée au type */ - PanelItemPersonality personality; /* Caractéristique de panneau */ - GtkTiledGrid *grid; /* Composant d'affichage */ - - class = g_type_class_ref(type); - - personality = gtk_panel_item_class_get_personality(class); - assert(path != NULL || personality == PIP_PERSISTENT_SINGLETON); - - g_type_class_unref(class); - - if (personality == PIP_PERSISTENT_SINGLETON || personality == PIP_SINGLETON) - { - result = G_PANEL_ITEM(find_editor_item_by_type(type)); - - if (result != NULL) - goto singleton; - - } - - result = create_object_from_type(type); - - grid = get_tiled_grid(); - - g_signal_connect_swapped(result, "dock-request", G_CALLBACK(gtk_tiled_grid_add), grid); - g_signal_connect_swapped(result, "undock-request", G_CALLBACK(gtk_tiled_grid_remove), grid); - - gtk_dockable_setup_dnd(GTK_DOCKABLE(result)); - - register_editor_item(G_EDITOR_ITEM(result)); - - notify_panel_creation(result); - - singleton: - - if (path != NULL) - { - if (path[0] != '\0') - gtk_panel_item_set_path(result, path); - - g_panel_item_dock(result); - - } - - return result; - -} - - -/****************************************************************************** -* * -* Paramètres : item = instance de panneau à consulter. * -* * -* Description : Indique le composant graphique principal du panneau. * -* * -* Retour : Composant graphique avec nom constituant le panneau. * -* * -* Remarques : - * -* * -******************************************************************************/ - -GNamedWidget *gtk_panel_item_get_named_widget(const GPanelItem *item) -{ - GNamedWidget *result; /* Composant nommé à retourner */ - - result = item->widget; - - g_object_ref(G_OBJECT(result)); - - return result; - -} - - -/****************************************************************************** -* * -* Paramètres : item = instance GTK dont l'interface est à consulter. * -* * -* Description : Fournit le nom court du composant encapsulable. * -* * -* Retour : Désignation humaine pour titre d'onglet ou de fenêtre. * -* * -* Remarques : - * -* * -******************************************************************************/ - -static char *gtk_panel_item_get_name(const GPanelItem *item) -{ - char *result; /* Désignation à retourner */ - - result = g_named_widget_get_name(G_NAMED_WIDGET(item->widget), false); - - return result; - -} - - -/****************************************************************************** -* * -* Paramètres : item = instance GTK dont l'interface est à consulter. * -* * -* Description : Fournit le nom long du composant encapsulable. * -* * -* Retour : Désignation humaine pour titre d'onglet ou de fenêtre. * -* * -* Remarques : - * -* * -******************************************************************************/ - -static char *gtk_panel_item_get_desc(const GPanelItem *item) -{ - char *result; /* Description à retourner */ - - result = g_named_widget_get_name(G_NAMED_WIDGET(item->widget), true); - - return result; - -} - - -/****************************************************************************** -* * -* Paramètres : item = instance GTK dont l'interface est à consulter. * -* * -* Description : Détermine si un panneau peut être filtré. * -* * -* Retour : Bilan de la consultation. * -* * -* Remarques : - * -* * -******************************************************************************/ - -static bool gtk_panel_item_can_search(const GPanelItem *item) -{ - bool result; /* Indication à retourner */ - GPanelItemClass *class; /* Classe de l'élément visé */ - - class = G_PANEL_ITEM_GET_CLASS(item); - - result = gtk_panel_item_class_can_search(class); - - return result; - -} - - -/****************************************************************************** -* * -* Paramètres : item = instance GTK dont l'interface est à consulter. * -* * -* Description : Fournit le composant graphique intégrable dans un ensemble. * -* * -* Retour : Composant graphique prêt à emploi. * -* * -* Remarques : - * -* * -******************************************************************************/ - -static GtkWidget *gtk_panel_item_get_widget(GPanelItem *item) -{ - GtkWidget *result; /* Composant à retourner */ - - if (item->cached_widget == NULL) - item->cached_widget = g_named_widget_get_widget(G_NAMED_WIDGET(item->widget)); - - result = item->cached_widget; - - g_object_ref(G_OBJECT(result)); - - return result; - -} - - -/****************************************************************************** -* * -* Paramètres : item = instance GTK dont l'interface est à sollicitée. * -* * -* Description : Démarre l'actualisation du filtrage du contenu. * -* * -* Retour : - * -* * -* Remarques : - * -* * -******************************************************************************/ - -static void gtk_panel_item_update_filtered(GPanelItem *item, const char *filter) -{ - assert(gtk_panel_item_can_search(item)); - - if (item->filter != NULL) - free(item->filter); - - item->filter = (filter ? strdup(filter) : NULL); - - G_PANEL_ITEM_GET_CLASS(item)->update_filtered(item); - -} - - -/****************************************************************************** -* * -* Paramètres : item = instance GTK à consulter. * -* path = nouvelle emplacement d'inclusion. * -* * -* Description : Définit le chemin d'accès à utiliser pour les encapsulations.* -* * -* Retour : - * -* * -* Remarques : - * -* * -******************************************************************************/ - -void gtk_panel_item_set_path(GPanelItem *item, const char *path) -{ - GGenConfig *config; /* Configuration courante */ - char *key; /* Clef d'accès à un paramètre */ - - config = get_main_configuration(); - - key = gtk_panel_item_class_build_configuration_key(G_PANEL_ITEM_GET_CLASS(item), "path"); - - g_generic_config_set_value(config, key, path); - - free(key); - -} - - -/****************************************************************************** -* * -* Paramètres : item = composant à présenter à l'affichage. * -* * -* Description : Place un panneau dans l'ensemble affiché. * -* * -* Retour : - * -* * -* Remarques : - * -* * -******************************************************************************/ - -void g_panel_item_dock(GPanelItem *item) -{ - assert(!item->docked); - - g_signal_emit_by_name(item, "dock-request"); - - if (G_PANEL_ITEM_GET_CLASS(item)->ack_dock != NULL) - G_PANEL_ITEM_GET_CLASS(item)->ack_dock(item); - - notify_panel_docking(item, true); - -} - - -/****************************************************************************** -* * -* Paramètres : item = composant d'affichage à mettre à jour. * -* status = nouvel état d'encapsulation. * -* * -* Description : Définit si le composant repose sur un support de l'éditeur. * -* * -* Retour : - * -* * -* Remarques : - * -* * -******************************************************************************/ - -void g_panel_item_set_dock_at_startup(GPanelItem *item, bool status) -{ - char *key; /* Clef d'accès à un paramètre */ - - item->docked = status; - - key = gtk_panel_item_class_build_configuration_key(G_PANEL_ITEM_GET_CLASS(item), "dock_at_startup"); - - g_generic_config_set_value(get_main_configuration(), key, status); - - free(key); - -} - - -/****************************************************************************** -* * -* Paramètres : item = composant d'affichage à consulter. * -* * -* Description : Indique si le composant repose sur un support de l'éditeur. * -* * -* Retour : true si le composant est bien incrusté quelque part. * -* * -* Remarques : - * -* * -******************************************************************************/ - -bool g_panel_item_is_docked(const GPanelItem *item) -{ - bool result; /* Statut à retourner */ - - result = item->docked; - - return result; - -} - - -/****************************************************************************** -* * -* Paramètres : item = composant à retirer de l'affichage. * -* * -* Description : Supprime un panneau de l'ensemble affiché. * -* * -* Retour : - * -* * -* Remarques : - * -* * -******************************************************************************/ - -void g_panel_item_undock(GPanelItem *item) -{ - PanelItemPersonality personality; /* Caractéristique de panneau */ - - assert(item->docked); - - g_signal_emit_by_name(item, "undock-request"); - - if (G_PANEL_ITEM_GET_CLASS(item)->ack_undock != NULL) - G_PANEL_ITEM_GET_CLASS(item)->ack_undock(item); - - notify_panel_docking(item, false); - - personality = gtk_panel_item_class_get_personality(G_PANEL_ITEM_GET_CLASS(item)); - - if (personality != PIP_PERSISTENT_SINGLETON) - unregister_editor_item(G_EDITOR_ITEM(item)); - -} - - - -/* ---------------------------------------------------------------------------------- */ -/* MECANISMES DE MISE A JOUR DE PANNEAU */ -/* ---------------------------------------------------------------------------------- */ - - -/****************************************************************************** -* * -* Paramètres : item = panneau ciblé par une mise à jour. * -* * -* Description : Obtient le groupe de travail dédié à une mise à jour. * -* * -* Retour : - * -* * -* Remarques : - * -* * -******************************************************************************/ - -wgroup_id_t g_panel_item_get_group(const GPanelItem *item) -{ - wgroup_id_t result; /* Identifiant à retourner */ - - result = G_PANEL_ITEM_GET_CLASS(item)->gid; - - return result; - -} - - -/****************************************************************************** -* * -* Paramètres : widget = composant graphique sur lequel dessiner. * -* cr = contexte graphique pour le dessin. * -* panel = panneau ciblé par une mise à jour. * -* * -* Description : Présente une copie de l'affichage du composant rafraîchi. * -* * -* Retour : FALSE afin de poursuivre les traitements. * -* * -* Remarques : - * -* * -******************************************************************************/ - -static gboolean g_panel_item_draw_mask(GtkWidget *widget, cairo_t *cr, GPanelItem *item) -{ - int width; /* Largeur du composant actuel */ - int height; /* Hauteur du composant actuel */ - - width = gtk_widget_get_allocated_width(widget); - height = gtk_widget_get_allocated_height(widget); - - cairo_save(cr); - - cairo_set_source_surface(cr, item->surface, 0, 0); - cairo_rectangle(cr, 0, 0, width, height); - - cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE); - cairo_fill(cr); - - cairo_restore(cr); - - return FALSE; - -} - - -/****************************************************************************** -* * -* Paramètres : panel = panneau ciblé par une mise à jour. * -* * -* Description : Bascule l'affichage d'un panneau avant sa mise à jour. * -* * -* Retour : - * -* * -* Remarques : - * -* * -******************************************************************************/ - -void g_panel_item_switch_to_updating_mask(GPanelItem *item) -{ - GtkBuilder *builder; /* Constructeur sous-jacent */ - GtkWidget *content; /* Composant à faire évoluer */ - GdkWindow *window; /* Fenêtre au contenu à copier */ - int width; /* Largeur du composant actuel */ - int height; /* Hauteur du composant actuel */ - cairo_t *cr; /* Pinceau pour les dessins */ - GtkAdjustment *adj; /* Défilement éventuel */ - GtkStack *stack; /* Pile de composants GTK */ - GtkWidget *mask; /* Masque des travaux */ - - if (g_atomic_int_add(&item->switched, 1) > 0) - return; - - /* Copie de l'affichage courant */ - - assert(item->surface == NULL); - - builder = gtk_built_named_widget_get_builder(GTK_BUILT_NAMED_WIDGET(item->widget)); - - content = GTK_WIDGET(gtk_builder_get_object(builder, "content")); - - window = gtk_widget_get_window(content); - - if (window != NULL) - { - width = gtk_widget_get_allocated_width(content); - height = gtk_widget_get_allocated_height(content); - - item->surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, width, height); - - cr = cairo_create(item->surface); - - gdk_cairo_set_source_window(cr, window, 0, 0); - - cairo_paint(cr); - - cairo_destroy(cr); - - } - - /* Sauvegarde de l'éventuelle position */ - - if (GTK_IS_SCROLLED_WINDOW(content)) - { - adj = gtk_scrolled_window_get_hadjustment(GTK_SCROLLED_WINDOW(content)); - item->hadj_value = gtk_adjustment_get_value(adj); - - adj = gtk_scrolled_window_get_vadjustment(GTK_SCROLLED_WINDOW(content)); - item->vadj_value = gtk_adjustment_get_value(adj); - - } - - /* Opération de basculement effectif */ - - stack = GTK_STACK(gtk_builder_get_object(builder, "stack")); - - mask = GTK_WIDGET(gtk_builder_get_object(builder, "mask")); - - gtk_spinner_start(GTK_SPINNER(mask)); - - if (item->surface != NULL) - g_signal_connect(mask, "draw", G_CALLBACK(g_panel_item_draw_mask), item); - - gtk_stack_set_visible_child(stack, mask); - - g_object_unref(G_OBJECT(builder)); - -} - - -/****************************************************************************** -* * -* Paramètres : panel = panneau ciblé par une mise à jour. * -* * -* Description : Bascule l'affichage d'un panneau après sa mise à jour. * -* * -* Retour : - * -* * -* Remarques : - * -* * -******************************************************************************/ - -void g_panel_item_switch_to_updated_content(GPanelItem *item) -{ - GtkBuilder *builder; /* Constructeur sous-jacent */ - GtkWidget *content; /* Composant à faire évoluer */ - GtkAdjustment *adj; /* Défilement éventuel */ - GtkStack *stack; /* Pile de composants GTK */ - GtkWidget *mask; /* Masque des travaux */ - - if (g_atomic_int_get(&item->switched) > 1) - goto skip; - - /* Restauration d'une éventuelle position */ - - builder = gtk_built_named_widget_get_builder(GTK_BUILT_NAMED_WIDGET(item->widget)); - - content = GTK_WIDGET(gtk_builder_get_object(builder, "content")); - - if (GTK_IS_SCROLLED_WINDOW(content)) - { - adj = gtk_scrolled_window_get_hadjustment(GTK_SCROLLED_WINDOW(content)); - gtk_adjustment_set_value(adj, item->hadj_value); - - adj = gtk_scrolled_window_get_vadjustment(GTK_SCROLLED_WINDOW(content)); - gtk_adjustment_set_value(adj, item->vadj_value); - - } - - /* Opération de basculement effectif */ - - stack = GTK_STACK(gtk_builder_get_object(builder, "stack")); - - gtk_stack_set_visible_child(stack, content); - - mask = GTK_WIDGET(gtk_builder_get_object(builder, "mask")); - - g_signal_handlers_disconnect_by_func(mask, G_CALLBACK(g_panel_item_draw_mask), item); - - gtk_spinner_stop(GTK_SPINNER(mask)); - - /* Supression de la copie d'affichage */ - - if (item->surface != NULL) - { - cairo_surface_destroy(item->surface); - item->surface = NULL; - } - - g_object_unref(G_OBJECT(builder)); - - skip: - - g_atomic_int_dec_and_test(&item->switched); - -} - - -#endif diff --git a/src/gui/panel.h b/src/gui/panel.h deleted file mode 100644 index 03b67d4..0000000 --- a/src/gui/panel.h +++ /dev/null @@ -1,148 +0,0 @@ - -/* 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-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_PANEL_H -#define _GUI_PANEL_H - - -#include "../glibext/helpers.h" -#include "../gtkext/panel.h" - - -#include <gtk/gtk.h> - - - -#define G_TYPE_PANEL_ITEM (g_panel_item_get_type()) - -DECLARE_GTYPE(GPanelItem, g_panel_item, G, PANEL_ITEM); - - -/* Types de panneaux pour éditeur */ -typedef enum _PanelItemPersonality -{ - PIP_NONE, /* Pas de particularité */ - - PIP_MAIN_PANEL, /* Panneau principal */ - PIP_SINGLETON, /* Instance unique */ - - PIP_COUNT - -} PanelItemPersonality; - - -/* Fournit une indication sur la personnalité du panneau. */ -PanelItemPersonality g_panel_item_get_personality(const GPanelItem *); - -/* Fournit un composant pour lancer l'activité d'un panneau. */ -GtkWidget *g_panel_item_get_launcher(GPanelItem *); - -/* Fournit un composant pour paramétrer l'activité d'un panneau. */ -GtkWidget *g_panel_item_get_properties(GPanelItem *); - -/* Fournit un composant représentant un panneau graphique. */ -GtkTiledPanel *g_panel_item_get_panel(GPanelItem *); - - - - - - - - - -#if 0 - - -#include <stdbool.h> -#include <gtk/gtk.h> - - -#include "../glibext/configuration.h" -#include "../glibext/named.h" - - - -#define G_TYPE_PANEL_ITEM g_panel_item_get_type() -#define G_PANEL_ITEM(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_PANEL_ITEM, GPanelItem)) -#define G_IS_PANEL_ITEM(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_PANEL_ITEM)) -#define G_PANEL_ITEM_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_PANEL_ITEM, GPanelItemClass)) -#define G_IS_PANEL_ITEM_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_PANEL_ITEM)) -#define G_PANEL_ITEM_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_PANEL_ITEM, GPanelItemClass)) - - -/* Elément réactif pour panneaux de l'éditeur (instance) */ -typedef struct _GPanelItem GPanelItem; - -/* Elément réactif pour panneaux de l'éditeur (classe) */ -typedef struct _GPanelItemClass GPanelItemClass; - - - - -/* Indique le type défini pour un élément destiné à un panneau. */ -GType g_panel_item_get_type(void); - -/* Fournit une indication d'accroche du panneau au démarrage. */ -bool gtk_panel_item_class_dock_at_startup(const GPanelItemClass *); - -/* Détermine si un panneau peut être filtré. */ -bool gtk_panel_item_class_can_search(const GPanelItemClass *); - -/* Indique le chemin initial de la localisation d'un panneau. */ -char *gtk_panel_item_class_get_path(const GPanelItemClass *); - -/* Indique la définition d'un éventuel raccourci clavier. */ -char *gtk_panel_item_class_get_key_bindings(const GPanelItemClass *); - -/* Met en place les bases de la configuration du panneau. */ -bool gtk_panel_item_class_setup_configuration(const GPanelItemClass *, GGenConfig *); - -/* Crée un élément de panneau réactif. */ -GPanelItem *g_panel_item_new(GType, const char *); - -/* Indique le composant graphique principal du panneau. */ -GNamedWidget *gtk_panel_item_get_named_widget(const GPanelItem *); - -/* Définit le chemin d'accès à utiliser pour les encapsulations. */ -void gtk_panel_item_set_path(GPanelItem *, const char *); - -/* Place un panneau dans l'ensemble affiché. */ -void g_panel_item_dock(GPanelItem *); - -/* Définit si le composant repose sur un support de l'éditeur. */ -void g_panel_item_set_dock_at_startup(GPanelItem *, bool); - -/* Indique si le composant repose sur un support de l'éditeur. */ -bool g_panel_item_is_docked(const GPanelItem *); - -/* Supprime un panneau de l'ensemble affiché. */ -void g_panel_item_undock(GPanelItem *); - - -#endif - - - -#endif /* _GUI_PANEL_H */ diff --git a/src/gui/panels/Makefile.am b/src/gui/panels/Makefile.am index 476a436..2765405 100644 --- a/src/gui/panels/Makefile.am +++ b/src/gui/panels/Makefile.am @@ -38,8 +38,7 @@ IMG_PATH = ../../../data/images RES_FILES = \ binary.ui \ - binary-launch.ui \ - binary-props.ui \ + binary-params.ui \ $(IMG_PATH)/binfile-symbolic.svg \ welcome.ui \ welcome-hints.txt \ @@ -48,6 +47,8 @@ RES_FILES = \ libguipanels4_la_SOURCES = \ binary-int.h \ binary.h binary.c \ + binary-params-int.h \ + binary-params.h binary-params.c \ resources.h resources.c \ welcome-int.h \ welcome.h welcome.c diff --git a/src/gui/panels/binary-int.h b/src/gui/panels/binary-int.h index f68da9b..5116f5c 100644 --- a/src/gui/panels/binary-int.h +++ b/src/gui/panels/binary-int.h @@ -27,14 +27,10 @@ #include "binary.h" -#include "../panel-int.h" #include "../../gtkext/panel-int.h" -/* ------------------------- COEUR D'UN PANNEAU D'AFFICHAGE ------------------------- */ - - /* Panneau d'accueil par défaut (instance) */ struct _GtkBinaryPanel { @@ -53,23 +49,4 @@ struct _GtkBinaryPanelClass -/* ---------------------- MANIPULATIONS D'UN PANNEAU GRAPHIQUE ---------------------- */ - - -/* Définition pour gestion par le framework d'un panneau graphique (instance) */ -struct _GBinaryPanel -{ - GPanelItem parent; /* A laisser en premier */ - -}; - -/* Définition pour gestion par le framework d'un panneau graphique (classe) */ -struct _GBinaryPanelClass -{ - GPanelItemClass parent; /* A laisser en premier */ - -}; - - - #endif /* _GUI_PANELS_BINARY_INT_H */ diff --git a/src/gui/panels/binary-launch.ui b/src/gui/panels/binary-launch.ui deleted file mode 100644 index 553f758..0000000 --- a/src/gui/panels/binary-launch.ui +++ /dev/null @@ -1,65 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<interface> - - <object class="GtkGrid" id="launcher"> - <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"> - <property name="icon-name">binfile-symbolic</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"> - <property name="label"><b>Binary analysis</b></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"> - <property name="label">Load a binary content and parse its format if recognized</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> - -</interface> 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-props.ui b/src/gui/panels/binary-params.ui index bd48ea8..dcbaf7c 100644 --- a/src/gui/panels/binary-props.ui +++ b/src/gui/panels/binary-params.ui @@ -1,13 +1,14 @@ <?xml version="1.0" encoding="UTF-8"?> <interface> - <object class="GtkGrid" id="properties"> + <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> @@ -18,8 +19,9 @@ </layout> </object> </child> + <child> - <object class="GtkEntry" id="new_file"> + <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> @@ -31,9 +33,10 @@ <style> <class name="background"/> </style> - <signal name="icon-release" handler="g_binary_panel_on_new_file_entry_icon_release"/> + <signal name="icon-release" handler="gtk_binary_parameters_on_new_file_entry_icon_release"/> </object> </child> - </object> + + </template> </interface> diff --git a/src/gui/panels/binary.c b/src/gui/panels/binary.c index de0a4d0..f58c06b 100644 --- a/src/gui/panels/binary.c +++ b/src/gui/panels/binary.c @@ -26,8 +26,6 @@ #include "binary-int.h" -#include "../window.h" -#include "../../analysis/contents/file.h" #include "../../gtkext/helpers.h" #include "../../gtkext/hexview.h" @@ -43,10 +41,10 @@ static void gtk_binary_panel_class_init(GtkBinaryPanelClass *); static void gtk_binary_panel_init(GtkBinaryPanel *); /* Supprime toutes les références externes. */ -static void gtk_binary_panel_dispose(GtkBinaryPanel *); +static void gtk_binary_panel_dispose(GObject *); /* Procède à la libération totale de la mémoire. */ -static void gtk_binary_panel_finalize(GtkBinaryPanel *); +static void gtk_binary_panel_finalize(GObject *); @@ -57,49 +55,12 @@ static void gtk_binary_panel_finalize(GtkBinaryPanel *); -/* ---------------------- MANIPULATIONS D'UN PANNEAU GRAPHIQUE ---------------------- */ - - -/* Initialise la classe des panneaux graphiques pour binaires. */ -static void g_binary_panel_class_init(GBinaryPanelClass *); - -/* Initialise une instance de panneau graphique pour binaire. */ -static void g_binary_panel_init(GBinaryPanel *); - -/* Supprime toutes les références externes. */ -static void g_binary_panel_dispose(GBinaryPanel *); - -/* Procède à la libération totale de la mémoire. */ -static void g_binary_panel_finalize(GBinaryPanel *); - - - -/* --------------------- IMPLEMENTATION DES FONCTIONS DE CLASSE --------------------- */ - - -/* Fournit une indication sur la personnalité du panneau. */ -static PanelItemPersonality g_binary_panel_get_personality(const GBinaryPanel *); - -/* Fournit un composant pour lancer l'activité d'un panneau. */ -static GtkWidget *g_binary_panel_get_launcher(GBinaryPanel *); - -/* Fournit un composant pour paramétrer l'activité d'un panneau. */ -static GtkWidget *g_binary_panel_get_properties(GBinaryPanel *); - -/* Ouvre une boîte de dialogue pour récupérer un fichier. */ -static void g_binary_panel_on_new_file_entry_icon_release(GtkEntry *, GtkEntryIconPosition, GBinaryPanel *); - -/* Fournit un composant représentant un panneau graphique. */ -static GtkTiledPanel *g_binary_panel_get_panel(GBinaryPanel *, GtkWidget *); - - - /* ---------------------------------------------------------------------------------- */ /* COEUR D'UN PANNEAU D'AFFICHAGE */ /* ---------------------------------------------------------------------------------- */ -/* Indique le type défini pour un panneau d'accueil. */ +/* 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); @@ -122,8 +83,8 @@ static void gtk_binary_panel_class_init(GtkBinaryPanelClass *class) object = G_OBJECT_CLASS(class); - object->dispose = (GObjectFinalizeFunc/* ! */)gtk_binary_panel_dispose; - object->finalize = (GObjectFinalizeFunc)gtk_binary_panel_finalize; + object->dispose = gtk_binary_panel_dispose; + object->finalize = gtk_binary_panel_finalize; widget = GTK_WIDGET_CLASS(class); @@ -155,7 +116,7 @@ static void gtk_binary_panel_init(GtkBinaryPanel *panel) /****************************************************************************** * * -* Paramètres : panel = instance d'objet GLib à traiter. * +* Paramètres : object = instance d'objet GLib à traiter. * * * * Description : Supprime toutes les références externes. * * * @@ -165,18 +126,18 @@ static void gtk_binary_panel_init(GtkBinaryPanel *panel) * * ******************************************************************************/ -static void gtk_binary_panel_dispose(GtkBinaryPanel *panel) +static void gtk_binary_panel_dispose(GObject *object) { - gtk_widget_dispose_template(GTK_WIDGET(panel), GTK_TYPE_BINARY_PANEL); + gtk_widget_dispose_template(GTK_WIDGET(object), GTK_TYPE_BINARY_PANEL); - G_OBJECT_CLASS(gtk_binary_panel_parent_class)->dispose(G_OBJECT(panel)); + G_OBJECT_CLASS(gtk_binary_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. * * * @@ -186,9 +147,9 @@ static void gtk_binary_panel_dispose(GtkBinaryPanel *panel) * * ******************************************************************************/ -static void gtk_binary_panel_finalize(GtkBinaryPanel *panel) +static void gtk_binary_panel_finalize(GObject *object) { - G_OBJECT_CLASS(gtk_binary_panel_parent_class)->finalize(G_OBJECT(panel)); + G_OBJECT_CLASS(gtk_binary_panel_parent_class)->finalize(object); } @@ -232,286 +193,3 @@ GtkTiledPanel *gtk_binary_panel_new_for_content(GBinContent *content) - -/* ---------------------------------------------------------------------------------- */ -/* MANIPULATIONS D'UN PANNEAU GRAPHIQUE */ -/* ---------------------------------------------------------------------------------- */ - - -/* Indique le type défini pour une manipulation de panneau pour binaires. */ -G_DEFINE_TYPE(GBinaryPanel, g_binary_panel, G_TYPE_PANEL_ITEM); - - -/****************************************************************************** -* * -* Paramètres : class = classe à initialiser. * -* * -* Description : Initialise la classe des panneaux graphiques pour binaires. * -* * -* Retour : - * -* * -* Remarques : - * -* * -******************************************************************************/ - -static void g_binary_panel_class_init(GBinaryPanelClass *class) -{ - GObjectClass *object; /* Autre version de la classe */ - GPanelItemClass *panel; /* Encore une autre vision... */ - - object = G_OBJECT_CLASS(class); - - object->dispose = (GObjectFinalizeFunc/* ! */)g_binary_panel_dispose; - object->finalize = (GObjectFinalizeFunc)g_binary_panel_finalize; - - panel = G_PANEL_ITEM_CLASS(class); - - panel->get_personality = (get_panel_item_personality_cb)g_binary_panel_get_personality; - panel->get_launcher = (get_panel_item_widget_cb)g_binary_panel_get_launcher; - panel->get_properties = (get_panel_item_widget_cb)g_binary_panel_get_properties; - panel->get_panel = (get_panel_item_panel_cb)g_binary_panel_get_panel; - -} - - -/****************************************************************************** -* * -* Paramètres : panel = instance à initialiser. * -* * -* Description : Initialise une instance de panneau graphique pour binaire. * -* * -* Retour : - * -* * -* Remarques : - * -* * -******************************************************************************/ - -static void g_binary_panel_init(GBinaryPanel *panel) -{ - -} - - -/****************************************************************************** -* * -* Paramètres : panel = instance d'objet GLib à traiter. * -* * -* Description : Supprime toutes les références externes. * -* * -* Retour : - * -* * -* Remarques : - * -* * -******************************************************************************/ - -static void g_binary_panel_dispose(GBinaryPanel *panel) -{ - G_OBJECT_CLASS(g_binary_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_binary_panel_finalize(GBinaryPanel *panel) -{ - G_OBJECT_CLASS(g_binary_panel_parent_class)->finalize(G_OBJECT(panel)); - -} - - -/****************************************************************************** -* * -* Paramètres : - * -* * -* Description : Constitue une définition de manipulation de panneau. * -* * -* Retour : Définition de propriétés mise en place. * -* * -* Remarques : - * -* * -******************************************************************************/ - -GPanelItem *g_binary_panel_new(void) -{ - GPanelItem *result; /* Structure à retourner */ - - result = g_object_new(G_TYPE_BINARY_PANEL, NULL); - - return result; - -} - - - -/* ---------------------------------------------------------------------------------- */ -/* IMPLEMENTATION DES FONCTIONS DE CLASSE */ -/* ---------------------------------------------------------------------------------- */ - - -/****************************************************************************** -* * -* Paramètres : panel = définition de panneau à consulter. * -* * -* Description : Fournit une indication sur la personnalité du panneau. * -* * -* Retour : Identifiant lié à la nature du panneau. * -* * -* Remarques : - * -* * -******************************************************************************/ - -static PanelItemPersonality g_binary_panel_get_personality(const GBinaryPanel *panel) -{ - PanelItemPersonality result; /* Personnalité à retourner */ - - result = PIP_MAIN_PANEL; - - return result; - -} - - -/****************************************************************************** -* * -* Paramètres : panel = définition de panneau à manipuler. * -* * -* Description : Fournit un composant pour lancer l'activité d'un panneau. * -* * -* Retour : Composant GTK (déjà ?) mis en place. * -* * -* Remarques : - * -* * -******************************************************************************/ - -static GtkWidget *g_binary_panel_get_launcher(GBinaryPanel *panel) -{ - GtkWidget *result; /* Composant à retourner */ - GtkBuilder *builder; /* Constructeur d'UI */ - - builder = gtk_builder_new_from_resource("/re/chrysalide/framework/gui/panels/binary-launch.ui"); - - result = GTK_WIDGET(gtk_builder_get_object(builder, "launcher")); - ref_object(result); - - unref_object(builder); - - return result; - -} - - -/****************************************************************************** -* * -* Paramètres : panel = définition de panneau à manipuler. * -* * -* Description : Fournit un composant pour paramétrer l'activité d'un panneau.* -* * -* Retour : Composant GTK (déjà ?) mis en place. * -* * -* Remarques : - * -* * -******************************************************************************/ - -static GtkWidget *g_binary_panel_get_properties(GBinaryPanel *panel) -{ - GtkWidget *result; /* Composant à retourner */ - GtkBuilderScope *scope; /* Fonctions pour signaux */ - GtkBuilderCScope *cscope; /* Fonctions pour signaux */ - GtkBuilder *builder; /* Constructeur d'UI */ -#ifndef NDEBUG - gboolean status; /* Bilan d'un chargement */ -#endif - - scope = gtk_builder_cscope_new(); - cscope = GTK_BUILDER_CSCOPE(scope); - - gtk_builder_cscope_add_callback_symbol(cscope, BUILDER_CB(g_binary_panel_on_new_file_entry_icon_release)); - - builder = gtk_builder_new(); - gtk_builder_set_scope(builder, scope); - gtk_builder_set_current_object(builder, G_OBJECT(panel)); - -#ifndef NDEBUG - status = gtk_builder_add_from_resource(builder, "/re/chrysalide/framework/gui/panels/binary-props.ui", NULL); - assert(status); -#else - gtk_builder_add_from_resource(builder, "/re/chrysalide/framework/gui/panels/binary-props.ui", NULL); -#endif - - result = GTK_WIDGET(gtk_builder_get_object(builder, "properties")); - ref_object(result); - - unref_object(builder); - unref_object(scope); - - return result; - -} - - -/****************************************************************************** -* * -* Paramètres : entry = zone de saisie concernée par l'appel. * -* icon_pos = position de l'icone incrustée dans la zone. * -* panel = définition de panneau à manipuler. * -* * -* Description : Ouvre une boîte de dialogue pour récupérer un fichier. * -* * -* Retour : - * -* * -* Remarques : - * -* * -******************************************************************************/ - -static void g_binary_panel_on_new_file_entry_icon_release(GtkEntry *entry, GtkEntryIconPosition icon_pos, GBinaryPanel *panel) -{ - GtkRoot *root; /* Racine du composant */ - GtkTiledPanel *tiled; /* Panneau d'affichage complet */ - - root = gtk_widget_get_root(GTK_WIDGET(entry)); - - tiled = g_binary_panel_get_panel(panel, NULL); - - gtk_framework_window_add(GTK_FRAMEWORK_WINDOW(root), tiled); - -} - - -/****************************************************************************** -* * -* Paramètres : panel = définition de panneau à manipuler. * -* props = éventuels éléments graphiques de paramétrages. * -* * -* Description : Fournit un composant représentant un panneau graphique. * -* * -* Retour : Composant GTK (déjà ?) mis en place. * -* * -* Remarques : - * -* * -******************************************************************************/ - -static GtkTiledPanel *g_binary_panel_get_panel(GBinaryPanel *panel, GtkWidget *props) -{ - GtkTiledPanel *result; /* Composant à retourner */ - GBinContent *content; /* Contenu binaire à afficher */ - - content = g_file_content_new("/bin/id"); - - result = gtk_binary_panel_new_for_content(content); - - unref_object(content); - - return result; - -} diff --git a/src/gui/panels/binary.h b/src/gui/panels/binary.h index e92895b..26f8a7d 100644 --- a/src/gui/panels/binary.h +++ b/src/gui/panels/binary.h @@ -29,16 +29,12 @@ #include <gtk/gtk.h> -#include "../panel.h" #include "../../analysis/content.h" #include "../../glibext/helpers.h" #include "../../gtkext/panel.h" -/* ------------------------- COEUR D'UN PANNEAU D'AFFICHAGE ------------------------- */ - - #define GTK_TYPE_BINARY_PANEL (gtk_binary_panel_get_type()) DECLARE_GTYPE(GtkBinaryPanel, gtk_binary_panel, GTK, BINARY_PANEL); @@ -49,17 +45,4 @@ GtkTiledPanel *gtk_binary_panel_new_for_content(GBinContent *); -/* ---------------------- MANIPULATIONS D'UN PANNEAU GRAPHIQUE ---------------------- */ - - -#define G_TYPE_BINARY_PANEL (g_binary_panel_get_type()) - -DECLARE_GTYPE(GBinaryPanel, g_binary_panel, G, BINARY_PANEL); - - -/* Constitue une définition de manipulation de panneau. */ -GPanelItem *g_binary_panel_new(void); - - - #endif /* _GUI_PANELS_BINARY_H */ diff --git a/src/gui/panels/gresource.xml b/src/gui/panels/gresource.xml index d00953d..f49a16f 100644 --- a/src/gui/panels/gresource.xml +++ b/src/gui/panels/gresource.xml @@ -2,8 +2,7 @@ <gresources> <gresource prefix="/re/chrysalide/framework/gui/panels"> <file compressed="true">binary.ui</file> - <file compressed="true">binary-launch.ui</file> - <file compressed="true">binary-props.ui</file> + <file compressed="true">binary-params.ui</file> <file compressed="true">welcome.ui</file> <file compressed="true">welcome-hints.txt</file> </gresource> diff --git a/src/gui/panels/welcome-int.h b/src/gui/panels/welcome-int.h index d99d316..206bc2c 100644 --- a/src/gui/panels/welcome-int.h +++ b/src/gui/panels/welcome-int.h @@ -27,20 +27,15 @@ #include "welcome.h" -#include "../panel-int.h" #include "../../gtkext/panel-int.h" -/* ------------------------- COEUR D'UN PANNEAU D'AFFICHAGE ------------------------- */ - - /* Panneau d'accueil par défaut (instance) */ struct _GtkWelcomePanel { GtkTiledPanel parent; /* A laisser en premier */ - GListStore *store; /* Données brutes */ GtkListBox *list; /* Liste de lanceurs */ GtkStack *properties; /* Premières propriétés */ @@ -62,28 +57,5 @@ struct _GtkWelcomePanelClass }; -/* Met en place un nouveau panneau d'accueil. */ -bool gtk_welcome_panel_create(GtkWelcomePanel *); - - - -/* ---------------------- MANIPULATIONS D'UN PANNEAU GRAPHIQUE ---------------------- */ - - -/* Définition pour gestion par le framework d'un panneau graphique (instance) */ -struct _GWelcomePanel -{ - GPanelItem parent; /* A laisser en premier */ - -}; - -/* Définition pour gestion par le framework d'un panneau graphique (classe) */ -struct _GWelcomePanelClass -{ - GPanelItemClass 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 3cd349f..6e8763b 100644 --- a/src/gui/panels/welcome.c +++ b/src/gui/panels/welcome.c @@ -28,9 +28,6 @@ #include <assert.h> -#include <i18n.h> - - #include "welcome-int.h" #include "../core/panels.h" #include "../../common/shuffle.h" @@ -48,16 +45,10 @@ static void gtk_welcome_panel_class_init(GtkWelcomePanelClass *); static void gtk_welcome_panel_init(GtkWelcomePanel *); /* Supprime toutes les références externes. */ -static void gtk_welcome_panel_dispose(GtkWelcomePanel *); +static void gtk_welcome_panel_dispose(GObject *); /* Procède à la libération totale de la mémoire. */ -static void gtk_welcome_panel_finalize(GtkWelcomePanel *); - -/* Intègre une définition de panneau enregistrée. */ -static bool gtk_welcome_panel_add_launcher(GPanelItem *, GListStore *); - -/* Prépare un composant pour représenter une définition. */ -static GtkWidget *gtk_welcome_panel_create_launcher_widget(GPanelItem *, gpointer); +static void gtk_welcome_panel_finalize(GObject *); /* Réagit à un changement de sélection de la liste de panneaux. */ static void gtk_welcome_panel_on_selected_rows_changed(GtkListBox *, GtkWelcomePanel *); @@ -78,32 +69,6 @@ static void gtk_welcome_panel_on_next_hint_clicked(GtkButton *, GtkWelcomePanel -/* ---------------------- MANIPULATIONS D'UN PANNEAU GRAPHIQUE ---------------------- */ - - -/* Initialise la classe des panneaux graphiques pour binaires. */ -static void g_welcome_panel_class_init(GWelcomePanelClass *); - -/* Initialise une instance de panneau graphique pour binaire. */ -static void g_welcome_panel_init(GWelcomePanel *); - -/* Supprime toutes les références externes. */ -static void g_welcome_panel_dispose(GWelcomePanel *); - -/* Procède à la libération totale de la mémoire. */ -static void g_welcome_panel_finalize(GWelcomePanel *); - - - -/* --------------------- IMPLEMENTATION DES FONCTIONS DE CLASSE --------------------- */ - - -/* Fournit une indication sur la personnalité du panneau. */ -static PanelItemPersonality g_welcome_panel_get_personality(const GWelcomePanel *); - -/* Fournit un composant représentant un panneau graphique. */ -static GtkTiledPanel *g_welcome_panel_get_panel(GWelcomePanel *, GtkWidget *); - /* ---------------------------------------------------------------------------------- */ @@ -134,8 +99,8 @@ static void gtk_welcome_panel_class_init(GtkWelcomePanelClass *class) object = G_OBJECT_CLASS(class); - object->dispose = (GObjectFinalizeFunc/* ! */)gtk_welcome_panel_dispose; - object->finalize = (GObjectFinalizeFunc)gtk_welcome_panel_finalize; + object->dispose = gtk_welcome_panel_dispose; + object->finalize = gtk_welcome_panel_finalize; widget = GTK_WIDGET_CLASS(class); @@ -169,13 +134,16 @@ static void gtk_welcome_panel_init(GtkWelcomePanel *panel) { 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 */ gtk_widget_init_template(GTK_WIDGET(panel)); - panel->store = g_list_store_new(G_TYPE_PANEL_ITEM); - panel->other_child = NULL; + /* Chargement des astuces */ + bytes = g_resources_lookup_data("/re/chrysalide/framework/gui/panels/welcome-hints.txt", G_RESOURCE_LOOKUP_FLAGS_NONE, NULL); assert(bytes != NULL); @@ -191,105 +159,9 @@ static void gtk_welcome_panel_init(GtkWelcomePanel *panel) panel->cur_hint = 0; -} - - -/****************************************************************************** -* * -* Paramètres : panel = instance d'objet GLib à traiter. * -* * -* Description : Supprime toutes les références externes. * -* * -* Retour : - * -* * -* Remarques : - * -* * -******************************************************************************/ - -static void gtk_welcome_panel_dispose(GtkWelcomePanel *panel) -{ - gtk_widget_dispose_template(GTK_WIDGET(panel), GTK_TYPE_WELCOME_PANEL); - - g_clear_object(&panel->other_child); - - G_OBJECT_CLASS(gtk_welcome_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_welcome_panel_finalize(GtkWelcomePanel *panel) -{ - G_OBJECT_CLASS(gtk_welcome_panel_parent_class)->finalize(G_OBJECT(panel)); - - g_strfreev(panel->raw_hints); - -} - - -/****************************************************************************** -* * -* Paramètres : - * -* * -* Description : Crée une nouvelle instance de panneau d'accueil. * -* * -* Retour : Composant GTK mis en place. * -* * -* Remarques : - * -* * -******************************************************************************/ - -GtkTiledPanel *gtk_welcome_panel_new(void) -{ - GtkTiledPanel *result; /* Instance à retourner */ - - result = g_object_new(GTK_TYPE_WELCOME_PANEL, NULL); - - if (!gtk_welcome_panel_create(GTK_WELCOME_PANEL(result))) - g_clear_object(&result); - - return result; - -} - - -/****************************************************************************** -* * -* Paramètres : panel = panneau d'accueil à initialiser. * -* * -* Description : Met en place un nouveau panneau d'accueil. * -* * -* Retour : Bilan de l'opération. * -* * -* Remarques : - * -* * -******************************************************************************/ - -bool gtk_welcome_panel_create(GtkWelcomePanel *panel) -{ - bool result; /* Bilan à retourner */ - int min; /* Taille à gauche minimale */ - GtkConstraintLayout *layout; /* Disposition fixant la taille*/ - GtkConstraint *constraint; /* Contrainte à considérer */ - /* Constitution de la liste des démarreurs */ - result = browse_all_item_panels(true, (handle_panel_item_fc)gtk_welcome_panel_add_launcher, panel->store); - - gtk_list_box_bind_model(panel->list, G_LIST_MODEL(panel->store), - (GtkListBoxCreateWidgetFunc)gtk_welcome_panel_create_launcher_widget, - NULL, NULL); + populate_framework_panel_launcher_list(panel->list); /* Dimensionnement de la zone d'astuces */ @@ -327,57 +199,57 @@ bool gtk_welcome_panel_create(GtkWelcomePanel *panel) gtk_label_set_markup(panel->hints, panel->raw_hints[panel->cur_hint]); - return result; - } /****************************************************************************** * * -* Paramètres : item = définition de panneau à intégrer. * -* store = liste à compléter. * +* Paramètres : object = instance d'objet GLib à traiter. * * * -* Description : Intègre une définition de panneau enregistrée. * +* Description : Supprime toutes les références externes. * * * -* Retour : true pour un parcours complet de la liste des définitions. * +* Retour : - * * * * Remarques : - * * * ******************************************************************************/ -static bool gtk_welcome_panel_add_launcher(GPanelItem *item, GListStore *store) +static void gtk_welcome_panel_dispose(GObject *object) { - bool result; /* Poursuite du parcours */ + GtkWelcomePanel *panel; /* Version spécialisée */ + + gtk_widget_dispose_template(GTK_WIDGET(object), GTK_TYPE_WELCOME_PANEL); - result = true; + panel = GTK_WELCOME_PANEL(object); - g_list_store_append(store, G_OBJECT(item)); + g_clear_object(&panel->other_child); - return result; + G_OBJECT_CLASS(gtk_welcome_panel_parent_class)->dispose(object); } /****************************************************************************** * * -* Paramètres : item = définition de panneau à consulter. * -* unused = adresse non utilisée ici. * +* Paramètres : object = instance d'objet GLib à traiter. * * * -* Description : Prépare un composant pour représenter une définition. * +* Description : Procède à la libération totale de la mémoire. * * * -* Retour : Composant de représentation de définition de panneau. * +* Retour : - * * * * Remarques : - * * * ******************************************************************************/ -static GtkWidget *gtk_welcome_panel_create_launcher_widget(GPanelItem *item, gpointer unused) +static void gtk_welcome_panel_finalize(GObject *object) { - GtkWidget *result; /* Composant GTK à retourner */ + GtkWelcomePanel *panel; /* Version spécialisée */ + + panel = GTK_WELCOME_PANEL(object); - result = g_panel_item_get_launcher(item); + g_strfreev(panel->raw_hints); - return result; + G_OBJECT_CLASS(gtk_welcome_panel_parent_class)->finalize(object); } @@ -398,8 +270,6 @@ static GtkWidget *gtk_welcome_panel_create_launcher_widget(GPanelItem *item, gpo static void gtk_welcome_panel_on_selected_rows_changed(GtkListBox *box, GtkWelcomePanel *panel) { GtkListBoxRow *row; /* Ligne sélectionnée */ - int selected; /* Indice de sélection */ - GPanelItem *item; /* Elément correspondant */ GtkWidget *new; /* Nouvelles propriétés */ row = gtk_list_box_get_selected_row(box); @@ -414,7 +284,7 @@ static void gtk_welcome_panel_on_selected_rows_changed(GtkListBox *box, GtkWelco gtk_stack_set_visible_child(panel->properties, panel->def_child); gtk_stack_remove(panel->properties, panel->other_child); - g_clear_object(&panel->other_child); + panel->other_child = NULL; } @@ -423,24 +293,16 @@ static void gtk_welcome_panel_on_selected_rows_changed(GtkListBox *box, GtkWelco */ else { - selected = gtk_list_box_row_get_index(row); - item = g_list_model_get_item(G_LIST_MODEL(panel->store), selected); + new = get_framework_panel_parameters(row); + assert(new != NULL); - new = g_panel_item_get_properties(item); - - if (new == panel->other_child) - unref_object(new); - - else + if (new != panel->other_child) { gtk_stack_add_child(panel->properties, new); gtk_stack_set_visible_child(panel->properties, new); if (panel->other_child != NULL) - { gtk_stack_remove(panel->properties, panel->other_child); - g_clear_object(&panel->other_child); - } panel->other_child = new; @@ -513,178 +375,3 @@ static void gtk_welcome_panel_on_next_hint_clicked(GtkButton *button, GtkWelcome - -/* ---------------------------------------------------------------------------------- */ -/* MANIPULATIONS D'UN PANNEAU GRAPHIQUE */ -/* ---------------------------------------------------------------------------------- */ - - -/* Indique le type défini pour une manipulation de panneau de bienvenue. */ -G_DEFINE_TYPE(GWelcomePanel, g_welcome_panel, G_TYPE_PANEL_ITEM); - - -/****************************************************************************** -* * -* Paramètres : class = classe à initialiser. * -* * -* Description : Initialise la classe des panneaux graphiques pour binaires. * -* * -* Retour : - * -* * -* Remarques : - * -* * -******************************************************************************/ - -static void g_welcome_panel_class_init(GWelcomePanelClass *class) -{ - GObjectClass *object; /* Autre version de la classe */ - GPanelItemClass *panel; /* Encore une autre vision... */ - - object = G_OBJECT_CLASS(class); - - object->dispose = (GObjectFinalizeFunc/* ! */)g_welcome_panel_dispose; - object->finalize = (GObjectFinalizeFunc)g_welcome_panel_finalize; - - panel = G_PANEL_ITEM_CLASS(class); - - panel->get_personality = (get_panel_item_personality_cb)g_welcome_panel_get_personality; - panel->get_panel = (get_panel_item_panel_cb)g_welcome_panel_get_panel; - -} - - -/****************************************************************************** -* * -* Paramètres : panel = instance à initialiser. * -* * -* Description : Initialise une instance de panneau graphique pour binaire. * -* * -* Retour : - * -* * -* Remarques : - * -* * -******************************************************************************/ - -static void g_welcome_panel_init(GWelcomePanel *panel) -{ - -} - - -/****************************************************************************** -* * -* Paramètres : panel = instance d'objet GLib à traiter. * -* * -* Description : Supprime toutes les références externes. * -* * -* Retour : - * -* * -* Remarques : - * -* * -******************************************************************************/ - -static void g_welcome_panel_dispose(GWelcomePanel *panel) -{ - G_OBJECT_CLASS(g_welcome_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_welcome_panel_finalize(GWelcomePanel *panel) -{ - G_OBJECT_CLASS(g_welcome_panel_parent_class)->finalize(G_OBJECT(panel)); - -} - - -/****************************************************************************** -* * -* Paramètres : - * -* * -* Description : Constitue une définition de manipulation de panneau. * -* * -* Retour : Définition de propriétés 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; - -} - - - -/* ---------------------------------------------------------------------------------- */ -/* IMPLEMENTATION DES FONCTIONS DE CLASSE */ -/* ---------------------------------------------------------------------------------- */ - - -/****************************************************************************** -* * -* Paramètres : panel = définition de panneau à consulter. * -* * -* Description : Fournit une indication sur la personnalité du panneau. * -* * -* Retour : Identifiant lié à la nature du panneau. * -* * -* Remarques : - * -* * -******************************************************************************/ - -static PanelItemPersonality g_welcome_panel_get_personality(const GWelcomePanel *panel) -{ - PanelItemPersonality result; /* Personnalité à retourner */ - - result = PIP_MAIN_PANEL | PIP_SINGLETON; - - return result; - -} - - -/****************************************************************************** -* * -* Paramètres : panel = définition de panneau à manipuler. * -* props = éventuels éléments graphiques de paramétrages. * -* * -* Description : Fournit un composant représentant un panneau graphique. * -* * -* Retour : Composant GTK (déjà ?) mis en place. * -* * -* Remarques : - * -* * -******************************************************************************/ - -static GtkTiledPanel *g_welcome_panel_get_panel(GWelcomePanel *panel, GtkWidget *props) -{ - GtkTiledPanel *result; /* Composant à retourner */ - - /** - * Il n'existe pas de composants de paramètrage pour ce panneau. - */ - assert(props == NULL); - - result = gtk_welcome_panel_new(); - - return result; - -} diff --git a/src/gui/panels/welcome.h b/src/gui/panels/welcome.h index d267f80..d9ea18d 100644 --- a/src/gui/panels/welcome.h +++ b/src/gui/panels/welcome.h @@ -29,36 +29,15 @@ #include <gtk/gtk.h> -#include "../panel.h" #include "../../glibext/helpers.h" #include "../../gtkext/panel.h" -/* ------------------------- COEUR D'UN PANNEAU D'AFFICHAGE ------------------------- */ - - #define GTK_TYPE_WELCOME_PANEL (gtk_welcome_panel_get_type()) DECLARE_GTYPE(GtkWelcomePanel, gtk_welcome_panel, GTK, WELCOME_PANEL); -/* Crée une nouvelle instance de panneau d'accueil. */ -GtkTiledPanel *gtk_welcome_panel_new(void); - - - -/* ---------------------- MANIPULATIONS D'UN PANNEAU GRAPHIQUE ---------------------- */ - - -#define G_TYPE_WELCOME_PANEL (g_welcome_panel_get_type()) - -DECLARE_GTYPE(GWelcomePanel, g_welcome_panel, G, WELCOME_PANEL); - - -/* Constitue une définition de manipulation de panneau. */ -GPanelItem *g_welcome_panel_new(void); - - #endif /* _GUI_PANELS_WELCOME_H */ diff --git a/src/gui/style.css b/src/gui/style.css index 44161f7..9078310 100644 --- a/src/gui/style.css +++ b/src/gui/style.css @@ -1,4 +1,13 @@ +/* Extension de style */ + +.dim-label { + + margin-bottom: 4px; + +} + + .boxed-widget { border-top-left-radius: 12px; diff --git a/src/gui/window.c b/src/gui/window.c index 2680c89..f45cec9 100644 --- a/src/gui/window.c +++ b/src/gui/window.c @@ -28,6 +28,7 @@ #include "window-int.h" #include "core/panels.h" #include "dialogs/about.h" +#include "dialogs/preferences.h" #include "panels/welcome.h" #include "../gtkext/helpers.h" #include "../gtkext/statusstack.h" @@ -46,6 +47,9 @@ static void gtk_framework_window_dispose(GtkFrameworkWindow *); /* Procède à la libération totale de la mémoire. */ static void gtk_framework_window_finalize(GtkFrameworkWindow *); +/* 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); @@ -88,6 +92,8 @@ static void gtk_framework_window_class_init(GtkFrameworkWindowClass *class) /* 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); + } @@ -106,6 +112,7 @@ static void gtk_framework_window_class_init(GtkFrameworkWindowClass *class) static void gtk_framework_window_init(GtkFrameworkWindow *window) { static GActionEntry app_entries[] = { + { "preferences", gtk_framework_window_activate_preferences, NULL, NULL, NULL }, { "about", gtk_framework_window_activate_about, NULL, NULL, NULL }, }; @@ -208,7 +215,6 @@ GtkApplicationWindow *gtk_framework_window_new(GtkApplication *app) bool gtk_framework_window_create(GtkFrameworkWindow *window, GtkApplication *app) { bool result; /* Bilan à retourner */ - GPanelItem *item; /* Définition de panneau */ GtkTiledPanel *panel; /* Panneau d'affichage */ GtkCssProvider *css; /* Feuille de style maison */ @@ -218,13 +224,10 @@ bool gtk_framework_window_create(GtkFrameworkWindow *window, GtkApplication *app /* Inclusion d'un écran d'accueil */ - item = find_item_panel_by_type(G_TYPE_WELCOME_PANEL); + panel = get_framework_panel_singleton(GTK_TYPE_WELCOME_PANEL); - panel = g_panel_item_get_panel(item); gtk_framework_window_add(window, panel); - unref_object(item); - /* Chargement des extensions de thème */ css = gtk_css_provider_new(); @@ -258,6 +261,34 @@ bool gtk_framework_window_create(GtkFrameworkWindow *window, GtkApplication *app * 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 : - * diff --git a/src/gui/window.ui b/src/gui/window.ui index 59b8b2c..363ea54 100644 --- a/src/gui/window.ui +++ b/src/gui/window.ui @@ -5,6 +5,7 @@ <section> <item> <attribute name="label" translatable="yes">Preferences</attribute> + <attribute name="action">win.preferences</attribute> </item> <item> <attribute name="label" translatable="yes">About</attribute> 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 2899845..0000000 --- a/src/plugins/dt.c +++ /dev/null @@ -1,562 +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); - - /** - * Constat est fait qu'un type implémenté en Python mais dont les - * instanciations conduisent toutes à des exceptions n'est pas - * associé à une classe à ce moment d'exécution. - * - * Cf. fonction testKnownFormatConstructor() de la suite de tests - * - * Cf. documentation de g_type_class_unref() également : - * - * """ - * Once the last reference count of a class has been released, - * classes may be finalized by the type system - * """ - */ - - if (g_class != NULL) - 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 e4cb825..3e107b8 100644 --- a/src/plugins/pglist.c +++ b/src/plugins/pglist.c @@ -30,13 +30,16 @@ #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" @@ -44,6 +47,12 @@ +/** + * 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; @@ -61,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 *); + /****************************************************************************** @@ -83,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); @@ -108,8 +119,6 @@ bool init_all_plugins(bool load) if (load) load_remaning_plugins(); - exit: - return result; } @@ -130,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(); - } @@ -244,83 +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 */ - bool nox; /* Absence de support graphique*/ - char *filename; /* Elément à ausculter */ - GPluginModule *plugin; /* Greffon à intégrer ou pas */ - - ret = scandir(dir, &namelist, filter_dirs_or_mods, alphasort); - if (ret < 0) - { - LOG_ERROR_N("scandir"); - return; - } - - nox = run_in_nox_mode(); - - while (ret--) - { + 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 */ - if (nox) - { #ifdef _WIN32 -# define UI_SHARED_SUFFIX "-ui.dll" +# define SHARED_SUFFIX ".dll" #else -# define UI_SHARED_SUFFIX "-ui.so" +# define SHARED_SUFFIX ".so" #endif +#define UI_SHARED_SUFFIX "ui" SHARED_SUFFIX - if (strstr(namelist[ret]->d_name, UI_SHARED_SUFFIX) != NULL) - { - log_variadic_message(LMT_ERROR, _("Skipping unsuitable file: %s"), namelist[ret]->d_name); - continue; - } + result = false; - } + /* Propriétés du fichier courant */ - filename = (char *)calloc(strlen(dir) + 1 + strlen(namelist[ret]->d_name) + 1, sizeof(char)); + length = strlen(filename); - strcpy(filename, dir); - strcat(filename, G_DIR_SEPARATOR_S); - strcat(filename, namelist[ret]->d_name); + if (length < STATIC_STR_SIZE(UI_SHARED_SUFFIX)) + *is_ui = false; - if (namelist[ret]->d_type == DT_DIR) - browse_directory_for_plugins(filename); + else + *is_ui = (strcmp(filename + length - STATIC_STR_SIZE(UI_SHARED_SUFFIX), UI_SHARED_SUFFIX) == 0); + + if (*is_ui) + *is_nox = false; + + else + { + if (length < STATIC_STR_SIZE(SHARED_SUFFIX)) + *is_nox = false; else - { - plugin = g_plugin_module_new(filename); + *is_nox = (strcmp(filename + length - STATIC_STR_SIZE(SHARED_SUFFIX), SHARED_SUFFIX) == 0); + + } + + /* Recherche d'une version alternative */ - if (plugin != NULL) - register_plugin(plugin); + 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) + { + LOG_ERROR_N("asprintf"); + goto exit; } - free(filename); - free(namelist[ret]); + ret = access(alt_path, R_OK | X_OK); + + result = (ret == 0); + + 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 : - * * * @@ -328,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); } @@ -394,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. + */ + + 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. + */ - g_object_unref(G_OBJECT(same)); + if (module != NULL) + g_module_close(module); } @@ -432,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); @@ -502,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--; @@ -535,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; @@ -557,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]; @@ -570,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; } @@ -580,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; @@ -615,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 75cf4e0..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; @@ -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; } @@ -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 */ diff --git a/src/schemas/re.chrysalide.framework.gschema.xml b/src/schemas/re.chrysalide.framework.gschema.xml index e8331ff..80a20db 100644 --- a/src/schemas/re.chrysalide.framework.gschema.xml +++ b/src/schemas/re.chrysalide.framework.gschema.xml @@ -1,19 +1,40 @@ <schemalist gettext-domain="chrysalide"> - <schema id="re.chrysalide.framework" path="/re/chrysalide/framework/"> - <child schema="re.chrysalide.framework.gui" name="gui"/> - </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.secstorage" name="secstorage"/> + </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> + <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> + + <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> |