diff options
Diffstat (limited to 'plugins')
84 files changed, 5448 insertions, 2584 deletions
diff --git a/plugins/Makefile.am b/plugins/Makefile.am index 89a8e25..529f4fe 100644 --- a/plugins/Makefile.am +++ b/plugins/Makefile.am @@ -14,7 +14,8 @@ endif # androhelpers SUBDIRS = \ $(PYTHON3_SUBDIRS) \ - pe + pe \ + pynb # arm \ # bootimg \ diff --git a/plugins/pychrysalide/Makefile.am b/plugins/pychrysalide/Makefile.am index d1bf457..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,9 +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 = +pychrysalideui_la_LIBADD = \ + arch/libpychrysaarchui.la \ + glibext/libpychrysaglibextui.la \ + gtkext/libpychrysagtkext.la # -ldl: dladdr(), dlerror() pychrysalideui_la_LDFLAGS = \ @@ -98,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 d3ee3f0..a0dcfdb 100644 --- a/plugins/pychrysalide/arch/Makefile.am +++ b/plugins/pychrysalide/arch/Makefile.am @@ -1,19 +1,13 @@ -noinst_LTLIBRARIES = libpychrysaarch4.la # libpychrysaarch.la +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 \ -# register.h register.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) \ @@ -22,21 +16,33 @@ noinst_LTLIBRARIES = libpychrysaarch4.la # libpychrysaarch.la 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_LIBADD = \ + instructions/libpychrysaarchinstructions.la \ + operands/libpychrysaarchoperands.la libpychrysaarch4_la_CFLAGS = $(LIBPYTHON_INTERPRETER_CFLAGS) $(LIBPYGOBJECT_CFLAGS) \ $(TOOLKIT_CFLAGS) \ -I$(top_srcdir)/src -DNO_IMPORT_PYGOBJECT +libpychrysaarchui_la_SOURCES = \ + module-ui.h module-ui.c \ + operand-ui.h operand-ui.c + +libpychrysaarchui_la_CFLAGS = $(LIBPYTHON_INTERPRETER_CFLAGS) $(LIBPYGOBJECT_CFLAGS) \ + $(TOOLKIT_CFLAGS) \ + -I$(top_srcdir)/src -DNO_IMPORT_PYGOBJECT + + devdir = $(includedir)/chrysalide/$(subdir) dev_HEADERS = $(libpychrysaarch_la_SOURCES:%c=) -# SUBDIRS = instructions 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 new file mode 100644 index 0000000..65d1290 --- /dev/null +++ b/plugins/pychrysalide/arch/module-ui.c @@ -0,0 +1,66 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * module.c - intégration du répertoire arch (forme graphique) en tant que module + * + * 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 "module-ui.h" + + +#include <assert.h> + + +#include "operand-ui.h" +#include "../glibext/generator.h" + + + +/****************************************************************************** +* * +* Paramètres : - * +* * +* Description : Intègre les objets du module 'arch' (mode UI). * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool populate_arch_module_ui(void) +{ + bool result; /* Bilan à retourner */ + + result = true; + + 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-ui.h b/plugins/pychrysalide/arch/module-ui.h new file mode 100644 index 0000000..afa31d2 --- /dev/null +++ b/plugins/pychrysalide/arch/module-ui.h @@ -0,0 +1,38 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * module.h - prototypes pour l'intégration du répertoire arch (forme graphique) en tant que module + * + * 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_ARCH_MODULE_UI_H +#define _PLUGINS_PYCHRYSALIDE_ARCH_MODULE_UI_H + + +#include <Python.h> +#include <stdbool.h> + + +/* Intègre les objets du module 'arch' (mode UI). */ +bool populate_arch_module_ui(void); + + + +#endif /* _PLUGINS_PYCHRYSALIDE_ARCH_MODULE_UI_H */ diff --git a/plugins/pychrysalide/arch/module.c b/plugins/pychrysalide/arch/module.c index 0127348..94f5ad7 100644 --- a/plugins/pychrysalide/arch/module.c +++ b/plugins/pychrysalide/arch/module.c @@ -31,16 +31,14 @@ /* #include "context.h" #include "instriter.h" +*/ #include "instruction.h" #include "operand.h" -#include "processor.h" +//#include "processor.h" #include "register.h" -*/ #include "vmpa.h" -/* #include "instructions/module.h" #include "operands/module.h" -*/ #include "../helpers.h" @@ -77,10 +75,8 @@ 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; @@ -108,18 +104,16 @@ 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_operand_is_registered(); - if (result) result = ensure_python_arch_processor_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-ui.c b/plugins/pychrysalide/arch/operand-ui.c new file mode 100644 index 0000000..5062513 --- /dev/null +++ b/plugins/pychrysalide/arch/operand-ui.c @@ -0,0 +1,461 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * operand-ui.c - équivalent Python du fichier "arch/operand-ui.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 "operand-ui.h" + + +#include <assert.h> +#include <pygobject.h> + + +#include <arch/operand-ui-int.h> + + +#include "../access.h" +#include "../helpers.h" + + + +/* Procède à l'initialisation de l'interface d'exportation. */ +static void py_arch_operand_ui_interface_init(GArchOperandUIInterface *, gpointer *); + +/* Traduit un opérande en version humainement lisible. */ +static void py_arch_operand_ui_print_wrapper(const GArchOperandUI *, GBufferLine *); + +/* Construit un petit résumé concis de l'opérande. */ +static char *py_arch_operand_ui_build_tooltip_wrapper(const GArchOperandUI *, const GLoadedBinary *); + +/* Traduit un opérande en version humainement lisible. */ +static PyObject *py_arch_operand_ui_print(PyObject *, PyObject *); + +/* Construit un petit résumé concis de l'opérande. */ +static PyObject *py_arch_operand_ui_build_tooltip(PyObject *, PyObject *); + + + +/****************************************************************************** +* * +* Paramètres : iface = interface GLib à initialiser. * +* unused = adresse non utilisée ici. * +* * +* Description : Procède à l'initialisation de l'interface d'exportation. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void py_arch_operand_ui_interface_init(GArchOperandUIInterface *iface, gpointer *unused) +{ +#define ARCH_OPERAND_UI_DOC \ + "The ArchOperandUI interface ensure pychrysalide.arch.ArchOperand" \ + " implementations provide UI features when Chrysalide is running with" \ + " a GUI.\n" \ + "\n" \ + "A typical class declaration for a new implementation looks like:\n" \ + "\n" \ + " class NewImplem(ArchOperand, ArchOperandUi):\n" \ + " ...\n" \ + "\n" \ + "The following method has to be defined for new implementations:\n" \ + "* pychrysalide.arch.ArchOperandUI._print();\n" \ + "* pychrysalide.arch.ArchOperandUI._build_tooltip().\n" + + iface->print = py_arch_operand_ui_print_wrapper; + iface->build_tooltip = py_arch_operand_ui_build_tooltip_wrapper; + +} + + +/****************************************************************************** +* * +* Paramètres : operand = registre visé par la procédure. * +* * +* Description : Traduit un opérande en version humainement lisible. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void py_arch_operand_ui_print_wrapper(const GArchOperandUI *operand, GBufferLine *line) +{ + PyGILState_STATE gstate; /* Sauvegarde d'environnement */ + PyObject *pyobj; /* Objet Python concerné */ + PyObject *args; /* Arguments pour l'appel */ + PyObject *pyret; /* Bilan de consultation */ + +#define ARCH_OPERAND_UI_PRINT_WRAPPER PYTHON_WRAPPER_DEF \ +( \ + _print, "$self, line, /", \ + METH_VARARGS, \ + "Abstract method used to print an operand into a rendering" \ + " *line*, which is a provided pychrysalide.glibext.BufferLine" \ + " instance." \ +) + + gstate = PyGILState_Ensure(); + + pyobj = pygobject_new(G_OBJECT(operand)); + + if (has_python_method(pyobj, "_print")) + { + args = PyTuple_New(1); + PyTuple_SetItem(args, 0, pygobject_new(G_OBJECT(line))); + + pyret = run_python_method(pyobj, "_print", args); + + Py_XDECREF(pyret); + + Py_DECREF(args); + + } + + Py_DECREF(pyobj); + + PyGILState_Release(gstate); + +} + + +/****************************************************************************** +* * +* Paramètres : operand = opérande à consulter. * +* binary = informations relatives au binaire chargé. * +* * +* Description : Construit un petit résumé concis de l'opérande. * +* * +* Retour : Chaîne de caractères à libérer après usage ou NULL. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static char *py_arch_operand_ui_build_tooltip_wrapper(const GArchOperandUI *operand, const GLoadedBinary *binary) +{ + char *result; /* Description à retourner */ + PyGILState_STATE gstate; /* Sauvegarde d'environnement */ + PyObject *pyobj; /* Objet Python concerné */ + PyObject *args; /* Arguments pour l'appel */ + PyObject *pyret; /* Bilan de consultation */ + +#define ARCH_OPERAND_UI_BUILD_TOOLTIP_WRAPPER PYTHON_WRAPPER_DEF \ +( \ + _build_tooltip, "$self, binary, /", \ + METH_VARARGS, \ + "Abstract method used to build a tooltip text shown when the" \ + " mouse is over an operand.\n" \ + "\n" \ + "A pychrysalide.analysis.LoadedBinary instance is provided in" \ + " case of need." \ +) + + result = NULL; + + gstate = PyGILState_Ensure(); + + pyobj = pygobject_new(G_OBJECT(operand)); + + if (has_python_method(pyobj, "_build_tooltip")) + { + args = PyTuple_New(1); + PyTuple_SetItem(args, 0, pygobject_new(G_OBJECT(binary))); + + pyret = run_python_method(pyobj, "_build_tooltip", args); + + if (pyret != NULL) + { + if (PyUnicode_Check(pyret)) + result = strdup(PyUnicode_AsUTF8(pyret)); + } + + Py_XDECREF(pyret); + + Py_DECREF(args); + + } + + Py_DECREF(pyobj); + + PyGILState_Release(gstate); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : self = objet manipulé ici. * +* args = adresse non utilisée ici. * +* * +* Description : Traduit un opérande en version humainement lisible. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static PyObject *py_arch_operand_ui_print(PyObject *self, PyObject *args) +{ + PyObject *result; /* Emplacement à retourner */ + +#if 0 // TODO + + GBufferLine *line; /* Zone d'impression du rendu */ + int ret; /* Bilan de lecture des args. */ + GArchOperandUI *operand; /* Mécanismes natifs */ + +#define ARCH_OPERAND_UI_PRINT_METHOD PYTHON_METHOD_DEF \ +( \ + print, "$self, line", \ + METH_VARARGS, py_arch_operand_ui, \ + "Translate an operand into a human readable version.\n" \ + "\n" \ + "The *line* arguement is a pychrysalide.glibext.BufferLine" \ + " instance which has to get filled with rendering" \ + " information.\n" \ + "\n" \ + "The result returns nothing (*None*)." \ +) + + ret = PyArg_ParseTuple(args, "O&", convert_to_buffer_line, &line); + if (!ret) return NULL; + + operand = G_ARCH_OPERAND_UI(pygobject_get(self)); + + g_arch_operand_ui_print(operand, line); + +#endif + + result = Py_None; + Py_INCREF(result); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : self = objet manipulé ici. * +* args = adresse non utilisée ici. * +* * +* Description : Construit un petit résumé concis de l'opérande. * +* * +* Retour : Chaîne de caractères à libérer après usage ou None. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static PyObject *py_arch_operand_ui_build_tooltip(PyObject *self, PyObject *args) +{ + PyObject *result; /* Emplacement à retourner */ + +#if 0 // TODO + + GLoadedBinary *binary; /* Infos sur le binaire chargé */ + int ret; /* Bilan de lecture des args. */ + GArchOperandUI *operand; /* Mécanismes natifs */ + char *tooltip; /* Eventuelle indication */ + +#define ARCH_OPERAND_UI_BUILD_TOOLTIP_METHOD PYTHON_METHOD_DEF \ +( \ + build_tooltip, "$self, binary", \ + METH_VARARGS, py_arch_operand_ui, \ + "Build a tooltip text shown when the mouse is over an" \ + " operand.\n" \ + "\n" \ + "The *binary* argument is a pychrysalide.analysis.LoadedBinary" \ + " instance provided in case of need." \ + "\n" \ + "The result is a string or *None* in case of error." \ +) + + ret = PyArg_ParseTuple(args, "O&", convert_to_loaded_binary, &binary); + if (!ret) return NULL; + + operand = G_ARCH_OPERAND_UI(pygobject_get(self)); + + tooltip = g_arch_operand_ui_build_tooltip(operand, binary); + + if (tooltip != NULL) + { + PyUnicode_FromString(tooltip); + free(tooltip); + } + else + +#endif + + { + result = Py_None; + Py_INCREF(result); + } + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : - * +* * +* Description : Fournit un accès à une définition de type à diffuser. * +* * +* Retour : Définition d'objet pour Python. * +* * +* Remarques : - * +* * +******************************************************************************/ + +PyTypeObject *get_python_arch_operand_ui_type(void) +{ + static PyMethodDef py_arch_operand_ui_methods[] = { + ARCH_OPERAND_UI_PRINT_WRAPPER, + ARCH_OPERAND_UI_BUILD_TOOLTIP_WRAPPER, +#if 0 // TODO + ARCH_OPERAND_UI_PRINT_METHOD, + ARCH_OPERAND_UI_BUILD_TOOLTIP_METHOD, +#endif + { NULL } + }; + + static PyGetSetDef py_arch_operand_ui_getseters[] = { + { NULL } + }; + + static PyTypeObject py_arch_operand_ui_type = { + + PyVarObject_HEAD_INIT(NULL, 0) + + .tp_name = "pychrysalide.arch.ArchOperandUI", + .tp_basicsize = sizeof(PyObject), + + .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, + + .tp_doc = ARCH_OPERAND_UI_DOC, + + .tp_methods = py_arch_operand_ui_methods, + .tp_getset = py_arch_operand_ui_getseters + + }; + + return &py_arch_operand_ui_type; + +} + + +/****************************************************************************** +* * +* Paramètres : - * +* * +* Description : Prend en charge l'objet 'pychrysalide.arch.ArchOperandUI'. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool ensure_python_arch_operand_ui_is_registered(void) +{ + PyTypeObject *type; /* Type Python 'ArchOperandUI' */ + PyObject *module; /* Module à recompléter */ + PyObject *dict; /* Dictionnaire du module */ + + static GInterfaceInfo info = { /* Paramètres d'inscription */ + + .interface_init = (GInterfaceInitFunc)py_arch_operand_ui_interface_init, + .interface_finalize = NULL, + .interface_data = NULL, + + }; + + type = get_python_arch_operand_ui_type(); + + if (!PyType_HasFeature(type, Py_TPFLAGS_READY)) + { + module = get_access_to_python_module("pychrysalide.arch"); + + dict = PyModule_GetDict(module); + + if (!register_interface_for_pygobject(dict, G_TYPE_ARCH_OPERAND_UI, type, &info)) + return false; + + } + + return true; + +} + + +/****************************************************************************** +* * +* 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 interface d'exportation graphique. * +* * +* Retour : Bilan de l'opération, voire indications supplémentaires. * +* * +* Remarques : - * +* * +******************************************************************************/ + +int convert_to_arch_operand_ui(PyObject *arg, void *dst) +{ + int result; /* Bilan à retourner */ + + result = PyObject_IsInstance(arg, (PyObject *)get_python_arch_operand_ui_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 UI arch operand"); + break; + + case 1: + *((GArchOperandUI **)dst) = G_ARCH_OPERAND_UI(pygobject_get(arg)); + break; + + default: + assert(false); + break; + + } + + return result; + +} diff --git a/plugins/pychrysalide/arch/operand-ui.h b/plugins/pychrysalide/arch/operand-ui.h new file mode 100644 index 0000000..b9e2131 --- /dev/null +++ b/plugins/pychrysalide/arch/operand-ui.h @@ -0,0 +1,45 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * operand-ui.h - prototypes pour l'équivalent Python du fichier "arch/operand-ui.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_ARCH_OPERAND_UI_H +#define _PLUGINS_PYCHRYSALIDE_ARCH_OPERAND_UI_H + + +#include <Python.h> +#include <stdbool.h> + + + +/* Fournit un accès à une définition de type à diffuser. */ +PyTypeObject *get_python_arch_operand_ui_type(void); + +/* Prend en charge l'objet 'pychrysalide.arch.ArchOperandUI'. */ +bool ensure_python_arch_operand_ui_is_registered(void); + +/* Tente de convertir en interface d'exportation graphique. */ +int convert_to_arch_operand_ui(PyObject *, void *); + + + +#endif /* _PLUGINS_PYCHRYSALIDE_ARCH_OPERAND_UI_H */ diff --git a/plugins/pychrysalide/arch/operand.c b/plugins/pychrysalide/arch/operand.c index 0aee4f7..2281dae 100644 --- a/plugins/pychrysalide/arch/operand.c +++ b/plugins/pychrysalide/arch/operand.c @@ -30,23 +30,32 @@ #include <i18n.h> #include <arch/operand-int.h> -#include <plugins/dt.h> +#include <glibext/strbuilder-int.h> #include "../access.h" #include "../helpers.h" +#include "../glibext/comparable.h" +#include "../glibext/hashable.h" +#include "../glibext/objhole.h" +#include "../glibext/serialize.h" #include "../glibext/singleton.h" +#include "../glibext/strbuilder.h" /* ------------------------ GLUE POUR CREATION DEPUIS PYTHON ------------------------ */ -/* Accompagne la création d'une instance dérivée en Python. */ -static PyObject *py_arch_operand_new(PyTypeObject *, PyObject *, PyObject *); - /* Initialise la classe générique des opérandes. */ -static void py_arch_operand_init_gclass(GArchOperandClass *, gpointer); +static int py_arch_operand_init_gclass(GArchOperandClass *, PyTypeObject *); + +CREATE_DYN_ABSTRACT_CONSTRUCTOR(arch_operand, G_TYPE_ARCH_OPERAND); + +/* Initialise une instance sur la base du dérivé de GObject. */ +static int py_arch_operand_init(PyObject *, PyObject *, PyObject *); + +#if 0 /* Compare un opérande avec un autre. */ static int py_arch_operand___cmp___wrapper(const GArchOperand *, const GArchOperand *, bool); @@ -57,14 +66,6 @@ static char *py_arch_operand_find_inner_operand_path_wrapper(const GArchOperand /* Obtient l'opérande correspondant à un chemin donné. */ static GArchOperand *py_arch_operand_get_inner_operand_from_path_wrapper(const GArchOperand *, const char *); -/* Traduit un opérande en version humainement lisible. */ -static void py_arch_operand_print_wrapper(const GArchOperand *, GBufferLine *); - -#ifdef INCLUDE_GTK_SUPPORT - -/* Construit un petit résumé concis de l'opérande. */ -static char *py_arch_operand_build_tooltip_wrapper(const GArchOperand *, const GLoadedBinary *); - #endif @@ -72,6 +73,9 @@ static char *py_arch_operand_build_tooltip_wrapper(const GArchOperand *, const G /* ------------------------ DEFINITION D'OPERANDE QUELCONQUE ------------------------ */ +#if 0 + + /* Effectue une comparaison avec un objet Python 'ArchOperand'. */ static PyObject *py_arch_operand_richcompare(PyObject *, PyObject *, int); @@ -81,6 +85,19 @@ static PyObject *py_arch_operand_find_inner_operand_path(PyObject *, PyObject *) /* Obtient l'opérande correspondant à un chemin donné. */ static PyObject *py_arch_operand_get_inner_operand_from_path(PyObject *, PyObject *); +#endif + + +/* Ajoute une information complémentaire à un opérande. */ +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 *); + + /* ---------------------------------------------------------------------------------- */ @@ -90,113 +107,109 @@ static PyObject *py_arch_operand_get_inner_operand_from_path(PyObject *, PyObjec /****************************************************************************** * * -* Paramètres : type = type du nouvel objet à mettre en place. * -* args = éventuelle liste d'arguments. * -* kwds = éventuel dictionnaire de valeurs mises à disposition. * +* Paramètres : gclass = classe GLib à initialiser. * +* pyclass = classe Python à initialiser. * * * -* Description : Accompagne la création d'une instance dérivée en Python. * +* Description : Initialise la classe générique des opérandes. * * * -* Retour : Nouvel objet Python mis en place ou NULL en cas d'échec. * +* Retour : 0 pour indiquer un succès de l'opération. * * * * Remarques : - * * * ******************************************************************************/ -static PyObject *py_arch_operand_new(PyTypeObject *type, PyObject *args, PyObject *kwds) +static int py_arch_operand_init_gclass(GArchOperandClass *gclass, PyTypeObject *pyclass) { - 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 */ - -#define ARCH_OPERAND_DOC \ - "The ArchOperand object aims to get subclassed to create" \ - " operands of any kind for new architectures.\n" \ - "\n" \ - "Calls to the *__init__* constructor of this abstract object expect"\ - " no particular argument.\n" \ - "\n" \ - "The following methods have to be defined for new classes:\n" \ - "* pychrysalide.arch.ArchRegister.__cmp__();\n" \ - "* pychrysalide.arch.ArchRegister._print();\n" \ - "* pychrysalide.arch.ArchRegister._build_tooltip().\n" \ - "\n" \ - "Some extra method definitions are optional for new classes:\n" \ - "* pychrysalide.arch.ArchRegister._find_inner_operand_path();\n" \ - "* pychrysalide.arch.ArchRegister._get_inner_operand_from_path().\n"\ - "\n" \ - "Chrysalide creates an internal glue to provide rich comparisons" \ - " for operands based on the old-style *__cmp__* function." - /* Validations diverses */ +#if 0 + GStringBuilderInterface *iface; /* Interface utilisée */ - base = get_python_arch_operand_type(); + iface = g_type_interface_peek(gclass, G_TYPE_STRING_BUILDER); - if (type == base) - { - result = NULL; - PyErr_Format(PyExc_RuntimeError, _("%s is an abstract class"), type->tp_name); - goto exit; - } - /* Mise en place d'un type dédié */ + /* + printf("???????? init Python Operand ?????????????? -> class: %p '%s' - strbuilder iface: %p\n", + gclass, g_type_name(G_TYPE_FROM_CLASS(gclass)), iface); + */ - first_time = (g_type_from_name(type->tp_name) == 0); +#endif - gtype = build_dynamic_type(G_TYPE_ARCH_OPERAND, type->tp_name, - (GClassInitFunc)py_arch_operand_init_gclass, NULL, NULL); +#if 0 - if (first_time) - { - status = register_class_for_dynamic_pygobject(gtype, type); + class->compare = py_arch_operand___cmp___wrapper; + class->find_inner = py_arch_operand_find_inner_operand_path_wrapper; + class->get_inner = py_arch_operand_get_inner_operand_from_path_wrapper; - if (!status) - { - result = NULL; - goto exit; - } - } +#endif - /* On crée, et on laisse ensuite la main à PyGObject_Type.tp_init() */ - result = PyType_GenericNew(type, args, kwds); - exit: + //PY_CLASS_SET_WRAPPER(gclass->xxx, py_arch_operand_xxx_wrapper); - return result; + return 0; } /****************************************************************************** * * -* Paramètres : class = classe à initialiser. * -* unused = données non utilisées ici. * +* Paramètres : self = objet à initialiser (théoriquement). * +* args = arguments fournis à l'appel. * +* kwds = arguments de type key=val fournis. * * * -* Description : Initialise la classe générique des opérandes. * +* Description : Initialise une instance sur la base du dérivé de GObject. * * * -* Retour : - * +* Retour : 0. * * * * Remarques : - * * * ******************************************************************************/ -static void py_arch_operand_init_gclass(GArchOperandClass *class, gpointer unused) +static int py_arch_operand_init(PyObject *self, PyObject *args, PyObject *kwds) { - class->compare = py_arch_operand___cmp___wrapper; - class->find_inner = py_arch_operand_find_inner_operand_path_wrapper; - class->get_inner = py_arch_operand_get_inner_operand_from_path_wrapper; + //unsigned int endianness; /* Boutisme du processeur */ + int ret; /* Bilan de lecture des args. */ + //GArchProcessor *proc; /* Processeur à manipuler */ - class->print = py_arch_operand_print_wrapper; -#ifdef INCLUDE_GTK_SUPPORT - class->build_tooltip = py_arch_operand_build_tooltip_wrapper; -#endif +#define ARCH_OPERAND_DOC \ + "The ArchOperand object aims to get subclassed to create" \ + " operands of any kind for new architectures.\n" \ + "\n" \ + "Calls to the *__init__* constructor of this abstract object expect"\ + " no particular argument.\n" \ + "\n" \ + "The following methods have to be defined for new classes:\n" \ + "* pychrysalide.arch.ArchRegister.__cmp__();\n" \ + "* pychrysalide.arch.ArchRegister._print();\n" \ + "* pychrysalide.arch.ArchRegister._build_tooltip().\n" \ + "\n" \ + "Some extra method definitions are optional for new classes:\n" \ + "* pychrysalide.arch.ArchRegister._find_inner_operand_path();\n" \ + "* pychrysalide.arch.ArchRegister._get_inner_operand_from_path().\n"\ + "\n" \ + "Chrysalide creates an internal glue to provide rich comparisons" \ + " for operands based on the old-style *__cmp__* function." + + /* Initialisation d'un objet GLib */ + + ret = forward_pygobjet_init(self); + if (ret == -1) return -1; + + /* Eléments de base */ + + //proc = G_ARCH_PROCESSOR(pygobject_get(self)); + + //proc->endianness = endianness; + + return 0; } + +#if 0 + /****************************************************************************** * * * Paramètres : a = premier opérande à consulter. * @@ -410,126 +423,6 @@ static GArchOperand *py_arch_operand_get_inner_operand_from_path_wrapper(const G } -/****************************************************************************** -* * -* Paramètres : operand = registre visé par la procédure. * -* * -* Description : Traduit un opérande en version humainement lisible. * -* * -* Retour : - * -* * -* Remarques : - * -* * -******************************************************************************/ - -static void py_arch_operand_print_wrapper(const GArchOperand *operand, GBufferLine *line) -{ - PyGILState_STATE gstate; /* Sauvegarde d'environnement */ - PyObject *pyobj; /* Objet Python concerné */ - PyObject *args; /* Arguments pour l'appel */ - PyObject *pyret; /* Bilan de consultation */ - -#define ARCH_OPERAND_PRINT_WRAPPER PYTHON_WRAPPER_DEF \ -( \ - _print, "$self, line, /", \ - METH_VARARGS, \ - "Abstract method used to print the operand into a rendering" \ - " line, which is a provided pychrysalide.glibext.BufferLine" \ - " instance." \ -) - - gstate = PyGILState_Ensure(); - - pyobj = pygobject_new(G_OBJECT(operand)); - - if (has_python_method(pyobj, "_print")) - { - args = PyTuple_New(1); - PyTuple_SetItem(args, 0, pygobject_new(G_OBJECT(line))); - - pyret = run_python_method(pyobj, "_print", args); - - Py_XDECREF(pyret); - - Py_DECREF(args); - - } - - Py_DECREF(pyobj); - - PyGILState_Release(gstate); - -} - - -#ifdef INCLUDE_GTK_SUPPORT - - -/****************************************************************************** -* * -* Paramètres : operand = opérande à consulter. * -* binary = informations relatives au binaire chargé. * -* * -* Description : Construit un petit résumé concis de l'opérande. * -* * -* Retour : Chaîne de caractères à libérer après usage ou NULL. * -* * -* Remarques : - * -* * -******************************************************************************/ - -static char *py_arch_operand_build_tooltip_wrapper(const GArchOperand *operand, const GLoadedBinary *binary) -{ - char *result; /* Description à retourner */ - PyGILState_STATE gstate; /* Sauvegarde d'environnement */ - PyObject *pyobj; /* Objet Python concerné */ - PyObject *args; /* Arguments pour l'appel */ - PyObject *pyret; /* Bilan de consultation */ - -#define ARCH_OPERAND_BUILD_TOOLTIP_WRAPPER PYTHON_WRAPPER_DEF \ -( \ - _build_tooltip, "$self, line, /", \ - METH_VARARGS, \ - "Abstract method used to build a tooltip text shown when the" \ - " mouse is over the operand.\n" \ - "\n" \ - "A pychrysalide.analysis.LoadedBinary instance is provided in" \ - " case of need." \ -) - - result = NULL; - - gstate = PyGILState_Ensure(); - - pyobj = pygobject_new(G_OBJECT(operand)); - - if (has_python_method(pyobj, "_build_tooltip")) - { - args = PyTuple_New(1); - PyTuple_SetItem(args, 0, pygobject_new(G_OBJECT(binary))); - - pyret = run_python_method(pyobj, "_build_tooltip", args); - - if (pyret != NULL) - { - if (PyUnicode_Check(pyret)) - result = strdup(PyUnicode_AsUTF8(pyret)); - } - - Py_XDECREF(pyret); - - Py_DECREF(args); - - } - - Py_DECREF(pyobj); - - PyGILState_Release(gstate); - - return result; - -} - #endif @@ -540,6 +433,9 @@ static char *py_arch_operand_build_tooltip_wrapper(const GArchOperand *operand, /* ---------------------------------------------------------------------------------- */ + +#if 0 + /****************************************************************************** * * * Paramètres : a = premier object Python à consulter. * @@ -701,6 +597,164 @@ static PyObject *py_arch_operand_get_inner_operand_from_path(PyObject *self, PyO } +#endif + + + + + + + + + + + +/****************************************************************************** +* * +* Paramètres : self = architecture concernée par la procédure. * +* args = instruction représentant le point de départ. * +* * +* Description : Ajoute une information complémentaire à un opérande. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static PyObject *py_arch_operand_set_flag(PyObject *self, PyObject *args) +{ + PyObject *result; /* Bilan à retourner */ + unsigned int flag; /* Fanion(s) à appliquer */ + int ret; /* Bilan de lecture des args. */ + GArchOperand *operand; /* Opérande manipulé */ + bool status; /* Bilan à transmettre */ + +#define ARCH_OPERAND_SET_FLAG_METHOD PYTHON_METHOD_DEF \ +( \ + set_flag, "$self, flag, /", \ + METH_VARARGS, py_arch_operand, \ + "Add some flags to the operand.\n" \ + "\n" \ + "This *flag* argument is an integer value containing" \ + " bits to apply to the operand 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; + + operand = G_ARCH_OPERAND(pygobject_get(self)); + + status = g_arch_operand_set_flag(operand, 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 : Retire une information complémentaire à un opérande. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static PyObject *py_arch_operand_unset_flag(PyObject *self, PyObject *args) +{ + PyObject *result; /* Bilan à retourner */ + unsigned int flag; /* Fanion(s) à appliquer */ + int ret; /* Bilan de lecture des args. */ + GArchOperand *operand; /* Opérande manipulé */ + bool status; /* Bilan à transmettre */ + +#define ARCH_OPERAND_UNSET_FLAG_METHOD PYTHON_METHOD_DEF \ +( \ + unset_flag, "$self, flag, /", \ + METH_VARARGS, py_arch_operand, \ + "Remove some flags from the operand.\n" \ + "\n" \ + "This *flag* argument is an integer value containing" \ + " bits to delete from the operand 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; + + operand = G_ARCH_OPERAND(pygobject_get(self)); + + status = g_arch_operand_unset_flag(operand, 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 un opérande possède un fanion particulier. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static PyObject *py_arch_operand_has_flag(PyObject *self, PyObject *args) +{ + PyObject *result; /* Bilan à retourner */ + unsigned int flag; /* Fanion(s) à appliquer */ + int ret; /* Bilan de lecture des args. */ + GArchOperand *operand; /* Opérande manipulé */ + bool status; /* Bilan à transmettre */ + +#define ARCH_OPERAND_HAS_FLAG_METHOD PYTHON_METHOD_DEF \ +( \ + has_flag, "$self, flag, /", \ + METH_VARARGS, py_arch_operand, \ + "Tell if some flags are set for the operand.\n" \ + "\n" \ + "This *flag* argument is an integer value containing" \ + " bits to test for the operand 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; + + operand = G_ARCH_OPERAND(pygobject_get(self)); + + status = g_arch_operand_has_flag(operand, flag); + + result = status ? Py_True : Py_False; + Py_INCREF(result); + + return result; + +} + /****************************************************************************** * * @@ -717,6 +771,11 @@ static PyObject *py_arch_operand_get_inner_operand_from_path(PyObject *self, PyO PyTypeObject *get_python_arch_operand_type(void) { static PyMethodDef py_arch_operand_methods[] = { + ARCH_OPERAND_SET_FLAG_METHOD, + ARCH_OPERAND_UNSET_FLAG_METHOD, + ARCH_OPERAND_HAS_FLAG_METHOD, + + /* ARCH_OPERAND_CMP_WRAPPER, ARCH_OPERAND_FIND_INNER_OPERAND_PATH_WRAPPER, ARCH_OPERAND_GET_INNER_OPERAND_FROM_PATH_WRAPPER, @@ -726,6 +785,7 @@ PyTypeObject *get_python_arch_operand_type(void) #endif ARCH_OPERAND_FIND_INNER_OPERAND_PATH_METHOD, ARCH_OPERAND_GET_INNER_OPERAND_FROM_PATH_METHOD, + */ { NULL } }; @@ -744,11 +804,12 @@ PyTypeObject *get_python_arch_operand_type(void) .tp_doc = ARCH_OPERAND_DOC, - .tp_richcompare = py_arch_operand_richcompare, + //.tp_richcompare = py_arch_operand_richcompare, .tp_methods = py_arch_operand_methods, .tp_getset = py_arch_operand_getseters, + .tp_init = py_arch_operand_init, .tp_new = py_arch_operand_new, }; @@ -784,9 +845,26 @@ bool ensure_python_arch_operand_is_registered(void) dict = PyModule_GetDict(module); + if (!ensure_python_thick_object_is_registered()) + return false; + + if (!ensure_python_comparable_object_is_registered()) + return false; + + if (!ensure_python_hashable_object_is_registered()) + return false; + + if (!ensure_python_serializable_object_is_registered()) + return false; + if (!ensure_python_singleton_candidate_is_registered()) return false; + if (!ensure_python_string_builder_is_registered()) + return false; + + pyg_register_class_init(G_TYPE_ARCH_OPERAND, (PyGClassInitFunc)py_arch_operand_init_gclass); + if (!register_class_for_pygobject(dict, G_TYPE_ARCH_OPERAND, type)) return false; diff --git a/plugins/pychrysalide/arch/operand.h b/plugins/pychrysalide/arch/operand.h index 9cb40a0..f3bfbf2 100644 --- a/plugins/pychrysalide/arch/operand.h +++ b/plugins/pychrysalide/arch/operand.h @@ -2,7 +2,7 @@ /* Chrysalide - Outil d'analyse de fichiers binaires * operand.h - prototypes pour l'équivalent Python du fichier "arch/operand.h" * - * Copyright (C) 2018-2019 Cyrille Bagard + * Copyright (C) 2018-2024 Cyrille Bagard * * This file is part of Chrysalide. * @@ -31,9 +31,6 @@ -/* ------------------------ DEFINITION D'OPERANDE QUELCONQUE ------------------------ */ - - /* Fournit un accès à une définition de type à diffuser. */ PyTypeObject *get_python_arch_operand_type(void); diff --git a/plugins/pychrysalide/arch/operands/Makefile.am b/plugins/pychrysalide/arch/operands/Makefile.am index a41cbbb..3b753cc 100644 --- a/plugins/pychrysalide/arch/operands/Makefile.am +++ b/plugins/pychrysalide/arch/operands/Makefile.am @@ -1,19 +1,21 @@ noinst_LTLIBRARIES = libpychrysaarchoperands.la +# libpychrysaarchoperands_la_SOURCES = \ +# feeder.h feeder.c \ +# proxy.h proxy.c \ +# rename.h rename.c \ +# target.h target.c \ +# targetable.h targetable.c + libpychrysaarchoperands_la_SOURCES = \ constants.h constants.c \ - feeder.h feeder.c \ immediate.h immediate.c \ known.h known.c \ module.h module.c \ - proxy.h proxy.c \ - register.h register.c \ - rename.h rename.c \ - target.h target.c \ - targetable.h targetable.c + register.h register.c -libpychrysaarchoperands_la_CFLAGS = $(TOOLKIT_CFLAGS) $(LIBXML_CFLAGS) $(LIBPYTHON_INTERPRETER_CFLAGS) $(LIBPYGOBJECT_CFLAGS) \ +libpychrysaarchoperands_la_CFLAGS = $(TOOLKIT_CFLAGS) $(LIBPYTHON_INTERPRETER_CFLAGS) $(LIBPYGOBJECT_CFLAGS) \ -I$(top_srcdir)/src -DNO_IMPORT_PYGOBJECT diff --git a/plugins/pychrysalide/arch/operands/constants.c b/plugins/pychrysalide/arch/operands/constants.c index b9d80e4..78eeded 100644 --- a/plugins/pychrysalide/arch/operands/constants.c +++ b/plugins/pychrysalide/arch/operands/constants.c @@ -2,7 +2,7 @@ /* Chrysalide - Outil d'analyse de fichiers binaires * constants.c - ajout des constantes de base pour les opérandes * - * Copyright (C) 2020 Cyrille Bagard + * Copyright (C) 2020-2025 Cyrille Bagard * * This file is part of Chrysalide. * @@ -47,20 +47,33 @@ * * ******************************************************************************/ -bool define_imm_operand_constants(PyTypeObject *type) +bool define_immediate_operand_constants(PyTypeObject *type) { bool result; /* Bilan à retourner */ PyObject *values; /* Groupe de valeurs à établir */ values = PyDict_New(); + result = add_const_to_group(values, "ZERO_PADDING_BY_DEFAULT", IOF_ZERO_PADDING_BY_DEFAULT); + if (result) result = add_const_to_group(values, "ZERO_PADDING", IOF_ZERO_PADDING); + + if (!result) + { + Py_DECREF(values); + goto exit; + } + + result = attach_constants_group_to_type(type, true, "ImmOperandFlag", values, + "Specific state bits for immediate operands."); + + values = PyDict_New(); + result = add_const_to_group(values, "BIN", IOD_BIN); if (result) result = add_const_to_group(values, "OCT", IOD_OCT); if (result) result = add_const_to_group(values, "DEC", IOD_DEC); if (result) result = add_const_to_group(values, "HEX", IOD_HEX); if (result) result = add_const_to_group(values, "CHAR", IOD_CHAR); if (result) result = add_const_to_group(values, "COUNT", IOD_COUNT); - if (result) result = add_const_to_group(values, "LAST_VALID", IOD_LAST_VALID); if (!result) { diff --git a/plugins/pychrysalide/arch/operands/constants.h b/plugins/pychrysalide/arch/operands/constants.h index 71a26cc..5170faa 100644 --- a/plugins/pychrysalide/arch/operands/constants.h +++ b/plugins/pychrysalide/arch/operands/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 opérandes * - * Copyright (C) 2020 Cyrille Bagard + * Copyright (C) 2020-2025 Cyrille Bagard * * This file is part of Chrysalide. * @@ -32,11 +32,14 @@ /* Définit les constantes relatives aux opérandes d'immédiats. */ -bool define_imm_operand_constants(PyTypeObject *); +bool define_immediate_operand_constants(PyTypeObject *); /* Tente de convertir en constante ImmOperandDisplay. */ int convert_to_imm_operand_display(PyObject *, void *); +#define cast_imm_operand_display_to_python(v) \ + cast_with_constants_group_from_type(get_python_immediate_operand_type(), "ImmOperandDisplay", v) + #endif /* _PLUGINS_PYCHRYSALIDE_ARCH_OPERANDS_CONSTANTS_H */ diff --git a/plugins/pychrysalide/arch/operands/immediate.c b/plugins/pychrysalide/arch/operands/immediate.c index 2239eb2..a335db3 100644 --- a/plugins/pychrysalide/arch/operands/immediate.c +++ b/plugins/pychrysalide/arch/operands/immediate.c @@ -2,7 +2,7 @@ /* Chrysalide - Outil d'analyse de fichiers binaires * immediate.c - équivalent Python du fichier "arch/operands/immediate.h" * - * Copyright (C) 2020 Cyrille Bagard + * Copyright (C) 2020-2025 Cyrille Bagard * * This file is part of Chrysalide. * @@ -30,201 +30,119 @@ #include <i18n.h> - - -#include <arch/operands/immediate.h> +#include <arch/operands/immediate-int.h> #include "constants.h" -#include "rename.h" -#include "targetable.h" #include "../operand.h" #include "../../access.h" +#include "../../constants.h" #include "../../helpers.h" #include "../../analysis/content.h" -#include "../../glibext/bufferline.h" -/* Crée un nouvel objet Python de type 'ImmOperand'. */ -static PyObject *py_imm_operand_new(PyTypeObject *, PyObject *, PyObject *); +/* ------------------------ GLUE POUR CREATION DEPUIS PYTHON ------------------------ */ + + +CREATE_DYN_CONSTRUCTOR(immediate_operand, G_TYPE_IMMEDIATE_OPERAND); + +/* Initialise une instance sur la base du dérivé de GObject. */ +static int py_immediate_operand_init(PyObject *, PyObject *, PyObject *); + + -/* Compare un opérande avec un autre. */ -static PyObject *py_imm_operand___cmp__(PyObject *, PyObject *); +/* ---------------------------- DEFINITION D'UN IMMEDIAT ---------------------------- */ -/* Traduit un opérande en version humainement lisible. */ -static PyObject *py_imm_operand__print(PyObject *, PyObject *); /* Renseigne la taille de la valeur indiquée à la construction. */ -static PyObject *py_imm_operand_get_size(PyObject *, void *); +static PyObject *py_immediate_operand_get_size(PyObject *, void *); /* Fournit la valeur portée par une opérande numérique. */ -static PyObject *py_imm_operand_get_value(PyObject *, void *); +static PyObject *py_immediate_operand_get_value(PyObject *, void *); + +/* Indique le signe d'une valeur immédiate. */ +static PyObject *py_immediate_operand_is_negative(PyObject *, void *); /* Indique le format textuel par défaut de la valeur. */ -static PyObject *py_imm_operand_get_default_display(PyObject *, void *); +static PyObject *py_immediate_operand_get_default_display(PyObject *, void *); /* Définit le format textuel par défaut de la valeur. */ -static int py_imm_operand_set_default_display(PyObject *, PyObject *, void *); +static int py_immediate_operand_set_default_display(PyObject *, PyObject *, void *); /* Indique la grande ligne du format textuel de la valeur. */ -static PyObject *py_imm_operand_get_display(PyObject *, void *); +static PyObject *py_immediate_operand_get_display(PyObject *, void *); /* Définit la grande ligne du format textuel de la valeur. */ -static int py_imm_operand_set_display(PyObject *, PyObject *, void *); +static int py_immediate_operand_set_display(PyObject *, PyObject *, void *); + +/* ---------------------------------------------------------------------------------- */ +/* GLUE POUR CREATION DEPUIS PYTHON */ +/* ---------------------------------------------------------------------------------- */ + /****************************************************************************** * * -* Paramètres : type = type de l'objet à instancier. * +* Paramètres : self = objet à initialiser (théoriquement). * * args = arguments fournis à l'appel. * * kwds = arguments de type key=val fournis. * * * -* Description : Crée un nouvel objet Python de type 'ImmOperand'. * +* Description : Initialise une instance sur la base du dérivé de GObject. * * * -* Retour : Instance Python mise en place. * +* Retour : 0. * * * * Remarques : - * * * ******************************************************************************/ -static PyObject *py_imm_operand_new(PyTypeObject *type, PyObject *args, PyObject *kwds) +static int py_immediate_operand_init(PyObject *self, PyObject *args, PyObject *kwds) { - PyObject *result; /* Instance à retourner */ - unsigned int raw_size; /* Taille obtenue de Python */ + MemoryDataSize size; /* Taille des données finale */ unsigned long long value; /* Valeur brute à représenter */ int ret; /* Bilan de lecture des args. */ - MemoryDataSize size; /* Taille des données finale */ - GArchOperand *operand; /* Création GLib à transmettre */ + GImmediateOperand *operand; /* Opérande natif à manipuler */ -#define IMM_OPERAND_DOC \ - "The ImmOperand deals with immediate value as operand." \ +#define IMMEDIATE_OPERAND_DOC \ + "The ImmediateOperand deals with immediate value as operand." \ "\n" \ "There are several ways to display these values in a disassembly," \ " the operand handles that.\n" \ "\n" \ "Instances can be created using the following constructor:\n" \ "\n" \ - " ImmOperand(size, value)" \ + " ImmediateOperand(size, value)" \ "\n" \ - "Where size specifies the original size of the provided value, as" \ - " a pychrysalide.analysis.BinContent.MemoryDataSize." + "Where *size* specifies the original size of the provided *value*," \ + " as a pychrysalide.MemoryDataSize." - ret = PyArg_ParseTuple(args, "IK", &raw_size, &value); - if (!ret) return NULL; + /* Récupération des paramètres */ - size = raw_size; + ret = PyArg_ParseTuple(args, "O&K", convert_to_memory_data_size, &size, &value); + if (!ret) return -1; - if (size != MDS_UNDEFINED - && !(MDS_4_BITS_UNSIGNED <= size && size <= MDS_64_BITS_UNSIGNED) - && !(MDS_4_BITS_SIGNED <= size && size <= MDS_64_BITS_SIGNED)) - { - PyErr_SetString(PyExc_ValueError, _("Invalid size to build an immediate operand")); - return NULL; - } + /* Initialisation d'un objet GLib */ - operand = g_imm_operand_new_from_value(size, value); + ret = forward_pygobjet_init(self); + if (ret == -1) return -1; - result = pygobject_new(G_OBJECT(operand)); + /* Eléments de base */ - g_object_unref(operand); + operand = G_IMMEDIATE_OPERAND(pygobject_get(self)); - return (PyObject *)result; - -} - - -/****************************************************************************** -* * -* Paramètres : self = serveur à manipuler. * -* args = arguments associés à l'appel. * -* * -* Description : Compare un opérande avec un autre. * -* * -* Retour : Bilan de l'opération. * -* * -* Remarques : - * -* * -******************************************************************************/ - -static PyObject *py_imm_operand___cmp__(PyObject *self, PyObject *args) -{ - PyObject *result; /* Bilan à retourner */ - GImmOperand *other; /* Autre opérande à manipuler */ - int ret; /* Bilan de lecture des args. */ - GImmOperand *operand; /* Elément à manipuler */ - int status; /* Bilan de comparaison */ - -#define IMM_OPERAND_CMP_METHOD PYTHON_METHOD_DEF \ -( \ - __cmp__, "$self, other, /", \ - METH_VARARGS, py_imm_operand, \ - "Implementation of the required method used to compare the" \ - " operand with another one. This second object is always" \ - " an pychrysalide.arch.ImmOperand instance.\n" \ - "\n" \ - "See the parent class for more information about this method." \ -) - - ret = PyArg_ParseTuple(args, "O&", convert_to_imm_operand, &other); - if (!ret) return NULL; - - operand = G_IMM_OPERAND(pygobject_get(self)); - - status = g_arch_operand_compare(G_ARCH_OPERAND(operand), G_ARCH_OPERAND(other)); - - result = PyLong_FromLong(status); + if (!g_immediate_operand_create_from_value(operand, size, value)) + return -1; - return result; + return 0; } -/****************************************************************************** -* * -* Paramètres : self = serveur à manipuler. * -* args = arguments associés à l'appel. * -* * -* Description : Traduit un opérande en version humainement lisible. * -* * -* Retour : Bilan de l'opération. * -* * -* Remarques : - * -* * -******************************************************************************/ -static PyObject *py_imm_operand__print(PyObject *self, PyObject *args) -{ - PyObject *result; /* Bilan à retourner */ - GBufferLine *line; /* Ligne fournie à peupler */ - int ret; /* Bilan de lecture des args. */ - GImmOperand *operand; /* Elément à manipuler */ - -#define IMM_OPERAND_PRINT_METHOD PYTHON_METHOD_DEF \ -( \ - _print, "$self, line, /", \ - METH_VARARGS, py_imm_operand, \ - "Implementation of the required method used to print the operand" \ - " into a rendering line, which is a provided" \ - " pychrysalide.glibext.BufferLine instance.\n" \ - "\n" \ - "See the parent class for more information about this method." \ -) - - ret = PyArg_ParseTuple(args, "O&", convert_to_buffer_line, &line); - if (!ret) return NULL; - - operand = G_IMM_OPERAND(pygobject_get(self)); - - g_arch_operand_print(G_ARCH_OPERAND(operand), line); - - result = Py_None; - Py_INCREF(result); - - return result; - -} +/* ---------------------------------------------------------------------------------- */ +/* DEFINITION D'UN IMMEDIAT */ +/* ---------------------------------------------------------------------------------- */ /****************************************************************************** @@ -240,25 +158,26 @@ static PyObject *py_imm_operand__print(PyObject *self, PyObject *args) * * ******************************************************************************/ -static PyObject *py_imm_operand_get_size(PyObject *self, void *closure) +static PyObject *py_immediate_operand_get_size(PyObject *self, void *closure) { PyObject *result; /* Instance Python à retourner */ - GImmOperand *operand; /* Version GLib de l'opérande */ + GImmediateOperand *operand; /* Version GLib de l'opérande */ MemoryDataSize size; /* Type de donnée représentée */ -#define IMM_OPERAND_SIZE_ATTRIB PYTHON_GET_DEF_FULL \ +#define IMMEDIATE_OPERAND_SIZE_ATTRIB PYTHON_GET_DEF_FULL \ ( \ - size, py_imm_operand, \ + size, py_immediate_operand, \ "Get or set the size of the value contained in the operand." \ "\n" \ "The property is a value of type" \ - " pychrysalide.analysis.BinContent.MemoryDataSize." \ + " pychrysalide.MemoryDataSize." \ ) - operand = G_IMM_OPERAND(pygobject_get(self)); - size = g_imm_operand_get_size(operand); + operand = G_IMMEDIATE_OPERAND(pygobject_get(self)); + + size = g_immediate_operand_get_size(operand); - result = cast_with_constants_group_from_type(get_python_binary_content_type(), "MemoryDataSize", size); + result = cast_memory_data_size_to_python(size); return result; @@ -278,10 +197,10 @@ static PyObject *py_imm_operand_get_size(PyObject *self, void *closure) * * ******************************************************************************/ -static PyObject *py_imm_operand_get_value(PyObject *self, void *closure) +static PyObject *py_immediate_operand_get_value(PyObject *self, void *closure) { PyObject *result; /* Instance Python à retourner */ - GImmOperand *operand; /* Version GLib de l'opérande */ + GImmediateOperand *operand; /* Version GLib de l'opérande */ MemoryDataSize size; /* Type de donnée représentée */ uint8_t uval8; /* Valeur sur 8 bits */ uint16_t uval16; /* Valeur sur 16 bits */ @@ -292,15 +211,15 @@ static PyObject *py_imm_operand_get_value(PyObject *self, void *closure) int32_t sval32; /* Valeur sur 32 bits */ int64_t sval64; /* Valeur sur 64 bits */ -#define IMM_OPERAND_VALUE_ATTRIB PYTHON_GET_DEF_FULL \ -( \ - value, py_imm_operand, \ - "Value of the immediate operand, as an integer." \ +#define IMMEDIATE_OPERAND_VALUE_ATTRIB PYTHON_GET_DEF_FULL \ +( \ + value, py_immediate_operand, \ + "Value of the immediate operand, as an integer." \ ) - operand = G_IMM_OPERAND(pygobject_get(self)); + operand = G_IMMEDIATE_OPERAND(pygobject_get(self)); - size = g_imm_operand_get_size(operand); + size = g_immediate_operand_get_size(operand); switch (size) { @@ -311,36 +230,36 @@ static PyObject *py_imm_operand_get_value(PyObject *self, void *closure) break; case MDS_4_BITS_UNSIGNED: case MDS_8_BITS_UNSIGNED: - g_imm_operand_get_value(operand, size, &uval8); + g_immediate_operand_get_value(operand, size, &uval8); result = PyLong_FromUnsignedLong(uval8); break; case MDS_16_BITS_UNSIGNED: - g_imm_operand_get_value(operand, size, &uval16); + g_immediate_operand_get_value(operand, size, &uval16); result = PyLong_FromUnsignedLong(uval16); break; case MDS_32_BITS_UNSIGNED: - g_imm_operand_get_value(operand, size, &uval32); + g_immediate_operand_get_value(operand, size, &uval32); result = PyLong_FromUnsignedLong(uval32); break; case MDS_64_BITS_UNSIGNED: - g_imm_operand_get_value(operand, size, &uval64); + g_immediate_operand_get_value(operand, size, &uval64); result = PyLong_FromUnsignedLongLong(uval64); break; case MDS_4_BITS_SIGNED: case MDS_8_BITS_SIGNED: - g_imm_operand_get_value(operand, size, &sval8); + g_immediate_operand_get_value(operand, size, &sval8); result = PyLong_FromLong(sval8); break; case MDS_16_BITS_SIGNED: - g_imm_operand_get_value(operand, size, &sval16); + g_immediate_operand_get_value(operand, size, &sval16); result = PyLong_FromLong(sval16); break; case MDS_32_BITS_SIGNED: - g_imm_operand_get_value(operand, size, &sval32); + g_immediate_operand_get_value(operand, size, &sval32); result = PyLong_FromLong(sval32); break; case MDS_64_BITS_SIGNED: - g_imm_operand_get_value(operand, size, &sval64); + g_immediate_operand_get_value(operand, size, &sval64); result = PyLong_FromLongLong(sval64); break; @@ -363,6 +282,43 @@ static PyObject *py_imm_operand_get_value(PyObject *self, void *closure) * Paramètres : self = objet Python concerné par l'appel. * * closure = non utilisé ici. * * * +* Description : Indique le signe d'une valeur immédiate. * +* * +* Retour : True si la valeur est strictement négative, False sinon. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static PyObject *py_immediate_operand_is_negative(PyObject *self, void *closure) +{ + PyObject *result; /* Instance Python à retourner */ + GImmediateOperand *operand; /* Version GLib de l'opérande */ + bool status; /* Etat à faire connaître */ + +#define IMMEDIATE_OPERAND_NEGATIVE_ATTRIB PYTHON_IS_DEF_FULL \ +( \ + negative, py_immediate_operand, \ + "Sign of the value, as a boolean status." \ +) + + operand = G_IMMEDIATE_OPERAND(pygobject_get(self)); + + status = g_immediate_operand_is_negative(operand); + + result = status ? Py_True : Py_False; + Py_INCREF(result); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : self = objet Python concerné par l'appel. * +* closure = non utilisé ici. * +* * * Description : Indique le format textuel par défaut de la valeur. * * * * Retour : Format global d'un affichage de valeur. * @@ -371,25 +327,26 @@ static PyObject *py_imm_operand_get_value(PyObject *self, void *closure) * * ******************************************************************************/ -static PyObject *py_imm_operand_get_default_display(PyObject *self, void *closure) +static PyObject *py_immediate_operand_get_default_display(PyObject *self, void *closure) { PyObject *result; /* Instance Python à retourner */ - GImmOperand *operand; /* Version GLib de l'opérande */ + GImmediateOperand *operand; /* Version GLib de l'opérande */ ImmOperandDisplay display; /* Type d'affichage courant */ -#define IMM_OPERAND_DEFAULT_DISPLAY_ATTRIB PYTHON_GETSET_DEF_FULL \ +#define IMMEDIATE_OPERAND_DEFAULT_DISPLAY_ATTRIB PYTHON_GETSET_DEF_FULL \ ( \ - default_display, py_imm_operand, \ + default_display, py_immediate_operand, \ "Define of the immediate operand default textual representation." \ "\n" \ "The property is a value of type" \ " pychrysalide.arch.operands.ImmOperand.ImmOperandDisplay." \ ) - operand = G_IMM_OPERAND(pygobject_get(self)); - display = g_imm_operand_get_default_display(operand); + operand = G_IMMEDIATE_OPERAND(pygobject_get(self)); + + display = g_immediate_operand_get_default_display(operand); - result = cast_with_constants_group_from_type(get_python_imm_operand_type(), "ImmOperandDisplay", display); + result = cast_imm_operand_display_to_python(display); return result; @@ -410,10 +367,10 @@ static PyObject *py_imm_operand_get_default_display(PyObject *self, void *closur * * ******************************************************************************/ -static int py_imm_operand_set_default_display(PyObject *self, PyObject *value, void *closure) +static int py_immediate_operand_set_default_display(PyObject *self, PyObject *value, void *closure) { ImmOperandDisplay display; /* Type d'affichage demandé */ - GImmOperand *operand; /* Version GLib de l'opérande */ + GImmediateOperand *operand; /* Version GLib de l'opérande */ if (!PyLong_Check(value)) { @@ -429,9 +386,9 @@ static int py_imm_operand_set_default_display(PyObject *self, PyObject *value, v return -1; } - operand = G_IMM_OPERAND(pygobject_get(self)); + operand = G_IMMEDIATE_OPERAND(pygobject_get(self)); - g_imm_operand_set_default_display(operand, display); + g_immediate_operand_set_default_display(operand, display); return 0; @@ -451,25 +408,27 @@ static int py_imm_operand_set_default_display(PyObject *self, PyObject *value, v * * ******************************************************************************/ -static PyObject *py_imm_operand_get_display(PyObject *self, void *closure) +static PyObject *py_immediate_operand_get_display(PyObject *self, void *closure) { PyObject *result; /* Instance Python à retourner */ - GImmOperand *operand; /* Version GLib de l'opérande */ + GImmediateOperand *operand; /* Version GLib de l'opérande */ ImmOperandDisplay display; /* Type d'affichage courant */ -#define IMM_OPERAND_DISPLAY_ATTRIB PYTHON_GETSET_DEF_FULL \ -( \ - display, py_imm_operand, \ - "Define of the immediate operand current textual representation." \ - "\n" \ - "The property is a value of type" \ - " pychrysalide.arch.operands.ImmOperand.ImmOperandDisplay." \ +#define IMMEDIATE_OPERAND_DISPLAY_ATTRIB PYTHON_GETSET_DEF_FULL \ +( \ + display, py_immediate_operand, \ + "Retrieve or define of the immediate operand current textual" \ + " representation." \ + "\n" \ + "The property is a value of type" \ + " pychrysalide.arch.operands.ImmOperand.ImmOperandDisplay." \ ) - operand = G_IMM_OPERAND(pygobject_get(self)); - display = g_imm_operand_get_display(operand); + operand = G_IMMEDIATE_OPERAND(pygobject_get(self)); - result = cast_with_constants_group_from_type(get_python_imm_operand_type(), "ImmOperandDisplay", display); + display = g_immediate_operand_get_display(operand); + + result = cast_imm_operand_display_to_python(display); return result; @@ -490,10 +449,10 @@ static PyObject *py_imm_operand_get_display(PyObject *self, void *closure) * * ******************************************************************************/ -static int py_imm_operand_set_display(PyObject *self, PyObject *value, void *closure) +static int py_immediate_operand_set_display(PyObject *self, PyObject *value, void *closure) { ImmOperandDisplay display; /* Type d'affichage demandé */ - GImmOperand *operand; /* Version GLib de l'opérande */ + GImmediateOperand *operand; /* Version GLib de l'opérande */ if (!PyLong_Check(value)) { @@ -509,9 +468,9 @@ static int py_imm_operand_set_display(PyObject *self, PyObject *value, void *clo return -1; } - operand = G_IMM_OPERAND(pygobject_get(self)); + operand = G_IMMEDIATE_OPERAND(pygobject_get(self)); - g_imm_operand_set_display(operand, display); + g_immediate_operand_set_display(operand, display); return 0; @@ -530,40 +489,41 @@ static int py_imm_operand_set_display(PyObject *self, PyObject *value, void *clo * * ******************************************************************************/ -PyTypeObject *get_python_imm_operand_type(void) +PyTypeObject *get_python_immediate_operand_type(void) { - static PyMethodDef py_imm_operand_methods[] = { - IMM_OPERAND_CMP_METHOD, - IMM_OPERAND_PRINT_METHOD, + static PyMethodDef py_immediate_operand_methods[] = { { NULL } }; - static PyGetSetDef py_imm_operand_getseters[] = { - IMM_OPERAND_SIZE_ATTRIB, - IMM_OPERAND_VALUE_ATTRIB, - IMM_OPERAND_DEFAULT_DISPLAY_ATTRIB, - IMM_OPERAND_DISPLAY_ATTRIB, + static PyGetSetDef py_immediate_operand_getseters[] = { + IMMEDIATE_OPERAND_SIZE_ATTRIB, + IMMEDIATE_OPERAND_VALUE_ATTRIB, + IMMEDIATE_OPERAND_NEGATIVE_ATTRIB, + IMMEDIATE_OPERAND_DEFAULT_DISPLAY_ATTRIB, + IMMEDIATE_OPERAND_DISPLAY_ATTRIB, { NULL } }; - static PyTypeObject py_imm_operand_type = { + static PyTypeObject py_immediate_operand_type = { PyVarObject_HEAD_INIT(NULL, 0) - .tp_name = "pychrysalide.arch.operands.ImmOperand", + .tp_name = "pychrysalide.arch.operands.ImmediateOperand", .tp_basicsize = sizeof(PyGObject), .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, - .tp_doc = IMM_OPERAND_DOC, + .tp_doc = IMMEDIATE_OPERAND_DOC, + + .tp_methods = py_immediate_operand_methods, + .tp_getset = py_immediate_operand_getseters, - .tp_methods = py_imm_operand_methods, - .tp_getset = py_imm_operand_getseters, - .tp_new = py_imm_operand_new + .tp_init = py_immediate_operand_init, + .tp_new = py_immediate_operand_new, }; - return &py_imm_operand_type; + return &py_immediate_operand_type; } @@ -580,13 +540,13 @@ PyTypeObject *get_python_imm_operand_type(void) * * ******************************************************************************/ -bool ensure_python_imm_operand_is_registered(void) +bool ensure_python_immediate_operand_is_registered(void) { - PyTypeObject *type; /* Type Python 'ImmOperand' */ + PyTypeObject *type; /* Type 'ImmediateOperand' */ PyObject *module; /* Module à recompléter */ PyObject *dict; /* Dictionnaire du module */ - type = get_python_imm_operand_type(); + type = get_python_immediate_operand_type(); if (!PyType_HasFeature(type, Py_TPFLAGS_READY)) { @@ -597,16 +557,10 @@ bool ensure_python_imm_operand_is_registered(void) if (!ensure_python_arch_operand_is_registered()) return false; - if (!ensure_python_targetable_operand_is_registered()) - return false; - - if (!ensure_python_renameable_operand_is_registered()) - return false; - - if (!register_class_for_pygobject(dict, G_TYPE_IMM_OPERAND, type)) + if (!register_class_for_pygobject(dict, G_TYPE_IMMEDIATE_OPERAND, type)) return false; - if (!define_imm_operand_constants(type)) + if (!define_immediate_operand_constants(type)) return false; } @@ -629,11 +583,11 @@ bool ensure_python_imm_operand_is_registered(void) * * ******************************************************************************/ -int convert_to_imm_operand(PyObject *arg, void *dst) +int convert_to_immediate_operand(PyObject *arg, void *dst) { int result; /* Bilan à retourner */ - result = PyObject_IsInstance(arg, (PyObject *)get_python_imm_operand_type()); + result = PyObject_IsInstance(arg, (PyObject *)get_python_immediate_operand_type()); switch (result) { @@ -647,7 +601,7 @@ int convert_to_imm_operand(PyObject *arg, void *dst) break; case 1: - *((GImmOperand **)dst) = G_IMM_OPERAND(pygobject_get(arg)); + *((GImmediateOperand **)dst) = G_IMMEDIATE_OPERAND(pygobject_get(arg)); break; default: diff --git a/plugins/pychrysalide/arch/operands/immediate.h b/plugins/pychrysalide/arch/operands/immediate.h index 4a1e6de..8b8de83 100644 --- a/plugins/pychrysalide/arch/operands/immediate.h +++ b/plugins/pychrysalide/arch/operands/immediate.h @@ -2,7 +2,7 @@ /* Chrysalide - Outil d'analyse de fichiers binaires * immediate.h - prototypes pour l'équivalent Python du fichier "arch/operands/immediate.h" * - * Copyright (C) 2020 Cyrille Bagard + * Copyright (C) 2020-2025 Cyrille Bagard * * This file is part of Chrysalide. * @@ -32,13 +32,13 @@ /* Fournit un accès à une définition de type à diffuser. */ -PyTypeObject *get_python_imm_operand_type(void); +PyTypeObject *get_python_immediate_operand_type(void); -/* Prend en charge l'objet 'pychrysalide.arch.ImmOperand'. */ -bool ensure_python_imm_operand_is_registered(void); +/* Prend en charge l'objet 'pychrysalide.arch.ImmediateOperand'. */ +bool ensure_python_immediate_operand_is_registered(void); /* Tente de convertir en opérande de valeur immédiate. */ -int convert_to_imm_operand(PyObject *, void *); +int convert_to_immediate_operand(PyObject *, void *); diff --git a/plugins/pychrysalide/arch/operands/known.c b/plugins/pychrysalide/arch/operands/known.c index fab426e..85cabc2 100644 --- a/plugins/pychrysalide/arch/operands/known.c +++ b/plugins/pychrysalide/arch/operands/known.c @@ -2,7 +2,7 @@ /* Chrysalide - Outil d'analyse de fichiers binaires * known.c - équivalent Python du fichier "arch/operands/known.h" * - * Copyright (C) 2020 Cyrille Bagard + * Copyright (C) 2020-2025 Cyrille Bagard * * This file is part of Chrysalide. * @@ -29,70 +29,92 @@ #include <pygobject.h> -#include <arch/operands/known.h> +#include <arch/operands/known-int.h> #include "immediate.h" -#include "rename.h" #include "../../access.h" #include "../../helpers.h" -/* Crée un nouvel objet Python de type 'KnownImmOperand'. */ -static PyObject *py_known_imm_operand_new(PyTypeObject *, PyObject *, PyObject *); +/* ------------------------ GLUE POUR CREATION DEPUIS PYTHON ------------------------ */ +CREATE_DYN_CONSTRUCTOR(known_immediate_operand, G_TYPE_KNOWN_IMMEDIATE_OPERAND); + +/* Initialise une instance sur la base du dérivé de GObject. */ +static int py_known_immediate_operand_init(PyObject *, PyObject *, PyObject *); + + + +/* ---------------------------------------------------------------------------------- */ +/* GLUE POUR CREATION DEPUIS PYTHON */ +/* ---------------------------------------------------------------------------------- */ + /****************************************************************************** * * -* Paramètres : type = type de l'objet à instancier. * +* Paramètres : self = objet à initialiser (théoriquement). * * args = arguments fournis à l'appel. * * kwds = arguments de type key=val fournis. * * * -* Description : Crée un nouvel objet Python de type 'KnownImmOperand'. * +* Description : Initialise une instance sur la base du dérivé de GObject. * * * -* Retour : Instance Python mise en place. * +* Retour : 0. * * * * Remarques : - * * * ******************************************************************************/ -static PyObject *py_known_imm_operand_new(PyTypeObject *type, PyObject *args, PyObject *kwds) +static int py_known_immediate_operand_init(PyObject *self, PyObject *args, PyObject *kwds) { - PyObject *result; /* Instance à retourner */ - GImmOperand *imm; /* Opérande à remplacer */ + GImmediateOperand *imm; /* Opérande à remplacer */ const char *alt; /* Impression alternative */ int ret; /* Bilan de lecture des args. */ - GArchOperand *operand; /* Création GLib à transmettre */ - -#define KNOWN_IMM_OPERAND_DOC \ - "The KnownImmOperand provides replacement of" \ - " pychrysalide.arch.operands.ImmOperand instances by an alternative" \ - " text.\n" \ - "\n" \ - "Instances can be created using the following constructor:\n" \ - "\n" \ - " KnownImmOperand(imm, alt)" \ - "\n" \ - "Where imm is an operand of type pychrysalide.arch.operands.ImmOperand" \ - " and alt is a string providing the text to be rendered at object" \ + GKnownImmediateOperand *operand; /* Opérande natif à manipuler */ + +#define KNOWN_IMMEDIATE_OPERAND_DOC \ + "The KnownImmediateOperand provides replacement of" \ + " pychrysalide.arch.operands.ImmediateOperand instances by an alternative" \ + " text.\n" \ + "\n" \ + "Instances can be created using the following constructor:\n" \ + "\n" \ + " KnownImmediateOperand(imm, alt)" \ + "\n" \ + "Where *imm* is an operand of type pychrysalide.arch.operands.ImmediateOperand" \ + " and *alt* is a string providing the text to be rendered at object" \ " display." - ret = PyArg_ParseTuple(args, "O&s", convert_to_imm_operand, &imm, &alt); - if (!ret) return NULL; + /* Récupération des paramètres */ + + ret = PyArg_ParseTuple(args, "O&s", convert_to_immediate_operand, &imm, &alt); + if (!ret) return -1; + + /* Initialisation d'un objet GLib */ - operand = g_known_imm_operand_new(imm, alt); + ret = forward_pygobjet_init(self); + if (ret == -1) return -1; - result = pygobject_new(G_OBJECT(operand)); + /* Eléments de base */ - g_object_unref(operand); + operand = G_KNOWN_IMMEDIATE_OPERAND(pygobject_get(self)); - return (PyObject *)result; + if (!g_known_immediate_operand_create(operand, imm, alt)) + return -1; + + return 0; } + +/* ---------------------------------------------------------------------------------- */ +/* DEFINITION D'UN IMMEDIAT CONNU */ +/* ---------------------------------------------------------------------------------- */ + + /****************************************************************************** * * * Paramètres : - * @@ -105,34 +127,36 @@ static PyObject *py_known_imm_operand_new(PyTypeObject *type, PyObject *args, Py * * ******************************************************************************/ -PyTypeObject *get_python_known_imm_operand_type(void) +PyTypeObject *get_python_known_immediate_operand_type(void) { - static PyMethodDef py_known_imm_operand_methods[] = { + static PyMethodDef py_known_immediate_operand_methods[] = { { NULL } }; - static PyGetSetDef py_known_imm_operand_getseters[] = { + static PyGetSetDef py_known_immediate_operand_getseters[] = { { NULL } }; - static PyTypeObject py_known_imm_operand_type = { + static PyTypeObject py_known_immediate_operand_type = { PyVarObject_HEAD_INIT(NULL, 0) - .tp_name = "pychrysalide.arch.operands.KnownImmOperand", + .tp_name = "pychrysalide.arch.operands.KnownImmediateOperand", .tp_basicsize = sizeof(PyGObject), .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, - .tp_doc = KNOWN_IMM_OPERAND_DOC, + .tp_doc = KNOWN_IMMEDIATE_OPERAND_DOC, - .tp_methods = py_known_imm_operand_methods, - .tp_getset = py_known_imm_operand_getseters, - .tp_new = py_known_imm_operand_new + .tp_methods = py_known_immediate_operand_methods, + .tp_getset = py_known_immediate_operand_getseters, + + .tp_init = py_known_immediate_operand_init, + .tp_new = py_known_immediate_operand_new, }; - return &py_known_imm_operand_type; + return &py_known_immediate_operand_type; } @@ -141,7 +165,7 @@ PyTypeObject *get_python_known_imm_operand_type(void) * * * Paramètres : module = module dont la définition est à compléter. * * * -* Description : Prend en charge l'objet 'pychrysalide.arch.KnownImmOperand'. * +* Description : Prend en charge l'objet '....KnownImmediateOperand'. * * * * Retour : Bilan de l'opération. * * * @@ -149,13 +173,13 @@ PyTypeObject *get_python_known_imm_operand_type(void) * * ******************************************************************************/ -bool ensure_python_known_imm_operand_is_registered(void) +bool ensure_python_known_immediate_operand_is_registered(void) { - PyTypeObject *type; /* Type Python 'ImmOperand' */ + PyTypeObject *type; /* Type 'KnownImmediateOperand'*/ PyObject *module; /* Module à recompléter */ PyObject *dict; /* Dictionnaire du module */ - type = get_python_known_imm_operand_type(); + type = get_python_known_immediate_operand_type(); if (!PyType_HasFeature(type, Py_TPFLAGS_READY)) { @@ -163,13 +187,10 @@ bool ensure_python_known_imm_operand_is_registered(void) dict = PyModule_GetDict(module); - if (!ensure_python_imm_operand_is_registered()) - return false; - - if (!ensure_python_renamed_operand_is_registered()) + if (!ensure_python_immediate_operand_is_registered()) return false; - if (!register_class_for_pygobject(dict, G_TYPE_KNOWN_IMM_OPERAND, type)) + if (!register_class_for_pygobject(dict, G_TYPE_KNOWN_IMMEDIATE_OPERAND, type)) return false; } @@ -192,11 +213,11 @@ bool ensure_python_known_imm_operand_is_registered(void) * * ******************************************************************************/ -int convert_to_known_imm_operand(PyObject *arg, void *dst) +int convert_to_known_immediate_operand(PyObject *arg, void *dst) { int result; /* Bilan à retourner */ - result = PyObject_IsInstance(arg, (PyObject *)get_python_known_imm_operand_type()); + result = PyObject_IsInstance(arg, (PyObject *)get_python_known_immediate_operand_type()); switch (result) { @@ -210,7 +231,7 @@ int convert_to_known_imm_operand(PyObject *arg, void *dst) break; case 1: - *((GKnownImmOperand **)dst) = G_KNOWN_IMM_OPERAND(pygobject_get(arg)); + *((GKnownImmediateOperand **)dst) = G_KNOWN_IMMEDIATE_OPERAND(pygobject_get(arg)); break; default: diff --git a/plugins/pychrysalide/arch/operands/known.h b/plugins/pychrysalide/arch/operands/known.h index b5ced68..f5b80e8 100644 --- a/plugins/pychrysalide/arch/operands/known.h +++ b/plugins/pychrysalide/arch/operands/known.h @@ -2,7 +2,7 @@ /* Chrysalide - Outil d'analyse de fichiers binaires * known.h - prototypes pour l'équivalent Python du fichier "arch/operands/known.h" * - * Copyright (C) 2020 Cyrille Bagard + * Copyright (C) 2020-2025 Cyrille Bagard * * This file is part of Chrysalide. * @@ -32,13 +32,13 @@ /* Fournit un accès à une définition de type à diffuser. */ -PyTypeObject *get_python_known_imm_operand_type(void); +PyTypeObject *get_python_known_immediate_operand_type(void); -/* Prend en charge l'objet 'pychrysalide.arch.KnownImmOperand'. */ -bool ensure_python_known_imm_operand_is_registered(void); +/* Prend en charge l'objet 'pychrysalide.arch.KnownImmediateOperand'. */ +bool ensure_python_known_immediate_operand_is_registered(void); /* Tente de convertir en remplaçant d'opérande d'immédiat. */ -int convert_to_known_imm_operand(PyObject *, void *); +int convert_to_known_immediate_operand(PyObject *, void *); diff --git a/plugins/pychrysalide/arch/operands/module.c b/plugins/pychrysalide/arch/operands/module.c index 89adecc..486e259 100644 --- a/plugins/pychrysalide/arch/operands/module.c +++ b/plugins/pychrysalide/arch/operands/module.c @@ -28,14 +28,20 @@ #include <assert.h> +/* #include "feeder.h" +*/ #include "immediate.h" #include "known.h" +/* #include "proxy.h" +*/ #include "register.h" +/* #include "rename.h" #include "target.h" #include "targetable.h" +*/ #include "../../helpers.h" @@ -101,15 +107,21 @@ bool populate_arch_operands_module(void) result = true; + /* if (result) result = ensure_python_proxy_feeder_is_registered(); - if (result) result = ensure_python_imm_operand_is_registered(); - if (result) result = ensure_python_known_imm_operand_is_registered(); + */ + if (result) result = ensure_python_immediate_operand_is_registered(); + if (result) result = ensure_python_known_immediate_operand_is_registered(); + /* if (result) result = ensure_python_proxy_operand_is_registered(); + */ if (result) result = ensure_python_register_operand_is_registered(); + /* if (result) result = ensure_python_renamed_operand_is_registered(); if (result) result = ensure_python_renameable_operand_is_registered(); if (result) result = ensure_python_target_operand_is_registered(); if (result) result = ensure_python_targetable_operand_is_registered(); + */ assert(result); diff --git a/plugins/pychrysalide/arch/operands/register.c b/plugins/pychrysalide/arch/operands/register.c index 2a48a0f..707524a 100644 --- a/plugins/pychrysalide/arch/operands/register.c +++ b/plugins/pychrysalide/arch/operands/register.c @@ -2,7 +2,7 @@ /* Chrysalide - Outil d'analyse de fichiers binaires * register.c - équivalent Python du fichier "arch/operands/register.c" * - * Copyright (C) 2019-2020 Cyrille Bagard + * Copyright (C) 2019-2025 Cyrille Bagard * * This file is part of Chrysalide. * @@ -30,25 +30,19 @@ #include <i18n.h> #include <arch/operands/register-int.h> -#include <plugins/dt.h> #include "../operand.h" #include "../register.h" #include "../../access.h" #include "../../helpers.h" -#include "../../glibext/bufferline.h" /* ------------------------ GLUE POUR CREATION DEPUIS PYTHON ------------------------ */ -/* Accompagne la création d'une instance dérivée en Python. */ -static PyObject *py_register_operand_new(PyTypeObject *, PyObject *, PyObject *); - -/* Initialise la classe des descriptions de fichier binaire. */ -static void py_register_operand_init_gclass(GRegisterOperandClass *, gpointer); +CREATE_DYN_CONSTRUCTOR(register_operand, G_TYPE_REGISTER_OPERAND); /* Initialise une instance sur la base du dérivé de GObject. */ static int py_register_operand_init(PyObject *, PyObject *, PyObject *); @@ -58,12 +52,6 @@ static int py_register_operand_init(PyObject *, PyObject *, PyObject *); /* ------------------------- REGISTRE SOUS FORME D'OPERANDE ------------------------- */ -/* Compare un opérande avec un autre. */ -static PyObject *py_register_operand___cmp__(PyObject *, PyObject *); - -/* Traduit un opérande en version humainement lisible. */ -static PyObject *py_register_operand__print(PyObject *, PyObject *); - /* Fournit le registre associé à l'opérande. */ static PyObject *py_register_operand_get_register(PyObject *, void *); @@ -76,86 +64,6 @@ static PyObject *py_register_operand_get_register(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_register_operand_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_register_operand_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_REGISTER_OPERAND, type->tp_name, - (GClassInitFunc)py_register_operand_init_gclass, 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; - -} - - -/****************************************************************************** -* * -* Paramètres : class = classe à initialiser. * -* unused = données non utilisées ici. * -* * -* Description : Initialise la classe des descriptions de fichier binaire. * -* * -* Retour : - * -* * -* Remarques : - * -* * -******************************************************************************/ - -static void py_register_operand_init_gclass(GRegisterOperandClass *class, gpointer unused) -{ - -} - - -/****************************************************************************** -* * * Paramètres : self = objet à initialiser (théoriquement). * * args = arguments fournis à l'appel. * * kwds = arguments de type key=val fournis. * @@ -182,7 +90,7 @@ static int py_register_operand_init(PyObject *self, PyObject *args, PyObject *kw "\n" \ " RegisterOperand(reg)" \ "\n" \ - "Where reg is an architecture register defined from a subclass of" \ + "Where *reg* is an architecture register defined from a subclass of" \ " pychrysalide.arch.ArchRegister." /* Récupération des paramètres */ @@ -199,8 +107,8 @@ static int py_register_operand_init(PyObject *self, PyObject *args, PyObject *kw operand = G_REGISTER_OPERAND(pygobject_get(self)); - g_object_ref(G_OBJECT(reg)); - operand->reg = reg; + if (!g_register_operand_create(operand, reg)) + return -1; return 0; @@ -215,98 +123,6 @@ static int py_register_operand_init(PyObject *self, PyObject *args, PyObject *kw /****************************************************************************** * * -* Paramètres : self = serveur à manipuler. * -* args = arguments associés à l'appel. * -* * -* Description : Compare un opérande avec un autre. * -* * -* Retour : Bilan de l'opération. * -* * -* Remarques : - * -* * -******************************************************************************/ - -static PyObject *py_register_operand___cmp__(PyObject *self, PyObject *args) -{ - PyObject *result; /* Bilan à retourner */ - GRegisterOperand *other; /* Autre opérande à manipuler */ - int ret; /* Bilan de lecture des args. */ - GRegisterOperand *operand; /* Elément à manipuler */ - int status; /* Bilan de comparaison */ - -#define REGISTER_OPERAND_CMP_METHOD PYTHON_METHOD_DEF \ -( \ - __cmp__, "$self, other, /", \ - METH_VARARGS, py_register_operand, \ - "Implementation of the required method used to compare the" \ - " operand with another one. This second object is always" \ - " a pychrysalide.arch.RegisterOperand instance.\n" \ - "\n" \ - "See the parent class for more information about this method." \ -) - - ret = PyArg_ParseTuple(args, "O&", convert_to_register_operand, &other); - if (!ret) return NULL; - - operand = G_REGISTER_OPERAND(pygobject_get(self)); - - status = g_arch_operand_compare(G_ARCH_OPERAND(operand), G_ARCH_OPERAND(other)); - - result = PyLong_FromLong(status); - - return result; - -} - - -/****************************************************************************** -* * -* Paramètres : self = serveur à manipuler. * -* args = arguments associés à l'appel. * -* * -* Description : Traduit un opérande en version humainement lisible. * -* * -* Retour : Bilan de l'opération. * -* * -* Remarques : - * -* * -******************************************************************************/ - -static PyObject *py_register_operand__print(PyObject *self, PyObject *args) -{ - PyObject *result; /* Bilan à retourner */ - GBufferLine *line; /* Ligne fournie à peupler */ - int ret; /* Bilan de lecture des args. */ - GRegisterOperand *operand; /* Elément à manipuler */ - -#define REGISTER_OPERAND_PRINT_METHOD PYTHON_METHOD_DEF \ -( \ - _print, "$self, line, /", \ - METH_VARARGS, py_register_operand, \ - "Implementation of the required method used to print the operand" \ - " into a rendering line, which is a provided" \ - " pychrysalide.glibext.BufferLine instance.\n" \ - "\n" \ - "See the parent class for more information about this method." \ -) - - ret = PyArg_ParseTuple(args, "O&", convert_to_buffer_line, &line); - if (!ret) return NULL; - - operand = G_REGISTER_OPERAND(pygobject_get(self)); - - g_arch_operand_print(G_ARCH_OPERAND(operand), line); - - result = Py_None; - Py_INCREF(result); - - return result; - -} - - -/****************************************************************************** -* * * Paramètres : self = objet Python concerné par l'appel. * * closure = non utilisé ici. * * * @@ -367,8 +183,6 @@ static PyObject *py_register_operand_get_register(PyObject *self, void *closure) PyTypeObject *get_python_register_operand_type(void) { static PyMethodDef py_register_operand_methods[] = { - REGISTER_OPERAND_CMP_METHOD, - REGISTER_OPERAND_PRINT_METHOD, { NULL } }; diff --git a/plugins/pychrysalide/arch/register.c b/plugins/pychrysalide/arch/register.c index 615a5b7..7139e47 100644 --- a/plugins/pychrysalide/arch/register.c +++ b/plugins/pychrysalide/arch/register.c @@ -2,7 +2,7 @@ /* Chrysalide - Outil d'analyse de fichiers binaires * register.c - équivalent Python du fichier "arch/register.c" * - * Copyright (C) 2019 Cyrille Bagard + * Copyright (C) 2019-2025 Cyrille Bagard * * This file is part of Chrysalide. * @@ -31,32 +31,27 @@ #include <i18n.h> #include <arch/register-int.h> -#include <plugins/dt.h> #include "../access.h" #include "../helpers.h" -#include "../analysis/storage/serialize.h" +#include "../glibext/comparable.h" +#include "../glibext/hashable.h" +#include "../glibext/serialize.h" +#include "../glibext/strbuilder.h" /* ------------------------ GLUE POUR CREATION DEPUIS PYTHON ------------------------ */ -/* Accompagne la création d'une instance dérivée en Python. */ -static PyObject *py_arch_register_new(PyTypeObject *, PyObject *, PyObject *); - /* Initialise la classe des registres. */ -static void py_arch_register_init_gclass(GArchRegisterClass *, gpointer); - -/* Produit une empreinte à partir d'un registre. */ -static guint py_arch_register___hash___wrapper(const GArchRegister *); +static int py_arch_register_init_gclass(GArchRegisterClass *, PyTypeObject *); -/* Compare un registre avec un autre. */ -static int py_arch_register___cmp___wrapper(const GArchRegister *, const GArchRegister *); +CREATE_DYN_ABSTRACT_CONSTRUCTOR(arch_register, G_TYPE_ARCH_REGISTER); -/* Traduit un registre en version humainement lisible. */ -static void py_arch_register_print_wrapper(const GArchRegister *, GBufferLine *); +/* Initialise une instance sur la base du dérivé de GObject. */ +static int py_arch_register_init(PyObject *, PyObject *, PyObject *); /* Indique si le registre correspond à ebp ou similaire. */ static bool py_arch_register_is_base_pointer_wrapper(const GArchRegister *); @@ -69,9 +64,6 @@ static bool py_arch_register_is_stack_pointer_wrapper(const GArchRegister *); /* ---------------------------- PUR REGISTRE DU MATERIEL ---------------------------- */ -/* Effectue une comparaison avec un objet Python 'ArchRegister'. */ -static PyObject *py_arch_register_richcompare(PyObject *, PyObject *, int); - /* Indique si le registre correspond à ebp ou similaire. */ static PyObject *py_arch_register_is_base_pointer(PyObject *, void *); @@ -87,88 +79,8 @@ static PyObject *py_arch_register_is_stack_pointer(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_arch_register_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 registre */ - bool status; /* Bilan d'un enregistrement */ - -#define ARCH_REGISTER_DOC \ - "The ArchRegister object aims to get subclassed to create" \ - " registers suitable for new architectures.\n" \ - "\n" \ - "Calls to the *__init__* constructor of this abstract object expect"\ - " no particular argument.\n" \ - "\n" \ - "The following methods have to be defined for new classes:\n" \ - "* pychrysalide.arch.ArchRegister.__hash__();\n" \ - "* pychrysalide.arch.ArchRegister.__cmp__();\n" \ - "* pychrysalide.arch.ArchRegister._print();\n" \ - "* pychrysalide.arch.ArchRegister._is_base_pointer();\n" \ - "* pychrysalide.arch.ArchRegister._is_stack_pointer().\n" \ - "\n" \ - "Chrysalide creates an internal glue to provide rich comparisons" \ - " for registers based on the old-style *__cmp__* function." - - /* Validations diverses */ - - base = get_python_arch_register_type(); - - if (type == base) - { - result = NULL; - PyErr_Format(PyExc_RuntimeError, _("%s is an abstract class"), type->tp_name); - goto exit; - } - - /* Mise en place d'un type dédié */ - - first_time = (g_type_from_name(type->tp_name) == 0); - - gtype = build_dynamic_type(G_TYPE_ARCH_REGISTER, type->tp_name, - (GClassInitFunc)py_arch_register_init_gclass, 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() */ - - result = PyType_GenericNew(type, args, kwds); - - exit: - - return result; - -} - - -/****************************************************************************** -* * -* 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 des registres. * * * @@ -178,190 +90,51 @@ static PyObject *py_arch_register_new(PyTypeObject *type, PyObject *args, PyObje * * ******************************************************************************/ -static void py_arch_register_init_gclass(GArchRegisterClass *class, gpointer unused) -{ - class->hash = py_arch_register___hash___wrapper; - class->compare = py_arch_register___cmp___wrapper; - class->print = py_arch_register_print_wrapper; - class->is_bp = py_arch_register_is_base_pointer_wrapper; - class->is_sp = py_arch_register_is_stack_pointer_wrapper; - -} - - -/****************************************************************************** -* * -* Paramètres : reg = registre visé par la procédure. * -* * -* Description : Produit une empreinte à partir d'un registre. * -* * -* Retour : Bilan de l'opération. * -* * -* Remarques : - * -* * -******************************************************************************/ - -static guint py_arch_register___hash___wrapper(const GArchRegister *reg) -{ - guint result; /* Empreinte à retourner */ - PyGILState_STATE gstate; /* Sauvegarde d'environnement */ - PyObject *pyobj; /* Objet Python concerné */ - PyObject *pyret; /* Bilan de consultation */ - -#define ARCH_REGISTER_HASH_WRAPPER PYTHON_WRAPPER_DEF \ -( \ - __hash__, "$self, /", \ - METH_NOARGS, \ - "Abstract method used to produce a hash of the object. The" \ - " result must be an integer value." \ -) - - result = 0; - - gstate = PyGILState_Ensure(); - - pyobj = pygobject_new(G_OBJECT(reg)); - - if (has_python_method(pyobj, "__hash__")) - { - pyret = run_python_method(pyobj, "__hash__", NULL); - - if (pyret != NULL) - { - if (PyLong_Check(pyret)) - result = PyLong_AsUnsignedLong(pyret); - - Py_DECREF(pyret); - - } - - } - - Py_DECREF(pyobj); - - PyGILState_Release(gstate); - - return result; - -} - - -/****************************************************************************** -* * -* Paramètres : a = premier registre à consulter. * -* b = second registre à consulter. * -* * -* Description : Compare un registre avec un autre. * -* * -* Retour : Bilan de la comparaison. * -* * -* Remarques : - * -* * -******************************************************************************/ - -static int py_arch_register___cmp___wrapper(const GArchRegister *a, const GArchRegister *b) +static int py_arch_register_init_gclass(GArchRegisterClass *gclass, PyTypeObject *pyclass) { - int result; /* Empreinte à retourner */ - PyGILState_STATE gstate; /* Sauvegarde d'environnement */ - PyObject *pyobj; /* Objet Python concerné */ - PyObject *args; /* Arguments pour l'appel */ - PyObject *pyret; /* Bilan de consultation */ - -#define ARCH_REGISTER_CMP_WRAPPER PYTHON_WRAPPER_DEF \ -( \ - __cmp__, "$self, other, /", \ - METH_VARARGS, \ - "Abstract method used to compare the register with another" \ - " one. This second object is always an" \ - " pychrysalide.arch.ArchRegister instance.\n" \ - "\n" \ - " This is the Python old-style comparison method, but" \ - " Chrysalide provides a glue to automatically build a rich" \ - " version of this function." \ -) - - result = 0; - - gstate = PyGILState_Ensure(); - - pyobj = pygobject_new(G_OBJECT(a)); - - if (has_python_method(pyobj, "__cmp__")) - { - args = PyTuple_New(1); - PyTuple_SetItem(args, 0, pygobject_new(G_OBJECT(b))); - - pyret = run_python_method(pyobj, "__cmp__", args); - - if (pyret != NULL) - { - if (PyLong_Check(pyret)) - result = PyLong_AsLong(pyret); - } + PY_CLASS_SET_WRAPPER(gclass->is_bp, py_arch_register_is_base_pointer_wrapper); + PY_CLASS_SET_WRAPPER(gclass->is_sp, py_arch_register_is_stack_pointer_wrapper); - Py_DECREF(args); - - Py_XDECREF(pyret); - - } - - Py_DECREF(pyobj); - - PyGILState_Release(gstate); - - return result; + return 0; } /****************************************************************************** * * -* Paramètres : reg = registre visé par la procédure. * +* Paramètres : self = objet à initialiser (théoriquement). * +* args = arguments fournis à l'appel. * +* kwds = arguments de type key=val fournis. * * * -* Description : Traduit un registre en version humainement lisible. * +* Description : Initialise une instance sur la base du dérivé de GObject. * * * -* Retour : - * +* Retour : 0. * * * * Remarques : - * * * ******************************************************************************/ -static void py_arch_register_print_wrapper(const GArchRegister *reg, GBufferLine *line) +static int py_arch_register_init(PyObject *self, PyObject *args, PyObject *kwds) { - PyGILState_STATE gstate; /* Sauvegarde d'environnement */ - PyObject *pyobj; /* Objet Python concerné */ - PyObject *args; /* Arguments pour l'appel */ - PyObject *pyret; /* Bilan de consultation */ - -#define ARCH_REGISTER_PRINT_WRAPPER PYTHON_WRAPPER_DEF \ -( \ - _print, "$self, line, /", \ - METH_VARARGS, \ - "Abstract method used to print the register into a rendering" \ - " line, which is a provided pychrysalide.glibext.BufferLine" \ - " instance." \ -) - - gstate = PyGILState_Ensure(); - - pyobj = pygobject_new(G_OBJECT(reg)); - - if (has_python_method(pyobj, "_print")) - { - args = PyTuple_New(1); - PyTuple_SetItem(args, 0, pygobject_new(G_OBJECT(line))); - - pyret = run_python_method(pyobj, "_print", args); - - Py_DECREF(args); + int ret; /* Bilan de lecture des args. */ - Py_XDECREF(pyret); +#define ARCH_REGISTER_DOC \ + "The ArchRegister object aims to get subclassed in order to create" \ + " registers suitable for new architectures.\n" \ + "\n" \ + "Calls to the *__init__* constructor of this abstract object expect"\ + " no particular argument.\n" \ + "\n" \ + "The following methods may to be implemnted for new classes:\n" \ + "* pychrysalide.arch.ArchRegister._is_base_pointer();\n" \ + "* pychrysalide.arch.ArchRegister._is_stack_pointer().\n" - } + /* Initialisation d'un objet GLib */ - Py_DECREF(pyobj); + ret = forward_pygobjet_init(self); + if (ret == -1) return -1; - PyGILState_Release(gstate); + return 0; } @@ -486,51 +259,6 @@ static bool py_arch_register_is_stack_pointer_wrapper(const GArchRegister *reg) /****************************************************************************** * * -* Paramètres : a = premier object Python à consulter. * -* b = second object Python à consulter. * -* op = type de comparaison menée. * -* * -* Description : Effectue une comparaison avec un objet Python 'ArchRegister'.* -* * -* Retour : Bilan de l'opération. * -* * -* Remarques : - * -* * -******************************************************************************/ - -static PyObject *py_arch_register_richcompare(PyObject *a, PyObject *b, int op) -{ - PyObject *result; /* Bilan à retourner */ - int ret; /* Bilan de lecture des args. */ - const GArchRegister *reg_a; /* Premier élément à traiter */ - const GArchRegister *reg_b; /* Second élément à traiter */ - int status; /* Résultat d'une comparaison */ - - ret = PyObject_IsInstance(b, (PyObject *)get_python_arch_register_type()); - if (!ret) - { - result = Py_NotImplemented; - goto cmp_done; - } - - reg_a = G_ARCH_REGISTER(pygobject_get(a)); - reg_b = G_ARCH_REGISTER(pygobject_get(b)); - - status = py_arch_register___cmp___wrapper(reg_a, reg_b); - - result = status_to_rich_cmp_state(status, op); - - cmp_done: - - Py_INCREF(result); - - return result; - -} - - -/****************************************************************************** -* * * Paramètres : self = objet Python concerné par l'appel. * * closure = non utilisé ici. * * * @@ -618,9 +346,6 @@ static PyObject *py_arch_register_is_stack_pointer(PyObject *self, void *closure PyTypeObject *get_python_arch_register_type(void) { static PyMethodDef py_arch_register_methods[] = { - ARCH_REGISTER_HASH_WRAPPER, - ARCH_REGISTER_CMP_WRAPPER, - ARCH_REGISTER_PRINT_WRAPPER, ARCH_REGISTER_IS_BASE_POINTER_WRAPPER, ARCH_REGISTER_IS_STACK_POINTER_WRAPPER, { NULL } @@ -643,11 +368,10 @@ PyTypeObject *get_python_arch_register_type(void) .tp_doc = ARCH_REGISTER_DOC, - .tp_richcompare = py_arch_register_richcompare, - .tp_methods = py_arch_register_methods, .tp_getset = py_arch_register_getseters, + .tp_init = py_arch_register_init, .tp_new = py_arch_register_new, }; @@ -683,9 +407,20 @@ bool ensure_python_arch_register_is_registered(void) dict = PyModule_GetDict(module); + if (!ensure_python_comparable_object_is_registered()) + return false; + + if (!ensure_python_hashable_object_is_registered()) + return false; + if (!ensure_python_serializable_object_is_registered()) return false; + if (!ensure_python_string_builder_is_registered()) + return false; + + pyg_register_class_init(G_TYPE_ARCH_REGISTER, (PyGClassInitFunc)py_arch_register_init_gclass); + if (!register_class_for_pygobject(dict, G_TYPE_ARCH_REGISTER, type)) return false; 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/common/Makefile.am b/plugins/pychrysalide/common/Makefile.am index 43e1fc4..ad58900 100644 --- a/plugins/pychrysalide/common/Makefile.am +++ b/plugins/pychrysalide/common/Makefile.am @@ -6,7 +6,6 @@ noinst_LTLIBRARIES = libpychrysacommon.la # fnv1a.h fnv1a.c \ # hex.h hex.c \ # itoa.h itoa.c \ -# leb128.h leb128.c \ # module.h module.c \ # packed.h packed.c \ # pathname.h pathname.c \ @@ -15,6 +14,7 @@ noinst_LTLIBRARIES = libpychrysacommon.la libpychrysacommon_la_SOURCES = \ bits.h bits.c \ entropy.h entropy.c \ + leb128.h leb128.c \ module.h module.c \ xdg.h xdg.c diff --git a/plugins/pychrysalide/common/leb128.c b/plugins/pychrysalide/common/leb128.c index 8b15303..2eeb191 100644 --- a/plugins/pychrysalide/common/leb128.c +++ b/plugins/pychrysalide/common/leb128.c @@ -2,7 +2,7 @@ /* Chrysalide - Outil d'analyse de fichiers binaires * leb128.c - équivalent Python du fichier "common/leb128.c" * - * Copyright (C) 2018-2020 Cyrille Bagard + * Copyright (C) 2018-2025 Cyrille Bagard * * This file is part of Chrysalide. * @@ -26,13 +26,13 @@ #include <assert.h> +#include <malloc.h> #include <pygobject.h> #include <common/leb128.h> -#include "packed.h" #include "../access.h" #include "../helpers.h" @@ -69,31 +69,29 @@ static PyObject *py_leb128_pack_uleb128(PyObject *self, PyObject *args) { PyObject *result; /* Valeur à retourner */ uleb128_t value; /* Valeur à manipuler */ - packed_buffer_t *pbuf; /* Tampon de données à employer*/ int ret; /* Bilan de lecture des args. */ - bool status; /* Bilan de l'opération */ - -#define LEB128_PACK_ULEB128_METHOD PYTHON_METHOD_DEF \ -( \ - pack_uleb128, "value, pbuf", \ - METH_VARARGS, py_leb128, \ - "Pack an unsigned LEB128 value into a data buffer.\n" \ - "\n" \ - "The *value* is an integer value. The *pbuf* argument has to" \ - " be a pychrysalide.common.PackedBuffer instance where data" \ - " will be appended.\n" \ - "\n" \ - "The returned value is the operation status: *True* for" \ - " success, *False* for failure." \ + size_t count; /* Nombre d'octets produits */ + void *bytes; /* Octets de représentation */ + +#define LEB128_PACK_ULEB128_METHOD PYTHON_METHOD_DEF \ +( \ + pack_uleb128, "value", \ + METH_VARARGS, py_leb128, \ + "Pack an unsigned LEB128 value into bytes.\n" \ + "\n" \ + "The *value* has to be an integer value.\n" \ + "\n" \ + "The returned value is byte data." \ ) - ret = PyArg_ParseTuple(args, "O&O&", convert_to_uleb128_value, &value, convert_to_packed_buffer, &pbuf); + ret = PyArg_ParseTuple(args, "O&", convert_to_uleb128_value, &value); if (!ret) return NULL; - status = pack_uleb128(&value, pbuf); + bytes = pack_uleb128(&value, &count); - result = status ? Py_True : Py_False; - Py_INCREF(result); + result = PyBytes_FromStringAndSize(bytes, count); + + free(bytes); return result; @@ -117,31 +115,29 @@ static PyObject *py_leb128_pack_leb128(PyObject *self, PyObject *args) { PyObject *result; /* Valeur à retourner */ leb128_t value; /* Valeur à manipuler */ - packed_buffer_t *pbuf; /* Tampon de données à employer*/ int ret; /* Bilan de lecture des args. */ - bool status; /* Bilan de l'opération */ - -#define LEB128_PACK_LEB128_METHOD PYTHON_METHOD_DEF \ -( \ - pack_leb128, "value, pbuf", \ - METH_VARARGS, py_leb128, \ - "Pack a signed LEB128 value into a data buffer.\n" \ - "\n" \ - "The *value* is an integer value. The *pbuf* argument has to" \ - " be a pychrysalide.common.PackedBuffer instance where data" \ - " will be appended.\n" \ - "\n" \ - "The returned value is the operation status: *True* for" \ - " success, *False* for failure." \ + size_t count; /* Nombre d'octets produits */ + void *bytes; /* Octets de représentation */ + +#define LEB128_PACK_LEB128_METHOD PYTHON_METHOD_DEF \ +( \ + pack_leb128, "value", \ + METH_VARARGS, py_leb128, \ + "Pack a signed LEB128 value into bytes.\n" \ + "\n" \ + "The *value* has to be an integer value.\n" \ + "\n" \ + "The returned value is byte data." \ ) - ret = PyArg_ParseTuple(args, "O&O&", convert_to_leb128_value, &value, convert_to_packed_buffer, &pbuf); + ret = PyArg_ParseTuple(args, "O&", convert_to_leb128_value, &value); if (!ret) return NULL; - status = pack_leb128(&value, pbuf); + bytes = pack_leb128(&value, &count); + + result = PyBytes_FromStringAndSize(bytes, count); - result = status ? Py_True : Py_False; - Py_INCREF(result); + free(bytes); return result; @@ -164,33 +160,42 @@ static PyObject *py_leb128_pack_leb128(PyObject *self, PyObject *args) static PyObject *py_leb128_unpack_uleb128(PyObject *self, PyObject *args) { PyObject *result; /* Valeur à retourner */ - packed_buffer_t *pbuf; /* Tampon de données à employer*/ + const char *bytes; /* Octets brutes transmis */ + Py_ssize_t count; /* Quantité de ces octets */ int ret; /* Bilan de lecture des args. */ + const void *pos; /* Tëte de lecture */ + const void *max; /* Position de lecture maximale*/ uleb128_t value; /* Valeur à manipuler */ bool status; /* Bilan de l'opération */ #define LEB128_UNPACK_ULEB128_METHOD PYTHON_METHOD_DEF \ ( \ - unpack_uleb128, "pbuf", \ + unpack_uleb128, "buf", \ METH_VARARGS, py_leb128, \ - "Unpack an unsigned LEB128 value into a data buffer.\n" \ + "Unpack an unsigned LEB128 value from bytes.\n" \ "\n" \ - "The *pbuf* argument has to be a" \ - " pychrysalide.common.PackedBuffer instance from where data" \ - " will be read.\n" \ + "The *buf* argument needs to be bytes with enough data aimed" \ + " to get translated into an unsigned LEB128 value.\n" \ "\n" \ "The returned value depends on the operation status: *None*" \ - " for failure or a integer value for success." \ + " for failure or a tuple with two items for success: the" \ + " decoded value and the remaining bytes." \ ) - ret = PyArg_ParseTuple(args, "O&", convert_to_packed_buffer, &pbuf); + ret = PyArg_ParseTuple(args, "y#", &bytes, &count); if (!ret) return NULL; - status = unpack_uleb128(&value, pbuf); + pos = bytes; + max = bytes + count; - if (status) - result = PyLong_FromUnsignedLongLong(value); + status = unpack_uleb128(&value, &pos, max); + if (status) + { + result = PyTuple_New(2); + PyTuple_SetItem(result, 0, PyLong_FromUnsignedLongLong(value)); + PyTuple_SetItem(result, 1, PyBytes_FromStringAndSize(pos, (char *)max - (char *)pos)); + } else { result = Py_None; @@ -218,33 +223,43 @@ static PyObject *py_leb128_unpack_uleb128(PyObject *self, PyObject *args) static PyObject *py_leb128_unpack_leb128(PyObject *self, PyObject *args) { PyObject *result; /* Valeur à retourner */ - packed_buffer_t *pbuf; /* Tampon de données à employer*/ + const char *bytes; /* Octets brutes transmis */ + Py_ssize_t count; /* Quantité de ces octets */ int ret; /* Bilan de lecture des args. */ + const void *pos; /* Tëte de lecture */ + const void *max; /* Position de lecture maximale*/ leb128_t value; /* Valeur à manipuler */ bool status; /* Bilan de l'opération */ #define LEB128_UNPACK_LEB128_METHOD PYTHON_METHOD_DEF \ ( \ - unpack_leb128, "pbuf", \ + unpack_leb128, "buf", \ METH_VARARGS, py_leb128, \ - "Unpack a signed LEB128 value into a data buffer.\n" \ + "Unpack a signed LEB128 value from bytes.\n" \ "\n" \ - "The *pbuf* argument has to be a" \ - " pychrysalide.common.PackedBuffer instance from where data" \ - " will be read.\n" \ + "\n" \ + "The *buf* argument needs to be bytes with enough data aimed" \ + " to get translated into a signed LEB128 value.\n" \ "\n" \ "The returned value depends on the operation status: *None*" \ - " for failure or a integer value for success." \ + " for failure or a tuple with two items for success: the" \ + " decoded value and the remaining bytes." \ ) - ret = PyArg_ParseTuple(args, "O&", convert_to_packed_buffer, &pbuf); + ret = PyArg_ParseTuple(args, "y#", &bytes, &count); if (!ret) return NULL; - status = unpack_leb128(&value, pbuf); + pos = bytes; + max = bytes + count; - if (status) - result = PyLong_FromLongLong(value); + status = unpack_leb128(&value, &pos, max); + if (status) + { + result = PyTuple_New(2); + PyTuple_SetItem(result, 0, PyLong_FromLongLong(value)); + PyTuple_SetItem(result, 1, PyBytes_FromStringAndSize(pos, (char *)max - (char *)pos)); + } else { result = Py_None; diff --git a/plugins/pychrysalide/common/module.c b/plugins/pychrysalide/common/module.c index fa2b4de..c82c7bc 100644 --- a/plugins/pychrysalide/common/module.c +++ b/plugins/pychrysalide/common/module.c @@ -30,7 +30,7 @@ //#include "fnv1a.h" //#include "hex.h" //#include "itoa.h" -//#include "leb128.h" +#include "leb128.h" //#include "packed.h" //#include "pathname.h" //#include "pearson.h" @@ -104,11 +104,11 @@ bool populate_common_module(void) if (result) result = populate_common_module_with_fnv1a(); if (result) result = populate_common_module_with_hex(); if (result) result = populate_common_module_with_itoa(); - if (result) result = populate_common_module_with_leb128(); if (result) result = populate_common_module_with_pathname(); if (result) result = populate_common_module_with_pearson(); */ if (result) result = populate_common_module_with_entropy(); + if (result) result = populate_common_module_with_leb128(); if (result) result = populate_common_module_with_xdg(); if (result) result = ensure_python_bitfield_is_registered(); diff --git a/plugins/pychrysalide/constants.h b/plugins/pychrysalide/constants.h index 332afe0..151f1eb 100644 --- a/plugins/pychrysalide/constants.h +++ b/plugins/pychrysalide/constants.h @@ -46,6 +46,9 @@ int convert_to_source_endian(PyObject *, void *); /* Tente de convertir en constante MemoryDataSize. */ int convert_to_memory_data_size(PyObject *, void *); +#define cast_memory_data_size_to_python(v) \ + cast_with_constants_group_from_module("pychrysalide", "MemoryDataSize", v) + #endif /* _PLUGINS_PYCHRYSALIDE_CONSTANTS_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 1b332b7..00d1cc1 100644 --- a/plugins/pychrysalide/core-ui.c +++ b/plugins/pychrysalide/core-ui.c @@ -28,11 +28,19 @@ #include <i18n.h> +#ifdef DISCARD_LOCAL +# include <core/paths.h> +#endif +#include <plugins/manager-int.h> #include <plugins/self.h> #include "bindings.h" #include "core-ui-int.h" +#include "arch/module-ui.h" +#include "glibext/module-ui.h" +#include "gtkext/module.h" +//#include "gui/module.h" @@ -47,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 *); @@ -62,7 +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(bool); @@ -72,7 +102,8 @@ static bool g_pychrysalide_plugin_ui_enable(GPyChrysalidePluginUI *); /* 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); @@ -97,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; } @@ -127,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. * * * @@ -137,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. * * * @@ -156,16 +206,16 @@ 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); } /****************************************************************************** * * -* Paramètres : filename = nom du fichier à charger. * +* Paramètres : module = extension vue du système. * * * * Description : Crée un module pour un greffon de support Python. * * * @@ -192,7 +242,7 @@ GPluginModule *g_pychrysalide_plugin_ui_new(GModule *module) /****************************************************************************** * * * Paramètres : plugin = instance à initialiser pleinement. * -* module = module système correspondant. * +* module = extension vue du système. * * * * Description : Met en place un module pour un greffon de support Python. * * * @@ -231,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; @@ -258,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 : @@ -273,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); @@ -286,12 +338,139 @@ 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 : 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. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static bool populate_python_modules_ui(bool modify) +{ + bool result; /* Bilan à retourner */ + + result = true; + + 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; + +} + + +/****************************************************************************** +* * * Paramètres : - * * * * Description : Point d'entrée pour l'initialisation de Python. * @@ -309,7 +488,8 @@ PyMODINIT_FUNC PyInit_pychrysalideui(void) details.standalone = _standalone; - details.populate_extra = NULL; + details.add_extra = add_python_ui_modules; + details.populate_extra = populate_python_modules_ui; details.create_self = g_pychrysalide_plugin_ui_new; result = init_python_pychrysalide_module(&details); diff --git a/plugins/pychrysalide/core.c b/plugins/pychrysalide/core.c index 0e72b46..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,16 +220,16 @@ 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); } /****************************************************************************** * * -* Paramètres : filename = nom du fichier à charger. * +* Paramètres : module = extension vue du système. * * * * Description : Crée un module pour un greffon de support Python. * * * @@ -278,7 +256,7 @@ GPluginModule *g_pychrysalide_plugin_new(GModule *module) /****************************************************************************** * * * Paramètres : plugin = instance à initialiser pleinement. * -* module = module système correspondant. * +* module = extension vue du système. * * * * Description : Met en place un module pour un greffon de support Python. * * * @@ -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/Makefile.am b/plugins/pychrysalide/glibext/Makefile.am index af1d9f2..6d3d746 100644 --- a/plugins/pychrysalide/glibext/Makefile.am +++ b/plugins/pychrysalide/glibext/Makefile.am @@ -1,14 +1,11 @@ -noinst_LTLIBRARIES = libpychrysaglibext.la +noinst_LTLIBRARIES = libpychrysaglibext.la libpychrysaglibextui.la # libpychrysaglibext_la_SOURCES = \ # binarycursor.h binarycursor.c \ # buffercache.h buffercache.c \ -# bufferline.h bufferline.c \ # configuration.h configuration.c \ -# linecursor.h linecursor.c \ -# linegen.h linegen.c \ -# module.h module.c +# linecursor.h linecursor.c # if BUILD_GTK_SUPPORT @@ -27,7 +24,9 @@ libpychrysaglibext_la_SOURCES = \ objhole.h objhole.c \ portion.h portion.c \ secstorage.h secstorage.c \ + serialize.h serialize.c \ singleton.h singleton.c \ + storage.h storage.c \ strbuilder.h strbuilder.c \ work.h work.c \ workqueue.h workqueue.c @@ -36,6 +35,16 @@ libpychrysaglibext_la_CFLAGS = $(TOOLKIT_CFLAGS) $(LIBPYTHON_INTERPRETER_CFLAGS) -I$(top_srcdir)/src -DNO_IMPORT_PYGOBJECT +libpychrysaglibextui_la_SOURCES = \ + bufferline.h bufferline.c \ + constants-ui.h constants-ui.c \ + generator.h generator.c \ + module-ui.h module-ui.c + +libpychrysaglibextui_la_CFLAGS = $(TOOLKIT_CFLAGS) $(LIBPYTHON_INTERPRETER_CFLAGS) $(LIBPYGOBJECT_CFLAGS) \ + -I$(top_srcdir)/src -DNO_IMPORT_PYGOBJECT + + devdir = $(includedir)/chrysalide/$(subdir) -dev_HEADERS = $(libpychrysaglibext_la_SOURCES:%c=) +dev_HEADERS = $(libpychrysaglibext_la_SOURCES:%c=) $(libpychrysaglibextui_la_SOURCES:%c=) diff --git a/plugins/pychrysalide/glibext/bufferline.c b/plugins/pychrysalide/glibext/bufferline.c index 09404bc..c5b3664 100644 --- a/plugins/pychrysalide/glibext/bufferline.c +++ b/plugins/pychrysalide/glibext/bufferline.c @@ -2,7 +2,7 @@ /* Chrysalide - Outil d'analyse de fichiers binaires * bufferline.c - équivalent Python du fichier "glibext/bufferline.h" * - * Copyright (C) 2018-2019 Cyrille Bagard + * Copyright (C) 2018-2025 Cyrille Bagard * * This file is part of Chrysalide. * @@ -26,25 +26,38 @@ #include <assert.h> -#include <malloc.h> +//#include <malloc.h> #include <pygobject.h> -#include <i18n.h> -#include <glibext/bufferline.h> -#include <plugins/dt.h> +#include <glibext/bufferline-int.h> -#include "constants.h" +//#include "constants.h" #include "../access.h" #include "../helpers.h" -#include "../arch/vmpa.h" +//#include "../arch/vmpa.h" +/* ------------------------ GLUE POUR CREATION DEPUIS PYTHON ------------------------ */ + + +CREATE_DYN_CONSTRUCTOR(buffer_line, G_TYPE_BUFFER_LINE); + +/* Initialise une instance sur la base du dérivé de GObject. */ +static int py_buffer_line_init(PyObject *, PyObject *, PyObject *); + + + +/* ------------------ LIAISON DE FONCTIONNALITES AVEC L'API PYTHON ------------------ */ + + /* Accompagne la création d'une instance dérivée en Python. */ static PyObject *py_buffer_line_new(PyTypeObject *, PyObject *, PyObject *); +#if 0 + /* Ajoute du texte à formater dans une ligne donnée. */ static PyObject *py_buffer_line_append_text(PyObject *, PyObject *); @@ -54,29 +67,34 @@ static PyObject *py_buffer_line_get_text(PyObject *, PyObject *); /* Renseigne sur les propriétés particulières liées à une ligne. */ static PyObject *py_buffer_line_get_flags(PyObject *, void *); +#endif + + + +/* ---------------------------------------------------------------------------------- */ +/* GLUE POUR CREATION DEPUIS PYTHON */ +/* ---------------------------------------------------------------------------------- */ /****************************************************************************** * * -* Paramètres : type = type du nouvel objet à mettre en place. * -* args = éventuelle liste d'arguments. * -* kwds = éventuel dictionnaire de valeurs mises à disposition. * +* Paramètres : self = objet à initialiser (théoriquement). * +* args = arguments fournis à l'appel. * +* kwds = arguments de type key=val fournis. * * * -* Description : Accompagne la création d'une instance dérivée en Python. * +* Description : Initialise une instance sur la base du dérivé de GObject. * * * -* Retour : Nouvel objet Python mis en place ou NULL en cas d'échec. * +* Retour : 0. * * * * Remarques : - * * * ******************************************************************************/ -static PyObject *py_buffer_line_new(PyTypeObject *type, PyObject *args, PyObject *kwds) +static int py_buffer_line_init(PyObject *self, 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 */ + unsigned char col_count; /* Qté de colonnes attendues */ + int ret; /* Bilan de lecture des args. */ + GBufferLine *line; /* Ligne en version native */ #define BUFFER_LINE_DOC \ "The BufferLine object is used to display processed data: disassembled" \ @@ -84,51 +102,40 @@ static PyObject *py_buffer_line_new(PyTypeObject *type, PyObject *args, PyObject "\n" \ "Instances can be created using the following constructor:\n" \ "\n" \ - " BufferLine()" \ + " BufferLine(col_count)" \ + "\n" \ + " Where *col_count* is a integer value providing the expected number of"\ + " rendering columns." \ "\n" \ "Such objets aim to be created from the Chrysalide core only, and" \ " then get populated on demand. Thus, these lines can be viewed as" \ " cached lines and their properties have to be set through the" \ " pychrysalide.glibext.BufferCache instance which contains them." - /* Validations diverses */ - - base = get_python_buffer_line_type(); + /* Récupération des paramètres */ - if (type == base) - goto simple_way; + ret = PyArg_ParseTuple(args, "B", &col_count); + if (!ret) return -1; - /* Mise en place d'un type dédié */ + /* Initialisation d'un objet GLib */ - first_time = (g_type_from_name(type->tp_name) == 0); + ret = forward_pygobjet_init(self); + if (ret == -1) return -1; - gtype = build_dynamic_type(G_TYPE_BUFFER_LINE, type->tp_name, NULL, NULL, NULL); - - if (first_time) - { - status = register_class_for_dynamic_pygobject(gtype, type); + /* Eléments de base */ - 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); + line = G_BUFFER_LINE(pygobject_get(self)); - exit: + if (!g_buffer_line_create(line, col_count)) + return -1; - return result; + return 0; } +#if 0 + /****************************************************************************** * * * Paramètres : self = classe représentant une ligne de tampon. * @@ -256,6 +263,7 @@ static PyObject *py_buffer_line_get_flags(PyObject *self, void *closure) return result; } +#endif /****************************************************************************** @@ -273,20 +281,24 @@ static PyObject *py_buffer_line_get_flags(PyObject *self, void *closure) PyTypeObject *get_python_buffer_line_type(void) { static PyMethodDef py_buffer_line_methods[] = { + /* BUFFER_LINE_APPEND_TEXT_METHOD, { "get_text", py_buffer_line_get_text, METH_VARARGS, "get_text($self, first_col, last_col, markup, /)\n--\n\nProvide the text of a buffer line." }, + */ { NULL } }; static PyGetSetDef py_buffer_line_getseters[] = { + /* { "flags", py_buffer_line_get_flags, NULL, "Current flags of the buffer line.", NULL }, + */ { NULL } }; @@ -304,7 +316,8 @@ PyTypeObject *get_python_buffer_line_type(void) .tp_methods = py_buffer_line_methods, .tp_getset = py_buffer_line_getseters, - .tp_new = py_buffer_line_new + .tp_init = py_buffer_line_init, + .tp_new = py_buffer_line_new, }; @@ -342,11 +355,13 @@ bool ensure_python_buffer_line_is_registered(void) if (!register_class_for_pygobject(dict, G_TYPE_BUFFER_LINE, type)) return false; + /* if (!define_line_segment_constants(type)) return false; if (!define_buffer_line_constants(type)) return false; + */ } diff --git a/plugins/pychrysalide/glibext/constants-ui.c b/plugins/pychrysalide/glibext/constants-ui.c new file mode 100644 index 0000000..4101600 --- /dev/null +++ b/plugins/pychrysalide/glibext/constants-ui.c @@ -0,0 +1,131 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * constants-ui.c - ajout des constantes pour les extensions graphique à la GLib + * + * 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 "constants-ui.h" + + +#include <glibext/bufferline.h> + + +#include "../helpers.h" + + + +/****************************************************************************** +* * +* Paramètres : type = type dont le dictionnaire est à compléter. * +* * +* Description : Définit les constantes relatives aux lignes de tampon. * +* * +* Retour : true en cas de succès de l'opération, false sinon. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool define_buffer_line_constants(PyTypeObject *type) +{ + bool result; /* Bilan à retourner */ + PyObject *values; /* Groupe de valeurs à établir */ + + values = PyDict_New(); + + result = add_const_to_group(values, "NONE", BLF_NONE); + if (result) result = add_const_to_group(values, "HAS_CODE", BLF_HAS_CODE); + if (result) result = add_const_to_group(values, "IS_LABEL", BLF_IS_LABEL); + if (result) result = add_const_to_group(values, "ENTRYPOINT", BLF_ENTRYPOINT); + if (result) result = add_const_to_group(values, "BOOKMARK", BLF_BOOKMARK); + if (result) result = add_const_to_group(values, "WIDTH_MANAGER", BLF_WIDTH_MANAGER); + if (result) result = add_const_to_group(values, "ALL", BLF_ALL); + + if (!result) + { + Py_DECREF(values); + goto exit; + } + + result = attach_constants_group_to_type(type, true, "BufferLineFlags", values, + "Optional flags linked to a rendering line."); + + exit: + + 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 BufferLineFlags. * +* * +* Retour : Bilan de l'opération, voire indications supplémentaires. * +* * +* Remarques : - * +* * +******************************************************************************/ + +int convert_to_buffer_line_flags(PyObject *arg, void *dst) +{ + int result; /* Bilan à retourner */ + unsigned long value; /* Valeur transcrite */ + + 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 BufferLineFlags"); + break; + + case 1: + value = PyLong_AsUnsignedLong(arg); + + if ((value & BLF_ALL) != value) + { + PyErr_SetString(PyExc_TypeError, "invalid value for BufferLineFlags"); + result = 0; + } + + else + *((BufferLineFlags *)dst) = value; + + break; + + default: + assert(false); + break; + + } + + return result; + +} diff --git a/plugins/pychrysalide/glibext/constants-ui.h b/plugins/pychrysalide/glibext/constants-ui.h new file mode 100644 index 0000000..6c7bc6e --- /dev/null +++ b/plugins/pychrysalide/glibext/constants-ui.h @@ -0,0 +1,41 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * constants-ui.h - prototypes pour l'ajout des constantes pour les extensions graphique à la GLib + * + * 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_GLIBEXT_CONSTANTS_UI_H +#define _PLUGINS_PYCHRYSALIDE_GLIBEXT_CONSTANTS_UI_H + + +#include <Python.h> +#include <stdbool.h> + + +/* Définit les constantes relatives aux lignes de tampon. */ +bool define_buffer_line_constants(PyTypeObject *); + +/* Tente de convertir en constante BufferLineFlags. */ +int convert_to_buffer_line_flags(PyObject *, void *); + + + +#endif /* _PLUGINS_PYCHRYSALIDE_GLIBEXT_CONSTANTS_UI_H */ diff --git a/plugins/pychrysalide/glibext/constants.c b/plugins/pychrysalide/glibext/constants.c index 90ce8cd..f733cf6 100644 --- a/plugins/pychrysalide/glibext/constants.c +++ b/plugins/pychrysalide/glibext/constants.c @@ -29,7 +29,6 @@ /* #include <i18n.h> -#include <glibext/bufferline.h> #include <glibext/comparison.h> #include <glibext/configuration.h> #include <glibext/linesegment.h> @@ -159,105 +158,6 @@ int convert_to_portion_access_rights(PyObject *arg, void *dst) * * * Paramètres : type = type dont le dictionnaire est à compléter. * * * -* Description : Définit les constantes relatives aux lignes de tampon. * -* * -* Retour : true en cas de succès de l'opération, false sinon. * -* * -* Remarques : - * -* * -******************************************************************************/ - -bool define_buffer_line_constants(PyTypeObject *type) -{ - bool result; /* Bilan à retourner */ - PyObject *values; /* Groupe de valeurs à établir */ - - values = PyDict_New(); - - result = add_const_to_group(values, "NONE", BLF_NONE); - if (result) result = add_const_to_group(values, "HAS_CODE", BLF_HAS_CODE); - if (result) result = add_const_to_group(values, "IS_LABEL", BLF_IS_LABEL); - if (result) result = add_const_to_group(values, "ENTRYPOINT", BLF_ENTRYPOINT); - if (result) result = add_const_to_group(values, "BOOKMARK", BLF_BOOKMARK); - if (result) result = add_const_to_group(values, "WIDTH_MANAGER", BLF_WIDTH_MANAGER); - if (result) result = add_const_to_group(values, "ALL", BLF_ALL); - - if (!result) - { - Py_DECREF(values); - goto exit; - } - - result = attach_constants_group_to_type(type, true, "BufferLineFlags", values, - "Optional flags linked to a rendering line."); - - exit: - - 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 BufferLineFlags. * -* * -* Retour : Bilan de l'opération, voire indications supplémentaires. * -* * -* Remarques : - * -* * -******************************************************************************/ - -int convert_to_buffer_line_flags(PyObject *arg, void *dst) -{ - int result; /* Bilan à retourner */ - unsigned long value; /* Valeur transcrite */ - - 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 BufferLineFlags"); - break; - - case 1: - value = PyLong_AsUnsignedLong(arg); - - if ((value & BLF_ALL) != value) - { - PyErr_SetString(PyExc_TypeError, "invalid value for BufferLineFlags"); - result = 0; - } - - else - *((BufferLineFlags *)dst) = value; - - break; - - default: - assert(false); - break; - - } - - return result; - -} - - -/****************************************************************************** -* * -* Paramètres : type = type dont le dictionnaire est à compléter. * -* * * Description : Définit les constantes relatives aux modes de comparaison. * * * * Retour : true en cas de succès de l'opération, false sinon. * diff --git a/plugins/pychrysalide/glibext/constants.h b/plugins/pychrysalide/glibext/constants.h index a950125..c695aa9 100644 --- a/plugins/pychrysalide/glibext/constants.h +++ b/plugins/pychrysalide/glibext/constants.h @@ -39,12 +39,6 @@ int convert_to_portion_access_rights(PyObject *, void *); #if 0 -/* Définit les constantes relatives aux lignes de tampon. */ -bool define_buffer_line_constants(PyTypeObject *); - -/* Tente de convertir en constante BufferLineFlags. */ -int convert_to_buffer_line_flags(PyObject *, void *); - /* Définit les constantes relatives aux modes de comparaison. */ bool define_comparable_item_constants(PyTypeObject *); diff --git a/plugins/pychrysalide/glibext/linegen.c b/plugins/pychrysalide/glibext/generator.c index d7e96fd..3a9a8ab 100644 --- a/plugins/pychrysalide/glibext/linegen.c +++ b/plugins/pychrysalide/glibext/generator.c @@ -1,8 +1,8 @@ /* Chrysalide - Outil d'analyse de fichiers binaires - * linegen.c - équivalent Python du fichier "glibext/linegen.h" + * generator.c - équivalent Python du fichier "glibext/generator.h" * - * Copyright (C) 2018-2019 Cyrille Bagard + * Copyright (C) 2018-2025 Cyrille Bagard * * This file is part of Chrysalide. * @@ -22,21 +22,21 @@ */ -#include "linegen.h" +#include "generator.h" #include <pygobject.h> -#include <glibext/linegen-int.h> +#include <glibext/generator-int.h> #include "bufferline.h" -#include "constants.h" -#include "linecursor.h" +#include "constants-ui.h" +//#include "linecursor.h" #include "../access.h" #include "../helpers.h" -#include "../analysis/content.h" +//#include "../analysis/content.h" @@ -44,42 +44,55 @@ /* Procède à l'initialisation de l'interface de génération. */ -static void py_line_generator_interface_init(GLineGeneratorIface *, gpointer *); +static void py_token_generator_interface_init(GTokenGeneratorInterface *, gpointer *); /* Indique le nombre de ligne prêtes à être générées. */ -static size_t py_line_generator_count_lines_wrapper(const GLineGenerator *); +static size_t py_token_generator_count_lines_wrapper(const GTokenGenerator *); + +/* Renseigne sur les propriétés liées à un générateur. */ +static BufferLineFlags py_token_generator_get_flags_wrapper(const GTokenGenerator *, size_t, size_t); + +/*Description : Etablit dans une ligne de rendu le contenu représenté. */ +static void py_token_generator_populate_line_wrappper(const GTokenGenerator *, size_t, size_t, GBufferLine *, void *); + + +#if 0 + /* Retrouve l'emplacement correspondant à une position donnée. */ -static void py_line_generator_compute_cursor_wrapper(const GLineGenerator *, gint, size_t, size_t, GLineCursor **); +static void py_token_generator_compute_cursor_wrapper(const GTokenGenerator *, gint, size_t, size_t, GLineCursor **); /* Détermine si le conteneur s'inscrit dans une plage donnée. */ -static int py_line_generator_contain_cursor_wrapper(const GLineGenerator *, size_t, size_t, const GLineCursor *); +static int py_token_generator_contain_cursor_wrapper(const GTokenGenerator *, size_t, size_t, const GLineCursor *); + + +#endif -/* Renseigne sur les propriétés liées à un générateur. */ -static BufferLineFlags py_line_generator_get_flags_wrapper(const GLineGenerator *, size_t, size_t); -/* Imprime dans une ligne de rendu le contenu représenté. */ -static void py_line_generator_print_wrapper(GLineGenerator *, GBufferLine *, size_t, size_t, const GBinContent *); +/* ------------------ LIAISON DE FONCTIONNALITES AVEC L'API PYTHON ------------------ */ -/* ------------------------- CONNEXION AVEC L'API DE PYTHON ------------------------- */ +/* Renseigne sur les propriétés liées à un générateur. */ +static PyObject *py_token_generator_get_flags(PyObject *, PyObject *); + +/* Etablit dans une ligne de rendu le contenu représenté. */ +static PyObject *py_token_generator_populate_line(PyObject *self, PyObject *args); + +#if 0 /* Retrouve l'emplacement correspondant à une position donnée. */ -static PyObject *py_line_generator_compute_cursor(PyObject *, PyObject *); +static PyObject *py_token_generator_compute_cursor(PyObject *, PyObject *); /* Détermine si le conteneur s'inscrit dans une plage donnée. */ -static PyObject *py_line_generator_contain_cursor(PyObject *, PyObject *); +static PyObject *py_token_generator_contain_cursor(PyObject *, PyObject *); -/* Renseigne sur les propriétés liées à un générateur. */ -static PyObject *py_line_generator_get_flags(PyObject *, PyObject *); +#endif -/* Imprime dans une ligne de rendu le contenu représenté. */ -static PyObject *py_line_generator_print(PyObject *, PyObject *); /* Indique le nombre de ligne prêtes à être générées. */ -static PyObject *py_line_generator_get_lines_count(PyObject *, void *); +static PyObject *py_token_generator_get_lines_count(PyObject *, void *); @@ -101,31 +114,33 @@ static PyObject *py_line_generator_get_lines_count(PyObject *, void *); * * ******************************************************************************/ -static void py_line_generator_interface_init(GLineGeneratorIface *iface, gpointer *unused) +static void py_token_generator_interface_init(GTokenGeneratorInterface *iface, gpointer *unused) { -#define LINE_GENERATOR_DOC \ - "LineGenerator gives an interface to all objects which aim to produce" \ +#define TOKEN_GENERATOR_DOC \ + "TokenGenerator gives an interface to all objects which aim to produce" \ " content for rendering lines. Such lines can be exported to graphical" \ " interfaces or text files.\n" \ "\n" \ "A typical class declaration for a new implementation looks like:\n" \ "\n" \ - " class NewImplem(GObject.Object, LineGenerator):\n" \ + " class NewImplem(GObject.Object, TokenGenerator):\n" \ " ...\n" \ "\n" \ "The following methods have to be defined for new implementations:\n" \ - "* pychrysalide.glibext.LineGenerator._count_lines();\n" \ - "* pychrysalide.glibext.LineGenerator._compute_cursor();\n" \ - "* pychrysalide.glibext.LineGenerator._contain_cursor();\n" \ - "* pychrysalide.glibext.LineGenerator._get_flags();\n" \ - "* pychrysalide.glibext.LineGenerator._print();\n" \ - - iface->count = py_line_generator_count_lines_wrapper; - iface->compute = py_line_generator_compute_cursor_wrapper; - iface->contain = py_line_generator_contain_cursor_wrapper; - iface->get_flags = py_line_generator_get_flags_wrapper; - iface->print = py_line_generator_print_wrapper; + "* pychrysalide.glibext.TokenGenerator._count_lines();\n" \ + "* pychrysalide.glibext.TokenGenerator._get_flags();\n" \ + "* pychrysalide.glibext.TokenGenerator._populate_line();\n" \ + "* pychrysalide.glibext.TokenGenerator._compute_cursor();\n" \ + "* pychrysalide.glibext.TokenGenerator._contain_cursor().\n" + + iface->count = py_token_generator_count_lines_wrapper; + iface->get_flags = py_token_generator_get_flags_wrapper; + iface->populate = py_token_generator_populate_line_wrappper; +#if 0 + iface->compute = py_token_generator_compute_cursor_wrapper; + iface->contain = py_token_generator_contain_cursor_wrapper; +#endif } @@ -142,7 +157,7 @@ static void py_line_generator_interface_init(GLineGeneratorIface *iface, gpointe * * ******************************************************************************/ -static size_t py_line_generator_count_lines_wrapper(const GLineGenerator *generator) +static size_t py_token_generator_count_lines_wrapper(const GTokenGenerator *generator) { size_t result; /* Décompte à retourner */ PyGILState_STATE gstate; /* Sauvegarde d'environnement */ @@ -150,7 +165,7 @@ static size_t py_line_generator_count_lines_wrapper(const GLineGenerator *genera PyObject *pyret; /* Bilan de consultation */ int ret; /* Bilan d'une conversion */ -#define LINE_GENERATOR_COUNT_LINES_WRAPPER PYTHON_WRAPPER_DEF \ +#define TOKEN_GENERATOR_COUNT_LINES_WRAPPER PYTHON_WRAPPER_DEF \ ( \ _count_lines, "$self, /", \ METH_NOARGS, \ @@ -193,61 +208,61 @@ static size_t py_line_generator_count_lines_wrapper(const GLineGenerator *genera /****************************************************************************** * * * Paramètres : generator = 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. * * * -* Description : Retrouve l'emplacement correspondant à une position donnée. * +* Description : Renseigne sur les propriétés liées à un générateur. * * * -* Retour : Emplacement constitué. * +* Retour : Propriétés particulières associées. * * * * Remarques : - * * * ******************************************************************************/ -static void py_line_generator_compute_cursor_wrapper(const GLineGenerator *generator, gint x, size_t index, size_t repeat, GLineCursor **cursor) +static BufferLineFlags py_token_generator_get_flags_wrapper(const GTokenGenerator *generator, size_t index, size_t repeat) { + BufferLineFlags result; /* Fanions à retourner */ PyGILState_STATE gstate; /* Sauvegarde d'environnement */ PyObject *pyobj; /* Objet Python concerné */ PyObject *args; /* Arguments pour l'appel */ PyObject *pyret; /* Bilan de consultation */ int ret; /* Bilan d'une conversion */ -#define LINE_GENERATOR_COMPUTE_CURSOR_WRAPPER PYTHON_WRAPPER_DEF \ +#define TOKEN_GENERATOR_GET_FLAGS_WRAPPER PYTHON_WRAPPER_DEF \ ( \ - _compute_cursor, "$self, x, index, repeat, /", \ + _get_flags, "$self, index, repeat, /", \ METH_VARARGS, \ - "Abstract method used to create a new cursor for a given" \ - " location inside displayed lines.\n" \ + "Abstract method used to provide flags for a given rendering" \ + " line.\n" \ "\n" \ - "The position on the horizontal axis, the line index and the" \ - " number of repetitions (only relevant if the generator" \ - " produces several lines) give indications about the active" \ - " position.\n" \ + "The line index and the number of repetitions (only relevant" \ + " if the generator produces several lines) give indications" \ + " about the active position.\n" \ "\n" \ - "The result has to be a pychrysalide.glibext.LineCursor" \ - " instance." \ + "The result has to be a" \ + " pychrysalide.glibext.BufferLine.BufferLineFlags value.\n" \ ) + result = BLF_NONE; + gstate = PyGILState_Ensure(); pyobj = pygobject_new(G_OBJECT(generator)); - if (has_python_method(pyobj, "_compute_cursor")) + if (has_python_method(pyobj, "_get_flags")) { - args = PyTuple_New(3); - PyTuple_SetItem(args, 0, PyLong_FromSize_t(x)); - PyTuple_SetItem(args, 1, PyLong_FromSize_t(index)); - PyTuple_SetItem(args, 2, PyLong_FromSize_t(repeat)); + args = PyTuple_New(2); + PyTuple_SetItem(args, 0, PyLong_FromSize_t(index)); + PyTuple_SetItem(args, 1, PyLong_FromSize_t(repeat)); - pyret = run_python_method(pyobj, "_compute_cursor", args); + pyret = run_python_method(pyobj, "_get_flags", args); if (pyret != NULL) { - ret = convert_to_line_cursor(pyret, cursor); + ret = convert_to_buffer_line_flags(pyret, &result); if (ret != 1) - *cursor = NULL; + result = BLF_NONE; Py_DECREF(pyret); @@ -261,75 +276,66 @@ static void py_line_generator_compute_cursor_wrapper(const GLineGenerator *gener PyGILState_Release(gstate); + return result; + } /****************************************************************************** * * -* Paramètres : generator = générateur à consulter. * +* 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. * -* cursor = emplacement à analyser. * +* line = ligne de rendu à compléter. * +* data = éventuelle donnée complémentaire fournie. * * * -* Description : Détermine si le conteneur s'inscrit dans une plage donnée. * +* Description : Etablit dans une ligne de rendu le contenu représenté. * * * -* Retour : Bilan de la détermination, utilisable en comparaisons. * +* Retour : - * * * * Remarques : - * * * ******************************************************************************/ -static int py_line_generator_contain_cursor_wrapper(const GLineGenerator *generator, size_t index, size_t repeat, const GLineCursor *cursor) +static void py_token_generator_populate_line_wrappper(const GTokenGenerator *generator, size_t index, size_t repeat, GBufferLine *line, void *data) { - int result; /* Bilan d'analyse à retourner */ PyGILState_STATE gstate; /* Sauvegarde d'environnement */ PyObject *pyobj; /* Objet Python concerné */ PyObject *args; /* Arguments pour l'appel */ PyObject *pyret; /* Bilan de consultation */ - int ret; /* Bilan d'une conversion */ -#define LINE_GENERATOR_CONTAIN_CURSOR_WRAPPER PYTHON_WRAPPER_DEF \ +#define TOKEN_GENERATOR_POPULATE_LINE_WRAPPER PYTHON_WRAPPER_DEF \ ( \ - _contain_cursor, "$self, index, repeat, cursor, /", \ + _populate_line, "$self, index, repeat, line, /", \ METH_VARARGS, \ - "Abstract method used to check the position of a cursor in" \ - " relation to rendering lines.\n" \ + "Abstract method used to generate content into a rendering" \ + " line.\n" \ "\n" \ - "The line index and the number of repetitions (only relevant" \ + "This rendering output is pointed by the *line* argument, which"\ + " is a provided pychrysalide.glibext.BufferLine instance. The" \ + " line *index* and the number of repetitions (only relevant" \ " if the generator produces several lines) give indications" \ - " about the active position. The cursor is a" \ - " pychrysalide.glibext.LineCursor instance.\n" \ + " about the current rendering position.\n" \ "\n" \ - "The result has to be an integer less than, equal to, or" \ - " greater than zero if the cursor is, respectively, before," \ - " inside or after the area covered by the generator." \ + "If set, the content is a pychrysalide.analysis.BinContent" \ + " instance providing access to the processed binary data." \ ) - result = 0; - gstate = PyGILState_Ensure(); pyobj = pygobject_new(G_OBJECT(generator)); - if (has_python_method(pyobj, "_contain_cursor")) + if (has_python_method(pyobj, "_populate_line")) { args = PyTuple_New(3); PyTuple_SetItem(args, 0, PyLong_FromSize_t(index)); PyTuple_SetItem(args, 1, PyLong_FromSize_t(repeat)); - PyTuple_SetItem(args, 2, pygobject_new(G_OBJECT(cursor))); + PyTuple_SetItem(args, 2, pygobject_new(G_OBJECT(line))); + //PyTuple_SetItem(args, 3, pygobject_new(G_OBJECT(content))); - pyret = run_python_method(pyobj, "_contain_cursor", args); - - if (pyret != NULL) - { - ret = PyLong_Check(pyret); + pyret = run_python_method(pyobj, "_populate_line", args); - if (ret) - result = PyLong_AsLong(pyret); - - Py_DECREF(pyret); - - } + Py_XDECREF(pyret); Py_DECREF(args); @@ -339,69 +345,70 @@ static int py_line_generator_contain_cursor_wrapper(const GLineGenerator *genera PyGILState_Release(gstate); - return result; - } +#if 0 + + /****************************************************************************** * * * Paramètres : generator = 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. * * * -* Description : Renseigne sur les propriétés liées à un générateur. * +* Description : Retrouve l'emplacement correspondant à une position donnée. * * * -* Retour : Propriétés particulières associées. * +* Retour : Emplacement constitué. * * * * Remarques : - * * * ******************************************************************************/ -static BufferLineFlags py_line_generator_get_flags_wrapper(const GLineGenerator *generator, size_t index, size_t repeat) +static void py_token_generator_compute_cursor_wrapper(const GTokenGenerator *generator, gint x, size_t index, size_t repeat, GLineCursor **cursor) { - BufferLineFlags result; /* Fanions à retourner */ PyGILState_STATE gstate; /* Sauvegarde d'environnement */ PyObject *pyobj; /* Objet Python concerné */ PyObject *args; /* Arguments pour l'appel */ PyObject *pyret; /* Bilan de consultation */ int ret; /* Bilan d'une conversion */ -#define LINE_GENERATOR_GET_FLAGS_WRAPPER PYTHON_WRAPPER_DEF \ +#define TOKEN_GENERATOR_COMPUTE_CURSOR_WRAPPER PYTHON_WRAPPER_DEF \ ( \ - _get_flags, "$self, index, repeat, /", \ + _compute_cursor, "$self, x, index, repeat, /", \ METH_VARARGS, \ - "Abstract method used to provide flags for a given rendering" \ - " line.\n" \ + "Abstract method used to create a new cursor for a given" \ + " location inside displayed lines.\n" \ "\n" \ - "The line index and the number of repetitions (only relevant" \ - " if the generator produces several lines) give indications" \ - " about the active position.\n" \ + "The position on the horizontal axis, the line index and the" \ + " number of repetitions (only relevant if the generator" \ + " produces several lines) give indications about the active" \ + " position.\n" \ "\n" \ - "The result has to be a" \ - " pychrysalide.glibext.BufferLine.BufferLineFlags value.\n" \ + "The result has to be a pychrysalide.glibext.LineCursor" \ + " instance." \ ) - result = BLF_NONE; - gstate = PyGILState_Ensure(); pyobj = pygobject_new(G_OBJECT(generator)); - if (has_python_method(pyobj, "_get_flags")) + if (has_python_method(pyobj, "_compute_cursor")) { - args = PyTuple_New(2); - PyTuple_SetItem(args, 0, PyLong_FromSize_t(index)); - PyTuple_SetItem(args, 1, PyLong_FromSize_t(repeat)); + args = PyTuple_New(3); + PyTuple_SetItem(args, 0, PyLong_FromSize_t(x)); + PyTuple_SetItem(args, 1, PyLong_FromSize_t(index)); + PyTuple_SetItem(args, 2, PyLong_FromSize_t(repeat)); - pyret = run_python_method(pyobj, "_get_flags", args); + pyret = run_python_method(pyobj, "_compute_cursor", args); if (pyret != NULL) { - ret = convert_to_buffer_line_flags(pyret, &result); + ret = convert_to_line_cursor(pyret, cursor); if (ret != 1) - result = BLF_NONE; + *cursor = NULL; Py_DECREF(pyret); @@ -415,65 +422,75 @@ static BufferLineFlags py_line_generator_get_flags_wrapper(const GLineGenerator PyGILState_Release(gstate); - return result; - } /****************************************************************************** * * -* Paramètres : generator = générateur à utiliser pour l'impression. * -* line = ligne de rendu à compléter. * +* 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. * -* content = éventuel contenu binaire brut à imprimer. * +* cursor = emplacement à analyser. * * * -* Description : Imprime dans une ligne de rendu le contenu représenté. * +* Description : Détermine si le conteneur s'inscrit dans une plage donnée. * * * -* Retour : - * +* Retour : Bilan de la détermination, utilisable en comparaisons. * * * * Remarques : - * * * ******************************************************************************/ -static void py_line_generator_print_wrapper(GLineGenerator *generator, GBufferLine *line, size_t index, size_t repeat, const GBinContent *content) +static int py_token_generator_contain_cursor_wrapper(const GTokenGenerator *generator, size_t index, size_t repeat, const GLineCursor *cursor) { + int result; /* Bilan d'analyse à retourner */ PyGILState_STATE gstate; /* Sauvegarde d'environnement */ PyObject *pyobj; /* Objet Python concerné */ PyObject *args; /* Arguments pour l'appel */ PyObject *pyret; /* Bilan de consultation */ + int ret; /* Bilan d'une conversion */ -#define LINE_GENERATOR_PRINT_WRAPPER PYTHON_WRAPPER_DEF \ +#define TOKEN_GENERATOR_CONTAIN_CURSOR_WRAPPER PYTHON_WRAPPER_DEF \ ( \ - _print, "$self, line, index, repeat, content, /", \ + _contain_cursor, "$self, index, repeat, cursor, /", \ METH_VARARGS, \ - "Abstract method used to generate content into a rendering" \ - " line, which is a provided pychrysalide.glibext.BufferLine" \ - " instance.\n" \ + "Abstract method used to check the position of a cursor in" \ + " relation to rendering lines.\n" \ "\n" \ "The line index and the number of repetitions (only relevant" \ " if the generator produces several lines) give indications" \ - " about the current rendering position.\n" \ + " about the active position. The cursor is a" \ + " pychrysalide.glibext.LineCursor instance.\n" \ "\n" \ - "If set, the content is a pychrysalide.analysis.BinContent" \ - " instance providing access to the processed binary data." \ + "The result has to be an integer less than, equal to, or" \ + " greater than zero if the cursor is, respectively, before," \ + " inside or after the area covered by the generator." \ ) + result = 0; + gstate = PyGILState_Ensure(); pyobj = pygobject_new(G_OBJECT(generator)); - if (has_python_method(pyobj, "_print")) + if (has_python_method(pyobj, "_contain_cursor")) { - args = PyTuple_New(4); - PyTuple_SetItem(args, 0, pygobject_new(G_OBJECT(line))); - PyTuple_SetItem(args, 1, PyLong_FromSize_t(index)); - PyTuple_SetItem(args, 2, PyLong_FromSize_t(repeat)); - PyTuple_SetItem(args, 3, pygobject_new(G_OBJECT(content))); + args = PyTuple_New(3); + PyTuple_SetItem(args, 0, PyLong_FromSize_t(index)); + PyTuple_SetItem(args, 1, PyLong_FromSize_t(repeat)); + PyTuple_SetItem(args, 2, pygobject_new(G_OBJECT(cursor))); - pyret = run_python_method(pyobj, "_print", args); + pyret = run_python_method(pyobj, "_contain_cursor", args); - Py_XDECREF(pyret); + if (pyret != NULL) + { + ret = PyLong_Check(pyret); + + if (ret) + result = PyLong_AsLong(pyret); + + Py_DECREF(pyret); + + } Py_DECREF(args); @@ -483,12 +500,16 @@ static void py_line_generator_print_wrapper(GLineGenerator *generator, GBufferLi PyGILState_Release(gstate); + return result; + } +#endif + /* ---------------------------------------------------------------------------------- */ -/* CONNEXION AVEC L'API DE PYTHON */ +/* LIAISON DE FONCTIONNALITES AVEC L'API PYTHON */ /* ---------------------------------------------------------------------------------- */ @@ -497,57 +518,45 @@ static void py_line_generator_print_wrapper(GLineGenerator *generator, GBufferLi * Paramètres : self = classe représentant un générateur à manipuler. * * args = arguments fournis à l'appel. * * * -* Description : Retrouve l'emplacement correspondant à une position donnée. * +* Description : Renseigne sur les propriétés liées à un générateur. * * * -* Retour : Emplacement constitué. * +* Retour : Propriétés particulières associées. * * * * Remarques : - * * * ******************************************************************************/ -static PyObject *py_line_generator_compute_cursor(PyObject *self, PyObject *args) +static PyObject *py_token_generator_get_flags(PyObject *self, PyObject *args) { PyObject *result; /* Propriétés à retourner */ - int x; /* Position horizontale */ size_t index; /* Indice dans le tampon */ size_t repeat; /* Utilisations successives */ int ret; /* Bilan de lecture des args. */ - GLineGenerator *generator; /* Version native */ - GLineCursor *cursor; /* Curseur nouveau obtenu */ + GTokenGenerator *generator; /* Version native */ + BufferLineFlags flags; /* Propriétés courantes */ -#define LINE_GENERATOR_COMPUTE_CURSOR_METHOD PYTHON_METHOD_DEF \ -( \ - compute_cursor, "$self, x, index, repeat, /", \ - METH_VARARGS, py_line_generator, \ - "Create a a new cursor for a given location inside displayed" \ - " lines.\n" \ - "\n" \ - "The position on the horizontal axis, the line index and the" \ - " number of repetitions (only relevant if the generator" \ - " produces several lines) give indications about the active" \ - " position.\n" \ - "\n" \ - "The result has to be a pychrysalide.glibext.LineCursor" \ - " instance." \ +#define TOKEN_GENERATOR_GET_FLAGS_METHOD PYTHON_METHOD_DEF \ +( \ + get_flags, "$self, index, repeat, /", \ + METH_VARARGS, py_token_generator, \ + "Get the flags of a given position from the generator.\n" \ + "\n" \ + "The line index and the number of repetitions (only relevant" \ + " if the generator produces several lines) give indications" \ + " about the active position.\n" \ + "\n" \ + "The result is a pychrysalide.glibext.BufferLine.BufferLineFlags" \ + " value." \ ) - ret = PyArg_ParseTuple(args, "inn", &x, &index, &repeat); + ret = PyArg_ParseTuple(args, "nn", &index, &repeat); if (!ret) return NULL; - generator = G_LINE_GENERATOR(pygobject_get(self)); + generator = G_TOKEN_GENERATOR(pygobject_get(self)); - cursor = g_line_generator_compute_cursor(generator, x, index, repeat); + flags = g_token_generator_get_flags(generator, index, repeat); - if (cursor != NULL) - { - result = pygobject_new(G_OBJECT(cursor)); - g_object_unref(G_OBJECT(cursor)); - } - else - { - result = Py_None; - Py_INCREF(result); - } + result = cast_with_constants_group_from_type(get_python_buffer_line_type(), "BufferLineFlags", flags); return result; @@ -559,99 +568,108 @@ static PyObject *py_line_generator_compute_cursor(PyObject *self, PyObject *args * Paramètres : self = classe représentant un générateur à manipuler. * * args = arguments fournis à l'appel. * * * -* Description : Détermine si le conteneur s'inscrit dans une plage donnée. * +* Description : Etablit dans une ligne de rendu le contenu représenté. * * * -* Retour : Bilan de la détermination, utilisable en comparaisons. * +* Retour : - * * * * Remarques : - * * * ******************************************************************************/ -static PyObject *py_line_generator_contain_cursor(PyObject *self, PyObject *args) +static PyObject *py_token_generator_populate_line(PyObject *self, PyObject *args) { - PyObject *result; /* Propriétés à retourner */ + GBufferLine *line; /* Ligne de rendu à compléter */ size_t index; /* Indice dans le tampon */ size_t repeat; /* Utilisations successives */ - GLineCursor *cursor; /* Curseur à venir situer */ + GTokenGenerator *generator; /* Version native */ int ret; /* Bilan de lecture des args. */ - GLineGenerator *generator; /* Version native */ - int status; /* Bilan d'une analyse */ -#define LINE_GENERATOR_CONTAIN_CURSOR_METHOD PYTHON_METHOD_DEF \ +#define TOKEN_GENERATOR_POPULATE_LINE_METHOD PYTHON_METHOD_DEF \ ( \ - contain_cursor, "$self, index, repeat, cursor, /", \ - METH_VARARGS, py_line_generator, \ - "Check the position of a cursor in relation to rendering" \ - " lines.\n" \ + populate_line, "$self, index, repeat, line, /", \ + METH_VARARGS, py_token_generator, \ + "Produce output into a rendering line with optional content.\n" \ "\n" \ - "The line index and the number of repetitions (only relevant" \ - " if the generator produces several lines) give indications" \ - " about the active position. The cursor is a" \ - " pychrysalide.glibext.LineCursor instance.\n" \ + "The provided *line* is a pychrysalide.glibext.BufferLine" \ + " instance. The *index* and the number of repetitions (only" \ + " relevant if the generator produces several lines) give" \ + " indications about the current rendering position.\n" \ "\n" \ - "The result has to be an integer less than, equal to, or" \ - " greater than zero if the cursor is, respectively, before," \ - " inside or after the area covered by the generator." \ + "If set, the content is a pychrysalide.analysis.BinContent" \ + " instance providing access to the processed binary data." \ ) - ret = PyArg_ParseTuple(args, "nnO&", &index, &repeat, convert_to_line_cursor, &cursor); + ret = PyArg_ParseTuple(args, "nnO&", &index, &repeat, convert_to_buffer_line, &line); if (!ret) return NULL; - generator = G_LINE_GENERATOR(pygobject_get(self)); + generator = G_TOKEN_GENERATOR(pygobject_get(self)); - status = g_line_generator_contain_cursor(generator, index, repeat, cursor); + g_token_generator_populate_line(generator, index, repeat, line, NULL); - result = PyLong_FromLong(status); - - return result; + Py_RETURN_NONE; } + +#if 0 + /****************************************************************************** * * * Paramètres : self = classe représentant un générateur à manipuler. * * args = arguments fournis à l'appel. * * * -* Description : Renseigne sur les propriétés liées à un générateur. * +* Description : Retrouve l'emplacement correspondant à une position donnée. * * * -* Retour : Propriétés particulières associées. * +* Retour : Emplacement constitué. * * * * Remarques : - * * * ******************************************************************************/ -static PyObject *py_line_generator_get_flags(PyObject *self, PyObject *args) +static PyObject *py_token_generator_compute_cursor(PyObject *self, PyObject *args) { PyObject *result; /* Propriétés à retourner */ + int x; /* Position horizontale */ size_t index; /* Indice dans le tampon */ size_t repeat; /* Utilisations successives */ int ret; /* Bilan de lecture des args. */ - GLineGenerator *generator; /* Version native */ - BufferLineFlags flags; /* Propriétés courantes */ + GTokenGenerator *generator; /* Version native */ + GLineCursor *cursor; /* Curseur nouveau obtenu */ -#define LINE_GENERATOR_GET_FLAGS_METHOD PYTHON_METHOD_DEF \ -( \ - get_flags, "$self, index, repeat, /", \ - METH_VARARGS, py_line_generator, \ - "Get the flags of a given position from the generator.\n" \ - "\n" \ - "The line index and the number of repetitions (only relevant" \ - " if the generator produces several lines) give indications" \ - " about the active position.\n" \ - "\n" \ - "The result is a pychrysalide.glibext.BufferLine.BufferLineFlags" \ - " value." \ +#define TOKEN_GENERATOR_COMPUTE_CURSOR_METHOD PYTHON_METHOD_DEF \ +( \ + compute_cursor, "$self, x, index, repeat, /", \ + METH_VARARGS, py_token_generator, \ + "Create a a new cursor for a given location inside displayed" \ + " lines.\n" \ + "\n" \ + "The position on the horizontal axis, the line index and the" \ + " number of repetitions (only relevant if the generator" \ + " produces several lines) give indications about the active" \ + " position.\n" \ + "\n" \ + "The result has to be a pychrysalide.glibext.LineCursor" \ + " instance." \ ) - ret = PyArg_ParseTuple(args, "nn", &index, &repeat); + ret = PyArg_ParseTuple(args, "inn", &x, &index, &repeat); if (!ret) return NULL; - generator = G_LINE_GENERATOR(pygobject_get(self)); + generator = G_TOKEN_GENERATOR(pygobject_get(self)); - flags = g_line_generator_get_flags(generator, index, repeat); + cursor = g_token_generator_compute_cursor(generator, x, index, repeat); - result = cast_with_constants_group_from_type(get_python_buffer_line_type(), "BufferLineFlags", flags); + if (cursor != NULL) + { + result = pygobject_new(G_OBJECT(cursor)); + g_object_unref(G_OBJECT(cursor)); + } + else + { + result = Py_None; + Py_INCREF(result); + } return result; @@ -663,50 +681,56 @@ static PyObject *py_line_generator_get_flags(PyObject *self, PyObject *args) * Paramètres : self = classe représentant un générateur à manipuler. * * args = arguments fournis à l'appel. * * * -* Description : Imprime dans une ligne de rendu le contenu représenté. * +* Description : Détermine si le conteneur s'inscrit dans une plage donnée. * * * -* Retour : - * +* Retour : Bilan de la détermination, utilisable en comparaisons. * * * * Remarques : - * * * ******************************************************************************/ -static PyObject *py_line_generator_print(PyObject *self, PyObject *args) +static PyObject *py_token_generator_contain_cursor(PyObject *self, PyObject *args) { - GBufferLine *line; /* Ligne de rendu à compléter */ + PyObject *result; /* Propriétés à retourner */ size_t index; /* Indice dans le tampon */ size_t repeat; /* Utilisations successives */ - GBinContent *content; /* Contenu binaire associé */ - GLineGenerator *generator; /* Version native */ + GLineCursor *cursor; /* Curseur à venir situer */ int ret; /* Bilan de lecture des args. */ + GTokenGenerator *generator; /* Version native */ + int status; /* Bilan d'une analyse */ -#define LINE_GENERATOR_PRINT_METHOD PYTHON_METHOD_DEF \ +#define TOKEN_GENERATOR_CONTAIN_CURSOR_METHOD PYTHON_METHOD_DEF \ ( \ - print, "$self, line, index, repeat, content, /", \ - METH_VARARGS, py_line_generator, \ - "Produce output into a rendering line with optional content.\n" \ + contain_cursor, "$self, index, repeat, cursor, /", \ + METH_VARARGS, py_token_generator, \ + "Check the position of a cursor in relation to rendering" \ + " lines.\n" \ "\n" \ - "The provided line is a pychrysalide.glibext.BufferLine" \ - " instance. The index and the number of repetitions (only" \ - " relevant if the generator produces several lines) give" \ - " indications about the current rendering position.\n" \ + "The line index and the number of repetitions (only relevant" \ + " if the generator produces several lines) give indications" \ + " about the active position. The cursor is a" \ + " pychrysalide.glibext.LineCursor instance.\n" \ "\n" \ - "If set, the content is a pychrysalide.analysis.BinContent" \ - " instance providing access to the processed binary data." \ + "The result has to be an integer less than, equal to, or" \ + " greater than zero if the cursor is, respectively, before," \ + " inside or after the area covered by the generator." \ ) - ret = PyArg_ParseTuple(args, "O&nnO&", convert_to_buffer_line, &line, &index, - &repeat, convert_to_binary_content, &content); + ret = PyArg_ParseTuple(args, "nnO&", &index, &repeat, convert_to_line_cursor, &cursor); if (!ret) return NULL; - generator = G_LINE_GENERATOR(pygobject_get(self)); + generator = G_TOKEN_GENERATOR(pygobject_get(self)); - g_line_generator_print(generator, line, index, repeat, content); + status = g_token_generator_contain_cursor(generator, index, repeat, cursor); - Py_RETURN_NONE; + result = PyLong_FromLong(status); + + return result; } +#endif + /****************************************************************************** * * @@ -721,24 +745,24 @@ static PyObject *py_line_generator_print(PyObject *self, PyObject *args) * * ******************************************************************************/ -static PyObject *py_line_generator_get_lines_count(PyObject *self, void *closure) +static PyObject *py_token_generator_get_lines_count(PyObject *self, void *closure) { PyObject *result; /* Décompte à retourner */ - GLineGenerator *generator; /* Version native */ + GTokenGenerator *generator; /* Version native */ size_t count; /* Nombre de lignes présentes */ -#define LINE_GENERATOR_LINES_COUNT_ATTRIB PYTHON_GET_DEF_FULL \ +#define TOKEN_GENERATOR_LINES_COUNT_ATTRIB PYTHON_GET_DEF_FULL \ ( \ - lines_count, py_line_generator, \ + lines_count, py_token_generator, \ "Quantity of lines produced by the generator.\n" \ "\n" \ "This number may vary between calls, if a width has changed" \ " for instance." \ ) - generator = G_LINE_GENERATOR(pygobject_get(self)); + generator = G_TOKEN_GENERATOR(pygobject_get(self)); - count = g_line_generator_count_lines(generator); + count = g_token_generator_count_lines(generator); result = PyLong_FromSize_t(count); @@ -759,43 +783,47 @@ static PyObject *py_line_generator_get_lines_count(PyObject *self, void *closure * * ******************************************************************************/ -PyTypeObject *get_python_line_generator_type(void) +PyTypeObject *get_python_token_generator_type(void) { - static PyMethodDef py_line_generator_methods[] = { - LINE_GENERATOR_COUNT_LINES_WRAPPER, - LINE_GENERATOR_COMPUTE_CURSOR_WRAPPER, - LINE_GENERATOR_CONTAIN_CURSOR_WRAPPER, - LINE_GENERATOR_GET_FLAGS_WRAPPER, - LINE_GENERATOR_PRINT_WRAPPER, - LINE_GENERATOR_COMPUTE_CURSOR_METHOD, - LINE_GENERATOR_CONTAIN_CURSOR_METHOD, - LINE_GENERATOR_GET_FLAGS_METHOD, - LINE_GENERATOR_PRINT_METHOD, + static PyMethodDef py_token_generator_methods[] = { + TOKEN_GENERATOR_COUNT_LINES_WRAPPER, + TOKEN_GENERATOR_GET_FLAGS_WRAPPER, + TOKEN_GENERATOR_POPULATE_LINE_WRAPPER, + /* + TOKEN_GENERATOR_COMPUTE_CURSOR_WRAPPER, + TOKEN_GENERATOR_CONTAIN_CURSOR_WRAPPER, + */ + TOKEN_GENERATOR_GET_FLAGS_METHOD, + TOKEN_GENERATOR_POPULATE_LINE_METHOD, + /* + TOKEN_GENERATOR_COMPUTE_CURSOR_METHOD, + TOKEN_GENERATOR_CONTAIN_CURSOR_METHOD, + */ { NULL } }; - static PyGetSetDef py_line_generator_getseters[] = { - LINE_GENERATOR_LINES_COUNT_ATTRIB, + static PyGetSetDef py_token_generator_getseters[] = { + TOKEN_GENERATOR_LINES_COUNT_ATTRIB, { NULL } }; - static PyTypeObject py_line_generator_type = { + static PyTypeObject py_token_generator_type = { PyVarObject_HEAD_INIT(NULL, 0) - .tp_name = "pychrysalide.glibext.LineGenerator", + .tp_name = "pychrysalide.glibext.TokenGenerator", .tp_basicsize = sizeof(PyObject), .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, - .tp_doc = LINE_GENERATOR_DOC, + .tp_doc = TOKEN_GENERATOR_DOC, - .tp_methods = py_line_generator_methods, - .tp_getset = py_line_generator_getseters, + .tp_methods = py_token_generator_methods, + .tp_getset = py_token_generator_getseters, }; - return &py_line_generator_type; + return &py_token_generator_type; } @@ -804,7 +832,7 @@ PyTypeObject *get_python_line_generator_type(void) * * * Paramètres : module = module dont la définition est à compléter. * * * -* Description : Prend en charge l'objet 'pychrysalide.glibext.LineGenerator'.* +* Description : Prend en charge l'objet 'pychrysalide.....TokenGenerator'. * * * * Retour : Bilan de l'opération. * * * @@ -812,21 +840,21 @@ PyTypeObject *get_python_line_generator_type(void) * * ******************************************************************************/ -bool ensure_python_line_generator_is_registered(void) +bool ensure_python_token_generator_is_registered(void) { - PyTypeObject *type; /* Type Python 'LineGenerator' */ + PyTypeObject *type; /* Type Python 'TokenGenerator'*/ PyObject *module; /* Module à recompléter */ PyObject *dict; /* Dictionnaire du module */ static GInterfaceInfo info = { /* Paramètres d'inscription */ - .interface_init = (GInterfaceInitFunc)py_line_generator_interface_init, + .interface_init = (GInterfaceInitFunc)py_token_generator_interface_init, .interface_finalize = NULL, .interface_data = NULL, }; - type = get_python_line_generator_type(); + type = get_python_token_generator_type(); if (!PyType_HasFeature(type, Py_TPFLAGS_READY)) { @@ -834,7 +862,7 @@ bool ensure_python_line_generator_is_registered(void) dict = PyModule_GetDict(module); - if (!register_interface_for_pygobject(dict, G_TYPE_LINE_GENERATOR, type, &info)) + if (!register_interface_for_pygobject(dict, G_TYPE_TOKEN_GENERATOR, type, &info)) return false; } @@ -857,11 +885,11 @@ bool ensure_python_line_generator_is_registered(void) * * ******************************************************************************/ -int convert_to_line_generator(PyObject *arg, void *dst) +int convert_to_token_generator(PyObject *arg, void *dst) { int result; /* Bilan à retourner */ - result = PyObject_IsInstance(arg, (PyObject *)get_python_line_generator_type()); + result = PyObject_IsInstance(arg, (PyObject *)get_python_token_generator_type()); switch (result) { @@ -871,11 +899,11 @@ int convert_to_line_generator(PyObject *arg, void *dst) break; case 0: - PyErr_SetString(PyExc_TypeError, "unable to convert the provided argument to line generator"); + PyErr_SetString(PyExc_TypeError, "unable to convert the provided argument to token generator"); break; case 1: - *((GLineGenerator **)dst) = G_LINE_GENERATOR(pygobject_get(arg)); + *((GTokenGenerator **)dst) = G_TOKEN_GENERATOR(pygobject_get(arg)); break; default: diff --git a/plugins/pychrysalide/glibext/linegen.h b/plugins/pychrysalide/glibext/generator.h index bfad885..b2672a8 100644 --- a/plugins/pychrysalide/glibext/linegen.h +++ b/plugins/pychrysalide/glibext/generator.h @@ -1,8 +1,8 @@ /* Chrysalide - Outil d'analyse de fichiers binaires - * linegen.h - prototypes pour l'équivalent Python du fichier "glibext/linegen.h" + * generator.h - prototypes pour l'équivalent Python du fichier "glibext/generator.h" * - * Copyright (C) 2018 Cyrille Bagard + * Copyright (C) 2018-2025 Cyrille Bagard * * This file is part of Chrysalide. * @@ -22,8 +22,8 @@ */ -#ifndef _PLUGINS_PYCHRYSALIDE_GLIBEXT_LINEGEN_H -#define _PLUGINS_PYCHRYSALIDE_GLIBEXT_LINEGEN_H +#ifndef _PLUGINS_PYCHRYSALIDE_GLIBEXT_GENERATOR_H +#define _PLUGINS_PYCHRYSALIDE_GLIBEXT_GENERATOR_H #include <Python.h> @@ -32,14 +32,14 @@ /* Fournit un accès à une définition de type à diffuser. */ -PyTypeObject *get_python_line_generator_type(void); +PyTypeObject *get_python_token_generator_type(void); -/* Prend en charge l'objet 'pychrysalide.glibext.LineGenerator'. */ -bool ensure_python_line_generator_is_registered(void); +/* Prend en charge l'objet 'pychrysalide.glibext.TokenGenerator'. */ +bool ensure_python_token_generator_is_registered(void); /* Tente de convertir en générateur de lignes. */ -int convert_to_line_generator(PyObject *, void *); +int convert_to_token_generator(PyObject *, void *); -#endif /* _PLUGINS_PYCHRYSALIDE_GLIBEXT_LINEGEN_H */ +#endif /* _PLUGINS_PYCHRYSALIDE_GLIBEXT_GENERATOR_H */ diff --git a/plugins/pychrysalide/glibext/module-ui.c b/plugins/pychrysalide/glibext/module-ui.c new file mode 100644 index 0000000..8fa6d0e --- /dev/null +++ b/plugins/pychrysalide/glibext/module-ui.c @@ -0,0 +1,62 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * module.c - intégration du répertoire glibext (forme graphique) en tant que module + * + * 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 "module-ui.h" + + +#include <assert.h> + + +#include "bufferline.h" +#include "generator.h" + + + +/****************************************************************************** +* * +* Paramètres : - * +* * +* Description : Intègre les objets du module 'glibext' (mode UI). * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool populate_glibext_module_ui(void) +{ + bool result; /* Bilan à retourner */ + + result = true; + + if (result) result = ensure_python_token_generator_is_registered(); + + if (result) result = ensure_python_buffer_line_is_registered(); + + assert(result); + + return result; + +} diff --git a/plugins/pychrysalide/glibext/module-ui.h b/plugins/pychrysalide/glibext/module-ui.h new file mode 100644 index 0000000..d91a2fa --- /dev/null +++ b/plugins/pychrysalide/glibext/module-ui.h @@ -0,0 +1,38 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * module.h - prototypes pour l'intégration du répertoire glibext (forme graphique) en tant que module + * + * 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_GLIBEXT_MODULE_UI_H +#define _PLUGINS_PYCHRYSALIDE_GLIBEXT_MODULE_UI_H + + +#include <Python.h> +#include <stdbool.h> + + +/* Intègre les objets du module 'glibext' (mode UI). */ +bool populate_glibext_module_ui(void); + + + +#endif /* _PLUGINS_PYCHRYSALIDE_GLIBEXT_MODULE_UI_H */ diff --git a/plugins/pychrysalide/glibext/module.c b/plugins/pychrysalide/glibext/module.c index 6ce0709..bbe357d 100644 --- a/plugins/pychrysalide/glibext/module.c +++ b/plugins/pychrysalide/glibext/module.c @@ -44,7 +44,9 @@ #include "objhole.h" #include "portion.h" #include "secstorage.h" +#include "serialize.h" #include "singleton.h" +#include "storage.h" #include "strbuilder.h" #include "work.h" #include "workqueue.h" @@ -116,12 +118,14 @@ bool populate_glibext_module(void) if (result) result = ensure_python_comparable_object_is_registered(); if (result) result = ensure_python_hashable_object_is_registered(); + if (result) result = ensure_python_serializable_object_is_registered(); if (result) result = ensure_python_singleton_candidate_is_registered(); if (result) result = ensure_python_string_builder_is_registered(); if (result) result = ensure_python_thick_object_is_registered(); if (result) result = ensure_python_binary_portion_is_registered(); if (result) result = ensure_python_generic_work_is_registered(); + if (result) result = ensure_python_object_storage_is_registered(); if (result) result = ensure_python_secret_storage_is_registered(); if (result) result = ensure_python_singleton_factory_is_registered(); if (result) result = ensure_python_work_queue_is_registered(); diff --git a/plugins/pychrysalide/glibext/objhole.c b/plugins/pychrysalide/glibext/objhole.c index 2a3ad6f..6bea5d1 100644 --- a/plugins/pychrysalide/glibext/objhole.c +++ b/plugins/pychrysalide/glibext/objhole.c @@ -37,12 +37,25 @@ -CREATE_DYN_CONSTRUCTOR(thick_object, G_TYPE_THICK_OBJECT); +/* ------------------------ GLUE POUR CREATION DEPUIS PYTHON ------------------------ */ + +CREATE_DYN_CONSTRUCTOR(thick_object, G_TYPE_THICK_OBJECT); /* Initialise une instance sur la base du dérivé de GObject. */ static int py_thick_object_init(PyObject *, PyObject *, PyObject *); + + +/* ------------------ LIAISON DE FONCTIONNALITES AVEC L'API PYTHON ------------------ */ + + +/* Pose un verrou à l'aide du bit dédié de GObject. */ +static PyObject *py_thick_object_lock(PyObject *, PyObject *); + +/* Retire un verrou via le bit dédié de GObject. */ +static PyObject *py_thick_object_unlock(PyObject *, PyObject *); + /* Indique le nombre de bits accaparés par la GLib. */ static PyObject *py_thick_object_get__GOBJECT_RESERVED_EXTRA_BITS(PyObject *, void *); @@ -54,6 +67,11 @@ static int py_thick_object_set_extra(PyObject *, PyObject *, void *); +/* ---------------------------------------------------------------------------------- */ +/* GLUE POUR CREATION DEPUIS PYTHON */ +/* ---------------------------------------------------------------------------------- */ + + /****************************************************************************** * * * Paramètres : self = objet à initialiser (théoriquement). * @@ -92,6 +110,86 @@ static int py_thick_object_init(PyObject *self, PyObject *args, PyObject *kwds) } + +/* ---------------------------------------------------------------------------------- */ +/* LIAISON DE FONCTIONNALITES AVEC L'API PYTHON */ +/* ---------------------------------------------------------------------------------- */ + + +/****************************************************************************** +* * +* Paramètres : self = instance représentant une extension d'objet. * +* args = arguments fournis à l'appel, non utilisé ici. * +* * +* Description : Pose un verrou à l'aide du bit dédié de GObject. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static PyObject *py_thick_object_lock(PyObject *self, PyObject *args) +{ + PyObject *result; /* Résultat à retourner */ + GThickObject *obj; /* Version GLib de l'instance */ + +#define THICK_OBJECT_LOCK_METHOD PYTHON_METHOD_DEF \ +( \ + lock, "$self", \ + METH_NOARGS, py_thick_object, \ + "Lock the object using the internal GLib bit.\n" \ +) + + obj = G_THICK_OBJECT(pygobject_get(self)); + + g_thick_object_lock(obj); + + result = Py_None; + Py_INCREF(result); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : self = instance représentant une extension d'objet. * +* args = arguments fournis à l'appel, non utilisé ici. * +* * +* Description : Retire un verrou via le bit dédié de GObject. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static PyObject *py_thick_object_unlock(PyObject *self, PyObject *args) +{ + PyObject *result; /* Résultat à retourner */ + GThickObject *obj; /* Version GLib de l'instance */ + +#define THICK_OBJECT_UNLOCK_METHOD PYTHON_METHOD_DEF \ +( \ + unlock, "$self", \ + METH_NOARGS, py_thick_object, \ + "Unlock the object using the internal GLib bit.\n" \ +) + + obj = G_THICK_OBJECT(pygobject_get(self)); + + g_thick_object_unlock(obj); + + result = Py_None; + Py_INCREF(result); + + return result; + +} + + /****************************************************************************** * * * Paramètres : self = objet Python concerné par l'appel. * @@ -215,6 +313,8 @@ static int py_thick_object_set_extra(PyObject *self, PyObject *value, void *clos PyTypeObject *get_python_thick_object_type(void) { static PyMethodDef py_thick_object_methods[] = { + THICK_OBJECT_LOCK_METHOD, + THICK_OBJECT_UNLOCK_METHOD, { NULL } }; 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/analysis/storage/serialize.c b/plugins/pychrysalide/glibext/serialize.c index 40fcef7..61f359f 100644 --- a/plugins/pychrysalide/analysis/storage/serialize.c +++ b/plugins/pychrysalide/glibext/serialize.c @@ -1,8 +1,8 @@ /* Chrysalide - Outil d'analyse de fichiers binaires - * serialize.c - équivalent Python du fichier "analysis/storage/serialize.h" + * serialize.c - équivalent Python du fichier "glibext/serialize.h" * - * Copyright (C) 2020 Cyrille Bagard + * Copyright (C) 2020-2025 Cyrille Bagard * * This file is part of Chrysalide. * @@ -28,13 +28,12 @@ #include <pygobject.h> -#include <analysis/storage/serialize-int.h> +#include <glibext/serialize-int.h> #include "storage.h" -#include "../../access.h" -#include "../../helpers.h" -#include "../../common/packed.h" +#include "../access.h" +#include "../helpers.h" @@ -42,23 +41,23 @@ /* Procède à l'initialisation de l'interface de génération. */ -static void py_serializable_object_interface_init(GSerializableObjectIface *, gpointer *); +static void py_serializable_object_interface_init(GSerializableObjectInterface *, gpointer *); -/* Charge un objet depuis une mémoire tampon. */ -static bool py_serializable_object_load_wrapper(GSerializableObject *, GObjectStorage *, packed_buffer_t *); +/* Charge un objet depuis un flux de données. */ +static bool py_serializable_object_load_wrapper(GSerializableObject *, GObjectStorage *, int); -/* Sauvegarde un objet dans une mémoire tampon. */ -static bool py_serializable_object_store_wrapper(const GSerializableObject *, GObjectStorage *, packed_buffer_t *); +/* Sauvegarde un objet dans un flux de données. */ +static bool py_serializable_object_store_wrapper(const GSerializableObject *, GObjectStorage *, int); /* ------------------------- CONNEXION AVEC L'API DE PYTHON ------------------------- */ -/* Charge un objet depuis une mémoire tampon. */ +/* Charge un objet depuis un flux de données. */ static bool py_serializable_object_load(PyObject *, PyObject *); -/* Sauvegarde un objet dans une mémoire tampon. */ +/* Sauvegarde un objet dans un flux de données. */ static bool py_serializable_object_store(PyObject *, PyObject *); @@ -81,7 +80,7 @@ static bool py_serializable_object_store(PyObject *, PyObject *); * * ******************************************************************************/ -static void py_serializable_object_interface_init(GSerializableObjectIface *iface, gpointer *unused) +static void py_serializable_object_interface_init(GSerializableObjectInterface *iface, gpointer *unused) { #define SERIALIZABLE_OBJECT_DOC \ @@ -94,8 +93,8 @@ static void py_serializable_object_interface_init(GSerializableObjectIface *ifac " ...\n" \ "\n" \ "The following methods have to be defined for new implementations:\n" \ - "* pychrysalide.analysis.storage.SerializableObject._load();\n" \ - "* pychrysalide.analysis.storage.SerializableObject._store();\n" + "* pychrysalide.glibext.SerializableObject._load();\n" \ + "* pychrysalide.glibext.SerializableObject._store();\n" iface->load = py_serializable_object_load_wrapper; iface->store = py_serializable_object_store_wrapper; @@ -106,10 +105,10 @@ static void py_serializable_object_interface_init(GSerializableObjectIface *ifac /****************************************************************************** * * * Paramètres : object = instruction d'assemblage à consulter. * -* storage = conservateur de données à manipuler ou NULL. * -* pbuf = zone tampon à remplir. * +* storage = conservateur de données à manipuler. * +* fd = flux ouvert en lecture. * * * -* Description : Charge un objet depuis une mémoire tampon. * +* Description : Charge un objet depuis un flux de données. * * * * Retour : Bilan de l'opération. * * * @@ -117,25 +116,24 @@ static void py_serializable_object_interface_init(GSerializableObjectIface *ifac * * ******************************************************************************/ -static bool py_serializable_object_load_wrapper(GSerializableObject *object, GObjectStorage *storage, packed_buffer_t *pbuf) +static bool py_serializable_object_load_wrapper(GSerializableObject *object, GObjectStorage *storage, int fd) { bool result; /* Bilan à retourner */ PyGILState_STATE gstate; /* Sauvegarde d'environnement */ - PyObject *storage_obj; /* Objet Python à emmployer */ PyObject *args; /* Arguments pour l'appel */ PyObject *pyobj; /* Objet Python concerné */ PyObject *pyret; /* Bilan de consultation */ #define SERIALIZABLE_OBJECT_LOAD_WRAPPER PYTHON_WRAPPER_DEF \ ( \ - _load, "$self, storage, pbuf, /", \ + _load, "$self, storage, fd, /", \ METH_VARARGS, \ - "Abstract method used to load an object definition from buffered data.\n" \ + "Abstract method used to load an object definition from a data stream.\n" \ "\n" \ - "The *storage* is a pychrysalide.analysis.storage.ObjectStorage instance" \ - " provided to store inner objects, if relevant, or None. The *pbuf*" \ - " argument points to a pychrysalide.common.PackedBuffer object containing" \ - " the data to process.\n" \ + "The *storage* is a pychrysalide.glibext.ObjectStorage instance" \ + " provided to store inner objects. The *fd* argument is an integer value" \ + " provided as a file descriptor which as to be kept open after" \ + " processing.\n" \ "\n" \ "The result is a boolean indicating the status of the operation." \ ) @@ -148,17 +146,9 @@ static bool py_serializable_object_load_wrapper(GSerializableObject *object, GOb if (has_python_method(pyobj, "_load")) { - if (storage == NULL) - { - storage_obj = Py_None; - Py_INCREF(storage_obj); - } - else - storage_obj = pygobject_new(G_OBJECT(storage)); - args = PyTuple_New(2); - PyTuple_SetItem(args, 0, storage_obj); - PyTuple_SetItem(args, 1, build_from_internal_packed_buffer(pbuf)); + PyTuple_SetItem(args, 0, pygobject_new(G_OBJECT(storage))); + PyTuple_SetItem(args, 1, PyLong_FromLong(fd)); pyret = run_python_method(pyobj, "_load", args); @@ -182,10 +172,10 @@ static bool py_serializable_object_load_wrapper(GSerializableObject *object, GOb /****************************************************************************** * * * Paramètres : object = instruction d'assemblage à consulter. * -* storage = conservateur de données à manipuler ou NULL. * -* pbuf = zone tampon à remplir. * +* storage = conservateur de données à manipuler. * +* fd = flux ouvert en écriture. * * * -* Description : Sauvegarde un objet dans une mémoire tampon. * +* Description : Sauvegarde un objet dans un flux de données. * * * * Retour : Bilan de l'opération. * * * @@ -193,25 +183,24 @@ static bool py_serializable_object_load_wrapper(GSerializableObject *object, GOb * * ******************************************************************************/ -static bool py_serializable_object_store_wrapper(const GSerializableObject *object, GObjectStorage *storage, packed_buffer_t *pbuf) +static bool py_serializable_object_store_wrapper(const GSerializableObject *object, GObjectStorage *storage, int fd) { bool result; /* Bilan à retourner */ PyGILState_STATE gstate; /* Sauvegarde d'environnement */ - PyObject *storage_obj; /* Objet Python à emmployer */ PyObject *args; /* Arguments pour l'appel */ PyObject *pyobj; /* Objet Python concerné */ PyObject *pyret; /* Bilan de consultation */ #define SERIALIZABLE_OBJECT_STORE_WRAPPER PYTHON_WRAPPER_DEF \ ( \ - _store, "$self, storage, pbuf, /", \ + _store, "$self, storage, fd, /", \ METH_VARARGS, \ - "Abstract method used to store an object definition into buffered data.\n" \ + "Abstract method used to store an object definition into a data stream.\n" \ "\n" \ - "The *storage* is a pychrysalide.analysis.storage.ObjectStorage instance" \ - " provided to store inner objects, if relevant, or None. The *pbuf*" \ - " argument points to a pychrysalide.common.PackedBuffer object containing" \ - " the data to process.\n" \ + "The *storage* is a pychrysalide.glibext.ObjectStorage instance" \ + " provided to store inner objects. The *fd* argument is an integer value" \ + " provided as a file descriptor which as to be kept open after" \ + " processing.\n" \ "\n" \ "The result is a boolean indicating the status of the operation." \ ) @@ -224,17 +213,9 @@ static bool py_serializable_object_store_wrapper(const GSerializableObject *obje if (has_python_method(pyobj, "_store")) { - if (storage == NULL) - { - storage_obj = Py_None; - Py_INCREF(storage_obj); - } - else - storage_obj = pygobject_new(G_OBJECT(storage)); - args = PyTuple_New(2); - PyTuple_SetItem(args, 0, storage_obj); - PyTuple_SetItem(args, 1, build_from_internal_packed_buffer(pbuf)); + PyTuple_SetItem(args, 0, pygobject_new(G_OBJECT(storage))); + PyTuple_SetItem(args, 1, PyLong_FromLong(fd)); pyret = run_python_method(pyobj, "_store", args); @@ -266,7 +247,7 @@ static bool py_serializable_object_store_wrapper(const GSerializableObject *obje * Paramètres : self = classe représentant un générateur à manipuler. * * args = arguments fournis à l'appel. * * * -* Description : Charge un objet depuis une mémoire tampon. * +* Description : Charge un objet depuis un flux de données. * * * * Retour : Bilan de l'opération. * * * @@ -278,32 +259,30 @@ static bool py_serializable_object_load(PyObject *self, PyObject *args) { PyObject *result; /* Bilan à retourner */ GObjectStorage *storage; /* Conservateur à manipuler */ - packed_buffer_t *pbuf; /* Tampon de données à employer*/ + int fd; /* Flux ouvert (en lecture) */ int ret; /* Bilan de lecture des args. */ GSerializableObject *object; /* Version native */ bool status; /* Bilan de l'opération */ #define SERIALIZABLE_OBJECT_LOAD_METHOD PYTHON_METHOD_DEF \ ( \ - load, "$self, storage, pbuf, /", \ + load, "$self, storage, fd, /", \ METH_VARARGS, py_serializable_object, \ - "Load an object definition from buffered data.\n" \ + "Load an object definition from a data stream.\n" \ "\n" \ - "The *storage* is a pychrysalide.analysis.storage.ObjectStorage instance" \ - " provided to store inner objects, if relevant, or None. The *pbuf*" \ - " argument points to a pychrysalide.common.PackedBuffer object containing" \ - " the data to process.\n" \ + "The *storage* is a pychrysalide.glibext.ObjectStorage instance" \ + " provided to store inner objects. The *fd* argument is an integer value" \ + " used as a file descriptor for writing data\n" \ "\n" \ "The result is a boolean indicating the status of the operation." \ ) - ret = PyArg_ParseTuple(args, "O&O&", convert_to_object_storage_or_none, &storage, - convert_to_packed_buffer, &pbuf); + ret = PyArg_ParseTuple(args, "O&i", convert_to_object_storage, &storage, &fd); if (!ret) return NULL; object = G_SERIALIZABLE_OBJECT(pygobject_get(self)); - status = g_serializable_object_load(object, storage, pbuf); + status = g_serializable_object_load(object, storage, fd); result = status ? Py_True : Py_False; Py_INCREF(result); @@ -318,7 +297,7 @@ static bool py_serializable_object_load(PyObject *self, PyObject *args) * Paramètres : self = classe représentant un générateur à manipuler. * * args = arguments fournis à l'appel. * * * -* Description : Sauvegarde un objet dans une mémoire tampon. * +* Description : Sauvegarde un objet dans un flux de données. * * * * Retour : Bilan de l'opération. * * * @@ -330,32 +309,30 @@ static bool py_serializable_object_store(PyObject *self, PyObject *args) { PyObject *result; /* Bilan à retourner */ GObjectStorage *storage; /* Conservateur à manipuler */ - packed_buffer_t *pbuf; /* Tampon de données à employer*/ + int fd; /* Flux ouvert (en lecture) */ int ret; /* Bilan de lecture des args. */ GSerializableObject *object; /* Version native */ bool status; /* Bilan de l'opération */ #define SERIALIZABLE_OBJECT_STORE_METHOD PYTHON_METHOD_DEF \ ( \ - store, "$self, storage, pbuf, /", \ + store, "$self, storage, fd, /", \ METH_VARARGS, py_serializable_object, \ - "Store an object definition into buffered data.\n" \ + "Store an object definition into a data stream.\n" \ "\n" \ - "The *storage* is a pychrysalide.analysis.storage.ObjectStorage instance" \ - " provided to store inner objects, if relevant, or None. The *pbuf*" \ - " argument points to a pychrysalide.common.PackedBuffer object containing" \ - " the data to process.\n" \ + "The *storage* is a pychrysalide.glibext.ObjectStorage instance" \ + " provided to store inner objects. The *fd* argument is an integer value" \ + " used as a file descriptor for writing data\n" \ "\n" \ "The result is a boolean indicating the status of the operation." \ ) - ret = PyArg_ParseTuple(args, "O&O&", convert_to_object_storage_or_none, &storage, - convert_to_packed_buffer, &pbuf); + ret = PyArg_ParseTuple(args, "O&i", convert_to_object_storage, &storage, &fd); if (!ret) return NULL; object = G_SERIALIZABLE_OBJECT(pygobject_get(self)); - status = g_serializable_object_store(object, storage, pbuf); + status = g_serializable_object_store(object, storage, fd); result = status ? Py_True : Py_False; Py_INCREF(result); @@ -395,7 +372,7 @@ PyTypeObject *get_python_serializable_object_type(void) PyVarObject_HEAD_INIT(NULL, 0) - .tp_name = "pychrysalide.analysis.storage.SerializableObject", + .tp_name = "pychrysalide.glibext.SerializableObject", .tp_basicsize = sizeof(PyObject), .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, @@ -442,7 +419,7 @@ bool ensure_python_serializable_object_is_registered(void) if (!PyType_HasFeature(type, Py_TPFLAGS_READY)) { - module = get_access_to_python_module("pychrysalide.analysis.storage"); + module = get_access_to_python_module("pychrysalide.glibext"); dict = PyModule_GetDict(module); diff --git a/plugins/pychrysalide/analysis/storage/serialize.h b/plugins/pychrysalide/glibext/serialize.h index 7e831e5..90688ba 100644 --- a/plugins/pychrysalide/analysis/storage/serialize.h +++ b/plugins/pychrysalide/glibext/serialize.h @@ -1,8 +1,8 @@ /* Chrysalide - Outil d'analyse de fichiers binaires - * serialize.h - prototypes pour l'équivalent Python du fichier "analysis/storage/serialize.h" + * serialize.h - prototypes pour l'équivalent Python du fichier "glibext/serialize.h" * - * Copyright (C) 2020 Cyrille Bagard + * Copyright (C) 2020-2025 Cyrille Bagard * * This file is part of Chrysalide. * @@ -22,8 +22,8 @@ */ -#ifndef _PLUGINS_PYCHRYSALIDE_ANALYSIS_STORAGE_SERIALIZE_H -#define _PLUGINS_PYCHRYSALIDE_ANALYSIS_STORAGE_SERIALIZE_H +#ifndef _PLUGINS_PYCHRYSALIDE_GLIBEXT_SERIALIZE_H +#define _PLUGINS_PYCHRYSALIDE_GLIBEXT_SERIALIZE_H #include <Python.h> @@ -34,7 +34,7 @@ /* Fournit un accès à une définition de type à diffuser. */ PyTypeObject *get_python_serializable_object_type(void); -/* Prend en charge l'objet 'pychrysalide.analysis.storage.SerializableObject'. */ +/* Prend en charge l'objet 'pychrysalide.glibext.SerializableObject'. */ bool ensure_python_serializable_object_is_registered(void); /* Tente de convertir en objet adapté à une mise en cache. */ @@ -42,4 +42,4 @@ int convert_to_serializable_object(PyObject *, void *); -#endif /* _PLUGINS_PYCHRYSALIDE_ANALYSIS_STORAGE_SERIALIZE_H */ +#endif /* _PLUGINS_PYCHRYSALIDE_GLIBEXT_SERIALIZE_H */ diff --git a/plugins/pychrysalide/analysis/storage/storage.c b/plugins/pychrysalide/glibext/storage.c index c54fe0f..f2962bf 100644 --- a/plugins/pychrysalide/analysis/storage/storage.c +++ b/plugins/pychrysalide/glibext/storage.c @@ -1,8 +1,8 @@ /* Chrysalide - Outil d'analyse de fichiers binaires - * storage.c - équivalent Python du fichier "analysis/storage/storage.c" + * storage.c - équivalent Python du fichier "glibext/storage.c" * - * Copyright (C) 2020 Cyrille Bagard + * Copyright (C) 2020-2025 Cyrille Bagard * * This file is part of Chrysalide. * @@ -25,25 +25,23 @@ #include "storage.h" +#include <assert.h> #include <pygobject.h> -#include <analysis/storage/storage-int.h> -#include <plugins/dt.h> +#include <glibext/storage-int.h> #include "serialize.h" -#include "../../access.h" -#include "../../helpers.h" -#include "../../common/packed.h" +#include "../access.h" +#include "../helpers.h" /* ------------------------ GLUE POUR CREATION DEPUIS PYTHON ------------------------ */ -/* Accompagne la création d'une instance dérivée en Python. */ -static PyObject *py_object_storage_new(PyTypeObject *, PyObject *, PyObject *); +CREATE_DYN_CONSTRUCTOR(object_storage, G_TYPE_OBJECT_STORAGE); /* Initialise une instance sur la base du dérivé de GObject. */ static int py_object_storage_init(PyObject *, PyObject *, PyObject *); @@ -68,9 +66,6 @@ static PyObject *py_object_storage_unpack_object(PyObject *, PyObject *); /* Sauvegarde un object sous forme de données rassemblées. */ static PyObject *py_object_storage_store_object(PyObject *, PyObject *); -/* Sauvegarde un object interne sous forme de données. */ -static PyObject *py_object_storage_pack_object(PyObject *, PyObject *); - /* ---------------------------------------------------------------------------------- */ @@ -80,66 +75,6 @@ static PyObject *py_object_storage_pack_object(PyObject *, PyObject *); /****************************************************************************** * * -* 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_object_storage_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_object_storage_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_OBJECT_STORAGE, 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; - -} - - -/****************************************************************************** -* * * Paramètres : self = objet à initialiser (théoriquement). * * args = arguments fournis à l'appel. * * kwds = arguments de type key=val fournis. * @@ -154,7 +89,9 @@ static PyObject *py_object_storage_new(PyTypeObject *type, PyObject *args, PyObj static int py_object_storage_init(PyObject *self, PyObject *args, PyObject *kwds) { - const char *hash; /* Empreinte de contenu */ + const char *type; /* Type global de conservation */ + unsigned char version; /* Version de ce type */ + const char *uid; /* Identifiant de distinction */ int ret; /* Bilan de lecture des args. */ GObjectStorage *storage; /* Mécanismes natifs */ @@ -164,14 +101,15 @@ static int py_object_storage_init(PyObject *self, PyObject *args, PyObject *kwds "\n" \ "Instances can be created using the following constructor:\n" \ "\n" \ - " ObjectStorage(hash)" \ + " ObjectStorage(type, version uid)" \ "\n" \ - "Where *hash* should a string built from the checksum of the" \ - " relative binary content linked to the storage.pychrysalide." + "Where *type* is a short string describing the storage kind," \ + " *version* provides a version control for this type and *uid* is" \ + " an arbitrary unique identifier used for creating temporary files." /* Récupération des paramètres */ - ret = PyArg_ParseTuple(args, "s", &hash); + ret = PyArg_ParseTuple(args, "sbs", &type, &version, &uid); if (!ret) return -1; /* Initialisation d'un objet GLib */ @@ -183,7 +121,8 @@ static int py_object_storage_init(PyObject *self, PyObject *args, PyObject *kwds storage = G_OBJECT_STORAGE(pygobject_get(self)); - storage->hash = strdup(hash); + if (!g_object_storage_create(storage, type, version, uid)) + return -1; return 0; @@ -212,27 +151,27 @@ static int py_object_storage_init(PyObject *self, PyObject *args, PyObject *kwds static PyObject *py_object_storage_load(PyObject *self, PyObject *args) { PyObject *result; /* Emplacement à retourner */ - packed_buffer_t *pbuf; /* Tampon de données à employer*/ + const char *filename; /* Fichier de source à traiter */ int ret; /* Bilan de lecture des args. */ GObjectStorage *storage; /* Mécanismes natifs */ -#define OBJECT_STORAGE_LOAD_METHOD PYTHON_METHOD_DEF \ -( \ - load, "pbuf, /", \ - METH_STATIC | METH_VARARGS, py_object_storage, \ - "Construct a new storage from a buffer.\n" \ - "\n" \ - "The *pbuf* has to be an instance of type" \ - " pychrysalide.common.PackedBuffer.\n" \ - "\n" \ - "The result is a new pychrysalide.analysis.storage.ObjectStorage" \ - " object on success, *None* otherwise." \ +#define OBJECT_STORAGE_LOAD_METHOD PYTHON_METHOD_DEF \ +( \ + load, "filename, /", \ + METH_STATIC | METH_VARARGS, py_object_storage, \ + "Construct a new storage from a filename.\n" \ + "\n" \ + "The *filename* argument points to the source file to" \ + " read.\n" \ + "\n" \ + "The result is a new pychrysalide.glibext.ObjectStorage" \ + " object on success, *None* otherwise." \ ) - ret = PyArg_ParseTuple(args, "O&", convert_to_packed_buffer, &pbuf); + ret = PyArg_ParseTuple(args, "s", &filename); if (!ret) return NULL; - storage = g_object_storage_load(pbuf); + storage = g_object_storage_load(filename); if (storage == NULL) { @@ -242,7 +181,7 @@ static PyObject *py_object_storage_load(PyObject *self, PyObject *args) else { result = pygobject_new(G_OBJECT(storage)); - g_object_unref(G_OBJECT(storage)); + unref_object(storage); } return result; @@ -266,29 +205,29 @@ static PyObject *py_object_storage_load(PyObject *self, PyObject *args) static PyObject *py_object_storage_store(PyObject *self, PyObject *args) { PyObject *result; /* Emplacement à retourner */ - packed_buffer_t *pbuf; /* Tampon de données à employer*/ + const char *filename; /* Fichier de destination */ int ret; /* Bilan de lecture des args. */ GObjectStorage *storage; /* Mécanismes natifs */ bool status; /* Bilan de l'opération */ #define OBJECT_STORAGE_STORE_METHOD PYTHON_METHOD_DEF \ ( \ - store, "$self, pbuf, /", \ + store, "$self, filename, /", \ METH_VARARGS, py_object_storage, \ - "Save a storage into a buffer.\n" \ + "Save a storage into a file.\n" \ "\n" \ - "The *pbuf* has to be an instance of type" \ - " pychrysalide.common.PackedBuffer.\n" \ + "The *filename* argument points to the destination" \ + " file to write.\n" \ "\n" \ "The result is *True* on success, *False* otherwise." \ ) - ret = PyArg_ParseTuple(args, "O&", convert_to_packed_buffer, &pbuf); + ret = PyArg_ParseTuple(args, "s", &filename); if (!ret) return NULL; storage = G_OBJECT_STORAGE(pygobject_get(self)); - status = g_object_storage_store(storage, pbuf); + status = g_object_storage_store(storage, filename); result = status ? Py_True : Py_False; Py_INCREF(result); @@ -331,7 +270,7 @@ static PyObject *py_object_storage_load_object(PyObject *self, PyObject *args) " the data to unserialize.\n" \ "\n" \ "The result is a pychrysalide.analysis.storage.SerializableObject" \ - " instancet in case of success, or None in case of failure." \ + " instancet in case of success, or *None* in case of failure." \ ) ret = PyArg_ParseTuple(args, "sK", &name, &pos); @@ -370,31 +309,34 @@ static PyObject *py_object_storage_load_object(PyObject *self, PyObject *args) static PyObject *py_object_storage_unpack_object(PyObject *self, PyObject *args) { PyObject *result; /* Bilan à retourner */ + int fd; /* Flux de fonnées courant */ const char *name; /* Désignation de groupe */ - packed_buffer_t *pbuf; /* Tampon de données à employer*/ int ret; /* Bilan de lecture des args. */ GObjectStorage *storage; /* Mécanismes natifs */ GSerializableObject *object; /* Objet reconstruit ou NULL */ #define OBJECT_STORAGE_UNPACK_OBJECT_METHOD PYTHON_METHOD_DEF \ ( \ - unpack_object, "$self, name, pbuf, /", \ + unpack_object, "$self, fd, name, /", \ METH_VARARGS, py_object_storage, \ - "Load an object from a buffer with a location pointing to data.\n" \ + "Load an object from a reference to serialized data.\n" \ "\n" \ - "The *name* is a string label for the group of target objects and" \ - " *pbuf* has to be a pychrysalide.common.PackedBuffer instance.\n" \ + "The *fd* argument is a file descriptor pointing to the data" \ + " stream for a current object being restored. A reference to" \ + " another object belonging to a group pointed by the string *name*" \ + " should be available at the current read position for this data" \ + " stream.\n" \ "\n" \ "The result is a pychrysalide.analysis.storage.SerializableObject" \ - " instancet in case of success, or None in case of failure." \ + " instancet in case of success, or *None* in case of failure." \ ) - ret = PyArg_ParseTuple(args, "sO&", &name, convert_to_packed_buffer, &pbuf); + ret = PyArg_ParseTuple(args, "is", &fd, &name); if (!ret) return NULL; storage = G_OBJECT_STORAGE(pygobject_get(self)); - object = g_object_storage_unpack_object(storage, name, pbuf); + object = g_object_storage_unpack_object(storage, fd, name); if (object != NULL) result = pygobject_new(G_OBJECT(object)); @@ -443,7 +385,7 @@ static PyObject *py_object_storage_store_object(PyObject *self, PyObject *args) " pychrysalide.analysis.storage.SerializableObject instance.\n" \ "\n" \ "The result is the position of the data for stored object," \ - " provided as an integer offset, in case of success or None" \ + " provided as an integer offset, in case of success or *None*" \ " in case of failure." \ ) @@ -469,62 +411,6 @@ static PyObject *py_object_storage_store_object(PyObject *self, PyObject *args) /****************************************************************************** * * -* Paramètres : self = classe représentant une mémorisation de types. * -* args = arguments fournis à l'appel. * -* * -* Description : Sauvegarde un object interne sous forme de données. * -* * -* Retour : Bilan de l'opération. * -* * -* Remarques : - * -* * -******************************************************************************/ - -static PyObject *py_object_storage_pack_object(PyObject *self, PyObject *args) -{ - PyObject *result; /* Emplacement à retourner */ - const char *name; /* Désignation de groupe */ - GSerializableObject *object; /* Objet à traiter */ - packed_buffer_t *pbuf; /* Tampon de données à employer*/ - int ret; /* Bilan de lecture des args. */ - GObjectStorage *storage; /* Mécanismes natifs */ - bool status; /* Bilan de l'opération */ - -#define OBJECT_STORAGE_PACK_OBJECT_METHOD PYTHON_METHOD_DEF \ -( \ - pack_object, "$self, name, object, pbuf/", \ - METH_VARARGS, py_object_storage, \ - "Save an object as serialized data and store the location of" \ - " the data intro a buffer.\n" \ - "\n" \ - "The *name* is a string label for the group of target objects," \ - " the processed *object* has to be a" \ - " pychrysalide.analysis.storage.SerializableObject instance" \ - " and *pbuf* is expected to be a" \ - " pychrysalide.common.PackedBuffer instance.\n" \ - "\n" \ - "The status of the operation is returned as a boolean value:" \ - " *True* for success, *False* for failure." \ -) - - ret = PyArg_ParseTuple(args, "sO&O&", &name, convert_to_serializable_object, &object, - convert_to_packed_buffer, &pbuf); - if (!ret) return NULL; - - storage = G_OBJECT_STORAGE(pygobject_get(self)); - - status = g_object_storage_pack_object(storage, name, object, pbuf); - - result = status ? Py_True : Py_False; - Py_INCREF(result); - - return result; - -} - - -/****************************************************************************** -* * * Paramètres : - * * * * Description : Fournit un accès à une définition de type à diffuser. * @@ -543,7 +429,6 @@ PyTypeObject *get_python_object_storage_type(void) OBJECT_STORAGE_LOAD_OBJECT_METHOD, OBJECT_STORAGE_UNPACK_OBJECT_METHOD, OBJECT_STORAGE_STORE_OBJECT_METHOD, - OBJECT_STORAGE_PACK_OBJECT_METHOD, { NULL } }; @@ -555,7 +440,7 @@ PyTypeObject *get_python_object_storage_type(void) PyVarObject_HEAD_INIT(NULL, 0) - .tp_name = "pychrysalide.analysis.storage.ObjectStorage", + .tp_name = "pychrysalide.glibext.ObjectStorage", .tp_basicsize = sizeof(PyGObject), .tp_flags = Py_TPFLAGS_DEFAULT, @@ -579,7 +464,7 @@ PyTypeObject *get_python_object_storage_type(void) * * * Paramètres : module = module dont la définition est à compléter. * * * -* Description : Prend en charge l'objet 'pychrysalide....ObjectStorage'. * +* Description : Prend en charge l'objet 'pychrysalide.glibext.ObjectStorage'.* * * * Retour : Bilan de l'opération. * * * @@ -597,7 +482,7 @@ bool ensure_python_object_storage_is_registered(void) if (!PyType_HasFeature(type, Py_TPFLAGS_READY)) { - module = get_access_to_python_module("pychrysalide.analysis.storage"); + module = get_access_to_python_module("pychrysalide.glibext"); dict = PyModule_GetDict(module); diff --git a/plugins/pychrysalide/analysis/storage/storage.h b/plugins/pychrysalide/glibext/storage.h index a0a2c18..681f99a 100644 --- a/plugins/pychrysalide/analysis/storage/storage.h +++ b/plugins/pychrysalide/glibext/storage.h @@ -1,8 +1,8 @@ /* Chrysalide - Outil d'analyse de fichiers binaires - * storage.h - prototypes pour l'équivalent Python du fichier "analysis/storage/storage.h" + * storage.h - prototypes pour l'équivalent Python du fichier "glibext/storage.h" * - * Copyright (C) 2020 Cyrille Bagard + * Copyright (C) 2020-2025 Cyrille Bagard * * This file is part of Chrysalide. * @@ -22,8 +22,8 @@ */ -#ifndef _PLUGINS_PYCHRYSALIDE_ANALYSIS_STORAGE_STORAGE_H -#define _PLUGINS_PYCHRYSALIDE_ANALYSIS_STORAGE_STORAGE_H +#ifndef _PLUGINS_PYCHRYSALIDE_GLIBEXT_STORAGE_H +#define _PLUGINS_PYCHRYSALIDE_GLIBEXT_STORAGE_H #include <Python.h> @@ -34,7 +34,7 @@ /* Fournit un accès à une définition de type à diffuser. */ PyTypeObject *get_python_object_storage_type(void); -/* Prend en charge l'objet 'pychrysalide.analysis.storage.ObjectStorage'. */ +/* Prend en charge l'objet 'pychrysalide.glibext.ObjectStorage'. */ bool ensure_python_object_storage_is_registered(void); /* Tente de convertir en conservateur d'objets. */ @@ -45,4 +45,4 @@ int convert_to_object_storage_or_none(PyObject *, void *); -#endif /* _PLUGINS_PYCHRYSALIDE_ANALYSIS_STORAGE_STORAGE_H */ +#endif /* _PLUGINS_PYCHRYSALIDE_GLIBEXT_STORAGE_H */ diff --git a/plugins/pychrysalide/analysis/storage/tpmem.c b/plugins/pychrysalide/glibext/tpmem.c index ae07008..ae07008 100644 --- a/plugins/pychrysalide/analysis/storage/tpmem.c +++ b/plugins/pychrysalide/glibext/tpmem.c diff --git a/plugins/pychrysalide/analysis/storage/tpmem.h b/plugins/pychrysalide/glibext/tpmem.h index 1085632..1085632 100644 --- a/plugins/pychrysalide/analysis/storage/tpmem.h +++ b/plugins/pychrysalide/glibext/tpmem.h 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/plugins/pynb/Makefile.am b/plugins/pynb/Makefile.am new file mode 100644 index 0000000..50e549f --- /dev/null +++ b/plugins/pynb/Makefile.am @@ -0,0 +1,77 @@ + +BUILT_SOURCES = resources.h resources.c + + +lib_LTLIBRARIES = libpynbui.la + +libdir = $(pluginslibdir) + + +# if BUILD_PYTHON3_BINDINGS + +# PYTHON3_LIBADD = python/libpynbpython.la + +# if BUILD_DISCARD_LOCAL + +# PYTHON3_LDFLAGS = -Wl,-rpath,$(pluginslibdir) \ +# -L$(top_srcdir)/plugins/pychrysalide/.libs -l:pychrysalide.so + +# else + +# PYTHON3_LDFLAGS = -Wl,-rpath,$(abs_top_srcdir)/plugins/pychrysalide/.libs \ +# -L$(top_srcdir)/plugins/pychrysalide/.libs -l:pychrysalide.so + +# endif + +# PYTHON3_SUBDIRS = python + +# endif + + +libpynbui_la_SOURCES = \ + core-ui-int.h \ + core-ui.h core-ui.c \ + panel-int.h \ + panel.h panel.c \ + params-int.h \ + params.h params.c \ + prefs-int.h \ + prefs.h prefs.c \ + resources.h resources.c + +libpynbui_la_LIBADD = \ + $(PYTHON3_LIBADD) + +libpynbui_la_CFLAGS = $(LIBGTK4_CFLAGS) + +libpynbui_la_LDFLAGS = \ + $(LIBGTK4_LIBS) $(PYTHON3_LDFLAGS) + + +devdir = $(includedir)/chrysalide-$(subdir) + +dev_HEADERS = $(libpynbui_la_SOURCES:%c=) + + +RES_FILES = \ + panel.ui \ + params.ui \ + prefs.ui \ + data/images/pynb-symbolic.svg + + +resources.c: gresource.xml $(RES_FILES) + glib-compile-resources --target=$@ --sourcedir=$(srcdir) --generate-source --c-name plugins_pynb gresource.xml + +resources.h: gresource.xml + glib-compile-resources --target=$@ --sourcedir=$(srcdir) --generate-header --c-name plugins_pynb gresource.xml + + +CLEANFILES = resources.h resources.c + +EXTRA_DIST = gresource.xml $(RES_FILES) + + +AM_CPPFLAGS = -I$(top_srcdir)/src $(DEBUG_CFLAGS) $(WARNING_FLAGS) $(COMPLIANCE_FLAGS) + +SUBDIRS = $(PYTHON3_SUBDIRS) diff --git a/plugins/pynb/core-ui-int.h b/plugins/pynb/core-ui-int.h new file mode 100644 index 0000000..caf5713 --- /dev/null +++ b/plugins/pynb/core-ui-int.h @@ -0,0 +1,56 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * core-ui-int.h - prototypes internes pour le plugin présentant des notes avec code 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_PYNB_CORE_UI_INT_H +#define _PLUGINS_PYNB_CORE_UI_INT_H + + +#include <plugins/native-int.h> + + +#include "core-ui.h" + + + +/* Greffon natif pour la présentation de notes avec texte et code Python (instance) */ +struct _GPythonNotebookPluginUI +{ + GNativePlugin parent; /* A laisser en premier */ + +}; + + +/* Greffon natif pour la présentation de notes avec texte et code Python (classe) */ +struct _GPythonNotebookPluginUIClass +{ + GNativePluginClass parent; /* A laisser en premier */ + +}; + + +/* Met en place un module pour un module pour présentation. */ +bool g_python_notebook_plugin_ui_create(GPythonNotebookPluginUI *, GModule *); + + + +#endif /* _PLUGINS_PYNB_CORE_UI_INT_H */ diff --git a/plugins/pynb/core-ui.c b/plugins/pynb/core-ui.c new file mode 100644 index 0000000..dd49a83 --- /dev/null +++ b/plugins/pynb/core-ui.c @@ -0,0 +1,363 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * core-ui.c - présentation de notes sous forme de texte et de code 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 "core-ui.h" + + +#include <i18n.h> +#include <gui/core/panels.h> +#include <plugins/self.h> +#include <plugins/tweakable-int.h> + + +#include "core-ui-int.h" +#include "panel.h" +#include "params.h" +#include "prefs.h" + + + +/* ---------------------- COMPOSITION DE NOUVEAU GREFFON NATIF ---------------------- */ + + +/* Initialise la classe des recherches et identifications. */ +static void g_python_notebook_plugin_ui_class_init(GPythonNotebookPluginUIClass *); + +/* Procède à l'initialisation de l'interface d'intervention. */ +static void g_python_notebook_plugin_ui_tweakable_plugin_interface_init(GTweakablePluginInterface *); + +/* Initialise une instance de recherches et identifications. */ +static void g_python_notebook_plugin_ui_init(GPythonNotebookPluginUI *); + +/* Supprime toutes les références externes. */ +static void g_python_notebook_plugin_ui_dispose(GObject *); + +/* Procède à la libération totale de la mémoire. */ +static void g_python_notebook_plugin_ui_finalize(GObject *); + + + +/* --------------------- IMPLEMENTATION DES FONCTIONS DE CLASSE --------------------- */ + + +/* Prend acte de l'activation du greffon. */ +static bool g_python_notebook_plugin_ui_enable(GPythonNotebookPluginUI *); + +/* Prend acte de la désactivation du greffon. */ +static bool g_python_notebook_plugin_ui_disable(GPythonNotebookPluginUI *); + + + +/* ------------------- INTEGRATION DANS L'EDITION DES PREFERENCES ------------------- */ + + +/* Fournit une liste de sections de configuration. */ +static tweak_info_t *g_python_notebook_plugin_ui_get_tweak_info(const GTweakablePlugin *, size_t *); + + + +/* ---------------------------------------------------------------------------------- */ +/* COMPOSITION DE NOUVEAU GREFFON NATIF */ +/* ---------------------------------------------------------------------------------- */ + + +/* Indique le type défini pour une présentation de notes texte et code Python. */ +G_DEFINE_TYPE_WITH_CODE(GPythonNotebookPluginUI, g_python_notebook_plugin_ui, G_TYPE_NATIVE_PLUGIN, + G_IMPLEMENT_INTERFACE(G_TYPE_TWEAKABLE_PLUGIN, g_python_notebook_plugin_ui_tweakable_plugin_interface_init)); + + +NATIVE_PLUGIN_ENTRYPOINT(g_python_notebook_plugin_ui_new); + + +/****************************************************************************** +* * +* Paramètres : class = classe à initialiser. * +* * +* Description : Initialise la classe des recherches et identifications. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_python_notebook_plugin_ui_class_init(GPythonNotebookPluginUIClass *class) +{ + GObjectClass *object; /* Autre version de la classe */ + GPluginModuleClass *plugin; /* Version parente de la classe*/ + + object = G_OBJECT_CLASS(class); + + object->dispose = g_python_notebook_plugin_ui_dispose; + object->finalize = g_python_notebook_plugin_ui_finalize; + + plugin = G_PLUGIN_MODULE_CLASS(class); + + plugin->enable = (pg_management_fc)g_python_notebook_plugin_ui_enable; + plugin->disable = (pg_management_fc)g_python_notebook_plugin_ui_disable; + +} + + +/****************************************************************************** +* * +* Paramètres : iface = interface GLib à initialiser. * +* * +* Description : Procède à l'initialisation de l'interface d'intervention. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_python_notebook_plugin_ui_tweakable_plugin_interface_init(GTweakablePluginInterface *iface) +{ + iface->get_info = g_python_notebook_plugin_ui_get_tweak_info; + +} + + +/****************************************************************************** +* * +* Paramètres : plugin = instance à initialiser. * +* * +* Description : Initialise une instance de recherches et identifications. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_python_notebook_plugin_ui_init(GPythonNotebookPluginUI *plugin) +{ + STORE_PLUGIN_ABI(plugin); + +} + + +/****************************************************************************** +* * +* Paramètres : object = instance d'objet GLib à traiter. * +* * +* Description : Supprime toutes les références externes. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_python_notebook_plugin_ui_dispose(GObject *object) +{ + G_OBJECT_CLASS(g_python_notebook_plugin_ui_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_python_notebook_plugin_ui_finalize(GObject *object) +{ + G_OBJECT_CLASS(g_python_notebook_plugin_ui_parent_class)->finalize(object); + +} + + +/****************************************************************************** +* * +* Paramètres : module = extension vue du système. * +* * +* Description : Crée un module pour présentation de notes. * +* * +* Retour : Adresse de la structure mise en place. * +* * +* Remarques : Le transfert de propriétée du module est total. * +* * +******************************************************************************/ + +GPluginModule *g_python_notebook_plugin_ui_new(GModule *module) +{ + GPythonNotebookPluginUI *result; /* Structure à retourner */ + + result = g_object_new(G_TYPE_PYTHON_NOTEBOOK_PLUGIN_UI, NULL); + + if (!g_python_notebook_plugin_ui_create(result, module)) + g_clear_object(&result); + + return G_PLUGIN_MODULE(result); + +} + + +/****************************************************************************** +* * +* Paramètres : plugin = instance à initialiser pleinement. * +* module = extension vue du système. * +* * +* Description : Met en place un module pour un module pour présentation. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : Le transfert de propriétée du module est total. * +* * +******************************************************************************/ + +bool g_python_notebook_plugin_ui_create(GPythonNotebookPluginUI *plugin, GModule *module) +{ + bool result; /* Bilan à retourner */ + +#ifdef INCLUDE_PYTHON3_BINDINGS +# define PG_REQ REQ_LIST("PyChrysalide") +#else +# define PG_REQ NO_REQ +#endif + + result = g_native_plugin_create(G_NATIVE_PLUGIN(plugin), + "PythonNotebook", + "Edit notebook with text and code to support binary analysis", + PACKAGE_VERSION, + CHRYSALIDE_WEBSITE("doc/plugins/pynb"), + PG_REQ, + module); + + return result; + +} + + + +/* ---------------------------------------------------------------------------------- */ +/* IMPLEMENTATION DES FONCTIONS DE CLASSE */ +/* ---------------------------------------------------------------------------------- */ + + +/****************************************************************************** +* * +* Paramètres : plugin = greffon à manipuler. * +* * +* Description : Prend acte de l'activation du greffon. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static bool g_python_notebook_plugin_ui_enable(GPythonNotebookPluginUI *plugin) +{ + bool result; /* Bilan à retourner */ + panel_info_t info; /* Infos d'enregistrement */ + + info.category = "Main"; + + info.image = "pynb-symbolic"; + info.title = _("Python notebook"); + info.desc = _("Edit notebook with text and code to support binary analysis"); + + info.personality = FPP_MAIN_PANEL; + + info.panel_type = GTK_TYPE_PYTHON_NOTEBOOK_PANEL; + info.params_type = GTK_TYPE_PYTHON_NOTEBOOK_PARAMETERS; + + result = register_framework_panel_definition(&info); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : plugin = greffon à manipuler. * +* * +* Description : Prend acte de la désactivation du greffon. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static bool g_python_notebook_plugin_ui_disable(GPythonNotebookPluginUI *plugin) +{ + bool result; /* Bilan à retourner */ + + + // TODO : unregister + + result = true; + + + return result; + +} + + + +/* ---------------------------------------------------------------------------------- */ +/* INTEGRATION DANS L'EDITION DES PREFERENCES */ +/* ---------------------------------------------------------------------------------- */ + + +/****************************************************************************** +* * +* Paramètres : plugin = interface à manipuler. * +* count = taille de la liste renvoyée. [OUT] * +* * +* Description : Fournit une liste de sections de configuration. * +* * +* Retour : Définition(s) de section de configuration ou NULL. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static tweak_info_t *g_python_notebook_plugin_ui_get_tweak_info(const GTweakablePlugin *plugin, size_t *count) +{ + tweak_info_t *result; /* Liste à renvoyer */ + + tweak_info_t infos[] = { + TWEAK_SIMPLE_DEF("root", "Basics", + "pynb-symbolic", "pynotebook", "Notebook", GTK_TYPE_PYTHON_NOTEBOOK_TWEAK_PANEL), + }; + + *count = 1; + result = malloc(*count * sizeof(tweak_info_t)); + + memcpy(result, infos, *count * sizeof(tweak_info_t)); + + return result; + +} diff --git a/plugins/pynb/core-ui.h b/plugins/pynb/core-ui.h new file mode 100644 index 0000000..8ab9dd9 --- /dev/null +++ b/plugins/pynb/core-ui.h @@ -0,0 +1,43 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * core-ui.h - prototypes pour la présentation de notes sous forme de texte et de code 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_FIDO_CORE_UI_H +#define _PLUGINS_FIDO_CORE_UI_H + + +#include <plugins/plugin.h> +#include <plugins/plugin-int.h> + + + +#define G_TYPE_PYTHON_NOTEBOOK_PLUGIN_UI (g_python_notebook_plugin_ui_get_type()) + +DECLARE_GTYPE(GPythonNotebookPluginUI, g_python_notebook_plugin_ui, G, PYTHON_NOTEBOOK_PLUGIN_UI); + + +/* Crée un module pour présentation de notes. */ +GPluginModule *g_python_notebook_plugin_ui_new(GModule *); + + + +#endif /* _PLUGINS_FIDO_CORE_UI_H */ diff --git a/plugins/pynb/data/images/pynb-symbolic.svg b/plugins/pynb/data/images/pynb-symbolic.svg new file mode 100644 index 0000000..f8cae60 --- /dev/null +++ b/plugins/pynb/data/images/pynb-symbolic.svg @@ -0,0 +1,144 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<!-- Created with Inkscape (http://www.inkscape.org/) --> + +<svg + width="256" + height="256" + viewBox="0 0 67.73333 67.733333" + version="1.1" + id="svg2759" + sodipodi:docname="pynotebook.svg" + inkscape:version="1.2.2 (b0a8486541, 2022-12-01)" + 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="namedview2761" + pagecolor="#ffffff" + bordercolor="#000000" + borderopacity="0.25" + inkscape:showpageshadow="2" + inkscape:pageopacity="0.0" + inkscape:pagecheckerboard="false" + inkscape:deskcolor="#d1d1d1" + inkscape:document-units="px" + showgrid="false" + inkscape:zoom="2.9329997" + inkscape:cx="126.83261" + inkscape:cy="128.1964" + 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="defs2756"> + <linearGradient + id="b" + x1="28.809" + y1="28.882" + x2="45.803001" + y2="45.162998" + gradientUnits="userSpaceOnUse" + gradientTransform="matrix(12.026515,0,0,11.963752,-37.015053,-73.520624)"> + <stop + stop-color="#FFE052" + id="stop3586" /> + <stop + offset="1" + stop-color="#FFC331" + id="stop3588" /> + </linearGradient> + <linearGradient + id="a" + x1="19.075001" + y1="18.782" + x2="34.897999" + y2="34.658001" + gradientUnits="userSpaceOnUse" + gradientTransform="matrix(12.026515,0,0,11.963752,-37.015053,-73.520624)"> + <stop + stop-color="#387EB8" + id="stop3581" /> + <stop + offset="1" + stop-color="#366994" + id="stop3583" /> + </linearGradient> + </defs> + <g + inkscape:label="Calque 1" + inkscape:groupmode="layer" + id="layer1"> + <g + id="g3524" + transform="translate(2.9562937,-0.62320885)" + sodipodi:insensitive="true" + style="display:none"> + <path + id="rect2966" + style="fill:#3a1616;fill-opacity:1;stroke-width:0.529167;stroke-linecap:round;stroke-linejoin:round;paint-order:fill markers stroke" + d="m 49.272443,10.836031 c 0.102978,0.351405 0.158647,0.723392 0.158647,1.108976 V 57.03476 c 0,2.168007 -1.745406,3.913456 -3.913456,3.913456 H 16.30288 c -0.385538,0 -0.75709,-0.05622 -1.108459,-0.159163 0.237938,0.812336 0.730853,1.513585 1.387112,2.01175 0.65626,0.498165 1.475864,0.793246 2.367181,0.793246 h 29.214753 c 2.16805,0 3.913456,-1.745449 3.913456,-3.913456 V 14.59084 c 0,-1.782422 -1.180022,-3.278791 -2.80448,-3.754809 z" + sodipodi:nodetypes="csssscsssssc" /> + <path + id="rect2964" + style="display:inline;fill:#a44040;stroke-width:0.529167;stroke-linecap:round;stroke-linejoin:round;paint-order:fill markers stroke" + d="m 13.657273,5.3857002 h 29.21476 c 2.168053,0 3.913452,1.7453645 3.913452,3.9133733 V 54.388991 c 0,2.168009 -1.745399,3.913373 -3.913452,3.913373 h -29.21476 c -1.084026,0 -2.062389,-0.436341 -2.769745,-1.143683 -0.707357,-0.707342 -1.1437069,-1.685685 -1.1437069,-2.76969 V 9.2990735 c 0,-2.1680088 1.7453999,-3.9133733 3.9134519,-3.9133733 z" + sodipodi:nodetypes="ssssssssss" /> + <path + id="rect3518" + style="fill:#2d3a16;stroke-width:0.529167;stroke-linecap:round;stroke-linejoin:round;paint-order:fill markers stroke" + d="m 10.887528,57.158681 5.291742,4.9e-5 5.29299,5.29246 h -5.291667 z" + sodipodi:nodetypes="ccccc" /> + </g> + <g + id="g3807" + transform="matrix(0.275,0,0,0.27644269,10.179141,20.324238)" + style="display:none;stroke-width:3.62685"> + <path + d="m 76.135321,-13.223349 c -26.868437,0 -25.19164,11.6515879 -25.19164,11.6515879 l 0.03307,12.0716141 h 25.638125 v 3.621485 h -35.82789 c 0,0 -17.187994,-1.951302 -17.187994,25.161874 0,27.106562 15.005182,26.147447 15.005182,26.147447 h 8.956145 V 52.849722 c 0,0 -0.482864,-15.005182 14.767057,-15.005182 h 25.426458 c 0,0 14.287506,0.231511 14.287506,-13.807942 V 0.82271803 c 0,0 2.16958,-14.04606703 -25.906021,-14.04606703 z m -14.138672,8.1160932 c 2.549922,0 4.613672,2.0637499 4.613672,4.61367177 0,2.54992183 -2.06375,4.61367183 -4.613672,4.61367183 a 4.6070572,4.6070572 0 0 1 -4.613672,-4.61367183 c 0,-2.54992187 2.06375,-4.61367177 4.613672,-4.61367177 z" + fill="url(#a)" + id="path3577" + style="fill:url(#a);stroke-width:11.9951" /> + <path + d="m 76.895998,92.057664 c 26.868432,0 25.191642,-11.651588 25.191642,-11.651588 l -0.0331,-12.071615 h -25.6381 v -3.621484 h 35.82458 c 0,0 17.1913,1.951302 17.1913,-25.158567 0,-27.109869 -15.00518,-26.147447 -15.00518,-26.147447 H 105.471 v 12.57763 c 0,0 0.48286,15.005182 -14.76706,15.005182 H 65.277482 c 0,0 -14.287499,-0.231511 -14.287499,13.807942 v 23.21388 c 0,0 -2.169584,14.046067 25.906015,14.046067 z m 14.138671,-8.116093 a 4.6070572,4.6070572 0 0 1 -4.613671,-4.613672 c 0,-2.546615 2.06375,-4.610365 4.613671,-4.610365 2.549922,0 4.613672,2.060443 4.613672,4.610365 0,2.553229 -2.06375,4.613672 -4.613672,4.613672 z" + fill="url(#b)" + id="path3579" + style="fill:url(#b);stroke-width:11.9951" /> + </g> + <g + id="g3859" + style="display:none;fill:#000000;fill-opacity:1"> + <path + id="path3544" + style="fill:#000000;fill-opacity:1;stroke-width:0.529167;stroke-linecap:round;stroke-linejoin:round;paint-order:fill markers stroke" + d="m 52.228737,10.212822 c 0.102978,0.351405 0.158647,0.723392 0.158647,1.108976 v 45.089753 c 0,2.168007 -1.745406,3.913456 -3.913456,3.913456 H 19.259174 c -0.385538,0 -0.75709,-0.05622 -1.108459,-0.159163 0.237938,0.812336 0.730853,1.513585 1.387112,2.01175 0.65626,0.498165 1.475864,0.793246 2.367181,0.793246 h 29.214753 c 2.16805,0 3.913456,-1.745449 3.913456,-3.913456 V 13.967631 c 0,-1.782422 -1.180022,-3.278791 -2.80448,-3.754809 z" + sodipodi:nodetypes="csssscsssssc" /> + <path + id="path3546" + style="display:inline;fill:#000000;fill-opacity:1;stroke-width:0.529167;stroke-linecap:round;stroke-linejoin:round;paint-order:fill markers stroke" + d="M 16.613456,4.7624999 C 14.445408,4.7625 12.7,6.5079516 12.7,8.675956 v 45.089753 c 0,1.084003 0.436244,2.062515 1.143599,2.769857 0.707354,0.70734 1.685833,1.143599 2.769857,1.143599 h 29.214753 c 2.168049,0 3.913456,-1.745451 3.913456,-3.913456 V 8.675956 c 0,-2.1680044 -1.745407,-3.9134561 -3.913456,-3.9134561 z M 31.116446,16.66875 c 7.720775,0 7.124113,3.882967 7.124113,3.882967 v 6.417179 c 0,3.881096 -3.928959,3.817338 -3.928959,3.817338 h -6.992338 c -4.19372,0 -4.061251,4.148067 -4.061251,4.148067 v 3.477824 h -2.462898 c 0,0 -4.126363,0.264897 -4.126363,-7.2285 0,-7.495223 4.726843,-6.955647 4.726843,-6.955647 h 9.852628 v -1.000973 h -7.050215 l -0.0093,-3.337264 c 0,0 -0.461064,-3.220991 6.927742,-3.220991 z m -3.888135,2.24379 c -0.701226,0 -1.268656,0.570469 -1.268656,1.275374 a 1.2669408,1.2735872 0 0 0 1.268656,1.275375 c 0.701229,0 1.268657,-0.570467 1.268657,-1.275375 0,-0.704905 -0.567428,-1.275374 -1.268657,-1.275374 z m 14.46475,5.117 c 0.453342,-0.0018 4.079854,0.203094 4.079854,7.229016 0,7.494318 -4.727359,6.955131 -4.727359,6.955131 h -9.852112 v 1.000973 h 7.050732 l 0.0093,3.337263 c 0,0 0.461069,3.220992 -6.927742,3.220992 -7.720783,0 -7.124113,-3.882967 -7.124113,-3.882967 v -6.417179 c 0,-3.881101 3.928959,-3.817338 3.928959,-3.817338 h 6.992338 c 4.193725,0 4.060734,-4.148067 4.060734,-4.148067 v -3.47679 h 2.462898 c 0,0 0.01629,-9.15e-4 0.04651,-0.001 z M 35.21387,40.97941 c -0.701227,0 -1.269173,0.570348 -1.269173,1.27434 a 1.2669408,1.2735872 0 0 0 1.269173,1.275375 c 0.701228,0 1.268657,-0.569554 1.268657,-1.275375 0,-0.704906 -0.567429,-1.27434 -1.268657,-1.27434 z" /> + <path + id="path3548" + style="fill:#000000;fill-opacity:1;stroke-width:0.529167;stroke-linecap:round;stroke-linejoin:round;paint-order:fill markers stroke" + d="m 13.843822,56.535472 5.291742,4.9e-5 5.29299,5.29246 h -5.291667 z" + sodipodi:nodetypes="ccccc" /> + </g> + <path + id="rect3934" + style="display:none;fill:#00ba2b;stroke-width:0.529167;stroke-linecap:round;stroke-linejoin:round;paint-order:fill markers stroke" + d="M 4.7624999,62.970832 20.637499,4.7624999 h 42.333333 l -15.875,58.2083321 z" + sodipodi:nodetypes="ccccc" /> + <path + id="path4924" + style="fill:#000000;fill-opacity:1;stroke-width:0.529167;stroke-linecap:round;stroke-linejoin:round;paint-order:fill markers stroke" + d="M 24.551 4.7625 C 22.3829 4.7625 20.1615 6.50795 19.5702 8.67596 L 7.27299 53.7657 C 6.97735 54.8497 7.14673 55.8282 7.66117 56.5356 L 11.5111 61.8277 L 11.5147 61.8277 C 11.6056 61.9525 11.7049 62.0706 11.8167 62.1776 C 12.3371 62.6758 13.0763 62.9708 13.9676 62.9708 L 43.1824 62.9708 C 45.3504 62.9708 47.5719 61.2254 48.1631 59.0574 L 60.4603 13.9676 C 60.9465 12.1852 60.1745 10.6888 58.6799 10.2128 C 58.687 10.5642 58.6413 10.9362 58.5361 11.3218 L 46.2389 56.4115 C 45.6476 58.5795 43.4262 60.325 41.2581 60.325 L 15.7098 60.325 L 13.7851 57.6792 L 39.3339 57.6792 C 41.5019 57.6792 43.7234 55.9337 44.3147 53.7657 L 56.6119 8.67596 C 57.2031 6.50795 55.9338 4.7625 53.7657 4.7625 L 24.551 4.7625 Z M 35.8068 16.6688 C 43.5276 16.6688 41.8719 20.5517 41.8719 20.5517 L 40.1218 26.9689 C 39.0633 30.85 35.1517 30.7862 35.1517 30.7862 L 28.1594 30.7862 C 23.9657 30.7862 22.9668 34.9343 22.9668 34.9343 L 22.0183 38.4121 L 19.5554 38.4121 C 19.5554 38.4121 15.3568 38.677 17.4005 31.1836 C 19.4446 23.6884 24.0243 24.228 24.0243 24.228 L 33.877 24.228 L 34.1499 23.227 L 27.0997 23.227 L 28.0006 19.8897 C 28.0006 19.8897 28.418 16.6688 35.8068 16.6688 Z M 31.3067 18.9125 C 30.6055 18.9125 29.8825 19.483 29.6902 20.1879 C 29.5975 20.5263 29.6424 20.851 29.8152 21.0902 C 29.9879 21.3295 30.2743 21.4637 30.611 21.4633 C 31.3123 21.4633 32.0353 20.8928 32.2275 20.1879 C 32.4198 19.483 32.0079 18.9125 31.3067 18.9125 Z M 44.3759 24.0295 C 44.8297 24.0277 48.4004 24.2326 46.4842 31.2586 C 44.4403 38.7529 39.86 38.2137 39.86 38.2137 L 30.0079 38.2137 L 29.7349 39.2147 L 36.7856 39.2147 L 35.8848 42.5519 C 35.8848 42.5519 35.4674 45.7729 28.0786 45.7729 C 20.3578 45.7729 22.0135 41.8899 22.0135 41.8899 L 23.7636 35.4728 C 24.8221 31.5917 28.7336 31.6554 28.7336 31.6554 L 35.726 31.6554 C 39.9197 31.6554 40.918 27.5074 40.918 27.5074 L 41.8662 24.0306 L 44.3291 24.0306 C 44.3291 24.0306 44.3457 24.0296 44.3759 24.0295 Z M 33.274 40.9794 C 32.5728 40.9794 31.8493 41.5498 31.6573 42.2538 C 31.5645 42.5922 31.6095 42.917 31.7824 43.1563 C 31.9553 43.3956 32.2418 43.5297 32.5787 43.5291 C 33.2799 43.5291 34.0026 42.9596 34.1951 42.2538 C 34.3874 41.5488 33.9753 40.9794 33.274 40.9794 Z" /> + <path + style="display:none;fill:#af00ba;fill-opacity:1;stroke-width:0.529167;stroke-linecap:round;stroke-linejoin:round;paint-order:fill markers stroke" + d="M 4.7624999,62.970832 20.637499,4.7624999 h 42.333333 l -15.875,58.2083321 z" + id="path5158" + sodipodi:nodetypes="ccccc" /> + </g> +</svg> diff --git a/plugins/pynb/gresource.xml b/plugins/pynb/gresource.xml new file mode 100644 index 0000000..71eb8ed --- /dev/null +++ b/plugins/pynb/gresource.xml @@ -0,0 +1,11 @@ +<?xml version="1.0" encoding="UTF-8"?> +<gresources> + <gresource prefix="/re/chrysalide/framework/gui/panels"> + <file compressed="true" alias="pynb-panel.ui">panel.ui</file> + <file compressed="true" alias="pynb-params.ui">params.ui</file> + <file compressed="true" alias="pynb-prefs.ui">prefs.ui</file> + </gresource> + <gresource prefix="/re/chrysalide/framework/gui/icons/scalable/actions"> + <file compressed="true" alias="pynb-symbolic.svg">data/images/pynb-symbolic.svg</file> + </gresource> +</gresources> diff --git a/plugins/pynb/panel-int.h b/plugins/pynb/panel-int.h new file mode 100644 index 0000000..23884c7 --- /dev/null +++ b/plugins/pynb/panel-int.h @@ -0,0 +1,56 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * panel-int.h - prototypes internes pour le panneau dédié à la présentation de notes + * + * 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_PYNB_PANEL_INT_H +#define _PLUGINS_PYNB_PANEL_INT_H + + +#include <gtkext/panel-int.h> + + +#include "panel.h" + + + +/* Panneau de cartopgraphie des dispositions d'échantillons (instance) */ +struct _GtkPythonNotebookPanel +{ + GtkTiledPanel parent; /* A laisser en premier */ + +}; + +/* Panneau de cartopgraphie des dispositions d'échantillons (classe) */ +struct _GtkPythonNotebookPanelClass +{ + GtkTiledPanelClass parent; /* A laisser en premier */ + +}; + + +/* Met en place nouvelle instance de panneau de présentation. */ +bool gtk_python_notebook_panel_create(GtkPythonNotebookPanel *); + + + +#endif /* _PLUGINS_PYNB_PANEL_INT_H */ diff --git a/plugins/pynb/panel.c b/plugins/pynb/panel.c new file mode 100644 index 0000000..8ce9cdb --- /dev/null +++ b/plugins/pynb/panel.c @@ -0,0 +1,210 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * panel.c - panneau dédié à la présentation de notes + * + * 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 <gtkext/helpers.h> + + +#include "panel-int.h" + + + +/* ------------------------- COEUR D'UN PANNEAU D'AFFICHAGE ------------------------- */ + + +/* Initialise la classe des panneaux pour binaires. */ +static void gtk_python_notebook_panel_class_init(GtkPythonNotebookPanelClass *); + +/* Initialise une instance de panneau pour binaire. */ +static void gtk_python_notebook_panel_init(GtkPythonNotebookPanel *); + +/* Supprime toutes les références externes. */ +static void gtk_python_notebook_panel_dispose(GObject *); + +/* Procède à la libération totale de la mémoire. */ +static void gtk_python_notebook_panel_finalize(GObject *); + + + +/* --------------------- IMPLEMENTATION DES FONCTIONS DE CLASSE --------------------- */ + + +/* Fournit les composants adaptés pour la barre de titre. */ +//static GListStore *gtk_python_notebook_panel_get_title_widgets(GtkTiledPanel *, bool); + + + +/* ---------------------------------------------------------------------------------- */ +/* COEUR D'UN PANNEAU D'AFFICHAGE */ +/* ---------------------------------------------------------------------------------- */ + + +/* Indique le type défini pour un panneau de présentation de notes. */ +G_DEFINE_TYPE(GtkPythonNotebookPanel, gtk_python_notebook_panel, GTK_TYPE_TILED_PANEL); + + +/****************************************************************************** +* * +* Paramètres : class = classe à initialiser. * +* * +* Description : Initialise la classe des panneaux pour binaires. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void gtk_python_notebook_panel_class_init(GtkPythonNotebookPanelClass *class) +{ + GObjectClass *object; /* Autre version de la classe */ + GtkWidgetClass *widget; /* Classe de haut niveau */ + GtkTiledPanelClass *panel; /* Version parente de classe */ + + object = G_OBJECT_CLASS(class); + + object->dispose = gtk_python_notebook_panel_dispose; + object->finalize = gtk_python_notebook_panel_finalize; + + widget = GTK_WIDGET_CLASS(class); + + gtk_widget_class_set_template_from_resource(widget, "/re/chrysalide/framework/gui/panels/pynb-panel.ui"); + + //gtk_widget_class_bind_template_child(widget, GtkPythonNotebookPanel, summary); + + panel = GTK_TILED_PANEL_CLASS(class); + + //panel->get_widgets = (get_tiled_panel_widgets_cb)gtk_python_notebook_panel_get_title_widgets; + +} + + +/****************************************************************************** +* * +* Paramètres : panel = instance à initialiser. * +* * +* Description : Initialise une instance de panneau pour binaire. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void gtk_python_notebook_panel_init(GtkPythonNotebookPanel *panel) +{ + gtk_widget_init_template(GTK_WIDGET(panel)); + +} + + +/****************************************************************************** +* * +* Paramètres : object = instance d'objet GLib à traiter. * +* * +* Description : Supprime toutes les références externes. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void gtk_python_notebook_panel_dispose(GObject *object) +{ + gtk_widget_dispose_template(GTK_WIDGET(object), GTK_TYPE_PYTHON_NOTEBOOK_PANEL); + + G_OBJECT_CLASS(gtk_python_notebook_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_python_notebook_panel_finalize(GObject *object) +{ + G_OBJECT_CLASS(gtk_python_notebook_panel_parent_class)->finalize(object); + +} + + +/****************************************************************************** +* * +* Paramètres : - * +* * +* Description : Crée une nouvelle instance de panneau de présentation. * +* * +* Retour : Composant GTK mis en place. * +* * +* Remarques : - * +* * +******************************************************************************/ + +GtkTiledPanel *gtk_python_notebook_panel_new(void) +{ + GtkTiledPanel *result; /* Instance à retourner */ + + result = g_object_new(GTK_TYPE_PYTHON_NOTEBOOK_PANEL, NULL); + + if (!gtk_python_notebook_panel_create(GTK_PYTHON_NOTEBOOK_PANEL(result))) + g_clear_object(&result); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : panel = panneau de recherche et récupération à remplir. * +* * +* Description : Met en place nouvelle instance de panneau de présentation. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool gtk_python_notebook_panel_create(GtkPythonNotebookPanel *panel) +{ + bool result; /* Bilan à retourner */ + + result = true; + + return result; + +} diff --git a/plugins/pynb/panel.h b/plugins/pynb/panel.h new file mode 100644 index 0000000..f9f8016 --- /dev/null +++ b/plugins/pynb/panel.h @@ -0,0 +1,47 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * panel.h - prototypes pour le panneau dédié à la présentation de notes + * + * 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_PYNB_PANEL_H +#define _PLUGINS_PYNB_PANEL_H + + +#include <gtk/gtk.h> + + +#include <glibext/helpers.h> +#include <gtkext/panel.h> + + + +#define GTK_TYPE_PYTHON_NOTEBOOK_PANEL (gtk_python_notebook_panel_get_type()) + +DECLARE_GTYPE(GtkPythonNotebookPanel, gtk_python_notebook_panel, GTK, PYTHON_NOTEBOOK_PANEL); + + +/* Crée une nouvelle instance de panneau de présentation. */ +GtkTiledPanel *gtk_python_notebook_panel_new(void); + + + +#endif /* _PLUGINS_PYNB_PANEL_H */ diff --git a/plugins/pynb/panel.ui b/plugins/pynb/panel.ui new file mode 100644 index 0000000..d16af80 --- /dev/null +++ b/plugins/pynb/panel.ui @@ -0,0 +1,21 @@ +<?xml version="1.0" encoding="UTF-8"?> +<interface> + + <template class="GtkPythonNotebookPanel" 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">true</property> + <property name="margin-start">8</property> + <property name="margin-top">8</property> + <property name="margin-end">8</property> + <property name="margin-bottom">8</property> + + </object> + </child> + </template> + +</interface> diff --git a/plugins/pynb/params-int.h b/plugins/pynb/params-int.h new file mode 100644 index 0000000..7f3bc8b --- /dev/null +++ b/plugins/pynb/params-int.h @@ -0,0 +1,50 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * params-int.h - définitions internes pour l'édition des paramètres initiaux d'une présentation de notes + * + * 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_PYNB_PARAMS_INT_H +#define _PLUGINS_PYNB_PARAMS_INT_H + + +#include "params.h" + + + +/* Composant pour les paramètres de chargement d'un binaire (instance) */ +struct _GtkPythonNotebookParameters +{ + GtkGrid parent; /* A laisser en premier */ + + //GtkEntry *filename; /* CHemin d'un binaire */ + +}; + +/* Composant pour les paramètres de chargement d'un binaire (classe) */ +struct _GtkPythonNotebookParametersClass +{ + GtkGridClass parent; /* A laisser en premier */ + +}; + + + +#endif /* _PLUGINS_PYNB_PARAMS_INT_H */ diff --git a/plugins/pynb/params.c b/plugins/pynb/params.c new file mode 100644 index 0000000..690ff95 --- /dev/null +++ b/plugins/pynb/params.c @@ -0,0 +1,171 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * params.c - édition des paramètres initiaux d'une présentation de notes + * + * 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 "params.h" + + +#include "panel.h" +#include "params-int.h" +#include <gtkext/helpers.h> +#include <gui/window.h> + + + +/* Initialise la classe des composants d'édition de paramètres. */ +static void gtk_python_notebook_parameters_class_init(GtkPythonNotebookParametersClass *); + +/* Initialise une instance de composant d'édition de paramètres. */ +static void gtk_python_notebook_parameters_init(GtkPythonNotebookParameters *); + +/* Supprime toutes les références externes. */ +static void gtk_python_notebook_parameters_dispose(GObject *); + +/* Procède à la libération totale de la mémoire. */ +static void gtk_python_notebook_parameters_finalize(GObject *); + +/* Réagit à une demande de création de notes. */ +static void gtk_python_notebook_parameters_on_create_clicked(GtkButton *, GtkPythonNotebookParameters *); + + + +/* Indique le type du composant d'édition des paramètres de chargement. */ +G_DEFINE_TYPE(GtkPythonNotebookParameters, gtk_python_notebook_parameters, GTK_TYPE_GRID); + + +/****************************************************************************** +* * +* Paramètres : class = classe GTK à initialiser. * +* * +* Description : Initialise la classe des composants d'édition de paramètres. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void gtk_python_notebook_parameters_class_init(GtkPythonNotebookParametersClass *class) +{ + GObjectClass *object; /* Plus haut niveau équivalent */ + GtkWidgetClass *widget; /* Classe de haut niveau */ + + object = G_OBJECT_CLASS(class); + + object->dispose = gtk_python_notebook_parameters_dispose; + object->finalize = gtk_python_notebook_parameters_finalize; + + widget = GTK_WIDGET_CLASS(class); + + gtk_widget_class_set_template_from_resource(widget, "/re/chrysalide/framework/gui/panels/pynb-params.ui"); + + gtk_widget_class_bind_template_callback_full(widget, BUILDER_CB(gtk_python_notebook_parameters_on_create_clicked)); + + //gtk_widget_class_bind_template_child(widget, GtkPythonNotebookParameters, filename); + +} + + +/****************************************************************************** +* * +* Paramètres : params = composant GTK à initialiser. * +* * +* Description : Initialise une instance de composant d'édition de paramètres.* +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void gtk_python_notebook_parameters_init(GtkPythonNotebookParameters *params) +{ + gtk_widget_init_template(GTK_WIDGET(params)); + +} + + +/****************************************************************************** +* * +* Paramètres : object = instance d'objet GLib à traiter. * +* * +* Description : Supprime toutes les références externes. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void gtk_python_notebook_parameters_dispose(GObject *object) +{ + gtk_widget_dispose_template(GTK_WIDGET(object), GTK_TYPE_PYTHON_NOTEBOOK_PARAMETERS); + + G_OBJECT_CLASS(gtk_python_notebook_parameters_parent_class)->dispose(object); + +} + + +/****************************************************************************** +* * +* Paramètres : object = instance d'objet GLib à traiter. * +* * +* Description : Procède à la libération totale de la mémoire. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void gtk_python_notebook_parameters_finalize(GObject *object) +{ + G_OBJECT_CLASS(gtk_python_notebook_parameters_parent_class)->finalize(object); + +} + + +/****************************************************************************** +* * +* Paramètres : button = bouton GTK concerné par l'appel. * +* params = paramètres du panneau à mettre en place. * +* * +* Description : Réagit à une demande de création de notes. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void gtk_python_notebook_parameters_on_create_clicked(GtkButton *button, GtkPythonNotebookParameters *params) +{ + GtkRoot *root; /* Racine du composant */ + GtkTiledPanel *tiled; /* Panneau d'affichage complet */ + + root = gtk_widget_get_root(GTK_WIDGET(button)); + + tiled = gtk_python_notebook_panel_new(); + + gtk_framework_window_add(GTK_FRAMEWORK_WINDOW(root), tiled); + +} diff --git a/plugins/pynb/params.h b/plugins/pynb/params.h new file mode 100644 index 0000000..2d4b39b --- /dev/null +++ b/plugins/pynb/params.h @@ -0,0 +1,41 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * params.h - prototypes pour l'édition des paramètres initiaux d'une présentation de notes + * + * 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_PYNB_PARAMS_H +#define _PLUGINS_PYNB_PARAMS_H + + +#include <gtk/gtk.h> + + +#include <glibext/helpers.h> + + + +#define GTK_TYPE_PYTHON_NOTEBOOK_PARAMETERS (gtk_python_notebook_parameters_get_type()) + +DECLARE_GTYPE(GtkPythonNotebookParameters, gtk_python_notebook_parameters, GTK, PYTHON_NOTEBOOK_PARAMETERS); + + + +#endif /* _PLUGINS_PYNB_PARAMS_H */ diff --git a/plugins/pynb/params.ui b/plugins/pynb/params.ui new file mode 100644 index 0000000..21a4788 --- /dev/null +++ b/plugins/pynb/params.ui @@ -0,0 +1,52 @@ +<?xml version="1.0" encoding="UTF-8"?> +<interface> + + <template class="GtkPythonNotebookParameters" parent="GtkGrid"> + <property name="margin-bottom">12</property> + <property name="margin-end">12</property> + <property name="margin-start">12</property> + <property name="margin-top">12</property> + <property name="column-spacing">12</property> + <property name="row-spacing">8</property> + + <child> + <object class="GtkLabel"> + <property name="label">Load and analyze a new notebook file:</property> + <property name="xalign">0</property> + <layout> + <property name="column">0</property> + <property name="row">0</property> + </layout> + </object> + </child> + + <child> + <object class="GtkEntry" id="filename"> + <property name="secondary-icon-name">document-open-symbolic</property> + <property name="placeholder-text">File location</property> + <property name="hexpand">TRUE</property> + <property name="hexpand-set">TRUE</property> + <layout> + <property name="column">0</property> + <property name="row">1</property> + </layout> + <style> + <class name="background"/> + </style> + </object> + </child> + + <child> + <object class="GtkButton" id="create"> + <property name="label">Create</property> + <layout> + <property name="column">0</property> + <property name="row">2</property> + </layout> + <signal name="clicked" handler="gtk_python_notebook_parameters_on_create_clicked"/> + </object> + </child> + + </template> + +</interface> diff --git a/plugins/pynb/prefs-int.h b/plugins/pynb/prefs-int.h new file mode 100644 index 0000000..9c44c68 --- /dev/null +++ b/plugins/pynb/prefs-int.h @@ -0,0 +1,48 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * prefs-int.h - définitions internes pour la configuration des paramètres liés aux notes + * + * 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_PYNB_PREFS_INT_H +#define _PLUGINS_PYNB_PREFS_INT_H + + +#include "prefs.h" + + + +/* Composant d'édition des paramètres liés aux notes (instance) */ +struct _GtkPythonNotebookTweakPanel +{ + GtkBox parent; /* A laisser en premier */ + +}; + +/* Composant d'édition des paramètres liés aux notes (classe) */ +struct _GtkPythonNotebookTweakPanelClass +{ + GtkBoxClass parent; /* A laisser en premier */ + +}; + + + +#endif /* _PLUGINS_PYNB_PREFS_INT_H */ diff --git a/plugins/pynb/prefs.c b/plugins/pynb/prefs.c new file mode 100644 index 0000000..9363e9b --- /dev/null +++ b/plugins/pynb/prefs.c @@ -0,0 +1,143 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * prefs.c - configuration des paramètres liés aux notes + * + * 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 "prefs.h" + + +#include <gtkext/helpers.h> + + +#include "prefs-int.h" + + + +/* Procède à l'initialisation de classe des configurations. */ +static void gtk_python_notebook_tweak_panel_class_init(GtkPythonNotebookTweakPanelClass *); + +/* Procède à l'initialisation des configurations de sécurité. */ +static void gtk_python_notebook_tweak_panel_init(GtkPythonNotebookTweakPanel *); + +/* Supprime toutes les références externes. */ +static void gtk_python_notebook_tweak_panel_dispose(GObject *); + +/* Procède à la libération totale de la mémoire. */ +static void gtk_python_notebook_tweak_panel_finalize(GObject *); + + + +/* Indique le type du composant de configuration des notes. */ +G_DEFINE_TYPE(GtkPythonNotebookTweakPanel, gtk_python_notebook_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_python_notebook_tweak_panel_class_init(GtkPythonNotebookTweakPanelClass *class) +{ + GObjectClass *object; /* Plus haut niveau équivalent */ + GtkWidgetClass *widget; /* Classe de haut niveau */ + + object = G_OBJECT_CLASS(class); + + object->dispose = gtk_python_notebook_tweak_panel_dispose; + object->finalize = gtk_python_notebook_tweak_panel_finalize; + + widget = GTK_WIDGET_CLASS(class); + + gtk_widget_class_set_template_from_resource(widget, "/re/chrysalide/framework/gui/panels/pynb-prefs.ui"); + + /* Stockage sécurisé */ + + //gtk_widget_class_bind_template_callback_full(widget, BUILDER_CB(gtk_python_notebook_tweak_panel_on_new_passwords_changed)); + + //gtk_widget_class_bind_template_child(widget, GtkPythonNotebookTweakPanel, current_primary_passwd); + +} + + +/****************************************************************************** +* * +* Paramètres : panel = composant GTK à initialiser. * +* * +* Description : Procède à l'initialisation des configurations de sécurité. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void gtk_python_notebook_tweak_panel_init(GtkPythonNotebookTweakPanel *panel) +{ + gtk_widget_init_template(GTK_WIDGET(panel)); + +} + + +/****************************************************************************** +* * +* Paramètres : object = instance d'objet GLib à traiter. * +* * +* Description : Supprime toutes les références externes. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void gtk_python_notebook_tweak_panel_dispose(GObject *object) +{ + gtk_widget_dispose_template(GTK_WIDGET(object), GTK_TYPE_PYTHON_NOTEBOOK_TWEAK_PANEL); + + G_OBJECT_CLASS(gtk_python_notebook_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_python_notebook_tweak_panel_finalize(GObject *object) +{ + G_OBJECT_CLASS(gtk_python_notebook_tweak_panel_parent_class)->finalize(object); + +} diff --git a/plugins/pynb/prefs.h b/plugins/pynb/prefs.h new file mode 100644 index 0000000..6551983 --- /dev/null +++ b/plugins/pynb/prefs.h @@ -0,0 +1,41 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * prefs.h - prototypes pour la configuration des paramètres liés aux notes + * + * 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_PYNB_PREFS_H +#define _PLUGINS_PYNB_PREFS_H + + +#include <gtk/gtk.h> + + +#include <glibext/helpers.h> + + + +#define GTK_TYPE_PYTHON_NOTEBOOK_TWEAK_PANEL (gtk_python_notebook_tweak_panel_get_type()) + +DECLARE_GTYPE(GtkPythonNotebookTweakPanel, gtk_python_notebook_tweak_panel, GTK, PYTHON_NOTEBOOK_TWEAK_PANEL); + + + +#endif /* _PLUGINS_PYNB_PREFS_H */ diff --git a/plugins/pynb/prefs.ui b/plugins/pynb/prefs.ui new file mode 100644 index 0000000..b8a6962 --- /dev/null +++ b/plugins/pynb/prefs.ui @@ -0,0 +1,38 @@ +<?xml version="1.0" encoding="UTF-8"?> +<interface> + + <template class="GtkPythonNotebookTweakPanel" parent="GtkBox"> + + <property name="orientation">vertical</property> + + <!-- Conservation de paramètres sécurisée --> + <child> + <object class="GtkGrid"> + <property name="margin-start">20</property> + <property name="margin-end">20</property> + <property name="margin-top">20</property> + <property name="margin-bottom">20</property> + <property name="row-spacing">10</property> + <property name="column-spacing">10</property> + + <child> + <object class="GtkLabel"> + <property name="label">Notes config</property> + <property name="use-markup">true</property> + <property name="xalign">0</property> + <layout> + <property name="column">0</property> + <property name="row">0</property> + <property name="column-span">2</property> + </layout> + <style> + <class name="heading"/> + </style> + </object> + </child> + + </object> + </child> + + </template> +</interface> |