From 2bd3ea7249d1234204c1b70abac8bc46e221fb95 Mon Sep 17 00:00:00 2001 From: Cyrille Bagard Date: Sun, 12 Jul 2020 15:52:22 +0200 Subject: Improved the API for loaded contents. --- plugins/pychrysalide/analysis/loaded.c | 791 +++++++++++++++++++++- plugins/pychrysalide/analysis/storage/serialize.c | 2 +- plugins/pychrysalide/gtkext/dockable.c | 32 +- plugins/pychrysalide/gtkext/graph/cluster.c | 6 - plugins/pychrysalide/helpers.c | 56 ++ plugins/pychrysalide/helpers.h | 3 + src/analysis/binary.c | 30 +- src/analysis/content.c | 5 +- src/analysis/loaded-int.h | 6 +- src/analysis/loaded.c | 20 +- src/analysis/loaded.h | 6 +- src/analysis/project.c | 11 +- src/gui/dialogs/loading.c | 12 +- src/gui/editor.c | 8 +- src/gui/menus/project.c | 4 +- src/gui/menus/view.c | 6 +- src/gui/panel.c | 4 +- 17 files changed, 896 insertions(+), 106 deletions(-) diff --git a/plugins/pychrysalide/analysis/loaded.c b/plugins/pychrysalide/analysis/loaded.c index 768b11c..e3b2625 100644 --- a/plugins/pychrysalide/analysis/loaded.c +++ b/plugins/pychrysalide/analysis/loaded.c @@ -33,22 +33,52 @@ #include -#include +#include #include +#include "content.h" #include "../access.h" #include "../helpers.h" -#define LOADED_CONTENT_DOC \ - "The LoadedContent interface 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," \ - " some basic features are available here." +/* ------------------------ 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 *); + +/* 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 *); + +/* Lance l'analyse propre à l'élément chargé. */ +static bool py_loaded_content_analyze_wrapper(GLoadedContent *, bool, bool, wgroup_id_t, GtkStatusStack *); +/* Fournit le désignation associée à l'élément chargé. */ +static char *py_loaded_content_describe_wrapper(const GLoadedContent *, bool); + +/* Détermine le nombre de vues disponibles pour un contenu. */ +static unsigned int py_loaded_content_count_views_wrapper(const GLoadedContent *); + +/* Fournit le nom d'une vue donnée d'un contenu chargé. */ +static char *py_loaded_content_get_view_name_wrapper(const GLoadedContent *, unsigned int); + +/* Met en place la vue initiale pour un contenu chargé. */ +static GtkWidget *py_loaded_content_build_default_view_wrapper(GLoadedContent *); + +/* Met en place la vue demandée pour un contenu chargé. */ +static GtkWidget *py_loaded_content_build_view_wrapper(GLoadedContent *, unsigned int); + +/* Retrouve l'indice correspondant à la vue donnée d'un contenu. */ +static unsigned int py_loaded_content_get_view_index_wrapper(GLoadedContent *, GtkWidget *); + + + +/* ------------------------- CONNEXION AVEC L'API DE PYTHON ------------------------- */ /* Lance l'analyse propre à l'élément chargé. */ @@ -83,6 +113,690 @@ static PyObject *py_loaded_content_get_format_name(PyObject *, void *); +/* ---------------------------------------------------------------------------------- */ +/* 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 génération. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void py_loaded_content_interface_init(GLoadedContentIface *iface, gpointer *unused) +{ +#define LOADED_CONTENT_DOC \ + "The LoadedContent interface 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," \ + " some basic features are available here." \ + "\n" \ + "A typical class declaration for a new implementation looks like:\n" \ + "\n" \ + " class NewImplem(GObject.Object, LoadedContent):\n" \ + " ...\n" \ + "\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._analyze();\n" \ + "* pychrysalide.analysis.storage.LoadedContent._describe();\n" \ + "* pychrysalide.analysis.storage.LoadedContent._count_views();\n" \ + "* pychrysalide.analysis.storage.LoadedContent._get_view_name();\n" \ + "* pychrysalide.analysis.storage.LoadedContent._build_default_view();\n"\ + "* 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; + + iface->analyze = py_loaded_content_analyze_wrapper; + + iface->describe = py_loaded_content_describe_wrapper; + + 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; + +} + + +/****************************************************************************** +* * +* Paramètres : content = élément chargé à manipuler. * +* * +* Description : Fournit le contenu représenté de l'élément chargé. * +* * +* Retour : Contenu représenté. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static GBinContent *py_loaded_content_get_content_wrapper(const GLoadedContent *content) +{ + GBinContent *result; /* Contenu interne à renvoyer */ + PyGILState_STATE gstate; /* Sauvegarde d'environnement */ + PyObject *pyobj; /* Objet Python concerné */ + PyObject *pyret; /* Bilan de consultation */ + +#define LOADED_CONTENT_GET_CONTENT_WRAPPER PYTHON_WRAPPER_DEF \ +( \ + _get_content, "$self", \ + METH_VARARGS, \ + "Abstract method used to get the binary content linked to the" \ + " loaded content. The result is provided as a" \ + " pychrysalide.analysis.BinContent instance." \ +) + + result = NULL; + + gstate = PyGILState_Ensure(); + + pyobj = pygobject_new(G_OBJECT(content)); + + if (has_python_method(pyobj, "_get_content")) + { + pyret = run_python_method(pyobj, "_get_content", NULL); + + if (pyret != NULL) + { + if (convert_to_binary_content(pyret, &result) != 1) + PyErr_Clear(); + + Py_DECREF(pyret); + + } + + } + + Py_DECREF(pyobj); + + PyGILState_Release(gstate); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : content = élément chargé à manipuler. * +* * +* Description : Fournit le format associé à l'élément chargé. * +* * +* Retour : Format associé à l'élément chargé. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static char *py_loaded_content_get_format_name_wrapper(const GLoadedContent *content) +{ + char *result; /* Contenu interne à renvoyer */ + PyGILState_STATE gstate; /* Sauvegarde d'environnement */ + PyObject *pyobj; /* Objet Python concerné */ + PyObject *pyret; /* Bilan de consultation */ + int ret; /* Validité d'une conversion */ + +#define LOADED_CONTENT_GET_FORMAT_NAME_WRAPPER PYTHON_WRAPPER_DEF \ +( \ + _get_format_name, "$self", \ + METH_VARARGS, \ + "Abstract method used to provide the aw name of the format connected" \ + " to the loaded content.\n" \ + "\n" \ + "The name associated to a loaded Elf binary is for instance 'elf'." \ +) + + result = NULL; + + gstate = PyGILState_Ensure(); + + pyobj = pygobject_new(G_OBJECT(content)); + + if (has_python_method(pyobj, "_get_format_name")) + { + pyret = run_python_method(pyobj, "_get_format_name", NULL); + + if (pyret != NULL) + { + ret = PyUnicode_Check(pyret); + + if (ret) + result = strdup(PyUnicode_AsUTF8(pyret)); + + Py_DECREF(pyret); + + } + + } + + Py_DECREF(pyobj); + + PyGILState_Release(gstate); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : content = élément chargé à manipuler. * +* connect = organise le lancement des connexions aux serveurs. * +* cache = précise si la préparation d'un rendu est demandée. * +* gid = groupe de travail dédié. * +* status = barre de statut à tenir informée. * +* * +* Description : Lance l'analyse propre à l'élément chargé. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static bool py_loaded_content_analyze_wrapper(GLoadedContent *content, bool connect, bool cache, wgroup_id_t gid, GtkStatusStack *status) +{ + bool result; /* Bilan à retourner */ + PyGILState_STATE gstate; /* Sauvegarde d'environnement */ + PyObject *connect_obj; /* Ordre de connexion */ + PyObject *cache_obj; /* Usage du cache */ + PyObject *args; /* Arguments pour l'appel */ + PyObject *pyobj; /* Objet Python concerné */ + PyObject *pyret; /* Bilan de consultation */ + +#define LOADED_CONTENT_ANALYZE_WRAPPER PYTHON_WRAPPER_DEF \ +( \ + _analyze, "$self, connect, cache, gid, status", \ + METH_VARARGS, \ + "Abstract method used to start the analysis of the loaded binary." \ + "\n" \ + "The *connect* parameter defines if connections to database servers" \ + " (internal and/or remote) will be established. The default value" \ + " depends on the running mode: if the analysis is run from the GUI," \ + " the binary will get connected to servers; in batch mode, no" \ + " connection will be made." \ + "\n" \ + "The *cache* parameter rules the build of the cache for rendering" \ + " lines. The same behavior relative to the running mode applies." \ + "\n" \ + "The identifier refers to the working queue used to process the" \ + " analysis. A reference to the main status bar may also be provided," \ + " as a pychrysalide.gtkext.StatusStack instance if running in" \ + " graphical mode or None otherwise." \ +) + + result = false; + + gstate = PyGILState_Ensure(); + + pyobj = pygobject_new(G_OBJECT(content)); + + if (has_python_method(pyobj, "_analyze")) + { + connect_obj = connect ? Py_True : Py_False; + Py_INCREF(connect_obj); + + cache_obj = cache ? Py_True : Py_False; + Py_INCREF(cache_obj); + + args = PyTuple_New(4); + PyTuple_SetItem(args, 0, connect_obj); + PyTuple_SetItem(args, 1, cache_obj); + PyTuple_SetItem(args, 2, PyLong_FromUnsignedLong(gid)); + PyTuple_SetItem(args, 3, pygobject_new(G_OBJECT(status))); + + pyret = run_python_method(pyobj, "_analyze", args); + + if (pyret != NULL) + { + result = (pyret == Py_True); + Py_DECREF(pyret); + } + + Py_DECREF(args); + + } + + Py_DECREF(pyobj); + + PyGILState_Release(gstate); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : content = élément chargé à consulter. * +* full = précise s'il s'agit d'une version longue ou non. * +* * +* Description : Fournit le désignation associée à l'élément chargé. * +* * +* Retour : Description courante. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static char *py_loaded_content_describe_wrapper(const GLoadedContent *content, bool full) +{ + char *result; /* Description à retourner */ + PyGILState_STATE gstate; /* Sauvegarde d'environnement */ + PyObject *full_obj; /* Précision sur la longueur */ + PyObject *args; /* Arguments pour l'appel */ + PyObject *pyobj; /* Objet Python concerné */ + PyObject *pyret; /* Bilan de consultation */ + int ret; /* Validité d'une conversion */ + +#define LOADED_CONTENT_DESCRIBE_WRAPPER PYTHON_WRAPPER_DEF \ +( \ + _describe, "$self, full", \ + METH_VARARGS, \ + "Abstract method used to describe the loaded content.\n" \ + "\n" \ + "The boolean *full* parameter shapes the size of the returned string.\n" \ + "\n" \ + "This method is mainly used to provide a label (or a tooltip text)" \ + " for tabs in the graphical main window." \ +) + + result = NULL; + + gstate = PyGILState_Ensure(); + + pyobj = pygobject_new(G_OBJECT(content)); + + if (has_python_method(pyobj, "_describe")) + { + full_obj = full ? Py_True : Py_False; + Py_INCREF(full_obj); + + args = PyTuple_New(1); + PyTuple_SetItem(args, 0, full_obj); + + pyret = run_python_method(pyobj, "_describe", args); + + if (pyret != NULL) + { + ret = PyUnicode_Check(pyret); + + if (ret) + result = strdup(PyUnicode_AsUTF8(pyret)); + + Py_DECREF(pyret); + + } + + Py_DECREF(args); + + } + + Py_DECREF(pyobj); + + PyGILState_Release(gstate); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : content = contenu chargé à consulter. * +* * +* Description : Détermine le nombre de vues disponibles pour un contenu. * +* * +* Retour : Quantité strictement positive. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static unsigned int py_loaded_content_count_views_wrapper(const GLoadedContent *content) +{ + unsigned int result; /* Quantité de vues à renvoyer */ + PyGILState_STATE gstate; /* Sauvegarde d'environnement */ + PyObject *pyobj; /* Objet Python concerné */ + PyObject *pyret; /* Bilan de consultation */ + int ret; /* Validité d'une conversion */ + +#define LOADED_CONTENT_COUNT_VIEWS_WRAPPER PYTHON_WRAPPER_DEF \ +( \ + _count_views, "$self", \ + METH_VARARGS, \ + "Abstract method used to compute the quantity of available" \ + " views for the loaded binary." \ +) + + result = 0; + + gstate = PyGILState_Ensure(); + + pyobj = pygobject_new(G_OBJECT(content)); + + if (has_python_method(pyobj, "_count_views")) + { + pyret = run_python_method(pyobj, "_count_views", NULL); + + if (pyret != NULL) + { + ret = PyLong_Check(pyret); + + if (ret) + result = PyLong_AsUnsignedLong(pyret); + + Py_DECREF(pyret); + + } + + } + + Py_DECREF(pyobj); + + PyGILState_Release(gstate); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : content = contenu chargé à consulter. * +* index = indice de la vue ciblée. * +* * +* Description : Fournit le nom d'une vue donnée d'un contenu chargé. * +* * +* Retour : Désignation humainement lisible. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static char *py_loaded_content_get_view_name_wrapper(const GLoadedContent *content, unsigned int index) +{ + char *result; /* Désignation à retourner */ + PyGILState_STATE gstate; /* Sauvegarde d'environnement */ + PyObject *args; /* Arguments pour l'appel */ + PyObject *pyobj; /* Objet Python concerné */ + PyObject *pyret; /* Bilan de consultation */ + int ret; /* Validité d'une conversion */ + +#define LOADED_CONTENT_GET_VIEW_NAME_WRAPPER PYTHON_WRAPPER_DEF \ +( \ + _get_view_name, "$self, index", \ + METH_VARARGS, \ + "Abstract method used to provide the human readable name for" \ + " a given view of a loaded binary.\n" \ + "\n" \ + "Such a method is used in the graphical main window for" \ + " building menu labels." \ +) + + result = NULL; + + gstate = PyGILState_Ensure(); + + pyobj = pygobject_new(G_OBJECT(content)); + + if (has_python_method(pyobj, "_get_view_name")) + { + args = PyTuple_New(1); + PyTuple_SetItem(args, 0, PyLong_FromUnsignedLong(index)); + + pyret = run_python_method(pyobj, "_get_view_name", args); + + if (pyret != NULL) + { + ret = PyUnicode_Check(pyret); + + if (ret) + result = strdup(PyUnicode_AsUTF8(pyret)); + + Py_DECREF(pyret); + + } + + Py_DECREF(args); + + } + + Py_DECREF(pyobj); + + PyGILState_Release(gstate); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : content = contenu chargé à consulter. * +* * +* Description : Met en place la vue initiale pour un contenu chargé. * +* * +* Retour : Composant graphique nouveau. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static GtkWidget *py_loaded_content_build_default_view_wrapper(GLoadedContent *content) +{ + GtkWidget *result; /* Support à retourner */ + PyGILState_STATE gstate; /* Sauvegarde d'environnement */ + PyObject *pyobj; /* Objet Python concerné */ + PyObject *pyret; /* Bilan de consultation */ + int ret; /* Validité d'une conversion */ + +#define LOADED_CONTENT_BUILD_DEFAULT_VIEW_WRAPPER PYTHON_WRAPPER_DEF \ +( \ + _build_default_view, "$self", \ + METH_VARARGS, \ + "Abstract method used to build a new widget for the default graphical" \ + " view of the loaded content." \ + "\n" \ + "This method is aimed to only be called from the GUI internals." \ + " It provides the first view displayed in the main Chrysalide window" \ + " after a binary loading." \ +) + + result = NULL; + + gstate = PyGILState_Ensure(); + + pyobj = pygobject_new(G_OBJECT(content)); + + if (has_python_method(pyobj, "_build_default_view")) + { + pyret = run_python_method(pyobj, "_build_default_view", NULL); + + if (pyret != NULL) + { + ret = convert_to_gtk_widget(pyret, &result); + + if (ret == 1) + g_object_ref(G_OBJECT(result)); + + Py_DECREF(pyret); + + } + + } + + Py_DECREF(pyobj); + + PyGILState_Release(gstate); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : content = contenu chargé à consulter. * +* index = indice de la vue ciblée. * +* * +* Description : Met en place la vue demandée pour un contenu chargé. * +* * +* Retour : Composant graphique nouveau. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static GtkWidget *py_loaded_content_build_view_wrapper(GLoadedContent *content, unsigned int index) +{ + GtkWidget *result; /* Support à retourner */ + PyGILState_STATE gstate; /* Sauvegarde d'environnement */ + PyObject *args; /* Arguments pour l'appel */ + PyObject *pyobj; /* Objet Python concerné */ + PyObject *pyret; /* Bilan de consultation */ + int ret; /* Validité d'une conversion */ + +#define LOADED_CONTENT_BUILD_VIEW_WRAPPER PYTHON_WRAPPER_DEF \ +( \ + _build_view, "$self, index", \ + METH_VARARGS, \ + "Abstract method used to build a new widget for a given graphical view" \ + " of the loaded content.\n" \ + "\n" \ + "This method is aimed to only be called from the GUI internals." \ + " It provides a view displayed in the main Chrysalide window" \ + " once the binary is loaded." \ +) + + result = NULL; + + gstate = PyGILState_Ensure(); + + pyobj = pygobject_new(G_OBJECT(content)); + + if (has_python_method(pyobj, "_build_view")) + { + args = PyTuple_New(1); + PyTuple_SetItem(args, 0, PyLong_FromUnsignedLong(index)); + + pyret = run_python_method(pyobj, "_build_view", args); + + if (pyret != NULL) + { + ret = convert_to_gtk_widget(pyret, &result); + + if (ret == 1) + g_object_ref(G_OBJECT(result)); + + Py_DECREF(pyret); + + } + + Py_DECREF(args); + + } + + Py_DECREF(pyobj); + + PyGILState_Release(gstate); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : content = contenu chargé à consulter. * +* index = composant graphique en place. * +* * +* Description : Retrouve l'indice correspondant à la vue donnée d'un contenu.* +* * +* Retour : Indice de la vue représentée, ou -1 en cas d'erreur. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static unsigned int py_loaded_content_get_view_index_wrapper(GLoadedContent *content, GtkWidget *view) +{ + unsigned int result; /* Indice à retourner */ + PyGILState_STATE gstate; /* Sauvegarde d'environnement */ + PyObject *args; /* Arguments pour l'appel */ + PyObject *pyobj; /* Objet Python concerné */ + PyObject *pyret; /* Bilan de consultation */ + int ret; /* Validité d'une conversion */ + +#define LOADED_CONTENT_GET_VIEW_INDEX_WRAPPER PYTHON_WRAPPER_DEF \ +( \ + _get_view_index, "$self, view", \ + METH_VARARGS, \ + "Abstract method used to define the index of a given view for the" \ + " loaded binary.\n" \ + "\n" \ + "The view is provided as a GTK *widget*.\n" \ + "\n" \ + "The result is the index of the type of view, or -1 in case of error." \ +) + + result = 0; + + gstate = PyGILState_Ensure(); + + pyobj = pygobject_new(G_OBJECT(content)); + + if (has_python_method(pyobj, "_get_view_index")) + { + args = PyTuple_New(1); + PyTuple_SetItem(args, 0, pygobject_new(G_OBJECT(view))); + + pyret = run_python_method(pyobj, "_get_view_index", args); + + if (pyret != NULL) + { + ret = PyLong_Check(pyret); + + if (ret) + result = PyLong_AsUnsignedLong(pyret); + + Py_DECREF(pyret); + + } + + Py_DECREF(args); + + } + + Py_DECREF(pyobj); + + PyGILState_Release(gstate); + + return result; + +} + + + +/* ---------------------------------------------------------------------------------- */ +/* CONNEXION AVEC L'API DE PYTHON */ +/* ---------------------------------------------------------------------------------- */ + + /****************************************************************************** * * * Paramètres : self = contenu binaire à manipuler. * @@ -416,15 +1130,16 @@ static PyObject *py_loaded_content_build_default_view(PyObject *self, PyObject * GLoadedContent *content; /* Version GLib de l'élément */ GtkWidget *view; /* Composant GTK à transposer */ -#define LOADED_CONTENT_BUILD_DEFAULT_VIEW_METHOD PYTHON_METHOD_DEF \ -( \ - build_default_view, "$self", \ - METH_NOARGS, py_loaded_content, \ - "Build a new widget for the default graphical view of the loaded content." \ - "\n" \ - "This method is aimed to only be called from the GUI internals." \ - " It provides the first view displayed in the main Chrysalide window" \ - " after a binary loading." \ +#define LOADED_CONTENT_BUILD_DEFAULT_VIEW_METHOD PYTHON_METHOD_DEF \ +( \ + build_default_view, "$self", \ + METH_NOARGS, py_loaded_content, \ + "Build a new widget for the default graphical view of the loaded" \ + " content.\n" \ + "\n" \ + "This method is aimed to only be called from the GUI internals." \ + " It provides the first view displayed in the main Chrysalide window" \ + " after a binary loading." \ ) content = G_LOADED_CONTENT(pygobject_get(self)); @@ -461,15 +1176,16 @@ static PyObject *py_loaded_content_build_view(PyObject *self, PyObject *args) GLoadedContent *content; /* Version GLib de l'élément */ GtkWidget *view; /* Composant GTK à transposer */ -#define LOADED_CONTENT_BUILD_VIEW_METHOD PYTHON_METHOD_DEF \ -( \ - build_view, "$self, index", \ - METH_VARARGS, py_loaded_content, \ - "Build a new widget for a given graphical view of the loaded content." \ - "\n" \ - "This method is aimed to only be called from the GUI internals." \ - " It provides a view displayed in the main Chrysalide window" \ - " once the binary is loaded." \ +#define LOADED_CONTENT_BUILD_VIEW_METHOD PYTHON_METHOD_DEF \ +( \ + build_view, "$self, index", \ + METH_VARARGS, py_loaded_content, \ + "Build a new widget for a given graphical view of the loaded" \ + " content.\n" \ + "\n" \ + "This method is aimed to only be called from the GUI internals." \ + " It provides a view displayed in the main Chrysalide window" \ + " once the binary is loaded." \ ) ret = PyArg_ParseTuple(args, "I", &index); @@ -541,12 +1257,6 @@ static PyObject *py_loaded_content_get_view_index(PyObject *self, PyObject *args if (!ret) return NULL; - if (!GTK_IS_WIDGET(pygobject_get(widget_obj))) - { - PyErr_SetString(PyExc_TypeError, "unable to convert the provided argument to GTK widget"); - return NULL; - } - content = G_LOADED_CONTENT(pygobject_get(self)); widget = GTK_WIDGET(pygobject_get(widget_obj)); @@ -653,6 +1363,15 @@ static PyObject *py_loaded_content_get_format_name(PyObject *self, void *closure 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_ANALYZE_WRAPPER, + LOADED_CONTENT_DESCRIBE_WRAPPER, + 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, LOADED_CONTENT_ANALYZE_METHOD, LOADED_CONTENT_ANALYZE_AND_WAIT_METHOD, LOADED_CONTENT_DESCRIBE_METHOD, @@ -710,6 +1429,14 @@ 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)) @@ -718,7 +1445,7 @@ bool ensure_python_loaded_content_is_registered(void) dict = PyModule_GetDict(module); - if (!register_interface_for_pygobject(dict, G_TYPE_LOADED_CONTENT, type)) + if (!register_interface_for_pygobject_2(dict, G_TYPE_LOADED_CONTENT, type, &info)) return false; } diff --git a/plugins/pychrysalide/analysis/storage/serialize.c b/plugins/pychrysalide/analysis/storage/serialize.c index 67e1256..3e94271 100644 --- a/plugins/pychrysalide/analysis/storage/serialize.c +++ b/plugins/pychrysalide/analysis/storage/serialize.c @@ -97,7 +97,7 @@ static void py_serializable_object_interface_init(GSerializableObjectIface *ifac "\n" \ "The following methods have to be defined for new implementations:\n" \ "* pychrysalide.analysis.storage.SerializableObject._load();\n" \ - "* pychrysalide.analysis.storage.SerializableObject._store();\n" \ + "* pychrysalide.analysis.storage.SerializableObject._store();\n" iface->load = py_serializable_object_load_wrapper; iface->store = py_serializable_object_store_wrapper; diff --git a/plugins/pychrysalide/gtkext/dockable.c b/plugins/pychrysalide/gtkext/dockable.c index 8bb26b7..1412589 100644 --- a/plugins/pychrysalide/gtkext/dockable.c +++ b/plugins/pychrysalide/gtkext/dockable.c @@ -299,8 +299,6 @@ static GtkWidget *py_dockable_get_widget_wrapper(const GtkDockable *dockable) PyGILState_STATE gstate; /* Sauvegarde d'environnement */ PyObject *pyobj; /* Objet Python concerné */ PyObject *pyret; /* Bilan de consultation */ - PyObject *gtk_mod; /* Module Python Gtk */ - PyObject *widget_type; /* Module "GtkWidget" */ int ret; /* Bilan d'une conversion */ #define DOCKABLE_GET_WIDGET_WRAPPER PYTHON_WRAPPER_DEF \ @@ -312,6 +310,8 @@ static GtkWidget *py_dockable_get_widget_wrapper(const GtkDockable *dockable) "The result has to be a Gtk.Widget instance." \ ) + result = NULL; + gstate = PyGILState_Ensure(); pyobj = pygobject_new(G_OBJECT(dockable)); @@ -322,32 +322,10 @@ static GtkWidget *py_dockable_get_widget_wrapper(const GtkDockable *dockable) if (pyret != NULL) { - gtk_mod = PyImport_ImportModule("gi.repository.Gtk"); - - if (gtk_mod == NULL) - { - PyErr_SetString(PyExc_TypeError, "unable to find the Gtk Python module"); - goto done; - } - - widget_type = PyObject_GetAttrString(gtk_mod, "Widget"); - - Py_DECREF(gtk_mod); - - ret = PyObject_TypeCheck(pyret, (PyTypeObject *)widget_type); - - Py_DECREF(widget_type); - - if (!ret) - { - PyErr_SetString(PyExc_TypeError, "unable to convert the provided argument to GTK widget"); - goto done; - } - - result = GTK_WIDGET(pygobject_get(pyret)); - g_object_ref(G_OBJECT(result)); + ret = convert_to_gtk_widget(pyret, &result); - done: + if (ret == 1) + g_object_ref(G_OBJECT(result)); Py_DECREF(pyret); diff --git a/plugins/pychrysalide/gtkext/graph/cluster.c b/plugins/pychrysalide/gtkext/graph/cluster.c index c87655a..fc73276 100644 --- a/plugins/pychrysalide/gtkext/graph/cluster.c +++ b/plugins/pychrysalide/gtkext/graph/cluster.c @@ -161,12 +161,6 @@ static PyObject *py_graph_cluster_find_by_widget(PyObject *self, PyObject *args) if (!ret) return NULL; - if (!GTK_IS_WIDGET(pygobject_get(widget_obj))) - { - PyErr_SetString(PyExc_TypeError, "unable to convert the provided argument to GTK widget"); - return NULL; - } - cluster = G_GRAPH_CLUSTER(pygobject_get(self)); widget = GTK_WIDGET(pygobject_get(widget_obj)); diff --git a/plugins/pychrysalide/helpers.c b/plugins/pychrysalide/helpers.c index 5c7ae75..3cd528e 100644 --- a/plugins/pychrysalide/helpers.c +++ b/plugins/pychrysalide/helpers.c @@ -32,6 +32,7 @@ #include #include #include +#include #include @@ -1132,6 +1133,61 @@ int convert_to_gobject(PyObject *arg, void *dst) } +/****************************************************************************** +* * +* Paramètres : arg = argument quelconque à tenter de convertir. * +* dst = destination des valeurs récupérées en cas de succès. * +* * +* Description : Tente de convertir en instance de composant GTK. * +* * +* Retour : Bilan de l'opération, voire indications supplémentaires. * +* * +* Remarques : - * +* * +******************************************************************************/ + +int convert_to_gtk_widget(PyObject *arg, void *dst) +{ + int result; /* Bilan à retourner */ + PyObject *gtk_mod; /* Module Python Gtk */ + PyObject *widget_type; /* Module "GtkWidget" */ + int ret; /* Bilan d'une conversion */ + + result = 0; + + gtk_mod = PyImport_ImportModule("gi.repository.Gtk"); + + if (gtk_mod == NULL) + { + PyErr_SetString(PyExc_TypeError, "unable to find the Gtk Python module"); + goto done; + } + + widget_type = PyObject_GetAttrString(gtk_mod, "Widget"); + + Py_DECREF(gtk_mod); + + ret = PyObject_TypeCheck(arg, (PyTypeObject *)widget_type); + + Py_DECREF(widget_type); + + if (!ret) + { + PyErr_SetString(PyExc_TypeError, "unable to convert the provided argument to GTK widget"); + goto done; + } + + *((GtkWidget **)dst) = GTK_WIDGET(pygobject_get(arg)); + + result = 1; + + done: + + return result; + +} + + /* ---------------------------------------------------------------------------------- */ /* TRANSFERT DES VALEURS CONSTANTES */ diff --git a/plugins/pychrysalide/helpers.h b/plugins/pychrysalide/helpers.h index fd0ece7..a74a747 100644 --- a/plugins/pychrysalide/helpers.h +++ b/plugins/pychrysalide/helpers.h @@ -187,6 +187,9 @@ int forward_pygobjet_init(PyObject *); /* Tente de convertir en instance GObject. */ int convert_to_gobject(PyObject *, void *); +/* Tente de convertir en instance de composant GTK. */ +int convert_to_gtk_widget(PyObject *, void *); + /* ----------------------- TRANSFERT DES VALEURS CONSTANTES ------------------------- */ diff --git a/src/analysis/binary.c b/src/analysis/binary.c index ad4ec1f..aee4499 100644 --- a/src/analysis/binary.c +++ b/src/analysis/binary.c @@ -167,7 +167,7 @@ static bool g_loaded_binary_save(GLoadedBinary *, xmlDoc *, xmlXPathContext *, c static GBinContent *g_loaded_binary_get_content(const GLoadedBinary *); /* Fournit le contenu représenté de l'élément chargé. */ -static const char *g_loaded_binary_get_format_name(const GLoadedBinary *); +static char *g_loaded_binary_get_format_name(const GLoadedBinary *); /* Assure le désassemblage en différé. */ static bool g_loaded_binary_analyze(GLoadedBinary *, bool, bool, wgroup_id_t, GtkStatusStack *); @@ -176,13 +176,13 @@ static bool g_loaded_binary_analyze(GLoadedBinary *, bool, bool, wgroup_id_t, Gt static void on_binary_processor_changed(GArchProcessor *, GArchInstruction *, gboolean, GLoadedBinary *); /* Fournit le désignation associée à l'élément chargé. */ -static const char *g_loaded_binary_describe(const GLoadedBinary *, bool); +static char *g_loaded_binary_describe(const GLoadedBinary *, bool); /* Détermine le nombre de vues disponibles pour un contenu. */ static unsigned int g_loaded_binary_count_views(const GLoadedBinary *); /* Fournit le nom d'une vue donnée d'un contenu chargé. */ -static const char *g_loaded_binary_get_view_name(const GLoadedBinary *, unsigned int); +static char *g_loaded_binary_get_view_name(const GLoadedBinary *, unsigned int); /* Met en place la vue initiale pour un contenu binaire. */ static GtkWidget *g_loaded_binary_build_default_view(GLoadedBinary *); @@ -1616,9 +1616,9 @@ static GBinContent *g_loaded_binary_get_content(const GLoadedBinary *binary) * * ******************************************************************************/ -static const char *g_loaded_binary_get_format_name(const GLoadedBinary *binary) +static char *g_loaded_binary_get_format_name(const GLoadedBinary *binary) { - const char *result; /* Désignation à retourner */ + char *result; /* Désignation à retourner */ result = g_known_format_get_key(G_KNOWN_FORMAT(binary->format)); @@ -1845,9 +1845,9 @@ static void on_binary_processor_changed(GArchProcessor *proc, GArchInstruction * * * ******************************************************************************/ -static const char *g_loaded_binary_describe(const GLoadedBinary *binary, bool full) +static char *g_loaded_binary_describe(const GLoadedBinary *binary, bool full) { - const char *result; /* Description à retourner */ + char *result; /* Description à retourner */ GBinContent *content; /* Contenu binaire mannipulé */ content = g_known_format_get_content(G_KNOWN_FORMAT(binary->format)); @@ -1875,7 +1875,11 @@ static const char *g_loaded_binary_describe(const GLoadedBinary *binary, bool fu static unsigned int g_loaded_binary_count_views(const GLoadedBinary *binary) { - return BVW_COUNT; + unsigned int result; /* Quantité de vues à renvoyer */ + + result = BVW_COUNT; + + return result; } @@ -1893,22 +1897,22 @@ static unsigned int g_loaded_binary_count_views(const GLoadedBinary *binary) * * ******************************************************************************/ -static const char *g_loaded_binary_get_view_name(const GLoadedBinary *binary, unsigned int index) +static char *g_loaded_binary_get_view_name(const GLoadedBinary *binary, unsigned int index) { - const char *result; /* Désignation à retourner */ + char *result; /* Désignation à retourner */ switch (index) { case BVW_HEX: - result = _("Hex view"); + result = strdup(_("Hex view")); break; case BVW_BLOCK: - result = _("Text view"); + result = strdup(_("Text view")); break; case BVW_GRAPH: - result = _("Graph view"); + result = strdup(_("Graph view")); break; default: diff --git a/src/analysis/content.c b/src/analysis/content.c index 007d46a..86fa490 100644 --- a/src/analysis/content.c +++ b/src/analysis/content.c @@ -199,11 +199,14 @@ GBinContent *g_binary_content_get_root(GBinContent *content) const char *g_binary_content_describe(const GBinContent *content, bool full) { + char *result; /* Description à retourner */ GBinContentIface *iface; /* Interface utilisée */ iface = G_BIN_CONTENT_GET_IFACE(content); - return iface->describe(content, full); + result = strdup(iface->describe(content, full)); + + return result; } diff --git a/src/analysis/loaded-int.h b/src/analysis/loaded-int.h index 0aacc3f..0476af5 100644 --- a/src/analysis/loaded-int.h +++ b/src/analysis/loaded-int.h @@ -40,19 +40,19 @@ typedef bool (* save_content_fc) (GLoadedContent *, xmlDoc *, xmlXPathContext *, typedef GBinContent * (* get_content_fc) (const GLoadedContent *); /* Fournit le format associé à l'élément chargé. */ -typedef const char * (* get_format_name_fc) (const GLoadedContent *); +typedef char * (* get_format_name_fc) (const GLoadedContent *); /* Assure l'analyse d'un contenu chargé en différé. */ typedef bool (* analyze_loaded_fc) (GLoadedContent *, bool, bool, wgroup_id_t, GtkStatusStack *); /* Fournit le désignation associée à l'élément chargé. */ -typedef const char * (* describe_loaded_fc) (const GLoadedContent *, bool); +typedef char * (* describe_loaded_fc) (const GLoadedContent *, bool); /* Détermine le nombre de vues disponibles pour un contenu. */ typedef unsigned int (* count_loaded_views_fc) (const GLoadedContent *); /* Fournit le nom d'une vue donnée d'un contenu chargé. */ -typedef const char * (* get_loaded_view_name_fc) (const GLoadedContent *, unsigned int); +typedef char * (* get_loaded_view_name_fc) (const GLoadedContent *, unsigned int); /* Met en place la vue initiale pour un contenu chargé. */ typedef GtkWidget * (* build_loaded_def_view_fc) (GLoadedContent *); diff --git a/src/analysis/loaded.c b/src/analysis/loaded.c index 79a311f..71b1838 100644 --- a/src/analysis/loaded.c +++ b/src/analysis/loaded.c @@ -245,9 +245,9 @@ GBinContent *g_loaded_content_get_content(const GLoadedContent *content) * * ******************************************************************************/ -const char *g_loaded_content_get_format_name(const GLoadedContent *content) +char *g_loaded_content_get_format_name(const GLoadedContent *content) { - const char *result; /* Contenu interne à renvoyer */ + char *result; /* Contenu interne à renvoyer */ GLoadedContentIface *iface; /* Interface utilisée */ iface = G_LOADED_CONTENT_GET_IFACE(content); @@ -365,13 +365,16 @@ bool g_loaded_content_analyze_and_wait(GLoadedContent *content, bool connect, bo * * ******************************************************************************/ -const char *g_loaded_content_describe(const GLoadedContent *content, bool full) +char *g_loaded_content_describe(const GLoadedContent *content, bool full) { + char *result; /* Description à retourner */ GLoadedContentIface *iface; /* Interface utilisée */ iface = G_LOADED_CONTENT_GET_IFACE(content); - return iface->describe(content, full); + result = iface->describe(content, full); + + return result; } @@ -424,11 +427,14 @@ char **g_loaded_content_detect_obfuscators(const GLoadedContent *content, bool v unsigned int g_loaded_content_count_views(const GLoadedContent *content) { + unsigned int result; /* Quantité de vues à renvoyer */ GLoadedContentIface *iface; /* Interface utilisée */ iface = G_LOADED_CONTENT_GET_IFACE(content); - return iface->count_views(content); + result = iface->count_views(content); + + return result; } @@ -446,9 +452,9 @@ unsigned int g_loaded_content_count_views(const GLoadedContent *content) * * ******************************************************************************/ -const char *g_loaded_content_get_view_name(const GLoadedContent *content, unsigned int index) +char *g_loaded_content_get_view_name(const GLoadedContent *content, unsigned int index) { - const char *result; /* Désignation à retourner */ + char *result; /* Désignation à retourner */ GLoadedContentIface *iface; /* Interface utilisée */ iface = G_LOADED_CONTENT_GET_IFACE(content); diff --git a/src/analysis/loaded.h b/src/analysis/loaded.h index 9df647b..9d446c4 100644 --- a/src/analysis/loaded.h +++ b/src/analysis/loaded.h @@ -68,7 +68,7 @@ bool g_loaded_content_save(GLoadedContent *, xmlDoc *, xmlXPathContext *, const GBinContent *g_loaded_content_get_content(const GLoadedContent *); /* Fournit le format associé à l'élément chargé. */ -const char *g_loaded_content_get_format_name(const GLoadedContent *); +char *g_loaded_content_get_format_name(const GLoadedContent *); /* Lance l'analyse propre à l'élément chargé. */ void g_loaded_content_analyze(GLoadedContent *, bool, bool); @@ -77,7 +77,7 @@ void g_loaded_content_analyze(GLoadedContent *, bool, bool); bool g_loaded_content_analyze_and_wait(GLoadedContent *, bool, bool); /* Fournit le désignation associée à l'élément chargé. */ -const char *g_loaded_content_describe(const GLoadedContent *, bool); +char *g_loaded_content_describe(const GLoadedContent *, bool); /* Etablit une liste d'obscurcissements présents. */ char **g_loaded_content_detect_obfuscators(const GLoadedContent *, bool, size_t *); @@ -91,7 +91,7 @@ char **g_loaded_content_detect_obfuscators(const GLoadedContent *, bool, size_t unsigned int g_loaded_content_count_views(const GLoadedContent *); /* Fournit le nom d'une vue donnée d'un contenu chargé. */ -const char *g_loaded_content_get_view_name(const GLoadedContent *, unsigned int); +char *g_loaded_content_get_view_name(const GLoadedContent *, unsigned int); /* Met en place la vue initiale pour un contenu chargé. */ GtkWidget *g_loaded_content_build_default_view(GLoadedContent *); diff --git a/src/analysis/project.c b/src/analysis/project.c index 71e0f43..13985f3 100644 --- a/src/analysis/project.c +++ b/src/analysis/project.c @@ -388,7 +388,7 @@ bool g_study_project_save(GStudyProject *project, const char *filename) const gchar *hash; /* Empreinte d'un contenu */ char *access; /* Chemin pour une sous-config.*/ xmlXPathObjectPtr xobject; /* Cible d'une recherche */ - const char *format; /* Format associé à un élément */ + char *format; /* Format associé à un élément */ /* Forme générale */ @@ -470,6 +470,7 @@ bool g_study_project_save(GStudyProject *project, const char *filename) { format = g_loaded_content_get_format_name(project->contents[i]); result = add_string_attribute_to_node(xdoc, context, access, "format", format); + free(format); } if (result) @@ -597,7 +598,7 @@ void g_study_project_discover_binary_content(GStudyProject *project, GBinContent void on_loaded_content_analyzed(GLoadedContent *content, gboolean success, GStudyProject *project) { - const char *desc; /* Description du contenu */ + char *desc; /* Description du contenu */ desc = g_loaded_content_describe(content, true); @@ -610,6 +611,8 @@ void on_loaded_content_analyzed(GLoadedContent *content, gboolean success, GStud else log_variadic_message(LMT_ERROR, _("Failed to load '%s'"), desc); + free(desc); + /** * Le contenu a normalement été sur-référencé pour ne pas disparaître * en cours d'analyse. @@ -1291,7 +1294,7 @@ static void on_new_content_resolved(GContentResolver *resolver, wgroup_id_t wid, size_t i; /* Boucle de parcours */ GBinContent *content; /* Contenu brut à manipuler */ const gchar *hash; /* Empreinte d'un contenu */ - const char *format; /* Format associé à un élément */ + char *format; /* Format associé à un élément */ char *access; /* Chemin pour une sous-config.*/ xmlXPathObjectPtr xobject; /* Cible d'une recherche */ bool status; /* Bilan d'une restauration */ @@ -1316,6 +1319,8 @@ static void on_new_content_resolved(GContentResolver *resolver, wgroup_id_t wid, asprintf(&access, "/ChrysalideProject/LoadedContents/Content[@hash='%s' and @format='%s']", hash, format); + free(format); + xobject = get_node_xpath_object(handler->context, access); if (XPATH_OBJ_NODES_COUNT(xobject) > 0) diff --git a/src/gui/dialogs/loading.c b/src/gui/dialogs/loading.c index 3e71df4..97cd892 100644 --- a/src/gui/dialogs/loading.c +++ b/src/gui/dialogs/loading.c @@ -457,6 +457,8 @@ static void update_loading_dialog_counter(GtkBuilder *builder) void add_content_to_loading_dialog(GtkBuilder *builder, GLoadedContent *content, GStudyProject *project) { GtkListStore *store; /* Modèle de gestion */ + char *desc; /* Description d'un contenu */ + char *format; /* Format associé à un contenu */ char *name; /* Désignation complète */ gboolean recognized; /* Nature du contenu */ GtkTreeIter iter; /* Point d'insertion */ @@ -472,9 +474,13 @@ void add_content_to_loading_dialog(GtkBuilder *builder, GLoadedContent *content, /* Inscription */ - asprintf(&name, "%s (%s)", - g_loaded_content_describe(content, false), - g_loaded_content_get_format_name(content)); + desc = g_loaded_content_describe(content, false); + format = g_loaded_content_get_format_name(content); + + asprintf(&name, "%s (%s)", desc, format); + + free(format); + free(desc); recognized = TRUE; diff --git a/src/gui/editor.c b/src/gui/editor.c index bdd9a78..8e20cc1 100644 --- a/src/gui/editor.c +++ b/src/gui/editor.c @@ -926,8 +926,8 @@ static void on_editor_content_available(GStudyProject *project, GLoadedContent * static void on_editor_loaded_content_added(GStudyProject *project, GLoadedContent *content, void *unused) { GtkWidget *selected; /* Interface de prédilection */ - const char *name; /* Titre associé au binaire */ - const char *lname; /* Description du binaire */ + char *name; /* Titre associé au binaire */ + char *lname; /* Description du binaire */ GPanelItem *panel; /* Nouveau panneau à integrer */ selected = g_loaded_content_build_default_view(content); @@ -936,6 +936,10 @@ static void on_editor_loaded_content_added(GStudyProject *project, GLoadedConten lname = g_loaded_content_describe(content, true); panel = g_panel_item_new(PIP_BINARY_VIEW, name, lname, selected, true, "M"); + + free(lname); + free(name); + register_panel_item(panel, get_main_configuration()); g_signal_connect(selected, "size-allocate", G_CALLBACK(scroll_for_the_first_time), content); diff --git a/src/gui/menus/project.c b/src/gui/menus/project.c index f0b9c17..a5992bf 100644 --- a/src/gui/menus/project.c +++ b/src/gui/menus/project.c @@ -117,7 +117,7 @@ void update_menu_project_for_project(GtkWidget *widget, GStudyProject *project, size_t count; /* Nombre de contenus attachés */ GLoadedContent **contents; /* Liste de ces contenus */ size_t i; /* Boucle de parcours #2 */ - const char *desc; /* Description à afficher */ + char *desc; /* Description à afficher */ GtkWidget *submenuitem; /* Sous-menu à ajouter */ menuitem = GTK_WIDGET(g_object_get_data(G_OBJECT(widget), "menu_prj_remove_bin")); @@ -145,6 +145,8 @@ void update_menu_project_for_project(GtkWidget *widget, GStudyProject *project, g_object_set_data_full(G_OBJECT(submenuitem), "content", contents[i], g_object_unref); gtk_container_add(GTK_CONTAINER(menubar), submenuitem); + free(desc); + /** * Note : l'appel à g_object_unref() est réalisé lorsque la référence * est retirée du menu. diff --git a/src/gui/menus/view.c b/src/gui/menus/view.c index bc833a3..b9451e0 100644 --- a/src/gui/menus/view.c +++ b/src/gui/menus/view.c @@ -198,6 +198,7 @@ void rebuild_menu_view_for_content(GtkWidget *widget, GObject *ref, GLoadedConte GList *iter; /* Boucle de parcours */ unsigned int count; /* Nombre d'itérations à mener */ GSList *rgroup; /* Groupe des boutons radio */ + char *caption; /* Etiquette pour un menu */ /* Retrait d'éventuels anciens menus */ @@ -246,12 +247,13 @@ void rebuild_menu_view_for_content(GtkWidget *widget, GObject *ref, GLoadedConte for (i = 0; i < count; i++) { asprintf(&key, "mnu_view_panel_%u", i); + caption = g_loaded_content_get_view_name(new, i); - submenuitem = qck_create_radio_menu_item(ref, key, rgroup, - g_loaded_content_get_view_name(new, i), + submenuitem = qck_create_radio_menu_item(ref, key, rgroup, caption, G_CALLBACK(mcb_view_change_support), NULL); g_object_set_data(G_OBJECT(submenuitem), "kind_of_view", GUINT_TO_POINTER(i)); + free(caption); free(key); asprintf(&key, "F%u", 3 + i); diff --git a/src/gui/panel.c b/src/gui/panel.c index a98119f..2ebcdad 100644 --- a/src/gui/panel.c +++ b/src/gui/panel.c @@ -258,13 +258,13 @@ GPanelItem *g_panel_item_new(PanelItemPersonality personality, const char *name, parent = G_EDITOR_ITEM(result); - parent->name = name; + parent->name = strdup(name); parent->widget = widget; assert(personality > PIP_INVALID && personality < PIP_COUNT); result->personality = personality; - result->lname = lname; + result->lname = strdup(lname); result->dock_at_startup = startup; result->path = strdup(path); -- cgit v0.11.2-87-g4458