diff options
Diffstat (limited to 'plugins/pychrysalide')
184 files changed, 13671 insertions, 2843 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 2f8af5f..6599ecc 100644 --- a/plugins/pychrysalide/analysis/binary.c +++ b/plugins/pychrysalide/analysis/binary.c @@ -124,27 +124,23 @@ 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  */ -    GHubClient *client;                     /* Eventuel client en place    */ +    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"                                                                \ +    "The returned object is a pychrysalide.analysis.db.AnalystClient"   \ +    " 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)      { @@ -566,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 fdf491e..a0dcc0d 100644 --- a/plugins/pychrysalide/analysis/db/Makefile.am +++ b/plugins/pychrysalide/analysis/db/Makefile.am @@ -1,19 +1,22 @@  noinst_LTLIBRARIES = libpychrysaanalysisdb.la -libpychrysaanalysisdb_la_SOURCES =		\ -	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) @@ -21,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 new file mode 100644 index 0000000..10a150e --- /dev/null +++ b/plugins/pychrysalide/analysis/db/admin.c @@ -0,0 +1,317 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * admin.c - équivalent Python du fichier "analysis/db/admin.c" + * + * Copyright (C) 2019 Cyrille Bagard + * + *  This file is part of Chrysalide. + * + *  Chrysalide is free software; you can redistribute it and/or modify + *  it under the terms of the GNU General Public License as published by + *  the Free Software Foundation; either version 3 of the License, or + *  (at your option) any later version. + * + *  Chrysalide is distributed in the hope that it will be useful, + *  but WITHOUT ANY WARRANTY; without even the implied warranty of + *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + *  GNU General Public License for more details. + * + *  You should have received a copy of the GNU General Public License + *  along with this program; if not, write to the Free Software + *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA + */ + + +#include "admin.h" + + +#include <assert.h> +#include <pygobject.h> + + +#include <i18n.h> +#include <analysis/db/admin.h> + + +#include "client.h" +#include "../../access.h" +#include "../../helpers.h" + + + +/* Crée un nouvel objet Python de type 'AdminClient'. */ +static PyObject *py_admin_client_new(PyTypeObject *, PyObject *, PyObject *); + +/* Effectue une demande de liste de binaires existants. */ +static PyObject *py_admin_client_request_existing_binaries(PyObject *, PyObject *); + +/* Fournit la liste des instantanés existants. */ +static PyObject *py_admin_client_get_existing_binaries(PyObject *, void *); + + + +/****************************************************************************** +*                                                                             * +*  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 'AdminClient'.           * +*                                                                             * +*  Retour      : Instance Python mise en place.                               * +*                                                                             * +*  Remarques   : -                                                            * +*                                                                             * +******************************************************************************/ + +static PyObject *py_admin_client_new(PyTypeObject *type, PyObject *args, PyObject *kwds) +{ +    PyObject *result;                       /* Instance à retourner        */ +    GAdminClient *client;                   /* Serveur mis en place        */ + +#define ADMIN_CLIENT_DOC                                                                \ +    "AdminClient provides control of the registered binary contents available from a"   \ +    " server.\n"                                                                        \ +    "\n"                                                                                \ +    "Such clients must be authenticated and communications are encrypted using TLS.\n"  \ +    "\n"                                                                                \ +    "Instances can be created using the following constructor:\n"                       \ +    "\n"                                                                                \ +    "    AdminClient()"                                                                 \ +    "\n"                                                                                \ +    "AdminClient instances emit the following signals:\n"                               \ +    "* 'existing-binaries-updated'\n"                                                   \ +    "    This signal is emitted when the list of existing binaries on server side"      \ +    " has been updated following a user request.\n"                                     \ + +    client = g_admin_client_new(); + +    if (client != NULL) +    { +        result = pygobject_new(G_OBJECT(client)); +        g_object_unref(client); +    } +    else result = NULL; + +    return result; + +} + + +/****************************************************************************** +*                                                                             * +*  Paramètres  : self = client à manipuler.                                   * +*                args = arguments d'appel non utilisés ici.                   * +*                                                                             * +*  Description : Effectue une demande de liste de binaires existants.         * +*                                                                             * +*  Retour      : True si la commande a bien été envoyée, False sinon.         * +*                                                                             * +*  Remarques   : -                                                            * +*                                                                             * +******************************************************************************/ + +static PyObject *py_admin_client_request_existing_binaries(PyObject *self, PyObject *args) +{ +    PyObject *result;                       /* Bilan à retourner           */ +    GAdminClient *client;                   /* Version native du serveur   */ +    bool status;                            /* Bilan de l'opération        */ + +#define ADMIN_CLIENT_REQUEST_EXISTING_BINARIES_METHOD PYTHON_METHOD_DEF \ +(                                                                       \ +    request_existing_binaries, "$self, /",                              \ +    METH_NOARGS, py_admin_client,                                       \ +    "Ask the server for a list of all existing analyzed binaries"       \ +    " and returns the status of the request transmission."              \ +    "\n"                                                                \ +    "A *existing-binaries-updated* signal is emitted when the"          \ +    " pychrysalide.analysis.db.AdminClient.existing_binaries attribute" \ +    " gets ready for reading."                                          \ +) + +    client = G_ADMIN_CLIENT(pygobject_get(self)); + +    status = g_admin_client_request_existing_binaries(client); + +    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 la liste des instantanés existants.                  * +*                                                                             * +*  Retour      : Liste de binaires en place, vide si aucun.                   * +*                                                                             * +*  Remarques   : -                                                            * +*                                                                             * +******************************************************************************/ + +static PyObject *py_admin_client_get_existing_binaries(PyObject *self, void *closure) +{ +    PyObject *result;                       /* Valeur à retourner          */ +    GAdminClient *client;                   /* Version native du serveur   */ +    size_t count;                           /* Taille de cette liste       */ +    char **binaries;                        /* Liste des binaires présents */ +    size_t i;                               /* Boucle de parcours          */ + +#define ADMIN_CLIENT_EXISTING_BINARIES_ATTRIB PYTHON_GET_DEF_FULL       \ +(                                                                       \ +    existing_binaries, py_admin_client,                                 \ +    "Provide the list of all exisiting binaries on the server side.\n"  \ +    "\n"                                                                \ +    "The returned value is a tuple of strings or an empty tuple."       \ +) + +    client = G_ADMIN_CLIENT(pygobject_get(self)); + +    binaries = g_admin_client_get_existing_binaries(client, &count); + +    result = PyTuple_New(count); + +    for (i = 0; i < count; i++) +        PyTuple_SetItem(result, i, PyUnicode_FromString(binaries[i])); + +    if (binaries != NULL) +        free(binaries); + +    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_admin_client_type(void) +{ +    static PyMethodDef py_admin_client_methods[] = { +        ADMIN_CLIENT_REQUEST_EXISTING_BINARIES_METHOD, +        { NULL } +    }; + +    static PyGetSetDef py_admin_client_getseters[] = { +        ADMIN_CLIENT_EXISTING_BINARIES_ATTRIB, +        { NULL } +    }; + +    static PyTypeObject py_admin_client_type = { + +        PyVarObject_HEAD_INIT(NULL, 0) + +        .tp_name        = "pychrysalide.analysis.db.AdminClient", +        .tp_basicsize   = sizeof(PyGObject), + +        .tp_flags       = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, + +        .tp_doc         = ADMIN_CLIENT_DOC, + +        .tp_methods     = py_admin_client_methods, +        .tp_getset      = py_admin_client_getseters, +        .tp_new         = py_admin_client_new, + +    }; + +    return &py_admin_client_type; + +} + + +/****************************************************************************** +*                                                                             * +*  Paramètres  : module = module dont la définition est à compléter.          * +*                                                                             * +*  Description : Prend en charge l'objet 'pychrysalide....db.AdminClient'.    * +*                                                                             * +*  Retour      : Bilan de l'opération.                                        * +*                                                                             * +*  Remarques   : -                                                            * +*                                                                             * +******************************************************************************/ + +bool ensure_python_admin_client_is_registered(void) +{ +    PyTypeObject *type;                     /* Type Python 'AdminClient'   */ +    PyObject *module;                       /* Module à recompléter        */ +    PyObject *dict;                         /* Dictionnaire du module      */ + +    type = get_python_admin_client_type(); + +    if (!PyType_HasFeature(type, Py_TPFLAGS_READY)) +    { +        module = get_access_to_python_module("pychrysalide.analysis.db"); + +        dict = PyModule_GetDict(module); + +        if (!ensure_python_hub_client_is_registered()) +            return false; + +        if (!register_class_for_pygobject(dict, G_TYPE_ADMIN_CLIENT, 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 client administrateur.                 * +*                                                                             * +*  Retour      : Bilan de l'opération, voire indications supplémentaires.     * +*                                                                             * +*  Remarques   : -                                                            * +*                                                                             * +******************************************************************************/ + +int convert_to_admin_client(PyObject *arg, void *dst) +{ +    int result;                             /* Bilan à retourner           */ + +    result = PyObject_IsInstance(arg, (PyObject *)get_python_admin_client_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 admin client"); +            break; + +        case 1: +            *((GAdminClient **)dst) = G_ADMIN_CLIENT(pygobject_get(arg)); +            break; + +        default: +            assert(false); +            break; + +    } + +    return result; + +} diff --git a/plugins/pychrysalide/analysis/db/admin.h b/plugins/pychrysalide/analysis/db/admin.h new file mode 100644 index 0000000..8a2dfeb --- /dev/null +++ b/plugins/pychrysalide/analysis/db/admin.h @@ -0,0 +1,45 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * admin.h - prototypes pour l'équivalent Python du fichier "analysis/db/admin.h" + * + * Copyright (C) 2019 Cyrille Bagard + * + *  This file is part of Chrysalide. + * + *  Chrysalide is free software; you can redistribute it and/or modify + *  it under the terms of the GNU General Public License as published by + *  the Free Software Foundation; either version 3 of the License, or + *  (at your option) any later version. + * + *  Chrysalide is distributed in the hope that it will be useful, + *  but WITHOUT ANY WARRANTY; without even the implied warranty of + *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + *  GNU General Public License for more details. + * + *  You should have received a copy of the GNU General Public License + *  along with 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_DB_ADMIN_H +#define _PLUGINS_PYCHRYSALIDE_ANALYSIS_DB_ADMIN_H + + +#include <Python.h> +#include <stdbool.h> + + + +/* Fournit un accès à une définition de type à diffuser. */ +PyTypeObject *get_python_admin_client_type(void); + +/* Prend en charge l'objet 'pychrysalide.analysis.db.AdminClient'. */ +bool ensure_python_admin_client_is_registered(void); + +/* Tente de convertir en client administrateur. */ +int convert_to_admin_client(PyObject *, void *); + + + +#endif  /* _PLUGINS_PYCHRYSALIDE_ANALYSIS_DB_ADMIN_H */ diff --git a/plugins/pychrysalide/analysis/db/analyst.c b/plugins/pychrysalide/analysis/db/analyst.c new file mode 100644 index 0000000..f2860ed --- /dev/null +++ b/plugins/pychrysalide/analysis/db/analyst.c @@ -0,0 +1,965 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * analyst.c - équivalent Python du fichier "analysis/db/analyst.c" + * + * Copyright (C) 2019 Cyrille Bagard + * + *  This file is part of Chrysalide. + * + *  Chrysalide is free software; you can redistribute it and/or modify + *  it under the terms of the GNU General Public License as published by + *  the Free Software Foundation; either version 3 of the License, or + *  (at your option) any later version. + * + *  Chrysalide is distributed in the hope that it will be useful, + *  but WITHOUT ANY WARRANTY; without even the implied warranty of + *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + *  GNU General Public License for more details. + * + *  You should have received a copy of the GNU General Public License + *  along with this program; if not, write to the Free Software + *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA + */ + + +#include "analyst.h" + + +#include <assert.h> +#include <pygobject.h> + + +#include <i18n.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" + + + +/* 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 *); + +/* Active les éléments en amont d'un horodatage donné. */ +static PyObject *py_analyst_client_set_last_active(PyObject *, PyObject *); + +/* Définit la désignation d'un instantané donné. */ +static PyObject *py_analyst_client_set_snapshot_name(PyObject *, PyObject *); + +/* Définit la désignation d'un instantané donné. */ +static PyObject *py_analyst_client_set_snapshot_desc(PyObject *, PyObject *); + +/* Restaure un ancien instantané. */ +static PyObject *py_analyst_client_restore_snapshot(PyObject *, PyObject *); + +/* Crée un nouvel instantané à partir d'un autre. */ +static PyObject *py_analyst_client_create_snapshot(PyObject *, PyObject *); + +/* Supprime un ancien instantané. */ +static PyObject *py_analyst_client_remove_snapshot(PyObject *, PyObject *); + +/* Fournit la liste des instantanés existants. */ +static PyObject *py_analyst_client_get_snapshots(PyObject *, void *); + +/* Fournit l'identifiant de l'instantané courant. */ +static PyObject *py_analyst_client_get_current_snapshot(PyObject *, void *); + + + +CREATE_DYN_CONSTRUCTOR(analyst_client, G_TYPE_ANALYST_CLIENT); + + +/****************************************************************************** +*                                                                             * +*  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_analyst_client_init(PyObject *self, PyObject *args, PyObject *kwds) +{ +    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 */ +    GList *collections;                     /* Liste native de collections */ +    Py_ssize_t i;                           /* Boucle de parcours          */ +    PyObject *item;                         /* Elément de la liste Python  */ +    GDbCollection *collec;                  /* Version équivalente native  */ +    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"        \ +    " to a server.\n"                                                                   \ +    "\n"                                                                                \ +    "Such clients must be authenticated and communications are encrypted using TLS.\n"  \ +    "\n"                                                                                \ +    "Instances can be created using the following constructor:\n"                       \ +    "\n"                                                                                \ +    "    AnalystClient(hash, class, list, loaded=None)"                                 \ +    "\n"                                                                                \ +    "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"                                                           \ +    "    This signal is emitted when the snapshot list has evolved.\n"                  \ +    "\n"                                                                                \ +    "    Handlers are expected to have only one argument: the client managing the"      \ +    "    updated snapshots.\n"                                                          \ +    "* 'snapshot-changed'\n"                                                            \ +    "    This signal is emitted when the identifier of the current snapshot changed.\n" \ +    "\n"                                                                                \ +    "    Handlers are expected to have only one argument: the client managing the"      \ +    "    snapshots." + +    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 -1; +    } + +    length = PySequence_Length(list); + +    collections = NULL; + +    for (i = 0; i < length; i++) +    { +        item = PySequence_GetItem(list, i); + +        ret = convert_to_db_collection(item, &collec); + +        Py_DECREF(item); + +        if (ret != 1) +        { +            delete_collections_list(&collections); +            result = -1; +            goto exit; +        } + +        g_object_ref(G_OBJECT(collec)); +        collections = g_list_append(collections, collec); + +    } + +    client = G_ANALYST_CLIENT(pygobject_get(self)); + +    status = g_analyst_client_setup(client, hash, class, collections, loaded); + +    result = status ? 0 : -1; + + exit: + +    return result; + +} + + +/****************************************************************************** +*                                                                             * +*  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.        * +*                                                                             * +*  Retour      : True si la commande a bien été envoyée, False sinon.         * +*                                                                             * +*  Remarques   : -                                                            * +*                                                                             * +******************************************************************************/ + +static PyObject *py_analyst_client_save(PyObject *self, PyObject *args) +{ +    PyObject *result;                       /* Bilan à retourner           */ +    GAnalystClient *client;                 /* Version native du serveur   */ +    bool status;                            /* Bilan de l'opération        */ + +#define ANALYST_CLIENT_SAVE_METHOD PYTHON_METHOD_DEF                        \ +(                                                                           \ +    save, "$self, /",                                                       \ +    METH_NOARGS, py_analyst_client,                                         \ +    "Ask the server for saving the current state of the analyzed binary"    \ +    " and returns the status of the request transmission."                  \ +) + +    client = G_ANALYST_CLIENT(pygobject_get(self)); + +    status = g_analyst_client_save(client); + +    result = status ? Py_True : Py_False; +    Py_INCREF(result); + +    return result; + +} + + +/****************************************************************************** +*                                                                             * +*  Paramètres  : self = client à manipuler.                                   * +*                args = arguments d'appel à consulter.                        * +*                                                                             * +*  Description : Active les éléments en amont d'un horodatage donné.          * +*                                                                             * +*  Retour      : True si la commande a bien été envoyée, False sinon.         * +*                                                                             * +*  Remarques   : -                                                            * +*                                                                             * +******************************************************************************/ + +static PyObject *py_analyst_client_set_last_active(PyObject *self, PyObject *args) +{ +    PyObject *result;                       /* Bilan à retourner           */ +    unsigned long long timestamp;           /* Horodatage de limite        */ +    int ret;                                /* Bilan de lecture des args.  */ +    GAnalystClient *client;                 /* Version native du serveur   */ +    bool status;                            /* Bilan de l'opération        */ + +#define ANALYST_CLIENT_SET_LAST_ACTIVE_METHOD PYTHON_METHOD_DEF         \ +(                                                                       \ +    set_last_active, "$self, timestamp, /",                             \ +    METH_VARARGS, py_analyst_client,                                    \ +    "Define the timestamp of the last active item in the collection"    \ +    " and returns the status of the request transmission."              \ +    "\n"                                                                \ +    "This method should not be used directly. Prefer calling"           \ +    " pychrysalide.analysis.LoadedBinary.set_last_active() instead,"    \ +    " as some items may be volatile and thus not handled by clients."   \ +) + +    ret = PyArg_ParseTuple(args, "K", ×tamp); +    if (!ret) return NULL; + +    client = G_ANALYST_CLIENT(pygobject_get(self)); + +    status = g_analyst_client_set_last_active(client, timestamp); + +    result = status ? Py_True : Py_False; +    Py_INCREF(result); + +    return result; + +} + + +/****************************************************************************** +*                                                                             * +*  Paramètres  : self = client à manipuler.                                   * +*                args = arguments d'appel à consulter.                        * +*                                                                             * +*  Description : Définit la désignation d'un instantané donné.                * +*                                                                             * +*  Retour      : True si la commande a bien été envoyée, False sinon.         * +*                                                                             * +*  Remarques   : -                                                            * +*                                                                             * +******************************************************************************/ + +static PyObject *py_analyst_client_set_snapshot_name(PyObject *self, PyObject *args) +{ +    PyObject *result;                       /* Bilan à retourner           */ +    const char *raw_id;                     /* Identifiant brut            */ +    const char *text;                       /* Texte fourni à transmettre  */ +    int ret;                                /* Bilan de lecture des args.  */ +    snapshot_id_t id;                       /* Identifiant utilisable      */ +    bool status;                            /* Bilan d'opération           */ +    GAnalystClient *client;                 /* Version native du serveur   */ + +#define ANALYST_CLIENT_SET_SNAPSHOT_NAME_METHOD PYTHON_METHOD_DEF           \ +(                                                                           \ +    set_snapshot_name, "$self, id, name, /",                                \ +    METH_VARARGS, py_analyst_client,                                        \ +    "Ask the server for defining a new name of for a snapshot using its"    \ +    " identifier and returns the status of the request transmission."       \ +    "\n"                                                                    \ +    "A 'snapshots-updated' signal is emitted once the request has been"     \ +    " processed with success."                                              \ +) + +    ret = PyArg_ParseTuple(args, "ss", &raw_id, &text); +    if (!ret) return NULL; + +    status = init_snapshot_id_from_text(&id, raw_id); +    if (!status) +    { +        PyErr_SetString(PyExc_TypeError, _("provided value is not a valid snapshot identifier.")); +        return NULL; +    } + +    client = G_ANALYST_CLIENT(pygobject_get(self)); + +    status = g_analyst_client_set_snapshot_name(client, &id, text); + +    result = status ? Py_True : Py_False; +    Py_INCREF(result); + +    return result; + +} + + +/****************************************************************************** +*                                                                             * +*  Paramètres  : self = client à manipuler.                                   * +*                args = arguments d'appel à consulter.                        * +*                                                                             * +*  Description : Définit la désignation d'un instantané donné.                * +*                                                                             * +*  Retour      : True si la commande a bien été envoyée, False sinon.         * +*                                                                             * +*  Remarques   : -                                                            * +*                                                                             * +******************************************************************************/ + +static PyObject *py_analyst_client_set_snapshot_desc(PyObject *self, PyObject *args) +{ +    PyObject *result;                       /* Bilan à retourner           */ +    const char *raw_id;                     /* Identifiant brut            */ +    const char *text;                       /* Texte fourni à transmettre  */ +    int ret;                                /* Bilan de lecture des args.  */ +    snapshot_id_t id;                       /* Identifiant utilisable      */ +    bool status;                            /* Bilan d'opération           */ +    GAnalystClient *client;                 /* Version native du serveur   */ + +#define ANALYST_CLIENT_SET_SNAPSHOT_DESC_METHOD PYTHON_METHOD_DEF           \ +(                                                                           \ +    set_snapshot_desc, "$self, id, desc, /",                                \ +    METH_VARARGS, py_analyst_client,                                        \ +    "Ask the server for defining a new description for a snapshot using"    \ +    " its identifier and returns the status of the request transmission."   \ +    "\n"                                                                    \ +    "A 'snapshots-updated' signal is emitted once the request has been"     \ +    " processed with success."                                              \ +) + +    ret = PyArg_ParseTuple(args, "ss", &raw_id, &text); +    if (!ret) return NULL; + +    status = init_snapshot_id_from_text(&id, raw_id); +    if (!status) +    { +        PyErr_SetString(PyExc_TypeError, _("provided value is not a valid snapshot identifier.")); +        return NULL; +    } + +    client = G_ANALYST_CLIENT(pygobject_get(self)); + +    status = g_analyst_client_set_snapshot_desc(client, &id, text); + +    result = status ? Py_True : Py_False; +    Py_INCREF(result); + +    return result; + +} + + +/****************************************************************************** +*                                                                             * +*  Paramètres  : self = client à manipuler.                                   * +*                args = arguments d'appel à consulter.                        * +*                                                                             * +*  Description : Restaure un ancien instantané.                               * +*                                                                             * +*  Retour      : True si la commande a bien été envoyée, False sinon.         * +*                                                                             * +*  Remarques   : -                                                            * +*                                                                             * +******************************************************************************/ + +static PyObject *py_analyst_client_restore_snapshot(PyObject *self, PyObject *args) +{ +    PyObject *result;                       /* Bilan à retourner           */ +    const char *raw_id;                     /* Identifiant brut            */ +    int ret;                                /* Bilan de lecture des args.  */ +    snapshot_id_t id;                       /* Identifiant utilisable      */ +    bool status;                            /* Bilan d'opération           */ +    GAnalystClient *client;                 /* Version native du serveur   */ + +#define ANALYST_CLIENT_RESTORE_SNAPSHOT_METHOD PYTHON_METHOD_DEF            \ +(                                                                           \ +    restore_snapshot, "$self, id, /",                                       \ +    METH_VARARGS, py_analyst_client,                                        \ +    "Ask the server for restoring a given snapshot using"                   \ +    " its identifier and returns the status of the request transmission."   \ +    "\n"                                                                    \ +    "A 'snapshot-changed' signal is emitted once the request has been"      \ +    " processed with success."                                              \ +) + +    ret = PyArg_ParseTuple(args, "s", &raw_id); +    if (!ret) return NULL; + +    status = init_snapshot_id_from_text(&id, raw_id); +    if (!status) +    { +        PyErr_SetString(PyExc_TypeError, _("provided value is not a valid snapshot identifier.")); +        return NULL; +    } + +    client = G_ANALYST_CLIENT(pygobject_get(self)); + +    status = g_analyst_client_restore_snapshot(client, &id); + +    result = status ? Py_True : Py_False; +    Py_INCREF(result); + +    return result; + +} + + +/****************************************************************************** +*                                                                             * +*  Paramètres  : self = client à manipuler.                                   * +*                args = arguments d'appel à consulter.                        * +*                                                                             * +*  Description : Crée un nouvel instantané à partir d'un autre.               * +*                                                                             * +*  Retour      : True si la commande a bien été envoyée, False sinon.         * +*                                                                             * +*  Remarques   : -                                                            * +*                                                                             * +******************************************************************************/ + +static PyObject *py_analyst_client_create_snapshot(PyObject *self, PyObject *args) +{ +    PyObject *result;                       /* Bilan à retourner           */ +    GAnalystClient *client;                 /* Version native du serveur   */ +    bool status;                            /* Bilan d'opération           */ + +#define ANALYST_CLIENT_CREATE_SNAPSHOT_METHOD PYTHON_METHOD_DEF             \ +(                                                                           \ +    create_snapshot, "$self, /",                                            \ +    METH_NOARGS, py_analyst_client,                                         \ +    "Ask the server for creating a new snapshot of the current state"       \ +    " and returns the status of the request transmission."                  \ +    "\n"                                                                    \ +    "A 'snapshots-updated' signal is emitted once the request has been"     \ +    " processed with success."                                              \ +) + +    client = G_ANALYST_CLIENT(pygobject_get(self)); + +    status = g_analyst_client_create_snapshot(client); + +    result = status ? Py_True : Py_False; +    Py_INCREF(result); + +    return result; + +} + + +/****************************************************************************** +*                                                                             * +*  Paramètres  : self = client à manipuler.                                   * +*                args = arguments d'appel à consulter.                        * +*                                                                             * +*  Description : Supprime un ancien instantané.                               * +*                                                                             * +*  Retour      : True si la commande a bien été envoyée, False sinon.         * +*                                                                             * +*  Remarques   : -                                                            * +*                                                                             * +******************************************************************************/ + +static PyObject *py_analyst_client_remove_snapshot(PyObject *self, PyObject *args) +{ +    PyObject *result;                       /* Bilan à retourner           */ +    const char *raw_id;                     /* Identifiant brut            */ +    int rec;                                /* Indicateur de récursivité   */ +    int ret;                                /* Bilan de lecture des args.  */ +    snapshot_id_t id;                       /* Identifiant utilisable      */ +    bool status;                            /* Bilan d'opération           */ +    GAnalystClient *client;                 /* Version native du serveur   */ + +#define ANALYST_CLIENT_REMOVE_SNAPSHOT_METHOD PYTHON_METHOD_DEF             \ +(                                                                           \ +    remove_snapshot, "$self, id, recursive, /",                             \ +    METH_VARARGS, py_analyst_client,                                        \ +    "Ask the server for removing a given snapshot using"                    \ +    " its identifier and returns the status of the request transmission."   \ +    "\n"                                                                    \ +    "If this removal has not to be recursive, all children snapshots get"   \ +    " reassigned to the parent snapshot of the target."                     \ +    "\n"                                                                    \ +    "A 'snapshots-updated' signal is emitted once the request has been"     \ +    " processed with success."                                              \ +) + +    ret = PyArg_ParseTuple(args, "sp", &raw_id, &rec); +    if (!ret) return NULL; + +    status = init_snapshot_id_from_text(&id, raw_id); +    if (!status) +    { +        PyErr_SetString(PyExc_TypeError, _("provided value is not a valid snapshot identifier.")); +        return NULL; +    } + +    client = G_ANALYST_CLIENT(pygobject_get(self)); + +    status = g_analyst_client_remove_snapshot(client, &id, rec); + +    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 la liste des instantanés existants.                  * +*                                                                             * +*  Retour      : Liste d'instantanés ou None.                                 * +*                                                                             * +*  Remarques   : -                                                            * +*                                                                             * +******************************************************************************/ + +static PyObject *py_analyst_client_get_snapshots(PyObject *self, void *closure) +{ +    PyObject *result;                       /* Valeur à retourner          */ +    GAnalystClient *client;                 /* Version native du serveur   */ +    snapshot_info_t *info;                  /* Liste d'instantanés présents*/ +    size_t count;                           /* Taille de cette liste       */ +    bool status;                            /* Validité de cet identifiant */ +    PyTypeObject *base;                     /* Modèle d'objet à créer      */ +    size_t i;                               /* Boucle de parcours          */ +    PyObject *item;                         /* Nouvelle description        */ +    char *text;                             /* Valeur textuelle à placer   */ +    PyObject *attrib;                       /* Attribut à constituer       */ +    int ret;                                /* Bilan d'une mise en place   */ +    bool failed;                            /* Détection d'une erreur      */ + +#define ANALYST_CLIENT_SNAPSHOTS_ATTRIB PYTHON_GET_DEF_FULL                             \ +(                                                                                       \ +    snapshots, py_analyst_client,                                                       \ +    "List of all existing snapshots, provided as a tuple of pychrysalide.StructObject." \ +    "\n"                                                                                \ +    "Each snapshot is characterised by the following properties :\n"                    \ +    "* parent_id : identifier of the parent snapshot;\n"                                \ +    "* id : identifier of the snapshot;\n"                                              \ +    "* created : timestamp of the creation date;\n"                                     \ +    "* name : name of the snapshot, or None;\n"                                         \ +    "* desc : description of the snapshot, or None."                                    \ +) + +    client = G_ANALYST_CLIENT(pygobject_get(self)); + +    status = g_analyst_client_get_snapshots(client, &info, &count); + +    if (status) +    { +        result = PyTuple_New(count); + +        base = get_python_py_struct_type(); + +        failed = false; + +        for (i = 0; i < count; i++) +        { +            item = PyObject_CallFunction((PyObject *)base, NULL); +            assert(item != NULL); + +            text = snapshot_id_as_string(get_snapshot_info_parent_id(&info[i])); +            attrib = PyUnicode_FromString(text); +            ret = PyDict_SetItemString(item, "parent_id", attrib); +            if (ret != 0) break; + +            text = snapshot_id_as_string(get_snapshot_info_id(&info[i])); +            attrib = PyUnicode_FromString(text); +            ret = PyDict_SetItemString(item, "id", attrib); +            if (ret != 0) break; + +            attrib = PyLong_FromUnsignedLongLong(get_snapshot_info_created(&info[i])); +            ret = PyDict_SetItemString(item, "created", attrib); +            if (ret != 0) break; + +            text = get_snapshot_info_name(&info[i]); + +            if (text != NULL) +                attrib = PyUnicode_FromString(text); +            else +            { +                attrib = Py_None; +                Py_INCREF(attrib); +            } + +            ret = PyDict_SetItemString(item, "name", attrib); +            if (ret != 0) break; + +            text = get_snapshot_info_desc(&info[i]); + +            if (text != NULL) +                attrib = PyUnicode_FromString(text); +            else +            { +                attrib = Py_None; +                Py_INCREF(attrib); +            } + +            ret = PyDict_SetItemString(item, "desc", attrib); +            if (ret != 0) break; + +            PyTuple_SetItem(result, i, item); + +        } + +        failed = (i < count); + +        for (i = 0; i < count; i++) +            exit_snapshot_info(&info[i]); + +        free(info); + +        if (failed) +            goto on_failure; + +    } + +    else +    { +        result = Py_None; +        Py_INCREF(result); +    } + +    return result; + + on_failure: + +    Py_DECREF(result); + +    return NULL; + +} + + +/****************************************************************************** +*                                                                             * +*  Paramètres  : self    = objet Python concerné par l'appel.                 * +*                closure = non utilisé ici.                                   * +*                                                                             * +*  Description : Fournit l'identifiant de l'instantané courant.               * +*                                                                             * +*  Retour      : Identifiant d'instantané ou None.                            * +*                                                                             * +*  Remarques   : -                                                            * +*                                                                             * +******************************************************************************/ + +static PyObject *py_analyst_client_get_current_snapshot(PyObject *self, void *closure) +{ +    PyObject *result;                       /* Valeur à retourner          */ +    GAnalystClient *client;                 /* Version native du serveur   */ +    snapshot_id_t id;                       /* Identifiant à transmettre   */ +    bool status;                            /* Validité de cet identifiant */ + +#define ANALYST_CLIENT_CURRENT_SNAPSHOT_ATTRIB PYTHON_GETSET_DEF_FULL   \ +(                                                                       \ +    current_snapshot, py_analyst_client,                                \ +    "Identifier of the current snapshot, provided as a string."         \ +    "\n"                                                                \ +    "The returned value is a cached version of the value stored at"     \ +    " server side. Thus, defining a new current snapshot is"            \ +    " successful as soon as the request to this server is sent."        \ +) + +    client = G_ANALYST_CLIENT(pygobject_get(self)); + +    status = g_analyst_client_get_current_snapshot(client, &id); + +    if (status) +        result = PyUnicode_FromString(snapshot_id_as_string(&id)); + +    else +    { +        result = Py_None; +        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 : Définit l'identifiant de l'instantané courant.               * +*                                                                             * +*  Retour      : Bilan de l'opération.                                        * +*                                                                             * +*  Remarques   : -                                                            * +*                                                                             * +******************************************************************************/ + +static int py_analyst_client_set_current_snapshot(PyObject *self, PyObject *value, void *closure) +{ +    int ret;                                /* Bilan d'analyse             */ +    void *raw;                              /* Valeur brute d'identifiant  */ +    snapshot_id_t id;                       /* Identifiant reconnu         */ +    bool status;                            /* Bilan d'une conversion      */ +    GAnalystClient *client;                 /* Version native du serveur   */ + +    ret = PyUnicode_Check(value); +    if (!ret) return -1; + +    raw = PyUnicode_DATA(value); + +    status = init_snapshot_id_from_text(&id, raw); +    if (!status) +    { +        PyErr_SetString(PyExc_TypeError, _("provided value is not a valid snapshot identifier.")); +        return -1; +    } + +    client = G_ANALYST_CLIENT(pygobject_get(self)); + +    status = g_analyst_client_set_current_snapshot(client, &id); +    if (!status) +    { +        PyErr_SetString(PyExc_TypeError, "unable to send the provided snapshot identifier"); +        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_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, +        ANALYST_CLIENT_SET_SNAPSHOT_DESC_METHOD, +        ANALYST_CLIENT_RESTORE_SNAPSHOT_METHOD, +        ANALYST_CLIENT_CREATE_SNAPSHOT_METHOD, +        ANALYST_CLIENT_REMOVE_SNAPSHOT_METHOD, +        { NULL } +    }; + +    static PyGetSetDef py_analyst_client_getseters[] = { +        ANALYST_CLIENT_SNAPSHOTS_ATTRIB, +        ANALYST_CLIENT_CURRENT_SNAPSHOT_ATTRIB, +        { NULL } +    }; + +    static PyTypeObject py_analyst_client_type = { + +        PyVarObject_HEAD_INIT(NULL, 0) + +        .tp_name        = "pychrysalide.analysis.db.AnalystClient", +        .tp_basicsize   = sizeof(PyGObject), + +        .tp_flags       = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, + +        .tp_doc         = ANALYST_CLIENT_DOC, + +        .tp_methods     = py_analyst_client_methods, +        .tp_getset      = py_analyst_client_getseters, + +        .tp_init        = py_analyst_client_init, +        .tp_new         = py_analyst_client_new + +    }; + +    return &py_analyst_client_type; + +} + + +/****************************************************************************** +*                                                                             * +*  Paramètres  : module = module dont la définition est à compléter.          * +*                                                                             * +*  Description : Prend en charge l'objet 'pychrysalide....db.AnalystClient'.  * +*                                                                             * +*  Retour      : Bilan de l'opération.                                        * +*                                                                             * +*  Remarques   : -                                                            * +*                                                                             * +******************************************************************************/ + +bool ensure_python_analyst_client_is_registered(void) +{ +    PyTypeObject *type;                     /* Type Python 'AnalystClient' */ +    PyObject *module;                       /* Module à recompléter        */ +    PyObject *dict;                         /* Dictionnaire du module      */ + +    type = get_python_analyst_client_type(); + +    if (!PyType_HasFeature(type, Py_TPFLAGS_READY)) +    { +        module = get_access_to_python_module("pychrysalide.analysis.db"); + +        dict = PyModule_GetDict(module); + +        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; + +    } + +    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 client analyste.                       * +*                                                                             * +*  Retour      : Bilan de l'opération, voire indications supplémentaires.     * +*                                                                             * +*  Remarques   : -                                                            * +*                                                                             * +******************************************************************************/ + +int convert_to_analyst_client(PyObject *arg, void *dst) +{ +    int result;                             /* Bilan à retourner           */ + +    result = PyObject_IsInstance(arg, (PyObject *)get_python_analyst_client_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 analyst client"); +            break; + +        case 1: +            *((GAnalystClient **)dst) = G_ANALYST_CLIENT(pygobject_get(arg)); +            break; + +        default: +            assert(false); +            break; + +    } + +    return result; + +} diff --git a/plugins/pychrysalide/analysis/db/analyst.h b/plugins/pychrysalide/analysis/db/analyst.h new file mode 100644 index 0000000..b250933 --- /dev/null +++ b/plugins/pychrysalide/analysis/db/analyst.h @@ -0,0 +1,45 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * analyst.h - prototypes pour l'équivalent Python du fichier "analysis/db/analyst.h" + * + * Copyright (C) 2019 Cyrille Bagard + * + *  This file is part of Chrysalide. + * + *  Chrysalide is free software; you can redistribute it and/or modify + *  it under the terms of the GNU General Public License as published by + *  the Free Software Foundation; either version 3 of the License, or + *  (at your option) any later version. + * + *  Chrysalide is distributed in the hope that it will be useful, + *  but WITHOUT ANY WARRANTY; without even the implied warranty of + *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + *  GNU General Public License for more details. + * + *  You should have received a copy of the GNU General Public License + *  along with 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_DB_ANALYST_H +#define _PLUGINS_PYCHRYSALIDE_ANALYSIS_DB_ANALYST_H + + +#include <Python.h> +#include <stdbool.h> + + + +/* Fournit un accès à une définition de type à diffuser. */ +PyTypeObject *get_python_analyst_client_type(void); + +/* Prend en charge l'objet 'pychrysalide.analysis.db.AnalystClient'. */ +bool ensure_python_analyst_client_is_registered(void); + +/* Tente de convertir en client analyste. */ +int convert_to_analyst_client(PyObject *, void *); + + + +#endif  /* _PLUGINS_PYCHRYSALIDE_ANALYSIS_DB_ANALYST_H */ diff --git a/plugins/pychrysalide/analysis/db/client.c b/plugins/pychrysalide/analysis/db/client.c index d5d8b48..7ef658e 100644 --- a/plugins/pychrysalide/analysis/db/client.c +++ b/plugins/pychrysalide/analysis/db/client.c @@ -41,84 +41,13 @@ -/* Crée un nouvel objet Python de type 'HubClient'. */ -static PyObject *py_hub_client_new(PyTypeObject *, PyObject *, PyObject *); - -/* Démarre la connexion à la base de données. */ -static PyObject *py_hub_client_start(PyObject *, PyObject *); - -/* Arrête la connexion à la base de données. */ -static PyObject *py_hub_client_stop(PyObject *, PyObject *); - -/* Effectue une demande de sauvegarde de l'état courant. */ -static PyObject *py_hub_client_save(PyObject *, PyObject *); - -/* Active les éléments en amont d'un horodatage donné. */ -static PyObject *py_hub_client_set_last_active(PyObject *, PyObject *); - -/* Définit la désignation d'un instantané donné. */ -static PyObject *py_hub_client_set_snapshot_name(PyObject *, PyObject *); - -/* Définit la désignation d'un instantané donné. */ -static PyObject *py_hub_client_set_snapshot_desc(PyObject *, PyObject *); - -/* Restaure un ancien instantané. */ -static PyObject *py_hub_client_restore_snapshot(PyObject *, PyObject *); - -/* Crée un nouvel instantané à partir d'un autre. */ -static PyObject *py_hub_client_create_snapshot(PyObject *, PyObject *); - -/* Supprime un ancien instantané. */ -static PyObject *py_hub_client_remove_snapshot(PyObject *, PyObject *); - -/* Fournit la liste des instantanés existants. */ -static PyObject *py_hub_client_get_snapshots(PyObject *, void *); - -/* Fournit l'identifiant de l'instantané courant. */ -static PyObject *py_hub_client_get_current_snapshot(PyObject *, void *); - - - -/****************************************************************************** -*                                                                             * -*  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 'HubClient'.             * -*                                                                             * -*  Retour      : Instance Python mise en place.                               * -*                                                                             * -*  Remarques   : -                                                            * -*                                                                             * -******************************************************************************/ - -static PyObject *py_hub_client_new(PyTypeObject *type, PyObject *args, PyObject *kwds) -{ -    PyObject *result;                       /* Instance à retourner        */ -    const char *hash;                       /* Empreinte du binaire visé   */ -    PyObject *list;                         /* Liste Python de collections */ -    int ret;                                /* Bilan de lecture des args.  */ -    Py_ssize_t length;                      /* Nombre d'éléments collectés */ -    GList *collections;                     /* Liste native de collections */ -    Py_ssize_t i;                           /* Boucle de parcours          */ -    PyObject *item;                         /* Elément de la liste Python  */ -    GDbCollection *collec;                  /* Version équivalente native  */ -    GHubClient *client;                     /* Serveur mis en place        */ -  #define HUB_CLIENT_DOC                                                                  \      "HubClient provides and receives binary updates to and from a connected"            \      " to a server.\n"                                                                   \      "\n"                                                                                \      "Such clients must be authenticated and communications are encrypted using TLS.\n"  \      "\n"                                                                                \ -    "Instances can be created using the following constructor:\n"                       \ -    "\n"                                                                                \ -    "    HubClient(hash, list)"                                                         \ -    "\n"                                                                                \ -    "Where hash is a SHA256 fingerprint of the studied binary and list is a list of"    \ -    " pychrysalide.analysis.db.DbCollection instances ; this kind of list can be"       \ -    " retrived with the pychrysalide.analysis.LoadedBinary.collections attribute."      \ +    "Instances can be created directly."                                                \      "\n"                                                                                \      "HubClient instances emit the following signals:\n"                                 \      "* 'snapshots-updated'\n"                                                           \ @@ -132,53 +61,14 @@ static PyObject *py_hub_client_new(PyTypeObject *type, PyObject *args, PyObject      "    Handlers are expected to have only one argument: the client managing the"      \      "    snapshots." -    ret = PyArg_ParseTuple(args, "sO", &hash, &list); -    if (!ret) return NULL; - -    if (!PySequence_Check(list)) -    { -        PyErr_SetString(PyExc_TypeError, _("The second argument must be a collection list")); -        return NULL; -    } - -    length = PySequence_Length(list); - -    collections = NULL; - -    for (i = 0; i < length; i++) -    { -        item = PySequence_GetItem(list, i); - -        ret = convert_to_db_collection(item, &collec); - -        Py_DECREF(item); -        if (ret != 1) -        { -            delete_collections_list(&collections); -            result = NULL; -            goto exit; -        } -        g_object_ref(G_OBJECT(collec)); -        collections = g_list_append(collections, collec); - -    } - -    client = g_hub_client_new(hash, collections); - -    if (client != NULL) -    { -        result = pygobject_new(G_OBJECT(client)); -        g_object_unref(client); -    } -    else result = NULL; - - exit: +/* Démarre la connexion à la base de données. */ +static PyObject *py_hub_client_start(PyObject *, PyObject *); -    return result; +/* Arrête la connexion à la base de données. */ +static PyObject *py_hub_client_stop(PyObject *, PyObject *); -}  /****************************************************************************** @@ -275,588 +165,6 @@ static PyObject *py_hub_client_stop(PyObject *self, PyObject *args)  /******************************************************************************  *                                                                             * -*  Paramètres  : self = client à manipuler.                                   * -*                args = arguments d'appel non utilisés ici.                   * -*                                                                             * -*  Description : Effectue une demande de sauvegarde de l'état courant.        * -*                                                                             * -*  Retour      : True si la commande a bien été envoyée, False sinon.         * -*                                                                             * -*  Remarques   : -                                                            * -*                                                                             * -******************************************************************************/ - -static PyObject *py_hub_client_save(PyObject *self, PyObject *args) -{ -    PyObject *result;                       /* Bilan à retourner           */ -    GHubClient *client;                     /* Version native du serveur   */ -    bool status;                            /* Bilan de l'opération        */ - -#define HUB_CLIENT_SAVE_METHOD PYTHON_METHOD_DEF                            \ -(                                                                           \ -    save, "$self, /",                                                       \ -    METH_NOARGS, py_hub_client,                                             \ -    "Ask the server for saving the current state of the analyzed binary"    \ -    " and returns the status of the request transmission."                  \ -) - -    client = G_HUB_CLIENT(pygobject_get(self)); - -    status = g_hub_client_save(client); - -    result = status ? Py_True : Py_False; -    Py_INCREF(result); - -    return result; - -} - - -/****************************************************************************** -*                                                                             * -*  Paramètres  : self = client à manipuler.                                   * -*                args = arguments d'appel à consulter.                        * -*                                                                             * -*  Description : Active les éléments en amont d'un horodatage donné.          * -*                                                                             * -*  Retour      : True si la commande a bien été envoyée, False sinon.         * -*                                                                             * -*  Remarques   : -                                                            * -*                                                                             * -******************************************************************************/ - -static PyObject *py_hub_client_set_last_active(PyObject *self, PyObject *args) -{ -    PyObject *result;                       /* Bilan à retourner           */ -    unsigned long long timestamp;           /* Horodatage de limite        */ -    int ret;                                /* Bilan de lecture des args.  */ -    GHubClient *client;                     /* Version native du serveur   */ -    bool status;                            /* Bilan de l'opération        */ - -#define HUB_CLIENT_SET_LAST_ACTIVE_METHOD PYTHON_METHOD_DEF             \ -(                                                                       \ -    set_last_active, "$self, timestamp, /",                             \ -    METH_VARARGS, py_hub_client,                                        \ -    "Define the timestamp of the last active item in the collection"    \ -    " and returns the status of the request transmission."              \ -    "\n"                                                                \ -    "This method should not be used directly. Prefer calling"           \ -    " pychrysalide.analysis.LoadedBinary.set_last_active() instead,"    \ -    " as some items may be volatile and thus not handled by clients."   \ -) - -    ret = PyArg_ParseTuple(args, "K", ×tamp); -    if (!ret) return NULL; - -    client = G_HUB_CLIENT(pygobject_get(self)); - -    status = g_hub_client_set_last_active(client, timestamp); - -    result = status ? Py_True : Py_False; -    Py_INCREF(result); - -    return result; - -} - - -/****************************************************************************** -*                                                                             * -*  Paramètres  : self = client à manipuler.                                   * -*                args = arguments d'appel à consulter.                        * -*                                                                             * -*  Description : Définit la désignation d'un instantané donné.                * -*                                                                             * -*  Retour      : True si la commande a bien été envoyée, False sinon.         * -*                                                                             * -*  Remarques   : -                                                            * -*                                                                             * -******************************************************************************/ - -static PyObject *py_hub_client_set_snapshot_name(PyObject *self, PyObject *args) -{ -    PyObject *result;                       /* Bilan à retourner           */ -    const char *raw_id;                     /* Identifiant brut            */ -    const char *text;                       /* Texte fourni à transmettre  */ -    int ret;                                /* Bilan de lecture des args.  */ -    snapshot_id_t id;                       /* Identifiant utilisable      */ -    bool status;                            /* Bilan d'opération           */ -    GHubClient *client;                     /* Version native du serveur   */ - -#define HUB_CLIENT_SET_SNAPSHOT_NAME_METHOD PYTHON_METHOD_DEF               \ -(                                                                           \ -    set_snapshot_name, "$self, id, name, /",                                \ -    METH_VARARGS, py_hub_client,                                            \ -    "Ask the server for defining a new name of for a snapshot using its"    \ -    " identifier and returns the status of the request transmission."       \ -    "\n"                                                                    \ -    "A 'snapshots-updated' signal is emitted once the request has been"     \ -    " processed with success."                                              \ -) - -    ret = PyArg_ParseTuple(args, "ss", &raw_id, &text); -    if (!ret) return NULL; - -    status = init_snapshot_id_from_text(&id, raw_id); -    if (!status) -    { -        PyErr_SetString(PyExc_TypeError, _("provided value is not a valid snapshot identifier.")); -        return NULL; -    } - -    client = G_HUB_CLIENT(pygobject_get(self)); - -    status = g_hub_client_set_snapshot_name(client, &id, text); - -    result = status ? Py_True : Py_False; -    Py_INCREF(result); - -    return result; - -} - - -/****************************************************************************** -*                                                                             * -*  Paramètres  : self = client à manipuler.                                   * -*                args = arguments d'appel à consulter.                        * -*                                                                             * -*  Description : Définit la désignation d'un instantané donné.                * -*                                                                             * -*  Retour      : True si la commande a bien été envoyée, False sinon.         * -*                                                                             * -*  Remarques   : -                                                            * -*                                                                             * -******************************************************************************/ - -static PyObject *py_hub_client_set_snapshot_desc(PyObject *self, PyObject *args) -{ -    PyObject *result;                       /* Bilan à retourner           */ -    const char *raw_id;                     /* Identifiant brut            */ -    const char *text;                       /* Texte fourni à transmettre  */ -    int ret;                                /* Bilan de lecture des args.  */ -    snapshot_id_t id;                       /* Identifiant utilisable      */ -    bool status;                            /* Bilan d'opération           */ -    GHubClient *client;                     /* Version native du serveur   */ - -#define HUB_CLIENT_SET_SNAPSHOT_DESC_METHOD PYTHON_METHOD_DEF               \ -(                                                                           \ -    set_snapshot_desc, "$self, id, desc, /",                                \ -    METH_VARARGS, py_hub_client,                                            \ -    "Ask the server for defining a new description for a snapshot using"    \ -    " its identifier and returns the status of the request transmission."   \ -    "\n"                                                                    \ -    "A 'snapshots-updated' signal is emitted once the request has been"     \ -    " processed with success."                                              \ -) - -    ret = PyArg_ParseTuple(args, "ss", &raw_id, &text); -    if (!ret) return NULL; - -    status = init_snapshot_id_from_text(&id, raw_id); -    if (!status) -    { -        PyErr_SetString(PyExc_TypeError, _("provided value is not a valid snapshot identifier.")); -        return NULL; -    } - -    client = G_HUB_CLIENT(pygobject_get(self)); - -    status = g_hub_client_set_snapshot_desc(client, &id, text); - -    result = status ? Py_True : Py_False; -    Py_INCREF(result); - -    return result; - -} - - -/****************************************************************************** -*                                                                             * -*  Paramètres  : self = client à manipuler.                                   * -*                args = arguments d'appel à consulter.                        * -*                                                                             * -*  Description : Restaure un ancien instantané.                               * -*                                                                             * -*  Retour      : True si la commande a bien été envoyée, False sinon.         * -*                                                                             * -*  Remarques   : -                                                            * -*                                                                             * -******************************************************************************/ - -static PyObject *py_hub_client_restore_snapshot(PyObject *self, PyObject *args) -{ -    PyObject *result;                       /* Bilan à retourner           */ -    const char *raw_id;                     /* Identifiant brut            */ -    int ret;                                /* Bilan de lecture des args.  */ -    snapshot_id_t id;                       /* Identifiant utilisable      */ -    bool status;                            /* Bilan d'opération           */ -    GHubClient *client;                     /* Version native du serveur   */ - -#define HUB_CLIENT_RESTORE_SNAPSHOT_METHOD PYTHON_METHOD_DEF                \ -(                                                                           \ -    restore_snapshot, "$self, id, /",                                       \ -    METH_VARARGS, py_hub_client,                                            \ -    "Ask the server for restoring a given snapshot using"                   \ -    " its identifier and returns the status of the request transmission."   \ -    "\n"                                                                    \ -    "A 'snapshot-changed' signal is emitted once the request has been"      \ -    " processed with success."                                              \ -) - -    ret = PyArg_ParseTuple(args, "s", &raw_id); -    if (!ret) return NULL; - -    status = init_snapshot_id_from_text(&id, raw_id); -    if (!status) -    { -        PyErr_SetString(PyExc_TypeError, _("provided value is not a valid snapshot identifier.")); -        return NULL; -    } - -    client = G_HUB_CLIENT(pygobject_get(self)); - -    status = g_hub_client_restore_snapshot(client, &id); - -    result = status ? Py_True : Py_False; -    Py_INCREF(result); - -    return result; - -} - - -/****************************************************************************** -*                                                                             * -*  Paramètres  : self = client à manipuler.                                   * -*                args = arguments d'appel à consulter.                        * -*                                                                             * -*  Description : Crée un nouvel instantané à partir d'un autre.               * -*                                                                             * -*  Retour      : True si la commande a bien été envoyée, False sinon.         * -*                                                                             * -*  Remarques   : -                                                            * -*                                                                             * -******************************************************************************/ - -static PyObject *py_hub_client_create_snapshot(PyObject *self, PyObject *args) -{ -    PyObject *result;                       /* Bilan à retourner           */ -    GHubClient *client;                     /* Version native du serveur   */ -    bool status;                            /* Bilan d'opération           */ - -#define HUB_CLIENT_CREATE_SNAPSHOT_METHOD PYTHON_METHOD_DEF                 \ -(                                                                           \ -    create_snapshot, "$self, /",                                            \ -    METH_NOARGS, py_hub_client,                                             \ -    "Ask the server for creating a new snapshot of the current state"       \ -    " and returns the status of the request transmission."                  \ -    "\n"                                                                    \ -    "A 'snapshots-updated' signal is emitted once the request has been"     \ -    " processed with success."                                              \ -) - -    client = G_HUB_CLIENT(pygobject_get(self)); - -    status = g_hub_client_create_snapshot(client); - -    result = status ? Py_True : Py_False; -    Py_INCREF(result); - -    return result; - -} - - -/****************************************************************************** -*                                                                             * -*  Paramètres  : self = client à manipuler.                                   * -*                args = arguments d'appel à consulter.                        * -*                                                                             * -*  Description : Supprime un ancien instantané.                               * -*                                                                             * -*  Retour      : True si la commande a bien été envoyée, False sinon.         * -*                                                                             * -*  Remarques   : -                                                            * -*                                                                             * -******************************************************************************/ - -static PyObject *py_hub_client_remove_snapshot(PyObject *self, PyObject *args) -{ -    PyObject *result;                       /* Bilan à retourner           */ -    const char *raw_id;                     /* Identifiant brut            */ -    int rec;                                /* Indicateur de récursivité   */ -    int ret;                                /* Bilan de lecture des args.  */ -    snapshot_id_t id;                       /* Identifiant utilisable      */ -    bool status;                            /* Bilan d'opération           */ -    GHubClient *client;                     /* Version native du serveur   */ - -#define HUB_CLIENT_REMOVE_SNAPSHOT_METHOD PYTHON_METHOD_DEF                 \ -(                                                                           \ -    remove_snapshot, "$self, id, recursive, /",                             \ -    METH_VARARGS, py_hub_client,                                            \ -    "Ask the server for removing a given snapshot using"                    \ -    " its identifier and returns the status of the request transmission."   \ -    "\n"                                                                    \ -    "If this removal has not to be recursive, all children snapshots get"   \ -    " reassigned to the parent snapshot of the target."                     \ -    "\n"                                                                    \ -    "A 'snapshots-updated' signal is emitted once the request has been"     \ -    " processed with success."                                              \ -) - -    ret = PyArg_ParseTuple(args, "sp", &raw_id, &rec); -    if (!ret) return NULL; - -    status = init_snapshot_id_from_text(&id, raw_id); -    if (!status) -    { -        PyErr_SetString(PyExc_TypeError, _("provided value is not a valid snapshot identifier.")); -        return NULL; -    } - -    client = G_HUB_CLIENT(pygobject_get(self)); - -    status = g_hub_client_remove_snapshot(client, &id, rec); - -    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 la liste des instantanés existants.                  * -*                                                                             * -*  Retour      : Liste d'instantanés ou None.                                 * -*                                                                             * -*  Remarques   : -                                                            * -*                                                                             * -******************************************************************************/ - -static PyObject *py_hub_client_get_snapshots(PyObject *self, void *closure) -{ -    PyObject *result;                       /* Valeur à retourner          */ -    GHubClient *client;                     /* Version native du serveur   */ -    snapshot_info_t *info;                  /* Liste d'instantanés présents*/ -    size_t count;                           /* Taille de cette liste       */ -    bool status;                            /* Validité de cet identifiant */ -    PyTypeObject *base;                     /* Modèle d'objet à créer      */ -    size_t i;                               /* Boucle de parcours          */ -    PyObject *item;                         /* Nouvelle description        */ -    char *text;                             /* Valeur textuelle à placer   */ -    PyObject *attrib;                       /* Attribut à constituer       */ -    int ret;                                /* Bilan d'une mise en place   */ -    bool failed;                            /* Détection d'une erreur      */ - -#define HUB_CLIENT_SNAPSHOTS_ATTRIB PYTHON_GET_DEF_FULL                                 \ -(                                                                                       \ -    snapshots, py_hub_client,                                                           \ -    "List of all existing snapshots, provided as a tuple of pychrysalide.StructObject." \ -    "\n"                                                                                \ -    "Each snapshot is characterised by the following properties :\n"                    \ -    "* parent_id : identifier of the parent snapshot;\n"                                \ -    "* id : identifier of the snapshot;\n"                                              \ -    "* created : timestamp of the creation date;\n"                                     \ -    "* name : name of the snapshot, or None;\n"                                         \ -    "* desc : description of the snapshot, or None."                                    \ -) - -    client = G_HUB_CLIENT(pygobject_get(self)); - -    status = g_hub_client_get_snapshots(client, &info, &count); - -    if (status) -    { -        result = PyTuple_New(count); - -        base = get_python_py_struct_type(); - -        failed = false; - -        for (i = 0; i < count; i++) -        { -            item = PyObject_CallFunction((PyObject *)base, NULL); -            assert(item != NULL); - -            text = snapshot_id_as_string(get_snapshot_info_parent_id(&info[i])); -            attrib = PyUnicode_FromString(text); -            ret = PyDict_SetItemString(item, "parent_id", attrib); -            if (ret != 0) break; - -            text = snapshot_id_as_string(get_snapshot_info_id(&info[i])); -            attrib = PyUnicode_FromString(text); -            ret = PyDict_SetItemString(item, "id", attrib); -            if (ret != 0) break; - -            attrib = PyLong_FromUnsignedLongLong(get_snapshot_info_created(&info[i])); -            ret = PyDict_SetItemString(item, "created", attrib); -            if (ret != 0) break; - -            text = get_snapshot_info_name(&info[i]); - -            if (text != NULL) -                attrib = PyUnicode_FromString(text); -            else -            { -                attrib = Py_None; -                Py_INCREF(attrib); -            } - -            ret = PyDict_SetItemString(item, "name", attrib); -            if (ret != 0) break; - -            text = get_snapshot_info_desc(&info[i]); - -            if (text != NULL) -                attrib = PyUnicode_FromString(text); -            else -            { -                attrib = Py_None; -                Py_INCREF(attrib); -            } - -            ret = PyDict_SetItemString(item, "desc", attrib); -            if (ret != 0) break; - -            PyTuple_SetItem(result, i, item); - -        } - -        failed = (i < count); - -        for (i = 0; i < count; i++) -            exit_snapshot_info(&info[i]); - -        free(info); - -        if (failed) -            goto on_failure; - -    } - -    else -    { -        result = Py_None; -        Py_INCREF(result); -    } - -    return result; - - on_failure: - -    Py_DECREF(result); - -    return NULL; - -} - - -/****************************************************************************** -*                                                                             * -*  Paramètres  : self    = objet Python concerné par l'appel.                 * -*                closure = non utilisé ici.                                   * -*                                                                             * -*  Description : Fournit l'identifiant de l'instantané courant.               * -*                                                                             * -*  Retour      : Identifiant d'instantané ou None.                            * -*                                                                             * -*  Remarques   : -                                                            * -*                                                                             * -******************************************************************************/ - -static PyObject *py_hub_client_get_current_snapshot(PyObject *self, void *closure) -{ -    PyObject *result;                       /* Valeur à retourner          */ -    GHubClient *client;                     /* Version native du serveur   */ -    snapshot_id_t id;                       /* Identifiant à transmettre   */ -    bool status;                            /* Validité de cet identifiant */ - -#define HUB_CLIENT_CURRENT_SNAPSHOT_ATTRIB PYTHON_GETSET_DEF_FULL   \ -(                                                                   \ -    current_snapshot, py_hub_client,                                \ -    "Identifier of the current snapshot, provided as a string."     \ -    "\n"                                                            \ -    "The returned value is a cached version of the value stored at" \ -    " server side. Thus, defining a new current snapshot is"        \ -    " successful as soon as the request to this server is sent."    \ -) - -    client = G_HUB_CLIENT(pygobject_get(self)); - -    status = g_hub_client_get_current_snapshot(client, &id); - -    if (status) -        result = PyUnicode_FromString(snapshot_id_as_string(&id)); - -    else -    { -        result = Py_None; -        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 : Définit l'identifiant de l'instantané courant.               * -*                                                                             * -*  Retour      : Bilan de l'opération.                                        * -*                                                                             * -*  Remarques   : -                                                            * -*                                                                             * -******************************************************************************/ - -static int py_hub_client_set_current_snapshot(PyObject *self, PyObject *value, void *closure) -{ -    int ret;                                /* Bilan d'analyse             */ -    void *raw;                              /* Valeur brute d'identifiant  */ -    snapshot_id_t id;                       /* Identifiant reconnu         */ -    bool status;                            /* Bilan d'une conversion      */ -    GHubClient *client;                     /* Version native du serveur   */ - -    ret = PyUnicode_Check(value); -    if (!ret) return -1; - -    raw = PyUnicode_DATA(value); - -    status = init_snapshot_id_from_text(&id, raw); -    if (!status) -    { -        PyErr_SetString(PyExc_TypeError, _("provided value is not a valid snapshot identifier.")); -        return -1; -    } - -    client = G_HUB_CLIENT(pygobject_get(self)); - -    status = g_hub_client_set_current_snapshot(client, &id); -    if (!status) -    { -        PyErr_SetString(PyExc_TypeError, "unable to send the provided snapshot identifier"); -        return -1; -    } - -    return 0; - -} - - -/****************************************************************************** -*                                                                             *  *  Paramètres  : -                                                            *  *                                                                             *  *  Description : Fournit un accès à une définition de type à diffuser.        * @@ -872,19 +180,10 @@ PyTypeObject *get_python_hub_client_type(void)      static PyMethodDef py_hub_client_methods[] = {          HUB_CLIENT_START_METHOD,          HUB_CLIENT_STOP_METHOD, -        HUB_CLIENT_SAVE_METHOD, -        HUB_CLIENT_SET_LAST_ACTIVE_METHOD, -        HUB_CLIENT_SET_SNAPSHOT_NAME_METHOD, -        HUB_CLIENT_SET_SNAPSHOT_DESC_METHOD, -        HUB_CLIENT_RESTORE_SNAPSHOT_METHOD, -        HUB_CLIENT_CREATE_SNAPSHOT_METHOD, -        HUB_CLIENT_REMOVE_SNAPSHOT_METHOD,          { NULL }      };      static PyGetSetDef py_hub_client_getseters[] = { -        HUB_CLIENT_SNAPSHOTS_ATTRIB, -        HUB_CLIENT_CURRENT_SNAPSHOT_ATTRIB,          { NULL }      }; @@ -901,7 +200,7 @@ PyTypeObject *get_python_hub_client_type(void)          .tp_methods     = py_hub_client_methods,          .tp_getset      = py_hub_client_getseters, -        .tp_new         = py_hub_client_new, +        .tp_new         = no_python_constructor_allowed,      }; @@ -936,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/module.c b/plugins/pychrysalide/analysis/db/module.c index fa5a139..ddae5a7 100644 --- a/plugins/pychrysalide/analysis/db/module.c +++ b/plugins/pychrysalide/analysis/db/module.c @@ -28,6 +28,8 @@  #include <assert.h> +#include "admin.h" +#include "analyst.h"  #include "certs.h"  #include "client.h"  #include "collection.h" @@ -98,6 +100,8 @@ bool populate_analysis_db_module(void)      result = true; +    if (result) result = ensure_python_admin_client_is_registered(); +    if (result) result = ensure_python_analyst_client_is_registered();      if (result) result = ensure_python_certs_is_registered();      if (result) result = ensure_python_hub_client_is_registered();      if (result) result = ensure_python_db_collection_is_registered(); diff --git a/plugins/pychrysalide/analysis/db/server.c b/plugins/pychrysalide/analysis/db/server.c index 80ff4e2..dae7b29 100644 --- a/plugins/pychrysalide/analysis/db/server.c +++ b/plugins/pychrysalide/analysis/db/server.c @@ -83,7 +83,8 @@ static PyObject *py_hub_server_new(PyTypeObject *type, PyObject *args, PyObject      "\n"                                                                                \      "Instances can be created using the following constructor:\n"                       \      "\n"                                                                                \ -    "    HubServer(host=None, port='1337', ipv6=True)"                                  \ +    "    HubServer()"                                                                   \ +    "    HubServer(host='localhost', port='1337', ipv6=True)"                           \      "\n"                                                                                \      "Where host and port define the listening properties of the server, and ipv6"       \      " tries to establish IPv6 connections first."                                       \ @@ -273,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/serialize.c b/plugins/pychrysalide/analysis/storage/serialize.c index 6e1dd41..40fcef7 100644 --- a/plugins/pychrysalide/analysis/storage/serialize.c +++ b/plugins/pychrysalide/analysis/storage/serialize.c @@ -45,10 +45,10 @@  static void py_serializable_object_interface_init(GSerializableObjectIface *, gpointer *);  /* Charge un objet depuis une mémoire tampon. */ -static bool py_serializable_object_load_wrapper(GSerializableObject *, GObjectStorage *, packed_buffer *); +static bool py_serializable_object_load_wrapper(GSerializableObject *, GObjectStorage *, packed_buffer_t *);  /* Sauvegarde un objet dans une mémoire tampon. */ -static bool py_serializable_object_store_wrapper(const GSerializableObject *, GObjectStorage *, packed_buffer *); +static bool py_serializable_object_store_wrapper(const GSerializableObject *, GObjectStorage *, packed_buffer_t *); @@ -117,7 +117,7 @@ static void py_serializable_object_interface_init(GSerializableObjectIface *ifac  *                                                                             *  ******************************************************************************/ -static bool py_serializable_object_load_wrapper(GSerializableObject *object, GObjectStorage *storage, packed_buffer *pbuf) +static bool py_serializable_object_load_wrapper(GSerializableObject *object, GObjectStorage *storage, packed_buffer_t *pbuf)  {      bool result;                            /* Bilan à retourner           */      PyGILState_STATE gstate;                /* Sauvegarde d'environnement  */ @@ -193,7 +193,7 @@ static bool py_serializable_object_load_wrapper(GSerializableObject *object, GOb  *                                                                             *  ******************************************************************************/ -static bool py_serializable_object_store_wrapper(const GSerializableObject *object, GObjectStorage *storage, packed_buffer *pbuf) +static bool py_serializable_object_store_wrapper(const GSerializableObject *object, GObjectStorage *storage, packed_buffer_t *pbuf)  {      bool result;                            /* Bilan à retourner           */      PyGILState_STATE gstate;                /* Sauvegarde d'environnement  */ @@ -278,7 +278,7 @@ static bool py_serializable_object_load(PyObject *self, PyObject *args)  {      PyObject *result;                       /* Bilan à retourner           */      GObjectStorage *storage;                /* Conservateur à manipuler    */ -    packed_buffer *pbuf;                    /* Tampon de données à employer*/ +    packed_buffer_t *pbuf;                  /* Tampon de données à employer*/      int ret;                                /* Bilan de lecture des args.  */      GSerializableObject *object;            /* Version native              */      bool status;                            /* Bilan de l'opération        */ @@ -330,7 +330,7 @@ static bool py_serializable_object_store(PyObject *self, PyObject *args)  {      PyObject *result;                       /* Bilan à retourner           */      GObjectStorage *storage;                /* Conservateur à manipuler    */ -    packed_buffer *pbuf;                    /* Tampon de données à employer*/ +    packed_buffer_t *pbuf;                  /* Tampon de données à employer*/      int ret;                                /* Bilan de lecture des args.  */      GSerializableObject *object;            /* Version native              */      bool status;                            /* Bilan de l'opération        */ diff --git a/plugins/pychrysalide/analysis/storage/storage.c b/plugins/pychrysalide/analysis/storage/storage.c index 1ebcc62..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); @@ -321,7 +371,7 @@ static PyObject *py_object_storage_unpack_object(PyObject *self, PyObject *args)  {      PyObject *result;                       /* Bilan à retourner           */      const char *name;                       /* Désignation de groupe       */ -    packed_buffer *pbuf;                    /* Tampon de données à employer*/ +    packed_buffer_t *pbuf;                  /* Tampon de données à employer*/      int ret;                                /* Bilan de lecture des args.  */      GObjectStorage *storage;                /* Mécanismes natifs           */      GSerializableObject *object;            /* Objet reconstruit ou NULL   */ @@ -435,7 +485,7 @@ static PyObject *py_object_storage_pack_object(PyObject *self, PyObject *args)      PyObject *result;                       /* Emplacement à retourner     */      const char *name;                       /* Désignation de groupe       */      GSerializableObject *object;            /* Objet à traiter             */ -    packed_buffer *pbuf;                    /* Tampon de données à employer*/ +    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        */ @@ -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 2cf659f..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); @@ -241,7 +241,7 @@ static PyObject *py_type_memory_read_types(PyObject *self, PyObject *args)  static PyObject *py_type_memory_create_object(PyObject *self, PyObject *args)  {      PyObject *result;                       /* Instance à retourner        */ -    packed_buffer *pbuf;                    /* Tampon à consulter          */ +    packed_buffer_t *pbuf;                  /* Tampon à consulter          */      int ret;                                /* Bilan de lecture des args.  */      GTypeMemory *tpmem;                     /* Mémorisation native         */      GObject *obj;                           /* Instance retournée          */ @@ -290,7 +290,7 @@ static PyObject *py_type_memory_store_object_gtype(PyObject *self, PyObject *arg  {      PyObject *result;                       /* Bilan à retourner           */      GObject *obj;                           /* Instance à traiter          */ -    packed_buffer *pbuf;                    /* Tampon à consulter          */ +    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        */ @@ -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/leb128.c b/plugins/pychrysalide/common/leb128.c index 8e1bf28..8b15303 100644 --- a/plugins/pychrysalide/common/leb128.c +++ b/plugins/pychrysalide/common/leb128.c @@ -69,7 +69,7 @@ static PyObject *py_leb128_pack_uleb128(PyObject *self, PyObject *args)  {      PyObject *result;                       /* Valeur à retourner          */      uleb128_t value;                        /* Valeur à manipuler          */ -    packed_buffer *pbuf;                    /* Tampon de données à employer*/ +    packed_buffer_t *pbuf;                  /* Tampon de données à employer*/      int ret;                                /* Bilan de lecture des args.  */      bool status;                            /* Bilan de l'opération        */ @@ -117,7 +117,7 @@ static PyObject *py_leb128_pack_leb128(PyObject *self, PyObject *args)  {      PyObject *result;                       /* Valeur à retourner          */      leb128_t value;                         /* Valeur à manipuler          */ -    packed_buffer *pbuf;                    /* Tampon de données à employer*/ +    packed_buffer_t *pbuf;                  /* Tampon de données à employer*/      int ret;                                /* Bilan de lecture des args.  */      bool status;                            /* Bilan de l'opération        */ @@ -164,7 +164,7 @@ static PyObject *py_leb128_pack_leb128(PyObject *self, PyObject *args)  static PyObject *py_leb128_unpack_uleb128(PyObject *self, PyObject *args)  {      PyObject *result;                       /* Valeur à retourner          */ -    packed_buffer *pbuf;                    /* Tampon de données à employer*/ +    packed_buffer_t *pbuf;                  /* Tampon de données à employer*/      int ret;                                /* Bilan de lecture des args.  */      uleb128_t value;                        /* Valeur à manipuler          */      bool status;                            /* Bilan de l'opération        */ @@ -218,9 +218,9 @@ static PyObject *py_leb128_unpack_uleb128(PyObject *self, PyObject *args)  static PyObject *py_leb128_unpack_leb128(PyObject *self, PyObject *args)  {      PyObject *result;                       /* Valeur à retourner          */ -    packed_buffer *pbuf;                    /* Tampon de données à employer*/ +    packed_buffer_t *pbuf;                  /* Tampon de données à employer*/      int ret;                                /* Bilan de lecture des args.  */ -    leb128_t value;                        /* Valeur à manipuler          */ +    leb128_t value;                         /* Valeur à manipuler          */      bool status;                            /* Bilan de l'opération        */  #define LEB128_UNPACK_LEB128_METHOD PYTHON_METHOD_DEF               \ 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 179a991..2ed2aa5 100644 --- a/plugins/pychrysalide/glibext/Makefile.am +++ b/plugins/pychrysalide/glibext/Makefile.am @@ -1,29 +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					\ +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 + +if BUILD_GTK_SUPPORT + +libpychrysaglibext_la_SOURCES +=			\ +	bufferview.h bufferview.c				\ +	loadedpanel.h loadedpanel.c				\  	named.h named.c -libpychrysaglibext_la_LDFLAGS =  +endif + +libpychrysaglibext_la_CFLAGS = $(TOOLKIT_CFLAGS) $(LIBXML_CFLAGS) $(LIBPYTHON_INTERPRETER_CFLAGS) $(LIBPYGOBJECT_CFLAGS) \ +	-I$(top_srcdir)/src -DNO_IMPORT_PYGOBJECT  devdir = $(includedir)/chrysalide/$(subdir)  dev_HEADERS = $(libpychrysaglibext_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/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 176d815..3e4307a 100644 --- a/plugins/pychrysalide/glibext/module.c +++ b/plugins/pychrysalide/glibext/module.c @@ -33,11 +33,13 @@  #include "buffercache.h"  #include "bufferline.h"  #include "bufferview.h" +#include "comparison.h"  #include "configuration.h"  #include "linecursor.h"  #include "linegen.h"  #include "loadedpanel.h"  #include "named.h" +#include "singleton.h"  #include "../helpers.h" @@ -104,18 +106,26 @@ bool populate_glibext_module(void)      result = true; +    if (result) result = ensure_python_singleton_candidate_is_registered(); +      if (result) result = ensure_python_binary_cursor_is_registered();      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 new file mode 100644 index 0000000..8491473 --- /dev/null +++ b/plugins/pychrysalide/glibext/singleton.c @@ -0,0 +1,1165 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * singleton.c - équivalent Python du fichier "glibext/singleton.c" + * + * Copyright (C) 2021 Cyrille Bagard + * + *  This file is part of Chrysalide. + * + *  Chrysalide is free software; you can redistribute it and/or modify + *  it under the terms of the GNU General Public License as published by + *  the Free Software Foundation; either version 3 of the License, or + *  (at your option) any later version. + * + *  Chrysalide is distributed in the hope that it will be useful, + *  but WITHOUT ANY WARRANTY; without even the implied warranty of + *  MERCHANTABILITY or FITNESS FOR A PARTICULAR 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 "singleton.h" + + +#include <assert.h> +#include <pygobject.h> + + +#include <glibext/singleton-int.h> +#include <plugins/dt.h> + + +#include "../access.h" +#include "../helpers.h" + + + +/* ------------------ INTERFACE POUR CANDIDAT A UNE CENTRALISATION ------------------ */ + + +/* Procède à l'initialisation de l'interface de candidature. */ +static void py_singleton_candidate_interface_init(GSingletonCandidateIface *, gpointer *); + +/* Fournit une liste de candidats embarqués par un candidat. */ +static GSingletonCandidate **py_singleton_candidate_list_inner_instances_wrapper(const GSingletonCandidate *, size_t *); + +/* Met à jour une liste de candidats embarqués par un candidat. */ +static void py_singleton_candidate_update_inner_instances_wrapper(GSingletonCandidate *, GSingletonCandidate **, size_t); + +/* Fournit l'empreinte d'un candidat à une centralisation. */ +static guint py_singleton_candidate___hash__wrapper(const GSingletonCandidate *); + +/* Détermine si deux candidats à l'unicité sont identiques. */ +static gboolean py_singleton_candidate___eq__wrapper(const GSingletonCandidate *, const GSingletonCandidate *); + +/* Marque un candidat comme figé. */ +static void py_singleton_candidate_set_ro_wrapper(GSingletonCandidate *); + +/* Indique si le candidat est figé. */ +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 *); + +/* Fournit une liste de candidats embarqués par un candidat. */ +static PyObject *py_singleton_candidate_get_inner_instances(PyObject *, void *); + +/* Indique si le candidat est figé. */ +static PyObject *py_singleton_candidate_get_read_only(PyObject *, void *); + +/* Effectue une comparaison avec un objet 'SingletonCandidate'. */ +static PyObject *py_singleton_candidate_richcompare(PyObject *, PyObject *, int); + + + +/* ------------------------- COLLECTION D'INSTANCES UNIQUES ------------------------- */ + + +/* Accompagne la création d'une instance dérivée en Python. */ +static PyObject *py_singleton_factory_new(PyTypeObject *, PyObject *, PyObject *); + +/* Initialise une instance sur la base du dérivé de GObject. */ +static int py_singleton_factory_init(PyObject *, PyObject *, PyObject *); + +/* Fournit l'instance unique correspondant à un objet. */ +static PyObject *py_singleton_factory_get_instance(PyObject *, PyObject *); + + + +/* ---------------------------------------------------------------------------------- */ +/*                    INTERFACE POUR CANDIDAT A UNE CENTRALISATION                    */ +/* ---------------------------------------------------------------------------------- */ + + +/****************************************************************************** +*                                                                             * +*  Paramètres  : iface  = interface GLib à initialiser.                       * +*                unused = adresse non utilisée ici.                           * +*                                                                             * +*  Description : Procède à l'initialisation de l'interface de candidature.    * +*                                                                             * +*  Retour      : -                                                            * +*                                                                             * +*  Remarques   : -                                                            * +*                                                                             * +******************************************************************************/ + +static void py_singleton_candidate_interface_init(GSingletonCandidateIface *iface, gpointer *unused) +{ +#define SINGLETON_CANDIDATE_DOC                                             \ +    "The SingletonCandidate class is a required interface for objects"      \ +    " aiming at becoming singleton instances. All shared singletons are"    \ +    " registered within a pychrysalide.glibext.SingletonFactory object.\n"  \ +    "\n"                                                                    \ +    "The main implemantations come with types derived from"                 \ +    " pychrysalide.analysis.DataType.\n"                                    \ +    "\n"                                                                    \ +    "A typical class declaration for a new implementation looks like:\n"    \ +    "\n"                                                                    \ +    "    class NewImplem(GObject.Object, SingletonCandidate):\n"            \ +    "        ...\n"                                                         \ +    "\n"                                                                    \ +    "The following methods have to be defined for new implementations:\n"   \ +    "* pychrysalide.glibext.SingletonCandidate._list_inner_instances();\n"  \ +    "* pychrysalide.glibext.SingletonCandidate._update_inner_instances();\n"\ +    "* pychrysalide.glibext.SingletonCandidate.__hash__();\n"               \ +    "* pychrysalide.glibext.SingletonCandidate.__eq__();\n"                 \ +    "* pychrysalide.glibext.SingletonCandidate._set_read_only();\n"         \ +    "* pychrysalide.glibext.SingletonCandidate._is_read_only().\n" + +    iface->update_inner = py_singleton_candidate_update_inner_instances_wrapper; +    iface->list_inner = py_singleton_candidate_list_inner_instances_wrapper; + +    iface->hash = py_singleton_candidate___hash__wrapper; +    iface->is_equal = py_singleton_candidate___eq__wrapper; + +    iface->set_ro = py_singleton_candidate_set_ro_wrapper; +    iface->is_ro = py_singleton_candidate_is_ro_wrapper; + +} + + +/****************************************************************************** +*                                                                             * +*  Paramètres  : candidate = objet dont l'instance se veut unique.            * +*                count     = quantité d'instances à l'unicité internes.       * +*                                                                             * +*  Description : Fournit une liste de candidats embarqués par un candidat.    * +*                                                                             * +*  Retour      : Liste de candidats internes ou NULL si aucun.                * +*                                                                             * +*  Remarques   : -                                                            * +*                                                                             * +******************************************************************************/ + +static GSingletonCandidate **py_singleton_candidate_list_inner_instances_wrapper(const GSingletonCandidate *candidate, size_t *count) +{ +    GSingletonCandidate **result;           /* Instances à retourner       */ +    PyGILState_STATE gstate;                /* Sauvegarde d'environnement  */ +    PyObject *pyobj;                        /* Objet Python concerné       */ +    PyObject *pyinstances;                  /* Liste en version Python     */ +    int ret;                                /* Bilan d'un appel            */ +    Py_ssize_t size;                        /* Taille de la liste          */ +    Py_ssize_t i;                           /* Boucle de parcours #1       */ +    PyObject *pyinstance;                   /* Instance interne            */ +    Py_ssize_t k;                           /* Boucle de parcours #2       */ + +#define SINGLETON_CANDIDATE_LIST_INNER_INSTANCES_WRAPPER PYTHON_WRAPPER_DEF     \ +(                                                                               \ +    _list_inner_instances, "$self, /",                                          \ +    METH_NOARGS,                                                                \ +    "Provide an internal access to the list of optional internal singleton"     \ +    " candidate instances.\n"                                                   \ +    "\n"                                                                        \ +    "The result has to be a tuple containing zero or more"                      \ +    " pychrysalide.glibext.SingletonCandidate instances."                       \ +) + +    result = NULL; +    *count = 0; + +    gstate = PyGILState_Ensure(); + +    pyobj = pygobject_new(G_OBJECT(candidate)); + +    if (has_python_method(pyobj, "_list_inner_instances")) +    { +        pyinstances = run_python_method(pyobj, "_list_inner_instances", NULL); + +        if (pyinstances != NULL) +        { +            ret = PyTuple_Check(pyinstances); +            if (!ret) +            { +                PyErr_SetString(PyExc_TypeError, "the _inner_instances attribute must be a tuple"); +                goto done; +            } + +            size = PyTuple_GET_SIZE(pyinstances); + +            result = calloc(size, sizeof(GSingletonCandidate *)); + +            for (i = 0; i < size; i++) +            { +                pyinstance = PyTuple_GET_ITEM(pyinstances, i); + +                ret = PyObject_IsInstance(pyinstance, (PyObject *)get_python_singleton_candidate_type()); +                if (ret != 1) +                { +                    PyErr_SetString(PyExc_TypeError, "the _inner_instances attribute must only contain pychrysalide.glibext.SingletonCandidate instances"); + +                    for (k = 0; k < i; k++) +                        g_object_unref(G_OBJECT(result[k])); + +                    free(result); +                    result = NULL; + +                    goto done; + +                } + +                result[i] = G_SINGLETON_CANDIDATE(pygobject_get(pyinstance)); +                assert(result[i] != NULL); + +                g_object_ref(G_OBJECT(result[i])); + +            } + +            *count = size; + + done: + +            Py_DECREF(pyinstances); + +        } + +    } + +    Py_DECREF(pyobj); + +    PyGILState_Release(gstate); + +    return result; + +} + + +/****************************************************************************** +*                                                                             * +*  Paramètres  : candidate = objet dont l'instance se veut unique.            * +*                instances = liste de candidats internes devenus singletons.  * +*                count     = quantité d'instances à l'unicité internes.       * +*                                                                             * +*  Description : Met à jour une liste de candidats embarqués par un candidat. * +*                                                                             * +*  Retour      : -                                                            * +*                                                                             * +*  Remarques   : -                                                            * +*                                                                             * +******************************************************************************/ + +static void py_singleton_candidate_update_inner_instances_wrapper(GSingletonCandidate *candidate, GSingletonCandidate **instances, size_t count) +{ +    PyGILState_STATE gstate;                /* Sauvegarde d'environnement  */ +    PyObject *pyobj;                        /* Objet Python concerné       */ +    PyObject *args;                         /* Arguments pour l'appel      */ +    PyObject *pyinstances;                  /* Liste d'instances converties*/ +    size_t i;                               /* Boucle de parcours          */ +    PyObject *pyret;                        /* Bilan de consultation       */ + +#define SINGLETON_CANDIDATE_UPDATE_INNER_INSTANCES_WRAPPER PYTHON_WRAPPER_DEF           \ +(                                                                                       \ +    _update_inner_instances, "$self, instances, /",                                     \ +    METH_VARARGS,                                                                       \ +    "Update the list of internal singleton candidate instances.\n"                      \ +    "\n"                                                                                \ +    "The provided *instances* are a tuple of pychrysalide.glibext.SingletonCandidate"   \ +    " objets promoted as singletons."                                                   \ +) + +    gstate = PyGILState_Ensure(); + +    pyobj = pygobject_new(G_OBJECT(candidate)); + +    if (has_python_method(pyobj, "_update_inner_instances")) +    { +        args = PyTuple_New(1); + +        pyinstances = PyTuple_New(count); +        PyTuple_SetItem(args, 0, pyinstances); + +        for (i = 0; i < count; i++) +            PyTuple_SetItem(pyinstances, i, pygobject_new(G_OBJECT(instances[i]))); + +        pyret = run_python_method(pyobj, "_update_inner_instances", args); + +        Py_XDECREF(pyret); +        Py_DECREF(args); + +    } + +    Py_DECREF(pyobj); + +    PyGILState_Release(gstate); + +} + + +/****************************************************************************** +*                                                                             * +*  Paramètres  : candidate = objet dont l'instance se veut unique.            * +*                                                                             * +*  Description : Fournit l'empreinte d'un candidat à une centralisation.      * +*                                                                             * +*  Retour      : Empreinte de l'élément représenté.                           * +*                                                                             * +*  Remarques   : -                                                            * +*                                                                             * +******************************************************************************/ + +static guint py_singleton_candidate___hash__wrapper(const GSingletonCandidate *candidate) +{ +    guint result;                           /* Empreinte à retourner       */ +    PyGILState_STATE gstate;                /* Sauvegarde d'environnement  */ +    PyObject *pyobj;                        /* Objet Python concerné       */ +    PyObject *pyret;                        /* Bilan de consultation       */ + +#define SINGLETON_CANDIDATE_HASH_WRAPPER PYTHON_WRAPPER_DEF             \ +(                                                                       \ +    __hash__, "$self, /",                                               \ +    METH_NOARGS,                                                        \ +    "Abstract method used to produce a hash of the object.\n"           \ +    "\n"                                                                \ +    "The result must be an integer value up to 64 bits."                \ +    "\n"                                                                \ +    "Inner instances which are listed through the"                      \ +    " pychrysalide.glibext.SingletonCandidate._list_inner_instances()"  \ +    " method do not need to get processed here as they are handled"     \ +    " automatically by the interface core."                             \ +) + +    result = 0; + +    gstate = PyGILState_Ensure(); + +    pyobj = pygobject_new(G_OBJECT(candidate)); + +    if (has_python_method(pyobj, "__hash__")) +    { +        pyret = run_python_method(pyobj, "__hash__", NULL); + +        if (pyret != NULL) +        { +            if (PyLong_Check(pyret)) +                result = PyLong_AsUnsignedLongMask(pyret); + +            Py_DECREF(pyret); + +        } + +    } + +    Py_DECREF(pyobj); + +    PyGILState_Release(gstate); + +    return result; + +} + + +/****************************************************************************** +*                                                                             * +*  Paramètres  : candidate = objet dont l'instance se veut unique.            * +*                other     = second élément à analyser.                       * +*                                                                             * +*  Description : Détermine si deux candidats à l'unicité sont identiques.     * +*                                                                             * +*  Retour      : Bilan de la comparaison.                                     * +*                                                                             * +*  Remarques   : -                                                            * +*                                                                             * +******************************************************************************/ + +static gboolean py_singleton_candidate___eq__wrapper(const GSingletonCandidate *candidate, const GSingletonCandidate *other) +{ +    guint result;                           /* Empreinte à retourner       */ +    PyGILState_STATE gstate;                /* Sauvegarde d'environnement  */ +    PyObject *pyobj;                        /* Objet Python concerné       */ +    PyObject *args;                         /* Arguments pour l'appel      */ +    PyObject *pyret;                        /* Bilan de consultation       */ + +#define SINGLETON_CANDIDATE_EQ_WRAPPER PYTHON_WRAPPER_DEF       \ +(                                                               \ +    __eq__, "$self, other, /",                                  \ +    METH_NOARGS,                                                \ +    "Abstract method used to provide the *__eq__* method for"   \ +    " rich comparison.\n"                                       \ +    "\n"                                                        \ +    "The expected result is a boolean value."                   \ +) + +    result = 0; + +    gstate = PyGILState_Ensure(); + +    pyobj = pygobject_new(G_OBJECT(candidate)); + +    if (has_python_method(pyobj, "__eq__")) +    { +        args = PyTuple_New(1); +        PyTuple_SetItem(args, 0, pygobject_new(G_OBJECT(other))); + +        pyret = run_python_method(pyobj, "__eq__", args); + +        if (pyret != NULL) +        { +            if (PyLong_Check(pyret)) +                result = PyLong_AsUnsignedLong(pyret); + +            Py_DECREF(pyret); + +        } + +        Py_DECREF(args); + +    } + +    Py_DECREF(pyobj); + +    PyGILState_Release(gstate); + +    return result; + +} + + +/****************************************************************************** +*                                                                             * +*  Paramètres  : candidate = objet dont l'instance se veut unique.            * +*                                                                             * +*  Description : Marque un candidat comme figé.                               * +*                                                                             * +*  Retour      : -                                                            * +*                                                                             * +*  Remarques   : -                                                            * +*                                                                             * +******************************************************************************/ + +static void py_singleton_candidate_set_ro_wrapper(GSingletonCandidate *candidate) +{ +    PyGILState_STATE gstate;                /* Sauvegarde d'environnement  */ +    PyObject *pyobj;                        /* Objet Python concerné       */ +    PyObject *pyret;                        /* Bilan de consultation       */ + +#define SINGLETON_CANDIDATE_SET_RO_WRAPPER PYTHON_WRAPPER_DEF   \ +(                                                               \ +    _set_read_only, "$self, /",                        \ +    METH_NOARGS,                                                \ +    "Abstract method used to mark the content of a singleton"   \ +    " candidate as read-only.\n"                                \ +    "\n"                                                        \ +    "The read-only state is mandatory once the candidate is"    \ +    " registered inside a pychrysalide.glibext.SingletonFactory"\ +    " instance as official singleton."                          \ +) + +    gstate = PyGILState_Ensure(); + +    pyobj = pygobject_new(G_OBJECT(candidate)); + +    if (has_python_method(pyobj, "_set_read_only")) +    { +        pyret = run_python_method(pyobj, "_set_read_only", NULL); + +        Py_XDECREF(pyret); + +    } + +    Py_DECREF(pyobj); + +    PyGILState_Release(gstate); + +} + + +/****************************************************************************** +*                                                                             * +*  Paramètres  : candidate = objet dont l'instance se veut unique.            * +*                                                                             * +*  Description : Indique si le candidat est figé.                             * +*                                                                             * +*  Retour      : true si le contenu du candidat ne peut plus être modifié.    * +*                                                                             * +*  Remarques   : -                                                            * +*                                                                             * +******************************************************************************/ + +static bool py_singleton_candidate_is_ro_wrapper(const GSingletonCandidate *candidate) +{ +    bool result;                            /* Etat à retourner            */ +    PyGILState_STATE gstate;                /* Sauvegarde d'environnement  */ +    PyObject *pyobj;                        /* Objet Python concerné       */ +    PyObject *pyret;                        /* Bilan de consultation       */ + +#define SINGLETON_CANDIDATE_IS_RO_WRAPPER PYTHON_WRAPPER_DEF    \ +(                                                               \ +    _is_read_only, "$self, /",                                  \ +    METH_NOARGS,                                                \ +    "Abstract method used to retrieve the status of the data"   \ +    " contained by a singleton candidate.\n"                    \ +    "\n"                                                        \ +    "The retured value is *True* if the candidate is"           \ +    " registered inside a pychrysalide.glibext.SingletonFactory"\ +    " instance as official singleton, *False* otherwise."       \ +) + +    result = false; + +    gstate = PyGILState_Ensure(); + +    pyobj = pygobject_new(G_OBJECT(candidate)); + +    if (has_python_method(pyobj, "_is_read_only")) +    { +        pyret = run_python_method(pyobj, "_is_read_only", NULL); + +        result = (pyret == Py_True); + +        Py_XDECREF(pyret); + +    } + +    Py_DECREF(pyobj); + +    PyGILState_Release(gstate); + +    return result; + +} + + +/****************************************************************************** +*                                                                             * +*  Paramètres  : self = objet dont l'instance se veut unique.                 * +*                args = adresse non utilisée ici.                             * +*                                                                             * +*  Description : Fournit l'empreinte d'un candidat à une centralisation.      * +*                                                                             * +*  Retour      : Empreinte de l'élément représenté.                           * +*                                                                             * +*  Remarques   : -                                                            * +*                                                                             * +******************************************************************************/ + +static PyObject *py_singleton_candidate_hash(PyObject *self, PyObject *args) +{ +    PyObject *result;                       /* Emplacement à retourner     */ +    GSingletonCandidate *candidate;         /* Mécanismes natifs           */ +    guint hash;                             /* Valeur d'empreitne          */ + +#define SINGLETON_CANDIDATE_HASH_METHOD PYTHON_METHOD_DEF           \ +(                                                                   \ +    hash, "$self",                                                  \ +    METH_NOARGS, py_singleton_candidate,                            \ +    "Compute the hash value of the singleton candidate.\n"          \ +    "\n"                                                            \ +    "The method relies on the interface core to include in the"     \ +    " process the optional embedded instances which may become"     \ +    " singletons.\n"                                                \ +    "\n"                                                            \ +    "The result is an integer value.\n"                             \ +    "\n"                                                            \ +    "Even if the Python *hash()* method, relying on the"            \ +    " pychrysalide.glibext.SingletonCandidate.__hash__()"           \ +    " implementation, provides values up to 64 bits, the final"     \ +    " hashes processed by the native GLib hash methods are"         \ +    " limited to 32 bits values."                                   \ +) + +    candidate = G_SINGLETON_CANDIDATE(pygobject_get(self)); + +    hash = g_singleton_candidate_hash(candidate); + +    result = PyLong_FromUnsignedLong(hash); + +    return result; + +} + + +/****************************************************************************** +*                                                                             * +*  Paramètres  : self    = objet Python concerné par l'appel.                 * +*                closure = non utilisé ici.                                   * +*                                                                             * +*  Description : Fournit une liste de candidats embarqués par un candidat.    * +*                                                                             * +*  Retour      : Liste de candidats internes, vide si aucun.                  * +*                                                                             * +*  Remarques   : -                                                            * +*                                                                             * +******************************************************************************/ + +static PyObject *py_singleton_candidate_get_inner_instances(PyObject *self, void *closure) +{ +    PyObject *result;                       /* Valeur à retourner          */ +    GSingletonCandidate *candidate;         /* Mécanismes natifs           */ +    size_t count;                           /* Quantité d'objets internes  */ +    GSingletonCandidate **instances;        /* Liste des embarqués         */ +    size_t i;                               /* Boucle de parcours          */ + +#define SINGLETON_CANDIDATE_INNER_INSTANCES_ATTRIB PYTHON_GET_DEF_FULL  \ +(                                                                       \ +    inner_instances, py_singleton_candidate,                            \ +    "List of optional internal singleton candidate instances.\n"        \ +    "\n"                                                                \ +    "The result has to be a tuple containing zero or more"              \ +    " pychrysalide.glibext.SingletonCandidate instances."               \ +) + +    candidate = G_SINGLETON_CANDIDATE(pygobject_get(self)); + +    instances = g_singleton_candidate_list_inner_instances(candidate, &count); + +    result = PyTuple_New(count); + +    for (i = 0; i < count; i++) +    { +        PyTuple_SetItem(result, i, pygobject_new(G_OBJECT(instances[i]))); +        g_object_unref(G_OBJECT(instances[i])); +    } + +    if (instances != NULL) +        free(instances); + +    return result; + +} + + +/****************************************************************************** +*                                                                             * +*  Paramètres  : self    = objet Python concerné par l'appel.                 * +*                closure = non utilisé ici.                                   * +*                                                                             * +*  Description : Indique si le candidat est figé.                             * +*                                                                             * +*  Retour      : true si le contenu du candidat ne peut plus être modifié.    * +*                                                                             * +*  Remarques   : -                                                            * +*                                                                             * +******************************************************************************/ + +static PyObject *py_singleton_candidate_get_read_only(PyObject *self, void *closure) +{ +    PyObject *result;                       /* Valeur à retourner          */ +    GSingletonCandidate *candidate;         /* Mécanismes natifs           */ +    bool status;                            /* Etat de l'élément consulté  */ + +#define SINGLETON_CANDIDATE_READ_ONLY_ATTRIB PYTHON_GET_DEF_FULL    \ +(                                                                   \ +    read_only, py_singleton_candidate,                              \ +    "State of the singleton candidate content.\n"                   \ +    "\n"                                                            \ +    "The result is a boolean: *True* if the object is registered"   \ +    " as singleton, *False* otherwise.\n"                           \ +    "\n"                                                            \ +    "Once a singleton, the object must not change its content as"   \ +    " it is a shared instance."                                     \ +) + +    candidate = G_SINGLETON_CANDIDATE(pygobject_get(self)); + +    status = g_singleton_candidate_is_read_only(candidate); + +    result = status ? Py_True : Py_False; +    Py_INCREF(result); + +    return result; + +} + + +/****************************************************************************** +*                                                                             * +*  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 'SingletonCandidate'. * +*                                                                             * +*  Retour      : Bilan de l'opération.                                        * +*                                                                             * +*  Remarques   : -                                                            * +*                                                                             * +******************************************************************************/ + +static PyObject *py_singleton_candidate_richcompare(PyObject *a, PyObject *b, int op) +{ +    PyObject *result;                       /* Bilan à retourner           */ +    int ret;                                /* Bilan de lecture des args.  */ +    GSingletonCandidate *cand_a;            /* Premier élément à traiter   */ +    GSingletonCandidate *cand_b;            /* Second élément à traiter    */ +    gboolean status;                        /* Résultat d'une comparaison  */ + +    if (op != Py_EQ) +    { +        result = Py_NotImplemented; +        goto cmp_done; +    } + +    ret = PyObject_IsInstance(b, (PyObject *)get_python_singleton_candidate_type()); +    if (!ret) +    { +        result = Py_NotImplemented; +        goto cmp_done; +    } + +    cand_a = G_SINGLETON_CANDIDATE(pygobject_get(a)); +    cand_b = G_SINGLETON_CANDIDATE(pygobject_get(b)); + +    status = g_singleton_candidate_is_equal(cand_a, cand_b); + +    result = (status ? Py_True : Py_False); + + 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_singleton_candidate_type(void) +{ +    static PyMethodDef py_singleton_candidate_methods[] = { +        SINGLETON_CANDIDATE_LIST_INNER_INSTANCES_WRAPPER, +        SINGLETON_CANDIDATE_UPDATE_INNER_INSTANCES_WRAPPER, +        SINGLETON_CANDIDATE_HASH_WRAPPER, +        SINGLETON_CANDIDATE_EQ_WRAPPER, +        SINGLETON_CANDIDATE_SET_RO_WRAPPER, +        SINGLETON_CANDIDATE_IS_RO_WRAPPER, +        SINGLETON_CANDIDATE_HASH_METHOD, +        { NULL } +    }; + +    static PyGetSetDef py_singleton_candidate_getseters[] = { +        SINGLETON_CANDIDATE_INNER_INSTANCES_ATTRIB, +        SINGLETON_CANDIDATE_READ_ONLY_ATTRIB, +        { NULL } +    }; + +    static PyTypeObject py_singleton_candidate_type = { + +        PyVarObject_HEAD_INIT(NULL, 0) + +        .tp_name        = "pychrysalide.glibext.SingletonCandidate", +        .tp_basicsize   = sizeof(PyObject), + +        .tp_flags       = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, + +        .tp_doc         = SINGLETON_CANDIDATE_DOC, + +        .tp_richcompare = py_singleton_candidate_richcompare, + +        .tp_methods     = py_singleton_candidate_methods, +        .tp_getset      = py_singleton_candidate_getseters + +    }; + +    return &py_singleton_candidate_type; + +} + + +/****************************************************************************** +*                                                                             * +*  Paramètres  : -                                                            * +*                                                                             * +*  Description : Prend en charge l'objet 'pychrysalide....SingletonCandidate'.* +*                                                                             * +*  Retour      : Bilan de l'opération.                                        * +*                                                                             * +*  Remarques   : -                                                            * +*                                                                             * +******************************************************************************/ + +bool ensure_python_singleton_candidate_is_registered(void) +{ +    PyTypeObject *type;                     /* Type Python 'BinContent'    */ +    PyObject *module;                       /* Module à recompléter        */ +    PyObject *dict;                         /* Dictionnaire du module      */ + +    static GInterfaceInfo info = {          /* Paramètres d'inscription    */ + +        .interface_init = (GInterfaceInitFunc)py_singleton_candidate_interface_init, +        .interface_finalize = NULL, +        .interface_data = NULL, + +    }; + +    type = get_python_singleton_candidate_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_SINGLETON_CANDIDATE, type, &info)) +            return false; + +    } + +    return true; + +} + + +/****************************************************************************** +*                                                                             * +*  Paramètres  : arg = argument quelconque à tenter de convertir.             * +*                dst = destination des valeurs récupérées en cas de succès.   * +*                                                                             * +*  Description : Tente de convertir en candidat à une centralisation.         * +*                                                                             * +*  Retour      : Bilan de l'opération, voire indications supplémentaires.     * +*                                                                             * +*  Remarques   : -                                                            * +*                                                                             * +******************************************************************************/ + +int convert_to_singleton_candidate(PyObject *arg, void *dst) +{ +    int result;                             /* Bilan à retourner           */ + +    result = PyObject_IsInstance(arg, (PyObject *)get_python_singleton_candidate_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 singleton candidate"); +            break; + +        case 1: +            *((GSingletonCandidate **)dst) = G_SINGLETON_CANDIDATE(pygobject_get(arg)); +            break; + +        default: +            assert(false); +            break; + +    } + +    return result; + +} + + + +/* ---------------------------------------------------------------------------------- */ +/*                           COLLECTION D'INSTANCES UNIQUES                           */ +/* ---------------------------------------------------------------------------------- */ + + +/****************************************************************************** +*                                                                             * +*  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_singleton_factory_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_singleton_factory_type(); + +    if (type == base) +        goto simple_way; + +    /* Mise en place d'un type dédié */ + +    first_time = (g_type_from_name(type->tp_name) == 0); + +    gtype = build_dynamic_type(G_TYPE_SINGLETON_FACTORY, type->tp_name, NULL, NULL, NULL); + +    if (first_time) +    { +        status = register_class_for_dynamic_pygobject(gtype, type); + +        if (!status) +        { +            result = NULL; +            goto exit; +        } + +    } + +    /* On crée, et on laisse ensuite la main à PyGObject_Type.tp_init() */ + + simple_way: + +    result = PyType_GenericNew(type, args, kwds); + + exit: + +    return result; + +} + + +/****************************************************************************** +*                                                                             * +*  Paramètres  : self = objet à initialiser (théoriquement).                  * +*                args = arguments fournis à l'appel.                          * +*                kwds = arguments de type key=val fournis.                    * +*                                                                             * +*  Description : Initialise une instance sur la base du dérivé de GObject.    * +*                                                                             * +*  Retour      : 0.                                                           * +*                                                                             * +*  Remarques   : -                                                            * +*                                                                             * +******************************************************************************/ + +static int py_singleton_factory_init(PyObject *self, PyObject *args, PyObject *kwds) +{ +    int ret;                                /* Bilan de lecture des args.  */ + +#define SINGLETON_FACTORY_DOC                                               \ +    "The SingletonFactory class reduces the memory footprint by compacting" \ +    " the quantity of running instances of a given GLib type.\n"            \ +    "\n"                                                                    \ +    "Instances can be created using the following constructor:\n"           \ +    "\n"                                                                    \ +    "    SingletonFactory()"                                                \ +    "\n"                                                                    \ +    "The first processed instance defines the type handled by the factory." + +    /* 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; + +    /* Eléments de base */ + +    return 0; + +} + + +/****************************************************************************** +*                                                                             * +*  Paramètres  : self = gestionnaire d'instances uniques à consulter.         * +*                args = arguments fournis à l'appel.                          * +*                                                                             * +*  Description : Fournit l'instance unique correspondant à un objet.          * +*                                                                             * +*  Retour      : Instance unique à utiliser.                                  * +*                                                                             * +*  Remarques   : -                                                            * +*                                                                             * +******************************************************************************/ + +static PyObject *py_singleton_factory_get_instance(PyObject *self, PyObject *args) +{ +    PyObject *result;                       /* Emplacement à retourner     */ +    GSingletonCandidate *candidate;         /* Candidat à traiter          */ +    int ret;                                /* Bilan de lecture des args.  */ +    GSingletonFactory *factory;             /* Gestionnaire à manipuler    */ +    GSingletonCandidate *instance;          /* Instance unique à retourner */ + +#define SINGLETON_FACTORY_GET_INSTANCE_METHOD PYTHON_METHOD_DEF         \ +(                                                                       \ +    get_instance, "$self, candidate, /",                                \ +    METH_VARARGS, py_singleton_factory,                                 \ +    "Provide the unique instance for a given singleton *candidate*.\n"  \ +    "\n"                                                                \ +    "The *candidate* object and the result of the function belong to"   \ +    " the same type: pychrysalide.glibext.SingletonCandidate."          \ +) + +    ret = PyArg_ParseTuple(args, "O&", convert_to_singleton_candidate, &candidate); +    if (!ret) return NULL; + +    factory = G_SINGLETON_FACTORY(pygobject_get(self)); + +    instance = g_singleton_factory_get_instance(factory, candidate); + +    result = pygobject_new(G_OBJECT(instance)); + +    g_object_unref(G_OBJECT(instance)); + +    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_singleton_factory_type(void) +{ +    static PyMethodDef py_singleton_factory_methods[] = { +        SINGLETON_FACTORY_GET_INSTANCE_METHOD, +        { NULL } +    }; + +    static PyGetSetDef py_singleton_factory_getseters[] = { +        { NULL } +    }; + +    static PyTypeObject py_singleton_factory_type = { + +        PyVarObject_HEAD_INIT(NULL, 0) + +        .tp_name        = "pychrysalide.glibext.SingletonFactory", +        .tp_basicsize   = sizeof(PyGObject), + +        .tp_flags       = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, + +        .tp_doc         = SINGLETON_FACTORY_DOC, + +        .tp_methods     = py_singleton_factory_methods, +        .tp_getset      = py_singleton_factory_getseters, + +        .tp_init        = py_singleton_factory_init, +        .tp_new         = py_singleton_factory_new + +    }; + +    return &py_singleton_factory_type; + +} + + +/****************************************************************************** +*                                                                             * +*  Paramètres  : module = module dont la définition est à compléter.          * +*                                                                             * +*  Description : Prend en charge l'objet 'pychrysalide....SingletonFactory'.  * +*                                                                             * +*  Retour      : Bilan de l'opération.                                        * +*                                                                             * +*  Remarques   : -                                                            * +*                                                                             * +******************************************************************************/ + +bool ensure_python_singleton_factory_is_registered(void) +{ +    PyTypeObject *type;                     /* Type 'SingletonFactory'     */ +    PyObject *module;                       /* Module à recompléter        */ +    PyObject *dict;                         /* Dictionnaire du module      */ + +    type = get_python_singleton_factory_type(); + +    if (!PyType_HasFeature(type, Py_TPFLAGS_READY)) +    { +        module = get_access_to_python_module("pychrysalide.glibext"); + +        dict = PyModule_GetDict(module); + +        if (!register_class_for_pygobject(dict, G_TYPE_SINGLETON_FACTORY, 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 compacteur d'instances.                * +*                                                                             * +*  Retour      : Bilan de l'opération, voire indications supplémentaires.     * +*                                                                             * +*  Remarques   : -                                                            * +*                                                                             * +******************************************************************************/ + +int convert_to_singleton_factory(PyObject *arg, void *dst) +{ +    int result;                             /* Bilan à retourner           */ + +    result = PyObject_IsInstance(arg, (PyObject *)get_python_singleton_factory_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 singleton factory"); +            break; + +        case 1: +            *((GSingletonFactory **)dst) = G_SINGLETON_FACTORY(pygobject_get(arg)); +            break; + +        default: +            assert(false); +            break; + +    } + +    return result; + +} diff --git a/plugins/pychrysalide/glibext/singleton.h b/plugins/pychrysalide/glibext/singleton.h new file mode 100644 index 0000000..6479219 --- /dev/null +++ b/plugins/pychrysalide/glibext/singleton.h @@ -0,0 +1,62 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * singleton.h - prototypes pour l'équivalent Python du fichier "glibext/singleton.h" + * + * Copyright (C) 2021 Cyrille Bagard + * + *  This file is part of Chrysalide. + * + *  Chrysalide is free software; you can redistribute it and/or modify + *  it under the terms of the GNU General Public License as published by + *  the Free Software Foundation; either version 3 of the License, or + *  (at your option) any later version. + * + *  Chrysalide is distributed in the hope that it will be useful, + *  but WITHOUT ANY WARRANTY; without even the implied warranty of + *  MERCHANTABILITY or FITNESS FOR A PARTICULAR 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_SINGLETON_H +#define _PLUGINS_PYCHRYSALIDE_GLIBEXT_SINGLETON_H + + +#include <Python.h> +#include <stdbool.h> + + + +/* ------------------ INTERFACE POUR CANDIDAT A UNE CENTRALISATION ------------------ */ + + +/* Fournit un accès à une définition de type à diffuser. */ +PyTypeObject *get_python_singleton_candidate_type(void); + +/* Prend en charge l'objet 'pychrysalide.glibext.SingletonCandidate'. */ +bool ensure_python_singleton_candidate_is_registered(void); + +/* Tente de convertir en candidat à une centralisation. */ +int convert_to_singleton_candidate(PyObject *, void *); + + + +/* ------------------------- COLLECTION D'INSTANCES UNIQUES ------------------------- */ + + +/* Fournit un accès à une définition de type à diffuser. */ +PyTypeObject *get_python_singleton_factory_type(void); + +/* Prend en charge l'objet 'pychrysalide.glibext.SingletonFactory'. */ +bool ensure_python_singleton_factory_is_registered(void); + +/* Tente de convertir en compacteur d'instances. */ +int convert_to_singleton_factory(PyObject *, void *); + + + +#endif  /* _PLUGINS_PYCHRYSALIDE_GLIBEXT_SINGLETON_H */ 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 */  | 
