diff options
162 files changed, 8966 insertions, 5093 deletions
@@ -66,6 +66,7 @@ plugins/dalvik/v35/opcodes/ # GLib src/glibext/chrysamarshal.* resources.[ch] +src/gtkext/bindings/*-enums.[ch] # Binaries src/chrysalide @@ -76,6 +77,9 @@ tools/d2c/d2c tools/fuzzing/rost/fast-rost tools/yara2rost/yara2rost +# Images générées +src/data/images/about-bg.png + # Schemas src/schemas/gschemas.compiled src/schemas/*.valid @@ -83,6 +87,8 @@ src/schemas/*.valid # Misc plugins/python/androperms/androperms.db system/pkgconfig/chrysalide.pc +tools/about/bg.png +tools/about/cour10p_b.ttf tools/fuzzing/rost/rost.dict # Themes diff --git a/configure.ac b/configure.ac index 5acf436..8429ae6 100644 --- a/configure.ac +++ b/configure.ac @@ -35,6 +35,10 @@ AC_PROG_INSTALL AC_PROG_MAKE_SET LT_INIT +PKG_PROG_PKG_CONFIG([0.28]) + +PKG_CHECK_VAR([GLIB_MKENUMS], [glib-2.0], [glib_mkenums]) + CFLAGS="" AC_EGREP_CPP(yes, @@ -245,6 +249,10 @@ AC_ARG_ENABLE([jsonglib-support], AS_HELP_STRING([--disable-jsonglib-support], [disable jsonglib support [default=no]]), [], [enable_jsonglib_support=yes]) +AC_ARG_ENABLE([hs-support], + AS_HELP_STRING([--disable-hs-support], [disable hs number recognition [default=no]]), + [], [enable_hs_support=yes]) + AC_ARG_ENABLE([python-bindings], AS_HELP_STRING([--disable-python-bindings], [disable Python bindings [default=no]]), [], [enable_python_bindings=yes]) @@ -589,10 +597,24 @@ if test "$libhs_found" = "yes"; then libhs_version=`pkg-config libhs --modversion` else libhs_version='-' + enable_hs_support='' +fi + +AM_CONDITIONAL([BUILD_HS_SUPPORT], [test "x$enable_hs_support" = "xyes"]) + +if test "x$BUILD_HS_SUPPORT_TRUE" = "x"; then + # Hyperscan support is available and enabled + CPPFLAGS="$CPPFLAGS -DINCLUDE_HS_SUPPORT" fi -AC_SUBST(LIBHS_CFLAGS) -AC_SUBST(LIBHS_LIBS) +if test "x$enable_hs_support" = "xyes"; then + + AC_SUBST(LIBHS_CFLAGS) + AC_SUBST(LIBHS_LIBS) + + true # empty if/then body not allowed + +fi #--- Checks for json-glib-1.0 @@ -722,6 +744,8 @@ AC_CONFIG_FILES([stamp-h po/Makefile.in], [echo timestamp > stamp-h]) AC_CONFIG_COMMANDS([marshal], [echo -e "VOID:UINT64\nVOID:INT,UINT64,INT\nVOID:OBJECT,OBJECT\nVOID:ENUM,OBJECT\nVOID:ENUM,ENUM\nVOID:BOOLEAN,UINT64\nVOID:BOOLEAN,ULONG,ULONG\nVOID:INT,INT\nVOID:OBJECT,BOOLEAN\nVOID:ULONG,BOOLEAN\nVOID:DOUBLE,DOUBLE" > src/glibext/chrysamarshal.list]) +AC_CONFIG_COMMANDS([about], [./tools/about/gen.sh $version], [version=r$PACKAGE_VERSION]) + AC_CONFIG_FILES([Makefile doc/Makefile pixmaps/Makefile @@ -862,12 +886,15 @@ AC_CONFIG_FILES([Makefile src/arch/operands/Makefile src/common/Makefile src/core/Makefile + src/data/Makefile + src/data/images/Makefile src/debug/Makefile src/format/Makefile src/glibext/Makefile src/glibext/generators/Makefile src/glibext/options/Makefile src/gtkext/Makefile + src/gtkext/bindings/Makefile src/gtkext/graph/Makefile src/gui/Makefile src/gui/core/Makefile @@ -954,6 +981,12 @@ else disable_magic_support="yes" fi +if test "x$enable_hs_support" = "xyes"; then + disable_hs_support="no" +else + disable_hs_support="yes" +fi + if test "x$enable_python_bindings" = "xyes"; then disable_python_bindings="no" else @@ -966,6 +999,7 @@ echo Consider local resources..................... : $with_local_resources echo Disable GTK support.......................... : $disable_gtk_support echo Disable cURL support......................... : $disable_curl_support echo Disable Magic support........................ : $disable_magic_support +echo Disable Hyperscan support.................... : $disable_hs_support echo Disable Python bindings...................... : $disable_python_bindings echo Build a Python binary distribution........... : $build_python_package @@ -1,4 +1,4 @@ -define([gitrepo], esyscmd([bash -c "echo -n $(( $(test -d .git && git rev-list HEAD | wc -l) + 4))"])) +define([gitrepo], esyscmd([bash -c "echo -n $(( $(test -d .git && git rev-list --count HEAD) + 4))"])) define([gitversion], ifelse(gitrepo, , 000, gitrepo)) diff --git a/pixmaps/Makefile.am b/pixmaps/Makefile.am index d1dff31..da3de19 100644 --- a/pixmaps/Makefile.am +++ b/pixmaps/Makefile.am @@ -4,19 +4,6 @@ APP_ICONS = \ chrysalide-64.png \ chrysalide-128.png -REVISION_PIX = \ - revision_0.png \ - revision_1.png \ - revision_2.png \ - revision_3.png \ - revision_4.png \ - revision_5.png \ - revision_6.png \ - revision_7.png \ - revision_8.png \ - revision_9.png \ - revision.png - TOOLBAR_BUTTONS = \ tbutton_collapse.png \ tbutton_expand.png \ @@ -41,8 +28,6 @@ OTHER_ICONS = \ breakpoint_normal.png MISC = \ - chrysalide-full.png \ - chrysalide_text.png \ welcome.png CORE = \ @@ -57,13 +42,12 @@ EXTRA_DIST = \ openida_text.xcf \ before-after.png \ $(APP_ICONS) \ - $(REVISION_PIX) \ $(TOOLBAR_BUTTONS) \ $(LIST_ICONS) \ $(ERROR_ICONS) \ $(MISC) \ $(CORE) -pix_DATA = $(APP_ICONS) $(REVISION_PIX) $(TOOLBAR_BUTTONS) $(LIST_ICONS) $(ERROR_ICONS) $(OTHER_ICONS) $(MISC) +pix_DATA = $(APP_ICONS) $(TOOLBAR_BUTTONS) $(LIST_ICONS) $(ERROR_ICONS) $(OTHER_ICONS) $(MISC) pixdir = $(pixmapsdir) diff --git a/pixmaps/chrysalide-full.png b/pixmaps/chrysalide-full.png Binary files differdeleted file mode 100644 index a153353..0000000 --- a/pixmaps/chrysalide-full.png +++ /dev/null diff --git a/pixmaps/chrysalide_text.png b/pixmaps/chrysalide_text.png Binary files differdeleted file mode 100644 index b4d8c78..0000000 --- a/pixmaps/chrysalide_text.png +++ /dev/null diff --git a/pixmaps/revision.png b/pixmaps/revision.png Binary files differdeleted file mode 100644 index 330e108..0000000 --- a/pixmaps/revision.png +++ /dev/null diff --git a/pixmaps/revision_0.png b/pixmaps/revision_0.png Binary files differdeleted file mode 100644 index 0a468de..0000000 --- a/pixmaps/revision_0.png +++ /dev/null diff --git a/pixmaps/revision_1.png b/pixmaps/revision_1.png Binary files differdeleted file mode 100644 index 738a881..0000000 --- a/pixmaps/revision_1.png +++ /dev/null diff --git a/pixmaps/revision_2.png b/pixmaps/revision_2.png Binary files differdeleted file mode 100644 index b567b80..0000000 --- a/pixmaps/revision_2.png +++ /dev/null diff --git a/pixmaps/revision_3.png b/pixmaps/revision_3.png Binary files differdeleted file mode 100644 index 7f5e3fc..0000000 --- a/pixmaps/revision_3.png +++ /dev/null diff --git a/pixmaps/revision_4.png b/pixmaps/revision_4.png Binary files differdeleted file mode 100644 index a21ccbb..0000000 --- a/pixmaps/revision_4.png +++ /dev/null diff --git a/pixmaps/revision_5.png b/pixmaps/revision_5.png Binary files differdeleted file mode 100644 index a9130d9..0000000 --- a/pixmaps/revision_5.png +++ /dev/null diff --git a/pixmaps/revision_6.png b/pixmaps/revision_6.png Binary files differdeleted file mode 100644 index 291febd..0000000 --- a/pixmaps/revision_6.png +++ /dev/null diff --git a/pixmaps/revision_7.png b/pixmaps/revision_7.png Binary files differdeleted file mode 100644 index ccd4d4e..0000000 --- a/pixmaps/revision_7.png +++ /dev/null diff --git a/pixmaps/revision_8.png b/pixmaps/revision_8.png Binary files differdeleted file mode 100644 index 054c250..0000000 --- a/pixmaps/revision_8.png +++ /dev/null diff --git a/pixmaps/revision_9.png b/pixmaps/revision_9.png Binary files differdeleted file mode 100644 index 1123669..0000000 --- a/pixmaps/revision_9.png +++ /dev/null diff --git a/plugins/pychrysalide/Makefile.am b/plugins/pychrysalide/Makefile.am index f0cd477..c574727 100644 --- a/plugins/pychrysalide/Makefile.am +++ b/plugins/pychrysalide/Makefile.am @@ -15,12 +15,6 @@ endif # if BUILD_GTK_SUPPORT -# GTKEXT_LIBADD = \ -# gtkext/libpychrysagtkext.la - -# GTKEXT_SUBDIR = \ -# gtkext - # GUI_LIBADD = \ # gui/libpychrysagui.la @@ -51,7 +45,6 @@ AM_CFLAGS = $(LIBPYTHON_INTERPRETER_CFLAGS) $(LIBPYGOBJECT_CFLAGS) $(TOOLKIT_CFL # common/libpychrysacommon.la \ # core/libpychrysacore.la \ # debug/libpychrysadebug.la \ -# $(GTKEXT_LIBADD) \ # $(GUI_LIBADD) \ # mangling/libpychrysamangling.la \ # plugins/libpychrysaplugins.la @@ -78,11 +71,13 @@ EXTRA_pychrysalideui_la_DEPENDENCIES = pychrysalide.la pychrysalideui_la_SOURCES = \ core-ui-int.h \ - core-ui.h core-ui.c + core-ui.h core-ui.c \ + helpers-ui.h helpers-ui.c pychrysalideui_la_LIBADD = \ arch/libpychrysaarchui.la \ - glibext/libpychrysaglibextui.la + glibext/libpychrysaglibextui.la \ + gtkext/libpychrysagtkext.la # -ldl: dladdr(), dlerror() pychrysalideui_la_LDFLAGS = \ @@ -100,4 +95,4 @@ dev_HEADERS = $(pychrysalide_la_SOURCES:%c=) #SUBDIRS = analysis arch common core debug $(GTKEXT_SUBDIR) $(GUI_SUBDIR) mangling plugins -SUBDIRS = analysis arch common core format glibext plugins +SUBDIRS = analysis arch common core format glibext gtkext plugins diff --git a/plugins/pychrysalide/arch/Makefile.am b/plugins/pychrysalide/arch/Makefile.am index a134947..a0dcfdb 100644 --- a/plugins/pychrysalide/arch/Makefile.am +++ b/plugins/pychrysalide/arch/Makefile.am @@ -2,17 +2,12 @@ noinst_LTLIBRARIES = libpychrysaarch4.la libpychrysaarchui.la # libpychrysaarch.la # libpychrysaarch_la_SOURCES = \ -# constants.h constants.c \ # context.h context.c \ # instriter.h instriter.c \ -# instruction.h instruction.c \ -# module.h module.c \ -# operand.h operand.c \ -# processor.h processor.c \ -# vmpa.h vmpa.c +# processor.h processor.c # libpychrysaarch_la_LIBADD = \ -# instructions/libpychrysaarchinstructions.la \ +# \ # operands/libpychrysaarchoperands.la # libpychrysaarch_la_CFLAGS = $(TOOLKIT_CFLAGS) $(LIBXML_CFLAGS) $(LIBPYTHON_INTERPRETER_CFLAGS) $(LIBPYGOBJECT_CFLAGS) \ @@ -21,12 +16,14 @@ noinst_LTLIBRARIES = libpychrysaarch4.la libpychrysaarchui.la # libpychrysaarch. libpychrysaarch4_la_SOURCES = \ constants.h constants.c \ + instruction.h instruction.c \ module.h module.c \ operand.h operand.c \ register.h register.c \ vmpa.h vmpa.c libpychrysaarch4_la_LIBADD = \ + instructions/libpychrysaarchinstructions.la \ operands/libpychrysaarchoperands.la libpychrysaarch4_la_CFLAGS = $(LIBPYTHON_INTERPRETER_CFLAGS) $(LIBPYGOBJECT_CFLAGS) \ @@ -48,5 +45,4 @@ devdir = $(includedir)/chrysalide/$(subdir) dev_HEADERS = $(libpychrysaarch_la_SOURCES:%c=) -# SUBDIRS = instructions operands -SUBDIRS = operands +SUBDIRS = instructions operands diff --git a/plugins/pychrysalide/arch/constants.c b/plugins/pychrysalide/arch/constants.c index 3604795..5db59ff 100644 --- a/plugins/pychrysalide/arch/constants.c +++ b/plugins/pychrysalide/arch/constants.c @@ -25,7 +25,7 @@ #include "constants.h" -//#include <arch/instruction.h> +#include <arch/instruction.h> //#include <arch/processor.h> #include <arch/vmpa.h> @@ -33,7 +33,6 @@ #include "../helpers.h" -#if 0 // FIXME /****************************************************************************** * * @@ -116,6 +115,8 @@ bool define_arch_instruction_constants(PyTypeObject *type) } +#if 0 // FIXME + /****************************************************************************** * * * Paramètres : type = type dont le dictionnaire est à compléter. * diff --git a/plugins/pychrysalide/arch/constants.h b/plugins/pychrysalide/arch/constants.h index b12579e..2f16c4f 100644 --- a/plugins/pychrysalide/arch/constants.h +++ b/plugins/pychrysalide/arch/constants.h @@ -30,10 +30,13 @@ #include <stdbool.h> -#if 0 // FIXME + /* Définit les constantes relatives aux instructions. */ bool define_arch_instruction_constants(PyTypeObject *); + +#if 0 // FIXME + /* Définit les constantes relatives aux processeurs. */ bool define_arch_processor_constants(PyTypeObject *); diff --git a/plugins/pychrysalide/arch/instruction.c b/plugins/pychrysalide/arch/instruction.c index 0a9ba16..49daa9c 100644 --- a/plugins/pychrysalide/arch/instruction.c +++ b/plugins/pychrysalide/arch/instruction.c @@ -27,13 +27,12 @@ #include <assert.h> #include <malloc.h> -#include <string.h> #include <pygobject.h> #include <i18n.h> +#include <plugins/self.h> #include <arch/instruction-int.h> -#include <plugins/dt.h> #include "constants.h" @@ -41,30 +40,38 @@ #include "vmpa.h" #include "../access.h" #include "../helpers.h" -#include "../glibext/linegen.h" - - - -static G_DEFINE_QUARK(cached_keyword, get_cached_keyword); +#include "../glibext/objhole.h" +#include "../glibext/serialize.h" /* ------------------------ GLUE POUR CREATION DEPUIS PYTHON ------------------------ */ -/* Accompagne la création d'une instance dérivée en Python. */ -static PyObject *py_arch_instruction_new(PyTypeObject *, PyObject *, PyObject *); - /* Initialise la classe générique des instructions. */ -static void py_arch_instruction_init_gclass(GArchInstructionClass *, gpointer); +static int py_arch_instruction_init_gclass(GArchInstructionClass *, PyTypeObject *); -CREATE_DYN_ABSTRACT_CONSTRUCTOR(arch_instruction, G_TYPE_ARCH_INSTRUCTION, py_arch_instruction_init_gclass); +CREATE_DYN_ABSTRACT_CONSTRUCTOR(arch_instruction, G_TYPE_ARCH_INSTRUCTION); /* Initialise une instance sur la base du dérivé de GObject. */ static int py_arch_instruction_init(PyObject *, PyObject *, PyObject *); +/* Indique l'encodage d'une instruction de façon détaillée. */ +static char *py_arch_instruction_get_encoding_wrapper(const GArchInstruction *); + /* Fournit le nom humain de l'instruction manipulée. */ -static const char *py_arch_instruction_get_class_keyword(GArchInstruction *); +static char *py_arch_instruction_get_keyword_wrapper(const GArchInstruction *); + + + +/* ------------------- DEFINITION DES LIAISONS ENTRE INSTRUCTIONS ------------------- */ + + +/* Fournit les origines d'une instruction donnée. */ +static PyObject *py_arch_instruction_get_sources(PyObject *, void *); + +/* Fournit les destinations d'une instruction donnée. */ +static PyObject *py_arch_instruction_get_destinations(PyObject *, void *); @@ -72,10 +79,7 @@ static const char *py_arch_instruction_get_class_keyword(GArchInstruction *); /* Attache un opérande supplémentaire à une instruction. */ -static PyObject *py_arch_instruction_attach_extra_operand(PyObject *, PyObject *); - -/* Fournit tous les opérandes d'une instruction. */ -static PyObject *py_arch_instruction_get_operands(PyObject *, void *); +static PyObject *py_arch_instruction_attach_operand(PyObject *, PyObject *); /* Remplace un opérande d'une instruction par un autre. */ static PyObject *py_arch_instruction_replace_operand(PyObject *, PyObject *); @@ -89,34 +93,35 @@ static PyObject *py_arch_instruction_find_operand_path(PyObject *, PyObject *); /* Obtient l'opérande correspondant à un chemin donné. */ static PyObject *py_arch_instruction_get_operand_from_path(PyObject *, PyObject *); +/* Fournit tous les opérandes d'une instruction. */ +static PyObject *py_arch_instruction_get_operands(PyObject *, void *); -/* ------------------- DEFINITION DES LIAISONS ENTRE INSTRUCTIONS ------------------- */ +/* ------------------ LIAISON DE FONCTIONNALITES AVEC L'API PYTHON ------------------ */ -/* Fournit les origines d'une instruction donnée. */ -static PyObject *py_arch_instruction_get_sources(PyObject *, void *); -/* Fournit les destinations d'une instruction donnée. */ -static PyObject *py_arch_instruction_get_destinations(PyObject *, void *); +/* Ajoute une information complémentaire à une instruction. */ +static PyObject *py_arch_instruction_set_flag(PyObject *, PyObject *); +/* Retire une information complémentaire à une instruction. */ +static PyObject *py_arch_instruction_unset_flag(PyObject *, PyObject *); +/* Détermine si une instruction possède un fanion particulier. */ +static PyObject *py_arch_instruction_has_flag(PyObject *, PyObject *); -/* --------------------- INSTRUCTIONS D'ARCHITECTURES EN PYTHON --------------------- */ +/* Fournit l'identifiant correspondant à un type d'instructions. */ +static PyObject *py_arch_instruction_get_type_id(PyObject *, void *); +/* Indique l'encodage d'une instruction de façon détaillée. */ +static PyObject *py_arch_instruction_get_encoding(PyObject *, void *); -/* Fournit l'identifiant unique pour un ensemble d'instructions. */ -static PyObject *py_arch_instruction_get_unique_id(PyObject *, void *); +/* Indique l'encodage d'une instruction de façon détaillée. */ +static PyObject *py_arch_instruction_get_keyword(PyObject *, void *); /* Fournit la place mémoire d'une instruction. */ static PyObject *py_arch_instruction_get_range(PyObject *, void *); -/* Définit la localisation d'une instruction. */ -static int py_arch_instruction_set_range(PyObject *, PyObject *, void *); - -/* Fournit le nom humain de l'instruction manipulée. */ -static PyObject *py_arch_instruction_get_keyword(PyObject *, void *); - /* ---------------------------------------------------------------------------------- */ @@ -126,24 +131,23 @@ static PyObject *py_arch_instruction_get_keyword(PyObject *, void *); /****************************************************************************** * * -* Paramètres : class = classe à initialiser. * -* unused = données non utilisées ici. * +* Paramètres : gclass = classe GLib à initialiser. * +* pyclass = classe Python à initialiser. * * * * Description : Initialise la classe générique des instructions. * * * -* Retour : - * +* Retour : 0 pour indiquer un succès de l'opération. * * * * Remarques : - * * * ******************************************************************************/ -static void py_arch_instruction_init_gclass(GArchInstructionClass *class, gpointer unused) +static int py_arch_instruction_init_gclass(GArchInstructionClass *gclass, PyTypeObject *pyclass) { - GArchInstructionClass *instr; /* Encore une autre vision... */ - - instr = G_ARCH_INSTRUCTION_CLASS(class); + PY_CLASS_SET_WRAPPER(gclass->get_encoding, py_arch_instruction_get_encoding_wrapper); + PY_CLASS_SET_WRAPPER(gclass->get_keyword, py_arch_instruction_get_keyword_wrapper); - instr->get_keyword = (get_instruction_keyword_fc)py_arch_instruction_get_class_keyword; + return 0; } @@ -164,17 +168,25 @@ static void py_arch_instruction_init_gclass(GArchInstructionClass *class, gpoint static int py_arch_instruction_init(PyObject *self, PyObject *args, PyObject *kwds) { - unsigned short int uid; /* Indentifiant unique de type */ - const char *keyword; /* Désignation d'instruction */ + unsigned short int tid; /* Indentifiant unique de type */ int ret; /* Bilan de lecture des args. */ GArchInstruction *instr; /* Instruction à manipuler */ - GQuark cache_key; /* Emplacement local */ - static char *kwlist[] = { "uid", "keyword", NULL }; +#define ARCH_INSTRUCTION_DOC \ + "The ArchInstruction object provides a base class for instructions" \ + " of any architecture.\n" \ + " operands of any kind for new architectures.\n" \ + "\n" \ + "Calls to the *__init__* constructor of this abstract object expect"\ + " one argument: an unique identifier, as an integer value.\n" \ + "\n" \ + "The following methods have to be defined for new classes:\n" \ + "* pychrysalide.arch.ArchRegister._get_encoding();\n" \ + "* pychrysalide.arch.ArchRegister._get_keyword().\n" /* Récupération des paramètres */ - ret = PyArg_ParseTupleAndKeywords(args, kwds, "Hs", kwlist, &uid, &keyword); + ret = PyArg_ParseTuple(args, "H", &tid); if (!ret) return -1; /* Initialisation d'un objet GLib */ @@ -186,13 +198,72 @@ static int py_arch_instruction_init(PyObject *self, PyObject *args, PyObject *kw instr = G_ARCH_INSTRUCTION(pygobject_get(self)); - cache_key = get_cached_keyword_quark(); + if (!g_arch_instruction_create(instr, tid)) + return -1; + + return 0; - g_object_set_qdata_full(G_OBJECT(instr), cache_key, strdup(keyword), g_free); +} - g_arch_instruction_set_unique_id(G_ARCH_INSTRUCTION(instr), uid); - return 0; +/****************************************************************************** +* * +* Paramètres : instr = instruction quelconque à consulter. * +* * +* Description : Indique l'encodage d'une instruction de façon détaillée. * +* * +* Retour : Description humaine de l'encodage utilisé. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static char *py_arch_instruction_get_encoding_wrapper(const GArchInstruction *instr) +{ + char *result; /* Encodage à retourner */ + PyGILState_STATE gstate; /* Sauvegarde d'environnement */ + PyObject *pyobj; /* Objet Python concerné */ + PyObject *pyret; /* Bilan d'exécution */ + +#define PLUGIN_MODULE_GET_ENCODING_WRAPPER PYTHON_WRAPPER_DEF \ +( \ + _get_encoding, "$self, /", \ + METH_NOARGS, \ + "Abstract method describing the encoding related to an" \ + " instruction.\n" \ + "\n" \ + "The result should be the string value.\n" \ +) + + result = NULL; + + gstate = PyGILState_Ensure(); + + pyobj = pygobject_new(G_OBJECT(instr)); + + if (has_python_method(pyobj, "_get_encoding")) + { + pyret = run_python_method(pyobj, "_get_encoding", NULL); + + if (pyret != NULL) + { + if (!PyUnicode_Check(pyret)) + log_variadic_message(LMT_ERROR, _("The returned raw name must be a string")); + + else + result = strdup(PyUnicode_DATA(pyret)); + + } + + Py_XDECREF(pyret); + + } + + Py_DECREF(pyobj); + + PyGILState_Release(gstate); + + return result; } @@ -209,15 +280,50 @@ static int py_arch_instruction_init(PyObject *self, PyObject *args, PyObject *kw * * ******************************************************************************/ -static const char *py_arch_instruction_get_class_keyword(GArchInstruction *instr) +static char *py_arch_instruction_get_keyword_wrapper(const GArchInstruction *instr) { - const char *result; /* Désignation à retourner */ - GQuark cache_key; /* Emplacement local */ + char *result; /* Etiquette à retourner */ + PyGILState_STATE gstate; /* Sauvegarde d'environnement */ + PyObject *pyobj; /* Objet Python concerné */ + PyObject *pyret; /* Bilan d'exécution */ + +#define PLUGIN_MODULE_GET_KEYWORD_WRAPPER PYTHON_WRAPPER_DEF \ +( \ + _get_keyword, "$self, /", \ + METH_NOARGS, \ + "Abstract method giving the official name of the assembly" \ + " instruction.\n" \ + "\n" \ + "The result should be the string value.\n" \ +) + + result = NULL; + + gstate = PyGILState_Ensure(); + + pyobj = pygobject_new(G_OBJECT(instr)); + + if (has_python_method(pyobj, "_get_keyword")) + { + pyret = run_python_method(pyobj, "_get_keyword", NULL); + + if (pyret != NULL) + { + if (!PyUnicode_Check(pyret)) + log_variadic_message(LMT_ERROR, _("The returned raw name must be a string")); - cache_key = get_cached_keyword_quark(); + else + result = strdup(PyUnicode_DATA(pyret)); - result = g_object_get_qdata(G_OBJECT(instr), cache_key); - assert(result != NULL); + } + + Py_XDECREF(pyret); + + } + + Py_DECREF(pyobj); + + PyGILState_Release(gstate); return result; @@ -226,94 +332,201 @@ static const char *py_arch_instruction_get_class_keyword(GArchInstruction *instr /* ---------------------------------------------------------------------------------- */ -/* MANIPULATION DES OPERANDES */ +/* DEFINITION DES LIAISONS ENTRE INSTRUCTIONS */ /* ---------------------------------------------------------------------------------- */ /****************************************************************************** * * -* Paramètres : self = architecture concernée par la procédure. * -* args = instruction représentant le point de départ. * +* Paramètres : self = instruction d'architecture à manipuler. * +* unused = adresse non utilisée ici. * * * -* Description : Attache un opérande supplémentaire à une instruction. * +* Description : Fournit les origines d'une instruction donnée. * * * -* Retour : None. * +* Retour : Nombre de ces origines. * * * * Remarques : - * * * ******************************************************************************/ -static PyObject *py_arch_instruction_attach_extra_operand(PyObject *self, PyObject *args) +static PyObject *py_arch_instruction_get_sources(PyObject *self, void *unused) { - GArchOperand *op; /* Opérande concerné à ajouter */ - int ret; /* Bilan de lecture des args. */ - GArchInstruction *instr; /* Instruction manipulée */ + PyObject *result; /* Instance à retourner */ + GArchInstruction *instr; /* Version native */ + size_t count; /* Nombre de liens présents */ + size_t i; /* Boucle de parcours */ - ret = PyArg_ParseTuple(args, "O&", convert_to_arch_operand, &op); - if (!ret) return NULL; + + GArchInstruction *src; /* Instruction en source */ + InstructionLinkType src_type; /* Type de lien */ + PyObject *linked; /* Source de lien Python */ + PyObject *lnk_type; /* Nature du lien en Python */ +#ifndef NDEBUG + int ret; /* Bilan d'une écriture d'arg. */ +#endif + +#define ARCH_INSTRUCTION_SOURCES_ATTRIB PYTHON_GET_DEF_FULL \ +( \ + sources, py_arch_instruction, \ + "Provide the instructions list driving to the current instruction.\n" \ + "\n" \ + "Each item of the resulting tuple is a pair of" \ + " pychrysalide.arch.ArchInstruction instance and" \ + " pychrysalide.arch.ArchInstruction.InstructionLinkType value." \ +) instr = G_ARCH_INSTRUCTION(pygobject_get(self)); - g_object_ref(G_OBJECT(op)); + g_thick_object_lock(G_THICK_OBJECT(instr)); + + count = g_arch_instruction_count_src_links(instr); + + result = PyTuple_New(count); + + for (i = 0; i < count; i++) + { + src = g_arch_instruction_get_linked_source(instr, i, &src_type); + + linked = pygobject_new(G_OBJECT(src)); + lnk_type = cast_with_constants_group_from_type(get_python_arch_instruction_type(), + "InstructionLinkType", src_type); + +#ifndef NDEBUG + ret = PyTuple_SetItem(result, i, Py_BuildValue("(OO)", linked, lnk_type)); + assert(ret == 0); +#else + PyTuple_SetItem(result, i, Py_BuildValue("(OO)", linked, lnk_type)); +#endif + + unref_object(src); + + } - g_arch_instruction_attach_extra_operand(instr, op); + g_thick_object_unlock(G_THICK_OBJECT(instr)); - Py_RETURN_NONE; + return result; } /****************************************************************************** * * -* Paramètres : self = objet représentant une instruction. * +* Paramètres : self = instruction d'architecture à manipuler. * * unused = adresse non utilisée ici. * * * -* Description : Fournit tous les opérandes d'une instruction. * +* Description : Fournit les destinations d'une instruction donnée. * * * -* Retour : Valeur associée à la propriété consultée. * +* Retour : Nombre de ces destinations. * * * * Remarques : - * * * ******************************************************************************/ -static PyObject *py_arch_instruction_get_operands(PyObject *self, void *unused) +static PyObject *py_arch_instruction_get_destinations(PyObject *self, void *unused) { PyObject *result; /* Instance à retourner */ GArchInstruction *instr; /* Version native */ - size_t count; /* Nombre d'opérandes présents */ + size_t count; /* Nombre de liens présents */ size_t i; /* Boucle de parcours */ - GArchOperand *operand; /* Opérande à manipuler */ - PyObject *opobj; /* Version Python */ + GArchInstruction *dest; /* Instruction en source */ + InstructionLinkType dest_type; /* Type de lien */ + PyObject *linked; /* Destination de lien Python */ + PyObject *lnk_type; /* Nature du lien en Python */ #ifndef NDEBUG int ret; /* Bilan d'une écriture d'arg. */ #endif +#define ARCH_INSTRUCTION_DESTINATIONS_ATTRIB PYTHON_GET_DEF_FULL \ +( \ + destinations, py_arch_instruction, \ + "Provide the instructions list following the current instruction.\n" \ + "\n" \ + "Each item of the resulting tuple is a pair of" \ + " pychrysalide.arch.ArchInstruction instance and" \ + " pychrysalide.arch.ArchInstruction.InstructionLinkType value." \ +) + instr = G_ARCH_INSTRUCTION(pygobject_get(self)); - g_arch_instruction_lock_operands(instr); + g_thick_object_lock(G_THICK_OBJECT(instr)); - count = _g_arch_instruction_count_operands(instr); + count = g_arch_instruction_count_dest_links(instr); result = PyTuple_New(count); for (i = 0; i < count; i++) { - operand = _g_arch_instruction_get_operand(instr, i); + dest = g_arch_instruction_get_linked_destination(instr, i, &dest_type); - opobj = pygobject_new(G_OBJECT(operand)); + linked = pygobject_new(G_OBJECT(dest)); + lnk_type = cast_with_constants_group_from_type(get_python_arch_instruction_type(), + "InstructionLinkType", dest_type); #ifndef NDEBUG - ret = PyTuple_SetItem(result, i, Py_BuildValue("O", opobj)); + ret = PyTuple_SetItem(result, i, Py_BuildValue("(OO)", linked, lnk_type)); assert(ret == 0); #else - PyTuple_SetItem(result, i, Py_BuildValue("O", opobj)); + PyTuple_SetItem(result, i, Py_BuildValue("(OO)", linked, lnk_type)); #endif - g_object_unref(G_OBJECT(operand)); + unref_object(dest); } - g_arch_instruction_unlock_operands(instr); + g_thick_object_unlock(G_THICK_OBJECT(instr)); + + return result; + +} + + + +/* ---------------------------------------------------------------------------------- */ +/* MANIPULATION DES OPERANDES */ +/* ---------------------------------------------------------------------------------- */ + + +/****************************************************************************** +* * +* Paramètres : self = architecture concernée par la procédure. * +* args = instruction représentant le point de départ. * +* * +* Description : Attache un opérande supplémentaire à une instruction. * +* * +* Retour : None. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static PyObject *py_arch_instruction_attach_operand(PyObject *self, PyObject *args) +{ + PyObject *result; /* Bilan à retourner */ + GArchOperand *op; /* Opérande concerné à ajouter */ + int ret; /* Bilan de lecture des args. */ + GArchInstruction *instr; /* Instruction manipulée */ + +#define ARCH_INSTRUCTION_ATTACH_OPERAND_METHOD PYTHON_METHOD_DEF \ +( \ + attach_operand, "$self, operand, /", \ + METH_VARARGS, py_arch_instruction, \ + "Add an extra operand to an instruction.\n" \ + "\n" \ + "The instruction has to be locked during the instruction.\n" \ + "\n" \ + "The *operand* argument has to be a pychrysalide.arch.ArchOperand" \ + " instance." \ +) + + ret = PyArg_ParseTuple(args, "O&", convert_to_arch_operand, &op); + if (!ret) return NULL; + + instr = G_ARCH_INSTRUCTION(pygobject_get(self)); + + g_arch_instruction_attach_operand(instr, op); + + result = Py_None; + Py_INCREF(result); return result; @@ -342,6 +555,21 @@ static PyObject *py_arch_instruction_replace_operand(PyObject *self, PyObject *a GArchInstruction *instr; /* Instruction manipulée */ bool status; /* Bilan de l'opération */ +#define ARCH_INSTRUCTION_REPLACE_OPERAND_METHOD PYTHON_METHOD_DEF \ +( \ + replace_operand, "$self, old, new, /", \ + METH_VARARGS, py_arch_instruction, \ + "Replace an old instruction operand by a another one.\n" \ + "\n" \ + "The instruction has to be locked during the instruction.\n" \ + "\n" \ + "Both the *old* and *new* arguments have to be a" \ + " pychrysalide.arch.ArchOperand instance.\n" \ + "\n" \ + "The status of the operation is returned as a boolean value: *True*"\ + " if the operand has been replaced, *False* in case of failure." \ +) + ret = PyArg_ParseTuple(args, "O&O&", convert_to_arch_operand, &old, convert_to_arch_operand, &new); if (!ret) return NULL; @@ -349,9 +577,6 @@ static PyObject *py_arch_instruction_replace_operand(PyObject *self, PyObject *a status = g_arch_instruction_replace_operand(instr, old, new); - if (status) - g_object_ref(G_OBJECT(new)); - result = status ? Py_True : Py_False; Py_INCREF(result); @@ -381,6 +606,21 @@ static PyObject *py_arch_instruction_detach_operand(PyObject *self, PyObject *ar GArchInstruction *instr; /* Instruction manipulée */ bool status; /* Bilan de l'opération */ +#define ARCH_INSTRUCTION_DETACH_OPERAND_METHOD PYTHON_METHOD_DEF \ +( \ + detach_operand, "$self, operand, /", \ + METH_VARARGS, py_arch_instruction, \ + "Remove an operand from the instruction.\n" \ + "\n" \ + "The instruction has to be locked during the instruction.\n" \ + "\n" \ + "The *operand* argument has to be a pychrysalide.arch.ArchOperand" \ + " instance.\n" \ + "\n" \ + "The status of the operation is returned as a boolean value: *True*"\ + " if the operand has been removed, *False* in case of failure." \ +) + ret = PyArg_ParseTuple(args, "O&", convert_to_arch_operand, &target); if (!ret) return NULL; @@ -500,7 +740,7 @@ static PyObject *py_arch_instruction_get_operand_from_path(PyObject *self, PyObj if (op != NULL) { result = pygobject_new(G_OBJECT(op)); - g_object_unref(G_OBJECT(op)); + unref_object(op); } else { @@ -513,182 +753,258 @@ static PyObject *py_arch_instruction_get_operand_from_path(PyObject *self, PyObj } - -/* ---------------------------------------------------------------------------------- */ -/* DEFINITION DES LIAISONS ENTRE INSTRUCTIONS */ -/* ---------------------------------------------------------------------------------- */ - - /****************************************************************************** * * -* Paramètres : self = instruction d'architecture à manipuler. * +* Paramètres : self = objet représentant une instruction. * * unused = adresse non utilisée ici. * * * -* Description : Fournit les origines d'une instruction donnée. * +* Description : Fournit tous les opérandes d'une instruction. * * * -* Retour : Nombre de ces origines. * +* Retour : Valeur associée à la propriété consultée. * * * * Remarques : - * * * ******************************************************************************/ -static PyObject *py_arch_instruction_get_sources(PyObject *self, void *unused) +static PyObject *py_arch_instruction_get_operands(PyObject *self, void *unused) { PyObject *result; /* Instance à retourner */ GArchInstruction *instr; /* Version native */ - size_t count; /* Nombre de liens présents */ + size_t count; /* Nombre d'opérandes présents */ size_t i; /* Boucle de parcours */ - const instr_link_t *source; /* Origine des liens */ - PyObject *linked; /* Source de lien Python */ - PyObject *type; /* Nature du lien en Python */ + GArchOperand *operand; /* Opérande à manipuler */ + PyObject *opobj; /* Version Python */ #ifndef NDEBUG int ret; /* Bilan d'une écriture d'arg. */ #endif -#define ARCH_INSTRUCTION_SOURCES_ATTRIB PYTHON_GET_DEF_FULL \ -( \ - sources, py_arch_instruction, \ - "Provide the instructions list driving to the current instruction.\n" \ - "\n" \ - "Each item of the resulting tuple is a pair of" \ - " pychrysalide.arch.ArchInstruction instance and" \ - " pychrysalide.arch.ArchInstruction.InstructionLinkType value." \ +#define ARCH_INSTRUCTION_OPERANDS_ATTRIB PYTHON_GET_DEF_FULL \ +( \ + operands, py_arch_instruction, \ + "List of instruction attached operands.\n" \ + "\n" \ + "The result is a list of pychrysalide.arch.ArchOperand" \ + " instances, which can be empty." \ ) instr = G_ARCH_INSTRUCTION(pygobject_get(self)); - g_arch_instruction_lock_src(instr); + g_thick_object_lock(G_THICK_OBJECT(instr)); - count = g_arch_instruction_count_sources(instr); + count = g_arch_instruction_count_operands(instr); result = PyTuple_New(count); for (i = 0; i < count; i++) { - source = g_arch_instruction_get_source(instr, i); + operand = g_arch_instruction_get_operand(instr, i); - linked = pygobject_new(G_OBJECT(source->linked)); - type = cast_with_constants_group_from_type(get_python_arch_instruction_type(), - "InstructionLinkType", source->type); + opobj = pygobject_new(G_OBJECT(operand)); #ifndef NDEBUG - ret = PyTuple_SetItem(result, i, Py_BuildValue("(OO)", linked, type)); + ret = PyTuple_SetItem(result, i, Py_BuildValue("O", opobj)); assert(ret == 0); #else - PyTuple_SetItem(result, i, Py_BuildValue("(OO)", linked, type)); + PyTuple_SetItem(result, i, Py_BuildValue("O", opobj)); #endif - unref_instr_link(source); + unref_object(operand); } - g_arch_instruction_unlock_src(instr); + g_thick_object_unlock(G_THICK_OBJECT(instr)); return result; } + +/* ---------------------------------------------------------------------------------- */ +/* LIAISON DE FONCTIONNALITES AVEC L'API PYTHON */ +/* ---------------------------------------------------------------------------------- */ + + /****************************************************************************** * * -* Paramètres : self = instruction d'architecture à manipuler. * -* unused = adresse non utilisée ici. * +* Paramètres : self = architecture concernée par la procédure. * +* args = instruction représentant le point de départ. * * * -* Description : Fournit les destinations d'une instruction donnée. * +* Description : Ajoute une information complémentaire à une instruction. * * * -* Retour : Nombre de ces destinations. * +* Retour : Bilan de l'opération. * * * * Remarques : - * * * ******************************************************************************/ -static PyObject *py_arch_instruction_get_destinations(PyObject *self, void *unused) +static PyObject *py_arch_instruction_set_flag(PyObject *self, PyObject *args) { - PyObject *result; /* Instance à retourner */ - GArchInstruction *instr; /* Version native */ - size_t count; /* Nombre de liens présents */ - size_t i; /* Boucle de parcours */ - const instr_link_t *dest; /* Destination des liens */ - PyObject *linked; /* Destination de lien Python */ - PyObject *type; /* Nature du lien en Python */ -#ifndef NDEBUG - int ret; /* Bilan d'une écriture d'arg. */ -#endif - -#define ARCH_INSTRUCTION_DESTINATIONS_ATTRIB PYTHON_GET_DEF_FULL \ -( \ - destinations, py_arch_instruction, \ - "Provide the instructions list following the current instruction.\n" \ - "\n" \ - "Each item of the resulting tuple is a pair of" \ - " pychrysalide.arch.ArchInstruction instance and" \ - " pychrysalide.arch.ArchInstruction.InstructionLinkType value." \ + PyObject *result; /* Bilan à retourner */ + unsigned int flag; /* Fanion(s) à appliquer */ + int ret; /* Bilan de lecture des args. */ + GArchInstruction *instr; /* Instruction manipulée */ + bool status; /* Bilan à transmettre */ + +#define ARCH_INSTRUCTION_SET_FLAG_METHOD PYTHON_METHOD_DEF \ +( \ + set_flag, "$self, flag, /", \ + METH_VARARGS, py_arch_instruction, \ + "Add some flags to the instruction.\n" \ + "\n" \ + "This *flag* argument is an integer value containing" \ + " bits to apply to the instruction state.\n" \ + "\n" \ + "The result is an boolean status: *True* for operation" \ + " success, *False* otherwise." \ ) + ret = PyArg_ParseTuple(args, "I", &flag); + if (!ret) return NULL; + instr = G_ARCH_INSTRUCTION(pygobject_get(self)); - g_arch_instruction_lock_dest(instr); + status = g_arch_instruction_set_flag(instr, flag); - count = g_arch_instruction_count_destinations(instr); + result = status ? Py_True : Py_False; + Py_INCREF(result); - result = PyTuple_New(count); + return result; - for (i = 0; i < count; i++) - { - dest = g_arch_instruction_get_destination(instr, i); +} - linked = pygobject_new(G_OBJECT(dest->linked)); - type = cast_with_constants_group_from_type(get_python_arch_instruction_type(), - "InstructionLinkType", dest->type); -#ifndef NDEBUG - ret = PyTuple_SetItem(result, i, Py_BuildValue("(OO)", linked, type)); - assert(ret == 0); -#else - PyTuple_SetItem(result, i, Py_BuildValue("(OO)", linked, type)); -#endif +/****************************************************************************** +* * +* Paramètres : self = architecture concernée par la procédure. * +* args = instruction représentant le point de départ. * +* * +* Description : Retire une information complémentaire à une instruction. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static PyObject *py_arch_instruction_unset_flag(PyObject *self, PyObject *args) +{ + PyObject *result; /* Bilan à retourner */ + unsigned int flag; /* Fanion(s) à appliquer */ + int ret; /* Bilan de lecture des args. */ + GArchInstruction *instr; /* Instruction manipulée */ + bool status; /* Bilan à transmettre */ + +#define ARCH_INSTRUCTION_UNSET_FLAG_METHOD PYTHON_METHOD_DEF \ +( \ + unset_flag, "$self, flag, /", \ + METH_VARARGS, py_arch_instruction, \ + "Remove some flags from the instruction.\n" \ + "\n" \ + "This *flag* argument is an integer value containing" \ + " bits to delete from the instruction state.\n" \ + "\n" \ + "The result is an boolean status: *True* for operation" \ + " success, *False* otherwise." \ +) - unref_instr_link(dest); + ret = PyArg_ParseTuple(args, "I", &flag); + if (!ret) return NULL; - } + instr = G_ARCH_INSTRUCTION(pygobject_get(self)); - g_arch_instruction_unlock_dest(instr); + status = g_arch_instruction_unset_flag(instr, flag); + + result = status ? Py_True : Py_False; + Py_INCREF(result); return result; } +/****************************************************************************** +* * +* Paramètres : self = architecture concernée par la procédure. * +* args = instruction représentant le point de départ. * +* * +* Description : Détermine si une instruction possède un fanion particulier. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ -/* ---------------------------------------------------------------------------------- */ -/* INSTRUCTIONS D'ARCHITECTURES EN PYTHON */ -/* ---------------------------------------------------------------------------------- */ +static PyObject *py_arch_instruction_has_flag(PyObject *self, PyObject *args) +{ + PyObject *result; /* Bilan à retourner */ + unsigned int flag; /* Fanion(s) à appliquer */ + int ret; /* Bilan de lecture des args. */ + GArchInstruction *instr; /* Instruction manipulée */ + bool status; /* Bilan à transmettre */ + +#define ARCH_INSTRUCTION_HAS_FLAG_METHOD PYTHON_METHOD_DEF \ +( \ + has_flag, "$self, flag, /", \ + METH_VARARGS, py_arch_instruction, \ + "Tell if some flags are set for the instruction.\n" \ + "\n" \ + "This *flag* argument is an integer value containing" \ + " bits to test for the instruction state.\n" \ + "\n" \ + "The result is an boolean status: *True* if the bits" \ + " are active, *False* otherwise." \ +) + + ret = PyArg_ParseTuple(args, "I", &flag); + if (!ret) return NULL; + + instr = G_ARCH_INSTRUCTION(pygobject_get(self)); + + status = g_arch_instruction_has_flag(instr, flag); + + result = status ? Py_True : Py_False; + Py_INCREF(result); + + return result; + +} /****************************************************************************** * * -* Paramètres : self = classe représentant une instruction. * -* closure = adresse non utilisée ici. * +* Paramètres : self = objet Python concerné par l'appel. * +* closure = non utilisé ici. * * * -* Description : Fournit l'identifiant unique pour un ensemble d'instructions.* +* Description : Fournit l'identifiant correspondant à un type d'instructions.* * * -* Retour : Identifiant unique par type d'instruction. * +* Retour : Identifiant unique par type d'instruction et architecture. * * * * Remarques : - * * * ******************************************************************************/ -static PyObject *py_arch_instruction_get_unique_id(PyObject *self, void *closure) +static PyObject *py_arch_instruction_get_type_id(PyObject *self, void *closure) { - PyObject *result; /* Conversion à retourner */ - GArchInstruction *instr; /* Version native */ - itid_t uid; /* Identifiant unique associé */ + PyObject *result; /* Valeur à retourner */ + GArchInstruction *instr; /* Instruction manipulée */ + itid_t tid; /* Identifiant à transmettre */ + +#define ARCH_INSTRUCTION_TYPE_ID_ATTRIB PYTHON_GET_DEF_FULL \ +( \ + type_id, py_arch_instruction, \ + "Provide the unique identifier given to this kind of" \ + " instruction.\n" \ + "\n" \ + "The returned value is an integer." \ +) instr = G_ARCH_INSTRUCTION(pygobject_get(self)); - uid = g_arch_instruction_get_unique_id(instr); + tid = g_arch_instruction_get_type_id(instr); - result = PyLong_FromUnsignedLong(uid); + result = PyLong_FromUnsignedLong(tid); return result; @@ -697,27 +1013,61 @@ static PyObject *py_arch_instruction_get_unique_id(PyObject *self, void *closure /****************************************************************************** * * -* Paramètres : self = classe représentant une instruction. * -* closure = adresse non utilisée ici. * +* Paramètres : self = objet Python concerné par l'appel. * +* closure = non utilisé ici. * * * -* Description : Fournit la place mémoire d'une instruction. * +* Description : Indique l'encodage d'une instruction de façon détaillée. * * * -* Retour : Valeur associée à la propriété consultée. * +* Retour : Description humaine de l'encodage utilisé. * * * * Remarques : - * * * ******************************************************************************/ -static PyObject *py_arch_instruction_get_range(PyObject *self, void *closure) +static PyObject *py_arch_instruction_get_encoding(PyObject *self, void *closure) { - PyObject *result; /* Conversion à retourner */ - GArchInstruction *instr; /* Version native */ - const mrange_t *range; /* Espace mémoire à exporter */ + PyObject *result; /* Valeur à retourner */ + GArchInstruction *instr; /* Instruction manipulée */ + char *encoding; /* Encodage d'une instruction */ + +#define ARCH_INSTRUCTION_ENCODING_ATTRIB PYTHON_GET_DEF_FULL \ +( \ + encoding, py_arch_instruction, \ + "Describe the encoding related to an instruction.\n" \ + "\n" \ + "The returned value is an arbitrary string value." \ +) instr = G_ARCH_INSTRUCTION(pygobject_get(self)); - range = g_arch_instruction_get_range(instr); - result = build_from_internal_mrange(range); + encoding = g_arch_instruction_get_encoding(instr); + + if (encoding != NULL) + { + result = PyUnicode_FromString(encoding); + + free(encoding); + + } + + else + { + /** + * La méthode de classe sollicitée a renvoyé une valeur nulle. + * + * Si cette méthode correspond à une implémentation Python + * (avec un appel à not_yet_implemented_method()), une exception + * est déjà en place. + * + * Si aucune exception n'a été prévue, un rattrapage est effectué ici. + */ + + if (PyErr_Occurred() == NULL) + PyErr_SetString(PyExc_NotImplementedError, _("unexpected NULL value as encoding")); + + result = NULL; + + } return result; @@ -727,59 +1077,108 @@ static PyObject *py_arch_instruction_get_range(PyObject *self, void *closure) /****************************************************************************** * * * Paramètres : self = objet Python concerné par l'appel. * -* value = valeur fournie à intégrer ou prendre en compte. * -* closure = adresse non utilisée ici. * +* closure = non utilisé ici. * * * -* Description : Définit la localisation d'une instruction. * +* Description : Indique l'encodage d'une instruction de façon détaillée. * * * -* Retour : Bilan de l'opération pour Python. * +* Retour : Description humaine de l'encodage utilisé. * * * * Remarques : - * * * ******************************************************************************/ -static int py_arch_instruction_set_range(PyObject *self, PyObject *value, void *closure) +static PyObject *py_arch_instruction_get_keyword(PyObject *self, void *closure) { - int ret; /* Bilan d'analyse */ - mrange_t *range; /* Espace mémoire à manipuler */ - GArchInstruction *instr; /* Version native */ + PyObject *result; /* Valeur à retourner */ + GArchInstruction *instr; /* Instruction manipulée */ + char *keyword; /* Désignation d'une instruct° */ + +#define ARCH_INSTRUCTION_KEYWORD_ATTRIB PYTHON_GET_DEF_FULL \ +( \ + keyword, py_arch_instruction, \ + "Give the official name of the assembly instruction.\n" \ + "\n" \ + "The returned value is a string value." \ +) - ret = PyObject_IsInstance(value, (PyObject *)get_python_mrange_type()); - if (!ret) return -1; + instr = G_ARCH_INSTRUCTION(pygobject_get(self)); - range = get_internal_mrange(value); + keyword = g_arch_instruction_get_keyword(instr); - instr = G_ARCH_INSTRUCTION(pygobject_get(self)); - g_arch_instruction_set_range(instr, range); + if (keyword != NULL) + { + result = PyUnicode_FromString(keyword); - return 0; + free(keyword); + + } + + else + { + /** + * La méthode de classe sollicitée a renvoyé une valeur nulle. + * + * Si cette méthode correspond à une implémentation Python + * (avec un appel à not_yet_implemented_method()), une exception + * est déjà en place. + * + * Si aucune exception n'a été prévue, un rattrapage est effectué ici. + */ + + if (PyErr_Occurred() == NULL) + PyErr_SetString(PyExc_NotImplementedError, _("unexpected NULL value as keyword")); + + result = NULL; + + } + + return result; } /****************************************************************************** * * -* Paramètres : self = classe représentant une instruction. * -* unused = adresse non utilisée ici. * +* Paramètres : self = objet Python concerné par l'appel. * +* closure = non utilisé ici. * * * -* Description : Fournit le nom humain de l'instruction manipulée. * +* Description : Fournit la place mémoire d'une instruction. * * * -* Retour : Valeur associée à la propriété consultée. * +* Retour : Définition de localisation ou *None*. * * * * Remarques : - * * * ******************************************************************************/ -static PyObject *py_arch_instruction_get_keyword(PyObject *self, void *unused) +static PyObject *py_arch_instruction_get_range(PyObject *self, void *closure) { - PyObject *result; /* Trouvailles à retourner */ - GArchInstruction *instr; /* Version native */ - const char *kw; /* Valeur récupérée */ + PyObject *result; /* Valeur à retourner */ + GArchInstruction *instr; /* Instruction manipulée */ + mrange_t range; /* Localisation d'instruction */ + bool valid; /* Validité de la localisation */ + +#define ARCH_INSTRUCTION_RANGE_ATTRIB PYTHON_GET_DEF_FULL \ +( \ + range, py_arch_instruction, \ + "Give access to the memory range covered by the" \ + " current instruction.\n" \ + "\n" \ + "The returned value is a pychrysalide.arch.mrange" \ + " instance or *None* if no location is currently" \ + " defined." \ +) instr = G_ARCH_INSTRUCTION(pygobject_get(self)); - kw = g_arch_instruction_get_keyword(instr); - result = PyUnicode_FromString(kw); + valid = g_arch_instruction_get_range(instr, &range); + + if (valid) + result = build_from_internal_mrange(&range); + else + { + result = Py_None; + Py_INCREF(result); + } return result; @@ -801,45 +1200,25 @@ static PyObject *py_arch_instruction_get_keyword(PyObject *self, void *unused) PyTypeObject *get_python_arch_instruction_type(void) { static PyMethodDef py_arch_instruction_methods[] = { - { - "attach_operand", py_arch_instruction_attach_extra_operand, - METH_VARARGS, - "attach_operand($self, op, /)\n--\n\nAdd a new operand to the instruction." - }, - { - "replace_operand", py_arch_instruction_replace_operand, - METH_VARARGS, - "replace_operand($self, old, new, /)\n--\n\nReplace an old instruction operand by a another one." - }, - { - "detach_operand", py_arch_instruction_detach_operand, - METH_VARARGS, - "detach_operand($self, target, /)\n--\n\nRemove an operand from the instruction." - }, + ARCH_INSTRUCTION_ATTACH_OPERAND_METHOD, + ARCH_INSTRUCTION_REPLACE_OPERAND_METHOD, + ARCH_INSTRUCTION_DETACH_OPERAND_METHOD, ARCH_INSTRUCTION_FIND_OPERAND_PATH_METHOD, ARCH_INSTRUCTION_GET_OPERAND_FROM_PATH_METHOD, + ARCH_INSTRUCTION_SET_FLAG_METHOD, + ARCH_INSTRUCTION_UNSET_FLAG_METHOD, + ARCH_INSTRUCTION_HAS_FLAG_METHOD, { NULL } }; static PyGetSetDef py_arch_instruction_getseters[] = { - { - "uid", py_arch_instruction_get_unique_id, NULL, - "Provide the unique identification number given to this kind of instruction.", NULL - }, - { - "range", py_arch_instruction_get_range, py_arch_instruction_set_range, - "Give access to the memory range covered by the current instruction.", NULL - }, - { - "keyword", (getter)py_arch_instruction_get_keyword, (setter)NULL, - "Give le name of the assembly instruction.", NULL - }, - { - "operands", (getter)py_arch_instruction_get_operands, (setter)NULL, - "Provide the list of instruction attached operands.", NULL - }, ARCH_INSTRUCTION_SOURCES_ATTRIB, ARCH_INSTRUCTION_DESTINATIONS_ATTRIB, + ARCH_INSTRUCTION_OPERANDS_ATTRIB, + ARCH_INSTRUCTION_TYPE_ID_ATTRIB, + ARCH_INSTRUCTION_ENCODING_ATTRIB, + ARCH_INSTRUCTION_KEYWORD_ATTRIB, + ARCH_INSTRUCTION_RANGE_ATTRIB, { NULL } }; @@ -852,7 +1231,7 @@ PyTypeObject *get_python_arch_instruction_type(void) .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_IS_ABSTRACT | Py_TPFLAGS_BASETYPE, - .tp_doc = "PyChrysalide instruction for a given architecture.", + .tp_doc = ARCH_INSTRUCTION_DOC, .tp_methods = py_arch_instruction_methods, .tp_getset = py_arch_instruction_getseters, @@ -893,9 +1272,14 @@ bool ensure_python_arch_instruction_is_registered(void) dict = PyModule_GetDict(module); - if (!ensure_python_line_generator_is_registered()) + if (!ensure_python_thick_object_is_registered()) return false; + if (!ensure_python_serializable_object_is_registered()) + return false; + + pyg_register_class_init(G_TYPE_ARCH_INSTRUCTION, (PyGClassInitFunc)py_arch_instruction_init_gclass); + if (!register_class_for_pygobject(dict, G_TYPE_ARCH_INSTRUCTION, type)) return false; diff --git a/plugins/pychrysalide/arch/instructions/Makefile.am b/plugins/pychrysalide/arch/instructions/Makefile.am index 65efe42..29c2a45 100644 --- a/plugins/pychrysalide/arch/instructions/Makefile.am +++ b/plugins/pychrysalide/arch/instructions/Makefile.am @@ -7,7 +7,8 @@ libpychrysaarchinstructions_la_SOURCES = \ raw.h raw.c \ undefined.h undefined.c -libpychrysaarchinstructions_la_CFLAGS = $(TOOLKIT_CFLAGS) $(LIBXML_CFLAGS) $(LIBPYTHON_INTERPRETER_CFLAGS) $(LIBPYGOBJECT_CFLAGS) \ +libpychrysaarchinstructions_la_CFLAGS = $(LIBPYTHON_INTERPRETER_CFLAGS) $(LIBPYGOBJECT_CFLAGS) \ + $(TOOLKIT_CFLAGS) \ -I$(top_srcdir)/src -DNO_IMPORT_PYGOBJECT diff --git a/plugins/pychrysalide/arch/instructions/constants.c b/plugins/pychrysalide/arch/instructions/constants.c index af7baa9..257c501 100644 --- a/plugins/pychrysalide/arch/instructions/constants.c +++ b/plugins/pychrysalide/arch/instructions/constants.c @@ -2,7 +2,7 @@ /* Chrysalide - Outil d'analyse de fichiers binaires * constants.c - ajout des constantes de base pour les instructions * - * Copyright (C) 2020 Cyrille Bagard + * Copyright (C) 2020-2025 Cyrille Bagard * * This file is part of Chrysalide. * @@ -112,3 +112,59 @@ bool define_undefined_instruction_constants(PyTypeObject *type) return result; } + + +/****************************************************************************** +* * +* Paramètres : arg = argument quelconque à tenter de convertir. * +* dst = destination des valeurs récupérées en cas de succès. * +* * +* Description : Tente de convertir en constante ExpectedBehavior. * +* * +* Retour : Bilan de l'opération, voire indications supplémentaires. * +* * +* Remarques : - * +* * +******************************************************************************/ + +int convert_to_undefined_expected_behavior(PyObject *arg, void *dst) +{ + int result; /* Bilan à retourner */ + unsigned long value; /* Valeur récupérée */ + + result = PyObject_IsInstance(arg, (PyObject *)&PyLong_Type); + + switch (result) + { + case -1: + /* L'exception est déjà fixée par Python */ + result = 0; + break; + + case 0: + PyErr_SetString(PyExc_TypeError, "unable to convert the provided argument to ExpectedBehavior"); + break; + + case 1: + value = PyLong_AsUnsignedLong(arg); + + if (value > IEB_RESERVED) + { + PyErr_SetString(PyExc_TypeError, "unable to convert the provided argument to ExpectedBehavior"); + result = 0; + } + + else + *((InstrExpectedBehavior *)dst) = value; + + break; + + default: + assert(false); + break; + + } + + return result; + +} diff --git a/plugins/pychrysalide/arch/instructions/constants.h b/plugins/pychrysalide/arch/instructions/constants.h index 2f0c587..b6ef9a4 100644 --- a/plugins/pychrysalide/arch/instructions/constants.h +++ b/plugins/pychrysalide/arch/instructions/constants.h @@ -2,7 +2,7 @@ /* Chrysalide - Outil d'analyse de fichiers binaires * constants.h - prototypes pour l'ajout des constantes de base pour les instructions * - * Copyright (C) 2020 Cyrille Bagard + * Copyright (C) 2020-2025 Cyrille Bagard * * This file is part of Chrysalide. * @@ -37,6 +37,9 @@ bool define_raw_instruction_constants(PyTypeObject *); /* Définit les constantes liées aux comportements erratiques. */ bool define_undefined_instruction_constants(PyTypeObject *); +/* Tente de convertir en constante ExpectedBehavior. */ +int convert_to_undefined_expected_behavior(PyObject *, void *); + #endif /* _PLUGINS_PYCHRYSALIDE_ARCH_INSTRUCTIONS_CONSTANTS_H */ diff --git a/plugins/pychrysalide/arch/instructions/raw.c b/plugins/pychrysalide/arch/instructions/raw.c index 7e58b96..ae730e8 100644 --- a/plugins/pychrysalide/arch/instructions/raw.c +++ b/plugins/pychrysalide/arch/instructions/raw.c @@ -2,7 +2,7 @@ /* Chrysalide - Outil d'analyse de fichiers binaires * raw.c - équivalent Python du fichier "arch/instructions/raw.h" * - * Copyright (C) 2018-2020 Cyrille Bagard + * Copyright (C) 2018-2025 Cyrille Bagard * * This file is part of Chrysalide. * @@ -28,26 +28,33 @@ #include <pygobject.h> -#include <i18n.h> -#include <arch/instructions/raw.h> -#include <plugins/dt.h> +#include <arch/instructions/raw-int.h> #include "constants.h" #include "../instruction.h" #include "../vmpa.h" #include "../../access.h" +#include "../../constants.h" #include "../../helpers.h" #include "../../analysis/content.h" +#include "../../glibext/portion.h" -/* Accompagne la création d'une instance dérivée en Python. */ -static PyObject *py_raw_instruction_new(PyTypeObject *, PyObject *, PyObject *); +/* ------------------------ GLUE POUR CREATION DEPUIS PYTHON ------------------------ */ + + +CREATE_DYN_CONSTRUCTOR(raw_instruction, G_TYPE_RAW_INSTRUCTION); /* Initialise une instance sur la base du dérivé de GObject. */ static int py_raw_instruction_init(PyObject *, PyObject *, PyObject *); + + +/* ------------------------ FONCTIONNALITES DE L'INSTRUCTION ------------------------ */ + + /* Indique si le contenu de l'instruction est du bourrage. */ static PyObject *py_raw_instruction_get_padding(PyObject *, void *); @@ -62,64 +69,9 @@ static int py_raw_instruction_set_string(PyObject *, PyObject *, void *); -/****************************************************************************** -* * -* Paramètres : type = type du nouvel objet à mettre en place. * -* args = éventuelle liste d'arguments. * -* kwds = éventuel dictionnaire de valeurs mises à disposition. * -* * -* Description : Accompagne la création d'une instance dérivée en Python. * -* * -* Retour : Nouvel objet Python mis en place ou NULL en cas d'échec. * -* * -* Remarques : - * -* * -******************************************************************************/ - -static PyObject *py_raw_instruction_new(PyTypeObject *type, PyObject *args, PyObject *kwds) -{ - PyObject *result; /* Objet à retourner */ - PyTypeObject *base; /* Type de base à dériver */ - bool first_time; /* Evite les multiples passages*/ - GType gtype; /* Nouveau type de processeur */ - bool status; /* Bilan d'un enregistrement */ - - /* Validations diverses */ - - base = get_python_raw_instruction_type(); - - if (type == base) - goto simple_way; - - /* Mise en place d'un type dédié */ - - first_time = (g_type_from_name(type->tp_name) == 0); - - gtype = build_dynamic_type(G_TYPE_RAW_INSTRUCTION, type->tp_name, NULL, NULL, NULL); - - if (first_time) - { - status = register_class_for_dynamic_pygobject(gtype, type); - - if (!status) - { - result = NULL; - goto exit; - } - - } - - /* On crée, et on laisse ensuite la main à PyGObject_Type.tp_init() */ - - simple_way: - - result = PyType_GenericNew(type, args, kwds); - - exit: - - return result; - -} +/* ---------------------------------------------------------------------------------- */ +/* GLUE POUR CREATION DEPUIS PYTHON */ +/* ---------------------------------------------------------------------------------- */ /****************************************************************************** @@ -139,20 +91,17 @@ static PyObject *py_raw_instruction_new(PyTypeObject *type, PyObject *args, PyOb static int py_raw_instruction_init(PyObject *self, PyObject *args, PyObject *kwds) { int result; /* Bilan à retourner */ + GBinaryPortion *area; /* Zone de contenance */ vmpa2t *addr; /* Texte de lecture */ - unsigned long mem_size; /* Taille de portion brute */ + MemoryDataSize size; /* Taille de portion brute */ unsigned long long value; /* Valeur brute à considérer */ GBinContent *content; /* Contenu à lire au besoin */ unsigned long count; /* Nombre d'éléments à lister */ - unsigned int endian; /* Type de boutisme impliqué */ + SourceEndian endian; /* Type de boutisme impliqué */ int ret; /* Bilan de lecture des args. */ - GArchInstruction *fake; /* Instruction à copier */ - GArchInstruction *instr; /* Instruction à manipuler */ - size_t op_count; /* Nombre d'opérande à copier */ - size_t i; /* Boucle de parcours */ - GArchOperand *op; /* Opérande à transférer */ + GRawInstruction *instr; /* Instruction à manipuler */ - static char *kwlist[] = { "addr", "mem_size", "value", "content", "count", "endian", NULL }; + static char *kwlist[] = { "area", "addr", "size", "value", "content", "count", "endian", NULL }; #define RAW_INSTRUCTION_DOC \ "The RawInstruction object handles data which is not (yet?) disassembled" \ @@ -187,9 +136,14 @@ static int py_raw_instruction_init(PyObject *self, PyObject *args, PyObject *kwd count = 0; endian = 0; - ret = PyArg_ParseTupleAndKeywords(args, kwds, "O&k|KO&kI", kwlist, - convert_any_to_vmpa, &addr, &mem_size, - &value, convert_to_binary_content, &content, &count, &endian); + ret = PyArg_ParseTupleAndKeywords(args, kwds, "O&O&O&|KO&kO&", kwlist, + convert_to_binary_portion, &area, + convert_any_to_vmpa, &addr, + convert_to_memory_data_size, &size, + &value, + convert_to_binary_content, &content, + &count, + convert_to_source_endian, &endian); if (!ret) return -1; /* Initialisation d'un objet GLib */ @@ -199,35 +153,19 @@ static int py_raw_instruction_init(PyObject *self, PyObject *args, PyObject *kwd /* Eléments de base */ - if (content != NULL) - fake = g_raw_instruction_new_array(content, mem_size, count, addr, endian); - else - fake = g_raw_instruction_new_from_value(addr, mem_size, value); + instr = G_RAW_INSTRUCTION(pygobject_get(self)); - if (fake == NULL) + if (content != NULL) { - PyErr_SetString(PyExc_ValueError, _("Unable to build the object with the given parameters.")); - goto clean_exit; + if (!g_raw_instruction_create_array(instr, area, addr, size, content, count, endian)) + goto clean_exit; } - - instr = G_ARCH_INSTRUCTION(pygobject_get(self)); - - g_arch_instruction_lock_operands(fake); - - op_count = _g_arch_instruction_count_operands(fake); - - for (i = 0; i < op_count; i++) + else { - op = _g_arch_instruction_get_operand(fake, i); - g_arch_instruction_attach_extra_operand(instr, op); + if (!g_raw_instruction_create_value(instr, area, addr, size, value)) + goto clean_exit; } - g_arch_instruction_unlock_operands(fake); - - g_arch_instruction_set_range(instr, g_arch_instruction_get_range(fake)); - - g_object_unref(G_OBJECT(fake)); - result = 0; clean_exit: @@ -239,6 +177,12 @@ static int py_raw_instruction_init(PyObject *self, PyObject *args, PyObject *kwd } + +/* ---------------------------------------------------------------------------------- */ +/* FONCTIONNALITES DE L'INSTRUCTION */ +/* ---------------------------------------------------------------------------------- */ + + /****************************************************************************** * * * Paramètres : self = classe représentant une instruction. * @@ -271,7 +215,6 @@ static PyObject *py_raw_instruction_get_padding(PyObject *self, void *closure) result = state ? Py_True : Py_False; Py_INCREF(result); - return result; } @@ -342,7 +285,6 @@ static PyObject *py_raw_instruction_get_string(PyObject *self, void *closure) result = state ? Py_True : Py_False; Py_INCREF(result); - return result; } diff --git a/plugins/pychrysalide/arch/instructions/undefined.c b/plugins/pychrysalide/arch/instructions/undefined.c index 1246daa..1c2bccc 100644 --- a/plugins/pychrysalide/arch/instructions/undefined.c +++ b/plugins/pychrysalide/arch/instructions/undefined.c @@ -2,7 +2,7 @@ /* Chrysalide - Outil d'analyse de fichiers binaires * undefined.c - équivalent Python du fichier "arch/instructions/undefined.h" * - * Copyright (C) 2019 Cyrille Bagard + * Copyright (C) 2019-2025 Cyrille Bagard * * This file is part of Chrysalide. * @@ -28,9 +28,7 @@ #include <pygobject.h> -#include <i18n.h> #include <arch/instructions/undefined-int.h> -#include <plugins/dt.h> #include "constants.h" @@ -40,75 +38,27 @@ -/* Accompagne la création d'une instance dérivée en Python. */ -static PyObject *py_undef_instruction_new(PyTypeObject *, PyObject *, PyObject *); +/* ------------------------ GLUE POUR CREATION DEPUIS PYTHON ------------------------ */ -/* Initialise une instance sur la base du dérivé de GObject. */ -static int py_undef_instruction_init(PyObject *, PyObject *, PyObject *); - -/* Indique le type de conséquences réél de l'instruction. */ -static PyObject *py_undef_instruction_get_behavior(PyObject *, void *); - - - -/****************************************************************************** -* * -* Paramètres : type = type du nouvel objet à mettre en place. * -* args = éventuelle liste d'arguments. * -* kwds = éventuel dictionnaire de valeurs mises à disposition. * -* * -* Description : Accompagne la création d'une instance dérivée en Python. * -* * -* Retour : Nouvel objet Python mis en place ou NULL en cas d'échec. * -* * -* Remarques : - * -* * -******************************************************************************/ - -static PyObject *py_undef_instruction_new(PyTypeObject *type, PyObject *args, PyObject *kwds) -{ - PyObject *result; /* Objet à retourner */ - PyTypeObject *base; /* Type de base à dériver */ - bool first_time; /* Evite les multiples passages*/ - GType gtype; /* Nouveau type de processeur */ - bool status; /* Bilan d'un enregistrement */ - - /* Validations diverses */ - base = get_python_undefined_instruction_type(); +CREATE_DYN_CONSTRUCTOR(undefined_instruction, G_TYPE_UNDEFINED_INSTRUCTION); - if (type == base) - goto simple_way; - - /* Mise en place d'un type dédié */ - - first_time = (g_type_from_name(type->tp_name) == 0); - - gtype = build_dynamic_type(G_TYPE_UNDEF_INSTRUCTION, type->tp_name, NULL, NULL, NULL); - - if (first_time) - { - status = register_class_for_dynamic_pygobject(gtype, type); +/* Initialise une instance sur la base du dérivé de GObject. */ +static int py_undefined_instruction_init(PyObject *, PyObject *, PyObject *); - if (!status) - { - result = NULL; - goto exit; - } - } - /* On crée, et on laisse ensuite la main à PyGObject_Type.tp_init() */ +/* ------------------------ FONCTIONNALITES DE L'INSTRUCTION ------------------------ */ - simple_way: - result = PyType_GenericNew(type, args, kwds); +/* Indique le type de conséquences réél de l'instruction. */ +static PyObject *py_undefined_instruction_get_behavior(PyObject *, void *); - exit: - return result; -} +/* ---------------------------------------------------------------------------------- */ +/* GLUE POUR CREATION DEPUIS PYTHON */ +/* ---------------------------------------------------------------------------------- */ /****************************************************************************** @@ -125,30 +75,27 @@ static PyObject *py_undef_instruction_new(PyTypeObject *type, PyObject *args, Py * * ******************************************************************************/ -static int py_undef_instruction_init(PyObject *self, PyObject *args, PyObject *kwds) +static int py_undefined_instruction_init(PyObject *self, PyObject *args, PyObject *kwds) { - unsigned long behavior; /* Conséquence pour l'instruct°*/ + InstrExpectedBehavior behavior; /* Conséquence pour l'instruct°*/ int ret; /* Bilan de lecture des args. */ - GUndefInstruction *instr; /* Instruction à manipuler */ - undef_extra_data_t *extra; /* Données insérées à modifier */ + GUndefinedInstruction *instr; /* Instruction à manipuler */ - static char *kwlist[] = { "behavior", NULL }; - -#define UNDEF_INSTRUCTION_DOC \ - "UndefInstruction represents all kinds of instructions which are" \ +#define UNDEFINED_INSTRUCTION_DOC \ + "UndefinedInstruction represents all kinds of instructions which are" \ " officially not part of a runnable instruction set.\n" \ "\n" \ "Instances can be created using the following constructor:\n" \ "\n" \ - " UndefInstruction(behavior)" \ + " UndefinedInstruction(behavior)" \ "\n" \ "Where behavior is a" \ - " pychrysalide.arch.instructions.UndefInstruction.ExpectedBehavior" \ + " pychrysalide.arch.instructions.UndefinedInstruction.ExpectedBehavior" \ " constant describing the state of the CPU once the instruction is run." /* Récupération des paramètres */ - ret = PyArg_ParseTupleAndKeywords(args, kwds, "k", kwlist, &behavior); + ret = PyArg_ParseTuple(args, "O&", convert_to_undefined_expected_behavior, &behavior); if (!ret) return -1; /* Initialisation d'un objet GLib */ @@ -158,17 +105,22 @@ static int py_undef_instruction_init(PyObject *self, PyObject *args, PyObject *k /* Eléments de base */ - instr = G_UNDEF_INSTRUCTION(pygobject_get(self)); - - extra = GET_UNDEF_INSTR_EXTRA(instr); + instr = G_UNDEFINED_INSTRUCTION(pygobject_get(self)); - extra->behavior = behavior; + if (!g_undefined_instruction_create(instr, behavior)) + return -1; return 0; } + +/* ---------------------------------------------------------------------------------- */ +/* FONCTIONNALITES DE L'INSTRUCTION */ +/* ---------------------------------------------------------------------------------- */ + + /****************************************************************************** * * * Paramètres : self = classe représentant une instruction. * @@ -182,24 +134,25 @@ static int py_undef_instruction_init(PyObject *self, PyObject *args, PyObject *k * * ******************************************************************************/ -static PyObject *py_undef_instruction_get_behavior(PyObject *self, void *closure) +static PyObject *py_undefined_instruction_get_behavior(PyObject *self, void *closure) { PyObject *result; /* Conversion à retourner */ - GUndefInstruction *instr; /* Version native */ + GUndefinedInstruction *instr; /* Version native */ InstrExpectedBehavior behavior; /* Comportement attendu */ -#define UNDEF_INSTRUCTION_BEHAVIOR_ATTRIB PYTHON_GET_DEF_FULL \ -( \ - behavior, py_undef_instruction, \ - "Consequence carried by the undefined instruction.\n" \ - "\n" \ - "The result is provided as a" \ - " pychrysalide.arch.instructions.UndefInstruction.ExpectedBehavior" \ - " constant." \ +#define UNDEFINED_INSTRUCTION_BEHAVIOR_ATTRIB PYTHON_GET_DEF_FULL \ +( \ + behavior, py_undefined_instruction, \ + "Consequence carried by the undefined instruction.\n" \ + "\n" \ + "The result is provided as a" \ + " pychrysalide.arch.instructions.UndefinedInstruction.ExpectedBehavior" \ + " constant." \ ) - instr = G_UNDEF_INSTRUCTION(pygobject_get(self)); - behavior = g_undef_instruction_get_behavior(instr); + instr = G_UNDEFINED_INSTRUCTION(pygobject_get(self)); + + behavior = g_undefined_instruction_get_behavior(instr); result = cast_with_constants_group_from_type(get_python_undefined_instruction_type(), "ExpectedBehavior", behavior); @@ -228,7 +181,7 @@ PyTypeObject *get_python_undefined_instruction_type(void) }; static PyGetSetDef py_undefined_instruction_getseters[] = { - UNDEF_INSTRUCTION_BEHAVIOR_ATTRIB, + UNDEFINED_INSTRUCTION_BEHAVIOR_ATTRIB, { NULL } }; @@ -236,18 +189,18 @@ PyTypeObject *get_python_undefined_instruction_type(void) PyVarObject_HEAD_INIT(NULL, 0) - .tp_name = "pychrysalide.arch.instructions.UndefInstruction", + .tp_name = "pychrysalide.arch.instructions.UndefinedInstruction", .tp_basicsize = sizeof(PyGObject), .tp_flags = Py_TPFLAGS_DEFAULT, - .tp_doc = UNDEF_INSTRUCTION_DOC, + .tp_doc = UNDEFINED_INSTRUCTION_DOC, .tp_methods = py_undefined_instruction_methods, .tp_getset = py_undefined_instruction_getseters, - .tp_init = py_undef_instruction_init, - .tp_new = py_undef_instruction_new, + .tp_init = py_undefined_instruction_init, + .tp_new = py_undefined_instruction_new, }; @@ -260,7 +213,7 @@ PyTypeObject *get_python_undefined_instruction_type(void) * * * Paramètres : module = module dont la définition est à compléter. * * * -* Description : Prend en charge l'objet 'pychrysalide.....UndefInstruction'. * +* Description : Prend en charge l'objet '....UndefinedInstruction'. * * * * Retour : Bilan de l'opération. * * * @@ -285,7 +238,7 @@ bool ensure_python_undefined_instruction_is_registered(void) if (!ensure_python_arch_instruction_is_registered()) return false; - if (!register_class_for_pygobject(dict, G_TYPE_UNDEF_INSTRUCTION, type)) + if (!register_class_for_pygobject(dict, G_TYPE_UNDEFINED_INSTRUCTION, type)) return false; if (!define_undefined_instruction_constants(type)) @@ -329,7 +282,7 @@ int convert_to_undefined_instruction(PyObject *arg, void *dst) break; case 1: - *((GUndefInstruction **)dst) = G_UNDEF_INSTRUCTION(pygobject_get(arg)); + *((GUndefinedInstruction **)dst) = G_UNDEFINED_INSTRUCTION(pygobject_get(arg)); break; default: diff --git a/plugins/pychrysalide/arch/instructions/undefined.h b/plugins/pychrysalide/arch/instructions/undefined.h index 3fa0453..1453612 100644 --- a/plugins/pychrysalide/arch/instructions/undefined.h +++ b/plugins/pychrysalide/arch/instructions/undefined.h @@ -2,7 +2,7 @@ /* Chrysalide - Outil d'analyse de fichiers binaires * undefined.h - prototypes pour l'équivalent Python du fichier "arch/instructions/undefined.h" * - * Copyright (C) 2019 Cyrille Bagard + * Copyright (C) 2019-2025 Cyrille Bagard * * This file is part of Chrysalide. * @@ -34,7 +34,7 @@ /* Fournit un accès à une définition de type à diffuser. */ PyTypeObject *get_python_undefined_instruction_type(void); -/* Prend en charge l'objet 'pychrysalide.arch.instructions.UndefInstruction'. */ +/* Prend en charge l'objet 'pychrysalide.arch.instructions.UndefinedInstruction'. */ bool ensure_python_undefined_instruction_is_registered(void); /* Tente de convertir en instruction non définie. */ diff --git a/plugins/pychrysalide/arch/module-ui.c b/plugins/pychrysalide/arch/module-ui.c index 201f760..65d1290 100644 --- a/plugins/pychrysalide/arch/module-ui.c +++ b/plugins/pychrysalide/arch/module-ui.c @@ -29,6 +29,7 @@ #include "operand-ui.h" +#include "../glibext/generator.h" @@ -52,6 +53,12 @@ bool populate_arch_module_ui(void) if (result) result = ensure_python_arch_operand_ui_is_registered(); + /** + * Préparation du terrain pour les instructions, sans lien directe + * de la partie UI depuis la partie NOX. + */ + if (result) result = ensure_python_token_generator_is_registered(); + assert(result); return result; diff --git a/plugins/pychrysalide/arch/module.c b/plugins/pychrysalide/arch/module.c index 3f52a58..94f5ad7 100644 --- a/plugins/pychrysalide/arch/module.c +++ b/plugins/pychrysalide/arch/module.c @@ -32,14 +32,12 @@ #include "context.h" #include "instriter.h" */ -//#include "instruction.h" +#include "instruction.h" #include "operand.h" //#include "processor.h" #include "register.h" #include "vmpa.h" -/* #include "instructions/module.h" -*/ #include "operands/module.h" #include "../helpers.h" @@ -77,9 +75,7 @@ bool add_arch_module(PyObject *super) result = (module != NULL); - /* if (result) result = add_arch_instructions_module(module); - */ if (result) result = add_arch_operands_module(module); return result; @@ -109,16 +105,14 @@ bool populate_arch_module(void) if (result) result = ensure_python_proc_context_is_registered(); if (result) result = ensure_python_instr_iterator_is_registered(); */ - //if (result) result = ensure_python_arch_instruction_is_registered(); + if (result) result = ensure_python_arch_instruction_is_registered(); if (result) result = ensure_python_arch_operand_is_registered(); //if (result) result = ensure_python_arch_processor_is_registered(); if (result) result = ensure_python_arch_register_is_registered(); if (result) result = ensure_python_vmpa_is_registered(); if (result) result = ensure_python_mrange_is_registered(); - /* if (result) result = populate_arch_instructions_module(); - */ if (result) result = populate_arch_operands_module(); assert(result); diff --git a/plugins/pychrysalide/arch/operand.c b/plugins/pychrysalide/arch/operand.c index 42bd247..2281dae 100644 --- a/plugins/pychrysalide/arch/operand.c +++ b/plugins/pychrysalide/arch/operand.c @@ -94,6 +94,10 @@ static PyObject *py_arch_operand_set_flag(PyObject *, PyObject *); /* Retire une information complémentaire à un opérande. */ static PyObject *py_arch_operand_unset_flag(PyObject *, PyObject *); +/* Détermine si un opérande possède un fanion particulier. */ +static PyObject *py_arch_operand_has_flag(PyObject *, PyObject *); + + /* ---------------------------------------------------------------------------------- */ diff --git a/plugins/pychrysalide/bindings.c b/plugins/pychrysalide/bindings.c index 7e87e27..f120c3b 100644 --- a/plugins/pychrysalide/bindings.c +++ b/plugins/pychrysalide/bindings.c @@ -33,6 +33,7 @@ #include <common/cpp.h> +#include <common/environment.h> #include <common/extstr.h> #include <core/core.h> #include <plugins/pglist.h> @@ -52,10 +53,6 @@ #include "glibext/module.h" /* #include "debug/module.h" */ #include "format/module.h" -/* #ifdef INCLUDE_GTK_SUPPORT */ -/* # include "gtkext/module.h" */ -/* # include "gui/module.h" */ -/* #endif */ /* #include "mangling/module.h" */ #include "plugins/module.h" @@ -149,7 +146,7 @@ static void ensure_native_pygobject_type(PyTypeObject **); static PyObject *get_existing_modules(void); /* Définit les différents modules du support Python. */ -static PyObject *create_basic_modules(void); +static PyObject *create_basic_modules(const pyinit_details_t *); /* Inscrit les défintions des objets Python de Chrysalide. */ static bool populate_python_modules(const pyinit_details_t *); @@ -158,6 +155,7 @@ static bool populate_python_modules(const pyinit_details_t *); static void restore_original_pygobject_type(PyTypeObject *); + /* ------------------------ FONCTIONS GLOBALES DE CHRYSALIDE ------------------------ */ @@ -978,7 +976,7 @@ static PyObject *get_existing_modules(void) /****************************************************************************** * * -* Paramètres : - * +* Paramètres : details = précisions de chargement complémentaires. * * * * Description : Définit les différents modules du support Python. * * * @@ -988,7 +986,7 @@ static PyObject *get_existing_modules(void) * * ******************************************************************************/ -static PyObject *create_basic_modules(void) +static PyObject *create_basic_modules(const pyinit_details_t *details) { PyObject *result; /* Module Python à retourner */ bool status; /* Bilan des inclusions */ @@ -1036,14 +1034,17 @@ static PyObject *create_basic_modules(void) */ if (status) status = add_format_module(result); /* -#ifdef INCLUDE_GTK_SUPPORT - if (status) status = add_gtkext_module(result); - if (status) status = add_gui_module(result); -#endif if (status) status = add_mangling_module(result); */ if (status) status = add_plugins_module(result); + /** + * Ajout de modules UI supplémentaires éventuels. + */ + + if (status && details->add_extra != NULL) + status = details->add_extra(result); + if (!status) { Py_DECREF(result); @@ -1081,8 +1082,8 @@ static bool populate_python_modules(const pyinit_details_t *details) * un chargement préliminaire, si besoin est. */ - if (details->populate_extra) - result = details->populate_extra(); + if (details->populate_extra != NULL) + result = details->populate_extra(false); else result = true; @@ -1101,14 +1102,22 @@ static bool populate_python_modules(const pyinit_details_t *details) */ if (result) result = populate_format_module(); /* -#ifdef INCLUDE_GTK_SUPPORT - if (result) result = populate_gtkext_module(); - if (result) result = populate_gui_module(); -#endif if (result) result = populate_mangling_module(); */ if (result) result = populate_plugins_module(); + /** + * Certaines définitions reposent sur une déclinaison de GtkWidget, + * dont le chargement va remplacer la définition statique de GObject + * par une version allouée dynamiquement. + * + * De telles définitions doivent donc être prise en compte à la fin + * du chargement. + */ + + if (result && details->populate_extra != NULL) + result = details->populate_extra(true); + return result; } @@ -1202,7 +1211,7 @@ PyObject *init_python_pychrysalide_module(const pyinit_details_t *details) ensure_native_pygobject_type(&py_gobj_def); - result = create_basic_modules(); + result = create_basic_modules(details); if (result == NULL) PyErr_SetString(PyExc_SystemError, "failed to create all PyChrysalide modules."); @@ -1356,6 +1365,54 @@ void log_pychrysalide_exception(const char *prefix, ...) /* ---------------------------------------------------------------------------------- */ +/* INTERVENTION DANS LA GESTION DE GREFFONS */ +/* ---------------------------------------------------------------------------------- */ + + +/****************************************************************************** +* * +* Paramètres : plugin = instance représentant le greffon courant. * +* path = chemin supplémentaire pour l'espace de recherche. * +* * +* Description : Complète les chemins de recherches de Python. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +void extend_python_path(const GPluginModule *plugin, const char *path) +{ + PyGILState_STATE gstate; /* Sauvegarde d'environnement */ + PyObject *list; /* Liste de chemins à compléter*/ + PyObject *new; /* Nouveau chemin à intégrer */ + + gstate = PyGILState_Ensure(); + + list = PySys_GetObject("path"); + assert(list != NULL); + + new = PyUnicode_FromString(path); + assert(new != NULL); + + PyList_Append(list, new); + + Py_DECREF(new); + + add_to_env_var("PYTHONPATH", path, ":"); + + PyGILState_Release(gstate); + + g_plugin_module_log_variadic_message(plugin, LMT_INFO, + _("PYTHONPATH environment variable set to '%s'"), + getenv("PYTHONPATH")); + +} + + + +/* ---------------------------------------------------------------------------------- */ /* FONCTIONS GLOBALES DE CHRYSALIDE */ /* ---------------------------------------------------------------------------------- */ diff --git a/plugins/pychrysalide/bindings.h b/plugins/pychrysalide/bindings.h index 1758747..036f852 100644 --- a/plugins/pychrysalide/bindings.h +++ b/plugins/pychrysalide/bindings.h @@ -2,7 +2,7 @@ /* Chrysalide - Outil d'analyse de fichiers binaires * bindings.h - prototypes pour les éléments d'un socle commun aux fonctionnalités graphiques et non graphiques * - * Copyright (C) 2024 Cyrille Bagard + * Copyright (C) 2024-2025 Cyrille Bagard * * This file is part of Chrysalide. * @@ -44,6 +44,9 @@ +/* ------------------------ FONCTIONNALITES DE MISE EN PLACE ------------------------ */ + + /* Charge un module GI dans Python avec une version attendue. */ bool import_namespace_from_gi_repository(const char *, const char *); @@ -52,7 +55,9 @@ typedef struct _pyinit_details_t { bool standalone; /* Chargement depuis Python ? */ - bool (* populate_extra) (void); /* Ajout de types ? */ + bool (* add_extra) (PyObject *); /* Ajout de modules ? */ + + bool (* populate_extra) (bool); /* Ajout de types ? */ /** * Prototype de la fonction de création, à garder synchronisé avec @@ -70,4 +75,12 @@ void log_pychrysalide_exception(const char *, ...); +/* -------------------- INTERVENTION DANS LA GESTION DE GREFFONS -------------------- */ + + +/* Complète les chemins de recherches de Python. */ +void extend_python_path(const GPluginModule *, const char *); + + + #endif /* _PLUGINS_PYCHRYSALIDE_BINDINGS_H */ diff --git a/plugins/pychrysalide/convert.c b/plugins/pychrysalide/convert.c index c67c8ba..08866cb 100644 --- a/plugins/pychrysalide/convert.c +++ b/plugins/pychrysalide/convert.c @@ -87,3 +87,34 @@ int convert_to_gsettings(PyObject *arg, void *dst) return result; } + + +/****************************************************************************** +* * +* Paramètres : arg = argument quelconque à tenter de convertir. * +* dst = destination des valeurs récupérées en cas de succès. * +* * +* Description : Tente de convertir en instance GSettings ou NULL. * +* * +* Retour : Bilan de l'opération, voire indications supplémentaires. * +* * +* Remarques : - * +* * +******************************************************************************/ + +int convert_to_gsettings_or_none(PyObject *arg, void *dst) +{ + int result; /* Bilan à retourner */ + + if (arg == Py_None) + { + *((GSettings **)dst) = NULL; + result = 1; + } + + else + result = convert_to_gsettings(arg, dst); + + return result; + +} diff --git a/plugins/pychrysalide/convert.h b/plugins/pychrysalide/convert.h index 7bdf7da..86d7528 100644 --- a/plugins/pychrysalide/convert.h +++ b/plugins/pychrysalide/convert.h @@ -33,6 +33,9 @@ /* Tente de convertir en instance GSettings. */ int convert_to_gsettings(PyObject *, void *); +/* Tente de convertir en instance GSettings ou NULL. */ +int convert_to_gsettings_or_none(PyObject *, void *); + #endif /* _PLUGINS_PYCHRYSALIDE_CONVERT_H */ diff --git a/plugins/pychrysalide/core-ui.c b/plugins/pychrysalide/core-ui.c index 1fb7931..00d1cc1 100644 --- a/plugins/pychrysalide/core-ui.c +++ b/plugins/pychrysalide/core-ui.c @@ -28,6 +28,10 @@ #include <i18n.h> +#ifdef DISCARD_LOCAL +# include <core/paths.h> +#endif +#include <plugins/manager-int.h> #include <plugins/self.h> @@ -35,6 +39,8 @@ #include "core-ui-int.h" #include "arch/module-ui.h" #include "glibext/module-ui.h" +#include "gtkext/module.h" +//#include "gui/module.h" @@ -49,14 +55,17 @@ static bool _standalone = true; /* Initialise la classe des greffons de support Python. */ static void g_pychrysalide_plugin_ui_class_init(GPyChrysalidePluginUIClass *); +/* Procède à l'initialisation de l'interface de gestion. */ +static void g_pychrysalide_plugin_ui_plugin_manager_interface_init(GPluginManagerInterface *); + /* Initialise une instance de greffon de support Python. */ static void g_pychrysalide_plugin_ui_init(GPyChrysalidePluginUI *); /* Supprime toutes les références externes. */ -static void g_pychrysalide_plugin_ui_dispose(GPyChrysalidePluginUI *); +static void g_pychrysalide_plugin_ui_dispose(GObject *); /* Procède à la libération totale de la mémoire. */ -static void g_pychrysalide_plugin_ui_finalize(GPyChrysalidePluginUI *); +static void g_pychrysalide_plugin_ui_finalize(GObject *); @@ -64,15 +73,26 @@ static void g_pychrysalide_plugin_ui_finalize(GPyChrysalidePluginUI *); /* Prend acte de l'activation du greffon. */ -static bool g_pychrysalide_plugin_ui_enable(GPyChrysalidePluginUI *); +static bool g_pychrysalide_plugin_ui_enable(GPluginModule *); + + + +/* -------------------- INTERVENTION DANS LA GESTION DE GREFFONS -------------------- */ + + +/* Prend acte du chargement de l'ensemble des greffons natifs. */ +static void g_pychrysalide_plugin_ui_handle_native_plugins_loaded_event(GPluginManager *); /* --------------------------- POINT D'ENTREE POUR PYTHON --------------------------- */ +/*Ajoute des modules UI aux extensions Python. */ +static bool add_python_ui_modules(PyObject *); + /* Inscrit les défintions des objets UI Python de Chrysalide. */ -static bool populate_python_modules_ui(void); +static bool populate_python_modules_ui(bool); @@ -82,7 +102,8 @@ static bool populate_python_modules_ui(void); /* Indique le type défini pour un greffon de liaison Python */ -G_DEFINE_TYPE(GPyChrysalidePluginUI, g_pychrysalide_plugin_ui, G_TYPE_PYCHRYSALIDE_PLUGIN); +G_DEFINE_TYPE_WITH_CODE(GPyChrysalidePluginUI, g_pychrysalide_plugin_ui, G_TYPE_PYCHRYSALIDE_PLUGIN, + G_IMPLEMENT_INTERFACE(G_TYPE_PLUGIN_MANAGER, g_pychrysalide_plugin_ui_plugin_manager_interface_init)); NATIVE_PLUGIN_ENTRYPOINT(g_pychrysalide_plugin_ui_new); @@ -107,12 +128,31 @@ static void g_pychrysalide_plugin_ui_class_init(GPyChrysalidePluginUIClass *clas object = G_OBJECT_CLASS(class); - object->dispose = (GObjectFinalizeFunc/* ! */)g_pychrysalide_plugin_ui_dispose; - object->finalize = (GObjectFinalizeFunc)g_pychrysalide_plugin_ui_finalize; + object->dispose = g_pychrysalide_plugin_ui_dispose; + object->finalize = g_pychrysalide_plugin_ui_finalize; plugin = G_PLUGIN_MODULE_CLASS(class); - plugin->enable = (pg_management_fc)g_pychrysalide_plugin_ui_enable; + plugin->enable = g_pychrysalide_plugin_ui_enable; + +} + + +/****************************************************************************** +* * +* Paramètres : iface = interface GLib à initialiser. * +* * +* Description : Procède à l'initialisation de l'interface de gestion. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_pychrysalide_plugin_ui_plugin_manager_interface_init(GPluginManagerInterface *iface) +{ + iface->handle_native = g_pychrysalide_plugin_ui_handle_native_plugins_loaded_event; } @@ -137,7 +177,7 @@ static void g_pychrysalide_plugin_ui_init(GPyChrysalidePluginUI *plugin) /****************************************************************************** * * -* Paramètres : plugin = instance d'objet GLib à traiter. * +* Paramètres : object = instance d'objet GLib à traiter. * * * * Description : Supprime toutes les références externes. * * * @@ -147,16 +187,16 @@ static void g_pychrysalide_plugin_ui_init(GPyChrysalidePluginUI *plugin) * * ******************************************************************************/ -static void g_pychrysalide_plugin_ui_dispose(GPyChrysalidePluginUI *plugin) +static void g_pychrysalide_plugin_ui_dispose(GObject *object) { - G_OBJECT_CLASS(g_pychrysalide_plugin_ui_parent_class)->dispose(G_OBJECT(plugin)); + G_OBJECT_CLASS(g_pychrysalide_plugin_ui_parent_class)->dispose(object); } /****************************************************************************** * * -* Paramètres : plugin = 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 +206,9 @@ static void g_pychrysalide_plugin_ui_dispose(GPyChrysalidePluginUI *plugin) * * ******************************************************************************/ -static void g_pychrysalide_plugin_ui_finalize(GPyChrysalidePluginUI *plugin) +static void g_pychrysalide_plugin_ui_finalize(GObject *object) { - G_OBJECT_CLASS(g_pychrysalide_plugin_ui_parent_class)->finalize(G_OBJECT(plugin)); + G_OBJECT_CLASS(g_pychrysalide_plugin_ui_parent_class)->finalize(object); } @@ -241,22 +281,24 @@ bool g_pychrysalide_plugin_ui_create(GPyChrysalidePluginUI *plugin, GModule *mod * * ******************************************************************************/ -static bool g_pychrysalide_plugin_ui_enable(GPyChrysalidePluginUI *plugin) +static bool g_pychrysalide_plugin_ui_enable(GPluginModule *plugin) { bool result; /* Bilan à retourner */ + GPyChrysalidePlugin *pychr_plugin; /* Version spécialisée */ PyGILState_STATE gstate; /* Sauvegarde d'environnement */ int ret; /* Bilan de préparatifs */ _standalone = false; + pychr_plugin = G_PYCHRYSALIDE_PLUGIN(plugin); + /* Chargement du module pour Python */ ret = PyImport_AppendInittab("pychrysalide", &PyInit_pychrysalideui); if (ret == -1) { - g_plugin_module_log_simple_message(G_PLUGIN_MODULE(plugin), - LMT_ERROR, + g_plugin_module_log_simple_message(plugin, LMT_ERROR, _("Can not extend the existing table of Python built-in modules.")); result = false; @@ -268,7 +310,7 @@ static bool g_pychrysalide_plugin_ui_enable(GPyChrysalidePluginUI *plugin) gstate = PyGILState_Ensure(); - G_PYCHRYSALIDE_PLUGIN(plugin)->py_module = PyImport_ImportModule("pychrysalide"); + pychr_plugin->py_module = PyImport_ImportModule("pychrysalide"); /** * Pour mémoire, une situation concrête conduisant à un échec : @@ -283,7 +325,7 @@ static bool g_pychrysalide_plugin_ui_enable(GPyChrysalidePluginUI *plugin) // TODO : check (2025) - result = (G_PYCHRYSALIDE_PLUGIN(plugin)->py_module != NULL); + result = (pychr_plugin->py_module != NULL); PyGILState_Release(gstate); @@ -296,13 +338,103 @@ static bool g_pychrysalide_plugin_ui_enable(GPyChrysalidePluginUI *plugin) /* ---------------------------------------------------------------------------------- */ +/* INTERVENTION DANS LA GESTION DE GREFFONS */ +/* ---------------------------------------------------------------------------------- */ + + +/****************************************************************************** +* * +* Paramètres : manager = interface à manipuler. * +* * +* Description : Accompagne la fin du chargement des modules natifs. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_pychrysalide_plugin_ui_handle_native_plugins_loaded_event(GPluginManager *manager) +{ + GPluginModule *plugin; /* Version de base du greffon */ +#ifdef DISCARD_LOCAL + char *edir; /* Répertoire de base effectif */ + DIR *dir; /* Répertoire à parcourir */ +#endif + GPluginManagerInterface *iface; /* Interface utilisée */ + GPluginManagerInterface *parent_iface; /* Interface parente */ + + plugin = G_PLUGIN_MODULE(manager); + + /* Définition des zones d'influence */ + +#ifndef DISCARD_LOCAL + + extend_python_path(plugin, PACKAGE_SOURCE_DIR G_DIR_SEPARATOR_S "plugins" G_DIR_SEPARATOR_S "pythonui"); + +#else + + edir = get_effective_directory(PLUGINS_DATA_DIR G_DIR_SEPARATOR_S "pythonui"); + + dir = opendir(edir); + + if (dir != NULL) + { + closedir(dir); + + extend_python_path(plugin, edir); + + } + + free(edir); + +#endif + + /* Chargements des extensions Python */ + + iface = G_PLUGIN_MANAGER_GET_IFACE(manager); + + parent_iface = g_type_interface_peek_parent(iface); + + parent_iface->handle_native(manager); + +} + + + +/* ---------------------------------------------------------------------------------- */ /* POINT D'ENTREE POUR PYTHON */ /* ---------------------------------------------------------------------------------- */ /****************************************************************************** * * -* Paramètres : - * +* Paramètres : super = module dont la définition est à compléter. * +* * +* Description : Ajoute des modules UI aux extensions Python. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static bool add_python_ui_modules(PyObject *super) +{ + bool result; /* Bilan à retourner */ + + result = true; + + if (result) result = add_gtkext_module(super); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : modify = autorisation de motification du type GObject. * * * * Description : Inscrit les défintions des objets UI Python de Chrysalide. * * * @@ -312,14 +444,25 @@ static bool g_pychrysalide_plugin_ui_enable(GPyChrysalidePluginUI *plugin) * * ******************************************************************************/ -static bool populate_python_modules_ui(void) +static bool populate_python_modules_ui(bool modify) { bool result; /* Bilan à retourner */ result = true; - if (result) result = populate_arch_module_ui(); - if (result) result = populate_glibext_module_ui(); + if (!modify) + { + if (result) result = populate_arch_module_ui(); + if (result) result = populate_glibext_module_ui(); + + } + + else + { + if (result) result = populate_gtkext_module(); + //if (result) result = populate_gui_module(); + + } return result; @@ -345,6 +488,7 @@ PyMODINIT_FUNC PyInit_pychrysalideui(void) details.standalone = _standalone; + details.add_extra = add_python_ui_modules; details.populate_extra = populate_python_modules_ui; details.create_self = g_pychrysalide_plugin_ui_new; diff --git a/plugins/pychrysalide/core.c b/plugins/pychrysalide/core.c index 51a06a1..0fea9c4 100644 --- a/plugins/pychrysalide/core.c +++ b/plugins/pychrysalide/core.c @@ -24,24 +24,14 @@ #include "core.h" -#include "core-int.h" - - - - - #undef NO_IMPORT_PYGOBJECT #include <pygobject.h> #define NO_IMPORT_PYGOBJECT -#include "core.h" - - #include <assert.h> #include <errno.h> #include <malloc.h> -//#include <pygobject.h> #include <stdarg.h> #include <stdbool.h> #include <string.h> @@ -60,10 +50,9 @@ #include <plugins/self.h> - - #include "access.h" #include "bindings.h" +#include "core-int.h" @@ -72,14 +61,6 @@ static bool _standalone = true; - - - - - - - - /* ---------------------- COMPOSITION DE NOUVEAU GREFFON NATIF ---------------------- */ @@ -93,10 +74,10 @@ static void g_pychrysalide_plugin_plugin_manager_interface_init(GPluginManagerIn static void g_pychrysalide_plugin_init(GPyChrysalidePlugin *); /* Supprime toutes les références externes. */ -static void g_pychrysalide_plugin_dispose(GPyChrysalidePlugin *); +static void g_pychrysalide_plugin_dispose(GObject *); /* Procède à la libération totale de la mémoire. */ -static void g_pychrysalide_plugin_finalize(GPyChrysalidePlugin *); +static void g_pychrysalide_plugin_finalize(GObject *); @@ -104,19 +85,16 @@ static void g_pychrysalide_plugin_finalize(GPyChrysalidePlugin *); /* Prend acte de l'activation du greffon. */ -static bool g_pychrysalide_plugin_enable(GPyChrysalidePlugin *); +static bool g_pychrysalide_plugin_enable(GPluginModule *); /* Prend acte de la désactivation du greffon. */ -static bool g_pychrysalide_plugin_disable(GPyChrysalidePlugin *); +static bool g_pychrysalide_plugin_disable(GPluginModule *); /* -------------------- INTERVENTION DANS LA GESTION DE GREFFONS -------------------- */ -/* Complète les chemins de recherches de Python. */ -static void extend_python_path(const char *); - /* Crée un greffon à partir de code Python. */ static GPluginModule *create_python_plugin(const char *, const char *); @@ -124,7 +102,7 @@ static GPluginModule *create_python_plugin(const char *, const char *); static void load_python_plugins(GPluginModule *); /* Prend acte du chargement de l'ensemble des greffons natifs. */ -static void g_pychrysalide_plugin_handle_native_plugins_loaded_event(GPyChrysalidePlugin *); +static void g_pychrysalide_plugin_handle_native_plugins_loaded_event(GPluginManager *); @@ -160,13 +138,13 @@ static void g_pychrysalide_plugin_class_init(GPyChrysalidePluginClass *class) object = G_OBJECT_CLASS(class); - object->dispose = (GObjectFinalizeFunc/* ! */)g_pychrysalide_plugin_dispose; - object->finalize = (GObjectFinalizeFunc)g_pychrysalide_plugin_finalize; + object->dispose = g_pychrysalide_plugin_dispose; + object->finalize = g_pychrysalide_plugin_finalize; plugin = G_PLUGIN_MODULE_CLASS(class); - plugin->enable = (pg_management_fc)g_pychrysalide_plugin_enable; - plugin->disable = (pg_management_fc)g_pychrysalide_plugin_disable; + plugin->enable = g_pychrysalide_plugin_enable; + plugin->disable = g_pychrysalide_plugin_disable; } @@ -185,7 +163,7 @@ static void g_pychrysalide_plugin_class_init(GPyChrysalidePluginClass *class) static void g_pychrysalide_plugin_plugin_manager_interface_init(GPluginManagerInterface *iface) { - iface->handle_native = (handle_native_plugins_cb)g_pychrysalide_plugin_handle_native_plugins_loaded_event; + iface->handle_native = g_pychrysalide_plugin_handle_native_plugins_loaded_event; } @@ -213,7 +191,7 @@ static void g_pychrysalide_plugin_init(GPyChrysalidePlugin *plugin) /****************************************************************************** * * -* Paramètres : plugin = instance d'objet GLib à traiter. * +* Paramètres : object = instance d'objet GLib à traiter. * * * * Description : Supprime toutes les références externes. * * * @@ -223,16 +201,16 @@ static void g_pychrysalide_plugin_init(GPyChrysalidePlugin *plugin) * * ******************************************************************************/ -static void g_pychrysalide_plugin_dispose(GPyChrysalidePlugin *plugin) +static void g_pychrysalide_plugin_dispose(GObject *object) { - G_OBJECT_CLASS(g_pychrysalide_plugin_parent_class)->dispose(G_OBJECT(plugin)); + G_OBJECT_CLASS(g_pychrysalide_plugin_parent_class)->dispose(object); } /****************************************************************************** * * -* Paramètres : plugin = instance d'objet GLib à traiter. * +* Paramètres : object = instance d'objet GLib à traiter. * * * * Description : Procède à la libération totale de la mémoire. * * * @@ -242,9 +220,9 @@ static void g_pychrysalide_plugin_dispose(GPyChrysalidePlugin *plugin) * * ******************************************************************************/ -static void g_pychrysalide_plugin_finalize(GPyChrysalidePlugin *plugin) +static void g_pychrysalide_plugin_finalize(GObject *object) { - G_OBJECT_CLASS(g_pychrysalide_plugin_parent_class)->finalize(G_OBJECT(plugin)); + G_OBJECT_CLASS(g_pychrysalide_plugin_parent_class)->finalize(object); } @@ -323,22 +301,24 @@ bool g_pychrysalide_plugin_create(GPyChrysalidePlugin *plugin, GModule *module) * * ******************************************************************************/ -static bool g_pychrysalide_plugin_enable(GPyChrysalidePlugin *plugin) +static bool g_pychrysalide_plugin_enable(GPluginModule *plugin) { bool result; /* Bilan à retourner */ + GPyChrysalidePlugin *pychr_plugin; /* Version spécialisée */ PyGILState_STATE gstate; /* Sauvegarde d'environnement */ int ret; /* Bilan de préparatifs */ _standalone = false; + pychr_plugin = G_PYCHRYSALIDE_PLUGIN(plugin); + /* Chargement du module pour Python */ ret = PyImport_AppendInittab("pychrysalide", &PyInit_pychrysalide); if (ret == -1) { - g_plugin_module_log_simple_message(G_PLUGIN_MODULE(plugin), - LMT_ERROR, + g_plugin_module_log_simple_message(plugin, LMT_ERROR, _("Can not extend the existing table of Python built-in modules.")); result = false; @@ -350,7 +330,7 @@ static bool g_pychrysalide_plugin_enable(GPyChrysalidePlugin *plugin) gstate = PyGILState_Ensure(); - plugin->py_module = PyImport_ImportModule("pychrysalide"); + pychr_plugin->py_module = PyImport_ImportModule("pychrysalide"); /** * Pour mémoire, une situation concrête conduisant à un échec : @@ -365,7 +345,7 @@ static bool g_pychrysalide_plugin_enable(GPyChrysalidePlugin *plugin) // TODO : check (2025) - result = (plugin->py_module != NULL); + result = (pychr_plugin->py_module != NULL); PyGILState_Release(gstate); @@ -388,14 +368,17 @@ static bool g_pychrysalide_plugin_enable(GPyChrysalidePlugin *plugin) * * ******************************************************************************/ -static bool g_pychrysalide_plugin_disable(GPyChrysalidePlugin *plugin) +static bool g_pychrysalide_plugin_disable(GPluginModule *plugin) { bool result; /* Bilan à retourner */ + GPyChrysalidePlugin *pychr_plugin; /* Version spécialisée */ bool standalone; /* Nature du chargement */ PyGILState_STATE gstate; /* Sauvegarde d'environnement */ result = true; + pychr_plugin = G_PYCHRYSALIDE_PLUGIN(plugin); + /** * Le champ plugin->py_module n'est défini que via la fonction * g_pychrysalide_plugin_enable(), qui n'est pas sollicitée lorsque @@ -407,7 +390,7 @@ static bool g_pychrysalide_plugin_disable(GPyChrysalidePlugin *plugin) * initial ici. */ - standalone = (plugin->py_module == NULL); + standalone = (pychr_plugin->py_module == NULL); /** * Si on se trouve embarqué dans un interpréteur Python, le déchargement @@ -430,8 +413,8 @@ static bool g_pychrysalide_plugin_disable(GPyChrysalidePlugin *plugin) clear_all_accesses_to_python_modules(); - Py_XDECREF(plugin->py_module); - plugin->py_module = NULL; + Py_XDECREF(pychr_plugin->py_module); + pychr_plugin->py_module = NULL; if (!standalone) PyGILState_Release(gstate); @@ -449,38 +432,6 @@ static bool g_pychrysalide_plugin_disable(GPyChrysalidePlugin *plugin) /****************************************************************************** * * -* Paramètres : path = chemin supplémentaire pour l'espace de recherche. * -* * -* Description : Complète les chemins de recherches de Python. * -* * -* Retour : - * -* * -* Remarques : - * -* * -******************************************************************************/ - -static void extend_python_path(const char *path) -{ - PyObject *list; /* Liste de chemins à compléter*/ - PyObject *new; /* Nouveau chemin à intégrer */ - - list = PySys_GetObject("path"); - assert(list != NULL); - - new = PyUnicode_FromString(path); - assert(new != NULL); - - PyList_Append(list, new); - - Py_DECREF(new); - - add_to_env_var("PYTHONPATH", path, ":"); - -} - - -/****************************************************************************** -* * * Paramètres : modname = nom du module à charger. * * filename = chemin d'accès au code Python à charger. * * * @@ -568,48 +519,18 @@ static GPluginModule *create_python_plugin(const char *modname, const char *file static void load_python_plugins(GPluginModule *plugin) { -#ifdef DISCARD_LOCAL - char *edir; /* Répertoire de base effectif */ -#endif - DIR *dir; /* Répertoire à parcourir */ + PyGILState_STATE gstate; /* Sauvegarde d'environnement */ char *paths; /* Emplacements de greffons */ char *save; /* Sauvegarde pour ré-entrance */ char *path; /* Chemin à fouiller */ + DIR *dir; /* Répertoire à parcourir */ struct dirent *entry; /* Elément trouvé */ char *modname; /* Nom du module pour Python */ char *filename; /* Chemin d'accès reconstruit */ GPluginModule *pyplugin; /* Lien vers un grffon Python */ bool status; /* Bilan d'une opération */ - /* Définition des zones d'influence */ - -#ifndef DISCARD_LOCAL - - extend_python_path(PACKAGE_SOURCE_DIR G_DIR_SEPARATOR_S "plugins" G_DIR_SEPARATOR_S "python"); - -#else - - edir = get_effective_directory(PLUGINS_DATA_DIR G_DIR_SEPARATOR_S "python"); - - dir = opendir(edir); - - if (dir != NULL) - { - closedir(dir); - - extend_python_path(edir); - - } - - free(edir); - -#endif - - g_plugin_module_log_variadic_message(plugin, LMT_INFO, - _("PYTHONPATH environment variable set to '%s'"), - getenv("PYTHONPATH")); - - /* Chargements des extensions Python */ + gstate = PyGILState_Ensure(); paths = get_env_var("PYTHONPATH"); @@ -622,7 +543,7 @@ static void load_python_plugins(GPluginModule *plugin) dir = opendir(path); if (dir == NULL) { - perror("opendir"); + LOG_ERROR_N("opendir"); continue; } @@ -639,7 +560,7 @@ static void load_python_plugins(GPluginModule *plugin) if (entry == NULL) { if (errno != 0) - perror("readdir"); + LOG_ERROR_N("readdir"); break; @@ -703,12 +624,14 @@ static void load_python_plugins(GPluginModule *plugin) free(paths); + PyGILState_Release(gstate); + } /****************************************************************************** * * -* Paramètres : plugin = interface à manipuler. * +* Paramètres : manager = interface à manipuler. * * * * Description : Accompagne la fin du chargement des modules natifs. * * * @@ -718,15 +641,43 @@ static void load_python_plugins(GPluginModule *plugin) * * ******************************************************************************/ -static void g_pychrysalide_plugin_handle_native_plugins_loaded_event(GPyChrysalidePlugin *plugin) +static void g_pychrysalide_plugin_handle_native_plugins_loaded_event(GPluginManager *manager) { - PyGILState_STATE gstate; /* Sauvegarde d'environnement */ + GPluginModule *plugin; /* Version de base du greffon */ +#ifdef DISCARD_LOCAL + char *edir; /* Répertoire de base effectif */ + DIR *dir; /* Répertoire à parcourir */ +#endif - gstate = PyGILState_Ensure(); + plugin = G_PLUGIN_MODULE(manager); - load_python_plugins(G_PLUGIN_MODULE(plugin)); + /* Définition des zones d'influence */ - PyGILState_Release(gstate); +#ifndef DISCARD_LOCAL + + extend_python_path(plugin, PACKAGE_SOURCE_DIR G_DIR_SEPARATOR_S "plugins" G_DIR_SEPARATOR_S "python"); + +#else + + edir = get_effective_directory(PLUGINS_DATA_DIR G_DIR_SEPARATOR_S "python"); + + dir = opendir(edir); + + if (dir != NULL) + { + closedir(dir); + + extend_python_path(plugin, edir); + + } + + free(edir); + +#endif + + /* Chargements des extensions Python */ + + load_python_plugins(plugin); } @@ -756,6 +707,7 @@ PyMODINIT_FUNC PyInit_pychrysalide(void) details.standalone = _standalone; + details.add_extra = NULL; details.populate_extra = NULL; details.create_self = g_pychrysalide_plugin_new; diff --git a/plugins/pychrysalide/glibext/secstorage.c b/plugins/pychrysalide/glibext/secstorage.c index b5adb7c..5935d29 100644 --- a/plugins/pychrysalide/glibext/secstorage.c +++ b/plugins/pychrysalide/glibext/secstorage.c @@ -106,14 +106,15 @@ static int py_secret_storage_init(PyObject *self, PyObject *args, PyObject *kwds "\n" \ "Instances can be created using the following constructor:\n" \ "\n" \ - " SecretStorage(settings)" \ + " SecretStorage(settings=None)" \ "\n" \ - "The *settings* arguement must point to a GSettings intance;" \ - " the main configuration settings are used by default." \ + "The *settings* arguement may point to a GSettings instance." \ + " This optional argument is mainly used for testing purpose;" \ + " the main configuration settings are used by default." settings = NULL; - ret = PyArg_ParseTuple(args, "|O&", convert_to_gsettings, &settings); + ret = PyArg_ParseTuple(args, "|O&", convert_to_gsettings_or_none, &settings); if (!ret) return -1; /* Initialisation d'un objet GLib */ diff --git a/plugins/pychrysalide/gtkext/Makefile.am b/plugins/pychrysalide/gtkext/Makefile.am index 2e1260f..1d91751 100644 --- a/plugins/pychrysalide/gtkext/Makefile.am +++ b/plugins/pychrysalide/gtkext/Makefile.am @@ -1,19 +1,23 @@ noinst_LTLIBRARIES = libpychrysagtkext.la +# libpychrysagtkext_la_SOURCES = \ +# blockdisplay.h blockdisplay.c \ +# bufferdisplay.h bufferdisplay.c \ +# displaypanel.h displaypanel.c \ +# dockable.h dockable.c \ +# easygtk.h easygtk.c \ +# module.h module.c \ +# named.h named.c + libpychrysagtkext_la_SOURCES = \ - blockdisplay.h blockdisplay.c \ - bufferdisplay.h bufferdisplay.c \ - displaypanel.h displaypanel.c \ - dockable.h dockable.c \ - easygtk.h easygtk.c \ - module.h module.c \ - named.h named.c - -libpychrysagtkext_la_LIBADD = \ - graph/libpychrysagtkextgraph.la - -libpychrysagtkext_la_CFLAGS = $(LIBGTK_CFLAGS) $(LIBXML_CFLAGS) $(LIBPYTHON_INTERPRETER_CFLAGS) $(LIBPYGOBJECT_CFLAGS) \ + panel.h panel.c \ + module.h module.c + +# libpychrysagtkext_la_LIBADD = \ +# graph/libpychrysagtkextgraph.la + +libpychrysagtkext_la_CFLAGS = $(LIBGTK4_CFLAGS) $(LIBPYTHON_INTERPRETER_CFLAGS) $(LIBPYGOBJECT_CFLAGS) \ -I$(top_srcdir)/src -DNO_IMPORT_PYGOBJECT @@ -22,4 +26,4 @@ devdir = $(includedir)/chrysalide/$(subdir) dev_HEADERS = $(libpychrysagtkext_la_SOURCES:%c=) -SUBDIRS = graph +#SUBDIRS = graph diff --git a/plugins/pychrysalide/gtkext/module.c b/plugins/pychrysalide/gtkext/module.c index f8264af..fa59b2b 100644 --- a/plugins/pychrysalide/gtkext/module.c +++ b/plugins/pychrysalide/gtkext/module.c @@ -2,7 +2,7 @@ /* Chrysalide - Outil d'analyse de fichiers binaires * module.c - intégration du répertoire gtkext en tant que module * - * Copyright (C) 2018-2019 Cyrille Bagard + * Copyright (C) 2018-2025 Cyrille Bagard * * This file is part of Chrysalide. * @@ -28,13 +28,13 @@ #include <assert.h> -#include "blockdisplay.h" -#include "bufferdisplay.h" -#include "displaypanel.h" -#include "dockable.h" -#include "easygtk.h" -#include "named.h" -#include "graph/module.h" +//#include "blockdisplay.h" +//#include "bufferdisplay.h" +//#include "displaypanel.h" +//#include "dockable.h" +//#include "named.h" +#include "panel.h" +//#include "graph/module.h" #include "../helpers.h" @@ -71,7 +71,7 @@ bool add_gtkext_module(PyObject *super) result = (module != NULL); - if (result) result = add_gtkext_graph_module(module); + //if (result) result = add_gtkext_graph_module(module); if (!result) Py_XDECREF(module); @@ -99,14 +99,16 @@ bool populate_gtkext_module(void) result = true; - if (result) result = ensure_python_block_display_is_registered(); - if (result) result = ensure_python_buffer_display_is_registered(); - if (result) result = ensure_python_display_panel_is_registered(); - if (result) result = ensure_python_dockable_is_registered(); - if (result) result = ensure_python_easygtk_is_registered(); - if (result) result = ensure_python_built_named_widget_is_registered(); + if (result) result = ensure_python_tiled_panel_is_registered(); - if (result) result = populate_gtkext_graph_module(); + //if (result) result = ensure_python_block_display_is_registered(); + //if (result) result = ensure_python_buffer_display_is_registered(); + //if (result) result = ensure_python_display_panel_is_registered(); + //if (result) result = ensure_python_dockable_is_registered(); + //if (result) result = ensure_python_easygtk_is_registered(); + //if (result) result = ensure_python_built_named_widget_is_registered(); + + //if (result) result = populate_gtkext_graph_module(); assert(result); diff --git a/plugins/pychrysalide/gtkext/panel.c b/plugins/pychrysalide/gtkext/panel.c new file mode 100644 index 0000000..9f6589a --- /dev/null +++ b/plugins/pychrysalide/gtkext/panel.c @@ -0,0 +1,130 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * panel.c - prototypes pour l'équivalent Python du fichier "gtkext/panel.c" + * + * 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 "panel.h" + + +#include <pygobject.h> + + +#include <gtkext/panel.h> + + +#include "../access.h" +#include "../helpers.h" +#include "../helpers-ui.h" + + + +#define TILED_PANEL_DOC \ + "The TiledPanel class defines a panel widget for the framework main" \ + " window." + + + +/****************************************************************************** +* * +* Paramètres : - * +* * +* Description : Fournit un accès à une définition de type à diffuser. * +* * +* Retour : Définition d'objet pour Python. * +* * +* Remarques : - * +* * +******************************************************************************/ + +PyTypeObject *get_python_tiled_panel_type(void) +{ + static PyMethodDef py_tiled_panel_methods[] = { + { NULL } + }; + + static PyGetSetDef py_tiled_panel_getseters[] = { + { NULL } + }; + + static PyTypeObject py_tiled_panel_type = { + + PyVarObject_HEAD_INIT(NULL, 0) + + .tp_name = "pychrysalide.gtkext.TiledPanel", + .tp_basicsize = sizeof(PyGObject), + + .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, + + .tp_doc = TILED_PANEL_DOC, + + .tp_methods = py_tiled_panel_methods, + .tp_getset = py_tiled_panel_getseters, + + }; + + static PyTypeObject *result = NULL; + + if (result == NULL) + result = define_python_dynamic_type(&py_tiled_panel_type); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : - * +* * +* Description : Prend en charge l'objet 'pychrysalide.gtkext.TiledPanel'. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool ensure_python_tiled_panel_is_registered(void) +{ + PyTypeObject *type; /* Type Python 'TiledPanel' */ + PyObject *module; /* Module à recompléter */ + PyObject *dict; /* Dictionnaire du module */ + + type = get_python_tiled_panel_type(); + + if (!PyType_HasFeature(type, Py_TPFLAGS_READY)) + { + module = get_access_to_python_module("pychrysalide.gtkext"); + + dict = PyModule_GetDict(module); + + if (!ensure_gtk_widget_is_registered()) + return false; + + if (!register_class_for_pygobject(dict, GTK_TYPE_TILED_PANEL, type)) + return false; + + } + + return true; + +} diff --git a/plugins/pychrysalide/gtkext/panel.h b/plugins/pychrysalide/gtkext/panel.h new file mode 100644 index 0000000..c5cbe86 --- /dev/null +++ b/plugins/pychrysalide/gtkext/panel.h @@ -0,0 +1,42 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * panel.h - prototypes pour l'équivalent Python du fichier "gtkext/panel.h" + * + * 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_PYCHRYSALIDE_GTKEXT_PANEL_H +#define _PLUGINS_PYCHRYSALIDE_GTKEXT_PANEL_H + + +#include <Python.h> +#include <stdbool.h> + + + +/* Fournit un accès à une définition de type à diffuser. */ +PyTypeObject *get_python_tiled_panel_type(void); + +/* Prend en charge l'objet 'pychrysalide.gtkext.TiledPanel'. */ +bool ensure_python_tiled_panel_is_registered(void); + + + +#endif /* _PLUGINS_PYCHRYSALIDE_GTKEXT_PANEL_H */ diff --git a/plugins/pychrysalide/helpers-ui.c b/plugins/pychrysalide/helpers-ui.c new file mode 100644 index 0000000..982e676 --- /dev/null +++ b/plugins/pychrysalide/helpers-ui.c @@ -0,0 +1,141 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * helpers-ui.c - simplification des interactions UI de base avec Python + * + * 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 "helpers-ui.h" + + +#include <assert.h> +#include <pygobject.h> +#include <gtk/gtk.h> + + +#include "bindings.h" + + + +/* ---------------------------------------------------------------------------------- */ +/* CONFORTS CIBLANT PYGOBJECT */ +/* ---------------------------------------------------------------------------------- */ + + +/****************************************************************************** +* * +* Paramètres : - * +* * +* Description : Assure une prise en charge de l'objet Gtk.WIdget. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool ensure_gtk_widget_is_registered(void) +{ + bool result; /* Bilan à retourner */ + PyObject *gtk_mod; /* Module Python Gtk */ + PyObject *widget_type; /* Module "GtkWidget" */ + + /** + * Afin d'éviter le message d'avertissement suivant, la version attendue + * est demandée : + * + * PyGIWarning: Gtk was imported without specifying a version first. + * Use gi.require_version('Gtk', '4.0') before import to ensure that the right version gets loaded. + * + */ + result = import_namespace_from_gi_repository("Gtk", "4.0"); + + if (result) + { + gtk_mod = PyImport_ImportModule("gi.repository.Gtk"); + assert(gtk_mod != NULL); + + widget_type = PyObject_GetAttrString(gtk_mod, "Widget"); + + result = (widget_type != NULL); + + Py_DECREF(gtk_mod); + Py_XDECREF(widget_type); + + } + + return result; + +} + + + +/****************************************************************************** +* * +* Paramètres : arg = argument quelconque à tenter de convertir. * +* dst = destination des valeurs récupérées en cas de succès. * +* * +* Description : Tente de convertir en instance de composant GTK. * +* * +* Retour : Bilan de l'opération, voire indications supplémentaires. * +* * +* Remarques : - * +* * +******************************************************************************/ + +int convert_to_gtk_widget(PyObject *arg, void *dst) +{ + int result; /* Bilan à retourner */ + PyObject *gtk_mod; /* Module Python Gtk */ + PyObject *widget_type; /* Module "GtkWidget" */ + int ret; /* Bilan d'une conversion */ + + result = 0; + + gtk_mod = PyImport_ImportModule("gi.repository.Gtk"); + + if (gtk_mod == NULL) + { + PyErr_SetString(PyExc_TypeError, "unable to find the Gtk Python module"); + goto done; + } + + widget_type = PyObject_GetAttrString(gtk_mod, "Widget"); + + Py_DECREF(gtk_mod); + + ret = PyObject_TypeCheck(arg, (PyTypeObject *)widget_type); + + Py_DECREF(widget_type); + + if (!ret) + { + PyErr_SetString(PyExc_TypeError, "unable to convert the provided argument to GTK widget"); + goto done; + } + + *((GtkWidget **)dst) = GTK_WIDGET(pygobject_get(arg)); + + result = 1; + + done: + + return result; + +} diff --git a/plugins/pychrysalide/helpers-ui.h b/plugins/pychrysalide/helpers-ui.h new file mode 100644 index 0000000..b575905 --- /dev/null +++ b/plugins/pychrysalide/helpers-ui.h @@ -0,0 +1,44 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * helpers-ui.h - prototypes pour la simplification des interactions UI de base avec Python + * + * 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_PYCHRYSALIDE_HELPERS_UI_H +#define _PLUGINS_PYCHRYSALIDE_HELPERS_UI_H + + +#include <Python.h> +#include <stdbool.h> + + + +/* --------------------------- CONFORTS CIBLANT PYGOBJECT --------------------------- */ + + +/* Assure une prise en charge de l'objet Gtk.WIdget. */ +bool ensure_gtk_widget_is_registered(void); + +/* Tente de convertir en instance de composant GTK. */ +int convert_to_gtk_widget(PyObject *, void *); + + + +#endif /* _PLUGINS_PYCHRYSALIDE_HELPERS_UI_H */ diff --git a/plugins/pychrysalide/helpers.c b/plugins/pychrysalide/helpers.c index 0c84278..4ff768c 100644 --- a/plugins/pychrysalide/helpers.c +++ b/plugins/pychrysalide/helpers.c @@ -2,7 +2,7 @@ /* Chrysalide - Outil d'analyse de fichiers binaires * helpers.c - simplification des interactions de base avec Python * - * Copyright (C) 2018-2024 Cyrille Bagard + * Copyright (C) 2018-2025 Cyrille Bagard * * This file is part of Chrysalide. * @@ -32,9 +32,6 @@ #include <stdlib.h> #include <string.h> #include <strings.h> -#ifdef INCLUDE_GTK_SUPPORT -# include <gtk/gtk.h> -#endif #include <i18n.h> @@ -1260,122 +1257,6 @@ int convert_to_gobject(PyObject *arg, void *dst) #if 0 -#ifdef INCLUDE_GTK_SUPPORT - - -/****************************************************************************** -* * -* Paramètres : arg = argument quelconque à tenter de convertir. * -* dst = destination des valeurs récupérées en cas de succès. * -* * -* Description : Tente de convertir en instance de composant GTK. * -* * -* Retour : Bilan de l'opération, voire indications supplémentaires. * -* * -* Remarques : - * -* * -******************************************************************************/ - -int convert_to_gtk_widget(PyObject *arg, void *dst) -{ - int result; /* Bilan à retourner */ - PyObject *gtk_mod; /* Module Python Gtk */ - PyObject *widget_type; /* Module "GtkWidget" */ - int ret; /* Bilan d'une conversion */ - - result = 0; - - gtk_mod = PyImport_ImportModule("gi.repository.Gtk"); - - if (gtk_mod == NULL) - { - PyErr_SetString(PyExc_TypeError, "unable to find the Gtk Python module"); - goto done; - } - - widget_type = PyObject_GetAttrString(gtk_mod, "Widget"); - - Py_DECREF(gtk_mod); - - ret = PyObject_TypeCheck(arg, (PyTypeObject *)widget_type); - - Py_DECREF(widget_type); - - if (!ret) - { - PyErr_SetString(PyExc_TypeError, "unable to convert the provided argument to GTK widget"); - goto done; - } - - *((GtkWidget **)dst) = GTK_WIDGET(pygobject_get(arg)); - - result = 1; - - done: - - return result; - -} - - -/****************************************************************************** -* * -* Paramètres : arg = argument quelconque à tenter de convertir. * -* dst = destination des valeurs récupérées en cas de succès. * -* * -* Description : Tente de convertir en instance de conteneur GTK. * -* * -* Retour : Bilan de l'opération, voire indications supplémentaires. * -* * -* Remarques : - * -* * -******************************************************************************/ - -int convert_to_gtk_container(PyObject *arg, void *dst) -{ - int result; /* Bilan à retourner */ - PyObject *gtk_mod; /* Module Python Gtk */ - PyObject *container_type; /* Module "GtkContainer" */ - int ret; /* Bilan d'une conversion */ - - result = 0; - - gtk_mod = PyImport_ImportModule("gi.repository.Gtk"); - - if (gtk_mod == NULL) - { - PyErr_SetString(PyExc_TypeError, "unable to find the Gtk Python module"); - goto done; - } - - container_type = PyObject_GetAttrString(gtk_mod, "Container"); - - Py_DECREF(gtk_mod); - - ret = PyObject_TypeCheck(arg, (PyTypeObject *)container_type); - - Py_DECREF(container_type); - - if (!ret) - { - PyErr_SetString(PyExc_TypeError, "unable to convert the provided argument to GTK container"); - goto done; - } - - *((GtkContainer **)dst) = GTK_CONTAINER(pygobject_get(arg)); - - result = 1; - - done: - - return result; - -} - - -#endif - - /****************************************************************************** * * * Paramètres : color = couleur dans sa définition native à copier. * diff --git a/plugins/pychrysalide/helpers.h b/plugins/pychrysalide/helpers.h index 745d013..f1c6337 100644 --- a/plugins/pychrysalide/helpers.h +++ b/plugins/pychrysalide/helpers.h @@ -2,7 +2,7 @@ /* Chrysalide - Outil d'analyse de fichiers binaires * helpers.h - prototypes pour la simplification des interactions de base avec Python * - * Copyright (C) 2018-2024 Cyrille Bagard + * Copyright (C) 2018-2025 Cyrille Bagard * * This file is part of Chrysalide. * @@ -313,17 +313,6 @@ int convert_to_gobject(PyObject *, void *); #if 0 -#ifdef INCLUDE_GTK_SUPPORT - -/* Tente de convertir en instance de composant GTK. */ -int convert_to_gtk_widget(PyObject *, void *); - -/* Tente de convertir en instance de conteneur GTK. */ -int convert_to_gtk_container(PyObject *, void *); - -#endif - - #if !defined(INCLUDE_GTK_SUPPORT) && !defined(HOMEMADE_RGBA) # define HOMEMADE_RGBA diff --git a/src/Makefile.am b/src/Makefile.am index 5c4d1e3..7411287 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -59,7 +59,7 @@ libchrysacore_la_LDFLAGS = \ -avoid-version -ldl -lm \ $(TOOLKIT_LIBS) $(LIBXML_LIBS) \ $(LIBSQLITE_LIBS) $(LIBARCHIVE_LIBS) \ - $(LIBSSL_LIBS) $(LIBHS_LIBS) + $(LIBSSL_LIBS) if BUILD_CURL_SUPPORT @@ -73,6 +73,12 @@ libchrysacore_la_LDFLAGS += $(LIBMAGIC_LIBS) endif +if BUILD_HS_SUPPORT + +libchrysacore_la_LDFLAGS += $(LIBHS_LIBS) + +endif + libchrysacore4_la_SOURCES = @@ -103,13 +109,14 @@ libchrysacoreui_la_SOURCES = libchrysacoreui_la_LIBADD = \ arch/libarchui.la \ + data/images/libdataimages.la \ glibext/libglibextui.la \ gtkext/libgtkext4.la \ gui/libgui4.la # -lm: log() libchrysacoreui_la_LDFLAGS = \ - $(LIBGTK4_CFLAGS) -L.libs -lchrysacore4 \ + $(LIBGTK4_LIBS) -L.libs -lchrysacore4 \ -lm @@ -189,4 +196,4 @@ rost_LDFLAGS = $(LIBGOBJ_LIBS) -L.libs -lchrysacore #SUBDIRS = core glibext $(GTKEXT_SUBDIR) analysis arch format common debug $(GUI_SUBDIR) mangling plugins schemas -SUBDIRS = analysis arch common core format glibext gtkext gui plugins +SUBDIRS = analysis arch common core data format glibext gtkext gui plugins schemas diff --git a/src/analysis/scan/patterns/backends/Makefile.am b/src/analysis/scan/patterns/backends/Makefile.am index 23b0163..84711a7 100644 --- a/src/analysis/scan/patterns/backends/Makefile.am +++ b/src/analysis/scan/patterns/backends/Makefile.am @@ -6,10 +6,16 @@ libanalysisscanpatternsbackends_la_SOURCES = \ acism-int.h \ acism.h acism.c \ bitap-int.h \ - bitap.h bitap.c \ + bitap.h bitap.c + +if BUILD_HS_SUPPORT + +libanalysisscanpatternsbackends_la_SOURCES += \ hyperscan-int.h \ hyperscan.h hyperscan.c +endif + # Cf. https://www.gnu.org/software/automake/manual/html_node/Per_002dObject-Flags.html AM_CFLAGS = $(LIBGOBJ_CFLAGS) $(LIBHS_CFLAGS) @@ -399,7 +399,7 @@ static void ensure_wm_icon_and_name(void) filename = get_xdg_data_dir("icons/hicolor/scalable/apps/chrysalide-logo.svg", true); - fd = open(filename, O_WRONLY | O_CREAT); + fd = open(filename, O_WRONLY | O_CREAT, S_IRUSR | S_IWUSR); if (fd == -1) LOG_ERROR_N("open"); @@ -505,6 +505,32 @@ int main(int argc, char **argv) set_log_verbosity(verbosity); + /** + * Même s'il est dit que l'usage de GtkApplication permet de s'affranchir + * d'un appel à gtk_init(), il se trouve que la journalisation en mode + * graphique peut solliciter le panneau en GTK pour afficher des messages + * avant la mise en place de l'applicatif GTK principal : + * + * #2 0x00007ffff7b33403 in gtk_css_lookup_resolve (lookup=lookup@entry=0x7fffffff88a0, provider=provider@entry=0x0, sstyle=sstyle@entry=0x7fffe800a730, parent_style=parent_style@entry=0x0) at ../gtk/gtkcssstaticstyle.c:911 + * #3 0x00007ffff7b3389f in gtk_css_static_style_new_compute (provider=0x0, filter=filter@entry=0x7fffffff8ea0, node=node@entry=0x0, change=<optimized out>, change@entry=0) at ../gtk/gtkcssstaticstyle.c:1026 + * #4 0x00007ffff7b3392c in gtk_css_static_style_get_default () at ../gtk/gtkcssstaticstyle.c:711 + * #5 0x00007ffff7b24b09 in gtk_css_node_init (cssnode=0x7fffe800a5b0) at ../gtk/gtkcssnode.c:641 + * #6 0x00007ffff75d8dab in g_type_create_instance () at /lib/x86_64-linux-gnu/libgobject-2.0.so.0 + * [...] + * #10 0x00007ffff7b3b8fa in gtk_css_widget_node_new (widget=widget@entry=0x5555555bf1b0) at ../gtk/gtkcsswidgetnode.c:160 + * #11 0x00007ffff7ae4576 in gtk_widget_init (instance=<optimized out>, g_class=0x5555555be380) at ../gtk/gtkwidget.c:2345 + * [...] + * #16 0x00007ffff73fd3f4 in get_framework_panel_singleton (...) at panels.c:329 + * #17 0x00007ffff73fce35 in do_log_message_alt (...) at logs.c:56 + * [...] + * #23 0x00007ffff74566db in init_all_plugins (load=true) at pglist.c:103 + * #24 0x0000555555556d44 in main (argc=2, argv=0x7fffffffb568) at app.c:514 + * + * L'initialisation permettant un retour de gtk_settings_get_default() non + * nul est ainsi forcée au plus tôt avec un appel à gtk_init() manuel. + */ + gtk_init(); + if (!load_core_components(ACC_GLOBAL_VARS)) goto exit; diff --git a/src/arch/Makefile.am b/src/arch/Makefile.am index 127ca4c..6683854 100644 --- a/src/arch/Makefile.am +++ b/src/arch/Makefile.am @@ -13,18 +13,17 @@ noinst_LTLIBRARIES = libarch.la libarchui.la # 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 = \ + instruction-int.h \ + instruction.h instruction.c \ operand-int.h \ operand.h operand.c \ register-int.h \ @@ -34,10 +33,13 @@ libarch_la_SOURCES = \ libarch_la_CFLAGS = $(LIBGOBJ_CFLAGS) libarch_la_LIBADD = \ + instructions/libarchinstructions.la \ operands/libarchoperands.la libarchui_la_SOURCES = \ + instruction-ui-int.h \ + instruction-ui.h instruction-ui.c \ operand-ui-int.h \ operand-ui.h operand-ui.c @@ -52,5 +54,4 @@ devdir = $(includedir)/chrysalide/$(subdir:src/%=core/%) dev_HEADERS = $(libarch_la_SOURCES:%c=) $(libarchui_la_SOURCES:%c=) -#SUBDIRS = instructions operands -SUBDIRS = operands +SUBDIRS = instructions operands diff --git a/src/arch/instruction-int.h b/src/arch/instruction-int.h index 7dbbe27..d426cea 100644 --- a/src/arch/instruction-int.h +++ b/src/arch/instruction-int.h @@ -2,7 +2,7 @@ /* Chrysalide - Outil d'analyse de fichiers binaires * instruction-int.h - prototypes pour la définition générique interne des instructions * - * Copyright (C) 2008-2020 Cyrille Bagard + * Copyright (C) 2008-2025 Cyrille Bagard * * This file is part of Chrysalide. * @@ -25,18 +25,29 @@ #define _ARCH_INSTRUCTION_INT_H +#include <stdint.h> + + #include "instruction.h" -#include "../analysis/storage/storage.h" #include "../common/array.h" -#include "../glibext/objhole.h" +#include "../glibext/objhole-int.h" /* Indique l'encodage d'une instruction de façon détaillée. */ -typedef const char * (* get_instruction_encoding_fc) (const GArchInstruction *); +typedef char * (* get_instruction_encoding_fc) (const GArchInstruction *); /* Fournit le nom humain de l'instruction manipulée. */ -typedef const char * (* get_instruction_keyword_fc) (GArchInstruction * ); +typedef char * (* get_instruction_keyword_fc) (const GArchInstruction *); + + + +#if 0 + +#include "../analysis/storage/storage.h" + + + /* Complète un désassemblage accompli pour une instruction. */ typedef void (* call_instruction_hook_fc) (GArchInstruction *, InstrProcessHook, GArchProcessor *, GProcContext *, GExeFormat *); @@ -67,80 +78,45 @@ typedef bool (* store_instruction_fc) (GArchInstruction *, GObjectStorage *, pac -/* Informations glissées dans la structure GObject de GArchOperand */ -typedef struct _instr_extra_data_t -{ - itid_t uid; /* Identifiant unique du type */ - - ArchInstrFlag flags; /* Informations complémentaires*/ - -} instr_extra_data_t; +#endif -/* Informations glissées dans la structure GObject de GArchInstruction */ -typedef union _instr_obj_extra_t -{ - instr_extra_data_t data; /* Données embarquées */ - lockable_obj_extra_t lockable; /* Gestion d'accès aux fanions */ -} instr_obj_extra_t; +/* Conservation d'une adresse et de propriétées */ +typedef unsigned long compact_ins_link_t; /* Définition générique d'une instruction d'architecture (instance) */ struct _GArchInstruction { - GObject parent; /* A laisser en premier */ + GThickObject parent; /* A laisser en premier */ -#if 1 //__SIZEOF_INT__ == __SIZEOF_LONG__ + GBinaryPortion *rel_area; /* Zone de référence */ + rel_mrange_t rel_range; /* Emplacement compressé */ /** - * L'inclusion des informations suivantes dépend de l'architecture. - * - * Si la structure GObject possède un trou, on remplit de préférence - * ce dernier. + * A laisser à la suite de la localisation précédente pour éviter + * les espaces vide dans la structure. */ + uint16_t link_count; /* Quantité de liens établis */ - instr_obj_extra_t extra; /* Externalisation embarquée */ - -#endif - - mrange_t range; /* Emplacement en mémoire */ + compact_ins_link_t *links; /* Liste de ces liens */ flat_array_t *operands; /* Liste des opérandes */ - /** - * Il existe le besoin indéniable d'un verrou pour les accès aux instructions - * liées. Il faut par ailleurs un verrou distinct pour les sources et les - * destinations car une même instruction peut boucler sur elle même et la - * fonction g_arch_instruction_change_link() pose des verrous sur les - * deux extrémités. - * - * La GLib propose les fonctions g_bit_lock() / g_bit_unlock(), légères mais - * sans distinction entre lectures et écritures. Tant pis : la réduction de - * l'empreinte mémoire prime ! - * - * Par contre la documentation indique : - * - * """ - * Attempting to lock on two different bits within the same integer is not supported. - * """ - * - * Donc on doit bien conserver un compteur distinct pour chaque extrémité. - * Cela correspond de toute façon à la définition optimisée des tableaux - * suivante. - */ - - flat_array_t *from; /* Origines des références */ - flat_array_t *to; /* Instructions visées */ - }; /* Définition générique d'une instruction d'architecture (classe) */ struct _GArchInstructionClass { - GObjectClass parent; /* A laisser en premier */ + GThickObjectClass parent; /* A laisser en premier */ get_instruction_encoding_fc get_encoding; /* Obtention de l'encodage */ get_instruction_keyword_fc get_keyword; /* Texte humain équivalent */ + +#if 0 + + //get_instruction_encoding_fc get_encoding; /* Obtention de l'encodage */ + //get_instruction_keyword_fc get_keyword; /* Texte humain équivalent */ call_instruction_hook_fc call_hook; /* Décrochages éventuels */ build_instruction_tooltip_fc build_tooltip; /* Construction d'une bulle*/ get_instruction_desc_fc get_desc; /* Description assez complète */ @@ -155,22 +131,50 @@ struct _GArchInstructionClass //get_instruction_rw_regs_fc get_rw_regs; /* Liste des registres liés */ +#endif + }; +/* Met en place une instruction d'architecture. */ +bool g_arch_instruction_create(GArchInstruction *, itid_t); + + + /** * Accès aux informations éventuellement déportées. */ -#if 1 //__SIZEOF_INT__ == __SIZEOF_LONG__ -# define GET_ARCH_INSTR_EXTRA(ins) (instr_extra_data_t *)&ins->extra +#define ARCH_INSTRUCTION_EXTRA_DATA \ + \ + unsigned int reserved : GOBJECT_RESERVED_EXTRA_BITS; \ + \ + /** \ + * itid_t \ + */ \ + unsigned int tid : 16; \ + \ + /** \ + * ArchOperandFlag \ + */ \ + unsigned int flags : 8; -#else -# define GET_ARCH_INSTR_EXTRA(ins) GET_GOBJECT_EXTRA(G_OBJECT(ins), instr_extra_data_t) +/* Informations glissées dans la structure GObject de GArchOperand */ +typedef struct _instruction_extra_data_t +{ + ARCH_INSTRUCTION_EXTRA_DATA; /* Socle commun */ + +} instruction_extra_data_t; + + +#define GET_ARCH_INSTR_EXTRA(op) \ + GET_GOBJECT_EXTRA(op, instruction_extra_data_t) + +#define SET_ARCH_INSTR_EXTRA(op, data) \ + SET_GOBJECT_EXTRA(op, instruction_extra_data_t, data) -#endif /** diff --git a/src/arch/instruction-ui-int.h b/src/arch/instruction-ui-int.h new file mode 100644 index 0000000..b07f40c --- /dev/null +++ b/src/arch/instruction-ui-int.h @@ -0,0 +1,55 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * instruction-ui-int.h - prototypes pour la définition générique interne des instructions sous forme graphique + * + * Copyright (C) 2025 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Chrysalide. If not, see <http://www.gnu.org/licenses/>. + */ + + +#ifndef _ARCH_INSTRUCTION_UI_INT_H +#define _ARCH_INSTRUCTION_UI_INT_H + + +#include "instruction-ui.h" + + + +#if 0 + +/* Traduit un opérande en version humainement lisible. */ +typedef void (* print_operand_ui_fc) (const GArchOperandUI *, GBufferLine *); + +/* Construit un petit résumé concis de l'opérande. */ +typedef char * (* build_operand_ui_tooltip_fc) (const GArchOperandUI *, const GLoadedBinary *); + + + +/* Définition générique d'un opérande d'architecture (interface) */ +struct _GArchOperandUIInterface +{ + GTypeInterface base_iface; /* A laisser en premier */ + + print_operand_ui_fc print; /* Texte humain équivalent */ + build_operand_ui_tooltip_fc build_tooltip; /* Définition de description*/ + +}; + +#endif + + +#endif /* _ARCH_INSTRUCTION_UI_INT_H */ diff --git a/src/arch/instruction-ui.c b/src/arch/instruction-ui.c new file mode 100644 index 0000000..7f923d8 --- /dev/null +++ b/src/arch/instruction-ui.c @@ -0,0 +1,254 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * instruction-ui.c - gestion générique des instructions sous forme graphique + * + * Copyright (C) 2025 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Chrysalide. If not, see <http://www.gnu.org/licenses/>. + */ + + +#include "instruction-ui.h" + + +#include "instruction-int.h" +#include "operand-ui.h" +#include "../analysis/content.h" +#include "../common/cpp.h" +#include "../glibext/generator-int.h" +#include "../glibext/options/asm.h" + + + +/* ------------------------ OFFRE DE CAPACITES DE GENERATION ------------------------ */ + + +/* Renseigne sur les propriétés liées à un générateur. */ +static BufferLineFlags g_arch_instruction_ui_get_flags(const GTokenGenerator *, size_t, size_t); + +/* Etablit dans une ligne de rendu le contenu représenté. */ +static void g_arch_instruction_ui_populate_line(const GTokenGenerator *, size_t, size_t, GBufferLine *, void *); + +#if 0 + +/* Retrouve l'emplacement correspondant à une position donnée. */ +static void g_arch_instruction_ui_compute_cursor(const GArchInstruction *, gint, size_t, size_t, GLineCursor **); + +/* Détermine si le conteneur s'inscrit dans une plage donnée. */ +static int g_arch_instruction_ui_contain_cursor(const GArchInstruction *, size_t, size_t, const GLineCursor *); + +#endif + + + +/* ---------------------------------------------------------------------------------- */ +/* OFFRE DE CAPACITES DE GENERATION */ +/* ---------------------------------------------------------------------------------- */ + + +/****************************************************************************** +* * +* Paramètres : iface = interface GLib à initialiser. * +* * +* Description : Procède à l'initialisation de l'interface de génération. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +void g_arch_instruction_ui_token_generator_iface_init(GTokenGeneratorInterface *iface) +{ + /** + * La procédure par défaut de iface->count() ne doit pas être retouchée ! + */ + + iface->get_flags = g_arch_instruction_ui_get_flags; + iface->populate = g_arch_instruction_ui_populate_line; + +#if 0 + iface->compute = (linegen_compute_fc)g_arch_instruction_ui_compute_cursor; + iface->contain = (linegen_contain_fc)g_arch_instruction_ui_contain_cursor; +#endif + +} + + +/****************************************************************************** +* * +* Paramètres : generator = générateur à consulter. * +* index = indice de cette même ligne dans le tampon global.* +* repeat = indice d'utilisations successives du générateur. * +* * +* Description : Renseigne sur les propriétés liées à un générateur. * +* * +* Retour : Propriétés particulières associées. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static BufferLineFlags g_arch_instruction_ui_get_flags(const GTokenGenerator *generator, size_t index, size_t repeat) +{ + BufferLineFlags result; /* Fanions à retourner */ + + result = BLF_HAS_CODE; + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : generator = générateur à utiliser pour l'impression. * +* index = indice de cette même ligne dans le tampon global.* +* repeat = indice d'utilisations successives du générateur. * +* line = ligne de rendu à compléter. * +* data = éventuelle donnée complémentaire fournie. * +* * +* Description : Etablit dans une ligne de rendu le contenu représenté. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_arch_instruction_ui_populate_line(const GTokenGenerator *generator, size_t index, size_t repeat, GBufferLine *line, void *data) +{ + GArchInstruction *instr; /* Version spécialisée */ + GBinContent *content; /* Contenu brut d'origine */ + mrange_t range; /* Emplacement couvert */ + char *key; /* Mot clef principal */ + size_t count; /* Nombre d'opérandes en place */ + size_t i; /* Boucle de parcours */ + GArchOperand *op; /* Opérande à manipuler */ + + instr = G_ARCH_INSTRUCTION(generator); + content = G_BIN_CONTENT(data); + + /* Prologue */ + + if (g_arch_instruction_get_range(instr, &range)) + { + g_buffer_line_fill_physical(line, ACO_PHYSICAL, MDS_32_BITS_UNSIGNED, get_mrange_addr(&range)); + + g_buffer_line_fill_virtual(line, ACO_VIRTUAL, MDS_32_BITS_UNSIGNED, get_mrange_addr(&range)); + + g_buffer_line_fill_content(line, ACO_BINARY, content, &range, VMPA_NO_PHYSICAL); + + } + + /* Instruction proprement dite */ + + key = g_arch_instruction_get_keyword(instr); + + g_buffer_line_append_text(line, ACO_ASSEMBLY_HEAD, TRT_INSTRUCTION, SL(key), NULL, G_OBJECT(instr)); + + free(key); + + /* Liste des opérandes */ + + g_thick_object_lock(G_THICK_OBJECT(instr)); + + count = g_arch_instruction_count_operands(instr); + + if (count > 0) + { + op = g_arch_instruction_get_operand(instr, 0); + g_arch_operand_ui_print(G_ARCH_OPERAND_UI(op), line); + unref_object(op); + + for (i = 1; i < count; i++) + { + g_buffer_line_append_text(line, ACO_ASSEMBLY, TRT_PUNCT, STCSL(","), NULL, NULL); + g_buffer_line_append_text(line, ACO_ASSEMBLY, TRT_NONE, STCSL(" "), NULL, NULL); + + op = g_arch_instruction_get_operand(instr, i); + g_arch_operand_ui_print(G_ARCH_OPERAND_UI(op), line); + unref_object(op); + + } + + } + + g_thick_object_unlock(G_THICK_OBJECT(instr)); + +} + + +#if 0 + + +/****************************************************************************** +* * +* Paramètres : instr = générateur à consulter. * +* x = position géographique sur la ligne concernée. * +* index = indice de cette même ligne dans le tampon global. * +* repeat = indice d'utilisations successives du générateur. * +* cursor = emplacement à constituer. [OUT] * +* * +* Description : Retrouve l'emplacement correspondant à une position donnée. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_arch_instruction_ui_compute_cursor(const GArchInstruction *instr, gint x, size_t index, size_t repeat, GLineCursor **cursor) +{ + *cursor = g_binary_cursor_new(); + + g_binary_cursor_update(G_BINARY_CURSOR(*cursor), get_mrange_addr(&instr->range)); + +} + + +/****************************************************************************** +* * +* Paramètres : instr = générateur à consulter. * +* index = indice de cette même ligne dans le tampon global. * +* repeat = indice d'utilisations successives du générateur. * +* cursor = emplacement à analyser. * +* * +* Description : Détermine si le conteneur s'inscrit dans une plage donnée. * +* * +* Retour : Bilan de la détermination, utilisable en comparaisons. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static int g_arch_instruction_ui_contain_cursor(const GArchInstruction *instr, size_t index, size_t repeat, const GLineCursor *cursor) +{ + int result; /* Conclusion à retourner */ + vmpa2t addr; /* Autre emplacement à comparer*/ + + assert(G_IS_BINARY_CURSOR(cursor)); + + g_binary_cursor_retrieve(G_BINARY_CURSOR(cursor), &addr); + + result = cmp_mrange_with_vmpa(&instr->range, &addr); + + return result; + +} + + +#endif diff --git a/src/arch/instruction-ui.h b/src/arch/instruction-ui.h new file mode 100644 index 0000000..62a52f2 --- /dev/null +++ b/src/arch/instruction-ui.h @@ -0,0 +1,41 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * instruction-ui.h - prototypes pour la gestion générique des instructions sous forme graphique + * + * Copyright (C) 2025 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Chrysalide. If not, see <http://www.gnu.org/licenses/>. + */ + + +#ifndef _ARCH_INSTRUCTION_UI_H +#define _ARCH_INSTRUCTION_UI_H + + +#include "../glibext/generator.h" +#include "../glibext/helpers.h" + + + +/* ------------------------ OFFRE DE CAPACITES DE GENERATION ------------------------ */ + + +/* Procède à l'initialisation de l'interface de génération. */ +void g_arch_instruction_ui_token_generator_iface_init(GTokenGeneratorInterface *); + + + +#endif /* _ARCH_INSTRUCTION_UI_H */ diff --git a/src/arch/instruction.c b/src/arch/instruction.c index cd1e9c7..36bdecb 100644 --- a/src/arch/instruction.c +++ b/src/arch/instruction.c @@ -2,7 +2,7 @@ /* Chrysalide - Outil d'analyse de fichiers binaires * instruction.c - gestion générique des instructions * - * Copyright (C) 2008-2020 Cyrille Bagard + * Copyright (C) 2008-2025 Cyrille Bagard * * This file is part of Chrysalide. * @@ -26,102 +26,93 @@ #include <assert.h> #include <malloc.h> -#include <stdarg.h> -#include <stdio.h> -#include <stdlib.h> +#include <limits.h> #include <string.h> #include "instruction-int.h" -#include "storage.h" -#include "../analysis/storage/serialize-int.h" -#include "../core/columns.h" +#include "../common/leb128.h" #include "../core/logs.h" #include "../core/processors.h" -#include "../glibext/gbinarycursor.h" -#include "../glibext/linegen-int.h" +#include "../glibext/serialize-int.h" -/* Initialise la classe générique des instructions. */ -static void g_arch_instruction_class_init(GArchInstructionClass *); - -/* Initialise une instance d'opérande d'architecture. */ -static void g_arch_instruction_init(GArchInstruction *); -/* Procède à l'initialisation de l'interface de génération. */ -static void g_arch_instruction_generator_init(GLineGeneratorInterface *); -/* Procède à l'initialisation de l'interface de sérialisation. */ -static void g_arch_instruction_serializable_init(GSerializableObjectInterface *); - -/* Supprime toutes les références externes. */ -static void g_arch_instruction_dispose(GArchInstruction *); - -/* Procède à la libération totale de la mémoire. */ -static void g_arch_instruction_finalize(GArchInstruction *); +/* ----------------------- DEFINITION GENERIQUE D'INSTRUCTION ----------------------- */ +/* Initialise la classe générique des instructions. */ +static void g_arch_instruction_class_init(GArchInstructionClass *); +/* Procède à l'initialisation de l'interface de sérialisation. */ +static void g_arch_instruction_serializable_object_iface_init(GSerializableObjectInterface *); -/* Charge un contenu depuis une mémoire tampon. */ -static bool g_arch_instruction_load_destinations(GArchInstruction *, GObjectStorage *, packed_buffer_t *); +/* Initialise une instance d'opérande d'architecture. */ +static void g_arch_instruction_init(GArchInstruction *); -/* Sauvegarde toutes les destinations d'une instruction. */ -bool g_arch_instruction_store_destinations(GArchInstruction *, GObjectStorage *, packed_buffer_t *); +/* Supprime toutes les références externes. */ +static void g_arch_instruction_dispose(GObject *); +/* Procède à la libération totale de la mémoire. */ +static void g_arch_instruction_finalize(GObject *); +/* ------------------- DEFINITION DES LIAISONS ENTRE INSTRUCTIONS ------------------- */ -/* ------------------------ OFFRE DE CAPACITES DE GENERATION ------------------------ */ +#define COMPACT_INS_LINK_MASK_DIR (1ul << (__WORDSIZE - 1)) +#define COMPACT_INS_LINK_MASK_TYPE 0xf +#define COMPACT_INS_LINK_MASK (COMPACT_INS_LINK_MASK_DIR | COMPACT_INS_LINK_MASK_TYPE) -/* Indique le nombre de ligne prêtes à être générées. */ -static size_t g_arch_instruction_count_lines(const GArchInstruction *); +#define COMPACT_INS_LINK_FROM (0ul << (__WORDSIZE - 1)) +#define COMPACT_INS_LINK_TO (1ul << (__WORDSIZE - 1)) -#ifdef INCLUDE_GTK_SUPPORT +#define COMPACT_INS_LINK_DIR(cl) (cl & COMPACT_INS_LINK_MASK_DIR) +#define COMPACT_INS_LINK_PTR(cl) ((GArchInstruction *)(cl & ~COMPACT_INS_LINK_MASK)) +#define COMPACT_INS_LINK_TYPE(cl) (cl & COMPACT_INS_LINK_MASK_TYPE) -/* Retrouve l'emplacement correspondant à une position donnée. */ -static void g_arch_instruction_compute_cursor(const GArchInstruction *, gint, size_t, size_t, GLineCursor **); +#define MAKE_COMPACT_INS_LINK(d, i, t) \ + (compact_ins_link_t)(d | (unsigned long)i | t) -/* Détermine si le conteneur s'inscrit dans une plage donnée. */ -static int g_arch_instruction_contain_cursor(const GArchInstruction *, size_t, size_t, const GLineCursor *); +/* Détermine si un type de lien existe dans une instruction. */ +static bool _g_arch_instruction_has_link(const GArchInstruction *, compact_ins_link_t, InstructionLinkType); -#endif +/* Détermine si un lien existe entre deux instructions. */ +static bool _g_arch_instruction_has_link_with(const GArchInstruction *, compact_ins_link_t, const GArchInstruction *); -/* Renseigne sur les propriétés liées à un générateur. */ -static BufferLineFlags g_arch_instruction_get_flags2(const GArchInstruction *, size_t, size_t); +/* Fournit la quantité d'instructions pointant vers une autre. */ +static size_t _g_arch_instruction_count_links(const GArchInstruction *, compact_ins_link_t); -/* Ajoute à un tampon GLib le contenu de l'instance spécifiée. */ -static void _g_arch_instruction_print(GArchInstruction *, GBufferLine *, size_t, size_t, const GBinContent *); +/* Fournit les détails d'un lien donné avec une instruction. */ +static GArchInstruction *_g_arch_instruction_get_linked_instruction(const GArchInstruction *, size_t, compact_ins_link_t, InstructionLinkType *); -/* Imprime dans une ligne de rendu le contenu représenté. */ -static void g_arch_instruction_print(GArchInstruction *, GBufferLine *, size_t, size_t, const GBinContent *); -/* -------------------- CONSERVATION ET RECHARGEMENT DES DONNEES -------------------- */ +/* ------------------- MECANISMES DE CONSERVATION ET RESTAURATION ------------------- */ -/* Charge un contenu depuis une mémoire tampon. */ -static bool _g_arch_instruction_load(GArchInstruction *, GObjectStorage *, packed_buffer_t *); +/* Charge un objet depuis un flux de données. */ +static bool g_arch_instruction_load(GSerializableObject *, GObjectStorage *, int); -/* Charge un contenu depuis une mémoire tampon. */ -static bool g_arch_instruction_load(GArchInstruction *, GObjectStorage *, packed_buffer_t *); +/* Sauvegarde un objet dans un flux de données. */ +static bool g_arch_instruction_store(const GSerializableObject *, GObjectStorage *, int); -/* Sauvegarde un contenu dans une mémoire tampon. */ -static bool _g_arch_instruction_store(GArchInstruction *, GObjectStorage *, packed_buffer_t *); -/* Sauvegarde un contenu dans une mémoire tampon. */ -static bool g_arch_instruction_store(GArchInstruction *, GObjectStorage *, packed_buffer_t *); +/* ---------------------------------------------------------------------------------- */ +/* DEFINITION GENERIQUE D'INSTRUCTION */ +/* ---------------------------------------------------------------------------------- */ /* Indique le type défini pour une instruction d'architecture. */ -G_DEFINE_TYPE_WITH_CODE(GArchInstruction, g_arch_instruction, G_TYPE_OBJECT, - G_IMPLEMENT_INTERFACE(G_TYPE_LINE_GENERATOR, g_arch_instruction_generator_init) - G_IMPLEMENT_INTERFACE(G_TYPE_SERIALIZABLE_OBJECT, g_arch_instruction_serializable_init)); +G_DEFINE_TYPE_WITH_CODE(GArchInstruction, g_arch_instruction, G_TYPE_THICK_OBJECT, + G_IMPLEMENT_INTERFACE(G_TYPE_SERIALIZABLE_OBJECT, g_arch_instruction_serializable_object_iface_init) + G_IMPLEMENT_INTERFACE_IF_SYM(g_token_generator_get_type, g_arch_instruction_ui_token_generator_iface_init)); + /****************************************************************************** @@ -139,28 +130,20 @@ G_DEFINE_TYPE_WITH_CODE(GArchInstruction, g_arch_instruction, G_TYPE_OBJECT, static void g_arch_instruction_class_init(GArchInstructionClass *klass) { GObjectClass *object; /* Autre version de la classe */ - GArchInstructionClass *instr; /* Encore une autre vision... */ object = G_OBJECT_CLASS(klass); - object->dispose = (GObjectFinalizeFunc/* ! */)g_arch_instruction_dispose; - object->finalize = (GObjectFinalizeFunc)g_arch_instruction_finalize; - - instr = G_ARCH_INSTRUCTION_CLASS(klass); - - instr->print = (print_instruction_fc)_g_arch_instruction_print; - - instr->load = (load_instruction_fc)_g_arch_instruction_load; - instr->store = (store_instruction_fc)_g_arch_instruction_store; + object->dispose = g_arch_instruction_dispose; + object->finalize = g_arch_instruction_finalize; } /****************************************************************************** * * -* Paramètres : instr = instance à initialiser. * +* Paramètres : iface = interface GLib à initialiser. * * * -* Description : Initialise une instance d'instruction d'architecture. * +* Description : Procède à l'initialisation de l'interface de sérialisation. * * * * Retour : - * * * @@ -168,27 +151,19 @@ static void g_arch_instruction_class_init(GArchInstructionClass *klass) * * ******************************************************************************/ -static void g_arch_instruction_init(GArchInstruction *instr) +static void g_arch_instruction_serializable_object_iface_init(GSerializableObjectInterface *iface) { - instr_extra_data_t *extra; /* Données insérées à modifier */ - - extra = GET_ARCH_INSTR_EXTRA(instr); - - INIT_GOBJECT_EXTRA_LOCK(extra); - - instr->operands = NULL; - - instr->from = NULL; - instr->to = NULL; + iface->load = g_arch_instruction_load; + iface->store = g_arch_instruction_store; } /****************************************************************************** * * -* Paramètres : iface = interface GLib à initialiser. * +* Paramètres : instr = instance à initialiser. * * * -* Description : Procède à l'initialisation de l'interface de génération. * +* Description : Initialise une instance d'instruction d'architecture. * * * * Retour : - * * * @@ -196,42 +171,22 @@ static void g_arch_instruction_init(GArchInstruction *instr) * * ******************************************************************************/ -static void g_arch_instruction_generator_init(GLineGeneratorInterface *iface) +static void g_arch_instruction_init(GArchInstruction *instr) { - iface->count = (linegen_count_lines_fc)g_arch_instruction_count_lines; -#ifdef INCLUDE_GTK_SUPPORT - iface->compute = (linegen_compute_fc)g_arch_instruction_compute_cursor; - iface->contain = (linegen_contain_fc)g_arch_instruction_contain_cursor; -#endif - iface->get_flags = (linegen_get_flags_fc)g_arch_instruction_get_flags2; - iface->print = (linegen_print_fc)g_arch_instruction_print; - -} + instr->rel_area = NULL; + instr->link_count = 0; -/****************************************************************************** -* * -* Paramètres : iface = interface GLib à initialiser. * -* * -* Description : Procède à l'initialisation de l'interface de sérialisation. * -* * -* Retour : - * -* * -* Remarques : - * -* * -******************************************************************************/ + instr->links = NULL; -static void g_arch_instruction_serializable_init(GSerializableObjectInterface *iface) -{ - iface->load = (load_serializable_object_cb)g_arch_instruction_load; - iface->store = (store_serializable_object_cb)g_arch_instruction_store; + instr->operands = NULL; } /****************************************************************************** * * -* Paramètres : instr = instance d'objet GLib à traiter. * +* Paramètres : object = instance d'objet GLib à traiter. * * * * Description : Supprime toutes les références externes. * * * @@ -241,43 +196,38 @@ static void g_arch_instruction_serializable_init(GSerializableObjectInterface *i * * ******************************************************************************/ -static void g_arch_instruction_dispose(GArchInstruction *instr) +static void g_arch_instruction_dispose(GObject *object) { + GArchInstruction *instr; /* Version spécialisée */ size_t count; /* Nombre d'opérandes en place */ size_t i; /* Boucle de parcours */ GArchOperand *op; /* Opérande à manipuler */ - g_arch_instruction_lock_operands(instr); + instr = G_ARCH_INSTRUCTION(object); + + g_clear_object(&instr->rel_area); + + g_arch_instruction_delete_all_links(instr); - count = _g_arch_instruction_count_operands(instr); + g_thick_object_lock(G_THICK_OBJECT(instr)); + + count = g_arch_instruction_count_operands(instr); for (i = 0; i < count; i++) { - op = _g_arch_instruction_get_operand(instr, 0); + op = g_arch_instruction_get_operand(instr, 0); rem_item_from_flat_array(&instr->operands, 0, sizeof(GArchOperand *)); /** * Une fois pour l'obtention, une autre pour la libération ! */ - g_object_unref(G_OBJECT(op)); - g_object_unref(G_OBJECT(op)); + unref_object(op); + unref_object(op); } - g_arch_instruction_unlock_operands(instr); - -#ifndef NDEBUG - g_arch_instruction_lock_src(instr); - assert(count_flat_array_items(instr->from) == 0); - g_arch_instruction_unlock_src(instr); -#endif - -#ifndef NDEBUG - g_arch_instruction_lock_dest(instr); - assert(count_flat_array_items(instr->to) == 0); - g_arch_instruction_unlock_dest(instr); -#endif + g_thick_object_unlock(G_THICK_OBJECT(instr)); G_OBJECT_CLASS(g_arch_instruction_parent_class)->dispose(G_OBJECT(instr)); @@ -286,7 +236,7 @@ static void g_arch_instruction_dispose(GArchInstruction *instr) /****************************************************************************** * * -* Paramètres : instr = instance d'objet GLib à traiter. * +* Paramètres : object = instance d'objet GLib à traiter. * * * * Description : Procède à la libération totale de la mémoire. * * * @@ -296,38 +246,26 @@ static void g_arch_instruction_dispose(GArchInstruction *instr) * * ******************************************************************************/ -static void g_arch_instruction_finalize(GArchInstruction *instr) +static void g_arch_instruction_finalize(GObject *object) { - G_OBJECT_CLASS(g_arch_instruction_parent_class)->finalize(G_OBJECT(instr)); + GArchInstruction *instr; /* Version spécialisée */ -} + instr = G_ARCH_INSTRUCTION(object); + if (instr->links != NULL) + free(instr->links); -/****************************************************************************** -* * -* Paramètres : instr = instruction quelconque à consulter. * -* * -* Description : Indique l'encodage d'une instruction de façon détaillée. * -* * -* Retour : Description humaine de l'encodage utilisé. * -* * -* Remarques : - * -* * -******************************************************************************/ - -const char *g_arch_instruction_get_encoding(const GArchInstruction *instr) -{ - return G_ARCH_INSTRUCTION_GET_CLASS(instr)->get_encoding(instr); + G_OBJECT_CLASS(g_arch_instruction_parent_class)->finalize(G_OBJECT(instr)); } /****************************************************************************** * * -* Paramètres : instr = instruction quelconque à modifier. * -* flag = drapeau d'information complémentaire à planter. * +* Paramètres : instr = instance à initialiser pleinement. * +* tid = identifiant associé au type d'instructions ciblé. * * * -* Description : Ajoute une information complémentaire à une instruction. * +* Description : Met en place une instruction d'architecture. * * * * Retour : Bilan de l'opération. * * * @@ -335,22 +273,18 @@ const char *g_arch_instruction_get_encoding(const GArchInstruction *instr) * * ******************************************************************************/ -bool g_arch_instruction_set_flag(GArchInstruction *instr, ArchInstrFlag flag) +bool g_arch_instruction_create(GArchInstruction *instr, itid_t tid) { bool result; /* Bilan à retourner */ - instr_extra_data_t *extra; /* Données insérées à modifier */ + instruction_extra_data_t extra; /* Données insérées à modifier */ - assert(flag <= AIF_HIGH_USER); + result = true; extra = GET_ARCH_INSTR_EXTRA(instr); - LOCK_GOBJECT_EXTRA(extra); - - result = !(extra->flags & flag); + extra.tid = tid; - extra->flags |= flag; - - UNLOCK_GOBJECT_EXTRA(extra); + SET_ARCH_INSTR_EXTRA(instr, &extra); return result; @@ -359,33 +293,24 @@ bool g_arch_instruction_set_flag(GArchInstruction *instr, ArchInstrFlag flag) /****************************************************************************** * * -* Paramètres : instr = instruction quelconque à modifier. * -* flag = drapeau d'information complémentaire à planter. * +* Paramètres : instr = instruction quelconque à consulter. * * * -* Description : Retire une information complémentaire à une instruction. * +* Description : Fournit l'identifiant correspondant à un type d'instructions.* * * -* Retour : Bilan de l'opération. * +* Retour : Identifiant unique par type d'instruction et architecture. * * * * Remarques : - * * * ******************************************************************************/ -bool g_arch_instruction_unset_flag(GArchInstruction *instr, ArchInstrFlag flag) +itid_t g_arch_instruction_get_type_id(const GArchInstruction *instr) { - bool result; /* Bilan à retourner */ - instr_extra_data_t *extra; /* Données insérées à modifier */ - - assert(flag <= AIF_HIGH_USER); + itid_t result; /* Numéro à retourner */ + instruction_extra_data_t extra; /* Données insérées à modifier */ extra = GET_ARCH_INSTR_EXTRA(instr); - LOCK_GOBJECT_EXTRA(extra); - - result = (extra->flags & flag); - - extra->flags &= ~flag; - - UNLOCK_GOBJECT_EXTRA(extra); + result = extra.tid; return result; @@ -395,30 +320,23 @@ bool g_arch_instruction_unset_flag(GArchInstruction *instr, ArchInstrFlag flag) /****************************************************************************** * * * Paramètres : instr = instruction quelconque à consulter. * -* flag = drapeau d'information à rechercher. * * * -* Description : Détermine si une instruction possède un fanion particulier. * +* Description : Indique l'encodage d'une instruction de façon détaillée. * * * -* Retour : Bilan de la détection. * +* Retour : Description humaine de l'encodage utilisé. * * * * Remarques : - * * * ******************************************************************************/ -bool g_arch_instruction_has_flag(const GArchInstruction *instr, ArchInstrFlag flag) +char *g_arch_instruction_get_encoding(const GArchInstruction *instr) { - bool result; /* Bilan à retourner */ - instr_extra_data_t *extra; /* Données insérées à modifier */ - - assert(flag <= AIF_HIGH_USER); - - extra = GET_ARCH_INSTR_EXTRA(instr); - - LOCK_GOBJECT_EXTRA(extra); + char *result; /* Encodage à retourner */ + GArchInstructionClass *class; /* Classe des instructions */ - result = (extra->flags & flag); + class = G_ARCH_INSTRUCTION_GET_CLASS(instr); - UNLOCK_GOBJECT_EXTRA(extra); + result = class->get_encoding(instr); return result; @@ -427,28 +345,24 @@ bool g_arch_instruction_has_flag(const GArchInstruction *instr, ArchInstrFlag fl /****************************************************************************** * * -* Paramètres : instr = instruction quelconque à modifier. * +* Paramètres : instr = instruction d'assemblage à consulter. * * * -* Description : Fournit les informations complémentaires d'une instruction. * +* Description : Fournit le nom humain de l'instruction manipulée. * * * -* Retour : Eventuels drapeaux d'information complémentaire à plantés. * +* Retour : Mot clef de bas niveau. * * * * Remarques : - * * * ******************************************************************************/ -ArchInstrFlag g_arch_instruction_get_flags(const GArchInstruction *instr) +char *g_arch_instruction_get_keyword(const GArchInstruction *instr) { - ArchInstrFlag result; /* Fanions à retourner */ - instr_extra_data_t *extra; /* Données insérées à modifier */ - - extra = GET_ARCH_INSTR_EXTRA(instr); - - LOCK_GOBJECT_EXTRA(extra); + char *result; /* Etiquette à retourner */ + GArchInstructionClass *class; /* Classe des instructions */ - result = extra->flags; + class = G_ARCH_INSTRUCTION_GET_CLASS(instr); - UNLOCK_GOBJECT_EXTRA(extra); + result = class->get_keyword(instr); return result; @@ -457,10 +371,12 @@ ArchInstrFlag g_arch_instruction_get_flags(const GArchInstruction *instr) /****************************************************************************** * * -* Paramètres : instr = instruction quelconque à consulter. * -* uid = identifiant unique par type d'instruction. * +* Paramètres : instr = instruction quelconque à compléter. * +* area = portion de binaire incluant l'instruction. * +* start = adresse virtuelle et/ou position physique. * +* length = taille de l'instruction. * * * -* Description : Définit l'identifiant unique pour un ensemble d'instructions.* +* Description : Calcule la localisation d'une instruction. * * * * Retour : - * * * @@ -468,358 +384,214 @@ ArchInstrFlag g_arch_instruction_get_flags(const GArchInstruction *instr) * * ******************************************************************************/ -void g_arch_instruction_set_unique_id(GArchInstruction *instr, itid_t uid) +void g_arch_instruction_compute_range(GArchInstruction *instr, GBinaryPortion *area, const vmpa2t *start, phys_t length) { - instr_extra_data_t *extra; /* Données insérées à modifier */ + const mrange_t *a_range; /* Couverture de la portion */ + phys_t diff; /* Décalage à appliquer */ - extra = GET_ARCH_INSTR_EXTRA(instr); - - LOCK_GOBJECT_EXTRA(extra); + a_range = g_binary_portion_get_range(area); - extra->uid = uid; + assert(mrange_contains_addr(a_range, start)); - UNLOCK_GOBJECT_EXTRA(extra); + diff = compute_vmpa_diff(get_mrange_addr(a_range), start); -} + instr->rel_area = area; + ref_object(area); - -/****************************************************************************** -* * -* Paramètres : instr = instruction quelconque à consulter. * -* * -* Description : Fournit l'identifiant unique pour un ensemble d'instructions.* -* * -* Retour : Identifiant unique par type d'instruction et architecture. * -* * -* Remarques : - * -* * -******************************************************************************/ - -itid_t g_arch_instruction_get_unique_id(const GArchInstruction *instr) -{ - itid_t result; /* Numéro à retourner */ - instr_extra_data_t *extra; /* Données insérées à consulter*/ - - extra = GET_ARCH_INSTR_EXTRA(instr); - - LOCK_GOBJECT_EXTRA(extra); - - result = extra->uid; - - UNLOCK_GOBJECT_EXTRA(extra); - - return result; + init_rel_mrange(&instr->rel_range, diff, length); } /****************************************************************************** * * -* Paramètres : instr = instruction quelconque à traiter. * -* type = type de procédure à utiliser. * -* proc = représentation de l'architecture utilisée. * -* context = contexte associé à la phase de désassemblage. * -* format = accès aux données du binaire d'origine. * +* Paramètres : instr = instruction quelconque à consulter. * +* range = localisation de l'instruction. [OUT] * * * -* Description : Complète un désassemblage accompli pour une instruction. * +* Description : Fournit la place mémoire d'une instruction. * * * -* Retour : - * +* Retour : Validité de la localisation : existence d'une définition ? * * * * Remarques : - * * * ******************************************************************************/ -void g_arch_instruction_call_hook(GArchInstruction *instr, InstrProcessHook type, GArchProcessor *proc, GProcContext *context, GExeFormat *format) +bool g_arch_instruction_get_range(const GArchInstruction *instr, mrange_t *range) { - GArchInstructionClass *class; /* Classe des instructions */ + bool result; /* Statut à retourner */ + const mrange_t *a_range; /* Couverture de la portion */ + vmpa2t start; /* Position de départ complète */ - class = G_ARCH_INSTRUCTION_GET_CLASS(instr); + result = (instr->rel_area != NULL); - if (class->call_hook != NULL) - class->call_hook(instr, type, proc, context, format); + if (result) + { + a_range = g_binary_portion_get_range(instr->rel_area); -} + copy_vmpa(&start, get_mrange_addr(a_range)); + advance_vmpa(&start, get_rel_mrange_offset(&instr->rel_range)); + init_mrange(range, &start, get_rel_mrange_length(&instr->rel_range)); -/****************************************************************************** -* * -* Paramètres : instr = instruction quelconque à modifier. * -* address = adresse virtuelle et/ou position physique. * -* length = taille de l'instruction. * -* * -* Description : Définit la localisation d'une instruction. * -* * -* Retour : - * -* * -* Remarques : - * -* * -******************************************************************************/ + } -void g_arch_instruction_set_range(GArchInstruction *instr, const mrange_t *range) -{ - copy_mrange(&instr->range, range); + return result; } /****************************************************************************** * * -* Paramètres : instr = instruction quelconque à consulter. * +* Paramètres : instr = instruction à venir modifier. * +* flag = drapeau d'information complémentaire à planter. * * * -* Description : Fournit la place mémoire d'une instruction. * +* Description : Ajoute une information complémentaire à une instruction. * * * -* Retour : Zone mémoire couverte par l'instruction. * +* Retour : Bilan de l'opération. * * * * Remarques : - * * * ******************************************************************************/ -const mrange_t *g_arch_instruction_get_range(const GArchInstruction *instr) +bool g_arch_instruction_set_flag(GArchInstruction *instr, ArchInstructionFlag flag) { - return &instr->range; + bool result; /* Bilan à retourner */ + instruction_extra_data_t extra; /* Données insérées à modifier */ -} + assert(flag <= AIF_HIGH_USER); + extra = GET_ARCH_INSTR_EXTRA(instr); + result = !(extra.flags & flag); -/****************************************************************************** -* * -* Paramètres : instr = instruction quelconque à consulter. * -* offset = position physique dans le code binaire/NULL. [OUT] * -* length = taille de l'instruction ou NULL. [OUT] * -* address = adresse virtuelle ou position physique/NULL. [OUT] * -* * -* Description : Fournit la localisation d'une instruction. * -* * -* Retour : - * -* * -* Remarques : - * -* * -******************************************************************************/ + extra.flags |= flag; -void g_arch_instruction_get_location(const GArchInstruction *instr, off_t *offset, off_t *length, vmpa_t *address) -{ - //if (offset != NULL) *offset = instr->offset; - //if (length != NULL) *length = instr->length; + SET_ARCH_INSTR_EXTRA(instr, &extra); - //if (address != NULL) *address = instr->address; + return result; } - /****************************************************************************** * * -* Paramètres : instr = instruction à consulter. * -* rregs = liste des rgistres lus. [OUT] * -* rcount = nombre de registres lus. [OUT] * -* wregs = liste des rgistres écrits. [OUT] * -* wcount = nombre de registres écrits. [OUT] * +* Paramètres : instr = instruction à venir modifier. * +* flag = drapeau d'information complémentaire à planter. * * * -* Description : Liste les registres lus et écrits par l'instruction. * +* Description : Retire une information complémentaire à une instruction. * * * -* Retour : - * +* Retour : Bilan de l'opération. * * * -* Remarques : Les compteurs de références sont à décrémenter après usage ! * +* Remarques : - * * * ******************************************************************************/ -void g_arch_instruction_get_rw_registers(const GArchInstruction *instr, GArchRegister ***rregs, size_t *rcount, GArchRegister ***wregs, size_t *wcount) +bool g_arch_instruction_unset_flag(GArchInstruction *instr, ArchInstructionFlag flag) { -#if 0 + bool result; /* Bilan à retourner */ + instruction_extra_data_t extra; /* Données insérées à modifier */ - size_t i; /* Boucle de parcours */ + assert(flag <= AIF_HIGH_USER); - *rregs = NULL; - *rcount = 0; - *wregs = NULL; - *wcount = 0; + extra = GET_ARCH_INSTR_EXTRA(instr); - instr->get_rw_regs(instr, rregs, rcount, wregs, wcount); + result = (extra.flags & flag); - for (i = 0; i < *rcount; i++) - g_object_ref(G_OBJECT((*rregs)[i])); + extra.flags &= ~flag; - for (i = 0; i < *wcount; i++) - g_object_ref(G_OBJECT((*wregs)[i])); + SET_ARCH_INSTR_EXTRA(instr, &extra); -#endif + return result; } - -/* ---------------------------------------------------------------------------------- */ -/* MANIPULATION DES OPERANDES */ -/* ---------------------------------------------------------------------------------- */ - - /****************************************************************************** * * -* Paramètres : instr = instruction à mettre à jour. * +* Paramètres : instr = instruction à venir consulter. * +* flag = drapeau d'information à rechercher. * * * -* Description : Verrouille les accès à la liste des opérandes. * +* Description : Détermine si une instruction possède un fanion particulier. * * * -* Retour : - * +* Retour : Bilan de la détection. * * * * Remarques : - * * * ******************************************************************************/ -void g_arch_instruction_lock_operands(GArchInstruction *instr) +bool g_arch_instruction_has_flag(const GArchInstruction *instr, ArchInstructionFlag flag) { - lock_flat_array(&instr->operands); + bool result; /* Bilan à retourner */ + instruction_extra_data_t extra; /* Données insérées à modifier */ -} + assert(flag <= AIF_HIGH_USER); + extra = GET_ARCH_INSTR_EXTRA(instr); -/****************************************************************************** -* * -* Paramètres : instr = instruction à mettre à jour. * -* * -* Description : Déverrouille les accès à la liste des opérandes. * -* * -* Retour : - * -* * -* Remarques : - * -* * -******************************************************************************/ + result = (extra.flags & flag); -void g_arch_instruction_unlock_operands(GArchInstruction *instr) -{ - unlock_flat_array(&instr->operands); + return result; } /****************************************************************************** * * -* Paramètres : instr = instance à mettre à jour. * -* operand = instruction à venir associer. * +* Paramètres : instr = instruction à venir consulter. * * * -* Description : Attache un opérande supplémentaire à une instruction. * +* Description : Fournit les particularités de l'instruction. * * * -* Retour : - * +* Retour : Somme de tous les fanions associés à l'opérande. * * * * Remarques : - * * * ******************************************************************************/ -void g_arch_instruction_attach_extra_operand(GArchInstruction *instr, GArchOperand *operand) +ArchInstructionFlag g_arch_instruction_get_flags(const GArchInstruction *instr) { - GSingletonFactory *factory; /* Unise à instances uniques */ - GArchOperand *singleton; /* Instance retenue */ - - factory = get_operands_factory(); - - singleton = G_ARCH_OPERAND(g_singleton_factory_get_instance(factory, G_SINGLETON_CANDIDATE(operand))); - - g_object_unref(G_OBJECT(operand)); - g_object_unref(G_OBJECT(factory)); - - g_arch_instruction_lock_operands(instr); - - add_item_to_flat_array(&instr->operands, &singleton, sizeof(GArchOperand *)); - - g_arch_instruction_unlock_operands(instr); + ArchInstructionFlag result; /* Fanions à retourner */ + instruction_extra_data_t extra; /* Données insérées à modifier */ -} - - -/****************************************************************************** -* * -* Paramètres : instr = instance à consulter. * -* * -* Description : Indique la quantité d'opérandes présents dans l'instruction. * -* * -* Retour : Nombre d'opérandes attachés. * -* * -* Remarques : - * -* * -******************************************************************************/ + extra = GET_ARCH_INSTR_EXTRA(instr); -size_t _g_arch_instruction_count_operands(const GArchInstruction *instr) -{ - size_t result; /* Décompte à retourner */ - - result = count_flat_array_items(instr->operands); + result = extra.flags; return result; } -/****************************************************************************** -* * -* Paramètres : instr = instance à consulter. * -* index = indice de l'opérande concerné. * -* * -* Description : Fournit un opérande donné d'une instruction. * -* * -* Retour : Opérande trouvée. * -* * -* Remarques : - * -* * -******************************************************************************/ - -GArchOperand *_g_arch_instruction_get_operand(const GArchInstruction *instr, size_t index) -{ - GArchOperand *result; /* Opérande à retourner */ - GArchOperand **ptr; /* Adresse dans le tableau */ - - ptr = get_flat_array_item(instr->operands, index, sizeof(GArchOperand *)); - - result = *ptr; - - g_object_ref(G_OBJECT(result)); - - return result; -} +/* ---------------------------------------------------------------------------------- */ +/* DEFINITION DES LIAISONS ENTRE INSTRUCTIONS */ +/* ---------------------------------------------------------------------------------- */ /****************************************************************************** * * -* Paramètres : instr = instance à mettre à jour. * -* old = ancienne opérande à détacher. * -* new = nouvelle opérande à attacher. * +* Paramètres : instr = instruction dont les liens sont à consulter. * +* dir = direction du lien recherché. * +* type = type de lien à détecter. * * * -* Description : Remplace un opérande d'une instruction par un autre. * +* Description : Détermine si un type de lien existe dans une instruction. * * * -* Retour : Bilan de l'opération. * +* Retour : Bilan du statut courant de l'instruction. * * * * Remarques : - * * * ******************************************************************************/ -bool _g_arch_instruction_replace_operand(GArchInstruction *instr, GArchOperand *old, GArchOperand *new) +static bool _g_arch_instruction_has_link(const GArchInstruction *instr, compact_ins_link_t dir, InstructionLinkType type) { bool result; /* Bilan à retourner */ - size_t count; /* Nombre d'opérandes en place */ - size_t i; /* Boucle de parcours */ - GArchOperand *op; /* Opérande à manipuler */ - - result = false; - - count = _g_arch_instruction_count_operands(instr); - - for (i = 0; i < count && !result; i++) - { - op = _g_arch_instruction_get_operand(instr, i); + uint16_t i; /* Boucle de parcours */ - result = (op == old); - - g_object_unref(G_OBJECT(op)); - - } - - if (result) - { - rpl_item_in_flat_array(instr->operands, i - 1, &new, sizeof(GArchOperand *)); + assert(g_thick_object_check_lock(G_THICK_OBJECT(instr))); - g_object_unref(G_OBJECT(old)); + result = false; - } + for (i = 0; i < instr->link_count && !result; i++) + result = COMPACT_INS_LINK_DIR(instr->links[i]) == dir; return result; @@ -828,45 +600,22 @@ bool _g_arch_instruction_replace_operand(GArchInstruction *instr, GArchOperand * /****************************************************************************** * * -* Paramètres : instr = instance à mettre à jour. * -* target = instruction à venir dissocier. * +* Paramètres : instr = instruction dont les liens sont à consulter. * +* type = type de lien à détecter. * * * -* Description : Détache un opérande liée d'une instruction. * +* Description : Détermine si un type de lien amène à une instruction. * * * -* Retour : Bilan de l'opération. * +* Retour : Bilan du statut courant de l'instruction. * * * * Remarques : - * * * ******************************************************************************/ -bool _g_arch_instruction_detach_operand(GArchInstruction *instr, GArchOperand *target) +bool g_arch_instruction_has_src_link(const GArchInstruction *instr, InstructionLinkType type) { bool result; /* Bilan à retourner */ - size_t count; /* Nombre d'opérandes en place */ - size_t i; /* Boucle de parcours */ - GArchOperand *op; /* Opérande à manipuler */ - - result = false; - - count = _g_arch_instruction_count_operands(instr); - for (i = 0; i < count && !result; i++) - { - op = _g_arch_instruction_get_operand(instr, i); - - result = (op == target); - - g_object_unref(G_OBJECT(op)); - - } - - if (result) - { - rem_item_from_flat_array(&instr->operands, i - 1, sizeof(GArchOperand *)); - - g_object_unref(G_OBJECT(target)); - - } + result = _g_arch_instruction_has_link(instr, COMPACT_INS_LINK_FROM, type); return result; @@ -875,78 +624,22 @@ bool _g_arch_instruction_detach_operand(GArchInstruction *instr, GArchOperand *t /****************************************************************************** * * -* Paramètres : instr = instance à consulter. * -* target = instruction à venir retrouver. * +* Paramètres : instr = instruction dont les liens sont à consulter. * +* type = type de lien à détecter. * * * -* Description : Détermine le chemin conduisant à un opérande. * +* Description : Détermine si un type de lien émerge d'une instruction. * * * -* Retour : Chemin d'accès à l'opérande ou NULL en cas d'absence. * +* Retour : Bilan du statut courant de l'instruction. * * * * Remarques : - * * * ******************************************************************************/ -char *g_arch_instruction_find_operand_path(GArchInstruction *instr, const GArchOperand *target) +bool g_arch_instruction_has_dest_link(const GArchInstruction *instr, InstructionLinkType type) { - char *result; /* Chemin à retourner */ - size_t count; /* Nombre d'opérandes en place */ - size_t i; /* Boucle de parcours */ - GArchOperand *op; /* Opérande à manipuler */ - int ret; /* Bilan d'une construction */ - char *sub_path; /* Sous-chemin emprunté */ - - result = NULL; - - g_arch_instruction_lock_operands(instr); - - count = _g_arch_instruction_count_operands(instr); - - /* Première passe : accès direct */ - - for (i = 0; i < count && result == NULL; i++) - { - op = _g_arch_instruction_get_operand(instr, i); - - if (op == target) - { - ret = asprintf(&result, "%zu", i); - if (ret == -1) - { - LOG_ERROR_N("asprintf"); - result = NULL; - } - } - - g_object_unref(G_OBJECT(op)); - - } - - /* Seconde passe : accès profond */ - - for (i = 0; i < count && result == NULL; i++) - { - op = _g_arch_instruction_get_operand(instr, i); - - sub_path = g_arch_operand_find_inner_operand_path(op, target); - - if (sub_path != NULL) - { - ret = asprintf(&result, "%zu:%s", i, sub_path); - if (ret == -1) - { - LOG_ERROR_N("asprintf"); - result = NULL; - } - - free(sub_path); - - } - - g_object_unref(G_OBJECT(op)); - - } + bool result; /* Bilan à retourner */ - g_arch_instruction_unlock_operands(instr); + result = _g_arch_instruction_has_link(instr, COMPACT_INS_LINK_TO, type); return result; @@ -955,104 +648,65 @@ char *g_arch_instruction_find_operand_path(GArchInstruction *instr, const GArchO /****************************************************************************** * * -* Paramètres : instr = instance à consulter. * -* path = chemin d'accès à un opérande à retrouver. * +* Paramètres : instr = instruction dont les liens sont à consulter. * +* dir = direction du lien recherché. * +* linked = seconde instruction à considérer. * * * -* Description : Obtient l'opérande correspondant à un chemin donné. * +* Description : Détermine si un lien existe entre deux instructions. * * * -* Retour : Opérande trouvé ou NULL en cas d'échec. * +* Retour : Bilan du statut courant de l'instruction. * * * * Remarques : - * * * ******************************************************************************/ -GArchOperand *g_arch_instruction_get_operand_from_path(GArchInstruction *instr, const char *path) +static bool _g_arch_instruction_has_link_with(const GArchInstruction *instr, compact_ins_link_t dir, const GArchInstruction *linked) { - GArchOperand *result; /* Opérande trouvée à renvoyer */ - size_t index; /* Indice de l'opérande visé */ - char *end; /* Poursuite du parcours ? */ - GArchOperand *found; /* Opérande trouvé */ - - result = NULL; - - g_arch_instruction_lock_operands(instr); - - /* Recherche au premier niveau */ - - index = strtoul(path, &end, 10); - - if ((index == ULONG_MAX && errno == ERANGE) || (index == 0 && errno == EINVAL)) - { - LOG_ERROR_N("strtoul"); - goto done; - } - - found = _g_arch_instruction_get_operand(instr, index); - if (found == NULL) goto done; - - if (*end == '\0') - { - result = found; - goto done; - } - - /* Recherche en profondeur */ - - assert(*end == ':'); - - result = g_arch_operand_get_inner_operand_from_path(found, end + 1); + bool result; /* Bilan à retourner */ + uint16_t i; /* Boucle de parcours */ - g_object_unref(G_OBJECT(found)); + assert(g_thick_object_check_lock(G_THICK_OBJECT(instr))); - done: + result = false; - g_arch_instruction_unlock_operands(instr); + for (i = 0; i < instr->link_count && !result; i++) + result = COMPACT_INS_LINK_PTR(instr->links[i]) == linked; return result; } - -/* ---------------------------------------------------------------------------------- */ -/* DEFINITION DES LIAISONS ENTRE INSTRUCTIONS */ -/* ---------------------------------------------------------------------------------- */ - - /****************************************************************************** * * -* Paramètres : instr = instruction à mettre à jour. * -* src = sélection de l'extrémité à traiter. * -* lock = indique le sens du verrouillage à mener. * +* Paramètres : instr = instruction dont les liens sont à consulter. * +* src = seconde instruction à considérer. * * * -* Description : Met à disposition un encadrement des accès aux liens. * +* Description : Détermine si une instruction est source d'une autre. * * * -* Retour : - * +* Retour : Bilan du statut courant de l'instruction. * * * * Remarques : - * * * ******************************************************************************/ -void g_arch_instruction_lock_unlock_links(GArchInstruction *instr, bool src, bool lock) +bool g_arch_instruction_has_src_link_with(const GArchInstruction *instr, const GArchInstruction *src) { - flat_array_t **array; /* Choix du tableau ciblé */ + bool result; /* Bilan à retourner */ - array = (src ? &instr->from : &instr->to); + result = _g_arch_instruction_has_link_with(instr, COMPACT_INS_LINK_FROM, src); - if (lock) - lock_flat_array(array); - else - unlock_flat_array(array); + return result; } /****************************************************************************** * * -* Paramètres : instr = instruction dont les informations sont à consulter. * -* type = type de lien à détecter. * +* Paramètres : instr = instruction dont les liens sont à consulter. * +* dest = seconde instruction à considérer. * * * -* Description : Détermine si un type de lien existe dans une instruction. * +* Description : Détermine si une instruction est destination d'une autre. * * * * Retour : Bilan du statut courant de l'instruction. * * * @@ -1060,30 +714,11 @@ void g_arch_instruction_lock_unlock_links(GArchInstruction *instr, bool src, boo * * ******************************************************************************/ -bool g_arch_instruction_has_link(GArchInstruction *instr, InstructionLinkType type) +bool g_arch_instruction_has_dest_link_with(const GArchInstruction *instr, const GArchInstruction *dest) { bool result; /* Bilan à retourner */ - size_t count; /* Nombre de liens à parcourir */ - size_t i; /* Boucle de parcours */ - const instr_link_t *dlink; /* Définition de destination */ - - result = false; - - g_arch_instruction_lock_dest(instr); - count = g_arch_instruction_count_destinations(instr); - - for (i = 0; i < count && !result; i++) - { - dlink = g_arch_instruction_get_destination(instr, i); - - result = (dlink->type == type); - - unref_instr_link(dlink); - - } - - g_arch_instruction_unlock_dest(instr); + result = _g_arch_instruction_has_link_with(instr, COMPACT_INS_LINK_TO, dest); return result; @@ -1092,54 +727,53 @@ bool g_arch_instruction_has_link(GArchInstruction *instr, InstructionLinkType ty /****************************************************************************** * * -* Paramètres : instr = instruction dont les informations sont à consulter. * +* Paramètres : instr = instruction dont les informations sont à manipuler. * * dest = ligne visée par la liaison (côté destination). * +* type = type de lien à construire. * * * -* Description : Détermine si un lien est déjà établi entre deux instructions.* +* Description : Etablit un lien entre deux instructions. * * * -* Retour : Bilan de l'état actuel des liaisons. * +* Retour : - * * * * Remarques : - * * * ******************************************************************************/ -bool g_arch_instruction_has_link_to(GArchInstruction *instr, const GArchInstruction *dest) +void g_arch_instruction_link(GArchInstruction *instr, GArchInstruction *dest, InstructionLinkType type) { - bool result; /* Bilan à retourner */ - size_t count; /* Nombre de liens à parcourir */ - size_t i; /* Boucle de parcours */ - const instr_link_t *dlink; /* Définition de destination */ + compact_ins_link_t new_from; /* Nouvel enregistrement #1 */ + compact_ins_link_t new_to; /* Nouvel enregistrement #2 */ - result = false; + new_from = MAKE_COMPACT_INS_LINK(COMPACT_INS_LINK_FROM, instr, type); + ref_object(instr); - g_arch_instruction_lock_dest(instr); + new_to = MAKE_COMPACT_INS_LINK(COMPACT_INS_LINK_TO, dest, type); + ref_object(dest); - count = g_arch_instruction_count_destinations(instr); + g_thick_object_lock(G_THICK_OBJECT(instr)); + g_thick_object_lock(G_THICK_OBJECT(dest)); - for (i = 0; i < count && !result; i++) - { - dlink = g_arch_instruction_get_destination(instr, i); - - result = (dlink->linked == dest); + dest->links = realloc(dest->links, ++dest->link_count * sizeof(compact_ins_link_t)); - unref_instr_link(dlink); + dest->links[dest->link_count - 1] = new_from; - } + instr->links = realloc(instr->links, ++instr->link_count * sizeof(compact_ins_link_t)); - g_arch_instruction_unlock_dest(instr); + instr->links[instr->link_count - 1] = new_to; - return result; + g_thick_object_unlock(G_THICK_OBJECT(dest)); + g_thick_object_unlock(G_THICK_OBJECT(instr)); } /****************************************************************************** * * -* Paramètres : instr = instruction dont les informations sont à consulter. * +* Paramètres : instr = instruction dont les informations sont à manipuler. * * dest = ligne visée par la liaison (côté destination). * * type = type de lien à construire. * * * -* Description : Etablit un lien entre deux instructions. * +* Description : Supprime un lien entre deux instructions. * * * * Retour : - * * * @@ -1147,43 +781,59 @@ bool g_arch_instruction_has_link_to(GArchInstruction *instr, const GArchInstruct * * ******************************************************************************/ -void g_arch_instruction_link_with(GArchInstruction *instr, GArchInstruction *dest, InstructionLinkType type) +void g_arch_instruction_unlink(GArchInstruction *instr, GArchInstruction *dest, InstructionLinkType type) { - instr_link_t new_src; /* Nouveau lien à définir #1 */ - instr_link_t new_dst; /* Nouveau lien à définir #2 */ + compact_ins_link_t old_from; /* Ancien enregistrement #1 */ + compact_ins_link_t old_to; /* Ancien enregistrement #2 */ + uint16_t i_from; /* Boucle de parcours #1 */ + uint16_t i_to; /* Boucle de parcours #2 */ + bool status; /* Bilan des recherches */ + + old_from = MAKE_COMPACT_INS_LINK(COMPACT_INS_LINK_FROM, instr, type); + + old_to = MAKE_COMPACT_INS_LINK(COMPACT_INS_LINK_TO, dest, type); - /* Côté destination */ + g_thick_object_lock(G_THICK_OBJECT(instr)); + g_thick_object_lock(G_THICK_OBJECT(dest)); - new_src.linked = instr; - new_src.type = type; + for (i_from = 0; i_from < dest->link_count; i_from++) + if (dest->links[i_from] == old_from) + break; - ref_instr_link((&new_src)); + for (i_to = 0; i_to < instr->link_count; i_to++) + if (instr->links[i_to] == old_to) + break; - /* Côté point de départ */ + assert((i_from < dest->link_count && i_to < instr->link_count) + || (i_from == dest->link_count && i_to == instr->link_count)); - new_dst.linked = dest; - new_dst.type = type; + status = (i_from < dest->link_count && i_to < instr->link_count); - ref_instr_link((&new_dst)); + if (status) + { + if ((i_from + 1) < dest->link_count) + memmove(&dest->links[i_from], &dest->links[i_from + 1], + (dest->link_count - i_from - 1) * sizeof(compact_ins_link_t)); - /* Ajout dans le respect d'une cohérence globale */ + dest->links = realloc(dest->links, --dest->link_count * sizeof(compact_ins_link_t)); - g_arch_instruction_lock_src(dest); - g_arch_instruction_lock_dest(instr); + if ((i_to + 1) < instr->link_count) + memmove(&instr->links[i_to], &instr->links[i_to + 1], + (instr->link_count - i_to - 1) * sizeof(compact_ins_link_t)); - add_item_to_flat_array(&dest->from, &new_src, sizeof(instr_link_t)); + instr->links = realloc(instr->links, --instr->link_count * sizeof(compact_ins_link_t)); - add_item_to_flat_array(&instr->to, &new_dst, sizeof(instr_link_t)); + } - g_arch_instruction_unlock_dest(instr); - g_arch_instruction_unlock_src(dest); + g_thick_object_unlock(G_THICK_OBJECT(dest)); + g_thick_object_unlock(G_THICK_OBJECT(instr)); } /****************************************************************************** * * -* Paramètres : instr = instruction dont les informations sont à consulter. * +* Paramètres : instr = instruction dont les informations sont à manipuler. * * dest = ligne visée par la liaison (côté destination). * * old = ancien type de lien construit. * * new = nouveau type de lien à construire. * @@ -1199,67 +849,43 @@ void g_arch_instruction_link_with(GArchInstruction *instr, GArchInstruction *des bool g_arch_instruction_change_link(GArchInstruction *instr, GArchInstruction *dest, InstructionLinkType old, InstructionLinkType new) { bool result; /* Bilan à retourner */ - size_t count; /* Raccourci pour la lecture */ - size_t i; /* Boucle de parcours */ - instr_link_t *slink; /* Définition de source */ - instr_link_t *dlink; /* Définition de destination */ - - result = false; + compact_ins_link_t old_from; /* Ancien enregistrement #1 */ + compact_ins_link_t new_from; /* Nouvel enregistrement #1 */ + compact_ins_link_t old_to; /* Ancien enregistrement #2 */ + compact_ins_link_t new_to; /* Nouvel enregistrement #2 */ + uint16_t i_from; /* Boucle de parcours #1 */ + uint16_t i_to; /* Boucle de parcours #2 */ - /** - * Note : pour la récupération des liens de sources et de destinations, - * on n'utilise pas les fonctions g_arch_instruction_get_(source|destination)(), - * qui renvoient un pointeur non modifiable. - * - * On a en effet besoin de modifier le type de lien. - */ + old_from = MAKE_COMPACT_INS_LINK(COMPACT_INS_LINK_FROM, instr, old); + new_from = MAKE_COMPACT_INS_LINK(COMPACT_INS_LINK_FROM, instr, new); + old_to = MAKE_COMPACT_INS_LINK(COMPACT_INS_LINK_TO, dest, old); + new_to = MAKE_COMPACT_INS_LINK(COMPACT_INS_LINK_TO, dest, new); - g_arch_instruction_lock_src(dest); + g_thick_object_lock(G_THICK_OBJECT(instr)); + g_thick_object_lock(G_THICK_OBJECT(dest)); - /* Côté destination */ - - count = g_arch_instruction_count_sources(dest); - - for (i = 0; i < count; i++) - { - slink = get_flat_array_item(dest->from, i, sizeof(instr_link_t)); - - if (slink->linked == instr && slink->type == old) + for (i_from = 0; i_from < dest->link_count; i_from++) + if (dest->links[i_from] == old_from) break; - } - - if (i == count) - goto gaicl_exit; + for (i_to = 0; i_to < instr->link_count; i_to++) + if (instr->links[i_to] == old_to) + break; - /* Côté point de départ */ + assert((i_from < dest->link_count && i_to < instr->link_count) + || (i_from == dest->link_count && i_to == instr->link_count)); - count = g_arch_instruction_count_destinations(instr); + result = (i_from < dest->link_count && i_to < instr->link_count); - for (i = 0; i < count; i++) + if (result) { - dlink = get_flat_array_item(instr->to, i, sizeof(instr_link_t)); - - if (dlink->linked == dest && dlink->type == old) - break; - + dest->links[i_from] = new_from; + instr->links[i_to] = new_to; } - if (i == count) - goto gaicl_exit; - - /* Si les deux extrémités sont raccord... */ - - slink->type = new; - - dlink->type = new; - - result = true; - - gaicl_exit: - - g_arch_instruction_unlock_src(dest); + g_thick_object_unlock(G_THICK_OBJECT(dest)); + g_thick_object_unlock(G_THICK_OBJECT(instr)); return result; @@ -1280,116 +906,92 @@ bool g_arch_instruction_change_link(GArchInstruction *instr, GArchInstruction *d void g_arch_instruction_delete_all_links(GArchInstruction *instr) { - instr_link_t *link_src; /* Lien à supprimer #2 */ - GArchInstruction *other; /* Instruction de l'autre bout */ - size_t count; /* Quantié de liens présents */ - size_t i; /* Boucle de parcours */ - instr_link_t *link_dst; /* Lien à supprimer #1 */ + GArchInstruction *linked; /* Autre instruction liée */ + InstructionLinkType type; /* Type de liaison */ - /* Coté sources */ + g_thick_object_lock(G_THICK_OBJECT(instr)); - g_arch_instruction_lock_src(instr); - - while (count_flat_array_items(instr->from) > 0) + while (g_arch_instruction_count_src_links(instr) > 0) { - link_src = get_flat_array_item(instr->from, 0, sizeof(instr_link_t)); - - other = link_src->linked; + linked = g_arch_instruction_get_linked_source(instr, 0, &type); - g_arch_instruction_lock_dest(other); + g_thick_object_unlock(G_THICK_OBJECT(instr)); - count = count_flat_array_items(other->to); + g_arch_instruction_unlink(linked, instr, type); - for (i = 0; i < count; i++) - { - link_dst = get_flat_array_item(other->to, i, sizeof(instr_link_t)); + g_thick_object_lock(G_THICK_OBJECT(instr)); - if (link_dst->linked == instr && link_dst->type == link_src->type) - { - unref_instr_link(link_dst); - - rem_item_from_flat_array(&other->to, i, sizeof(instr_link_t)); - - break; - - } - - } - - assert(i < count); - - g_arch_instruction_unlock_dest(other); - - unref_instr_link(link_src); - - rem_item_from_flat_array(&instr->from, 0, sizeof(instr_link_t)); + unref_object(linked); } - g_arch_instruction_unlock_src(instr); - - /* Coté destinations */ - - g_arch_instruction_lock_dest(instr); - - while (count_flat_array_items(instr->to) > 0) + while (g_arch_instruction_count_dest_links(instr) > 0) { - link_dst = get_flat_array_item(instr->to, 0, sizeof(instr_link_t)); + linked = g_arch_instruction_get_linked_destination(instr, 0, &type); - other = link_dst->linked; + g_thick_object_unlock(G_THICK_OBJECT(instr)); - g_arch_instruction_lock_src(other); + g_arch_instruction_unlink(instr, linked, type); - count = count_flat_array_items(other->from); + g_thick_object_lock(G_THICK_OBJECT(instr)); - for (i = 0; i < count; i++) - { - link_src = get_flat_array_item(other->from, i, sizeof(instr_link_t)); + unref_object(linked); - if (link_src->linked == instr && link_src->type == link_dst->type) - { - unref_instr_link(link_src); - - rem_item_from_flat_array(&other->from, i, sizeof(instr_link_t)); + } - break; + g_thick_object_unlock(G_THICK_OBJECT(instr)); - } +} - } - assert(i < count); +/****************************************************************************** +* * +* Paramètres : instr = instruction dont les liens sont à consulter. * +* dir = direction des liens à considérer. * +* * +* Description : Fournit la quantité d'instructions pointant vers une autre. * +* * +* Retour : Nombre de ces liens. * +* * +* Remarques : - * +* * +******************************************************************************/ - g_arch_instruction_unlock_src(other); +static size_t _g_arch_instruction_count_links(const GArchInstruction *instr, compact_ins_link_t dir) +{ + size_t result; /* Nombre de liens à renvoyer */ + uint16_t i; /* Boucle de parcours */ - unref_instr_link(link_dst); + assert(g_thick_object_check_lock(G_THICK_OBJECT(instr))); - rem_item_from_flat_array(&instr->to, 0, sizeof(instr_link_t)); + result = 0; - } + for (i = 0; i < instr->link_count; i++) + if (COMPACT_INS_LINK_DIR(instr->links[i]) == dir) + result++; - g_arch_instruction_unlock_dest(instr); + return result; } /****************************************************************************** * * -* Paramètres : instr = instruction dont les informations sont à consulter. * +* Paramètres : instr = instruction dont les liens sont à consulter. * * * -* Description : Fournit la quantité d'instructions pointant vers une autre. * +* Description : Fournit la quantité d'instructions placées en source. * * * -* Retour : Nombre de ces origines. * +* Retour : Nombre de ces liens. * * * * Remarques : - * * * ******************************************************************************/ -size_t g_arch_instruction_count_sources(const GArchInstruction *instr) +size_t g_arch_instruction_count_src_links(const GArchInstruction *instr) { size_t result; /* Nombre de liens à renvoyer */ - result = count_flat_array_items(instr->from); + result = _g_arch_instruction_count_links(instr, COMPACT_INS_LINK_FROM); return result; @@ -1398,24 +1000,21 @@ size_t g_arch_instruction_count_sources(const GArchInstruction *instr) /****************************************************************************** * * -* Paramètres : instr = instruction dont les informations sont à consulter. * -* index = indice de l'élément à retrouver. * +* Paramètres : instr = instruction dont les liens sont à consulter. * * * -* Description : Fournit les détails d'une origine d'une instruction donnée. * +* Description : Fournit la quantité d'instructions placées en destination. * * * -* Retour : Lien déterminé vers une instruction d'origine. * +* Retour : Nombre de ces liens. * * * * Remarques : - * * * ******************************************************************************/ -const instr_link_t *g_arch_instruction_get_source(GArchInstruction *instr, size_t index) +size_t g_arch_instruction_count_dest_links(const GArchInstruction *instr) { - instr_link_t *result; /* Détails présents à renvoyer */ - - result = get_flat_array_item(instr->from, index, sizeof(instr_link_t)); + size_t result; /* Nombre de liens à renvoyer */ - ref_instr_link(result); + result = _g_arch_instruction_count_links(instr, COMPACT_INS_LINK_TO); return result; @@ -1424,43 +1023,47 @@ const instr_link_t *g_arch_instruction_get_source(GArchInstruction *instr, size_ /****************************************************************************** * * -* Paramètres : instr = instruction dont les informations sont à consulter. * -* count = quantié de liens présents. [OUT] * +* Paramètres : instr = instruction dont les liens sont à consulter. * +* index = indice de l'élément à retrouver. * +* dir = direction des liens à considérer. * +* type = type de lien enregistré. [OUT] * * * -* Description : Fournit tous les détails d'origine d'une instruction donnée. * +* Description : Fournit les détails d'un lien donné avec une instruction. * * * -* Retour : Liens vers des instructions d'origine à libérer. * +* Retour : Autre instruction pointée par l'instruction, voire NULL. * * * * Remarques : - * * * ******************************************************************************/ -instr_link_t *g_arch_instruction_get_sources(GArchInstruction *instr, size_t *count) +static GArchInstruction *_g_arch_instruction_get_linked_instruction(const GArchInstruction *instr, size_t index, compact_ins_link_t dir, InstructionLinkType *type) { - instr_link_t *result; /* Détails présents à renvoyer */ - size_t i; /* Boucle de parcours */ - const instr_link_t *link; /* Lien à fournir */ - - g_arch_instruction_lock_src(instr); + GArchInstruction *result; /* Instance ciblée à renvoyer */ + uint16_t i; /* Boucle de parcours */ - *count = g_arch_instruction_count_sources(instr); + assert(g_thick_object_check_lock(G_THICK_OBJECT(instr))); - if (*count == 0) - result = NULL; + result = NULL; + *type = ILT_COUNT; - else + for (i = 0; i < instr->link_count; i++) { - result = (instr_link_t *)malloc(*count * sizeof(instr_link_t)); + if (COMPACT_INS_LINK_DIR(instr->links[i]) != dir) + continue; - for (i = 0; i < *count; i++) + if (index == 0) { - link = g_arch_instruction_get_source(instr, i); - memcpy(&result[i], link, sizeof(instr_link_t)); + result = COMPACT_INS_LINK_PTR(instr->links[i]); + *type = COMPACT_INS_LINK_TYPE(instr->links[i]); } + else + index--; + } - g_arch_instruction_unlock_src(instr); + if (result != NULL) + ref_object(result); return result; @@ -1469,21 +1072,23 @@ instr_link_t *g_arch_instruction_get_sources(GArchInstruction *instr, size_t *co /****************************************************************************** * * -* Paramètres : instr = instruction dont les informations sont à consulter. * +* Paramètres : instr = instruction dont les liens sont à consulter. * +* index = indice de l'élément à retrouver. * +* type = type de lien enregistré. [OUT] * * * -* Description : Donne le nombre d'instructions non naturellement suivantes. * +* Description : Fournit les détails d'une source donnée d'une instruction. * * * -* Retour : Nombre de ces destinations. * +* Retour : Autre instruction pointée par l'instruction, voire NULL. * * * * Remarques : - * * * ******************************************************************************/ -size_t g_arch_instruction_count_destinations(const GArchInstruction *instr) +GArchInstruction *g_arch_instruction_get_linked_source(const GArchInstruction *instr, size_t index, InstructionLinkType *type) { - size_t result; /* Nombre de liens à renvoyer */ + GArchInstruction *result; /* Instance ciblée à renvoyer */ - result = count_flat_array_items(instr->to); + result = _g_arch_instruction_get_linked_instruction(instr, index, COMPACT_INS_LINK_FROM, type); return result; @@ -1492,71 +1097,54 @@ size_t g_arch_instruction_count_destinations(const GArchInstruction *instr) /****************************************************************************** * * -* Paramètres : instr = instruction dont les informations sont à consulter. * +* Paramètres : instr = instruction dont les liens sont à consulter. * * index = indice de l'élément à retrouver. * +* type = type de lien enregistré. [OUT] * * * -* Description : Fournit les détails d'une destination d'une instruction. * +* Description : Fournit les détails d'une destination donnée d'une instruct. * * * -* Retour : Lien déterminé vers une instruction de destination. * +* Retour : Autre instruction pointée par l'instruction, voire NULL. * * * * Remarques : - * * * ******************************************************************************/ -const instr_link_t *g_arch_instruction_get_destination(GArchInstruction *instr, size_t index) +GArchInstruction *g_arch_instruction_get_linked_destination(const GArchInstruction *instr, size_t index, InstructionLinkType *type) { - instr_link_t *result; /* Détails présents à renvoyer */ - - result = get_flat_array_item(instr->to, index, sizeof(instr_link_t)); + GArchInstruction *result; /* Instance ciblée à renvoyer */ - ref_instr_link(result); + result = _g_arch_instruction_get_linked_instruction(instr, index, COMPACT_INS_LINK_TO, type); return result; } + +/* ---------------------------------------------------------------------------------- */ +/* MANIPULATION DES OPERANDES */ +/* ---------------------------------------------------------------------------------- */ + + /****************************************************************************** * * -* Paramètres : instr = instruction dont les informations sont à consulter. * -* type = type de lien recherché. * +* Paramètres : instr = instance à consulter. * * * -* Description : Fournit la destination d'une instruction et d'un type donné. * +* Description : Indique la quantité d'opérandes présents dans l'instruction. * * * -* Retour : Instruction de destination trouvée ou NULL. * +* Retour : Nombre d'opérandes attachés. * * * * Remarques : - * * * ******************************************************************************/ -GArchInstruction *g_arch_instruction_get_given_destination(GArchInstruction *instr, InstructionLinkType type) +size_t g_arch_instruction_count_operands(const GArchInstruction *instr) { - GArchInstruction *result; /* Résultat à remonter */ - size_t count; /* Nombre de liens à parcourir */ - size_t i; /* Boucle de parcours */ - const instr_link_t *dest; /* Destination à étudier */ - - result = NULL; - - g_arch_instruction_lock_dest(instr); - - count = g_arch_instruction_count_destinations(instr); - - for (i = 0; i < count && result == NULL; i++) - { - dest = g_arch_instruction_get_destination(instr, i); - - if (dest->type == type) - { - result = dest->linked; - g_object_ref(G_OBJECT(result)); - } + size_t result; /* Décompte à retourner */ - unref_instr_link(dest); + assert(g_thick_object_check_lock(G_THICK_OBJECT(instr))); - } - - g_arch_instruction_unlock_dest(instr); + result = count_flat_array_items(instr->operands); return result; @@ -1565,56 +1153,45 @@ GArchInstruction *g_arch_instruction_get_given_destination(GArchInstruction *ins /****************************************************************************** * * -* Paramètres : instr = instruction dont les informations sont à consulter. * -* count = quantié de liens présents. [OUT] * +* Paramètres : instr = instance à mettre à jour. * +* operand = instruction à venir associer. * * * -* Description : Fournit tous les détails de destination d'une instruction. * +* Description : Attache un opérande supplémentaire à une instruction. * * * -* Retour : Liens vers des instructions de destination à libérer. * +* Retour : - * * * * Remarques : - * * * ******************************************************************************/ -instr_link_t *g_arch_instruction_get_destinations(GArchInstruction *instr, size_t *count) +void g_arch_instruction_attach_operand(GArchInstruction *instr, GArchOperand *operand) { - instr_link_t *result; /* Détails présents à renvoyer */ - size_t i; /* Boucle de parcours */ - const instr_link_t *link; /* Lien à fournir */ - - g_arch_instruction_lock_dest(instr); - - *count = g_arch_instruction_count_destinations(instr); + GSingletonFactory *factory; /* Unise à instances uniques */ + GSingletonCandidate *singleton; /* Instance retenue */ + GArchOperand *stored; /* Forme d'opérande conservée */ - if (*count == 0) - result = NULL; + assert(g_thick_object_check_lock(G_THICK_OBJECT(instr))); - else - { - result = (instr_link_t *)malloc(*count * sizeof(instr_link_t)); + factory = get_operands_factory(); - for (i = 0; i < *count; i++) - { - link = g_arch_instruction_get_destination(instr, i); - memcpy(&result[i], link, sizeof(instr_link_t)); - } + singleton = g_singleton_factory_get_instance(factory, G_SINGLETON_CANDIDATE(operand)); - } + unref_object(factory); - g_arch_instruction_unlock_dest(instr); + stored = G_ARCH_OPERAND(singleton); - return result; + add_item_to_flat_array(&instr->operands, &stored, sizeof(GArchOperand *)); } /****************************************************************************** * * -* Paramètres : instr = élément GLib à constuire. * -* storage = conservateur de données à manipuler ou NULL. * -* pbuf = zone tampon à lire. * +* Paramètres : instr = instance à mettre à jour. * +* old = ancienne opérande à détacher. * +* new = nouvelle opérande à attacher. * * * -* Description : Charge un contenu depuis une mémoire tampon. * +* Description : Remplace un opérande d'une instruction par un autre. * * * * Retour : Bilan de l'opération. * * * @@ -1622,40 +1199,47 @@ instr_link_t *g_arch_instruction_get_destinations(GArchInstruction *instr, size_ * * ******************************************************************************/ -static bool g_arch_instruction_load_destinations(GArchInstruction *instr, GObjectStorage *storage, packed_buffer_t *pbuf) +bool g_arch_instruction_replace_operand(GArchInstruction *instr, GArchOperand *old, GArchOperand *new) { bool result; /* Bilan à retourner */ - uleb128_t count; /* Nombre de liens à charger */ - uleb128_t i; /* Boucle de parcours */ - GArchInstruction *linked; /* Lien vers une instruction */ - uleb128_t type; /* Valeur ULEB128 à charger */ + size_t count; /* Nombre d'opérandes en place */ + size_t i; /* Boucle de parcours */ + GArchOperand *op; /* Opérande à manipuler */ + GSingletonFactory *factory; /* Unise à instances uniques */ + GSingletonCandidate *singleton; /* Instance retenue */ + GArchOperand *stored; /* Forme d'opérande conservée */ - g_arch_instruction_lock_dest(instr); + assert(g_thick_object_check_lock(G_THICK_OBJECT(instr))); - result = unpack_uleb128(&count, pbuf); + result = false; - for (i = 0; i < count && result; i++) + count = g_arch_instruction_count_operands(instr); + + for (i = 0; i < count && !result; i++) { - linked = G_ARCH_INSTRUCTION(g_object_storage_unpack_object(storage, "instructions", pbuf)); - if (linked == NULL) - { - result = false; - break; - } + op = g_arch_instruction_get_operand(instr, i); - result = unpack_uleb128(&type, pbuf); - if (!result) - { - g_object_unref(G_OBJECT(linked)); - break; - } + result = (op == old); - g_arch_instruction_link_with(instr, linked, type); - g_object_unref(G_OBJECT(linked)); + unref_object(op); } - g_arch_instruction_unlock_dest(instr); + if (result) + { + factory = get_operands_factory(); + + singleton = g_singleton_factory_get_instance(factory, G_SINGLETON_CANDIDATE(new)); + + unref_object(factory); + + stored = G_ARCH_OPERAND(singleton); + + rpl_item_in_flat_array(instr->operands, i - 1, &stored, sizeof(GArchOperand *)); + + unref_object(old); + + } return result; @@ -1664,11 +1248,10 @@ static bool g_arch_instruction_load_destinations(GArchInstruction *instr, GObjec /****************************************************************************** * * -* Paramètres : instr = instruction dont les informations sont à consulter.* -* storage = conservateur de données à manipuler ou NULL. * -* pbuf = zone tampon à remplir. * +* Paramètres : instr = instance à mettre à jour. * +* target = instruction à venir dissocier. * * * -* Description : Sauvegarde toutes les destinations d'une instruction. * +* Description : Détache un opérande liée d'une instruction. * * * * Retour : Bilan de l'opération. * * * @@ -1676,87 +1259,67 @@ static bool g_arch_instruction_load_destinations(GArchInstruction *instr, GObjec * * ******************************************************************************/ -bool g_arch_instruction_store_destinations(GArchInstruction *instr, GObjectStorage *storage, packed_buffer_t *pbuf) +bool g_arch_instruction_detach_operand(GArchInstruction *instr, GArchOperand *target) { bool result; /* Bilan à retourner */ - size_t count; /* Nombre d'éléments à traiter */ - size_t kept; /* Nombre de liens conservés */ + size_t count; /* Nombre d'opérandes en place */ size_t i; /* Boucle de parcours */ - const instr_link_t *link; /* Lien vers une instruction */ - - g_arch_instruction_lock_dest(instr); + GArchOperand *op; /* Opérande à manipuler */ - count = g_arch_instruction_count_destinations(instr); + assert(g_thick_object_check_lock(G_THICK_OBJECT(instr))); - /** - * Le type de lien ILT_REF n'est mis en place que lors de la création - * d'opérandes de type G_TYPE_TARGET_OPERAND, et sera donc remis en place - * dynamiquement lors de la restauration de ces derniers. - */ + result = false; - kept = 0; + count = g_arch_instruction_count_operands(instr); - for (i = 0; i < count; i++) + for (i = 0; i < count && !result; i++) { - link = g_arch_instruction_get_destination(instr, i); + op = g_arch_instruction_get_operand(instr, i); - if (link->type != ILT_REF) - kept++; + result = (op == target); - unref_instr_link(link); + unref_object(op); } - result = pack_uleb128((uleb128_t []){ kept }, pbuf); - - for (i = 0; i < count && result; i++) + if (result) { - link = g_arch_instruction_get_destination(instr, i); - - if (link->type != ILT_REF) - { - result = g_object_storage_pack_object(storage, "instructions", - G_SERIALIZABLE_OBJECT(link->linked), pbuf); - - if (result) - result = pack_uleb128((uleb128_t []){ link->type }, pbuf); - - } + rem_item_from_flat_array(&instr->operands, i - 1, sizeof(GArchOperand *)); - unref_instr_link(link); + unref_object(target); } - g_arch_instruction_unlock_dest(instr); - return result; } - -/* ---------------------------------------------------------------------------------- */ -/* CONVERSIONS DU FORMAT DES INSTRUCTIONS */ -/* ---------------------------------------------------------------------------------- */ - - /****************************************************************************** * * -* Paramètres : instr = instruction d'assemblage à consulter. * +* Paramètres : instr = instance à consulter. * +* index = indice de l'opérande concerné. * * * -* Description : Fournit le nom humain de l'instruction manipulée. * +* Description : Fournit un opérande donné d'une instruction. * * * -* Retour : Mot clef de bas niveau. * +* Retour : Opérande trouvée. * * * * Remarques : - * * * ******************************************************************************/ -const char *g_arch_instruction_get_keyword(GArchInstruction *instr) +GArchOperand *g_arch_instruction_get_operand(const GArchInstruction *instr, size_t index) { - const char *result; /* Désignation à retourner */ + GArchOperand *result; /* Opérande à retourner */ + GArchOperand **ptr; /* Adresse dans le tableau */ + + assert(g_thick_object_check_lock(G_THICK_OBJECT(instr))); - result = G_ARCH_INSTRUCTION_GET_CLASS(instr)->get_keyword(instr); + ptr = get_flat_array_item(instr->operands, index, sizeof(GArchOperand *)); + + result = *ptr; + + ref_object(result); return result; @@ -1765,450 +1328,396 @@ const char *g_arch_instruction_get_keyword(GArchInstruction *instr) /****************************************************************************** * * -* Paramètres : instr = instruction d'assemblage à consulter. * +* Paramètres : instr = instance à consulter. * +* target = instruction à venir retrouver. * * * -* Description : Construit un petit résumé concis de l'instruction. * +* Description : Détermine le chemin conduisant à un opérande. * * * -* Retour : Chaîne de caractères à libérer après usage ou NULL. * +* Retour : Chemin d'accès à l'opérande ou NULL en cas d'absence. * * * * Remarques : - * * * ******************************************************************************/ -char *g_arch_instruction_build_tooltip(const GArchInstruction *instr) +char *g_arch_instruction_find_operand_path(GArchInstruction *instr, const GArchOperand *target) { - char *result; /* Description à retourner */ - GArchInstructionClass *class; /* Classe des instructions */ + char *result; /* Chemin à retourner */ + size_t count; /* Nombre d'opérandes en place */ + size_t i; /* Boucle de parcours */ + GArchOperand *op; /* Opérande à manipuler */ + int ret; /* Bilan d'une construction */ + char *sub_path; /* Sous-chemin emprunté */ - class = G_ARCH_INSTRUCTION_GET_CLASS(instr); + result = NULL; - if (class->build_tooltip != NULL) - result = class->build_tooltip(instr); + g_thick_object_lock(G_THICK_OBJECT(instr)); - else - result = NULL; + count = g_arch_instruction_count_operands(instr); - return result; + /* Première passe : accès direct */ -} + for (i = 0; i < count && result == NULL; i++) + { + op = g_arch_instruction_get_operand(instr, i); + if (op == target) + { + ret = asprintf(&result, "%zu", i); + if (ret == -1) + { + LOG_ERROR_N("asprintf"); + result = NULL; + } + } -/****************************************************************************** -* * -* Paramètres : instr = instruction d'assemblage à consulter. * -* * -* Description : Fournit une description pour l'instruction manipulée. * -* * -* Retour : Chaîne de caractères avec balises éventuelles. * -* * -* Remarques : - * -* * -******************************************************************************/ + unref_object(op); -const char *g_arch_instruction_get_description(const GArchInstruction *instr) -{ - const char *result; /* Description à retourner */ + } - result = G_ARCH_INSTRUCTION_GET_CLASS(instr)->get_desc(instr); + /* Seconde passe : accès profond */ - return result; - -} + for (i = 0; i < count && result == NULL; i++) + { + op = g_arch_instruction_get_operand(instr, i); + sub_path = NULL;//g_arch_operand_find_inner_operand_path(op, target); + if (sub_path != NULL) + { + ret = asprintf(&result, "%zu:%s", i, sub_path); + if (ret == -1) + { + LOG_ERROR_N("asprintf"); + result = NULL; + } -/* ---------------------------------------------------------------------------------- */ -/* OFFRE DE CAPACITES DE GENERATION */ -/* ---------------------------------------------------------------------------------- */ + free(sub_path); + } -/****************************************************************************** -* * -* Paramètres : instr = générateur à consulter. * -* * -* Description : Indique le nombre de ligne prêtes à être générées. * -* * -* Retour : Nombre de lignes devant apparaître au final. * -* * -* Remarques : - * -* * -******************************************************************************/ + unref_object(op); -static size_t g_arch_instruction_count_lines(const GArchInstruction *instr) -{ - return 1; + } -} + g_thick_object_unlock(G_THICK_OBJECT(instr)); + return result; -#ifdef INCLUDE_GTK_SUPPORT +} /****************************************************************************** * * -* Paramètres : instr = générateur à consulter. * -* x = position géographique sur la ligne concernée. * -* index = indice de cette même ligne dans le tampon global. * -* repeat = indice d'utilisations successives du générateur. * -* cursor = emplacement à constituer. [OUT] * +* Paramètres : instr = instance à consulter. * +* path = chemin d'accès à un opérande à retrouver. * * * -* Description : Retrouve l'emplacement correspondant à une position donnée. * +* Description : Obtient l'opérande correspondant à un chemin donné. * * * -* Retour : - * +* Retour : Opérande trouvé ou NULL en cas d'échec. * * * * Remarques : - * * * ******************************************************************************/ -static void g_arch_instruction_compute_cursor(const GArchInstruction *instr, gint x, size_t index, size_t repeat, GLineCursor **cursor) +GArchOperand *g_arch_instruction_get_operand_from_path(GArchInstruction *instr, const char *path) { - *cursor = g_binary_cursor_new(); + GArchOperand *result; /* Opérande trouvée à renvoyer */ + size_t index; /* Indice de l'opérande visé */ + char *end; /* Poursuite du parcours ? */ + GArchOperand *found; /* Opérande trouvé */ - g_binary_cursor_update(G_BINARY_CURSOR(*cursor), get_mrange_addr(&instr->range)); + result = NULL; -} + g_thick_object_lock(G_THICK_OBJECT(instr)); + /* Recherche au premier niveau */ -/****************************************************************************** -* * -* Paramètres : instr = générateur à consulter. * -* index = indice de cette même ligne dans le tampon global. * -* repeat = indice d'utilisations successives du générateur. * -* cursor = emplacement à analyser. * -* * -* Description : Détermine si le conteneur s'inscrit dans une plage donnée. * -* * -* Retour : Bilan de la détermination, utilisable en comparaisons. * -* * -* Remarques : - * -* * -******************************************************************************/ + index = strtoul(path, &end, 10); -static int g_arch_instruction_contain_cursor(const GArchInstruction *instr, size_t index, size_t repeat, const GLineCursor *cursor) -{ - int result; /* Conclusion à retourner */ - vmpa2t addr; /* Autre emplacement à comparer*/ + if ((index == ULONG_MAX && errno == ERANGE) || (index == 0 && errno == EINVAL)) + { + LOG_ERROR_N("strtoul"); + goto done; + } + + found = g_arch_instruction_get_operand(instr, index); + if (found == NULL) goto done; + + if (*end == '\0') + { + result = found; + goto done; + } + + /* Recherche en profondeur */ + + assert(*end == ':'); + + result = NULL;//g_arch_operand_get_inner_operand_from_path(found, end + 1); - assert(G_IS_BINARY_CURSOR(cursor)); + unref_object(found); - g_binary_cursor_retrieve(G_BINARY_CURSOR(cursor), &addr); + done: - result = cmp_mrange_with_vmpa(&instr->range, &addr); + g_thick_object_unlock(G_THICK_OBJECT(instr)); return result; } -#endif + +/* ---------------------------------------------------------------------------------- */ +/* MECANISMES DE CONSERVATION ET RESTAURATION */ +/* ---------------------------------------------------------------------------------- */ /****************************************************************************** * * -* Paramètres : instr = générateur à consulter. * -* index = indice de cette même ligne dans le tampon global. * -* repeat = indice d'utilisations successives du générateur. * +* Paramètres : object = élément GLib à constuire. * +* storage = conservateur de données à manipuler. * +* fd = flux ouvert en lecture. * * * -* Description : Renseigne sur les propriétés liées à un générateur. * +* Description : Charge un objet depuis un flux de données. * * * -* Retour : Propriétés particulières associées. * +* Retour : Bilan de l'opération. * * * * Remarques : - * * * ******************************************************************************/ -static BufferLineFlags g_arch_instruction_get_flags2(const GArchInstruction *instr, size_t index, size_t repeat) +static bool g_arch_instruction_load(GSerializableObject *object, GObjectStorage *storage, int fd) { - return BLF_HAS_CODE; + bool result; /* Bilan à retourner */ + uleb128_t extra; /* Données embarquées */ + + /* Propriétés internes */ + + result = load_uleb128(&extra, fd); + + if (result) + g_thick_object_set_extra(G_THICK_OBJECT(object), extra); + + /* Liaisons avec d'autres instructions */ + + return result; } /****************************************************************************** * * -* Paramètres : instr = instruction d'assemblage à représenter. * -* line = ligne de rendu à compléter. * -* index = indice de cette même ligne dans le tampon global. * -* repeat = indice d'utilisations successives du générateur. * -* content = éventuel contenu binaire brut à imprimer. * +* Paramètres : object = élément GLib à consulter. * +* storage = conservateur de données à manipuler. * +* fd = flux ouvert en écriture. * * * -* Description : Ajoute à un tampon GLib le contenu de l'instance spécifiée. * +* Description : Sauvegarde un objet dans un flux de données. * * * -* Retour : - * +* Retour : Bilan de l'opération. * * * * Remarques : - * * * ******************************************************************************/ -static void _g_arch_instruction_print(GArchInstruction *instr, GBufferLine *line, size_t index, size_t repeat, const GBinContent *content) +static bool g_arch_instruction_store(const GSerializableObject *object, GObjectStorage *storage, int fd) { - const char *key; /* Mot clef principal */ - size_t klen; /* Taille de ce mot clef */ - size_t count; /* Nombre d'opérandes en place */ + bool result; /* Bilan à retourner */ + GArchInstruction *instr; /* Version spécialisée */ + size_t src_count; /* Quantité de sources */ + size_t dest_count; /* Quantité de destinations */ + off64_t *ins_offsets; /* Emplacements d'instructions */ size_t i; /* Boucle de parcours */ - GArchOperand *op; /* Opérande à manipuler */ + GArchInstruction *linked; /* Instruction liée */ + size_t op_count; /* Quantité d'opérandes */ + off64_t *op_offsets; /* Emplacements d'opérandes */ + GArchOperand *op; /* Opérande à traiter */ + guint extra; /* Données embarquées */ + InstructionLinkType type; /* Type de lien */ - g_buffer_line_fill_phys(line, DLC_PHYSICAL, MDS_32_BITS_UNSIGNED, get_mrange_addr(&instr->range)); + assert(g_thick_object_check_lock(G_THICK_OBJECT(object))); - g_buffer_line_fill_virt(line, DLC_VIRTUAL, MDS_32_BITS_UNSIGNED, get_mrange_addr(&instr->range)); + /* Préparation des références aux instructions liées */ - g_buffer_line_fill_content(line, DLC_BINARY, content, &instr->range, VMPA_NO_PHYSICAL); + instr = G_ARCH_INSTRUCTION(object); - /* Instruction proprement dite */ + src_count = g_arch_instruction_count_src_links(instr); + dest_count = g_arch_instruction_count_dest_links(instr); - key = g_arch_instruction_get_keyword(instr); - klen = strlen(key); + ins_offsets = malloc((src_count + dest_count) * sizeof(off64_t)); - g_buffer_line_append_text(line, DLC_ASSEMBLY_HEAD, key, klen, RTT_INSTRUCTION, G_OBJECT(instr)); + for (i = 0; i < src_count && result; i++) + { + linked = g_arch_instruction_get_linked_source(instr, i, (InstructionLinkType []) { 0 }); - /* Liste des opérandes */ + result = g_object_storage_store_object(storage, "instructions", + G_SERIALIZABLE_OBJECT(linked), &ins_offsets[i]); - g_arch_instruction_lock_operands(instr); + unref_object(linked); - count = _g_arch_instruction_count_operands(instr); + } - if (count > 0) + for (i = 0; i < dest_count && result; i++) { - op = _g_arch_instruction_get_operand(instr, 0); - g_arch_operand_print(op, line); - g_object_unref(G_OBJECT(op)); + linked = g_arch_instruction_get_linked_destination(instr, i, (InstructionLinkType []) { 0 }); - for (i = 1; i < count; i++) - { - g_buffer_line_append_text(line, DLC_ASSEMBLY, ",", 1, RTT_PUNCT, NULL); - g_buffer_line_append_text(line, DLC_ASSEMBLY, " ", 1, RTT_RAW, NULL); + result = g_object_storage_store_object(storage, "instructions", + G_SERIALIZABLE_OBJECT(linked), &ins_offsets[src_count + i]); - op = _g_arch_instruction_get_operand(instr, i); + unref_object(linked); - g_arch_operand_print(op, line); + } - g_object_unref(G_OBJECT(op)); + if (!result) + goto exit_with_ins_off; - } + /* Préparation des références aux opérandes embarqués */ - } + op_count = g_arch_instruction_count_operands(instr); - g_arch_instruction_unlock_operands(instr); + op_offsets = malloc(op_count * sizeof(off64_t)); -} + for (i = 0; i < op_count && result; i++) + { + op = g_arch_instruction_get_operand(instr, i); + result = g_object_storage_store_object(storage, "operandss", + G_SERIALIZABLE_OBJECT(op), &op_offsets[i]); -/****************************************************************************** -* * -* Paramètres : instr = générateur à utiliser pour l'impression. * -* line = ligne de rendu à compléter. * -* index = indice de cette même ligne dans le tampon global. * -* repeat = indice d'utilisations successives du générateur. * -* content = éventuel contenu binaire brut à imprimer. * -* * -* Description : Imprime dans une ligne de rendu le contenu représenté. * -* * -* Retour : - * -* * -* Remarques : - * -* * -******************************************************************************/ + unref_object(op); -static void g_arch_instruction_print(GArchInstruction *instr, GBufferLine *line, size_t index, size_t repeat, const GBinContent *content) -{ - G_ARCH_INSTRUCTION_GET_CLASS(instr)->print(instr, line, index, repeat, content); + } -} + if (!result) + goto exit_with_op_off; + /* Propriétés internes */ + extra = g_thick_object_get_extra(G_THICK_OBJECT(object)); -/* ---------------------------------------------------------------------------------- */ -/* CONSERVATION ET RECHARGEMENT DES DONNEES */ -/* ---------------------------------------------------------------------------------- */ + result = store_uleb128((uleb128_t []) { extra }, fd); + if (!result) goto exit; + /* Liaisons avec d'autres instructions */ -/****************************************************************************** -* * -* Paramètres : instr = élément GLib à constuire. * -* storage = conservateur de données à manipuler ou NULL. * -* pbuf = zone tampon à lire. * -* * -* Description : Charge un contenu depuis une mémoire tampon. * -* * -* Retour : Bilan de l'opération. * -* * -* Remarques : - * -* * -******************************************************************************/ + instr = G_ARCH_INSTRUCTION(object); -static bool _g_arch_instruction_load(GArchInstruction *instr, GObjectStorage *storage, packed_buffer_t *pbuf) -{ - bool result; /* Bilan à retourner */ - instr_extra_data_t *extra; /* Données insérées à consulter*/ - uleb128_t value; /* Valeur ULEB128 à charger */ - uleb128_t count; /* Nombre d'éléments à traiter */ - uleb128_t i; /* Boucle de parcours */ - GArchOperand *op; /* Opérande à traiter */ + src_count = g_arch_instruction_count_src_links(instr); + dest_count = g_arch_instruction_count_dest_links(instr); - extra = GET_ARCH_INSTR_EXTRA(instr); + result = store_uleb128((uleb128_t []) { src_count }, fd); + if (!result) goto exit; - LOCK_GOBJECT_EXTRA(extra); + result = store_uleb128((uleb128_t []) { dest_count }, fd); + if (!result) goto exit; - result = unpack_uleb128(&value, pbuf); + for (i = 0; i < src_count && result; i++) + { + linked = g_arch_instruction_get_linked_source(instr, i, &type); - if (result) - extra->uid = value; + result = store_uleb128((uleb128_t []) { type }, fd); - if (result) - { - result = unpack_uleb128(&value, pbuf); + unref_object(linked); if (result) - extra->flags = value; + result = store_uleb128((uleb128_t []) { ins_offsets[i] }, fd); } - UNLOCK_GOBJECT_EXTRA(extra); - - if (result) - result = unpack_mrange(&instr->range, pbuf); - - if (result) + for (i = 0; i < dest_count && result; i++) { - result = unpack_uleb128(&count, pbuf); + linked = g_arch_instruction_get_linked_destination(instr, i, &type); - for (i = 0; i < count && result; i++) - { - op = G_ARCH_OPERAND(g_object_storage_unpack_object(storage, "operands", pbuf)); - result = (op != NULL); + result = store_uleb128((uleb128_t []) { type }, fd); - if (result) - g_arch_instruction_attach_extra_operand(instr, op); + unref_object(linked); - } + if (result) + result = store_uleb128((uleb128_t []) { ins_offsets[src_count + i] }, fd); } - if (result) - result = g_arch_instruction_load_destinations(instr, storage, pbuf); - - return result; + /* Opérandes embarqués */ -} + result = store_uleb128((uleb128_t []) { op_count }, fd); + if (!result) goto exit; + for (i = 0; i < op_count && result; i++) + result = store_uleb128((uleb128_t []) { op_offsets[i] }, fd); -/****************************************************************************** -* * -* Paramètres : instr = élément GLib à constuire. * -* storage = conservateur de données à manipuler ou NULL. * -* pbuf = zone tampon à lire. * -* * -* Description : Charge un contenu depuis une mémoire tampon. * -* * -* Retour : Bilan de l'opération. * -* * -* Remarques : - * -* * -******************************************************************************/ + exit: + exit_with_op_off: -static bool g_arch_instruction_load(GArchInstruction *instr, GObjectStorage *storage, packed_buffer_t *pbuf) -{ - bool result; /* Bilan à retourner */ - GArchInstructionClass *class; /* Classe à activer */ + free(op_offsets); - class = G_ARCH_INSTRUCTION_GET_CLASS(instr); + exit_with_ins_off: - result = class->load(instr, storage, pbuf); + free(ins_offsets); return result; } -/****************************************************************************** -* * -* Paramètres : instr = élément GLib à consulter. * -* storage = conservateur de données à manipuler ou NULL. * -* pbuf = zone tampon à remplir. * -* * -* Description : Sauvegarde un contenu dans une mémoire tampon. * -* * -* Retour : Bilan de l'opération. * -* * -* Remarques : - * -* * -******************************************************************************/ -static bool _g_arch_instruction_store(GArchInstruction *instr, GObjectStorage *storage, packed_buffer_t *pbuf) -{ - bool result; /* Bilan à retourner */ - instr_extra_data_t *extra; /* Données insérées à consulter*/ - size_t count; /* Nombre d'éléments à traiter */ - size_t i; /* Boucle de parcours */ - GArchOperand *op; /* Opérande à traiter */ - - extra = GET_ARCH_INSTR_EXTRA(instr); - LOCK_GOBJECT_EXTRA(extra); - result = pack_uleb128((uleb128_t []){ extra->uid }, pbuf); - if (result) - result = pack_uleb128((uleb128_t []){ extra->flags }, pbuf); - UNLOCK_GOBJECT_EXTRA(extra); - if (result) - result = pack_mrange(&instr->range, pbuf); - if (result) - { - g_arch_instruction_lock_operands(instr); - count = _g_arch_instruction_count_operands(instr); - result = pack_uleb128((uleb128_t []){ count }, pbuf); - for (i = 0; i < count && result; i++) - { - op = _g_arch_instruction_get_operand(instr, i); - result = g_object_storage_pack_object(storage, "operands", G_SERIALIZABLE_OBJECT(op), pbuf); - g_object_unref(G_OBJECT(op)); - } - g_arch_instruction_unlock_operands(instr); - } - if (result) - result = g_arch_instruction_store_destinations(instr, storage, pbuf); +#if 0 - return result; -} /****************************************************************************** * * -* Paramètres : instr = élément GLib à consulter. * -* storage = conservateur de données à manipuler ou NULL. * -* pbuf = zone tampon à remplir. * +* Paramètres : instr = instruction quelconque à traiter. * +* type = type de procédure à utiliser. * +* proc = représentation de l'architecture utilisée. * +* context = contexte associé à la phase de désassemblage. * +* format = accès aux données du binaire d'origine. * * * -* Description : Sauvegarde un contenu dans une mémoire tampon. * +* Description : Complète un désassemblage accompli pour une instruction. * * * -* Retour : Bilan de l'opération. * +* Retour : - * * * * Remarques : - * * * ******************************************************************************/ -static bool g_arch_instruction_store(GArchInstruction *instr, GObjectStorage *storage, packed_buffer_t *pbuf) +void g_arch_instruction_call_hook(GArchInstruction *instr, InstrProcessHook type, GArchProcessor *proc, GProcContext *context, GExeFormat *format) { - bool result; /* Bilan à retourner */ - GArchInstructionClass *class; /* Classe à activer */ + GArchInstructionClass *class; /* Classe des instructions */ class = G_ARCH_INSTRUCTION_GET_CLASS(instr); - result = class->store(instr, storage, pbuf); - - return result; + if (class->call_hook != NULL) + class->call_hook(instr, type, proc, context, format); } + + + + + +#endif + + + + + + + + + + diff --git a/src/arch/instruction.h b/src/arch/instruction.h index 3c9c149..98bc73e 100644 --- a/src/arch/instruction.h +++ b/src/arch/instruction.h @@ -2,7 +2,7 @@ /* Chrysalide - Outil d'analyse de fichiers binaires * instruction.h - prototypes pour la gestion générique des instructions * - * Copyright (C) 2008-2020 Cyrille Bagard + * Copyright (C) 2008-2025 Cyrille Bagard * * This file is part of Chrysalide. * @@ -25,194 +25,118 @@ #define _ARCH_INSTRUCTION_H -#include <sys/types.h> +#include <stdbool.h> +#include <stdint.h> -#include "context.h" #include "operand.h" -#include "register.h" #include "vmpa.h" -#include "../analysis/type.h" -#include "../common/packed.h" -#include "../format/executable.h" +#include "../glibext/helpers.h" +#include "../glibext/portion.h" -#define G_TYPE_ARCH_INSTRUCTION g_arch_instruction_get_type() -#define G_ARCH_INSTRUCTION(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), g_arch_instruction_get_type(), GArchInstruction)) -#define G_IS_ARCH_INSTRUCTION(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), g_arch_instruction_get_type())) -#define G_ARCH_INSTRUCTION_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_ARCH_INSTRUCTION, GArchInstructionClass)) -#define G_IS_ARCH_INSTRUCTION_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_ARCH_INSTRUCTION)) -#define G_ARCH_INSTRUCTION_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_ARCH_INSTRUCTION, GArchInstructionClass)) +/* ----------------------- DEFINITION GENERIQUE D'INSTRUCTION ----------------------- */ -/* Définition générique d'une instruction d'architecture (instance) */ -typedef struct _GArchInstruction GArchInstruction; +#define G_TYPE_ARCH_INSTRUCTION (g_arch_instruction_get_type()) -/* Définition générique d'une instruction d'architecture (classe) */ -typedef struct _GArchInstructionClass GArchInstructionClass; +DECLARE_GTYPE(GArchInstruction, g_arch_instruction, G, ARCH_INSTRUCTION); -/* Drapeaux pour informations complémentaires */ - -#define AIF_USER_BIT 4 - -typedef enum _ArchInstrFlag -{ - AIF_NONE = (0 << 0), /* Aucune information */ - AIF_ROUTINE_START = (1 << 0), /* Début de routine */ - AIF_RETURN_POINT = (1 << 1), /* Retour de fonction appelée */ - AIF_COND_RETURN_POINT = (1 << 2), /* Retour éventuel de fonction */ - AIF_CALL = (1 << 3), /* Instruction d'appel */ - - AIF_LOW_USER = (1 << AIF_USER_BIT), /* Premier bit disponible */ - AIF_HIGH_USER = (1 << 7), /* Dernier bit disponible */ - -} ArchInstrFlag; - /* Type pour les types d'instructions */ typedef uint16_t itid_t; -/* Types de crochet de traitement */ -typedef enum _InstrProcessHook -{ - IPH_FETCH, /* Itinéraire de désassemblage */ - IPH_LINK, /* Edition des liens */ - IPH_POST, /* Résolution des symboles */ - - IPH_COUNT - -} InstrProcessHook; - - -/* Indique le type défini pour une instruction d'architecture. */ -GType g_arch_instruction_get_type(void); +/* Fournit l'identifiant correspondant à un type d'instructions. */ +itid_t g_arch_instruction_get_type_id(const GArchInstruction *); /* Indique l'encodage d'une instruction de façon détaillée. */ -const char *g_arch_instruction_get_encoding(const GArchInstruction *); - -/* Ajoute une information complémentaire à une instruction. */ -bool g_arch_instruction_set_flag(GArchInstruction *, ArchInstrFlag); +char *g_arch_instruction_get_encoding(const GArchInstruction *); -/* Retire une information complémentaire à une instruction. */ -bool g_arch_instruction_unset_flag(GArchInstruction *, ArchInstrFlag); - -/* Détermine si une instruction possède un fanion particulier. */ -bool g_arch_instruction_has_flag(const GArchInstruction *, ArchInstrFlag); +/* Fournit le nom humain de l'instruction manipulée. */ +char *g_arch_instruction_get_keyword(const GArchInstruction *); -/* Fournit les informations complémentaires d'une instruction. */ -ArchInstrFlag g_arch_instruction_get_flags(const GArchInstruction *); -/* Définit l'identifiant unique pour un ensemble d'instructions. */ -void g_arch_instruction_set_unique_id(GArchInstruction *, itid_t); + /* Type de masques pour les encodages d'instructions */ +typedef enum _InstructionBytesMask +{ + /** + * Correspond aux bits fixes : pas de valeurs de registre ni de valeur entière. + */ + IBM_LOOSE, -/* Fournit l'identifiant unique pour un ensemble d'instructions. */ -itid_t g_arch_instruction_get_unique_id(const GArchInstruction *); + /** + * Dissimulation des références à des éléments externes pouvant varier avec + * entre compilations : adresses de saut ou d'appel, références vers des tables, + * etc. + */ + IBM_LOCAL, + /** + * Dissimulation des déplacements à partir d'une base. + */ + IBM_STRICT, -/** - * La définition de "GArchProcessor", utile aux traitements complémentaires, ne peut - * se faire en incluant le fichier d'en-tête "processor.h", pour cause de références - * circulaires. - * - * On procède donc à une seconde déclaration, en attendant éventuellement mieux. - */ + /** + * Conservation de toutes les valeurs immédiates et dissimulation des registres. + */ + IBM_LARGE, -/* Depuis "processeur.h" : définition générique d'un processeur d'architecture (instance) */ -typedef struct _GArchProcessor GArchProcessor; + IBM_COUNT +} InstructionBytesMask; -/* Complète un désassemblage accompli pour une instruction. */ -typedef void (* instr_hook_fc) (GArchInstruction *, GArchProcessor *, GProcContext *, GExeFormat *); - -/* Complète un désassemblage accompli pour une instruction. */ -void g_arch_instruction_call_hook(GArchInstruction *, InstrProcessHook, GArchProcessor *, GProcContext *, GExeFormat *); -/* Définit la localisation d'une instruction. */ -void g_arch_instruction_set_range(GArchInstruction *, const mrange_t *); +/* Calcule la localisation d'une instruction. */ +void g_arch_instruction_compute_range(GArchInstruction *, GBinaryPortion *, const vmpa2t *, phys_t); /* Fournit la place mémoire d'une instruction. */ -const mrange_t *g_arch_instruction_get_range(const GArchInstruction *); - - - -/* Fournit la localisation d'une instruction. */ -void g_arch_instruction_get_location(const GArchInstruction *, off_t *, off_t *, vmpa_t *) __attribute__ ((deprecated)); +bool g_arch_instruction_get_range(const GArchInstruction *, mrange_t *); +#define AIF_USER_BIT 4 -/* Liste les registres lus et écrits par l'instruction. */ -void g_arch_instruction_get_rw_registers(const GArchInstruction *, GArchRegister ***, size_t *, GArchRegister ***, size_t *) __attribute__ ((deprecated)); +typedef enum _ArchInstructionFlag +{ + AIF_NONE = (0 << 0), /* Aucune information */ + AIF_ROUTINE_START = (1 << 0), /* Début de routine */ + AIF_RETURN_POINT = (1 << 1), /* Retour de fonction appelée */ + AIF_COND_RETURN_POINT = (1 << 2), /* Retour éventuel de fonction */ + AIF_CALL = (1 << 3), /* Instruction d'appel */ + AIF_LOW_USER = (1 << AIF_USER_BIT), /* Premier bit disponible */ + AIF_HIGH_USER = (1 << 7), /* Dernier bit disponible */ +} ArchInstructionFlag; -/* --------------------------- MANIPULATION DES OPERANDES --------------------------- */ +#define AIF_USER_FLAG(n) (1 << (AIF_USER_BIT + n)) -/* Verrouille les accès à la liste des opérandes. */ -void g_arch_instruction_lock_operands(GArchInstruction *); +/* Ajoute une information complémentaire à une instruction. */ +bool g_arch_instruction_set_flag(GArchInstruction *, ArchInstructionFlag); -/* Déverrouille les accès à la liste des opérandes. */ -void g_arch_instruction_unlock_operands(GArchInstruction *); +/* Retire une information complémentaire à une instruction. */ +bool g_arch_instruction_unset_flag(GArchInstruction *, ArchInstructionFlag); -/* Attache un opérande supplémentaire à une instruction. */ -void g_arch_instruction_attach_extra_operand(GArchInstruction *, GArchOperand *); +/* Détermine si une instruction possède un fanion particulier. */ +bool g_arch_instruction_has_flag(const GArchInstruction *, ArchInstructionFlag); -/* Indique la quantité d'opérandes présents dans l'instruction. */ -size_t _g_arch_instruction_count_operands(const GArchInstruction *); +/* Fournit les particularités de l'instruction. */ +ArchInstructionFlag g_arch_instruction_get_flags(const GArchInstruction *); -/* Fournit un opérande donné d'une instruction. */ -GArchOperand *_g_arch_instruction_get_operand(const GArchInstruction *, size_t); -/* Remplace un opérande d'une instruction par un autre. */ -bool _g_arch_instruction_replace_operand(GArchInstruction *, GArchOperand *, GArchOperand *); +/* Types de crochet de traitement */ +typedef enum _InstrProcessHook +{ + IPH_FETCH, /* Itinéraire de désassemblage */ + IPH_LINK, /* Edition des liens */ + IPH_POST, /* Résolution des symboles */ -/* Détache un opérande liée d'une instruction. */ -bool _g_arch_instruction_detach_operand(GArchInstruction *, GArchOperand *); - - -#define g_arch_instruction_count_operands(ins) \ - ({ \ - size_t __result; \ - g_arch_instruction_lock_operands(ins); \ - __result = _g_arch_instruction_count_operands(ins); \ - g_arch_instruction_unlock_operands(ins); \ - __result; \ - }) - -#define g_arch_instruction_get_operand(ins, idx) \ - ({ \ - GArchOperand *__result; \ - g_arch_instruction_lock_operands(ins); \ - __result = _g_arch_instruction_get_operand(ins, idx); \ - g_arch_instruction_unlock_operands(ins); \ - __result; \ - }) - -#define g_arch_instruction_replace_operand(ins, o, n) \ - ({ \ - bool __result; \ - g_arch_instruction_lock_operands(ins); \ - __result = _g_arch_instruction_replace_operand(ins, o, n); \ - g_arch_instruction_unlock_operands(ins); \ - __result; \ - }) - -#define g_arch_instruction_detach_operand(ins, o) \ - ({ \ - bool __result; \ - g_arch_instruction_lock_operands(ins); \ - __result = _g_arch_instruction_detach_operand(ins, o); \ - g_arch_instruction_unlock_operands(ins); \ - __result; \ - }) + IPH_COUNT +} InstrProcessHook; -/* Détermine le chemin conduisant à un opérande. */ -char *g_arch_instruction_find_operand_path(GArchInstruction *, const GArchOperand *); -/* Obtient l'opérande correspondant à un chemin donné. */ -GArchOperand *g_arch_instruction_get_operand_from_path(GArchInstruction *, const char *); @@ -236,30 +160,24 @@ typedef enum _InstructionLinkType } InstructionLinkType; -/* Déscription d'une liaison entre deux instructions */ -typedef struct _instr_link_t -{ - GArchInstruction *linked; /* Autre instruction liée */ - InstructionLinkType type; /* Type de liaison */ - -} instr_link_t; - -#define ref_instr_link(l) g_object_ref(G_OBJECT(l->linked)); -#define unref_instr_link(l) g_object_unref(G_OBJECT(l->linked)); +/* Détermine si un type de lien amène à une instruction. */ +bool g_arch_instruction_has_src_link(const GArchInstruction *, InstructionLinkType); +/* Détermine si un type de lien émerge d'une instruction. */ +bool g_arch_instruction_has_dest_link(const GArchInstruction *, InstructionLinkType); -/* Met à disposition un encadrement des accès aux liens. */ -void g_arch_instruction_lock_unlock_links(GArchInstruction *, bool, bool); +/* Détermine si une instruction est source d'une autre. */ +bool g_arch_instruction_has_src_link_with(const GArchInstruction *, const GArchInstruction *); -/* Détermine si un type de lien existe dans une instruction. */ -bool g_arch_instruction_has_link(GArchInstruction *, InstructionLinkType); - -/* Détermine si un lien est déjà établi entre deux instructions. */ -bool g_arch_instruction_has_link_to(GArchInstruction *, const GArchInstruction *); +/* Détermine si une instruction est destination d'une autre. */ +bool g_arch_instruction_has_dest_link_with(const GArchInstruction *, const GArchInstruction *); /* Etablit un lien entre deux instructions. */ -void g_arch_instruction_link_with(GArchInstruction *, GArchInstruction *, InstructionLinkType); +void g_arch_instruction_link(GArchInstruction *, GArchInstruction *, InstructionLinkType); + +/* Supprime un lien entre deux instructions. */ +void g_arch_instruction_unlink(GArchInstruction *, GArchInstruction *, InstructionLinkType); /* Change la nature d'un lien entre deux instructions. */ bool g_arch_instruction_change_link(GArchInstruction *, GArchInstruction *, InstructionLinkType, InstructionLinkType); @@ -267,46 +185,72 @@ bool g_arch_instruction_change_link(GArchInstruction *, GArchInstruction *, Inst /* Supprime tous les liens établis avec d'autres instructions. */ void g_arch_instruction_delete_all_links(GArchInstruction *); -#define g_arch_instruction_lock_src(ins) g_arch_instruction_lock_unlock_links(ins, true, true) -#define g_arch_instruction_unlock_src(ins) g_arch_instruction_lock_unlock_links(ins, true, false) +/* Fournit la quantité d'instructions placées en source. */ +size_t g_arch_instruction_count_src_links(const GArchInstruction *); -/* Fournit la quantité d'instructions pointant vers une autre. */ -size_t g_arch_instruction_count_sources(const GArchInstruction *); +/* Fournit la quantité d'instructions placées en destination. */ +size_t g_arch_instruction_count_dest_links(const GArchInstruction *); -/* Fournit les détails d'une origine d'une instruction donnée. */ -const instr_link_t *g_arch_instruction_get_source(GArchInstruction *, size_t); +/* Fournit les détails d'une source donnée d'une instruction. */ +GArchInstruction *g_arch_instruction_get_linked_source(const GArchInstruction *, size_t, InstructionLinkType *); -/* Fournit tous les détails d'origine d'une instruction donnée. */ -instr_link_t *g_arch_instruction_get_sources(GArchInstruction *, size_t *); +/* Fournit les détails d'une destination donnée d'une instruction. */ +GArchInstruction *g_arch_instruction_get_linked_destination(const GArchInstruction *, size_t, InstructionLinkType *); -#define g_arch_instruction_lock_dest(ins) g_arch_instruction_lock_unlock_links(ins, false, true) -#define g_arch_instruction_unlock_dest(ins) g_arch_instruction_lock_unlock_links(ins, false, false) -/* Donne le nombre d'instructions non naturellement suivantes. */ -size_t g_arch_instruction_count_destinations(const GArchInstruction *); -/* Fournit les détails d'une destination d'une instruction. */ -const instr_link_t *g_arch_instruction_get_destination(GArchInstruction *, size_t); +/* --------------------------- MANIPULATION DES OPERANDES --------------------------- */ -/* Fournit la destination d'une instruction et d'un type donné. */ -GArchInstruction *g_arch_instruction_get_given_destination(GArchInstruction *, InstructionLinkType); -/* Fournit tous les détails de destination d'une instruction. */ -instr_link_t *g_arch_instruction_get_destinations(GArchInstruction *, size_t *); +/* Indique la quantité d'opérandes présents dans l'instruction. */ +size_t g_arch_instruction_count_operands(const GArchInstruction *); +/* Attache un opérande supplémentaire à une instruction. */ +void g_arch_instruction_attach_operand(GArchInstruction *, GArchOperand *); +/* Remplace un opérande d'une instruction par un autre. */ +bool g_arch_instruction_replace_operand(GArchInstruction *, GArchOperand *, GArchOperand *); -/* --------------------- CONVERSIONS DU FORMAT DES INSTRUCTIONS --------------------- */ +/* Détache un opérande liée d'une instruction. */ +bool g_arch_instruction_detach_operand(GArchInstruction *, GArchOperand *); +/* Fournit un opérande donné d'une instruction. */ +GArchOperand *g_arch_instruction_get_operand(const GArchInstruction *, size_t); + +/* Détermine le chemin conduisant à un opérande. */ +char *g_arch_instruction_find_operand_path(GArchInstruction *, const GArchOperand *); + +/* Obtient l'opérande correspondant à un chemin donné. */ +GArchOperand *g_arch_instruction_get_operand_from_path(GArchInstruction *, const char *); + + + + +#if 0 + + + +/** + * La définition de "GArchProcessor", utile aux traitements complémentaires, ne peut + * se faire en incluant le fichier d'en-tête "processor.h", pour cause de références + * circulaires. + * + * On procède donc à une seconde déclaration, en attendant éventuellement mieux. + */ + +/* Depuis "processeur.h" : définition générique d'un processeur d'architecture (instance) */ +typedef struct _GArchProcessor GArchProcessor; + + +/* Complète un désassemblage accompli pour une instruction. */ +typedef void (* instr_hook_fc) (GArchInstruction *, GArchProcessor *, GProcContext *, GExeFormat *); + +/* Complète un désassemblage accompli pour une instruction. */ +void g_arch_instruction_call_hook(GArchInstruction *, InstrProcessHook, GArchProcessor *, GProcContext *, GExeFormat *); -/* Fournit le nom humain de l'instruction manipulée. */ -const char *g_arch_instruction_get_keyword(GArchInstruction *); -/* Construit un petit résumé concis de l'instruction. */ -char *g_arch_instruction_build_tooltip(const GArchInstruction *); -/* Fournit une description pour l'instruction manipulée. */ -const char *g_arch_instruction_get_description(const GArchInstruction *); +#endif diff --git a/src/arch/instructions/Makefile.am b/src/arch/instructions/Makefile.am index 28cf90f..d6fc4bd 100644 --- a/src/arch/instructions/Makefile.am +++ b/src/arch/instructions/Makefile.am @@ -1,12 +1,19 @@ -noinst_LTLIBRARIES = libarchinstructions.la +noinst_LTLIBRARIES = libarchinstructions.la libarchinstructionsui.la libarchinstructions_la_SOURCES = \ + raw-int.h \ raw.h raw.c \ undefined-int.h \ undefined.h undefined.c -libarchinstructions_la_CFLAGS = $(TOOLKIT_CFLAGS) $(LIBXML_CFLAGS) +libarchinstructions_la_CFLAGS = $(LIBGOBJ_CFLAGS) + +libarchinstructionsui_la_SOURCES = \ + raw-ui.h raw-ui.c \ + undefined-ui.h undefined-ui.c + +libarchinstructionsui_la_CFLAGS = $(LIBGTK4_CFLAGS) devdir = $(includedir)/chrysalide/$(subdir:src/%=core/%) diff --git a/src/arch/instructions/raw-int.h b/src/arch/instructions/raw-int.h new file mode 100644 index 0000000..4a5e64b --- /dev/null +++ b/src/arch/instructions/raw-int.h @@ -0,0 +1,56 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * raw-int.h - prototypes pour la définition interne des instructions de données brutes + * + * Copyright (C) 2025 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Chrysalide. If not, see <http://www.gnu.org/licenses/>. + */ + + +#ifndef _ARCH_INSTRUCTIONS_RAW_INT_H +#define _ARCH_INSTRUCTIONS_RAW_INT_H + + +#include "raw.h" +#include "../instruction-int.h" + + + +/* Définition générique d'une instruction brute d'architecture (instance) */ +struct _GRawInstruction +{ + GArchInstruction parent; /* A laisser en premier */ + +}; + +/* Définition générique d'une instruction brute d'architecture (instance) */ +struct _GRawInstructionClass +{ + GArchInstructionClass parent; /* A laisser en premier */ + +}; + + +/* Met en place une instruction de type 'db/dw/etc' simple. */ +bool g_raw_instruction_create_value(GRawInstruction *, GBinaryPortion *, const vmpa2t *, MemoryDataSize, uint64_t); + +/* Met en place une instruction de type 'db/dw/etc' étendue. */ +bool g_raw_instruction_create_array(GRawInstruction *, GBinaryPortion *, vmpa2t *, MemoryDataSize, const GBinContent *, size_t, SourceEndian); + + + +#endif /* _ARCH_INSTRUCTIONS_RAW_INT_H */ diff --git a/src/arch/instructions/raw-ui.c b/src/arch/instructions/raw-ui.c new file mode 100644 index 0000000..1026dfb --- /dev/null +++ b/src/arch/instructions/raw-ui.c @@ -0,0 +1,261 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * raw-ui.c - opérandes représentant des instructions de données brutes sous forme graphique + * + * Copyright (C) 2025 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Chrysalide. If not, see <http://www.gnu.org/licenses/>. + */ + + +#include "raw-ui.h" + + +#include <assert.h> +#include <ctype.h> +#include <malloc.h> + + +#include "raw.h" +#include "../operand-ui.h" +#include "../operands/immediate.h" +#include "../../glibext/objhole.h" +#include "../../glibext/options/asm.h" + + + +/* Etablit dans une ligne de rendu le contenu représenté. */ +static void g_raw_instruction_ui_populate_line(const GTokenGenerator *, size_t, size_t, GBufferLine *, void *); + + + +/****************************************************************************** +* * +* Paramètres : iface = interface GLib à initialiser. * +* * +* Description : Procède à l'initialisation de l'interface de génération. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +void g_raw_instruction_ui_token_generator_iface_init(GTokenGeneratorInterface *iface) +{ + iface->populate = g_raw_instruction_ui_populate_line; + +} + + +/****************************************************************************** +* * +* Paramètres : generator = générateur à utiliser pour l'impression. * +* index = indice de cette même ligne dans le tampon global.* +* repeat = indice d'utilisations successives du générateur. * +* line = ligne de rendu à compléter. * +* data = éventuelle donnée complémentaire fournie. * +* * +* Description : Etablit dans une ligne de rendu le contenu représenté. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_raw_instruction_ui_populate_line(const GTokenGenerator *generator, size_t index, size_t repeat, GBufferLine *line, void *data) +{ + GArchInstruction *instr; /* Version spécialisée #1 */ + GRawInstruction *raw; /* Version spécialisée #2 */ + GBinContent *content; /* Contenu brut d'origine */ + mrange_t range; /* Emplacement couvert */ + phys_t max_displayed_len; /* Quantité de code affichée */ + char *key; /* Mot clef principal */ + char *string; /* Chaîne reconstituée */ + size_t iter; /* Tête d'écriture */ + bool first; /* Mémorise une énumération */ + size_t count; /* Nombre d'opérandes en place */ + size_t i; /* Boucle de parcours */ + GArchOperand *op; /* Opérande à manipuler */ + GImmediateOperand *imm; /* Version opérande de valeur */ + char byte; /* Octet à afficher (ou pas) */ +#ifndef NDEBUG + bool status; /* Bilan d'une récupération */ +#endif + + instr = G_ARCH_INSTRUCTION(generator); + raw = G_RAW_INSTRUCTION(instr); + content = G_BIN_CONTENT(data); + + g_thick_object_lock(G_THICK_OBJECT(instr)); + + /* Prologue */ + + if (g_arch_instruction_get_range(instr, &range)) + { + /* Localisation */ + + g_buffer_line_fill_physical(line, ACO_PHYSICAL, MDS_32_BITS_UNSIGNED, get_mrange_addr(&range)); + + g_buffer_line_fill_virtual(line, ACO_VIRTUAL, MDS_32_BITS_UNSIGNED, get_mrange_addr(&range)); + + /* Contenu */ + + if (g_raw_instruction_is_padding(raw)) + max_displayed_len = 0; + + else if (g_raw_instruction_is_string(raw)) + max_displayed_len = 1; + + else + { + max_displayed_len = get_mrange_length(&range); + max_displayed_len /= g_arch_instruction_count_operands(instr); + } + + g_buffer_line_fill_content(line, ACO_BINARY, content, &range, max_displayed_len); + + } + + /* Instruction proprement dite */ + + key = g_arch_instruction_get_keyword(instr); + + g_buffer_line_append_text(line, ACO_ASSEMBLY_HEAD, TRT_INSTRUCTION, SL(key), NULL, G_OBJECT(instr)); + + free(key); + + /* Contenu sous forme d'opérandes */ + + if (g_raw_instruction_is_padding(raw)) + g_buffer_line_append_text(line, ACO_ASSEMBLY, TRT_CHR_PRINTABLE, STCSL("..."), NULL, NULL); + + else + { + string = NULL; + iter = 0; + + first = true; + + count = g_arch_instruction_count_operands(instr); + + for (i = 0; i < count; i++) + { + op = g_arch_instruction_get_operand(instr, i); + + if (!G_IS_IMMEDIATE_OPERAND(op)) + goto fallback; + + imm = G_IMMEDIATE_OPERAND(op); + + if (g_immediate_operand_get_size(imm) != MDS_8_BITS) + goto fallback; + + if (!g_raw_instruction_is_string(raw) && g_immediate_operand_get_display(imm) != IOD_CHAR) + goto fallback; + +#ifndef NDEBUG + status = g_immediate_operand_get_value(imm, MDS_8_BITS, &byte); + assert(status); +#else + g_immediate_operand_get_value(imm, MDS_8_BITS, &byte); +#endif + + /* Si le caractère doit apparaître en hexadécimal... */ + + if (!isprint(byte)) + goto fallback; + + /* Impression de l'octet */ + + if (string == NULL) + { + string = calloc(count + 3, sizeof(char)); + + strcpy(string, "\""); + iter = 1; + + } + + string[iter++] = byte; + + unref_object(op); + + continue; + + fallback: + + /* Si une chaîne précède */ + + if (string != NULL && iter > 1) + { + if (!first) + { + g_buffer_line_append_text(line, ACO_ASSEMBLY, TRT_PUNCT, STCSL(","), NULL, NULL); + g_buffer_line_append_text(line, ACO_ASSEMBLY, TRT_CHR_PRINTABLE, STCSL(" "), NULL, NULL); + } + else + first = false; + + string[iter++] = '"'; + + g_buffer_line_append_text(line, ACO_ASSEMBLY, TRT_STRING, string, iter, NULL, NULL); + + iter = 1; + + } + + /* Intégration en tant qu'opérande classique */ + + if (!first) + { + g_buffer_line_append_text(line, ACO_ASSEMBLY, TRT_PUNCT, STCSL(","), NULL, NULL); + g_buffer_line_append_text(line, ACO_ASSEMBLY, TRT_CHR_PRINTABLE, STCSL(" "), NULL, NULL); + } + else + first = false; + + g_arch_operand_ui_print(G_ARCH_OPERAND_UI(op), line); + + unref_object(op); + + } + + /* Si au final une chaîne traine encore */ + + if (string != NULL && iter > 1) + { + if (!first) + { + g_buffer_line_append_text(line, ACO_ASSEMBLY, TRT_PUNCT, STCSL(","), NULL, NULL); + g_buffer_line_append_text(line, ACO_ASSEMBLY, TRT_CHR_PRINTABLE, STCSL(" "), NULL, NULL); + } + + string[iter++] = '"'; + + g_buffer_line_append_text(line, ACO_ASSEMBLY, TRT_STRING, string, iter, NULL, NULL); + + } + + if (string != NULL) + free(string); + + } + + g_thick_object_unlock(G_THICK_OBJECT(instr)); + +} diff --git a/src/arch/instructions/raw-ui.h b/src/arch/instructions/raw-ui.h new file mode 100644 index 0000000..cd604e6 --- /dev/null +++ b/src/arch/instructions/raw-ui.h @@ -0,0 +1,37 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * raw-ui.h - prototypes pour les opérandes représentant des instructions de données brutes sous forme graphique + * + * Copyright (C) 2025 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Chrysalide. If not, see <http://www.gnu.org/licenses/>. + */ + + +#ifndef _ARCH_OPERANDS_RAW_UI_H +#define _ARCH_OPERANDS_RAW_UI_H + + +#include "../../glibext/generator-int.h" + + + +/* Procède à l'initialisation de l'interface de génération. */ +void g_raw_instruction_ui_token_generator_iface_init(GTokenGeneratorInterface *); + + + +#endif /* _ARCH_OPERANDS_RAW_UI_H */ diff --git a/src/arch/instructions/raw.c b/src/arch/instructions/raw.c index 26282fa..87297f1 100644 --- a/src/arch/instructions/raw.c +++ b/src/arch/instructions/raw.c @@ -2,7 +2,7 @@ /* Chrysalide - Outil d'analyse de fichiers binaires * raw.c - instructions pures vues de l'esprit * - * Copyright (C) 2014-2020 Cyrille Bagard + * Copyright (C) 2014-2025 Cyrille Bagard * * This file is part of Chrysalide. * @@ -25,36 +25,19 @@ #include <assert.h> -#include <ctype.h> #include <string.h> #include <i18n.h> -#include "../instruction-int.h" +#include "raw-int.h" #include "../operands/immediate.h" -#include "../operands/target.h" -#include "../../core/columns.h" +//#include "../operands/target.h" // FIXME -/* ------------------------- INSTRUCTION INCONNUE / DONNEES ------------------------- */ - - -/* Définition générique d'une instruction brute d'architecture (instance) */ -struct _GRawInstruction -{ - GArchInstruction parent; /* A laisser en premier */ - -}; - -/* Définition générique d'une instruction brute d'architecture (classe) */ -struct _GRawInstructionClass -{ - GArchInstructionClass parent; /* A laisser en premier */ - -}; +/* --------------------- INSTRUCTION AVEC JEU DE DONNEES BRUTES --------------------- */ /* Initialise la classe des instructions brutes d'architecture. */ @@ -64,40 +47,26 @@ static void g_raw_instruction_class_init(GRawInstructionClass *); static void g_raw_instruction_init(GRawInstruction *); /* Supprime toutes les références externes. */ -static void g_raw_instruction_dispose(GRawInstruction *); +static void g_raw_instruction_dispose(GObject *); /* Procède à la libération totale de la mémoire. */ -static void g_raw_instruction_finalize(GRawInstruction *); - -/* Indique l'encodage d'une instruction de façon détaillée. */ -static const char *g_raw_instruction_get_encoding(const GRawInstruction *); - -/* Fournit le nom humain de l'instruction manipulée. */ -static const char *g_raw_instruction_get_keyword(const GRawInstruction *); +static void g_raw_instruction_finalize(GObject *); -/* -------------------- CONSERVATION SUR DISQUE DES INSTRUCTIONS -------------------- */ +/* --------------------- IMPLEMENTATION DES FONCTIONS DE CLASSE --------------------- */ -/* Charge une instruction depuis une mémoire tampon. */ -static bool g_raw_instruction_unserialize(GRawInstruction *, GAsmStorage *, GBinFormat *, packed_buffer_t *); - -/* Sauvegarde une instruction dans une mémoire tampon. */ -static bool g_raw_instruction_serialize(GRawInstruction *, GAsmStorage *, packed_buffer_t *); - - - -/* ------------------------ OFFRE DE CAPACITES DE GENERATION ------------------------ */ - +/* Indique l'encodage d'une instruction de façon détaillée. */ +static char *g_raw_instruction_get_encoding(const GArchInstruction *); -/* Ajoute à un tampon GLib le contenu de l'instance spécifiée. */ -static void g_raw_instruction_print(GRawInstruction *, GBufferLine *, size_t, size_t, const GBinContent *); +/* Fournit le nom humain de l'instruction manipulée. */ +static char *g_raw_instruction_get_keyword(const GArchInstruction *); /* ---------------------------------------------------------------------------------- */ -/* INSTRUCTION INCONNUE / DONNEES */ +/* INSTRUCTION AVEC JEU DE DONNEES BRUTES */ /* ---------------------------------------------------------------------------------- */ @@ -124,18 +93,13 @@ static void g_raw_instruction_class_init(GRawInstructionClass *klass) object = G_OBJECT_CLASS(klass); - object->dispose = (GObjectFinalizeFunc/* ! */)g_raw_instruction_dispose; - object->finalize = (GObjectFinalizeFunc)g_raw_instruction_finalize; + object->dispose = g_raw_instruction_dispose; + object->finalize = g_raw_instruction_finalize; instr = G_ARCH_INSTRUCTION_CLASS(klass); - instr->get_encoding = (get_instruction_encoding_fc)g_raw_instruction_get_encoding; - instr->get_keyword = (get_instruction_keyword_fc)g_raw_instruction_get_keyword; - - instr->unserialize = (unserialize_instruction_fc)g_raw_instruction_unserialize; - instr->serialize = (serialize_instruction_fc)g_raw_instruction_serialize; - - instr->print = (print_instruction_fc)g_raw_instruction_print; + instr->get_encoding = g_raw_instruction_get_encoding; + instr->get_keyword = g_raw_instruction_get_keyword; } @@ -160,7 +124,7 @@ static void g_raw_instruction_init(GRawInstruction *instr) /****************************************************************************** * * -* Paramètres : instr = instance d'objet GLib à traiter. * +* Paramètres : object = instance d'objet GLib à traiter. * * * * Description : Supprime toutes les références externes. * * * @@ -170,16 +134,16 @@ static void g_raw_instruction_init(GRawInstruction *instr) * * ******************************************************************************/ -static void g_raw_instruction_dispose(GRawInstruction *instr) +static void g_raw_instruction_dispose(GObject *object) { - G_OBJECT_CLASS(g_raw_instruction_parent_class)->dispose(G_OBJECT(instr)); + G_OBJECT_CLASS(g_raw_instruction_parent_class)->dispose(object); } /****************************************************************************** * * -* Paramètres : instr = instance d'objet GLib à traiter. * +* Paramètres : object = instance d'objet GLib à traiter. * * * * Description : Procède à la libération totale de la mémoire. * * * @@ -189,16 +153,17 @@ static void g_raw_instruction_dispose(GRawInstruction *instr) * * ******************************************************************************/ -static void g_raw_instruction_finalize(GRawInstruction *instr) +static void g_raw_instruction_finalize(GObject *object) { - G_OBJECT_CLASS(g_raw_instruction_parent_class)->finalize(G_OBJECT(instr)); + G_OBJECT_CLASS(g_raw_instruction_parent_class)->finalize(object); } /****************************************************************************** * * -* Paramètres : addr = position à associer à l'instruction. * +* Paramètres : area = portion de binaire incluant l'instruction. * +* addr = adresse virtuelle et/ou position physique. * * size = taille de l'opérande souhaitée. * * value = valeur sur x bits à venir récupérer. * * * @@ -210,127 +175,106 @@ static void g_raw_instruction_finalize(GRawInstruction *instr) * * ******************************************************************************/ -GArchInstruction *g_raw_instruction_new_from_value(const vmpa2t *addr, MemoryDataSize size, uint64_t value) +GArchInstruction *g_raw_instruction_new_from_value(GBinaryPortion *area, const vmpa2t *addr, MemoryDataSize size, uint64_t value) { GArchInstruction *result; /* Instruction à retourner */ - GArchOperand *operand; /* Octet non décodé à afficher */ - mrange_t range; /* Couverture de l'instruction */ result = g_object_new(G_TYPE_RAW_INSTRUCTION, NULL); - operand = g_imm_operand_new_from_value(size, value); - if (operand == NULL) goto error; + if (!g_raw_instruction_create_value(G_RAW_INSTRUCTION(result), area, addr, size, value)) + g_clear_object(&result); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : instr = instance à initialiser pleinement. * +* area = portion de binaire incluant l'instruction. * +* addr = adresse virtuelle et/ou position physique. * +* size = taille de chacun des éléments à représenter. * +* value = valeur sur x bits à venir récupérer. * +* * +* Description : Met en place une instruction de type 'db/dw/etc' simple. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool g_raw_instruction_create_value(GRawInstruction *instr, GBinaryPortion *area, const vmpa2t *addr, MemoryDataSize size, uint64_t value) +{ + bool result; /* Bilan à retourner */ + GArchOperand *operand; /* Octet non décodé à afficher */ + uint16_t length; /* Taille de l'instruction */ + + result = false; + + operand = g_immediate_operand_new_from_value(size, value); + if (operand == NULL) goto exit; g_arch_operand_set_flag(operand, IOF_ZERO_PADDING_BY_DEFAULT | IOF_ZERO_PADDING); - g_arch_instruction_attach_extra_operand(result, operand); + g_thick_object_lock(G_THICK_OBJECT(instr)); + + g_arch_instruction_attach_operand(G_ARCH_INSTRUCTION(instr), operand); + unref_object(operand); + + g_thick_object_unlock(G_THICK_OBJECT(instr)); switch (size) { case MDS_8_BITS_UNSIGNED: case MDS_8_BITS_SIGNED: - init_mrange(&range, addr, 1); + length = 1; break; case MDS_16_BITS_UNSIGNED: case MDS_16_BITS_SIGNED: - init_mrange(&range, addr, 2); + length = 2; break; case MDS_32_BITS_UNSIGNED: case MDS_32_BITS_SIGNED: - init_mrange(&range, addr, 4); + length = 4; break; case MDS_64_BITS_UNSIGNED: case MDS_64_BITS_SIGNED: - init_mrange(&range, addr, 8); + length = 8; break; default: assert(false); - goto error; + goto exit; break; } - g_arch_instruction_set_range(result, &range); + g_arch_instruction_compute_range(G_ARCH_INSTRUCTION(instr), area, addr, length); - return result; - - error: - - g_object_unref(G_OBJECT(result)); - - return NULL; - -} + result = true; - -/****************************************************************************** -* * -* Paramètres : content = flux de données à analyser. * -* addr = position courante dans ce flux. [OUT] * -* * -* Description : Crée une instruction de type 'db/dw/etc' pour un uleb128. * -* * -* Retour : Instruction mise en place. * -* * -* Remarques : - * -* * -******************************************************************************/ - -GArchInstruction *g_raw_instruction_new_uleb128(const GBinContent *content, vmpa2t *addr) -{ - GArchInstruction *result; /* Instruction à retourner */ - vmpa2t start; /* Départ original de lecture */ - uleb128_t value; /* Valeur uleb128 à représenter*/ - phys_t diff; /* Couverture de la lecture */ - MemoryDataSize leb_size; /* Taille de la valeur */ - GArchOperand *operand; /* Octet non décodé à afficher */ - mrange_t range; /* Couverture de l'instruction */ - - result = NULL; - - copy_vmpa(&start, addr); - - if (!g_binary_content_read_uleb128(content, addr, &value)) - goto error; - - diff = compute_vmpa_diff(&start, addr); - - leb_size = MDS_FROM_BYTES(diff); - assert(leb_size != MDS_UNDEFINED); - - result = g_object_new(G_TYPE_RAW_INSTRUCTION, NULL); - - init_mrange(&range, &start, diff); - g_arch_instruction_set_range(result, &range); - - operand = g_imm_operand_new_from_value(leb_size, (uint64_t)value); - if (operand == NULL) goto error; - - g_arch_operand_set_flag(operand, IOF_ZERO_PADDING_BY_DEFAULT | IOF_ZERO_PADDING); - - g_arch_instruction_attach_extra_operand(result, operand); + exit: return result; - error: - - g_clear_object(&result); - - return NULL; - } /****************************************************************************** * * -* Paramètres : content = flux de données à analyser. * -* addr = position courante dans ce flux. [OUT] * +* Paramètres : area = portion de binaire incluant l'instruction. * +* addr = adresse virtuelle et/ou position physique. * +* size = taille de chacun des éléments à représenter. * +* content = flux de données à analyser. * +* count = nombre de ces éléments. * +* endian = ordre des bits dans la source. * * * -* Description : Crée une instruction de type 'db/dw/etc' pour un sleb128. * +* Description : Crée une instruction de type 'db/dw/etc' étendue. * * * * Retour : Instruction mise en place. * * * @@ -338,256 +282,174 @@ GArchInstruction *g_raw_instruction_new_uleb128(const GBinContent *content, vmpa * * ******************************************************************************/ -GArchInstruction *g_raw_instruction_new_sleb128(const GBinContent *content, vmpa2t *addr) +GArchInstruction *g_raw_instruction_new_array(GBinaryPortion *area, vmpa2t *addr, MemoryDataSize size, const GBinContent *content, size_t count, SourceEndian endian) { GArchInstruction *result; /* Instruction à retourner */ - vmpa2t start; /* Départ original de lecture */ - uleb128_t value; /* Valeur uleb128 à représenter*/ - phys_t diff; /* Couverture de la lecture */ - MemoryDataSize leb_size; /* Taille de la valeur */ - GArchOperand *operand; /* Octet non décodé à afficher */ - mrange_t range; /* Couverture de l'instruction */ - - result = NULL; - - copy_vmpa(&start, addr); - - if (!g_binary_content_read_uleb128(content, addr, &value)) - goto error; - - diff = compute_vmpa_diff(&start, addr); - - leb_size = MDS_FROM_BYTES(diff) | MDS_SIGN; - assert(leb_size != MDS_SIGN); result = g_object_new(G_TYPE_RAW_INSTRUCTION, NULL); - init_mrange(&range, &start, diff); - g_arch_instruction_set_range(result, &range); - - operand = g_imm_operand_new_from_value(leb_size, (uint64_t)value); - if (operand == NULL) goto error; - - g_arch_operand_set_flag(operand, IOF_ZERO_PADDING_BY_DEFAULT | IOF_ZERO_PADDING); - - g_arch_instruction_attach_extra_operand(result, operand); + if (!g_raw_instruction_create_array(G_RAW_INSTRUCTION(result), area, addr, size, content, count, endian)) + g_clear_object(&result); return result; - error: - - g_clear_object(&result); - - return NULL; - } /****************************************************************************** * * -* Paramètres : content = flux de données à analyser. * +* Paramètres : instr = instance à initialiser pleinement. * +* area = portion de binaire incluant l'instruction. * +* addr = adresse virtuelle et/ou position physique. * * size = taille de chacun des éléments à représenter. * +* content = flux de données à analyser. * * count = nombre de ces éléments. * -* addr = position courante dans ce flux. [OUT] * * endian = ordre des bits dans la source. * * * -* Description : Crée une instruction de type 'db/dw/etc' étendue. * +* Description : Met en place une instruction de type 'db/dw/etc' étendue. * * * -* Retour : Instruction mise en place. * +* Retour : Bilan de l'opération. * * * * Remarques : - * * * ******************************************************************************/ -GArchInstruction *g_raw_instruction_new_array(const GBinContent *content, MemoryDataSize size, size_t count, vmpa2t *addr, SourceEndian endian) +bool g_raw_instruction_create_array(GRawInstruction *instr, GBinaryPortion *area, vmpa2t *addr, MemoryDataSize size, const GBinContent *content, size_t count, SourceEndian endian) { - GArchInstruction *result; /* Instruction à retourner */ - vmpa2t old; /* Sauvegarde de la position */ + bool result; /* Bilan à retourner */ + vmpa2t start; /* Sauvegarde de la position */ size_t i; /* Boucle de parcours */ GArchOperand *operand; /* Octet non décodé à afficher */ - mrange_t range; /* Couverture de l'instruction */ + phys_t diff; /* Décalage à appliquer */ + + result = false; /* Par soucis de cohérence */ - if (count == 0) return NULL; + if (count == 0) + goto exit; - result = g_object_new(G_TYPE_RAW_INSTRUCTION, NULL); + copy_vmpa(&start, addr); - copy_vmpa(&old, addr); + g_thick_object_lock(G_THICK_OBJECT(instr)); for (i = 0; i < count; i++) { - operand = g_imm_operand_new_from_data(size, content, addr, endian); - if (operand == NULL) goto error; + operand = g_immediate_operand_new_from_data(size, content, addr, (bool []){ false /* unused */ }, endian); + if (operand == NULL) break; g_arch_operand_set_flag(operand, IOF_ZERO_PADDING_BY_DEFAULT | IOF_ZERO_PADDING); - g_arch_instruction_attach_extra_operand(result, operand); + g_arch_instruction_attach_operand(G_ARCH_INSTRUCTION(instr), operand); + unref_object(operand); } - init_mrange(&range, &old, compute_vmpa_diff(addr, &old)); + g_thick_object_unlock(G_THICK_OBJECT(instr)); - g_arch_instruction_set_range(result, &range); + if (i < count) + goto exit; - return result; + diff = compute_vmpa_diff(addr, &start); + + g_arch_instruction_compute_range(G_ARCH_INSTRUCTION(instr), area, &start, diff); - error: + result = true; - g_object_unref(G_OBJECT(result)); + exit: - return NULL; + return result; } /****************************************************************************** * * -* Paramètres : instr = instruction quelconque à consulter. * +* Paramètres : instr = instruction à traiter. * +* is_padding = nouveau statut à associer au contenu. * * * -* Description : Indique l'encodage d'une instruction de façon détaillée. * +* Description : Marque l'instruction comme ne contenant que du bourrage. * * * -* Retour : Description humaine de l'encodage utilisé. * +* Retour : - * * * * Remarques : - * * * ******************************************************************************/ -static const char *g_raw_instruction_get_encoding(const GRawInstruction *instr) +void g_raw_instruction_mark_as_padding(GRawInstruction *instr, bool is_padding) { - const char *result; /* Description à retourner */ - - if (g_raw_instruction_is_string(instr)) - result = _("String"); + if (is_padding) + g_arch_instruction_set_flag(G_ARCH_INSTRUCTION(instr), RIF_PADDING); else - result = _("Raw"); - - return result; + g_arch_instruction_unset_flag(G_ARCH_INSTRUCTION(instr), RIF_PADDING); } /****************************************************************************** * * -* Paramètres : instr = instruction d'assemblage à consulter. * +* Paramètres : instr = instruction à traiter. * +* is_padding = nouveau statut à associer au contenu. * * * -* Description : Fournit le nom humain de l'instruction manipulée. * +* Description : Indique si le contenu de l'instruction est du bourrage. * * * -* Retour : Mot clef de bas niveau. * +* Retour : Statut du contenu de l'instruction. * * * * Remarques : - * * * ******************************************************************************/ -static const char *g_raw_instruction_get_keyword(const GRawInstruction *instr) +bool g_raw_instruction_is_padding(const GRawInstruction *instr) { - GArchOperand *operand; /* Octet décodé à afficher */ - MemoryDataSize size; /* Taille de valeur associée */ - - static char *defines[] = { "dn", "db", "dw", "dd", "dq" }; - - operand = g_arch_instruction_get_operand(G_ARCH_INSTRUCTION(instr), 0); - - if (G_IS_TARGET_OPERAND(operand)) - size = g_target_operand_get_size(G_TARGET_OPERAND(operand)); - else - size = g_imm_operand_get_size(G_IMM_OPERAND(operand)); + bool result; /* Indication à retourner */ - g_object_unref(G_OBJECT(operand)); + result = g_arch_instruction_has_flag(G_ARCH_INSTRUCTION(instr), RIF_PADDING); - return defines[MDS_RANGE(size)]; + return result; } - -/* ---------------------------------------------------------------------------------- */ -/* CONSERVATION SUR DISQUE DES INSTRUCTIONS */ -/* ---------------------------------------------------------------------------------- */ - - /****************************************************************************** * * -* Paramètres : instr = instruction d'assemblage à consulter. * -* storage = mécanisme de sauvegarde à manipuler. * -* format = format binaire chargé associé à l'architecture. * -* pbuf = zone tampon à remplir. * +* Paramètres : instr = instruction à traiter. * +* is_string = nouveau statut à associer au contenu. * * * -* Description : Charge une instruction depuis une mémoire tampon. * +* Description : Marque l'instruction comme contenant une chaîne de texte. * * * -* Retour : Bilan de l'opération. * +* Retour : - * * * * Remarques : - * * * ******************************************************************************/ -static bool g_raw_instruction_unserialize(GRawInstruction *instr, GAsmStorage *storage, GBinFormat *format, packed_buffer_t *pbuf) +void g_raw_instruction_mark_as_string(GRawInstruction *instr, bool is_string) { - bool result; /* Bilan à retourner */ - GArchInstructionClass *parent; /* Classe parente à consulter */ - uint8_t boolean; /* Valeur booléenne */ - - parent = G_ARCH_INSTRUCTION_CLASS(g_raw_instruction_parent_class); - - result = parent->unserialize(G_ARCH_INSTRUCTION(instr), storage, format, pbuf); - - if (result) - { - result = extract_packed_buffer(pbuf, &boolean, sizeof(uint8_t), false); - - if (result) - g_raw_instruction_mark_as_padding(instr, (boolean == 1)); - - } - - if (result) - { - result = extract_packed_buffer(pbuf, &boolean, sizeof(uint8_t), false); - - if (result) - g_raw_instruction_mark_as_string(instr, (boolean == 1)); - - } - - return result; + if (is_string) + g_arch_instruction_set_flag(G_ARCH_INSTRUCTION(instr), RIF_STRING); + else + g_arch_instruction_unset_flag(G_ARCH_INSTRUCTION(instr), RIF_STRING); } /****************************************************************************** * * -* Paramètres : instr = instruction d'assemblage à consulter. * -* storage = mécanisme de sauvegarde à manipuler. * -* pbuf = zone tampon à remplir. * +* Paramètres : instr = instruction à traiter. * +* is_string = nouveau statut à associer au contenu. * * * -* Description : Sauvegarde une instruction dans une mémoire tampon. * +* Description : Indique si le contenu de l'instruction est un texte. * * * -* Retour : Bilan de l'opération. * +* Retour : Statut du contenu de l'instruction. * * * * Remarques : - * * * ******************************************************************************/ -static bool g_raw_instruction_serialize(GRawInstruction *instr, GAsmStorage *storage, packed_buffer_t *pbuf) +bool g_raw_instruction_is_string(const GRawInstruction *instr) { - bool result; /* Bilan à retourner */ - GArchInstructionClass *parent; /* Classe parente à consulter */ - uint8_t boolean; /* Valeur booléenne */ - - parent = G_ARCH_INSTRUCTION_CLASS(g_raw_instruction_parent_class); - - result = parent->serialize(G_ARCH_INSTRUCTION(instr), storage, pbuf); - - if (result) - { - boolean = (g_raw_instruction_is_padding(instr) ? 1 : 0); - result = extend_packed_buffer(pbuf, &boolean, sizeof(uint8_t), false); - } + bool result; /* Indication à retourner */ - if (result) - { - boolean = (g_raw_instruction_is_string(instr) ? 1 : 0); - result = extend_packed_buffer(pbuf, &boolean, sizeof(uint8_t), false); - } + result = g_arch_instruction_has_flag(G_ARCH_INSTRUCTION(instr), RIF_STRING); return result; @@ -596,285 +458,73 @@ static bool g_raw_instruction_serialize(GRawInstruction *instr, GAsmStorage *sto /* ---------------------------------------------------------------------------------- */ -/* OFFRE DE CAPACITES DE GENERATION */ +/* IMPLEMENTATION DES FONCTIONS DE CLASSE */ /* ---------------------------------------------------------------------------------- */ /****************************************************************************** * * -* Paramètres : instr = instruction d'assemblage à représenter. * -* line = ligne de rendu à compléter. * -* index = indice de cette même ligne dans le tampon global. * -* repeat = indice d'utilisations successives du générateur. * -* content = éventuel contenu binaire brut à imprimer. * +* Paramètres : instr = instruction quelconque à consulter. * * * -* Description : Ajoute à un tampon GLib le contenu de l'instance spécifiée. * +* Description : Indique l'encodage d'une instruction de façon détaillée. * * * -* Retour : - * +* Retour : Description humaine de l'encodage utilisé. * * * * Remarques : - * * * ******************************************************************************/ -static void g_raw_instruction_print(GRawInstruction *instr, GBufferLine *line, size_t index, size_t repeat, const GBinContent *content) +static char *g_raw_instruction_get_encoding(const GArchInstruction *instr) { - GArchInstruction *base; /* Autre version de l'instance */ - phys_t max_displayed_len; /* Quantité de code affichée */ - const char *key; /* Mot clef principal */ - size_t klen; /* Taille de ce mot clef */ - char *string; /* Chaîne reconstituée */ - size_t iter; /* Tête d'écriture */ - bool first; /* Mémorise une énumération */ - size_t count; /* Nombre d'opérandes en place */ - size_t i; /* Boucle de parcours */ - GArchOperand *op; /* Opérande à manipuler */ - GImmOperand *imm; /* Version opérande de valeur */ - char byte; /* Octet à afficher (ou pas) */ -#ifndef NDEBUG - bool status; /* Bilan d'une récupération */ -#endif - - base = G_ARCH_INSTRUCTION(instr); - - /* Localisation */ - - g_buffer_line_fill_phys(line, DLC_PHYSICAL, MDS_32_BITS_UNSIGNED, get_mrange_addr(&base->range)); - - g_buffer_line_fill_virt(line, DLC_VIRTUAL, MDS_32_BITS_UNSIGNED, get_mrange_addr(&base->range)); - - /* Contenu */ - - if (g_raw_instruction_is_padding(instr)) - max_displayed_len = 0; - - else if (g_raw_instruction_is_string(instr)) - max_displayed_len = 1; - - else - { - max_displayed_len = get_mrange_length(&base->range); - max_displayed_len /= g_arch_instruction_count_operands(base); - } - - g_buffer_line_fill_content(line, DLC_BINARY, content, &base->range, max_displayed_len); - - /* Zone du code d'assemblage */ + char *result; /* Description à retourner */ + GRawInstruction *raw; /* Version spécialisée */ - key = g_arch_instruction_get_keyword(base); - klen = strlen(key); - - g_buffer_line_append_text(line, DLC_ASSEMBLY_HEAD, key, klen, RTT_INSTRUCTION, NULL); - - if (g_raw_instruction_is_padding(instr)) - g_buffer_line_append_text(line, DLC_ASSEMBLY, "...", 3, RTT_RAW, NULL); + raw = G_RAW_INSTRUCTION(instr); + if (g_raw_instruction_is_string(raw)) + result = strdup(_("String")); else - { - string = NULL; - iter = 0; - - first = true; - - g_arch_instruction_lock_operands(base); - - count = _g_arch_instruction_count_operands(base); - - for (i = 0; i < count; i++) - { - op = _g_arch_instruction_get_operand(base, i); - - if (!G_IS_IMM_OPERAND(op)) - goto grip_fallback; - - imm = G_IMM_OPERAND(op); - - if (g_imm_operand_get_size(imm) != MDS_8_BITS) - goto grip_fallback; - - if (!g_raw_instruction_is_string(instr) && g_imm_operand_get_display(imm) != IOD_CHAR) - goto grip_fallback; - -#ifndef NDEBUG - status = g_imm_operand_get_value(imm, MDS_8_BITS, &byte); - assert(status); -#else - g_imm_operand_get_value(imm, MDS_8_BITS, &byte); -#endif - - /* Si le caractère doit apparaître en hexadécimal... */ - - if (!isprint(byte)) - goto grip_fallback; - - /* Impression de l'octet */ - - if (string == NULL) - { - string = (char *)calloc(count + 3, sizeof(char)); - - strcpy(string, "\""); - iter = 1; - - } - - string[iter++] = byte; - - g_object_unref(G_OBJECT(op)); - - continue; - - grip_fallback: - - /* Si une chaîne précède */ - - if (string != NULL && iter > 1) - { - if (!first) - { - g_buffer_line_append_text(line, DLC_ASSEMBLY, ",", 1, RTT_PUNCT, NULL); - g_buffer_line_append_text(line, DLC_ASSEMBLY, " ", 1, RTT_RAW, NULL); - } - else - first = false; - - string[iter++] = '"'; - - g_buffer_line_append_text(line, DLC_ASSEMBLY, string, iter, RTT_STRING, NULL); - - iter = 1; - - } - - /* Intégration en tant qu'opérande classique */ - - if (!first) - { - g_buffer_line_append_text(line, DLC_ASSEMBLY, ",", 1, RTT_PUNCT, NULL); - g_buffer_line_append_text(line, DLC_ASSEMBLY, " ", 1, RTT_RAW, NULL); - } - else - first = false; - - g_arch_operand_print(op, line); - - g_object_unref(G_OBJECT(op)); - - } - - /* Si au final une chaîne traine encore */ - - if (string != NULL && iter > 1) - { - if (!first) - { - g_buffer_line_append_text(line, DLC_ASSEMBLY, ",", 1, RTT_PUNCT, NULL); - g_buffer_line_append_text(line, DLC_ASSEMBLY, " ", 1, RTT_RAW, NULL); - } - - string[iter++] = '"'; - - g_buffer_line_append_text(line, DLC_ASSEMBLY, string, iter, RTT_STRING, NULL); - - } + result = strdup(_("Raw")); - g_arch_instruction_unlock_operands(base); - - if (string != NULL) - free(string); - - } - -} - - -/****************************************************************************** -* * -* Paramètres : instr = instruction à traiter. * -* is_padding = nouveau statut à associer au contenu. * -* * -* Description : Marque l'instruction comme ne contenant que du bourrage. * -* * -* Retour : - * -* * -* Remarques : - * -* * -******************************************************************************/ - -void g_raw_instruction_mark_as_padding(GRawInstruction *instr, bool is_padding) -{ - if (is_padding) - g_arch_instruction_set_flag(G_ARCH_INSTRUCTION(instr), RIF_PADDING); - else - g_arch_instruction_unset_flag(G_ARCH_INSTRUCTION(instr), RIF_PADDING); + return result; } /****************************************************************************** * * -* Paramètres : instr = instruction à traiter. * -* is_padding = nouveau statut à associer au contenu. * +* Paramètres : instr = instruction d'assemblage à consulter. * * * -* Description : Indique si le contenu de l'instruction est du bourrage. * +* Description : Fournit le nom humain de l'instruction manipulée. * * * -* Retour : Statut du contenu de l'instruction. * +* Retour : Mot clef de bas niveau. * * * * Remarques : - * * * ******************************************************************************/ -bool g_raw_instruction_is_padding(const GRawInstruction *instr) +static char *g_raw_instruction_get_keyword(const GArchInstruction *instr) { - bool result; /* Indication à retourner */ - - result = g_arch_instruction_has_flag(G_ARCH_INSTRUCTION(instr), RIF_PADDING); - - return result; - -} + char *result; /* Désignation à retourner */ + GArchOperand *operand; /* Octet décodé à afficher */ + MemoryDataSize size; /* Taille de valeur associée */ + static char *defines[] = { "dn", "db", "dw", "dd", "dq" }; -/****************************************************************************** -* * -* Paramètres : instr = instruction à traiter. * -* is_string = nouveau statut à associer au contenu. * -* * -* Description : Marque l'instruction comme contenant une chaîne de texte. * -* * -* Retour : - * -* * -* Remarques : - * -* * -******************************************************************************/ + g_thick_object_lock(G_THICK_OBJECT(instr)); -void g_raw_instruction_mark_as_string(GRawInstruction *instr, bool is_string) -{ - if (is_string) - g_arch_instruction_set_flag(G_ARCH_INSTRUCTION(instr), RIF_STRING); - else - g_arch_instruction_unset_flag(G_ARCH_INSTRUCTION(instr), RIF_STRING); - -} + operand = g_arch_instruction_get_operand(instr, 0); + /*if (G_IS_TARGET_OPERAND(operand)) FIXME + size = g_target_operand_get_size(G_TARGET_OPERAND(operand)); + else*/ + size = g_immediate_operand_get_size(G_IMMEDIATE_OPERAND(operand)); -/****************************************************************************** -* * -* Paramètres : instr = instruction à traiter. * -* is_string = nouveau statut à associer au contenu. * -* * -* Description : Indique si le contenu de l'instruction est un texte. * -* * -* Retour : Statut du contenu de l'instruction. * -* * -* Remarques : - * -* * -******************************************************************************/ + unref_object(operand); -bool g_raw_instruction_is_string(const GRawInstruction *instr) -{ - bool result; /* Indication à retourner */ + g_thick_object_unlock(G_THICK_OBJECT(instr)); - result = g_arch_instruction_has_flag(G_ARCH_INSTRUCTION(instr), RIF_STRING); + result = strdup(defines[MDS_RANGE(size)]); return result; diff --git a/src/arch/instructions/raw.h b/src/arch/instructions/raw.h index 4e92cd4..712f877 100644 --- a/src/arch/instructions/raw.h +++ b/src/arch/instructions/raw.h @@ -1,8 +1,8 @@ /* Chrysalide - Outil d'analyse de fichiers binaires - * raw.h - prototypes pour les instructions pures vues de l'esprit + * raw.h - prototypes pour les instructions de données brutes * - * Copyright (C) 2014-2020 Cyrille Bagard + * Copyright (C) 2014-2025 Cyrille Bagard * * This file is part of Chrysalide. * @@ -25,46 +25,24 @@ #define _ARCH_INSTRUCTIONS_RAW_H -#include <glib-object.h> - - #include "../instruction.h" #include "../vmpa.h" +#include "../../analysis/content.h" +#include "../../glibext/helpers.h" -/* ------------------------- INSTRUCTION INCONNUE / DONNEES ------------------------- */ - - -#define G_TYPE_RAW_INSTRUCTION g_raw_instruction_get_type() -#define G_RAW_INSTRUCTION(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_RAW_INSTRUCTION, GRawInstruction)) -#define G_IS_RAW_INSTRUCTION(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_RAW_INSTRUCTION)) -#define G_RAW_INSTRUCTION_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_RAW_INSTRUCTION, GRawInstructionClass)) -#define G_IS_RAW_INSTRUCTION_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_RAW_INSTRUCTION)) -#define G_RAW_INSTRUCTION_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_RAW_INSTRUCTION, GRawInstructionClass)) - +#define G_TYPE_RAW_INSTRUCTION (g_raw_instruction_get_type()) -/* Définition générique d'une instruction brute d'architecture (instance) */ -typedef struct _GRawInstruction GRawInstruction; +DECLARE_GTYPE(GRawInstruction, g_raw_instruction, G, RAW_INSTRUCTION); -/* Définition générique d'une instruction brute d'architecture (classe) */ -typedef struct _GRawInstructionClass GRawInstructionClass; - - -/* Indique le type défini pour une instruction inconnue d'architecture. */ -GType g_raw_instruction_get_type(void); /* Crée une instruction de type 'db/dw/etc' simple. */ -GArchInstruction *g_raw_instruction_new_from_value(const vmpa2t *, MemoryDataSize, uint64_t); +GArchInstruction *g_raw_instruction_new_from_value(GBinaryPortion *, const vmpa2t *, MemoryDataSize, uint64_t); -/* Crée une instruction de type 'db/dw/etc' pour un uleb128. */ -GArchInstruction *g_raw_instruction_new_uleb128(const GBinContent *content, vmpa2t *); +/* Crée une instruction de type 'db/dw/etc' étendue. */ +GArchInstruction *g_raw_instruction_new_array(GBinaryPortion *, vmpa2t *, MemoryDataSize, const GBinContent *, size_t, SourceEndian); -/* Crée une instruction de type 'db/dw/etc' pour un sleb128. */ -GArchInstruction *g_raw_instruction_new_sleb128(const GBinContent *content, vmpa2t *); - -/* Crée une instruction de type 'db/dw/etc' étendue. */ -GArchInstruction *g_raw_instruction_new_array(const GBinContent *, MemoryDataSize, size_t, vmpa2t *, SourceEndian); /* Drapeaux pour informations complémentaires */ typedef enum _RawInstrFlag @@ -74,6 +52,7 @@ typedef enum _RawInstrFlag } RawInstrFlag; + /* Marque l'instruction comme ne contenant que du bourrage. */ void g_raw_instruction_mark_as_padding(GRawInstruction *, bool); diff --git a/src/arch/instructions/undefined-int.h b/src/arch/instructions/undefined-int.h index a9b7627..faf0b4b 100644 --- a/src/arch/instructions/undefined-int.h +++ b/src/arch/instructions/undefined-int.h @@ -1,8 +1,8 @@ /* Chrysalide - Outil d'analyse de fichiers binaires - * undefined-int.h - prototypes pour la définition générique interne des instructions au comportement non défini + * undefined-int.h - prototypes pour la définition interne des instructions au comportement non défini * - * Copyright (C) 2019 Cyrille Bagard + * Copyright (C) 2019-2025 Cyrille Bagard * * This file is part of Chrysalide. * @@ -27,42 +27,18 @@ #include "undefined.h" #include "../instruction-int.h" -#include "../../glibext/objhole.h" -/* Informations glissées dans la structure GObject de GArchInstruction */ -typedef struct _undef_extra_data_t -{ - /** - * Le champ uid de la structure parente attendue conduit à une taille - * alignée sur 2 octets, donc à une taille totale de 4 octets ce qui - * représente la limite maximale de taille supportée. - * - * Pour 3 octets à la base, qui devraient laisser 8 - 1 octets disponbibles - * en incluant le bit de verrouillage. - * - * On reproduit donc la structure instr_extra_data_t ici, en basculant - * l'énumération InstrExpectedBehavior en champ de bits. - */ - - itid_t uid; /* Identifiant unique du type */ - ArchInstrFlag flags; /* Informations complémentaires*/ - - unsigned int behavior : 2; /* Conséquences réelles */ - -} undef_extra_data_t; - - /* Définition générique d'une instruction au comportement non défini (instance) */ -struct _GUndefInstruction +struct _GUndefinedInstruction { GArchInstruction parent; /* A laisser en premier */ }; /* Définition générique d'une instruction au comportement non défini (classe) */ -struct _GUndefInstructionClass +struct _GUndefinedInstructionClass { GArchInstructionClass parent; /* A laisser en premier */ @@ -73,15 +49,25 @@ struct _GUndefInstructionClass * Accès aux informations éventuellement déportées. */ -#if 1 //__SIZEOF_INT__ == __SIZEOF_LONG__ +/* Informations glissées dans la structure GObject de GArchInstruction */ +typedef struct _undef_extra_data_t +{ + ARCH_INSTRUCTION_EXTRA_DATA + + unsigned int behavior : 2; /* Conséquences réelles */ + +} undef_extra_data_t; + -# define GET_UNDEF_INSTR_EXTRA(ins) ((undef_extra_data_t *)&((GArchInstruction *)ins)->extra) +#define GET_UNDEF_INSTR_EXTRA(op) \ + GET_GOBJECT_EXTRA(op, undef_extra_data_t) -#else +#define SET_UNDEF_INSTR_EXTRA(op, data) \ + SET_GOBJECT_EXTRA(op, undef_extra_data_t, data) -# define GET_UNDEF_INSTR_EXTRA(ins) GET_GOBJECT_EXTRA(G_OBJECT(ins), undef_extra_data_t) -#endif +/* Met en place une instruction au comportement indéfini. */ +bool g_undefined_instruction_create(GUndefinedInstruction *, InstrExpectedBehavior); diff --git a/src/arch/instructions/undefined-ui.c b/src/arch/instructions/undefined-ui.c new file mode 100644 index 0000000..fbc0452 --- /dev/null +++ b/src/arch/instructions/undefined-ui.c @@ -0,0 +1,102 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * undefined-ui.c - opérandes représentant des instructions indéfinies sous forme graphique + * + * Copyright (C) 2025 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Chrysalide. If not, see <http://www.gnu.org/licenses/>. + */ + + +#include "undefined-ui.h" + + +#include "../instruction.h" +#include "../../glibext/options/asm.h" + + + +/* Etablit dans une ligne de rendu le contenu représenté. */ +static void g_undefined_instruction_ui_populate_line(const GTokenGenerator *, size_t, size_t, GBufferLine *, void *); + + + +/****************************************************************************** +* * +* Paramètres : iface = interface GLib à initialiser. * +* * +* Description : Procède à l'initialisation de l'interface de génération. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +void g_undefined_instruction_ui_token_generator_iface_init(GTokenGeneratorInterface *iface) +{ + iface->populate = g_undefined_instruction_ui_populate_line; + +} + + +/****************************************************************************** +* * +* Paramètres : generator = générateur à utiliser pour l'impression. * +* index = indice de cette même ligne dans le tampon global.* +* repeat = indice d'utilisations successives du générateur. * +* line = ligne de rendu à compléter. * +* data = éventuelle donnée complémentaire fournie. * +* * +* Description : Etablit dans une ligne de rendu le contenu représenté. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_undefined_instruction_ui_populate_line(const GTokenGenerator *generator, size_t index, size_t repeat, GBufferLine *line, void *data) +{ + GArchInstruction *instr; /* Version spécialisée */ + GBinContent *content; /* Contenu brut d'origine */ + mrange_t range; /* Emplacement couvert */ + char *key; /* Mot clef principal */ + + instr = G_ARCH_INSTRUCTION(generator); + content = G_BIN_CONTENT(data); + + /* Prologue */ + + if (g_arch_instruction_get_range(instr, &range)) + { + g_buffer_line_fill_physical(line, ACO_PHYSICAL, MDS_32_BITS_UNSIGNED, get_mrange_addr(&range)); + + g_buffer_line_fill_virtual(line, ACO_VIRTUAL, MDS_32_BITS_UNSIGNED, get_mrange_addr(&range)); + + g_buffer_line_fill_content(line, ACO_BINARY, content, &range, VMPA_NO_PHYSICAL); + + } + + /* Instruction proprement dite */ + + key = g_arch_instruction_get_keyword(instr); + + g_buffer_line_append_text(line, ACO_ASSEMBLY_HEAD, TRT_ERROR, SL(key), NULL, G_OBJECT(instr)); + + free(key); + +} diff --git a/src/arch/instructions/undefined-ui.h b/src/arch/instructions/undefined-ui.h new file mode 100644 index 0000000..8bc2d67 --- /dev/null +++ b/src/arch/instructions/undefined-ui.h @@ -0,0 +1,37 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * undefined-ui.h - prototypes pour les opérandes représentant des instructions indéfinies sous forme graphique + * + * Copyright (C) 2025 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Chrysalide. If not, see <http://www.gnu.org/licenses/>. + */ + + +#ifndef _ARCH_OPERANDS_UNDEFINED_UI_H +#define _ARCH_OPERANDS_UNDEFINED_UI_H + + +#include "../../glibext/generator-int.h" + + + +/* Procède à l'initialisation de l'interface de génération. */ +void g_undefined_instruction_ui_token_generator_iface_init(GTokenGeneratorInterface *); + + + +#endif /* _ARCH_OPERANDS_UNDEFINED_UI_H */ diff --git a/src/arch/instructions/undefined.c b/src/arch/instructions/undefined.c index 15c63e7..75df493 100644 --- a/src/arch/instructions/undefined.c +++ b/src/arch/instructions/undefined.c @@ -2,7 +2,7 @@ /* Chrysalide - Outil d'analyse de fichiers binaires * undefined.c - instructions au comportement non défini * - * Copyright (C) 2016-2019 Cyrille Bagard + * Copyright (C) 2016-2025 Cyrille Bagard * * This file is part of Chrysalide. * @@ -25,63 +25,42 @@ #include <assert.h> +#include <string.h> #include <i18n.h> #include "undefined-int.h" -#include "../../core/columns.h" +#include "../../glibext/serialize-int.h" +/* ------------------------- INSTRUCTION INCONNUE / DONNEES ------------------------- */ + + /* Initialise la classe des instructions non définies. */ -static void g_undef_instruction_class_init(GUndefInstructionClass *); +static void g_undefined_instruction_class_init(GUndefinedInstructionClass *); /* Initialise une instance d'instruction non définie. */ -static void g_undef_instruction_init(GUndefInstruction *); +static void g_undefined_instruction_init(GUndefinedInstruction *); /* Supprime toutes les références externes. */ -static void g_undef_instruction_dispose(GUndefInstruction *); +static void g_undefined_instruction_dispose(GObject *); /* Procède à la libération totale de la mémoire. */ -static void g_undef_instruction_finalize(GUndefInstruction *); - -/* Indique l'encodage d'une instruction de façon détaillée. */ -static const char *g_undef_instruction_get_encoding(const GUndefInstruction *); - -/* Fournit le nom humain de l'instruction manipulée. */ -static const char *g_undef_instruction_get_keyword(const GUndefInstruction *); - - - -/* -------------------- CONSERVATION SUR DISQUE DES INSTRUCTIONS -------------------- */ - - -/* Charge une instruction depuis une mémoire tampon. */ -static bool g_undef_instruction_unserialize(GUndefInstruction *, GAsmStorage *, GBinFormat *, packed_buffer_t *); - -/* Sauvegarde une instruction dans une mémoire tampon. */ -static bool g_undef_instruction_serialize(GUndefInstruction *, GAsmStorage *, packed_buffer_t *); - - - -/* ------------------------ OFFRE DE CAPACITES DE GENERATION ------------------------ */ - - -/* Ajoute à un tampon GLib le contenu de l'instance spécifiée. */ -static void g_undef_instruction_print(GUndefInstruction *, GBufferLine *, size_t, size_t, const GBinContent *); +static void g_undefined_instruction_finalize(GObject *); /* --------------------- IMPLEMENTATION DES FONCTIONS DE CLASSE --------------------- */ -/* Charge un contenu depuis une mémoire tampon. */ -static bool g_undef_instruction_load(GUndefInstruction *, GObjectStorage *, packed_buffer_t *); +/* Indique l'encodage d'une instruction de façon détaillée. */ +static char *g_undefined_instruction_get_encoding(const GArchInstruction *); -/* Sauvegarde un contenu dans une mémoire tampon. */ -static bool g_undef_instruction_store(GUndefInstruction *, GObjectStorage *, packed_buffer_t *); +/* Fournit le nom humain de l'instruction manipulée. */ +static char *g_undefined_instruction_get_keyword(const GArchInstruction *); @@ -91,7 +70,9 @@ static bool g_undef_instruction_store(GUndefInstruction *, GObjectStorage *, pac /* Indique le type défini pour une instruction au comportement non défini. */ -G_DEFINE_TYPE(GUndefInstruction, g_undef_instruction, G_TYPE_ARCH_INSTRUCTION); +G_DEFINE_TYPE_WITH_CODE(GUndefinedInstruction, g_undefined_instruction, G_TYPE_ARCH_INSTRUCTION, + G_IMPLEMENT_INTERFACE_IF_SYM(g_token_generator_get_type, g_undefined_instruction_ui_token_generator_iface_init)); + /****************************************************************************** @@ -106,28 +87,20 @@ G_DEFINE_TYPE(GUndefInstruction, g_undef_instruction, G_TYPE_ARCH_INSTRUCTION); * * ******************************************************************************/ -static void g_undef_instruction_class_init(GUndefInstructionClass *klass) +static void g_undefined_instruction_class_init(GUndefinedInstructionClass *klass) { GObjectClass *object; /* Autre version de la classe */ GArchInstructionClass *instr; /* Encore une autre vision... */ object = G_OBJECT_CLASS(klass); - object->dispose = (GObjectFinalizeFunc/* ! */)g_undef_instruction_dispose; - object->finalize = (GObjectFinalizeFunc)g_undef_instruction_finalize; + object->dispose = g_undefined_instruction_dispose; + object->finalize = g_undefined_instruction_finalize; instr = G_ARCH_INSTRUCTION_CLASS(klass); - instr->get_encoding = (get_instruction_encoding_fc)g_undef_instruction_get_encoding; - instr->get_keyword = (get_instruction_keyword_fc)g_undef_instruction_get_keyword; - - instr->unserialize = (unserialize_instruction_fc)g_undef_instruction_unserialize; - instr->serialize = (serialize_instruction_fc)g_undef_instruction_serialize; - - instr->print = (print_instruction_fc)g_undef_instruction_print; - - instr->load = (load_instruction_fc)g_undef_instruction_load; - instr->store = (store_instruction_fc)g_undef_instruction_store; + instr->get_encoding = g_undefined_instruction_get_encoding; + instr->get_keyword = g_undefined_instruction_get_keyword; } @@ -144,16 +117,22 @@ static void g_undef_instruction_class_init(GUndefInstructionClass *klass) * * ******************************************************************************/ -static void g_undef_instruction_init(GUndefInstruction *instr) +static void g_undefined_instruction_init(GUndefinedInstruction *instr) { - GET_UNDEF_INSTR_EXTRA(instr)->behavior = IEB_UNDEFINED; + undef_extra_data_t extra; /* Données insérées à consulter*/ + + extra = GET_UNDEF_INSTR_EXTRA(instr); + + extra.behavior = IEB_UNDEFINED; + + SET_UNDEF_INSTR_EXTRA(instr, &extra); } /****************************************************************************** * * -* Paramètres : instr = instance d'objet GLib à traiter. * +* Paramètres : object = instance d'objet GLib à traiter. * * * * Description : Supprime toutes les références externes. * * * @@ -163,16 +142,16 @@ static void g_undef_instruction_init(GUndefInstruction *instr) * * ******************************************************************************/ -static void g_undef_instruction_dispose(GUndefInstruction *instr) +static void g_undefined_instruction_dispose(GObject *object) { - G_OBJECT_CLASS(g_undef_instruction_parent_class)->dispose(G_OBJECT(instr)); + G_OBJECT_CLASS(g_undefined_instruction_parent_class)->dispose(object); } /****************************************************************************** * * -* Paramètres : instr = instance d'objet GLib à traiter. * +* Paramètres : object = instance d'objet GLib à traiter. * * * * Description : Procède à la libération totale de la mémoire. * * * @@ -182,9 +161,9 @@ static void g_undef_instruction_dispose(GUndefInstruction *instr) * * ******************************************************************************/ -static void g_undef_instruction_finalize(GUndefInstruction *instr) +static void g_undefined_instruction_finalize(GObject *object) { - G_OBJECT_CLASS(g_undef_instruction_parent_class)->finalize(G_OBJECT(instr)); + G_OBJECT_CLASS(g_undefined_instruction_parent_class)->finalize(object); } @@ -201,16 +180,14 @@ static void g_undef_instruction_finalize(GUndefInstruction *instr) * * ******************************************************************************/ -GArchInstruction *g_undef_instruction_new(InstrExpectedBehavior behavior) +GArchInstruction *g_undefined_instruction_new(InstrExpectedBehavior behavior) { GArchInstruction *result; /* Instruction à retourner */ - undef_extra_data_t *extra; /* Données insérées à modifier */ - result = g_object_new(G_TYPE_UNDEF_INSTRUCTION, NULL); + result = g_object_new(G_TYPE_UNDEFINED_INSTRUCTION, NULL); - extra = GET_UNDEF_INSTR_EXTRA(result); - - extra->behavior = behavior; + if (!g_undefined_instruction_create(G_UNDEFINED_INSTRUCTION(result), behavior)) + g_clear_object(&result); return result; @@ -219,90 +196,10 @@ GArchInstruction *g_undef_instruction_new(InstrExpectedBehavior behavior) /****************************************************************************** * * -* Paramètres : instr = instruction quelconque à consulter. * -* * -* Description : Indique l'encodage d'une instruction de façon détaillée. * -* * -* Retour : Description humaine de l'encodage utilisé. * -* * -* Remarques : - * -* * -******************************************************************************/ - -static const char *g_undef_instruction_get_encoding(const GUndefInstruction *instr) -{ - const char *result; /* Description à retourner */ - - result = _("Undefined"); - - return result; - -} - - -/****************************************************************************** +* Paramètres : instr = instance à initialiser pleinement. * +* behavior = état réel du CPU après une passe de l'instruction.* * * -* Paramètres : instr = instruction d'assemblage à consulter. * -* * -* Description : Fournit le nom humain de l'instruction manipulée. * -* * -* Retour : Mot clef de bas niveau. * -* * -* Remarques : - * -* * -******************************************************************************/ - -const char *g_undef_instruction_get_keyword(const GUndefInstruction *instr) -{ - const char *result; /* Désignation à retourner */ - undef_extra_data_t *extra; /* Données insérées à consulter*/ - - extra = GET_UNDEF_INSTR_EXTRA(instr); - - switch (extra->behavior) - { - case IEB_NOP: - result = "nop"; - break; - - case IEB_UNDEFINED: - result = "undefined"; - break; - - case IEB_UNPREDICTABLE: - result = "unpredictable"; - break; - - case IEB_RESERVED: - result = "reserved"; - break; - - default: - assert(false); - result = NULL; - break; - - } - - return result; - -} - - - -/* ---------------------------------------------------------------------------------- */ -/* CONSERVATION SUR DISQUE DES INSTRUCTIONS */ -/* ---------------------------------------------------------------------------------- */ - - -/****************************************************************************** -* * -* Paramètres : instr = instruction d'assemblage à consulter. * -* storage = mécanisme de sauvegarde à manipuler. * -* format = format binaire chargé associé à l'architecture. * -* pbuf = zone tampon à remplir. * -* * -* Description : Charge une instruction depuis une mémoire tampon. * +* Description : Met en place une instruction au comportement indéfini. * * * * Retour : Bilan de l'opération. * * * @@ -310,122 +207,24 @@ const char *g_undef_instruction_get_keyword(const GUndefInstruction *instr) * * ******************************************************************************/ -static bool g_undef_instruction_unserialize(GUndefInstruction *instr, GAsmStorage *storage, GBinFormat *format, packed_buffer_t *pbuf) +bool g_undefined_instruction_create(GUndefinedInstruction *instr, InstrExpectedBehavior behavior) { bool result; /* Bilan à retourner */ - GArchInstructionClass *parent; /* Classe parente à consulter */ - undef_extra_data_t *extra; /* Données insérées à consulter*/ - uint8_t val; /* Champ de bits manipulé */ - - parent = G_ARCH_INSTRUCTION_CLASS(g_undef_instruction_parent_class); + undef_extra_data_t extra; /* Données insérées à modifier */ - result = parent->unserialize(G_ARCH_INSTRUCTION(instr), storage, format, pbuf); + result = true; - if (result) - { - extra = GET_UNDEF_INSTR_EXTRA(instr); - - LOCK_GOBJECT_EXTRA(extra); - - result = extract_packed_buffer(pbuf, &val, sizeof(uint8_t), false); - extra->behavior = val; - - UNLOCK_GOBJECT_EXTRA(extra); - - } - - return result; - -} - - -/****************************************************************************** -* * -* Paramètres : instr = instruction d'assemblage à consulter. * -* storage = mécanisme de sauvegarde à manipuler. * -* pbuf = zone tampon à remplir. * -* * -* Description : Sauvegarde une instruction dans une mémoire tampon. * -* * -* Retour : Bilan de l'opération. * -* * -* Remarques : - * -* * -******************************************************************************/ - -static bool g_undef_instruction_serialize(GUndefInstruction *instr, GAsmStorage *storage, packed_buffer_t *pbuf) -{ - bool result; /* Bilan à retourner */ - GArchInstructionClass *parent; /* Classe parente à consulter */ - undef_extra_data_t *extra; /* Données insérées à consulter*/ - - parent = G_ARCH_INSTRUCTION_CLASS(g_undef_instruction_parent_class); - - result = parent->serialize(G_ARCH_INSTRUCTION(instr), storage, pbuf); - - if (result) - { - extra = GET_UNDEF_INSTR_EXTRA(instr); - - LOCK_GOBJECT_EXTRA(extra); - - result = extend_packed_buffer(pbuf, (uint8_t []){ extra->behavior }, sizeof(uint8_t), false); + extra = GET_UNDEF_INSTR_EXTRA(instr); - UNLOCK_GOBJECT_EXTRA(extra); + extra.behavior = behavior; - } + SET_UNDEF_INSTR_EXTRA(instr, &extra); return result; } - -/* ---------------------------------------------------------------------------------- */ -/* OFFRE DE CAPACITES DE GENERATION */ -/* ---------------------------------------------------------------------------------- */ - - -/****************************************************************************** -* * -* Paramètres : instr = instruction d'assemblage à représenter. * -* line = ligne de rendu à compléter. * -* index = indice de cette même ligne dans le tampon global. * -* repeat = indice d'utilisations successives du générateur. * -* content = éventuel contenu binaire brut à imprimer. * -* * -* Description : Ajoute à un tampon GLib le contenu de l'instance spécifiée. * -* * -* Retour : - * -* * -* Remarques : - * -* * -******************************************************************************/ - -static void g_undef_instruction_print(GUndefInstruction *instr, GBufferLine *line, size_t index, size_t repeat, const GBinContent *content) -{ - GArchInstruction *base; /* Version de base */ - const char *key; /* Mot clef principal */ - size_t klen; /* Taille de ce mot clef */ - - base = G_ARCH_INSTRUCTION(instr); - - g_buffer_line_fill_phys(line, DLC_PHYSICAL, MDS_32_BITS_UNSIGNED, get_mrange_addr(&base->range)); - - g_buffer_line_fill_virt(line, DLC_VIRTUAL, MDS_32_BITS_UNSIGNED, get_mrange_addr(&base->range)); - - g_buffer_line_fill_content(line, DLC_BINARY, content, &base->range, VMPA_NO_PHYSICAL); - - /* Instruction proprement dite */ - - key = g_arch_instruction_get_keyword(base); - klen = strlen(key); - - g_buffer_line_append_text(line, DLC_ASSEMBLY_HEAD, key, klen, RTT_ERROR, NULL); - -} - - /****************************************************************************** * * * Paramètres : instr = instruction à consulter. * @@ -438,18 +237,14 @@ static void g_undef_instruction_print(GUndefInstruction *instr, GBufferLine *lin * * ******************************************************************************/ -InstrExpectedBehavior g_undef_instruction_get_behavior(const GUndefInstruction *instr) +InstrExpectedBehavior g_undefined_instruction_get_behavior(const GUndefinedInstruction *instr) { InstrExpectedBehavior result; /* Comportement à retourner */ - undef_extra_data_t *extra; /* Données insérées à consulter*/ + undef_extra_data_t extra; /* Données insérées à consulter*/ extra = GET_UNDEF_INSTR_EXTRA(instr); - LOCK_GOBJECT_EXTRA(extra); - - result = extra->behavior; - - UNLOCK_GOBJECT_EXTRA(extra); + result = extra.behavior; return result; @@ -464,41 +259,21 @@ InstrExpectedBehavior g_undef_instruction_get_behavior(const GUndefInstruction * /****************************************************************************** * * -* Paramètres : instr = élément GLib à constuire. * -* storage = conservateur de données à manipuler ou NULL. * -* pbuf = zone tampon à lire. * +* Paramètres : instr = instruction quelconque à consulter. * * * -* Description : Charge un contenu depuis une mémoire tampon. * +* Description : Indique l'encodage d'une instruction de façon détaillée. * * * -* Retour : Bilan de l'opération. * +* Retour : Description humaine de l'encodage utilisé. * * * * Remarques : - * * * ******************************************************************************/ -static bool g_undef_instruction_load(GUndefInstruction *instr, GObjectStorage *storage, packed_buffer_t *pbuf) +static char *g_undefined_instruction_get_encoding(const GArchInstruction *instr) { - bool result; /* Bilan à retourner */ - GArchInstructionClass *parent; /* Classe parente à consulter */ - undef_extra_data_t *extra; /* Données insérées à consulter*/ - uint8_t val; /* Champ de bits manipulé */ - - parent = G_ARCH_INSTRUCTION_CLASS(g_undef_instruction_parent_class); - - result = parent->load(G_ARCH_INSTRUCTION(instr), storage, pbuf); - - if (result) - { - extra = GET_UNDEF_INSTR_EXTRA(instr); - - LOCK_GOBJECT_EXTRA(extra); + char *result; /* Description à retourner */ - result = extract_packed_buffer(pbuf, &val, sizeof(uint8_t), false); - extra->behavior = val; - - UNLOCK_GOBJECT_EXTRA(extra); - - } + result = strdup(_("Undefined")); return result; @@ -507,37 +282,45 @@ static bool g_undef_instruction_load(GUndefInstruction *instr, GObjectStorage *s /****************************************************************************** * * -* Paramètres : instr = élément GLib à consulter. * -* storage = conservateur de données à manipuler ou NULL. * -* pbuf = zone tampon à remplir. * +* Paramètres : instr = instruction d'assemblage à consulter. * * * -* Description : Sauvegarde un contenu dans une mémoire tampon. * +* Description : Fournit le nom humain de l'instruction manipulée. * * * -* Retour : Bilan de l'opération. * +* Retour : Mot clef de bas niveau. * * * * Remarques : - * * * ******************************************************************************/ -static bool g_undef_instruction_store(GUndefInstruction *instr, GObjectStorage *storage, packed_buffer_t *pbuf) +static char *g_undefined_instruction_get_keyword(const GArchInstruction *instr) { - bool result; /* Bilan à retourner */ - GArchInstructionClass *parent; /* Classe parente à consulter */ - undef_extra_data_t *extra; /* Données insérées à consulter*/ - - parent = G_ARCH_INSTRUCTION_CLASS(g_undef_instruction_parent_class); + char *result; /* Désignation à retourner */ + undef_extra_data_t extra; /* Données insérées à consulter*/ - result = parent->store(G_ARCH_INSTRUCTION(instr), storage, pbuf); + extra = GET_UNDEF_INSTR_EXTRA(instr); - if (result) + switch (extra.behavior) { - extra = GET_UNDEF_INSTR_EXTRA(instr); + case IEB_NOP: + result = strdup("nop"); + break; - LOCK_GOBJECT_EXTRA(extra); + case IEB_UNDEFINED: + result = strdup("undefined"); + break; - result = extend_packed_buffer(pbuf, (uint8_t []){ extra->behavior }, sizeof(uint8_t), false); + case IEB_UNPREDICTABLE: + result = strdup("unpredictable"); + break; - UNLOCK_GOBJECT_EXTRA(extra); + case IEB_RESERVED: + result = strdup("reserved"); + break; + + default: + assert(false); + result = NULL; + break; } diff --git a/src/arch/instructions/undefined.h b/src/arch/instructions/undefined.h index 8f35f35..d4b35f4 100644 --- a/src/arch/instructions/undefined.h +++ b/src/arch/instructions/undefined.h @@ -2,7 +2,7 @@ /* Chrysalide - Outil d'analyse de fichiers binaires * undefined.h - prototypes pour les instructions au comportement non défini * - * Copyright (C) 2016-2019 Cyrille Bagard + * Copyright (C) 2016-2025 Cyrille Bagard * * This file is part of Chrysalide. * @@ -25,27 +25,14 @@ #define _ARCH_INSTRUCTIONS_UNDEFINED_H -#include <glib-object.h> - - #include "../instruction.h" -#include "../vmpa.h" - +#include "../../glibext/helpers.h" -#define G_TYPE_UNDEF_INSTRUCTION g_undef_instruction_get_type() -#define G_UNDEF_INSTRUCTION(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_UNDEF_INSTRUCTION, GUndefInstruction)) -#define G_IS_UNDEF_INSTRUCTION(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_UNDEF_INSTRUCTION)) -#define G_UNDEF_INSTRUCTION_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_UNDEF_INSTRUCTION, GUndefInstructionClass)) -#define G_IS_UNDEF_INSTRUCTION_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_UNDEF_INSTRUCTION)) -#define G_UNDEF_INSTRUCTION_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_UNDEF_INSTRUCTION, GUndefInstructionClass)) +#define G_TYPE_UNDEFINED_INSTRUCTION (g_undefined_instruction_get_type()) -/* Définition générique d'une instruction au comportement non défini (instance) */ -typedef struct _GUndefInstruction GUndefInstruction; - -/* Définition générique d'une instruction au comportement non défini (classe) */ -typedef struct _GUndefInstructionClass GUndefInstructionClass; +DECLARE_GTYPE(GUndefinedInstruction, g_undefined_instruction, G, UNDEFINED_INSTRUCTION); /* Etat précis de l'instruction */ @@ -59,14 +46,11 @@ typedef enum _InstrExpectedBehavior } InstrExpectedBehavior; -/* Indique le type défini pour une instruction au comportement non défini. */ -GType g_undef_instruction_get_type(void); - /* Crée une instruction au comportement nominalement indéfini. */ -GArchInstruction *g_undef_instruction_new(InstrExpectedBehavior); +GArchInstruction *g_undefined_instruction_new(InstrExpectedBehavior); /* Indique le type de conséquences réél de l'instruction. */ -InstrExpectedBehavior g_undef_instruction_get_behavior(const GUndefInstruction *); +InstrExpectedBehavior g_undefined_instruction_get_behavior(const GUndefinedInstruction *); diff --git a/src/arch/vmpa.h b/src/arch/vmpa.h index 8a9b961..7a11deb 100644 --- a/src/arch/vmpa.h +++ b/src/arch/vmpa.h @@ -296,4 +296,33 @@ char *mrange_length_to_string(const mrange_t *, MemoryDataSize, char [VMPA_MAX_L +/* ------------------- DEFINITION D'UN ESPACE RELATIVE EN MEMOIRE ------------------- */ + + +/* Couverture mémoire */ +typedef struct _rel_mrange_t +{ + uint32_t offset; /* Décalage depuis une ref. */ + uint16_t length; /* Taille de la couverture */ + +} rel_mrange_t; + + +#define init_rel_mrange(rr, o, l) \ + do \ + { \ + (rr)->offset = o; \ + (rr)->length = l; \ + } \ + while (0); + + +#define get_rel_mrange_offset(rr) \ + (rr)->offset + +#define get_rel_mrange_length(rr) \ + (rr)->length + + + #endif /* _ARCH_VMPA_H */ diff --git a/src/common/Makefile.am b/src/common/Makefile.am index d09b661..1056cb2 100644 --- a/src/common/Makefile.am +++ b/src/common/Makefile.am @@ -47,6 +47,7 @@ endif libcommon4_la_SOURCES = \ + array.h array.c \ asm.h asm.c \ bits.h bits.c \ compiler.h \ diff --git a/src/common/cpp.h b/src/common/cpp.h index 9616db3..4ebad82 100644 --- a/src/common/cpp.h +++ b/src/common/cpp.h @@ -48,6 +48,8 @@ */ #define SL(str) str, strlen(str) +#define STCSL(str) str, STATIC_STR_SIZE(str) + /** * Détermine la taille de la plus longue chaîne de caractères diff --git a/src/common/sort.h b/src/common/sort.h index 39a6f33..27e3739 100644 --- a/src/common/sort.h +++ b/src/common/sort.h @@ -37,6 +37,9 @@ int sort_boolean(bool, bool); /* Compare une valeur avec une autre. */ int sort_unsigned_long(unsigned long, unsigned long); +#define sort_size(v1, v2) \ + sort_unsigned_long(v1, v2) + /* Compare une valeur avec une autre. */ int sort_signed_long_long(signed long long, signed long long); diff --git a/src/common/szbin.h b/src/common/szbin.h index 182739a..8524ae3 100644 --- a/src/common/szbin.h +++ b/src/common/szbin.h @@ -143,15 +143,13 @@ typedef struct _sized_binary_t while (0) -#define memcmp_sized_binary(s1, s2) \ - ({ \ - int __ret; \ - size_t __n; \ - __n = (s1)->size < (s2)->size ? (s1)->size : (s2)->size; \ - __ret = memcmp((s1)->data, (s2)->data, __n); \ - if (__ret == 0) \ - __ret = sort_unsigned_long_long((s1)->size, (s2)->size);\ - __ret; \ +#define memcmp_sized_binary(s1, s2) \ + ({ \ + int __ret; \ + __ret = sort_size((s1)->size, (s2)->size); \ + if (__ret == 0) \ + __ret = memcmp((s1)->data, (s2)->data, (s1)->size); \ + __ret; \ }) diff --git a/src/core/Makefile.am b/src/core/Makefile.am index 17fd2bf..15ed866 100644 --- a/src/core/Makefile.am +++ b/src/core/Makefile.am @@ -20,7 +20,8 @@ libcore4_la_SOURCES = \ logs.h logs.c \ nox.h nox.c \ nproc.h nproc.c \ - paths.h paths.c + paths.h paths.c \ + processors.h processors.c libcore4_la_CFLAGS = $(TOOLKIT_CFLAGS) $(LIBSSL_CFLAGS) diff --git a/src/core/core.c b/src/core/core.c index 8fe12f5..c730fad 100644 --- a/src/core/core.c +++ b/src/core/core.c @@ -25,6 +25,7 @@ #include "global.h" +#include "processors.h" @@ -61,6 +62,14 @@ bool load_core_components(AvailableCoreComponent flags) } + if ((flags & ACC_CODE_ANALYSIS) != 0 && (__loaded & ACC_CODE_ANALYSIS) == 0) + { + register_arch_gtypes(); + + init_operands_factory(); + + } + return result; } @@ -80,6 +89,12 @@ bool load_core_components(AvailableCoreComponent flags) void unload_core_components(AvailableCoreComponent flags) { + if ((flags & ACC_CODE_ANALYSIS) != 0 && (__loaded & ACC_CODE_ANALYSIS) == 0) + { + exit_operands_factory(); + + } + if ((flags & ACC_GLOBAL_VARS) != 0 && (__loaded & ACC_GLOBAL_VARS) == 0) { set_work_queue(NULL); @@ -111,7 +126,6 @@ void unload_core_components(AvailableCoreComponent flags) #include "demanglers.h" #include "global.h" #include "params.h" -#include "processors.h" #include "queue.h" #include "../analysis/scan/core.h" #ifdef INCLUDE_MAGIC_SUPPORT @@ -195,9 +209,6 @@ bool load_all_core_components(bool cs) if (result) result = init_segment_content_hash_table(); - register_arch_gtypes(); - init_operands_factory(); - } } @@ -223,8 +234,6 @@ void unload_all_core_components(bool cs) { if (cs) { - exit_operands_factory(); - exit_segment_content_hash_table(); unload_demanglers_definitions(); diff --git a/src/core/core.h b/src/core/core.h index e5f0a60..640476a 100644 --- a/src/core/core.h +++ b/src/core/core.h @@ -34,9 +34,10 @@ typedef enum _AvailableCoreComponent { ACC_NONE = (0 << 0), /* Statut initial */ ACC_GLOBAL_VARS = (1 << 0), /* Singletons globaux */ - ACC_SCAN_FEATURES = (1 << 1), /* Espace de noms pour scan */ + ACC_CODE_ANALYSIS = (1 << 1), /* Désassemblage de code */ + ACC_SCAN_FEATURES = (1 << 2), /* Espace de noms pour scan */ - ACC_ALL_COMPONENTS = (1 << 2) - 1 + ACC_ALL_COMPONENTS = (1 << 3) - 1 } AvailableCoreComponent; diff --git a/src/core/processors.c b/src/core/processors.c index e4a558f..056fc23 100644 --- a/src/core/processors.c +++ b/src/core/processors.c @@ -2,7 +2,7 @@ /* Chrysalide - Outil d'analyse de fichiers binaires * processors.c - enregistrement et fourniture des architectures supportées * - * Copyright (C) 2015-2020 Cyrille Bagard + * Copyright (C) 2015-2025 Cyrille Bagard * * This file is part of Chrysalide. * @@ -29,13 +29,13 @@ #include <pthread.h> #include <string.h> - +#if 0 #include "../arch/instructions/raw.h" #include "../arch/instructions/undefined.h" #include "../arch/operands/immediate.h" #include "../arch/operands/register.h" #include "../arch/operands/target.h" - +#endif /* Cache des singletons d'opérandes */ @@ -77,12 +77,12 @@ static proc_t *find_processor_by_key(const char *); void register_arch_gtypes(void) { - g_type_ensure(G_TYPE_RAW_INSTRUCTION); - g_type_ensure(G_TYPE_UNDEF_INSTRUCTION); + //g_type_ensure(G_TYPE_RAW_INSTRUCTION); + //g_type_ensure(G_TYPE_UNDEF_INSTRUCTION); - g_type_ensure(G_TYPE_IMM_OPERAND); - g_type_ensure(G_TYPE_REGISTER_OPERAND); - g_type_ensure(G_TYPE_TARGET_OPERAND); + //g_type_ensure(G_TYPE_IMM_OPERAND); + //g_type_ensure(G_TYPE_REGISTER_OPERAND); + //g_type_ensure(G_TYPE_TARGET_OPERAND); } @@ -126,7 +126,7 @@ GSingletonFactory *get_operands_factory(void) result = __operands_factory; - g_object_ref(G_OBJECT(result)); + ref_object(result); return result; @@ -154,7 +154,7 @@ void exit_operands_factory(void) } - +#if 0 /****************************************************************************** * * * Paramètres : type = type GLib représentant le type à instancier. * @@ -206,7 +206,7 @@ bool register_processor_type(GType type) done: - g_object_unref(G_OBJECT(proc)); + unref_object(proc); return result; @@ -341,3 +341,4 @@ GArchProcessor *get_arch_processor_for_key(const char *key) return result; } +#endif diff --git a/src/core/processors.h b/src/core/processors.h index 6aa2d1e..b622305 100644 --- a/src/core/processors.h +++ b/src/core/processors.h @@ -29,7 +29,7 @@ #include <stdbool.h> -#include "../arch/processor.h" +//#include "../arch/processor.h" #include "../glibext/singleton.h" @@ -45,7 +45,7 @@ GSingletonFactory *get_operands_factory(void); /* Supprime le fournisseur d'instances uniques d'opérandes. */ void exit_operands_factory(void); - +#if 0 /* Enregistre un processeur pour une architecture donnée. */ bool register_processor_type(GType); @@ -57,7 +57,7 @@ char **get_all_processor_keys(size_t *); /* Fournit le processeur d'architecture correspondant à un nom. */ GArchProcessor *get_arch_processor_for_key(const char *); - +#endif #endif /* _CORE_PROCESSORS_H */ diff --git a/src/data/Makefile.am b/src/data/Makefile.am new file mode 100644 index 0000000..8cbe67a --- /dev/null +++ b/src/data/Makefile.am @@ -0,0 +1,2 @@ + +SUBDIRS = images diff --git a/src/data/images/Makefile.am b/src/data/images/Makefile.am new file mode 100644 index 0000000..d5ec84f --- /dev/null +++ b/src/data/images/Makefile.am @@ -0,0 +1,33 @@ + +BUILT_SOURCES = resources.h resources.c + +noinst_LTLIBRARIES = libdataimages.la + +RES_FILES = \ + about-bg.png \ + dock-station-left-symbolic.svg \ + dock-station-right-symbolic.svg \ + dock-station-bottom-symbolic.svg \ + logs-symbolic.svg + +libdataimages_la_SOURCES = \ + resources.h resources.c + +libdataimages_la_CFLAGS = $(LIBGIOUNIX_CFLAGS) + + +devdir = $(includedir)/chrysalide/$(subdir:src/%=core/%) + +dev_HEADERS = $(libdataimages_la_SOURCES:%c=) + + +resources.c: gresource.xml $(RES_FILES) + glib-compile-resources --target=$@ --sourcedir=$(srcdir) --generate-source --c-name data_images gresource.xml + +resources.h: gresource.xml + glib-compile-resources --target=$@ --sourcedir=$(srcdir) --generate-header --c-name data_images gresource.xml + + +CLEANFILES = resources.h resources.c + +EXTRA_DIST = gresource.xml $(RES_FILES) diff --git a/src/data/images/dock-station-bottom-symbolic.svg b/src/data/images/dock-station-bottom-symbolic.svg new file mode 100644 index 0000000..37084ac --- /dev/null +++ b/src/data/images/dock-station-bottom-symbolic.svg @@ -0,0 +1,197 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<!-- Created with Inkscape (http://www.inkscape.org/) --> + +<svg + width="180" + height="180" + viewBox="0 0 180 180" + version="1.1" + id="svg5" + inkscape:version="1.2.2 (b0a8486541, 2022-12-01)" + sodipodi:docname="dock-station-bottom-symbolic.svg" + xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" + xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" + xmlns="http://www.w3.org/2000/svg" + xmlns:svg="http://www.w3.org/2000/svg"> + <sodipodi:namedview + id="namedview7" + pagecolor="#ffffff" + bordercolor="#000000" + borderopacity="0.25" + inkscape:showpageshadow="2" + inkscape:pageopacity="0.0" + inkscape:pagecheckerboard="true" + inkscape:deskcolor="#d1d1d1" + inkscape:document-units="px" + showgrid="false" + inkscape:zoom="4.2708118" + inkscape:cx="87.219952" + inkscape:cy="89.444353" + inkscape:window-width="1920" + inkscape:window-height="1011" + inkscape:window-x="0" + inkscape:window-y="0" + inkscape:window-maximized="1" + inkscape:current-layer="g3929" /> + <defs + id="defs2"> + <clipPath + id="k"> + <path + d="M 0,0 H 800 V 800 H 0 Z" + id="path1320" /> + </clipPath> + <mask + id="j"> + <g + filter="url(#a)" + id="g1317"> + <path + d="M 0,0 H 16 V 16 H 0 Z" + fill-opacity="0.35" + id="path1315" /> + </g> + </mask> + <filter + id="a" + height="1" + width="1" + x="0" + y="0"> + <feColorMatrix + in="SourceGraphic" + type="matrix" + values="0 0 0 0 1 0 0 0 0 1 0 0 0 0 1 0 0 0 1 0" + id="feColorMatrix1280" /> + </filter> + <clipPath + id="i"> + <path + d="M 0,0 H 800 V 800 H 0 Z" + id="path1312" /> + </clipPath> + <mask + id="h"> + <g + filter="url(#a)" + id="g1309"> + <path + d="M 0,0 H 16 V 16 H 0 Z" + fill-opacity="0.35" + id="path1307" /> + </g> + </mask> + <filter + id="filter3652" + height="1" + width="1" + x="0" + y="0"> + <feColorMatrix + in="SourceGraphic" + type="matrix" + values="0 0 0 0 1 0 0 0 0 1 0 0 0 0 1 0 0 0 1 0" + id="feColorMatrix3650" /> + </filter> + <clipPath + id="g"> + <path + d="M 0,0 H 800 V 800 H 0 Z" + id="path1304" /> + </clipPath> + <mask + id="f"> + <g + filter="url(#a)" + id="g1301"> + <path + d="M 0,0 H 16 V 16 H 0 Z" + fill-opacity="0.35" + id="path1299" /> + </g> + </mask> + <filter + id="filter3661" + height="1" + width="1" + x="0" + y="0"> + <feColorMatrix + in="SourceGraphic" + type="matrix" + values="0 0 0 0 1 0 0 0 0 1 0 0 0 0 1 0 0 0 1 0" + id="feColorMatrix3659" /> + </filter> + <clipPath + id="e"> + <path + d="M 0,0 H 800 V 800 H 0 Z" + id="path1296" /> + </clipPath> + <mask + id="d"> + <g + filter="url(#a)" + id="g1293"> + <path + d="M 0,0 H 16 V 16 H 0 Z" + fill-opacity="0.35" + id="path1291" /> + </g> + </mask> + <filter + id="filter3670" + height="1" + width="1" + x="0" + y="0"> + <feColorMatrix + in="SourceGraphic" + type="matrix" + values="0 0 0 0 1 0 0 0 0 1 0 0 0 0 1 0 0 0 1 0" + id="feColorMatrix3668" /> + </filter> + <clipPath + id="c"> + <path + d="M 0,0 H 800 V 800 H 0 Z" + id="path1288" /> + </clipPath> + <mask + id="b"> + <g + filter="url(#a)" + id="g1285"> + <path + d="M 0,0 H 16 V 16 H 0 Z" + fill-opacity="0.3" + id="path1283" /> + </g> + </mask> + <filter + id="filter3679" + height="1" + width="1" + x="0" + y="0"> + <feColorMatrix + in="SourceGraphic" + type="matrix" + values="0 0 0 0 1 0 0 0 0 1 0 0 0 0 1 0 0 0 1 0" + id="feColorMatrix3677" /> + </filter> + </defs> + <g + inkscape:label="Calque 1" + inkscape:groupmode="layer" + id="g3929"> + <path + id="rect3921" + style="fill:#000000;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;paint-order:fill markers stroke;fill-opacity:1" + d="M 30 15 C 13.380034 15 0 28.380034 0 45 L 0 100 L 0 110 L 0 135 C 0 151.61996 13.380034 165 30 165 L 150 165 C 166.61996 165 180 151.61996 180 135 L 180 110 L 180 100 L 180 45 C 180 28.380034 166.61996 15 150 15 L 30 15 z M 35 35 L 145 35 C 153.30998 35 160 41.690016 160 50 L 160 100 L 20 100 L 20 50 C 20 41.690016 26.690016 35 35 35 z M 20 110 L 160 110 L 160 130 C 160 138.30998 153.30998 145 145 145 L 35 145 C 26.690016 145 20 138.30998 20 130 L 20 110 z " /> + <path + id="rect3923" + style="fill:#000000;fill-opacity:0.41999999;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;paint-order:fill markers stroke" + d="M 20 110 L 20 130 C 20 138.30999 26.690008 145 35 145 L 145 145 C 153.30999 145 160 138.30999 160 130 L 160 110 L 20 110 z " /> + </g> +</svg> diff --git a/src/data/images/dock-station-left-symbolic.svg b/src/data/images/dock-station-left-symbolic.svg new file mode 100644 index 0000000..0f90e8f --- /dev/null +++ b/src/data/images/dock-station-left-symbolic.svg @@ -0,0 +1,51 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<!-- Created with Inkscape (http://www.inkscape.org/) --> + +<svg + width="180" + height="180" + viewBox="0 0 180 180" + version="1.1" + id="svg5" + inkscape:version="1.2.2 (b0a8486541, 2022-12-01)" + sodipodi:docname="dock-station-left-symbolic.svg" + xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" + xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" + xmlns="http://www.w3.org/2000/svg" + xmlns:svg="http://www.w3.org/2000/svg"> + <sodipodi:namedview + id="namedview7" + pagecolor="#ffffff" + bordercolor="#000000" + borderopacity="0.25" + inkscape:showpageshadow="2" + inkscape:pageopacity="0.0" + inkscape:pagecheckerboard="true" + inkscape:deskcolor="#d1d1d1" + inkscape:document-units="px" + showgrid="false" + inkscape:zoom="4.4555556" + inkscape:cx="88.541146" + inkscape:cy="89.999999" + inkscape:window-width="1920" + inkscape:window-height="1011" + inkscape:window-x="0" + inkscape:window-y="0" + inkscape:window-maximized="1" + inkscape:current-layer="layer1" /> + <defs + id="defs2" /> + <g + inkscape:label="Calque 1" + inkscape:groupmode="layer" + id="layer1"> + <path + id="rect254" + style="fill:#000000;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;paint-order:fill markers stroke;fill-opacity:1" + d="M 30 15 C 13.380034 15 0 28.380034 0 45 L 0 135 C 0 151.61996 13.380034 165 30 165 L 65 165 L 75 165 L 150 165 C 166.61996 165 180 151.61996 180 135 L 180 45 C 180 28.380034 166.61996 15 150 15 L 75 15 L 65 15 L 30 15 z M 35 35 L 65 35 L 65 145 L 35 145 C 26.690016 145 20 138.30998 20 130 L 20 50 C 20 41.690016 26.690016 35 35 35 z M 75 35 L 145 35 C 153.30998 35 160 41.690016 160 50 L 160 130 C 160 138.30998 153.30998 145 145 145 L 75 145 L 75 35 z " /> + <path + id="rect390" + style="fill:#000000;fill-opacity:0.41999999;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;paint-order:fill markers stroke" + d="M 35 35 C 26.690008 35 20 41.690008 20 50 L 20 130 C 20 138.30999 26.690008 145 35 145 L 65 145 L 65 35 L 35 35 z " /> + </g> +</svg> diff --git a/src/data/images/dock-station-right-symbolic.svg b/src/data/images/dock-station-right-symbolic.svg new file mode 100644 index 0000000..774476a --- /dev/null +++ b/src/data/images/dock-station-right-symbolic.svg @@ -0,0 +1,76 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<!-- Created with Inkscape (http://www.inkscape.org/) --> + +<svg + width="180" + height="180" + viewBox="0 0 180 180" + version="1.1" + id="svg5" + inkscape:version="1.2.2 (b0a8486541, 2022-12-01)" + sodipodi:docname="dock-station-right-symbolic.svg" + xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" + xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" + xmlns="http://www.w3.org/2000/svg" + xmlns:svg="http://www.w3.org/2000/svg"> + <sodipodi:namedview + id="namedview7" + pagecolor="#ffffff" + bordercolor="#000000" + borderopacity="0.25" + inkscape:showpageshadow="2" + inkscape:pageopacity="0.0" + inkscape:pagecheckerboard="true" + inkscape:deskcolor="#d1d1d1" + inkscape:document-units="px" + showgrid="false" + inkscape:zoom="4.4555556" + inkscape:cx="86.408977" + inkscape:cy="89.999999" + inkscape:window-width="1920" + inkscape:window-height="1011" + inkscape:window-x="0" + inkscape:window-y="0" + inkscape:window-maximized="1" + inkscape:current-layer="layer1" /> + <defs + id="defs2" /> + <g + inkscape:label="Calque 1" + inkscape:groupmode="layer" + id="layer1"> + <path + id="rect254" + style="fill:#000000;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;paint-order:fill markers stroke;fill-opacity:1" + d="M 30 15 C 13.380034 15 0 28.380034 0 45 L 0 135 C 0 151.61996 13.380034 165 30 165 L 105 165 L 115 165 L 150 165 C 166.61996 165 180 151.61996 180 135 L 180 45 C 180 28.380034 166.61996 15 150 15 L 115 15 L 105 15 L 30 15 z M 35 35 L 105 35 L 105 145 L 35 145 C 26.690016 145 20 138.30998 20 130 L 20 50 C 20 41.690016 26.690016 35 35 35 z M 115 35 L 145 35 C 153.30998 35 160 41.690016 160 50 L 160 130 C 160 138.30998 153.30998 145 145 145 L 115 145 L 115 35 z " /> + <path + id="rect390" + style="fill:#000000;fill-opacity:0.41999999;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;paint-order:fill markers stroke" + d="M 115 35 L 115 145 L 145 145 C 153.30999 145 160 138.30999 160 130 L 160 50 C 160 41.690008 153.30999 35 145 35 L 115 35 z " /> + </g> + <g + inkscape:groupmode="layer" + id="layer2" + inkscape:label="Calque 2" + style="display:none;opacity:0.700936"> + <g + fill="#2e3436" + id="g182" + transform="matrix(11.328515,0,0,10.683311,-1.25624,4.6587097)" + style="stroke-width:0.0908993"> + <path + d="m 6.5,13.988281 v -12 h -5 v 12 z m 0,0" + fill-opacity="0.35" + id="path176" + style="stroke-width:0.00826268" /> + <path + d="m 3,0.988281 c -1.644531,0 -3,1.355469 -3,3 v 8 c 0,1.644531 1.355469,3 3,3 h 10 c 1.644531,0 3,-1.355469 3,-3 v -8 c 0,-1.644531 -1.355469,-3 -3,-3 z m 0,2 h 10 c 0.570312,0 1,0.429688 1,1 v 8 c 0,0.570313 -0.429688,1 -1,1 H 3 c -0.570312,0 -1,-0.429687 -1,-1 v -8 c 0,-0.570312 0.429688,-1 1,-1 z m 0,0" + id="path178" + style="stroke-width:0.0908993" /> + <path + d="m 6,1.988281 h 1 v 12 H 6 Z m 0,0" + id="path180" + style="stroke-width:0.0908993" /> + </g> + </g> +</svg> diff --git a/src/data/images/gresource.xml b/src/data/images/gresource.xml new file mode 100644 index 0000000..25c8274 --- /dev/null +++ b/src/data/images/gresource.xml @@ -0,0 +1,12 @@ +<?xml version="1.0" encoding="UTF-8"?> +<gresources> + <gresource prefix="/re/chrysalide/framework/gui/dialogs/about"> + <file compressed="true" alias="bg.png">about-bg.png</file> + </gresource> + <gresource prefix="/re/chrysalide/framework/gui/icons/scalable/actions"> + <file compressed="true">dock-station-left-symbolic.svg</file> + <file compressed="true">dock-station-right-symbolic.svg</file> + <file compressed="true">dock-station-bottom-symbolic.svg</file> + <file compressed="true">logs-symbolic.svg</file> + </gresource> +</gresources> diff --git a/src/data/images/logs-symbolic.svg b/src/data/images/logs-symbolic.svg new file mode 100644 index 0000000..f541607 --- /dev/null +++ b/src/data/images/logs-symbolic.svg @@ -0,0 +1,93 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<!-- Created with Inkscape (http://www.inkscape.org/) --> + +<svg + width="180" + height="180" + viewBox="0 0 180 180" + version="1.1" + id="svg5" + inkscape:version="1.2.2 (b0a8486541, 2022-12-01)" + sodipodi:docname="logs-symbolic.svg" + xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" + xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" + xmlns="http://www.w3.org/2000/svg" + xmlns:svg="http://www.w3.org/2000/svg"> + <sodipodi:namedview + id="namedview7" + pagecolor="#ffffff" + bordercolor="#000000" + borderopacity="0.25" + inkscape:showpageshadow="2" + inkscape:pageopacity="0.0" + inkscape:pagecheckerboard="0" + inkscape:deskcolor="#d1d1d1" + inkscape:document-units="px" + showgrid="false" + inkscape:zoom="3.9657403" + inkscape:cx="110.44596" + inkscape:cy="77.413036" + inkscape:window-width="1920" + inkscape:window-height="1011" + inkscape:window-x="0" + inkscape:window-y="0" + inkscape:window-maximized="1" + inkscape:current-layer="layer1" /> + <defs + id="defs2" /> + <g + inkscape:label="Calque 1" + inkscape:groupmode="layer" + id="layer1" + style="fill:#25ff4c;fill-opacity:1"> + <path + id="rect495" + style="opacity:1;fill:#000000;fill-opacity:1;stroke-width:1.99999;stroke-linecap:round;stroke-linejoin:round;paint-order:fill markers stroke" + d="M 45 0 C 31.150014 0 20 11.150014 20 25 L 20 155 C 20 168.84999 31.150014 180 45 180 L 155 180 C 168.84999 180 180 168.84999 180 155 L 180 25 C 180 11.150014 168.84999 0 155 0 L 45 0 z M 55 10 L 145 10 C 158.84999 10 170 21.150014 170 35 L 170 145 C 170 158.84999 158.84999 170 145 170 L 55 170 C 41.150014 170 30 158.84999 30 145 L 30 35 C 30 21.150014 41.150014 10 55 10 z " /> + <rect + style="display:inline;opacity:1;fill:#000000;fill-opacity:1;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;paint-order:fill markers stroke" + id="rect3619" + width="75" + height="12" + x="62.5" + y="84" + rx="6" + ry="6" /> + <rect + style="display:inline;opacity:1;fill:#000000;fill-opacity:1;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;paint-order:fill markers stroke" + id="rect5029" + width="75" + height="12" + x="62.5" + y="127" + rx="6" + ry="6" /> + <rect + style="display:inline;opacity:1;fill:#000000;fill-opacity:1;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;paint-order:fill markers stroke" + id="rect5031" + width="75" + height="12" + x="62.5" + y="41" + rx="6" + ry="6" /> + <rect + style="display:inline;opacity:1;fill:#000000;fill-opacity:1;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;paint-order:fill markers stroke" + id="rect5049" + width="34" + height="12" + x="8.2744884" + y="41" + rx="6" + ry="6" /> + <rect + style="display:inline;opacity:1;fill:#000000;fill-opacity:1;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;paint-order:fill markers stroke" + id="rect5051" + width="34" + height="12" + x="8.2744884" + y="127" + rx="6" + ry="6" /> + </g> +</svg> diff --git a/src/glibext/Makefile.am b/src/glibext/Makefile.am index f946665..b0a7c31 100644 --- a/src/glibext/Makefile.am +++ b/src/glibext/Makefile.am @@ -14,7 +14,6 @@ noinst_LTLIBRARIES = libglibext.la libglibextui.la # \ # proto.h \ # seq.h seq.c \ -# _signal.h signal.c \ # singleton.h singleton.c \ # linetoken.h linetoken.c \ # umemslice-int.h \ @@ -43,6 +42,8 @@ libglibext_la_SOURCES = \ hashable-int.h \ hashable.h hashable.c \ helpers.h \ + log-int.h \ + log.h log.c \ objhole-int.h \ objhole.h objhole.c \ portion-int.h \ @@ -51,6 +52,7 @@ libglibext_la_SOURCES = \ secstorage.h secstorage.c \ serialize-int.h \ serialize.h serialize.c \ + sigredir.h sigredir.c \ singleton-int.h \ singleton.h singleton.c \ storage-int.h \ diff --git a/src/glibext/bufferline.c b/src/glibext/bufferline.c index 4862e9f..e3fb27b 100644 --- a/src/glibext/bufferline.c +++ b/src/glibext/bufferline.c @@ -24,14 +24,16 @@ #include "bufferline.h" +#include <assert.h> +#include <malloc.h> + + #include "bufferline-int.h" #if 0 -#include <assert.h> -#include <malloc.h> #include <string.h> @@ -273,158 +275,12 @@ bool g_buffer_line_create(GBufferLine *line, size_t col_count) } - - - - - - - -/****************************************************************************** -* * -* Paramètres : line = ligne à venir compléter. * -* column = colonne de la ligne visée par l'insertion. * -* tag = type de décorateur à utiliser. * -* text = texte à insérer dans l'existant. * -* length = taille du texte à traiter. * -* style = gestionnaire de paramètres de rendu à consulter. * -* creator = instance GLib quelconque à associer. * -* * -* Description : Ajoute du texte à formater dans une ligne donnée. * -* * -* Retour : - * -* * -* Remarques : - * -* * -******************************************************************************/ - -void g_buffer_line_append_text(GBufferLine *line, size_t column, TokenRenderingTag tag, const char *text, size_t length, const GTokenStyle *style, GObject *creator) -{ - size_t index; /* Indice d'insertion */ - //content_origin *origin; /* Définition d'une origine */ - - assert(column < line->col_count); - assert(length > 0); - - index = append_text_to_line_column(&line->columns[column], tag, text, length, style); - - /* - if (creator != NULL) - { - line->origins = realloc(line->origins, ++line->ocount * sizeof(content_origin)); - - origin = &line->origins[line->ocount - 1]; - - origin->coord.column = column; - origin->coord.index = index; - - origin->creator = creator; - g_object_ref(G_OBJECT(creator)); - - } - */ - -} - - - - - - - - - - - -/****************************************************************************** -* * -* Paramètres : line = ligne de texte à manipuler. * -* cr = contexte graphique dédié à la procédure. * -* column = (première) colonne à traiter. * -* y = ordonnée du point d'impression. * -* style = style de rendu pour les bribes de texte. * -* * -* Description : Imprime la ligne de texte représentée. * -* * -* Retour : - * -* * -* Remarques : - * -* * -******************************************************************************/ - -void g_buffer_line_draw(const GBufferLine *line, cairo_t *cr, size_t column, int y, const GTokenStyle *style) -{ -#if 0 - GBufferLineClass *class; /* Stockage de briques de base */ - bool has_src_surface; /* Note une présence définie */ -#endif - size_t max_column; /* Borne de fin des colonnes */ - int x; /* Point de départ d'impression*/ - size_t i; /* Boucle de parcours */ - - /* - if (line->flags != BLF_NONE) - { - class = G_BUFFER_LINE_GET_CLASS(line); - - if (line->flags & BLF_ENTRYPOINT) - { - cairo_set_source_surface(cairo, class->entrypoint_img, 5, y); - has_src_surface = true; - } - else if (line->flags & BLF_BOOKMARK) - { - cairo_set_source_surface(cairo, class->bookmark_img, 5, y); - has_src_surface = true; - } - else - has_src_surface = false; - - if (has_src_surface) - cairo_paint(cairo); - - } - */ - - - /* Détermination de l'éventail des colonnes à traiter */ - - if (column == line->merge_start) - max_column = line->col_count; - - else if (column > line->merge_start) - max_column = 0; - - else - max_column = column + 1; - - /* Dessin du contenu de ces colonnes */ - - x = 0; - - for (i = column; i < max_column; i++) - draw_line_column(&line->columns[i], cr, &x, y, style); - -} - - - - - - - - - - -#if 0 - - /****************************************************************************** * * -* Paramètres : line = ligne à venir compléter. * -* col = indice de la colonne à constituer. * -* size = taille souhaitée de l'impression des positions. * -* addr = localisation physique à venir représenter. * +* Paramètres : line = ligne à venir compléter. * +* column = indice de la colonne visée par l'insertion. * +* size = taille souhaitée de l'impression des positions. * +* addr = localisation physique à venir représenter. * * * * Description : Construit le tronc commun d'une ligne autour de sa position. * * * @@ -434,7 +290,7 @@ void g_buffer_line_draw(const GBufferLine *line, cairo_t *cr, size_t column, int * * ******************************************************************************/ -void g_buffer_line_fill_phys(GBufferLine *line, size_t col, MemoryDataSize size, const vmpa2t *addr) +void g_buffer_line_fill_physical(GBufferLine *line, size_t column, MemoryDataSize size, const vmpa2t *addr) { VMPA_BUFFER(position); /* Emplacement au format texte */ size_t len; /* Taille de l'élément inséré */ @@ -448,20 +304,22 @@ void g_buffer_line_fill_phys(GBufferLine *line, size_t col, MemoryDataSize size, if (i == len) i = len - 1; + assert(column < line->col_count); + if (i > 0) - g_buffer_line_append_text(line, col, position, i, RTT_PHYS_ADDR_PAD, NULL); + g_buffer_line_append_text(line, column, TRT_PHYS_ADDR_PAD, position, i, NULL, NULL); - g_buffer_line_append_text(line, col, &position[i], len - i, RTT_PHYS_ADDR, NULL); + g_buffer_line_append_text(line, column, TRT_PHYS_ADDR, &position[i], len - i, NULL, NULL); } /****************************************************************************** * * -* Paramètres : line = ligne à venir compléter. * -* col = indice de la colonne à constituer. * -* size = taille souhaitée de l'impression des positions. * -* addr = localisation virtuelle à venir représenter. * +* Paramètres : line = ligne à venir compléter. * +* column = indice de la colonne visée par l'insertion. * +* size = taille souhaitée de l'impression des positions. * +* addr = localisation virtuelle à venir représenter. * * * * Description : Construit le tronc commun d'une ligne autour de sa position. * * * @@ -471,7 +329,7 @@ void g_buffer_line_fill_phys(GBufferLine *line, size_t col, MemoryDataSize size, * * ******************************************************************************/ -void g_buffer_line_fill_virt(GBufferLine *line, size_t col, MemoryDataSize size, const vmpa2t *addr) +void g_buffer_line_fill_virtual(GBufferLine *line, size_t column, MemoryDataSize size, const vmpa2t *addr) { VMPA_BUFFER(position); /* Emplacement au format texte */ size_t len; /* Taille de l'élément inséré */ @@ -479,6 +337,8 @@ void g_buffer_line_fill_virt(GBufferLine *line, size_t col, MemoryDataSize size, vmpa2_virt_to_string(addr, size, position, &len); + assert(column < line->col_count); + if (has_virt_addr(addr)) { for (i = 2; i < len; i++) @@ -488,14 +348,14 @@ void g_buffer_line_fill_virt(GBufferLine *line, size_t col, MemoryDataSize size, i = len - 1; if (i > 0) - g_buffer_line_append_text(line, col, position, i, RTT_VIRT_ADDR_PAD, NULL); + g_buffer_line_append_text(line, column, TRT_VIRT_ADDR_PAD, position, i, NULL, NULL); - g_buffer_line_append_text(line, col, &position[i], len - i, RTT_VIRT_ADDR, NULL); + g_buffer_line_append_text(line, column, TRT_VIRT_ADDR, &position[i], len - i, NULL, NULL); } else - g_buffer_line_append_text(line, col, position, len, RTT_VIRT_ADDR_PAD, NULL); + g_buffer_line_append_text(line, column, TRT_VIRT_ADDR_PAD, position, len, NULL, NULL); } @@ -503,7 +363,7 @@ void g_buffer_line_fill_virt(GBufferLine *line, size_t col, MemoryDataSize size, /****************************************************************************** * * * Paramètres : line = ligne à venir compléter. * -* col = indice de la colonne à constituer. * +* column = indice de la colonne visée par l'insertion. * * content = contenu binaire global à venir lire. * * range = localisation des données à venir lire et présenter.* * max = taille maximale de la portion binaire en octets. * @@ -516,7 +376,7 @@ void g_buffer_line_fill_virt(GBufferLine *line, size_t col, MemoryDataSize size, * * ******************************************************************************/ -void g_buffer_line_fill_content(GBufferLine *line, size_t col, const GBinContent *content, const mrange_t *range, phys_t max) +void g_buffer_line_fill_content(GBufferLine *line, size_t column, const GBinContent *content, const mrange_t *range, phys_t max) { phys_t length; /* Taille de la couverture */ bool truncated; /* Indique si le code est coupé*/ @@ -548,7 +408,7 @@ void g_buffer_line_fill_content(GBufferLine *line, size_t col, const GBinContent if (required <= sizeof(static_buffer)) bin_code = static_buffer; else - bin_code = (char *)calloc(required, sizeof(char)); + bin_code = calloc(required, sizeof(char)); /* Code brut */ @@ -589,7 +449,7 @@ void g_buffer_line_fill_content(GBufferLine *line, size_t col, const GBinContent /* Conclusion */ - g_buffer_line_append_text(line, col, bin_code, iter - bin_code, RTT_RAW_CODE, NULL); + g_buffer_line_append_text(line, column, TRT_RAW_CODE, bin_code, iter - bin_code, NULL, NULL); if (bin_code != static_buffer) free(bin_code); @@ -599,6 +459,146 @@ void g_buffer_line_fill_content(GBufferLine *line, size_t col, const GBinContent /****************************************************************************** * * +* Paramètres : line = ligne à venir compléter. * +* column = colonne de la ligne visée par l'insertion. * +* tag = type de décorateur à utiliser. * +* text = texte à insérer dans l'existant. * +* length = taille du texte à traiter. * +* style = gestionnaire de paramètres de rendu à consulter. * +* creator = instance GLib quelconque à associer. * +* * +* Description : Ajoute du texte à formater dans une ligne donnée. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +void g_buffer_line_append_text(GBufferLine *line, size_t column, TokenRenderingTag tag, const char *text, size_t length, const GTokenStyle *style, GObject *creator) +{ + size_t index; /* Indice d'insertion */ + //content_origin *origin; /* Définition d'une origine */ + + assert(column < line->col_count); + assert(length > 0); + + index = append_text_to_line_column(&line->columns[column], tag, text, length, style); + + /* + if (creator != NULL) + { + line->origins = realloc(line->origins, ++line->ocount * sizeof(content_origin)); + + origin = &line->origins[line->ocount - 1]; + + origin->coord.column = column; + origin->coord.index = index; + + origin->creator = creator; + g_object_ref(G_OBJECT(creator)); + + } + */ + +} + + + + + + + + + + + +/****************************************************************************** +* * +* Paramètres : line = ligne de texte à manipuler. * +* cr = contexte graphique dédié à la procédure. * +* column = (première) colonne à traiter. * +* y = ordonnée du point d'impression. * +* style = style de rendu pour les bribes de texte. * +* * +* Description : Imprime la ligne de texte représentée. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +void g_buffer_line_draw(const GBufferLine *line, cairo_t *cr, size_t column, int y, const GTokenStyle *style) +{ +#if 0 + GBufferLineClass *class; /* Stockage de briques de base */ + bool has_src_surface; /* Note une présence définie */ +#endif + size_t max_column; /* Borne de fin des colonnes */ + int x; /* Point de départ d'impression*/ + size_t i; /* Boucle de parcours */ + + /* + if (line->flags != BLF_NONE) + { + class = G_BUFFER_LINE_GET_CLASS(line); + + if (line->flags & BLF_ENTRYPOINT) + { + cairo_set_source_surface(cairo, class->entrypoint_img, 5, y); + has_src_surface = true; + } + else if (line->flags & BLF_BOOKMARK) + { + cairo_set_source_surface(cairo, class->bookmark_img, 5, y); + has_src_surface = true; + } + else + has_src_surface = false; + + if (has_src_surface) + cairo_paint(cairo); + + } + */ + + + /* Détermination de l'éventail des colonnes à traiter */ + + if (column == line->merge_start) + max_column = line->col_count; + + else if (column > line->merge_start) + max_column = 0; + + else + max_column = column + 1; + + /* Dessin du contenu de ces colonnes */ + + x = 0; + + for (i = column; i < max_column; i++) + draw_line_column(&line->columns[i], cr, &x, y, style); + +} + + + + + + + + + + +#if 0 + + + +/****************************************************************************** +* * * Paramètres : line = ligne à venir consulter. * * column = indice de la colonne visée par les recherches. * * * diff --git a/src/glibext/bufferline.h b/src/glibext/bufferline.h index d6a2e2d..e95ee2b 100644 --- a/src/glibext/bufferline.h +++ b/src/glibext/bufferline.h @@ -30,6 +30,8 @@ #include "helpers.h" #include "tokenstyle.h" +#include "../arch/vmpa.h" +#include "../analysis/content.h" @@ -45,8 +47,6 @@ #ifdef INCLUDE_GTK_SUPPORT # include "widthtracker.h" #endif -#include "../analysis/content.h" -#include "../arch/vmpa.h" @@ -75,6 +75,9 @@ typedef struct _GBufferLineClass GBufferLineClass; + + + #define G_TYPE_BUFFER_LINE (g_buffer_line_get_type()) DECLARE_GTYPE(GBufferLine, g_buffer_line, G, BUFFER_LINE); @@ -98,7 +101,14 @@ typedef enum _BufferLineFlags /* Crée une nouvelle représentation de fragments de texte. */ GBufferLine *g_buffer_line_new(size_t); +/* Construit le tronc commun d'une ligne autour de sa position. */ +void g_buffer_line_fill_physical(GBufferLine *, size_t, MemoryDataSize, const vmpa2t *); + +/* Construit le tronc commun d'une ligne autour de sa position. */ +void g_buffer_line_fill_virtual(GBufferLine *, size_t, MemoryDataSize, const vmpa2t *); +/* Construit le tronc commun d'une ligne autour de son contenu. */ +void g_buffer_line_fill_content(GBufferLine *, size_t, const GBinContent *, const mrange_t *, phys_t); /* Ajoute du texte à formater dans une ligne donnée. */ void g_buffer_line_append_text(GBufferLine *, size_t, TokenRenderingTag, const char *, size_t, const GTokenStyle *, GObject *); diff --git a/src/glibext/log-int.h b/src/glibext/log-int.h new file mode 100644 index 0000000..3b3208a --- /dev/null +++ b/src/glibext/log-int.h @@ -0,0 +1,58 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * log-int.h - prototypes internes pour la conservation à destination graphique des éléments de journalisation + * + * Copyright (C) 2025 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Foobar. If not, see <http://www.gnu.org/licenses/>. + */ + + +#ifndef _GLIBEXT_LOG_INT_H +#define _GLIBEXT_LOG_INT_H + + +#include <stdbool.h> + + +#include "log.h" + + + +/* Définition d'une conservation d'objets construits (instance) */ +struct _GLogEntry +{ + GObject parent; /* A laisser en premier */ + + LogMessageType type; /* Type de message porté */ + char *msg; /* Contenu du message diffusé */ + +}; + +/* Définition d'une conservation d'objets construits (classe) */ +struct _GLogEntryClass +{ + GObjectClass parent; /* A laisser en premier */ + +}; + + +/* Met en place une conservation pour élément de journalisation. */ +bool g_log_entry_create(GLogEntry *, LogMessageType, const char *); + + + +#endif /* _GLIBEXT_LOG_INT_H */ diff --git a/src/glibext/log.c b/src/glibext/log.c new file mode 100644 index 0000000..039172c --- /dev/null +++ b/src/glibext/log.c @@ -0,0 +1,306 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * log.c - conservation hors mémoire d'objets choisis + * + * Copyright (C) 2020-2025 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Foobar. If not, see <http://www.gnu.org/licenses/>. + */ + + +#include "log.h" + + +#include <malloc.h> +#include <string.h> + + +#include "log-int.h" + + + +/* ---------------------------- ENTREE DE JOURNALISATION ---------------------------- */ + + +/* Liste des propriétés */ + +typedef enum _LogEntryProperty { + + PROP_0, /* Réservé */ + + PROP_ICON_NAME, /* Nom d'image de représentat° */ + PROP_MESSAGE, /* Contenu du message diffusé */ + + N_PROPERTIES + +} LogEntryProperty; + +static GParamSpec *_log_entry_properties[N_PROPERTIES] = { NULL, }; + + +/* Initialise la classe des conservations d'objets en place. */ +static void g_log_entry_class_init(GLogEntryClass *); + +/* Initialise une instance de conservation d'objets en place. */ +static void g_log_entry_init(GLogEntry *); + +/* Supprime toutes les références externes. */ +static void g_log_entry_dispose(GObject *); + +/* Procède à la libération totale de la mémoire. */ +static void g_log_entry_finalize(GObject *); + + + +/* --------------------- IMPLEMENTATION DES FONCTIONS DE CLASSE --------------------- */ + + +/* Fournit la valeur d'une propriété d'instance GObject. */ +static void gtk_log_entry_get_property(GObject *, guint, GValue *, GParamSpec *); + + + +/* ---------------------------------------------------------------------------------- */ +/* ENTREE DE JOURNALISATION */ +/* ---------------------------------------------------------------------------------- */ + + +/* Indique le type défini pour une conservation d'objets construits. */ +G_DEFINE_TYPE(GLogEntry, g_log_entry, G_TYPE_OBJECT); + + +/****************************************************************************** +* * +* Paramètres : klass = classe à initialiser. * +* * +* Description : Initialise la classe des conservations d'objets en place. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_log_entry_class_init(GLogEntryClass *klass) +{ + GObjectClass *object; /* Autre version de la classe */ + + object = G_OBJECT_CLASS(klass); + + object->dispose = g_log_entry_dispose; + object->finalize = g_log_entry_finalize; + object->get_property = gtk_log_entry_get_property; + + _log_entry_properties[PROP_ICON_NAME] = + g_param_spec_string("icon-name", NULL, NULL, + NULL, + G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); + + _log_entry_properties[PROP_MESSAGE] = + g_param_spec_string("message", NULL, NULL, + NULL, + G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); + + g_object_class_install_properties(object, N_PROPERTIES, _log_entry_properties); + +} + + +/****************************************************************************** +* * +* Paramètres : entry = instance à initialiser. * +* * +* Description : Initialise une instance de conservation d'objets en place. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_log_entry_init(GLogEntry *entry) +{ + entry->type = LMT_COUNT; + entry->msg = NULL; + +} + + +/****************************************************************************** +* * +* Paramètres : object = instance d'objet GLib à traiter. * +* * +* Description : Supprime toutes les références externes. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_log_entry_dispose(GObject *object) +{ + G_OBJECT_CLASS(g_log_entry_parent_class)->dispose(object); + +} + + +/****************************************************************************** +* * +* Paramètres : object = instance d'objet GLib à traiter. * +* * +* Description : Procède à la libération totale de la mémoire. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_log_entry_finalize(GObject *object) +{ + GLogEntry *entry; /* Version spécialisée */ + + entry = G_LOG_ENTRY(object); + + if (entry->msg != NULL) + free(entry->msg); + + G_OBJECT_CLASS(g_log_entry_parent_class)->finalize(object); + +} + + +/****************************************************************************** +* * +* Paramètres : type = espèce du message à représenter. * +* msg = message à faire apparaître à l'écran. * +* * +* Description : Crée une conservation pour un élément de journalisation. * +* * +* Retour : Conservation mise en place. * +* * +* Remarques : - * +* * +******************************************************************************/ + +GLogEntry *g_log_entry_new(LogMessageType type, const char *msg) +{ + GLogEntry *result; /* Structure à retourner */ + + result = g_object_new(G_TYPE_LOG_ENTRY, NULL); + + if (!g_log_entry_create(result, type, msg)) + g_clear_object(&result); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : entry = instance de conservation à initialiser pleinement. * +* type = espèce du message à représenter. * +* msg = message à faire apparaître à l'écran. * +* * +* Description : Met en place une conservation pour élément de journalisation.* +* * +* Retour : Conservation mise en place. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool g_log_entry_create(GLogEntry *entry, LogMessageType type, const char *msg) +{ + bool result; /* Bilan à retourner */ + + result = true; + + entry->type = type; + entry->msg = strdup(msg); + + return result; + +} + + + +/* ---------------------------------------------------------------------------------- */ +/* IMPLEMENTATION DES FONCTIONS DE CLASSE */ +/* ---------------------------------------------------------------------------------- */ + + +/****************************************************************************** +* * +* Paramètres : object = instance d'objet GLib à mamnipuler. * +* prop_id = identifiant de la propriété visée. * +* value = valeur à transmettre. [OUT] * +* pspec = définition de la propriété. * +* * +* Description : Fournit la valeur d'une propriété d'instance GObject. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void gtk_log_entry_get_property(GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) +{ + GLogEntry *entry; /* Version spécialisée */ + + entry = G_LOG_ENTRY(object); + + switch (prop_id) + { + case PROP_ICON_NAME: + switch (entry->type) + { + case LMT_INFO: + g_value_set_string(value, "dialog-information-symbolic"); + break; + + case LMT_PROCESS: + g_value_set_string(value, "system-run-symbolic"); + break; + + case LMT_WARNING: + case LMT_BAD_BINARY: + g_value_set_string(value, "dialog-warning-symbolic"); + break; + + case LMT_ERROR: + case LMT_EXT_ERROR: + g_value_set_string(value, "computer-fail-symbolic"); + break; + + + case LMT_COUNT: + g_value_set_string(value, "dialog-question-symbolic"); + break; + + } + break; + + case PROP_MESSAGE: + g_value_set_string(value, entry->msg); + break; + + } + +} diff --git a/src/glibext/log.h b/src/glibext/log.h new file mode 100644 index 0000000..472773c --- /dev/null +++ b/src/glibext/log.h @@ -0,0 +1,43 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * log.h - prototypes pour la conservation à destination graphique des éléments de journalisation + * + * Copyright (C) 2025 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Foobar. If not, see <http://www.gnu.org/licenses/>. + */ + + +#ifndef _GLIBEXT_LOG_H +#define _GLIBEXT_LOG_H + + +#include "helpers.h" +#include "../core/logs.h" + + + +#define G_TYPE_LOG_ENTRY (g_log_entry_get_type()) + +DECLARE_GTYPE(GLogEntry, g_log_entry, G, LOG_ENTRY); + + +/* Crée une conservation pour un élément de journalisation. */ +GLogEntry *g_log_entry_new(LogMessageType, const char *); + + + +#endif /* _GLIBEXT_LOG_H */ diff --git a/src/glibext/options/asm.h b/src/glibext/options/asm.h index e916083..d7a2c86 100644 --- a/src/glibext/options/asm.h +++ b/src/glibext/options/asm.h @@ -1,6 +1,6 @@ /* Chrysalide - Outil d'analyse de fichiers binaires - * disass.h - prototypes pour les options de rendus de code désassemblé + * asm.h - prototypes pour les options de rendus de code désassemblé * * Copyright (C) 2025 Cyrille Bagard * @@ -21,8 +21,8 @@ */ -#ifndef _GLIBEXT_OPTIONS_DISASS_H -#define _GLIBEXT_OPTIONS_DISASS_H +#ifndef _GLIBEXT_OPTIONS_ASM_H +#define _GLIBEXT_OPTIONS_ASM_H #include "../helpers.h" @@ -32,14 +32,23 @@ /* Liste des colonnes en options */ typedef enum _DisassColumnOptions { - ACO_OFFSET, /* Position */ + ACO_PHYSICAL, /* Position physique */ + ACO_VIRTUAL, /* Adresse virtuelle */ + ACO_BINARY, /* Contenu sous forme binaire */ ACO_COUNT } DisassColumnOptions; -#define ACO_ASSEMBLY (ACO_COUNT + 0) /* Code pour assembleur */ +#define ACO_ASSEMBLY_LABEL (ACO_COUNT + 0) /* Etiquette dans les données */ +#define ACO_ASSEMBLY_HEAD (ACO_COUNT + 1) /* Instruction pour assembleur */ +#define ACO_ASSEMBLY (ACO_COUNT + 2) /* Code pour assembleur */ +#define ACO_COMMENTS (ACO_COUNT + 3) /* Commentaires éventuels */ + + + + #if 0 diff --git a/src/glibext/secstorage.c b/src/glibext/secstorage.c index b118aa6..161214c 100644 --- a/src/glibext/secstorage.c +++ b/src/glibext/secstorage.c @@ -160,7 +160,7 @@ static void g_secret_storage_init(GSecretStorage *storage) static void g_secret_storage_dispose(GObject *object) { - GSecretStorage *storage; /* Gestion de stockage sécurisé*/ + GSecretStorage *storage; /* Version spécialisée */ storage = G_SECRET_STORAGE(object); @@ -185,7 +185,7 @@ static void g_secret_storage_dispose(GObject *object) static void g_secret_storage_finalize(GObject *object) { - GSecretStorage *storage; /* Gestion de stockage sécurisé*/ + GSecretStorage *storage; /* Version spécialisée */ storage = G_SECRET_STORAGE(object); diff --git a/src/glibext/signal.c b/src/glibext/sigredir.c index 33290fb..67e8563 100644 --- a/src/glibext/signal.c +++ b/src/glibext/sigredir.c @@ -1,8 +1,8 @@ /* Chrysalide - Outil d'analyse de fichiers binaires - * signal.c - encadrement des signaux supplémentaire par rapport à celui de la GLib + * sigredir.c - encadrement des signaux supplémentaire par rapport à celui de la GLib * - * Copyright (C) 2014-2018 Cyrille Bagard + * Copyright (C) 2014-2025 Cyrille Bagard * * This file is part of Chrysalide. * @@ -21,49 +21,55 @@ */ -#include "signal.h" +#include "sigredir.h" #include <assert.h> #include <malloc.h> #include <stdarg.h> #include <stdbool.h> +#include <gobject/gclosure.h> #include <gobject/gvaluecollector.h> -/* Prototype pour le transfert d'exécution. */ -typedef void (* GSignalCallback) (gpointer, ...); +/* Informations utiles à l'appel final */ +typedef struct _gsignal_wrapper_params_t +{ + GClosure *closure; /* Glue pour les appels */ + + guint n_params; /* Nombre de paramètres */ + GValue instance_and_params[0]; /* Instance & paramètres */ + +} gsignal_wrapper_params_t; + +/* Transmet un signal dans le contexte principal. */ +static gboolean to_main_wrapper(gpointer); +/* Supprime de la mémoire le transporteur d'informations. */ +static void destroy_wrapper_params(gpointer); /* Informations concernant une diffusion de signal */ -typedef struct _gsignal_wrapper_info +typedef struct _gsignal_wrapper_info_t { gpointer instance; /* Instance GLib initiatrice */ + gulong id; /* Identifiant de connexion */ GClosure *closure; /* Glue pour les appels */ - GType return_type; /* Type de la valeur retournée */ guint n_params; /* Nombre de paramètres */ - const GType *param_types; /* Type des paramètres associés*/ + GType param_types[0]; /* Type des paramètres associés*/ - GValue return_value; /* Valeur de retour */ - GValue instance_and_params[0]; /* Instance & paramètres */ - -} gsignal_wrapper_info; - - -/* Transmet un signal dans le contexte principal. */ -static gboolean to_main_wrapper(gsignal_wrapper_info *); +} gsignal_wrapper_info_t; /* Réceptionne un signal et redirige son exécution. */ -static void carry_signal_to_main_thread(gsignal_wrapper_info *, ...); +static void carry_signal_to_main_thread(gsignal_wrapper_info_t *, ...); /****************************************************************************** * * -* Paramètres : info = collecteur d'informations sur la diffusion. * +* Paramètres : data = collecteur d'informations sur la diffusion. * * * * Description : Transmet un signal dans le contexte principal. * * * @@ -73,11 +79,17 @@ static void carry_signal_to_main_thread(gsignal_wrapper_info *, ...); * * ******************************************************************************/ -static gboolean to_main_wrapper(gsignal_wrapper_info *info) +static gboolean to_main_wrapper(gpointer data) { - g_closure_invoke(info->closure, NULL/*&info->return_value*/, - info->n_params + 1, info->instance_and_params, - NULL); + gsignal_wrapper_params_t *params; /* Informations d'appel */ + + params = (gsignal_wrapper_params_t *)data; + + g_closure_invoke(params->closure, + NULL /* return_value */, + params->n_params + 1, + params->instance_and_params, + NULL /* invocation_hint */); return G_SOURCE_REMOVE; @@ -86,6 +98,35 @@ static gboolean to_main_wrapper(gsignal_wrapper_info *info) /****************************************************************************** * * +* Paramètres : data = collecteur d'informations à supprimer. * +* * +* Description : Supprime de la mémoire le transporteur d'informations. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void destroy_wrapper_params(gpointer data) +{ + gsignal_wrapper_params_t *params; /* Informations d'appel */ + guint i; /* Boucle de parcours */ + + params = (gsignal_wrapper_params_t *)data; + + g_closure_unref(params->closure); + + for (i = 0; i < (params->n_params + 1); i++) + g_value_unset(params->instance_and_params + i); + + free(params); + +} + + +/****************************************************************************** +* * * Paramètres : info = collecteur d'informations sur la diffusion. * * ... = arguments poussés par la GLib sur la pile. * * * @@ -97,23 +138,26 @@ static gboolean to_main_wrapper(gsignal_wrapper_info *info) * * ******************************************************************************/ -static void carry_signal_to_main_thread(gsignal_wrapper_info *info, ...) +static void carry_signal_to_main_thread(gsignal_wrapper_info_t *info, ...) { + gsignal_wrapper_params_t *params; /* Informations d'appel */ GValue *param_values; /* Paramètres d'appel */ va_list ap; /* Liste d'arguments sur pile */ guint i; /* Boucle de parcours */ bool static_scope; /* Portée des arguments */ gchar *error; /* Eventuelle erreur inattendue*/ - //g_value_init(&info->return_value, info->return_type & ~G_SIGNAL_TYPE_STATIC_SCOPE); + params = calloc(1, sizeof(gsignal_wrapper_params_t) + sizeof(GValue) * (info->n_params + 1)); + + params->closure = info->closure; + g_closure_ref(info->closure); - if (G_IS_VALUE(info->instance_and_params)) - g_value_unset(info->instance_and_params); + params->n_params = info->n_params; - g_value_init(info->instance_and_params, G_TYPE_FROM_INSTANCE(info->instance)); - g_value_set_instance(info->instance_and_params, info->instance); + g_value_init(params->instance_and_params, G_TYPE_FROM_INSTANCE(info->instance)); + g_value_set_instance(params->instance_and_params, info->instance); - param_values = info->instance_and_params + 1; + param_values = params->instance_and_params + 1; va_start(ap, info); @@ -121,9 +165,6 @@ static void carry_signal_to_main_thread(gsignal_wrapper_info *info, ...) for (i = 0; i < info->n_params; i++) { - if (G_IS_VALUE(param_values + i)) - g_value_unset(param_values + i); - static_scope = info->param_types[i] & G_SIGNAL_TYPE_STATIC_SCOPE; G_VALUE_COLLECT_INIT(param_values + i, @@ -143,7 +184,28 @@ static void carry_signal_to_main_thread(gsignal_wrapper_info *info, ...) va_end(ap); if (error == NULL) - g_idle_add_full(G_PRIORITY_HIGH_IDLE, (GSourceFunc)to_main_wrapper, info, NULL); + g_idle_add_full(G_PRIORITY_HIGH_IDLE, to_main_wrapper, params, destroy_wrapper_params); + +} + + +/****************************************************************************** +* * +* Paramètres : info = collecteur d'informations à supprimer. * +* * +* Description : Déconnecte un signal redirigé vers le contexte principal. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +void g_signal_disconnect_from_main(gsignal_wrapper_info_t *info) +{ + g_signal_handler_disconnect(info->instance, info->id); + + free(info); } @@ -165,41 +227,44 @@ static void carry_signal_to_main_thread(gsignal_wrapper_info *info, ...) * * ******************************************************************************/ -gulong _g_signal_connect_to_main(gpointer instance, const gchar *signal, GCallback handler, gpointer data, GClosureMarshal marshal, GConnectFlags flags) +gsignal_wrapper_info_t *_g_signal_connect_to_main(gpointer instance, const gchar *signal, GCallback handler, gpointer data, GClosureMarshal marshal, GConnectFlags flags) { + gsignal_wrapper_info_t *result; /* Structure à renvoyer */ guint signal_id; /* Identifiant du signal visé */ GSignalQuery query; /* Information sur le signal */ - gsignal_wrapper_info *info; /* Encapsulation des données */ /* Collection d'informations */ signal_id = g_signal_lookup(signal, G_TYPE_FROM_INSTANCE(instance)); g_signal_query(signal_id, &query); + assert(query.signal_id != 0); + assert(query.return_type == G_TYPE_NONE); /* Allocation adaptée */ - info = calloc(1, sizeof(gsignal_wrapper_info) + sizeof(GValue) * (query.n_params + 1)); + result = malloc(sizeof(gsignal_wrapper_info_t) + sizeof(GType) * query.n_params); - info->instance = instance; + result->instance = instance; if (flags & G_CONNECT_SWAPPED) - info->closure = g_cclosure_new_swap(handler, data, NULL); + result->closure = g_cclosure_new_swap(handler, data, NULL); else - info->closure = g_cclosure_new(handler, data, NULL); + result->closure = g_cclosure_new(handler, data, NULL); - g_closure_ref(info->closure); - g_closure_sink(info->closure); + g_closure_ref(result->closure); + g_closure_sink(result->closure); - g_closure_set_marshal(info->closure, marshal); + g_closure_set_marshal(result->closure, marshal); - info->return_type = query.return_type; - info->n_params = query.n_params; - info->param_types = query.param_types; + result->n_params = query.n_params; + memcpy(result->param_types, query.param_types, sizeof(GType) * query.n_params); - assert(query.return_type == G_TYPE_NONE); + /* Connexion au signal */ + + result->id = g_signal_connect_swapped(instance, signal, G_CALLBACK(carry_signal_to_main_thread), result); - return g_signal_connect_swapped(instance, signal, G_CALLBACK(carry_signal_to_main_thread), info); + return result; } diff --git a/src/glibext/_signal.h b/src/glibext/sigredir.h index 4f0ab4b..f394d77 100644 --- a/src/glibext/_signal.h +++ b/src/glibext/sigredir.h @@ -1,8 +1,8 @@ /* Chrysalide - Outil d'analyse de fichiers binaires - * signal.h - prototypes pour un encadrement des signaux supplémentaire par rapport à celui de la GLib + * sigredir.h - prototypes pour un encadrement des signaux supplémentaire par rapport à celui de la GLib * - * Copyright (C) 2014-2018 Cyrille Bagard + * Copyright (C) 2014-2025 Cyrille Bagard * * This file is part of Chrysalide. * @@ -21,20 +21,23 @@ */ -#ifndef _GLIBEXT_SIGNAL_H -#define _GLIBEXT_SIGNAL_H +#ifndef _GLIBEXT_SIGREDIR_H +#define _GLIBEXT_SIGREDIR_H #include <glib-object.h> -#include <gobject/gclosure.h> -#include <glib/gdataset.h> -#include <glib/glist.h> #include <gobject/gsignal.h> +/* Informations concernant une diffusion de signal */ +typedef struct _gsignal_wrapper_info_t gsignal_wrapper_info_t; + /* Reproduit le comportement de la fonction g_signal_connect(). */ -gulong _g_signal_connect_to_main(gpointer, const gchar *, GCallback, gpointer, GClosureMarshal, GConnectFlags); +gsignal_wrapper_info_t *_g_signal_connect_to_main(gpointer, const gchar *, GCallback, gpointer, GClosureMarshal, GConnectFlags); + +/* Déconnecte un signal redirigé vers le contexte principal. */ +void g_signal_disconnect_from_main(gsignal_wrapper_info_t *); #define g_signal_connect_to_main(instance, signal, handler, data, marshal) \ @@ -45,4 +48,4 @@ gulong _g_signal_connect_to_main(gpointer, const gchar *, GCallback, gpointer, G -#endif /* _GLIBEXT_SIGNAL_H */ +#endif /* _GLIBEXT_SIGREDIR_H */ diff --git a/src/glibext/storage-int.h b/src/glibext/storage-int.h index e4bac7a..d89e1c8 100644 --- a/src/glibext/storage-int.h +++ b/src/glibext/storage-int.h @@ -1,6 +1,6 @@ /* Chrysalide - Outil d'analyse de fichiers binaires - * storage.h - prototypes internes pour la conservation sur disque d'objets construits + * storage-int.h - prototypes internes pour la conservation sur disque d'objets construits * * Copyright (C) 2020-2025 Cyrille Bagard * diff --git a/src/glibext/widthtracker.c b/src/glibext/widthtracker.c index 7e06578..0a3dbe6 100644 --- a/src/glibext/widthtracker.c +++ b/src/glibext/widthtracker.c @@ -330,13 +330,17 @@ void g_width_tracker_set_column_min_width(GWidthTracker *tracker, size_t col, in void g_width_tracker_compute_width(const GWidthTracker *tracker, int *width) { + size_t col_count; /* Nombre maximum de colonnes */ size_t i; /* Boucle de parcours */ *width = 0; - // FIX access to col_count - for (i = 0; i < tracker->col_count; i++) + + col_count = tracker->opt_count + tracker->reg_count; + + + for (i = 0; i < col_count; i++) *width += tracker->min_widths[i]; } diff --git a/src/gtkext/Makefile.am b/src/gtkext/Makefile.am index 839ee8f..c6908dd 100644 --- a/src/gtkext/Makefile.am +++ b/src/gtkext/Makefile.am @@ -29,6 +29,8 @@ libgtkext_la_CFLAGS = $(LIBGTK_CFLAGS) $(LIBXML_CFLAGS) IMG_PATH = ../../data/images RES_FILES = \ + grid.ui \ + dockstation.ui \ hexview.css \ hexview.ui \ launcher.ui \ @@ -64,6 +66,9 @@ libgtkext4_la_SOURCES = \ libgtkext4_la_CFLAGS = $(LIBGTK4_CFLAGS) +libgtkext4_la_LIBADD = \ + bindings/libgtkextbindings.la + devdir = $(includedir)/chrysalide/$(subdir:src/%=core/%) @@ -71,6 +76,7 @@ dev_HEADERS = $(libgtkext4_la_SOURCES:%c=) #SUBDIRS = graph +SUBDIRS = bindings resources.c: gresource.xml $(RES_FILES) diff --git a/src/gtkext/area.c b/src/gtkext/area.c index 3c59a59..3c573b2 100644 --- a/src/gtkext/area.c +++ b/src/gtkext/area.c @@ -85,6 +85,8 @@ static void gtk_composing_area_class_init(GtkComposingAreaClass *class) widget = GTK_WIDGET_CLASS(class); + gtk_widget_class_set_css_name(widget, "comparea"); + widget->snapshot = gtk_composing_area_snapshot; } diff --git a/src/gtkext/bindings/Makefile.am b/src/gtkext/bindings/Makefile.am new file mode 100644 index 0000000..71e770d --- /dev/null +++ b/src/gtkext/bindings/Makefile.am @@ -0,0 +1,42 @@ + +EXTRA_DIST = \ + generated-enums.c.template \ + generated-enums.h.template + + +noinst_LTLIBRARIES = libgtkextbindings.la + + +nodist_libgtkextbindings_la_SOURCES = \ + grid-enums.h grid-enums.c + +libgtkextbindings_la_CFLAGS = $(LIBGTK4_CFLAGS) + + +BUILT_SOURCES = $(nodist_libgtkextbindings_la_SOURCES) +CLEANFILES = $(nodist_libgtkextbindings_la_SOURCES) + + +devdir = $(includedir)/chrysalide/$(subdir:src/%=core/%) + +dev_HEADERS = $(nodist_libgtkextbindings_la_SOURCES:%c=) + + +grid-enums.c: ../../gtkext/grid.h generated-enums.c.template + $(AM_V_GEN)$(GLIB_MKENUMS) \ + --fhead "#include \"$(subst .c,.h,$@)\"\n" \ + --template=$(srcdir)/generated-enums.c.template \ + --output=$(srcdir)/$@ \ + $< + +grid-enums.h: ../../gtkext/grid.h generated-enums.h.template + $(AM_V_GEN)$(GLIB_MKENUMS) \ + --fhead "#ifndef _GTKEXT_BINDINGS_GRID_ENUM_H\n" \ + --fhead "#define _GTKEXT_BINDINGS_GRID_ENUM_H\n" \ + --fhead "\n" \ + --fhead "#include \"$<\"\n" \ + --fhead "\n" \ + --ftail "#endif /* _GTKEXT_BINDINGS_GRID_ENUM_H */\n" \ + --template=$(srcdir)/generated-enums.h.template \ + --output=$(srcdir)/$@ \ + $< diff --git a/src/gtkext/bindings/generated-enums.c.template b/src/gtkext/bindings/generated-enums.c.template new file mode 100644 index 0000000..8f54149 --- /dev/null +++ b/src/gtkext/bindings/generated-enums.c.template @@ -0,0 +1,41 @@ +// SPDX-License-Identifier: LGPL-2.1-or-later +// SPDX-FileCopyrightText: 2023 Bartosz Golaszewski <bartosz.golaszewski@linaro.org> + +/*** BEGIN file-header ***/ + +/*** END file-header ***/ + +/*** BEGIN file-production ***/ + +/* Enumerations de "@filename@" */ + +/*** END file-production ***/ + +/*** BEGIN value-header ***/ + +GType @enum_name@_get_type(void) +{ + static gsize static_g_@type@_type_id; + + if (g_once_init_enter(&static_g_@type@_type_id)) { + static const G@Type@Value values[] = { +/*** END value-header ***/ + +/*** BEGIN value-production ***/ + {@VALUENAME@, "@VALUENAME@", "@valuenick@"}, +/*** END value-production ***/ + +/*** BEGIN value-tail ***/ + { 0, NULL, NULL } + }; + + GType g_@type@_type_id = g_@type@_register_static( + g_intern_static_string("@EnumName@"), values); + + g_once_init_leave (&static_g_@type@_type_id, g_@type@_type_id); + } + + return static_g_@type@_type_id; +} + +/*** END value-tail ***/ diff --git a/src/gtkext/bindings/generated-enums.h.template b/src/gtkext/bindings/generated-enums.h.template new file mode 100644 index 0000000..58c772d --- /dev/null +++ b/src/gtkext/bindings/generated-enums.h.template @@ -0,0 +1,23 @@ +// SPDX-License-Identifier: LGPL-2.1-or-later +// SPDX-FileCopyrightText: 2023-2024 Bartosz Golaszewski <bartosz.golaszewski@linaro.org> + +/*** BEGIN file-header ***/ + +G_BEGIN_DECLS + +/*** END file-header ***/ + +/*** BEGIN file-production ***/ + +/*** END file-production ***/ + +/*** BEGIN value-header ***/ +GType @enum_name@_get_type(void) G_GNUC_CONST; +#define @ENUMPREFIX@_@ENUMSHORT@_TYPE (@enum_name@_get_type()) +/*** END value-header ***/ + +/*** BEGIN file-tail ***/ + +G_END_DECLS + +/*** END file-tail ***/ diff --git a/src/gtkext/dockstation-int.h b/src/gtkext/dockstation-int.h index a44371a..17ed828 100644 --- a/src/gtkext/dockstation-int.h +++ b/src/gtkext/dockstation-int.h @@ -32,19 +32,29 @@ /* Station de réception pour concentration d'éléments (instance) */ struct _GtkDockStation { - GtkWidget parent; /* A laisser en premier */ + GtkBox parent; /* A laisser en premier */ + + GtkOrientation orientation; /* Spécification d'orientation */ + + GtkWidget *tabs; /* Bascule entre panneaux */ + GtkWidget *toolbar; /* Boutons d'action */ + GtkWidget *sep1; /* Séparateur #1 */ + GtkStack *stack; /* Pile de panneaux affichés */ + GtkWidget *sep2; /* Séparateur #2 */ + + GtkTiledPanel *def_panel; /* Eventuel panneau à maintenir*/ }; /* Station de réception pour concentration d'éléments (classe) */ struct _GtkDockStationClass { - GtkWidgetClass parent; /* A laisser en premier */ + GtkBoxClass parent; /* A laisser en premier */ /* Signaux */ - void (* dock_widget) (GtkDockStation *, GtkWidget *); - void (* undock_widget) (GtkDockStation *, GtkWidget *); + void (* panel_docked) (GtkDockStation *, GtkTiledPanel *); + void (* panel_undocked) (GtkDockStation *, GtkTiledPanel *); void (* switch_widget) (GtkDockStation *, GtkWidget *); diff --git a/src/gtkext/dockstation.c b/src/gtkext/dockstation.c index 093f120..80bae75 100644 --- a/src/gtkext/dockstation.c +++ b/src/gtkext/dockstation.c @@ -28,6 +28,25 @@ +/* --------------------------- INTERFACE DU COMPOSANT GTK --------------------------- */ + + +/* Liste des propriétés */ + +typedef enum _DockStationProperty { + + PROP_0, /* Réservé */ + + /* Interface GtkOrientable */ + PROP_ORIENTATION, + + N_PROPERTIES = PROP_ORIENTATION + +} DockStationProperty; + +//static GParamSpec *_dock_station_properties[N_PROPERTIES] = { NULL, }; + + /* Procède à l'initialisation de l'afficheur concentré. */ static void gtk_dock_station_class_init(GtkDockStationClass *); @@ -35,16 +54,31 @@ static void gtk_dock_station_class_init(GtkDockStationClass *); static void gtk_dock_station_init(GtkDockStation *); /* Supprime toutes les références externes. */ -static void gtk_dock_station_dispose(GtkDockStation *); +static void gtk_dock_station_dispose(GObject *); /* Procède à la libération totale de la mémoire. */ -static void gtk_dock_station_finalize(GtkDockStation *); +static void gtk_dock_station_finalize(GObject *); + + + +/* --------------------- IMPLEMENTATION DES FONCTIONS DE CLASSE --------------------- */ + + +/* Met à jour une propriété d'instance GObject. */ +static void gtk_dock_station_set_property(GObject *, guint, const GValue *, GParamSpec *); +/* Fournit la valeur d'une propriété d'instance GObject. */ +static void gtk_dock_station_get_property(GObject *, guint, GValue *, GParamSpec *); +/* ---------------------------------------------------------------------------------- */ +/* INTERFACE DU COMPOSANT GTK */ +/* ---------------------------------------------------------------------------------- */ + + /* Détermine le type du composant d'affichage concentré. */ -G_DEFINE_TYPE(GtkDockStation, gtk_dock_station, GTK_TYPE_WIDGET) +G_DEFINE_TYPE(GtkDockStation, gtk_dock_station, GTK_TYPE_GRID) /****************************************************************************** @@ -62,28 +96,47 @@ G_DEFINE_TYPE(GtkDockStation, gtk_dock_station, GTK_TYPE_WIDGET) static void gtk_dock_station_class_init(GtkDockStationClass *class) { GObjectClass *object; /* Autre version de la classe */ + GtkWidgetClass *widget; /* Classe de haut niveau */ object = G_OBJECT_CLASS(class); - object->dispose = (GObjectFinalizeFunc/* ! */)gtk_dock_station_dispose; - object->finalize = (GObjectFinalizeFunc)gtk_dock_station_finalize; + object->dispose = gtk_dock_station_dispose; + object->finalize = gtk_dock_station_finalize; + object->set_property = gtk_dock_station_set_property; + object->get_property = gtk_dock_station_get_property; - g_signal_new("dock-widget", + //g_object_class_install_properties(object, N_PROPERTIES, _dock_station_properties); + g_object_class_override_property(object, PROP_ORIENTATION, "orientation"); + + widget = GTK_WIDGET_CLASS(class); + + gtk_widget_class_set_template_from_resource(widget, "/re/chrysalide/framework/gtkext/dockstation.ui"); + + //gtk_widget_class_bind_template_callback_full(widget, BUILDER_CB(gtk_status_stack_on_zoom_icon_press)); + + gtk_widget_class_bind_template_child(widget, GtkDockStation, tabs); + gtk_widget_class_bind_template_child(widget, GtkDockStation, toolbar); + gtk_widget_class_bind_template_child(widget, GtkDockStation, sep1); + gtk_widget_class_bind_template_child(widget, GtkDockStation, stack); + gtk_widget_class_bind_template_child(widget, GtkDockStation, sep2); + + g_signal_new("panel-docked", GTK_TYPE_DOCK_STATION, G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET(GtkDockStationClass, dock_widget), + G_STRUCT_OFFSET(GtkDockStationClass, panel_docked), NULL, NULL, g_cclosure_marshal_VOID__OBJECT, G_TYPE_NONE, 1, GTK_TYPE_WIDGET); - g_signal_new("undock-widget", + g_signal_new("panel-undocked", GTK_TYPE_DOCK_STATION, G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET(GtkDockStationClass, undock_widget), + G_STRUCT_OFFSET(GtkDockStationClass, panel_undocked), NULL, NULL, g_cclosure_marshal_VOID__OBJECT, G_TYPE_NONE, 1, GTK_TYPE_WIDGET); + /* g_signal_new("switch-widget", GTK_TYPE_DOCK_STATION, G_SIGNAL_RUN_LAST, @@ -107,6 +160,7 @@ static void gtk_dock_station_class_init(GtkDockStationClass *class) NULL, NULL, g_cclosure_marshal_VOID__OBJECT, G_TYPE_NONE, 1, GTK_TYPE_WIDGET); + */ } @@ -125,57 +179,66 @@ static void gtk_dock_station_class_init(GtkDockStationClass *class) static void gtk_dock_station_init(GtkDockStation *station) { -#if 0 + gtk_widget_init_template(GTK_WIDGET(station)); - GtkNotebook *notebook; /* Autre version du composant */ - GtkWidget *hbox; /* Division supérieure */ - GtkWidget *button; /* Bouton de contrôle */ + station->orientation = GTK_ORIENTATION_HORIZONTAL; - notebook = GTK_NOTEBOOK(station); + station->def_panel = NULL; - gtk_notebook_set_show_border(notebook, FALSE); - gtk_notebook_set_scrollable(notebook, TRUE); +} - /* Définition de la zone de contrôle */ - hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0); - gtk_widget_set_valign(hbox, GTK_ALIGN_CENTER); - gtk_widget_set_margin_end(hbox, 8); - gtk_widget_show(hbox); +/****************************************************************************** +* * +* Paramètres : object = instance d'objet GLib à traiter. * +* * +* Description : Supprime toutes les références externes. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ - button = qck_create_toggle_button_with_named_img(G_OBJECT(station), "search", - "edit-find-symbolic", GTK_ICON_SIZE_MENU, NULL, - G_CALLBACK(on_toggle_revealer), station); - gtk_button_set_relief(GTK_BUTTON(button), GTK_RELIEF_NONE); - gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, FALSE, 0); +static void gtk_dock_station_dispose(GObject *object) +{ + GtkDockStation *station; /* Version spécialisée */ - button = qck_create_button_with_named_img(G_OBJECT(station), "menu", - "go-down-symbolic", GTK_ICON_SIZE_MENU, NULL, - G_CALLBACK(on_click_for_menu), station); - gtk_button_set_relief(GTK_BUTTON(button), GTK_RELIEF_NONE); - gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, FALSE, 0); + station = GTK_DOCK_STATION(object); - button = qck_create_button_with_named_img(G_OBJECT(station), "close", - "window-close-symbolic", GTK_ICON_SIZE_MENU, NULL, - G_CALLBACK(on_click_for_close), station); - gtk_button_set_relief(GTK_BUTTON(button), GTK_RELIEF_NONE); - gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, FALSE, 0); + gtk_widget_dispose_template(GTK_WIDGET(object), GTK_TYPE_DOCK_STATION); - gtk_notebook_set_action_widget(notebook, hbox, GTK_PACK_END); + g_clear_object(&station->def_panel); - g_signal_connect(notebook, "switch-page", - G_CALLBACK(gtk_dock_station_switch_panel), station); + G_OBJECT_CLASS(gtk_dock_station_parent_class)->dispose(object); -#endif +} + + +/****************************************************************************** +* * +* Paramètres : object = instance d'objet GLib à traiter. * +* * +* Description : Procède à la libération totale de la mémoire. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void gtk_dock_station_finalize(GObject *object) +{ + G_OBJECT_CLASS(gtk_dock_station_parent_class)->finalize(object); } /****************************************************************************** * * -* Paramètres : station = instance d'objet GLib à traiter. * +* Paramètres : - * * * -* Description : Supprime toutes les références externes. * +* Description : Crée un nouveau composant pour support d'affichage concentré.* * * * Retour : - * * * @@ -183,18 +246,23 @@ static void gtk_dock_station_init(GtkDockStation *station) * * ******************************************************************************/ -static void gtk_dock_station_dispose(GtkDockStation *station) +GtkWidget *gtk_dock_station_new(void) { - G_OBJECT_CLASS(gtk_dock_station_parent_class)->dispose(G_OBJECT(station)); + GtkWidget *result; /* Instance à retourner */ + + result = g_object_new(GTK_TYPE_DOCK_STATION, NULL); + + return result; } /****************************************************************************** * * -* Paramètres : station = instance d'objet GLib à traiter. * +* Paramètres : station = station d'accueil pour panneaux à compléter. * +* panel = nouveau panneau à afficher. * * * -* Description : Procède à la libération totale de la mémoire. * +* Description : Ajoute un panneau à un groupe de tuiles. * * * * Retour : - * * * @@ -202,18 +270,33 @@ static void gtk_dock_station_dispose(GtkDockStation *station) * * ******************************************************************************/ -static void gtk_dock_station_finalize(GtkDockStation *station) +void gtk_dock_station_add_panel(GtkDockStation *station, GtkTiledPanel *panel) { - G_OBJECT_CLASS(gtk_dock_station_parent_class)->finalize(G_OBJECT(station)); + GtkStackPage *page; /* Nouvelle page insérée */ + + page = gtk_stack_add_child(station->stack, GTK_WIDGET(panel)); + + if (0) // TODO + gtk_stack_page_set_title(page, "settings"); + + else + gtk_stack_page_set_icon_name(page, "logs-symbolic"); + + gtk_stack_set_visible_child(station->stack, GTK_WIDGET(panel)); + + + g_signal_emit_by_name(station, "panel-docked", panel); + } /****************************************************************************** * * -* Paramètres : - * +* Paramètres : station = station d'accueil pour panneaux à compléter. * +* panel = nouveau panneau à afficher. * * * -* Description : Crée un nouveau composant pour support d'affichage concentré.* +* Description : Ajoute un panneau à conserver à un groupe de tuiles. * * * * Retour : - * * * @@ -221,17 +304,300 @@ static void gtk_dock_station_finalize(GtkDockStation *station) * * ******************************************************************************/ -GtkWidget *gtk_dock_station_new(void) +void gtk_dock_station_keep_panel(GtkDockStation *station, GtkTiledPanel *panel) { - GtkWidget *result; /* Instance à retourner */ + bool visible; /* Visibilité des barres */ - result = g_object_new(GTK_TYPE_DOCK_STATION, NULL); + g_clear_object(&station->def_panel); + + if (panel != NULL) + { + station->def_panel = panel; + ref_object(panel); + + if (gtk_stack_get_page(station->stack, GTK_WIDGET(panel)) == NULL) + gtk_dock_station_add_panel(station, panel); + + } + + visible = (station->def_panel == NULL); + + gtk_widget_set_visible(station->tabs, visible); + gtk_widget_set_visible(station->toolbar, visible); + gtk_widget_set_visible(station->sep1, visible); + gtk_widget_set_visible(station->sep2, visible && station->orientation == GTK_ORIENTATION_HORIZONTAL); + +} + + +/****************************************************************************** +* * +* Paramètres : station = station d'accueil pour panneaux à consulter. * +* * +* Description : Indique si la station d'accueil contient au moins un panneau.* +* * +* Retour : true si aucun panneau n'est intégré, false sinon. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool gtk_dock_station_is_empty(const GtkDockStation *station) +{ + bool result; /* Bilan à retourner */ + GtkSelectionModel *model; /* Modèle pour la pile */ + guint count; /* Nombre de panneaux présents */ + + model = gtk_stack_get_pages(station->stack); + + count = g_list_model_get_n_items(G_LIST_MODEL(model)); + + result = (count == 0); + + unref_object(model); return result; } +/****************************************************************************** +* * +* Paramètres : station = station d'accueil pour panneaux à manipuler. * +* main = panneau principal visé par l'opération. * +* activated = nature du changement de statut : ajout, retrait ?* +* * +* Description : Note un ajout ou un retrait de panneau principal. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +void gtk_dock_station_notify_new_main_panel_state(const GtkDockStation *station, GtkTiledPanel *main, bool activated) +{ + GListModel *list; /* Liste de pages à parcourir */ + guint count; /* Nombre de pages */ + guint i; /* Boucle de parcours */ + GtkStackPage *page; /* Page à consulter */ + GtkWidget *panel; /* Panneau intégré */ + + list = G_LIST_MODEL(gtk_stack_get_pages(station->stack)); + + count = g_list_model_get_n_items(list); + + for (i = 0; i < count; i++) + { + page = GTK_STACK_PAGE(g_list_model_get_object(list, i)); + if (page == NULL) continue; + + panel = gtk_stack_page_get_child(page); + + gtk_tiled_panel_notify_new_main_panel_state(GTK_TILED_PANEL(panel), main, activated); + + unref_object(page); + + } + + unref_object(list); + +} + + + +/* ---------------------------------------------------------------------------------- */ +/* IMPLEMENTATION DES FONCTIONS DE CLASSE */ +/* ---------------------------------------------------------------------------------- */ + + +/****************************************************************************** +* * +* Paramètres : object = instance d'objet GLib à mamnipuler. * +* prop_id = identifiant de la propriété visée. * +* value = valeur à prendre en compte. * +* pspec = définition de la propriété. * +* * +* Description : Met à jour une propriété d'instance GObject. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void gtk_dock_station_set_property(GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) +{ + GtkDockStation *station; /* Version spécialisée */ + GtkOrientation orientation; /* Spécification d'orientation */ + GtkLayoutManager *layout; /* Gestionnaire de disposition */ + GtkLayoutChild *child_layout; /* Disposition de composant */ + + station = GTK_DOCK_STATION(object); + + switch (prop_id) + { + case PROP_ORIENTATION: + + orientation = g_value_get_enum(value); + + if (station->orientation != orientation) + { + station->orientation = orientation; + + gtk_orientable_set_orientation(GTK_ORIENTABLE(station->tabs), orientation); + gtk_orientable_set_orientation(GTK_ORIENTABLE(station->toolbar), orientation); + + layout = gtk_widget_get_layout_manager(GTK_WIDGET(object)); + + if (orientation == GTK_ORIENTATION_VERTICAL) + { + g_object_set(G_OBJECT(station->tabs), + "halign", GTK_ALIGN_START, + "valign", GTK_ALIGN_CENTER, + NULL); + + g_object_set(G_OBJECT(station->toolbar), + "halign", GTK_ALIGN_END, + "valign", GTK_ALIGN_CENTER, + NULL); + + child_layout = gtk_layout_manager_get_layout_child(layout, station->toolbar); + + g_object_set(G_OBJECT(child_layout), + "column", 1, + "row", 0, + NULL); + + child_layout = gtk_layout_manager_get_layout_child(layout, station->sep1); + + g_object_set(G_OBJECT(child_layout), + "column", 0, + "row", 1, + "column-span", 2, + NULL); + + gtk_widget_set_visible(station->sep2, FALSE); + + child_layout = gtk_layout_manager_get_layout_child(layout, GTK_WIDGET(station->stack)); + + g_object_set(G_OBJECT(child_layout), + "column", 0, + "row", 2, + "column-span", 2, + NULL); + + } + else + { + g_object_set(G_OBJECT(station->tabs), + "halign", GTK_ALIGN_START, + "valign", GTK_ALIGN_START, + NULL); + + g_object_set(G_OBJECT(station->toolbar), + "halign", GTK_ALIGN_END, + "valign", GTK_ALIGN_START, + NULL); + + child_layout = gtk_layout_manager_get_layout_child(layout, station->sep1); + + g_object_set(G_OBJECT(child_layout), + "column", 1, + "row", 0, + "column-span", 1, + NULL); + + child_layout = gtk_layout_manager_get_layout_child(layout, GTK_WIDGET(station->stack)); + + g_object_set(G_OBJECT(child_layout), + "column", 2, + "row", 0, + "column-span", 1, + NULL); + + gtk_widget_set_visible(station->sep2, TRUE); + + child_layout = gtk_layout_manager_get_layout_child(layout, station->sep2); + + g_object_set(G_OBJECT(child_layout), + "column", 3, + "row", 0, + NULL); + + child_layout = gtk_layout_manager_get_layout_child(layout, station->toolbar); + + g_object_set(G_OBJECT(child_layout), + "column", 4, + "row", 0, + NULL); + + } + + g_object_notify_by_pspec(object, pspec); + + } + + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec); + break; + + } + +} + + +/****************************************************************************** +* * +* Paramètres : object = instance d'objet GLib à mamnipuler. * +* prop_id = identifiant de la propriété visée. * +* value = valeur à transmettre. [OUT] * +* pspec = définition de la propriété. * +* * +* Description : Fournit la valeur d'une propriété d'instance GObject. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void gtk_dock_station_get_property(GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) +{ + GtkDockStation *station; /* Version spécialisée */ + + station = GTK_DOCK_STATION(object); + + switch (prop_id) + { + case PROP_ORIENTATION: + g_value_set_enum(value, station->orientation); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec); + break; + + } + +} + + + + + + + + + + + + + + + diff --git a/src/gtkext/dockstation.h b/src/gtkext/dockstation.h index a857626..e4c849f 100644 --- a/src/gtkext/dockstation.h +++ b/src/gtkext/dockstation.h @@ -28,6 +28,7 @@ #include <gtk/gtk.h> +#include "panel.h" #include "../glibext/helpers.h" @@ -40,7 +41,17 @@ DECLARE_GTYPE(GtkDockStation, gtk_dock_station, GTK, DOCK_STATION); /* Crée un nouveau composant pour support d'affichage concentré. */ GtkWidget *gtk_dock_station_new(void); +/* Ajoute un panneau à un groupe de tuiles. */ +void gtk_dock_station_add_panel(GtkDockStation *, GtkTiledPanel *); +/* Ajoute un panneau à conserver à un groupe de tuiles. */ +void gtk_dock_station_keep_panel(GtkDockStation *, GtkTiledPanel *); + +/* Indique si la station d'accueil contient au moins un panneau. */ +bool gtk_dock_station_is_empty(const GtkDockStation *); + +/* Note un ajout ou un retrait de panneau principal. */ +void gtk_dock_station_notify_new_main_panel_state(const GtkDockStation *, GtkTiledPanel *, bool); diff --git a/src/gtkext/dockstation.ui b/src/gtkext/dockstation.ui new file mode 100644 index 0000000..4d25134 --- /dev/null +++ b/src/gtkext/dockstation.ui @@ -0,0 +1,80 @@ +<?xml version="1.0" encoding="UTF-8"?> +<interface> + <template class="GtkDockStation" parent="GtkGrid"> + <property name="orientation">horizontal</property> + + <child> + <object class="GtkStackSwitcher" id="tabs"> + <property name="orientation">horizontal</property> + <property name="halign">start</property> + <property name="valign">start</property> + <property name="margin-start">2</property> + <property name="margin-top">2</property> + <property name="margin-end">2</property> + <property name="margin-bottom">2</property> + <property name="stack">stack</property> + <layout> + <property name="column">0</property> + <property name="row">0</property> + </layout> + </object> + </child> + + <child> + <object class="GtkBox" id="toolbar"> + <property name="orientation">horizontal</property> + <property name="halign">end</property> + <property name="valign">start</property> + + <child> + <object class="GtkButton"> + <property name="icon-name">window-close-symbolic</property> + <style> + <class name="circular"/> + <class name="flat"/> + <class name="control-button"/> + </style> + </object> + </child> + + <layout> + <property name="column">4</property> + <property name="row">0</property> + </layout> + </object> + </child> + + <child> + <object class="GtkSeparator" id="sep1"> + <property name="orientation">horizontal</property> + <layout> + <property name="column">1</property> + <property name="row">0</property> + <property name="column-span">1</property> + </layout> + </object> + </child> + + <child> + <object class="GtkStack" id="stack"> + <property name="hexpand">true</property> + <layout> + <property name="column">2</property> + <property name="row">0</property> + <property name="column-span">1</property> + </layout> + </object> + </child> + + <child> + <object class="GtkSeparator" id="sep2"> + <property name="orientation">horizontal</property> + <layout> + <property name="column">3</property> + <property name="row">0</property> + </layout> + </object> + </child> + + </template> +</interface> diff --git a/src/gtkext/gresource.xml b/src/gtkext/gresource.xml index 640985f..26943a6 100644 --- a/src/gtkext/gresource.xml +++ b/src/gtkext/gresource.xml @@ -1,6 +1,8 @@ <?xml version="1.0" encoding="UTF-8"?> <gresources> <gresource prefix="/re/chrysalide/framework/gtkext"> + <file compressed="true">dockstation.ui</file> + <file compressed="true">grid.ui</file> <file compressed="true">hexview.css</file> <file compressed="true">hexview.ui</file> <file compressed="true">launcher.ui</file> diff --git a/src/gtkext/grid-int.h b/src/gtkext/grid-int.h index 5ae48ad..8a2702b 100644 --- a/src/gtkext/grid-int.h +++ b/src/gtkext/grid-int.h @@ -25,46 +25,50 @@ #define _GTKEXT_GRID_INT_H +#include "dockstation.h" #include "grid.h" -/* -------------------------- GESTION DES TUILES AFFICHEES -------------------------- */ - - -/* Informations concernant une tuile */ -typedef struct _grid_tile_t +/* Conteneur pour un affichage en tuiles nommées (instance) */ +struct _GtkTilingGrid { - struct _grid_tile_t *parent; /* Tuile parente */ + GtkGrid parent; /* A laisser en premier */ - GtkWidget *widget; /* Support d'affichage */ + GSettings *settings; /* Configuration du conteneur */ - char *path; /* Chemin d'accès */ + LayoutReachOptions layout; /* Disposition générale */ - struct _grid_tile_t *children[2]; /* Tuiles encastrées ou 2xNULL */ + bool visible[TGB_COUNT]; /* Visibilités souhaitées */ -} grid_tile_t; + GtkRevealer *top; /* Zone d'accueil #1 */ + GtkWidget *top_handle; /* Poignée de redimensionnement*/ + GtkDockStation *top_station; /* Station entière */ + GtkRevealer *left; /* Zone d'accueil #2 */ + GtkWidget *left_handle; /* Poignée de redimensionnement*/ + GtkDockStation *left_station; /* Station entière */ + GtkDockStation *main_station; /* Zone d'accueil #3 */ -/* --------------------------- INTERFACE DU COMPOSANT GTK --------------------------- */ + GtkRevealer *right; /* Zone d'accueil #4 */ + GtkWidget *right_handle; /* Poignée de redimensionnement*/ + GtkDockStation *right_station; /* Station entière */ + GtkRevealer *bottom; /* Zone d'accueil #5 */ + GtkWidget *bottom_handle; /* Poignée de redimensionnement*/ + GtkDockStation *bottom_station; /* Station entière */ -/* Conteneur pour un affichage en tuiles nommées (instance) */ -struct _GtkTilingGrid -{ - GtkWidget parent; /* A laisser en premier */ - - grid_tile_t *tiles; /* Tuiles représentées */ + GtkGesture *tpad_gesture[TGB_COUNT]; /* Gestionnaires du touchpad */ - GtkTiledPanel *def_panel; /* Panneau principal par défaut*/ + bool panning; /* Redimensionnement en cours */ }; /* Conteneur pour un affichage en tuiles nommées (classe) */ struct _GtkTilingGridClass { - GtkWidgetClass parent; /* A laisser en premier */ + GtkGridClass parent; /* A laisser en premier */ /* Signaux */ diff --git a/src/gtkext/grid.c b/src/gtkext/grid.c index 1b9c909..eb3cdf9 100644 --- a/src/gtkext/grid.c +++ b/src/gtkext/grid.c @@ -24,29 +24,43 @@ #include "grid.h" +#include <assert.h> +#include <malloc.h> +#include <string.h> + + #include "grid-int.h" +#include "helpers.h" +#include "bindings/grid-enums.h" + +/* --------------------------- INTERFACE DU COMPOSANT GTK --------------------------- */ -/* -------------------------- GESTION DES TUILES AFFICHEES -------------------------- */ +/* Liste des propriétés */ +typedef enum _TilingGridProperty { -#define IS_LEAF_TILE(t) \ - ({ \ - bool __result; \ - __result = GTK_IS_DOCK_STATION((t)->widget); \ - assert(__result || GTK_IS_PANED((t)->widget)); \ - __result; \ - }) + PROP_0, /* Réservé */ + PROP_LAYOUT, /* Disposition générale */ -/* Supprime une tuile de la mémoire. */ -static void delete_tile(grid_tile_t *); + PROP_EMPTY_TOP, /* Vide de la zone supérieure */ + PROP_EMPTY_LEFT, /* Vide de la zone de gauche */ + PROP_EMPTY_RIGHT, /* Vide de la zone de droite */ + PROP_EMPTY_BOTTOM, /* Vide de la zone inférieure */ + PROP_VISIBLE_TOP, /* Visibilité de zone sup. */ + PROP_VISIBLE_LEFT, /* Visibilité de zone de gauche*/ + PROP_VISIBLE_RIGHT, /* Visibilité de zone de droite*/ + PROP_VISIBLE_BOTTOM, /* Visibilité de zone inf. */ + N_PROPERTIES -/* --------------------------- INTERFACE DU COMPOSANT GTK --------------------------- */ +} TilingGridProperty; + +static GParamSpec *_tiling_grid_properties[N_PROPERTIES] = { NULL, }; /* Initialise la classe des conteneurs d'affichage en tuiles. */ @@ -56,48 +70,50 @@ static void gtk_tiling_grid_class_init(GtkTilingGridClass *); static void gtk_tiling_grid_init(GtkTilingGrid *); /* Supprime toutes les références externes. */ -static void gtk_tiling_grid_dispose(GtkTilingGrid *); +static void gtk_tiling_grid_dispose(GObject *); /* Procède à la libération totale de la mémoire. */ -static void gtk_tiling_grid_finalize(GtkTilingGrid *); +static void gtk_tiling_grid_finalize(GObject *); +/* Réagit à une intégration ou à un retrait de panneau. */ +static void gtk_tiling_grid_on_panel_un_docked(GtkDockStation *, GtkTiledPanel *, GtkTilingGrid *); +/* -------------------- REDIMENSIONNEMENT DE ZONES POUR PANNEAUX -------------------- */ -/* ---------------------------------------------------------------------------------- */ -/* GESTION DES TUILES AFFICHEES */ -/* ---------------------------------------------------------------------------------- */ +/* Initie un redimensionnement par drag-and-drop. */ +static void gtk_tiling_grid_on_gesture_drag_begin(GtkGestureDrag *, double, double, GtkTilingGrid *); -/****************************************************************************** -* * -* Paramètres : tile = tuile à supprimer. * -* * -* Description : Supprime une tuile de la mémoire. * -* * -* Retour : - * -* * -* Remarques : - * -* * -******************************************************************************/ +/* Applique l'effet d'un redimensionnement drag-and-drop donné. */ +static void gtk_tiling_grid_on_gesture_drag_update(GtkTilingGrid *, TilingGridBorder, double, double); -static void delete_tile(grid_tile_t *tile) -{ - if (!IS_LEAF_TILE(tile)) - { - delete_tile(tile->children[0]); - delete_tile(tile->children[1]); - } +/* Actualise l'effet d'un redimensionnement drag-and-drop. */ +static void gtk_tiling_grid_on_top_gesture_drag_update(GtkGestureDrag *, double, double, GtkTilingGrid *); - else - free(tile->path); +/* Actualise l'effet d'un redimensionnement drag-and-drop. */ +static void gtk_tiling_grid_on_left_gesture_drag_update(GtkGestureDrag *, double, double, GtkTilingGrid *); - unref_object(tile->widget); +/* Actualise l'effet d'un redimensionnement drag-and-drop. */ +static void gtk_tiling_grid_on_right_gesture_drag_update(GtkGestureDrag *, double, double, GtkTilingGrid *); - free(tile); +/* Actualise l'effet d'un redimensionnement drag-and-drop. */ +static void gtk_tiling_grid_on_bottom_gesture_drag_update(GtkGestureDrag *, double, double, GtkTilingGrid *); -} +/* Clôture un drag-and-drop de redimensionnement. */ +static void gtk_tiling_grid_on_gesture_drag_end(GtkGestureDrag *, double, double, GtkTilingGrid *); + + + +/* --------------------- IMPLEMENTATION DES FONCTIONS DE CLASSE --------------------- */ + + +/* Met à jour une propriété d'instance GObject. */ +static void gtk_tiling_grid_set_property(GObject *, guint, const GValue *, GParamSpec *); + +/* Fournit la valeur d'une propriété d'instance GObject. */ +static void gtk_tiling_grid_get_property(GObject *, guint, GValue *, GParamSpec *); @@ -107,12 +123,12 @@ static void delete_tile(grid_tile_t *tile) /* Détermine le type du conteneur d'affichage en tuiles nommées. */ -G_DEFINE_TYPE(GtkTilingGrid, gtk_tiling_grid, GTK_TYPE_WIDGET) +G_DEFINE_TYPE(GtkTilingGrid, gtk_tiling_grid, GTK_TYPE_GRID) /****************************************************************************** * * -* Paramètres : klass = classe GTK à initialiser. * +* Paramètres : class = classe GTK à initialiser. * * * * Description : Initialise la classe des conteneurs d'affichage en tuiles. * * * @@ -122,14 +138,101 @@ G_DEFINE_TYPE(GtkTilingGrid, gtk_tiling_grid, GTK_TYPE_WIDGET) * * ******************************************************************************/ -static void gtk_tiling_grid_class_init(GtkTilingGridClass *klass) +static void gtk_tiling_grid_class_init(GtkTilingGridClass *class) { GObjectClass *object; /* Autre version de la classe */ + GtkWidgetClass *widget; /* Classe de haut niveau */ + + object = G_OBJECT_CLASS(class); + + object->dispose = gtk_tiling_grid_dispose; + object->finalize = gtk_tiling_grid_finalize; + object->set_property = gtk_tiling_grid_set_property; + object->get_property = gtk_tiling_grid_get_property; + + _tiling_grid_properties[PROP_LAYOUT] = + g_param_spec_flags("layout", NULL, NULL, + LAYOUT_REACH_OPTIONS_TYPE, + LRO_NONE, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_EXPLICIT_NOTIFY); + + _tiling_grid_properties[PROP_EMPTY_TOP] = + g_param_spec_boolean("empty-top", NULL, NULL, + TRUE, + G_PARAM_READABLE | G_PARAM_STATIC_STRINGS | G_PARAM_EXPLICIT_NOTIFY); + + _tiling_grid_properties[PROP_EMPTY_LEFT] = + g_param_spec_boolean("empty-left", NULL, NULL, + TRUE, + G_PARAM_READABLE | G_PARAM_STATIC_STRINGS | G_PARAM_EXPLICIT_NOTIFY); + + _tiling_grid_properties[PROP_EMPTY_RIGHT] = + g_param_spec_boolean("empty-right", NULL, NULL, + TRUE, + G_PARAM_READABLE | G_PARAM_STATIC_STRINGS | G_PARAM_EXPLICIT_NOTIFY); + + _tiling_grid_properties[PROP_EMPTY_BOTTOM] = + g_param_spec_boolean("empty-bottom", NULL, NULL, + TRUE, + G_PARAM_READABLE | G_PARAM_STATIC_STRINGS | G_PARAM_EXPLICIT_NOTIFY); + + /** + * La valeur initiale des champs suivants est à maintenir synchronisée avec + * les initialisations de gtk_tiling_grid_init(). + */ + + _tiling_grid_properties[PROP_VISIBLE_TOP] = + g_param_spec_boolean("visible-top", NULL, NULL, + TRUE, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_EXPLICIT_NOTIFY); + + _tiling_grid_properties[PROP_VISIBLE_LEFT] = + g_param_spec_boolean("visible-left", NULL, NULL, + TRUE, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_EXPLICIT_NOTIFY); + + _tiling_grid_properties[PROP_VISIBLE_RIGHT] = + g_param_spec_boolean("visible-right", NULL, NULL, + TRUE, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_EXPLICIT_NOTIFY); + + _tiling_grid_properties[PROP_VISIBLE_BOTTOM] = + g_param_spec_boolean("visible-bottom", NULL, NULL, + TRUE, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_EXPLICIT_NOTIFY); + + g_object_class_install_properties(object, N_PROPERTIES, _tiling_grid_properties); + + widget = GTK_WIDGET_CLASS(class); + + g_type_ensure(GTK_TYPE_DOCK_STATION); - object = G_OBJECT_CLASS(klass); + gtk_widget_class_set_template_from_resource(widget, "/re/chrysalide/framework/gtkext/grid.ui"); - object->dispose = (GObjectFinalizeFunc/* ! */)gtk_tiling_grid_dispose; - object->finalize = (GObjectFinalizeFunc)gtk_tiling_grid_finalize; + gtk_widget_class_bind_template_callback_full(widget, BUILDER_CB(gtk_tiling_grid_on_panel_un_docked)); + gtk_widget_class_bind_template_callback_full(widget, BUILDER_CB(gtk_tiling_grid_on_gesture_drag_begin)); + gtk_widget_class_bind_template_callback_full(widget, BUILDER_CB(gtk_tiling_grid_on_top_gesture_drag_update)); + gtk_widget_class_bind_template_callback_full(widget, BUILDER_CB(gtk_tiling_grid_on_left_gesture_drag_update)); + gtk_widget_class_bind_template_callback_full(widget, BUILDER_CB(gtk_tiling_grid_on_right_gesture_drag_update)); + gtk_widget_class_bind_template_callback_full(widget, BUILDER_CB(gtk_tiling_grid_on_bottom_gesture_drag_update)); + gtk_widget_class_bind_template_callback_full(widget, BUILDER_CB(gtk_tiling_grid_on_gesture_drag_end)); + + gtk_widget_class_bind_template_child(widget, GtkTilingGrid, top); + gtk_widget_class_bind_template_child(widget, GtkTilingGrid, top_handle); + gtk_widget_class_bind_template_child(widget, GtkTilingGrid, top_station); + gtk_widget_class_bind_template_child(widget, GtkTilingGrid, left); + gtk_widget_class_bind_template_child(widget, GtkTilingGrid, left_handle); + gtk_widget_class_bind_template_child(widget, GtkTilingGrid, left_station); + gtk_widget_class_bind_template_child(widget, GtkTilingGrid, main_station); + gtk_widget_class_bind_template_child(widget, GtkTilingGrid, right); + gtk_widget_class_bind_template_child(widget, GtkTilingGrid, right_handle); + gtk_widget_class_bind_template_child(widget, GtkTilingGrid, right_station); + gtk_widget_class_bind_template_child(widget, GtkTilingGrid, bottom); + gtk_widget_class_bind_template_child(widget, GtkTilingGrid, bottom_handle); + gtk_widget_class_bind_template_child(widget, GtkTilingGrid, bottom_station); + + + ///////////// g_signal_new("station-created", GTK_TYPE_TILING_GRID, @@ -144,7 +247,7 @@ static void gtk_tiling_grid_class_init(GtkTilingGridClass *klass) /****************************************************************************** * * -* Paramètres : tgrid = instance GTK à initialiser. * +* Paramètres : grid = instance GTK à initialiser. * * * * Description : Initialise une instance de conteneur d'affichage en tuiles. * * * @@ -154,18 +257,70 @@ static void gtk_tiling_grid_class_init(GtkTilingGridClass *klass) * * ******************************************************************************/ -static void gtk_tiling_grid_init(GtkTilingGrid *tgrid) +static void gtk_tiling_grid_init(GtkTilingGrid *grid) { - tgrid->tiles = NULL; + gtk_widget_init_template(GTK_WIDGET(grid)); + + grid->settings = g_settings_new_with_path("re.chrysalide.framework.tiledgrid", + "/re/chrysalide/framework/gui/tiles/"); + + g_settings_bind(grid->settings, "layout", + grid, "layout", + G_SETTINGS_BIND_DEFAULT); + + /** + * L'initialisation des champs suivants est à maintenir synchronisée avec + * les valeurs initiales de gtk_tiling_grid_class_init(). + */ + + grid->visible[TGB_TOP] = true; + grid->visible[TGB_LEFT] = true; + grid->visible[TGB_RIGHT] = true; + grid->visible[TGB_BOTTOM] = true; + + g_settings_bind(grid->settings, "top-request", + grid->top_station, "height-request", + G_SETTINGS_BIND_DEFAULT); + + g_settings_bind(grid->settings, "top-visibility", + grid, "visible-top", + G_SETTINGS_BIND_DEFAULT); + + g_settings_bind(grid->settings, "left-request", + grid->left_station, "width-request", + G_SETTINGS_BIND_DEFAULT); - tgrid->def_panel = NULL; + g_settings_bind(grid->settings, "left-visibility", + grid, "visible-left", + G_SETTINGS_BIND_DEFAULT); + + g_settings_bind(grid->settings, "right-request", + grid->right_station, "width-request", + G_SETTINGS_BIND_DEFAULT); + + g_settings_bind(grid->settings, "right-visibility", + grid, "visible-right", + G_SETTINGS_BIND_DEFAULT); + + g_settings_bind(grid->settings, "bottom-request", + grid->bottom_station, "height-request", + G_SETTINGS_BIND_DEFAULT); + + g_settings_bind(grid->settings, "bottom-visibility", + grid, "visible-bottom", + G_SETTINGS_BIND_DEFAULT); + + gtk_widget_set_cursor_from_name(grid->top_handle, "row-resize"); + gtk_widget_set_cursor_from_name(grid->left_handle, "col-resize"); + gtk_widget_set_cursor_from_name(grid->right_handle, "col-resize"); + gtk_widget_set_cursor_from_name(grid->bottom_handle, "row-resize"); } /****************************************************************************** * * -* Paramètres : grid = instance d'objet GLib à traiter. * +* Paramètres : object = instance d'objet GLib à traiter. * * * * Description : Supprime toutes les références externes. * * * @@ -175,24 +330,24 @@ static void gtk_tiling_grid_init(GtkTilingGrid *tgrid) * * ******************************************************************************/ -static void gtk_tiling_grid_dispose(GtkTilingGrid *grid) +static void gtk_tiling_grid_dispose(GObject *object) { - if (grid->tiles != NULL) - { - delete_tile(grid->tiles); - grid->tiles = NULL; - } + GtkTilingGrid *grid; /* Version spécialisée */ + + gtk_widget_dispose_template(GTK_WIDGET(object), GTK_TYPE_DOCK_STATION); + + grid = GTK_TILING_GRID(object); - g_clear_object(&grid->def_panel); + g_clear_object(&grid->settings); - G_OBJECT_CLASS(gtk_tiling_grid_parent_class)->dispose(G_OBJECT(grid)); + G_OBJECT_CLASS(gtk_tiling_grid_parent_class)->dispose(object); } /****************************************************************************** * * -* Paramètres : grid = instance d'objet GLib à traiter. * +* Paramètres : object = instance d'objet GLib à traiter. * * * * Description : Procède à la libération totale de la mémoire. * * * @@ -202,9 +357,9 @@ static void gtk_tiling_grid_dispose(GtkTilingGrid *grid) * * ******************************************************************************/ -static void gtk_tiling_grid_finalize(GtkTilingGrid *grid) +static void gtk_tiling_grid_finalize(GObject *object) { - G_OBJECT_CLASS(gtk_tiling_grid_parent_class)->finalize(G_OBJECT(grid)); + G_OBJECT_CLASS(gtk_tiling_grid_parent_class)->finalize(object); } @@ -232,142 +387,80 @@ GtkWidget *gtk_tiling_grid_new(void) } - - - - -#if 0 - - -#include <assert.h> -#include <ctype.h> -#include <malloc.h> -#include <string.h> - - -#include "../core/logs.h" - - - -/* Valide un chemin d'accès à une tuile. */ -static bool is_valid_tile_path(const char *); - -/* Crée une tuile finale d'affichage de panneaux. */ -static grid_tile_t *create_leaf_tile(const char *, GtkTiledGrid *); - -/* Crée une tuile intermédiaire d'affichage de panneaux. */ -static grid_tile_t *create_inter_tile(grid_tile_t *, bool, grid_tile_t *, grid_tile_t *); - -/* Supprime une tuile de la mémoire. */ -//static void delete_tile(grid_tile_t *); - -/* Calcule la taille comme entre un chemin et celui d'une tuile. */ -static size_t compute_tile_score(const grid_tile_t *, const char *); - -/* Indique la tuile adaptée pour un chemin donné. */ -static grid_tile_t *find_suitable_tile(grid_tile_t **, const char *, GtkTiledGrid *); - -/* Découpe une tuile pour y insérer une zone. */ -static grid_tile_t *split_tile(grid_tile_t **, const char *, char, GtkTiledGrid *); - -/* Tente de mettre la main sur une station d'accueil. */ -static grid_tile_t *find_tile_for_widget(grid_tile_t *, GtkWidget *); - -/* Retire une moitié de tuile vide au plein profit de l'autre. */ -static void collapse_tile(grid_tile_t *, grid_tile_t *); - - - -/* --------------------------- INTERFACE DU COMPOSANT GTK --------------------------- */ - - - - - -/* ---------------------------------------------------------------------------------- */ -/* GESTION DES TUILES AFFICHEES */ -/* ---------------------------------------------------------------------------------- */ - - /****************************************************************************** * * -* Paramètres : path = chemin destiné à sélectionner une tuile. * +* Paramètres : grid = zone d'affichage en tuiles à manipuler. * +* border = sélection de la zone à considérer. * +* visible = nouveau statut de visibilité à appliquer. * * * -* Description : Valide un chemin d'accès à une tuile. * +* Description : Affiche ou masque une zone du conteneur en tuiles. * * * -* Retour : true si le chemin est utilisable, false sinon. * +* Retour : - * * * * Remarques : - * * * ******************************************************************************/ -static bool is_valid_tile_path(const char *path) +void gtk_tiling_grid_set_visible(GtkTilingGrid *grid, TilingGridBorder border, bool visible) { - bool result; /* Bilan à retourner */ - size_t len; /* Taille du chemin */ - size_t i; /* Boucle de parcours */ - char c; /* Caractère de chemin analysé */ - - /** - * M[NESWnesw]* - */ - - len = strlen(path); + GtkRevealer *revealer; /* Cible visée par l'opération */ + GtkDockStation *station; /* Apport d'une contrainte */ - result = (len >= 1); + if (grid->visible[border] != visible) + { + grid->visible[border] = visible; - if (result) - result = (path[0] == 'M'); + switch (border) + { + case TGB_TOP: + revealer = grid->top; + station = grid->top_station; + break; + + case TGB_LEFT: + revealer = grid->left; + station = grid->left_station; + break; + + case TGB_RIGHT: + revealer = grid->right; + station = grid->right_station; + break; + + case TGB_BOTTOM: + revealer = grid->bottom; + station = grid->bottom_station; + break; - for (i = 1; i < len && result; i++) - { - c = path[i]; + } - if (c == '\0') - break; + gtk_revealer_set_reveal_child(revealer, visible && !gtk_dock_station_is_empty(station)); - result = (c == 'N' || c == 'n' - || c == 'E' || c == 'e' - || c == 'S' || c == 's' - || c == 'W' || c == 'w'); + g_object_notify_by_pspec(G_OBJECT(grid), _tiling_grid_properties[PROP_VISIBLE_TOP + border]); } - return result; - } /****************************************************************************** * * -* Paramètres : path = chemin d'accès à la future tuile. * -* tgrid = conteneur d'affichage en tuiles à manipuler. * +* Paramètres : grid = zone d'affichage en tuiles à manipuler. * +* border = sélection de la zone à considérer. * * * -* Description : Crée une tuile finale d'affichage de panneaux. * +* Description : Fournit la visibilité d'une zone du conteneur en tuiles. * * * -* Retour : Structure mise en place. * +* Retour : Visibilité de la zone considérée. * * * * Remarques : - * * * ******************************************************************************/ -static grid_tile_t *create_leaf_tile(const char *path, GtkTiledGrid *tgrid) +bool gtk_tiling_grid_get_visible(GtkTilingGrid *grid, TilingGridBorder border) { - grid_tile_t *result; /* Structure à retourner */ - - result = (grid_tile_t *)malloc(sizeof(grid_tile_t)); - - result->parent = NULL; - - result->widget = gtk_dock_station_new(); - gtk_widget_show(result->widget); + bool result; /* Statut à retourner */ - result->path = strdup(path); - - result->children[0] = NULL; - result->children[1] = NULL; - - g_signal_emit_by_name(tgrid, "station-created", result->widget); + result = grid->visible[border]; return result; @@ -376,333 +469,307 @@ static grid_tile_t *create_leaf_tile(const char *path, GtkTiledGrid *tgrid) /****************************************************************************** * * -* Paramètres : parent = tuile parente ou NULL si aucune. * -* horiz = indique le type d'orientation désiré. * -* first = première tuile à intégrer. * -* second = seconde tuile à intégrer. * +* Paramètres : grid = zone d'affichage en tuiles à manipuler. * +* panel = nouveau panneau à afficher. * +* keep = indique si le panneau est à conserver présent. * * * -* Description : Crée une tuile intermédiaire d'affichage de panneaux. * +* Description : Ajoute un panneau à un conteneur en tuiles. * * * -* Retour : Structure mise en place. * +* Retour : - * * * * Remarques : - * * * ******************************************************************************/ -static grid_tile_t *create_inter_tile(grid_tile_t *parent, bool horiz, grid_tile_t *first, grid_tile_t *second) +void gtk_tiling_grid_add_panel(GtkTilingGrid *grid, GtkTiledPanel *panel, bool keep) { - grid_tile_t *result; /* Structure à retourner */ - GtkWidget *container; /* Conteneur à vider */ - - result = (grid_tile_t *)malloc(sizeof(grid_tile_t)); - - result->parent = parent; - - if (horiz) - result->widget = gtk_paned_new(GTK_ORIENTATION_HORIZONTAL); - else - result->widget = gtk_paned_new(GTK_ORIENTATION_VERTICAL); + char *path; /* Chemin visé par le panneau */ + bool static_path; /* Nature du chemin à traiter */ - gtk_widget_show(result->widget); + path = gtk_tiled_panel_get_path(panel); - result->path = NULL; + static_path = (path == NULL); - result->children[0] = first; - result->children[1] = second; + if (static_path) + path = ""; - /* Changement de propriétaire */ + switch (path[0]) + { + case 'N': + if (keep) + gtk_dock_station_keep_panel(grid->top_station, panel); + else + gtk_dock_station_add_panel(grid->top_station, panel); + break; - container = gtk_widget_get_parent(first->widget); + case 'W': + if (keep) + gtk_dock_station_keep_panel(grid->left_station, panel); + else + gtk_dock_station_add_panel(grid->left_station, panel); + break; - if (container != NULL) - gtk_container_remove(GTK_CONTAINER(container), first->widget); + case '\0': + case 'M': + if (keep) + gtk_dock_station_keep_panel(grid->main_station, panel); + else + gtk_dock_station_add_panel(grid->main_station, panel); + break; - g_object_ref(G_OBJECT(first->widget)); - gtk_paned_pack1(GTK_PANED(result->widget), first->widget, TRUE, FALSE); + case 'E': + if (keep) + gtk_dock_station_keep_panel(grid->right_station, panel); + else + gtk_dock_station_add_panel(grid->right_station, panel); + break; - container = gtk_widget_get_parent(second->widget); + case 'S': + if (keep) + gtk_dock_station_keep_panel(grid->bottom_station, panel); + else + gtk_dock_station_add_panel(grid->bottom_station, panel); + break; - if (container != NULL) - gtk_container_remove(GTK_CONTAINER(container), second->widget); + default: + break; - g_object_ref(G_OBJECT(second->widget)); - gtk_paned_pack2(GTK_PANED(result->widget), second->widget, TRUE, FALSE); + } - return result; + if (!static_path) + free(path); } - /****************************************************************************** * * -* Paramètres : tile = tuile à analyser. * -* path = chemin final complet recherché. * +* Paramètres : grid = zone d'affichage en tuiles à manipuler. * +* main = panneau principal visé par l'opération. * +* activated = nature du changement de statut : ajout, retrait ?* * * -* Description : Calcule la taille comme entre un chemin et celui d'une tuile.* +* Description : Note un ajout ou un retrait de panneau principal. * * * -* Retour : Quantité de caractères communs. * +* Retour : - * * * * Remarques : - * * * ******************************************************************************/ -static size_t compute_tile_score(const grid_tile_t *tile, const char *path) +void gtk_tiling_grid_notify_new_main_panel_state(const GtkTilingGrid *grid, GtkTiledPanel *main, bool activated) { - size_t result; /* Nombre de points à renvoyer */ - size_t max; /* Taille du chemin de la tuile*/ - size_t i; /* Boucle de parcours */ - size_t score_0; /* Score du sous-élément #1 */ - size_t score_1; /* Score du sous-élément #2 */ - - if (IS_LEAF_TILE(tile)) - { - max = strlen(tile->path); - - if (strlen(path) < max) - result = 0; - - else - { - result = 0; - - for (i = 0; i < max; i++) - { - if (tolower((unsigned char)tile->path[i]) == tolower((unsigned char)path[i])) - result++; - else - break; - } + gtk_dock_station_notify_new_main_panel_state(grid->top_station, main, activated); - } - - } - else - { - score_0 = compute_tile_score(tile->children[0], path); - score_1 = compute_tile_score(tile->children[1], path); + gtk_dock_station_notify_new_main_panel_state(grid->left_station, main, activated); - result = score_0 > score_1 ? score_0 : score_1; + gtk_dock_station_notify_new_main_panel_state(grid->main_station, main, activated); - } + gtk_dock_station_notify_new_main_panel_state(grid->right_station, main, activated); - return result; + gtk_dock_station_notify_new_main_panel_state(grid->bottom_station, main, activated); } /****************************************************************************** * * -* Paramètres : tile = tuile ou NULL si aucune. [OUT] * -* path = chemin d'accès à la tuile visée. * -* tgrid = conteneur d'affichage en tuiles à manipuler. * +* Paramètres : station = plateforme GTK ayant connu un changement. * +* widget = nouvel élément à intégrer. * +* grid = gestionnaire de placement en tuile concerné. * * * -* Description : Indique la tuile adaptée pour un chemin donné. * +* Description : Réagit à une intégration ou à un retrait de panneau. * * * -* Retour : Structure d'acceuil à disposition. * +* Retour : - * * * * Remarques : - * * * ******************************************************************************/ -static grid_tile_t *find_suitable_tile(grid_tile_t **tile, const char *path, GtkTiledGrid *tgrid) +static void gtk_tiling_grid_on_panel_un_docked(GtkDockStation *station, GtkTiledPanel *panel, GtkTilingGrid *grid) { - grid_tile_t *result; /* Structure à renvoyer */ - size_t best_len; /* Taille du chemin associé */ - size_t score_0; /* Score du sous-élément #1 */ - size_t score_1; /* Score du sous-élément #2 */ - char *sub_path; /* Nouvelle tentative d'accès */ - grid_tile_t **best; /* Direction à prendre */ - unsigned char next; /* Prochaine étape */ - - /* Cas d'école : appel initial */ - if (*tile == NULL) - { - assert(path[0] == 'M' && path[1] == '\0'); - - result = create_leaf_tile("M", tgrid); - *tile = result; + TilingGridBorder border; /* Aire concernée par l'action */ + GtkRevealer *revealer; /* Cible visée par l'opération */ + bool new_state; /* Nouveau statut d'affichage */ + if (station == grid->top_station) + { + border = TGB_TOP; + revealer = grid->top; } - else + else if (station == grid->left_station) { - if (IS_LEAF_TILE(*tile)) - { - best_len = compute_tile_score(*tile, path); - - assert(best_len > 0); + border = TGB_LEFT; + revealer = grid->left; + } - if (path[best_len] == '\0') - result = *tile; + else if (station == grid->right_station) + { + border = TGB_RIGHT; + revealer = grid->right; + } - else - result = split_tile(tile, path, path[best_len], tgrid); + else if (station == grid->bottom_station) + { + border = TGB_BOTTOM; + revealer = grid->bottom; + } - } + else + assert(false); - else - { - score_0 = compute_tile_score((*tile)->children[0], path); - score_1 = compute_tile_score((*tile)->children[1], path); + new_state = grid->visible[border] && !gtk_dock_station_is_empty(station); - assert(score_0 > 0 || score_0 > 0); + if (gtk_revealer_get_reveal_child(revealer) != new_state) + gtk_revealer_set_reveal_child(revealer, new_state); - if (score_0 == score_1) - { - sub_path = strndup(path, score_0); + /** + * On ne sait pas si l'état a réellement changé, mais on avertit + * d'une mise à jour quand même, au cas où. + */ - score_0 = compute_tile_score((*tile)->children[0], sub_path); - score_1 = compute_tile_score((*tile)->children[1], sub_path); + g_object_notify_by_pspec(G_OBJECT(grid), _tiling_grid_properties[PROP_EMPTY_TOP + border]); - free(sub_path); +} - } - if (score_0 == score_1) - result = split_tile(tile, path, path[score_0], tgrid); - else - { - if (score_0 > score_1) - { - best = &(*tile)->children[0]; - best_len = score_0; - } - else - { - best = &(*tile)->children[1]; - best_len = score_1; - } - - /** - * Si on vient de tomber une feuille, trois cas de figure : - * - soit c'est elle qui est visée. - * - soit on veut la diviser. - * - soit on veut la diviser en englobant ses voisines. - */ - - if (IS_LEAF_TILE(*best)) - { - assert(best_len <= strlen(path)); - - next = path[best_len]; - - /* Premier cas */ - if (next == '\0') - result = *best; - - else - { - /* Second cas */ - if (islower(next)) - result = find_suitable_tile(best, path, tgrid); - - /* Troisième cas */ - else - result = split_tile(tile, path, next, tgrid); - - } - - } - - else - result = find_suitable_tile(best, path, tgrid); - - } +/* ---------------------------------------------------------------------------------- */ +/* REDIMENSIONNEMENT DE ZONES POUR PANNEAUX */ +/* ---------------------------------------------------------------------------------- */ - } - } +/****************************************************************************** +* * +* Paramètres : gesture = encadrement de déplacement à l'origine de l'appel. * +* start_x = pointe de départ sur l'axe des abscisses. * +* start_y = pointe de départ sur l'axe des ordonnées. * +* grid = gestionnaire de placement en tuile concerné. * +* * +* Description : Initie un redimensionnement par drag-and-drop. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ - assert(IS_LEAF_TILE(result)); +static void gtk_tiling_grid_on_gesture_drag_begin(GtkGestureDrag *gesture, double start_x, double start_y, GtkTilingGrid *grid) +{ + gtk_gesture_set_state(GTK_GESTURE(gesture), GTK_EVENT_SEQUENCE_CLAIMED); - return result; + grid->panning = true; } /****************************************************************************** * * -* Paramètres : tile = tuile à découper en deux. [OUT] * -* path = chemin d'accès à la future tuile. * -* endpoint = désignation de la zone représentée. * -* tgrid = conteneur d'affichage en tuiles à manipuler. * +* Paramètres : grid = zone d'affichage en tuiles à manipuler. * +* border = sélection de la zone à considérer. * +* offset_x = déplacement sur l'axe des abscisses. * +* offset_y = déplacement sur l'axe des ordonnées. * * * -* Description : Découpe une tuile pour y insérer une zone. * +* Description : Applique l'effet d'un redimensionnement drag-and-drop donné. * * * -* Retour : Structure fille mise en place. * +* Retour : - * * * * Remarques : - * * * ******************************************************************************/ -static grid_tile_t *split_tile(grid_tile_t **tile, const char *path, char endpoint, GtkTiledGrid *tgrid) +static void gtk_tiling_grid_on_gesture_drag_update(GtkTilingGrid *grid, TilingGridBorder border, double offset_x, double offset_y) { - grid_tile_t *result; /* Création à retourner */ - GtkWidget *container; /* Conteneur à vider */ - grid_tile_t *new; /* Nouvelle tuile intermédiaire*/ + GtkDockStation *station; /* Station entière */ + int request; /* Taille requise */ + + /* Sélection de la poignée adaptée */ + + switch (border) + { + case TGB_TOP: + station = grid->top_station; + break; + + case TGB_LEFT: + station = grid->left_station; + break; - container = gtk_widget_get_parent((*tile)->widget); + case TGB_RIGHT: + station = grid->right_station; + break; - /* Création */ + case TGB_BOTTOM: + station = grid->bottom_station; + break; - result = create_leaf_tile(path, tgrid); + } - /* Encapsulation */ + /* Détermination d'une nouvelle position et application */ - switch (endpoint) + switch (border) { - case 'N': - case 'n': - new = create_inter_tile((*tile)->parent, false, result, *tile); + case TGB_TOP: + case TGB_BOTTOM: + g_object_get(G_OBJECT(station), "height-request", &request, NULL); break; - case 'E': - case 'e': - new = create_inter_tile((*tile)->parent, true, *tile, result); + case TGB_LEFT: + case TGB_RIGHT: + g_object_get(G_OBJECT(station), "width-request", &request, NULL); break; - case 'S': - case 's': - new = create_inter_tile((*tile)->parent, false, *tile, result); + } + + switch (border) + { + case TGB_TOP: + request += offset_y; break; - case 'W': - case 'w': - new = create_inter_tile((*tile)->parent, true, result, *tile); + case TGB_LEFT: + request += offset_x; break; - default: - assert(false); - new = NULL; + case TGB_RIGHT: + request += -offset_x; + break; + + case TGB_BOTTOM: + request += -offset_y; break; } - /* Connexions */ + if (request > 0) + { + switch (border) + { + case TGB_TOP: + case TGB_BOTTOM: + g_object_set(G_OBJECT(station), "height-request", request, NULL); + break; - *tile = new; + case TGB_LEFT: + case TGB_RIGHT: + g_object_set(G_OBJECT(station), "width-request", request, NULL); + break; - result->parent = new; + } - if (container != NULL) - { - g_object_ref(G_OBJECT(new->widget)); - gtk_container_add(GTK_CONTAINER(container), new->widget); } - return result; - } /****************************************************************************** * * -* Paramètres : tile = tuile parente, prochaine victime de promotion. * -* side = côté de tuile amené à disparaître. * +* Paramètres : gesture = encadrement de déplacement à l'origine de l'appel. * +* offset_x = déplacement sur l'axe des abscisses. * +* offset_y = déplacement sur l'axe des ordonnées. * +* grid = gestionnaire de placement en tuile concerné. * * * -* Description : Retire une moitié de tuile vide au plein profit de l'autre. * +* Description : Actualise l'effet d'un redimensionnement drag-and-drop. * * * * Retour : - * * * @@ -710,114 +777,65 @@ static grid_tile_t *split_tile(grid_tile_t **tile, const char *path, char endpoi * * ******************************************************************************/ -static void collapse_tile(grid_tile_t *tile, grid_tile_t *side) +static void gtk_tiling_grid_on_top_gesture_drag_update(GtkGestureDrag *gesture, double offset_x, double offset_y, GtkTilingGrid *grid) { - grid_tile_t *promoted; /* Tuile à faire remonter */ - GtkWidget *container; /* Conteneur à vider */ - - assert(!IS_LEAF_TILE(tile)); - - /* Sélection du remplaçant */ - - if (side == tile->children[0]) - promoted = tile->children[1]; - else - promoted = tile->children[0]; - - /* Etablissement d'une place nette */ - - gtk_container_remove(GTK_CONTAINER(tile->widget), promoted->widget); - - container = gtk_widget_get_parent(tile->widget); - gtk_container_remove(GTK_CONTAINER(container), tile->widget); - - delete_tile(side); - - /* Promotion effective */ - - tile->widget = promoted->widget; - - tile->path = promoted->path; - - tile->children[0] = promoted->children[0]; - tile->children[1] = promoted->children[1]; - - g_object_ref(G_OBJECT(promoted->widget)); - gtk_container_add(GTK_CONTAINER(container), tile->widget); - - free(promoted); + gtk_tiling_grid_on_gesture_drag_update(grid, TGB_TOP, offset_x, offset_y); } /****************************************************************************** * * -* Paramètres : tile = point de départ des recherches locales. * -* widget = composant graphique à retrouver. * +* Paramètres : gesture = encadrement de déplacement à l'origine de l'appel. * +* offset_x = déplacement sur l'axe des abscisses. * +* offset_y = déplacement sur l'axe des ordonnées. * +* grid = gestionnaire de placement en tuile concerné. * * * -* Description : Tente de mettre la main sur une station d'accueil. * +* Description : Actualise l'effet d'un redimensionnement drag-and-drop. * * * -* Retour : Eventuelle tuile trouvée ou NULL. * +* Retour : - * * * * Remarques : - * * * ******************************************************************************/ -static grid_tile_t *find_tile_for_widget(grid_tile_t *tile, GtkWidget *widget) +static void gtk_tiling_grid_on_left_gesture_drag_update(GtkGestureDrag *gesture, double offset_x, double offset_y, GtkTilingGrid *grid) { - grid_tile_t *result; /* Tuile à retourner */ - - if (IS_LEAF_TILE(tile)) - result = tile->widget == widget ? tile : NULL; - - else - { - result = find_tile_for_widget(tile->children[0], widget); - - if (result == NULL) - result = find_tile_for_widget(tile->children[1], widget); - - } - - return result; + gtk_tiling_grid_on_gesture_drag_update(grid, TGB_LEFT, offset_x, offset_y); } - - /****************************************************************************** * * -* Paramètres : tgrid = conteneur d'affichage en tuiles à consulter. * +* Paramètres : gesture = encadrement de déplacement à l'origine de l'appel. * +* offset_x = déplacement sur l'axe des abscisses. * +* offset_y = déplacement sur l'axe des ordonnées. * +* grid = gestionnaire de placement en tuile concerné. * * * -* Description : Donne le panneau fourni par défaut pour la zone principale. * +* Description : Actualise l'effet d'un redimensionnement drag-and-drop. * * * -* Retour : Panneau d'affichage par défault ou NULL. * +* Retour : - * * * * Remarques : - * * * ******************************************************************************/ -GPanelItem *gtk_tiled_grid_get_default_main_panel(const GtkTiledGrid *tgrid) +static void gtk_tiling_grid_on_right_gesture_drag_update(GtkGestureDrag *gesture, double offset_x, double offset_y, GtkTilingGrid *grid) { - GPanelItem *result; /* Panneau à retourner */ - - result = tgrid->def_panel; - - if (result != NULL) - g_object_ref(G_OBJECT(result)); - - return result; + gtk_tiling_grid_on_gesture_drag_update(grid, TGB_RIGHT, offset_x, offset_y); } /****************************************************************************** * * -* Paramètres : tgrid = conteneur d'affichage en tuiles à modifier. * -* panel = panneau d'affichage par défault ou NULL. * +* Paramètres : gesture = encadrement de déplacement à l'origine de l'appel. * +* offset_x = déplacement sur l'axe des abscisses. * +* offset_y = déplacement sur l'axe des ordonnées. * +* grid = gestionnaire de placement en tuile concerné. * * * -* Description : Fournit le panneau par défaut pour la zone principale. * +* Description : Actualise l'effet d'un redimensionnement drag-and-drop. * * * * Retour : - * * * @@ -825,56 +843,21 @@ GPanelItem *gtk_tiled_grid_get_default_main_panel(const GtkTiledGrid *tgrid) * * ******************************************************************************/ -void gtk_tiled_grid_set_default_main_panel(GtkTiledGrid *tgrid, GPanelItem *panel) +static void gtk_tiling_grid_on_bottom_gesture_drag_update(GtkGestureDrag *gesture, double offset_x, double offset_y, GtkTilingGrid *grid) { - GtkWidget *widget; /* Composant GTK à retirer */ - GtkWidget *parent; /* Conteneur à vider */ - grid_tile_t *tile; /* Première tuile d'accueil */ - - if (tgrid->def_panel != NULL) - { - widget = gtk_dockable_build_widget(GTK_DOCKABLE(tgrid->def_panel)); - - parent = gtk_widget_get_parent(widget); - - if (parent != NULL) - gtk_container_remove(GTK_CONTAINER(parent), widget); - - g_object_unref(G_OBJECT(widget)); - - g_object_unref(G_OBJECT(tgrid->def_panel)); - - } - - tgrid->def_panel = panel; - - if (panel != NULL) - { - g_object_ref(G_OBJECT(panel)); - - if (tgrid->tiles == NULL) - gtk_tiled_grid_add(tgrid, panel); - - else - { - tile = find_suitable_tile(&tgrid->tiles, "M", tgrid); - - if (gtk_notebook_get_n_pages(GTK_NOTEBOOK(tile->widget)) == 0) - gtk_tiled_grid_add(tgrid, panel); - - } - - } + gtk_tiling_grid_on_gesture_drag_update(grid, TGB_BOTTOM, offset_x, offset_y); } /****************************************************************************** * * -* Paramètres : tgrid = conteneur d'affichage en tuiles à modifier. * -* panel = panneau d'affichage à intégrer. * +* Paramètres : gesture = encadrement de déplacement à l'origine de l'appel. * +* offset_x = déplacement final sur l'axe des abscisses. * +* offset_y = déplacement final sur l'axe des ordonnées. * +* grid = gestionnaire de placement en tuile concerné. * * * -* Description : Incorpore un nouveau panneau dans le conteneur en tuiles. * +* Description : Clôture un drag-and-drop de redimensionnement. * * * * Retour : - * * * @@ -882,66 +865,30 @@ void gtk_tiled_grid_set_default_main_panel(GtkTiledGrid *tgrid, GPanelItem *pane * * ******************************************************************************/ -void gtk_tiled_grid_add(GtkTiledGrid *tgrid, GPanelItem *panel) +static void gtk_tiling_grid_on_gesture_drag_end(GtkGestureDrag *gesture, double offset_x, double offset_y, GtkTilingGrid *grid) { - char *path; /* Chemin d'accès */ - char *name; /* Nom à donner à l'onglet */ - grid_tile_t *tile; /* Tuile d'accueil */ - - path = gtk_panel_item_class_get_path(G_PANEL_ITEM_GET_CLASS(panel)); - - if (!is_valid_tile_path(path)) - { - name = gtk_dockable_get_name(GTK_DOCKABLE(panel)); - log_variadic_message(LMT_ERROR, _("Invalid path '%s' for panel '%s'"), path, name); - free(name); - } - + if (!grid->panning) + gtk_gesture_set_state(GTK_GESTURE(gesture), GTK_EVENT_SEQUENCE_DENIED); else - { - tile = find_suitable_tile(&tgrid->tiles, path, tgrid); - assert(tile != NULL); - - gtk_dock_station_add_dockable(GTK_DOCK_STATION(tile->widget), GTK_DOCKABLE(panel)); + grid->panning = false; - g_panel_item_set_dock_at_startup(panel, true); - - /* Si c'est la toute première fois... */ - if (gtk_widget_get_parent(tile->widget) == NULL) - { - assert(tile == tgrid->tiles); - assert(tile->path[0] == 'M' && tile->path[1] == '\0'); - g_object_ref(G_OBJECT(tile->widget)); - gtk_container_add(GTK_CONTAINER(tgrid), tile->widget); - } - - /* Si on n'a plus besoin du panneau par défaut */ - if (tgrid->def_panel != NULL && tile->path[0] == 'M' && tile->path[1] == '\0') - { - /* Si ce n'est pas le panneau qu'on vient de rajouter...*/ - if (panel != tgrid->def_panel) - { - /* Enfin : si ce panneau par défaut est réellement en place */ - if (g_panel_item_is_docked(tgrid->def_panel)) - gtk_tiled_grid_remove(tgrid, tgrid->def_panel); - - } - - } +} - } - free(path); -} +/* ---------------------------------------------------------------------------------- */ +/* IMPLEMENTATION DES FONCTIONS DE CLASSE */ +/* ---------------------------------------------------------------------------------- */ /****************************************************************************** * * -* Paramètres : tgrid = conteneur d'affichage en tuiles à modifier. * -* panel = panneau d'affichage à supprimer. * +* Paramètres : object = instance d'objet GLib à mamnipuler. * +* prop_id = identifiant de la propriété visée. * +* value = valeur à prendre en compte. * +* pspec = définition de la propriété. * * * -* Description : Retire un panneau dans le conteneur en tuiles. * +* Description : Met à jour une propriété d'instance GObject. * * * * Retour : - * * * @@ -949,90 +896,65 @@ void gtk_tiled_grid_add(GtkTiledGrid *tgrid, GPanelItem *panel) * * ******************************************************************************/ -void gtk_tiled_grid_remove(GtkTiledGrid *tgrid, GPanelItem *panel) +static void gtk_tiling_grid_set_property(GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) { - GtkWidget *station; /* Support courant */ - grid_tile_t *tile; /* Tuile d'accueil */ - - assert(g_panel_item_is_docked(panel)); - - gtk_dockable_decompose(GTK_DOCKABLE(panel), &station); - - tile = find_tile_for_widget(tgrid->tiles, station); - assert(tile != NULL); + GtkTilingGrid *grid; /* Version spécialisée */ - gtk_dock_station_remove_dockable(GTK_DOCK_STATION(station), GTK_DOCKABLE(panel)); + grid = GTK_TILING_GRID(object); - g_panel_item_set_dock_at_startup(panel, false); - - if (gtk_notebook_get_n_pages(GTK_NOTEBOOK(station)) == 0) + switch (prop_id) { - /* Si le panneau par défaut devient nécessaire */ - if (tgrid->def_panel != NULL && tile->path[0] == 'M' && tile->path[1] == '\0') - gtk_tiled_grid_add(tgrid, tgrid->def_panel); - - else - { - /* La racine est concernée ! */ - if (tile->parent == NULL) + case PROP_LAYOUT: + if (grid->layout != g_value_get_flags(value)) { - assert(tile == tgrid->tiles); + grid->layout = g_value_get_flags(value); - g_object_ref(G_OBJECT(tile->widget)); - gtk_container_remove(GTK_CONTAINER(tgrid), tile->widget); + apply_tiling_grid_layout(GTK_GRID(grid), grid->layout, (GtkWidget *[]) { + GTK_WIDGET(grid->top), GTK_WIDGET(grid->left), + GTK_WIDGET(grid->right), GTK_WIDGET(grid->bottom) + }); - delete_tile(tile); - tgrid->tiles = NULL; + g_object_notify_by_pspec(object, pspec); } + break; - else - collapse_tile(tile->parent, tile); - - } - - } - -} - + gtk_tiling_grid_set_visible(grid, TGB_TOP, g_value_get_boolean(value)); + break; -/****************************************************************************** -* * -* Paramètres : tgrid = conteneur d'affichage en tuiles à consulter. * -* station = station d'accueil à retrouver. * -* * -* Description : Indique le chemin correspondant à une station intégrée. * -* * -* Retour : Copie de chemin trouvé, à libérer ensuite, ou NULL si échec. * -* * -* Remarques : - * -* * -******************************************************************************/ + case PROP_VISIBLE_TOP: + gtk_tiling_grid_set_visible(grid, TGB_TOP, g_value_get_boolean(value)); + break; -char *gtk_tiled_grid_get_path_for_station(const GtkTiledGrid *tgrid, GtkDockStation *station) -{ - char *result; /* Chemin d'accès à renvoyer */ - grid_tile_t *tile; /* Tuile d'accueil */ + case PROP_VISIBLE_LEFT: + gtk_tiling_grid_set_visible(grid, TGB_LEFT, g_value_get_boolean(value)); + break; - tile = find_tile_for_widget(tgrid->tiles, GTK_WIDGET(station)); + case PROP_VISIBLE_RIGHT: + gtk_tiling_grid_set_visible(grid, TGB_RIGHT, g_value_get_boolean(value)); + break; - if (tile == NULL) - result = NULL; + case PROP_VISIBLE_BOTTOM: + gtk_tiling_grid_set_visible(grid, TGB_BOTTOM, g_value_get_boolean(value)); + break; - else - result = strdup(tile->path); + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec); + break; - return result; + } } /****************************************************************************** * * -* Paramètres : tgrid = conteneur d'affichage en tuiles à mettre à jour. * -* config = configuration à consulter. * +* Paramètres : object = instance d'objet GLib à mamnipuler. * +* prop_id = identifiant de la propriété visée. * +* value = valeur à transmettre. [OUT] * +* pspec = définition de la propriété. * * * -* Description : Replace les positions des séparateurs de tuiles. * +* Description : Fournit la valeur d'une propriété d'instance GObject. * * * * Retour : - * * * @@ -1040,57 +962,68 @@ char *gtk_tiled_grid_get_path_for_station(const GtkTiledGrid *tgrid, GtkDockStat * * ******************************************************************************/ -void gtk_tiled_grid_restore_positions(const GtkTiledGrid *tgrid, GGenConfig *config) +static void gtk_tiling_grid_get_property(GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) { + GtkTilingGrid *grid; /* Version spécialisée */ - void visit_tiles_for_restoring(grid_tile_t *tile, const char *vpath) - { - GtkOrientation orientation; /* Direction de la tuile */ - char hint; /* Inutile donc indispensable */ - char *key; /* Clef d'accès à un paramètre */ - gint position; /* Nouvelle position de barre */ - size_t i; /* Boucle de parcours */ - char *child_key; /* Clef d'accès des suivants */ - - if (!IS_LEAF_TILE(tile)) - { - orientation = gtk_orientable_get_orientation(GTK_ORIENTABLE(tile->widget)); + grid = GTK_TILING_GRID(object); - hint = orientation == GTK_ORIENTATION_HORIZONTAL ? 'h' : 'v'; + switch (prop_id) + { + case PROP_EMPTY_TOP: + g_value_set_boolean(value, gtk_dock_station_is_empty(grid->top_station)); + break; - asprintf(&key, "%s%c", vpath, hint); + case PROP_EMPTY_LEFT: + g_value_set_boolean(value, gtk_dock_station_is_empty(grid->left_station)); + break; - if (g_generic_config_get_value(config, key, &position)) - gtk_paned_set_position(GTK_PANED(tile->widget), position); + case PROP_EMPTY_RIGHT: + g_value_set_boolean(value, gtk_dock_station_is_empty(grid->right_station)); + break; - for (i = 0; i < 2; i++) - { - asprintf(&child_key, "%s%zu", key, i); + case PROP_EMPTY_BOTTOM: + g_value_set_boolean(value, gtk_dock_station_is_empty(grid->bottom_station)); + break; - visit_tiles_for_restoring(tile->children[i], child_key); + case PROP_VISIBLE_TOP: + g_value_set_boolean(value, gtk_tiling_grid_get_visible(grid, TGB_TOP)); + break; - free(child_key); + case PROP_VISIBLE_LEFT: + g_value_set_boolean(value, gtk_tiling_grid_get_visible(grid, TGB_LEFT)); + break; - } + case PROP_VISIBLE_RIGHT: + g_value_set_boolean(value, gtk_tiling_grid_get_visible(grid, TGB_RIGHT)); + break; - free(key); + case PROP_VISIBLE_BOTTOM: + g_value_set_boolean(value, gtk_tiling_grid_get_visible(grid, TGB_BOTTOM)); + break; - } + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec); + break; } +} - visit_tiles_for_restoring(tgrid->tiles, "gui.panels.positions.R"); -} + +/* ---------------------------------------------------------------------------------- */ +/* FORME GENERIQUE DE MISE EN DISPOSITION */ +/* ---------------------------------------------------------------------------------- */ /****************************************************************************** * * -* Paramètres : tgrid = conteneur d'affichage en tuiles à consulter. * -* config = configuration à mettre à jour. * +* Paramètres : grid = composant GTK dont le contenu est à arranger. * +* options = options de mise en place. * +* panels = liste organisée de composants à déplacer. * * * -* Description : Sauvegarde les positions des séparateurs de tuiles. * +* Description : Met en place une disposition particulière de panneaux. * * * * Retour : - * * * @@ -1098,49 +1031,98 @@ void gtk_tiled_grid_restore_positions(const GtkTiledGrid *tgrid, GGenConfig *con * * ******************************************************************************/ -void gtk_tiled_grid_save_positions(const GtkTiledGrid *tgrid, GGenConfig *config) +void apply_tiling_grid_layout(GtkGrid *grid, LayoutReachOptions options, GtkWidget *panels[TGB_COUNT]) { - - void visit_tiles_for_saving(grid_tile_t *tile, const char *vpath) + int top_panel_span; /* Etendue d'un composant #1 */ + int left_panel_span; /* Etendue d'un composant #2 */ + int right_panel_span; /* Etendue d'un composant #3 */ + int bottom_panel_span; /* Etendue d'un composant #4 */ + int top_panel_column; /* Position de composant #1 */ + int left_panel_row; /* Position de composant #2 */ + int right_panel_row; /* Position de composant #3 */ + int bottom_panel_column; /* Position de composant #4 */ + GtkLayoutManager *layout; /* Gestionnaire de disposition */ + GtkGridLayoutChild *top_panel_layout; /* Disposition de composant #1 */ + GtkGridLayoutChild *left_panel_layout; /* Disposition de composant #2 */ + GtkGridLayoutChild *right_panel_layout; /* Disposition de composant #3 */ + GtkGridLayoutChild *bottom_panel_layout;/* Disposition de composant #4 */ + + /* Calcul des placements */ + + top_panel_span = 3; + left_panel_span = 3; + right_panel_span = 3; + bottom_panel_span = 3; + + if (options & LRO_LEFT_TOP_REACH) { - GtkOrientation orientation; /* Direction de la tuile */ - char hint; /* Inutile donc indispensable */ - char *key; /* Clef d'accès à un paramètre */ - gint position; /* Nouvelle position de barre */ - size_t i; /* Boucle de parcours */ - char *child_key; /* Clef d'accès des suivants */ - - if (!IS_LEAF_TILE(tile)) - { - orientation = gtk_orientable_get_orientation(GTK_ORIENTABLE(tile->widget)); - - hint = orientation == GTK_ORIENTATION_HORIZONTAL ? 'h' : 'v'; + top_panel_column = 1; + top_panel_span--; + left_panel_row = 0; + } + else + { + top_panel_column = 0; + left_panel_row = 1; + left_panel_span--; + } - asprintf(&key, "%s%c", vpath, hint); + if (options & LRO_LEFT_BOTTOM_REACH) + { + bottom_panel_column = 1; + bottom_panel_span--; + } + else + { + left_panel_span--; + bottom_panel_column = 0; + } - position = gtk_paned_get_position(GTK_PANED(tile->widget)); - g_generic_config_create_or_udpdate_param(config, key, CPT_INTEGER, -1, position); + if (options & LRO_RIGHT_TOP_REACH) + { + top_panel_span--; + right_panel_row = 0; + } + else + { + right_panel_row = 1; + right_panel_span--; + } - for (i = 0; i < 2; i++) - { - asprintf(&child_key, "%s%zu", key, i); + if (options & LRO_RIGHT_BOTTOM_REACH) + bottom_panel_span--; + else + right_panel_span--; - visit_tiles_for_saving(tile->children[i], child_key); + /* Mise en application des contraintes */ - free(child_key); + layout = gtk_widget_get_layout_manager(GTK_WIDGET(grid)); - } + top_panel_layout = GTK_GRID_LAYOUT_CHILD(gtk_layout_manager_get_layout_child(layout, panels[TGB_TOP])); + left_panel_layout = GTK_GRID_LAYOUT_CHILD(gtk_layout_manager_get_layout_child(layout, panels[TGB_LEFT])); + right_panel_layout = GTK_GRID_LAYOUT_CHILD(gtk_layout_manager_get_layout_child(layout, panels[TGB_RIGHT])); + bottom_panel_layout = GTK_GRID_LAYOUT_CHILD(gtk_layout_manager_get_layout_child(layout, panels[TGB_BOTTOM])); - free(key); + g_object_set(G_OBJECT(top_panel_layout), + "column", top_panel_column, + "column-span", top_panel_span, + NULL); - } + g_object_set(G_OBJECT(left_panel_layout), + "row", left_panel_row, + "row-span", left_panel_span, + NULL); - } + g_object_set(G_OBJECT(right_panel_layout), + "row", right_panel_row, + "row-span", right_panel_span, + NULL); + g_object_set(G_OBJECT(bottom_panel_layout), + "column", bottom_panel_column, + "column-span", bottom_panel_span, + NULL); - visit_tiles_for_saving(tgrid->tiles, "gui.panels.positions.R"); + gtk_layout_manager_layout_changed(layout); } - - -#endif diff --git a/src/gtkext/grid.h b/src/gtkext/grid.h index d9b7ef1..fd98035 100644 --- a/src/gtkext/grid.h +++ b/src/gtkext/grid.h @@ -25,10 +25,10 @@ #define _GTKEXT_GRID_H +#include <stdbool.h> #include <gtk/gtk.h> -#include "dockstation.h" #include "panel.h" #include "../glibext/helpers.h" @@ -42,7 +42,51 @@ DECLARE_GTYPE(GtkTilingGrid, gtk_tiling_grid, GTK, TILING_GRID); /* Crée une nouvelle instance de conteneur avec tuiles. */ GtkWidget *gtk_tiling_grid_new(void); +/* Liste des zones de bordure */ +typedef enum _TilingGridBorder /*< skip (glib-mkenums) >*/ +{ + TGB_TOP, /* Zone supérieure */ + TGB_LEFT, /* Zone de gauche */ + TGB_RIGHT, /* Zone de droite */ + TGB_BOTTOM, /* Zone inférieure */ +} TilingGridBorder; + +/** + * Fixe le nombre de combinaisons sans le rendre visible dans l'énumération. + */ +#define TGB_COUNT (TGB_BOTTOM + 1) + +/* Affiche ou masque une zone du conteneur en tuiles. */ +void gtk_tiling_grid_set_visible(GtkTilingGrid *, TilingGridBorder, bool); + +/* Fournit la visibilité d'une zone du conteneur en tuiles. */ +bool gtk_tiling_grid_get_visible(GtkTilingGrid *, TilingGridBorder); + +/* Ajoute un panneau à un conteneur en tuiles. */ +void gtk_tiling_grid_add_panel(GtkTilingGrid *, GtkTiledPanel *, bool); + +/* Note un ajout ou un retrait de panneau principal. */ +void gtk_tiling_grid_notify_new_main_panel_state(const GtkTilingGrid *, GtkTiledPanel *, bool); + + + +/* --------------------- FORME GENERIQUE DE MISE EN DISPOSITION --------------------- */ + + +/* Options de dispositions cumulables */ +typedef enum _LayoutReachOptions /*< flags (glib-mkenums) >*/ +{ + LRO_NONE = (0 << 0), /* Aucune atteinte des bords */ + LRO_LEFT_TOP_REACH = (1 << 0), /* Atteinte du bord haut à G. */ + LRO_LEFT_BOTTOM_REACH = (1 << 1), /* Atteinte du bord bas à G. */ + LRO_RIGHT_TOP_REACH = (1 << 2), /* Atteinte du bord haut à D. */ + LRO_RIGHT_BOTTOM_REACH = (1 << 3), /* Atteinte du bord bas à D. */ + +} LayoutReachOptions; + +/* Met en place une disposition particulière de panneaux. */ +void apply_tiling_grid_layout(GtkGrid *, LayoutReachOptions, GtkWidget *[TGB_COUNT]); diff --git a/src/gtkext/grid.ui b/src/gtkext/grid.ui new file mode 100644 index 0000000..b14ced2 --- /dev/null +++ b/src/gtkext/grid.ui @@ -0,0 +1,217 @@ +<?xml version="1.0" encoding="UTF-8"?> +<interface> + <template class="GtkTilingGrid" parent="GtkGrid"> + + <!-- Zone supérieure --> + + <child> + <object class="GtkRevealer" id="top"> + <property name="transition-type">slide-up</property> + <property name="reveal-child">false</property> + + <child> + <object class="GtkBox"> + <property name="orientation">vertical</property> + + <child> + <object class="GtkDockStation" id="top_station"> + <property name="orientation">vertical</property> + <property name="hexpand">true</property> + <property name="vexpand">false</property> + <property name="height-request">30</property> + <signal name="panel-docked" handler="gtk_tiling_grid_on_panel_un_docked"/> + <signal name="panel-undocked" handler="gtk_tiling_grid_on_panel_un_docked"/> + </object> + </child> + + <child> + <object class="GtkSeparator" id="top_handle"> + <property name="orientation">vertical</property> + <property name="height-request">5</property> + + <child> + <object class="GtkGestureDrag"> + <property name="propagation-phase">capture</property> + <signal name="drag-begin" handler="gtk_tiling_grid_on_gesture_drag_begin"/> + <signal name="drag-update" handler="gtk_tiling_grid_on_top_gesture_drag_update"/> + <signal name="drag-end" handler="gtk_tiling_grid_on_gesture_drag_end"/> + </object> + </child> + + </object> + </child> + + </object> + </child> + + <layout> + <property name="column">0</property> + <property name="row">0</property> + <property name="column-span">3</property> + </layout> + </object> + </child> + + <!-- Zone de gauche --> + + <child> + <object class="GtkRevealer" id="left"> + <property name="transition-type">slide-right</property> + <property name="reveal-child">false</property> + + <child> + <object class="GtkBox"> + <property name="orientation">horizontal</property> + + <child> + <object class="GtkDockStation" id="left_station"> + <property name="orientation">vertical</property> + <property name="hexpand">false</property> + <property name="vexpand">true</property> + <property name="width-request">300</property> + <signal name="panel-docked" handler="gtk_tiling_grid_on_panel_un_docked"/> + <signal name="panel-undocked" handler="gtk_tiling_grid_on_panel_un_docked"/> + </object> + </child> + + <child> + <object class="GtkSeparator" id="left_handle"> + <property name="orientation">horizontal</property> + <property name="width-request">5</property> + + <child> + <object class="GtkGestureDrag"> + <property name="propagation-phase">capture</property> + <signal name="drag-begin" handler="gtk_tiling_grid_on_gesture_drag_begin"/> + <signal name="drag-update" handler="gtk_tiling_grid_on_left_gesture_drag_update"/> + <signal name="drag-end" handler="gtk_tiling_grid_on_gesture_drag_end"/> + </object> + </child> + + </object> + </child> + + </object> + </child> + + <layout> + <property name="column">0</property> + <property name="row">1</property> + </layout> + </object> + </child> + + <!-- Zone centrale --> + + <child> + <object class="GtkDockStation" id="main_station"> + <property name="hexpand">true</property> + <property name="vexpand">true</property> + <layout> + <property name="column">1</property> + <property name="row">1</property> + </layout> + </object> + </child> + + <!-- Zone de droite --> + + <child> + <object class="GtkRevealer" id="right"> + <property name="transition-type">slide-left</property> + <property name="reveal-child">false</property> + + <child> + <object class="GtkBox"> + <property name="orientation">horizontal</property> + + <child> + <object class="GtkSeparator" id="right_handle"> + <property name="orientation">horizontal</property> + <property name="width-request">5</property> + + <child> + <object class="GtkGestureDrag"> + <property name="propagation-phase">capture</property> + <signal name="drag-begin" handler="gtk_tiling_grid_on_gesture_drag_begin"/> + <signal name="drag-update" handler="gtk_tiling_grid_on_right_gesture_drag_update"/> + <signal name="drag-end" handler="gtk_tiling_grid_on_gesture_drag_end"/> + </object> + </child> + + </object> + </child> + + <child> + <object class="GtkDockStation" id="right_station"> + <property name="orientation">vertical</property> + <property name="hexpand">false</property> + <property name="vexpand">true</property> + <property name="width-request">300</property> + <signal name="panel-docked" handler="gtk_tiling_grid_on_panel_un_docked"/> + <signal name="panel-undocked" handler="gtk_tiling_grid_on_panel_un_docked"/> + </object> + </child> + + </object> + </child> + + <layout> + <property name="column">2</property> + <property name="row">1</property> + </layout> + </object> + </child> + + <!-- Zone inférieure --> + + <child> + <object class="GtkRevealer" id="bottom"> + <property name="transition-type">slide-up</property> + <property name="reveal-child">false</property> + + <child> + <object class="GtkBox"> + <property name="orientation">vertical</property> + + <child> + <object class="GtkSeparator" id="bottom_handle"> + <property name="orientation">vertical</property> + <property name="height-request">5</property> + + <child> + <object class="GtkGestureDrag"> + <property name="propagation-phase">capture</property> + <signal name="drag-begin" handler="gtk_tiling_grid_on_gesture_drag_begin"/> + <signal name="drag-update" handler="gtk_tiling_grid_on_bottom_gesture_drag_update"/> + <signal name="drag-end" handler="gtk_tiling_grid_on_gesture_drag_end"/> + </object> + </child> + + </object> + </child> + + <child> + <object class="GtkDockStation" id="bottom_station"> + <property name="orientation">horizontal</property> + <property name="hexpand">true</property> + <property name="vexpand">false</property> + <property name="height-request">250</property> + <signal name="panel-docked" handler="gtk_tiling_grid_on_panel_un_docked"/> + <signal name="panel-undocked" handler="gtk_tiling_grid_on_panel_un_docked"/> + </object> + </child> + + </object> + </child> + + <layout> + <property name="column">0</property> + <property name="row">2</property> + <property name="column-span">3</property> + </layout> + </object> + </child> + + </template> +</interface> diff --git a/src/gtkext/hexview.c b/src/gtkext/hexview.c index 5a8dd04..95b592e 100644 --- a/src/gtkext/hexview.c +++ b/src/gtkext/hexview.c @@ -37,6 +37,22 @@ /* ------------------------- BASES D'UN COMPOSANT GRAPHIQUE ------------------------- */ +/* Liste des propriétés */ + +typedef enum _HexViewProperty { + + PROP_0, /* Réservé */ + + PROP_SHOW_OFFSETS, /* Affichage des positions */ + PROP_CONTENT, /* Contenu binaire affiché */ + + N_PROPERTIES + +} HexViewProperty; + +static GParamSpec *_hex_view_properties[N_PROPERTIES] = { NULL, }; + + /* Initialise la classe des afficheurs de tampons bruts. */ static void gtk_hex_view_class_init(GtkHexViewClass *); @@ -44,10 +60,10 @@ static void gtk_hex_view_class_init(GtkHexViewClass *); static void gtk_hex_view_init(GtkHexView *); /* Supprime toutes les références externes. */ -static void gtk_hex_view_dispose(GtkHexView *); +static void gtk_hex_view_dispose(GObject *); /* Procède à la libération totale de la mémoire. */ -static void gtk_hex_view_finalize(GtkHexView *); +static void gtk_hex_view_finalize(GObject *); /* Procède à l'actualisation de l'affichage d'un sous-composant. */ static void gtk_hex_view_dispatch_sub_snapshot(GtkWidget *, GtkSnapshot *, GtkWidget *); @@ -57,14 +73,14 @@ static void gtk_hex_view_populate_cache(GtkHexView *); -void demo_snapshot (GtkWidget *widget, GtkSnapshot *snapshot, GtkWidget *parent); - - - +/* --------------------- IMPLEMENTATION DES FONCTIONS DE CLASSE --------------------- */ -/* --------------------- IMPLEMENTATION DES FONCTIONS DE CLASSE --------------------- */ +/* Met à jour une propriété d'instance GObject. */ +static void gtk_hex_view_set_property(GObject *, guint, const GValue *, GParamSpec *); +/* Fournit la valeur d'une propriété d'instance GObject. */ +static void gtk_hex_view_get_property(GObject *, guint, GValue *, GParamSpec *); /* Prend acte de la taille allouée au composant d'affichage. */ static void gtk_hex_view_size_allocate(GtkWidget *, int, int, int); @@ -105,12 +121,26 @@ static void gtk_hex_view_class_init(GtkHexViewClass *class) object = G_OBJECT_CLASS(class); - object->dispose = (GObjectFinalizeFunc/* ! */)gtk_hex_view_dispose; - object->finalize = (GObjectFinalizeFunc)gtk_hex_view_finalize; + object->dispose = gtk_hex_view_dispose; + object->finalize = gtk_hex_view_finalize; + object->set_property = gtk_hex_view_set_property; + object->get_property = gtk_hex_view_get_property; + + _hex_view_properties[PROP_SHOW_OFFSETS] = + g_param_spec_boolean("show-offsets", NULL, NULL, + TRUE, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); + + _hex_view_properties[PROP_CONTENT] = + g_param_spec_object("content", NULL, NULL, + G_TYPE_BIN_CONTENT, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_EXPLICIT_NOTIFY); + + g_object_class_install_properties(object, N_PROPERTIES, _hex_view_properties); widget = GTK_WIDGET_CLASS(class); - // REMME gtk_widget_class_set_css_name(widget, "GtkHexView"); + gtk_widget_class_set_css_name(widget, "hexview"); g_type_ensure(GTK_TYPE_COMPOSING_AREA); @@ -167,12 +197,14 @@ static void gtk_hex_view_init(GtkHexView *view) view->generator = NULL; + gtk_hex_view_create(view, NULL); + } /****************************************************************************** * * -* Paramètres : view = instance d'objet GLib à traiter. * +* Paramètres : object = instance d'objet GLib à traiter. * * * * Description : Supprime toutes les références externes. * * * @@ -182,20 +214,24 @@ static void gtk_hex_view_init(GtkHexView *view) * * ******************************************************************************/ -static void gtk_hex_view_dispose(GtkHexView *view) +static void gtk_hex_view_dispose(GObject *object) { - gtk_widget_dispose_template(GTK_WIDGET(view), GTK_TYPE_HEX_VIEW); + GtkHexView *view; /* Version spécialisée */ + + gtk_widget_dispose_template(GTK_WIDGET(object), GTK_TYPE_HEX_VIEW); + + view = GTK_HEX_VIEW(object); g_clear_object(&view->generator); - G_OBJECT_CLASS(gtk_hex_view_parent_class)->dispose(G_OBJECT(view)); + G_OBJECT_CLASS(gtk_hex_view_parent_class)->dispose(object); } /****************************************************************************** * * -* Paramètres : view = instance d'objet GLib à traiter. * +* Paramètres : object = instance d'objet GLib à traiter. * * * * Description : Procède à la libération totale de la mémoire. * * * @@ -205,9 +241,9 @@ static void gtk_hex_view_dispose(GtkHexView *view) * * ******************************************************************************/ -static void gtk_hex_view_finalize(GtkHexView *view) +static void gtk_hex_view_finalize(GObject *object) { - G_OBJECT_CLASS(gtk_hex_view_parent_class)->finalize(G_OBJECT(view)); + G_OBJECT_CLASS(gtk_hex_view_parent_class)->finalize(object); } @@ -263,13 +299,43 @@ bool gtk_hex_view_create(GtkHexView *view, GBinContent *content) parent = GTK_BUFFER_VIEW(view); - cache = g_buffer_cache_new(1, 2); + cache = g_buffer_cache_new(1 /* opt_count */, 2 /* reg_count */); parent->view = g_buffer_view_new(cache, parent->style); unref_object(cache); - view->generator = g_hex_generator_new(content); + + + gtk_hex_view_set_content(view, content); + + + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : view = composant d'affichage à consulter. * +* * +* Description : Fournit le contenu associé au composant d'affichage. * +* * +* Retour : Contenu dans lequel puise le générateur pour les lignes. * +* * +* Remarques : - * +* * +******************************************************************************/ + +GBinContent *gtk_hex_view_get_content(const GtkHexView *view) +{ + GBinContent *result; /* Référence à retourner */ + + if (view->generator != NULL) + result = g_hex_generator_get_content(view->generator); + else + result = NULL; return result; @@ -278,6 +344,61 @@ bool gtk_hex_view_create(GtkHexView *view, GBinContent *content) /****************************************************************************** * * +* Paramètres : view = composant d'affichage à modifier. * +* content = nouveau contenu pour source de génération. * +* * +* Description : Définit le contenu associé au composant d'affichage. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +void gtk_hex_view_set_content(GtkHexView *view, GBinContent *content) +{ + GBinContent *old; /* Ancienne valeur */ + GBufferCache *cache; /* Tampon à représenter */ + + old = gtk_hex_view_get_content(view); + + assert((old == NULL && view->generator == NULL) || (old != NULL && view->generator != NULL)); + + if (old != content) + { + if (view->generator != NULL) + { + cache = g_buffer_view_get_cache(GTK_BUFFER_VIEW(view)->view); + + g_buffer_cache_wlock(cache); + + g_buffer_cache_truncate(cache, 0); + + g_buffer_cache_wunlock(cache); + + unref_object(cache); + + g_clear_object(&view->generator); + + } + + if (content != NULL) + view->generator = g_hex_generator_new(content); + + g_object_notify_by_pspec(G_OBJECT(view), _hex_view_properties[PROP_CONTENT]); + + assert(content != NULL); + gtk_widget_queue_resize(GTK_WIDGET(view)); + + } + + g_clear_object(&old); + +} + + +/****************************************************************************** +* * * Paramètres : widget = composant GTK à redessiner. * * snapshot = gestionnaire de noeuds de rendu à solliciter. * * parent = composant GTK parent et cadre de l'appel. * @@ -380,60 +501,101 @@ static void gtk_hex_view_populate_cache(GtkHexView *view) /* Mise à jour de l'affichage ? */ + /* if (needed != count) gtk_widget_queue_resize(GTK_WIDGET(view)); + */ } +/* ---------------------------------------------------------------------------------- */ +/* IMPLEMENTATION DES FONCTIONS DE CLASSE */ +/* ---------------------------------------------------------------------------------- */ +/****************************************************************************** +* * +* Paramètres : object = instance d'objet GLib à mamnipuler. * +* prop_id = identifiant de la propriété visée. * +* value = valeur à prendre en compte. * +* pspec = définition de la propriété. * +* * +* Description : Met à jour une propriété d'instance GObject. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ - -void demo_snapshot (GtkWidget *widget, GtkSnapshot *snapshot, GtkWidget *parent) +static void gtk_hex_view_set_property(GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) { - GdkRGBA red, green, yellow, blue; - float w, h; - - gdk_rgba_parse (&red, "red"); - gdk_rgba_parse (&green, "green"); - gdk_rgba_parse (&yellow, "yellow"); - gdk_rgba_parse (&blue, "blue"); + GtkHexView *view; /* Version spécialisée */ + GObject *content; /* Contenu sous forme simple */ - w = gtk_widget_get_width (widget) / 2.0; - h = gtk_widget_get_height (widget) / 2.0; + view = GTK_HEX_VIEW(object); - h /= 2.0; + switch (prop_id) + { + case PROP_SHOW_OFFSETS: + g_display_options_set(GTK_CONTENT_VIEW(view)->options, HCO_OFFSET, g_value_get_boolean(value)); + gtk_widget_set_visible(view->offsets, g_value_get_boolean(value)); + break; - gtk_snapshot_append_color (snapshot, &red, - &GRAPHENE_RECT_INIT(0, 0, w, h)); - gtk_snapshot_append_color (snapshot, &green, - &GRAPHENE_RECT_INIT(w, 0, w, h)); - gtk_snapshot_append_color (snapshot, &yellow, - &GRAPHENE_RECT_INIT(0, h, w, h)); - gtk_snapshot_append_color (snapshot, &blue, - &GRAPHENE_RECT_INIT(w, h, w, h)); + case PROP_CONTENT: + content = g_value_get_object(value); + gtk_hex_view_set_content(view, G_BIN_CONTENT(content)); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec); + break; + } } +/****************************************************************************** +* * +* Paramètres : object = instance d'objet GLib à mamnipuler. * +* prop_id = identifiant de la propriété visée. * +* value = valeur à transmettre. [OUT] * +* pspec = définition de la propriété. * +* * +* Description : Fournit la valeur d'une propriété d'instance GObject. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ +static void gtk_hex_view_get_property(GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) +{ + GtkHexView *view; /* Version spécialisée */ + view = GTK_HEX_VIEW(object); + switch (prop_id) + { + case PROP_SHOW_OFFSETS: + g_value_set_boolean(value, gtk_widget_get_visible(view->offsets)); + break; + case PROP_CONTENT: + g_value_take_object(value, gtk_hex_view_get_content(view)); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec); + break; + } - - - - -/* ---------------------------------------------------------------------------------- */ -/* IMPLEMENTATION DES FONCTIONS DE CLASSE */ -/* ---------------------------------------------------------------------------------- */ +} /****************************************************************************** @@ -467,7 +629,13 @@ static void gtk_hex_view_size_allocate(GtkWidget *widget, int width, int height, final_widths = alloca(_CHILDREN_COUNT * sizeof(int)); for (i = 0; i < _CHILDREN_COUNT; i++) - gtk_widget_measure(view->children[i], GTK_ORIENTATION_HORIZONTAL, -1, &min_widths[i], NULL, NULL, NULL); + { + if (!gtk_widget_get_visible(view->children[i])) + min_widths[i] = 0; + else + gtk_widget_measure(view->children[i], GTK_ORIENTATION_HORIZONTAL, -1, &min_widths[i], NULL, NULL, NULL); + + } /* Passe 1 : tentative sans défilement vertical */ @@ -491,7 +659,10 @@ static void gtk_hex_view_size_allocate(GtkWidget *widget, int width, int height, for (i = 0; i < _CHILDREN_COUNT; i++) { - final_widths[i] += min_widths[i]; + if (!gtk_widget_get_visible(view->children[i])) + final_widths[i] = 0; + else + final_widths[i] += min_widths[i]; g_width_tracker_set_column_min_width(tracker, i, final_widths[i]); @@ -531,17 +702,6 @@ static GtkSizeRequestMode gtk_hex_view_get_request_mode(GtkWidget *widget) } - - - - - - - - - - - /****************************************************************************** * * * Paramètres : widget = composant GTK à examiner. * @@ -580,8 +740,12 @@ static void gtk_hex_view_measure(GtkWidget *widget, GtkOrientation orientation, for (i = 0; i < _CHILDREN_COUNT; i++) { + if (!gtk_widget_get_visible(view->children[i])) + continue; + gtk_widget_measure(view->children[i], GTK_ORIENTATION_HORIZONTAL, -1, &min, NULL, NULL, NULL); requested += min; + } for_size -= requested; @@ -593,11 +757,14 @@ static void gtk_hex_view_measure(GtkWidget *widget, GtkOrientation orientation, GTK_BUFFER_VIEW(view)->style, for_size); - if (minimum != NULL) *minimum = 0; + if (minimum != NULL) *minimum = requested; if (natural != NULL) *natural = requested; for (i = 0; i < _CHILDREN_COUNT; i++) { + if (!gtk_widget_get_visible(view->children[i])) + continue; + gtk_widget_measure(view->children[i], GTK_ORIENTATION_VERTICAL, -1, &min, &nat, NULL, NULL); if (minimum != NULL && min > *minimum) diff --git a/src/gtkext/hexview.h b/src/gtkext/hexview.h index 2199786..0d2cd5a 100644 --- a/src/gtkext/hexview.h +++ b/src/gtkext/hexview.h @@ -41,6 +41,12 @@ DECLARE_GTYPE(GtkHexView, gtk_hex_view, GTK, HEX_VIEW); /* Crée un composant d'affichage d'octets bruts et imprimables. */ GtkHexView *gtk_hex_view_new(GBinContent *); +/* Fournit le contenu associé au composant d'affichage. */ +GBinContent *gtk_hex_view_get_content(const GtkHexView *); + +/* Définit le contenu associé au composant d'affichage. */ +void gtk_hex_view_set_content(GtkHexView *, GBinContent *); + #endif /* _GTKEXT_HEXVIEW_H */ diff --git a/src/gtkext/hexview.ui b/src/gtkext/hexview.ui index ae4586c..9b42936 100644 --- a/src/gtkext/hexview.ui +++ b/src/gtkext/hexview.ui @@ -1,27 +1,29 @@ +<?xml version="1.0" encoding="UTF-8"?> <interface> - <template class="GtkHexView" parent="GtkBufferView"> - <property name="css-name">GtkHexView</property> - <child> - <object class="GtkComposingArea" id="offsets"> - <style> - <class name="gutter"/> - </style> - </object> - </child> - <child> - <object class="GtkComposingArea" id="hex"> - <property name="hexpand">true</property> - <style> - <class name="custom-view"/> - </style> - </object> - </child> - <child> - <object class="GtkComposingArea" id="ascii"> - <style> - <class name="custom-view"/> - </style> - </object> - </child> - </template> + + <template class="GtkHexView" parent="GtkBufferView"> + <child> + <object class="GtkComposingArea" id="offsets"> + <style> + <class name="gutter"/> + </style> + </object> + </child> + <child> + <object class="GtkComposingArea" id="hex"> + <property name="hexpand">true</property> + <style> + <class name="custom-view"/> + </style> + </object> + </child> + <child> + <object class="GtkComposingArea" id="ascii"> + <style> + <class name="custom-view"/> + </style> + </object> + </child> + </template> + </interface> diff --git a/src/gtkext/panel-int.h b/src/gtkext/panel-int.h index 07ade20..5398e51 100644 --- a/src/gtkext/panel-int.h +++ b/src/gtkext/panel-int.h @@ -30,9 +30,14 @@ +/* Indique l'emplacement par défaut pour un affichage. */ +typedef char * (* get_tiled_panel_path) (const GtkTiledPanel *); + /* Fournit les composants adaptés pour la barre de titre. */ -typedef GListStore * (* get_tiled_panel_widgets_cb) (GtkTiledPanel *, bool); +typedef GListStore * (* get_tiled_panel_widgets_cb) (const GtkTiledPanel *, bool); +/* Note un ajout ou un retrait de panneau principal. */ +typedef void (* notify_tiled_panel_state_cb) (GtkTiledPanel *, GtkTiledPanel *, bool); /* Elément réactif pour panneaux de l'éditeur (instance) */ @@ -47,8 +52,11 @@ struct _GtkTiledPanelClass { GtkBoxClass parent; /* A laisser en premier */ + get_tiled_panel_path get_default_path; /* Localisation de l'affichage */ get_tiled_panel_widgets_cb get_widgets; /* Récupération de composants */ + notify_tiled_panel_state_cb notify; /* Note d'un ajout ou retrait */ + }; diff --git a/src/gtkext/panel.c b/src/gtkext/panel.c index de55917..f63cfa1 100644 --- a/src/gtkext/panel.c +++ b/src/gtkext/panel.c @@ -137,6 +137,35 @@ static void gtk_tiled_panel_finalize(GtkTiledPanel *panel) /****************************************************************************** * * * Paramètres : panel = panneau graphique à consulter. * +* * +* Description : Indique l'emplacement attendu pour un affichage. * +* * +* Retour : Chemin représenté ou NULL pour l'emplacement "M" par défaut. * +* * +* Remarques : - * +* * +******************************************************************************/ + +char *gtk_tiled_panel_get_path(const GtkTiledPanel *panel) +{ + char *result; /* Chemin à retourner */ + GtkTiledPanelClass *class; /* Classe à actionner */ + + class = GTK_TILED_PANEL_GET_CLASS(panel); + + if (class->get_default_path != NULL) + result = class->get_default_path(panel); + else + result = NULL; + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : panel = panneau graphique à consulter. * * left = indication quant au côté ciblé. * * * * Description : Fournit les composants adaptés pour la barre de titre. * @@ -147,7 +176,7 @@ static void gtk_tiled_panel_finalize(GtkTiledPanel *panel) * * ******************************************************************************/ -GListStore *gtk_tiled_panel_get_title_widgets(GtkTiledPanel *panel, bool left) +GListStore *gtk_tiled_panel_get_title_widgets(const GtkTiledPanel *panel, bool left) { GListStore *result; /* Composant(s) à retourner */ GtkTiledPanelClass *class; /* Classe à actionner */ @@ -164,6 +193,32 @@ GListStore *gtk_tiled_panel_get_title_widgets(GtkTiledPanel *panel, bool left) } +/****************************************************************************** +* * +* Paramètres : panel = panneau graphique à manipuler. * +* main = panneau principal visé par l'opération. * +* activated = nature du changement de statut : ajout, retrait ?* +* * +* Description : Note un ajout ou un retrait de panneau principal. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +void gtk_tiled_panel_notify_new_main_panel_state(GtkTiledPanel *panel, GtkTiledPanel *main, bool activated) +{ + GtkTiledPanelClass *class; /* Classe à actionner */ + + class = GTK_TILED_PANEL_GET_CLASS(panel); + + if (class->notify != NULL) + class->notify(panel, main, activated); + +} + + diff --git a/src/gtkext/panel.h b/src/gtkext/panel.h index d2259ef..9b00657 100644 --- a/src/gtkext/panel.h +++ b/src/gtkext/panel.h @@ -38,9 +38,14 @@ DECLARE_GTYPE(GtkTiledPanel, gtk_tiled_panel, GTK, TILED_PANEL); +/* Indique l'emplacement attendu pour un affichage. */ +char *gtk_tiled_panel_get_path(const GtkTiledPanel *); + /* Fournit les composants adaptés pour la barre de titre. */ -GListStore *gtk_tiled_panel_get_title_widgets(GtkTiledPanel *, bool); +GListStore *gtk_tiled_panel_get_title_widgets(const GtkTiledPanel *, bool); +/* Note un ajout ou un retrait de panneau principal. */ +void gtk_tiled_panel_notify_new_main_panel_state(GtkTiledPanel *, GtkTiledPanel *, bool); diff --git a/src/gtkext/statusstack-int.h b/src/gtkext/statusstack-int.h index 2a9e99e..721b982 100644 --- a/src/gtkext/statusstack-int.h +++ b/src/gtkext/statusstack-int.h @@ -50,6 +50,12 @@ struct _GtkStatusStack GSourceFunc def_source; /* Appel en fin d'activité */ + /* Message simple par défaut */ + + GtkLabel *def_label; /* Afficheur de message */ + + char *msg; /* Contenu associé */ + /* Navigation */ GtkLabel *nav_segment; /* Désignation du segment */ @@ -84,6 +90,8 @@ struct _GtkStatusStack guint network_update_tag; /* Identifiant de mise à jour */ + GtkToggleButton *bottom_toggler; /* Bascule de panneaux inf. */ + }; /* Gestion de barre de statut adaptable (classe) */ diff --git a/src/gtkext/statusstack.c b/src/gtkext/statusstack.c index 76dbee8..92c296a 100644 --- a/src/gtkext/statusstack.c +++ b/src/gtkext/statusstack.c @@ -41,6 +41,25 @@ /* -------------------------- GESTION GENERALE DES STATUTS -------------------------- */ +/* Liste des propriétés */ + +typedef enum _StatusStackProperty { + + PROP_0, /* Réservé */ + + PROP_SHOW_BOTTOM, /* Affichage de la zone inf. */ + + N_PROPERTIES + +} StatusStackProperty; + +static GParamSpec *_status_stack_properties[N_PROPERTIES] = { NULL, }; + + +/* Source d'affichage par défaut */ +#define gtk_status_stack_default_source gtk_status_stack_show_simple_message + + /* Initialise la classe des barres de statut améliorées. */ static void gtk_status_stack_class_init(GtkStatusStackClass *); @@ -61,6 +80,25 @@ static gboolean gtk_status_stack_update_network_stats(GtkStatusStack *); +/* --------------------- IMPLEMENTATION DES FONCTIONS DE CLASSE --------------------- */ + + +/* Met à jour une propriété d'instance GObject. */ +static void gtk_status_stack_set_property(GObject *, guint, const GValue *, GParamSpec *); + +/* Fournit la valeur d'une propriété d'instance GObject. */ +static void gtk_status_stack_get_property(GObject *, guint, GValue *, GParamSpec *); + + + +/* ----------------------- MISE EN AVANT DES MESSAGES SIMPLES ----------------------- */ + + +/* S'assure de l'affichage à jour de la partie "default". */ +static gboolean gtk_status_stack_show_simple_message(gpointer); + + + /* -------------------- STATUT DES INFORMATIONS DE DESASSEMBLAGE -------------------- */ @@ -89,7 +127,7 @@ static void init_navigation_info(navigation_info_t *); static void fini_navigation_info(navigation_info_t *); /* S'assure de l'affichage à jour de la partie "navigation". */ -static gboolean gtk_status_stack_show_current_location(GtkStatusStack *); +static gboolean gtk_status_stack_show_current_location(gpointer); /* Réagit à un clic sur l'icône de zoom. */ static void gtk_status_stack_on_zoom_icon_press(GtkEntry *, GtkEntryIconPosition, GtkStatusStack *); @@ -139,7 +177,7 @@ static void fini_activity_info(activity_info_t *); static activity_status_t *find_activity_status_by_id(activity_info_t *, activity_id_t); /* S'assure de l'affichage à jour de la partie "activité". */ -static gboolean gtk_status_stack_show_current_activity(GtkStatusStack *); +static gboolean gtk_status_stack_show_current_activity(gpointer); @@ -173,6 +211,15 @@ static void gtk_status_stack_class_init(GtkStatusStackClass *class) object->dispose = (GObjectFinalizeFunc/* ! */)gtk_status_stack_dispose; object->finalize = (GObjectFinalizeFunc)gtk_status_stack_finalize; + object->set_property = gtk_status_stack_set_property; + object->get_property = gtk_status_stack_get_property; + + _status_stack_properties[PROP_SHOW_BOTTOM] = + g_param_spec_boolean("show-bottom", NULL, NULL, + TRUE, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); + + g_object_class_install_properties(object, N_PROPERTIES, _status_stack_properties); widget = GTK_WIDGET_CLASS(class); @@ -182,6 +229,8 @@ static void gtk_status_stack_class_init(GtkStatusStackClass *class) gtk_widget_class_bind_template_child(widget, GtkStatusStack, main); + gtk_widget_class_bind_template_child(widget, GtkStatusStack, def_label); + gtk_widget_class_bind_template_child(widget, GtkStatusStack, nav_segment); gtk_widget_class_bind_template_child(widget, GtkStatusStack, nav_phys); gtk_widget_class_bind_template_child(widget, GtkStatusStack, nav_virt); @@ -198,6 +247,8 @@ static void gtk_status_stack_class_init(GtkStatusStackClass *class) gtk_widget_class_bind_template_child(widget, GtkStatusStack, net_recv_speed); gtk_widget_class_bind_template_child(widget, GtkStatusStack, net_send_speed); + gtk_widget_class_bind_template_child(widget, GtkStatusStack, bottom_toggler); + } @@ -217,7 +268,9 @@ static void gtk_status_stack_init(GtkStatusStack *stack) { gtk_widget_init_template(GTK_WIDGET(stack)); - stack->def_source = NULL; + stack->def_source = gtk_status_stack_default_source; + + stack->msg = NULL; stack->nav_info = calloc(1, sizeof(navigation_info_t)); init_navigation_info(stack->nav_info); @@ -241,6 +294,10 @@ static void gtk_status_stack_init(GtkStatusStack *stack) stack->network_update_tag = g_timeout_add(NETWORK_UPDATE_INTERVAL, G_SOURCE_FUNC(gtk_status_stack_update_network_stats), stack); + /* Premier affichage... */ + + gtk_status_stack_reset_to_default(stack); + } @@ -287,6 +344,9 @@ static void gtk_status_stack_dispose(GtkStatusStack *stack) static void gtk_status_stack_finalize(GtkStatusStack *stack) { + if (stack->msg != NULL) + free(stack->msg); + fini_navigation_info(stack->nav_info); free(stack->nav_info); @@ -333,11 +393,15 @@ GtkStatusStack *gtk_status_stack_new(void) * * ******************************************************************************/ -void gtk_status_stack_reset(GtkStatusStack *stack) +void gtk_status_stack_reset_to_default(GtkStatusStack *stack) { - gtk_stack_set_visible_child_name(stack->main, "default"); + /** + * Une amélioration possible serait de passer à g_idle_add_once(), + * et de s'affranchir des retours G_SOURCE_REMOVE systématiques, + * mais la fonction n'est disponible qu'à partir de la GLib 2.74. + */ - stack->def_source = NULL; + g_idle_add(stack->def_source, stack); } @@ -497,6 +561,148 @@ static gboolean gtk_status_stack_update_network_stats(GtkStatusStack *stack) + +/* ---------------------------------------------------------------------------------- */ +/* IMPLEMENTATION DES FONCTIONS DE CLASSE */ +/* ---------------------------------------------------------------------------------- */ + + +/****************************************************************************** +* * +* Paramètres : object = instance d'objet GLib à mamnipuler. * +* prop_id = identifiant de la propriété visée. * +* value = valeur à prendre en compte. * +* pspec = définition de la propriété. * +* * +* Description : Met à jour une propriété d'instance GObject. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void gtk_status_stack_set_property(GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) +{ + GtkStatusStack *stack; /* Version spécialisée */ + + stack = GTK_STATUS_STACK(object); + + switch (prop_id) + { + case PROP_SHOW_BOTTOM: + gtk_toggle_button_set_active(stack->bottom_toggler, g_value_get_boolean(value)); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec); + break; + + } + +} + + +/****************************************************************************** +* * +* Paramètres : object = instance d'objet GLib à mamnipuler. * +* prop_id = identifiant de la propriété visée. * +* value = valeur à transmettre. [OUT] * +* pspec = définition de la propriété. * +* * +* Description : Fournit la valeur d'une propriété d'instance GObject. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void gtk_status_stack_get_property(GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) +{ + GtkStatusStack *stack; /* Version spécialisée */ + + stack = GTK_STATUS_STACK(object); + + switch (prop_id) + { + case PROP_SHOW_BOTTOM: + g_value_set_boolean(value, gtk_toggle_button_get_active(stack->bottom_toggler)); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec); + break; + + } + +} + + + +/* ---------------------------------------------------------------------------------- */ +/* MISE EN AVANT DES MESSAGES SIMPLES */ +/* ---------------------------------------------------------------------------------- */ + + +/****************************************************************************** +* * +* Paramètres : stack = barre de statut à actualiser. * +* msg = simple message à faire paraître. * +* * +* Description : Inscrit un message simple dans la barre de statut. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +void gtk_status_stack_display_message(GtkStatusStack *stack, const char *msg) +{ + if (stack->msg != NULL) + free(stack->msg); + + if (msg != NULL) + stack->msg = strdup(msg); + else + stack->msg = NULL; + + gtk_status_stack_show_simple_message(stack); + +} + + +/****************************************************************************** +* * +* Paramètres : data = pile de statuts à manipuler. * +* * +* Description : S'assure de l'affichage à jour de la partie "default". * +* * +* Retour : G_SOURCE_REMOVE pour une exécution unique. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static gboolean gtk_status_stack_show_simple_message(gpointer data) +{ + GtkStatusStack *stack; /* Version spécialisée */ + + stack = GTK_STATUS_STACK(data); + + stack->def_source = gtk_status_stack_show_simple_message; + + gtk_label_set_text(stack->def_label, stack->msg != NULL ? stack->msg : ""); + + gtk_stack_set_visible_child_name(stack->main, "default"); + + return G_SOURCE_REMOVE; + +} + + + /* ---------------------------------------------------------------------------------- */ /* STATUT DES INFORMATIONS DE DESASSEMBLAGE */ /* ---------------------------------------------------------------------------------- */ @@ -628,7 +834,7 @@ void gtk_status_stack_update_current_location(GtkStatusStack *stack, const mrang /****************************************************************************** * * -* Paramètres : stack = pile de statuts à manipuler. * +* Paramètres : data = pile de statuts à manipuler. * * * * Description : S'assure de l'affichage à jour de la partie "navigation". * * * @@ -638,14 +844,15 @@ void gtk_status_stack_update_current_location(GtkStatusStack *stack, const mrang * * ******************************************************************************/ -static gboolean gtk_status_stack_show_current_location(GtkStatusStack *stack) +static gboolean gtk_status_stack_show_current_location(gpointer data) { + GtkStatusStack *stack; /* Version spécialisée */ navigation_info_t *info; /* Informations à constituer */ char raw_pos[6 + VMPA_MAX_LEN + 1]; /* Formatage final en direct */ - stack->def_source = (GSourceFunc)gtk_status_stack_show_current_location; + stack = GTK_STATUS_STACK(data); - gtk_stack_set_visible_child_name(stack->main, "navigation"); + stack->def_source = gtk_status_stack_show_current_location; info = stack->nav_info; @@ -669,6 +876,10 @@ static gboolean gtk_status_stack_show_current_location(GtkStatusStack *stack) gtk_label_set_text(stack->nav_details, info->details != NULL ? info->details : ""); + /* Conclusion */ + + gtk_stack_set_visible_child_name(stack->main, "navigation"); + return G_SOURCE_REMOVE; } @@ -869,7 +1080,7 @@ activity_id_t gtk_status_stack_add_activity(GtkStatusStack *stack, const char *m if (info->tag != 0) g_source_remove(info->tag); - info->tag = g_idle_add((GSourceFunc)gtk_status_stack_show_current_activity, stack); + info->tag = g_idle_add(gtk_status_stack_show_current_activity, stack); g_mutex_unlock(&info->access); @@ -936,7 +1147,7 @@ void gtk_status_stack_update_activity_message(GtkStatusStack *stack, activity_id if (info->tag != 0) g_source_remove(info->tag); - info->tag = g_idle_add((GSourceFunc)gtk_status_stack_show_current_activity, stack); + info->tag = g_idle_add(gtk_status_stack_show_current_activity, stack); } @@ -993,7 +1204,7 @@ void gtk_status_stack_update_activity_value(GtkStatusStack *stack, activity_id_t if (info->tag != 0) g_source_remove(info->tag); - info->tag = g_idle_add((GSourceFunc)gtk_status_stack_show_current_activity, stack); + info->tag = g_idle_add(gtk_status_stack_show_current_activity, stack); } @@ -1045,7 +1256,7 @@ void gtk_status_stack_extend_activity_max(GtkStatusStack *stack, activity_id_t i if (info->tag != 0) g_source_remove(info->tag); - info->tag = g_idle_add((GSourceFunc)gtk_status_stack_show_current_activity, stack); + info->tag = g_idle_add(gtk_status_stack_show_current_activity, stack); } @@ -1111,10 +1322,10 @@ void gtk_status_stack_remove_activity(GtkStatusStack *stack, activity_id_t id) if (info->count == 0) { info->tag = 0; - g_idle_add(stack->def_source, stack); + gtk_status_stack_reset_to_default(stack); } else if (is_last) - info->tag = g_idle_add((GSourceFunc)gtk_status_stack_show_current_activity, stack); + info->tag = g_idle_add(gtk_status_stack_show_current_activity, stack); exit: @@ -1125,7 +1336,7 @@ void gtk_status_stack_remove_activity(GtkStatusStack *stack, activity_id_t id) /****************************************************************************** * * -* Paramètres : stack = pile de statuts à manipuler. * +* Paramètres : data = pile de statuts à manipuler. * * * * Description : S'assure de l'affichage à jour de la partie "activité". * * * @@ -1135,11 +1346,14 @@ void gtk_status_stack_remove_activity(GtkStatusStack *stack, activity_id_t id) * * ******************************************************************************/ -static gboolean gtk_status_stack_show_current_activity(GtkStatusStack *stack) +static gboolean gtk_status_stack_show_current_activity(gpointer data) { + GtkStatusStack *stack; /* Version spécialisée */ activity_info_t *info; /* Informations à consulter */ activity_status_t *last; /* Dernier statut à traiter */ + stack = GTK_STATUS_STACK(data); + info = stack->activity_info; g_mutex_lock(&info->access); @@ -1148,14 +1362,14 @@ static gboolean gtk_status_stack_show_current_activity(GtkStatusStack *stack) { if (info->count > 0) { - gtk_stack_set_visible_child_name(stack->main, "activity"); - last = &info->statuses[info->count - 1]; gtk_label_set_text(stack->activity_message, last->message); gtk_progress_bar_set_fraction(stack->activity_progress, (last->current * 1.0) / last->max); + gtk_stack_set_visible_child_name(stack->main, "activity"); + } info->tag = 0; diff --git a/src/gtkext/statusstack.h b/src/gtkext/statusstack.h index 66ad6db..96d008c 100644 --- a/src/gtkext/statusstack.h +++ b/src/gtkext/statusstack.h @@ -45,7 +45,15 @@ DECLARE_GTYPE(GtkStatusStack, gtk_status_stack, GTK, STATUS_STACK); GtkStatusStack *gtk_status_stack_new(void); /* Réinitialise la barre de statut à son stade par défaut. */ -void gtk_status_stack_reset(GtkStatusStack *); +void gtk_status_stack_reset_to_default(GtkStatusStack *); + + + +/* ----------------------- MISE EN AVANT DES MESSAGES SIMPLES ----------------------- */ + + +/* Inscrit un message simple dans la barre de statut. */ +void gtk_status_stack_display_message(GtkStatusStack *, const char *); diff --git a/src/gtkext/statusstack.ui b/src/gtkext/statusstack.ui index 8469e6e..0b7cd6d 100644 --- a/src/gtkext/statusstack.ui +++ b/src/gtkext/statusstack.ui @@ -2,6 +2,8 @@ <interface> <template class="GtkStatusStack" parent="GtkBox"> + <!--property name="show-bottom" bind-source="bottom_toggler" bind-property="active" bind-flags="bidirectional|sync-create"/--> + <child> <object class="GtkStack" id="main"> <property name="margin-start">8</property> @@ -10,16 +12,19 @@ <!-- Vide par défaut --> <child> - <object class="GtkStackPage" id="stack"> + <object class="GtkStackPage"> <property name="name">default</property> <property name="child"> - <object class="GtkLabel"> + <object class="GtkLabel" id="def_label"> <property name="hexpand">true</property> <property name="halign">fill</property> - <property name="valign">center</property> + <property name="valign">baseline</property> <property name="xalign">0</property> <property name="label"></property> + <style> + <class name="dim-label"/> + </style> </object> </property> @@ -200,7 +205,8 @@ <child> <object class="GtkToggleButton" id="bottom_toggler"> <property name="has-frame">false</property> - <property name="icon-name">panel-bottom-symbolic</property> + <property name="icon-name">dock-station-bottom-symbolic</property> + <property name="action-name">win.toggle-bottom</property> </object> </child> diff --git a/src/gui/core/logs.c b/src/gui/core/logs.c index 59910f1..cdb2a0d 100644 --- a/src/gui/core/logs.c +++ b/src/gui/core/logs.c @@ -24,6 +24,14 @@ #include "logs.h" +#include <assert.h> + + +#include "panels.h" +#include "../panels/logs.h" +#include "../../glibext/log.h" + + /****************************************************************************** * * @@ -38,26 +46,20 @@ * * ******************************************************************************/ -void do_log_message_alt2(LogMessageType type, const char *msg) +void do_log_message_alt(LogMessageType type, const char *msg) { -#if 0 - -#ifdef INCLUDE_GTK_SUPPORT - - GEditorItem *item; /* Eventuel affichage présent */ + GLogEntry *entry; /* Nouvel élément de journal */ + GtkTiledPanel *panel; /* Panneau de journalisation */ - item = find_editor_item_by_type(G_TYPE_LOG_PANEL); + entry = g_log_entry_new(type, msg); - if (item != NULL) - { - g_log_panel_add_message(G_LOG_PANEL(item), type, msg); - g_object_unref(G_OBJECT(item)); - } + panel = get_framework_panel_singleton(GTK_TYPE_LOGS_PANEL); + assert(panel != NULL); -#endif + g_log_panel_add_message(GTK_LOGS_PANEL(panel), entry); -#endif + unref_object(panel); - printf("[log GUI] [%u] %s\n", type, msg); + unref_object(entry); } diff --git a/src/gui/core/panels.c b/src/gui/core/panels.c index 4c113b8..9fca411 100644 --- a/src/gui/core/panels.c +++ b/src/gui/core/panels.c @@ -35,6 +35,7 @@ #include "../panels/binary.h" #include "../panels/binary-params.h" +#include "../panels/logs.h" #include "../panels/welcome.h" #include "../../gtkext/launcher.h" @@ -168,10 +169,23 @@ bool load_main_framework_panel_definitions(void) bool result; /* Bilan à retourner */ 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); + + info.category = NULL; + + info.image = NULL; + info.title = _("Logs"); + info.desc = NULL; + + info.personality = FPP_SINGLETON; + + info.panel_type = GTK_TYPE_LOGS_PANEL; + info.params_type = G_TYPE_INVALID; + + result = register_framework_panel_definition(&info); + if (!result) goto done; + + /* Chargements des panneaux restants */ info.category = "Main"; @@ -187,6 +201,8 @@ bool load_main_framework_panel_definitions(void) result = register_framework_panel_definition(&info); if (!result) goto done; + /* --- */ + info.category = NULL; info.image = NULL; @@ -283,6 +299,43 @@ bool register_framework_panel_definition(const panel_info_t *info) * * * Paramètres : target = type de définition de panneau recherchée. * * * +* Description : Récupère les particularités d'un panneau graphique. * +* * +* Retour : Détails du comportement associé au panneau visé. * +* * +* Remarques : - * +* * +******************************************************************************/ + +FrameworkPanelPersonality get_framework_panel_personality(GType target) +{ + FrameworkPanelPersonality result; /* Propriétées à retourner */ + size_t i; /* Boucle de parcours */ + ext_panel_info_t *info; /* Informations conservées */ + + result = FPP_NONE; + + for (i = 0; i < _panels_count; i++) + { + info = _panels_list[i]; + + if (info->panel_type == target) + { + result = info->personality; + break; + } + + } + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : target = type de définition de panneau recherchée. * +* * * Description : Met en place (au besoin) un panneau graphique unique. * * * * Retour : Instance de définition identifiée ou NULL en cas d'échec. * diff --git a/src/gui/core/panels.h b/src/gui/core/panels.h index 4d0ce41..e17ef8a 100644 --- a/src/gui/core/panels.h +++ b/src/gui/core/panels.h @@ -71,6 +71,9 @@ void unload_all_framework_panel_definitions(void); /* Enregistre la définition d'un panneau graphique. */ bool register_framework_panel_definition(const panel_info_t *); +/* Récupère les particularités d'un panneau graphique. */ +FrameworkPanelPersonality get_framework_panel_personality(GType); + /* Met en place (au besoin) un panneau graphique unique. */ GtkTiledPanel *get_framework_panel_singleton(GType); diff --git a/src/gui/dialogs/Makefile.am b/src/gui/dialogs/Makefile.am index e910c96..3492f63 100644 --- a/src/gui/dialogs/Makefile.am +++ b/src/gui/dialogs/Makefile.am @@ -3,7 +3,9 @@ BUILT_SOURCES = resources.h resources.c noinst_LTLIBRARIES = libguidialogs.la + UI_FILES = \ + about.css \ about.ui \ preferences.ui # bookmark.ui \ diff --git a/src/gui/dialogs/about-int.h b/src/gui/dialogs/about-int.h index 616c73f..96a470e 100644 --- a/src/gui/dialogs/about-int.h +++ b/src/gui/dialogs/about-int.h @@ -37,20 +37,6 @@ struct _GtkAppAboutDialog { GtkWindow parent; /* A laisser en premier */ - union - { - struct - { - GtkPicture *revision_0; /* Numéro #0 */ - GtkPicture *revision_1; /* Numéro #1 */ - GtkPicture *revision_2; /* Numéro #2 */ - GtkPicture *revision_3; /* Numéro #3 */ - GtkPicture *revision_4; /* Numéro #4 */ - GtkPicture *revision_5; /* Numéro #5 */ - }; - GtkPicture *revisions[6]; /* Tous les numéros d'un coup */ - }; - }; /* Boîte "A propos de" dédiée à l'application (classe) */ diff --git a/src/gui/dialogs/about.c b/src/gui/dialogs/about.c index 956918b..1dca752 100644 --- a/src/gui/dialogs/about.c +++ b/src/gui/dialogs/about.c @@ -44,10 +44,10 @@ static void gtk_app_about_dialog_class_init(GtkAppAboutDialogClass *); static void gtk_app_about_dialog_init(GtkAppAboutDialog *); /* Supprime toutes les références externes. */ -static void gtk_app_about_dialog_dispose(GtkAppAboutDialog *); +static void gtk_app_about_dialog_dispose(GObject *); /* Procède à la libération totale de la mémoire. */ -static void gtk_app_about_dialog_finalize(GtkAppAboutDialog *); +static void gtk_app_about_dialog_finalize(GObject *); @@ -74,22 +74,17 @@ static void gtk_app_about_dialog_class_init(GtkAppAboutDialogClass *class) object = G_OBJECT_CLASS(class); - object->dispose = (GObjectFinalizeFunc/* ! */)gtk_app_about_dialog_dispose; - object->finalize = (GObjectFinalizeFunc)gtk_app_about_dialog_finalize; + object->dispose = gtk_app_about_dialog_dispose; + object->finalize = gtk_app_about_dialog_finalize; widget = GTK_WIDGET_CLASS(class); + gtk_widget_class_set_css_name(widget, "aboutdialog"); + gtk_widget_class_add_binding_action(widget, GDK_KEY_Escape, 0, "window.close", NULL); gtk_widget_class_set_template_from_resource(widget, "/re/chrysalide/framework/gui/dialogs/about.ui"); - gtk_widget_class_bind_template_child(widget, GtkAppAboutDialog, revision_0); - gtk_widget_class_bind_template_child(widget, GtkAppAboutDialog, revision_1); - gtk_widget_class_bind_template_child(widget, GtkAppAboutDialog, revision_2); - gtk_widget_class_bind_template_child(widget, GtkAppAboutDialog, revision_3); - gtk_widget_class_bind_template_child(widget, GtkAppAboutDialog, revision_4); - gtk_widget_class_bind_template_child(widget, GtkAppAboutDialog, revision_5); - } @@ -107,40 +102,14 @@ static void gtk_app_about_dialog_class_init(GtkAppAboutDialogClass *class) static void gtk_app_about_dialog_init(GtkAppAboutDialog *dialog) { - unsigned int revision; /* Numéro de révision */ - unsigned int max; /* Nbre. de boucles à effectuer*/ - unsigned int i; /* Boucle de parcours */ - unsigned int level; /* Unité la plus importante */ - char buffer[64]; /* Nom d'image à forger */ - gtk_widget_init_template(GTK_WIDGET(dialog)); - revision = REVISION; - max = log(revision) / log(10); - - assert(max <= 6); - - for (i = 0; i <= max; i++) - { - level = pow(10, max - i); - - snprintf(buffer, 64, "/org/chrysalide/gui/dialogs/about/revision_%u.png", revision / level); - - gtk_picture_set_resource(dialog->revisions[i], buffer); - - revision %= level; - - } - - for (; i < 6; i++) - gtk_widget_set_visible(GTK_WIDGET(dialog->revisions[i]), FALSE); - } /****************************************************************************** * * -* Paramètres : dialog = instance d'objet GLib à traiter. * +* Paramètres : object = instance d'objet GLib à traiter. * * * * Description : Supprime toutes les références externes. * * * @@ -150,18 +119,18 @@ static void gtk_app_about_dialog_init(GtkAppAboutDialog *dialog) * * ******************************************************************************/ -static void gtk_app_about_dialog_dispose(GtkAppAboutDialog *dialog) +static void gtk_app_about_dialog_dispose(GObject *object) { - gtk_widget_dispose_template(GTK_WIDGET(dialog), GTK_TYPE_APP_ABOUT_DIALOG); + gtk_widget_dispose_template(GTK_WIDGET(object), GTK_TYPE_APP_ABOUT_DIALOG); - G_OBJECT_CLASS(gtk_app_about_dialog_parent_class)->dispose(G_OBJECT(dialog)); + G_OBJECT_CLASS(gtk_app_about_dialog_parent_class)->dispose(object); } /****************************************************************************** * * -* Paramètres : dialog = instance d'objet GLib à traiter. * +* Paramètres : object = instance d'objet GLib à traiter. * * * * Description : Procède à la libération totale de la mémoire. * * * @@ -171,9 +140,9 @@ static void gtk_app_about_dialog_dispose(GtkAppAboutDialog *dialog) * * ******************************************************************************/ -static void gtk_app_about_dialog_finalize(GtkAppAboutDialog *dialog) +static void gtk_app_about_dialog_finalize(GObject *object) { - G_OBJECT_CLASS(gtk_app_about_dialog_parent_class)->finalize(G_OBJECT(dialog)); + G_OBJECT_CLASS(gtk_app_about_dialog_parent_class)->finalize(object); } diff --git a/src/gui/dialogs/about.css b/src/gui/dialogs/about.css new file mode 100644 index 0000000..af3fa97 --- /dev/null +++ b/src/gui/dialogs/about.css @@ -0,0 +1,9 @@ + +aboutdialog > box { + + background-color: black; + + background-image: url('resource:///re/chrysalide/framework/gui/dialogs/about/bg.png'); + background-repeat: no-repeat; + +} diff --git a/src/gui/dialogs/about.ui b/src/gui/dialogs/about.ui index 989e53b..7b519d2 100644 --- a/src/gui/dialogs/about.ui +++ b/src/gui/dialogs/about.ui @@ -8,91 +8,13 @@ <property name="modal">true</property> <property name="resizable">false</property> - <style> - <class name="black-bg"/> - </style> - <child> <object class="GtkBox"> <property name="orientation">vertical</property> - <child> - <object class="GtkPicture" id="logo"> - <property name="margin-top">10</property> - <property name="file">resource://org/chrysalide/gui/dialogs/about/chrysalide-full.png</property> - </object> - </child> - - <!-- - Etage intermédiaire pour ne pas que l'image se voie allouer la largeur entière - de la fenêtre. Sinon des marges sont placées autour du rendu lors que l'image - n'est pas étendue pour couvrir cette largeur entière. - --> - <child> - <object class="GtkBox"> - <property name="orientation">horizontal</property> - <property name="halign">center</property> - <property name="margin-top">14</property> - <child> - <object class="GtkPicture" id="text"> - <property name="width-request">253</property> - <property name="file">resource:///org/chrysalide/gui/dialogs/about/chrysalide_text.png</property> - </object> - </child> - </object> - </child> - - <child> - <object class="GtkBox"> - <property name="orientation">horizontal</property> - <property name="margin-start">149</property> - <child> - <object class="GtkPicture" id="revision"> - <property name="width-request">14</property> - <property name="file">resource:///org/chrysalide/gui/dialogs/about/revision.png</property> - </object> - </child> - <child> - <object class="GtkPicture" id="revision_0"> - <property name="width-request">14</property> - <property name="file">resource:///org/chrysalide/gui/dialogs/about/revision.png</property> - </object> - </child> - <child> - <object class="GtkPicture" id="revision_1"> - <property name="width-request">14</property> - <property name="file">resource:///org/chrysalide/gui/dialogs/about/revision.png</property> - </object> - </child> - <child> - <object class="GtkPicture" id="revision_2"> - <property name="width-request">14</property> - <property name="file">resource:///org/chrysalide/gui/dialogs/about/revision.png</property> - </object> - </child> - <child> - <object class="GtkPicture" id="revision_3"> - <property name="width-request">14</property> - <property name="file">resource:///org/chrysalide/gui/dialogs/about/revision.png</property> - </object> - </child> - <child> - <object class="GtkPicture" id="revision_4"> - <property name="width-request">14</property> - <property name="file">resource:///org/chrysalide/gui/dialogs/about/revision.png</property> - </object> - </child> - <child> - <object class="GtkPicture" id="revision_5"> - <property name="width-request">14</property> - <property name="file">resource:///org/chrysalide/gui/dialogs/about/revision.png</property> - </object> - </child> - </object> - </child> <child> <object class="GtkLabel"> - <property name="margin-top">22</property> + <property name="margin-top">368</property> <property name="margin-bottom">10</property> <property name="label" translatable="yes"><span fgcolor='white'>Copyright (C) 2008-2025 Cyrille Bagard</span></property> <property name="use-markup">True</property> diff --git a/src/gui/dialogs/gresource.xml b/src/gui/dialogs/gresource.xml index 169f440..966d9c8 100644 --- a/src/gui/dialogs/gresource.xml +++ b/src/gui/dialogs/gresource.xml @@ -1,22 +1,8 @@ <?xml version="1.0" encoding="UTF-8"?> <gresources> <gresource prefix="/re/chrysalide/framework/gui/dialogs"> + <file compressed="true">about.css</file> <file compressed="true">about.ui</file> <file compressed="true">preferences.ui</file> </gresource> - <gresource prefix="/org/chrysalide/gui/dialogs/about"> - <file compressed="true" alias="chrysalide-full.png">../../../pixmaps/chrysalide-full.png</file> - <file compressed="true" alias="chrysalide_text.png">../../../pixmaps/chrysalide_text.png</file> - <file compressed="true" alias="revision.png">../../../pixmaps/revision.png</file> - <file compressed="true" alias="revision_0.png">../../../pixmaps/revision_0.png</file> - <file compressed="true" alias="revision_1.png">../../../pixmaps/revision_1.png</file> - <file compressed="true" alias="revision_2.png">../../../pixmaps/revision_2.png</file> - <file compressed="true" alias="revision_3.png">../../../pixmaps/revision_3.png</file> - <file compressed="true" alias="revision_4.png">../../../pixmaps/revision_4.png</file> - <file compressed="true" alias="revision_5.png">../../../pixmaps/revision_5.png</file> - <file compressed="true" alias="revision_6.png">../../../pixmaps/revision_6.png</file> - <file compressed="true" alias="revision_7.png">../../../pixmaps/revision_7.png</file> - <file compressed="true" alias="revision_8.png">../../../pixmaps/revision_8.png</file> - <file compressed="true" alias="revision_9.png">../../../pixmaps/revision_9.png</file> - </gresource> </gresources> diff --git a/src/gui/dialogs/preferences.c b/src/gui/dialogs/preferences.c index 68e7fd9..0369241 100644 --- a/src/gui/dialogs/preferences.c +++ b/src/gui/dialogs/preferences.c @@ -34,6 +34,7 @@ #include "preferences-int.h" +#include "prefs/appearance.h" #include "prefs/security.h" #include "../../common/cpp.h" #include "../../gtkext/tweak.h" @@ -140,6 +141,8 @@ static void gtk_preferences_dialog_init(GtkPreferencesDialog *dialog) tweak_info_t infos[] = { TWEAK_SIMPLE_DEF("root", "Basics", + "security-high-symbolic", "appearance", "Appearance", GTK_TYPE_APPEARANCE_TWEAK_PANEL), + TWEAK_SIMPLE_DEF("root", "Basics", "security-high-symbolic", "security", "Security", GTK_TYPE_SECURITY_TWEAK_PANEL), }; diff --git a/src/gui/dialogs/prefs/Makefile.am b/src/gui/dialogs/prefs/Makefile.am index fa1af96..50bc3c8 100644 --- a/src/gui/dialogs/prefs/Makefile.am +++ b/src/gui/dialogs/prefs/Makefile.am @@ -4,9 +4,12 @@ BUILT_SOURCES = resources.h resources.c noinst_LTLIBRARIES = libguidialogsprefs.la UI_FILES = \ + appearance.ui \ security.ui libguidialogsprefs_la_SOURCES = \ + appearance-int.h \ + appearance.h appearance.c \ resources.h resources.c \ security-int.h \ security.h security.c diff --git a/src/gui/dialogs/prefs/appearance-int.h b/src/gui/dialogs/prefs/appearance-int.h new file mode 100644 index 0000000..886a562 --- /dev/null +++ b/src/gui/dialogs/prefs/appearance-int.h @@ -0,0 +1,64 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * appearance-int.h - définitions internes pour la configuration des paramètres liés aux apparences + * + * Copyright (C) 2025 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Chrysalide. If not, see <http://www.gnu.org/licenses/>. + */ + + +#ifndef _GUI_DIALOGS_PREFS_APPEARANCE_INT_H +#define _GUI_DIALOGS_PREFS_APPEARANCE_INT_H + + +#include "appearance.h" + + + +/* Composant d'édition des paramètres liés aux apparences (instance) */ +struct _GtkAppearanceTweakPanel +{ + GtkBox parent; /* A laisser en premier */ + + /* Disposition des panneaux */ + + GSettings *tiles_settings; /* Configuration sollicitée */ + + GtkWidget *layout_preview; /* Zone d'aperçu de dispositon*/ + + GtkWidget *top_panel; /* Composant d'aperçu #1 */ + GtkWidget *left_panel; /* Composant d'aperçu #2 */ + GtkWidget *right_panel; /* Composant d'aperçu #3 */ + GtkWidget *bottom_panel; /* Composant d'aperçu #4 */ + + GtkCheckButton *left_top_reach; /* Paramètre de disposition #1 */ + GtkCheckButton *left_bottom_reach; /* Paramètre de disposition #2 */ + GtkCheckButton *right_top_reach; /* Paramètre de disposition #3 */ + GtkCheckButton *right_bottom_reach; /* Paramètre de disposition #4 */ + +}; + +/* Composant d'édition des paramètres liés aux apparences (classe) */ +struct _GtkAppearanceTweakPanelClass +{ + GtkBoxClass parent; /* A laisser en premier */ + +}; + + + +#endif /* _GUI_DIALOGS_PREFS_APPEARANCE_INT_H */ diff --git a/src/gui/dialogs/prefs/appearance.c b/src/gui/dialogs/prefs/appearance.c new file mode 100644 index 0000000..a8585fa --- /dev/null +++ b/src/gui/dialogs/prefs/appearance.c @@ -0,0 +1,251 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * appearance.c - configuration des paramètres liés aux apparences + * + * Copyright (C) 2025 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Chrysalide. If not, see <http://www.gnu.org/licenses/>. + */ + + +#include "appearance.h" + + +#include "appearance-int.h" +#include "../../../gtkext/grid.h" +#include "../../../gtkext/helpers.h" + + + +/* Procède à l'initialisation de classe des configurations. */ +static void gtk_appearance_tweak_panel_class_init(GtkAppearanceTweakPanelClass *); + +/* Procède à l'initialisation des configurations de sécurité. */ +static void gtk_appearance_tweak_panel_init(GtkAppearanceTweakPanel *); + +/* Supprime toutes les références externes. */ +static void gtk_appearance_tweak_panel_dispose(GObject *); + +/* Procède à la libération totale de la mémoire. */ +static void gtk_appearance_tweak_panel_finalize(GObject *); + +/* Réagit à un changement de paramètre de configuration. */ +static void gtk_appearance_tweak_panel_on_tiles_settings_changed(GSettings *, const gchar *, GtkAppearanceTweakPanel *); + +/* Change la disposition des panneaux de la fenêtre principale. */ +static void gtk_appearance_tweak_panel_on_panel_reach_toggled(GtkCheckButton *, GtkAppearanceTweakPanel *); + + +/* Indique le type du composant de configuration des notes. */ +G_DEFINE_TYPE(GtkAppearanceTweakPanel, gtk_appearance_tweak_panel, GTK_TYPE_BOX); + + +/****************************************************************************** +* * +* Paramètres : class = classe GTK à initialiser. * +* * +* Description : Procède à l'initialisation de classe des configurations. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void gtk_appearance_tweak_panel_class_init(GtkAppearanceTweakPanelClass *class) +{ + GObjectClass *object; /* Plus haut niveau équivalent */ + GtkWidgetClass *widget; /* Classe de haut niveau */ + + object = G_OBJECT_CLASS(class); + + object->dispose = gtk_appearance_tweak_panel_dispose; + object->finalize = gtk_appearance_tweak_panel_finalize; + + widget = GTK_WIDGET_CLASS(class); + + gtk_widget_class_set_template_from_resource(widget, "/re/chrysalide/framework/gui/dialogs/prefs/appearance.ui"); + + gtk_widget_class_bind_template_callback_full(widget, BUILDER_CB(gtk_appearance_tweak_panel_on_panel_reach_toggled)); + + gtk_widget_class_bind_template_child(widget, GtkAppearanceTweakPanel, layout_preview); + + gtk_widget_class_bind_template_child(widget, GtkAppearanceTweakPanel, top_panel); + gtk_widget_class_bind_template_child(widget, GtkAppearanceTweakPanel, left_panel); + gtk_widget_class_bind_template_child(widget, GtkAppearanceTweakPanel, right_panel); + gtk_widget_class_bind_template_child(widget, GtkAppearanceTweakPanel, bottom_panel); + + gtk_widget_class_bind_template_child(widget, GtkAppearanceTweakPanel, left_top_reach); + gtk_widget_class_bind_template_child(widget, GtkAppearanceTweakPanel, left_bottom_reach); + gtk_widget_class_bind_template_child(widget, GtkAppearanceTweakPanel, right_top_reach); + gtk_widget_class_bind_template_child(widget, GtkAppearanceTweakPanel, right_bottom_reach); + +} + + +/****************************************************************************** +* * +* Paramètres : panel = composant GTK à initialiser. * +* * +* Description : Procède à l'initialisation des configurations de sécurité. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void gtk_appearance_tweak_panel_init(GtkAppearanceTweakPanel *panel) +{ + LayoutReachOptions options; /* Détails de disposition */ + + gtk_widget_init_template(GTK_WIDGET(panel)); + + panel->tiles_settings = g_settings_new_with_path("re.chrysalide.framework.tiledgrid", + "/re/chrysalide/framework/gui/tiles/"); + + options = g_settings_get_flags(panel->tiles_settings, "layout"); + + gtk_check_button_set_active(panel->left_top_reach, options & LRO_LEFT_TOP_REACH); + gtk_check_button_set_active(panel->left_bottom_reach, options & LRO_LEFT_BOTTOM_REACH); + gtk_check_button_set_active(panel->right_top_reach, options & LRO_RIGHT_TOP_REACH); + gtk_check_button_set_active(panel->right_bottom_reach, options & LRO_RIGHT_BOTTOM_REACH); + + gtk_appearance_tweak_panel_on_tiles_settings_changed(panel->tiles_settings, "layout", panel); + + g_signal_connect(panel->tiles_settings, "changed", + G_CALLBACK(gtk_appearance_tweak_panel_on_tiles_settings_changed), panel); + +} + + +/****************************************************************************** +* * +* Paramètres : object = instance d'objet GLib à traiter. * +* * +* Description : Supprime toutes les références externes. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void gtk_appearance_tweak_panel_dispose(GObject *object) +{ + GtkAppearanceTweakPanel *panel; /* Version spécialisée */ + + gtk_widget_dispose_template(GTK_WIDGET(object), GTK_TYPE_APPEARANCE_TWEAK_PANEL); + + panel = GTK_APPEARANCE_TWEAK_PANEL(object); + + g_clear_object(&panel->tiles_settings); + + G_OBJECT_CLASS(gtk_appearance_tweak_panel_parent_class)->dispose(object); + +} + + +/****************************************************************************** +* * +* Paramètres : object = instance d'objet GLib à traiter. * +* * +* Description : Procède à la libération totale de la mémoire. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void gtk_appearance_tweak_panel_finalize(GObject *object) +{ + G_OBJECT_CLASS(gtk_appearance_tweak_panel_parent_class)->finalize(object); + +} + + +/****************************************************************************** +* * +* Paramètres : settings = ensemble de paramètres connaissant une évolution. * +* key = identifiant du paramètre ayant changé. * +* panel = panneau de paramétrage concerné par l'appel. * +* * +* Description : Réagit à un changement de paramètre de configuration. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void gtk_appearance_tweak_panel_on_tiles_settings_changed(GSettings *settings, const gchar *key, GtkAppearanceTweakPanel *panel) +{ + LayoutReachOptions options; /* Détails de disposition */ + + if (strcmp(key, "layout") == 0) + { + options = g_settings_get_flags(panel->tiles_settings, "layout"); + + apply_tiling_grid_layout(GTK_GRID(panel->layout_preview), options, (GtkWidget *[]) { + panel->top_panel, panel->left_panel, panel->right_panel, panel->bottom_panel + }); + + } + +} + + +/****************************************************************************** +* * +* Paramètres : button = composant radio dont l'état vient de basculer. * +* panel = panneau d'édition des préférences courant. * +* * +* Description : Change la disposition des panneaux de la fenêtre principale. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void gtk_appearance_tweak_panel_on_panel_reach_toggled(GtkCheckButton *button, GtkAppearanceTweakPanel *panel) +{ + gboolean left_top_reach; /* Paramètre de disposition #1 */ + gboolean left_bottom_reach; /* Paramètre de disposition #2 */ + gboolean right_top_reach; /* Paramètre de disposition #3 */ + gboolean right_bottom_reach; /* Paramètre de disposition #4 */ + LayoutReachOptions options; /* Options à appliquer */ + + /* Récupération des indications */ + + left_top_reach = gtk_check_button_get_active(panel->left_top_reach); + left_bottom_reach = gtk_check_button_get_active(panel->left_bottom_reach); + right_top_reach = gtk_check_button_get_active(panel->right_top_reach); + right_bottom_reach = gtk_check_button_get_active(panel->right_bottom_reach); + + /* Conversion et application */ + + options = LRO_NONE; + + if (left_top_reach) options |= LRO_LEFT_TOP_REACH; + if (left_bottom_reach) options |= LRO_LEFT_BOTTOM_REACH; + if (right_top_reach) options |= LRO_RIGHT_TOP_REACH; + if (right_bottom_reach) options |= LRO_RIGHT_BOTTOM_REACH; + + g_settings_set_flags(panel->tiles_settings, "layout", options); + +} diff --git a/src/gui/dialogs/prefs/appearance.h b/src/gui/dialogs/prefs/appearance.h new file mode 100644 index 0000000..916b194 --- /dev/null +++ b/src/gui/dialogs/prefs/appearance.h @@ -0,0 +1,41 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * appearance.h - prototypes pour la configuration des paramètres liés aux apparences + * + * Copyright (C) 2025 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Chrysalide. If not, see <http://www.gnu.org/licenses/>. + */ + + +#ifndef _GUI_DIALOGS_PREFS_APPEARANCE_H +#define _GUI_DIALOGS_PREFS_APPEARANCE_H + + +#include <gtk/gtk.h> + + +#include "../../../glibext/helpers.h" + + + +#define GTK_TYPE_APPEARANCE_TWEAK_PANEL (gtk_appearance_tweak_panel_get_type()) + +DECLARE_GTYPE(GtkAppearanceTweakPanel, gtk_appearance_tweak_panel, GTK, APPEARANCE_TWEAK_PANEL); + + + +#endif /* _GUI_DIALOGS_PREFS_APPEARANCE_H */ diff --git a/src/gui/dialogs/prefs/appearance.ui b/src/gui/dialogs/prefs/appearance.ui new file mode 100644 index 0000000..3410115 --- /dev/null +++ b/src/gui/dialogs/prefs/appearance.ui @@ -0,0 +1,184 @@ +<?xml version="1.0" encoding="UTF-8"?> +<interface> + + <template class="GtkAppearanceTweakPanel" parent="GtkBox"> + + <property name="orientation">vertical</property> + <property name="margin-start">20</property> + <property name="margin-end">20</property> + <property name="margin-top">20</property> + <property name="margin-bottom">20</property> + <property name="spacing">10</property> + + <!-- Disposition des panneaux --> + + <child> + <object class="GtkLabel"> + <property name="label">Layout</property> + <property name="use-markup">true</property> + <property name="xalign">0</property> + <style> + <class name="heading"/> + </style> + </object> + </child> + + <child> + <object class="GtkLabel"> + <property name="label">Layout defines the global panel organization of the main window.</property> + <property name="wrap">true</property> + <property name="use-markup">true</property> + <property name="xalign">0</property> + <style> + <class name="dim-label"/> + </style> + </object> + </child> + + + <child> + <object class="GtkBox"> + <property name="orientation">horizontal</property> + + <!-- Aperçu --> + + <child> + <object class="GtkGrid" id="layout_preview"> + <property name="margin-start">20</property> + <property name="margin-end">20</property> + <property name="margin-top">10</property> + <property name="margin-bottom">10</property> + <property name="row-spacing">5</property> + <property name="column-spacing">5</property> + <property name="hexpand">false</property> + <property name="vexpand">false</property> + <property name="height-request">200</property> + <property name="width-request">300</property> + + <child> + <object class="GtkFrame" id="top_panel"> + <property name="hexpand">true</property> + <property name="vexpand">false</property> + <property name="height-request">20</property> + <layout> + <property name="column">0</property> + <property name="row">0</property> + <property name="column-span">3</property> + </layout> + <style> + <class name="view"/> + </style> + </object> + </child> + + <child> + <object class="GtkFrame" id="left_panel"> + <property name="hexpand">false</property> + <property name="vexpand">true</property> + <property name="width-request">50</property> + <layout> + <property name="column">0</property> + <property name="row">1</property> + </layout> + <style> + <class name="view"/> + </style> + </object> + </child> + + <child> + <object class="GtkFrame"> + <property name="hexpand">true</property> + <property name="vexpand">true</property> + <layout> + <property name="column">1</property> + <property name="row">1</property> + </layout> + <style> + <class name="view"/> + </style> + </object> + </child> + + <child> + <object class="GtkFrame" id="right_panel"> + <property name="hexpand">false</property> + <property name="vexpand">true</property> + <property name="width-request">50</property> + <layout> + <property name="column">2</property> + <property name="row">1</property> + </layout> + <style> + <class name="view"/> + </style> + </object> + </child> + + <child> + <object class="GtkFrame" id="bottom_panel"> + <property name="hexpand">true</property> + <property name="vexpand">false</property> + <property name="height-request">50</property> + <layout> + <property name="column">0</property> + <property name="row">2</property> + <property name="column-span">3</property> + </layout> + <style> + <class name="view"/> + </style> + </object> + </child> + + </object> + </child> + + <!-- Options --> + + <child> + <object class="GtkBox"> + <property name="orientation">vertical</property> + <property name="valign">center</property> + <property name="spacing">10</property> + + <child> + <object class="GtkCheckButton" id="left_top_reach"> + <property name="label">Left panels reach the top of the window</property> + <property name="active">false</property> + <signal name="toggled" handler="gtk_appearance_tweak_panel_on_panel_reach_toggled"/> + </object> + </child> + + <child> + <object class="GtkCheckButton" id="left_bottom_reach"> + <property name="label">Left panels reach the bottom of the window</property> + <property name="active">false</property> + <signal name="toggled" handler="gtk_appearance_tweak_panel_on_panel_reach_toggled"/> + </object> + </child> + + <child> + <object class="GtkCheckButton" id="right_top_reach"> + <property name="label">Right panels reach the top of the window</property> + <property name="active">false</property> + <signal name="toggled" handler="gtk_appearance_tweak_panel_on_panel_reach_toggled"/> + </object> + </child> + + <child> + <object class="GtkCheckButton" id="right_bottom_reach"> + <property name="label">Right panels reach the bottom of the window</property> + <property name="active">false</property> + <signal name="toggled" handler="gtk_appearance_tweak_panel_on_panel_reach_toggled"/> + </object> + </child> + + </object> + </child> + + </object> + </child> + + </template> +</interface> diff --git a/src/gui/dialogs/prefs/gresource.xml b/src/gui/dialogs/prefs/gresource.xml index 7b18143..ad0f97f 100644 --- a/src/gui/dialogs/prefs/gresource.xml +++ b/src/gui/dialogs/prefs/gresource.xml @@ -1,6 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <gresources> <gresource prefix="/re/chrysalide/framework/gui/dialogs/prefs"> + <file compressed="true">appearance.ui</file> <file compressed="true">security.ui</file> </gresource> </gresources> diff --git a/src/gui/panels/Makefile.am b/src/gui/panels/Makefile.am index 2765405..ecff6c7 100644 --- a/src/gui/panels/Makefile.am +++ b/src/gui/panels/Makefile.am @@ -11,7 +11,6 @@ UI_FILES = \ errors.ui \ glance.ui \ history.ui \ - log.ui \ regedit.ui \ strings.ui \ symbols.ui @@ -22,7 +21,6 @@ libguipanels_la_SOURCES = \ errors.h errors.c \ glance.h glance.c \ history.h history.c \ - log.h log.c \ regedit.h regedit.c \ resources.h resources.c \ strings.h strings.c \ @@ -40,6 +38,9 @@ RES_FILES = \ binary.ui \ binary-params.ui \ $(IMG_PATH)/binfile-symbolic.svg \ + logs.ui \ + logs-col-icon.ui \ + logs-col-message.ui \ welcome.ui \ welcome-hints.txt \ $(IMG_PATH)/tipoftheday-symbolic.svg @@ -49,6 +50,8 @@ libguipanels4_la_SOURCES = \ binary.h binary.c \ binary-params-int.h \ binary-params.h binary-params.c \ + logs-int.h \ + logs.h logs.c \ resources.h resources.c \ welcome-int.h \ welcome.h welcome.c diff --git a/src/gui/panels/gresource.xml b/src/gui/panels/gresource.xml index f49a16f..2765b25 100644 --- a/src/gui/panels/gresource.xml +++ b/src/gui/panels/gresource.xml @@ -3,6 +3,9 @@ <gresource prefix="/re/chrysalide/framework/gui/panels"> <file compressed="true">binary.ui</file> <file compressed="true">binary-params.ui</file> + <file compressed="true">logs.ui</file> + <file compressed="true">logs-col-icon.ui</file> + <file compressed="true">logs-col-message.ui</file> <file compressed="true">welcome.ui</file> <file compressed="true">welcome-hints.txt</file> </gresource> diff --git a/src/gui/panels/log.c b/src/gui/panels/log.c deleted file mode 100644 index d11fbd2..0000000 --- a/src/gui/panels/log.c +++ /dev/null @@ -1,451 +0,0 @@ - -/* Chrysalide - Outil d'analyse de fichiers binaires - * log.c - panneau d'affichage des messages système - * - * Copyright (C) 2012-2019 Cyrille Bagard - * - * This file is part of Chrysalide. - * - * Chrysalide is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 3 of the License, or - * (at your option) any later version. - * - * Chrysalide is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - - -#include "log.h" - - -#include <malloc.h> -#include <stdarg.h> -#include <stdio.h> -#include <string.h> -#include <gtk/gtk.h> - - -#include "../panel-int.h" -#include "../core/panels.h" -#include "../../gtkext/easygtk.h" -#include "../../gtkext/named.h" - - - -/* Colonnes de la liste des messages */ -typedef enum _LogColumn -{ - LGC_PICTURE, /* Image de représentation */ - LGC_STRING, /* Chaîne de caractères */ - - LGC_COUNT /* Nombre de colonnes */ - -} LogColumn; - - -/* Paramètres à transmettre pour un affichage */ -typedef struct _log_data -{ - GPanelItem *item; /* Intermédiaire mis en place */ - LogMessageType type; /* Type de message à afficher */ - char *msg; /* Contenu du message */ - -} log_data; - - -/* Panneau d'accueil (instance) */ -struct _GLogPanel -{ - GPanelItem parent; /* A laisser en premier */ - -}; - - -/* Panneau d'accueil (classe) */ -struct _GLogPanelClass -{ - GPanelItemClass parent; /* A laisser en premier */ - -}; - - -/* Initialise la classe des panneaux d'affichage des messages. */ -static void g_log_panel_class_init(GLogPanelClass *); - -/* Initialise une instance de panneau d'affichage des messages. */ -static void g_log_panel_init(GLogPanel *); - -/* Supprime toutes les références externes. */ -static void g_log_panel_dispose(GLogPanel *); - -/* Procède à la libération totale de la mémoire. */ -static void g_log_panel_finalize(GLogPanel *); - -/* Fournit le nom interne attribué à l'élément réactif. */ -static char *g_log_panel_class_get_key(const GLogPanelClass *); - -/* Fournit une indication sur la personnalité du panneau. */ -static PanelItemPersonality g_log_panel_class_get_personality(const GLogPanelClass *); - -/* Indique le chemin initial de la localisation d'un panneau. */ -static char *g_log_panel_class_get_path(const GLogPanelClass *); - -/* Indique la définition d'un éventuel raccourci clavier. */ -static char *g_log_panel_class_get_key_bindings(const GLogPanelClass *); - -/* Affiche un message dans le journal des messages système. */ -static gboolean log_message(log_data *); - - - -/* Indique le type défini pour un panneau d'affichage de messages. */ -G_DEFINE_TYPE(GLogPanel, g_log_panel, G_TYPE_PANEL_ITEM); - - -/****************************************************************************** -* * -* Paramètres : class = classe à initialiser. * -* * -* Description : Initialise la classe des panneaux d'affichage des messages. * -* * -* Retour : - * -* * -* Remarques : - * -* * -******************************************************************************/ - -static void g_log_panel_class_init(GLogPanelClass *class) -{ - GObjectClass *object; /* Autre version de la classe */ - GEditorItemClass *item; /* Encore une autre vision... */ - GPanelItemClass *panel; /* Version parente de la classe*/ - - object = G_OBJECT_CLASS(class); - - object->dispose = (GObjectFinalizeFunc/* ! */)g_log_panel_dispose; - object->finalize = (GObjectFinalizeFunc)g_log_panel_finalize; - - item = G_EDITOR_ITEM_CLASS(class); - - item->get_key = (get_item_key_fc)g_log_panel_class_get_key; - - panel = G_PANEL_ITEM_CLASS(class); - - panel->get_personality = (get_panel_personality_fc)g_log_panel_class_get_personality; - panel->get_path = (get_panel_path_fc)g_log_panel_class_get_path; - panel->get_bindings = (get_panel_bindings_fc)g_log_panel_class_get_key_bindings; - -} - - -/****************************************************************************** -* * -* Paramètres : panel = instance à initialiser. * -* * -* Description : Initialise une instance de panneau d'affichage des messages. * -* * -* Retour : - * -* * -* Remarques : - * -* * -******************************************************************************/ - -static void g_log_panel_init(GLogPanel *panel) -{ - GPanelItem *pitem; /* Version parente du panneau */ - - /* Eléments de base */ - - pitem = G_PANEL_ITEM(panel); - - pitem->widget = G_NAMED_WIDGET(gtk_built_named_widget_new_for_panel(_("Messages"), - _("Misc information"), - PANEL_LOG_ID)); - -} - - -/****************************************************************************** -* * -* Paramètres : panel = instance d'objet GLib à traiter. * -* * -* Description : Supprime toutes les références externes. * -* * -* Retour : - * -* * -* Remarques : - * -* * -******************************************************************************/ - -static void g_log_panel_dispose(GLogPanel *panel) -{ - G_OBJECT_CLASS(g_log_panel_parent_class)->dispose(G_OBJECT(panel)); - -} - - -/****************************************************************************** -* * -* Paramètres : panel = instance d'objet GLib à traiter. * -* * -* Description : Procède à la libération totale de la mémoire. * -* * -* Retour : - * -* * -* Remarques : - * -* * -******************************************************************************/ - -static void g_log_panel_finalize(GLogPanel *panel) -{ - G_OBJECT_CLASS(g_log_panel_parent_class)->finalize(G_OBJECT(panel)); - -} - - -/****************************************************************************** -* * -* Paramètres : class = classe à consulter. * -* * -* Description : Fournit le nom interne attribué à l'élément réactif. * -* * -* Retour : Désignation (courte) de l'élément de l'éditeur. * -* * -* Remarques : - * -* * -******************************************************************************/ - -static char *g_log_panel_class_get_key(const GLogPanelClass *class) -{ - char *result; /* Description à renvoyer */ - - result = strdup(PANEL_LOG_ID); - - return result; - -} - - -/****************************************************************************** -* * -* Paramètres : class = classe à consulter. * -* * -* Description : Fournit une indication sur la personnalité du panneau. * -* * -* Retour : Identifiant lié à la nature unique du panneau. * -* * -* Remarques : - * -* * -******************************************************************************/ - -static PanelItemPersonality g_log_panel_class_get_personality(const GLogPanelClass *class) -{ - PanelItemPersonality result; /* Personnalité à retourner */ - - result = PIP_PERSISTENT_SINGLETON; - - return result; - -} - - -/****************************************************************************** -* * -* Paramètres : class = classe à consulter. * -* * -* Description : Indique le chemin initial de la localisation d'un panneau. * -* * -* Retour : Chemin fixé associé à la position initiale. * -* * -* Remarques : - * -* * -******************************************************************************/ - -static char *g_log_panel_class_get_path(const GLogPanelClass *class) -{ - char *result; /* Emplacement à retourner */ - - result = strdup("Ms"); - - return result; - -} - - -/****************************************************************************** -* * -* Paramètres : class = classe à consulter. * -* * -* Description : Indique la définition d'un éventuel raccourci clavier. * -* * -* Retour : Description d'un raccourci ou NULL si aucun de défini. * -* * -* Remarques : - * -* * -******************************************************************************/ - -static char *g_log_panel_class_get_key_bindings(const GLogPanelClass *class) -{ - char *result; /* Emplacement à retourner */ - - result = strdup("<Shift>F1"); - - return result; - -} - - -/****************************************************************************** -* * -* Paramètres : - * -* * -* Description : Crée un panneau d'affichage des messages système. * -* * -* Retour : Adresse de la structure mise en place. * -* * -* Remarques : - * -* * -******************************************************************************/ - -GPanelItem *g_log_panel_new(void) -{ - GPanelItem *result; /* Structure à retourner */ - - result = g_object_new(G_TYPE_LOG_PANEL, NULL); - - return result; - -} - - -/****************************************************************************** -* * -* Paramètres : panel = instance d'objet GLib à traiter. * -* type = espèce du message à ajouter. * -* msg = message à faire apparaître à l'écran. * -* * -* Description : Affiche un message dans le journal des messages système. * -* * -* Retour : - * -* * -* Remarques : - * -* * -******************************************************************************/ - -void g_log_panel_add_message(GLogPanel *panel, LogMessageType type, const char *msg) -{ - log_data *data; /* Paramètres à joindre */ - - data = calloc(1, sizeof(log_data)); - - data->item = G_PANEL_ITEM(panel); - data->type = type; - data->msg = strdup(msg); - - g_object_ref(G_OBJECT(data->item)); - - g_main_context_invoke(NULL, (GSourceFunc)log_message, data); - -} - - -/****************************************************************************** -* * -* Paramètres : data = paramètres destinés à l'affichage d'un message. * -* * -* Description : Affiche un message dans le journal des messages système. * -* * -* Retour : - * -* * -* Remarques : Cette fonction, et c'est tout son intérêt, est toujours * -* exécutée dans le contexte GTK principal. * -* * -******************************************************************************/ - -static gboolean log_message(log_data *data) -{ - GtkBuilder *builder; /* Constructeur utilisé */ - GtkListStore *store; /* Modèle de gestion */ - GtkTreeIter iter; /* Point d'insertion */ - GtkTreeView *treeview; /* Affichage de la liste */ - - builder = gtk_built_named_widget_get_builder(GTK_BUILT_NAMED_WIDGET(G_PANEL_ITEM(data->item)->widget)); - - /* Mise en place du message */ - - store = GTK_LIST_STORE(gtk_builder_get_object(builder, "store")); - - gtk_list_store_append(store, &iter); - - switch (data->type) - { - case LMT_INFO: - gtk_list_store_set(store, &iter, - LGC_PICTURE, "gtk-info", - LGC_STRING, data->msg, - -1); - break; - - case LMT_PROCESS: - gtk_list_store_set(store, &iter, - LGC_PICTURE, "gtk-execute", - LGC_STRING, data->msg, - -1); - break; - - case LMT_WARNING: - gtk_list_store_set(store, &iter, - LGC_PICTURE, "gtk-dialog-warning", - LGC_STRING, data->msg, - -1); - break; - - case LMT_BAD_BINARY: - gtk_list_store_set(store, &iter, - LGC_PICTURE, "gtk-dialog-warning", - LGC_STRING, data->msg, - -1); - break; - - case LMT_ERROR: - case LMT_EXT_ERROR: - gtk_list_store_set(store, &iter, - LGC_PICTURE, "gtk-dialog-error", - LGC_STRING, data->msg, - -1); - break; - - default: - gtk_list_store_set(store, &iter, - LGC_STRING, data->msg, - -1); - break; - - } - - /* Défilement pour pointer à l'affichage */ - - treeview = GTK_TREE_VIEW(gtk_builder_get_object(builder, "treeview")); - - scroll_to_treeview_iter(treeview, GTK_TREE_MODEL(store), &iter); - - g_object_unref(G_OBJECT(builder)); - - /* Nettoyage de la mémoire */ - - g_object_unref(G_OBJECT(data->item)); - - free(data->msg); - - free(data); - - return G_SOURCE_REMOVE; - -} diff --git a/src/gui/panels/log.h b/src/gui/panels/log.h deleted file mode 100644 index 4d155a2..0000000 --- a/src/gui/panels/log.h +++ /dev/null @@ -1,67 +0,0 @@ - -/* Chrysalide - Outil d'analyse de fichiers binaires - * log.h - prototypes pour le panneau d'affichage des messages système - * - * Copyright (C) 2012-2019 Cyrille Bagard - * - * This file is part of Chrysalide. - * - * Chrysalide is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 3 of the License, or - * (at your option) any later version. - * - * Chrysalide is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - - -#ifndef _GUI_PANELS_LOG_H -#define _GUI_PANELS_LOG_H - - -#include <i18n.h> - - -#include "../panel.h" -#include "../../core/logs.h" - - - -#define PANEL_LOG_ID "log" - - -#define G_TYPE_LOG_PANEL g_log_panel_get_type() -#define G_LOG_PANEL(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), g_log_panel_get_type(), GLogPanel)) -#define G_IS_LOG_PANEL(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), g_log_panel_get_type())) -#define G_LOG_PANEL_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_LOG_PANEL, GLogPanelClass)) -#define G_IS_LOG_PANEL_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_LOG_PANEL)) -#define G_LOG_PANEL_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_LOG_PANEL, GLogPanelClass)) - - -/* Panneau d'affichage de messages (instance) */ -typedef struct _GLogPanel GLogPanel; - -/* Panneau d'affichage de messages (classe) */ -typedef struct _GLogPanelClass GLogPanelClass; - - - -/* Indique le type défini pour un panneau d'affichage de messages. */ -GType g_log_panel_get_type(void); - -/* Crée un panneau d'affichage des messages système. */ -GPanelItem *g_log_panel_new(void); - -/* Affiche un message dans le journal des messages système. */ -void g_log_panel_add_message(GLogPanel *, LogMessageType, const char *); - - - -#endif /* _GUI_PANELS_LOG_H */ diff --git a/src/gui/panels/log.ui b/src/gui/panels/log.ui deleted file mode 100644 index 4ffe96c..0000000 --- a/src/gui/panels/log.ui +++ /dev/null @@ -1,59 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- Generated with glade 3.21.0 --> -<interface> - <requires lib="gtk+" version="3.20"/> - <object class="GtkListStore" id="store"> - <columns> - <!-- column-name picture --> - <column type="gchararray"/> - <!-- column-name string --> - <column type="gchararray"/> - </columns> - </object> - <object class="GtkOffscreenWindow"> - <property name="can_focus">False</property> - <child> - <object class="GtkScrolledWindow" id="box"> - <property name="visible">True</property> - <property name="can_focus">True</property> - <property name="shadow_type">in</property> - <child> - <object class="GtkTreeView" id="treeview"> - <property name="visible">True</property> - <property name="can_focus">True</property> - <property name="model">store</property> - <property name="headers_visible">False</property> - <child internal-child="selection"> - <object class="GtkTreeSelection"/> - </child> - <child> - <object class="GtkTreeViewColumn"> - <property name="title" translatable="yes">picture</property> - <child> - <object class="GtkCellRendererPixbuf"/> - <attributes> - <attribute name="stock-id">0</attribute> - </attributes> - </child> - </object> - </child> - <child> - <object class="GtkTreeViewColumn"> - <property name="title" translatable="yes">string</property> - <child> - <object class="GtkCellRendererText"/> - <attributes> - <attribute name="markup">1</attribute> - </attributes> - </child> - </object> - </child> - </object> - </child> - </object> - </child> - <child type="titlebar"> - <placeholder/> - </child> - </object> -</interface> diff --git a/src/gui/panels/logs-col-icon.ui b/src/gui/panels/logs-col-icon.ui new file mode 100644 index 0000000..6463e84 --- /dev/null +++ b/src/gui/panels/logs-col-icon.ui @@ -0,0 +1,17 @@ +<?xml version="1.0" encoding="UTF-8"?> +<interface> + + <template class="GtkListItem"> + <property name="child"> + <object class="GtkImage"> + <binding name="icon-name"> + <lookup name="icon-name" type="GLogEntry"> + <lookup name="item">GtkListItem</lookup> + </lookup> + </binding> + </object> + </property> + + </template> + +</interface> diff --git a/src/gui/panels/logs-col-message.ui b/src/gui/panels/logs-col-message.ui new file mode 100644 index 0000000..49839e4 --- /dev/null +++ b/src/gui/panels/logs-col-message.ui @@ -0,0 +1,19 @@ +<?xml version="1.0" encoding="UTF-8"?> +<interface> + + <template class="GtkListItem"> + <property name="child"> + <object class="GtkLabel"> + <property name="xalign">0</property> + <property name="use-markup">true</property> + <binding name="label"> + <lookup name="message" type="GLogEntry"> + <lookup name="item">GtkListItem</lookup> + </lookup> + </binding> + </object> + </property> + + </template> + +</interface> diff --git a/src/gui/panels/logs-int.h b/src/gui/panels/logs-int.h new file mode 100644 index 0000000..692c1b4 --- /dev/null +++ b/src/gui/panels/logs-int.h @@ -0,0 +1,53 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * logs-int.h - prototypes internes pour le panneau d'affichage des messages système + * + * Copyright (C) 2025 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +#ifndef _GUI_PANELS_LOGS_INT_H +#define _GUI_PANELS_LOGS_INT_H + + +#include "logs.h" +#include "../../gtkext/panel-int.h" + + + +/* Panneau d'affichage de messages (instance) */ +struct _GtkLogsPanel +{ + GtkTiledPanel parent; /* A laisser en premier */ + + GListStore *store; /* Liste des eléments conservés*/ + GtkWidget *list; /* Composant d'affichage */ + +}; + +/* Panneau d'affichage de messages (classe) */ +struct _GtkLogsPanelClass +{ + GtkTiledPanelClass parent; /* A laisser en premier */ + +}; + + + +#endif /* _GUI_PANELS_LOGS_INT_H */ diff --git a/src/gui/panels/logs.c b/src/gui/panels/logs.c new file mode 100644 index 0000000..399c4c0 --- /dev/null +++ b/src/gui/panels/logs.c @@ -0,0 +1,227 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * logs.c - panneau d'affichage des messages système + * + * Copyright (C) 2012-2025 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +#include "logs.h" + + +#include <assert.h> +#include <string.h> + + +#include "logs-int.h" +#include "../../gtkext/helpers.h" + + + +/* ------------------------- COEUR D'UN PANNEAU D'AFFICHAGE ------------------------- */ + + +/* Initialise la classe des panneaux d'affichage des journaux. */ +static void gtk_logs_panel_class_init(GtkLogsPanelClass *); + +/* Initialise une instance de panneau d'affichage des journaux. */ +static void gtk_logs_panel_init(GtkLogsPanel *); + +/* Supprime toutes les références externes. */ +static void gtk_logs_panel_dispose(GObject *); + +/* Procède à la libération totale de la mémoire. */ +static void gtk_logs_panel_finalize(GObject *); + + + +/* --------------------- IMPLEMENTATION DES FONCTIONS DE CLASSE --------------------- */ + + +/* Indique l'emplacement par défaut pour un affichage. */ +static char *gtk_logs_panel_get_default_path(const GtkTiledPanel *); + + + +/* ---------------------------------------------------------------------------------- */ +/* COEUR D'UN PANNEAU D'AFFICHAGE */ +/* ---------------------------------------------------------------------------------- */ + + +/* Indique le type défini pour un panneau d'accueil. */ +G_DEFINE_TYPE(GtkLogsPanel, gtk_logs_panel, GTK_TYPE_TILED_PANEL); + + +/****************************************************************************** +* * +* Paramètres : class = classe à initialiser. * +* * +* Description : Initialise la classe des panneaux d'affichage des journaux. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void gtk_logs_panel_class_init(GtkLogsPanelClass *class) +{ + GObjectClass *object; /* Autre version de la classe */ + GtkWidgetClass *widget; /* Classe de haut niveau */ + GtkTiledPanelClass *panel; /* Classe parente */ + + object = G_OBJECT_CLASS(class); + + object->dispose = gtk_logs_panel_dispose; + object->finalize = gtk_logs_panel_finalize; + + widget = GTK_WIDGET_CLASS(class); + + g_type_ensure(G_TYPE_LOG_ENTRY); + + gtk_widget_class_set_template_from_resource(widget, "/re/chrysalide/framework/gui/panels/logs.ui"); + + //gtk_widget_class_bind_template_callback_full(widget, BUILDER_CB(gtk_logs_panel_on_selected_rows_changed)); + + gtk_widget_class_bind_template_child(widget, GtkLogsPanel, store); + gtk_widget_class_bind_template_child(widget, GtkLogsPanel, list); + + panel = GTK_TILED_PANEL_CLASS(class); + + panel->get_default_path = gtk_logs_panel_get_default_path; + +} + + +/****************************************************************************** +* * +* Paramètres : panel = instance à initialiser. * +* * +* Description : Initialise une instance de panneau d'affichage des journaux. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void gtk_logs_panel_init(GtkLogsPanel *panel) +{ + GtkWidget *headers; /* Composant à cacher */ + + gtk_widget_init_template(GTK_WIDGET(panel)); + + /** + * Retrait des entêtes de colonne de l'affichage. + */ + + headers = gtk_widget_get_first_child(panel->list); + + gtk_widget_set_visible(headers, FALSE); + +} + + +/****************************************************************************** +* * +* Paramètres : object = instance d'objet GLib à traiter. * +* * +* Description : Supprime toutes les références externes. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void gtk_logs_panel_dispose(GObject *object) +{ + gtk_widget_dispose_template(GTK_WIDGET(object), GTK_TYPE_LOGS_PANEL); + + G_OBJECT_CLASS(gtk_logs_panel_parent_class)->dispose(object); + +} + + +/****************************************************************************** +* * +* Paramètres : object = instance d'objet GLib à traiter. * +* * +* Description : Procède à la libération totale de la mémoire. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void gtk_logs_panel_finalize(GObject *object) +{ + G_OBJECT_CLASS(gtk_logs_panel_parent_class)->finalize(object); + +} + + +/****************************************************************************** +* * +* Paramètres : panel = instance d'objet GLib à traiter. * +* entry = élément de journalisation à intégrer. * +* * +* Description : Affiche un message dans le journal des messages système. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +void g_log_panel_add_message(GtkLogsPanel *panel, GLogEntry *entry) +{ + g_list_store_append(panel->store, entry); + +} + + + +/* ---------------------------------------------------------------------------------- */ +/* IMPLEMENTATION DES FONCTIONS DE CLASSE */ +/* ---------------------------------------------------------------------------------- */ + + +/****************************************************************************** +* * +* Paramètres : panel = panneau graphique à consulter. * +* * +* Description : Indique l'emplacement par défaut pour un affichage. * +* * +* Retour : Chemin représenté ou NULL pour l'emplacement "M" par défaut. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static char *gtk_logs_panel_get_default_path(const GtkTiledPanel *panel) +{ + char *result; /* Chemin à retourner */ + + result = strdup("S"); + + return result; + +} diff --git a/src/gui/panels/logs.h b/src/gui/panels/logs.h new file mode 100644 index 0000000..a8b902b --- /dev/null +++ b/src/gui/panels/logs.h @@ -0,0 +1,47 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * logs.h - prototypes pour le panneau d'affichage des messages système + * + * Copyright (C) 2012-2025 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +#ifndef _GUI_PANELS_LOGS_H +#define _GUI_PANELS_LOGS_H + + +#include <gtk/gtk.h> + + +#include "../../glibext/helpers.h" +#include "../../glibext/log.h" + + + +#define GTK_TYPE_LOGS_PANEL (gtk_logs_panel_get_type()) + +DECLARE_GTYPE(GtkLogsPanel, gtk_logs_panel, GTK, LOGS_PANEL); + + +/* Affiche un message dans le journal des messages système. */ +void g_log_panel_add_message(GtkLogsPanel *, GLogEntry *); + + + +#endif /* _GUI_PANELS_LOGS_H */ diff --git a/src/gui/panels/logs.ui b/src/gui/panels/logs.ui new file mode 100644 index 0000000..ba920cd --- /dev/null +++ b/src/gui/panels/logs.ui @@ -0,0 +1,58 @@ +<?xml version="1.0" encoding="UTF-8"?> +<interface> + + <object class="GtkNoSelection" id="noselection"> + <property name="model"> + <object class="GListStore" id="store"> + <property name="item-type">GLogEntry</property> + </object> + </property> + </object> + + <template class="GtkLogsPanel" parent="GtkTiledPanel"> + + <child> + <object class="GtkScrolledWindow"> + <property name="hscrollbar-policy">automatic</property> + <property name="vscrollbar-policy">automatic</property> + <property name="hexpand">true</property> + <property name="vexpand">true</property> + <property name="has-frame">0</property> + + <child> + <object class="GtkColumnView" id="list"> + <property name="vexpand">true</property> + <property name="model">noselection</property> + + <child> + <object class="GtkColumnViewColumn"> + <property name="title"></property> + <property name="factory"> + <object class="GtkBuilderListItemFactory"> + <property name="resource">/re/chrysalide/framework/gui/panels/logs-col-icon.ui</property> + </object> + </property> + </object> + </child> + + <child> + <object class="GtkColumnViewColumn"> + <property name="expand">true</property> + <property name="title">Message</property> + <property name="factory"> + <object class="GtkBuilderListItemFactory"> + <property name="resource">/re/chrysalide/framework/gui/panels/logs-col-message.ui</property> + </object> + </property> + </object> + </child> + + </object> + </child> + + </object> + </child> + + </template> + +</interface> diff --git a/src/gui/style.css b/src/gui/style.css index 9078310..dce41fa 100644 --- a/src/gui/style.css +++ b/src/gui/style.css @@ -36,11 +36,7 @@ list.boxed-list, list.boxed-list > row:last-child { /* about.css */ -.black-bg { - - background-color: black; - -} +@import url('resource:///re/chrysalide/framework/gui/dialogs/about.css'); /* welcome.css */ @@ -61,3 +57,15 @@ grid.hints > box { min-width: 130px; } + + +/* dockstation.css */ + +.control-button { + + min-height: 0; + min-width: 0; + + padding: 6px; + +} diff --git a/src/gui/window-int.h b/src/gui/window-int.h index d79e189..4f3dd57 100644 --- a/src/gui/window-int.h +++ b/src/gui/window-int.h @@ -37,7 +37,10 @@ struct _GtkFrameworkWindow GSettings *settings; /* Paramètres globaux */ - GtkStack *grid; /* Réceptacle de panneaux */ + GtkTilingGrid *grid; /* Réceptacle de panneaux */ + GtkStatusStack *status; /* Barre de statut */ + + GtkTiledPanel *main; /* Panneau principal courant */ }; diff --git a/src/gui/window.c b/src/gui/window.c index f45cec9..e14ecf7 100644 --- a/src/gui/window.c +++ b/src/gui/window.c @@ -29,9 +29,10 @@ #include "core/panels.h" #include "dialogs/about.h" #include "dialogs/preferences.h" +#include "panels/logs.h" #include "panels/welcome.h" +#include "../gtkext/grid.h" #include "../gtkext/helpers.h" -#include "../gtkext/statusstack.h" @@ -42,10 +43,25 @@ static void gtk_framework_window_class_init(GtkFrameworkWindowClass *); static void gtk_framework_window_init(GtkFrameworkWindow *); /* Supprime toutes les références externes. */ -static void gtk_framework_window_dispose(GtkFrameworkWindow *); +static void gtk_framework_window_dispose(GObject *); /* Procède à la libération totale de la mémoire. */ -static void gtk_framework_window_finalize(GtkFrameworkWindow *); +static void gtk_framework_window_finalize(GObject *); + +/* Bascule l'affichage d'un panneau de bordure. */ +static void gtk_framework_window_toggle_pannel_visibility(GtkFrameworkWindow *, TilingGridBorder); + +/* Réagit à une activation de bascule du panneau supérieur. */ +static void gtk_framework_window_activate_toggle_top(GSimpleAction *, GVariant *, gpointer); + +/* Réagit à une activation de bascule du panneau de gauche. */ +static void gtk_framework_window_activate_toggle_left(GSimpleAction *action, GVariant *, gpointer); + +/* Réagit à une activation de bascule du panneau de droite. */ +static void gtk_framework_window_activate_toggle_right(GSimpleAction *, GVariant *, gpointer); + +/* Réagit à une activation de bascule du panneau inférieur. */ +static void gtk_framework_window_activate_toggle_bottom(GSimpleAction *, GVariant *, gpointer); /* Réagit à une activation du menu "Préférences" de la fenetre. */ static void gtk_framework_window_activate_preferences(GSimpleAction *, GVariant *, gpointer); @@ -83,11 +99,13 @@ static void gtk_framework_window_class_init(GtkFrameworkWindowClass *class) widget = GTK_WIDGET_CLASS(class); + g_type_ensure(GTK_TYPE_TILING_GRID); g_type_ensure(GTK_TYPE_STATUS_STACK); gtk_widget_class_set_template_from_resource(widget, "/re/chrysalide/framework/gui/window.ui"); gtk_widget_class_bind_template_child(widget, GtkFrameworkWindow, grid); + gtk_widget_class_bind_template_child(widget, GtkFrameworkWindow, status); /* Active une action native (cf. https://docs.gtk.org/gtk4/class.Window.html#actions) */ gtk_widget_class_add_binding_action(widget, GDK_KEY_Q, GDK_CONTROL_MASK, "window.close", NULL); @@ -111,7 +129,13 @@ static void gtk_framework_window_class_init(GtkFrameworkWindowClass *class) static void gtk_framework_window_init(GtkFrameworkWindow *window) { + GAction *action; /* Action mise en place */ + static GActionEntry app_entries[] = { + { "toggle-top", gtk_framework_window_activate_toggle_top, NULL, NULL, NULL }, + { "toggle-left", gtk_framework_window_activate_toggle_left, NULL, NULL, NULL }, + { "toggle-right", gtk_framework_window_activate_toggle_right, NULL, NULL, NULL }, + { "toggle-bottom", gtk_framework_window_activate_toggle_bottom, NULL, NULL, NULL }, { "preferences", gtk_framework_window_activate_preferences, NULL, NULL, NULL }, { "about", gtk_framework_window_activate_about, NULL, NULL, NULL }, }; @@ -124,16 +148,47 @@ static void gtk_framework_window_init(GtkFrameworkWindow *window) g_settings_bind(window->settings, "window-height", G_OBJECT(window), "default-height", G_SETTINGS_BIND_DEFAULT); g_settings_bind(window->settings, "window-maximized", G_OBJECT(window), "maximized", G_SETTINGS_BIND_DEFAULT); + window->main = NULL; + g_action_map_add_action_entries(G_ACTION_MAP(window), app_entries, G_N_ELEMENTS(app_entries), window); + /** + * Définition de l'accès aux actions pour obtenir un effet de bord sur + * l'accès aux boutons graphiques de déclenchement. + */ + + action = g_action_map_lookup_action(G_ACTION_MAP(window), "toggle-top"); + + g_object_bind_property(G_OBJECT(window->grid), "empty-top", + G_OBJECT(action), "enabled", + G_BINDING_SYNC_CREATE | G_BINDING_INVERT_BOOLEAN); + + action = g_action_map_lookup_action(G_ACTION_MAP(window), "toggle-left"); + + g_object_bind_property(G_OBJECT(window->grid), "empty-left", + G_OBJECT(action), "enabled", + G_BINDING_SYNC_CREATE | G_BINDING_INVERT_BOOLEAN); + + action = g_action_map_lookup_action(G_ACTION_MAP(window), "toggle-right"); + + g_object_bind_property(G_OBJECT(window->grid), "empty-right", + G_OBJECT(action), "enabled", + G_BINDING_SYNC_CREATE | G_BINDING_INVERT_BOOLEAN); + + action = g_action_map_lookup_action(G_ACTION_MAP(window), "toggle-bottom"); + + g_object_bind_property(G_OBJECT(window->grid), "empty-bottom", + G_OBJECT(action), "enabled", + G_BINDING_SYNC_CREATE | G_BINDING_INVERT_BOOLEAN); + } /****************************************************************************** * * -* Paramètres : window = instance d'objet GLib à traiter. * +* Paramètres : object = instance d'objet GLib à traiter. * * * * Description : Supprime toutes les références externes. * * * @@ -143,20 +198,26 @@ static void gtk_framework_window_init(GtkFrameworkWindow *window) * * ******************************************************************************/ -static void gtk_framework_window_dispose(GtkFrameworkWindow *window) +static void gtk_framework_window_dispose(GObject *object) { + GtkFrameworkWindow *window; /* Version spécialisée */ + + window = GTK_FRAMEWORK_WINDOW(object); + gtk_widget_dispose_template(GTK_WIDGET(window), GTK_TYPE_FRAMEWORK_WINDOW); g_clear_object(&window->settings); - G_OBJECT_CLASS(gtk_framework_window_parent_class)->dispose(G_OBJECT(window)); + g_clear_object(&window->main); + + G_OBJECT_CLASS(gtk_framework_window_parent_class)->dispose(object); } /****************************************************************************** * * -* Paramètres : window = 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 +227,9 @@ static void gtk_framework_window_dispose(GtkFrameworkWindow *window) * * ******************************************************************************/ -static void gtk_framework_window_finalize(GtkFrameworkWindow *window) +static void gtk_framework_window_finalize(GObject *object) { - G_OBJECT_CLASS(gtk_framework_window_parent_class)->finalize(G_OBJECT(window)); + G_OBJECT_CLASS(gtk_framework_window_parent_class)->finalize(object); } @@ -228,6 +289,14 @@ bool gtk_framework_window_create(GtkFrameworkWindow *window, GtkApplication *app gtk_framework_window_add(window, panel); + if (1/* FIXME : first time */) + { + panel = get_framework_panel_singleton(GTK_TYPE_LOGS_PANEL); + + gtk_framework_window_add(window, panel); + + } + /* Chargement des extensions de thème */ css = gtk_css_provider_new(); @@ -257,6 +326,116 @@ bool gtk_framework_window_create(GtkFrameworkWindow *window, GtkApplication *app /****************************************************************************** * * +* Paramètres : window = instance de fenêtre principale à manipuler. * +* border = sélection de la zone à considérer. * +* * +* Description : Bascule l'affichage d'un panneau de bordure. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void gtk_framework_window_toggle_pannel_visibility(GtkFrameworkWindow *window, TilingGridBorder border) +{ + bool state; /* Etat courant à basculer */ + + state = gtk_tiling_grid_get_visible(window->grid, border); + + state = !state; + + gtk_tiling_grid_set_visible(window->grid, border, state); + +} + + +/****************************************************************************** +* * +* Paramètres : action = désignation de l'action concernée par l'appel. * +* unused = adresse non utilisée ici. * +* _window = instance de fenêtre principale à manipuler. * +* * +* Description : Réagit à une activation de bascule du panneau supérieur. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void gtk_framework_window_activate_toggle_top(GSimpleAction *action, GVariant *unused, gpointer _window) +{ + gtk_framework_window_toggle_pannel_visibility(_window, TGB_TOP); + +} + + +/****************************************************************************** +* * +* Paramètres : action = désignation de l'action concernée par l'appel. * +* unused = adresse non utilisée ici. * +* _window = instance de fenêtre principale à manipuler. * +* * +* Description : Réagit à une activation de bascule du panneau de gauche. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void gtk_framework_window_activate_toggle_left(GSimpleAction *action, GVariant *unused, gpointer _window) +{ + gtk_framework_window_toggle_pannel_visibility(_window, TGB_LEFT); + +} + + +/****************************************************************************** +* * +* Paramètres : action = désignation de l'action concernée par l'appel. * +* unused = adresse non utilisée ici. * +* _window = instance de fenêtre principale à manipuler. * +* * +* Description : Réagit à une activation de bascule du panneau de droite. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void gtk_framework_window_activate_toggle_right(GSimpleAction *action, GVariant *unused, gpointer _window) +{ + gtk_framework_window_toggle_pannel_visibility(_window, TGB_RIGHT); + +} + + +/****************************************************************************** +* * +* Paramètres : action = désignation de l'action concernée par l'appel. * +* unused = adresse non utilisée ici. * +* _window = instance de fenêtre principale à manipuler. * +* * +* Description : Réagit à une activation de bascule du panneau inférieur. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void gtk_framework_window_activate_toggle_bottom(GSimpleAction *action, GVariant *unused, gpointer _window) +{ + gtk_framework_window_toggle_pannel_visibility(_window, TGB_BOTTOM); + +} + + +/****************************************************************************** +* * * Paramètres : action = désignation de l'action concernée par l'appel. * * unused = adresse non utilisée ici. * * _window = instance de fenêtre principale à manipuler. * @@ -313,6 +492,31 @@ static void gtk_framework_window_activate_about(GSimpleAction *action, GVariant /****************************************************************************** * * +* Paramètres : window = instance de fenêtre principale à consulter. * +* * +* Description : Fournit une référence à la barre de statut intégrée. * +* * +* Retour : Composant GTK en place. * +* * +* Remarques : - * +* * +******************************************************************************/ + +GtkStatusStack *gtk_framework_window_get_status_stack(const GtkFrameworkWindow *window) +{ + GtkStatusStack *result; /* Instance à retourner */ + + result = window->status; + ref_object(result); + + return result; + +} + + + +/****************************************************************************** +* * * Paramètres : window = instance de fenêtre principale à remplir. * * panel = nouveau panneau à afficher. * * * @@ -331,10 +535,12 @@ void gtk_framework_window_add(GtkFrameworkWindow *window, /* __steal */GtkTiledP guint count; /* Nombre d'élements présents */ guint i; /* Boucle de parcours */ GtkWidget *widget; /* Composant à intégrer */ + FrameworkPanelPersonality personality; /* Propriétés du panneau */ + + - gtk_stack_add_child(window->grid, GTK_WIDGET(panel)); + gtk_tiling_grid_add_panel(window->grid, panel, G_OBJECT_TYPE(panel) == GTK_TYPE_WELCOME_PANEL); - gtk_stack_set_visible_child(window->grid, GTK_WIDGET(panel)); @@ -362,4 +568,54 @@ void gtk_framework_window_add(GtkFrameworkWindow *window, /* __steal */GtkTiledP } + /* Mise à jour des liens vers un panneau principal */ + + personality = get_framework_panel_personality(G_OBJECT_TYPE(panel)); + + if (personality & FPP_MAIN_PANEL) + gtk_framework_window_notify_new_main_panel_state(window, panel, true); + + else + { + if (window->main != NULL) + gtk_tiled_panel_notify_new_main_panel_state(panel, window->main, true); + } + +} + + +/****************************************************************************** +* * +* Paramètres : window = instance de fenêtre principale à manipuler. * +* main = panneau principal visé par l'opération. * +* activated = nature du changement de statut : ajout, retrait ?* +* * +* Description : Note un ajout ou un retrait de panneau principal. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +void gtk_framework_window_notify_new_main_panel_state(GtkFrameworkWindow *window, GtkTiledPanel *main, bool activated) +{ + if (activated) + { + g_clear_object(&window->main); + + window->main = main; + ref_object(main); + + } + + else + { + if (main == window->main) + g_clear_object(&window->main); + + } + + gtk_tiling_grid_notify_new_main_panel_state(window->grid, main, activated); + } diff --git a/src/gui/window.h b/src/gui/window.h index 56c56ec..077d51a 100644 --- a/src/gui/window.h +++ b/src/gui/window.h @@ -30,6 +30,7 @@ #include "../glibext/helpers.h" #include "../gtkext/panel.h" +#include "../gtkext/statusstack.h" @@ -43,13 +44,18 @@ DECLARE_GTYPE(GtkFrameworkWindow, gtk_framework_window, GTK, FRAMEWORK_WINDOW); - /* Crée une nouvelle application principale pour Chrysalide. */ GtkApplicationWindow *gtk_framework_window_new(GtkApplication *); +/* Fournit une référence à la barre de statut intégrée. */ +GtkStatusStack *gtk_framework_window_get_status_stack(const GtkFrameworkWindow *); + /* Ajoute un panneau à la fenêtre principale de Chrysalide. */ void gtk_framework_window_add(GtkFrameworkWindow *, GtkTiledPanel *); +/* Note un ajout ou un retrait de panneau principal. */ +void gtk_framework_window_notify_new_main_panel_state(GtkFrameworkWindow *, GtkTiledPanel *, bool); + #endif /* _GUI_WINDOW_H */ diff --git a/src/gui/window.ui b/src/gui/window.ui index 363ea54..1c6a89a 100644 --- a/src/gui/window.ui +++ b/src/gui/window.ui @@ -22,6 +22,23 @@ <child type="titlebar"> <object class="GtkHeaderBar"> + + <child type="start"> + <object class="GtkToggleButton"> + <property name="icon-name">dock-station-left-symbolic</property> + <property name="action-name">win.toggle-left</property> + <property name="active" bind-source="grid" bind-property="visible-left" bind-flags="sync-create"/> + </object> + </child> + + <child type="end"> + <object class="GtkToggleButton"> + <property name="icon-name">dock-station-right-symbolic</property> + <property name="action-name">win.toggle-right</property> + <property name="active" bind-source="grid" bind-property="visible-right" bind-flags="sync-create"/> + </object> + </child> + <child type="end"> <object class="GtkMenuButton"> <property name="icon-name">open-menu-symbolic</property> @@ -37,7 +54,7 @@ <property name="orientation">vertical</property> <child> - <object class="GtkStack" id="grid"> + <object class="GtkTilingGrid" id="grid"> <property name="vexpand">TRUE</property> </object> </child> @@ -50,6 +67,7 @@ <child> <object class="GtkStatusStack" id="status"> + <property name="show-bottom" bind-source="grid" bind-property="visible-bottom" bind-flags="sync-create"/> </object> </child> @@ -41,7 +41,9 @@ #include "analysis/scan/scanner.h" #include "analysis/scan/patterns/backends/acism.h" #include "analysis/scan/patterns/backends/bitap.h" -#include "analysis/scan/patterns/backends/hyperscan.h" +#ifdef INCLUDE_HS_SUPPORT +# include "analysis/scan/patterns/backends/hyperscan.h" +#endif #include "core/core.h" #include "core/global.h" #include "core/logs.h" @@ -93,7 +95,11 @@ static void show_rost_help(const char *name) printf("\n"); +#ifdef INCLUDE_HS_SUPPORT printf("\t-A --algorithm=NAME\tSelect one of the available algorithms for data: acism, bitmap, hyperscan (default: acsim).\n"); +#else + printf("\t-A --algorithm=NAME\tSelect one of the available algorithms for data: acism, bitmap (default: acsim).\n"); +#endif printf("\t-C --check-only\t\tValidate the rule syntax without performing a scan (discard the file/dir argument).\n"); printf("\t-j --print-json\t\tPrint matching strings in JSON format instead of simple text.\n"); printf("\t-s --print-strings\tPrint matching strings (default text format only).\n"); @@ -303,8 +309,10 @@ int main(int argc, char **argv) g_scan_options_set_backend_for_data(options, G_TYPE_ACISM_BACKEND); else if (strcmp(optarg, "bitmap") == 0) g_scan_options_set_backend_for_data(options, G_TYPE_BITAP_BACKEND); +#ifdef INCLUDE_HS_SUPPORT else if (strcmp(optarg, "hyperscan") == 0) g_scan_options_set_backend_for_data(options, G_TYPE_HYPERSCAN_BACKEND); +#endif else g_scan_options_set_backend_for_data(options, G_TYPE_INVALID); break; diff --git a/src/schemas/re.chrysalide.framework.gschema.xml b/src/schemas/re.chrysalide.framework.gschema.xml index 80a20db..534f735 100644 --- a/src/schemas/re.chrysalide.framework.gschema.xml +++ b/src/schemas/re.chrysalide.framework.gschema.xml @@ -3,6 +3,7 @@ <schema id="re.chrysalide.framework" path="/re/chrysalide/framework/"> <child schema="re.chrysalide.framework.paths" name="paths"/> <child schema="re.chrysalide.framework.gui" name="gui"/> + <child schema="re.chrysalide.framework.tiledgrid" name="tiles"/> <child schema="re.chrysalide.framework.secstorage" name="secstorage"/> </schema> @@ -28,6 +29,71 @@ </key> </schema> + <flags id="re.chrysalide.framework.tiledgrid.LayoutReachOptions"> + <value nick="left-top-reach" value="1"/> + <value nick="left-bottom-reach" value="2"/> + <value nick="right-top-reach" value="4"/> + <value nick="right-bottom-reach" value="8"/> + </flags> + + <schema id="re.chrysalide.framework.tiledgrid"> + + <key name="layout" flags="re.chrysalide.framework.tiledgrid.LayoutReachOptions"> + <default>["left-top-reach","right-top-reach"]</default> + <summary>Main panel layout</summary> + <description>Layout details describing the border panel locations</description> + </key> + + <key name="top-visibility" type="b"> + <default>false</default> + <summary>Top panel visibility</summary> + <description>Visbility of the panel located at the top of a tiling grid</description> + </key> + + <key name="top-request" type="u"> + <default>300</default> + <summary>Top panel height</summary> + <description>Height request for the panel located at the top of a tiling grid</description> + </key> + + <key name="left-visibility" type="b"> + <default>false</default> + <summary>Left panel visibility</summary> + <description>Visbility of the panel located at the left of a tiling grid</description> + </key> + + <key name="left-request" type="u"> + <default>300</default> + <summary>Left panel height</summary> + <description>Width request for the panel located at the left of a tiling grid</description> + </key> + + <key name="right-visibility" type="b"> + <default>false</default> + <summary>Right panel visibility</summary> + <description>Visbility of the panel located at the right of a tiling grid</description> + </key> + + <key name="right-request" type="u"> + <default>300</default> + <summary>Right panel height</summary> + <description>Width request for the panel located at the right of a tiling grid</description> + </key> + + <key name="bottom-visibility" type="b"> + <default>false</default> + <summary>Bottom panel visibility</summary> + <description>Visbility of the panel located at the bottom of a tiling grid</description> + </key> + + <key name="bottom-request" type="u"> + <default>250</default> + <summary>Bottom panel height</summary> + <description>Height request for the panel located at the bottom of a tiling grid</description> + </key> + + </schema> + <schema id="re.chrysalide.framework.secstorage" path="/re/chrysalide/framework/secstorage/"> <key name="salt" type="ay"> <default>[]</default> diff --git a/tests/arch/instruction.py b/tests/arch/instruction.py new file mode 100644 index 0000000..da4d8c1 --- /dev/null +++ b/tests/arch/instruction.py @@ -0,0 +1,52 @@ + +import pychrysalide +from chrysacase import ChrysalideTestCase +from pychrysalide.arch import ArchInstruction + + +class TestProcessor(ChrysalideTestCase): + """TestCase for arch.ArchProcessor.""" + + + def testAbstractClass(self): + """Forbid instruction class instance.""" + + with self.assertRaisesRegex(RuntimeError, 'pychrysalide.arch.ArchInstruction is an abstract class'): + ins = ArchInstruction() + + + def testInstructionBasicImplementation(self): + """Implement basic custom instructions.""" + + + class TodoInstruction(ArchInstruction): + + def __init__(self): + super().__init__(0x123) + + + ins = TodoInstruction() + + with self.assertRaisesRegex(NotImplementedError, 'unexpected NULL value as encoding'): + print(ins.encoding) + + with self.assertRaisesRegex(NotImplementedError, 'unexpected NULL value as keyword'): + print(ins.keyword) + + + class CustomInstruction(ArchInstruction): + + def __init__(self): + super().__init__(0x123) + + def _get_encoding(self): + return 'custom' + + def _get_keyword(self): + return 'kw' + + + ins = CustomInstruction() + + self.assertEqual('custom', ins.encoding) + self.assertEqual('kw', ins.keyword) diff --git a/tools/about/build.py b/tools/about/build.py new file mode 100644 index 0000000..2267492 --- /dev/null +++ b/tools/about/build.py @@ -0,0 +1,120 @@ + +# apt install libcairo2-dev pkg-config python3-dev +# pip install pycairo + +import cairo +import math +import sys + +from enum import IntEnum + +from ttf import create_cairo_font_face_for_file + + +WIDTH = 350 +HEIGHT = 430 + + +def deg2rad(degrees): + return degrees * (math.pi / 180) + + +class TextAlignment(IntEnum): + LEFT = 1 + CENTER = 2 + RIGHT = 3 + + +def draw_text(ctx, text, pos, fsize, noise, theta = 0.0, align = TextAlignment.CENTER): + """Dessine un texte en respectant des propriétées.""" + + ctx.save() + + ctx.set_font_size(fsize) + + fascent, fdescent, fheight, fxadvance, fyadvance = ctx.font_extents() + x_off, y_off, tw, th = ctx.text_extents(text)[:4] + + if align == TextAlignment.LEFT: + nx = 0 + elif align == TextAlignment.RIGHT: + nx = -tw + else: + nx = -tw / 2.0 + + ny = fheight / 2 + + ctx.translate(pos[0], pos[1]) + ctx.rotate(theta) + ctx.translate(nx, ny) + ctx.move_to(0,0) + + ctx.text_path(text) + ctx.set_source_surface(noise, 0, -fheight) + ctx.fill_preserve() + ctx.set_source_rgb(1.0, 1.0, 1.0) + ctx.set_line_width(1) + ctx.stroke() + + ctx.restore() + + +if __name__ == '__main__': + """Point d'entrée du script.""" + + surface = cairo.ImageSurface(cairo.FORMAT_ARGB32, WIDTH, HEIGHT) + + cr = cairo.Context(surface) + + face = create_cairo_font_face_for_file('cour10p_b.ttf') + cr.set_font_face(face) + + noise = cairo.ImageSurface.create_from_png('noise.png') + + # Type d'édition + + if len(sys.argv) > 2: + + draw_text(cr, sys.argv[2], [ 300, 25 ], 32, noise, + theta = deg2rad(270), align = TextAlignment.RIGHT) + + cr.set_source_rgb(0, 0, 0) + cr.paint_with_alpha(0.4) + + # Numéro de version + + draw_text(cr, sys.argv[1], [ 149, 10 + 259 + 14 + 42 + 2 ], 23, noise, align=TextAlignment.LEFT) + + cr.set_source_rgb(0, 0, 0) + cr.paint_with_alpha(0.5) + + # Logo + + logo = cairo.ImageSurface.create_from_png('logo.png') + + scale_y = 259 / logo.get_height() + + cr.save() + + cr.translate((WIDTH - (logo.get_width() * scale_y)) / 2, 12) + + cr.scale(scale_y, scale_y) + + cr.set_source_surface(logo, 0, 0) + cr.paint() + + cr.restore() + + # Titre + + draw_text(cr, 'Chrysalide', [ WIDTH / 2, 10 + 259 + 14 + 4 ], 42, noise) + + # cr.rectangle(265, 30, 10, 10) + # cr.set_source_rgb(1, 0, 0) + # cr.fill() + + # cr.rectangle(265, 255, 10, 10) + # cr.set_source_rgb(1, 0, 0) + # cr.fill() + + surface.write_to_png('bg.png') diff --git a/tools/about/courier-10-pitch-bold_EQ97V.zip b/tools/about/courier-10-pitch-bold_EQ97V.zip Binary files differnew file mode 100644 index 0000000..0585fe6 --- /dev/null +++ b/tools/about/courier-10-pitch-bold_EQ97V.zip diff --git a/tools/about/courier10point.zip b/tools/about/courier10point.zip Binary files differnew file mode 100644 index 0000000..82cd0de --- /dev/null +++ b/tools/about/courier10point.zip diff --git a/tools/about/gen.sh b/tools/about/gen.sh new file mode 100755 index 0000000..c22ec59 --- /dev/null +++ b/tools/about/gen.sh @@ -0,0 +1,52 @@ +#!/bin/bash + + +# Cf. https://stackoverflow.com/questions/59895/how-do-i-get-the-directory-where-a-bash-script-is-located-from-within-the-script/246128#246128 +SCRIPT_DIR=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd ) + +pushd $SCRIPT_DIR > /dev/null + + +# Obtention de la police Courier-10-Pitch-Bold +# -------------------------------------------- + +# https://fontsgeek.com/fonts/Courier-10-Pitch-Bold +# https://fontsgeek.com/terms-and-conditions + +# => courier-10-pitch-bold_EQ97V.zip + + +# Courier 10 Pitch font missing after upgrade to 17.04? +# https://askubuntu.com/questions/914352/courier-10-pitch-font-missing-after-upgrade-to-17-04 + +# https://groups.google.com/g/trelby/c/CGkpcMBXW9U +# -> http://www.trelby.org/files/release/font/courier10point.zip +# --> https://web.archive.org/web/20140326080337/http://www.trelby.org/files/release/font/courier10point.zip + +# https://news.ycombinator.com/item?id=18802628 +# -> https://www.trelby.org/assets/courier10point.zip + +# => courier10point.zip + +if [ ! -f cour10p_b.ttf ]; then + + unzip -p courier10point.zip courier10point/cour10p_b.ttf > cour10p_b.ttf + +fi + + +# Construction de l'image de fond +#-------------------------------- + +if [ $# -lt 1 -o $# -gt 2 ]; then + + echo "Usage: $0 <version> <edition>" + exit 123 + +fi + +python3 ./build.py $* + +cp bg.png ../../src/data/images/about-bg.png + +popd > /dev/null diff --git a/tools/about/logo.png b/tools/about/logo.png Binary files differnew file mode 100644 index 0000000..9bf9969 --- /dev/null +++ b/tools/about/logo.png diff --git a/tools/about/noise.png b/tools/about/noise.png Binary files differnew file mode 100644 index 0000000..b5d6b91 --- /dev/null +++ b/tools/about/noise.png diff --git a/tools/about/ttf.py b/tools/about/ttf.py new file mode 100644 index 0000000..eb6c027 --- /dev/null +++ b/tools/about/ttf.py @@ -0,0 +1,111 @@ + +# Source: https://www.cairographics.org/cookbook/freetypepython/ + +import ctypes as ct +import cairo + +_initialized = False +def create_cairo_font_face_for_file (filename, faceindex=0, loadoptions=0): + "given the name of a font file, and optional faceindex to pass to FT_New_Face" \ + " and loadoptions to pass to cairo_ft_font_face_create_for_ft_face, creates" \ + " a cairo.FontFace object that may be used to render text with that font." + global _initialized + global _freetype_so + global _cairo_so + global _ft_lib + global _ft_destroy_key + global _surface + + CAIRO_STATUS_SUCCESS = 0 + FT_Err_Ok = 0 + + if not _initialized: + # find shared objects + _freetype_so = ct.CDLL("libfreetype.so.6") + _cairo_so = ct.CDLL("libcairo.so.2") + _cairo_so.cairo_ft_font_face_create_for_ft_face.restype = ct.c_void_p + _cairo_so.cairo_ft_font_face_create_for_ft_face.argtypes = [ ct.c_void_p, ct.c_int ] + _cairo_so.cairo_font_face_get_user_data.restype = ct.c_void_p + _cairo_so.cairo_font_face_get_user_data.argtypes = (ct.c_void_p, ct.c_void_p) + _cairo_so.cairo_font_face_set_user_data.argtypes = (ct.c_void_p, ct.c_void_p, ct.c_void_p, ct.c_void_p) + _cairo_so.cairo_set_font_face.argtypes = [ ct.c_void_p, ct.c_void_p ] + _cairo_so.cairo_font_face_status.argtypes = [ ct.c_void_p ] + _cairo_so.cairo_font_face_destroy.argtypes = (ct.c_void_p,) + _cairo_so.cairo_status.argtypes = [ ct.c_void_p ] + # initialize freetype + _ft_lib = ct.c_void_p() + status = _freetype_so.FT_Init_FreeType(ct.byref(_ft_lib)) + if status != FT_Err_Ok : + raise RuntimeError("Error %d initializing FreeType library." % status) + #end if + + class PycairoContext(ct.Structure): + _fields_ = \ + [ + ("PyObject_HEAD", ct.c_byte * object.__basicsize__), + ("ctx", ct.c_void_p), + ("base", ct.c_void_p), + ] + #end PycairoContext + + _surface = cairo.ImageSurface(cairo.FORMAT_A8, 0, 0) + _ft_destroy_key = ct.c_int() # dummy address + _initialized = True + #end if + + ft_face = ct.c_void_p() + cr_face = None + try : + # load FreeType face + status = _freetype_so.FT_New_Face(_ft_lib, filename.encode("utf-8"), faceindex, ct.byref(ft_face)) + if status != FT_Err_Ok : + raise RuntimeError("Error %d creating FreeType font face for %s" % (status, filename)) + #end if + + # create Cairo font face for freetype face + cr_face = _cairo_so.cairo_ft_font_face_create_for_ft_face(ft_face, loadoptions) + status = _cairo_so.cairo_font_face_status(cr_face) + if status != CAIRO_STATUS_SUCCESS : + raise RuntimeError("Error %d creating cairo font face for %s" % (status, filename)) + #end if + # Problem: Cairo doesn't know to call FT_Done_Face when its font_face object is + # destroyed, so we have to do that for it, by attaching a cleanup callback to + # the font_face. This only needs to be done once for each font face, while + # cairo_ft_font_face_create_for_ft_face will return the same font_face if called + # twice with the same FT Face. + # The following check for whether the cleanup has been attached or not is + # actually unnecessary in our situation, because each call to FT_New_Face + # will return a new FT Face, but we include it here to show how to handle the + # general case. + if _cairo_so.cairo_font_face_get_user_data(cr_face, ct.byref(_ft_destroy_key)) == None : + status = _cairo_so.cairo_font_face_set_user_data \ + ( + cr_face, + ct.byref(_ft_destroy_key), + ft_face, + _freetype_so.FT_Done_Face + ) + if status != CAIRO_STATUS_SUCCESS : + raise RuntimeError("Error %d doing user_data dance for %s" % (status, filename)) + #end if + ft_face = None # Cairo has stolen my reference + #end if + + # set Cairo font face into Cairo context + cairo_ctx = cairo.Context(_surface) + cairo_t = PycairoContext.from_address(id(cairo_ctx)).ctx + _cairo_so.cairo_set_font_face(cairo_t, cr_face) + status = _cairo_so.cairo_font_face_status(cairo_t) + if status != CAIRO_STATUS_SUCCESS : + raise RuntimeError("Error %d creating cairo font face for %s" % (status, filename)) + #end if + + finally : + _cairo_so.cairo_font_face_destroy(cr_face) + _freetype_so.FT_Done_Face(ft_face) + #end try + + # get back Cairo font face as a Python object + face = cairo_ctx.get_font_face() + return face +#end create_cairo_font_face_for_file |