diff options
Diffstat (limited to 'plugins/pychrysalide')
178 files changed, 11142 insertions, 2157 deletions
diff --git a/plugins/pychrysalide/Makefile.am b/plugins/pychrysalide/Makefile.am index fb3986c..4b6e551 100644 --- a/plugins/pychrysalide/Makefile.am +++ b/plugins/pychrysalide/Makefile.am @@ -13,32 +13,52 @@ RUN_PATH = -Wl,-rpath,'$$ORIGIN/chrysalide-libs' endif -pychrysalide_la_SOURCES = \ - access.h access.c \ - core.h core.c \ - helpers.h helpers.c \ - star.h star.c \ - strenum.h strenum.c \ - struct.h struct.c \ - weak.h weak.c - -pychrysalide_la_LIBADD = \ - analysis/libpychrysaanalysis.la \ - arch/libpychrysaarch.la \ - common/libpychrysacommon.la \ - core/libpychrysacore.la \ - debug/libpychrysadebug.la \ - format/libpychrysaformat.la \ - glibext/libpychrysaglibext.la \ - gtkext/libpychrysagtkext.la \ - gui/libpychrysagui.la \ - mangling/libpychrysamangling.la \ +if BUILD_GTK_SUPPORT + +GTKEXT_LIBADD = \ + gtkext/libpychrysagtkext.la + +GTKEXT_SUBDIR = \ + gtkext + +GUI_LIBADD = \ + gui/libpychrysagui.la + +GUI_SUBDIR = \ + gui + +endif + + +pychrysalide_la_SOURCES = \ + access.h access.c \ + core.h core.c \ + helpers.h helpers.c \ + star.h star.c \ + strenum.h strenum.c \ + struct.h struct.c + +AM_CFLAGS = $(LIBPYTHON_INTERPRETER_CFLAGS) $(LIBPYGOBJECT_CFLAGS) $(TOOLKIT_CFLAGS) $(LIBXML_CFLAGS) \ + -I$(top_srcdir)/src -DNO_IMPORT_PYGOBJECT + +pychrysalide_la_LIBADD = \ + analysis/libpychrysaanalysis.la \ + arch/libpychrysaarch.la \ + common/libpychrysacommon.la \ + core/libpychrysacore.la \ + debug/libpychrysadebug.la \ + format/libpychrysaformat.la \ + glibext/libpychrysaglibext.la \ + $(GTKEXT_LIBADD) \ + $(GUI_LIBADD) \ + mangling/libpychrysamangling.la \ plugins/libpychrysaplugins.la # -ldl: dladdr(), dlerror() pychrysalide_la_LDFLAGS = \ -module -avoid-version -ldl \ - $(LIBPYTHON_LIBS) $(LIBPYGOBJECT_LIBS) \ + $(LIBPYTHON_INTERPRETER_LIBS) \ + $(LIBPYGOBJECT_LIBS) \ -L$(top_srcdir)/src/.libs -lchrysacore \ $(RUN_PATH) @@ -48,9 +68,4 @@ devdir = $(includedir)/chrysalide/$(subdir) dev_HEADERS = $(pychrysalide_la_SOURCES:%c=) -AM_CPPFLAGS = $(LIBPYTHON_CFLAGS) $(LIBPYGOBJECT_CFLAGS) $(LIBGTK_CFLAGS) $(LIBXML_CFLAGS) \ - -I$(top_srcdir)/src - -AM_CFLAGS = $(DEBUG_CFLAGS) $(WARNING_FLAGS) $(COMPLIANCE_FLAGS) - -SUBDIRS = analysis arch common core debug format glibext gtkext gui mangling plugins +SUBDIRS = analysis arch common core debug format glibext $(GTKEXT_SUBDIR) $(GUI_SUBDIR) mangling plugins diff --git a/plugins/pychrysalide/analysis/Makefile.am b/plugins/pychrysalide/analysis/Makefile.am index d09cced..43e8ed2 100644 --- a/plugins/pychrysalide/analysis/Makefile.am +++ b/plugins/pychrysalide/analysis/Makefile.am @@ -1,28 +1,30 @@ noinst_LTLIBRARIES = libpychrysaanalysis.la -libpychrysaanalysis_la_SOURCES = \ - binary.h binary.c \ - block.h block.c \ - cattribs.h cattribs.c \ - constants.h constants.c \ - content.h content.c \ - loaded.h loaded.c \ - loading.h loading.c \ - module.h module.c \ - project.h project.c \ - routine.h routine.c \ - type.h type.c \ +libpychrysaanalysis_la_SOURCES = \ + binary.h binary.c \ + block.h block.c \ + cattribs.h cattribs.c \ + constants.h constants.c \ + content.h content.c \ + loaded.h loaded.c \ + loading.h loading.c \ + module.h module.c \ + project.h project.c \ + routine.h routine.c \ + type.h type.c \ variable.h variable.c libpychrysaanalysis_la_LIBADD = \ contents/libpychrysaanalysiscontents.la \ db/libpychrysaanalysisdb.la \ disass/libpychrysaanalysisdisass.la \ + scan/libpychrysaanalysisscan.la \ storage/libpychrysaanalysisstorage.la \ types/libpychrysaanalysistypes.la -libpychrysaanalysis_la_LDFLAGS = +libpychrysaanalysis_la_CFLAGS = $(TOOLKIT_CFLAGS) $(LIBXML_CFLAGS) $(LIBPYTHON_INTERPRETER_CFLAGS) $(LIBPYGOBJECT_CFLAGS) \ + -I$(top_srcdir)/src -DNO_IMPORT_PYGOBJECT devdir = $(includedir)/chrysalide/$(subdir) @@ -30,9 +32,4 @@ devdir = $(includedir)/chrysalide/$(subdir) dev_HEADERS = $(libpychrysaanalysis_la_SOURCES:%c=) -AM_CPPFLAGS = $(LIBGTK_CFLAGS) $(LIBXML_CFLAGS) $(LIBPYTHON_CFLAGS) $(LIBPYGOBJECT_CFLAGS) \ - -I$(top_srcdir)/src - -AM_CFLAGS = $(DEBUG_CFLAGS) $(WARNING_FLAGS) $(COMPLIANCE_FLAGS) - -SUBDIRS = contents db disass storage types +SUBDIRS = contents db disass scan storage types diff --git a/plugins/pychrysalide/analysis/binary.c b/plugins/pychrysalide/analysis/binary.c index 68f2d88..6599ecc 100644 --- a/plugins/pychrysalide/analysis/binary.c +++ b/plugins/pychrysalide/analysis/binary.c @@ -124,15 +124,13 @@ static PyObject *py_loaded_binary_new(PyTypeObject *type, PyObject *args, PyObje static PyObject *py_loaded_binary_get_client(PyObject *self, PyObject *args) { PyObject *result; /* Bilan à retourner */ - int internal; /* Nature du client visé */ - int ret; /* Bilan de lecture des args. */ GLoadedBinary *binary; /* Binaire en cours d'analyse */ GAnalystClient *client; /* Eventuel client en place */ #define LOADED_BINARY_GET_CLIENT_METHOD PYTHON_METHOD_DEF \ ( \ - get_client, "$self, /, internal=True", \ - METH_VARARGS, py_loaded_binary, \ + get_client, "$self", \ + METH_NOARGS, py_loaded_binary, \ "Provide the client connected to an internal or remote server" \ " if defined, or return None otherwise.\n" \ "\n" \ @@ -140,14 +138,9 @@ static PyObject *py_loaded_binary_get_client(PyObject *self, PyObject *args) " instance or *None*." \ ) - internal = 1; - - ret = PyArg_ParseTuple(args, "|p", &internal); - if (!ret) return NULL; - binary = G_LOADED_BINARY(pygobject_get(self)); - client = g_loaded_binary_get_client(binary, internal); + client = g_loaded_binary_get_client(binary); if (client != NULL) { @@ -569,7 +562,7 @@ bool ensure_python_loaded_binary_is_registered(void) if (!ensure_python_loaded_content_is_registered()) return false; - if (!register_class_for_pygobject(dict, G_TYPE_LOADED_BINARY, type, &PyGObject_Type)) + if (!register_class_for_pygobject(dict, G_TYPE_LOADED_BINARY, type)) return false; } diff --git a/plugins/pychrysalide/analysis/block.c b/plugins/pychrysalide/analysis/block.c index 0b09eb7..7f74c2f 100644 --- a/plugins/pychrysalide/analysis/block.c +++ b/plugins/pychrysalide/analysis/block.c @@ -353,7 +353,7 @@ bool ensure_python_code_block_is_registered(void) dict = PyModule_GetDict(module); - if (!register_class_for_pygobject(dict, G_TYPE_CODE_BLOCK, type, &PyGObject_Type)) + if (!register_class_for_pygobject(dict, G_TYPE_CODE_BLOCK, type)) return false; } @@ -612,7 +612,7 @@ bool ensure_python_block_list_is_registered(void) dict = PyModule_GetDict(module); - if (!register_class_for_pygobject(dict, G_TYPE_BLOCK_LIST, type, &PyGObject_Type)) + if (!register_class_for_pygobject(dict, G_TYPE_BLOCK_LIST, type)) return false; } diff --git a/plugins/pychrysalide/analysis/cattribs.c b/plugins/pychrysalide/analysis/cattribs.c index be5c5b1..84a5e1d 100644 --- a/plugins/pychrysalide/analysis/cattribs.c +++ b/plugins/pychrysalide/analysis/cattribs.c @@ -45,9 +45,6 @@ static PyObject *py_content_attributes_new(PyTypeObject *, PyObject *, PyObject /* Fournit l'ensemble des clefs d'un ensemble d'attributs. */ static PyObject *py_content_attributes_subscript(PyObject *, PyObject *); -/* Fournit le fichier de base compris dans le chemin initial. */ -static PyObject *py_content_attributes_get_filename(PyObject *, void *); - /* Fournit l'ensemble des clefs d'un ensemble d'attributs. */ static PyObject *py_content_attributes_get_keys(PyObject *, void *); @@ -72,7 +69,10 @@ static PyObject *py_content_attributes_new(PyTypeObject *type, PyObject *args, P PyObject *result; /* Instance à retourner */ const char *path; /* Chemin d'accès à traiter */ int ret; /* Bilan de lecture des args. */ + char *filename; /* Nom de fichier embarqué */ GContentAttributes *attribs; /* Création GLib à transmettre */ + PyObject *obj; /* Objet Python à retourner */ + PyObject *str; /* Chaîne à retourner */ #define CONTENT_ATTRIBUTES_DOC \ "ContentAttributes is a set of values used at binary content loading.\n" \ @@ -87,25 +87,43 @@ static PyObject *py_content_attributes_new(PyTypeObject *type, PyObject *args, P "\n" \ " ContentAttributes(path)\n" \ "\n" \ - "Where path is a list of parameters: '[...]&key0=value0&key1=value1...'" + "Where path is a list of parameters: '[...]&key0=value0&key1=value1...'" \ + "\n" \ + "The constructor returns a tuple containing a ContentAttributes instance" \ + " and the original targot filename." ret = PyArg_ParseTuple(args, "s", &path); if (!ret) return NULL; - attribs = g_content_attributes_new(path); + attribs = g_content_attributes_new(path, &filename); if (attribs != NULL) { g_object_ref_sink(G_OBJECT(attribs)); - result = pygobject_new(G_OBJECT(attribs)); + obj = pygobject_new(G_OBJECT(attribs)); g_object_unref(attribs); } else { - result = Py_None; - Py_INCREF(result); + obj = Py_None; + Py_INCREF(obj); } + if (filename != NULL) + { + str = PyUnicode_FromString(filename); + free(filename); + } + else + { + str = Py_None; + Py_INCREF(str); + } + + result = PyTuple_New(2); + PyTuple_SetItem(result, 0, obj); + PyTuple_SetItem(result, 1, str); + return result; } @@ -200,50 +218,6 @@ static PyObject *py_content_attributes_get_keys(PyObject *self, void *closure) /****************************************************************************** * * -* Paramètres : self = objet Python concerné par l'appel. * -* closure = non utilisé ici. * -* * -* Description : Fournit le fichier de base compris dans le chemin initial. * -* * -* Retour : Nom de fichier renvoyant vers un contenu à charger ou None. * -* * -* Remarques : - * -* * -******************************************************************************/ - -static PyObject *py_content_attributes_get_filename(PyObject *self, void *closure) -{ - PyObject *result; /* Valeur à retourner */ - GContentAttributes *cattribs; /* Version native */ - const char *filename; /* Nom de fichier natif */ - -#define CONTENT_ATTRIBUTES_FILENAME_ATTRIB PYTHON_GET_DEF_FULL \ -( \ - filename, py_content_attributes, \ - "Filename extracted from the path provided to the attribute set," \ - " constructor, or None if no filename was defined." \ -) - - cattribs = G_CONTENT_ATTRIBUTES(pygobject_get(self)); - - filename = g_content_attributes_get_filename(cattribs); - - if (filename != NULL) - result = PyUnicode_FromString(filename); - - else - { - result = Py_None; - Py_INCREF(result); - } - - return result; - -} - - -/****************************************************************************** -* * * Paramètres : - * * * * Description : Fournit un accès à une définition de type à diffuser. * @@ -267,7 +241,6 @@ PyTypeObject *get_python_content_attributes_type(void) }; static PyGetSetDef py_content_attributes_getseters[] = { - CONTENT_ATTRIBUTES_FILENAME_ATTRIB, CONTENT_ATTRIBUTES_KEYS_ATTRIB, { NULL } }; @@ -321,7 +294,7 @@ bool ensure_python_content_attributes_is_registered(void) dict = PyModule_GetDict(module); - if (!register_class_for_pygobject(dict, G_TYPE_CONTENT_ATTRIBUTES, type, &PyGObject_Type)) + if (!register_class_for_pygobject(dict, G_TYPE_CONTENT_ATTRIBUTES, type)) return false; } diff --git a/plugins/pychrysalide/analysis/content.c b/plugins/pychrysalide/analysis/content.c index 68ecba2..c30cdd8 100644 --- a/plugins/pychrysalide/analysis/content.c +++ b/plugins/pychrysalide/analysis/content.c @@ -40,6 +40,7 @@ #include "cattribs.h" #include "constants.h" +#include "storage/serialize.h" #include "../access.h" #include "../helpers.h" #include "../arch/vmpa.h" @@ -49,8 +50,13 @@ /* ------------------------ GLUE POUR CREATION DEPUIS PYTHON ------------------------ */ -/* Procède à l'initialisation de l'interface de génération. */ -static void py_binary_content_interface_init(GBinContentIface *, gpointer *); +/* Initialise la classe générique des contenus de binaire. */ +static void py_binary_content_init_gclass(GBinContentClass *, gpointer); + +CREATE_DYN_ABSTRACT_CONSTRUCTOR(binary_content, G_TYPE_BIN_CONTENT, py_binary_content_init_gclass); + +/* Initialise une instance sur la base du dérivé de GObject. */ +static int py_binary_content_init(PyObject *, PyObject *, PyObject *); /* Fournit le nom associé au contenu binaire. */ static char *py_binary_content_describe_wrapper(const GBinContent *, bool); @@ -99,6 +105,9 @@ static int py_binary_content_set_attributes(PyObject *, PyObject *, void *); /* Fournit l'ensemble des attributs associés à un contenu. */ static PyObject *py_binary_content_get_attributes(PyObject *, void *); +/* Donne l'origine d'un contenu binaire. */ +static PyObject *py_binary_content_get_root(PyObject *, void *); + /* Fournit une empreinte unique (SHA256) pour les données. */ static PyObject *py_binary_content_get_checksum(PyObject *, void *); @@ -123,10 +132,10 @@ static PyObject *py_binary_content_get_data(PyObject *, void *); /****************************************************************************** * * -* Paramètres : iface = interface GLib à initialiser. * -* unused = adresse non utilisée ici. * +* Paramètres : class = classe à initialiser. * +* unused = données non utilisées ici. * * * -* Description : Procède à l'initialisation de l'interface de génération. * +* Description : Initialise la classe générique des contenus de binaire. * * * * Retour : - * * * @@ -134,21 +143,45 @@ static PyObject *py_binary_content_get_data(PyObject *, void *); * * ******************************************************************************/ -static void py_binary_content_interface_init(GBinContentIface *iface, gpointer *unused) +static void py_binary_content_init_gclass(GBinContentClass *class, gpointer unused) +{ + class->describe = py_binary_content_describe_wrapper; + + class->read_raw = py_binary_content_read_raw_wrapper; + class->read_u8 = py_binary_content_read_u8_wrapper; + class->read_u16 = py_binary_content_read_u16_wrapper; + class->read_u32 = py_binary_content_read_u32_wrapper; + class->read_u64 = py_binary_content_read_u64_wrapper; + +} + + +/****************************************************************************** +* * +* Paramètres : self = objet à initialiser (théoriquement). * +* args = arguments fournis à l'appel. * +* kwds = arguments de type key=val fournis. * +* * +* Description : Initialise une instance sur la base du dérivé de GObject. * +* * +* Retour : 0. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static int py_binary_content_init(PyObject *self, PyObject *args, PyObject *kwds) { + int ret; /* Bilan de lecture des args. */ + #define BINARY_CONTENT_DOC \ - "The BinContent is an interface which handles access to a given binary" \ - " content.\n" \ + "A BinContent is an abstract object which handles access to a given" \ + " binary content.\n" \ "\n" \ "All of its implementations are located in the" \ " pychrysalide.analysis.contents module. The main implemantation is" \ " the pychrysalide.analysis.contents.FileContent class.\n" \ "\n" \ - "A typical class declaration for a new implementation looks like:\n" \ - "\n" \ - " class NewImplem(GObject.Object, BinContent):\n" \ - " ...\n" \ - "\n" \ "The following methods have to be defined for new implementations:\n" \ "* pychrysalide.analysis.BinContent._describe();\n" \ "* pychrysalide.analysis.BinContent._read_raw();\n" \ @@ -158,13 +191,12 @@ static void py_binary_content_interface_init(GBinContentIface *iface, gpointer * "* pychrysalide.analysis.BinContent._read_u32();\n" \ "* pychrysalide.analysis.BinContent._read_u64();\n" - iface->describe = py_binary_content_describe_wrapper; + /* Initialisation d'un objet GLib */ - iface->read_raw = py_binary_content_read_raw_wrapper; - iface->read_u8 = py_binary_content_read_u8_wrapper; - iface->read_u16 = py_binary_content_read_u16_wrapper; - iface->read_u32 = py_binary_content_read_u32_wrapper; - iface->read_u64 = py_binary_content_read_u64_wrapper; + ret = forward_pygobjet_init(self); + if (ret == -1) return -1; + + return 0; } @@ -1133,6 +1165,48 @@ static PyObject *py_binary_content_get_attributes(PyObject *self, void *closure) * Paramètres : self = contenu binaire à manipuler. * * closure = adresse non utilisée ici. * * * +* Description : Donne l'origine d'un contenu binaire. * +* * +* Retour : Contenu à l'origine du contenu courant. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static PyObject *py_binary_content_get_root(PyObject *self, void *closure) +{ + PyObject *result; /* Instance à retourner */ + GBinContent *content; /* Version GLib du format */ + GContentAttributes *attribs; /* Attributs à transmettre */ + +#define BINARY_CONTENT_ROOT_ATTRIB PYTHON_GET_DEF_FULL \ +( \ + root, py_binary_content, \ + "Provide, as a pychrysalide.analysis.BinContent instance, the root" \ + " content leading to the current content." \ + "\n" \ + "This property is relevant only for" \ + " pychrysalide.analysis.contents.EncapsulatedContent objects." \ +) + + content = G_BIN_CONTENT(pygobject_get(self)); + + attribs = g_binary_content_get_attributes(content); + + result = pygobject_new(G_OBJECT(attribs)); + + g_object_unref(attribs); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : self = contenu binaire à manipuler. * +* closure = adresse non utilisée ici. * +* * * Description : Fournit une empreinte unique (SHA256) pour les données. * * * * Retour : Bilan de l'opération. * @@ -1347,6 +1421,7 @@ PyTypeObject *get_python_binary_content_type(void) static PyGetSetDef py_binary_content_getseters[] = { BINARY_CONTENT_ATTRIBUTES_ATTRIB, + BINARY_CONTENT_ROOT_ATTRIB, BINARY_CONTENT_CHECKSUM_ATTRIB, BINARY_CONTENT_SIZE_ATTRIB, BINARY_CONTENT_START_POS_ATTRIB, @@ -1360,14 +1435,17 @@ PyTypeObject *get_python_binary_content_type(void) PyVarObject_HEAD_INIT(NULL, 0) .tp_name = "pychrysalide.analysis.BinContent", - .tp_basicsize = sizeof(PyObject), + .tp_basicsize = sizeof(PyGObject), .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, .tp_doc = BINARY_CONTENT_DOC, .tp_methods = py_binary_content_methods, - .tp_getset = py_binary_content_getseters + .tp_getset = py_binary_content_getseters, + + .tp_init = py_binary_content_init, + .tp_new = py_binary_content_new, }; @@ -1394,23 +1472,18 @@ bool ensure_python_binary_content_is_registered(void) PyObject *module; /* Module à recompléter */ PyObject *dict; /* Dictionnaire du module */ - static GInterfaceInfo info = { /* Paramètres d'inscription */ - - .interface_init = (GInterfaceInitFunc)py_binary_content_interface_init, - .interface_finalize = NULL, - .interface_data = NULL, - - }; - type = get_python_binary_content_type(); if (!PyType_HasFeature(type, Py_TPFLAGS_READY)) { + if (!ensure_python_serializable_object_is_registered()) + return false; + module = get_access_to_python_module("pychrysalide.analysis"); dict = PyModule_GetDict(module); - if (!register_interface_for_pygobject(dict, G_TYPE_BIN_CONTENT, type, &info)) + if (!register_class_for_pygobject(dict, G_TYPE_BIN_CONTENT, type)) return false; if (!define_analysis_content_constants(type)) diff --git a/plugins/pychrysalide/analysis/contents/Makefile.am b/plugins/pychrysalide/analysis/contents/Makefile.am index 07fafd0..9238a58 100644 --- a/plugins/pychrysalide/analysis/contents/Makefile.am +++ b/plugins/pychrysalide/analysis/contents/Makefile.am @@ -1,22 +1,17 @@ noinst_LTLIBRARIES = libpychrysaanalysiscontents.la -libpychrysaanalysiscontents_la_SOURCES = \ - encapsulated.h encapsulated.c \ - file.h file.c \ - memory.h memory.c \ - module.h module.c \ +libpychrysaanalysiscontents_la_SOURCES = \ + encapsulated.h encapsulated.c \ + file.h file.c \ + memory.h memory.c \ + module.h module.c \ restricted.h restricted.c -libpychrysaanalysiscontents_la_LDFLAGS = +libpychrysaanalysiscontents_la_CFLAGS = $(TOOLKIT_CFLAGS) $(LIBXML_CFLAGS) $(LIBPYTHON_INTERPRETER_CFLAGS) $(LIBPYGOBJECT_CFLAGS) \ + -I$(top_srcdir)/src -DNO_IMPORT_PYGOBJECT devdir = $(includedir)/chrysalide/$(subdir) dev_HEADERS = $(libpychrysaanalysiscontents_la_SOURCES:%c=) - - -AM_CPPFLAGS = $(LIBGTK_CFLAGS) $(LIBXML_CFLAGS) $(LIBPYTHON_CFLAGS) $(LIBPYGOBJECT_CFLAGS) \ - -I$(top_srcdir)/src - -AM_CFLAGS = $(DEBUG_CFLAGS) $(WARNING_FLAGS) $(COMPLIANCE_FLAGS) diff --git a/plugins/pychrysalide/analysis/contents/encapsulated.c b/plugins/pychrysalide/analysis/contents/encapsulated.c index ef26caa..e9583e6 100644 --- a/plugins/pychrysalide/analysis/contents/encapsulated.c +++ b/plugins/pychrysalide/analysis/contents/encapsulated.c @@ -28,7 +28,8 @@ #include <pygobject.h> -#include <analysis/contents/encapsulated.h> +#include <i18n.h> +#include <analysis/contents/encapsulated-int.h> #include "../content.h" @@ -37,8 +38,10 @@ -/* Crée un nouvel objet Python de type 'BinContent'. */ -static PyObject *py_encaps_content_new(PyTypeObject *, PyObject *, PyObject *); +CREATE_DYN_CONSTRUCTOR(encaps_content, G_TYPE_ENCAPS_CONTENT); + +/* Initialise une instance sur la base du dérivé de GObject. */ +static int py_encaps_content_init(PyObject *, PyObject *, PyObject *); /* Indique la base d'un contenu binaire encapsulé. */ static PyObject *py_encaps_content_get_base(PyObject *, void *); @@ -53,26 +56,25 @@ static PyObject *py_encaps_content_get_endpoint(PyObject *, void *); /****************************************************************************** * * -* 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 'BinContent'. * +* Description : Initialise une instance sur la base du dérivé de GObject. * * * -* Retour : Instance Python mise en place. * +* Retour : 0. * * * * Remarques : - * * * ******************************************************************************/ -static PyObject *py_encaps_content_new(PyTypeObject *type, PyObject *args, PyObject *kwds) +static int py_encaps_content_init(PyObject *self, PyObject *args, PyObject *kwds) { - PyObject *result; /* Instance à retourner */ GBinContent *base; /* Base de l'extraction */ const char *path; /* Chemin vers le contenu final*/ GBinContent *endpoint; /* Contenu accessible au final */ int ret; /* Bilan de lecture des args. */ - GBinContent *content; /* Version GLib du contenu */ + GEncapsContent *content; /* Version GLib du contenu */ #define ENCAPS_CONTENT_DOC \ "EncapsulatedContent gathers items relative to a binary encapsulated" \ @@ -93,20 +95,30 @@ static PyObject *py_encaps_content_new(PyTypeObject *type, PyObject *args, PyObj " pychrysalide.analysis.BinContent instances and the access path must" \ " be provided as a string." + /* Récupération des paramètres */ + ret = PyArg_ParseTuple(args, "O&sO&", convert_to_binary_content, &base, &path, convert_to_binary_content, &endpoint); - if (!ret) return NULL; + if (!ret) return -1; - content = g_encaps_content_new(base, path, endpoint); + /* Initialisation d'un objet GLib */ - result = pygobject_new(G_OBJECT(content)); + ret = forward_pygobjet_init(self); + if (ret == -1) return -1; - if (content != NULL) - g_object_unref(content); + /* Eléments de base */ - return result; + content = G_ENCAPS_CONTENT(pygobject_get(self)); + + if (!g_encaps_content_create(content, base, path, endpoint)) + { + PyErr_SetString(PyExc_ValueError, _("Unable to create encapsulated content.")); + return -1; + } + + return 0; } @@ -275,7 +287,9 @@ PyTypeObject *get_python_encaps_content_type(void) .tp_methods = py_encaps_content_methods, .tp_getset = py_encaps_content_getseters, - .tp_new = py_encaps_content_new + + .tp_init = py_encaps_content_init, + .tp_new = py_encaps_content_new, }; @@ -310,7 +324,10 @@ bool ensure_python_encaps_content_is_registered(void) dict = PyModule_GetDict(module); - if (!register_class_for_pygobject(dict, G_TYPE_ENCAPS_CONTENT, type, &PyGObject_Type)) + if (!ensure_python_binary_content_is_registered()) + return false; + + if (!register_class_for_pygobject(dict, G_TYPE_ENCAPS_CONTENT, type)) return false; } diff --git a/plugins/pychrysalide/analysis/contents/file.c b/plugins/pychrysalide/analysis/contents/file.c index 93a1ce8..5bef069 100644 --- a/plugins/pychrysalide/analysis/contents/file.c +++ b/plugins/pychrysalide/analysis/contents/file.c @@ -28,16 +28,20 @@ #include <pygobject.h> -#include <analysis/contents/file.h> +#include <i18n.h> +#include <analysis/contents/file-int.h> +#include "memory.h" #include "../../access.h" #include "../../helpers.h" -/* Crée un nouvel objet Python de type 'BinContent'. */ -static PyObject *py_file_content_new(PyTypeObject *, PyObject *, PyObject *); +CREATE_DYN_CONSTRUCTOR(file_content, G_TYPE_FILE_CONTENT); + +/* Initialise une instance sur la base du dérivé de GObject. */ +static int py_file_content_init(PyObject *, PyObject *, PyObject *); /* Fournit le nom de fichier associé au contenu binaire. */ static PyObject *py_file_content_get_filename(PyObject *, void *); @@ -46,24 +50,23 @@ static PyObject *py_file_content_get_filename(PyObject *, void *); /****************************************************************************** * * -* 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 'BinContent'. * +* Description : Initialise une instance sur la base du dérivé de GObject. * * * -* Retour : Instance Python mise en place. * +* Retour : 0. * * * * Remarques : - * * * ******************************************************************************/ -static PyObject *py_file_content_new(PyTypeObject *type, PyObject *args, PyObject *kwds) +static int py_file_content_init(PyObject *self, PyObject *args, PyObject *kwds) { - PyObject *result; /* Instance à retourner */ const char *filename; /* Nom du fichier à charger */ int ret; /* Bilan de lecture des args. */ - GBinContent *content; /* Version GLib du contenu */ + GFileContent *content; /* Version GLib du contenu */ #define FILE_CONTENT_DOC \ "FileContent handles binary content loaded from a file.\n" \ @@ -74,17 +77,27 @@ static PyObject *py_file_content_new(PyTypeObject *type, PyObject *args, PyObjec "\n" \ "Where filename is a path to an existing file." + /* Récupération des paramètres */ + ret = PyArg_ParseTuple(args, "s", &filename); - if (!ret) return NULL; + if (!ret) return -1; - content = g_file_content_new(filename); + /* Initialisation d'un objet GLib */ - result = pygobject_new(G_OBJECT(content)); + ret = forward_pygobjet_init(self); + if (ret == -1) return -1; - if (content != NULL) - g_object_unref(content); + /* Eléments de base */ - return result; + content = G_FILE_CONTENT(pygobject_get(self)); + + if (!g_file_content_create(content, filename)) + { + PyErr_SetString(PyExc_ValueError, _("Unable to create file content.")); + return -1; + } + + return 0; } @@ -161,7 +174,9 @@ PyTypeObject *get_python_file_content_type(void) .tp_methods = py_file_content_methods, .tp_getset = py_file_content_getseters, - .tp_new = py_file_content_new + + .tp_init = py_file_content_init, + .tp_new = py_file_content_new, }; @@ -196,7 +211,10 @@ bool ensure_python_file_content_is_registered(void) dict = PyModule_GetDict(module); - if (!register_class_for_pygobject(dict, G_TYPE_FILE_CONTENT, type, &PyGObject_Type)) + if (!ensure_python_memory_content_is_registered()) + return false; + + if (!register_class_for_pygobject(dict, G_TYPE_FILE_CONTENT, type)) return false; } diff --git a/plugins/pychrysalide/analysis/contents/memory.c b/plugins/pychrysalide/analysis/contents/memory.c index 8926300..7464779 100644 --- a/plugins/pychrysalide/analysis/contents/memory.c +++ b/plugins/pychrysalide/analysis/contents/memory.c @@ -28,40 +28,43 @@ #include <pygobject.h> -#include <analysis/contents/memory.h> +#include <i18n.h> +#include <analysis/contents/memory-int.h> +#include "../content.h" #include "../../access.h" #include "../../helpers.h" -/* Crée un nouvel objet Python de type 'BinContent'. */ -static PyObject *py_memory_content_new(PyTypeObject *, PyObject *, PyObject *); +CREATE_DYN_CONSTRUCTOR(memory_content, G_TYPE_MEMORY_CONTENT); + +/* Initialise une instance sur la base du dérivé de GObject. */ +static int py_memory_content_init(PyObject *, PyObject *, PyObject *); /****************************************************************************** * * -* 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 'BinContent'. * +* Description : Initialise une instance sur la base du dérivé de GObject. * * * -* Retour : Instance Python mise en place. * +* Retour : 0. * * * * Remarques : - * * * ******************************************************************************/ -static PyObject *py_memory_content_new(PyTypeObject *type, PyObject *args, PyObject *kwds) +static int py_memory_content_init(PyObject *self, PyObject *args, PyObject *kwds) { - PyObject *result; /* Instance à retourner */ const char *data; /* Tampon interne de Python */ - int length; /* Taille utilisé de ce tampon */ + Py_ssize_t length; /* Taille utilisé de ce tampon */ int ret; /* Bilan de lecture des args. */ - GBinContent *content; /* Version GLib du contenu */ + GMemoryContent *content; /* Version GLib du contenu */ #define MEMORY_CONTENT_DOC \ "MemoryContent builds a binary content from memory data only." \ @@ -74,22 +77,32 @@ static PyObject *py_memory_content_new(PyTypeObject *type, PyObject *args, PyObj "Where data is provided as string or read-only bytes-like object." \ " The string may contain embedded null bytes." + /* Récupération des paramètres */ + /** * La taille doit être de type 'int' et non 'Py_ssize_t', sinon les 32 bits * de poids fort ne sont pas initialisés ! */ ret = PyArg_ParseTuple(args, "s#", &data, &length); - if (!ret) return NULL; + if (!ret) return -1; + + /* Initialisation d'un objet GLib */ - content = g_memory_content_new((const bin_t *)data, length); + ret = forward_pygobjet_init(self); + if (ret == -1) return -1; - result = pygobject_new(G_OBJECT(content)); + /* Eléments de base */ - if (content != NULL) - g_object_unref(content); + content = G_MEMORY_CONTENT(pygobject_get(self)); - return result; + if (!g_memory_content_create(content, (const bin_t *)data, length)) + { + PyErr_SetString(PyExc_ValueError, _("Unable to create memory content.")); + return -1; + } + + return 0; } @@ -129,7 +142,9 @@ PyTypeObject *get_python_memory_content_type(void) .tp_methods = py_memory_content_methods, .tp_getset = py_memory_content_getseters, - .tp_new = py_memory_content_new + + .tp_init = py_memory_content_init, + .tp_new = py_memory_content_new, }; @@ -152,7 +167,7 @@ PyTypeObject *get_python_memory_content_type(void) bool ensure_python_memory_content_is_registered(void) { - PyTypeObject *type; /* Type Python 'MemoryContent' */ + PyTypeObject *type; /* Type Python 'MemoryContent' */ PyObject *module; /* Module à recompléter */ PyObject *dict; /* Dictionnaire du module */ @@ -164,7 +179,10 @@ bool ensure_python_memory_content_is_registered(void) dict = PyModule_GetDict(module); - if (!register_class_for_pygobject(dict, G_TYPE_MEMORY_CONTENT, type, &PyGObject_Type)) + if (!ensure_python_binary_content_is_registered()) + return false; + + if (!register_class_for_pygobject(dict, G_TYPE_MEMORY_CONTENT, type)) return false; } diff --git a/plugins/pychrysalide/analysis/contents/restricted.c b/plugins/pychrysalide/analysis/contents/restricted.c index bbe364a..4521578 100644 --- a/plugins/pychrysalide/analysis/contents/restricted.c +++ b/plugins/pychrysalide/analysis/contents/restricted.c @@ -31,7 +31,8 @@ #include <i18n.h> -#include <analysis/contents/restricted.h> +#include <i18n.h> +#include <analysis/contents/restricted-int.h> #include "../content.h" @@ -41,8 +42,10 @@ -/* Crée un nouvel objet Python de type 'BinContent'. */ -static PyObject *py_restricted_content_new(PyTypeObject *, PyObject *, PyObject *); +CREATE_DYN_CONSTRUCTOR(restricted_content, G_TYPE_RESTRICTED_CONTENT); + +/* Initialise une instance sur la base du dérivé de GObject. */ +static int py_restricted_content_init(PyObject *, PyObject *, PyObject *); /* Indique l'espace de restriction appliqué à un contenu. */ static PyObject *py_restricted_content_get_range(PyObject *, void *); @@ -51,25 +54,24 @@ static PyObject *py_restricted_content_get_range(PyObject *, void *); /****************************************************************************** * * -* 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 'BinContent'. * +* Description : Initialise une instance sur la base du dérivé de GObject. * * * -* Retour : Instance Python mise en place. * +* Retour : 0. * * * * Remarques : - * * * ******************************************************************************/ -static PyObject *py_restricted_content_new(PyTypeObject *type, PyObject *args, PyObject *kwds) +static int py_restricted_content_init(PyObject *self, PyObject *args, PyObject *kwds) { - PyObject *result; /* Instance à retourner */ - GBinContent *content; /* Instance GLib correspondante*/ + GBinContent *internal; /* Instance GLib correspondante*/ mrange_t range; /* Restriction à appliquer */ int ret; /* Bilan de lecture des args. */ - GBinContent *restricted; /* Création GLib à transmettre */ + GRestrictedContent *content; /* Version GLib du contenu */ #define RESTRICTED_CONTENT_DOC \ "RestrictedContent restricts access to a given area for a binary content." \ @@ -81,14 +83,27 @@ static PyObject *py_restricted_content_new(PyTypeObject *type, PyObject *args, P "Where content is a pychrysalide.analysis.BinContent instance and range" \ " a Python object which can be converted into pychrysalide.arch.mrange." - ret = PyArg_ParseTuple(args, "O&O&", convert_to_binary_content, &content, convert_any_to_mrange, &range); - if (!ret) return NULL; + /* Récupération des paramètres */ - restricted = g_restricted_content_new(content, &range); + ret = PyArg_ParseTuple(args, "O&O&", convert_to_binary_content, &internal, convert_any_to_mrange, &range); + if (!ret) return -1; - result = pygobject_new(G_OBJECT(restricted)); + /* Initialisation d'un objet GLib */ - return result; + ret = forward_pygobjet_init(self); + if (ret == -1) return -1; + + /* Eléments de base */ + + content = G_RESTRICTED_CONTENT(pygobject_get(self)); + + if (!g_restricted_content_create(content, internal, &range)) + { + PyErr_SetString(PyExc_ValueError, _("Unable to create restricted content.")); + return -1; + } + + return 0; } @@ -165,7 +180,9 @@ PyTypeObject *get_python_restricted_content_type(void) .tp_methods = py_restricted_content_methods, .tp_getset = py_restricted_content_getseters, - .tp_new = py_restricted_content_new + + .tp_init = py_restricted_content_init, + .tp_new = py_restricted_content_new, }; @@ -200,7 +217,10 @@ bool ensure_python_restricted_content_is_registered(void) dict = PyModule_GetDict(module); - if (!register_class_for_pygobject(dict, G_TYPE_RESTRICTED_CONTENT, type, &PyGObject_Type)) + if (!ensure_python_binary_content_is_registered()) + return false; + + if (!register_class_for_pygobject(dict, G_TYPE_RESTRICTED_CONTENT, type)) return false; } diff --git a/plugins/pychrysalide/analysis/db/Makefile.am b/plugins/pychrysalide/analysis/db/Makefile.am index 721f5b6..a0dcc0d 100644 --- a/plugins/pychrysalide/analysis/db/Makefile.am +++ b/plugins/pychrysalide/analysis/db/Makefile.am @@ -1,21 +1,22 @@ noinst_LTLIBRARIES = libpychrysaanalysisdb.la -libpychrysaanalysisdb_la_SOURCES = \ - admin.h admin.c \ - analyst.h analyst.c \ - certs.h certs.c \ - client.h client.c \ - collection.h collection.c \ - constants.h constants.c \ - item.h item.c \ - module.h module.c \ +libpychrysaanalysisdb_la_SOURCES = \ + admin.h admin.c \ + analyst.h analyst.c \ + certs.h certs.c \ + client.h client.c \ + collection.h collection.c \ + constants.h constants.c \ + item.h item.c \ + module.h module.c \ server.h server.c -libpychrysaanalysisdb_la_LIBADD = \ +libpychrysaanalysisdb_la_LIBADD = \ items/libpychrysaanalysisdbitems.la -libpychrysaanalysisdb_la_LDFLAGS = +libpychrysaanalysisdb_la_CFLAGS = $(TOOLKIT_CFLAGS) $(LIBXML_CFLAGS) $(LIBPYTHON_INTERPRETER_CFLAGS) $(LIBPYGOBJECT_CFLAGS) \ + -I$(top_srcdir)/src -DNO_IMPORT_PYGOBJECT devdir = $(includedir)/chrysalide/$(subdir) @@ -23,9 +24,4 @@ devdir = $(includedir)/chrysalide/$(subdir) dev_HEADERS = $(libpychrysaanalysisdb_la_SOURCES:%c=) -AM_CPPFLAGS = $(LIBGTK_CFLAGS) $(LIBXML_CFLAGS) $(LIBPYTHON_CFLAGS) $(LIBPYGOBJECT_CFLAGS) \ - -I$(top_srcdir)/src - -AM_CFLAGS = $(DEBUG_CFLAGS) $(WARNING_FLAGS) $(COMPLIANCE_FLAGS) - SUBDIRS = items diff --git a/plugins/pychrysalide/analysis/db/admin.c b/plugins/pychrysalide/analysis/db/admin.c index a4694e6..10a150e 100644 --- a/plugins/pychrysalide/analysis/db/admin.c +++ b/plugins/pychrysalide/analysis/db/admin.c @@ -237,7 +237,7 @@ PyTypeObject *get_python_admin_client_type(void) * * * Paramètres : module = module dont la définition est à compléter. * * * -* Description : Prend en charge l'objet 'pychrysalide....db.AdminClient'. * +* Description : Prend en charge l'objet 'pychrysalide....db.AdminClient'. * * * * Retour : Bilan de l'opération. * * * @@ -255,14 +255,14 @@ bool ensure_python_admin_client_is_registered(void) if (!PyType_HasFeature(type, Py_TPFLAGS_READY)) { - if (!ensure_python_hub_client_is_registered()) - return false; - module = get_access_to_python_module("pychrysalide.analysis.db"); dict = PyModule_GetDict(module); - if (!register_class_for_pygobject(dict, G_TYPE_ADMIN_CLIENT, type, get_python_hub_client_type())) + if (!ensure_python_hub_client_is_registered()) + return false; + + if (!register_class_for_pygobject(dict, G_TYPE_ADMIN_CLIENT, type)) return false; } diff --git a/plugins/pychrysalide/analysis/db/analyst.c b/plugins/pychrysalide/analysis/db/analyst.c index 83e3878..f2860ed 100644 --- a/plugins/pychrysalide/analysis/db/analyst.c +++ b/plugins/pychrysalide/analysis/db/analyst.c @@ -30,20 +30,26 @@ #include <i18n.h> -#include <analysis/db/analyst.h> +#include <analysis/db/analyst-int.h> #include <core/collections.h> #include "client.h" #include "collection.h" +#include "constants.h" +#include "../content.h" +#include "../loaded.h" #include "../../access.h" #include "../../helpers.h" #include "../../struct.h" -/* Crée un nouvel objet Python de type 'AnalystClient'. */ -static PyObject *py_analyst_client_new(PyTypeObject *, PyObject *, PyObject *); +/* Initialise une instance sur la base du dérivé de GObject. */ +static int py_analyst_client_init(PyObject *, PyObject *, PyObject *); + +/* Envoie un contenu binaire pour conservation côté serveur. */ +static PyObject *py_analyst_client_send_content(PyObject *, PyObject *); /* Effectue une demande de sauvegarde de l'état courant. */ static PyObject *py_analyst_client_save(PyObject *, PyObject *); @@ -74,24 +80,29 @@ static PyObject *py_analyst_client_get_current_snapshot(PyObject *, void *); +CREATE_DYN_CONSTRUCTOR(analyst_client, G_TYPE_ANALYST_CLIENT); + + /****************************************************************************** * * -* 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 'AnalystClient'. * +* Description : Initialise une instance sur la base du dérivé de GObject. * * * -* Retour : Instance Python mise en place. * +* Retour : 0. * * * * Remarques : - * * * ******************************************************************************/ -static PyObject *py_analyst_client_new(PyTypeObject *type, PyObject *args, PyObject *kwds) +static int py_analyst_client_init(PyObject *self, PyObject *args, PyObject *kwds) { - PyObject *result; /* Instance à retourner */ + int result; /* Bilan à retourner */ + GLoadedContent *loaded; /* Contenu local déjà chargé */ const char *hash; /* Empreinte du binaire visé */ + const char *class; /* Nature du contenu analysé */ PyObject *list; /* Liste Python de collections */ int ret; /* Bilan de lecture des args. */ Py_ssize_t length; /* Nombre d'éléments collectés */ @@ -99,7 +110,8 @@ static PyObject *py_analyst_client_new(PyTypeObject *type, PyObject *args, PyObj Py_ssize_t i; /* Boucle de parcours */ PyObject *item; /* Elément de la liste Python */ GDbCollection *collec; /* Version équivalente native */ - GAnalystClient *client; /* Serveur mis en place */ + GAnalystClient *client; /* Client mis en place */ + bool status; /* Bilan d'initialisation */ #define ANALYST_CLIENT_DOC \ "AnalystClient provides and receives binary updates to and from a connected" \ @@ -109,11 +121,15 @@ static PyObject *py_analyst_client_new(PyTypeObject *type, PyObject *args, PyObj "\n" \ "Instances can be created using the following constructor:\n" \ "\n" \ - " AnalystClient(hash, list)" \ + " AnalystClient(hash, class, list, loaded=None)" \ "\n" \ - "Where hash is a SHA256 fingerprint of the studied binary and list is a list of" \ + "Where *hash* is a SHA256 fingerprint of the studied binary, *class* refers to" \ + " the nature description of the loaded content (as provided from" \ + " pychrysalide.analysis.LoadedContent.content_class), *list* is a list of" \ " pychrysalide.analysis.db.DbCollection instances ; this kind of list can be" \ " retrived with the pychrysalide.analysis.LoadedBinary.collections attribute." \ + " The *loaded* object is an optional local already loaded content which has to" \ + " be a pychrysalide.analysis.LoadedContent instance or *None*." \ "\n" \ "AnalystClient instances emit the following signals:\n" \ "* 'snapshots-updated'\n" \ @@ -127,13 +143,20 @@ static PyObject *py_analyst_client_new(PyTypeObject *type, PyObject *args, PyObj " Handlers are expected to have only one argument: the client managing the" \ " snapshots." - ret = PyArg_ParseTuple(args, "sO", &hash, &list); - if (!ret) return NULL; + loaded = NULL; + + ret = PyArg_ParseTuple(args, "ssO|O&", &hash, &class, &list, convert_to_loaded_content, &loaded); + if (!ret) return -1; + + /* Initialisation d'un objet GLib */ + + ret = forward_pygobjet_init(self); + if (ret == -1) return -1; if (!PySequence_Check(list)) { PyErr_SetString(PyExc_TypeError, _("The second argument must be a collection list")); - return NULL; + return -1; } length = PySequence_Length(list); @@ -151,7 +174,7 @@ static PyObject *py_analyst_client_new(PyTypeObject *type, PyObject *args, PyObj if (ret != 1) { delete_collections_list(&collections); - result = NULL; + result = -1; goto exit; } @@ -160,14 +183,11 @@ static PyObject *py_analyst_client_new(PyTypeObject *type, PyObject *args, PyObj } - client = g_analyst_client_new(hash, collections); + client = G_ANALYST_CLIENT(pygobject_get(self)); + + status = g_analyst_client_setup(client, hash, class, collections, loaded); - if (client != NULL) - { - result = pygobject_new(G_OBJECT(client)); - g_object_unref(client); - } - else result = NULL; + result = status ? 0 : -1; exit: @@ -179,6 +199,50 @@ static PyObject *py_analyst_client_new(PyTypeObject *type, PyObject *args, PyObj /****************************************************************************** * * * Paramètres : self = client à manipuler. * +* args = arguments fournis à l'appel. * +* * +* Description : Envoie un contenu binaire pour conservation côté serveur. * +* * +* Retour : True si la commande a bien été envoyée, False sinon. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static PyObject *py_analyst_client_send_content(PyObject *self, PyObject *args) +{ + PyObject *result; /* Bilan à retourner */ + GBinContent *content; /* Contenu binaire à envoyer */ + int ret; /* Bilan de lecture des args. */ + GAnalystClient *client; /* Version native du serveur */ + bool status; /* Bilan de l'opération */ + +#define ANALYST_CLIENT_SEND_CONTENT_METHOD PYTHON_METHOD_DEF \ +( \ + send_content, "$self, content, /", \ + METH_VARARGS, py_analyst_client, \ + "Ask the server for saving the current state of the analyzed binary" \ + " and returns the status of the request transmission." \ +) + + ret = PyArg_ParseTuple(args, "O&", convert_to_binary_content, &content); + if (!ret) return NULL; + + client = G_ANALYST_CLIENT(pygobject_get(self)); + + status = g_analyst_client_send_content(client, content); + + result = status ? Py_True : Py_False; + Py_INCREF(result); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : self = client à manipuler. * * args = arguments d'appel non utilisés ici. * * * * Description : Effectue une demande de sauvegarde de l'état courant. * @@ -773,6 +837,7 @@ static int py_analyst_client_set_current_snapshot(PyObject *self, PyObject *valu PyTypeObject *get_python_analyst_client_type(void) { static PyMethodDef py_analyst_client_methods[] = { + ANALYST_CLIENT_SEND_CONTENT_METHOD, ANALYST_CLIENT_SAVE_METHOD, ANALYST_CLIENT_SET_LAST_ACTIVE_METHOD, ANALYST_CLIENT_SET_SNAPSHOT_NAME_METHOD, @@ -802,7 +867,9 @@ PyTypeObject *get_python_analyst_client_type(void) .tp_methods = py_analyst_client_methods, .tp_getset = py_analyst_client_getseters, - .tp_new = py_analyst_client_new, + + .tp_init = py_analyst_client_init, + .tp_new = py_analyst_client_new }; @@ -833,14 +900,17 @@ bool ensure_python_analyst_client_is_registered(void) if (!PyType_HasFeature(type, Py_TPFLAGS_READY)) { - if (!ensure_python_hub_client_is_registered()) - return false; - module = get_access_to_python_module("pychrysalide.analysis.db"); dict = PyModule_GetDict(module); - if (!register_class_for_pygobject(dict, G_TYPE_ANALYST_CLIENT, type, get_python_hub_client_type())) + if (!ensure_python_hub_client_is_registered()) + return false; + + if (!register_class_for_pygobject(dict, G_TYPE_ANALYST_CLIENT, type)) + return false; + + if (!define_loading_status_hint_constants(type)) return false; } diff --git a/plugins/pychrysalide/analysis/db/client.c b/plugins/pychrysalide/analysis/db/client.c index 0cd9704..7ef658e 100644 --- a/plugins/pychrysalide/analysis/db/client.c +++ b/plugins/pychrysalide/analysis/db/client.c @@ -235,7 +235,7 @@ bool ensure_python_hub_client_is_registered(void) dict = PyModule_GetDict(module); - if (!register_class_for_pygobject(dict, G_TYPE_HUB_CLIENT, type, &PyGObject_Type)) + if (!register_class_for_pygobject(dict, G_TYPE_HUB_CLIENT, type)) return false; } diff --git a/plugins/pychrysalide/analysis/db/collection.c b/plugins/pychrysalide/analysis/db/collection.c index ca4151c..5970d15 100644 --- a/plugins/pychrysalide/analysis/db/collection.c +++ b/plugins/pychrysalide/analysis/db/collection.c @@ -165,7 +165,7 @@ bool ensure_python_db_collection_is_registered(void) dict = PyModule_GetDict(module); - if (!register_class_for_pygobject(dict, G_TYPE_DB_COLLECTION, type, &PyGObject_Type)) + if (!register_class_for_pygobject(dict, G_TYPE_DB_COLLECTION, type)) return false; } diff --git a/plugins/pychrysalide/analysis/db/constants.c b/plugins/pychrysalide/analysis/db/constants.c index 8e7765a..5e8c20d 100644 --- a/plugins/pychrysalide/analysis/db/constants.c +++ b/plugins/pychrysalide/analysis/db/constants.c @@ -25,6 +25,7 @@ #include "constants.h" +#include <analysis/db/analyst.h> #include <analysis/db/item.h> #include <analysis/db/server.h> @@ -152,3 +153,45 @@ bool define_hub_server_constants(PyTypeObject *type) return result; } + + +/****************************************************************************** +* * +* Paramètres : type = type dont le dictionnaire est à compléter. * +* * +* Description : Définit les constantes pour les indications de chargement. * +* * +* Retour : true en cas de succès de l'opération, false sinon. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool define_loading_status_hint_constants(PyTypeObject *type) +{ + bool result; /* Bilan à retourner */ + PyObject *values; /* Groupe de valeurs à établir */ + + values = PyDict_New(); + + result = add_const_to_group(values, "READY", LSH_READY); + if (result) result = add_const_to_group(values, "ON_WAIT_LIST", LSH_ON_WAIT_LIST); + if (result) result = add_const_to_group(values, "NEED_CONTENT", LSH_NEED_CONTENT); + if (result) result = add_const_to_group(values, "NEED_FORMAT", LSH_NEED_FORMAT); + if (result) result = add_const_to_group(values, "NEED_ARCH", LSH_NEED_ARCH); + + if (!result) + { + Py_DECREF(values); + goto exit; + } + + result = attach_constants_group_to_type_with_pyg_enum(type, false, "LoadingStatusHint", values, + "Indication about a loading process state.", + G_TYPE_LOADING_STATUS_HINT); + + exit: + + return result; + +} diff --git a/plugins/pychrysalide/analysis/db/constants.h b/plugins/pychrysalide/analysis/db/constants.h index 5f0afeb..ea7a0c0 100644 --- a/plugins/pychrysalide/analysis/db/constants.h +++ b/plugins/pychrysalide/analysis/db/constants.h @@ -39,6 +39,9 @@ bool define_db_item_constants(PyTypeObject *); /* Définit les constantes pour les serveurs de données. */ bool define_hub_server_constants(PyTypeObject *); +/* Définit les constantes pour les indications de chargement. */ +bool define_loading_status_hint_constants(PyTypeObject *); + #endif /* _PLUGINS_PYCHRYSALIDE_ANALYSIS_DB_CONSTANTS_H */ diff --git a/plugins/pychrysalide/analysis/db/item.c b/plugins/pychrysalide/analysis/db/item.c index 836f902..cc9bdf4 100644 --- a/plugins/pychrysalide/analysis/db/item.c +++ b/plugins/pychrysalide/analysis/db/item.c @@ -369,7 +369,7 @@ bool ensure_python_db_item_is_registered(void) dict = PyModule_GetDict(module); - if (!register_class_for_pygobject(dict, G_TYPE_DB_ITEM, type, &PyGObject_Type)) + if (!register_class_for_pygobject(dict, G_TYPE_DB_ITEM, type)) return false; if (!define_db_protocol_constants(type)) diff --git a/plugins/pychrysalide/analysis/db/items/Makefile.am b/plugins/pychrysalide/analysis/db/items/Makefile.am index 80f9756..201aed7 100644 --- a/plugins/pychrysalide/analysis/db/items/Makefile.am +++ b/plugins/pychrysalide/analysis/db/items/Makefile.am @@ -1,22 +1,17 @@ noinst_LTLIBRARIES = libpychrysaanalysisdbitems.la -libpychrysaanalysisdbitems_la_SOURCES = \ - bookmark.h bookmark.c \ - comment.h comment.c \ - constants.h constants.c \ - module.h module.c \ +libpychrysaanalysisdbitems_la_SOURCES = \ + bookmark.h bookmark.c \ + comment.h comment.c \ + constants.h constants.c \ + module.h module.c \ switcher.h switcher.c -libpychrysaanalysisdbitems_la_LDFLAGS = +libpychrysaanalysisdbitems_la_CFLAGS = $(TOOLKIT_CFLAGS) $(LIBXML_CFLAGS) $(LIBPYTHON_INTERPRETER_CFLAGS) $(LIBPYGOBJECT_CFLAGS) \ + -I$(top_srcdir)/src -DNO_IMPORT_PYGOBJECT devdir = $(includedir)/chrysalide/$(subdir) dev_HEADERS = $(libpychrysaanalysisdbitems_la_SOURCES:%c=) - - -AM_CPPFLAGS = $(LIBGTK_CFLAGS) $(LIBXML_CFLAGS) $(LIBPYTHON_CFLAGS) $(LIBPYGOBJECT_CFLAGS) \ - -I$(top_srcdir)/src - -AM_CFLAGS = $(DEBUG_CFLAGS) $(WARNING_FLAGS) $(COMPLIANCE_FLAGS) diff --git a/plugins/pychrysalide/analysis/db/items/bookmark.c b/plugins/pychrysalide/analysis/db/items/bookmark.c index af649e3..d2bc0f0 100644 --- a/plugins/pychrysalide/analysis/db/items/bookmark.c +++ b/plugins/pychrysalide/analysis/db/items/bookmark.c @@ -108,7 +108,7 @@ static PyObject *py_db_bookmark_new(PyTypeObject *type, PyObject *args, PyObject if (first_time) { - status = register_class_for_dynamic_pygobject(gtype, type, base); + status = register_class_for_dynamic_pygobject(gtype, type); if (!status) { @@ -366,7 +366,7 @@ bool ensure_python_db_bookmark_is_registered(void) if (!ensure_python_db_item_is_registered()) return false; - if (!register_class_for_pygobject(dict, G_TYPE_DB_BOOKMARK, type, get_python_db_item_type())) + if (!register_class_for_pygobject(dict, G_TYPE_DB_BOOKMARK, type)) return false; } @@ -473,7 +473,7 @@ static PyObject *py_bookmark_collection_new(PyTypeObject *type, PyObject *args, if (first_time) { - status = register_class_for_dynamic_pygobject(gtype, type, base); + status = register_class_for_dynamic_pygobject(gtype, type); if (!status) { @@ -570,7 +570,7 @@ bool ensure_python_bookmark_collection_is_registered(void) if (!ensure_python_db_collection_is_registered()) return false; - if (!register_class_for_pygobject(dict, G_TYPE_BM_COLLECTION, type, get_python_db_collection_type())) + if (!register_class_for_pygobject(dict, G_TYPE_BM_COLLECTION, type)) return false; } diff --git a/plugins/pychrysalide/analysis/db/items/comment.c b/plugins/pychrysalide/analysis/db/items/comment.c index 78d4902..1358f1d 100644 --- a/plugins/pychrysalide/analysis/db/items/comment.c +++ b/plugins/pychrysalide/analysis/db/items/comment.c @@ -117,7 +117,7 @@ static PyObject *py_db_comment_new(PyTypeObject *type, PyObject *args, PyObject if (first_time) { - status = register_class_for_dynamic_pygobject(gtype, type, base); + status = register_class_for_dynamic_pygobject(gtype, type); if (!status) { @@ -464,7 +464,7 @@ bool ensure_python_db_comment_is_registered(void) if (!ensure_python_db_item_is_registered()) return false; - if (!register_class_for_pygobject(dict, G_TYPE_DB_COMMENT, type, get_python_db_item_type())) + if (!register_class_for_pygobject(dict, G_TYPE_DB_COMMENT, type)) return false; if (!define_db_comment_constants(type)) @@ -574,7 +574,7 @@ static PyObject *py_comment_collection_new(PyTypeObject *type, PyObject *args, P if (first_time) { - status = register_class_for_dynamic_pygobject(gtype, type, base); + status = register_class_for_dynamic_pygobject(gtype, type); if (!status) { @@ -671,7 +671,7 @@ bool ensure_python_comment_collection_is_registered(void) if (!ensure_python_db_collection_is_registered()) return false; - if (!register_class_for_pygobject(dict, G_TYPE_COMMENT_COLLECTION, type, get_python_db_collection_type())) + if (!register_class_for_pygobject(dict, G_TYPE_COMMENT_COLLECTION, type)) return false; } diff --git a/plugins/pychrysalide/analysis/db/items/switcher.c b/plugins/pychrysalide/analysis/db/items/switcher.c index 6ac5cdf..5766fe1 100644 --- a/plugins/pychrysalide/analysis/db/items/switcher.c +++ b/plugins/pychrysalide/analysis/db/items/switcher.c @@ -114,7 +114,7 @@ static PyObject *py_db_switcher_new(PyTypeObject *type, PyObject *args, PyObject if (first_time) { - status = register_class_for_dynamic_pygobject(gtype, type, base); + status = register_class_for_dynamic_pygobject(gtype, type); if (!status) { @@ -398,7 +398,7 @@ bool ensure_python_db_switcher_is_registered(void) if (!ensure_python_db_item_is_registered()) return false; - if (!register_class_for_pygobject(dict, G_TYPE_DB_SWITCHER, type, get_python_db_item_type())) + if (!register_class_for_pygobject(dict, G_TYPE_DB_SWITCHER, type)) return false; } @@ -506,7 +506,7 @@ static PyObject *py_switcher_collection_new(PyTypeObject *type, PyObject *args, if (first_time) { - status = register_class_for_dynamic_pygobject(gtype, type, base); + status = register_class_for_dynamic_pygobject(gtype, type); if (!status) { @@ -603,7 +603,7 @@ bool ensure_python_switcher_collection_is_registered(void) if (!ensure_python_db_collection_is_registered()) return false; - if (!register_class_for_pygobject(dict, G_TYPE_SWITCHER_COLLECTION, type, get_python_db_collection_type())) + if (!register_class_for_pygobject(dict, G_TYPE_SWITCHER_COLLECTION, type)) return false; } diff --git a/plugins/pychrysalide/analysis/db/server.c b/plugins/pychrysalide/analysis/db/server.c index 9e4ee61..dae7b29 100644 --- a/plugins/pychrysalide/analysis/db/server.c +++ b/plugins/pychrysalide/analysis/db/server.c @@ -274,7 +274,7 @@ bool ensure_python_hub_server_is_registered(void) dict = PyModule_GetDict(module); - if (!register_class_for_pygobject(dict, G_TYPE_HUB_SERVER, type, &PyGObject_Type)) + if (!register_class_for_pygobject(dict, G_TYPE_HUB_SERVER, type)) return false; if (!define_hub_server_constants(type)) diff --git a/plugins/pychrysalide/analysis/disass/Makefile.am b/plugins/pychrysalide/analysis/disass/Makefile.am index 0dacc15..0daa930 100644 --- a/plugins/pychrysalide/analysis/disass/Makefile.am +++ b/plugins/pychrysalide/analysis/disass/Makefile.am @@ -1,21 +1,14 @@ noinst_LTLIBRARIES = libpychrysaanalysisdisass.la -libpychrysaanalysisdisass_la_SOURCES = \ - block.h block.c \ +libpychrysaanalysisdisass_la_SOURCES = \ + block.h block.c \ module.h module.c -libpychrysaanalysisdisass_la_LDFLAGS = +libpychrysaanalysisdisass_la_CFLAGS = $(TOOLKIT_CFLAGS) $(LIBXML_CFLAGS) $(LIBPYTHON_INTERPRETER_CFLAGS) $(LIBPYGOBJECT_CFLAGS) \ + -I$(top_srcdir)/src -DNO_IMPORT_PYGOBJECT devdir = $(includedir)/chrysalide/$(subdir) dev_HEADERS = $(libpychrysaanalysisdisass_la_SOURCES:%c=) - - -AM_CPPFLAGS = $(LIBGTK_CFLAGS) $(LIBXML_CFLAGS) $(LIBPYTHON_CFLAGS) $(LIBPYGOBJECT_CFLAGS) \ - -I$(top_srcdir)/src - -AM_CFLAGS = $(DEBUG_CFLAGS) $(WARNING_FLAGS) $(COMPLIANCE_FLAGS) - -SUBDIRS = diff --git a/plugins/pychrysalide/analysis/disass/block.c b/plugins/pychrysalide/analysis/disass/block.c index 38e65a1..d82e3e2 100644 --- a/plugins/pychrysalide/analysis/disass/block.c +++ b/plugins/pychrysalide/analysis/disass/block.c @@ -159,7 +159,10 @@ bool ensure_python_basic_block_is_registered(void) dict = PyModule_GetDict(module); - if (!register_class_for_pygobject(dict, G_TYPE_BASIC_BLOCK, type, get_python_code_block_type())) + if (!ensure_python_code_block_is_registered()) + return false; + + if (!register_class_for_pygobject(dict, G_TYPE_BASIC_BLOCK, type)) return false; } diff --git a/plugins/pychrysalide/analysis/loaded.c b/plugins/pychrysalide/analysis/loaded.c index 3ed51d5..a2bf13f 100644 --- a/plugins/pychrysalide/analysis/loaded.c +++ b/plugins/pychrysalide/analysis/loaded.c @@ -35,6 +35,7 @@ #include <analysis/loaded-int.h> #include <core/global.h> +#include <plugins/dt.h> #include "content.h" @@ -47,14 +48,17 @@ /* ------------------------ GLUE POUR CREATION DEPUIS PYTHON ------------------------ */ -/* Procède à l'initialisation de l'interface de génération. */ -static void py_loaded_content_interface_init(GLoadedContentIface *, gpointer *); +/* Accompagne la création d'une instance dérivée en Python. */ +static PyObject *py_loaded_content_new(PyTypeObject *, PyObject *, PyObject *); + +/* Initialise la classe générique des contenus chargés. */ +static void py_loaded_content_init_gclass(GLoadedContentClass *, gpointer); /* Fournit le contenu représenté de l'élément chargé. */ static GBinContent *py_loaded_content_get_content_wrapper(const GLoadedContent *); -/* Fournit le format associé à l'élément chargé. */ -static char *py_loaded_content_get_format_name_wrapper(const GLoadedContent *); +/* Décrit la nature du contenu reconnu pour l'élément chargé. */ +static char *py_loaded_content_get_content_class_wrapper(const GLoadedContent *, bool); /* Lance l'analyse propre à l'élément chargé. */ static bool py_loaded_content_analyze_wrapper(GLoadedContent *, bool, bool, wgroup_id_t, GtkStatusStack *); @@ -62,6 +66,8 @@ static bool py_loaded_content_analyze_wrapper(GLoadedContent *, bool, bool, wgro /* Fournit le désignation associée à l'élément chargé. */ static char *py_loaded_content_describe_wrapper(const GLoadedContent *, bool); +#ifdef INCLUDE_GTK_SUPPORT + /* Détermine le nombre de vues disponibles pour un contenu. */ static unsigned int py_loaded_content_count_views_wrapper(const GLoadedContent *); @@ -77,6 +83,8 @@ static GtkWidget *py_loaded_content_build_view_wrapper(GLoadedContent *, unsigne /* Retrouve l'indice correspondant à la vue donnée d'un contenu. */ static unsigned int py_loaded_content_get_view_index_wrapper(GLoadedContent *, GtkWidget *); +#endif + /* ------------------------- CONNEXION AVEC L'API DE PYTHON ------------------------- */ @@ -94,6 +102,8 @@ static PyObject *py_loaded_content_describe(PyObject *, PyObject *); /* Etablit une liste d'obscurcissements présents. */ static PyObject *py_loaded_content_detect_obfuscators(PyObject *, PyObject *); +#ifdef INCLUDE_GTK_SUPPORT + /* Détermine le nombre de vues disponibles pour un contenu. */ static PyObject *py_loaded_content_count_views(PyObject *, PyObject *); @@ -106,11 +116,16 @@ static PyObject *py_loaded_content_build_default_view(PyObject *, PyObject *); /* Met en place la vue initiale pour un contenu chargé. */ static PyObject *py_loaded_content_build_view(PyObject *, PyObject *); +#endif + /* Fournit le contenu représenté de l'élément chargé. */ static PyObject *py_loaded_content_get_content(PyObject *, void *); -/* Fournit le format associé à l'élément chargé. */ -static PyObject *py_loaded_content_get_format_name(PyObject *, void *); +/* Décrit la nature du contenu reconnu pour l'élément chargé. */ +static PyObject *py_loaded_content_get_content_class(PyObject *, void *); + +/* Décrit la nature du contenu reconnu pour l'élément chargé. */ +static PyObject *py_loaded_content_get_content_class_for_human(PyObject *, void *); @@ -121,21 +136,28 @@ static PyObject *py_loaded_content_get_format_name(PyObject *, void *); /****************************************************************************** * * -* Paramètres : iface = interface GLib à initialiser. * -* unused = adresse non utilisée ici. * +* Paramètres : type = type du nouvel objet à mettre en place. * +* args = éventuelle liste d'arguments. * +* kwds = éventuel dictionnaire de valeurs mises à disposition. * * * -* Description : Procède à l'initialisation de l'interface de génération. * +* Description : Accompagne la création d'une instance dérivée en Python. * * * -* Retour : - * +* Retour : Nouvel objet Python mis en place ou NULL en cas d'échec. * * * * Remarques : - * * * ******************************************************************************/ -static void py_loaded_content_interface_init(GLoadedContentIface *iface, gpointer *unused) +static PyObject *py_loaded_content_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 */ + #define LOADED_CONTENT_DOC \ - "The LoadedContent interface is an intermediary level of abstraction" \ + "The LoadedContent object is an intermediary level of abstraction" \ " for all loaded binary contents to analyze." \ "\n" \ "No matter if the loaded content comes from an ELF file or XML data," \ @@ -148,7 +170,7 @@ static void py_loaded_content_interface_init(GLoadedContentIface *iface, gpointe "\n" \ "The following methods have to be defined for new implementations:\n" \ "* pychrysalide.analysis.storage.LoadedContent._get_content();\n" \ - "* pychrysalide.analysis.storage.LoadedContent._get_format_name();\n" \ + "* pychrysalide.analysis.storage.LoadedContent._get_content_class();\n" \ "* pychrysalide.analysis.storage.LoadedContent._analyze();\n" \ "* pychrysalide.analysis.storage.LoadedContent._describe();\n" \ "* pychrysalide.analysis.storage.LoadedContent._count_views();\n" \ @@ -157,18 +179,76 @@ static void py_loaded_content_interface_init(GLoadedContentIface *iface, gpointe "* pychrysalide.analysis.storage.LoadedContent._build_view();\n" \ "* pychrysalide.analysis.storage.LoadedContent._get_view_index();\n" - iface->get_content = py_loaded_content_get_content_wrapper; - iface->get_format_name = py_loaded_content_get_format_name_wrapper; + /* Validations diverses */ + + base = get_python_loaded_content_type(); + + if (type == base) + { + result = NULL; + PyErr_Format(PyExc_RuntimeError, _("%s is an abstract class"), type->tp_name); + goto exit; + } - iface->analyze = py_loaded_content_analyze_wrapper; + /* Mise en place d'un type dédié */ - iface->describe = py_loaded_content_describe_wrapper; + first_time = (g_type_from_name(type->tp_name) == 0); - iface->count_views = py_loaded_content_count_views_wrapper; - iface->get_view_name = py_loaded_content_get_view_name_wrapper; - iface->build_def_view = py_loaded_content_build_default_view_wrapper; - iface->build_view = py_loaded_content_build_view_wrapper; - iface->get_view_index = py_loaded_content_get_view_index_wrapper; + gtype = build_dynamic_type(G_TYPE_LOADED_CONTENT, type->tp_name, + (GClassInitFunc)py_loaded_content_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. * +* * +* Description : Initialise la classe générique des contenus chargés. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void py_loaded_content_init_gclass(GLoadedContentClass *class, gpointer unused) +{ + class->get_content = py_loaded_content_get_content_wrapper; + class->get_content_class = py_loaded_content_get_content_class_wrapper; + + class->analyze = py_loaded_content_analyze_wrapper; + + class->describe = py_loaded_content_describe_wrapper; + +#ifdef INCLUDE_GTK_SUPPORT + class->count_views = py_loaded_content_count_views_wrapper; + class->get_view_name = py_loaded_content_get_view_name_wrapper; + class->build_def_view = py_loaded_content_build_default_view_wrapper; + class->build_view = py_loaded_content_build_view_wrapper; + class->get_view_index = py_loaded_content_get_view_index_wrapper; +#endif } @@ -234,31 +314,34 @@ static GBinContent *py_loaded_content_get_content_wrapper(const GLoadedContent * /****************************************************************************** * * * Paramètres : content = élément chargé à manipuler. * +* human = description humaine attendue ? * * * -* Description : Fournit le format associé à l'élément chargé. * +* Description : Décrit la nature du contenu reconnu pour l'élément chargé. * * * -* Retour : Format associé à l'élément chargé. * +* Retour : Classe de contenu associée à l'élément chargé. * * * * Remarques : - * * * ******************************************************************************/ -static char *py_loaded_content_get_format_name_wrapper(const GLoadedContent *content) +static char *py_loaded_content_get_content_class_wrapper(const GLoadedContent *content, bool human) { char *result; /* Contenu interne à renvoyer */ PyGILState_STATE gstate; /* Sauvegarde d'environnement */ PyObject *pyobj; /* Objet Python concerné */ + PyObject *args; /* Arguments pour l'appel */ + PyObject *hobj; /* Argument pour Python */ PyObject *pyret; /* Bilan de consultation */ int ret; /* Validité d'une conversion */ -#define LOADED_CONTENT_GET_FORMAT_NAME_WRAPPER PYTHON_WRAPPER_DEF \ +#define LOADED_CONTENT_GET_CONTENT_CLASS_WRAPPER PYTHON_WRAPPER_DEF \ ( \ - _get_format_name, "$self", \ + _get_content_class, "$self, human", \ METH_VARARGS, \ - "Abstract method used to provide the aw name of the format connected" \ - " to the loaded content.\n" \ + "Abstract method used to provide the nature of the loaded content.\n" \ "\n" \ - "The name associated to a loaded Elf binary is for instance 'elf'." \ + "The description associated to a loaded ARM Elf binary is for instance" \ + " 'elf-armv7', or 'Elf, ARMv7' for the human version." \ ) result = NULL; @@ -267,9 +350,16 @@ static char *py_loaded_content_get_format_name_wrapper(const GLoadedContent *con pyobj = pygobject_new(G_OBJECT(content)); - if (has_python_method(pyobj, "_get_format_name")) + if (has_python_method(pyobj, "_get_content_class")) { - pyret = run_python_method(pyobj, "_get_format_name", NULL); + args = PyTuple_New(1); + + hobj = (human ? Py_True : Py_False); + Py_INCREF(hobj); + + PyTuple_SetItem(args, 0, hobj); + + pyret = run_python_method(pyobj, "_get_content_class", args); if (pyret != NULL) { @@ -282,6 +372,8 @@ static char *py_loaded_content_get_format_name_wrapper(const GLoadedContent *con } + Py_DECREF(args); + } Py_DECREF(pyobj); @@ -456,6 +548,9 @@ static char *py_loaded_content_describe_wrapper(const GLoadedContent *content, b } +#ifdef INCLUDE_GTK_SUPPORT + + /****************************************************************************** * * * Paramètres : content = contenu chargé à consulter. * @@ -792,6 +887,9 @@ static unsigned int py_loaded_content_get_view_index_wrapper(GLoadedContent *con } +#endif + + /* ---------------------------------------------------------------------------------- */ /* CONNEXION AVEC L'API DE PYTHON */ @@ -876,7 +974,6 @@ static PyObject *py_loaded_content_analyze_and_wait(PyObject *self, PyObject *ar int connect; /* Connexion à la base ? */ int cache; /* Préparation de rendu ? */ int ret; /* Bilan de lecture des args. */ - PyThreadState *_save; /* Sauvegarde de contexte */ GLoadedContent *content; /* Version GLib de l'élément */ bool status; /* Bilan de l'opération */ @@ -911,12 +1008,8 @@ static PyObject *py_loaded_content_analyze_and_wait(PyObject *self, PyObject *ar content = G_LOADED_CONTENT(pygobject_get(self)); - Py_UNBLOCK_THREADS; - status = g_loaded_content_analyze_and_wait(content, connect, cache); - Py_BLOCK_THREADS; - result = status ? Py_True : Py_False; Py_INCREF(result); @@ -1030,6 +1123,9 @@ static PyObject *py_loaded_content_detect_obfuscators(PyObject *self, PyObject * } +#ifdef INCLUDE_GTK_SUPPORT + + /****************************************************************************** * * * Paramètres : self = contenu chargé à manipuler. * @@ -1271,6 +1367,9 @@ static PyObject *py_loaded_content_get_view_index(PyObject *self, PyObject *args } +#endif + + /****************************************************************************** * * * Paramètres : self = objet Python concerné par l'appel. * @@ -1314,35 +1413,77 @@ static PyObject *py_loaded_content_get_content(PyObject *self, void *closure) * Paramètres : self = objet Python concerné par l'appel. * * closure = non utilisé ici. * * * -* Description : Fournit le format associé à l'élément chargé. * +* Description : Décrit la nature du contenu reconnu pour l'élément chargé. * * * -* Retour : Format associé à l'élément chargé. * +* Retour : Classe de contenu associée à l'élément chargé. * * * * Remarques : - * * * ******************************************************************************/ -static PyObject *py_loaded_content_get_format_name(PyObject *self, void *closure) +static PyObject *py_loaded_content_get_content_class(PyObject *self, void *closure) { PyObject *result; /* Instance Python à retourner */ GLoadedContent *content; /* Version GLib de l'élément */ - GBinContent *bincnt; /* Contenu binaire associé */ + char *class; /* Nature du contenu binaire */ -#define LOADED_CONTENT_FORMAT_NAME_ATTRIB PYTHON_GET_DEF_FULL \ +#define LOADED_CONTENT_CONTENT_CLASS_ATTRIB PYTHON_GET_DEF_FULL \ ( \ - format_name, py_loaded_content, \ - "Raw name of the format connected to the loaded content.\n" \ + content_class, py_loaded_content, \ + "Nature of the loaded content.\n" \ "\n" \ - "The name associated to a loaded Elf binary is for instance 'elf'." \ + "The description associated to a loaded ARM Elf binary is for instance" \ + " 'elf-armv7'." \ ) content = G_LOADED_CONTENT(pygobject_get(self)); - bincnt = g_loaded_content_get_content(content); + class = g_loaded_content_get_content_class(content, false); - result = pygobject_new(G_OBJECT(bincnt)); + result = PyUnicode_FromString(class); - g_object_unref(G_OBJECT(bincnt)); + free(class); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : self = objet Python concerné par l'appel. * +* closure = non utilisé ici. * +* * +* Description : Décrit la nature du contenu reconnu pour l'élément chargé. * +* * +* Retour : Classe de contenu associée à l'élément chargé. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static PyObject *py_loaded_content_get_content_class_for_human(PyObject *self, void *closure) +{ + PyObject *result; /* Instance Python à retourner */ + GLoadedContent *content; /* Version GLib de l'élément */ + char *class; /* Nature du contenu binaire */ + +#define LOADED_CONTENT_CONTENT_CLASS_FOR_HUMAN_ATTRIB PYTHON_GET_DEF_FULL \ +( \ + content_class_for_human, py_loaded_content, \ + "Humain version of the nature of the loaded content.\n" \ + "\n" \ + "The description associated to a loaded ARM Elf binary is for instance" \ + " ''Elf, ARMv7'." \ +) + + content = G_LOADED_CONTENT(pygobject_get(self)); + + class = g_loaded_content_get_content_class(content, true); + + result = PyUnicode_FromString(class); + + free(class); return result; @@ -1365,29 +1506,34 @@ PyTypeObject *get_python_loaded_content_type(void) { static PyMethodDef py_loaded_content_methods[] = { LOADED_CONTENT_GET_CONTENT_WRAPPER, - LOADED_CONTENT_GET_FORMAT_NAME_WRAPPER, + LOADED_CONTENT_GET_CONTENT_CLASS_WRAPPER, LOADED_CONTENT_ANALYZE_WRAPPER, LOADED_CONTENT_DESCRIBE_WRAPPER, +#ifdef INCLUDE_GTK_SUPPORT LOADED_CONTENT_COUNT_VIEWS_WRAPPER, LOADED_CONTENT_GET_VIEW_NAME_WRAPPER, LOADED_CONTENT_BUILD_DEFAULT_VIEW_WRAPPER, LOADED_CONTENT_BUILD_VIEW_WRAPPER, LOADED_CONTENT_GET_VIEW_INDEX_WRAPPER, +#endif LOADED_CONTENT_ANALYZE_METHOD, LOADED_CONTENT_ANALYZE_AND_WAIT_METHOD, LOADED_CONTENT_DESCRIBE_METHOD, LOADED_CONTENT_DETECT_OBFUSCATORS_METHOD, +#ifdef INCLUDE_GTK_SUPPORT LOADED_CONTENT_COUNT_VIEWS_METHOD, LOADED_CONTENT_GET_VIEW_NAME_METHOD, LOADED_CONTENT_BUILD_DEFAULT_VIEW_METHOD, LOADED_CONTENT_BUILD_VIEW_METHOD, LOADED_CONTENT_GET_VIEW_INDEX_METHOD, +#endif { NULL } }; static PyGetSetDef py_loaded_content_getseters[] = { LOADED_CONTENT_CONTENT_ATTRIB, - LOADED_CONTENT_FORMAT_NAME_ATTRIB, + LOADED_CONTENT_CONTENT_CLASS_ATTRIB, + LOADED_CONTENT_CONTENT_CLASS_FOR_HUMAN_ATTRIB, { NULL } }; @@ -1396,14 +1542,16 @@ PyTypeObject *get_python_loaded_content_type(void) PyVarObject_HEAD_INIT(NULL, 0) .tp_name = "pychrysalide.analysis.LoadedContent", - .tp_basicsize = sizeof(PyObject), + .tp_basicsize = sizeof(PyGObject), - .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, + .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_IS_ABSTRACT | Py_TPFLAGS_BASETYPE, .tp_doc = LOADED_CONTENT_DOC, .tp_methods = py_loaded_content_methods, - .tp_getset = py_loaded_content_getseters + .tp_getset = py_loaded_content_getseters, + + .tp_new = py_loaded_content_new, }; @@ -1430,14 +1578,6 @@ bool ensure_python_loaded_content_is_registered(void) PyObject *module; /* Module à recompléter */ PyObject *dict; /* Dictionnaire du module */ - static GInterfaceInfo info = { /* Paramètres d'inscription */ - - .interface_init = (GInterfaceInitFunc)py_loaded_content_interface_init, - .interface_finalize = NULL, - .interface_data = NULL, - - }; - type = get_python_loaded_content_type(); if (!PyType_HasFeature(type, Py_TPFLAGS_READY)) @@ -1446,10 +1586,12 @@ bool ensure_python_loaded_content_is_registered(void) dict = PyModule_GetDict(module); +#ifdef INCLUDE_GTK_SUPPORT if (!ensure_python_named_widget_is_registered()) return false; +#endif - if (!register_interface_for_pygobject(dict, G_TYPE_LOADED_CONTENT, type, &info)) + if (!register_class_for_pygobject(dict, G_TYPE_LOADED_CONTENT, type)) return false; } diff --git a/plugins/pychrysalide/analysis/loading.c b/plugins/pychrysalide/analysis/loading.c index dea4e31..8a60d8a 100644 --- a/plugins/pychrysalide/analysis/loading.c +++ b/plugins/pychrysalide/analysis/loading.c @@ -168,7 +168,7 @@ bool ensure_python_content_explorer_is_registered(void) dict = PyModule_GetDict(module); - if (!register_class_for_pygobject(dict, G_TYPE_CONTENT_EXPLORER, type, &PyGObject_Type)) + if (!register_class_for_pygobject(dict, G_TYPE_CONTENT_EXPLORER, type)) return false; } @@ -294,7 +294,7 @@ bool ensure_python_content_resolver_is_registered(void) dict = PyModule_GetDict(module); - if (!register_class_for_pygobject(dict, G_TYPE_CONTENT_RESOLVER, type, &PyGObject_Type)) + if (!register_class_for_pygobject(dict, G_TYPE_CONTENT_RESOLVER, type)) return false; } diff --git a/plugins/pychrysalide/analysis/module.c b/plugins/pychrysalide/analysis/module.c index 9632956..6b8e441 100644 --- a/plugins/pychrysalide/analysis/module.c +++ b/plugins/pychrysalide/analysis/module.c @@ -41,6 +41,7 @@ #include "contents/module.h" #include "db/module.h" #include "disass/module.h" +#include "scan/module.h" #include "storage/module.h" #include "types/module.h" #include "../helpers.h" @@ -86,6 +87,7 @@ bool add_analysis_module(PyObject *super) if (result) result = add_analysis_contents_module(module); if (result) result = add_analysis_db_module(module); if (result) result = add_analysis_disass_module(module); + if (result) result = add_analysis_scan_module(module); if (result) result = add_analysis_storage_module(module); if (result) result = add_analysis_types_module(module); @@ -131,6 +133,7 @@ bool populate_analysis_module(void) if (result) result = populate_analysis_contents_module(); if (result) result = populate_analysis_db_module(); if (result) result = populate_analysis_disass_module(); + if (result) result = populate_analysis_scan_module(); if (result) result = populate_analysis_storage_module(); if (result) result = populate_analysis_types_module(); diff --git a/plugins/pychrysalide/analysis/project.c b/plugins/pychrysalide/analysis/project.c index e66119c..b00259a 100644 --- a/plugins/pychrysalide/analysis/project.c +++ b/plugins/pychrysalide/analysis/project.c @@ -402,7 +402,7 @@ bool ensure_python_study_project_is_registered(void) dict = PyModule_GetDict(module); - if (!register_class_for_pygobject(dict, G_TYPE_STUDY_PROJECT, type, &PyGObject_Type)) + if (!register_class_for_pygobject(dict, G_TYPE_STUDY_PROJECT, type)) return false; } diff --git a/plugins/pychrysalide/analysis/routine.c b/plugins/pychrysalide/analysis/routine.c index e33ca90..535ba84 100644 --- a/plugins/pychrysalide/analysis/routine.c +++ b/plugins/pychrysalide/analysis/routine.c @@ -757,7 +757,7 @@ bool ensure_python_binary_routine_is_registered(void) if (!ensure_python_binary_symbol_is_registered()) return false; - if (!register_class_for_pygobject(dict, G_TYPE_BIN_ROUTINE, type, get_python_binary_symbol_type())) + if (!register_class_for_pygobject(dict, G_TYPE_BIN_ROUTINE, type)) return false; } diff --git a/plugins/pychrysalide/analysis/scan/Makefile.am b/plugins/pychrysalide/analysis/scan/Makefile.am new file mode 100644 index 0000000..8c9fb77 --- /dev/null +++ b/plugins/pychrysalide/analysis/scan/Makefile.am @@ -0,0 +1,28 @@ + +noinst_LTLIBRARIES = libpychrysaanalysisscan.la + +libpychrysaanalysisscan_la_SOURCES = \ + constants.h constants.c \ + context.h context.c \ + core.h core.c \ + expr.h expr.c \ + item.h item.c \ + module.h module.c \ + options.h options.c \ + scanner.h scanner.c \ + space.h space.c + +libpychrysaanalysisscan_la_LIBADD = \ + exprs/libpychrysaanalysisscanexprs.la \ + patterns/libpychrysaanalysisscanpatterns.la + +libpychrysaanalysisscan_la_CFLAGS = $(LIBPYTHON_INTERPRETER_CFLAGS) $(LIBPYGOBJECT_CFLAGS) $(TOOLKIT_CFLAGS) \ + -I$(top_srcdir)/src -DNO_IMPORT_PYGOBJECT + + +devdir = $(includedir)/chrysalide/$(subdir) + +dev_HEADERS = $(libpychrysaanalysisscan_la_SOURCES:%c=) + + +SUBDIRS = exprs patterns diff --git a/plugins/pychrysalide/analysis/scan/constants.c b/plugins/pychrysalide/analysis/scan/constants.c new file mode 100644 index 0000000..d030df2 --- /dev/null +++ b/plugins/pychrysalide/analysis/scan/constants.c @@ -0,0 +1,128 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * constants.c - ajout des constantes de base pour les types + * + * Copyright (C) 2020 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +#include "constants.h" + + +#include <analysis/scan/expr.h> + + +#include "../../helpers.h" + + + +/****************************************************************************** +* * +* Paramètres : type = type dont le dictionnaire est à compléter. * +* * +* Description : Définit les constantes relatives aux expressions de scan. * +* * +* Retour : true en cas de succès de l'opération, false sinon. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool define_expression_value_type_constants(PyTypeObject *type) +{ + bool result; /* Bilan à retourner */ + PyObject *values; /* Groupe de valeurs à établir */ + + values = PyDict_New(); + + result = add_const_to_group(values, "PENDING", SRS_PENDING); + if (result) result = add_const_to_group(values, "REDUCED", SRS_REDUCED); + if (result) result = add_const_to_group(values, "WAIT_FOR_SCAN", SRS_WAIT_FOR_SCAN); + if (result) result = add_const_to_group(values, "UNRESOLVABLE", SRS_UNRESOLVABLE); + + if (!result) + { + Py_DECREF(values); + goto exit; + } + + result = attach_constants_group_to_type(type, false, "ScanReductionState", values, + "State of a scanexpression during the reduction process."); + + 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 ScanReductionState. * +* * +* Retour : Bilan de l'opération, voire indications supplémentaires. * +* * +* Remarques : - * +* * +******************************************************************************/ + +int convert_to_scan_reduction_state(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 ScanReductionState"); + break; + + case 1: + value = PyLong_AsUnsignedLong(arg); + + if (value > SRS_UNRESOLVABLE) + { + PyErr_SetString(PyExc_TypeError, "invalid value for ScanReductionState"); + result = 0; + } + + else + *((ScanReductionState *)dst) = value; + + break; + + default: + assert(false); + break; + + } + + return result; + +} diff --git a/plugins/pychrysalide/analysis/scan/constants.h b/plugins/pychrysalide/analysis/scan/constants.h new file mode 100644 index 0000000..aa6c571 --- /dev/null +++ b/plugins/pychrysalide/analysis/scan/constants.h @@ -0,0 +1,42 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * constants.h - prototypes pour l'ajout des constantes de base pour les types + * + * Copyright (C) 2020 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +#ifndef _PLUGINS_PYCHRYSALIDE_ANALYSIS_TYPES_CONSTANTS_H +#define _PLUGINS_PYCHRYSALIDE_ANALYSIS_TYPES_CONSTANTS_H + + +#include <Python.h> +#include <stdbool.h> + + + +/* Définit les constantes relatives aux expressions de scan. */ +bool define_expression_value_type_constants(PyTypeObject *); + +/* Tente de convertir en constante ScanReductionState. */ +int convert_to_scan_reduction_state(PyObject *, void *); + + + +#endif /* _PLUGINS_PYCHRYSALIDE_ANALYSIS_TYPES_CONSTANTS_H */ diff --git a/plugins/pychrysalide/analysis/scan/context.c b/plugins/pychrysalide/analysis/scan/context.c new file mode 100644 index 0000000..9becaf7 --- /dev/null +++ b/plugins/pychrysalide/analysis/scan/context.c @@ -0,0 +1,432 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * context.c - équivalent Python du fichier "analysis/scan/context.c" + * + * Copyright (C) 2022 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +#include "context.h" + + +#include <pygobject.h> + + +#include <i18n.h> +#include <analysis/content.h> +#include <analysis/scan/context-int.h> +#include <analysis/scan/expr.h> + +#include "expr.h" +#include "../content.h" +#include "../../access.h" +#include "../../helpers.h" + + + +CREATE_DYN_CONSTRUCTOR(scan_context, G_TYPE_SCAN_CONTEXT); + +/* Initialise une instance sur la base du dérivé de GObject. */ +static int py_scan_context_init(PyObject *, PyObject *, PyObject *); + +/* Note que la phase d'analyse de contenu est terminée. */ +static PyObject *py_scan_context_mark_scan_as_done(PyObject *, PyObject *); + +/* Indique si une correspondance globale a pu être établie. */ +static PyObject *py_scan_context_has_match_for_rule(PyObject *, PyObject *); + +/* Fournit une référence au contenu principal analysé. */ +static PyObject *py_scan_context_get_content(PyObject *, void *); + +/* Définit le contenu principal à analyser. */ +static int py_scan_context_set_content(PyObject *, PyObject *, void *); + +/* Indique si la phase d'analyse de contenu est terminée. */ +static PyObject *py_scan_context_is_scan_done(PyObject *, void *); + + + +/****************************************************************************** +* * +* Paramètres : self = objet à initialiser (théoriquement). * +* args = arguments fournis à l'appel. * +* kwds = arguments de type key=val fournis. * +* * +* Description : Initialise une instance sur la base du dérivé de GObject. * +* * +* Retour : 0. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static int py_scan_context_init(PyObject *self, PyObject *args, PyObject *kwds) +{ + int ret; /* Bilan de lecture des args. */ + +#define SCAN_CONTEXT_DOC \ + "A ScanContext object tracks results of a run analysis process" \ + " against binary contents.\n" \ + "\n" \ + "Instances can be created using the following constructor:\n" \ + "\n" \ + " ScanContext()" + + /* Récupération des paramètres */ + + ret = PyArg_ParseTuple(args, ""); + if (!ret) return -1; + + /* Initialisation d'un objet GLib */ + + ret = forward_pygobjet_init(self); + if (ret == -1) return -1; + + return 0; + +} + + +/****************************************************************************** +* * +* Paramètres : self = classe représentant un format. * +* args = arguments fournis à l'appel. * +* * +* Description : Note que la phase d'analyse de contenu est terminée. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static PyObject *py_scan_context_mark_scan_as_done(PyObject *self, PyObject *args) +{ + PyObject *result; /* Contexte de suivi à renvoyer*/ + GScanContext *context; /* Contexte de suivi d'analyse */ + +#define SCAN_CONTEXT_MARK_SCAN_AS_DONE_METHOD PYTHON_METHOD_DEF \ +( \ + mark_scan_as_done, "$self", \ + METH_NOARGS, py_scan_context, \ + "Note that the analysis operations are finished." \ +) + + context = G_SCAN_CONTEXT(pygobject_get(self)); + + g_scan_context_mark_scan_as_done(context); + + result = Py_None; + Py_INCREF(result); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : self = classe représentant un format. * +* args = arguments fournis à l'appel. * +* * +* Description : Indique si une correspondance globale a pu être établie. * +* * +* Retour : Bilan final d'une analyse (False par défaut). * +* * +* Remarques : - * +* * +******************************************************************************/ + +static PyObject *py_scan_context_has_match_for_rule(PyObject *self, PyObject *args) +{ + PyObject *result; /* Contexte de suivi à renvoyer*/ + const char *name; /* Désignation de règle */ + int ret; /* Bilan de lecture des args. */ + GScanContext *context; /* Contexte de suivi d'analyse */ + bool matched; /* Bilan d'analyse à renvoyer */ + +#define SCAN_CONTEXT_HAS_MATCH_FOR_RULE_METHOD PYTHON_METHOD_DEF \ +( \ + has_match_for_rule, "$self, name, /", \ + METH_VARARGS, py_scan_context, \ + "Provide the match status for a given scan rule.\n" \ + "\n" \ + "The *name* argument points to the registered rule to query.\n" \ + "\n" \ + "The method returns the scan final status as a boolean: *True*" \ + " in case of match, *False* otherwise." \ +) + + ret = PyArg_ParseTuple(args, "s", &name); + if (!ret) return NULL; + + context = G_SCAN_CONTEXT(pygobject_get(self)); + + matched = g_scan_context_has_match_for_rule(context, name); + + result = matched ? Py_True : Py_False; + Py_INCREF(result); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : self = classe représentant une routine binaire. * +* closure = adresse non utilisée ici. * +* * +* Description : Fournit une référence au contenu principal analysé. * +* * +* Retour : Content binaire associé au context. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static PyObject *py_scan_context_get_content(PyObject *self, void *closure) +{ + PyObject *result; /* Eléments à retourner */ + GScanContext *context; /* Version native */ + GBinContent *content; /* Contenu binaire à référencer*/ + +#define SCAN_CONTEXT_CONTENT_ATTRIB PYTHON_GETSET_DEF_FULL \ +( \ + content, py_scan_context, \ + "Link to the scanned binary content.\n" \ + "\n" \ + "The result is a pychrysalide.analysis.BinContent for" \ + " fully initialized context." \ +) + + context = G_SCAN_CONTEXT(pygobject_get(self)); + content = g_scan_context_get_content(context); + + result = pygobject_new(G_OBJECT(content)); + + g_object_unref(G_OBJECT(content)); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : self = objet Python concerné par l'appel. * +* value = valeur fournie à intégrer ou prendre en compte. * +* closure = non utilisé ici. * +* * +* Description : Définit le contenu principal à analyser. * +* * +* Retour : Content binaire associé au context. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static int py_scan_context_set_content(PyObject *self, PyObject *value, void *closure) +{ + GScanContext *context; /* Elément à consulter */ + int ret; /* Bilan de lecture des args. */ + GBinContent *content; /* Contenu binaire à référencer*/ + + ret = PyObject_IsInstance(value, (PyObject *)get_python_binary_content_type()); + if (!ret) return -1; + + context = G_SCAN_CONTEXT(pygobject_get(self)); + content = G_BIN_CONTENT(pygobject_get(value)); + + // FIXME g_scan_context_set_content(context, content); + + return 0; + +} + + +/****************************************************************************** +* * +* Paramètres : self = objet Python concerné par l'appel. * +* closure = non utilisé ici. * +* * +* Description : Indique si la phase d'analyse de contenu est terminée. * +* * +* Retour : True si la phase de scan est terminée, False sinon. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static PyObject *py_scan_context_is_scan_done(PyObject *self, void *closure) +{ + PyObject *result; /* Instance Python à retourner */ + GScanContext *context; /* Contexte de suivi d'analyse */ + bool status; /* Bilan de consultation */ + +#define SCAN_CONTEXT_IS_SCAN_DONE_ATTRIB PYTHON_IS_DEF_FULL \ +( \ + scan_done, py_scan_context, \ + "Tell if the analysis operations are finished.\n" \ + "\n" \ + "The result is a boolean: *True* if the scan is marked as" \ + " done, *False* otherwise." \ +) + + context = G_SCAN_CONTEXT(pygobject_get(self)); + + status = g_scan_context_is_scan_done(context); + + result = status ? Py_True : Py_False; + 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_scan_context_type(void) +{ + static PyMethodDef py_scan_context_methods[] = { + SCAN_CONTEXT_MARK_SCAN_AS_DONE_METHOD, + SCAN_CONTEXT_HAS_MATCH_FOR_RULE_METHOD, + { NULL } + }; + + static PyGetSetDef py_scan_context_getseters[] = { + SCAN_CONTEXT_CONTENT_ATTRIB, + SCAN_CONTEXT_IS_SCAN_DONE_ATTRIB, + { NULL } + }; + + static PyTypeObject py_scan_context_type = { + + PyVarObject_HEAD_INIT(NULL, 0) + + .tp_name = "pychrysalide.analysis.scan.ScanContext", + .tp_basicsize = sizeof(PyGObject), + + .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, + + .tp_doc = SCAN_CONTEXT_DOC, + + .tp_methods = py_scan_context_methods, + .tp_getset = py_scan_context_getseters, + + .tp_init = py_scan_context_init, + .tp_new = py_scan_context_new, + + }; + + return &py_scan_context_type; + +} + + +/****************************************************************************** +* * +* Paramètres : - * +* * +* Description : Prend en charge l'objet 'pychrysalide.....scan.ScanContext. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool ensure_python_scan_context_is_registered(void) +{ + PyTypeObject *type; /* Type Python 'ScanContext' */ + PyObject *module; /* Module à recompléter */ + PyObject *dict; /* Dictionnaire du module */ + + type = get_python_scan_context_type(); + + if (!PyType_HasFeature(type, Py_TPFLAGS_READY)) + { + module = get_access_to_python_module("pychrysalide.analysis.scan"); + + dict = PyModule_GetDict(module); + + if (!register_class_for_pygobject(dict, G_TYPE_SCAN_CONTEXT, type)) + 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 contexte de suivi d'analyse. * +* * +* Retour : Bilan de l'opération, voire indications supplémentaires. * +* * +* Remarques : - * +* * +******************************************************************************/ + +int convert_to_scan_context(PyObject *arg, void *dst) +{ + int result; /* Bilan à retourner */ + + result = PyObject_IsInstance(arg, (PyObject *)get_python_scan_context_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 scan context"); + break; + + case 1: + *((GScanContext **)dst) = G_SCAN_CONTEXT(pygobject_get(arg)); + break; + + default: + assert(false); + break; + + } + + return result; + +} diff --git a/plugins/pychrysalide/analysis/scan/context.h b/plugins/pychrysalide/analysis/scan/context.h new file mode 100644 index 0000000..477205b --- /dev/null +++ b/plugins/pychrysalide/analysis/scan/context.h @@ -0,0 +1,45 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * context.h - prototypes pour l'équivalent Python du fichier "analysis/scan/context.h" + * + * Copyright (C) 2022 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +#ifndef _PLUGINS_PYCHRYSALIDE_ANALYSIS_SCAN_CONTEXT_H +#define _PLUGINS_PYCHRYSALIDE_ANALYSIS_SCAN_CONTEXT_H + + +#include <Python.h> +#include <stdbool.h> + + + +/* Fournit un accès à une définition de type à diffuser. */ +PyTypeObject *get_python_scan_context_type(void); + +/* Prend en charge l'objet 'pychrysalide.analysis.scan.ScanContext'. */ +bool ensure_python_scan_context_is_registered(void); + +/* Tente de convertir en contexte de suivi d'analyse. */ +int convert_to_scan_context(PyObject *, void *); + + + +#endif /* _PLUGINS_PYCHRYSALIDE_ANALYSIS_SCAN_CONTEXT_H */ diff --git a/plugins/pychrysalide/analysis/scan/core.c b/plugins/pychrysalide/analysis/scan/core.c new file mode 100644 index 0000000..16df9a9 --- /dev/null +++ b/plugins/pychrysalide/analysis/scan/core.c @@ -0,0 +1,179 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * core.c - équivalent Python du fichier "analysis/scan/core.c" + * + * Copyright (C) 2023 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 "core.h" + + +#include <pygobject.h> + + +#include <analysis/scan/core.h> + + +#include "patterns/modifier.h" +#include "../../access.h" +#include "../../helpers.h" + + + +/* Inscrit un modificateur dans la liste des disponibles. */ +static PyObject *py_scan_register_token_modifier(PyObject *, PyObject *); + +/* Fournit le modificateur correspondant à un nom. */ +static PyObject *py_scan_find_token_modifiers_for_name(PyObject *, PyObject *); + + + +/****************************************************************************** +* * +* Paramètres : self = objet Python concerné par l'appel. * +* args = arguments fournis à l'appel. * +* * +* Description : Inscrit un modificateur dans la liste des disponibles. * +* * +* Retour : Bilan des enregistrements effectués : True si nouveauté. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static PyObject *py_scan_register_token_modifier(PyObject *self, PyObject *args) +{ + PyObject *result; /* Bilan à retourner */ + PyObject *instance; /* Instance Python fournie */ + GScanTokenModifier *modifier; /* Version native */ + int ret; /* Bilan de lecture des args. */ + bool status; /* Bilan d'un enregistrement */ + +#define SCAN_REGISTER_TOKEN_MODIFIER_METHOD PYTHON_METHOD_DEF \ +( \ + register_token_modifier, "inst, /", \ + METH_VARARGS, py_scan, \ + "Register a token modifier for byte patterns to scan.\n" \ + "\n" \ + "This instance will be used as singleton and has to be a" \ + " subclass of pychrysalide.analysis.scan.patterns.TokenModifier." \ +) + + ret = PyArg_ParseTuple(args, "O!", get_python_scan_token_modifier_type(), &instance); + if (!ret) return NULL; + + modifier = G_SCAN_TOKEN_MODIFIER(pygobject_get(instance)); + + status = register_scan_token_modifier(modifier); + + result = status ? Py_True : Py_False; + Py_INCREF(result); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : self = objet Python concerné par l'appel. * +* args = arguments fournis à l'appel. * +* * +* Description : Fournit le modificateur correspondant à un nom. * +* * +* Retour : Instance du modificateur identifié ou None. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static PyObject *py_scan_find_token_modifiers_for_name(PyObject *self, PyObject *args) +{ + PyObject *result; /* Bilan à retourner */ + sized_string_t name; /* Nom d'appel à rechercher */ + Py_ssize_t len; /* Taille de ce nom */ + int ret; /* Bilan de lecture des args. */ + GScanTokenModifier *modifier; /* Instance mise en place */ + +#define SCAN_FIND_TOKEN_MODIFIERS_FOR_NAME_METHOD PYTHON_METHOD_DEF \ +( \ + find_token_modifiers_for_name, "name, /", \ + METH_VARARGS, py_scan, \ + "Provide the registered instance of a pattern modifier linked" \ + " to a given *name* provided as a key string.\n" \ + "\n" \ + "The returned instance is an object inherited from" \ + " pychrysalide.analysis.scan.patterns.TokenModifier or *None*" \ + " if no instance was found for the provided name." \ +) + + ret = PyArg_ParseTuple(args, "s#", &name.static_data, &len); + if (!ret) return NULL; + + name.len = len; + + modifier = find_scan_token_modifiers_for_name(&name); + + if (modifier != NULL) + { + result = pygobject_new(G_OBJECT(modifier)); + g_object_unref(G_OBJECT(modifier)); + } + else + { + result = Py_None; + Py_INCREF(result); + } + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : - * +* * +* Description : Définit une extension du module 'scan' à compléter. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool populate_scan_module_with_core_methods(void) +{ + bool result; /* Bilan à retourner */ + PyObject *module; /* Module à recompléter */ + + static PyMethodDef py_core_methods[] = { + SCAN_REGISTER_TOKEN_MODIFIER_METHOD, + SCAN_FIND_TOKEN_MODIFIERS_FOR_NAME_METHOD, + { NULL } + }; + + module = get_access_to_python_module("pychrysalide.analysis.scan"); + + result = register_python_module_methods(module, py_core_methods); + + return result; + +} diff --git a/plugins/pychrysalide/analysis/scan/core.h b/plugins/pychrysalide/analysis/scan/core.h new file mode 100644 index 0000000..e283f91 --- /dev/null +++ b/plugins/pychrysalide/analysis/scan/core.h @@ -0,0 +1,39 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * core.h - prototypes pour l'équivalent Python du fichier "analysis/scan/core.h" + * + * Copyright (C) 2023 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_CORE_CORE_H +#define _PLUGINS_PYCHRYSALIDE_CORE_CORE_H + + +#include <Python.h> +#include <stdbool.h> + + + +/* Définit une extension du module 'scan' à compléter. */ +bool populate_scan_module_with_core_methods(void); + + + +#endif /* _PLUGINS_PYCHRYSALIDE_CORE_CORE_H */ diff --git a/plugins/pychrysalide/analysis/scan/expr.c b/plugins/pychrysalide/analysis/scan/expr.c new file mode 100644 index 0000000..2d8245a --- /dev/null +++ b/plugins/pychrysalide/analysis/scan/expr.c @@ -0,0 +1,393 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * expr.c - équivalent Python du fichier "analysis/scan/expr.c" + * + * Copyright (C) 2022 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +#include "expr.h" + + +#include <pygobject.h> + + +#include <i18n.h> +#include <analysis/content.h> +#include <analysis/scan/expr-int.h> +#include <plugins/pychrysalide/access.h> +#include <plugins/pychrysalide/helpers.h> +#include <plugins/pychrysalide/analysis/content.h> +#include <plugins/pychrysalide/glibext/comparison.h> + + +#include "constants.h" + + + +/* Initialise la classe générique des expressions d'évaluation. */ +static void py_scan_expression_init_gclass(GScanExpressionClass *, gpointer); + +CREATE_DYN_ABSTRACT_CONSTRUCTOR(scan_expression, G_TYPE_SCAN_EXPRESSION, py_scan_expression_init_gclass); + +/* Initialise une instance sur la base du dérivé de GObject. */ +static int py_scan_expression_init(PyObject *, PyObject *, PyObject *); + +/* Réalise une comparaison entre objets selon un critère précis. */ +static bool py_scan_expression_compare_rich_wrapper(const GScanExpression *, const GScanExpression *, RichCmpOperation, bool *); + +/* Indique l'état de réduction d'une expression. */ +static PyObject *py_scan_expression_get_state(PyObject *, void *); + + + +/****************************************************************************** +* * +* Paramètres : class = classe à initialiser. * +* unused = données non utilisées ici. * +* * +* Description : Initialise la classe générique des expressions d'évaluation. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void py_scan_expression_init_gclass(GScanExpressionClass *class, gpointer unused) +{ + class->cmp_rich = py_scan_expression_compare_rich_wrapper; + +} + + +/****************************************************************************** +* * +* Paramètres : self = objet à initialiser (théoriquement). * +* args = arguments fournis à l'appel. * +* kwds = arguments de type key=val fournis. * +* * +* Description : Initialise une instance sur la base du dérivé de GObject. * +* * +* Retour : 0. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static int py_scan_expression_init(PyObject *self, PyObject *args, PyObject *kwds) +{ + ScanReductionState state; /* Etat de réduction initial */ + int ret; /* Bilan de lecture des args. */ + GScanExpression *expr; /* Création GLib à transmettre */ + + static char *kwlist[] = { "state", NULL }; + +#define SCAN_EXPRESSION_DOC \ + "A ScanExpression is an abstract object which defines an expression"\ + " involved in data matching when running a scan.\n" \ + "\n" \ + "Calls to the *__init__* constructor of this abstract object expect"\ + " the following arguments as keyword parameters:\n" \ + "* *state*: initial state of reduction for the expression, as a" \ + " pychrysalide.analysis.scan.ScanExpression.ScanReductionState" \ + " value." \ + "\n" \ + "The following methods have to be defined for new classes:\n" \ + "* pychrysalide.analysis.scan.ScanExpression._cmp_rich().\n" + + /* Récupération des paramètres */ + + ret = PyArg_ParseTupleAndKeywords(args, kwds, "O&", kwlist, convert_to_scan_reduction_state, &state); + if (!ret) return -1; + + /* Initialisation d'un objet GLib */ + + ret = forward_pygobjet_init(self); + if (ret == -1) return -1; + + /* Eléments de base */ + + expr = G_SCAN_EXPRESSION(pygobject_get(self)); + + if (!g_scan_expression_create(expr, state)) + { + PyErr_SetString(PyExc_ValueError, _("Unable to create scan expression.")); + return -1; + } + + return 0; + +} + + +/****************************************************************************** +* * +* Paramètres : item = premier objet à cnsulter pour une comparaison. * +* other = second objet à cnsulter pour une comparaison. * +* op = opération de comparaison à réaliser. * +* status = bilan des opérations de comparaison. [OUT] * +* * +* Description : Réalise une comparaison entre objets selon un critère précis.* +* * +* Retour : true si la comparaison a pu être effectuée, false sinon. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static bool py_scan_expression_compare_rich_wrapper(const GScanExpression *item, const GScanExpression *other, RichCmpOperation op, bool *status) +{ + bool result; /* Etat à 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 SCAN_EXPRESSION_CMP_RICH_WRAPPER PYTHON_WRAPPER_DEF \ +( \ + _cmp_rich, "$self, other, op, /", \ + METH_VARARGS, \ + "Abstract method used to compare the expression against another" \ + " one.\n" \ + "\n" \ + "The second *other* instance is built from the same type as *self*."\ + " The *op* argument points to a" \ + " pychrysalide.glibext.ComparableItem.RichCmpOperation mode" \ + " describing the expected comparison.\n" \ + "\n" \ + "The result is a boolean status or *None* if the comparison" \ + " process is undefined." \ +) + + result = false; + + gstate = PyGILState_Ensure(); + + pyobj = pygobject_new(G_OBJECT(item)); + + if (has_python_method(pyobj, "_cmp_rich")) + { + args = PyTuple_New(2); + PyTuple_SetItem(args, 0, pygobject_new(G_OBJECT(other))); + PyTuple_SetItem(args, 1, cast_with_constants_group_from_type(get_python_comparable_item_type(), + "RichCmpOperation", op)); + + pyret = run_python_method(pyobj, "_cmp_rich", args); + + if (pyret != NULL) + { + ret = PyBool_Check(pyret); + + if (ret) + { + *status = (pyret == Py_True); + result = true; + } + + Py_DECREF(pyret); + + } + + Py_DECREF(args); + + } + + Py_DECREF(pyobj); + + PyGILState_Release(gstate); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : self = objet Python concerné par l'appel. * +* closure = non utilisé ici. * +* * +* Description : Indique l'état de réduction d'une expression. * +* * +* Retour : Etat courant associé à l'expression. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static PyObject *py_scan_expression_get_state(PyObject *self, void *closure) +{ + PyObject *result; /* Instance Python à retourner */ + GScanExpression *expr; /* Version GLib de l'opérande */ + ScanReductionState state; /* Etat courant de l'expression*/ + +#define SCAN_EXPRESSION_STATE_ATTRIB PYTHON_GET_DEF_FULL \ +( \ + state, py_scan_expression, \ + "Current state of the expression, relative to the reduction" \ + " process, as a" \ + " pychrysalide.analysis.scan.ScanExpression.ScanReductionState" \ + " value." \ +) + + expr = G_SCAN_EXPRESSION(pygobject_get(self)); + + state = g_scan_expression_get_state(expr); + + result = cast_with_constants_group_from_type(get_python_scan_expression_type(), "ScanReductionState", state); + + 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_scan_expression_type(void) +{ + static PyMethodDef py_scan_expression_methods[] = { + SCAN_EXPRESSION_CMP_RICH_WRAPPER, + { NULL } + }; + + static PyGetSetDef py_scan_expression_getseters[] = { + SCAN_EXPRESSION_STATE_ATTRIB, + { NULL } + }; + + static PyTypeObject py_scan_expression_type = { + + PyVarObject_HEAD_INIT(NULL, 0) + + .tp_name = "pychrysalide.analysis.scan.ScanExpression", + .tp_basicsize = sizeof(PyGObject), + + .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_IS_ABSTRACT | Py_TPFLAGS_BASETYPE, + + .tp_doc = SCAN_EXPRESSION_DOC, + + .tp_methods = py_scan_expression_methods, + .tp_getset = py_scan_expression_getseters, + + .tp_init = py_scan_expression_init, + .tp_new = py_scan_expression_new, + + }; + + return &py_scan_expression_type; + +} + + +/****************************************************************************** +* * +* Paramètres : - * +* * +* Description : Prend en charge l'objet 'pychrysalide...scan.ScanExpression'.* +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool ensure_python_scan_expression_is_registered(void) +{ + PyTypeObject *type; /* Type Python 'ScanExpression'*/ + PyObject *module; /* Module à recompléter */ + PyObject *dict; /* Dictionnaire du module */ + + type = get_python_scan_expression_type(); + + if (!PyType_HasFeature(type, Py_TPFLAGS_READY)) + { + module = get_access_to_python_module("pychrysalide.analysis.scan"); + + dict = PyModule_GetDict(module); + + if (!ensure_python_comparable_item_is_registered()) + return false; + + if (!register_class_for_pygobject(dict, G_TYPE_SCAN_EXPRESSION, type)) + return false; + + if (!define_expression_value_type_constants(type)) + 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 expression d'évaluation généraliste. * +* * +* Retour : Bilan de l'opération, voire indications supplémentaires. * +* * +* Remarques : - * +* * +******************************************************************************/ + +int convert_to_scan_expression(PyObject *arg, void *dst) +{ + int result; /* Bilan à retourner */ + + result = PyObject_IsInstance(arg, (PyObject *)get_python_scan_expression_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 match expression"); + break; + + case 1: + *((GScanExpression **)dst) = G_SCAN_EXPRESSION(pygobject_get(arg)); + break; + + default: + assert(false); + break; + + } + + return result; + +} diff --git a/plugins/pychrysalide/analysis/scan/expr.h b/plugins/pychrysalide/analysis/scan/expr.h new file mode 100644 index 0000000..42f5350 --- /dev/null +++ b/plugins/pychrysalide/analysis/scan/expr.h @@ -0,0 +1,45 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * expr.h - prototypes pour l'équivalent Python du fichier "analysis/scan/expr.h" + * + * Copyright (C) 2022 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +#ifndef _PLUGINS_PYCHRYSALIDE_ANALYSIS_SCAN_EXPR_H +#define _PLUGINS_PYCHRYSALIDE_ANALYSIS_SCAN_EXPR_H + + +#include <Python.h> +#include <stdbool.h> + + + +/* Fournit un accès à une définition de type à diffuser. */ +PyTypeObject *get_python_scan_expression_type(void); + +/* Prend en charge l'objet 'pychrysalide.analysis.scan.ScanExpression'. */ +bool ensure_python_scan_expression_is_registered(void); + +/* Tente de convertir en expression d'évaluation généraliste. */ +int convert_to_scan_expression(PyObject *, void *); + + + +#endif /* _PLUGINS_PYCHRYSALIDE_ANALYSIS_SCAN_EXPR_H */ diff --git a/plugins/pychrysalide/analysis/scan/exprs/Makefile.am b/plugins/pychrysalide/analysis/scan/exprs/Makefile.am new file mode 100644 index 0000000..e40d4de --- /dev/null +++ b/plugins/pychrysalide/analysis/scan/exprs/Makefile.am @@ -0,0 +1,15 @@ + +noinst_LTLIBRARIES = libpychrysaanalysisscanexprs.la + +libpychrysaanalysisscanexprs_la_SOURCES = \ + constants.h constants.c \ + literal.h literal.c \ + module.h module.c + +libpychrysaanalysisscanexprs_la_CFLAGS = $(LIBPYTHON_INTERPRETER_CFLAGS) $(LIBPYGOBJECT_CFLAGS) \ + $(TOOLKIT_CFLAGS) -I$(top_srcdir)/src -DNO_IMPORT_PYGOBJECT + + +devdir = $(includedir)/chrysalide/$(subdir) + +dev_HEADERS = $(libpychrysaanalysisscanexprs_la_SOURCES:%c=) diff --git a/plugins/pychrysalide/analysis/scan/exprs/constants.c b/plugins/pychrysalide/analysis/scan/exprs/constants.c new file mode 100644 index 0000000..b11ac4c --- /dev/null +++ b/plugins/pychrysalide/analysis/scan/exprs/constants.c @@ -0,0 +1,128 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * constants.c - ajout des constantes de base pour les expressions + * + * Copyright (C) 2023 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.h" + + +#include <analysis/scan/exprs/literal.h> + + +#include "../../../helpers.h" + + + +/****************************************************************************** +* * +* Paramètres : type = type dont le dictionnaire est à compléter. * +* * +* Description : Définit les constantes relatives aux expressions de scan. * +* * +* Retour : true en cas de succès de l'opération, false sinon. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool define_literal_expression_value_type_constants(PyTypeObject *type) +{ + bool result; /* Bilan à retourner */ + PyObject *values; /* Groupe de valeurs à établir */ + + values = PyDict_New(); + + result = add_const_to_group(values, "LVT_BOOLEAN", LVT_BOOLEAN); + if (result) result = add_const_to_group(values, "SIGNED_INTEGER", LVT_SIGNED_INTEGER); + if (result) result = add_const_to_group(values, "UNSIGNED_INTEGER", LVT_UNSIGNED_INTEGER); + if (result) result = add_const_to_group(values, "STRING", LVT_STRING); + + if (!result) + { + Py_DECREF(values); + goto exit; + } + + result = attach_constants_group_to_type(type, false, "LiteralValueType", values, + "Type of value carried by a literal scan expression."); + + 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 LiteralValueType. * +* * +* Retour : Bilan de l'opération, voire indications supplémentaires. * +* * +* Remarques : - * +* * +******************************************************************************/ + +int convert_to_literal_expression_value_type(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 LiteralValueType"); + break; + + case 1: + value = PyLong_AsUnsignedLong(arg); + + if (value > LVT_REG_EXPR) + { + PyErr_SetString(PyExc_TypeError, "invalid value for LiteralValueType"); + result = 0; + } + + else + *((LiteralValueType *)dst) = value; + + break; + + default: + assert(false); + break; + + } + + return result; + +} diff --git a/plugins/pychrysalide/analysis/scan/exprs/constants.h b/plugins/pychrysalide/analysis/scan/exprs/constants.h new file mode 100644 index 0000000..e5b8e8c --- /dev/null +++ b/plugins/pychrysalide/analysis/scan/exprs/constants.h @@ -0,0 +1,42 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * constants.h - prototypes pour l'ajout des constantes de base pour les expressions + * + * Copyright (C) 2023 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_ANALYSIS_SCAN_EXPRS_CONSTANTS_H +#define _PLUGINS_PYCHRYSALIDE_ANALYSIS_SCAN_EXPRS_CONSTANTS_H + + +#include <Python.h> +#include <stdbool.h> + + + +/* Définit les constantes relatives aux expressions litérales. */ +bool define_literal_expression_value_type_constants(PyTypeObject *); + +/* Tente de convertir en constante LiteralValueType. */ +int convert_to_literal_expression_value_type(PyObject *, void *); + + + +#endif /* _PLUGINS_PYCHRYSALIDE_ANALYSIS_SCAN_EXPRS_CONSTANTS_H */ diff --git a/plugins/pychrysalide/analysis/scan/exprs/literal.c b/plugins/pychrysalide/analysis/scan/exprs/literal.c new file mode 100644 index 0000000..d7ae002 --- /dev/null +++ b/plugins/pychrysalide/analysis/scan/exprs/literal.c @@ -0,0 +1,281 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * literal.c - équivalent Python du fichier "analysis/scan/exprs/literal.c" + * + * Copyright (C) 2023 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 "literal.h" + + +#include <pygobject.h> + + +#include <i18n.h> +#include <analysis/scan/exprs/literal-int.h> + + +#include "constants.h" +#include "../expr.h" +#include "../../../access.h" +#include "../../../helpers.h" + + + +CREATE_DYN_CONSTRUCTOR(scan_literal_expression, G_TYPE_SCAN_LITERAL_EXPRESSION); + +/* Initialise une instance sur la base du dérivé de GObject. */ +static int py_scan_literal_expression_init(PyObject *, PyObject *, PyObject *); + + + +/****************************************************************************** +* * +* Paramètres : self = objet à initialiser (théoriquement). * +* args = arguments fournis à l'appel. * +* kwds = arguments de type key=val fournis. * +* * +* Description : Initialise une instance sur la base du dérivé de GObject. * +* * +* Retour : 0. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static int py_scan_literal_expression_init(PyObject *self, PyObject *args, PyObject *kwds) +{ + PyObject *py_value; /* Valeur en version Python */ + int ret; /* Bilan de lecture des args. */ + LiteralValueType vtype; /* Valeur à porter */ + bool arg_boolean; /* Argument natif booléen */ + unsigned long long arg_uinteger; /* Argument natif entier */ + sized_string_t arg_string; /* Argument natif textuel */ + Py_ssize_t arg_str_length; /* Taille de ce texte */ + void *arg_ptr; /* Pointeur vers un argument */ + GScanLiteralExpression *expr; /* Création GLib à transmettre */ + +#define SCAN_LITERAL_EXPRESSION_DOC \ + "A ScanLiteralExpression object defines expression carrying" \ + " literal values available for scan match conditions.\n" \ + "\n" \ + "Instances can be created using one of the following" \ + " constructors:\n" \ + "\n" \ + " ScanLiteralExpression(value)" \ + "\n" \ + "\n" \ + "Where *value* is either a boolean, an integer or bytes." + + /* Récupération des paramètres */ + + ret = PyArg_ParseTuple(args, "O", &py_value); + if (!ret) return -1; + + if (PyBool_Check(py_value)) + { + vtype = LVT_BOOLEAN; + + arg_boolean = (py_value == Py_True); + arg_ptr = &arg_boolean; + + } + + else if (PyLong_Check(py_value)) + { + if (1 /* sign - TODO */) + ; + + vtype = LVT_UNSIGNED_INTEGER; + + arg_uinteger = PyLong_AsUnsignedLongLong(py_value); + arg_ptr = &arg_uinteger; + + } + + else if (PyBytes_Check(py_value)) + { + vtype = LVT_STRING; + + ret = PyBytes_AsStringAndSize(py_value, &arg_string.data, &arg_str_length); + if (ret == -1) return -1; + + arg_string.len = arg_str_length; + arg_ptr = &arg_string; + + } + + else + { + PyErr_SetString(PyExc_ValueError, _("Unsupported Python value for a literal scan expression.")); + return -1; + } + + /* Initialisation d'un objet GLib */ + + ret = forward_pygobjet_init(self); + if (ret == -1) return -1; + + /* Eléments de base */ + + expr = G_SCAN_LITERAL_EXPRESSION(pygobject_get(self)); + + if (!g_scan_literal_expression_create(expr, vtype, arg_ptr)) + { + PyErr_SetString(PyExc_ValueError, _("Unable to create literal expression.")); + return -1; + } + + return 0; + +} + + +/****************************************************************************** +* * +* Paramètres : - * +* * +* Description : Fournit un accès à une définition de type à diffuser. * +* * +* Retour : Définition d'objet pour Python. * +* * +* Remarques : - * +* * +******************************************************************************/ + +PyTypeObject *get_python_scan_literal_expression_type(void) +{ + static PyMethodDef py_scan_literal_expression_methods[] = { + { NULL } + }; + + static PyGetSetDef py_scan_literal_expression_getseters[] = { + { NULL } + }; + + static PyTypeObject py_scan_literal_expression_type = { + + PyVarObject_HEAD_INIT(NULL, 0) + + .tp_name = "pychrysalide.analysis.scan.exprs.ScanLiteralExpression", + .tp_basicsize = sizeof(PyGObject), + + .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, + + .tp_doc = SCAN_LITERAL_EXPRESSION_DOC, + + .tp_methods = py_scan_literal_expression_methods, + .tp_getset = py_scan_literal_expression_getseters, + + .tp_init = py_scan_literal_expression_init, + .tp_new = py_scan_literal_expression_new, + + }; + + return &py_scan_literal_expression_type; + +} + + +/****************************************************************************** +* * +* Paramètres : - * +* * +* Description : Prend en charge l'objet 'pychrysalide....PlainModifier'. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool ensure_python_scan_literal_expression_is_registered(void) +{ + PyTypeObject *type; /* Type Python 'PlainModifier' */ + PyObject *module; /* Module à recompléter */ + PyObject *dict; /* Dictionnaire du module */ + + type = get_python_scan_literal_expression_type(); + + if (!PyType_HasFeature(type, Py_TPFLAGS_READY)) + { + module = get_access_to_python_module("pychrysalide.analysis.scan.exprs"); + + dict = PyModule_GetDict(module); + + if (!ensure_python_scan_expression_is_registered()) + return false; + + if (!register_class_for_pygobject(dict, G_TYPE_SCAN_LITERAL_EXPRESSION, type)) + return false; + + if (!define_literal_expression_value_type_constants(type)) + 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 transmission d'octets à l'identique. * +* * +* Retour : Bilan de l'opération, voire indications supplémentaires. * +* * +* Remarques : - * +* * +******************************************************************************/ + +int convert_to_scan_literal_expression(PyObject *arg, void *dst) +{ + int result; /* Bilan à retourner */ + + result = PyObject_IsInstance(arg, (PyObject *)get_python_scan_literal_expression_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 scan literal expression"); + break; + + case 1: + *((GScanLiteralExpression **)dst) = G_SCAN_LITERAL_EXPRESSION(pygobject_get(arg)); + break; + + default: + assert(false); + break; + + } + + return result; + +} diff --git a/plugins/pychrysalide/analysis/scan/exprs/literal.h b/plugins/pychrysalide/analysis/scan/exprs/literal.h new file mode 100644 index 0000000..8e7ea70 --- /dev/null +++ b/plugins/pychrysalide/analysis/scan/exprs/literal.h @@ -0,0 +1,45 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * literal.h - équivalent Python du fichier "analysis/scan/exprs/literal.h" + * + * Copyright (C) 2023 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_ANALYSIS_SCAN_EXPRS_LITERAL_H +#define _PLUGINS_PYCHRYSALIDE_ANALYSIS_SCAN_EXPRS_LITERAL_H + + +#include <Python.h> +#include <stdbool.h> + + + +/* Fournit un accès à une définition de type à diffuser. */ +PyTypeObject *get_python_scan_literal_expression_type(void); + +/* Prend en charge l'objet 'pychrysalide.analysis.scan.exprs.ScanLiteralExpression'. */ +bool ensure_python_scan_literal_expression_is_registered(void); + +/* Tente de convertir en transmission d'octets à l'identique. */ +int convert_to_scan_literal_expression(PyObject *, void *); + + + +#endif /* _PLUGINS_PYCHRYSALIDE_ANALYSIS_SCAN_EXPRS_LITERAL_H */ diff --git a/plugins/pychrysalide/analysis/scan/exprs/module.c b/plugins/pychrysalide/analysis/scan/exprs/module.c new file mode 100644 index 0000000..4f38430 --- /dev/null +++ b/plugins/pychrysalide/analysis/scan/exprs/module.c @@ -0,0 +1,103 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * module.c - intégration du répertoire exprs en tant que module + * + * Copyright (C) 2023 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.h" + + +#include <assert.h> + + +#include "literal.h" +#include "../../../helpers.h" + + + +/****************************************************************************** +* * +* Paramètres : super = module dont la définition est à compléter. * +* * +* Description : Ajoute le module 'analysis....modifiers' à un module Python. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool add_analysis_scan_exprs_module(PyObject *super) +{ + bool result; /* Bilan à retourner */ + PyObject *module; /* Sous-module mis en place */ + +#define PYCHRYSALIDE_ANALYSIS_SCAN_EXPRS_MODULE_DOC \ + "This module provide expressions used to build a match condition." + + static PyModuleDef py_chrysalide_analysis_scan_exprs_module = { + + .m_base = PyModuleDef_HEAD_INIT, + + .m_name = "pychrysalide.analysis.scan.exprs", + .m_doc = PYCHRYSALIDE_ANALYSIS_SCAN_EXPRS_MODULE_DOC, + + .m_size = -1, + + }; + + module = build_python_module(super, &py_chrysalide_analysis_scan_exprs_module); + + result = (module != NULL); + + if (!result) + Py_XDECREF(module); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : - * +* * +* Description : Intègre les objets du module 'analysis...patterns.modifiers'.* +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool populate_analysis_scan_exprs_module(void) +{ + bool result; /* Bilan à retourner */ + + result = true; + + if (result) result = ensure_python_scan_literal_expression_is_registered(); + + assert(result); + + return result; + +} diff --git a/plugins/pychrysalide/analysis/scan/exprs/module.h b/plugins/pychrysalide/analysis/scan/exprs/module.h new file mode 100644 index 0000000..ee4b8ab --- /dev/null +++ b/plugins/pychrysalide/analysis/scan/exprs/module.h @@ -0,0 +1,42 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * module.h - prototypes pour l'intégration du répertoire exprs en tant que module + * + * Copyright (C) 2023 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_ANALYSIS_SCAN_EXPRS_MODULE_H +#define _PLUGINS_PYCHRYSALIDE_ANALYSIS_SCAN_EXPRS_MODULE_H + + +#include <Python.h> +#include <stdbool.h> + + + +/* Ajoute le module 'analysis.scan.exprs' à un module Python. */ +bool add_analysis_scan_exprs_module(PyObject *); + +/* Intègre les objets du module 'analysis.scan.exprs'. */ +bool populate_analysis_scan_exprs_module(void); + + + +#endif /* _PLUGINS_PYCHRYSALIDE_ANALYSIS_SCAN_EXPRS_MODULE_H */ diff --git a/plugins/pychrysalide/analysis/scan/item.c b/plugins/pychrysalide/analysis/scan/item.c new file mode 100644 index 0000000..014ae24 --- /dev/null +++ b/plugins/pychrysalide/analysis/scan/item.c @@ -0,0 +1,740 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * item.c - équivalent Python du fichier "analysis/scan/item.c" + * + * Copyright (C) 2022 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +#include "item.h" + + +#include <pygobject.h> + + +#include <i18n.h> +#include <analysis/scan/item-int.h> +#include <plugins/pychrysalide/access.h> +#include <plugins/pychrysalide/helpers.h> + + +#include "context.h" + + + +/* ------------------------ GLUE POUR CREATION DEPUIS PYTHON ------------------------ */ + + +/* Initialise la classe des éléments appelables enregistrés. */ +static void py_scan_registered_item_init_gclass(GScanRegisteredItemClass *, gpointer); + +CREATE_DYN_ABSTRACT_CONSTRUCTOR(scan_registered_item, G_TYPE_SCAN_REGISTERED_ITEM, py_scan_registered_item_init_gclass); + +/* Initialise une instance sur la base du dérivé de GObject. */ +static int py_scan_registered_item_init(PyObject *, PyObject *, PyObject *); + +/* Indique le nom associé à une expression d'évaluation. */ +static char *py_scan_registered_item_get_name_wrapper(const GScanRegisteredItem *); + +/* Lance une résolution d'élément à solliciter. */ +static bool py_scan_registered_item_resolve_wrapper(GScanRegisteredItem *, const char *, GScanContext *, GScanScope *, GScanRegisteredItem **); + +/* Réduit une expression à une forme plus simple. */ +static bool py_scan_registered_item_reduce_wrapper(GScanRegisteredItem *, GScanContext *, GScanScope *, GScanExpression **); + +/* Effectue un appel à une fonction enregistrée. */ +static bool py_scan_registered_item_run_call_wrapper(GScanRegisteredItem *, GScanExpression **, size_t, GScanContext *, GScanScope *, GObject **); + + + +/* ------------------------- CONNEXION AVEC L'API DE PYTHON ------------------------- */ + + +/* Lance une résolution d'élément à appeler. */ +static PyObject *py_scan_registered_item_resolve(PyObject *, PyObject *); + +/* Fournit le désignation associée à un composant nommé. */ +static PyObject *py_scan_registered_item_get_name(PyObject *, void *); + + + +/* ---------------------------------------------------------------------------------- */ +/* GLUE POUR CREATION DEPUIS PYTHON */ +/* ---------------------------------------------------------------------------------- */ + + +/****************************************************************************** +* * +* Paramètres : class = classe à initialiser. * +* unused = données non utilisées ici. * +* * +* Description : Initialise la classe des éléments appelables enregistrés. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void py_scan_registered_item_init_gclass(GScanRegisteredItemClass *class, gpointer unused) +{ + class->get_name = py_scan_registered_item_get_name_wrapper; + class->resolve = py_scan_registered_item_resolve_wrapper; + class->reduce = py_scan_registered_item_reduce_wrapper; + class->run_call = py_scan_registered_item_run_call_wrapper; + +} + + +/****************************************************************************** +* * +* Paramètres : self = objet à initialiser (théoriquement). * +* args = arguments fournis à l'appel. * +* kwds = arguments de type key=val fournis. * +* * +* Description : Initialise une instance sur la base du dérivé de GObject. * +* * +* Retour : 0. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static int py_scan_registered_item_init(PyObject *self, PyObject *args, PyObject *kwds) +{ + int ret; /* Bilan de lecture des args. */ + +#define SCAN_REGISTERED_ITEM_DOC \ + "The *RegisteredItem* class is an abstract definition which is" \ + " the base for all keywords involved in a match condition" \ + " expression.\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.analysis.scan.RegisteredItem._resolve();\n" \ + "* pychrysalide.analysis.scan.RegisteredItem._reduce();\n" \ + "* pychrysalide.analysis.scan.RegisteredItem._call().\n" \ + "\n" \ + "One item has to be defined as class attributes in the final" \ + " class:\n" \ + "* pychrysalide.analysis.scan.RegisteredItem._name.\n" + + /* Initialisation d'un objet GLib */ + + ret = forward_pygobjet_init(self); + if (ret == -1) return -1; + + return 0; + +} + + +/****************************************************************************** +* * +* Paramètres : item = élément d'appel à consulter. * +* * +* Description : Indique le nom associé à une expression d'évaluation. * +* * +* Retour : Désignation humaine de l'expression d'évaluation. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static char *py_scan_registered_item_get_name_wrapper(const GScanRegisteredItem *item) +{ + char *result; /* Désignation à retourner */ + PyGILState_STATE gstate; /* Sauvegarde d'environnement */ + PyObject *pyobj; /* Objet Python concerné */ + PyObject *pyname; /* Nom en objet Python */ + int ret; /* Bilan d'une conversion */ + +#define SCAN_REGISTERED_ITEM_NAME_ATTRIB_WRAPPER PYTHON_GETTER_WRAPPER_DEF \ +( \ + _name, \ + "Provide the keyword of the expression item to be evaluated.\n" \ + "\n" \ + "The result has to be a string." \ +) + + result = NULL; + + gstate = PyGILState_Ensure(); + + pyobj = pygobject_new(G_OBJECT(item)); + + if (PyObject_HasAttrString(pyobj, "_name")) + { + pyname = PyObject_GetAttrString(pyobj, "_name"); + + if (pyname != NULL) + { + ret = PyUnicode_Check(pyname); + + if (ret) + result = strdup(PyUnicode_AsUTF8(pyname)); + + Py_DECREF(pyname); + + } + + } + + Py_DECREF(pyobj); + + PyGILState_Release(gstate); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : item = élément d'appel à consulter. * +* target = désignation de l'objet d'appel à identifier. * +* ctx = contexte de suivi de l'analyse courante. * +* scope = portée courante des variables locales. * +* out = zone d'enregistrement de la résolution opérée. [OUT]* +* * +* Description : Lance une résolution d'élément à solliciter. * +* * +* Retour : Bilan de l'opération : false en cas d'erreur irrécupérable. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static bool py_scan_registered_item_resolve_wrapper(GScanRegisteredItem *item, const char *target, GScanContext *ctx, GScanScope *scope, GScanRegisteredItem **out) +{ + bool result; /* Bilan à retourner */ + PyGILState_STATE gstate; /* Sauvegarde d'environnement */ + PyObject *pyobj; /* Objet Python concerné */ + PyObject *args; /* Arguments pour l'appel */ + PyObject *pyret; /* Bilan de consultation */ + GObject *gobj_ret; /* Bilan natif de consultation */ + +#define SCAN_REGISTERED_ITEM_RESOLVE_WRAPPER PYTHON_WRAPPER_DEF \ +( \ + _cmp_rich, "$self, target, ctx, scope, /", \ + METH_VARARGS, \ + "Abstract method used to resolve an item by name.\n" \ + "\n" \ + "The *target* argument provide the name of the searched item;" \ + " *ctx* is a pychrysalide.analysis.scan.ScanContext instance" \ + " providing information about the current state; *scope* is a" \ + " pychrysalide.analysis.scan.ScanScope offering a view on the" \ + " current namespace for variables.\n" \ + "\n" \ + "The result has to be a pychrysalide.analysis.scan.RegisteredItem" \ + " instance on success, or *None* in case of failure." \ +) + + result = false; + + gstate = PyGILState_Ensure(); + + pyobj = pygobject_new(G_OBJECT(item)); + + if (has_python_method(pyobj, "_resolve")) + { + args = PyTuple_New(3); + PyTuple_SetItem(args, 0, PyUnicode_FromString(target)); + PyTuple_SetItem(args, 1, pygobject_new(G_OBJECT(ctx))); + PyTuple_SetItem(args, 2, pygobject_new(G_OBJECT(scope))); + + pyret = run_python_method(pyobj, "_resolve", args); + + if (pyret != NULL) + { + gobj_ret = pygobject_get(pyret); + + if (G_IS_SCAN_REGISTERED_ITEM(gobj_ret)) + { + *out = G_SCAN_REGISTERED_ITEM(gobj_ret); + + g_object_ref(G_OBJECT(*out)); + result = true; + + } + + Py_DECREF(pyret); + + } + + Py_DECREF(args); + + } + + Py_DECREF(pyobj); + + PyGILState_Release(gstate); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : item = élément d'appel à consulter. * +* ctx = contexte de suivi de l'analyse courante. * +* scope = portée courante des variables locales. * +* out = zone d'enregistrement de la réduction opérée. [OUT] * +* * +* Description : Réduit une expression à une forme plus simple. * +* * +* Retour : Bilan de l'opération : false en cas d'erreur irrécupérable. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static bool py_scan_registered_item_reduce_wrapper(GScanRegisteredItem *item, GScanContext *ctx, GScanScope *scope, GScanExpression **out) +{ + bool result; /* Bilan à retourner */ + PyGILState_STATE gstate; /* Sauvegarde d'environnement */ + PyObject *pyobj; /* Objet Python concerné */ + PyObject *args; /* Arguments pour l'appel */ + PyObject *pyret; /* Bilan de consultation */ + GObject *gobj_ret; /* Bilan natif de consultation */ + +#define SCAN_REGISTERED_ITEM_REDUCE_WRAPPER PYTHON_WRAPPER_DEF \ +( \ + _cmp_rich, "$self, ctx, scope, /", \ + METH_VARARGS, \ + "Abstract method used to replace the item by an equivalent reduced" \ + " value.\n" \ + "\n" \ + "The *ctx* argument is a pychrysalide.analysis.scan.ScanContext" \ + " instance providing information about the current state; *scope*" \ + " is a pychrysalide.analysis.scan.ScanScope offering a view on the" \ + " current namespace for variables.\n" \ + "\n" \ + "The result has to be a pychrysalide.analysis.scan.ScanExpression" \ + " instance on success, or *None* in case of failure." \ +) + + result = false; + + gstate = PyGILState_Ensure(); + + pyobj = pygobject_new(G_OBJECT(item)); + + if (has_python_method(pyobj, "_reduce")) + { + args = PyTuple_New(2); + PyTuple_SetItem(args, 0, pygobject_new(G_OBJECT(ctx))); + PyTuple_SetItem(args, 1, pygobject_new(G_OBJECT(scope))); + + pyret = run_python_method(pyobj, "_reduce", args); + + if (pyret != NULL) + { + gobj_ret = pygobject_get(pyret); + + if (G_IS_SCAN_EXPRESSION(gobj_ret)) + { + *out = G_SCAN_EXPRESSION(gobj_ret); + + g_object_ref(G_OBJECT(*out)); + result = true; + + } + + Py_DECREF(pyret); + + } + + Py_DECREF(args); + + } + + Py_DECREF(pyobj); + + PyGILState_Release(gstate); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : item = élément d'appel à consulter. * +* args = liste d'éventuels arguments fournis. * +* count = taille de cette liste. * +* ctx = contexte de suivi de l'analyse courante. * +* scope = portée courante des variables locales. * +* out = zone d'enregistrement de la résolution opérée. [OUT] * +* * +* Description : Effectue un appel à une fonction enregistrée. * +* * +* Retour : Bilan de l'opération : false en cas d'erreur irrécupérable. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static bool py_scan_registered_item_run_call_wrapper(GScanRegisteredItem *item, GScanExpression **args, size_t count, GScanContext *ctx, GScanScope *scope, GObject **out) +{ + bool result; /* Bilan à retourner */ + PyGILState_STATE gstate; /* Sauvegarde d'environnement */ + PyObject *pyobj; /* Objet Python concerné */ + PyObject *sub_args; /* Sous-arguments pour l'appel */ + size_t i; /* Boucle de parcours */ + PyObject *py_args; /* Arguments pour l'appel */ + PyObject *pyret; /* Bilan de consultation */ + GObject *gobj_ret; /* Bilan natif de consultation */ + +#define SCAN_REGISTERED_ITEM_CALL_WRAPPER PYTHON_WRAPPER_DEF \ +( \ + _cmp_rich, "$self, args, ctx, scope, /", \ + METH_VARARGS, \ + "Abstract method used to replace the item and its arguments by an" \ + " equivalent reduced value.\n" \ + "\n" \ + "The *args* argument is a tuple of already reduced" \ + " pychrysalide.analysis.scan.ScanExpression objects; ctx* argument" \ + " is a pychrysalide.analysis.scan.ScanContext instance providing" \ + " information about the current state; *scope* is a" \ + " pychrysalide.analysis.scan.ScanScope offering a view on the" \ + " current namespace for variables.\n" \ + "\n" \ + "The result has to be a pychrysalide.analysis.scan.ScanExpression" \ + " instance on success, or *None* in case of failure." \ +) + + result = false; + + gstate = PyGILState_Ensure(); + + pyobj = pygobject_new(G_OBJECT(item)); + + if (has_python_method(pyobj, "_call")) + { + sub_args = PyTuple_New(count); + + for (i = 0; i < count; i++) + PyTuple_SetItem(sub_args, 1, pygobject_new(G_OBJECT(args[i]))); + + py_args = PyTuple_New(3); + PyTuple_SetItem(py_args, 0, sub_args); + PyTuple_SetItem(py_args, 1, pygobject_new(G_OBJECT(ctx))); + PyTuple_SetItem(py_args, 2, pygobject_new(G_OBJECT(scope))); + + pyret = run_python_method(pyobj, "_call", py_args); + + if (pyret != NULL) + { + gobj_ret = pygobject_get(pyret); + + if (G_IS_OBJECT(gobj_ret)) + { + *out = gobj_ret; + + g_object_ref(G_OBJECT(*out)); + result = true; + + } + + Py_DECREF(pyret); + + } + + Py_DECREF(py_args); + + } + + Py_DECREF(pyobj); + + PyGILState_Release(gstate); + + return result; + +} + + + +/* ---------------------------------------------------------------------------------- */ +/* CONNEXION AVEC L'API DE PYTHON */ +/* ---------------------------------------------------------------------------------- */ + + +/****************************************************************************** +* * +* Paramètres : self = élément d'appel à consulter. * +* args = arguments fournis pour l'opération. * +* * +* Description : Lance une résolution d'élément à appeler. * +* * +* Retour : Nouvel élément d'appel identifié ou None. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static PyObject *py_scan_registered_item_resolve(PyObject *self, PyObject *args) +{ + PyObject *result; /* Bilan à retourner */ + const char *target; /* Désignation de la cible */ + GScanContext *ctx; /* Contexte d'analyse */ + GScanScope *scope; /* Portée de variables locales */ + int ret; /* Bilan de lecture des args. */ + GScanRegisteredItem *item; /* Version native */ + bool status; /* Bilan d'exécution */ + GScanRegisteredItem *resolved; /* Elément trouvé */ + +#define SCAN_REGISTERED_ITEM_RESOLVE_METHOD PYTHON_METHOD_DEF \ +( \ + resolve, "$self, target, /, ctx=None, scope=None", \ + METH_VARARGS, py_scan_registered_item, \ + "Resolve a name into a scan item." \ + "\n" \ + "The *target* name is the only mandatory parameter and has to point"\ + " to only one item. The *ctx* argument points to an optional useful"\ + " storage for resolution lookup, as a" \ + " pychrysalide.analysis.scan.ScanContext instance. The *args* list" \ + " defines an optional list of arguments, as" \ + " pychrysalide.analysis.scan.ScanExpression instances, to use for" \ + " building the resolved item. The *final* flag states if the" \ + " scanning process is about to conclude or not." \ + "\n" \ + "The result is an object inheriting from" \ + " pychrysalide.analysis.scan.RegisteredItem or *None* if the" \ + " resolution operation failed." \ +) + + ctx = NULL; + scope = NULL; + + ret = PyArg_ParseTuple(args, "s|O&", &target, + convert_to_scan_context, &ctx); + if (!ret) return NULL; + + item = G_SCAN_REGISTERED_ITEM(pygobject_get(self)); + + status = g_scan_registered_item_resolve(item, target, ctx, scope, &resolved); + + if (!status) + { + result = NULL; + PyErr_Format(PyExc_RuntimeError, _("Unable to resolve any target from the item")); + } + else + { + if (resolved != NULL) + { + result = pygobject_new(G_OBJECT(resolved)); + g_object_unref(G_OBJECT(resolved)); + } + else + { + result = Py_None; + Py_INCREF(result); + } + } + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : self = classe représentant un composant nommé à manipuler.* +* closure = non utilisé ici. * +* * +* Description : Fournit le désignation associée à un composant nommé. * +* * +* Retour : Description courante. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static PyObject *py_scan_registered_item_get_name(PyObject *self, void *closure) +{ + PyObject *result; /* Décompte à retourner */ + GScanRegisteredItem *item; /* Version native */ + char *name; /* Désignation à convertir */ + +#define SCAN_REGISTERED_ITEM_NAME_ATTRIB PYTHON_GET_DEF_FULL \ +( \ + name, py_scan_registered_item, \ + "Name linked to the registered item.\n" \ + "\n" \ + "The result should be a string, or *None* for the root namespace." \ +) + + item = G_SCAN_REGISTERED_ITEM(pygobject_get(self)); + + name = g_scan_registered_item_get_name(item); + + if (name == NULL) + { + result = Py_None; + Py_INCREF(result); + } + else + { + result = PyUnicode_FromString(name); + free(name); + } + + 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_scan_registered_item_type(void) +{ + static PyMethodDef py_scan_registered_item_methods[] = { + SCAN_REGISTERED_ITEM_RESOLVE_WRAPPER, + SCAN_REGISTERED_ITEM_REDUCE_WRAPPER, + SCAN_REGISTERED_ITEM_CALL_WRAPPER, + SCAN_REGISTERED_ITEM_RESOLVE_METHOD, + { NULL } + }; + + static PyGetSetDef py_scan_registered_item_getseters[] = { + SCAN_REGISTERED_ITEM_NAME_ATTRIB_WRAPPER, + SCAN_REGISTERED_ITEM_NAME_ATTRIB, + { NULL } + }; + + static PyTypeObject py_scan_registered_item_type = { + + PyVarObject_HEAD_INIT(NULL, 0) + + .tp_name = "pychrysalide.analysis.scan.ScanRegisteredItem", + .tp_basicsize = sizeof(PyGObject), + + .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_IS_ABSTRACT | Py_TPFLAGS_BASETYPE, + + .tp_doc = SCAN_REGISTERED_ITEM_DOC, + + .tp_methods = py_scan_registered_item_methods, + .tp_getset = py_scan_registered_item_getseters, + + .tp_init = py_scan_registered_item_init, + .tp_new = py_scan_registered_item_new, + + }; + + return &py_scan_registered_item_type; + +} + + +/****************************************************************************** +* * +* Paramètres : - * +* * +* Description : Prend en charge l'objet 'pychrysalide...ScanRegisteredItem'. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool ensure_python_scan_registered_item_is_registered(void) +{ + PyTypeObject *type; /* Type 'ScanRegisteredItem' */ + PyObject *module; /* Module à recompléter */ + PyObject *dict; /* Dictionnaire du module */ + + type = get_python_scan_registered_item_type(); + + if (!PyType_HasFeature(type, Py_TPFLAGS_READY)) + { + module = get_access_to_python_module("pychrysalide.analysis.scan"); + + dict = PyModule_GetDict(module); + + if (!register_class_for_pygobject(dict, G_TYPE_SCAN_REGISTERED_ITEM, type)) + 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 expression d'évaluation généraliste. * +* * +* Retour : Bilan de l'opération, voire indications supplémentaires. * +* * +* Remarques : - * +* * +******************************************************************************/ + +int convert_to_scan_registered_item(PyObject *arg, void *dst) +{ + int result; /* Bilan à retourner */ + + result = PyObject_IsInstance(arg, (PyObject *)get_python_scan_registered_item_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 generic scan expression"); + break; + + case 1: + *((GScanRegisteredItem **)dst) = G_SCAN_REGISTERED_ITEM(pygobject_get(arg)); + break; + + default: + assert(false); + break; + + } + + return result; + +} diff --git a/plugins/pychrysalide/analysis/scan/item.h b/plugins/pychrysalide/analysis/scan/item.h new file mode 100644 index 0000000..773908c --- /dev/null +++ b/plugins/pychrysalide/analysis/scan/item.h @@ -0,0 +1,45 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * item.h - prototypes pour l'équivalent Python du fichier "analysis/scan/item.h" + * + * Copyright (C) 2022 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +#ifndef _PLUGINS_PYCHRYSALIDE_ANALYSIS_SCAN_ITEM_H +#define _PLUGINS_PYCHRYSALIDE_ANALYSIS_SCAN_ITEM_H + + +#include <Python.h> +#include <stdbool.h> + + + +/* Fournit un accès à une définition de type à diffuser. */ +PyTypeObject *get_python_scan_registered_item_type(void); + +/* Prend en charge l'objet 'pychrysalide.analysis.scan.ScanRegisteredItem'. */ +bool ensure_python_scan_registered_item_is_registered(void); + +/* Tente de convertir en expression d'évaluation généraliste. */ +int convert_to_scan_registered_item(PyObject *, void *); + + + +#endif /* _PLUGINS_PYCHRYSALIDE_ANALYSIS_SCAN_ITEM_H */ diff --git a/plugins/pychrysalide/analysis/scan/module.c b/plugins/pychrysalide/analysis/scan/module.c new file mode 100644 index 0000000..9ae0e52 --- /dev/null +++ b/plugins/pychrysalide/analysis/scan/module.c @@ -0,0 +1,125 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * module.c - intégration du répertoire scan en tant que module + * + * Copyright (C) 2022 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +#include "module.h" + + +#include <assert.h> + + +#include "context.h" +#include "core.h" +#include "expr.h" +#include "item.h" +#include "options.h" +#include "scanner.h" +#include "space.h" +#include "exprs/module.h" +#include "patterns/module.h" +#include "../../helpers.h" + + + +/****************************************************************************** +* * +* Paramètres : super = module dont la définition est à compléter. * +* * +* Description : Ajoute le module 'analysis.scan' à un module Python. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool add_analysis_scan_module(PyObject *super) +{ + bool result; /* Bilan à retourner */ + PyObject *module; /* Sous-module mis en place */ + +#define PYCHRYSALIDE_ANALYSIS_SCAN_MODULE_DOC \ + "This module provide all the features useful for scanning" \ + " binary contents." + + static PyModuleDef py_chrysalide_analysis_scan_module = { + + .m_base = PyModuleDef_HEAD_INIT, + + .m_name = "pychrysalide.analysis.scan", + .m_doc = PYCHRYSALIDE_ANALYSIS_SCAN_MODULE_DOC, + + .m_size = -1, + + }; + + module = build_python_module(super, &py_chrysalide_analysis_scan_module); + + result = (module != NULL); + + if (result) result = add_analysis_scan_exprs_module(module); + if (result) result = add_analysis_scan_patterns_module(module); + + if (!result) + Py_XDECREF(module); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : - * +* * +* Description : Intègre les objets du module 'analysis.scan'. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool populate_analysis_scan_module(void) +{ + bool result; /* Bilan à retourner */ + + result = true; + + if (result) result = ensure_python_content_scanner_is_registered(); + if (result) result = ensure_python_scan_context_is_registered(); + if (result) result = ensure_python_scan_expression_is_registered(); + if (result) result = ensure_python_scan_registered_item_is_registered(); + if (result) result = ensure_python_scan_options_is_registered(); + if (result) result = ensure_python_scan_namespace_is_registered(); + + if (result) result = populate_scan_module_with_core_methods(); + + if (result) result = populate_analysis_scan_exprs_module(); + if (result) result = populate_analysis_scan_patterns_module(); + + assert(result); + + return result; + +} diff --git a/plugins/pychrysalide/analysis/scan/module.h b/plugins/pychrysalide/analysis/scan/module.h new file mode 100644 index 0000000..a5e84b5 --- /dev/null +++ b/plugins/pychrysalide/analysis/scan/module.h @@ -0,0 +1,42 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * module.h - prototypes pour l'intégration du répertoire scan en tant que module + * + * Copyright (C) 2022 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +#ifndef _PLUGINS_PYCHRYSALIDE_ANALYSIS_SCAN_MODULE_H +#define _PLUGINS_PYCHRYSALIDE_ANALYSIS_SCAN_MODULE_H + + +#include <Python.h> +#include <stdbool.h> + + + +/* Ajoute le module 'analysis.scan' à un module Python. */ +bool add_analysis_scan_module(PyObject *); + +/* Intègre les objets du module 'analysis.scan'. */ +bool populate_analysis_scan_module(void); + + + +#endif /* _PLUGINS_PYCHRYSALIDE_ANALYSIS_SCAN_MODULE_H */ diff --git a/plugins/pychrysalide/analysis/scan/options.c b/plugins/pychrysalide/analysis/scan/options.c new file mode 100644 index 0000000..84c1784 --- /dev/null +++ b/plugins/pychrysalide/analysis/scan/options.c @@ -0,0 +1,511 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * options.c - équivalent Python du fichier "analysis/scan/options.c" + * + * Copyright (C) 2022 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +#include "options.h" + + +#include <pygobject.h> + + +#include <i18n.h> +#include <analysis/scan/options-int.h> +#include <plugins/pychrysalide/access.h> +#include <plugins/pychrysalide/helpers.h> + + + +CREATE_DYN_CONSTRUCTOR(scan_options, G_TYPE_SCAN_OPTIONS); + +/* Initialise une instance sur la base du dérivé de GObject. */ +static int py_scan_options_init(PyObject *, PyObject *, PyObject *); + +/* Indique le type d'un moteur d'analyse de données sélectionné. */ +static PyObject *py_scan_options_get_backend_for_data(PyObject *, void *); + +/* Sélectionne un type de moteur d'analyse pour données brutes. */ +static int py_scan_options_set_backend_for_data(PyObject *, PyObject *, void *); + +/* Impose le format JSON comme type de sortie. */ +static PyObject *py_scan_options_get_print_json(PyObject *, void *); + +/* Mémorise le format JSON comme type de sortie. */ +static int py_scan_options_set_print_json(PyObject *, PyObject *, void *); + +/* Indique un besoin d'affichage des correspondances finales. */ +static PyObject *py_scan_options_get_print_strings(PyObject *, void *); + +/* Mémorise un besoin d'affichage des correspondances finales. */ +static int py_scan_options_set_print_strings(PyObject *, PyObject *, void *); + +/* Indique un besoin de statistiques en fin de compilation. */ +static PyObject *py_scan_options_get_print_stats(PyObject *, void *); + +/* Mémorise un besoin de statistiques en fin de compilation. */ +static int py_scan_options_set_print_stats(PyObject *, PyObject *, void *); + + + +/****************************************************************************** +* * +* Paramètres : self = objet à initialiser (théoriquement). * +* args = arguments fournis à l'appel. * +* kwds = arguments de type key=val fournis. * +* * +* Description : Initialise une instance sur la base du dérivé de GObject. * +* * +* Retour : 0. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static int py_scan_options_init(PyObject *self, PyObject *args, PyObject *kwds) +{ + int ret; /* Bilan de lecture des args. */ + +#define SCAN_OPTIONS_DOC \ + "The *ScanOptions* class stores all parameters used to tune" \ + " a scanning process.\n" \ + "\n" \ + "Instances can be created using the following constructor:\n" \ + "\n" \ + " ScanOptions()" + + /* Initialisation d'un objet GLib */ + + ret = forward_pygobjet_init(self); + if (ret == -1) return -1; + + return 0; + +} + + +/****************************************************************************** +* * +* Paramètres : self = classe représentant un format Axml. * +* closure = adresse non utilisée ici. * +* * +* Description : Indique le type d'un moteur d'analyse de données sélectionné.* +* * +* Retour : Type d'objet, idéalement valide. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static PyObject *py_scan_options_get_backend_for_data(PyObject *self, void *closure) +{ + PyObject *result; /* Liste éventuelle à renvoyer */ + GScanOptions *options; /* Version native */ + GType type; /* Type à transcrire */ + +#define SCAN_OPTIONS_BACKEND_FOR_DATA_ATTRIB PYTHON_GETSET_DEF_FULL \ +( \ + backend_for_data, py_scan_options, \ + "Type of the selected scan algorithm." \ +) + + options = G_SCAN_OPTIONS(pygobject_get(self)); + + type = g_scan_options_get_backend_for_data(options); + + result = pyg_type_wrapper_new(type); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : self = objet Python concerné par l'appel. * +* value = valeur fournie à intégrer ou prendre en compte. * +* closure = adresse non utilisée ici. * +* * +* Description : Sélectionne un type de moteur d'analyse pour données brutes. * +* * +* Retour : Bilan de l'opération pour Python. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static int py_scan_options_set_backend_for_data(PyObject *self, PyObject *value, void *closure) +{ + GType type; /* Type à transcrit */ + GScanOptions *options; /* Version native */ + + type = pyg_type_from_object(value); + + options = G_SCAN_OPTIONS(pygobject_get(self)); + + g_scan_options_set_backend_for_data(options, type); + + return 0; + +} + + +/****************************************************************************** +* * +* Paramètres : self = classe représentant un format Axml. * +* closure = adresse non utilisée ici. * +* * +* Description : Impose le format JSON comme type de sortie. * +* * +* Retour : Etat de l'option visée à conservé. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static PyObject *py_scan_options_get_print_json(PyObject *self, void *closure) +{ + PyObject *result; /* Liste éventuelle à renvoyer */ + GScanOptions *options; /* Version native */ + bool state; /* Etat courant à consulter */ + +#define SCAN_OPTIONS_PRINT_JSON_ATTRIB PYTHON_GETSET_DEF_FULL \ +( \ + print_json, py_scan_options, \ + "Define if the process summary is output into a JSON" \ + " format at the end of the scan or not." \ +) + + options = G_SCAN_OPTIONS(pygobject_get(self)); + + state = g_scan_options_get_print_json(options); + + result = state ? Py_True : Py_False; + Py_INCREF(result); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : self = objet Python concerné par l'appel. * +* value = valeur fournie à intégrer ou prendre en compte. * +* closure = adresse non utilisée ici. * +* * +* Description : Mémorise le format JSON comme type de sortie. * +* * +* Retour : Bilan de l'opération pour Python. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static int py_scan_options_set_print_json(PyObject *self, PyObject *value, void *closure) +{ + bool state; /* Nouvel état à définir */ + GScanOptions *options; /* Version native */ + + if (value != Py_True && value != Py_False) + return -1; + + state = (value == Py_True); + + options = G_SCAN_OPTIONS(pygobject_get(self)); + + g_scan_options_set_print_json(options, state); + + return 0; + +} + + +/****************************************************************************** +* * +* Paramètres : self = classe représentant un format Axml. * +* closure = adresse non utilisée ici. * +* * +* Description : Indique un besoin d'affichage des correspondances finales. * +* * +* Retour : Etat de l'option visée à conservé. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static PyObject *py_scan_options_get_print_strings(PyObject *self, void *closure) +{ + PyObject *result; /* Liste éventuelle à renvoyer */ + GScanOptions *options; /* Version native */ + bool state; /* Etat courant à consulter */ + +#define SCAN_OPTIONS_PRINT_STRINGS_ATTRIB PYTHON_GETSET_DEF_FULL \ +( \ + print_strings, py_scan_options, \ + "Define if the matching patterns are printed with found" \ + " offset at the end of the scan or not." \ +) + + options = G_SCAN_OPTIONS(pygobject_get(self)); + + state = g_scan_options_get_print_strings(options); + + result = state ? Py_True : Py_False; + Py_INCREF(result); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : self = objet Python concerné par l'appel. * +* value = valeur fournie à intégrer ou prendre en compte. * +* closure = adresse non utilisée ici. * +* * +* Description : Mémorise un besoin d'affichage des correspondances finales. * +* * +* Retour : Bilan de l'opération pour Python. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static int py_scan_options_set_print_strings(PyObject *self, PyObject *value, void *closure) +{ + bool state; /* Nouvel état à définir */ + GScanOptions *options; /* Version native */ + + if (value != Py_True && value != Py_False) + return -1; + + state = (value == Py_True); + + options = G_SCAN_OPTIONS(pygobject_get(self)); + + g_scan_options_set_print_strings(options, state); + + return 0; + +} + + +/****************************************************************************** +* * +* Paramètres : self = classe représentant un format Axml. * +* closure = adresse non utilisée ici. * +* * +* Description : Indique un besoin de statistiques en fin de compilation. * +* * +* Retour : Etat de l'option visée à conservé. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static PyObject *py_scan_options_get_print_stats(PyObject *self, void *closure) +{ + PyObject *result; /* Liste éventuelle à renvoyer */ + GScanOptions *options; /* Version native */ + bool state; /* Etat courant à consulter */ + +#define SCAN_OPTIONS_PRINT_STATS_ATTRIB PYTHON_GETSET_DEF_FULL \ +( \ + print_stats, py_scan_options, \ + "Control the output of final statistics afer a scan." \ +) + + options = G_SCAN_OPTIONS(pygobject_get(self)); + + state = g_scan_options_get_print_stats(options); + + result = state ? Py_True : Py_False; + Py_INCREF(result); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : self = objet Python concerné par l'appel. * +* value = valeur fournie à intégrer ou prendre en compte. * +* closure = adresse non utilisée ici. * +* * +* Description : Mémorise un besoin de statistiques en fin de compilation. * +* * +* Retour : Bilan de l'opération pour Python. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static int py_scan_options_set_print_stats(PyObject *self, PyObject *value, void *closure) +{ + bool state; /* Nouvel état à définir */ + GScanOptions *options; /* Version native */ + + if (value != Py_True && value != Py_False) + return -1; + + state = (value == Py_True); + + options = G_SCAN_OPTIONS(pygobject_get(self)); + + g_scan_options_set_print_stats(options, state); + + return 0; + +} + + +/****************************************************************************** +* * +* Paramètres : - * +* * +* Description : Fournit un accès à une définition de type à diffuser. * +* * +* Retour : Définition d'objet pour Python. * +* * +* Remarques : - * +* * +******************************************************************************/ + +PyTypeObject *get_python_scan_options_type(void) +{ + static PyMethodDef py_scan_options_methods[] = { + { NULL } + }; + + static PyGetSetDef py_scan_options_getseters[] = { + SCAN_OPTIONS_BACKEND_FOR_DATA_ATTRIB, + SCAN_OPTIONS_PRINT_JSON_ATTRIB, + SCAN_OPTIONS_PRINT_STRINGS_ATTRIB, + SCAN_OPTIONS_PRINT_STATS_ATTRIB, + { NULL } + }; + + static PyTypeObject py_scan_options_type = { + + PyVarObject_HEAD_INIT(NULL, 0) + + .tp_name = "pychrysalide.analysis.scan.ScanOptions", + .tp_basicsize = sizeof(PyGObject), + + .tp_flags = Py_TPFLAGS_DEFAULT, + + .tp_doc = SCAN_OPTIONS_DOC, + + .tp_methods = py_scan_options_methods, + .tp_getset = py_scan_options_getseters, + + .tp_init = py_scan_options_init, + .tp_new = py_scan_options_new, + + }; + + return &py_scan_options_type; + +} + + +/****************************************************************************** +* * +* Paramètres : - * +* * +* Description : Prend en charge l'objet 'pychrysalide...scan.ScanOptions'. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool ensure_python_scan_options_is_registered(void) +{ + PyTypeObject *type; /* Type Python 'ScanOptions' */ + PyObject *module; /* Module à recompléter */ + PyObject *dict; /* Dictionnaire du module */ + + type = get_python_scan_options_type(); + + if (!PyType_HasFeature(type, Py_TPFLAGS_READY)) + { + module = get_access_to_python_module("pychrysalide.analysis.scan"); + + dict = PyModule_GetDict(module); + + if (!register_class_for_pygobject(dict, G_TYPE_SCAN_OPTIONS, type)) + 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 ensemble d'options d'analyses. * +* * +* Retour : Bilan de l'opération, voire indications supplémentaires. * +* * +* Remarques : - * +* * +******************************************************************************/ + +int convert_to_scan_options(PyObject *arg, void *dst) +{ + int result; /* Bilan à retourner */ + + result = PyObject_IsInstance(arg, (PyObject *)get_python_scan_options_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 scan options"); + break; + + case 1: + *((GScanOptions **)dst) = G_SCAN_OPTIONS(pygobject_get(arg)); + break; + + default: + assert(false); + break; + + } + + return result; + +} diff --git a/plugins/pychrysalide/analysis/scan/options.h b/plugins/pychrysalide/analysis/scan/options.h new file mode 100644 index 0000000..3e83880 --- /dev/null +++ b/plugins/pychrysalide/analysis/scan/options.h @@ -0,0 +1,45 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * options.h - prototypes pour l'équivalent Python du fichier "analysis/scan/options.h" + * + * Copyright (C) 2022 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +#ifndef _PLUGINS_PYCHRYSALIDE_ANALYSIS_SCAN_OPTIONS_H +#define _PLUGINS_PYCHRYSALIDE_ANALYSIS_SCAN_OPTIONS_H + + +#include <Python.h> +#include <stdbool.h> + + + +/* Fournit un accès à une définition de type à diffuser. */ +PyTypeObject *get_python_scan_options_type(void); + +/* Prend en charge l'objet 'pychrysalide.analysis.scan.ScanOptions'. */ +bool ensure_python_scan_options_is_registered(void); + +/* Tente de convertir en ensemble d'options d'analyses. */ +int convert_to_scan_options(PyObject *, void *); + + + +#endif /* _PLUGINS_PYCHRYSALIDE_ANALYSIS_SCAN_OPTIONS_H */ diff --git a/plugins/pychrysalide/analysis/scan/patterns/Makefile.am b/plugins/pychrysalide/analysis/scan/patterns/Makefile.am new file mode 100644 index 0000000..dd26fa5 --- /dev/null +++ b/plugins/pychrysalide/analysis/scan/patterns/Makefile.am @@ -0,0 +1,22 @@ + +noinst_LTLIBRARIES = libpychrysaanalysisscanpatterns.la + +libpychrysaanalysisscanpatterns_la_SOURCES = \ + backend.h backend.c \ + modifier.h modifier.c \ + module.h module.c + +libpychrysaanalysisscanpatterns_la_LIBADD = \ + backends/libpychrysaanalysisscanpatternsbackends.la \ + modifiers/libpychrysaanalysisscanpatternsmodifiers.la + +libpychrysaanalysisscanpatterns_la_CFLAGS = $(LIBPYTHON_INTERPRETER_CFLAGS) $(LIBPYGOBJECT_CFLAGS) \ + $(TOOLKIT_CFLAGS) -I$(top_srcdir)/src -DNO_IMPORT_PYGOBJECT + + +devdir = $(includedir)/chrysalide/$(subdir) + +dev_HEADERS = $(libpychrysaanalysisscanpatterns_la_SOURCES:%c=) + + +SUBDIRS = backends modifiers diff --git a/plugins/pychrysalide/analysis/scan/patterns/backend.c b/plugins/pychrysalide/analysis/scan/patterns/backend.c new file mode 100644 index 0000000..03db143 --- /dev/null +++ b/plugins/pychrysalide/analysis/scan/patterns/backend.c @@ -0,0 +1,202 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * backend.c - équivalent Python du fichier "analysis/scan/backend.c" + * + * Copyright (C) 2022 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +#include "backend.h" + + +#include <pygobject.h> + + +#include <analysis/scan/patterns/backend-int.h> + + +#include "../../../access.h" +#include "../../../helpers.h" + + + +CREATE_DYN_ABSTRACT_CONSTRUCTOR(engine_backend, G_TYPE_ENGINE_BACKEND, NULL); + +/* Initialise une instance sur la base du dérivé de GObject. */ +static int py_engine_backend_init(PyObject *, PyObject *, PyObject *); + + + +/****************************************************************************** +* * +* Paramètres : self = objet à initialiser (théoriquement). * +* args = arguments fournis à l'appel. * +* kwds = arguments de type key=val fournis. * +* * +* Description : Initialise une instance sur la base du dérivé de GObject. * +* * +* Retour : 0. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static int py_engine_backend_init(PyObject *self, PyObject *args, PyObject *kwds) +{ + int ret; /* Bilan de lecture des args. */ + +#define ENGINE_BACKEND_DOC \ + "An *EngineBackend* object is the root class of all scan algorithm" \ + " looking for data patterns." + + /* Initialisation d'un objet GLib */ + + ret = forward_pygobjet_init(self); + if (ret == -1) return -1; + + return 0; + +} + + +/****************************************************************************** +* * +* Paramètres : - * +* * +* Description : Fournit un accès à une définition de type à diffuser. * +* * +* Retour : Définition d'objet pour Python. * +* * +* Remarques : - * +* * +******************************************************************************/ + +PyTypeObject *get_python_engine_backend_type(void) +{ + static PyMethodDef py_engine_backend_methods[] = { + { NULL } + }; + + static PyGetSetDef py_engine_backend_getseters[] = { + { NULL } + }; + + static PyTypeObject py_engine_backend_type = { + + PyVarObject_HEAD_INIT(NULL, 0) + + .tp_name = "pychrysalide.analysis.scan.patterns.EngineBackend", + .tp_basicsize = sizeof(PyGObject), + + .tp_flags = Py_TPFLAGS_DEFAULT, + + .tp_doc = ENGINE_BACKEND_DOC, + + .tp_methods = py_engine_backend_methods, + .tp_getset = py_engine_backend_getseters, + + .tp_init = py_engine_backend_init, + .tp_new = py_engine_backend_new, + + }; + + return &py_engine_backend_type; + +} + + +/****************************************************************************** +* * +* Paramètres : - * +* * +* Description : Prend en charge l'objet 'pychrysalide....EngineBackend'. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool ensure_python_engine_backend_is_registered(void) +{ + PyTypeObject *type; /* Type Python 'ScanNamespace' */ + PyObject *module; /* Module à recompléter */ + PyObject *dict; /* Dictionnaire du module */ + + type = get_python_engine_backend_type(); + + if (!PyType_HasFeature(type, Py_TPFLAGS_READY)) + { + module = get_access_to_python_module("pychrysalide.analysis.scan"); + + dict = PyModule_GetDict(module); + + if (!register_class_for_pygobject(dict, G_TYPE_ENGINE_BACKEND, type)) + 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 méthode de recherches. * +* * +* Retour : Bilan de l'opération, voire indications supplémentaires. * +* * +* Remarques : - * +* * +******************************************************************************/ + +int convert_to_engine_backend(PyObject *arg, void *dst) +{ + int result; /* Bilan à retourner */ + + result = PyObject_IsInstance(arg, (PyObject *)get_python_engine_backend_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 engine backend"); + break; + + case 1: + *((GEngineBackend **)dst) = G_ENGINE_BACKEND(pygobject_get(arg)); + break; + + default: + assert(false); + break; + + } + + return result; + +} diff --git a/plugins/pychrysalide/analysis/scan/patterns/backend.h b/plugins/pychrysalide/analysis/scan/patterns/backend.h new file mode 100644 index 0000000..6b1f4cd --- /dev/null +++ b/plugins/pychrysalide/analysis/scan/patterns/backend.h @@ -0,0 +1,45 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * backend.h - prototypes pour l'équivalent Python du fichier "analysis/scan/backend.h" + * + * Copyright (C) 2022 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +#ifndef _PLUGINS_PYCHRYSALIDE_ANALYSIS_SCAN_BACKEND_H +#define _PLUGINS_PYCHRYSALIDE_ANALYSIS_SCAN_BACKEND_H + + +#include <Python.h> +#include <stdbool.h> + + + +/* Fournit un accès à une définition de type à diffuser. */ +PyTypeObject *get_python_engine_backend_type(void); + +/* Prend en charge l'objet 'pychrysalide.analysis.scan.patterns.EngineBackend'. */ +bool ensure_python_engine_backend_is_registered(void); + +/* Tente de convertir en méthode de recherches. */ +int convert_to_engine_backend(PyObject *, void *); + + + +#endif /* _PLUGINS_PYCHRYSALIDE_ANALYSIS_SCAN_BACKEND_H */ diff --git a/plugins/pychrysalide/analysis/scan/patterns/backends/Makefile.am b/plugins/pychrysalide/analysis/scan/patterns/backends/Makefile.am new file mode 100644 index 0000000..cccfc2d --- /dev/null +++ b/plugins/pychrysalide/analysis/scan/patterns/backends/Makefile.am @@ -0,0 +1,15 @@ + +noinst_LTLIBRARIES = libpychrysaanalysisscanpatternsbackends.la + +libpychrysaanalysisscanpatternsbackends_la_SOURCES = \ + acism.h acism.c \ + bitap.h bitap.c \ + module.h module.c + +libpychrysaanalysisscanpatternsbackends_la_CFLAGS = $(LIBPYTHON_CFLAGS) $(LIBPYGOBJECT_CFLAGS) $(TOOLKIT_CFLAGS) \ + -I$(top_srcdir)/src -DNO_IMPORT_PYGOBJECT + + +devdir = $(includedir)/chrysalide/$(subdir) + +dev_HEADERS = $(libpychrysaanalysisscanpatternsbackends_la_SOURCES:%c=) diff --git a/plugins/pychrysalide/analysis/scan/patterns/backends/acism.c b/plugins/pychrysalide/analysis/scan/patterns/backends/acism.c new file mode 100644 index 0000000..56d0b55 --- /dev/null +++ b/plugins/pychrysalide/analysis/scan/patterns/backends/acism.c @@ -0,0 +1,214 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * acism.c - équivalent Python du fichier "analysis/scan/patterns/backends/acism.c" + * + * Copyright (C) 2022 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +#include "acism.h" + + +#include <pygobject.h> + + +#include <i18n.h> +#include <analysis/scan/patterns/backends/acism-int.h> + + +#include "../backend.h" +#include "../../../../access.h" +#include "../../../../helpers.h" + + + +CREATE_DYN_CONSTRUCTOR(acism_backend, G_TYPE_ACISM_BACKEND); + +/* Initialise une instance sur la base du dérivé de GObject. */ +static int py_acism_backend_init(PyObject *, PyObject *, PyObject *); + + + +/****************************************************************************** +* * +* Paramètres : self = objet à initialiser (théoriquement). * +* args = arguments fournis à l'appel. * +* kwds = arguments de type key=val fournis. * +* * +* Description : Initialise une instance sur la base du dérivé de GObject. * +* * +* Retour : 0. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static int py_acism_backend_init(PyObject *self, PyObject *args, PyObject *kwds) +{ + int ret; /* Bilan de lecture des args. */ + +#define ACISM_BACKEND_DOC \ + "A *AcismBackend* class provide an implementation of the Aho-Corasick" \ + " search algorithm with Interleaved State-transition Matrix (ACISM)." \ + "\n" \ + "Instances can be created using the following constructor:\n" \ + "\n" \ + " AcismBackend()" \ + "\n" \ + "See the relative white paper for more information:" \ + " https://docs.google.com/document/d/1e9Qbn22__togYgQ7PNyCz3YzIIVPKvrf8PCrFa74IFM" + + /* Initialisation d'un objet GLib */ + + ret = forward_pygobjet_init(self); + if (ret == -1) return -1; + + return 0; + +} + + +/****************************************************************************** +* * +* Paramètres : - * +* * +* Description : Fournit un accès à une définition de type à diffuser. * +* * +* Retour : Définition d'objet pour Python. * +* * +* Remarques : - * +* * +******************************************************************************/ + +PyTypeObject *get_python_acism_backend_type(void) +{ + static PyMethodDef py_acism_backend_methods[] = { + { NULL } + }; + + static PyGetSetDef py_acism_backend_getseters[] = { + { NULL } + }; + + static PyTypeObject py_acism_backend_type = { + + PyVarObject_HEAD_INIT(NULL, 0) + + .tp_name = "pychrysalide.analysis.scan.patterns.backends.AcismBackend", + .tp_basicsize = sizeof(PyGObject), + + .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, + + .tp_doc = ACISM_BACKEND_DOC, + + .tp_methods = py_acism_backend_methods, + .tp_getset = py_acism_backend_getseters, + + .tp_init = py_acism_backend_init, + .tp_new = py_acism_backend_new, + + }; + + return &py_acism_backend_type; + +} + + +/****************************************************************************** +* * +* Paramètres : - * +* * +* Description : Prend en charge l'objet 'pychrysalide....AcismBackend'. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool ensure_python_acism_backend_is_registered(void) +{ + PyTypeObject *type; /* Type Python 'AcismBackend'*/ + PyObject *module; /* Module à recompléter */ + PyObject *dict; /* Dictionnaire du module */ + + type = get_python_acism_backend_type(); + + if (!PyType_HasFeature(type, Py_TPFLAGS_READY)) + { + module = get_access_to_python_module("pychrysalide.analysis.scan.patterns.backends"); + + dict = PyModule_GetDict(module); + + if (!ensure_python_engine_backend_is_registered()) + return false; + + if (!register_class_for_pygobject(dict, G_TYPE_ACISM_BACKEND, type)) + 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 méthode de recherche ACISM. * +* * +* Retour : Bilan de l'opération, voire indications supplémentaires. * +* * +* Remarques : - * +* * +******************************************************************************/ + +int convert_to_acism_backend(PyObject *arg, void *dst) +{ + int result; /* Bilan à retourner */ + + result = PyObject_IsInstance(arg, (PyObject *)get_python_acism_backend_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 ACISM backend"); + break; + + case 1: + *((GAcismBackend **)dst) = G_ACISM_BACKEND(pygobject_get(arg)); + break; + + default: + assert(false); + break; + + } + + return result; + +} diff --git a/plugins/pychrysalide/analysis/scan/patterns/backends/acism.h b/plugins/pychrysalide/analysis/scan/patterns/backends/acism.h new file mode 100644 index 0000000..9ed61fa --- /dev/null +++ b/plugins/pychrysalide/analysis/scan/patterns/backends/acism.h @@ -0,0 +1,45 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * acism.h - prototypes pour l'équivalent Python du fichier "analysis/scan/patterns/backends/acism.h" + * + * Copyright (C) 2022 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +#ifndef _PLUGINS_PYCHRYSALIDE_ANALYSIS_SCAN_PATTERNS_BACKENDS_ACISM_H +#define _PLUGINS_PYCHRYSALIDE_ANALYSIS_SCAN_PATTERNS_BACKENDS_ACISM_H + + +#include <Python.h> +#include <stdbool.h> + + + +/* Fournit un accès à une définition de type à diffuser. */ +PyTypeObject *get_python_acism_backend_type(void); + +/* Prend en charge l'objet 'pychrysalide.analysis.scan.patterns.backends.AcismBackend'. */ +bool ensure_python_acism_backend_is_registered(void); + +/* Tente de convertir en méthode de recherche ACISM. */ +int convert_to_acism_backend(PyObject *, void *); + + + +#endif /* _PLUGINS_PYCHRYSALIDE_ANALYSIS_SCAN_PATTERNS_BACKENDS_ACISM_H */ diff --git a/plugins/pychrysalide/analysis/scan/patterns/backends/bitap.c b/plugins/pychrysalide/analysis/scan/patterns/backends/bitap.c new file mode 100644 index 0000000..c910f26 --- /dev/null +++ b/plugins/pychrysalide/analysis/scan/patterns/backends/bitap.c @@ -0,0 +1,214 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * bitap.c - équivalent Python du fichier "analysis/scan/patterns/backends/bitap.c" + * + * Copyright (C) 2022 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +#include "bitap.h" + + +#include <pygobject.h> + + +#include <i18n.h> +#include <analysis/scan/patterns/backends/bitap-int.h> + + +#include "../backend.h" +#include "../../../../access.h" +#include "../../../../helpers.h" + + + +CREATE_DYN_CONSTRUCTOR(bitap_backend, G_TYPE_BITAP_BACKEND); + +/* Initialise une instance sur la base du dérivé de GObject. */ +static int py_bitap_backend_init(PyObject *, PyObject *, PyObject *); + + + +/****************************************************************************** +* * +* Paramètres : self = objet à initialiser (théoriquement). * +* args = arguments fournis à l'appel. * +* kwds = arguments de type key=val fournis. * +* * +* Description : Initialise une instance sur la base du dérivé de GObject. * +* * +* Retour : 0. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static int py_bitap_backend_init(PyObject *self, PyObject *args, PyObject *kwds) +{ + int ret; /* Bilan de lecture des args. */ + +#define BITAP_BACKEND_DOC \ + "A *BitapBackend* class provide an implementation of the Bitap" \ + " search algorithm." \ + "\n" \ + "Instances can be created using the following constructor:\n" \ + "\n" \ + " BitapBackend()" \ + "\n" \ + "See the relative white paper for more information:" \ + " https://en.wikipedia.org/wiki/Bitap_algorithm" + + /* Initialisation d'un objet GLib */ + + ret = forward_pygobjet_init(self); + if (ret == -1) return -1; + + return 0; + +} + + +/****************************************************************************** +* * +* Paramètres : - * +* * +* Description : Fournit un accès à une définition de type à diffuser. * +* * +* Retour : Définition d'objet pour Python. * +* * +* Remarques : - * +* * +******************************************************************************/ + +PyTypeObject *get_python_bitap_backend_type(void) +{ + static PyMethodDef py_bitap_backend_methods[] = { + { NULL } + }; + + static PyGetSetDef py_bitap_backend_getseters[] = { + { NULL } + }; + + static PyTypeObject py_bitap_backend_type = { + + PyVarObject_HEAD_INIT(NULL, 0) + + .tp_name = "pychrysalide.analysis.scan.patterns.backends.BitapBackend", + .tp_basicsize = sizeof(PyGObject), + + .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, + + .tp_doc = BITAP_BACKEND_DOC, + + .tp_methods = py_bitap_backend_methods, + .tp_getset = py_bitap_backend_getseters, + + .tp_init = py_bitap_backend_init, + .tp_new = py_bitap_backend_new, + + }; + + return &py_bitap_backend_type; + +} + + +/****************************************************************************** +* * +* Paramètres : - * +* * +* Description : Prend en charge l'objet 'pychrysalide....BitapBackend'. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool ensure_python_bitap_backend_is_registered(void) +{ + PyTypeObject *type; /* Type Python 'BitapBackend'*/ + PyObject *module; /* Module à recompléter */ + PyObject *dict; /* Dictionnaire du module */ + + type = get_python_bitap_backend_type(); + + if (!PyType_HasFeature(type, Py_TPFLAGS_READY)) + { + module = get_access_to_python_module("pychrysalide.analysis.scan.patterns.backends"); + + dict = PyModule_GetDict(module); + + if (!ensure_python_engine_backend_is_registered()) + return false; + + if (!register_class_for_pygobject(dict, G_TYPE_BITAP_BACKEND, type)) + 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 méthode de recherche BITAP. * +* * +* Retour : Bilan de l'opération, voire indications supplémentaires. * +* * +* Remarques : - * +* * +******************************************************************************/ + +int convert_to_bitap_backend(PyObject *arg, void *dst) +{ + int result; /* Bilan à retourner */ + + result = PyObject_IsInstance(arg, (PyObject *)get_python_bitap_backend_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 Bitap backend"); + break; + + case 1: + *((GBitapBackend **)dst) = G_BITAP_BACKEND(pygobject_get(arg)); + break; + + default: + assert(false); + break; + + } + + return result; + +} diff --git a/plugins/pychrysalide/analysis/scan/patterns/backends/bitap.h b/plugins/pychrysalide/analysis/scan/patterns/backends/bitap.h new file mode 100644 index 0000000..f7853d4 --- /dev/null +++ b/plugins/pychrysalide/analysis/scan/patterns/backends/bitap.h @@ -0,0 +1,45 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * bitap.h - prototypes pour l'équivalent Python du fichier "analysis/scan/patterns/backends/bitap.h" + * + * Copyright (C) 2022 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +#ifndef _PLUGINS_PYCHRYSALIDE_ANALYSIS_SCAN_PATTERNS_BACKENDS_BITAP_H +#define _PLUGINS_PYCHRYSALIDE_ANALYSIS_SCAN_PATTERNS_BACKENDS_BITAP_H + + +#include <Python.h> +#include <stdbool.h> + + + +/* Fournit un accès à une définition de type à diffuser. */ +PyTypeObject *get_python_bitap_backend_type(void); + +/* Prend en charge l'objet 'pychrysalide.analysis.scan.patterns.backends.BitapBackend'. */ +bool ensure_python_bitap_backend_is_registered(void); + +/* Tente de convertir en méthode de recherche Bitap. */ +int convert_to_bitap_backend(PyObject *, void *); + + + +#endif /* _PLUGINS_PYCHRYSALIDE_ANALYSIS_SCAN_PATTERNS_BACKENDS_BITAP_H */ diff --git a/plugins/pychrysalide/analysis/scan/patterns/backends/module.c b/plugins/pychrysalide/analysis/scan/patterns/backends/module.c new file mode 100644 index 0000000..f4a0293 --- /dev/null +++ b/plugins/pychrysalide/analysis/scan/patterns/backends/module.c @@ -0,0 +1,106 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * module.c - intégration du répertoire backends en tant que module + * + * Copyright (C) 2022 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +#include "module.h" + + +#include <assert.h> + + +#include "acism.h" +#include "bitap.h" +#include "../../../../helpers.h" + + + +/****************************************************************************** +* * +* Paramètres : super = module dont la définition est à compléter. * +* * +* Description : Ajoute le module 'analysis.....backends' à un module Python. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool add_analysis_scan_patterns_backends_module(PyObject *super) +{ + bool result; /* Bilan à retourner */ + PyObject *module; /* Sous-module mis en place */ + +#define PYCHRYSALIDE_ANALYSIS_SCAN_PATTERNS_BACKENDS_MODULE_DOC \ + "This module provide all the features useful for scanning" \ + " binary contents." + + static PyModuleDef py_chrysalide_analysis_scan_patterns_backends_module = { + + .m_base = PyModuleDef_HEAD_INIT, + + .m_name = "pychrysalide.analysis.scan.patterns.backends", + .m_doc = PYCHRYSALIDE_ANALYSIS_SCAN_PATTERNS_BACKENDS_MODULE_DOC, + + .m_size = -1, + + }; + + module = build_python_module(super, &py_chrysalide_analysis_scan_patterns_backends_module); + + result = (module != NULL); + + if (!result) + Py_XDECREF(module); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : - * +* * +* Description : Intègre les objets du module 'analysis....patterns.backends'.* +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool populate_analysis_scan_patterns_backends_module(void) +{ + bool result; /* Bilan à retourner */ + + result = true; + + if (result) result = ensure_python_acism_backend_is_registered(); + if (result) result = ensure_python_bitap_backend_is_registered(); + + assert(result); + + return result; + +} diff --git a/plugins/pychrysalide/analysis/scan/patterns/backends/module.h b/plugins/pychrysalide/analysis/scan/patterns/backends/module.h new file mode 100644 index 0000000..ab1aad5 --- /dev/null +++ b/plugins/pychrysalide/analysis/scan/patterns/backends/module.h @@ -0,0 +1,42 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * module.h - prototypes pour l'intégration du répertoire backends en tant que module + * + * Copyright (C) 2022 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +#ifndef _PLUGINS_PYCHRYSALIDE_ANALYSIS_SCAN_PATTERNS_BACKENDS_MODULE_H +#define _PLUGINS_PYCHRYSALIDE_ANALYSIS_SCAN_PATTERNS_BACKENDS_MODULE_H + + +#include <Python.h> +#include <stdbool.h> + + + +/* Ajoute le module 'analysis.scan.patterns.backends' à un module Python. */ +bool add_analysis_scan_patterns_backends_module(PyObject *); + +/* Intègre les objets du module 'analysis.scan.patterns.backends'. */ +bool populate_analysis_scan_patterns_backends_module(void); + + + +#endif /* _PLUGINS_PYCHRYSALIDE_ANALYSIS_SCAN_PATTERNS_BACKENDS_MODULE_H */ diff --git a/plugins/pychrysalide/analysis/scan/patterns/modifier.c b/plugins/pychrysalide/analysis/scan/patterns/modifier.c new file mode 100644 index 0000000..6547d91 --- /dev/null +++ b/plugins/pychrysalide/analysis/scan/patterns/modifier.c @@ -0,0 +1,416 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * modifier.c - équivalent Python du fichier "analysis/scan/modifier.c" + * + * Copyright (C) 2023 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 "modifier.h" + + +#include <pygobject.h> + + +#include <analysis/scan/patterns/modifier-int.h> + + +#include "../../../access.h" +#include "../../../helpers.h" + + + +CREATE_DYN_ABSTRACT_CONSTRUCTOR(scan_token_modifier, G_TYPE_SCAN_TOKEN_MODIFIER, NULL); + +/* Initialise une instance sur la base du dérivé de GObject. */ +static int py_scan_token_modifier_init(PyObject *, PyObject *, PyObject *); + + + +/****************************************************************************** +* * +* Paramètres : self = objet à initialiser (théoriquement). * +* args = arguments fournis à l'appel. * +* kwds = arguments de type key=val fournis. * +* * +* Description : Initialise une instance sur la base du dérivé de GObject. * +* * +* Retour : 0. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static int py_scan_token_modifier_init(PyObject *self, PyObject *args, PyObject *kwds) +{ + int ret; /* Bilan de lecture des args. */ + +#define SCAN_TOKEN_MODIFIER_DOC \ + "An *TokenModifier* object is the root class of all modifiers" \ + " for byte patterns." + + /* Initialisation d'un objet GLib */ + + ret = forward_pygobjet_init(self); + if (ret == -1) return -1; + + return 0; + +} + + +/****************************************************************************** +* * +* Paramètres : self = tampon de données à consulter. * +* args = arguments fournis pour la conduite de l'opération. * +* * +* Description : Transforme une séquence d'octets pour motif de recherche. * +* * +* Retour : Liste des nouvelle(s) séquence(s) d'octets obtenue(s). * +* * +* Remarques : - * +* * +******************************************************************************/ + +static PyObject *py_scan_token_modifier_transform(PyObject *self, PyObject *args) +{ + PyObject *result; /* Bilan à faire remonter */ + PyObject *py_src; /* Motifs Python en entrée */ + PyObject *py_arg; /* Eventuel paramètre de config*/ + sized_binary_t src; /* Entrée au format adapté */ + Py_ssize_t len; /* Quantité de ces données */ + int ret; /* Bilan de lecture des args. */ + sized_binary_t *src_list; /* Entrées au format adapté */ + size_t scount; /* Taille de cette liste */ + bool dyn_src; /* Allocation dynamique ? */ + Py_ssize_t size; /* Taille d'une séquence */ + Py_ssize_t k; /* Boucle de parcours #1 */ + PyObject *item; /* Elément de liste de motifs */ + modifier_arg_t arg; /* Eventuelle précision */ + GScanTokenModifier *modifier; /* Version native de l'instance*/ + sized_binary_t *dest; /* Liste des nouvelles chaînes */ + size_t dcount; /* Taille de cette liste */ + bool status; /* Bilan de l'opération */ + size_t i; /* Boucle de parcours #2 */ + +#define SCAN_TOKEN_MODIFIER_TRANSFORM_METHOD PYTHON_METHOD_DEF \ +( \ + transform, "$self, data, /, arg", \ + METH_VARARGS, py_scan_token_modifier, \ + "Transform data from a byte pattern for an incoming scan.\n" \ + "\n" \ + "The data has to be provided as bytes.\n" \ + "\n" \ + "The method returns a tuple of transformed data as bytes, or" \ + " *None* in case of error." \ +) + + py_arg = NULL; + + ret = PyArg_ParseTuple(args, "O|O", &py_src, &py_arg); + if (!ret) return NULL; + + /* Constitution des motifs d'entrée */ + + if (PyBytes_Check(py_src)) + { + ret = PyBytes_AsStringAndSize(py_src, &src.data, &len); + if (ret == -1) return NULL; + + src.len = len; + + src_list = &src; + scount = 1; + + dyn_src = false; + + } + + else if (PySequence_Check(py_src)) + { + size = PySequence_Size(py_src); + + src_list = malloc(size * sizeof(sized_binary_t)); + scount = size; + + dyn_src = true; + + for (k = 0; k < size; k++) + { + item = PySequence_ITEM(py_src, k); + + if (PyBytes_Check(item)) + { + ret = PyBytes_AsStringAndSize(item, &src_list[k].data, &len); + if (ret == -1) return NULL; + + src_list[k].len = len; + + } + else + { + free(src_list); + + PyErr_SetString(PyExc_TypeError, "lists of items other than bytes are not supported"); + return NULL; + } + + } + + } + + else + { + PyErr_SetString(PyExc_TypeError, "only bytes and lists of bytes are expected as input for modifiers"); + return NULL; + } + + /* Récupération d'une éventuelle précision opérationnelle */ + + if (py_arg != NULL) + { + if (PyLong_Check(py_arg)) + { + arg.type = MAT_UNSIGNED_INTEGER; + arg.value.u_integer = PyLong_AsUnsignedLongLong(py_arg); + } + + else + { + if (dyn_src) + free(src_list); + + PyErr_SetString(PyExc_TypeError, "unable to handle the argument type for calling a modifier"); + return NULL; + + } + + } + + /* Création des nouveaux motifs */ + + modifier = G_SCAN_TOKEN_MODIFIER(pygobject_get(self)); + + if (py_arg == NULL) + status = g_scan_token_modifier_transform(modifier, src_list, scount, &dest, &dcount); + else + status = g_scan_token_modifier_transform_with_arg(modifier, src_list, scount, &arg, &dest, &dcount); + + if (dyn_src) + free(src_list); + + if (status) + { + result = PyTuple_New(dcount); + + for (i = 0; i < dcount; i++) + { + PyTuple_SetItem(result, i, PyBytes_FromStringAndSize(dest[i].data, dest[i].len)); + exit_szstr(&dest[i]); + } + + free(dest); + + } + + else + { + result = Py_None; + Py_INCREF(result); + } + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : self = classe représentant un composant nommé à manipuler.* +* closure = non utilisé ici. * +* * +* Description : Fournit le désignation associée à un composant nommé. * +* * +* Retour : Description courante. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static PyObject *py_scan_token_modifier_get_name(PyObject *self, void *closure) +{ + PyObject *result; /* Décompte à retourner */ + GScanTokenModifier *modifier; /* Version native */ + char *name; /* Désignation à convertir */ + +#define SCAN_TOKEN_MODIFIER_NAME_ATTRIB PYTHON_GET_DEF_FULL \ +( \ + name, py_scan_token_modifier, \ + "Call name for the modifier.\n" \ + "\n" \ + "The result is a string." \ +) + + modifier = G_SCAN_TOKEN_MODIFIER(pygobject_get(self)); + + name = g_scan_token_modifier_get_name(modifier); + + if (name == NULL) + { + result = Py_None; + Py_INCREF(result); + } + else + { + result = PyUnicode_FromString(name); + free(name); + } + + 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_scan_token_modifier_type(void) +{ + static PyMethodDef py_scan_token_modifier_methods[] = { + SCAN_TOKEN_MODIFIER_TRANSFORM_METHOD, + { NULL } + }; + + static PyGetSetDef py_scan_token_modifier_getseters[] = { + SCAN_TOKEN_MODIFIER_NAME_ATTRIB, + { NULL } + }; + + static PyTypeObject py_scan_token_modifier_type = { + + PyVarObject_HEAD_INIT(NULL, 0) + + .tp_name = "pychrysalide.analysis.scan.patterns.TokenModifier", + .tp_basicsize = sizeof(PyGObject), + + .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, + + .tp_doc = SCAN_TOKEN_MODIFIER_DOC, + + .tp_methods = py_scan_token_modifier_methods, + .tp_getset = py_scan_token_modifier_getseters, + + .tp_init = py_scan_token_modifier_init, + .tp_new = py_scan_token_modifier_new, + + }; + + return &py_scan_token_modifier_type; + +} + + +/****************************************************************************** +* * +* Paramètres : - * +* * +* Description : Prend en charge l'objet 'pychrysalide....TokenModifier'. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool ensure_python_scan_token_modifier_is_registered(void) +{ + PyTypeObject *type; /* Type Python 'TokenModifier' */ + PyObject *module; /* Module à recompléter */ + PyObject *dict; /* Dictionnaire du module */ + + type = get_python_scan_token_modifier_type(); + + if (!PyType_HasFeature(type, Py_TPFLAGS_READY)) + { + module = get_access_to_python_module("pychrysalide.analysis.scan"); + + dict = PyModule_GetDict(module); + + if (!register_class_for_pygobject(dict, G_TYPE_SCAN_TOKEN_MODIFIER, type)) + 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 transformation de séquence d'octets. * +* * +* Retour : Bilan de l'opération, voire indications supplémentaires. * +* * +* Remarques : - * +* * +******************************************************************************/ + +int convert_to_scan_token_modifier(PyObject *arg, void *dst) +{ + int result; /* Bilan à retourner */ + + result = PyObject_IsInstance(arg, (PyObject *)get_python_scan_token_modifier_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 token modifier"); + break; + + case 1: + *((GScanTokenModifier **)dst) = G_SCAN_TOKEN_MODIFIER(pygobject_get(arg)); + break; + + default: + assert(false); + break; + + } + + return result; + +} diff --git a/plugins/pychrysalide/analysis/scan/patterns/modifier.h b/plugins/pychrysalide/analysis/scan/patterns/modifier.h new file mode 100644 index 0000000..770b2c1 --- /dev/null +++ b/plugins/pychrysalide/analysis/scan/patterns/modifier.h @@ -0,0 +1,45 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * modifier.h - prototypes pour l'équivalent Python du fichier "analysis/scan/modifier.h" + * + * Copyright (C) 2023 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_ANALYSIS_SCAN_MODIFIER_H +#define _PLUGINS_PYCHRYSALIDE_ANALYSIS_SCAN_MODIFIER_H + + +#include <Python.h> +#include <stdbool.h> + + + +/* Fournit un accès à une définition de type à diffuser. */ +PyTypeObject *get_python_scan_token_modifier_type(void); + +/* Prend en charge l'objet 'pychrysalide.analysis.scan.patterns.TokenModifier'. */ +bool ensure_python_scan_token_modifier_is_registered(void); + +/* Tente de convertir en transformation de séquence d'octets. */ +int convert_to_scan_token_modifier(PyObject *, void *); + + + +#endif /* _PLUGINS_PYCHRYSALIDE_ANALYSIS_SCAN_MODIFIER_H */ diff --git a/plugins/pychrysalide/analysis/scan/patterns/modifiers/Makefile.am b/plugins/pychrysalide/analysis/scan/patterns/modifiers/Makefile.am new file mode 100644 index 0000000..ae53e45 --- /dev/null +++ b/plugins/pychrysalide/analysis/scan/patterns/modifiers/Makefile.am @@ -0,0 +1,18 @@ + +noinst_LTLIBRARIES = libpychrysaanalysisscanpatternsmodifiers.la + +libpychrysaanalysisscanpatternsmodifiers_la_SOURCES = \ + hex.h hex.c \ + list.h list.c \ + module.h module.c \ + plain.h plain.c \ + rev.h rev.c \ + xor.h xor.c + +libpychrysaanalysisscanpatternsmodifiers_la_CFLAGS = $(LIBPYTHON_CFLAGS) $(LIBPYGOBJECT_CFLAGS) $(TOOLKIT_CFLAGS) \ + -I$(top_srcdir)/src -DNO_IMPORT_PYGOBJECT + + +devdir = $(includedir)/chrysalide/$(subdir) + +dev_HEADERS = $(libpychrysaanalysisscanpatternsmodifiers_la_SOURCES:%c=) diff --git a/plugins/pychrysalide/analysis/scan/patterns/modifiers/hex.c b/plugins/pychrysalide/analysis/scan/patterns/modifiers/hex.c new file mode 100644 index 0000000..503580d --- /dev/null +++ b/plugins/pychrysalide/analysis/scan/patterns/modifiers/hex.c @@ -0,0 +1,211 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * hex.c - équivalent Python du fichier "analysis/scan/patterns/modifiers/hex.c" + * + * Copyright (C) 2023 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 "hex.h" + + +#include <pygobject.h> + + +#include <i18n.h> +#include <analysis/scan/patterns/modifiers/hex.h> + + +#include "../modifier.h" +#include "../../../../access.h" +#include "../../../../helpers.h" + + + +CREATE_DYN_CONSTRUCTOR(scan_hex_modifier, G_TYPE_SCAN_HEX_MODIFIER); + +/* Initialise une instance sur la base du dérivé de GObject. */ +static int py_scan_hex_modifier_init(PyObject *, PyObject *, PyObject *); + + + +/****************************************************************************** +* * +* Paramètres : self = objet à initialiser (théoriquement). * +* args = arguments fournis à l'appel. * +* kwds = arguments de type key=val fournis. * +* * +* Description : Initialise une instance sur la base du dérivé de GObject. * +* * +* Retour : 0. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static int py_scan_hex_modifier_init(PyObject *self, PyObject *args, PyObject *kwds) +{ + int ret; /* Bilan de lecture des args. */ + +#define SCAN_HEX_MODIFIER_DOC \ + "The *HexModifier* class transforms a byte pattern into its" \ + " corresponding byte sequence in lower case." \ + "\n" \ + "Instances can be created using the following constructor:\n" \ + "\n" \ + " HexModifier()" + + /* Initialisation d'un objet GLib */ + + ret = forward_pygobjet_init(self); + if (ret == -1) return -1; + + return 0; + +} + + +/****************************************************************************** +* * +* Paramètres : - * +* * +* Description : Fournit un accès à une définition de type à diffuser. * +* * +* Retour : Définition d'objet pour Python. * +* * +* Remarques : - * +* * +******************************************************************************/ + +PyTypeObject *get_python_scan_hex_modifier_type(void) +{ + static PyMethodDef py_scan_hex_modifier_methods[] = { + { NULL } + }; + + static PyGetSetDef py_scan_hex_modifier_getseters[] = { + { NULL } + }; + + static PyTypeObject py_scan_hex_modifier_type = { + + PyVarObject_HEAD_INIT(NULL, 0) + + .tp_name = "pychrysalide.analysis.scan.patterns.modifiers.HexModifier", + .tp_basicsize = sizeof(PyGObject), + + .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, + + .tp_doc = SCAN_HEX_MODIFIER_DOC, + + .tp_methods = py_scan_hex_modifier_methods, + .tp_getset = py_scan_hex_modifier_getseters, + + .tp_init = py_scan_hex_modifier_init, + .tp_new = py_scan_hex_modifier_new, + + }; + + return &py_scan_hex_modifier_type; + +} + + +/****************************************************************************** +* * +* Paramètres : - * +* * +* Description : Prend en charge l'objet 'pychrysalide....HexModifier'. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool ensure_python_scan_hex_modifier_is_registered(void) +{ + PyTypeObject *type; /* Type Python 'HexModifier' */ + PyObject *module; /* Module à recompléter */ + PyObject *dict; /* Dictionnaire du module */ + + type = get_python_scan_hex_modifier_type(); + + if (!PyType_HasFeature(type, Py_TPFLAGS_READY)) + { + module = get_access_to_python_module("pychrysalide.analysis.scan.patterns.modifiers"); + + dict = PyModule_GetDict(module); + + if (!ensure_python_scan_token_modifier_is_registered()) + return false; + + if (!register_class_for_pygobject(dict, G_TYPE_SCAN_HEX_MODIFIER, type)) + 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 transmission d'octets à l'identique. * +* * +* Retour : Bilan de l'opération, voire indications supplémentaires. * +* * +* Remarques : - * +* * +******************************************************************************/ + +int convert_to_scan_hex_modifier(PyObject *arg, void *dst) +{ + int result; /* Bilan à retourner */ + + result = PyObject_IsInstance(arg, (PyObject *)get_python_scan_hex_modifier_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 hex modifier"); + break; + + case 1: + *((GScanHexModifier **)dst) = G_SCAN_HEX_MODIFIER(pygobject_get(arg)); + break; + + default: + assert(false); + break; + + } + + return result; + +} diff --git a/plugins/pychrysalide/analysis/scan/patterns/modifiers/hex.h b/plugins/pychrysalide/analysis/scan/patterns/modifiers/hex.h new file mode 100644 index 0000000..5d70a01 --- /dev/null +++ b/plugins/pychrysalide/analysis/scan/patterns/modifiers/hex.h @@ -0,0 +1,45 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * hex.h - équivalent Python du fichier "analysis/scan/patterns/modifiers/hex.h" + * + * Copyright (C) 2023 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_ANALYSIS_SCAN_PATTERNS_MODIFIERS_HEX_H +#define _PLUGINS_PYCHRYSALIDE_ANALYSIS_SCAN_PATTERNS_MODIFIERS_HEX_H + + +#include <Python.h> +#include <stdbool.h> + + + +/* Fournit un accès à une définition de type à diffuser. */ +PyTypeObject *get_python_scan_hex_modifier_type(void); + +/* Prend en charge l'objet 'pychrysalide.analysis.scan.patterns.modifiers.HexModifier'. */ +bool ensure_python_scan_hex_modifier_is_registered(void); + +/* Tente de convertir en transmission d'octets à l'identique. */ +int convert_to_scan_hex_modifier(PyObject *, void *); + + + +#endif /* _PLUGINS_PYCHRYSALIDE_ANALYSIS_SCAN_PATTERNS_MODIFIERS_HEX_H */ diff --git a/plugins/pychrysalide/analysis/scan/patterns/modifiers/list.c b/plugins/pychrysalide/analysis/scan/patterns/modifiers/list.c new file mode 100644 index 0000000..7c77d63 --- /dev/null +++ b/plugins/pychrysalide/analysis/scan/patterns/modifiers/list.c @@ -0,0 +1,320 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * list.c - équivalent Python du fichier "analysis/scan/patterns/modifiers/list.c" + * + * Copyright (C) 2023 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 "list.h" + + +#include <pygobject.h> + + +#include <i18n.h> +#include <analysis/scan/patterns/modifiers/list.h> + + +#include "../modifier.h" +#include "../../../../access.h" +#include "../../../../helpers.h" + + + +CREATE_DYN_CONSTRUCTOR(scan_modifier_list, G_TYPE_SCAN_MODIFIER_LIST); + +/* Initialise une instance sur la base du dérivé de GObject. */ +static int py_scan_modifier_list_init(PyObject *, PyObject *, PyObject *); + +/* Intègre un nouveau transformateur dans une liste. */ +static PyObject *py_scan_modifier_list_add(PyObject *, PyObject *); + +/* Fournit les transformateurs associés à la liste. */ +static PyObject *py_scan_modifier_list_get_modifiers(PyObject *, void *); + + + +/****************************************************************************** +* * +* Paramètres : self = objet à initialiser (théoriquement). * +* args = arguments fournis à l'appel. * +* kwds = arguments de type key=val fournis. * +* * +* Description : Initialise une instance sur la base du dérivé de GObject. * +* * +* Retour : 0. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static int py_scan_modifier_list_init(PyObject *self, PyObject *args, PyObject *kwds) +{ + int ret; /* Bilan de lecture des args. */ + +#define SCAN_MODIFIER_LIST_DOC \ + "The *ModifierList* class is a special modifier which groups a list of" \ + " modifiers for byte patterns." \ + "\n" \ + "Instances can be created using the following constructor:\n" \ + "\n" \ + " ModifierList()" \ + "\n" \ + "The keyword for such a modifier is *(list)*." + + /* Initialisation d'un objet GLib */ + + ret = forward_pygobjet_init(self); + if (ret == -1) return -1; + + return 0; + +} + + +/****************************************************************************** +* * +* Paramètres : self = projet d'étude à manipuler. * +* args = arguments accompagnant l'appel. * +* * +* Description : Intègre un nouveau transformateur dans une liste. * +* * +* Retour : Bilan de l'ajout : False si un élément similaire est déjà là.* +* * +* Remarques : - * +* * +******************************************************************************/ + +static PyObject *py_scan_modifier_list_add(PyObject *self, PyObject *args) +{ + PyObject *result; /* Absence de retour Python */ + GScanTokenModifier *modifier; /* Modificateur à intégrer */ + int ret; /* Bilan de lecture des args. */ + GScanModifierList *list; /* Version GLib du type */ + bool status; /* Bilan de l'opération */ + +#define SCAN_MODIFIER_LIST_ADD_METHOD PYTHON_METHOD_DEF \ +( \ + add, "$self, modifier, /", \ + METH_VARARGS, py_scan_modifier_list, \ + "Add an extra modifier to the list.\n" \ + "\n" \ + "This *modifier* parameter has to be a" \ + " pychrysalide.analysis.scan.patterns.TokenModifier instance." \ + "\n" \ + "The function returns *True* if the provided modifier did not already" \ + " exist in the list, *False* otherwise." \ +) + + ret = PyArg_ParseTuple(args, "O&", convert_to_scan_token_modifier, &modifier); + if (!ret) return NULL; + + list = G_SCAN_MODIFIER_LIST(pygobject_get(self)); + + status = g_scan_modifier_list_add(list, modifier); + + 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 : Fournit les transformateurs associés à la liste. * +* * +* Retour : Liste de modificateurs de séquence d'octets. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static PyObject *py_scan_modifier_list_get_modifiers(PyObject *self, void *closure) +{ + PyObject *result; /* Résultat à retourner */ + GScanModifierList *list; /* Version GLib du type */ + size_t count; /* Nombre de transformateurs */ + size_t i; /* Boucle de parcours */ + GScanTokenModifier *modifier; /* Modificateur de la liste */ + +#define SCAN_MODIFIER_LIST_MODIFIERS_ATTRIB PYTHON_GET_DEF_FULL \ +( \ + modifiers, py_scan_modifier_list, \ + "List of all modifiers contained in a list.\n" \ + "\n" \ + "The returned value is a tuple of pychrysalide.analysis.scan.patterns.TokenModifier" \ + " instances." \ +) + + list = G_SCAN_MODIFIER_LIST(pygobject_get(self)); + + count = g_scan_modifier_list_count(list); + + result = PyTuple_New(count); + + for (i = 0; i < count; i++) + { + modifier = g_scan_modifier_list_get(list, i); + + PyTuple_SetItem(result, i, pygobject_new(G_OBJECT(modifier))); + + g_object_unref(modifier); + + } + + 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_scan_modifier_list_type(void) +{ + static PyMethodDef py_scan_modifier_list_methods[] = { + SCAN_MODIFIER_LIST_ADD_METHOD, + { NULL } + }; + + static PyGetSetDef py_scan_modifier_list_getseters[] = { + SCAN_MODIFIER_LIST_MODIFIERS_ATTRIB, + { NULL } + }; + + static PyTypeObject py_scan_modifier_list_type = { + + PyVarObject_HEAD_INIT(NULL, 0) + + .tp_name = "pychrysalide.analysis.scan.patterns.modifiers.ModifierList", + .tp_basicsize = sizeof(PyGObject), + + .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, + + .tp_doc = SCAN_MODIFIER_LIST_DOC, + + .tp_methods = py_scan_modifier_list_methods, + .tp_getset = py_scan_modifier_list_getseters, + + .tp_init = py_scan_modifier_list_init, + .tp_new = py_scan_modifier_list_new, + + }; + + return &py_scan_modifier_list_type; + +} + + +/****************************************************************************** +* * +* Paramètres : - * +* * +* Description : Prend en charge l'objet 'pychrysalide....ModifierList'. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool ensure_python_scan_modifier_list_is_registered(void) +{ + PyTypeObject *type; /* Type Python 'ModifierList' */ + PyObject *module; /* Module à recompléter */ + PyObject *dict; /* Dictionnaire du module */ + + type = get_python_scan_modifier_list_type(); + + if (!PyType_HasFeature(type, Py_TPFLAGS_READY)) + { + module = get_access_to_python_module("pychrysalide.analysis.scan.patterns.modifiers"); + + dict = PyModule_GetDict(module); + + if (!ensure_python_scan_token_modifier_is_registered()) + return false; + + if (!register_class_for_pygobject(dict, G_TYPE_SCAN_MODIFIER_LIST, type)) + 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 liste de transormations d'octets. * +* * +* Retour : Bilan de l'opération, voire indications supplémentaires. * +* * +* Remarques : - * +* * +******************************************************************************/ + +int convert_to_scan_modifier_list(PyObject *arg, void *dst) +{ + int result; /* Bilan à retourner */ + + result = PyObject_IsInstance(arg, (PyObject *)get_python_scan_modifier_list_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 modifier list"); + break; + + case 1: + *((GScanModifierList **)dst) = G_SCAN_MODIFIER_LIST(pygobject_get(arg)); + break; + + default: + assert(false); + break; + + } + + return result; + +} diff --git a/plugins/pychrysalide/analysis/scan/patterns/modifiers/list.h b/plugins/pychrysalide/analysis/scan/patterns/modifiers/list.h new file mode 100644 index 0000000..133de8d --- /dev/null +++ b/plugins/pychrysalide/analysis/scan/patterns/modifiers/list.h @@ -0,0 +1,45 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * list.h - équivalent Python du fichier "analysis/scan/patterns/modifiers/list.h" + * + * Copyright (C) 2023 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_ANALYSIS_SCAN_PATTERNS_MODIFIERS_LIST_H +#define _PLUGINS_PYCHRYSALIDE_ANALYSIS_SCAN_PATTERNS_MODIFIERS_LIST_H + + +#include <Python.h> +#include <stdbool.h> + + + +/* Fournit un accès à une définition de type à diffuser. */ +PyTypeObject *get_python_scan_modifier_list_type(void); + +/* Prend en charge l'objet 'pychrysalide.analysis.scan.patterns.modifiers.ModifierList'. */ +bool ensure_python_scan_modifier_list_is_registered(void); + +/* Tente de convertir en liste de transormations d'octets. */ +int convert_to_scan_modifier_list(PyObject *, void *); + + + +#endif /* _PLUGINS_PYCHRYSALIDE_ANALYSIS_SCAN_PATTERNS_MODIFIERS_LIST_H */ diff --git a/plugins/pychrysalide/analysis/scan/patterns/modifiers/module.c b/plugins/pychrysalide/analysis/scan/patterns/modifiers/module.c new file mode 100644 index 0000000..ae450dc --- /dev/null +++ b/plugins/pychrysalide/analysis/scan/patterns/modifiers/module.c @@ -0,0 +1,112 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * module.c - intégration du répertoire modifiers en tant que module + * + * Copyright (C) 2022 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +#include "module.h" + + +#include <assert.h> + + +#include "hex.h" +#include "list.h" +#include "plain.h" +#include "rev.h" +#include "xor.h" +#include "../../../../helpers.h" + + + +/****************************************************************************** +* * +* Paramètres : super = module dont la définition est à compléter. * +* * +* Description : Ajoute le module 'analysis....modifiers' à un module Python. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool add_analysis_scan_patterns_modifiers_module(PyObject *super) +{ + bool result; /* Bilan à retourner */ + PyObject *module; /* Sous-module mis en place */ + +#define PYCHRYSALIDE_ANALYSIS_SCAN_PATTERNS_MODIFIERS_MODULE_DOC \ + "This module provide all the features useful for scanning" \ + " binary contents." + + static PyModuleDef py_chrysalide_analysis_scan_patterns_modifiers_module = { + + .m_base = PyModuleDef_HEAD_INIT, + + .m_name = "pychrysalide.analysis.scan.patterns.modifiers", + .m_doc = PYCHRYSALIDE_ANALYSIS_SCAN_PATTERNS_MODIFIERS_MODULE_DOC, + + .m_size = -1, + + }; + + module = build_python_module(super, &py_chrysalide_analysis_scan_patterns_modifiers_module); + + result = (module != NULL); + + if (!result) + Py_XDECREF(module); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : - * +* * +* Description : Intègre les objets du module 'analysis...patterns.modifiers'.* +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool populate_analysis_scan_patterns_modifiers_module(void) +{ + bool result; /* Bilan à retourner */ + + result = true; + + if (result) result = ensure_python_scan_hex_modifier_is_registered(); + if (result) result = ensure_python_scan_modifier_list_is_registered(); + if (result) result = ensure_python_scan_plain_modifier_is_registered(); + if (result) result = ensure_python_scan_reverse_modifier_is_registered(); + if (result) result = ensure_python_scan_xor_modifier_is_registered(); + + assert(result); + + return result; + +} diff --git a/plugins/pychrysalide/analysis/scan/patterns/modifiers/module.h b/plugins/pychrysalide/analysis/scan/patterns/modifiers/module.h new file mode 100644 index 0000000..8094efc --- /dev/null +++ b/plugins/pychrysalide/analysis/scan/patterns/modifiers/module.h @@ -0,0 +1,42 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * module.h - prototypes pour l'intégration du répertoire modifiers en tant que module + * + * Copyright (C) 2022 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +#ifndef _PLUGINS_PYCHRYSALIDE_ANALYSIS_SCAN_PATTERNS_MODIFIERS_MODULE_H +#define _PLUGINS_PYCHRYSALIDE_ANALYSIS_SCAN_PATTERNS_MODIFIERS_MODULE_H + + +#include <Python.h> +#include <stdbool.h> + + + +/* Ajoute le module 'analysis.scan.patterns.modifiers' à un module Python. */ +bool add_analysis_scan_patterns_modifiers_module(PyObject *); + +/* Intègre les objets du module 'analysis.scan.patterns.modifiers'. */ +bool populate_analysis_scan_patterns_modifiers_module(void); + + + +#endif /* _PLUGINS_PYCHRYSALIDE_ANALYSIS_SCAN_PATTERNS_MODIFIERS_MODULE_H */ diff --git a/plugins/pychrysalide/analysis/scan/patterns/modifiers/plain.c b/plugins/pychrysalide/analysis/scan/patterns/modifiers/plain.c new file mode 100644 index 0000000..7a260c1 --- /dev/null +++ b/plugins/pychrysalide/analysis/scan/patterns/modifiers/plain.c @@ -0,0 +1,211 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * plain.c - équivalent Python du fichier "analysis/scan/patterns/modifiers/plain.c" + * + * Copyright (C) 2023 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 "plain.h" + + +#include <pygobject.h> + + +#include <i18n.h> +#include <analysis/scan/patterns/modifiers/plain.h> + + +#include "../modifier.h" +#include "../../../../access.h" +#include "../../../../helpers.h" + + + +CREATE_DYN_CONSTRUCTOR(scan_plain_modifier, G_TYPE_SCAN_PLAIN_MODIFIER); + +/* Initialise une instance sur la base du dérivé de GObject. */ +static int py_scan_plain_modifier_init(PyObject *, PyObject *, PyObject *); + + + +/****************************************************************************** +* * +* Paramètres : self = objet à initialiser (théoriquement). * +* args = arguments fournis à l'appel. * +* kwds = arguments de type key=val fournis. * +* * +* Description : Initialise une instance sur la base du dérivé de GObject. * +* * +* Retour : 0. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static int py_scan_plain_modifier_init(PyObject *self, PyObject *args, PyObject *kwds) +{ + int ret; /* Bilan de lecture des args. */ + +#define SCAN_PLAIN_MODIFIER_DOC \ + "The *PlainModifier* class provide an transmision of a byte pattern" \ + " without any modification." \ + "\n" \ + "Instances can be created using the following constructor:\n" \ + "\n" \ + " PlainModifier()" + + /* Initialisation d'un objet GLib */ + + ret = forward_pygobjet_init(self); + if (ret == -1) return -1; + + return 0; + +} + + +/****************************************************************************** +* * +* Paramètres : - * +* * +* Description : Fournit un accès à une définition de type à diffuser. * +* * +* Retour : Définition d'objet pour Python. * +* * +* Remarques : - * +* * +******************************************************************************/ + +PyTypeObject *get_python_scan_plain_modifier_type(void) +{ + static PyMethodDef py_scan_plain_modifier_methods[] = { + { NULL } + }; + + static PyGetSetDef py_scan_plain_modifier_getseters[] = { + { NULL } + }; + + static PyTypeObject py_scan_plain_modifier_type = { + + PyVarObject_HEAD_INIT(NULL, 0) + + .tp_name = "pychrysalide.analysis.scan.patterns.modifiers.PlainModifier", + .tp_basicsize = sizeof(PyGObject), + + .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, + + .tp_doc = SCAN_PLAIN_MODIFIER_DOC, + + .tp_methods = py_scan_plain_modifier_methods, + .tp_getset = py_scan_plain_modifier_getseters, + + .tp_init = py_scan_plain_modifier_init, + .tp_new = py_scan_plain_modifier_new, + + }; + + return &py_scan_plain_modifier_type; + +} + + +/****************************************************************************** +* * +* Paramètres : - * +* * +* Description : Prend en charge l'objet 'pychrysalide....PlainModifier'. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool ensure_python_scan_plain_modifier_is_registered(void) +{ + PyTypeObject *type; /* Type Python 'PlainModifier' */ + PyObject *module; /* Module à recompléter */ + PyObject *dict; /* Dictionnaire du module */ + + type = get_python_scan_plain_modifier_type(); + + if (!PyType_HasFeature(type, Py_TPFLAGS_READY)) + { + module = get_access_to_python_module("pychrysalide.analysis.scan.patterns.modifiers"); + + dict = PyModule_GetDict(module); + + if (!ensure_python_scan_token_modifier_is_registered()) + return false; + + if (!register_class_for_pygobject(dict, G_TYPE_SCAN_PLAIN_MODIFIER, type)) + 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 transmission d'octets à l'identique. * +* * +* Retour : Bilan de l'opération, voire indications supplémentaires. * +* * +* Remarques : - * +* * +******************************************************************************/ + +int convert_to_scan_plain_modifier(PyObject *arg, void *dst) +{ + int result; /* Bilan à retourner */ + + result = PyObject_IsInstance(arg, (PyObject *)get_python_scan_plain_modifier_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 plain modifier"); + break; + + case 1: + *((GScanPlainModifier **)dst) = G_SCAN_PLAIN_MODIFIER(pygobject_get(arg)); + break; + + default: + assert(false); + break; + + } + + return result; + +} diff --git a/plugins/pychrysalide/analysis/scan/patterns/modifiers/plain.h b/plugins/pychrysalide/analysis/scan/patterns/modifiers/plain.h new file mode 100644 index 0000000..03949d8 --- /dev/null +++ b/plugins/pychrysalide/analysis/scan/patterns/modifiers/plain.h @@ -0,0 +1,45 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * plain.h - équivalent Python du fichier "analysis/scan/patterns/modifiers/plain.h" + * + * Copyright (C) 2023 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_ANALYSIS_SCAN_PATTERNS_MODIFIERS_PLAIN_H +#define _PLUGINS_PYCHRYSALIDE_ANALYSIS_SCAN_PATTERNS_MODIFIERS_PLAIN_H + + +#include <Python.h> +#include <stdbool.h> + + + +/* Fournit un accès à une définition de type à diffuser. */ +PyTypeObject *get_python_scan_plain_modifier_type(void); + +/* Prend en charge l'objet 'pychrysalide.analysis.scan.patterns.modifiers.PlainModifier'. */ +bool ensure_python_scan_plain_modifier_is_registered(void); + +/* Tente de convertir en transmission d'octets à l'identique. */ +int convert_to_scan_plain_modifier(PyObject *, void *); + + + +#endif /* _PLUGINS_PYCHRYSALIDE_ANALYSIS_SCAN_PATTERNS_MODIFIERS_PLAIN_H */ diff --git a/plugins/pychrysalide/analysis/scan/patterns/modifiers/rev.c b/plugins/pychrysalide/analysis/scan/patterns/modifiers/rev.c new file mode 100644 index 0000000..841e929 --- /dev/null +++ b/plugins/pychrysalide/analysis/scan/patterns/modifiers/rev.c @@ -0,0 +1,211 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * hex.c - équivalent Python du fichier "analysis/scan/patterns/modifiers/hex.c" + * + * Copyright (C) 2023 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 "rev.h" + + +#include <pygobject.h> + + +#include <i18n.h> +#include <analysis/scan/patterns/modifiers/rev.h> + + +#include "../modifier.h" +#include "../../../../access.h" +#include "../../../../helpers.h" + + + +CREATE_DYN_CONSTRUCTOR(scan_reverse_modifier, G_TYPE_SCAN_REVERSE_MODIFIER); + +/* Initialise une instance sur la base du dérivé de GObject. */ +static int py_scan_reverse_modifier_init(PyObject *, PyObject *, PyObject *); + + + +/****************************************************************************** +* * +* Paramètres : self = objet à initialiser (théoriquement). * +* args = arguments fournis à l'appel. * +* kwds = arguments de type key=val fournis. * +* * +* Description : Initialise une instance sur la base du dérivé de GObject. * +* * +* Retour : 0. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static int py_scan_reverse_modifier_init(PyObject *self, PyObject *args, PyObject *kwds) +{ + int ret; /* Bilan de lecture des args. */ + +#define SCAN_HEX_MODIFIER_DOC \ + "The *ReverseModifier* class transforms a byte pattern by reversing" \ + " the order of each bytes." \ + "\n" \ + "Instances can be created using the following constructor:\n" \ + "\n" \ + " ReverseModifier()" + + /* Initialisation d'un objet GLib */ + + ret = forward_pygobjet_init(self); + if (ret == -1) return -1; + + return 0; + +} + + +/****************************************************************************** +* * +* Paramètres : - * +* * +* Description : Fournit un accès à une définition de type à diffuser. * +* * +* Retour : Définition d'objet pour Python. * +* * +* Remarques : - * +* * +******************************************************************************/ + +PyTypeObject *get_python_scan_reverse_modifier_type(void) +{ + static PyMethodDef py_scan_reverse_modifier_methods[] = { + { NULL } + }; + + static PyGetSetDef py_scan_reverse_modifier_getseters[] = { + { NULL } + }; + + static PyTypeObject py_scan_reverse_modifier_type = { + + PyVarObject_HEAD_INIT(NULL, 0) + + .tp_name = "pychrysalide.analysis.scan.patterns.modifiers.ReverseModifier", + .tp_basicsize = sizeof(PyGObject), + + .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, + + .tp_doc = SCAN_HEX_MODIFIER_DOC, + + .tp_methods = py_scan_reverse_modifier_methods, + .tp_getset = py_scan_reverse_modifier_getseters, + + .tp_init = py_scan_reverse_modifier_init, + .tp_new = py_scan_reverse_modifier_new, + + }; + + return &py_scan_reverse_modifier_type; + +} + + +/****************************************************************************** +* * +* Paramètres : - * +* * +* Description : Prend en charge l'objet 'pychrysalide....ReverseModifier'. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool ensure_python_scan_reverse_modifier_is_registered(void) +{ + PyTypeObject *type; /* Type Python ReverseModifier */ + PyObject *module; /* Module à recompléter */ + PyObject *dict; /* Dictionnaire du module */ + + type = get_python_scan_reverse_modifier_type(); + + if (!PyType_HasFeature(type, Py_TPFLAGS_READY)) + { + module = get_access_to_python_module("pychrysalide.analysis.scan.patterns.modifiers"); + + dict = PyModule_GetDict(module); + + if (!ensure_python_scan_token_modifier_is_registered()) + return false; + + if (!register_class_for_pygobject(dict, G_TYPE_SCAN_REVERSE_MODIFIER, type)) + 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 transformation d'octets par inverse. * +* * +* Retour : Bilan de l'opération, voire indications supplémentaires. * +* * +* Remarques : - * +* * +******************************************************************************/ + +int convert_to_scan_reverse_modifier(PyObject *arg, void *dst) +{ + int result; /* Bilan à retourner */ + + result = PyObject_IsInstance(arg, (PyObject *)get_python_scan_reverse_modifier_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 reverse modifier"); + break; + + case 1: + *((GScanReverseModifier **)dst) = G_SCAN_REVERSE_MODIFIER(pygobject_get(arg)); + break; + + default: + assert(false); + break; + + } + + return result; + +} diff --git a/plugins/pychrysalide/analysis/scan/patterns/modifiers/rev.h b/plugins/pychrysalide/analysis/scan/patterns/modifiers/rev.h new file mode 100644 index 0000000..fe10e1e --- /dev/null +++ b/plugins/pychrysalide/analysis/scan/patterns/modifiers/rev.h @@ -0,0 +1,45 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * rev.h - équivalent Python du fichier "analysis/scan/patterns/modifiers/rev.h" + * + * Copyright (C) 2023 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_ANALYSIS_SCAN_PATTERNS_MODIFIERS_REV_H +#define _PLUGINS_PYCHRYSALIDE_ANALYSIS_SCAN_PATTERNS_MODIFIERS_REV_H + + +#include <Python.h> +#include <stdbool.h> + + + +/* Fournit un accès à une définition de type à diffuser. */ +PyTypeObject *get_python_scan_reverse_modifier_type(void); + +/* Prend en charge l'objet 'pychrysalide.analysis.scan.patterns.modifiers.ReverseModifier'. */ +bool ensure_python_scan_reverse_modifier_is_registered(void); + +/* Tente de convertir en transformation d'octets par inverse. */ +int convert_to_scan_reverse_modifier(PyObject *, void *); + + + +#endif /* _PLUGINS_PYCHRYSALIDE_ANALYSIS_SCAN_PATTERNS_MODIFIERS_REV_H */ diff --git a/plugins/pychrysalide/analysis/scan/patterns/modifiers/xor.c b/plugins/pychrysalide/analysis/scan/patterns/modifiers/xor.c new file mode 100644 index 0000000..17a32f4 --- /dev/null +++ b/plugins/pychrysalide/analysis/scan/patterns/modifiers/xor.c @@ -0,0 +1,210 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * xor.c - équivalent Python du fichier "analysis/scan/patterns/modifiers/xor.c" + * + * Copyright (C) 2023 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 "xor.h" + + +#include <pygobject.h> + + +#include <i18n.h> +#include <analysis/scan/patterns/modifiers/xor.h> + + +#include "../modifier.h" +#include "../../../../access.h" +#include "../../../../helpers.h" + + + +CREATE_DYN_CONSTRUCTOR(scan_xor_modifier, G_TYPE_SCAN_XOR_MODIFIER); + +/* Initialise une instance sur la base du dérivé de GObject. */ +static int py_scan_xor_modifier_init(PyObject *, PyObject *, PyObject *); + + + +/****************************************************************************** +* * +* Paramètres : self = objet à initialiser (théoriquement). * +* args = arguments fournis à l'appel. * +* kwds = arguments de type key=val fournis. * +* * +* Description : Initialise une instance sur la base du dérivé de GObject. * +* * +* Retour : 0. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static int py_scan_xor_modifier_init(PyObject *self, PyObject *args, PyObject *kwds) +{ + int ret; /* Bilan de lecture des args. */ + +#define SCAN_XOR_MODIFIER_DOC \ + "The *XorModifier* class transforms a byte pattern by XORing bytes.\n" \ + "\n" \ + "Instances can be created using the following constructor:\n" \ + "\n" \ + " XorModifier()" + + /* Initialisation d'un objet GLib */ + + ret = forward_pygobjet_init(self); + if (ret == -1) return -1; + + return 0; + +} + + +/****************************************************************************** +* * +* Paramètres : - * +* * +* Description : Fournit un accès à une définition de type à diffuser. * +* * +* Retour : Définition d'objet pour Python. * +* * +* Remarques : - * +* * +******************************************************************************/ + +PyTypeObject *get_python_scan_xor_modifier_type(void) +{ + static PyMethodDef py_scan_xor_modifier_methods[] = { + { NULL } + }; + + static PyGetSetDef py_scan_xor_modifier_getseters[] = { + { NULL } + }; + + static PyTypeObject py_scan_xor_modifier_type = { + + PyVarObject_HEAD_INIT(NULL, 0) + + .tp_name = "pychrysalide.analysis.scan.patterns.modifiers.XorModifier", + .tp_basicsize = sizeof(PyGObject), + + .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, + + .tp_doc = SCAN_XOR_MODIFIER_DOC, + + .tp_methods = py_scan_xor_modifier_methods, + .tp_getset = py_scan_xor_modifier_getseters, + + .tp_init = py_scan_xor_modifier_init, + .tp_new = py_scan_xor_modifier_new, + + }; + + return &py_scan_xor_modifier_type; + +} + + +/****************************************************************************** +* * +* Paramètres : - * +* * +* Description : Prend en charge l'objet 'pychrysalide....XorModifier'. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool ensure_python_scan_xor_modifier_is_registered(void) +{ + PyTypeObject *type; /* Type Python XorModifier */ + PyObject *module; /* Module à recompléter */ + PyObject *dict; /* Dictionnaire du module */ + + type = get_python_scan_xor_modifier_type(); + + if (!PyType_HasFeature(type, Py_TPFLAGS_READY)) + { + module = get_access_to_python_module("pychrysalide.analysis.scan.patterns.modifiers"); + + dict = PyModule_GetDict(module); + + if (!ensure_python_scan_token_modifier_is_registered()) + return false; + + if (!register_class_for_pygobject(dict, G_TYPE_SCAN_XOR_MODIFIER, type)) + 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 transformation d'octets par inverse. * +* * +* Retour : Bilan de l'opération, voire indications supplémentaires. * +* * +* Remarques : - * +* * +******************************************************************************/ + +int convert_to_scan_xor_modifier(PyObject *arg, void *dst) +{ + int result; /* Bilan à retourner */ + + result = PyObject_IsInstance(arg, (PyObject *)get_python_scan_xor_modifier_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 XOR modifier"); + break; + + case 1: + *((GScanXorModifier **)dst) = G_SCAN_XOR_MODIFIER(pygobject_get(arg)); + break; + + default: + assert(false); + break; + + } + + return result; + +} diff --git a/plugins/pychrysalide/analysis/scan/patterns/modifiers/xor.h b/plugins/pychrysalide/analysis/scan/patterns/modifiers/xor.h new file mode 100644 index 0000000..7b9bb69 --- /dev/null +++ b/plugins/pychrysalide/analysis/scan/patterns/modifiers/xor.h @@ -0,0 +1,45 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * xor.h - équivalent Python du fichier "analysis/scan/patterns/modifiers/xor.h" + * + * Copyright (C) 2023 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_ANALYSIS_SCAN_PATTERNS_MODIFIERS_XOR_H +#define _PLUGINS_PYCHRYSALIDE_ANALYSIS_SCAN_PATTERNS_MODIFIERS_XOR_H + + +#include <Python.h> +#include <stdbool.h> + + + +/* Fournit un accès à une définition de type à diffuser. */ +PyTypeObject *get_python_scan_xor_modifier_type(void); + +/* Prend en charge l'objet 'pychrysalide.analysis.scan.patterns.modifiers.XorModifier'. */ +bool ensure_python_scan_xor_modifier_is_registered(void); + +/* Tente de convertir en transformation d'octets par inverse. */ +int convert_to_scan_xor_modifier(PyObject *, void *); + + + +#endif /* _PLUGINS_PYCHRYSALIDE_ANALYSIS_SCAN_PATTERNS_MODIFIERS_XOR_H */ diff --git a/plugins/pychrysalide/analysis/scan/patterns/module.c b/plugins/pychrysalide/analysis/scan/patterns/module.c new file mode 100644 index 0000000..123b23a --- /dev/null +++ b/plugins/pychrysalide/analysis/scan/patterns/module.c @@ -0,0 +1,114 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * module.c - intégration du répertoire patterns en tant que module + * + * Copyright (C) 2022 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +#include "module.h" + + +#include <assert.h> + + +#include "backend.h" +#include "modifier.h" +#include "backends/module.h" +#include "modifiers/module.h" +#include "../../../helpers.h" + + + +/****************************************************************************** +* * +* Paramètres : super = module dont la définition est à compléter. * +* * +* Description : Ajoute le module 'analysis.scan.patterns' à un module Python.* +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool add_analysis_scan_patterns_module(PyObject *super) +{ + bool result; /* Bilan à retourner */ + PyObject *module; /* Sous-module mis en place */ + +#define PYCHRYSALIDE_ANALYSIS_SCAN_PATTERNS_MODULE_DOC \ + "This module provide all the features useful for scanning" \ + " binary contents." + + static PyModuleDef py_chrysalide_analysis_scan_patterns_module = { + + .m_base = PyModuleDef_HEAD_INIT, + + .m_name = "pychrysalide.analysis.scan.patterns", + .m_doc = PYCHRYSALIDE_ANALYSIS_SCAN_PATTERNS_MODULE_DOC, + + .m_size = -1, + + }; + + module = build_python_module(super, &py_chrysalide_analysis_scan_patterns_module); + + result = (module != NULL); + + if (result) result = add_analysis_scan_patterns_backends_module(module); + if (result) result = add_analysis_scan_patterns_modifiers_module(module); + + if (!result) + Py_XDECREF(module); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : - * +* * +* Description : Intègre les objets du module 'analysis.scan.patterns'. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool populate_analysis_scan_patterns_module(void) +{ + bool result; /* Bilan à retourner */ + + result = true; + + if (result) result = ensure_python_engine_backend_is_registered(); + if (result) result = ensure_python_scan_token_modifier_is_registered(); + + if (result) result = populate_analysis_scan_patterns_backends_module(); + if (result) result = populate_analysis_scan_patterns_modifiers_module(); + + assert(result); + + return result; + +} diff --git a/plugins/pychrysalide/analysis/scan/patterns/module.h b/plugins/pychrysalide/analysis/scan/patterns/module.h new file mode 100644 index 0000000..bc25129 --- /dev/null +++ b/plugins/pychrysalide/analysis/scan/patterns/module.h @@ -0,0 +1,42 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * module.h - prototypes pour l'intégration du répertoire patterns en tant que module + * + * Copyright (C) 2022 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +#ifndef _PLUGINS_PYCHRYSALIDE_ANALYSIS_SCAN_PATTERNS_MODULE_H +#define _PLUGINS_PYCHRYSALIDE_ANALYSIS_SCAN_PATTERNS_MODULE_H + + +#include <Python.h> +#include <stdbool.h> + + + +/* Ajoute le module 'analysis.scan.patterns' à un module Python. */ +bool add_analysis_scan_patterns_module(PyObject *); + +/* Intègre les objets du module 'analysis.scan.patterns'. */ +bool populate_analysis_scan_patterns_module(void); + + + +#endif /* _PLUGINS_PYCHRYSALIDE_ANALYSIS_SCAN_PATTERNS_MODULE_H */ diff --git a/plugins/pychrysalide/analysis/scan/scanner.c b/plugins/pychrysalide/analysis/scan/scanner.c new file mode 100644 index 0000000..bc58c9a --- /dev/null +++ b/plugins/pychrysalide/analysis/scan/scanner.c @@ -0,0 +1,487 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * scanner.c - équivalent Python du fichier "analysis/scan/scanner.c" + * + * Copyright (C) 2022 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +#include "scanner.h" + + +#include <malloc.h> +#include <pygobject.h> + + +#include <i18n.h> +#include <analysis/content.h> +#include <analysis/scan/context.h> +#include <analysis/scan/scanner-int.h> + + +#include "context.h" +#include "options.h" +#include "../content.h" +#include "../../access.h" +#include "../../helpers.h" + + + +CREATE_DYN_CONSTRUCTOR(content_scanner, G_TYPE_CONTENT_SCANNER); + +/* Initialise une instance sur la base du dérivé de GObject. */ +static int py_content_scanner_init(PyObject *, PyObject *, PyObject *); + +/* Lance une analyse d'un contenu binaire. */ +static PyObject *py_content_scanner_analyze(PyObject *, PyObject *); + +/* Convertit un gestionnaire de recherches en JSON. */ +static PyObject *py_content_scanner_convert_to_json(PyObject *, PyObject *); + +/* Indique le chemin d'un éventuel fichier de source. */ +static PyObject *py_content_scanner_get_filename(PyObject *, void *); + + + +/****************************************************************************** +* * +* Paramètres : self = objet à initialiser (théoriquement). * +* args = arguments fournis à l'appel. * +* kwds = arguments de type key=val fournis. * +* * +* Description : Initialise une instance sur la base du dérivé de GObject. * +* * +* Retour : 0. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static int py_content_scanner_init(PyObject *self, PyObject *args, PyObject *kwds) +{ + const char *text; /* Contenu de règles à traiter */ + Py_ssize_t len; /* Taille de ce nom */ + const char *filename; /* Fichier de définitions */ + int ret; /* Bilan de lecture des args. */ + GContentScanner *scanner; /* Création GLib à transmettre */ + + static char *kwlist[] = { "text", "filename", NULL }; + +#define CONTENT_SCANNER_DOC \ + "A ContentScanner object provides support for rules processing" \ + " against binary contents.\n" \ + "\n" \ + "Instances can be created using one of the following" \ + " constructors:\n" \ + "\n" \ + " ContentScanner(text=str)" \ + "\n" \ + " ContentScanner(filename=str)" \ + "\n" \ + "Where *text* is a string for the rules definitions and" \ + " *filename* an alternative string for a path pointing to a" \ + " definition file." + + /* Récupération des paramètres */ + + text = NULL; + len = 0; + filename = NULL; + + ret = PyArg_ParseTupleAndKeywords(args, kwds, "|s#s", kwlist, &text, &len, &filename); + if (!ret) return -1; + + /* Initialisation d'un objet GLib */ + + ret = forward_pygobjet_init(self); + if (ret == -1) return -1; + + /* Eléments de base */ + + scanner = G_CONTENT_SCANNER(pygobject_get(self)); + + if (text != NULL) + { + if (!g_content_scanner_create_from_text(scanner, text, len)) + { + PyErr_SetString(PyExc_ValueError, _("Unable to create content scanner.")); + return -1; + } + + } + + else if (filename != NULL) + { + if (!g_content_scanner_create_from_file(scanner, filename)) + { + PyErr_SetString(PyExc_ValueError, _("Unable to create content scanner.")); + return -1; + } + + } + + else + { + PyErr_SetString(PyExc_ValueError, _("Unable to create empty content scanner.")); + return -1; + } + + return 0; + +} + + +/****************************************************************************** +* * +* Paramètres : self = classe représentant un format. * +* args = arguments fournis à l'appel. * +* * +* Description : Lance une analyse d'un contenu binaire. * +* * +* Retour : Contexte de suivi pour l'analyse menée. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static PyObject *py_content_scanner_analyze(PyObject *self, PyObject *args) +{ + PyObject *result; /* Contexte de suivi à renvoyer*/ + GScanOptions *options; /* Paramètres d'analyse */ + GBinContent *content; /* Contenu binaire à traiter */ + int ret; /* Bilan de lecture des args. */ + GContentScanner *scanner; /* Encadrement de recherche */ + GScanContext *context; /* Contexte de suivi */ + +#define CONTENT_SCANNER_ANALYZE_METHOD PYTHON_METHOD_DEF \ +( \ + analyze, "$self, options, content, /", \ + METH_VARARGS, py_content_scanner, \ + "Run a scan against a binary content.\n" \ + "\n" \ + "The *content* argument is a pychrysalide.analysis.BinContent" \ + " object pointing to data to analyze.\n" \ + "\n" \ + "The method returns a pychrysalide.analysis.scan.ScanContext" \ + " object tracking all the scan results." \ +) + + ret = PyArg_ParseTuple(args, "O&O&", convert_to_scan_options, &options, convert_to_binary_content, &content); + if (!ret) return NULL; + + scanner = G_CONTENT_SCANNER(pygobject_get(self)); + + context = g_content_scanner_analyze(scanner, options, content); + + result = pygobject_new(G_OBJECT(context)); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : self = classe représentant un format. * +* args = arguments fournis à l'appel. * +* * +* Description : Convertit un gestionnaire de recherches en texte. * +* * +* Retour : Données textuelles ou None en cas d'erreur. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static PyObject *py_content_scanner_convert_to_text(PyObject *self, PyObject *args) +{ + PyObject *result; /* Contexte de suivi à renvoyer*/ + GScanContext *context; /* Contexte d'analyse */ + int ret; /* Bilan de lecture des args. */ + GContentScanner *scanner; /* Encadrement de recherche */ + char *out; /* Données en sortie */ + +#define CONTENT_SCANNER_CONVERT_TO_TEXT_METHOD PYTHON_METHOD_DEF \ +( \ + convert_to_text, "$self, context, /", \ + METH_VARARGS, py_content_scanner, \ + "Output a scan results as text.\n" \ + "\n" \ + "The *context* argument is a pychrysalide.analysis.scan.ScanContext" \ + " instance provided by a previous call to *self.analyze()*. This" \ + " context stores all the scan results.\n" \ + "\n" \ + "The method returns a string value, or *None* in case of failure." \ +) + + ret = PyArg_ParseTuple(args, "O&", convert_to_scan_context, &context); + if (!ret) return NULL; + + scanner = G_CONTENT_SCANNER(pygobject_get(self)); + + out = g_content_scanner_convert_to_text(scanner, context); + + if (out != NULL) + { + result = PyUnicode_FromString(out); + free(out); + } + else + { + result = Py_None; + Py_INCREF(result); + } + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : self = classe représentant un format. * +* args = arguments fournis à l'appel. * +* * +* Description : Convertit un gestionnaire de recherches en JSON. * +* * +* Retour : Données textuelles au format JSON ou None en cas d'erreur. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static PyObject *py_content_scanner_convert_to_json(PyObject *self, PyObject *args) +{ + PyObject *result; /* Contexte de suivi à renvoyer*/ + GScanContext *context; /* Contexte d'analyse */ + int ret; /* Bilan de lecture des args. */ + GContentScanner *scanner; /* Encadrement de recherche */ + char *out; /* Données en sortie */ + +#define CONTENT_SCANNER_CONVERT_TO_JSON_METHOD PYTHON_METHOD_DEF \ +( \ + convert_to_json, "$self, context, /", \ + METH_VARARGS, py_content_scanner, \ + "Output a scan results as JSON data.\n" \ + "\n" \ + "The *context* argument is a pychrysalide.analysis.scan.ScanContext" \ + " instance provided by a previous call to *self.analyze()*. This" \ + " context stores all the scan results.\n" \ + "\n" \ + "The method returns JSON data as a string value, or *None* in case" \ + " of failure." \ +) + + ret = PyArg_ParseTuple(args, "O&", convert_to_scan_context, &context); + if (!ret) return NULL; + + scanner = G_CONTENT_SCANNER(pygobject_get(self)); + + out = g_content_scanner_convert_to_json(scanner, context); + + if (out != NULL) + { + result = PyUnicode_FromString(out); + free(out); + } + else + { + result = Py_None; + Py_INCREF(result); + } + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : self = objet Python concerné par l'appel. * +* closure = non utilisé ici. * +* * +* Description : Indique le chemin d'un éventuel fichier de source. * +* * +* Retour : Chemin d'un éventuel fichier de définitions ou NULL. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static PyObject *py_content_scanner_get_filename(PyObject *self, void *closure) +{ + PyObject *result; /* Valeur à retourner */ + GContentScanner *scanner; /* Analyseur à consulter */ + const char *filename; /* Chemin d'accès à transmettre*/ + +#define CONTENT_SCANNER_FILENAME_ATTRIB PYTHON_GET_DEF_FULL \ +( \ + filename, py_content_scanner, \ + "Provide the access path to the source file of the rules'" \ + " definition, or *None* if these rules have not been loaded"\ + " from memory." \ +) + + scanner = G_CONTENT_SCANNER(pygobject_get(self)); + + filename = g_content_scanner_get_filename(scanner); + + if (filename != NULL) + result = PyUnicode_FromString(filename); + + else + { + 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_content_scanner_type(void) +{ + static PyMethodDef py_content_scanner_methods[] = { + CONTENT_SCANNER_ANALYZE_METHOD, + CONTENT_SCANNER_CONVERT_TO_TEXT_METHOD, + CONTENT_SCANNER_CONVERT_TO_JSON_METHOD, + { NULL } + }; + + static PyGetSetDef py_content_scanner_getseters[] = { + CONTENT_SCANNER_FILENAME_ATTRIB, + { NULL } + }; + + static PyTypeObject py_content_scanner_type = { + + PyVarObject_HEAD_INIT(NULL, 0) + + .tp_name = "pychrysalide.analysis.scan.ContentScanner", + .tp_basicsize = sizeof(PyGObject), + + .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, + + .tp_doc = CONTENT_SCANNER_DOC, + + .tp_methods = py_content_scanner_methods, + .tp_getset = py_content_scanner_getseters, + + .tp_init = py_content_scanner_init, + .tp_new = py_content_scanner_new, + + }; + + return &py_content_scanner_type; + +} + + +/****************************************************************************** +* * +* Paramètres : - * +* * +* Description : Prend en charge l'objet 'pychrysalide...scan.ContentScanner. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool ensure_python_content_scanner_is_registered(void) +{ + PyTypeObject *type; /* Type Python 'ContentScanner'*/ + PyObject *module; /* Module à recompléter */ + PyObject *dict; /* Dictionnaire du module */ + + type = get_python_content_scanner_type(); + + if (!PyType_HasFeature(type, Py_TPFLAGS_READY)) + { + module = get_access_to_python_module("pychrysalide.analysis.scan"); + + dict = PyModule_GetDict(module); + + if (!register_class_for_pygobject(dict, G_TYPE_CONTENT_SCANNER, type)) + 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 scanner de contenus binaires. * +* * +* Retour : Bilan de l'opération, voire indications supplémentaires. * +* * +* Remarques : - * +* * +******************************************************************************/ + +int convert_to_content_scanner(PyObject *arg, void *dst) +{ + int result; /* Bilan à retourner */ + + result = PyObject_IsInstance(arg, (PyObject *)get_python_content_scanner_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 content scanner"); + break; + + case 1: + *((GContentScanner **)dst) = G_CONTENT_SCANNER(pygobject_get(arg)); + break; + + default: + assert(false); + break; + + } + + return result; + +} diff --git a/plugins/pychrysalide/analysis/scan/scanner.h b/plugins/pychrysalide/analysis/scan/scanner.h new file mode 100644 index 0000000..b3b1baf --- /dev/null +++ b/plugins/pychrysalide/analysis/scan/scanner.h @@ -0,0 +1,45 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * scanner.h - prototypes pour l'équivalent Python du fichier "analysis/scan/scanner.h" + * + * Copyright (C) 2022 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +#ifndef _PLUGINS_PYCHRYSALIDE_ANALYSIS_SCAN_SCANNER_H +#define _PLUGINS_PYCHRYSALIDE_ANALYSIS_SCAN_SCANNER_H + + +#include <Python.h> +#include <stdbool.h> + + + +/* Fournit un accès à une définition de type à diffuser. */ +PyTypeObject *get_python_content_scanner_type(void); + +/* Prend en charge l'objet 'pychrysalide.analysis.scan.ContentScanner'. */ +bool ensure_python_content_scanner_is_registered(void); + +/* Tente de convertir en scanner de contenus binaires. */ +int convert_to_content_scanner(PyObject *, void *); + + + +#endif /* _PLUGINS_PYCHRYSALIDE_ANALYSIS_SCAN_SCANNER_H */ diff --git a/plugins/pychrysalide/analysis/scan/space.c b/plugins/pychrysalide/analysis/scan/space.c new file mode 100644 index 0000000..6ea87b8 --- /dev/null +++ b/plugins/pychrysalide/analysis/scan/space.c @@ -0,0 +1,283 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * space.c - équivalent Python du fichier "analysis/scan/space.c" + * + * Copyright (C) 2022 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +#include "space.h" + + +#include <pygobject.h> + + +#include <i18n.h> +#include <analysis/content.h> +#include <analysis/scan/item.h> +#include <analysis/scan/space-int.h> +#include <plugins/pychrysalide/access.h> +#include <plugins/pychrysalide/helpers.h> +#include <plugins/pychrysalide/analysis/content.h> + + +#include "item.h" + + + +CREATE_DYN_CONSTRUCTOR(scan_namespace, G_TYPE_SCAN_NAMESPACE); + +/* Initialise une instance sur la base du dérivé de GObject. */ +static int py_scan_namespace_init(PyObject *, PyObject *, PyObject *); + +/* Intègre un nouvel élément dans l'esapce de noms. */ +static PyObject *py_scan_namespace_register_item(PyObject *, PyObject *); + + + +/****************************************************************************** +* * +* Paramètres : self = objet à initialiser (théoriquement). * +* args = arguments fournis à l'appel. * +* kwds = arguments de type key=val fournis. * +* * +* Description : Initialise une instance sur la base du dérivé de GObject. * +* * +* Retour : 0. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static int py_scan_namespace_init(PyObject *self, PyObject *args, PyObject *kwds) +{ + const char *name; /* Désignation de l'espace */ + int ret; /* Bilan de lecture des args. */ + GScanNamespace *space; /* Création GLib à transmettre */ + +#define SCAN_NAMESPACE_DOC \ + "ScanNamespace defines a group of properties and functions for a" \ + " given scan theme.\n" \ + "\n" \ + "Instances can be created using the following constructor:\n" \ + "\n" \ + " ScanNamespace(name)" \ + "\n" \ + "Where *name* is a string providing the name of the new namespace." + + /* Récupération des paramètres */ + + ret = PyArg_ParseTuple(args, "s", &name); + if (!ret) return -1; + + /* Initialisation d'un objet GLib */ + + ret = forward_pygobjet_init(self); + if (ret == -1) return -1; + + /* Elément de base */ + + space = G_SCAN_NAMESPACE(pygobject_get(self)); + + if (!g_scan_namespace_create(space, name)) + { + PyErr_SetString(PyExc_ValueError, _("Unable to create scan namespace.")); + return -1; + } + + return 0; + +} + + +/****************************************************************************** +* * +* Paramètres : self = objet représentant une table de chaînes. * +* args = arguments fournis pour l'opération. * +* * +* Description : Intègre un nouvel élément dans l'esapce de noms. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static PyObject *py_scan_namespace_register_item(PyObject *self, PyObject *args) +{ + PyObject *result; /* Bilan à retourner */ + GScanRegisteredItem *item; /* Elément d'évaluation à lier */ + int ret; /* Bilan de lecture des args. */ + GScanNamespace *space; /* Version native */ + bool status; /* Bilan de l'opération */ + +#define SCAN_NAMESPACE_REGISTER_ITEM_METHOD PYTHON_METHOD_DEF \ +( \ + register_item, "$self, item, /", \ + METH_VARARGS, py_scan_namespace, \ + "Include an item into a namespace.\n" \ + "\n" \ + "The *item* argument has to be a pychrysalide.analysis.scan.RegisteredItem" \ + " instance.\n" \ + "\n" \ + "The function returns a boolean value translating the operation status:" \ + " *True* in case of success, *False* for a failure.\n" \ +) + + ret = PyArg_ParseTuple(args, "O&", convert_to_scan_registered_item, &item); + if (!ret) return NULL; + + space = G_SCAN_NAMESPACE(pygobject_get(self)); + + status = g_scan_namespace_register_item(space, item); + + result = status ? Py_True : Py_False; + 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_scan_namespace_type(void) +{ + static PyMethodDef py_scan_namespace_methods[] = { + SCAN_NAMESPACE_REGISTER_ITEM_METHOD, + { NULL } + }; + + static PyGetSetDef py_scan_namespace_getseters[] = { + { NULL } + }; + + static PyTypeObject py_scan_namespace_type = { + + PyVarObject_HEAD_INIT(NULL, 0) + + .tp_name = "pychrysalide.analysis.scan.ScanNamespace", + .tp_basicsize = sizeof(PyGObject), + + .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, + + .tp_doc = SCAN_NAMESPACE_DOC, + + .tp_methods = py_scan_namespace_methods, + .tp_getset = py_scan_namespace_getseters, + + .tp_init = py_scan_namespace_init, + .tp_new = py_scan_namespace_new, + + }; + + return &py_scan_namespace_type; + +} + + +/****************************************************************************** +* * +* Paramètres : - * +* * +* Description : Prend en charge l'objet 'pychrysalide...scan.ScanNamespace'. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool ensure_python_scan_namespace_is_registered(void) +{ + PyTypeObject *type; /* Type Python 'ScanNamespace' */ + PyObject *module; /* Module à recompléter */ + PyObject *dict; /* Dictionnaire du module */ + + type = get_python_scan_namespace_type(); + + if (!PyType_HasFeature(type, Py_TPFLAGS_READY)) + { + module = get_access_to_python_module("pychrysalide.analysis.scan"); + + dict = PyModule_GetDict(module); + + if (!register_class_for_pygobject(dict, G_TYPE_SCAN_NAMESPACE, type)) + 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 espace de noms pour scan. * +* * +* Retour : Bilan de l'opération, voire indications supplémentaires. * +* * +* Remarques : - * +* * +******************************************************************************/ + +int convert_to_scan_namespace(PyObject *arg, void *dst) +{ + int result; /* Bilan à retourner */ + + result = PyObject_IsInstance(arg, (PyObject *)get_python_scan_namespace_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 scan namespace"); + break; + + case 1: + *((GScanNamespace **)dst) = G_SCAN_NAMESPACE(pygobject_get(arg)); + break; + + default: + assert(false); + break; + + } + + return result; + +} diff --git a/plugins/pychrysalide/analysis/scan/space.h b/plugins/pychrysalide/analysis/scan/space.h new file mode 100644 index 0000000..0166c04 --- /dev/null +++ b/plugins/pychrysalide/analysis/scan/space.h @@ -0,0 +1,45 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * space.h - prototypes pour l'équivalent Python du fichier "analysis/scan/space.h" + * + * Copyright (C) 2022 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +#ifndef _PLUGINS_PYCHRYSALIDE_ANALYSIS_SCAN_SPACE_H +#define _PLUGINS_PYCHRYSALIDE_ANALYSIS_SCAN_SPACE_H + + +#include <Python.h> +#include <stdbool.h> + + + +/* Fournit un accès à une définition de type à diffuser. */ +PyTypeObject *get_python_scan_namespace_type(void); + +/* Prend en charge l'objet 'pychrysalide.analysis.scan.ScanNamespace'. */ +bool ensure_python_scan_namespace_is_registered(void); + +/* Tente de convertir en espace de noms pour scan. */ +int convert_to_scan_namespace(PyObject *, void *); + + + +#endif /* _PLUGINS_PYCHRYSALIDE_ANALYSIS_SCAN_SPACE_H */ diff --git a/plugins/pychrysalide/analysis/storage/Makefile.am b/plugins/pychrysalide/analysis/storage/Makefile.am index 01240cb..d0a4df4 100644 --- a/plugins/pychrysalide/analysis/storage/Makefile.am +++ b/plugins/pychrysalide/analysis/storage/Makefile.am @@ -9,19 +9,10 @@ libpychrysaanalysisstorage_la_SOURCES = \ storage.h storage.c \ tpmem.h tpmem.c -libpychrysaanalysisstorage_la_LIBADD = - -libpychrysaanalysisstorage_la_LDFLAGS = +libpychrysaanalysisstorage_la_CFLAGS = $(TOOLKIT_CFLAGS) $(LIBXML_CFLAGS) $(LIBPYTHON_INTERPRETER_CFLAGS) $(LIBPYGOBJECT_CFLAGS) \ + -I$(top_srcdir)/src -DNO_IMPORT_PYGOBJECT devdir = $(includedir)/chrysalide/$(subdir) dev_HEADERS = $(libpychrysaanalysisstorage_la_SOURCES:%c=) - - -AM_CPPFLAGS = $(LIBGTK_CFLAGS) $(LIBXML_CFLAGS) $(LIBPYTHON_CFLAGS) $(LIBPYGOBJECT_CFLAGS) \ - -I$(top_srcdir)/src - -AM_CFLAGS = $(DEBUG_CFLAGS) $(WARNING_FLAGS) $(COMPLIANCE_FLAGS) - -SUBDIRS = diff --git a/plugins/pychrysalide/analysis/storage/cache.c b/plugins/pychrysalide/analysis/storage/cache.c index 9859623..8cd5bac 100644 --- a/plugins/pychrysalide/analysis/storage/cache.c +++ b/plugins/pychrysalide/analysis/storage/cache.c @@ -100,7 +100,7 @@ static PyObject *py_object_cache_new(PyTypeObject *type, PyObject *args, PyObjec if (first_time) { - status = register_class_for_dynamic_pygobject(gtype, type, base); + status = register_class_for_dynamic_pygobject(gtype, type); if (!status) { @@ -304,7 +304,7 @@ bool ensure_python_object_cache_is_registered(void) dict = PyModule_GetDict(module); - if (!register_class_for_pygobject(dict, G_TYPE_OBJECT_CACHE, type, &PyGObject_Type)) + if (!register_class_for_pygobject(dict, G_TYPE_OBJECT_CACHE, type)) return false; } diff --git a/plugins/pychrysalide/analysis/storage/storage.c b/plugins/pychrysalide/analysis/storage/storage.c index 107980e..c54fe0f 100644 --- a/plugins/pychrysalide/analysis/storage/storage.c +++ b/plugins/pychrysalide/analysis/storage/storage.c @@ -33,7 +33,6 @@ #include "serialize.h" -#include "../loaded.h" #include "../../access.h" #include "../../helpers.h" #include "../../common/packed.h" @@ -54,8 +53,11 @@ static int py_object_storage_init(PyObject *, PyObject *, PyObject *); /* -------------------------- TAMPON POUR CODE DESASSEMBLE -------------------------- */ -/* Ajoute le support d'un nouveau groupe d'objets construits. */ -static PyObject *py_object_storage_add_backend(PyObject *, PyObject *); +/* Charge le support d'une conservation d'objets en place. */ +static PyObject *py_object_storage_load(PyObject *, PyObject *); + +/* Sauvegarde le support d'une conservation d'objets en place. */ +static PyObject *py_object_storage_store(PyObject *, PyObject *); /* Charge un objet à partir de données rassemblées. */ static PyObject *py_object_storage_load_object(PyObject *, PyObject *); @@ -113,7 +115,7 @@ static PyObject *py_object_storage_new(PyTypeObject *type, PyObject *args, PyObj if (first_time) { - status = register_class_for_dynamic_pygobject(gtype, type, base); + status = register_class_for_dynamic_pygobject(gtype, type); if (!status) { @@ -152,7 +154,7 @@ static PyObject *py_object_storage_new(PyTypeObject *type, PyObject *args, PyObj static int py_object_storage_init(PyObject *self, PyObject *args, PyObject *kwds) { - GLoadedContent *loaded; /* Contenu chargé et traité */ + const char *hash; /* Empreinte de contenu */ int ret; /* Bilan de lecture des args. */ GObjectStorage *storage; /* Mécanismes natifs */ @@ -162,14 +164,14 @@ static int py_object_storage_init(PyObject *self, PyObject *args, PyObject *kwds "\n" \ "Instances can be created using the following constructor:\n" \ "\n" \ - " ObjectStorage(loaded)" \ + " ObjectStorage(hash)" \ "\n" \ - "Where *loaded* is a pychrysalide.analysis.LoadedContent instance" \ - " linked to the objects which can apply for a storage process." + "Where *hash* should a string built from the checksum of the" \ + " relative binary content linked to the storage.pychrysalide." /* Récupération des paramètres */ - ret = PyArg_ParseTuple(args, "O&", convert_to_loaded_content, &loaded); + ret = PyArg_ParseTuple(args, "s", &hash); if (!ret) return -1; /* Initialisation d'un objet GLib */ @@ -181,8 +183,7 @@ static int py_object_storage_init(PyObject *self, PyObject *args, PyObject *kwds storage = G_OBJECT_STORAGE(pygobject_get(self)); - storage->loaded = loaded; - g_object_ref(G_OBJECT(loaded)); + storage->hash = strdup(hash); return 0; @@ -200,7 +201,61 @@ static int py_object_storage_init(PyObject *self, PyObject *args, PyObject *kwds * Paramètres : self = classe représentant une mémorisation de types. * * args = arguments fournis à l'appel. * * * -* Description : Ajoute le support d'un nouveau groupe d'objets construits. * +* Description : Charge le support d'une conservation d'objets en place. * +* * +* Retour : Gestionnaire de conservations construit ou None si erreur. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static PyObject *py_object_storage_load(PyObject *self, PyObject *args) +{ + PyObject *result; /* Emplacement à retourner */ + packed_buffer_t *pbuf; /* Tampon de données à employer*/ + 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." \ +) + + ret = PyArg_ParseTuple(args, "O&", convert_to_packed_buffer, &pbuf); + if (!ret) return NULL; + + storage = g_object_storage_load(pbuf); + + if (storage == NULL) + { + result = Py_None; + Py_INCREF(result); + } + else + { + result = pygobject_new(G_OBJECT(storage)); + g_object_unref(G_OBJECT(storage)); + } + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : self = classe représentant une mémorisation de types. * +* args = arguments fournis à l'appel. * +* * +* Description : Sauvegarde le support d'une conservation d'objets en place. * * * * Retour : Bilan de l'opération. * * * @@ -208,37 +263,32 @@ static int py_object_storage_init(PyObject *self, PyObject *args, PyObject *kwds * * ******************************************************************************/ -static PyObject *py_object_storage_add_backend(PyObject *self, PyObject *args) +static PyObject *py_object_storage_store(PyObject *self, PyObject *args) { - PyObject *result; /* Bilan à retourner */ - const char *name; /* Désignation de groupe */ - const char *filename; /* Nom de fichier à associer */ + PyObject *result; /* Emplacement à retourner */ + 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_ADD_BACKEND_METHOD PYTHON_METHOD_DEF \ -( \ - add_backend, "$self, name, /, filename", \ - METH_VARARGS, py_object_storage, \ - "Add storage support for a new kind of GLib objects.\n" \ - "\n" \ - "The *name* is a string label for the group of target objects" \ - " and the optional *filename* points to a file used to load" \ - " objects.\n" \ - "\n" \ - "The result is a boolean value indicating the status of" \ - " the operation: True for success, False for failure." \ +#define OBJECT_STORAGE_STORE_METHOD PYTHON_METHOD_DEF \ +( \ + store, "$self, pbuf, /", \ + METH_VARARGS, py_object_storage, \ + "Save a storage into a buffer.\n" \ + "\n" \ + "The *pbuf* has to be an instance of type" \ + " pychrysalide.common.PackedBuffer.\n" \ + "\n" \ + "The result is *True* on success, *False* otherwise." \ ) - filename = NULL; - - ret = PyArg_ParseTuple(args, "s|s", &name, &filename); + ret = PyArg_ParseTuple(args, "O&", convert_to_packed_buffer, &pbuf); if (!ret) return NULL; storage = G_OBJECT_STORAGE(pygobject_get(self)); - status = g_object_storage_add_backend(storage, name, filename); + status = g_object_storage_store(storage, pbuf); result = status ? Py_True : Py_False; Py_INCREF(result); @@ -488,7 +538,8 @@ static PyObject *py_object_storage_pack_object(PyObject *self, PyObject *args) PyTypeObject *get_python_object_storage_type(void) { static PyMethodDef py_object_storage_methods[] = { - OBJECT_STORAGE_ADD_BACKEND_METHOD, + OBJECT_STORAGE_LOAD_METHOD, + OBJECT_STORAGE_STORE_METHOD, OBJECT_STORAGE_LOAD_OBJECT_METHOD, OBJECT_STORAGE_UNPACK_OBJECT_METHOD, OBJECT_STORAGE_STORE_OBJECT_METHOD, @@ -550,7 +601,7 @@ bool ensure_python_object_storage_is_registered(void) dict = PyModule_GetDict(module); - if (!register_class_for_pygobject(dict, G_TYPE_OBJECT_STORAGE, type, &PyGObject_Type)) + if (!register_class_for_pygobject(dict, G_TYPE_OBJECT_STORAGE, type)) return false; } diff --git a/plugins/pychrysalide/analysis/storage/tpmem.c b/plugins/pychrysalide/analysis/storage/tpmem.c index 8df20b2..ae07008 100644 --- a/plugins/pychrysalide/analysis/storage/tpmem.c +++ b/plugins/pychrysalide/analysis/storage/tpmem.c @@ -52,8 +52,8 @@ static int py_type_memory_init(PyObject *, PyObject *, PyObject *); /* -------------------------- TAMPON POUR CODE DESASSEMBLE -------------------------- */ -/* Apprend tous les types mémorisés dans un flux. */ -static PyObject *py_type_memory_read_types(PyObject *, PyObject *); +/* Apprend tous les types mémorisés dans un tampon. */ +static PyObject *py_type_memory_load_types(PyObject *, PyObject *); /* Crée une nouvelle instance d'objet à partir de son type. */ static PyObject *py_type_memory_create_object(PyObject *, PyObject *); @@ -61,8 +61,8 @@ static PyObject *py_type_memory_create_object(PyObject *, PyObject *); /* Sauvegarde le type d'un objet instancié. */ static PyObject *py_type_memory_store_object_gtype(PyObject *, PyObject *); -/* Enregistre tous les types mémorisés dans un flux. */ -static PyObject *py_type_memory_write_types(PyObject *, PyObject *); +/* Enregistre tous les types mémorisés dans un tampon. */ +static PyObject *py_type_memory_store_types(PyObject *, PyObject *); @@ -108,7 +108,7 @@ static PyObject *py_type_memory_new(PyTypeObject *type, PyObject *args, PyObject if (first_time) { - status = register_class_for_dynamic_pygobject(gtype, type, base); + status = register_class_for_dynamic_pygobject(gtype, type); if (!status) { @@ -178,7 +178,7 @@ static int py_type_memory_init(PyObject *self, PyObject *args, PyObject *kwds) * Paramètres : self = classe représentant une mémorisation de types. * * args = arguments fournis à l'appel. * * * -* Description : Apprend tous les types mémorisés dans un flux. * +* Description : Apprend tous les types mémorisés dans un tampon. * * * * Retour : Bilan de l'opération. * * * @@ -186,36 +186,36 @@ static int py_type_memory_init(PyObject *self, PyObject *args, PyObject *kwds) * * ******************************************************************************/ -static PyObject *py_type_memory_read_types(PyObject *self, PyObject *args) +static PyObject *py_type_memory_load_types(PyObject *self, PyObject *args) { PyObject *result; /* Bilan à retourner */ - int fd; /* Flux ouvert en lecture */ + packed_buffer_t *pbuf; /* Tampon à consulter */ int ret; /* Bilan de lecture des args. */ GTypeMemory *tpmem; /* Mémorisation native */ bool status; /* Bilan de l'opération */ -#define TYPE_MEMORY_READ_TYPES_METHOD PYTHON_METHOD_DEF \ +#define TYPE_MEMORY_LOAD_TYPES_METHOD PYTHON_METHOD_DEF \ ( \ - read_types, "$self, fd", \ + load_types, "$self, pbuf", \ METH_VARARGS, py_type_memory, \ - "Read types from a stream.\n" \ + "Read types from a buffer.\n" \ "\n" \ "This operation is usually handled internally by the" \ " Chrysalide's core.\n" \ "\n" \ - "The *fd* parameter is an integer representing a valid" \ - " identifier for a file descriptor opened for reading." \ + "The *pbuf* parameter is a pychrysalide.common.PackedBuffer"\ + " instance providing buffered data to read." \ "\n" \ "The result is a boolean value indicating the status of" \ " the operation: True for success, False for failure." \ ) - ret = PyArg_ParseTuple(args, "i", &fd); + ret = PyArg_ParseTuple(args, "O&", convert_to_packed_buffer, &pbuf); if (!ret) return NULL; tpmem = G_TYPE_MEMORY(pygobject_get(self)); - status = g_type_memory_read_types(tpmem, fd); + status = g_type_memory_load_types(tpmem, pbuf); result = status ? Py_True : Py_False; Py_INCREF(result); @@ -330,7 +330,7 @@ static PyObject *py_type_memory_store_object_gtype(PyObject *self, PyObject *arg * Paramètres : self = classe représentant une mémorisation de types. * * args = arguments fournis à l'appel. * * * -* Description : Enregistre tous les types mémorisés dans un flux. * +* Description : Enregistre tous les types mémorisés dans un tampon. * * * * Retour : Bilan de l'opération. * * * @@ -338,36 +338,36 @@ static PyObject *py_type_memory_store_object_gtype(PyObject *self, PyObject *arg * * ******************************************************************************/ -static PyObject *py_type_memory_write_types(PyObject *self, PyObject *args) +static PyObject *py_type_memory_store_types(PyObject *self, PyObject *args) { PyObject *result; /* Bilan à retourner */ - int fd; /* Flux ouvert en lecture */ + packed_buffer_t *pbuf; /* Tampon à consulter */ int ret; /* Bilan de lecture des args. */ GTypeMemory *tpmem; /* Mémorisation native */ bool status; /* Bilan de l'opération */ -#define TYPE_MEMORY_WRITE_TYPES_METHOD PYTHON_METHOD_DEF \ +#define TYPE_MEMORY_STORE_TYPES_METHOD PYTHON_METHOD_DEF \ ( \ - write_types, "$self, fd", \ + store_types, "$self, pbuf", \ METH_VARARGS, py_type_memory, \ - "Write types into a stream.\n" \ + "Write types into a buffer.\n" \ "\n" \ "This operation is usually handled internally by the" \ " Chrysalide's core.\n" \ "\n" \ - "The *fd* parameter is an integer representing a valid" \ - " identifier for a file descriptor opened for writing." \ + "The *pbuf* parameter is a pychrysalide.common.PackedBuffer"\ + " instance providing buffered data to read." \ "\n" \ "The result is a boolean value indicating the status of" \ " the operation: True for success, False for failure." \ ) - ret = PyArg_ParseTuple(args, "i", &fd); + ret = PyArg_ParseTuple(args, "O&", convert_to_packed_buffer, &pbuf); if (!ret) return NULL; tpmem = G_TYPE_MEMORY(pygobject_get(self)); - status = g_type_memory_write_types(tpmem, fd); + status = g_type_memory_store_types(tpmem, pbuf); result = status ? Py_True : Py_False; Py_INCREF(result); @@ -392,10 +392,10 @@ static PyObject *py_type_memory_write_types(PyObject *self, PyObject *args) PyTypeObject *get_python_type_memory_type(void) { static PyMethodDef py_type_memory_methods[] = { - TYPE_MEMORY_READ_TYPES_METHOD, + TYPE_MEMORY_LOAD_TYPES_METHOD, TYPE_MEMORY_CREATE_OBJECT_METHOD, TYPE_MEMORY_STORE_OBJECT_GTYPE_METHOD, - TYPE_MEMORY_WRITE_TYPES_METHOD, + TYPE_MEMORY_STORE_TYPES_METHOD, { NULL } }; @@ -453,7 +453,7 @@ bool ensure_python_type_memory_is_registered(void) dict = PyModule_GetDict(module); - if (!register_class_for_pygobject(dict, G_TYPE_TYPE_MEMORY, type, &PyGObject_Type)) + if (!register_class_for_pygobject(dict, G_TYPE_TYPE_MEMORY, type)) return false; } diff --git a/plugins/pychrysalide/analysis/type.c b/plugins/pychrysalide/analysis/type.c index 86a0ffb..ea8affd 100644 --- a/plugins/pychrysalide/analysis/type.c +++ b/plugins/pychrysalide/analysis/type.c @@ -158,7 +158,7 @@ static PyObject *py_data_type_new(PyTypeObject *type, PyObject *args, PyObject * if (first_time) { - status = register_class_for_dynamic_pygobject(gtype, type, base); + status = register_class_for_dynamic_pygobject(gtype, type); if (!status) { @@ -220,6 +220,7 @@ static void py_data_type_init_gclass(GDataTypeClass *class, gpointer unused) static guint py_data_type_hash_wrapper(const GDataType *type) { guint result; /* Empreinte à renvoyer */ + PyGILState_STATE gstate; /* Sauvegarde d'environnement */ PyObject *pyobj; /* Objet Python concerné */ PyObject *pyret; /* Bilan de consultation */ @@ -234,6 +235,8 @@ static guint py_data_type_hash_wrapper(const GDataType *type) result = 0; + gstate = PyGILState_Ensure(); + pyobj = pygobject_new(G_OBJECT(type)); if (has_python_method(pyobj, "_hash")) @@ -252,6 +255,8 @@ static guint py_data_type_hash_wrapper(const GDataType *type) Py_DECREF(pyobj); + PyGILState_Release(gstate); + return result; } @@ -272,6 +277,7 @@ static guint py_data_type_hash_wrapper(const GDataType *type) static GDataType *py_data_type_dup_wrapper(const GDataType *type) { GDataType *result; /* Copie à retourner */ + PyGILState_STATE gstate; /* Sauvegarde d'environnement */ PyObject *pyobj; /* Objet Python concerné */ PyObject *pyret; /* Bilan de consultation */ @@ -287,6 +293,8 @@ static GDataType *py_data_type_dup_wrapper(const GDataType *type) result = NULL; + gstate = PyGILState_Ensure(); + pyobj = pygobject_new(G_OBJECT(type)); if (has_python_method(pyobj, "_dup")) @@ -308,6 +316,8 @@ static GDataType *py_data_type_dup_wrapper(const GDataType *type) Py_DECREF(pyobj); + PyGILState_Release(gstate); + return result; } @@ -329,6 +339,7 @@ static GDataType *py_data_type_dup_wrapper(const GDataType *type) static char *py_data_type_to_string_wrapper(const GDataType *type, bool include) { char *result; /* Etiquette à retourner */ + PyGILState_STATE gstate; /* Sauvegarde d'environnement */ PyObject *pyobj; /* Objet Python concerné */ PyObject *arg; /* Version Python de l'argument*/ PyObject *args; /* Arguments pour l'appel */ @@ -349,6 +360,8 @@ static char *py_data_type_to_string_wrapper(const GDataType *type, bool include) result = NULL; + gstate = PyGILState_Ensure(); + pyobj = pygobject_new(G_OBJECT(type)); if (has_python_method(pyobj, "_to_string")) @@ -375,6 +388,8 @@ static char *py_data_type_to_string_wrapper(const GDataType *type, bool include) Py_DECREF(pyobj); + PyGILState_Release(gstate); + return result; } @@ -395,6 +410,7 @@ static char *py_data_type_to_string_wrapper(const GDataType *type, bool include) static bool py_data_type_handle_namespaces_wrapper(const GDataType *type) { bool result; /* Bilan à retourner */ + PyGILState_STATE gstate; /* Sauvegarde d'environnement */ PyObject *pyobj; /* Objet Python concerné */ PyObject *pyret; /* Bilan de consultation */ @@ -411,6 +427,8 @@ static bool py_data_type_handle_namespaces_wrapper(const GDataType *type) result = true; + gstate = PyGILState_Ensure(); + pyobj = pygobject_new(G_OBJECT(type)); if (has_python_method(pyobj, "_handle_namespaces")) @@ -425,6 +443,8 @@ static bool py_data_type_handle_namespaces_wrapper(const GDataType *type) Py_DECREF(pyobj); + PyGILState_Release(gstate); + return result; } @@ -445,6 +465,7 @@ static bool py_data_type_handle_namespaces_wrapper(const GDataType *type) static bool py_data_type_is_pointer_wrapper(const GDataType *type) { bool result; /* Bilan à retourner */ + PyGILState_STATE gstate; /* Sauvegarde d'environnement */ PyObject *pyobj; /* Objet Python concerné */ PyObject *pyret; /* Bilan de consultation */ @@ -461,6 +482,8 @@ static bool py_data_type_is_pointer_wrapper(const GDataType *type) result = false; + gstate = PyGILState_Ensure(); + pyobj = pygobject_new(G_OBJECT(type)); if (has_python_method(pyobj, "_is_pointer")) @@ -475,6 +498,8 @@ static bool py_data_type_is_pointer_wrapper(const GDataType *type) Py_DECREF(pyobj); + PyGILState_Release(gstate); + return result; } @@ -495,6 +520,7 @@ static bool py_data_type_is_pointer_wrapper(const GDataType *type) static bool py_data_type_is_reference_wrapper(const GDataType *type) { bool result; /* Bilan à retourner */ + PyGILState_STATE gstate; /* Sauvegarde d'environnement */ PyObject *pyobj; /* Objet Python concerné */ PyObject *pyret; /* Bilan de consultation */ @@ -511,6 +537,8 @@ static bool py_data_type_is_reference_wrapper(const GDataType *type) result = false; + gstate = PyGILState_Ensure(); + pyobj = pygobject_new(G_OBJECT(type)); if (has_python_method(pyobj, "_is_reference")) @@ -525,6 +553,8 @@ static bool py_data_type_is_reference_wrapper(const GDataType *type) Py_DECREF(pyobj); + PyGILState_Release(gstate); + return result; } @@ -1095,7 +1125,7 @@ bool ensure_python_data_type_is_registered(void) dict = PyModule_GetDict(module); - if (!register_class_for_pygobject(dict, G_TYPE_DATA_TYPE, type, &PyGObject_Type)) + if (!register_class_for_pygobject(dict, G_TYPE_DATA_TYPE, type)) return false; if (!define_analysis_data_type_constants(type)) diff --git a/plugins/pychrysalide/analysis/types/Makefile.am b/plugins/pychrysalide/analysis/types/Makefile.am index 8f1799f..697c998 100644 --- a/plugins/pychrysalide/analysis/types/Makefile.am +++ b/plugins/pychrysalide/analysis/types/Makefile.am @@ -1,30 +1,23 @@ noinst_LTLIBRARIES = libpychrysaanalysistypes.la -libpychrysaanalysistypes_la_SOURCES = \ - array.h array.c \ - basic.h basic.c \ - constants.h constants.c \ - cse.h cse.c \ - encaps.h encaps.c \ - expr.h expr.c \ - literal.h literal.c \ - module.h module.c \ - override.h override.c \ - proto.h proto.c \ +libpychrysaanalysistypes_la_SOURCES = \ + array.h array.c \ + basic.h basic.c \ + constants.h constants.c \ + cse.h cse.c \ + encaps.h encaps.c \ + expr.h expr.c \ + literal.h literal.c \ + module.h module.c \ + override.h override.c \ + proto.h proto.c \ template.h template.c -libpychrysaanalysistypes_la_LDFLAGS = +libpychrysaanalysistypes_la_CFLAGS = $(TOOLKIT_CFLAGS) $(LIBXML_CFLAGS) $(LIBPYTHON_INTERPRETER_CFLAGS) $(LIBPYGOBJECT_CFLAGS) \ + -I$(top_srcdir)/src -DNO_IMPORT_PYGOBJECT devdir = $(includedir)/chrysalide/$(subdir) dev_HEADERS = $(libpychrysaanalysistypes_la_SOURCES:%c=) - - -AM_CPPFLAGS = $(LIBGTK_CFLAGS) $(LIBXML_CFLAGS) $(LIBPYTHON_CFLAGS) $(LIBPYGOBJECT_CFLAGS) \ - -I$(top_srcdir)/src - -AM_CFLAGS = $(DEBUG_CFLAGS) $(WARNING_FLAGS) $(COMPLIANCE_FLAGS) - -SUBDIRS = diff --git a/plugins/pychrysalide/analysis/types/array.c b/plugins/pychrysalide/analysis/types/array.c index 8055316..88b773e 100644 --- a/plugins/pychrysalide/analysis/types/array.c +++ b/plugins/pychrysalide/analysis/types/array.c @@ -423,7 +423,7 @@ bool ensure_python_array_type_is_registered(void) if (!ensure_python_data_type_is_registered()) return false; - if (!register_class_for_pygobject(dict, G_TYPE_ARRAY_TYPE, type, get_python_data_type_type())) + if (!register_class_for_pygobject(dict, G_TYPE_ARRAY_TYPE, type)) return false; } diff --git a/plugins/pychrysalide/analysis/types/basic.c b/plugins/pychrysalide/analysis/types/basic.c index 9ae4f8f..19fb9d1 100644 --- a/plugins/pychrysalide/analysis/types/basic.c +++ b/plugins/pychrysalide/analysis/types/basic.c @@ -210,7 +210,7 @@ bool ensure_python_basic_type_is_registered(void) if (!ensure_python_data_type_is_registered()) return false; - if (!register_class_for_pygobject(dict, G_TYPE_BASIC_TYPE, type, get_python_data_type_type())) + if (!register_class_for_pygobject(dict, G_TYPE_BASIC_TYPE, type)) return false; if (!define_basic_type_constants(type)) diff --git a/plugins/pychrysalide/analysis/types/cse.c b/plugins/pychrysalide/analysis/types/cse.c index 7701d48..0aab4d9 100644 --- a/plugins/pychrysalide/analysis/types/cse.c +++ b/plugins/pychrysalide/analysis/types/cse.c @@ -262,7 +262,7 @@ bool ensure_python_class_enum_type_is_registered(void) if (!ensure_python_data_type_is_registered()) return false; - if (!register_class_for_pygobject(dict, G_TYPE_CLASS_ENUM_TYPE, type, get_python_data_type_type())) + if (!register_class_for_pygobject(dict, G_TYPE_CLASS_ENUM_TYPE, type)) return false; if (!define_class_enum_type_constants(type)) diff --git a/plugins/pychrysalide/analysis/types/encaps.c b/plugins/pychrysalide/analysis/types/encaps.c index 3a5acb5..bc9f4db 100644 --- a/plugins/pychrysalide/analysis/types/encaps.c +++ b/plugins/pychrysalide/analysis/types/encaps.c @@ -223,7 +223,7 @@ bool ensure_python_encapsulated_type_is_registered(void) if (!ensure_python_data_type_is_registered()) return false; - if (!register_class_for_pygobject(dict, G_TYPE_ENCAPSULATED_TYPE, type, get_python_data_type_type())) + if (!register_class_for_pygobject(dict, G_TYPE_ENCAPSULATED_TYPE, type)) return false; if (!define_encapsulated_type_constants(type)) diff --git a/plugins/pychrysalide/analysis/types/expr.c b/plugins/pychrysalide/analysis/types/expr.c index 02cb02f..e3b2b0a 100644 --- a/plugins/pychrysalide/analysis/types/expr.c +++ b/plugins/pychrysalide/analysis/types/expr.c @@ -201,7 +201,7 @@ bool ensure_python_expr_type_is_registered(void) if (!ensure_python_data_type_is_registered()) return false; - if (!register_class_for_pygobject(dict, G_TYPE_EXPR_TYPE, type, get_python_data_type_type())) + if (!register_class_for_pygobject(dict, G_TYPE_EXPR_TYPE, type)) return false; } diff --git a/plugins/pychrysalide/analysis/types/literal.c b/plugins/pychrysalide/analysis/types/literal.c index e00104f..3d9d5e3 100644 --- a/plugins/pychrysalide/analysis/types/literal.c +++ b/plugins/pychrysalide/analysis/types/literal.c @@ -136,7 +136,7 @@ bool ensure_python_literal_type_is_registered(void) if (!ensure_python_data_type_is_registered()) return false; - if (!register_class_for_pygobject(dict, G_TYPE_LITERAL_TYPE, type, get_python_data_type_type())) + if (!register_class_for_pygobject(dict, G_TYPE_LITERAL_TYPE, type)) return false; } diff --git a/plugins/pychrysalide/analysis/types/override.c b/plugins/pychrysalide/analysis/types/override.c index 896163f..236a34c 100644 --- a/plugins/pychrysalide/analysis/types/override.c +++ b/plugins/pychrysalide/analysis/types/override.c @@ -247,7 +247,7 @@ bool ensure_python_override_type_is_registered(void) if (!ensure_python_data_type_is_registered()) return false; - if (!register_class_for_pygobject(dict, G_TYPE_OVERRIDE_TYPE, type, get_python_data_type_type())) + if (!register_class_for_pygobject(dict, G_TYPE_OVERRIDE_TYPE, type)) return false; } diff --git a/plugins/pychrysalide/analysis/types/proto.c b/plugins/pychrysalide/analysis/types/proto.c index 7c3ebed..1da3119 100644 --- a/plugins/pychrysalide/analysis/types/proto.c +++ b/plugins/pychrysalide/analysis/types/proto.c @@ -349,7 +349,7 @@ bool ensure_python_proto_type_is_registered(void) if (!ensure_python_data_type_is_registered()) return false; - if (!register_class_for_pygobject(dict, G_TYPE_PROTO_TYPE, type, get_python_data_type_type())) + if (!register_class_for_pygobject(dict, G_TYPE_PROTO_TYPE, type)) return false; } diff --git a/plugins/pychrysalide/analysis/types/template.c b/plugins/pychrysalide/analysis/types/template.c index 6fc50e4..68f390a 100644 --- a/plugins/pychrysalide/analysis/types/template.c +++ b/plugins/pychrysalide/analysis/types/template.c @@ -345,7 +345,7 @@ bool ensure_python_template_type_is_registered(void) if (!ensure_python_data_type_is_registered()) return false; - if (!register_class_for_pygobject(dict, G_TYPE_TEMPLATE_TYPE, type, get_python_data_type_type())) + if (!register_class_for_pygobject(dict, G_TYPE_TEMPLATE_TYPE, type)) return false; } diff --git a/plugins/pychrysalide/analysis/variable.c b/plugins/pychrysalide/analysis/variable.c index 3aeddf4..5f8d490 100644 --- a/plugins/pychrysalide/analysis/variable.c +++ b/plugins/pychrysalide/analysis/variable.c @@ -266,7 +266,7 @@ bool ensure_python_binary_variable_is_registered(void) dict = PyModule_GetDict(module); - if (!register_class_for_pygobject(dict, G_TYPE_BIN_VARIABLE, type, &PyGObject_Type)) + if (!register_class_for_pygobject(dict, G_TYPE_BIN_VARIABLE, type)) return false; } diff --git a/plugins/pychrysalide/arch/Makefile.am b/plugins/pychrysalide/arch/Makefile.am index ab4ca23..c113f6e 100644 --- a/plugins/pychrysalide/arch/Makefile.am +++ b/plugins/pychrysalide/arch/Makefile.am @@ -1,22 +1,23 @@ noinst_LTLIBRARIES = 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 \ +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 -libpychrysaarch_la_LIBADD = \ +libpychrysaarch_la_LIBADD = \ instructions/libpychrysaarchinstructions.la \ operands/libpychrysaarchoperands.la -libpychrysaarch_la_LDFLAGS = +libpychrysaarch_la_CFLAGS = $(TOOLKIT_CFLAGS) $(LIBXML_CFLAGS) $(LIBPYTHON_INTERPRETER_CFLAGS) $(LIBPYGOBJECT_CFLAGS) \ + -I$(top_srcdir)/src -DNO_IMPORT_PYGOBJECT devdir = $(includedir)/chrysalide/$(subdir) @@ -24,9 +25,4 @@ devdir = $(includedir)/chrysalide/$(subdir) dev_HEADERS = $(libpychrysaarch_la_SOURCES:%c=) -AM_CPPFLAGS = $(LIBGTK_CFLAGS) $(LIBXML_CFLAGS) $(LIBPYTHON_CFLAGS) $(LIBPYGOBJECT_CFLAGS) \ - -I$(top_srcdir)/src - -AM_CFLAGS = $(DEBUG_CFLAGS) $(WARNING_FLAGS) $(COMPLIANCE_FLAGS) - SUBDIRS = instructions operands diff --git a/plugins/pychrysalide/arch/context.c b/plugins/pychrysalide/arch/context.c index ce1ef01..79c782f 100644 --- a/plugins/pychrysalide/arch/context.c +++ b/plugins/pychrysalide/arch/context.c @@ -1,6 +1,6 @@ /* Chrysalide - Outil d'analyse de fichiers binaires - * context.c - équivalent Python du fichier "arch/context.h" + * context.c - équivalent Python du fichier "arch/context.c" * * Copyright (C) 2018 Cyrille Bagard * @@ -39,6 +39,7 @@ #include "../helpers.h" #include "../analysis/db/item.h" #include "../arch/vmpa.h" +#include "../format/preload.h" @@ -120,7 +121,7 @@ static PyObject *py_proc_context_new(PyTypeObject *type, PyObject *args, PyObjec if (first_time) { - status = register_class_for_dynamic_pygobject(gtype, type, base); + status = register_class_for_dynamic_pygobject(gtype, type); if (!status) { @@ -518,7 +519,10 @@ bool ensure_python_proc_context_is_registered(void) dict = PyModule_GetDict(module); - if (!register_class_for_pygobject(dict, G_TYPE_PROC_CONTEXT, type, &PyGObject_Type)) + if (!ensure_python_preload_info_is_registered()) + return false; + + if (!register_class_for_pygobject(dict, G_TYPE_PROC_CONTEXT, type)) return false; if (!define_proc_context_constants(type)) diff --git a/plugins/pychrysalide/arch/instruction.c b/plugins/pychrysalide/arch/instruction.c index 3606cfe..0a9ba16 100644 --- a/plugins/pychrysalide/arch/instruction.c +++ b/plugins/pychrysalide/arch/instruction.c @@ -45,52 +45,7 @@ -/* -------------------- INTERFACE INTERNE POUR EXTENSIONS PYTHON -------------------- */ - - -/* Définition générique d'une instruction d'architecture (instance) */ -typedef struct _GPyArchInstruction -{ - GArchInstruction parent; /* A laisser en premier */ - - char *cached_keyword; /* Conservation de constante */ - -} GPyArchInstruction; - - -/* Définition générique d'une instruction d'architecture (classe) */ -typedef struct _GPyArchInstructionClass -{ - GArchInstructionClass parent; /* A laisser en premier */ - -} GPyArchInstructionClass; - - -#define G_TYPE_PYARCH_INSTRUCTION g_pyarch_instruction_get_type() -#define G_PYARCH_INSTRUCTION(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_PYARCH_INSTRUCTION, GPyArchInstruction)) -#define G_IS_PYTHON_INSTRUCTION(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_PYARCH_INSTRUCTION)) -#define G_PYARCH_INSTRUCTION_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_PYARCH_INSTRUCTION, GPyArchInstructionClass)) -#define G_IS_PYTHON_INSTRUCTION_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_PYARCH_INSTRUCTION)) -#define G_PYARCH_INSTRUCTION_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_PYARCH_INSTRUCTION, GPyArchInstructionClass)) - - -/* Indique le type défini pour une instruction d'architecture en Python. */ -GType g_pyarch_instruction_get_type(void); - -/* Initialise la classe générique des instructions en Python. */ -static void g_pyarch_instruction_class_init(GPyArchInstructionClass *); - -/* Initialise une instance d'opérande d'architecture. */ -static void g_pyarch_instruction_init(GPyArchInstruction *); - -/* Supprime toutes les références externes. */ -static void g_pyarch_instruction_dispose(GPyArchInstruction *); - -/* Procède à la libération totale de la mémoire. */ -static void g_pyarch_instruction_finalize(GPyArchInstruction *); - -/* Fournit le nom humain de l'instruction manipulée. */ -static const char *g_pyarch_instruction_get_keyword(GPyArchInstruction *); +static G_DEFINE_QUARK(cached_keyword, get_cached_keyword); @@ -101,11 +56,16 @@ static const char *g_pyarch_instruction_get_keyword(GPyArchInstruction *); static PyObject *py_arch_instruction_new(PyTypeObject *, PyObject *, PyObject *); /* Initialise la classe générique des instructions. */ -static void py_arch_instruction_init_gclass(GPyArchInstructionClass *, gpointer); +static void py_arch_instruction_init_gclass(GArchInstructionClass *, gpointer); + +CREATE_DYN_ABSTRACT_CONSTRUCTOR(arch_instruction, G_TYPE_ARCH_INSTRUCTION, py_arch_instruction_init_gclass); /* Initialise une instance sur la base du dérivé de GObject. */ static int py_arch_instruction_init(PyObject *, PyObject *, PyObject *); +/* Fournit le nom humain de l'instruction manipulée. */ +static const char *py_arch_instruction_get_class_keyword(GArchInstruction *); + /* --------------------------- MANIPULATION DES OPERANDES --------------------------- */ @@ -160,19 +120,16 @@ static PyObject *py_arch_instruction_get_keyword(PyObject *, void *); /* ---------------------------------------------------------------------------------- */ -/* INTERFACE INTERNE POUR EXTENSIONS PYTHON */ +/* GLUE POUR CREATION DEPUIS PYTHON */ /* ---------------------------------------------------------------------------------- */ -/* Indique le type défini pour une instruction d'architecture en Python. */ -G_DEFINE_TYPE(GPyArchInstruction, g_pyarch_instruction, G_TYPE_ARCH_INSTRUCTION); - - /****************************************************************************** * * -* Paramètres : klass = classe à initialiser. * +* Paramètres : class = classe à initialiser. * +* unused = données non utilisées ici. * * * -* Description : Initialise la classe générique des instructions en Python. * +* Description : Initialise la classe générique des instructions. * * * * Retour : - * * * @@ -180,78 +137,62 @@ G_DEFINE_TYPE(GPyArchInstruction, g_pyarch_instruction, G_TYPE_ARCH_INSTRUCTION) * * ******************************************************************************/ -static void g_pyarch_instruction_class_init(GPyArchInstructionClass *klass) +static void py_arch_instruction_init_gclass(GArchInstructionClass *class, gpointer unused) { - GObjectClass *object; /* Autre version de la classe */ GArchInstructionClass *instr; /* Encore une autre vision... */ - object = G_OBJECT_CLASS(klass); + instr = G_ARCH_INSTRUCTION_CLASS(class); - object->dispose = (GObjectFinalizeFunc/* ! */)g_pyarch_instruction_dispose; - object->finalize = (GObjectFinalizeFunc)g_pyarch_instruction_finalize; - - instr = G_ARCH_INSTRUCTION_CLASS(klass); - - instr->get_keyword = (get_instruction_keyword_fc)g_pyarch_instruction_get_keyword; + instr->get_keyword = (get_instruction_keyword_fc)py_arch_instruction_get_class_keyword; } /****************************************************************************** * * -* Paramètres : instr = instance à initialiser. * +* Paramètres : self = objet à initialiser (théoriquement). * +* args = arguments fournis à l'appel. * +* kwds = arguments de type key=val fournis. * * * -* Description : Initialise une instance d'instruction d'architecture. * +* Description : Initialise une instance sur la base du dérivé de GObject. * * * -* Retour : - * +* Retour : 0. * * * * Remarques : - * * * ******************************************************************************/ -static void g_pyarch_instruction_init(GPyArchInstruction *instr) +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 */ + int ret; /* Bilan de lecture des args. */ + GArchInstruction *instr; /* Instruction à manipuler */ + GQuark cache_key; /* Emplacement local */ -} + static char *kwlist[] = { "uid", "keyword", NULL }; + /* Récupération des paramètres */ -/****************************************************************************** -* * -* Paramètres : instr = instance d'objet GLib à traiter. * -* * -* Description : Supprime toutes les références externes. * -* * -* Retour : - * -* * -* Remarques : - * -* * -******************************************************************************/ + ret = PyArg_ParseTupleAndKeywords(args, kwds, "Hs", kwlist, &uid, &keyword); + if (!ret) return -1; -static void g_pyarch_instruction_dispose(GPyArchInstruction *instr) -{ - G_OBJECT_CLASS(g_pyarch_instruction_parent_class)->dispose(G_OBJECT(instr)); + /* Initialisation d'un objet GLib */ -} + ret = forward_pygobjet_init(self); + if (ret == -1) return -1; + /* Eléments de base */ -/****************************************************************************** -* * -* Paramètres : instr = instance d'objet GLib à traiter. * -* * -* Description : Procède à la libération totale de la mémoire. * -* * -* Retour : - * -* * -* Remarques : - * -* * -******************************************************************************/ + instr = G_ARCH_INSTRUCTION(pygobject_get(self)); -static void g_pyarch_instruction_finalize(GPyArchInstruction *instr) -{ - if (instr->cached_keyword) - free(instr->cached_keyword); + cache_key = get_cached_keyword_quark(); - G_OBJECT_CLASS(g_pyarch_instruction_parent_class)->finalize(G_OBJECT(instr)); + 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; } @@ -268,151 +209,21 @@ static void g_pyarch_instruction_finalize(GPyArchInstruction *instr) * * ******************************************************************************/ -static const char *g_pyarch_instruction_get_keyword(GPyArchInstruction *instr) +static const char *py_arch_instruction_get_class_keyword(GArchInstruction *instr) { const char *result; /* Désignation à retourner */ + GQuark cache_key; /* Emplacement local */ - result = instr->cached_keyword; + cache_key = get_cached_keyword_quark(); - return result; - -} - - -/* ---------------------------------------------------------------------------------- */ -/* 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. * -* * -* 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_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_arch_instruction_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_PYARCH_INSTRUCTION, type->tp_name, - (GClassInitFunc)py_arch_instruction_init_gclass, NULL, NULL); - - if (first_time) - { - status = register_class_for_dynamic_pygobject(gtype, type, base); - - 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: + result = g_object_get_qdata(G_OBJECT(instr), cache_key); + assert(result != NULL); return result; } -/****************************************************************************** -* * -* Paramètres : class = classe à initialiser. * -* unused = données non utilisées ici. * -* * -* Description : Initialise la classe générique des instructions. * -* * -* Retour : - * -* * -* Remarques : - * -* * -******************************************************************************/ - -static void py_arch_instruction_init_gclass(GPyArchInstructionClass *class, gpointer unused) -{ - /// .... - -} - - -/****************************************************************************** -* * -* Paramètres : self = objet à initialiser (théoriquement). * -* args = arguments fournis à l'appel. * -* kwds = arguments de type key=val fournis. * -* * -* Description : Initialise une instance sur la base du dérivé de GObject. * -* * -* Retour : 0. * -* * -* Remarques : - * -* * -******************************************************************************/ - -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 */ - int ret; /* Bilan de lecture des args. */ - GPyArchInstruction *instr; /* Instruction à manipuler */ - - static char *kwlist[] = { "uid", "keyword", NULL }; - - /* Récupération des paramètres */ - - ret = PyArg_ParseTupleAndKeywords(args, kwds, "Hs", kwlist, &uid, &keyword); - if (!ret) return -1; - - /* Initialisation d'un objet GLib */ - - ret = forward_pygobjet_init(self); - if (ret == -1) return -1; - - /* Eléments de base */ - - instr = G_PYARCH_INSTRUCTION(pygobject_get(self)); - - instr->cached_keyword = strdup(keyword); - - g_arch_instruction_set_unique_id(G_ARCH_INSTRUCTION(instr), uid); - - return 0; - -} - - /* ---------------------------------------------------------------------------------- */ /* MANIPULATION DES OPERANDES */ @@ -1085,8 +896,7 @@ bool ensure_python_arch_instruction_is_registered(void) if (!ensure_python_line_generator_is_registered()) return false; - if (!_register_class_for_pygobject(dict, G_TYPE_PYARCH_INSTRUCTION, type, - &PyGObject_Type, get_python_line_generator_type(), NULL)) + if (!register_class_for_pygobject(dict, G_TYPE_ARCH_INSTRUCTION, type)) return false; if (!define_arch_instruction_constants(type)) diff --git a/plugins/pychrysalide/arch/instructions/Makefile.am b/plugins/pychrysalide/arch/instructions/Makefile.am index 4c36acf..65efe42 100644 --- a/plugins/pychrysalide/arch/instructions/Makefile.am +++ b/plugins/pychrysalide/arch/instructions/Makefile.am @@ -2,24 +2,15 @@ noinst_LTLIBRARIES = libpychrysaarchinstructions.la libpychrysaarchinstructions_la_SOURCES = \ - constants.h constants.c \ - module.h module.c \ - raw.h raw.c \ + constants.h constants.c \ + module.h module.c \ + raw.h raw.c \ undefined.h undefined.c -libpychrysaarchinstructions_la_LIBADD = - -libpychrysaarchinstructions_la_LDFLAGS = +libpychrysaarchinstructions_la_CFLAGS = $(TOOLKIT_CFLAGS) $(LIBXML_CFLAGS) $(LIBPYTHON_INTERPRETER_CFLAGS) $(LIBPYGOBJECT_CFLAGS) \ + -I$(top_srcdir)/src -DNO_IMPORT_PYGOBJECT devdir = $(includedir)/chrysalide/$(subdir) dev_HEADERS = $(libpychrysaarchinstructions_la_SOURCES:%c=) - - -AM_CPPFLAGS = $(LIBGTK_CFLAGS) $(LIBXML_CFLAGS) $(LIBPYTHON_CFLAGS) $(LIBPYGOBJECT_CFLAGS) \ - -I$(top_srcdir)/src - -AM_CFLAGS = $(DEBUG_CFLAGS) $(WARNING_FLAGS) $(COMPLIANCE_FLAGS) - -SUBDIRS = diff --git a/plugins/pychrysalide/arch/instructions/raw.c b/plugins/pychrysalide/arch/instructions/raw.c index c1366c6..7e58b96 100644 --- a/plugins/pychrysalide/arch/instructions/raw.c +++ b/plugins/pychrysalide/arch/instructions/raw.c @@ -99,7 +99,7 @@ static PyObject *py_raw_instruction_new(PyTypeObject *type, PyObject *args, PyOb if (first_time) { - status = register_class_for_dynamic_pygobject(gtype, type, base); + status = register_class_for_dynamic_pygobject(gtype, type); if (!status) { @@ -458,7 +458,7 @@ bool ensure_python_raw_instruction_is_registered(void) if (!ensure_python_arch_instruction_is_registered()) return false; - if (!register_class_for_pygobject(dict, G_TYPE_RAW_INSTRUCTION, type, get_python_arch_instruction_type())) + if (!register_class_for_pygobject(dict, G_TYPE_RAW_INSTRUCTION, type)) return false; if (!define_raw_instruction_constants(type)) diff --git a/plugins/pychrysalide/arch/instructions/undefined.c b/plugins/pychrysalide/arch/instructions/undefined.c index 5741609..1246daa 100644 --- a/plugins/pychrysalide/arch/instructions/undefined.c +++ b/plugins/pychrysalide/arch/instructions/undefined.c @@ -88,7 +88,7 @@ static PyObject *py_undef_instruction_new(PyTypeObject *type, PyObject *args, Py if (first_time) { - status = register_class_for_dynamic_pygobject(gtype, type, base); + status = register_class_for_dynamic_pygobject(gtype, type); if (!status) { @@ -130,7 +130,7 @@ static int py_undef_instruction_init(PyObject *self, PyObject *args, PyObject *k unsigned long behavior; /* Conséquence pour l'instruct°*/ int ret; /* Bilan de lecture des args. */ GUndefInstruction *instr; /* Instruction à manipuler */ - undef_obj_extra *extra; /* Données insérées à modifier */ + undef_extra_data_t *extra; /* Données insérées à modifier */ static char *kwlist[] = { "behavior", NULL }; @@ -285,7 +285,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, get_python_arch_instruction_type())) + if (!register_class_for_pygobject(dict, G_TYPE_UNDEF_INSTRUCTION, type)) return false; if (!define_undefined_instruction_constants(type)) diff --git a/plugins/pychrysalide/arch/operand.c b/plugins/pychrysalide/arch/operand.c index 7fa5118..0aee4f7 100644 --- a/plugins/pychrysalide/arch/operand.c +++ b/plugins/pychrysalide/arch/operand.c @@ -35,6 +35,7 @@ #include "../access.h" #include "../helpers.h" +#include "../glibext/singleton.h" @@ -48,7 +49,7 @@ static PyObject *py_arch_operand_new(PyTypeObject *, PyObject *, PyObject *); static void py_arch_operand_init_gclass(GArchOperandClass *, gpointer); /* Compare un opérande avec un autre. */ -static int py_arch_operand___cmp___wrapper(const GArchOperand *, const GArchOperand *); +static int py_arch_operand___cmp___wrapper(const GArchOperand *, const GArchOperand *, bool); /* Détermine le chemin conduisant à un opérande interne. */ static char *py_arch_operand_find_inner_operand_path_wrapper(const GArchOperand *, const GArchOperand *); @@ -59,9 +60,13 @@ static GArchOperand *py_arch_operand_get_inner_operand_from_path_wrapper(const G /* 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 + /* ------------------------ DEFINITION D'OPERANDE QUELCONQUE ------------------------ */ @@ -144,7 +149,7 @@ static PyObject *py_arch_operand_new(PyTypeObject *type, PyObject *args, PyObjec if (first_time) { - status = register_class_for_dynamic_pygobject(gtype, type, base); + status = register_class_for_dynamic_pygobject(gtype, type); if (!status) { @@ -185,15 +190,18 @@ static void py_arch_operand_init_gclass(GArchOperandClass *class, gpointer unuse class->get_inner = py_arch_operand_get_inner_operand_from_path_wrapper; class->print = py_arch_operand_print_wrapper; +#ifdef INCLUDE_GTK_SUPPORT class->build_tooltip = py_arch_operand_build_tooltip_wrapper; +#endif } /****************************************************************************** * * -* Paramètres : a = premier opérande à consulter. * -* b = second opérande à consulter. * +* Paramètres : a = premier opérande à consulter. * +* b = second opérande à consulter. * +* lock = précise le besoin en verrouillage. * * * * Description : Compare un opérande avec un autre. * * * @@ -203,7 +211,7 @@ static void py_arch_operand_init_gclass(GArchOperandClass *class, gpointer unuse * * ******************************************************************************/ -static int py_arch_operand___cmp___wrapper(const GArchOperand *a, const GArchOperand *b) +static int py_arch_operand___cmp___wrapper(const GArchOperand *a, const GArchOperand *b, bool lock) { int result; /* Empreinte à retourner */ PyGILState_STATE gstate; /* Sauvegarde d'environnement */ @@ -454,6 +462,9 @@ static void py_arch_operand_print_wrapper(const GArchOperand *operand, GBufferLi } +#ifdef INCLUDE_GTK_SUPPORT + + /****************************************************************************** * * * Paramètres : operand = opérande à consulter. * @@ -520,6 +531,9 @@ static char *py_arch_operand_build_tooltip_wrapper(const GArchOperand *operand, } +#endif + + /* ---------------------------------------------------------------------------------- */ /* DEFINITION D'OPERANDE QUELCONQUE */ @@ -558,7 +572,7 @@ static PyObject *py_arch_operand_richcompare(PyObject *a, PyObject *b, int op) reg_a = G_ARCH_OPERAND(pygobject_get(a)); reg_b = G_ARCH_OPERAND(pygobject_get(b)); - status = py_arch_operand___cmp___wrapper(reg_a, reg_b); + status = py_arch_operand___cmp___wrapper(reg_a, reg_b, true); result = status_to_rich_cmp_state(status, op); @@ -707,7 +721,9 @@ PyTypeObject *get_python_arch_operand_type(void) ARCH_OPERAND_FIND_INNER_OPERAND_PATH_WRAPPER, ARCH_OPERAND_GET_INNER_OPERAND_FROM_PATH_WRAPPER, ARCH_OPERAND_PRINT_WRAPPER, +#ifdef INCLUDE_GTK_SUPPORT ARCH_OPERAND_BUILD_TOOLTIP_WRAPPER, +#endif ARCH_OPERAND_FIND_INNER_OPERAND_PATH_METHOD, ARCH_OPERAND_GET_INNER_OPERAND_FROM_PATH_METHOD, { NULL } @@ -768,7 +784,10 @@ bool ensure_python_arch_operand_is_registered(void) dict = PyModule_GetDict(module); - if (!register_class_for_pygobject(dict, G_TYPE_ARCH_OPERAND, type, &PyGObject_Type)) + if (!ensure_python_singleton_candidate_is_registered()) + return false; + + if (!register_class_for_pygobject(dict, G_TYPE_ARCH_OPERAND, type)) return false; } diff --git a/plugins/pychrysalide/arch/operands/Makefile.am b/plugins/pychrysalide/arch/operands/Makefile.am index 725096f..a41cbbb 100644 --- a/plugins/pychrysalide/arch/operands/Makefile.am +++ b/plugins/pychrysalide/arch/operands/Makefile.am @@ -1,30 +1,22 @@ noinst_LTLIBRARIES = libpychrysaarchoperands.la -libpychrysaarchoperands_la_SOURCES = \ - constants.h constants.c \ - feeder.h feeder.c \ - immediate.h immediate.c \ - module.h module.c \ - proxy.h proxy.c \ - register.h register.c \ - rename.h rename.c \ - target.h target.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 -libpychrysaarchoperands_la_LIBADD = - -libpychrysaarchoperands_la_LDFLAGS = +libpychrysaarchoperands_la_CFLAGS = $(TOOLKIT_CFLAGS) $(LIBXML_CFLAGS) $(LIBPYTHON_INTERPRETER_CFLAGS) $(LIBPYGOBJECT_CFLAGS) \ + -I$(top_srcdir)/src -DNO_IMPORT_PYGOBJECT devdir = $(includedir)/chrysalide/$(subdir) dev_HEADERS = $(libpychrysaarchoperands_la_SOURCES:%c=) - - -AM_CPPFLAGS = $(LIBGTK_CFLAGS) $(LIBXML_CFLAGS) $(LIBPYTHON_CFLAGS) $(LIBPYGOBJECT_CFLAGS) \ - -I$(top_srcdir)/src - -AM_CFLAGS = $(DEBUG_CFLAGS) $(WARNING_FLAGS) $(COMPLIANCE_FLAGS) - -SUBDIRS = diff --git a/plugins/pychrysalide/arch/operands/immediate.c b/plugins/pychrysalide/arch/operands/immediate.c index 2634352..2239eb2 100644 --- a/plugins/pychrysalide/arch/operands/immediate.c +++ b/plugins/pychrysalide/arch/operands/immediate.c @@ -46,9 +46,6 @@ -/* ------------------------- OPERANDE POUR VALEUR IMMEDIATE ------------------------- */ - - /* Crée un nouvel objet Python de type 'ImmOperand'. */ static PyObject *py_imm_operand_new(PyTypeObject *, PyObject *, PyObject *); @@ -64,18 +61,6 @@ static PyObject *py_imm_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 *); -/* Indique si l'affichage est complété avec des zéros. */ -static PyObject *py_imm_operand_get_default_padding(PyObject *self, void *); - -/* Précise si des zéro doivent compléter l'affichage ou non. */ -static int py_imm_operand_set_default_padding(PyObject *, PyObject *, void *); - -/* Indique si l'affichage est complété avec des zéros. */ -static PyObject *py_imm_operand_get_padding(PyObject *self, void *); - -/* Précise si des zéro doivent compléter l'affichage ou non. */ -static int py_imm_operand_set_padding(PyObject *, PyObject *, void *); - /* Indique le format textuel par défaut de la valeur. */ static PyObject *py_imm_operand_get_default_display(PyObject *, void *); @@ -90,19 +75,6 @@ static int py_imm_operand_set_display(PyObject *, PyObject *, void *); -/* ----------------------- REMPLACEMENT DE VALEURS IMMEDIATES ----------------------- */ - - -/* Crée un nouvel objet Python de type 'KnownImmOperand'. */ -static PyObject *py_known_imm_operand_new(PyTypeObject *, PyObject *, PyObject *); - - - -/* ---------------------------------------------------------------------------------- */ -/* OPERANDE POUR VALEUR IMMEDIATE */ -/* ---------------------------------------------------------------------------------- */ - - /****************************************************************************** * * * Paramètres : type = type de l'objet à instancier. * @@ -391,158 +363,6 @@ 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 si l'affichage est complété avec des zéros. * -* * -* Retour : true si des zéro sont ajoutés à l'affichage, false sinon. * -* * -* Remarques : - * -* * -******************************************************************************/ - -static PyObject *py_imm_operand_get_default_padding(PyObject *self, void *closure) -{ - PyObject *result; /* Instance Python à retourner */ - GImmOperand *operand; /* Version GLib de l'opérande */ - bool padding; /* Bourrage en préfixe ? */ - -#define IMM_OPERAND_DEFAULT_PADDING_ATTRIB PYTHON_GETSET_DEF_FULL \ -( \ - default_padding, py_imm_operand, \ - "Get or set the status of default padding with zeros in front of the" \ - " textual representation." \ - "\n" \ - "The status is a boolean value." \ -) - - operand = G_IMM_OPERAND(pygobject_get(self)); - - padding = g_imm_operand_get_default_padding(operand); - - result = padding ? Py_True : Py_False; - Py_INCREF(result); - - return result; - -} - - -/****************************************************************************** -* * -* Paramètres : self = objet Python concerné par l'appel. * -* value = valeur fournie à intégrer ou prendre en compte. * -* closure = non utilisé ici. * -* * -* Description : Précise si des zéro doivent compléter l'affichage ou non. * -* * -* Retour : Bilan de l'opération pour Python. * -* * -* Remarques : - * -* * -******************************************************************************/ - -static int py_imm_operand_set_default_padding(PyObject *self, PyObject *value, void *closure) -{ - bool padding; /* Bourrage en préfixe ? */ - GImmOperand *operand; /* Version GLib de l'opérande */ - - if (!PyBool_Check(value)) - { - PyErr_SetString(PyExc_TypeError, _("Invalid padding state")); - return -1; - } - - padding = (value == Py_True); - - operand = G_IMM_OPERAND(pygobject_get(self)); - - g_imm_operand_set_default_padding(operand, padding); - - return 0; - -} - - -/****************************************************************************** -* * -* Paramètres : self = objet Python concerné par l'appel. * -* closure = non utilisé ici. * -* * -* Description : Indique si l'affichage est complété avec des zéros. * -* * -* Retour : true si des zéro sont ajoutés à l'affichage, false sinon. * -* * -* Remarques : - * -* * -******************************************************************************/ - -static PyObject *py_imm_operand_get_padding(PyObject *self, void *closure) -{ - PyObject *result; /* Instance Python à retourner */ - GImmOperand *operand; /* Version GLib de l'opérande */ - bool padding; /* Bourrage en préfixe ? */ - -#define IMM_OPERAND_PADDING_ATTRIB PYTHON_GETSET_DEF_FULL \ -( \ - padding, py_imm_operand, \ - "Get or set the status of padding with zeros in front of the" \ - " textual representation." \ - "\n" \ - "The status is a boolean value." \ -) - - operand = G_IMM_OPERAND(pygobject_get(self)); - - padding = g_imm_operand_does_padding(operand); - - result = padding ? Py_True : Py_False; - Py_INCREF(result); - - return result; - -} - - -/****************************************************************************** -* * -* Paramètres : self = objet Python concerné par l'appel. * -* value = valeur fournie à intégrer ou prendre en compte. * -* closure = non utilisé ici. * -* * -* Description : Précise si des zéro doivent compléter l'affichage ou non. * -* * -* Retour : Bilan de l'opération pour Python. * -* * -* Remarques : - * -* * -******************************************************************************/ - -static int py_imm_operand_set_padding(PyObject *self, PyObject *value, void *closure) -{ - bool padding; /* Bourrage en préfixe ? */ - GImmOperand *operand; /* Version GLib de l'opérande */ - - if (!PyBool_Check(value)) - { - PyErr_SetString(PyExc_TypeError, _("Invalid padding state")); - return -1; - } - - padding = (value == Py_True); - - operand = G_IMM_OPERAND(pygobject_get(self)); - - g_imm_operand_pad(operand, padding); - - return 0; - -} - - -/****************************************************************************** -* * -* 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. * @@ -721,8 +541,6 @@ PyTypeObject *get_python_imm_operand_type(void) static PyGetSetDef py_imm_operand_getseters[] = { IMM_OPERAND_SIZE_ATTRIB, IMM_OPERAND_VALUE_ATTRIB, - IMM_OPERAND_DEFAULT_PADDING_ATTRIB, - IMM_OPERAND_PADDING_ATTRIB, IMM_OPERAND_DEFAULT_DISPLAY_ATTRIB, IMM_OPERAND_DISPLAY_ATTRIB, { NULL } @@ -785,7 +603,7 @@ bool ensure_python_imm_operand_is_registered(void) if (!ensure_python_renameable_operand_is_registered()) return false; - if (!register_class_for_pygobject(dict, G_TYPE_IMM_OPERAND, type, get_python_arch_operand_type())) + if (!register_class_for_pygobject(dict, G_TYPE_IMM_OPERAND, type)) return false; if (!define_imm_operand_constants(type)) @@ -841,189 +659,3 @@ int convert_to_imm_operand(PyObject *arg, void *dst) return result; } - - - -/* ---------------------------------------------------------------------------------- */ -/* REMPLACEMENT DE VALEURS IMMEDIATES */ -/* ---------------------------------------------------------------------------------- */ - - -/****************************************************************************** -* * -* Paramètres : type = type de l'objet à instancier. * -* args = arguments fournis à l'appel. * -* kwds = arguments de type key=val fournis. * -* * -* Description : Crée un nouvel objet Python de type 'KnownImmOperand'. * -* * -* Retour : Instance Python mise en place. * -* * -* Remarques : - * -* * -******************************************************************************/ - -static PyObject *py_known_imm_operand_new(PyTypeObject *type, PyObject *args, PyObject *kwds) -{ - PyObject *result; /* Instance à retourner */ - GImmOperand *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" \ - " display." - - ret = PyArg_ParseTuple(args, "O&s", convert_to_imm_operand, &imm, &alt); - if (!ret) return NULL; - - operand = g_known_imm_operand_new(imm, alt); - - result = pygobject_new(G_OBJECT(operand)); - - g_object_unref(operand); - - return (PyObject *)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_known_imm_operand_type(void) -{ - static PyMethodDef py_known_imm_operand_methods[] = { - { NULL } - }; - - static PyGetSetDef py_known_imm_operand_getseters[] = { - { NULL } - }; - - static PyTypeObject py_known_imm_operand_type = { - - PyVarObject_HEAD_INIT(NULL, 0) - - .tp_name = "pychrysalide.arch.operands.KnownImmOperand", - .tp_basicsize = sizeof(PyGObject), - - .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, - - .tp_doc = KNOWN_IMM_OPERAND_DOC, - - .tp_methods = py_known_imm_operand_methods, - .tp_getset = py_known_imm_operand_getseters, - .tp_new = py_known_imm_operand_new - - }; - - return &py_known_imm_operand_type; - -} - - -/****************************************************************************** -* * -* Paramètres : module = module dont la définition est à compléter. * -* * -* Description : Prend en charge l'objet 'pychrysalide.arch.KnownImmOperand'. * -* * -* Retour : Bilan de l'opération. * -* * -* Remarques : - * -* * -******************************************************************************/ - -bool ensure_python_known_imm_operand_is_registered(void) -{ - PyTypeObject *type; /* Type Python 'ImmOperand' */ - PyObject *module; /* Module à recompléter */ - PyObject *dict; /* Dictionnaire du module */ - - type = get_python_known_imm_operand_type(); - - if (!PyType_HasFeature(type, Py_TPFLAGS_READY)) - { - module = get_access_to_python_module("pychrysalide.arch.operands"); - - dict = PyModule_GetDict(module); - - if (!ensure_python_imm_operand_is_registered()) - return false; - - if (!ensure_python_renamed_operand_is_registered()) - return false; - - if (!register_class_for_pygobject(dict, G_TYPE_KNOWN_IMM_OPERAND, type, get_python_imm_operand_type())) - 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 remplaçant d'opérande d'immédiat. * -* * -* Retour : Bilan de l'opération, voire indications supplémentaires. * -* * -* Remarques : - * -* * -******************************************************************************/ - -int convert_to_known_imm_operand(PyObject *arg, void *dst) -{ - int result; /* Bilan à retourner */ - - result = PyObject_IsInstance(arg, (PyObject *)get_python_known_imm_operand_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 known immediate operand"); - break; - - case 1: - *((GKnownImmOperand **)dst) = G_KNOWN_IMM_OPERAND(pygobject_get(arg)); - break; - - default: - assert(false); - break; - - } - - return result; - -} diff --git a/plugins/pychrysalide/arch/operands/immediate.h b/plugins/pychrysalide/arch/operands/immediate.h index 15d2c3e..4a1e6de 100644 --- a/plugins/pychrysalide/arch/operands/immediate.h +++ b/plugins/pychrysalide/arch/operands/immediate.h @@ -31,9 +31,6 @@ -/* ------------------------- OPERANDE POUR VALEUR IMMEDIATE ------------------------- */ - - /* Fournit un accès à une définition de type à diffuser. */ PyTypeObject *get_python_imm_operand_type(void); @@ -45,18 +42,4 @@ int convert_to_imm_operand(PyObject *, void *); -/* ----------------------- REMPLACEMENT DE VALEURS IMMEDIATES ----------------------- */ - - -/* Fournit un accès à une définition de type à diffuser. */ -PyTypeObject *get_python_known_imm_operand_type(void); - -/* Prend en charge l'objet 'pychrysalide.arch.KnownImmOperand'. */ -bool ensure_python_known_imm_operand_is_registered(void); - -/* Tente de convertir en remplaçant d'opérande d'immédiat. */ -int convert_to_known_imm_operand(PyObject *, void *); - - - #endif /* _PLUGINS_PYCHRYSALIDE_ARCH_OPERANDS_IMMEDIATE_H */ diff --git a/plugins/pychrysalide/arch/operands/known.c b/plugins/pychrysalide/arch/operands/known.c new file mode 100644 index 0000000..fab426e --- /dev/null +++ b/plugins/pychrysalide/arch/operands/known.c @@ -0,0 +1,224 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * known.c - équivalent Python du fichier "arch/operands/known.h" + * + * Copyright (C) 2020 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +#include "known.h" + + +#include <assert.h> +#include <pygobject.h> + + +#include <arch/operands/known.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 *); + + + +/****************************************************************************** +* * +* Paramètres : type = type de l'objet à instancier. * +* args = arguments fournis à l'appel. * +* kwds = arguments de type key=val fournis. * +* * +* Description : Crée un nouvel objet Python de type 'KnownImmOperand'. * +* * +* Retour : Instance Python mise en place. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static PyObject *py_known_imm_operand_new(PyTypeObject *type, PyObject *args, PyObject *kwds) +{ + PyObject *result; /* Instance à retourner */ + GImmOperand *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" \ + " display." + + ret = PyArg_ParseTuple(args, "O&s", convert_to_imm_operand, &imm, &alt); + if (!ret) return NULL; + + operand = g_known_imm_operand_new(imm, alt); + + result = pygobject_new(G_OBJECT(operand)); + + g_object_unref(operand); + + return (PyObject *)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_known_imm_operand_type(void) +{ + static PyMethodDef py_known_imm_operand_methods[] = { + { NULL } + }; + + static PyGetSetDef py_known_imm_operand_getseters[] = { + { NULL } + }; + + static PyTypeObject py_known_imm_operand_type = { + + PyVarObject_HEAD_INIT(NULL, 0) + + .tp_name = "pychrysalide.arch.operands.KnownImmOperand", + .tp_basicsize = sizeof(PyGObject), + + .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, + + .tp_doc = KNOWN_IMM_OPERAND_DOC, + + .tp_methods = py_known_imm_operand_methods, + .tp_getset = py_known_imm_operand_getseters, + .tp_new = py_known_imm_operand_new + + }; + + return &py_known_imm_operand_type; + +} + + +/****************************************************************************** +* * +* Paramètres : module = module dont la définition est à compléter. * +* * +* Description : Prend en charge l'objet 'pychrysalide.arch.KnownImmOperand'. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool ensure_python_known_imm_operand_is_registered(void) +{ + PyTypeObject *type; /* Type Python 'ImmOperand' */ + PyObject *module; /* Module à recompléter */ + PyObject *dict; /* Dictionnaire du module */ + + type = get_python_known_imm_operand_type(); + + if (!PyType_HasFeature(type, Py_TPFLAGS_READY)) + { + module = get_access_to_python_module("pychrysalide.arch.operands"); + + dict = PyModule_GetDict(module); + + if (!ensure_python_imm_operand_is_registered()) + return false; + + if (!ensure_python_renamed_operand_is_registered()) + return false; + + if (!register_class_for_pygobject(dict, G_TYPE_KNOWN_IMM_OPERAND, type)) + 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 remplaçant d'opérande d'immédiat. * +* * +* Retour : Bilan de l'opération, voire indications supplémentaires. * +* * +* Remarques : - * +* * +******************************************************************************/ + +int convert_to_known_imm_operand(PyObject *arg, void *dst) +{ + int result; /* Bilan à retourner */ + + result = PyObject_IsInstance(arg, (PyObject *)get_python_known_imm_operand_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 known immediate operand"); + break; + + case 1: + *((GKnownImmOperand **)dst) = G_KNOWN_IMM_OPERAND(pygobject_get(arg)); + break; + + default: + assert(false); + break; + + } + + return result; + +} diff --git a/plugins/pychrysalide/arch/operands/known.h b/plugins/pychrysalide/arch/operands/known.h new file mode 100644 index 0000000..b5ced68 --- /dev/null +++ b/plugins/pychrysalide/arch/operands/known.h @@ -0,0 +1,45 @@ + +/* 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 + * + * 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_OPERANDS_KNOWN_H +#define _PLUGINS_PYCHRYSALIDE_ARCH_OPERANDS_KNOWN_H + + +#include <Python.h> +#include <stdbool.h> + + + +/* Fournit un accès à une définition de type à diffuser. */ +PyTypeObject *get_python_known_imm_operand_type(void); + +/* Prend en charge l'objet 'pychrysalide.arch.KnownImmOperand'. */ +bool ensure_python_known_imm_operand_is_registered(void); + +/* Tente de convertir en remplaçant d'opérande d'immédiat. */ +int convert_to_known_imm_operand(PyObject *, void *); + + + +#endif /* _PLUGINS_PYCHRYSALIDE_ARCH_OPERANDS_KNOWN_H */ diff --git a/plugins/pychrysalide/arch/operands/module.c b/plugins/pychrysalide/arch/operands/module.c index f1669fb..89adecc 100644 --- a/plugins/pychrysalide/arch/operands/module.c +++ b/plugins/pychrysalide/arch/operands/module.c @@ -30,6 +30,7 @@ #include "feeder.h" #include "immediate.h" +#include "known.h" #include "proxy.h" #include "register.h" #include "rename.h" diff --git a/plugins/pychrysalide/arch/operands/proxy.c b/plugins/pychrysalide/arch/operands/proxy.c index 1cfd4a4..5009d29 100644 --- a/plugins/pychrysalide/arch/operands/proxy.c +++ b/plugins/pychrysalide/arch/operands/proxy.c @@ -105,7 +105,7 @@ static PyObject *py_proxy_operand_new(PyTypeObject *type, PyObject *args, PyObje if (first_time) { - status = register_class_for_dynamic_pygobject(gtype, type, base); + status = register_class_for_dynamic_pygobject(gtype, type); if (!status) { @@ -319,7 +319,10 @@ bool ensure_python_proxy_operand_is_registered(void) dict = PyModule_GetDict(module); - if (!register_class_for_pygobject(dict, G_TYPE_PROXY_OPERAND, type, get_python_arch_operand_type())) + if (!ensure_python_arch_operand_is_registered()) + return false; + + if (!register_class_for_pygobject(dict, G_TYPE_PROXY_OPERAND, type)) return false; } diff --git a/plugins/pychrysalide/arch/operands/register.c b/plugins/pychrysalide/arch/operands/register.c index fcf838c..2a48a0f 100644 --- a/plugins/pychrysalide/arch/operands/register.c +++ b/plugins/pychrysalide/arch/operands/register.c @@ -67,9 +67,6 @@ static PyObject *py_register_operand__print(PyObject *, PyObject *); /* Fournit le registre associé à l'opérande. */ static PyObject *py_register_operand_get_register(PyObject *, void *); -/* Indique le type d'accès réalisé sur l'opérande. */ -static PyObject *py_register_operand_is_written(PyObject *, void *); - /* ---------------------------------------------------------------------------------- */ @@ -115,7 +112,7 @@ static PyObject *py_register_operand_new(PyTypeObject *type, PyObject *args, PyO if (first_time) { - status = register_class_for_dynamic_pygobject(gtype, type, base); + status = register_class_for_dynamic_pygobject(gtype, type); if (!status) { @@ -357,43 +354,6 @@ static PyObject *py_register_operand_get_register(PyObject *self, void *closure) /****************************************************************************** * * -* Paramètres : self = objet Python concerné par l'appel. * -* closure = non utilisé ici. * -* * -* Description : Indique le type d'accès réalisé sur l'opérande. * -* * -* Retour : Type d'accès : True en cas d'écriture, False sinon. * -* * -* Remarques : - * -* * -******************************************************************************/ - -static PyObject *py_register_operand_is_written(PyObject *self, void *closure) -{ - PyObject *result; /* Résultat à retourner */ - GRegisterOperand *operand; /* Version GLib du type */ - bool status; /* Statut de la ligne */ - -#define REGISTER_OPERAND_IS_WRITTEN_ATTRIB PYTHON_IS_DEF_FULL \ -( \ - written, py_register_operand, \ - "Kind of access for the register when its instruction is executed." \ -) - - operand = G_REGISTER_OPERAND(pygobject_get(self)); - - status = g_register_operand_is_written(operand); - - result = status ? Py_True : Py_False; - Py_INCREF(result); - - return result; - -} - - -/****************************************************************************** -* * * Paramètres : - * * * * Description : Fournit un accès à une définition de type à diffuser. * @@ -414,7 +374,6 @@ PyTypeObject *get_python_register_operand_type(void) static PyGetSetDef py_register_operand_getseters[] = { REGISTER_OPERAND_REGISTER_ATTRIB, - REGISTER_OPERAND_IS_WRITTEN_ATTRIB, { NULL } }; @@ -468,7 +427,10 @@ bool ensure_python_register_operand_is_registered(void) dict = PyModule_GetDict(module); - if (!register_class_for_pygobject(dict, G_TYPE_REGISTER_OPERAND, type, get_python_arch_operand_type())) + if (!ensure_python_arch_operand_is_registered()) + return false; + + if (!register_class_for_pygobject(dict, G_TYPE_REGISTER_OPERAND, type)) return false; } diff --git a/plugins/pychrysalide/arch/operands/target.c b/plugins/pychrysalide/arch/operands/target.c index 5cd9f59..b8cd536 100644 --- a/plugins/pychrysalide/arch/operands/target.c +++ b/plugins/pychrysalide/arch/operands/target.c @@ -115,7 +115,7 @@ static PyObject *py_target_operand_new(PyTypeObject *type, PyObject *args, PyObj if (first_time) { - status = register_class_for_dynamic_pygobject(gtype, type, base); + status = register_class_for_dynamic_pygobject(gtype, type); if (!status) { @@ -176,7 +176,8 @@ static int py_target_operand_init(PyObject *self, PyObject *args, PyObject *kwds MemoryDataSize size; /* Taille des adresses mémoire */ vmpa2t *addr; /* Emplacement de symbole */ int ret; /* Bilan de lecture des args. */ - GTargetOperand *operand; /* Opérande à manipuler */ + GTargetOperand *operand; /* Opérande à manipuler */ + tarop_extra_data_t *extra; /* Données insérées à modifier */ #define TARGET_OPERAND_DOC \ "The TargetOperand object translates immediate values as symbols.\n" \ @@ -203,7 +204,10 @@ static int py_target_operand_init(PyObject *self, PyObject *args, PyObject *kwds operand = G_TARGET_OPERAND(pygobject_get(self)); - operand->size = size; + extra = GET_TARGET_OP_EXTRA(operand); + + extra->size = size; + copy_vmpa(&operand->addr, addr); clean_vmpa_arg(addr); @@ -425,10 +429,13 @@ bool ensure_python_target_operand_is_registered(void) dict = PyModule_GetDict(module); + if (!ensure_python_arch_operand_is_registered()) + return false; + if (!ensure_python_targetable_operand_is_registered()) return false; - if (!register_class_for_pygobject(dict, G_TYPE_TARGET_OPERAND, type, get_python_arch_operand_type())) + if (!register_class_for_pygobject(dict, G_TYPE_TARGET_OPERAND, type)) return false; } diff --git a/plugins/pychrysalide/arch/processor.c b/plugins/pychrysalide/arch/processor.c index 80b55d3..00b472f 100644 --- a/plugins/pychrysalide/arch/processor.c +++ b/plugins/pychrysalide/arch/processor.c @@ -186,7 +186,7 @@ static PyObject *py_arch_processor_new(PyTypeObject *type, PyObject *args, PyObj if (first_time) { - status = register_class_for_dynamic_pygobject(gtype, type, base); + status = register_class_for_dynamic_pygobject(gtype, type); if (!status) { @@ -1452,7 +1452,7 @@ bool ensure_python_arch_processor_is_registered(void) dict = PyModule_GetDict(module); - if (!register_class_for_pygobject(dict, G_TYPE_ARCH_PROCESSOR, type, &PyGObject_Type)) + if (!register_class_for_pygobject(dict, G_TYPE_ARCH_PROCESSOR, type)) return false; if (!define_arch_processor_constants(type)) diff --git a/plugins/pychrysalide/arch/register.c b/plugins/pychrysalide/arch/register.c index 61da77f..615a5b7 100644 --- a/plugins/pychrysalide/arch/register.c +++ b/plugins/pychrysalide/arch/register.c @@ -36,6 +36,7 @@ #include "../access.h" #include "../helpers.h" +#include "../analysis/storage/serialize.h" @@ -143,7 +144,7 @@ static PyObject *py_arch_register_new(PyTypeObject *type, PyObject *args, PyObje if (first_time) { - status = register_class_for_dynamic_pygobject(gtype, type, base); + status = register_class_for_dynamic_pygobject(gtype, type); if (!status) { @@ -682,7 +683,10 @@ bool ensure_python_arch_register_is_registered(void) dict = PyModule_GetDict(module); - if (!register_class_for_pygobject(dict, G_TYPE_ARCH_REGISTER, type, &PyGObject_Type)) + if (!ensure_python_serializable_object_is_registered()) + return false; + + if (!register_class_for_pygobject(dict, G_TYPE_ARCH_REGISTER, type)) return false; } diff --git a/plugins/pychrysalide/common/Makefile.am b/plugins/pychrysalide/common/Makefile.am index 1fb268d..b5249b9 100644 --- a/plugins/pychrysalide/common/Makefile.am +++ b/plugins/pychrysalide/common/Makefile.am @@ -1,25 +1,21 @@ noinst_LTLIBRARIES = libpychrysacommon.la -libpychrysacommon_la_SOURCES = \ - bits.h bits.c \ - fnv1a.h fnv1a.c \ - hex.h hex.c \ - leb128.h leb128.c \ - module.h module.c \ - packed.h packed.c \ - pathname.h pathname.c \ +libpychrysacommon_la_SOURCES = \ + bits.h bits.c \ + 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 \ pearson.h pearson.c -libpychrysacommon_la_LDFLAGS = +libpychrysacommon_la_CFLAGS = $(TOOLKIT_CFLAGS) $(LIBXML_CFLAGS) $(LIBPYTHON_INTERPRETER_CFLAGS) $(LIBPYGOBJECT_CFLAGS) \ + -I$(top_srcdir)/src -DNO_IMPORT_PYGOBJECT devdir = $(includedir)/chrysalide/$(subdir) dev_HEADERS = $(libpychrysacommon_la_SOURCES:%c=) - - -AM_CPPFLAGS = $(LIBGTK_CFLAGS) $(LIBXML_CFLAGS) $(LIBPYTHON_CFLAGS) $(LIBPYGOBJECT_CFLAGS) \ - -I$(top_srcdir)/src - -AM_CFLAGS = $(DEBUG_CFLAGS) $(WARNING_FLAGS) $(COMPLIANCE_FLAGS) diff --git a/plugins/pychrysalide/common/bits.c b/plugins/pychrysalide/common/bits.c index 73fd55b..a127251 100644 --- a/plugins/pychrysalide/common/bits.c +++ b/plugins/pychrysalide/common/bits.c @@ -65,6 +65,9 @@ static PyObject *py_bitfield_richcompare(PyObject *, PyObject *, int); /* Crée une copie d'un champ de bits classique. */ static PyObject *py_bitfield_dup(PyObject *, PyObject *); +/* Redimensionne un champ de bits. */ +static PyObject *py_bitfield_resize(PyObject *, PyObject *); + /* Bascule à 0 un champ de bits dans son intégralité. */ static PyObject *py_bitfield_reset_all(PyObject *, PyObject *); @@ -77,6 +80,9 @@ static PyObject *py_bitfield_reset(PyObject *, PyObject *); /* Bascule à 1 une partie d'un champ de bits. */ static PyObject *py_bitfield_set(PyObject *, PyObject *); +/* Réalise une opération OU logique entre deux champs de bits. */ +static PyObject *py_bitfield_or_at(PyObject *, PyObject *); + /* Détermine si un bit est à 1 dans un champ de bits. */ static PyObject *py_bitfield_test(PyObject *, PyObject *); @@ -86,6 +92,15 @@ static PyObject *py_bitfield_test_none(PyObject *, PyObject *); /* Détermine si un ensemble de bits est à 1 dans un champ. */ static PyObject *py_bitfield_test_all(PyObject *, PyObject *); +/* Teste l'état à 0 de bits selon un masque de bits. */ +static PyObject *py_bitfield_test_zeros_with(PyObject *, PyObject *); + +/* Teste l'état à 1 de bits selon un masque de bits. */ +static PyObject *py_bitfield_test_ones_with(PyObject *, PyObject *); + +/* Recherche un prochain bit défini dans un champ de bits. */ +static PyObject *py_bitfield_find_next_set(PyObject *, PyObject *); + /* Indique la taille d'un champ de bits donné. */ static PyObject *py_bitfield_get_size(PyObject *, void *); @@ -399,6 +414,47 @@ static PyObject *py_bitfield_dup(PyObject *self, PyObject *args) /****************************************************************************** * * +* Paramètres : self = champ de bits à dupliquer. * +* args = non utilisé ici. * +* * +* Description : Redimensionne un champ de bits. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static PyObject *py_bitfield_resize(PyObject *self, PyObject *args) +{ + unsigned long length; /* Nouvelle taille à respecter */ + int ret; /* Bilan de lecture des args. */ + py_bitfield_t *bf; /* Instance à manipuler */ + +#define BITFIELD_RESIZE_METHOD PYTHON_METHOD_DEF \ +( \ + resize, "$self, length, /", \ + METH_VARARGS, py_bitfield, \ + "Resize a bitfield and fix its new size to *length*.\n" \ + "\n" \ + "The new bits get initialized to the same state used at the" \ + " bitfield creation." \ +) + + ret = PyArg_ParseTuple(args, "k", &length); + if (!ret) return NULL; + + bf = (py_bitfield_t *)self; + + resize_bit_field(&bf->native, length); + + Py_RETURN_NONE; + +} + + +/****************************************************************************** +* * * Paramètres : self = champ de bits à modifier. * * args = non utilisé ici. * * * @@ -552,6 +608,49 @@ static PyObject *py_bitfield_set(PyObject *self, PyObject *args) * Paramètres : self = champ de bits à consulter. * * args = arguments fournis pour la conduite de l'opération. * * * +* Description : Réalise une opération OU logique entre deux champs de bits. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static PyObject *py_bitfield_or_at(PyObject *self, PyObject *args) +{ + bitfield_t *src; /* Seconde champ de bits */ + unsigned long first; /* Indice du premier bit testé */ + int ret; /* Bilan de lecture des args. */ + py_bitfield_t *bf; /* Instance à manipuler */ + +#define BITFIELD_OR_AT_METHOD PYTHON_METHOD_DEF \ +( \ + or_at, "$self, src, first, /", \ + METH_VARARGS, py_bitfield, \ + "Perform an OR operation with another bitfield.\n" \ + "\n" \ + "The *src* argument is expected to be another" \ + " pychrysalide.common.BitField instance. The area to" \ + " process starts at bit *first* from *src*." \ +) + + ret = PyArg_ParseTuple(args, "O&k", convert_to_bitfield, &src, &first); + if (!ret) return NULL; + + bf = (py_bitfield_t *)self; + + or_bit_field_at(bf->native, src, first); + + Py_RETURN_NONE; + +} + + +/****************************************************************************** +* * +* Paramètres : self = champ de bits à consulter. * +* args = arguments fournis pour la conduite de l'opération. * +* * * Description : Détermine si un bit est à 1 dans un champ de bits. * * * * Retour : true si le bit correspondant est à l'état haut. * @@ -695,6 +794,158 @@ static PyObject *py_bitfield_test_all(PyObject *self, PyObject *args) /****************************************************************************** * * +* Paramètres : self = champ de bits à consulter. * +* args = arguments fournis pour la conduite de l'opération. * +* * +* Description : Teste l'état à 0 de bits selon un masque de bits. * +* * +* Retour : true si les bits visés sont à l'état bas. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static PyObject *py_bitfield_test_zeros_with(PyObject *self, PyObject *args) +{ + PyObject *result; /* Bilan à faire remonter */ + unsigned long first; /* Indice du premier bit testé */ + bitfield_t *mask; /* Champ de bits natif */ + int ret; /* Bilan de lecture des args. */ + py_bitfield_t *bf; /* Instance à manipuler */ + bool status; /* Bilan d'analyse */ + +#define BITFIELD_TEST_ZEROS_WITH_METHOD PYTHON_METHOD_DEF \ +( \ + test_zeros_with, "$self, first, mask, /", \ + METH_VARARGS, py_bitfield, \ + "Test a range of bits against another bit field.\n" \ + "\n" \ + "The area to process starts at bit *first* and the" \ + " test relies on bits set within the *mask* object.\n" \ + "\n" \ + "The result is a boolean value: True if all tested" \ + " bits are unset, False otherwise." \ +) + + ret = PyArg_ParseTuple(args, "kO&", &first, convert_to_bitfield, &mask); + if (!ret) return NULL; + + bf = (py_bitfield_t *)self; + + status = test_zeros_within_bit_field(bf->native, first, mask); + + result = status ? Py_True : Py_False; + Py_INCREF(result); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : self = champ de bits à consulter. * +* args = arguments fournis pour la conduite de l'opération. * +* * +* Description : Teste l'état à 1 de bits selon un masque de bits. * +* * +* Retour : true si les bits visés sont à l'état haut. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static PyObject *py_bitfield_test_ones_with(PyObject *self, PyObject *args) +{ + PyObject *result; /* Bilan à faire remonter */ + unsigned long first; /* Indice du premier bit testé */ + bitfield_t *mask; /* Champ de bits natif */ + int ret; /* Bilan de lecture des args. */ + py_bitfield_t *bf; /* Instance à manipuler */ + bool status; /* Bilan d'analyse */ + +#define BITFIELD_TEST_ONES_WITH_METHOD PYTHON_METHOD_DEF \ +( \ + test_ones_with, "$self, first, mask, /", \ + METH_VARARGS, py_bitfield, \ + "Test a range of bits against another bit field.\n" \ + "\n" \ + "The area to process starts at bit *first* and the" \ + " test relies on bits set within the *mask* object.\n" \ + "\n" \ + "The result is a boolean value: True if all tested" \ + " bits are set, False otherwise." \ +) + + ret = PyArg_ParseTuple(args, "kO&", &first, convert_to_bitfield, &mask); + if (!ret) return NULL; + + bf = (py_bitfield_t *)self; + + status = test_ones_within_bit_field(bf->native, first, mask); + + result = status ? Py_True : Py_False; + Py_INCREF(result); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : self = champ de bits à consulter. * +* args = arguments fournis pour la conduite de l'opération. * +* * +* Description : Recherche un prochain bit défini dans un champ de bits. * +* * +* Retour : Position d'un bit à 1 ou taille du champ si plus aucun. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static PyObject *py_bitfield_find_next_set(PyObject *self, PyObject *args) +{ + PyObject *result; /* Bilan à faire remonter */ + unsigned long prev; /* Indice d'un bit à écarter */ + int ret; /* Bilan de lecture des args. */ + py_bitfield_t *bf; /* Instance à manipuler */ + size_t found; /* Indice de bit trouvé */ + +#define BITFIELD_FIND_NEXT_SET_METHOD PYTHON_METHOD_DEF \ +( \ + find_next_set, "$self, /, prev=None", \ + METH_VARARGS, py_bitfield, \ + "Find the index of the next set bit in the bit field.\n"\ + "\n" \ + "If provided, the *prev* argument is the position of" \ + " a previously found bit, which gets discarded for the" \ + " current call.\n" \ + "\n" \ + "The result is a integer value: a valid index inside" \ + " the bit field, or the bit field size if no set bit" \ + " is found." \ +) + + prev = (unsigned long)-1; + + ret = PyArg_ParseTuple(args, "|k", &prev); + if (!ret) return NULL; + + bf = (py_bitfield_t *)self; + + found = find_next_set_in_bit_field(bf->native, prev == (unsigned long)-1 ? NULL : (size_t []) { prev }); + + result = PyLong_FromSize_t(found); + + return result; + +} + + +/****************************************************************************** +* * * Paramètres : self = classe représentant une instruction. * * closure = adresse non utilisée ici. * * * @@ -791,13 +1042,18 @@ PyTypeObject *get_python_bitfield_type(void) static PyMethodDef py_bitfield_methods[] = { BITFIELD_DUP_METHOD, + BITFIELD_RESIZE_METHOD, BITFIELD_RESET_ALL_METHOD, BITFIELD_SET_ALL_METHOD, BITFIELD_RESET_METHOD, BITFIELD_SET_METHOD, + BITFIELD_OR_AT_METHOD, BITFIELD_TEST_METHOD, BITFIELD_TEST_NONE_METHOD, BITFIELD_TEST_ALL_METHOD, + BITFIELD_TEST_ZEROS_WITH_METHOD, + BITFIELD_TEST_ONES_WITH_METHOD, + BITFIELD_FIND_NEXT_SET_METHOD, { NULL } }; @@ -876,6 +1132,51 @@ bool ensure_python_bitfield_is_registered(void) /****************************************************************************** * * +* 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 champ de bits. * +* * +* Retour : Bilan de l'opération, voire indications supplémentaires. * +* * +* Remarques : - * +* * +******************************************************************************/ + +int convert_to_bitfield(PyObject *arg, void *dst) +{ + int result; /* Bilan à retourner */ + + result = PyObject_IsInstance(arg, (PyObject *)get_python_bitfield_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 bit field"); + break; + + case 1: + *((bitfield_t **)dst) = ((py_bitfield_t *)arg)->native; + break; + + default: + assert(false); + break; + + } + + return result; + +} + + +/****************************************************************************** +* * * Paramètres : field = structure interne à copier en objet Python. * * * * Description : Convertit une structure de type 'bitfield_t' en objet Python.* diff --git a/plugins/pychrysalide/common/bits.h b/plugins/pychrysalide/common/bits.h index 6ddaaa5..804c3b5 100644 --- a/plugins/pychrysalide/common/bits.h +++ b/plugins/pychrysalide/common/bits.h @@ -40,6 +40,9 @@ PyTypeObject *get_python_bitfield_type(void); /* Prend en charge l'objet 'pychrysalide.common.BitField'. */ bool ensure_python_bitfield_is_registered(void); +/* Tente de convertir en champ de bits. */ +int convert_to_bitfield(PyObject *, void *); + /* Convertit une structure de type 'bitfield_t' en objet Python. */ PyObject *build_from_internal_bitfield(const bitfield_t *); diff --git a/plugins/pychrysalide/common/itoa.c b/plugins/pychrysalide/common/itoa.c new file mode 100644 index 0000000..107b047 --- /dev/null +++ b/plugins/pychrysalide/common/itoa.c @@ -0,0 +1,124 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * itoa.c - équivalent Python du fichier "common/itoa.c" + * + * Copyright (C) 2023 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 "itoa.h" + + +#include <common/itoa.h> + + +#include "../access.h" +#include "../helpers.h" + + + +/* Détermine l'empreinte Itoa d'une chaîne de caractères. */ +static PyObject *py_itoa(PyObject *, PyObject *); + + + +/****************************************************************************** +* * +* Paramètres : self = NULL car méthode statique. * +* args = arguments fournis lors de l'appel à la fonction. * +* * +* Description : Convertit une valeur en une forme textuelle. * +* * +* Retour : Chaîne de caractères mises en place. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static PyObject *py_itoa(PyObject *self, PyObject *args) +{ + PyObject *result; /* Instance à retourner */ + long long n; /* Valeur à transformer */ + unsigned char base; /* Base de travail */ + int ret; /* Bilan de lecture des args. */ + char *strval; /* Valeur sous forme de chaîne */ + +#define ITOA_METHOD PYTHON_METHOD_DEF \ +( \ + itoa, "n, /, base=10", \ + METH_VARARGS, py, \ + "Construct a string representation of an integer *n* according" \ + " to a given *base*.\n" \ + "\n" \ + "Both arguments are expected to be integer values; the result" \ + " is a string or None in case of failure." \ +) + + base = 10; + + ret = PyArg_ParseTuple(args, "L|b", &n, &base); + if (!ret) return NULL; + + strval = itoa(n, base); + + if (strval != NULL) + { + result = PyUnicode_FromString(strval); + free(strval); + } + else + { + result = Py_None; + Py_INCREF(result); + } + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : - * +* * +* Description : Définit une extension du module 'common' à compléter. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool populate_common_module_with_itoa(void) +{ + bool result; /* Bilan à retourner */ + PyObject *module; /* Module à recompléter */ + + static PyMethodDef py_itoa_methods[] = { + ITOA_METHOD, + { NULL } + }; + + module = get_access_to_python_module("pychrysalide.common"); + + result = register_python_module_methods(module, py_itoa_methods); + + return result; + +} diff --git a/plugins/pychrysalide/common/itoa.h b/plugins/pychrysalide/common/itoa.h new file mode 100644 index 0000000..a66e767 --- /dev/null +++ b/plugins/pychrysalide/common/itoa.h @@ -0,0 +1,39 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * itoa.h - prototypes pour l'équivalent Python du fichier "common/itoa.c" + * + * Copyright (C) 2023 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_COMMON_ITOA_H +#define _PLUGINS_PYCHRYSALIDE_COMMON_ITOA_H + + +#include <Python.h> +#include <stdbool.h> + + + +/* Définit une extension du module 'common' à compléter. */ +bool populate_common_module_with_itoa(void); + + + +#endif /* _PLUGINS_PYCHRYSALIDE_COMMON_ITOA_H */ diff --git a/plugins/pychrysalide/common/module.c b/plugins/pychrysalide/common/module.c index 6ced1b7..a0042ee 100644 --- a/plugins/pychrysalide/common/module.c +++ b/plugins/pychrysalide/common/module.c @@ -28,6 +28,7 @@ #include "bits.h" #include "fnv1a.h" #include "hex.h" +#include "itoa.h" #include "leb128.h" #include "packed.h" #include "pathname.h" @@ -99,6 +100,7 @@ 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(); diff --git a/plugins/pychrysalide/core.c b/plugins/pychrysalide/core.c index 98f94b6..08f570f 100644 --- a/plugins/pychrysalide/core.c +++ b/plugins/pychrysalide/core.c @@ -21,6 +21,11 @@ */ +#undef NO_IMPORT_PYGOBJECT +#include <pygobject.h> +#define NO_IMPORT_PYGOBJECT + + #include "core.h" @@ -35,7 +40,6 @@ #include <unistd.h> -#include <config.h> #include <i18n.h> #include <gleak.h> #include <common/cpp.h> @@ -60,8 +64,10 @@ #include "debug/module.h" #include "format/module.h" #include "glibext/module.h" -#include "gtkext/module.h" -#include "gui/module.h" +#ifdef INCLUDE_GTK_SUPPORT +# include "gtkext/module.h" +# include "gui/module.h" +#endif #include "mangling/module.h" #include "plugins/module.h" #include "plugins/plugin.h" @@ -80,9 +86,6 @@ static bool _standalone = true; /* Réceptacle pour le chargement forcé */ static PyObject *_chrysalide_module = NULL; -/* Conservation des informations du thread principal */ -static PyThreadState *_main_tstate = NULL; - /* Fournit la révision du programme global. */ static PyObject *py_chrysalide_revision(PyObject *, PyObject *); @@ -96,8 +99,13 @@ static PyObject *py_chrysalide_mod_version(PyObject *, PyObject *); /* Détermine si l'interpréteur lancé est celui pris en compte. */ static bool is_current_abi_suitable(void); +/* Assure une pleine initialisation des objets de Python-GI. */ +static bool install_metaclass_for_python_gobjects(void); + /* Définit la version attendue de GTK à charger dans Python. */ +#ifdef INCLUDE_GTK_SUPPORT static bool set_version_for_gtk_namespace(const char *); +#endif /* Point de sortie pour l'initialisation de Python. */ static void PyExit_pychrysalide(void); @@ -249,7 +257,8 @@ static bool is_current_abi_suitable(void) #define GRAB_ABI_FLAGS_IN_PYTHON \ "import sys" "\n" \ "import os" "\n" \ - "os.write(%d, bytes(sys.abiflags, 'UTF-8'))" "\n" + "data = bytes(sys.abiflags, 'UTF-8') + b'\\0'" "\n" \ + "os.write(%d, data)" "\n" result = false; @@ -289,6 +298,126 @@ static bool is_current_abi_suitable(void) /****************************************************************************** * * +* Paramètres : - * +* * +* Description : Assure une pleine initialisation des objets de Python-GI. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static bool install_metaclass_for_python_gobjects(void) +{ + bool result; /* Bilan à retourner */ + PyObject *gi_types_mod; /* Module Python-GObject */ + + /** + * Les extensions Python sont chargées à partir de la fonction load_python_plugins(), + * qui fait appel à create_python_plugin(). Une instance y est construite via un + * appel à PyObject_CallFunction() avec la classe spécifiée par l'alias AutoLoad + * dans le fichier __init__.py présent dans chaque module d'extension. + * + * Le constructeur py_plugin_module_new() renvoie in fine à la fonction générique + * python_abstract_constructor_with_dynamic_gtype(), laquelle conduit à la fonction + * pygobject_register_class() définie dans <python3-gi>/gi/pygobject-object.c. + * Le code de cette dernière comprend notamment la portion suivante : + * + * [...] + * Py_SET_TYPE(type, PyGObject_MetaType); + * [...] + * if (PyType_Ready(type) < 0) { + * g_warning ("couldn't make the type `%s' ready", type->tp_name); + * return; + * } + * [...] + * + * La fonction PyType_Ready() est définie dans <python3>/Objects/typeobject.c + * et commence par : + * + * int PyType_Ready(PyTypeObject *type) + * { + * if (type->tp_flags & Py_TPFLAGS_READY) { + * assert(_PyType_CheckConsistency(type)); + * return 0; + * } + * [...] + * } + * + * La vérification de cohérencce commence par analyser le type et son propre + * type : + * + * - cf. _PyType_CheckConsistency() dans <python3>/Objects/typeobject.c : + * + * int _PyType_CheckConsistency(PyTypeObject *type) + * { + * [...] + * CHECK(!_PyObject_IsFreed((PyObject *)type)); + * [...] + * } + * + * - cf. _PyObject_IsFreed() dans <python3>/Objects/object.c : + * + * int _PyObject_IsFreed(PyObject *op) + * { + * if (_PyMem_IsPtrFreed(op) || _PyMem_IsPtrFreed(Py_TYPE(op))) { + * return 1; + * } + * + * La fonction _PyMem_IsPtrFreed() recherche entre autres la valeur NULL. + * + * Or le type du type est écrasé dans la fonction pygobject_register_class() + * avec la valeur de la variable PyGObject_MetaType. Cette variable n'est + * définie qu'à un seul endroit, dans <python3-gi>/gi/gimodule.c : + * + * static PyObject * + * pyg__install_metaclass(PyObject *dummy, PyTypeObject *metaclass) + * { + * Py_INCREF(metaclass); + * PyGObject_MetaType = metaclass; + * Py_INCREF(metaclass); + * + * Py_SET_TYPE(&PyGObject_Type, metaclass); + * + * Py_INCREF(Py_None); + * return Py_None; + * } + * + * Afin de valider la vérification de _PyType_CheckConsistency() pour les + * modules externes qui entraînent un enregistrement tout en portant le drapeau + * Py_TPFLAGS_READY (typiquement ceux du répertoire "plugins/python/", il faut + * initialiser au besoin la variable PyGObject_MetaType. + * + * Une ligne suffit donc à enregistrer le type intermédiaire : + * + * from _gi import types + * + * On simule ici une déclaration similaire si nécessaire + */ + + result = false; + + if (PyType_CheckExact(&PyGObject_Type)) + { + gi_types_mod = PyImport_ImportModule("gi.types"); + + result = (PyErr_Occurred() == NULL); + + if (result) + result = (PyType_CheckExact(&PyGObject_Type) == 0); + + Py_XDECREF(gi_types_mod); + + } + + return result; + +} + + +/****************************************************************************** +* * * Paramètres : version = idenfiant de la version de GTK à stipuler. * * * * Description : Définit la version attendue de GTK à charger dans Python. * @@ -298,7 +427,7 @@ static bool is_current_abi_suitable(void) * Remarques : - * * * ******************************************************************************/ - +#ifdef INCLUDE_GTK_SUPPORT static bool set_version_for_gtk_namespace(const char *version) { bool result; /* Bilan à retourner */ @@ -334,6 +463,7 @@ static bool set_version_for_gtk_namespace(const char *version) return result; } +#endif /****************************************************************************** @@ -456,8 +586,13 @@ PyMODINIT_FUNC PyInit_pychrysalide(void) goto exit; } + if (!install_metaclass_for_python_gobjects()) + goto exit; + +#ifdef INCLUDE_GTK_SUPPORT if (!set_version_for_gtk_namespace("3.0")) goto exit; +#endif if (!load_all_core_components(true)) { @@ -482,8 +617,10 @@ PyMODINIT_FUNC PyInit_pychrysalide(void) if (status) status = add_debug_module(result); if (status) status = add_format_module(result); if (status) status = add_glibext_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); @@ -497,8 +634,10 @@ PyMODINIT_FUNC PyInit_pychrysalide(void) if (status) status = populate_debug_module(); if (status) status = populate_format_module(); if (status) status = populate_glibext_module(); +#ifdef INCLUDE_GTK_SUPPORT if (status) status = populate_gtkext_module(); if (status) status = populate_gui_module(); +#endif if (status) status = populate_mangling_module(); if (status) status = populate_plugins_module(); @@ -650,7 +789,6 @@ static void load_python_plugins(GPluginModule *plugin) struct dirent *entry; /* Elément trouvé */ char *modname; /* Nom du module pour Python */ char *filename; /* Chemin d'accès reconstruit */ - PyThreadState *tstate; /* Contexte d'environnement */ GPluginModule *pyplugin; /* Lien vers un grffon Python */ bool status; /* Bilan d'une opération */ GGenConfig *config; /* Configuration à charger */ @@ -669,11 +807,11 @@ static void load_python_plugins(GPluginModule *plugin) if (dir != NULL) { - closedir(dir); + closedir(dir); - edir = get_effective_directory(PLUGINS_DATA_DIR G_DIR_SEPARATOR_S "python"); - extend_python_path(edir); - free(edir); + edir = get_effective_directory(PLUGINS_DATA_DIR G_DIR_SEPARATOR_S "python"); + extend_python_path(edir); + free(edir); } @@ -690,7 +828,7 @@ static void load_python_plugins(GPluginModule *plugin) save = NULL; /* gcc... */ for (path = strtok_r(paths, ":", &save); - path != NULL; + path != NULL; path = strtok_r(NULL, ":", &save)) { dir = opendir(path); @@ -730,16 +868,7 @@ static void load_python_plugins(GPluginModule *plugin) filename = stradd(filename, G_DIR_SEPARATOR_S); filename = stradd(filename, entry->d_name); - if (!_standalone) - { - tstate = get_pychrysalide_main_tstate(); - PyEval_RestoreThread(tstate); - } - - pyplugin = g_python_plugin_new(modname, filename); - - if (!_standalone) - PyEval_SaveThread(); + pyplugin = create_python_plugin(modname, filename); if (pyplugin == NULL) { @@ -778,7 +907,7 @@ static void load_python_plugins(GPluginModule *plugin) } - closedir(dir); + closedir(dir); } @@ -802,6 +931,7 @@ static void load_python_plugins(GPluginModule *plugin) G_MODULE_EXPORT bool chrysalide_plugin_init(GPluginModule *plugin) { bool result; /* Bilan à retourner */ + PyGILState_STATE gstate; /* Sauvegarde d'environnement */ int ret; /* Bilan de préparatifs */ _standalone = false; @@ -819,9 +949,7 @@ G_MODULE_EXPORT bool chrysalide_plugin_init(GPluginModule *plugin) Py_Initialize(); - PyEval_InitThreads(); - - PySys_SetArgv(0, (wchar_t *[]) { NULL }); + gstate = PyGILState_Ensure(); _chrysalide_module = PyImport_ImportModule("pychrysalide"); @@ -838,9 +966,7 @@ G_MODULE_EXPORT bool chrysalide_plugin_init(GPluginModule *plugin) result = (_chrysalide_module != NULL); - _main_tstate = PyThreadState_Get(); - - PyEval_ReleaseLock(); + PyGILState_Release(gstate); cpi_done: @@ -863,10 +989,16 @@ G_MODULE_EXPORT bool chrysalide_plugin_init(GPluginModule *plugin) G_MODULE_EXPORT void chrysalide_plugin_exit(GPluginModule *plugin) { + PyGILState_STATE gstate; /* Sauvegarde d'environnement */ + + gstate = PyGILState_Ensure(); + clear_all_accesses_to_python_modules(); Py_XDECREF(_chrysalide_module); + PyGILState_Release(gstate); + } @@ -907,8 +1039,8 @@ static void free_native_plugin_type(PyTypeObject *type) G_MODULE_EXPORT void chrysalide_plugin_on_plugins_loaded(GPluginModule *plugin, PluginAction action) { + PyGILState_STATE gstate; /* Sauvegarde d'environnement */ size_t count; /* Quantité de greffons chargés*/ - PyTypeObject *parent; /* Type Python pour greffon */ PyObject *module; /* Module à recompléter */ PyObject *dict; /* Dictionnaire du module */ GPluginModule **list; /* Ensemble de ces greffons */ @@ -918,14 +1050,14 @@ G_MODULE_EXPORT void chrysalide_plugin_on_plugins_loaded(GPluginModule *plugin, int ret; /* Bilan d'un appel */ PyTypeObject *type; /* Nouveau type dynamique */ + gstate = PyGILState_Ensure(); + if (action == PGA_NATIVE_PLUGINS_LOADED) { /* Intégration des greffons natifs en Python */ if (ensure_python_plugin_module_is_registered()) { - parent = get_python_plugin_module_type(); - module = get_access_to_python_module("pychrysalide.plugins"); assert(module != NULL); @@ -958,7 +1090,7 @@ G_MODULE_EXPORT void chrysalide_plugin_on_plugins_loaded(GPluginModule *plugin, type->tp_flags = Py_TPFLAGS_DEFAULT; type->tp_new = no_python_constructor_allowed; - if (register_class_for_pygobject(dict, G_OBJECT_TYPE(list[i]), type, parent)) + if (register_class_for_pygobject(dict, G_OBJECT_TYPE(list[i]), type)) g_object_set_data_full(G_OBJECT(list[i]), "python_type", type, (GDestroyNotify)free_native_plugin_type); @@ -978,6 +1110,8 @@ G_MODULE_EXPORT void chrysalide_plugin_on_plugins_loaded(GPluginModule *plugin, } + PyGILState_Release(gstate); + } @@ -998,17 +1132,13 @@ G_MODULE_EXPORT void chrysalide_plugin_on_plugins_loaded(GPluginModule *plugin, G_MODULE_EXPORT gpointer chrysalide_plugin_build_type_instance(GPluginModule *plugin, PluginAction action, GType type) { gpointer result; /* Instance à retourner */ - PyThreadState *tstate; /* Contexte d'environnement */ + PyGILState_STATE gstate; /* Sauvegarde d'environnement */ PyTypeObject *pytype; /* Classe Python concernée */ PyObject *instance; /* Initialisation forcée */ result = NULL; - if (!_standalone) - { - tstate = get_pychrysalide_main_tstate(); - PyEval_RestoreThread(tstate); - } + gstate = PyGILState_Ensure(); pytype = pygobject_lookup_class(type); @@ -1021,31 +1151,7 @@ G_MODULE_EXPORT gpointer chrysalide_plugin_build_type_instance(GPluginModule *pl } - if (!_standalone) - PyEval_SaveThread(); - - return result; - -} - - -/****************************************************************************** -* * -* Paramètres : - * -* * -* Description : Fournit les informations du thread principal. * -* * -* Retour : Indications utiles à Python. * -* * -* Remarques : - * -* * -******************************************************************************/ - -PyThreadState *get_pychrysalide_main_tstate(void) -{ - PyThreadState *result; /* Indications à retourner */ - - result = _main_tstate; + PyGILState_Release(gstate); return result; @@ -1074,6 +1180,8 @@ void log_pychrysalide_exception(const char *prefix, ...) PyObject *err_string; /* Description Python d'erreur */ const char *err_msg; /* Représentation humaine */ + assert(PyGILState_Check() == 1); + if (PyErr_Occurred()) { /* Base de la communication */ @@ -1120,7 +1228,7 @@ void log_pychrysalide_exception(const char *prefix, ...) * * C'est par exemple le cas quand un greffon Python ne peut se lancer * correctement ; l'exception est alors levée à partir de la fonction - * g_python_plugin_new() et le plantage intervient en sortie d'exécution, + * create_python_plugin() et le plantage intervient en sortie d'exécution, * au moment de la libération de l'extension Python : * * ==14939== Jump to the invalid address stated on the next line diff --git a/plugins/pychrysalide/core.h b/plugins/pychrysalide/core.h index 6a7b9d1..88c4140 100644 --- a/plugins/pychrysalide/core.h +++ b/plugins/pychrysalide/core.h @@ -55,9 +55,6 @@ G_MODULE_EXPORT void chrysalide_plugin_on_plugins_loaded(GPluginModule *, Plugin /* Crée une instance à partir d'un type dynamique externe. */ G_MODULE_EXPORT gpointer chrysalide_plugin_build_type_instance(GPluginModule *, PluginAction, GType); -/* Fournit les informations du thread principal. */ -PyThreadState *get_pychrysalide_main_tstate(void); - /* Présente dans le journal une exception survenue. */ void log_pychrysalide_exception(const char *, ...); diff --git a/plugins/pychrysalide/core/Makefile.am b/plugins/pychrysalide/core/Makefile.am index 6c032c3..880823d 100644 --- a/plugins/pychrysalide/core/Makefile.am +++ b/plugins/pychrysalide/core/Makefile.am @@ -1,25 +1,20 @@ noinst_LTLIBRARIES = libpychrysacore.la -libpychrysacore_la_SOURCES = \ - constants.h constants.c \ - demanglers.h demanglers.c \ - global.h global.c \ - logs.h logs.c \ - module.h module.c \ - params.h params.c \ - processors.h processors.c \ +libpychrysacore_la_SOURCES = \ + constants.h constants.c \ + demanglers.h demanglers.c \ + global.h global.c \ + logs.h logs.c \ + module.h module.c \ + params.h params.c \ + processors.h processors.c \ queue.h queue.c -libpychrysacore_la_LDFLAGS = +libpychrysacore_la_CFLAGS = $(TOOLKIT_CFLAGS) $(LIBXML_CFLAGS) $(LIBPYTHON_INTERPRETER_CFLAGS) $(LIBPYGOBJECT_CFLAGS) \ + -I$(top_srcdir)/src -DNO_IMPORT_PYGOBJECT devdir = $(includedir)/chrysalide/$(subdir) dev_HEADERS = $(libpychrysacore_la_SOURCES:%c=) - - -AM_CPPFLAGS = $(LIBGTK_CFLAGS) $(LIBXML_CFLAGS) $(LIBPYTHON_CFLAGS) $(LIBPYGOBJECT_CFLAGS) \ - -I$(top_srcdir)/src - -AM_CFLAGS = $(DEBUG_CFLAGS) $(WARNING_FLAGS) $(COMPLIANCE_FLAGS) diff --git a/plugins/pychrysalide/core/global.c b/plugins/pychrysalide/core/global.c index ecaf2c6..9632e75 100644 --- a/plugins/pychrysalide/core/global.c +++ b/plugins/pychrysalide/core/global.c @@ -187,6 +187,52 @@ static PyObject *py_global_get_content_resolver(PyObject *self, PyObject *args) * Paramètres : self = objet Python concerné par l'appel. * * args = non utilisé ici. * * * +* Description : Fournit l'adresse de l'espace de noms principal pour ROST. * +* * +* Retour : Espace de noms racine de ROST ou NULL si aucun (!). * +* * +* Remarques : - * +* * +******************************************************************************/ + +static PyObject *py_global_get_rost_root_namespace(PyObject *self, PyObject *args) +{ + PyObject *result; /* Instance Python à retourner */ + GScanNamespace *root_ns; /* Espace de noms ROST racine */ + +#define GLOBAL_GET_ROST_ROOT_NAMESPACE_METHOD PYTHON_METHOD_DEF \ +( \ + get_rost_root_namespace, "", \ + METH_NOARGS, py_global, \ + "Get the root namespace for ROST." \ + "\n" \ + "The returned object is a pychrysalide.analysis.scan.ScanNamespace" \ + " instance used as singleton; it should not be *None*." \ +) + + root_ns = get_rost_root_namespace(); + + if (root_ns != NULL) + { + result = pygobject_new(G_OBJECT(root_ns)); + g_object_unref(G_OBJECT(root_ns)); + } + else + { + result = Py_None; + Py_INCREF(result); + } + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : self = objet Python concerné par l'appel. * +* args = non utilisé ici. * +* * * Description : Fournit l'adresse du projet courant. * * * * Retour : Adresse du résolveur global ou None si aucun. * @@ -289,6 +335,7 @@ bool populate_core_module_with_global(void) GLOBAL_IS_BATCH_MODE_METHOD, GLOBAL_GET_CONTENT_EXPLORER_METHOD, GLOBAL_GET_CONTENT_RESOLVER_METHOD, + GLOBAL_GET_ROST_ROOT_NAMESPACE_METHOD, GLOBAL_GET_CURRENT_PROJECT_METHOD, GLOBAL_SET_CURRENT_PROJECT_METHOD, { NULL } diff --git a/plugins/pychrysalide/core/queue.c b/plugins/pychrysalide/core/queue.c index d0fbed8..febf1b0 100644 --- a/plugins/pychrysalide/core/queue.c +++ b/plugins/pychrysalide/core/queue.c @@ -63,7 +63,6 @@ static PyObject *py_queue_wait_for_all_global_works(PyObject *, PyObject *); static PyObject *py_queue_setup_global_work_group(PyObject *self, PyObject *args) { PyObject *result; /* Valeur à retourner */ - PyThreadState *_save; /* Sauvegarde de contexte */ wgroup_id_t wid; /* Identifiant de groupe */ #define QUEUE_SETUP_GLOBAL_WORK_GROUP_METHOD PYTHON_METHOD_DEF \ @@ -79,14 +78,10 @@ static PyObject *py_queue_setup_global_work_group(PyObject *self, PyObject *args " unique identifier of a work group." \ ) - Py_UNBLOCK_THREADS; - wid = setup_global_work_group(); result = PyLong_FromUnsignedLongLong(wid); - Py_BLOCK_THREADS; - return result; } @@ -109,8 +104,6 @@ static PyObject *py_queue_setup_tiny_global_work_group(PyObject *self, PyObject { PyObject *result; /* Valeur à retourner */ unsigned int count; /* Nombre de thread parallèle */ - PyThreadState *_save; /* Sauvegarde de contexte */ - int ret; /* Bilan de lecture des args. */ wgroup_id_t wid; /* Identifiant de groupe */ @@ -131,8 +124,6 @@ static PyObject *py_queue_setup_tiny_global_work_group(PyObject *self, PyObject count = 1; - Py_UNBLOCK_THREADS; - ret = PyArg_ParseTuple(args, "|I", &count); if (!ret) goto exit; @@ -148,8 +139,6 @@ static PyObject *py_queue_setup_tiny_global_work_group(PyObject *self, PyObject exit: - Py_BLOCK_THREADS; - return result; } @@ -170,8 +159,6 @@ static PyObject *py_queue_setup_tiny_global_work_group(PyObject *self, PyObject static PyObject *py_queue_wait_for_all_global_works(PyObject *self, PyObject *args) { - PyThreadState *_save; /* Sauvegarde de contexte */ - #define QUEUE_WAIT_FOR_ALL_GLOBAL_WORKS_METHOD PYTHON_METHOD_DEF \ ( \ wait_for_all_global_works, "", \ @@ -179,12 +166,8 @@ static PyObject *py_queue_wait_for_all_global_works(PyObject *self, PyObject *ar "Wait for all global tasks being processed." \ ) - Py_UNBLOCK_THREADS; - wait_for_all_global_works(); - Py_BLOCK_THREADS; - Py_RETURN_NONE; } diff --git a/plugins/pychrysalide/debug/Makefile.am b/plugins/pychrysalide/debug/Makefile.am index 4bd8e78..c653a6d 100644 --- a/plugins/pychrysalide/debug/Makefile.am +++ b/plugins/pychrysalide/debug/Makefile.am @@ -1,23 +1,14 @@ noinst_LTLIBRARIES = libpychrysadebug.la -libpychrysadebug_la_SOURCES = \ - debugger.h debugger.c \ +libpychrysadebug_la_SOURCES = \ + debugger.h debugger.c \ module.h module.c -libpychrysadebug_la_LIBADD = - -libpychrysadebug_la_LDFLAGS = +libpychrysadebug_la_CFLAGS = $(TOOLKIT_CFLAGS) $(LIBXML_CFLAGS) $(LIBPYTHON_INTERPRETER_CFLAGS) $(LIBPYGOBJECT_CFLAGS) \ + -I$(top_srcdir)/src -DNO_IMPORT_PYGOBJECT devdir = $(includedir)/chrysalide/$(subdir) dev_HEADERS = $(libpychrysadebug_la_SOURCES:%c=) - - -AM_CPPFLAGS = $(LIBGTK_CFLAGS) $(LIBXML_CFLAGS) $(LIBPYTHON_CFLAGS) $(LIBPYGOBJECT_CFLAGS) \ - -I$(top_srcdir)/src - -AM_CFLAGS = $(DEBUG_CFLAGS) $(WARNING_FLAGS) $(COMPLIANCE_FLAGS) - -SUBDIRS = diff --git a/plugins/pychrysalide/debug/debugger.c b/plugins/pychrysalide/debug/debugger.c index e65e295..b21087d 100644 --- a/plugins/pychrysalide/debug/debugger.c +++ b/plugins/pychrysalide/debug/debugger.c @@ -1195,7 +1195,7 @@ bool ensure_python_binary_debugger_is_registered(void) dict = PyModule_GetDict(module); - if (!register_class_for_pygobject(dict, G_TYPE_BINARY_DEBUGGER, type, &PyGObject_Type)) + if (!register_class_for_pygobject(dict, G_TYPE_BINARY_DEBUGGER, type)) return false; } diff --git a/plugins/pychrysalide/format/Makefile.am b/plugins/pychrysalide/format/Makefile.am index 68eb3be..337265d 100644 --- a/plugins/pychrysalide/format/Makefile.am +++ b/plugins/pychrysalide/format/Makefile.am @@ -1,30 +1,22 @@ noinst_LTLIBRARIES = libpychrysaformat.la -libpychrysaformat_la_SOURCES = \ - constants.h constants.c \ - executable.h executable.c \ - flat.h flat.c \ - format.h format.c \ - known.h known.c \ - module.h module.c \ - strsym.h strsym.c \ - symbol.h symbol.c \ +libpychrysaformat_la_SOURCES = \ + constants.h constants.c \ + executable.h executable.c \ + flat.h flat.c \ + format.h format.c \ + known.h known.c \ + module.h module.c \ + preload.h preload.c \ + strsym.h strsym.c \ + symbol.h symbol.c \ symiter.h symiter.c -libpychrysaformat_la_LIBADD = - -libpychrysaformat_la_LDFLAGS = +libpychrysaformat_la_CFLAGS = $(TOOLKIT_CFLAGS) $(LIBXML_CFLAGS) $(LIBPYTHON_INTERPRETER_CFLAGS) $(LIBPYGOBJECT_CFLAGS) \ + -I$(top_srcdir)/src -DNO_IMPORT_PYGOBJECT devdir = $(includedir)/chrysalide/$(subdir) dev_HEADERS = $(libpychrysaformat_la_SOURCES:%c=) - - -AM_CPPFLAGS = $(LIBGTK_CFLAGS) $(LIBXML_CFLAGS) $(LIBPYTHON_CFLAGS) $(LIBPYGOBJECT_CFLAGS) \ - -I$(top_srcdir)/src - -AM_CFLAGS = $(DEBUG_CFLAGS) $(WARNING_FLAGS) $(COMPLIANCE_FLAGS) - -SUBDIRS = diff --git a/plugins/pychrysalide/format/executable.c b/plugins/pychrysalide/format/executable.c index ac0125d..ff2d14a 100644 --- a/plugins/pychrysalide/format/executable.c +++ b/plugins/pychrysalide/format/executable.c @@ -268,7 +268,7 @@ bool ensure_python_executable_format_is_registered(void) if (!ensure_python_binary_format_is_registered()) return false; - if (!register_class_for_pygobject(dict, G_TYPE_EXE_FORMAT, type, get_python_binary_format_type())) + if (!register_class_for_pygobject(dict, G_TYPE_EXE_FORMAT, type)) return false; } diff --git a/plugins/pychrysalide/format/flat.c b/plugins/pychrysalide/format/flat.c index 2c8e9fd..4df3646 100644 --- a/plugins/pychrysalide/format/flat.c +++ b/plugins/pychrysalide/format/flat.c @@ -173,7 +173,7 @@ bool ensure_python_flat_format_is_registered(void) if (!ensure_python_executable_format_is_registered()) return false; - if (!register_class_for_pygobject(dict, G_TYPE_FLAT_FORMAT, type, get_python_executable_format_type())) + if (!register_class_for_pygobject(dict, G_TYPE_FLAT_FORMAT, type)) return false; } diff --git a/plugins/pychrysalide/format/format.c b/plugins/pychrysalide/format/format.c index 66d346c..82c6c33 100644 --- a/plugins/pychrysalide/format/format.c +++ b/plugins/pychrysalide/format/format.c @@ -166,7 +166,7 @@ static PyObject *py_binary_format_new(PyTypeObject *type, PyObject *args, PyObje if (first_time) { - status = register_class_for_dynamic_pygobject(gtype, type, base); + status = register_class_for_dynamic_pygobject(gtype, type); if (!status) { @@ -1150,7 +1150,7 @@ bool ensure_python_binary_format_is_registered(void) if (!ensure_python_known_format_is_registered()) return false; - if (!register_class_for_pygobject(dict, G_TYPE_BIN_FORMAT, type, get_python_known_format_type())) + if (!register_class_for_pygobject(dict, G_TYPE_BIN_FORMAT, type)) return false; if (!define_binary_format_constants(type)) diff --git a/plugins/pychrysalide/format/known.c b/plugins/pychrysalide/format/known.c index a2fc18c..3167ba2 100644 --- a/plugins/pychrysalide/format/known.c +++ b/plugins/pychrysalide/format/known.c @@ -132,7 +132,7 @@ static PyObject *py_known_format_new(PyTypeObject *type, PyObject *args, PyObjec if (first_time) { - status = register_class_for_dynamic_pygobject(gtype, type, base); + status = register_class_for_dynamic_pygobject(gtype, type); if (!status) { @@ -789,7 +789,7 @@ bool ensure_python_known_format_is_registered(void) dict = PyModule_GetDict(module); - if (!register_class_for_pygobject(dict, G_TYPE_KNOWN_FORMAT, type, &PyGObject_Type)) + if (!register_class_for_pygobject(dict, G_TYPE_KNOWN_FORMAT, type)) return false; } diff --git a/plugins/pychrysalide/format/module.c b/plugins/pychrysalide/format/module.c index 52dc58b..62c15ed 100644 --- a/plugins/pychrysalide/format/module.c +++ b/plugins/pychrysalide/format/module.c @@ -32,6 +32,7 @@ #include "flat.h" #include "format.h" #include "known.h" +#include "preload.h" #include "strsym.h" #include "symbol.h" #include "symiter.h" @@ -105,6 +106,7 @@ bool populate_format_module(void) if (result) result = ensure_python_flat_format_is_registered(); if (result) result = ensure_python_known_format_is_registered(); if (result) result = ensure_python_binary_format_is_registered(); + if (result) result = ensure_python_preload_info_is_registered(); if (result) result = ensure_python_string_symbol_is_registered(); if (result) result = ensure_python_binary_symbol_is_registered(); if (result) result = ensure_python_sym_iterator_is_registered(); diff --git a/plugins/pychrysalide/format/preload.c b/plugins/pychrysalide/format/preload.c new file mode 100644 index 0000000..e4f2a9c --- /dev/null +++ b/plugins/pychrysalide/format/preload.c @@ -0,0 +1,207 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * preload.c - équivalent Python du fichier "format/preload.c" + * + * Copyright (C) 2023 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 "preload.h" + + +#include <pygobject.h> + + +#include <format/preload-int.h> + + +#include "../access.h" +#include "../helpers.h" + + + +CREATE_DYN_CONSTRUCTOR(preload_info, G_TYPE_PRELOAD_INFO); + +/* Initialise une instance sur la base du dérivé de GObject. */ +static int py_preload_info_init(PyObject *, PyObject *, PyObject *); + + + +/****************************************************************************** +* * +* Paramètres : self = objet à initialiser (théoriquement). * +* args = arguments fournis à l'appel. * +* kwds = arguments de type key=val fournis. * +* * +* Description : Initialise une instance sur la base du dérivé de GObject. * +* * +* Retour : 0. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static int py_preload_info_init(PyObject *self, PyObject *args, PyObject *kwds) +{ + int ret; /* Bilan d'initialisation */ + +#define PRELOAD_INFO_DOC \ + "The PreloadInfo object stores all kinds of disassembling" \ + " information available from the analysis of a file format" \ + " itsself.\n" \ + "\n" \ + "Instances can be created using the following constructor:\n" \ + "\n" \ + " PreloadInfo()" + + /* Initialisation d'un objet GLib */ + + ret = forward_pygobjet_init(self); + if (ret == -1) return -1; + + return 0; + +} + + +/****************************************************************************** +* * +* Paramètres : - * +* * +* Description : Fournit un accès à une définition de type à diffuser. * +* * +* Retour : Définition d'objet pour Python. * +* * +* Remarques : - * +* * +******************************************************************************/ + +PyTypeObject *get_python_preload_info_type(void) +{ + static PyMethodDef py_preload_info_methods[] = { + { NULL } + }; + + static PyGetSetDef py_preload_info_getseters[] = { + { NULL } + }; + + static PyTypeObject py_preload_info_type = { + + PyVarObject_HEAD_INIT(NULL, 0) + + .tp_name = "pychrysalide.format.PreloadInfo", + .tp_basicsize = sizeof(PyGObject), + + .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, + + .tp_doc = PRELOAD_INFO_DOC, + + .tp_methods = py_preload_info_methods, + .tp_getset = py_preload_info_getseters, + + .tp_init = py_preload_info_init, + .tp_new = py_preload_info_new, + + }; + + return &py_preload_info_type; + +} + + +/****************************************************************************** +* * +* Paramètres : module = module dont la définition est à compléter. * +* * +* Description : Prend en charge l'objet 'pychrysalide.format.PreloadInfo'. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool ensure_python_preload_info_is_registered(void) +{ + PyTypeObject *type; /* Type Python 'ArchContext' */ + PyObject *module; /* Module à recompléter */ + PyObject *dict; /* Dictionnaire du module */ + + type = get_python_preload_info_type(); + + if (!PyType_HasFeature(type, Py_TPFLAGS_READY)) + { + module = get_access_to_python_module("pychrysalide.format"); + + dict = PyModule_GetDict(module); + + if (!register_class_for_pygobject(dict, G_TYPE_PRELOAD_INFO, type)) + 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 espace de préchargement. * +* * +* Retour : Bilan de l'opération, voire indications supplémentaires. * +* * +* Remarques : - * +* * +******************************************************************************/ + +int convert_to_preload_info(PyObject *arg, void *dst) +{ + int result; /* Bilan à retourner */ + + result = PyObject_IsInstance(arg, (PyObject *)get_python_preload_info_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 disassembly context"); + break; + + case 1: + *((GPreloadInfo **)dst) = G_PRELOAD_INFO(pygobject_get(arg)); + break; + + default: + assert(false); + break; + + } + + return result; + +} diff --git a/plugins/pychrysalide/format/preload.h b/plugins/pychrysalide/format/preload.h new file mode 100644 index 0000000..bf33e82 --- /dev/null +++ b/plugins/pychrysalide/format/preload.h @@ -0,0 +1,45 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * preload.h - prototypes pour l'équivalent Python du fichier "format/preload.h" + * + * Copyright (C) 2023 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_FORMAT_PRELOAD_H +#define _PLUGINS_PYCHRYSALIDE_FORMAT_PRELOAD_H + + +#include <Python.h> +#include <stdbool.h> + + + +/* Fournit un accès à une définition de type à diffuser. */ +PyTypeObject *get_python_preload_info_type(void); + +/* Prend en charge l'objet 'pychrysalide.format.PreloadInfo'. */ +bool ensure_python_preload_info_is_registered(void); + +/* Tente de convertir en espace de préchargement. */ +int convert_to_preload_info(PyObject *, void *); + + + +#endif /* _PLUGINS_PYCHRYSALIDE_FORMAT_PRELOAD_H */ diff --git a/plugins/pychrysalide/format/strsym.c b/plugins/pychrysalide/format/strsym.c index c85d61f..adc0e48 100644 --- a/plugins/pychrysalide/format/strsym.c +++ b/plugins/pychrysalide/format/strsym.c @@ -119,7 +119,7 @@ static PyObject *py_string_symbol_new(PyTypeObject *type, PyObject *args, PyObje if (first_time) { - status = register_class_for_dynamic_pygobject(gtype, type, base); + status = register_class_for_dynamic_pygobject(gtype, type); if (!status) { @@ -501,7 +501,7 @@ bool ensure_python_string_symbol_is_registered(void) if (!ensure_python_binary_symbol_is_registered()) return false; - if (!register_class_for_pygobject(dict, G_TYPE_STR_SYMBOL, type, get_python_binary_symbol_type())) + if (!register_class_for_pygobject(dict, G_TYPE_STR_SYMBOL, type)) return false; if (!define_string_symbol_constants(type)) diff --git a/plugins/pychrysalide/format/symbol.c b/plugins/pychrysalide/format/symbol.c index d6d6402..d3a9c1e 100644 --- a/plugins/pychrysalide/format/symbol.c +++ b/plugins/pychrysalide/format/symbol.c @@ -43,6 +43,7 @@ #include "../helpers.h" #include "../analysis/routine.h" #include "../analysis/db/items/comment.h" +#include "../analysis/storage/serialize.h" #include "../arch/instruction.h" #include "../arch/vmpa.h" #include "../glibext/linegen.h" @@ -156,7 +157,7 @@ static PyObject *py_binary_symbol_new(PyTypeObject *type, PyObject *args, PyObje if (first_time) { - status = register_class_for_dynamic_pygobject(gtype, type, base); + status = register_class_for_dynamic_pygobject(gtype, type); if (!status) { @@ -214,6 +215,7 @@ static void py_binary_symbol_init_gclass(GBinSymbolClass *class, gpointer unused static char *py_binary_symbol_get_label_wrapper(const GBinSymbol *symbol) { char *result; /* Etiquette à retourner */ + PyGILState_STATE gstate; /* Sauvegarde d'environnement */ PyObject *pyobj; /* Objet Python concerné */ PyObject *pyret; /* Bilan de consultation */ @@ -228,6 +230,8 @@ static char *py_binary_symbol_get_label_wrapper(const GBinSymbol *symbol) result = NULL; + gstate = PyGILState_Ensure(); + pyobj = pygobject_new(G_OBJECT(symbol)); if (has_python_method(pyobj, "_get_label")) @@ -246,6 +250,8 @@ static char *py_binary_symbol_get_label_wrapper(const GBinSymbol *symbol) Py_DECREF(pyobj); + PyGILState_Release(gstate); + return result; } @@ -973,7 +979,10 @@ bool ensure_python_binary_symbol_is_registered(void) if (!ensure_python_line_generator_is_registered()) return false; - if (!register_class_for_pygobject(dict, G_TYPE_BIN_SYMBOL, type, &PyGObject_Type)) + if (!ensure_python_serializable_object_is_registered()) + return false; + + if (!register_class_for_pygobject(dict, G_TYPE_BIN_SYMBOL, type)) return false; if (!define_binary_symbol_constants(type)) diff --git a/plugins/pychrysalide/glibext/Makefile.am b/plugins/pychrysalide/glibext/Makefile.am index cfed869..2ed2aa5 100644 --- a/plugins/pychrysalide/glibext/Makefile.am +++ b/plugins/pychrysalide/glibext/Makefile.am @@ -1,30 +1,32 @@ noinst_LTLIBRARIES = libpychrysaglibext.la -libpychrysaglibext_la_SOURCES = \ - constants.h constants.c \ - binarycursor.h binarycursor.c \ - binportion.h binportion.c \ - buffercache.h buffercache.c \ - bufferline.h bufferline.c \ - bufferview.h bufferview.c \ - configuration.h configuration.c \ - linecursor.h linecursor.c \ - linegen.h linegen.c \ - loadedpanel.h loadedpanel.c \ - module.h module.c \ - named.h named.c \ +libpychrysaglibext_la_SOURCES = \ + constants.h constants.c \ + binarycursor.h binarycursor.c \ + binportion.h binportion.c \ + buffercache.h buffercache.c \ + bufferline.h bufferline.c \ + comparison.h comparison.c \ + configuration.h configuration.c \ + linecursor.h linecursor.c \ + linegen.h linegen.c \ + module.h module.c \ singleton.h singleton.c -libpychrysaglibext_la_LDFLAGS = +if BUILD_GTK_SUPPORT +libpychrysaglibext_la_SOURCES += \ + bufferview.h bufferview.c \ + loadedpanel.h loadedpanel.c \ + named.h named.c -devdir = $(includedir)/chrysalide/$(subdir) +endif -dev_HEADERS = $(libpychrysaglibext_la_SOURCES:%c=) +libpychrysaglibext_la_CFLAGS = $(TOOLKIT_CFLAGS) $(LIBXML_CFLAGS) $(LIBPYTHON_INTERPRETER_CFLAGS) $(LIBPYGOBJECT_CFLAGS) \ + -I$(top_srcdir)/src -DNO_IMPORT_PYGOBJECT -AM_CPPFLAGS = $(LIBGTK_CFLAGS) $(LIBXML_CFLAGS) $(LIBPYTHON_CFLAGS) $(LIBPYGOBJECT_CFLAGS) \ - -I$(top_srcdir)/src +devdir = $(includedir)/chrysalide/$(subdir) -AM_CFLAGS = $(DEBUG_CFLAGS) $(WARNING_FLAGS) $(COMPLIANCE_FLAGS) +dev_HEADERS = $(libpychrysaglibext_la_SOURCES:%c=) diff --git a/plugins/pychrysalide/glibext/binarycursor.c b/plugins/pychrysalide/glibext/binarycursor.c index 4da040a..91dce3e 100644 --- a/plugins/pychrysalide/glibext/binarycursor.c +++ b/plugins/pychrysalide/glibext/binarycursor.c @@ -321,7 +321,7 @@ bool ensure_python_binary_cursor_is_registered(void) if (!ensure_python_line_cursor_is_registered()) return false; - if (!register_class_for_pygobject(dict, G_TYPE_BINARY_CURSOR, type, get_python_line_cursor_type())) + if (!register_class_for_pygobject(dict, G_TYPE_BINARY_CURSOR, type)) return false; } diff --git a/plugins/pychrysalide/glibext/binportion.c b/plugins/pychrysalide/glibext/binportion.c index 060f001..70eb314 100644 --- a/plugins/pychrysalide/glibext/binportion.c +++ b/plugins/pychrysalide/glibext/binportion.c @@ -112,7 +112,7 @@ static PyObject *py_bin_portion_new(PyTypeObject *type, PyObject *args, PyObject if (first_time) { - status = register_class_for_dynamic_pygobject(gtype, type, base); + status = register_class_for_dynamic_pygobject(gtype, type); if (!status) { @@ -674,7 +674,7 @@ bool ensure_python_binary_portion_is_registered(void) dict = PyModule_GetDict(module); - if (!register_class_for_pygobject(dict, G_TYPE_BIN_PORTION, type, &PyGObject_Type)) + if (!register_class_for_pygobject(dict, G_TYPE_BIN_PORTION, type)) return false; if (!define_binary_portion_constants(type)) diff --git a/plugins/pychrysalide/glibext/buffercache.c b/plugins/pychrysalide/glibext/buffercache.c index 0cf3342..03301d6 100644 --- a/plugins/pychrysalide/glibext/buffercache.c +++ b/plugins/pychrysalide/glibext/buffercache.c @@ -88,9 +88,13 @@ static PyObject *py_buffer_cache_get_line_flags(PyObject *, PyObject *); /* Retire une propriété particulière attachée à une ligne. */ static PyObject *py_buffer_cache_remove_line_flag(PyObject *, PyObject *); +#ifdef INCLUDE_GTK_SUPPORT + /* Retrouve une ligne au sein d'un tampon avec un indice. */ static PyObject *py_buffer_cache_find_line_by_index(PyObject *, PyObject *); +#endif + /* Avance autant que possible vers une ligne idéale. */ static PyObject *py_buffer_cache_look_for_flag(PyObject *, PyObject *); @@ -153,7 +157,7 @@ static PyObject *py_buffer_cache_new(PyTypeObject *type, PyObject *args, PyObjec if (first_time) { - status = register_class_for_dynamic_pygobject(gtype, type, base); + status = register_class_for_dynamic_pygobject(gtype, type); if (!status) { @@ -825,6 +829,9 @@ static PyObject *py_buffer_cache_remove_line_flag(PyObject *self, PyObject *args } +#ifdef INCLUDE_GTK_SUPPORT + + /****************************************************************************** * * * Paramètres : self = classe représentant un tampon de code. * @@ -883,6 +890,9 @@ static PyObject *py_buffer_cache_find_line_by_index(PyObject *self, PyObject *ar } +#endif + + /****************************************************************************** * * * Paramètres : self = classe représentant un tampon de code. * @@ -1157,7 +1167,9 @@ PyTypeObject *get_python_buffer_cache_type(void) BUFFER_CACHE_ADD_LINE_FLAG_METHOD, BUFFER_CACHE_GET_LINE_FLAGS_METHOD, BUFFER_CACHE_REMOVE_LINE_FLAG_METHOD, +#ifdef INCLUDE_GTK_SUPPORT BUFFER_CACHE_FIND_LINE_BY_INDEX_METHOD, +#endif BUFFER_CACHE_LOOK_FOR_FLAG_METHOD, { NULL } }; @@ -1221,7 +1233,7 @@ bool ensure_python_buffer_cache_is_registered(void) dict = PyModule_GetDict(module); - if (!register_class_for_pygobject(dict, G_TYPE_BUFFER_CACHE, type, &PyGObject_Type)) + if (!register_class_for_pygobject(dict, G_TYPE_BUFFER_CACHE, type)) return false; } diff --git a/plugins/pychrysalide/glibext/bufferline.c b/plugins/pychrysalide/glibext/bufferline.c index c88fe7f..09404bc 100644 --- a/plugins/pychrysalide/glibext/bufferline.c +++ b/plugins/pychrysalide/glibext/bufferline.c @@ -106,7 +106,7 @@ static PyObject *py_buffer_line_new(PyTypeObject *type, PyObject *args, PyObject if (first_time) { - status = register_class_for_dynamic_pygobject(gtype, type, base); + status = register_class_for_dynamic_pygobject(gtype, type); if (!status) { @@ -339,7 +339,7 @@ bool ensure_python_buffer_line_is_registered(void) dict = PyModule_GetDict(module); - if (!register_class_for_pygobject(dict, G_TYPE_BUFFER_LINE, type, &PyGObject_Type)) + if (!register_class_for_pygobject(dict, G_TYPE_BUFFER_LINE, type)) return false; if (!define_line_segment_constants(type)) diff --git a/plugins/pychrysalide/glibext/bufferview.c b/plugins/pychrysalide/glibext/bufferview.c index 98cc10a..d4cbdc2 100644 --- a/plugins/pychrysalide/glibext/bufferview.c +++ b/plugins/pychrysalide/glibext/bufferview.c @@ -146,7 +146,7 @@ bool ensure_python_buffer_view_is_registered(void) dict = PyModule_GetDict(module); - if (!register_class_for_pygobject(dict, G_TYPE_BUFFER_VIEW, type, &PyGObject_Type)) + if (!register_class_for_pygobject(dict, G_TYPE_BUFFER_VIEW, type)) return false; } diff --git a/plugins/pychrysalide/glibext/comparison.c b/plugins/pychrysalide/glibext/comparison.c new file mode 100644 index 0000000..548f700 --- /dev/null +++ b/plugins/pychrysalide/glibext/comparison.c @@ -0,0 +1,341 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * comparison.c - équivalent Python du fichier "glibext/comparison.h" + * + * Copyright (C) 2018-2019 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +#include "comparison.h" + + +#include <pygobject.h> + + +#include <glibext/comparison-int.h> + + +#include "constants.h" +#include "../access.h" +#include "../helpers.h" +#include "../analysis/content.h" + + + +/* ------------------------ GLUE POUR CREATION DEPUIS PYTHON ------------------------ */ + + +/* Procède à l'initialisation de l'interface de comparaison. */ +static void py_comparable_item_interface_init(GComparableItemIface *, gpointer *); + +/* Réalise une comparaison entre objets selon un critère précis. */ +static bool py_comparable_item_compare_rich(const GComparableItem *, const GComparableItem *, RichCmpOperation, bool *); + + + +/* ------------------------- CONNEXION AVEC L'API DE PYTHON ------------------------- */ + + +/* Effectue une comparaison avec un objet 'ComparableItem'. */ +static PyObject *py_comparable_item_richcompare(PyObject *, PyObject *, int); + + + +/* ---------------------------------------------------------------------------------- */ +/* GLUE POUR CREATION DEPUIS PYTHON */ +/* ---------------------------------------------------------------------------------- */ + + +/****************************************************************************** +* * +* Paramètres : iface = interface GLib à initialiser. * +* unused = adresse non utilisée ici. * +* * +* Description : Procède à l'initialisation de l'interface de comparaison. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void py_comparable_item_interface_init(GComparableItemIface *iface, gpointer *unused) +{ + +#define COMPARABLE_ITEM_DOC \ + "ComparableItem provides an interface to compare objects.\n" \ + "\n" \ + "A typical class declaration for a new implementation looks like:\n" \ + "\n" \ + " class NewImplem(GObject.Object, ComparableItem):\n" \ + " ...\n" \ + "\n" + + iface->cmp_rich = py_comparable_item_compare_rich; + +} + + +/****************************************************************************** +* * +* Paramètres : item = premier objet à cnsulter pour une comparaison. * +* other = second objet à cnsulter pour une comparaison. * +* op = opération de comparaison à réaliser. * +* status = bilan des opérations de comparaison. [OUT] * +* * +* Description : Réalise une comparaison entre objets selon un critère précis.* +* * +* Retour : true si la comparaison a pu être effectuée, false sinon. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static bool py_comparable_item_compare_rich(const GComparableItem *item, const GComparableItem *other, RichCmpOperation op, bool *status) +{ + bool result; /* Etat à retourner */ + PyGILState_STATE gstate; /* Sauvegarde d'environnement */ + PyObject *pyitem; /* Objet Python concerné #1 */ + PyObject *pyother; /* Objet Python concerné #2 */ + PyObject *pyret; /* Bilan de consultation */ + int ret; /* Bilan d'une conversion */ + + result = false; + + gstate = PyGILState_Ensure(); + + pyitem = pygobject_new(G_OBJECT(item)); + pyother = pygobject_new(G_OBJECT(other)); + + pyret = PyObject_RichCompare(pyitem, pyother, op); + + if (pyret != NULL) + { + ret = PyBool_Check(pyret); + + if (ret) + { + *status = (pyret == Py_True); + result = true; + } + + Py_DECREF(pyret); + + } + + Py_DECREF(pyother); + Py_DECREF(pyitem); + + PyGILState_Release(gstate); + + return result; + +} + + + +/* ---------------------------------------------------------------------------------- */ +/* CONNEXION AVEC L'API DE PYTHON */ +/* ---------------------------------------------------------------------------------- */ + + +/****************************************************************************** +* * +* 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 'ComparableItem'. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static PyObject *py_comparable_item_richcompare(PyObject *a, PyObject *b, int op) +{ + PyObject *result; /* Bilan à retourner */ + int ret; /* Bilan de lecture des args. */ + GComparableItem *item_a; /* Instance à manipuler #1 */ + GComparableItem *item_b; /* Instance à manipuler #2 */ + bool valid; /* Indication de validité */ + bool status; /* Résultat d'une comparaison */ + + ret = PyObject_IsInstance(b, (PyObject *)get_python_comparable_item_type()); + if (!ret) + { + result = Py_NotImplemented; + goto cmp_done; + } + + item_a = G_COMPARABLE_ITEM(pygobject_get(a)); + item_b = G_COMPARABLE_ITEM(pygobject_get(b)); + + valid = g_comparable_item_compare_rich(item_a, item_b, op, &status); + + if (valid) + result = status ? Py_True : Py_False; + else + result = Py_NotImplemented; + + cmp_done: + + 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_comparable_item_type(void) +{ + static PyMethodDef py_comparable_item_methods[] = { + { NULL } + }; + + static PyGetSetDef py_comparable_item_getseters[] = { + { NULL } + }; + + static PyTypeObject py_comparable_item_type = { + + PyVarObject_HEAD_INIT(NULL, 0) + + .tp_name = "pychrysalide.glibext.ComparableItem", + .tp_basicsize = sizeof(PyObject), + + .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, + + .tp_doc = COMPARABLE_ITEM_DOC, + + .tp_richcompare = py_comparable_item_richcompare, + + .tp_methods = py_comparable_item_methods, + .tp_getset = py_comparable_item_getseters, + + }; + + return &py_comparable_item_type; + +} + + +/****************************************************************************** +* * +* Paramètres : module = module dont la définition est à compléter. * +* * +* Description : Prend en charge l'objet 'pychrysalide.....ComparableItem'. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool ensure_python_comparable_item_is_registered(void) +{ + PyTypeObject *type; /* Type Python 'ComparableItem' */ + PyObject *module; /* Module à recompléter */ + PyObject *dict; /* Dictionnaire du module */ + + static GInterfaceInfo info = { /* Paramètres d'inscription */ + + .interface_init = (GInterfaceInitFunc)py_comparable_item_interface_init, + .interface_finalize = NULL, + .interface_data = NULL, + + }; + + type = get_python_comparable_item_type(); + + if (!PyType_HasFeature(type, Py_TPFLAGS_READY)) + { + module = get_access_to_python_module("pychrysalide.glibext"); + + dict = PyModule_GetDict(module); + + if (!register_interface_for_pygobject(dict, G_TYPE_COMPARABLE_ITEM, type, &info)) + return false; + + if (!define_comparable_item_constants(type)) + 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 élément comparable. * +* * +* Retour : Bilan de l'opération, voire indications supplémentaires. * +* * +* Remarques : - * +* * +******************************************************************************/ + +int convert_to_comparable_item(PyObject *arg, void *dst) +{ + int result; /* Bilan à retourner */ + + result = PyObject_IsInstance(arg, (PyObject *)get_python_comparable_item_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 comparable item"); + break; + + case 1: + *((GComparableItem **)dst) = G_COMPARABLE_ITEM(pygobject_get(arg)); + break; + + default: + assert(false); + break; + + } + + return result; + +} diff --git a/plugins/pychrysalide/glibext/comparison.h b/plugins/pychrysalide/glibext/comparison.h new file mode 100644 index 0000000..79f7092 --- /dev/null +++ b/plugins/pychrysalide/glibext/comparison.h @@ -0,0 +1,45 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * comparison.h - prototypes pour l'équivalent Python du fichier "glibext/comparison.h" + * + * Copyright (C) 2018 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with 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_COMPARISON_H +#define _PLUGINS_PYCHRYSALIDE_GLIBEXT_COMPARISON_H + + +#include <Python.h> +#include <stdbool.h> + + + +/* Fournit un accès à une définition de type à diffuser. */ +PyTypeObject *get_python_comparable_item_type(void); + +/* Prend en charge l'objet 'pychrysalide.glibext.ComparableItem'. */ +bool ensure_python_comparable_item_is_registered(void); + +/* Tente de convertir en élément comparable. */ +int convert_to_comparable_item(PyObject *, void *); + + + +#endif /* _PLUGINS_PYCHRYSALIDE_GLIBEXT_COMPARISON_H */ diff --git a/plugins/pychrysalide/glibext/configuration.c b/plugins/pychrysalide/glibext/configuration.c index b0586af..c630331 100644 --- a/plugins/pychrysalide/glibext/configuration.c +++ b/plugins/pychrysalide/glibext/configuration.c @@ -174,7 +174,7 @@ static PyObject *py_config_param_new(PyTypeObject *type, PyObject *args, PyObjec if (first_time) { - status = register_class_for_dynamic_pygobject(gtype, type, base); + status = register_class_for_dynamic_pygobject(gtype, type); if (!status) { @@ -733,7 +733,7 @@ bool ensure_python_config_param_is_registered(void) dict = PyModule_GetDict(module); - if (!register_class_for_pygobject(dict, G_TYPE_CFG_PARAM, type, &PyGObject_Type)) + if (!register_class_for_pygobject(dict, G_TYPE_CFG_PARAM, type)) return false; if (!define_config_param_constants(type)) @@ -1036,7 +1036,7 @@ static PyObject *py_generic_config_new(PyTypeObject *type, PyObject *args, PyObj if (first_time) { - status = register_class_for_dynamic_pygobject(gtype, type, base); + status = register_class_for_dynamic_pygobject(gtype, type); if (!status) { @@ -1580,7 +1580,7 @@ bool ensure_python_generic_config_is_registered(void) dict = PyModule_GetDict(module); - if (!register_class_for_pygobject(dict, G_TYPE_GEN_CONFIG, type, &PyGObject_Type)) + if (!register_class_for_pygobject(dict, G_TYPE_GEN_CONFIG, type)) return false; } diff --git a/plugins/pychrysalide/glibext/constants.c b/plugins/pychrysalide/glibext/constants.c index 373d1bf..169ffa2 100644 --- a/plugins/pychrysalide/glibext/constants.c +++ b/plugins/pychrysalide/glibext/constants.c @@ -27,10 +27,13 @@ #include <i18n.h> #include <glibext/bufferline.h> +#include <glibext/comparison.h> #include <glibext/configuration.h> #include <glibext/linesegment.h> #include <glibext/gbinportion.h> -#include <glibext/gloadedpanel.h> +#ifdef INCLUDE_GTK_SUPPORT +# include <glibext/gloadedpanel.h> +#endif #include "../helpers.h" @@ -250,6 +253,48 @@ int convert_to_buffer_line_flags(PyObject *arg, void *dst) * * * 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. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool define_comparable_item_constants(PyTypeObject *type) +{ + bool result; /* Bilan à retourner */ + PyObject *values; /* Groupe de valeurs à établir */ + + values = PyDict_New(); + + result = add_const_to_group(values, "LT", RCO_LT); + if (result) result = add_const_to_group(values, "LE", RCO_LE); + if (result) result = add_const_to_group(values, "EQ", RCO_EQ); + if (result) result = add_const_to_group(values, "NE", RCO_NE); + if (result) result = add_const_to_group(values, "GT", RCO_GT); + if (result) result = add_const_to_group(values, "GE", RCO_GE); + + if (!result) + { + Py_DECREF(values); + goto exit; + } + + result = attach_constants_group_to_type(type, true, "RichCmpOperation", values, + "Modes for objects comparison."); + + exit: + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : type = type dont le dictionnaire est à compléter. * +* * * Description : Définit les constantes relatives aux paramètres de config. * * * * Retour : true en cas de succès de l'opération, false sinon. * @@ -471,6 +516,9 @@ int convert_to_rendering_tag_type(PyObject *arg, void *dst) } +#ifdef INCLUDE_GTK_SUPPORT + + /****************************************************************************** * * * Paramètres : type = type dont le dictionnaire est à compléter. * @@ -566,3 +614,6 @@ int convert_to_scroll_position_tweak(PyObject *arg, void *dst) return result; } + + +#endif diff --git a/plugins/pychrysalide/glibext/constants.h b/plugins/pychrysalide/glibext/constants.h index 342b7ad..4a4f6da 100644 --- a/plugins/pychrysalide/glibext/constants.h +++ b/plugins/pychrysalide/glibext/constants.h @@ -43,6 +43,9 @@ 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 *); + /* Définit les constantes relatives aux paramètres de configuration. */ bool define_config_param_constants(PyTypeObject *); @@ -55,12 +58,16 @@ bool define_line_segment_constants(PyTypeObject *); /* Tente de convertir en constante RenderingTagType. */ int convert_to_rendering_tag_type(PyObject *, void *); +#ifdef INCLUDE_GTK_SUPPORT + /* Définit les constantes relatives aux panneaux de chargement. */ bool define_loaded_panel_constants(PyTypeObject *); /* Tente de convertir en constante ScrollPositionTweak. */ int convert_to_scroll_position_tweak(PyObject *, void *); +#endif + #endif /* _PLUGINS_PYCHRYSALIDE_GLIBEXT_CONSTANTS_H */ diff --git a/plugins/pychrysalide/glibext/linecursor.c b/plugins/pychrysalide/glibext/linecursor.c index 217234a..4ac7f85 100644 --- a/plugins/pychrysalide/glibext/linecursor.c +++ b/plugins/pychrysalide/glibext/linecursor.c @@ -184,7 +184,7 @@ bool ensure_python_line_cursor_is_registered(void) dict = PyModule_GetDict(module); - if (!register_class_for_pygobject(dict, G_TYPE_LINE_CURSOR, type, &PyGObject_Type)) + if (!register_class_for_pygobject(dict, G_TYPE_LINE_CURSOR, type)) return false; } diff --git a/plugins/pychrysalide/glibext/module.c b/plugins/pychrysalide/glibext/module.c index 634cf5c..3e4307a 100644 --- a/plugins/pychrysalide/glibext/module.c +++ b/plugins/pychrysalide/glibext/module.c @@ -33,6 +33,7 @@ #include "buffercache.h" #include "bufferline.h" #include "bufferview.h" +#include "comparison.h" #include "configuration.h" #include "linecursor.h" #include "linegen.h" @@ -111,14 +112,19 @@ bool populate_glibext_module(void) if (result) result = ensure_python_binary_portion_is_registered(); if (result) result = ensure_python_buffer_cache_is_registered(); if (result) result = ensure_python_buffer_line_is_registered(); +#ifdef INCLUDE_GTK_SUPPORT if (result) result = ensure_python_buffer_view_is_registered(); +#endif + if (result) result = ensure_python_comparable_item_is_registered(); if (result) result = ensure_python_config_param_is_registered(); if (result) result = ensure_python_config_param_iterator_is_registered(); if (result) result = ensure_python_generic_config_is_registered(); if (result) result = ensure_python_line_cursor_is_registered(); if (result) result = ensure_python_line_generator_is_registered(); +#ifdef INCLUDE_GTK_SUPPORT if (result) result = ensure_python_loaded_panel_is_registered(); if (result) result = ensure_python_named_widget_is_registered(); +#endif if (result) result = ensure_python_singleton_factory_is_registered(); assert(result); diff --git a/plugins/pychrysalide/glibext/singleton.c b/plugins/pychrysalide/glibext/singleton.c index c4592ac..8491473 100644 --- a/plugins/pychrysalide/glibext/singleton.c +++ b/plugins/pychrysalide/glibext/singleton.c @@ -60,7 +60,7 @@ static gboolean py_singleton_candidate___eq__wrapper(const GSingletonCandidate * static void py_singleton_candidate_set_ro_wrapper(GSingletonCandidate *); /* Indique si le candidat est figé. */ -static bool py_singleton_candidate_is_ro_wrapper(GSingletonCandidate *); +static bool py_singleton_candidate_is_ro_wrapper(const GSingletonCandidate *); /* Fournit l'empreinte d'un candidat à une centralisation. */ static PyObject *py_singleton_candidate_hash(PyObject *, PyObject *); @@ -499,7 +499,7 @@ static void py_singleton_candidate_set_ro_wrapper(GSingletonCandidate *candidate * * ******************************************************************************/ -static bool py_singleton_candidate_is_ro_wrapper(GSingletonCandidate *candidate) +static bool py_singleton_candidate_is_ro_wrapper(const GSingletonCandidate *candidate) { bool result; /* Etat à retourner */ PyGILState_STATE gstate; /* Sauvegarde d'environnement */ @@ -922,7 +922,7 @@ static PyObject *py_singleton_factory_new(PyTypeObject *type, PyObject *args, Py if (first_time) { - status = register_class_for_dynamic_pygobject(gtype, type, base); + status = register_class_for_dynamic_pygobject(gtype, type); if (!status) { @@ -1110,7 +1110,7 @@ bool ensure_python_singleton_factory_is_registered(void) dict = PyModule_GetDict(module); - if (!register_class_for_pygobject(dict, G_TYPE_SINGLETON_FACTORY, type, &PyGObject_Type)) + if (!register_class_for_pygobject(dict, G_TYPE_SINGLETON_FACTORY, type)) return false; } diff --git a/plugins/pychrysalide/gtkext/Makefile.am b/plugins/pychrysalide/gtkext/Makefile.am index 77cce65..2e1260f 100644 --- a/plugins/pychrysalide/gtkext/Makefile.am +++ b/plugins/pychrysalide/gtkext/Makefile.am @@ -1,19 +1,20 @@ 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 \ +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 = \ +libpychrysagtkext_la_LIBADD = \ graph/libpychrysagtkextgraph.la -libpychrysagtkext_la_LDFLAGS = +libpychrysagtkext_la_CFLAGS = $(LIBGTK_CFLAGS) $(LIBXML_CFLAGS) $(LIBPYTHON_INTERPRETER_CFLAGS) $(LIBPYGOBJECT_CFLAGS) \ + -I$(top_srcdir)/src -DNO_IMPORT_PYGOBJECT devdir = $(includedir)/chrysalide/$(subdir) @@ -21,10 +22,4 @@ devdir = $(includedir)/chrysalide/$(subdir) dev_HEADERS = $(libpychrysagtkext_la_SOURCES:%c=) -AM_CPPFLAGS = $(LIBGTK_CFLAGS) $(LIBXML_CFLAGS) $(LIBPYTHON_CFLAGS) $(LIBPYGOBJECT_CFLAGS) \ - -I$(top_srcdir)/src - -AM_CFLAGS = $(DEBUG_CFLAGS) $(WARNING_FLAGS) $(COMPLIANCE_FLAGS) - - SUBDIRS = graph diff --git a/plugins/pychrysalide/gtkext/blockdisplay.c b/plugins/pychrysalide/gtkext/blockdisplay.c index 6741553..b4b8515 100644 --- a/plugins/pychrysalide/gtkext/blockdisplay.c +++ b/plugins/pychrysalide/gtkext/blockdisplay.c @@ -115,7 +115,7 @@ bool ensure_python_block_display_is_registered(void) if (!ensure_python_buffer_display_is_registered()) return false; - if (!register_class_for_pygobject(dict, GTK_TYPE_BLOCK_DISPLAY, type, get_python_buffer_display_type())) + if (!register_class_for_pygobject(dict, GTK_TYPE_BLOCK_DISPLAY, type)) return false; } diff --git a/plugins/pychrysalide/gtkext/bufferdisplay.c b/plugins/pychrysalide/gtkext/bufferdisplay.c index 310e60a..4babcc8 100644 --- a/plugins/pychrysalide/gtkext/bufferdisplay.c +++ b/plugins/pychrysalide/gtkext/bufferdisplay.c @@ -115,7 +115,7 @@ bool ensure_python_buffer_display_is_registered(void) if (!ensure_python_display_panel_is_registered()) return false; - if (!register_class_for_pygobject(dict, GTK_TYPE_BUFFER_DISPLAY, type, get_python_display_panel_type())) + if (!register_class_for_pygobject(dict, GTK_TYPE_BUFFER_DISPLAY, type)) return false; } diff --git a/plugins/pychrysalide/gtkext/displaypanel.c b/plugins/pychrysalide/gtkext/displaypanel.c index dc7b8e5..a871af9 100644 --- a/plugins/pychrysalide/gtkext/displaypanel.c +++ b/plugins/pychrysalide/gtkext/displaypanel.c @@ -98,42 +98,23 @@ PyTypeObject *get_python_display_panel_type(void) bool ensure_python_display_panel_is_registered(void) { - bool result; /* Bilan à retourner */ PyTypeObject *type; /* Type Python 'DisplayPanel' */ - PyObject *parent_mod; /* Module Python Fixed */ - PyObject *fixed; /* Module "GtkFixed" */ PyObject *module; /* Module à recompléter */ PyObject *dict; /* Dictionnaire du module */ - result = false; - type = get_python_display_panel_type(); if (!PyType_HasFeature(type, Py_TPFLAGS_READY)) { module = get_access_to_python_module("pychrysalide.gtkext"); - parent_mod = PyImport_ImportModule("gi.repository.Gtk"); - - if (parent_mod == NULL) - goto rpdp_exit; - - fixed = PyObject_GetAttrString(parent_mod, "Fixed"); - - Py_DECREF(parent_mod); - dict = PyModule_GetDict(module); - result = register_class_for_pygobject(dict, GTK_TYPE_DISPLAY_PANEL, type, (PyTypeObject *)fixed); - Py_DECREF(fixed); + if (!register_class_for_pygobject(dict, GTK_TYPE_DISPLAY_PANEL, type)) + return false; } - else - result = true; - - rpdp_exit: - - return result; + return true; } diff --git a/plugins/pychrysalide/gtkext/graph/Makefile.am b/plugins/pychrysalide/gtkext/graph/Makefile.am index 7e9b5e5..25e3088 100644 --- a/plugins/pychrysalide/gtkext/graph/Makefile.am +++ b/plugins/pychrysalide/gtkext/graph/Makefile.am @@ -1,21 +1,16 @@ noinst_LTLIBRARIES = libpychrysagtkextgraph.la -libpychrysagtkextgraph_la_SOURCES = \ - constants.h constants.c \ - cluster.h cluster.c \ - edge.h edge.c \ +libpychrysagtkextgraph_la_SOURCES = \ + constants.h constants.c \ + cluster.h cluster.c \ + edge.h edge.c \ module.h module.c -libpychrysagtkextgraph_la_LDFLAGS = +libpychrysagtkextgraph_la_CFLAGS = $(LIBGTK_CFLAGS) $(LIBXML_CFLAGS) $(LIBPYTHON_INTERPRETER_CFLAGS) $(LIBPYGOBJECT_CFLAGS) \ + -I$(top_srcdir)/src -DNO_IMPORT_PYGOBJECT devdir = $(includedir)/chrysalide/$(subdir) dev_HEADERS = $(libpychrysagtkextgraph_la_SOURCES:%c=) - - -AM_CPPFLAGS = $(LIBGTK_CFLAGS) $(LIBXML_CFLAGS) $(LIBPYTHON_CFLAGS) $(LIBPYGOBJECT_CFLAGS) \ - -I$(top_srcdir)/src - -AM_CFLAGS = $(DEBUG_CFLAGS) $(WARNING_FLAGS) $(COMPLIANCE_FLAGS) diff --git a/plugins/pychrysalide/gtkext/graph/cluster.c b/plugins/pychrysalide/gtkext/graph/cluster.c index fc73276..11cb8fa 100644 --- a/plugins/pychrysalide/gtkext/graph/cluster.c +++ b/plugins/pychrysalide/gtkext/graph/cluster.c @@ -656,7 +656,7 @@ bool ensure_python_graph_cluster_is_registered(void) dict = PyModule_GetDict(module); - if (!register_class_for_pygobject(dict, G_TYPE_GRAPH_CLUSTER, type, &PyGObject_Type)) + if (!register_class_for_pygobject(dict, G_TYPE_GRAPH_CLUSTER, type)) return false; } diff --git a/plugins/pychrysalide/gtkext/graph/edge.c b/plugins/pychrysalide/gtkext/graph/edge.c index ce20ce9..d016e30 100644 --- a/plugins/pychrysalide/gtkext/graph/edge.c +++ b/plugins/pychrysalide/gtkext/graph/edge.c @@ -267,7 +267,7 @@ bool ensure_python_graph_edge_is_registered(void) dict = PyModule_GetDict(module); - if (!register_class_for_pygobject(dict, G_TYPE_GRAPH_EDGE, type, &PyGObject_Type)) + if (!register_class_for_pygobject(dict, G_TYPE_GRAPH_EDGE, type)) return false; if (!define_graph_edge_constants(type)) diff --git a/plugins/pychrysalide/gtkext/named.c b/plugins/pychrysalide/gtkext/named.c index e272097..ee963de 100644 --- a/plugins/pychrysalide/gtkext/named.c +++ b/plugins/pychrysalide/gtkext/named.c @@ -99,7 +99,7 @@ static PyObject *py_built_named_widget_new(PyTypeObject *type, PyObject *args, P if (first_time) { - status = register_class_for_dynamic_pygobject(gtype, type, base); + status = register_class_for_dynamic_pygobject(gtype, type); if (!status) { @@ -278,12 +278,7 @@ PyTypeObject *get_python_built_named_widget_type(void) }; - static PyTypeObject *result = NULL; - - if (result == NULL) - result = define_python_dynamic_type(&py_built_named_widget_type); - - return result; + return &py_built_named_widget_type; } @@ -317,7 +312,7 @@ bool ensure_python_built_named_widget_is_registered(void) if (!ensure_python_named_widget_is_registered()) return false; - if (!register_class_for_pygobject(dict, GTK_TYPE_BUILT_NAMED_WIDGET, type, &PyGObject_Type)) + if (!register_class_for_pygobject(dict, GTK_TYPE_BUILT_NAMED_WIDGET, type)) return false; } diff --git a/plugins/pychrysalide/gui/Makefile.am b/plugins/pychrysalide/gui/Makefile.am index 360f7ff..de2e888 100644 --- a/plugins/pychrysalide/gui/Makefile.am +++ b/plugins/pychrysalide/gui/Makefile.am @@ -1,18 +1,19 @@ noinst_LTLIBRARIES = libpychrysagui.la -libpychrysagui_la_SOURCES = \ - constants.h constants.c \ - item.h item.c \ - menubar.h menubar.c \ - module.h module.c \ +libpychrysagui_la_SOURCES = \ + constants.h constants.c \ + item.h item.c \ + menubar.h menubar.c \ + module.h module.c \ panel.h panel.c -libpychrysagui_la_LIBADD = \ - core/libpychrysaguicore.la \ +libpychrysagui_la_LIBADD = \ + core/libpychrysaguicore.la \ panels/libpychrysaguipanels.la -libpychrysagui_la_LDFLAGS = +libpychrysagui_la_CFLAGS = $(TOOLKIT_CFLAGS) $(LIBXML_CFLAGS) $(LIBPYTHON_INTERPRETER_CFLAGS) $(LIBPYGOBJECT_CFLAGS) \ + -I$(top_srcdir)/src -DNO_IMPORT_PYGOBJECT devdir = $(includedir)/chrysalide/$(subdir) @@ -20,9 +21,4 @@ devdir = $(includedir)/chrysalide/$(subdir) dev_HEADERS = $(libpychrysagui_la_SOURCES:%c=) -AM_CPPFLAGS = $(LIBGTK_CFLAGS) $(LIBXML_CFLAGS) $(LIBPYTHON_CFLAGS) $(LIBPYGOBJECT_CFLAGS) \ - -I$(top_srcdir)/src - -AM_CFLAGS = $(DEBUG_CFLAGS) $(WARNING_FLAGS) $(COMPLIANCE_FLAGS) - SUBDIRS = core panels diff --git a/plugins/pychrysalide/gui/core/Makefile.am b/plugins/pychrysalide/gui/core/Makefile.am index 02f3596..8f49176 100644 --- a/plugins/pychrysalide/gui/core/Makefile.am +++ b/plugins/pychrysalide/gui/core/Makefile.am @@ -1,21 +1,16 @@ noinst_LTLIBRARIES = libpychrysaguicore.la -libpychrysaguicore_la_SOURCES = \ - global.h global.c \ - items.h items.c \ - module.h module.c \ +libpychrysaguicore_la_SOURCES = \ + global.h global.c \ + items.h items.c \ + module.h module.c \ panels.h panels.c -libpychrysaguicore_la_LDFLAGS = +libpychrysaguicore_la_CFLAGS = $(TOOLKIT_CFLAGS) $(LIBXML_CFLAGS) $(LIBPYTHON_INTERPRETER_CFLAGS) $(LIBPYGOBJECT_CFLAGS) \ + -I$(top_srcdir)/src -DNO_IMPORT_PYGOBJECT devdir = $(includedir)/chrysalide/$(subdir) dev_HEADERS = $(libpychrysaguicore_la_SOURCES:%c=) - - -AM_CPPFLAGS = $(LIBGTK_CFLAGS) $(LIBXML_CFLAGS) $(LIBPYTHON_CFLAGS) $(LIBPYGOBJECT_CFLAGS) \ - -I$(top_srcdir)/src - -AM_CFLAGS = $(DEBUG_CFLAGS) $(WARNING_FLAGS) $(COMPLIANCE_FLAGS) diff --git a/plugins/pychrysalide/gui/item.c b/plugins/pychrysalide/gui/item.c index 2046587..0c604b5 100644 --- a/plugins/pychrysalide/gui/item.c +++ b/plugins/pychrysalide/gui/item.c @@ -291,19 +291,16 @@ static GtkWidget *py_editor_item_get_widget_wrapper(const GEditorItem *item) static void py_editor_item_change_content_wrapper(GEditorItem *item, GLoadedContent *old, GLoadedContent *new) { + PyGILState_STATE gstate; /* Sauvegarde d'environnement */ PyObject *pyobj; /* Objet Python concerné */ - PyThreadState *tstate; /* Contexte d'environnement */ PyObject *pyold; /* Conversion ou None */ PyObject *pynew; /* Conversion ou None */ PyObject *args; /* Arguments pour l'appel */ PyObject *pyret; /* Retour de Python */ - pyobj = pygobject_new(G_OBJECT(item)); - - tstate = get_pychrysalide_main_tstate(); + gstate = PyGILState_Ensure(); - if (tstate != NULL) - PyEval_RestoreThread(tstate); + pyobj = pygobject_new(G_OBJECT(item)); if (has_python_method(pyobj, "_change_content")) { @@ -334,8 +331,7 @@ static void py_editor_item_change_content_wrapper(GEditorItem *item, GLoadedCont } - if (tstate != NULL) - PyEval_SaveThread(); + PyGILState_Release(gstate); } @@ -356,19 +352,16 @@ static void py_editor_item_change_content_wrapper(GEditorItem *item, GLoadedCont static void py_editor_item_change_view_wrapper(GEditorItem *item, GLoadedPanel *old, GLoadedPanel *new) { + PyGILState_STATE gstate; /* Sauvegarde d'environnement */ PyObject *pyobj; /* Objet Python concerné */ - PyThreadState *tstate; /* Contexte d'environnement */ PyObject *pyold; /* Conversion ou None */ PyObject *pynew; /* Conversion ou None */ PyObject *args; /* Arguments pour l'appel */ PyObject *pyret; /* Retour de Python */ - pyobj = pygobject_new(G_OBJECT(item)); - - tstate = get_pychrysalide_main_tstate(); + gstate = PyGILState_Ensure(); - if (tstate != NULL) - PyEval_RestoreThread(tstate); + pyobj = pygobject_new(G_OBJECT(item)); if (has_python_method(pyobj, "_change_view")) { @@ -399,8 +392,7 @@ static void py_editor_item_change_view_wrapper(GEditorItem *item, GLoadedPanel * } - if (tstate != NULL) - PyEval_SaveThread(); + PyGILState_Release(gstate); } @@ -420,17 +412,14 @@ static void py_editor_item_change_view_wrapper(GEditorItem *item, GLoadedPanel * static void py_editor_item_update_view_wrapper(GEditorItem *item, GLoadedPanel *panel) { + PyGILState_STATE gstate; /* Sauvegarde d'environnement */ PyObject *pyobj; /* Objet Python concerné */ - PyThreadState *tstate; /* Contexte d'environnement */ PyObject *args; /* Arguments pour l'appel */ PyObject *pyret; /* Retour de Python */ - pyobj = pygobject_new(G_OBJECT(item)); - - tstate = get_pychrysalide_main_tstate(); + gstate = PyGILState_Ensure(); - if (tstate != NULL) - PyEval_RestoreThread(tstate); + pyobj = pygobject_new(G_OBJECT(item)); if (has_python_method(pyobj, "_update_view")) { @@ -444,8 +433,7 @@ static void py_editor_item_update_view_wrapper(GEditorItem *item, GLoadedPanel * } - if (tstate != NULL) - PyEval_SaveThread(); + PyGILState_Release(gstate); } @@ -466,17 +454,14 @@ static void py_editor_item_update_view_wrapper(GEditorItem *item, GLoadedPanel * static void py_editor_item_track_cursor_wrapper(GEditorItem *item, GLoadedPanel *panel, const GLineCursor *cursor) { + PyGILState_STATE gstate; /* Sauvegarde d'environnement */ PyObject *pyobj; /* Objet Python concerné */ - PyThreadState *tstate; /* Contexte d'environnement */ PyObject *args; /* Arguments pour l'appel */ PyObject *pyret; /* Retour de Python */ - pyobj = pygobject_new(G_OBJECT(item)); - - tstate = get_pychrysalide_main_tstate(); + gstate = PyGILState_Ensure(); - if (tstate != NULL) - PyEval_RestoreThread(tstate); + pyobj = pygobject_new(G_OBJECT(item)); if (has_python_method(pyobj, "_track_cursor")) { @@ -491,8 +476,7 @@ static void py_editor_item_track_cursor_wrapper(GEditorItem *item, GLoadedPanel } - if (tstate != NULL) - PyEval_SaveThread(); + PyGILState_Release(gstate); } @@ -513,17 +497,14 @@ static void py_editor_item_track_cursor_wrapper(GEditorItem *item, GLoadedPanel static void py_editor_item_focus_cursor_wrapper(GEditorItem *item, GLoadedContent *content, const GLineCursor *cursor) { + PyGILState_STATE gstate; /* Sauvegarde d'environnement */ PyObject *pyobj; /* Objet Python concerné */ - PyThreadState *tstate; /* Contexte d'environnement */ PyObject *args; /* Arguments pour l'appel */ PyObject *pyret; /* Retour de Python */ - pyobj = pygobject_new(G_OBJECT(item)); - - tstate = get_pychrysalide_main_tstate(); + gstate = PyGILState_Ensure(); - if (tstate != NULL) - PyEval_RestoreThread(tstate); + pyobj = pygobject_new(G_OBJECT(item)); if (has_python_method(pyobj, "_focus_cursor")) { @@ -538,8 +519,7 @@ static void py_editor_item_focus_cursor_wrapper(GEditorItem *item, GLoadedConten } - if (tstate != NULL) - PyEval_SaveThread(); + PyGILState_Release(gstate); } @@ -711,7 +691,7 @@ bool ensure_python_editor_item_is_registered(void) dict = PyModule_GetDict(module); - if (!register_class_for_pygobject(dict, G_TYPE_EDITOR_ITEM, type, &PyGObject_Type)) + if (!register_class_for_pygobject(dict, G_TYPE_EDITOR_ITEM, type)) return false; } diff --git a/plugins/pychrysalide/gui/menubar.c b/plugins/pychrysalide/gui/menubar.c index 5c6270e..29b76ac 100644 --- a/plugins/pychrysalide/gui/menubar.c +++ b/plugins/pychrysalide/gui/menubar.c @@ -160,7 +160,10 @@ bool ensure_python_menu_bar_is_registered(void) dict = PyModule_GetDict(module); - if (!register_class_for_pygobject(dict, G_TYPE_MENU_BAR, type, get_python_editor_item_type())) + if (!ensure_python_editor_item_is_registered()) + return false; + + if (!register_class_for_pygobject(dict, G_TYPE_MENU_BAR, type)) return false; } diff --git a/plugins/pychrysalide/gui/panel.c b/plugins/pychrysalide/gui/panel.c index 2afb2a1..949243c 100644 --- a/plugins/pychrysalide/gui/panel.c +++ b/plugins/pychrysalide/gui/panel.c @@ -164,7 +164,7 @@ static PyObject *py_panel_item_new(PyTypeObject *type, PyObject *args, PyObject if (first_time) { - status = register_class_for_dynamic_pygobject(gtype, type, base); + status = register_class_for_dynamic_pygobject(gtype, type); if (!status) { @@ -1188,8 +1188,7 @@ bool ensure_python_panel_item_is_registered(void) if (!ensure_python_dockable_is_registered()) return false; - if (!_register_class_for_pygobject(dict, G_TYPE_PANEL_ITEM, type, - get_python_editor_item_type(), get_python_dockable_type(), NULL)) + if (!register_class_for_pygobject(dict, G_TYPE_PANEL_ITEM, type)) return false; if (!define_panel_item_constants(type)) diff --git a/plugins/pychrysalide/gui/panels/Makefile.am b/plugins/pychrysalide/gui/panels/Makefile.am index 9585ec4..067c798 100644 --- a/plugins/pychrysalide/gui/panels/Makefile.am +++ b/plugins/pychrysalide/gui/panels/Makefile.am @@ -1,19 +1,14 @@ noinst_LTLIBRARIES = libpychrysaguipanels.la -libpychrysaguipanels_la_SOURCES = \ - module.h module.c \ +libpychrysaguipanels_la_SOURCES = \ + module.h module.c \ updating.h updating.c -libpychrysaguipanels_la_LDFLAGS = +libpychrysaguipanels_la_CFLAGS = $(TOOLKIT_CFLAGS) $(LIBXML_CFLAGS) $(LIBPYTHON_INTERPRETER_CFLAGS) $(LIBPYGOBJECT_CFLAGS) \ + -I$(top_srcdir)/src -DNO_IMPORT_PYGOBJECT devdir = $(includedir)/chrysalide/$(subdir) dev_HEADERS = $(libpychrysaguipanels_la_SOURCES:%c=) - - -AM_CPPFLAGS = $(LIBGTK_CFLAGS) $(LIBXML_CFLAGS) $(LIBPYTHON_CFLAGS) $(LIBPYGOBJECT_CFLAGS) \ - -I$(top_srcdir)/src - -AM_CFLAGS = $(DEBUG_CFLAGS) $(WARNING_FLAGS) $(COMPLIANCE_FLAGS) diff --git a/plugins/pychrysalide/helpers.c b/plugins/pychrysalide/helpers.c index 92a5db9..c2b1868 100644 --- a/plugins/pychrysalide/helpers.c +++ b/plugins/pychrysalide/helpers.c @@ -32,11 +32,14 @@ #include <stdlib.h> #include <string.h> #include <strings.h> -#include <gtk/gtk.h> +#ifdef INCLUDE_GTK_SUPPORT +# include <gtk/gtk.h> +#endif #include <i18n.h> #include <common/extstr.h> +#include <plugins/dt.h> #include "access.h" @@ -233,6 +236,8 @@ PyObject *run_python_method(PyObject *module, const char *method, PyObject *args PyObject *traceback; /* Pile d'appels de l'exception*/ PyObject *refmsg; /* Message de référence */ + assert(PyGILState_Check() == 1); + /* Exécution */ result = NULL; @@ -505,6 +510,131 @@ bool register_python_module_object(PyObject *module, PyTypeObject *type) /****************************************************************************** * * +* Paramètres : type = type du nouvel objet à mettre en place. * +* gbase = type de base natif. * +* 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 : - * +* * +******************************************************************************/ + +PyObject *python_constructor_with_dynamic_gtype(PyTypeObject *type, GType gbase, PyObject *args, PyObject *kwds) +{ + PyObject *result; /* Objet à retourner */ + PyTypeObject *base; /* Type parent version Python */ + bool first_time; /* Evite les multiples passages*/ + GType gtype; /* Nouveau type de processeur */ + bool status; /* Bilan d'un enregistrement */ + + /* Validations diverses */ + + base = pygobject_lookup_class(gbase); + + 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(gbase, 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 : type = type du nouvel objet à mettre en place. * +* gbase = type de base natif. * +* cinit = procédure d'initialisation de la classe associée. * +* 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 : - * +* * +******************************************************************************/ + +PyObject *python_abstract_constructor_with_dynamic_gtype(PyTypeObject *type, GType gbase, GClassInitFunc cinit, PyObject *args, PyObject *kwds) +{ + PyObject *result; /* Objet à retourner */ + PyTypeObject *base; /* Type parent version Python */ + bool first_time; /* Evite les multiples passages*/ + GType gtype; /* Nouveau type de processeur */ + bool status; /* Bilan d'un enregistrement */ + + /* Validations diverses */ + + base = pygobject_lookup_class(gbase); + + 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(gbase, type->tp_name, cinit, 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 : type = type du nouvel objet à mettre en place. * * args = éventuelle liste d'arguments. * * kwds = éventuel dictionnaire de valeurs mises à disposition. * @@ -659,7 +789,7 @@ PyObject *not_yet_implemented_getter(PyObject *self, void *closure) /****************************************************************************** * * -* Paramètres : spec = définition à mettre en place dynamiquement. * +* Paramètres : otype = définition à mettre en place dynamiquement. * * * * Description : Définit dans le tas de Python un nouveau type. * * * @@ -669,102 +799,63 @@ PyObject *not_yet_implemented_getter(PyObject *self, void *closure) * * ******************************************************************************/ -PyTypeObject *define_python_dynamic_type(const PyTypeObject *spec) +PyTypeObject *define_python_dynamic_type(const PyTypeObject *otype) { PyTypeObject *result; /* Définition créée à renvoyer */ - PyTypeObject *type; /* Type de tous les types */ - size_t size; /* Taille de la définition */ - char *s; /* Marqueur de début de chaîne */ - PyHeapTypeObject *hobj; /* Version réelle du type créé */ + PyType_Slot slots[10]; /* Emplacements pour infos */ + PyType_Spec spec; /* Définition du type */ + PyType_Slot *iter; /* Boucle de parcours */ + PyObject *bases; /* Bases de construction */ - /** - * Le cahier des charges est ici d'éviter les erreurs suivantes : - * - * TypeError: type 'XXX' is not dynamically allocated but its base type 'YYY' is dynamically allocated - * Fatal Python error: unexpected exception during garbage collection - * - * L'allocation dynamique est marquée par le fanion Py_TPFLAGS_HEAPTYPE. - * - * Une des rares fonctions qui appliquent ce fanion est PyType_FromSpecWithBases(), - * mais elle appelle ensuite PyType_Ready(), ce qui est incompatible avec des modifications - * utltérieures avant un appel à pygobject_register_class(). - * - * Le code suivant s'inspire fortement des méthodes originales de Python, - * dont les mécanismes employés par PyType_GenericAlloc(). - */ - - type = &PyType_Type; - size = _PyObject_SIZE(type); - - if (PyType_IS_GC(type)) - result = (PyTypeObject *)_PyObject_GC_Malloc(size); - else - result = (PyTypeObject *)PyObject_MALLOC(size); - - if (type->tp_flags & Py_TPFLAGS_HEAPTYPE) - Py_INCREF(type); - - /* Définitions sommaires */ - - memset(result, 0, sizeof(PyHeapTypeObject)); + bases = PyTuple_Pack(1, &PyType_Type); - memcpy(result, spec, sizeof(PyTypeObject)); - - result->tp_flags |= Py_TPFLAGS_HEAPTYPE; - - /* Définitions des noms */ - - /** - * Pour un type dynamique, les désignations ne s'appuient pas sur la partie réservée - * au type, mais sur les données suivantes (cf. type_name() et type_qualname()). - * - * Les deux fonctions désignées sont par ailleurs facilement accessibles : - * - * #0 0x0000555555689bf0 in type_qualname (...) at Objects/typeobject.c:393 - * #1 0x000055555568b3b4 in type_repr (...) at Objects/typeobject.c:855 - * #2 0x0000555555693574 in object_str (...) at Objects/typeobject.c:3511 - * #3 0x0000555555670d02 in PyObject_Str (...) at Objects/object.c:535 - * ... - * - * On s'inspire donc du contenu de PyType_FromSpecWithBases() pour éviter tout - * plantage du fait de données non initialisées. - */ - - hobj = (PyHeapTypeObject *)result; - - s = strrchr(spec->tp_name, '.'); - - if (s == NULL) - s = (char *)spec->tp_name; - else - s++; + spec.name = otype->tp_name; + spec.basicsize = otype->tp_basicsize; + spec.flags = otype->tp_flags; + spec.slots = slots; - hobj->ht_name = PyUnicode_FromString(s); - assert(hobj->ht_name != NULL); + iter = &slots[0]; - hobj->ht_qualname = hobj->ht_name; - Py_INCREF(hobj->ht_qualname); + if (otype->tp_doc != NULL) + { + iter->slot = Py_tp_doc; + iter->pfunc = (void *)otype->tp_doc; + iter++; + } - result->tp_as_async = &hobj->as_async; - result->tp_as_number = &hobj->as_number; - result->tp_as_sequence = &hobj->as_sequence; - result->tp_as_mapping = &hobj->as_mapping; - result->tp_as_buffer = &hobj->as_buffer; + if (otype->tp_methods != NULL) + { + iter->slot = Py_tp_methods; + iter->pfunc = otype->tp_methods; + iter++; + } - hobj->ht_cached_keys = _PyDict_NewKeysForClass(); + if (otype->tp_getset != NULL) + { + iter->slot = Py_tp_getset; + iter->pfunc = otype->tp_getset; + iter++; + } + if (otype->tp_init != NULL) + { + iter->slot = Py_tp_init; + iter->pfunc = otype->tp_init; + iter++; + } + if (otype->tp_new != NULL) + { + iter->slot = Py_tp_new; + iter->pfunc = otype->tp_new; + iter++; + } + iter->slot = 0; -#if 0 - if (type->tp_itemsize == 0) - (void)PyObject_INIT(result, type); - else - (void) PyObject_INIT_VAR((PyVarObject *)result, type, 0); + result = (PyTypeObject *)PyType_FromSpecWithBases(&spec, bases); - if (PyType_IS_GC(type)) - _PyObject_GC_TRACK(result); -#endif + Py_DECREF(bases); return result; @@ -800,7 +891,6 @@ static void define_auto_documentation(PyTypeObject *type) * Paramètres : dict = dictionnaire où conserver une référence au type créé.* * gtype = type dans sa version GLib. * * type = type dans sa version Python. * -* base = type de base de l'objet. * * * * Description : Enregistre correctement une surcouche de conversion GObject. * * * @@ -810,13 +900,11 @@ static void define_auto_documentation(PyTypeObject *type) * * ******************************************************************************/ -bool _register_class_for_pygobject(PyObject *dict, GType gtype, PyTypeObject *type, PyTypeObject *base, ...) +bool register_class_for_pygobject(PyObject *dict, GType gtype, PyTypeObject *type) { bool result; /* Bilan à retourner */ - Py_ssize_t size; /* Taille de liste actuelle */ - PyObject *static_bases; /* Base(s) de l'objet */ - va_list ap; /* Parcours des arguments */ - PyTypeObject *static_base; /* Base à rajouter à la liste */ + GType parent_type; /* Type parent version GObject */ + PyTypeObject *base; /* Type parent version Python */ assert(gtype != G_TYPE_INVALID); @@ -841,45 +929,17 @@ bool _register_class_for_pygobject(PyObject *dict, GType gtype, PyTypeObject *ty * Et quelqu'un doit se coller à la tâche. PyGObject ne fait rien, donc... */ + parent_type = g_type_parent(gtype); + + base = pygobject_lookup_class(parent_type); + if (type->tp_basicsize < base->tp_basicsize) { assert(type->tp_basicsize == 0); type->tp_basicsize = base->tp_basicsize; } - size = 1; - static_bases = PyTuple_New(size); - - Py_INCREF(base); - PyTuple_SetItem(static_bases, 0, (PyObject *)base); - - va_start(ap, base); - - while (1) - { - static_base = va_arg(ap, PyTypeObject *); - - if (static_base == NULL) break; - - _PyTuple_Resize(&static_bases, ++size); - - Py_INCREF(static_base); - PyTuple_SetItem(static_bases, size - 1, (PyObject *)static_base); - - } - - va_end(ap); - - /** - * les renseignements suivants ne semblent pas nécessaires... - */ - - /* - type->tp_weaklistoffset = offsetof(PyGObject, weakreflist); - type->tp_dictoffset = offsetof(PyGObject, inst_dict); - */ - - pygobject_register_class(dict, NULL, gtype, type, static_bases); + pygobject_register_class(dict, NULL, gtype, type, NULL); if (PyErr_Occurred() == NULL) result = true; @@ -956,10 +1016,8 @@ bool register_interface_for_pygobject(PyObject *dict, GType gtype, PyTypeObject /****************************************************************************** * * -* Paramètres : dict = dictionnaire où conserver une référence au type créé.* -* gtype = type dans sa version GLib. * +* Paramètres : gtype = type dans sa version GLib. * * type = type dans sa version Python. * -* base = type de base de l'objet. * * * * Description : Enregistre un type Python dérivant d'un type GLib dynamique. * * * @@ -969,7 +1027,7 @@ bool register_interface_for_pygobject(PyObject *dict, GType gtype, PyTypeObject * * ******************************************************************************/ -bool register_class_for_dynamic_pygobject(GType gtype, PyTypeObject *type, PyTypeObject *base) +bool register_class_for_dynamic_pygobject(GType gtype, PyTypeObject *type) { bool result; /* Bilan à retourner */ PyTypeObject *legacy_parent; /* Type parent d'origine */ @@ -1024,9 +1082,9 @@ bool register_class_for_dynamic_pygobject(GType gtype, PyTypeObject *type, PyTyp dict = PyModule_GetDict(module); - result = _register_class_for_pygobject(dict, gtype, type, &PyGObject_Type, base, NULL); + result = register_class_for_pygobject(dict, gtype, type); - Py_TYPE(type) = legacy_parent; + Py_SET_TYPE(type, legacy_parent); /** * Comme la mise en place dynamique de nouveau GType court-circuite les @@ -1189,6 +1247,9 @@ int convert_to_gobject(PyObject *arg, void *dst) } +#ifdef INCLUDE_GTK_SUPPORT + + /****************************************************************************** * * * Paramètres : arg = argument quelconque à tenter de convertir. * @@ -1299,6 +1360,9 @@ int convert_to_gtk_container(PyObject *arg, void *dst) } +#endif + + /****************************************************************************** * * * Paramètres : color = couleur dans sa définition native à copier. * @@ -1440,15 +1504,15 @@ int convert_to_gdk_rgba(PyObject *arg, void *dst) * * * Description : Officialise un groupe de constantes avec sémentique. * * * -* Retour : true en cas de succès de l'opération, false sinon. * +* Retour : Groupe de constantes mis en place ou NULL en cas d'échec. * * * * Remarques : - * * * ******************************************************************************/ -bool _attach_constants_group(const char *owner, PyObject *dict, bool flags, const char *name, PyObject *values, const char *doc) +PyObject *_attach_constants_group(const char *owner, PyObject *dict, bool flags, const char *name, PyObject *values, const char *doc) { - bool result; /* Bilan à retourner */ + PyObject *result; /* Instance à retourner */ PyObject *enum_mod; /* Module Python enum */ PyObject *class; /* Classe "Enum*" */ PyObject *str_obj; /* Conversion en Python */ @@ -1462,7 +1526,7 @@ bool _attach_constants_group(const char *owner, PyObject *dict, bool flags, cons PyObject *features; /* Module à recompléter */ PyObject *features_dict; /* Dictionnaire à compléter */ - result = false; + result = NULL; /* Recherche de la classe Python */ @@ -1539,7 +1603,8 @@ bool _attach_constants_group(const char *owner, PyObject *dict, bool flags, cons ret = PyDict_SetItemString(features_dict, name, new); if (ret != 0) goto register_1_error; - result = true; + result = new; + Py_INCREF(result); /* Sortie propre */ @@ -1570,6 +1635,99 @@ bool _attach_constants_group(const char *owner, PyObject *dict, bool flags, cons } +/****************************************************************************** +* * +* Paramètres : owner = désignation du propriétaire du dictionnaire visé. * +* dict = dictionnaire dont le contenu est à compléter. * +* flags = indique le type d'énumération ciblée. * +* name = désignation humaine du groupe à constituer. * +* values = noms et valeurs associées. * +* doc = documentation à associer au groupe. * +* gtype = énumération GLib à lier. * +* * +* Description : Officialise un groupe de constantes avec lien GLib. * +* * +* Retour : Groupe de constantes mis en place ou NULL en cas d'échec. * +* * +* Remarques : - * +* * +******************************************************************************/ + +PyObject *_attach_constants_group_with_pyg_enum(const char *owner, PyObject *dict, bool flags, const char *name, PyObject *values, const char *doc, GType gtype) +{ + PyObject *result; /* Instance à retourner */ + PyObject *values_set; /* Zone pour nouvelles valeurs */ + int ret; /* Bilan d'une insertion */ + PyObject *new; /* Nouvelle instance en place */ + PyObject *values_src; /* Source de nouvelles valeurs */ + PyObject *values_dest; /* Destination des valeurs */ + + static GQuark pygenum_class_key = 0; /* Clef d'accès au marquage */ + + result = NULL; + + /** + * Le seul intérêt d'un tel enregistrement en bonne et due forme est de + * permettre une impression, via str() ou repr(), de l'énumération + * transcrite en GLib via g_enum_register_static() et potentiellement + * convertie de façon brusque par _pygi_argument_to_object(), lors d'une + * émission de signal par exemple. + * + * La satisfaction de la fonction pyg_enum_from_gtype() est ainsi recherchée. + * Tous les éléments sont normalement mis en place à partir de la fonction + * pyg_enum_add(). + */ + + /* Préparation du réceptacle */ + + values_set = PyDict_New(); + + ret = PyDict_SetItemString(values, "__enum_values__", values_set); + + Py_DECREF(values_set); + + if (ret != 0) goto exit; + + /* Création */ + + new = _attach_constants_group(owner, dict, flags, name, values, doc); + if (new == NULL) goto exit; + + /* Actualisation des valeurs */ + + values_src = PyDict_GetItemString(((PyTypeObject *)new)->tp_dict, "_value2member_map_"); + if (values_src == NULL) goto exit_without_src; + + values_dest = PyDict_GetItemString(((PyTypeObject *)new)->tp_dict, "__enum_values__"); + if (values_dest == NULL) goto exit_without_dest; + + assert(values_dest == values_set); + + ret = PyDict_Merge(values_dest, values_src, true); + + if (ret == 0) + { + result = new; + Py_INCREF(result); + + if (pygenum_class_key == 0) + pygenum_class_key = g_quark_from_static_string("PyGEnum::class"); + + g_type_set_qdata(gtype, pygenum_class_key, result); + + } + + exit_without_dest: + exit_without_src: + + Py_DECREF(new); + + exit: + + return result; + +} + /****************************************************************************** * * diff --git a/plugins/pychrysalide/helpers.h b/plugins/pychrysalide/helpers.h index 931be95..57cf96d 100644 --- a/plugins/pychrysalide/helpers.h +++ b/plugins/pychrysalide/helpers.h @@ -29,7 +29,9 @@ #include <assert.h> #include <glib-object.h> #include <stdbool.h> -#include <gdk/gdk.h> +#ifdef INCLUDE_GTK_SUPPORT +# include <gdk/gdk.h> +#endif @@ -85,26 +87,21 @@ bool register_python_module_object(PyObject *, PyTypeObject *); #name "(" args ")\n--\n\n" doc \ } -#define PYTHON_VOID_WRAPPER_DEF(name, args, flags, doc) \ - { \ - #name, (PyCFunction)py_return_none, \ - flags, \ - #name "(" args ")\n--\n\n" doc \ +#define PYTHON_WRAPPER_DEF_WITH(name, args, flags, defcb, doc) \ + { \ + #name, (PyCFunction)defcb, \ + flags, \ + #name "(" args ")\n--\n\n" doc \ } -#define PYTHON_FALSE_WRAPPER_DEF(name, args, flags, doc)\ - { \ - #name, (PyCFunction)py_return_false, \ - flags, \ - #name "(" args ")\n--\n\n" doc \ - } +#define PYTHON_VOID_WRAPPER_DEF(name, args, flags, doc) \ + PYTHON_WRAPPER_DEF_WITH(name, args, flags, py_return_none, doc) -#define PYTHON_TRUE_WRAPPER_DEF(name, args, flags, doc)\ - { \ - #name, (PyCFunction)py_return_true, \ - flags, \ - #name "(" args ")\n--\n\n" doc \ - } +#define PYTHON_FALSE_WRAPPER_DEF(name, args, flags, doc) \ + PYTHON_WRAPPER_DEF_WITH(name, args, flags, py_return_false, doc) + +#define PYTHON_TRUE_WRAPPER_DEF(name, args, flags, doc) \ + PYTHON_WRAPPER_DEF_WITH(name, args, flags, py_return_true, doc) /** * Il ne semble pas exister de moyen de déterminer @@ -158,6 +155,34 @@ bool register_python_module_object(PyObject *, PyTypeObject *); #define APPLY_ABSTRACT_FLAG(tp) tp->tp_new = PyBaseObject_Type.tp_new +/* Accompagne la création d'une instance dérivée en Python. */ +PyObject *python_constructor_with_dynamic_gtype(PyTypeObject *, GType, PyObject *, PyObject *); + +/* Accompagne la création d'une instance dérivée en Python. */ +PyObject *python_abstract_constructor_with_dynamic_gtype(PyTypeObject *, GType, GClassInitFunc, PyObject *, PyObject *); + + +#define CREATE_DYN_CONSTRUCTOR(pyname, gbase) \ +static PyObject *py_ ## pyname ## _new(PyTypeObject *, PyObject *, PyObject *); \ +static PyObject *py_ ## pyname ## _new(PyTypeObject *type, PyObject *args, PyObject *kwds) \ +{ \ + PyObject *result; /* Objet à retourner */ \ + result = python_constructor_with_dynamic_gtype(type, gbase, args, kwds); \ + return result; \ +} + + +#define CREATE_DYN_ABSTRACT_CONSTRUCTOR(pyname, gbase, cinit) \ +static PyObject *py_ ## pyname ## _new(PyTypeObject *, PyObject *, PyObject *); \ +static PyObject *py_ ## pyname ## _new(PyTypeObject *type, PyObject *args, PyObject *kwds) \ +{ \ + PyObject *result; /* Objet à retourner */ \ + result = python_abstract_constructor_with_dynamic_gtype(type, gbase, (GClassInitFunc)cinit, \ + args, kwds); \ + return result; \ +} + + /* Marque l'interdiction d'une instanciation depuis Python. */ PyObject *no_python_constructor_allowed(PyTypeObject *, PyObject *, PyObject *); @@ -200,16 +225,13 @@ PyTypeObject *define_python_dynamic_type(const PyTypeObject *); /* Enregistre correctement une surcouche de conversion GObject. */ -bool _register_class_for_pygobject(PyObject *, GType, PyTypeObject *, PyTypeObject *, ...); - -#define register_class_for_pygobject(dict, gtype, type, base) \ - _register_class_for_pygobject(dict, gtype, type, base, NULL) +bool register_class_for_pygobject(PyObject *, GType, PyTypeObject *); /* Enregistre correctement une interface GObject pour Python. */ bool register_interface_for_pygobject(PyObject *, GType, PyTypeObject *, const GInterfaceInfo *); /* Enregistre un type Python dérivant d'un type GLib dynamique. */ -bool register_class_for_dynamic_pygobject(GType, PyTypeObject *, PyTypeObject *); +bool register_class_for_dynamic_pygobject(GType, PyTypeObject *); /* Fait suivre à la partie GObject une initialisation nouvelle. */ int forward_pygobjet_init(PyObject *); @@ -220,12 +242,36 @@ int convert_to_gtype(PyObject *, void *); /* Tente de convertir en instance GObject. */ int convert_to_gobject(PyObject *, void *); +#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 + +/** + * Copie depuis /usr/include/gtk-3.0/gdk/gdkrgba.h + */ +typedef struct _GdkRGBA +{ + gdouble red; + gdouble green; + gdouble blue; + gdouble alpha; + +} GdkRGBA; + +#endif + + /* Construit un objet Python pour une couleur RGBA. */ PyObject *create_gdk_rgba(const GdkRGBA *); @@ -261,6 +307,41 @@ int convert_to_gdk_rgba(PyObject *, void *); }) +#define TRANSLATE_NUMERIC_FIELD(dict, base, field) \ + ({ \ + PyObject *__attrib; \ + __attrib = PyLong_FromUnsignedLongLong(base->field); \ + Py_INCREF(__attrib); \ + ADD_FIELD_TRANSLATION(dict, #field, __attrib); \ + }) + + +#define RETRIEVE_NUMERIC_FIELD(dict, base, field) \ + ({ \ + bool __status; \ + PyObject *__attrib; \ + __status = false; \ + __attrib = PyDict_GetItemString(dict, #field); \ + if (__attrib != NULL && PyLong_Check(__attrib)) \ + { \ + base->field = PyLong_AsUnsignedLongLong(__attrib); \ + __status = (PyErr_Occurred() == NULL); \ + } \ + __status; \ + }) + + +#define TRANSLATE_BYTES_FIELD(dict, base, field, len) \ + ({ \ + void *__data; \ + PyObject *__attrib; \ + __data = (void *)&base->field; \ + __attrib = PyBytes_FromStringAndSize(__data, len); \ + Py_INCREF(__attrib); \ + ADD_FIELD_TRANSLATION(dict, #field, __attrib); \ + }) + + #define TRANSLATE_STRING_FIELD(dict, base, field) \ ({ \ PyObject *__attrib; \ @@ -308,20 +389,46 @@ int convert_to_gdk_rgba(PyObject *, void *); }) /* Officialise un groupe de constantes avec sémentique. */ -bool _attach_constants_group(const char *, PyObject *, bool, const char *, PyObject *, const char *); - -#define attach_constants_group_to_type(type, flags, name, values, doc) \ - _attach_constants_group(type->tp_name, type->tp_dict, flags, name, values, doc) - -#define attach_constants_group_to_module(mod, flags, name, values, doc) \ - ({ \ - bool __result; \ - const char *__owner; \ - PyObject *__dict; \ - __owner = PyModule_GetName(mod); \ - __dict = PyModule_GetDict(mod); \ - __result = _attach_constants_group(__owner, __dict, flags, name, values, doc); \ - __result; \ +PyObject *_attach_constants_group(const char *, PyObject *, bool, const char *, PyObject *, const char *); + +#define attach_constants_group_to_type(type, flags, name, values, doc) \ + ({ \ + bool __result; \ + PyObject *__new; \ + __new = _attach_constants_group(type->tp_name, type->tp_dict, flags, name, values, \ + doc); \ + __result = (__new != NULL); \ + Py_XDECREF(__new); \ + __result; \ + }) + +#define attach_constants_group_to_module(mod, flags, name, values, doc) \ + ({ \ + bool __result; \ + const char *__owner; \ + PyObject *__dict; \ + PyObject *__new; \ + __owner = PyModule_GetName(mod); \ + __dict = PyModule_GetDict(mod); \ + __new = _attach_constants_group(__owner, __dict, flags, name, values, doc); \ + __result = (__new != NULL); \ + Py_XDECREF(__new); \ + __result; \ + }) + +/* Officialise un groupe de constantes avec lien GLib. */ +PyObject *_attach_constants_group_with_pyg_enum(const char *, PyObject *, bool, const char *, PyObject *, const char *, GType); + + +#define attach_constants_group_to_type_with_pyg_enum(type, flags, name, values, doc, gtype) \ + ({ \ + bool __result; \ + PyObject *__new; \ + __new = _attach_constants_group_with_pyg_enum(type->tp_name, type->tp_dict, flags, \ + name, values, doc, gtype); \ + __result = (__new != NULL); \ + Py_XDECREF(__new); \ + __result; \ }) /* Traduit une valeur constante C en équivalent Python. */ diff --git a/plugins/pychrysalide/mangling/Makefile.am b/plugins/pychrysalide/mangling/Makefile.am index bec4baf..640e420 100644 --- a/plugins/pychrysalide/mangling/Makefile.am +++ b/plugins/pychrysalide/mangling/Makefile.am @@ -1,23 +1,14 @@ noinst_LTLIBRARIES = libpychrysamangling.la -libpychrysamangling_la_SOURCES = \ - demangler.h demangler.c \ +libpychrysamangling_la_SOURCES = \ + demangler.h demangler.c \ module.h module.c -libpychrysamangling_la_LIBADD = - -libpychrysamangling_la_LDFLAGS = +libpychrysamangling_la_CFLAGS = $(TOOLKIT_CFLAGS) $(LIBXML_CFLAGS) $(LIBPYTHON_INTERPRETER_CFLAGS) $(LIBPYGOBJECT_CFLAGS) \ + -I$(top_srcdir)/src -DNO_IMPORT_PYGOBJECT devdir = $(includedir)/chrysalide/$(subdir) dev_HEADERS = $(libpychrysamangling_la_SOURCES:%c=) - - -AM_CPPFLAGS = $(LIBGTK_CFLAGS) $(LIBXML_CFLAGS) $(LIBPYTHON_CFLAGS) $(LIBPYGOBJECT_CFLAGS) \ - -I$(top_srcdir)/src - -AM_CFLAGS = $(DEBUG_CFLAGS) $(WARNING_FLAGS) $(COMPLIANCE_FLAGS) - -SUBDIRS = diff --git a/plugins/pychrysalide/mangling/demangler.c b/plugins/pychrysalide/mangling/demangler.c index 87a19dc..fb90dca 100644 --- a/plugins/pychrysalide/mangling/demangler.c +++ b/plugins/pychrysalide/mangling/demangler.c @@ -25,6 +25,7 @@ #include "demangler.h" +#include <malloc.h> #include <pygobject.h> @@ -41,6 +42,9 @@ +/* Fournit la désignation interne du décodeur de désignations. */ +static PyObject *py_compiler_demangler_get_key(PyObject *, void *); + /* Tente de décoder une chaîne de caractères donnée en type. */ static PyObject *py_compiler_demangler_decode_type(PyObject *, PyObject *); @@ -51,6 +55,53 @@ static PyObject *py_compiler_demangler_decode_routine(PyObject *, PyObject *); /****************************************************************************** * * +* Paramètres : self = objet Python concerné par l'appel. * +* closure = non utilisé ici. * +* * +* Description : Fournit la désignation interne du décodeur de désignations. * +* * +* Retour : Simple chaîne de caractères. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static PyObject *py_compiler_demangler_get_key(PyObject *self, void *closure) +{ + PyObject *result; /* Instance Python à retourner */ + GCompDemangler *demangler; /* Version GLib de l'opérande */ + char *key; /* Désignation du décodeur */ + +#define COMPILER_DEMANGLER_KEY_ATTRIB PYTHON_GET_DEF_FULL \ +( \ + key, py_compiler_demangler, \ + "Provide the small name used to identify the demangler," \ + " as a code string." \ +) + + demangler = G_COMP_DEMANGLER(pygobject_get(self)); + assert(demangler != NULL); + + key = g_compiler_demangler_get_key(demangler); + + if (key != NULL) + { + result = PyUnicode_FromString(key); + free(key); + } + else + { + result = Py_None; + Py_INCREF(result); + } + + return result; + +} + + +/****************************************************************************** +* * * Paramètres : self = décodeur à solliciter pour l'opération. * * args = chaîne de caractères à décoder. * * * @@ -184,6 +235,7 @@ PyTypeObject *get_python_compiler_demangler_type(void) }; static PyGetSetDef py_comp_demangler_getseters[] = { + COMPILER_DEMANGLER_KEY_ATTRIB, { NULL } }; @@ -212,7 +264,7 @@ PyTypeObject *get_python_compiler_demangler_type(void) * * * Paramètres : module = module dont la définition est à compléter. * * * -* Description : Prend en charge l'objet 'pychrysalide.mangling.DexDemangler'.* +* Description : Prend en charge l'objet 'pychrysalide....CompDemangler'. * * * * Retour : Bilan de l'opération. * * * @@ -234,7 +286,7 @@ bool ensure_python_compiler_demangler_is_registered(void) dict = PyModule_GetDict(module); - if (!register_class_for_pygobject(dict, G_TYPE_COMP_DEMANGLER, type, &PyGObject_Type)) + if (!register_class_for_pygobject(dict, G_TYPE_COMP_DEMANGLER, type)) return false; } diff --git a/plugins/pychrysalide/mangling/demangler.h b/plugins/pychrysalide/mangling/demangler.h index 0c31f7c..496aa21 100644 --- a/plugins/pychrysalide/mangling/demangler.h +++ b/plugins/pychrysalide/mangling/demangler.h @@ -34,7 +34,7 @@ /* Fournit un accès à une définition de type à diffuser. */ PyTypeObject *get_python_compiler_demangler_type(void); -/* Prend en charge l'objet 'pychrysalide.format.elf.ElfFormat'. */ +/* Prend en charge l'objet 'pychrysalide.mangling.CompDemangler'. */ bool ensure_python_compiler_demangler_is_registered(void); diff --git a/plugins/pychrysalide/plugins/Makefile.am b/plugins/pychrysalide/plugins/Makefile.am index 8a0d4c9..bb9ed5d 100644 --- a/plugins/pychrysalide/plugins/Makefile.am +++ b/plugins/pychrysalide/plugins/Makefile.am @@ -1,25 +1,16 @@ noinst_LTLIBRARIES = libpychrysaplugins.la -libpychrysaplugins_la_SOURCES = \ - constants.h constants.c \ - plugin.h plugin.c \ - module.h module.c \ +libpychrysaplugins_la_SOURCES = \ + constants.h constants.c \ + plugin.h plugin.c \ + module.h module.c \ translate.h translate.c -libpychrysaplugins_la_LIBADD = - -libpychrysaplugins_la_LDFLAGS = +libpychrysaplugins_la_CFLAGS = $(TOOLKIT_CFLAGS) $(LIBXML_CFLAGS) $(LIBPYTHON_INTERPRETER_CFLAGS) $(LIBPYGOBJECT_CFLAGS) \ + -I$(top_srcdir)/src -DNO_IMPORT_PYGOBJECT devdir = $(includedir)/chrysalide/$(subdir) dev_HEADERS = $(libpychrysaplugins_la_SOURCES:%c=) - - -AM_CPPFLAGS = $(LIBGTK_CFLAGS) $(LIBXML_CFLAGS) $(LIBPYTHON_CFLAGS) $(LIBPYGOBJECT_CFLAGS) \ - -I$(top_srcdir)/src - -AM_CFLAGS = $(DEBUG_CFLAGS) $(WARNING_FLAGS) $(COMPLIANCE_FLAGS) - -SUBDIRS = diff --git a/plugins/pychrysalide/plugins/plugin.c b/plugins/pychrysalide/plugins/plugin.c index bd9cdfe..b013345 100644 --- a/plugins/pychrysalide/plugins/plugin.c +++ b/plugins/pychrysalide/plugins/plugin.c @@ -51,21 +51,31 @@ /* ------------------------ GLUE POUR CREATION DEPUIS PYTHON ------------------------ */ -/* Accompagne la création d'une instance dérivée en Python. */ -static PyObject *py_plugin_module_new(PyTypeObject *, PyObject *, PyObject *); - /* Initialise la classe des greffons d'extension. */ static void py_plugin_module_init_gclass(GPluginModuleClass *, gpointer); +CREATE_DYN_ABSTRACT_CONSTRUCTOR(plugin_module, G_TYPE_PLUGIN_MODULE, py_plugin_module_init_gclass); + /* Initialise une instance sur la base du dérivé de GObject. */ static int py_plugin_module_init(PyObject *self, PyObject *args, PyObject *kwds); /* Encadre une étape de la vie d'un greffon. */ static bool py_plugin_module_manage_wrapper(GPluginModule *); +/* Assiste la désactivation d'un greffon. */ +static bool py_plugin_module_exit(GPluginModule *); + /* Accompagne la fin du chargement des modules natifs. */ static void py_plugin_module_notify_plugins_loaded_wrapper(GPluginModule *, PluginAction); +/* Fournit le nom brut associé au greffon par défaut. */ +static PyObject *py_plugin_module_get_modname_by_default(PyObject *, PyObject *); + +/* Fournit le nom brut associé au greffon. */ +static char *py_plugin_module_get_modname_wrapper(const GPluginModule *); + +#ifdef INCLUDE_GTK_SUPPORT + /* Complète une liste de resources pour thème. */ static void py_plugin_module_include_theme_wrapper(const GPluginModule *, PluginAction, gboolean, char ***, size_t *); @@ -75,6 +85,8 @@ static void py_plugin_module_notify_panel_creation_wrapper(const GPluginModule * /* Rend compte d'un affichage ou d'un retrait de panneau. */ static void py_plugin_module_notify_panel_docking_wrapper(const GPluginModule *, PluginAction, GPanelItem *, bool); +#endif + /* Procède à une opération liée à un contenu binaire. */ static void py_plugin_module_handle_binary_content_wrapper(const GPluginModule *, PluginAction, GBinContent *, wgroup_id_t, GtkStatusStack *); @@ -98,42 +110,6 @@ static void py_plugin_module_detect_external_tools_wrapper(const GPluginModule * -/* --------------------- INTERFACE INTERNE POUR GREFFONS PYTHON --------------------- */ - - -/* Ligne de représentation de code binaire (instance) */ -struct _GPythonPlugin -{ - GPluginModule parent; /* Instance parente */ - -}; - - -/* Ligne de représentation de code binaire (classe) */ -struct _GPythonPluginClass -{ - GPluginModuleClass parent; /* Classe parente */ - -}; - - -/* Initialise la classe des greffons Python. */ -static void g_python_plugin_class_init(GPythonPluginClass *); - -/* Initialise l'instance d'un greffon Python. */ -static void g_python_plugin_init(GPythonPlugin *); - -/* Supprime toutes les références externes. */ -static void g_python_plugin_dispose(GPythonPlugin *); - -/* Description : Procède à la libération totale de la mémoire. */ -static void g_python_plugin_finalize(GPythonPlugin *); - -/* Fournit le nom brut associé au greffon. */ -static char *g_python_plugin_get_modname(const GPythonPlugin *); - - - /* ------------------------- MODULE PYTHON POUR LES SCRIPTS ------------------------- */ @@ -161,69 +137,6 @@ static PyObject *py_plugin_module_get_interface(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_plugin_module_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_plugin_module_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_PYTHON_PLUGIN, type->tp_name, - (GClassInitFunc)py_plugin_module_init_gclass, NULL, NULL); - - if (first_time) - { - status = register_class_for_dynamic_pygobject(gtype, type, base); - - 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. * * * @@ -239,13 +152,17 @@ static void py_plugin_module_init_gclass(GPluginModuleClass *class, gpointer unu { class->init = NULL; class->manage = py_plugin_module_manage_wrapper; - class->exit = NULL; + class->exit = py_plugin_module_exit; class->plugins_loaded = py_plugin_module_notify_plugins_loaded_wrapper; + class->get_modname = py_plugin_module_get_modname_wrapper; + +#ifdef INCLUDE_GTK_SUPPORT class->include_theme = py_plugin_module_include_theme_wrapper; class->notify_panel = py_plugin_module_notify_panel_creation_wrapper; class->notify_docking = py_plugin_module_notify_panel_docking_wrapper; +#endif class->handle_content = py_plugin_module_handle_binary_content_wrapper; class->handle_loaded = py_plugin_module_handle_loaded_content_wrapper; @@ -498,6 +415,51 @@ static bool py_plugin_module_manage_wrapper(GPluginModule *plugin) /****************************************************************************** * * * Paramètres : plugin = greffon à manipuler. * +* * +* Description : Assiste la désactivation d'un greffon. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static bool py_plugin_module_exit(GPluginModule *plugin) +{ + bool result; /* Bilan à faire remonter */ + plugin_interface *final; /* Interface finale conservée */ + + result = true; + + final = (plugin_interface *)G_PLUGIN_MODULE(plugin)->interface; + + if (final != NULL) + { + if (final->name != NULL) free(final->name); + if (final->desc != NULL) free(final->desc); + if (final->version != NULL) free(final->version); + if (final->url != NULL) free(final->url); + + assert(final->required_count == 1); + + if (final->required != NULL) + free(final->required); + + if (final->actions != NULL) + free(final->actions); + + free(final); + + } + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : plugin = greffon à manipuler. * * action = type d'action attendue. * * * * Description : Accompagne la fin du chargement des modules natifs. * @@ -555,6 +517,103 @@ static void py_plugin_module_notify_plugins_loaded_wrapper(GPluginModule *plugin /****************************************************************************** * * +* Paramètres : self = objet Python concerné par l'appel. * +* args = arguments fournis à l'appel. * +* * +* Description : Fournit le nom brut associé au greffon par défaut. * +* * +* Retour : Désignation brute du greffon. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static PyObject *py_plugin_module_get_modname_by_default(PyObject *self, PyObject *args) +{ + PyObject *result; /* Bilan à retourner */ + GPluginModule *plugin; /* Version native du greffon */ + char *path; /* Chemin à traiter */ + + plugin = G_PLUGIN_MODULE(pygobject_get(self)); + + path = strdup(g_plugin_module_get_filename(plugin)); + + result = PyUnicode_FromString(basename(path)); + + free(path); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : plugin = greffon à valider. * +* * +* Description : Fournit le nom brut associé au greffon. * +* * +* Retour : Désignation brute du greffon. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static char *py_plugin_module_get_modname_wrapper(const GPluginModule *plugin) +{ + char *result; /* Désignation brute à renvoyer*/ + PyGILState_STATE gstate; /* Sauvegarde d'environnement */ + PyObject *pyobj; /* Objet Python concerné */ + PyObject *pyret; /* Bilan d'exécution */ + +#define PLUGIN_MODULE_GET_MODNAME_WRAPPER PYTHON_WRAPPER_DEF_WITH \ +( \ + _get_modname, "$self, /", \ + METH_VARARGS, py_plugin_module_get_modname_by_default, \ + "(Abstract) method providing the raw module name of the plugin.\n" \ + " loaded.\n" \ + "\n" \ + "The result should be a short string value.\n" \ + "\n" \ + "A default implementation builds the module name from the Python" \ + " script filename." \ +) + + result = NULL; + + gstate = PyGILState_Ensure(); + + pyobj = pygobject_new(G_OBJECT(plugin)); + + if (has_python_method(pyobj, "_get_modname")) + { + pyret = run_python_method(pyobj, "_get_modname", NULL); + + if (!PyUnicode_Check(pyret)) + g_plugin_module_log_variadic_message(plugin, 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; + +} + + +#ifdef INCLUDE_GTK_SUPPORT + + +/****************************************************************************** +* * * Paramètres : plugin = greffon à manipuler. * * action = type d'action attendue. * * dark = indique une préférence pour la variante foncée. * @@ -783,6 +842,9 @@ static void py_plugin_module_notify_panel_docking_wrapper(const GPluginModule *p } +#endif + + /****************************************************************************** * * * Paramètres : plugin = greffon à manipuler. * @@ -1300,262 +1362,6 @@ static void py_plugin_module_detect_external_tools_wrapper(const GPluginModule * /* ---------------------------------------------------------------------------------- */ -/* INTERFACE INTERNE POUR GREFFONS PYTHON */ -/* ---------------------------------------------------------------------------------- */ - - -/* Indique le type défini par la GLib pour le greffon Python. */ -G_DEFINE_TYPE(GPythonPlugin, g_python_plugin, G_TYPE_PLUGIN_MODULE); - - -/****************************************************************************** -* * -* Paramètres : klass = classe à initialiser. * -* * -* Description : Initialise la classe des greffons Python. * -* * -* Retour : - * -* * -* Remarques : - * -* * -******************************************************************************/ - -static void g_python_plugin_class_init(GPythonPluginClass *klass) -{ - GObjectClass *object; /* Autre version de la classe */ - GPluginModuleClass *plugin; /* Version parente de la classe*/ - - object = G_OBJECT_CLASS(klass); - - object->dispose = (GObjectFinalizeFunc/* ! */)g_python_plugin_dispose; - object->finalize = (GObjectFinalizeFunc)g_python_plugin_finalize; - - plugin = G_PLUGIN_MODULE_CLASS(klass); - - plugin->get_modname = (pg_get_modname_fc)g_python_plugin_get_modname; - -} - - -/****************************************************************************** -* * -* Paramètres : plugin = instance à initialiser. * -* * -* Description : Initialise l'instance d'un greffon Python. * -* * -* Retour : - * -* * -* Remarques : - * -* * -******************************************************************************/ - -static void g_python_plugin_init(GPythonPlugin *plugin) -{ - -} - - -/****************************************************************************** -* * -* Paramètres : plugin = instance d'objet GLib à traiter. * -* * -* Description : Supprime toutes les références externes. * -* * -* Retour : - * -* * -* Remarques : - * -* * -******************************************************************************/ - -static void g_python_plugin_dispose(GPythonPlugin *plugin) -{ -#if 0 - PyThreadState *tstate; /* Contexte d'environnement */ - - /** - * Cf. https://docs.python.org/3/c-api/init.html#thread-state-and-the-global-interpreter-lock - * - * Cependant, comme on se trouve à priori dans le thread principal de l'interpréteur, - * PyGILState_Ensure() ne pose aucun verrou. Ce qui aboutit à la situation suivante : - * - * Fatal Python error: drop_gil: GIL is not locked - * - * On peut forcer les choses avec PyEval_AcquireLock(), mais cette fonction est marquée - * comme dépréciée depuis Python 3.2. - * - * Donc on choisit les alternatives officielles. - * - * Cependant, PyThreadState_Get() renvoit l'erreur suivante : - * - * Fatal Python error: PyThreadState_Get: no current thread - * - * Donc on se rabat sur une sauvegarde, qui n'est initialisée que lorsque l'interpréteur - * est intégré dans l'éditeur. - */ - - tstate = get_pychrysalide_main_tstate(); - - if (tstate != NULL) - PyEval_RestoreThread(tstate); - - if (tstate != NULL) - PyEval_SaveThread(); -#endif - - G_OBJECT_CLASS(g_python_plugin_parent_class)->dispose(G_OBJECT(plugin)); - -} - - -/****************************************************************************** -* * -* Paramètres : plugin = instance d'objet GLib à traiter. * -* * -* Description : Procède à la libération totale de la mémoire. * -* * -* Retour : - * -* * -* Remarques : - * -* * -******************************************************************************/ - -static void g_python_plugin_finalize(GPythonPlugin *plugin) -{ - plugin_interface *final; /* Interface finale conservée */ - - final = (plugin_interface *)G_PLUGIN_MODULE(plugin)->interface; - - if (final != NULL) - { - if (final->name != NULL) free(final->name); - if (final->desc != NULL) free(final->desc); - if (final->version != NULL) free(final->version); - if (final->url != NULL) free(final->url); - - assert(final->required_count == 1); - - if (final->required != NULL) - free(final->required); - - if (final->actions != NULL) - free(final->actions); - - free(final); - - } - - G_OBJECT_CLASS(g_python_plugin_parent_class)->finalize(G_OBJECT(plugin)); - -} - - -/****************************************************************************** -* * -* Paramètres : plugin = greffon à valider. * -* * -* Description : Fournit le nom brut associé au greffon. * -* * -* Retour : Désignation brute du greffon. * -* * -* Remarques : - * -* * -******************************************************************************/ - -static char *g_python_plugin_get_modname(const GPythonPlugin *plugin) -{ - char *result; /* Désignation brute à renvoyer*/ - char *path; /* Chemin à traiter */ - - path = strdup(g_plugin_module_get_filename(G_PLUGIN_MODULE(plugin))); - - result = strdup(basename(path)); - - free(path); - - return result; - -} - - -/****************************************************************************** -* * -* Paramètres : modname = nom du module à charger. * -* filename = chemin d'accès au code Python à charger. * -* * -* Description : Crée un greffon à partir de code Python. * -* * -* Retour : Adresse de la structure mise en place ou NULL si erreur. * -* * -* Remarques : - * -* * -******************************************************************************/ - -GPluginModule *g_python_plugin_new(const char *modname, const char *filename) -{ - GPythonPlugin *result; /* Structure à retourner */ - PyObject *name; /* Chemin d'accès pour Python */ - PyObject *module; /* Script Python chargé */ - PyObject *dict; /* Dictionnaire associé */ - PyObject *class; /* Classe à instancier */ - PyObject *instance; /* Instance Python du greffon */ - - name = PyUnicode_FromString(modname); - if (name == NULL) goto bad_exit; - - module = PyImport_Import(name); - Py_DECREF(name); - - if (module == NULL) goto no_import; - - dict = PyModule_GetDict(module); - class = PyDict_GetItemString(dict, "AutoLoad"); - - if (class == NULL) goto no_class; - if (!PyType_Check(class->ob_type)) goto no_class; - - instance = PyObject_CallFunction(class, NULL); - if (instance == NULL) goto no_instance; - - result = G_PYTHON_PLUGIN(pygobject_get(instance)); - - G_PLUGIN_MODULE(result)->filename = strdup(filename); - - /** - * L'instance Python et l'objet GLib résultante sont un même PyGObject. - * - * Donc pas besoin de toucher au comptage des références ici, la libération - * se réalisera à la fin, quand l'objet GLib sera libéré. - */ - - Py_DECREF(module); - - return G_PLUGIN_MODULE(result); - - no_instance: - - log_pychrysalide_exception(_("An error occured when building the 'AutoLoad' instance")); - - no_class: - - if (class == NULL) - log_plugin_simple_message(LMT_ERROR, - _("An error occured when looking for the 'AutoLoad': item not found!")); - - no_import: - - Py_XDECREF(module); - - log_pychrysalide_exception(_("An error occured when importing '%s'"), modname); - - bad_exit: - - return NULL; - -} - - - -/* ---------------------------------------------------------------------------------- */ /* MODULE PYTHON POUR LES SCRIPTS */ /* ---------------------------------------------------------------------------------- */ @@ -1865,9 +1671,12 @@ PyTypeObject *get_python_plugin_module_type(void) static PyMethodDef py_plugin_module_methods[] = { PLUGIN_MODULE_MANAGE_WRAPPER, PLUGIN_MODULE_NOTIFY_PLUGINS_LOADED_WRAPPER, + PLUGIN_MODULE_GET_MODNAME_WRAPPER, +#ifdef INCLUDE_GTK_SUPPORT PLUGIN_MODULE_INCLUDE_THEME_WRAPPER, PLUGIN_MODULE_ON_PANEL_CREATION_WRAPPER, PLUGIN_MODULE_ON_PANEL_DOCKING_WRAPPER, +#endif PLUGIN_MODULE_HANDLE_BINARY_CONTENT_WRAPPER, PLUGIN_MODULE_HANDLE_LOADED_CONTENT_WRAPPER, PLUGIN_MODULE_HANDLE_BINARY_FORMAT_ANALYSIS_WRAPPER, @@ -1938,7 +1747,7 @@ bool ensure_python_plugin_module_is_registered(void) dict = PyModule_GetDict(module); - if (!register_class_for_pygobject(dict, G_TYPE_PYTHON_PLUGIN, type, &PyGObject_Type)) + if (!register_class_for_pygobject(dict, G_TYPE_PLUGIN_MODULE, type)) return false; if (!define_plugin_module_constants(type)) @@ -1949,3 +1758,80 @@ bool ensure_python_plugin_module_is_registered(void) return true; } + + +/****************************************************************************** +* * +* Paramètres : modname = nom du module à charger. * +* filename = chemin d'accès au code Python à charger. * +* * +* Description : Crée un greffon à partir de code Python. * +* * +* Retour : Adresse de la structure mise en place ou NULL si erreur. * +* * +* Remarques : - * +* * +******************************************************************************/ + +GPluginModule *create_python_plugin(const char *modname, const char *filename) +{ + GPluginModule *result; /* Structure à retourner */ + PyObject *name; /* Chemin d'accès pour Python */ + PyObject *module; /* Script Python chargé */ + PyObject *dict; /* Dictionnaire associé */ + PyObject *class; /* Classe à instancier */ + PyObject *instance; /* Instance Python du greffon */ + + name = PyUnicode_FromString(modname); + if (name == NULL) goto bad_exit; + + module = PyImport_Import(name); + Py_DECREF(name); + + if (module == NULL) goto no_import; + + dict = PyModule_GetDict(module); + class = PyDict_GetItemString(dict, "AutoLoad"); + + if (class == NULL) goto no_class; + if (!PyType_Check(class->ob_type)) goto no_class; + + instance = PyObject_CallFunction(class, NULL); + if (instance == NULL) goto no_instance; + + result = G_PLUGIN_MODULE(pygobject_get(instance)); + + result->filename = strdup(filename); + + /** + * L'instance Python et l'objet GLib résultante sont un même PyGObject. + * + * Donc pas besoin de toucher au comptage des références ici, la libération + * se réalisera à la fin, quand l'objet GLib sera libéré. + */ + + Py_DECREF(module); + + return result; + + no_instance: + + log_pychrysalide_exception(_("An error occured when building the 'AutoLoad' instance")); + + no_class: + + if (class == NULL) + log_plugin_simple_message(LMT_ERROR, + _("An error occured when looking for the 'AutoLoad': item not found!")); + + no_import: + + Py_XDECREF(module); + + log_pychrysalide_exception(_("An error occured when importing '%s'"), modname); + + bad_exit: + + return NULL; + +} diff --git a/plugins/pychrysalide/plugins/plugin.h b/plugins/pychrysalide/plugins/plugin.h index ff805f4..ad54b8e 100644 --- a/plugins/pychrysalide/plugins/plugin.h +++ b/plugins/pychrysalide/plugins/plugin.h @@ -35,41 +35,15 @@ -/* --------------------- INTERFACE INTERNE POUR GREFFONS PYTHON --------------------- */ - - -#define G_TYPE_PYTHON_PLUGIN (g_python_plugin_get_type()) -#define G_PYTHON_PLUGIN(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_PYTHON_PLUGIN, GPythonPlugin)) -#define G_IS_PYTHON_PLUGIN(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_PYTHON_PLUGIN)) -#define G_PYTHON_PLUGIN_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_PYTHON_PLUGIN, GPythonPluginClass)) -#define G_IS_PYTHON_PLUGIN_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_PYTHON_PLUGIN)) -#define G_PYTHON_PLUGIN_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_PYTHON_PLUGIN, GPythonPluginClass)) - - -/* Ligne de représentation de code binaire (instance) */ -typedef struct _GPythonPlugin GPythonPlugin; - -/* Ligne de représentation de code binaire (classe) */ -typedef struct _GPythonPluginClass GPythonPluginClass; - - -/* Indique le type défini par la GLib pour le greffon Python. */ -GType g_python_plugin_get_type(void); - -/* Crée un greffon à partir de code Python. */ -GPluginModule *g_python_plugin_new(const char *, const char *); - - - -/* ------------------------- MODULE PYTHON POUR LES SCRIPTS ------------------------- */ - - /* Fournit un accès à une définition de type à diffuser. */ PyTypeObject *get_python_plugin_module_type(void); /* Prend en charge l'objet 'pychrysalide.plugins.PluginModule'. */ bool ensure_python_plugin_module_is_registered(void); +/* Crée un greffon à partir de code Python. */ +GPluginModule *create_python_plugin(const char *, const char *); + #endif /* _PLUGINS_PYCHRYSALIDE_PLUGINS_PLUGIN_H */ diff --git a/plugins/pychrysalide/weak.h b/plugins/pychrysalide/weak.h index 01885b0..767873f 100644 --- a/plugins/pychrysalide/weak.h +++ b/plugins/pychrysalide/weak.h @@ -26,10 +26,10 @@ #define _PLUGINS_PYCHRYSALIDE_WEAK_H -#include <gtkext/gtkstatusstack.h> - +#include <glibext/notifier.h> +#if 0 /* Démarre le suivi d'une nouvelle activité. */ activity_id_t gtk_status_stack_add_activity(GtkStatusStack *, const char *, unsigned long) __attribute__((weak)); @@ -44,7 +44,7 @@ void gtk_status_stack_update_activity_value(GtkStatusStack *, activity_id_t, uns /* Met fin au suivi d'une activité donnée. */ void gtk_status_stack_remove_activity(GtkStatusStack *, activity_id_t) __attribute__((weak)); - +#endif #endif /* _PLUGINS_PYCHRYSALIDE_WEAK_H */ |