From 94cb8acac1027a4deee933c84d7918f4a5ea4983 Mon Sep 17 00:00:00 2001 From: Cyrille Bagard Date: Mon, 28 Jan 2019 01:24:40 +0100 Subject: Allowed to filter contents before running analysis. --- configure.ac | 2 +- plugins/pychrysalide/analysis/project.c | 80 ++++++++++++++++++++++++++++++--- plugins/pychrysalide/helpers.c | 45 +++++++++++++++++++ plugins/pychrysalide/helpers.h | 3 ++ src/analysis/project.c | 69 ++++++++++++++++++++++------ src/analysis/project.h | 8 +++- src/gui/editor.c | 49 +++++++++++++++++++- src/gui/menus/project.c | 2 +- src/main.c | 2 +- 9 files changed, 236 insertions(+), 24 deletions(-) diff --git a/configure.ac b/configure.ac index 9effa17..c8e6cf1 100644 --- a/configure.ac +++ b/configure.ac @@ -332,7 +332,7 @@ AC_SUBST(LIBPYGOBJECT_LIBS) AC_CONFIG_FILES([stamp-h po/Makefile.in], [echo timestamp > stamp-h]) -AC_CONFIG_COMMANDS([marshal], [echo -e "VOID:UINT64\nVOID:INT,UINT64,INT\nVOID:OBJECT,OBJECT\nVOID:ENUM,OBJECT\nVOID:ENUM,ENUM\nVOID:BOOLEAN,UINT64\nVOID:BOOLEAN,ULONG,ULONG\nVOID:INT,INT\nVOID:OBJECT,BOOLEAN\nVOID:ULONG,BOOLEAN" > src/glibext/chrysamarshal.list]) +AC_CONFIG_COMMANDS([marshal], [echo -e "VOID:UINT64\nVOID:INT,UINT64,INT\nVOID:OBJECT,OBJECT\nVOID:ENUM,OBJECT\nVOID:ENUM,ENUM\nVOID:BOOLEAN,UINT64\nVOID:BOOLEAN,ULONG,ULONG\nVOID:INT,INT\nVOID:OBJECT,BOOLEAN\nVOID:ULONG,BOOLEAN\nVOID:POINTER,UINT" > src/glibext/chrysamarshal.list]) AC_CONFIG_FILES([Makefile doc/Makefile diff --git a/plugins/pychrysalide/analysis/project.c b/plugins/pychrysalide/analysis/project.c index 1a85f71..137efbf 100644 --- a/plugins/pychrysalide/analysis/project.c +++ b/plugins/pychrysalide/analysis/project.c @@ -45,6 +45,9 @@ static PyObject *py_study_project_new(PyTypeObject *, PyObject *, PyObject *); /* Procède à l'enregistrement d'un projet donné. */ static PyObject *py_study_project_save(PyObject *, PyObject *); +/* Détermine si un contenu doit être écarté ou conservé. */ +static bool filter_loadable_content_with_python(GLoadedContent *, PyObject *); + /* Assure l'intégration de contenus binaires dans un projet. */ static PyObject *py_study_project_discover_binary_content(PyObject *, PyObject *); @@ -135,6 +138,57 @@ static PyObject *py_study_project_save(PyObject *self, PyObject *args) /****************************************************************************** * * +* Paramètres : content = contenu chargeable à étudier ou NULL à la fin. * +* callable = procédure de filtre en Python. * +* * +* Description : Détermine si un contenu doit être écarté ou conservé. * +* * +* Retour : true si le contenu doit être conservé, false sinon. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static bool filter_loadable_content_with_python(GLoadedContent *content, PyObject *callable) +{ + bool result; /* Bilan à retourner */ + PyGILState_STATE gstate; /* Sauvegarde d'environnement */ + PyObject *arg; /* Argument à fournir au filtre*/ + PyObject *status; /* Bilan de l'analyse */ + + gstate = PyGILState_Ensure(); + + if (content == NULL) + { + Py_DECREF(callable); + result = false; + } + + else + { + arg = pygobject_new(G_OBJECT(content)); + + status = PyObject_CallFunctionObjArgs(callable, arg, NULL); + + if (PyErr_Occurred()) + PyErr_Print(); + + result = status == NULL || status == Py_False || status == Py_None ? false : true; + Py_XDECREF(status); + + Py_DECREF(arg); + + } + + PyGILState_Release(gstate); + + return result; + +} + + +/****************************************************************************** +* * * Paramètres : self = projet d'étude à manipuler. * * args = arguments accompagnant l'appel. * * * @@ -148,16 +202,32 @@ static PyObject *py_study_project_save(PyObject *self, PyObject *args) static PyObject *py_study_project_discover_binary_content(PyObject *self, PyObject *args) { - GStudyProject *project; /* Version GLib du format */ - int ret; /* Bilan de lecture des args. */ + PyObject *callable; /* Filtre de contenus éventuel */ GBinContent *content; /* Instance de contenu binaire */ + int ret; /* Bilan de lecture des args. */ + GStudyProject *project; /* Version GLib du format */ - project = G_STUDY_PROJECT(pygobject_get(self)); + callable = NULL; - ret = PyArg_ParseTuple(args, "O&", convert_to_binary_content, &content); + ret = PyArg_ParseTuple(args, "O&|O&", + convert_to_binary_content, &content, + convert_to_callable, &callable); if (!ret) return NULL; - g_study_project_discover_binary_content(project, content); + project = G_STUDY_PROJECT(pygobject_get(self)); + + if (callable != NULL) + { + Py_INCREF(callable); + + g_study_project_discover_binary_content(project, content, + (filter_loadable_cb)filter_loadable_content_with_python, + callable); + + } + + else + g_study_project_discover_binary_content(project, content, NULL, NULL); Py_RETURN_NONE; diff --git a/plugins/pychrysalide/helpers.c b/plugins/pychrysalide/helpers.c index 7e31fa7..2b62e57 100644 --- a/plugins/pychrysalide/helpers.c +++ b/plugins/pychrysalide/helpers.c @@ -109,6 +109,51 @@ PyObject *status_to_rich_cmp_state(int status, int op) /****************************************************************************** * * +* 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 appelable. * +* * +* Retour : Bilan de l'opération, voire indications supplémentaires. * +* * +* Remarques : - * +* * +******************************************************************************/ + +int convert_to_callable(PyObject *arg, void *dst) +{ + int result; /* Bilan à retourner */ + + result = PyCallable_Check(arg); + + 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 a callable object"); + break; + + case 1: + *((PyObject **)dst) = arg; + break; + + default: + assert(false); + break; + + } + + return result; + +} + + +/****************************************************************************** +* * * Paramètres : target = propriétaire de la routine visée. * * method = désignation de la fonction à appeler. * * * diff --git a/plugins/pychrysalide/helpers.h b/plugins/pychrysalide/helpers.h index ce5840b..f7ebdc3 100644 --- a/plugins/pychrysalide/helpers.h +++ b/plugins/pychrysalide/helpers.h @@ -38,6 +38,9 @@ /* Traduit pour Python le bilan d'une comparaison riche. */ PyObject *status_to_rich_cmp_state(int, int); +/* Tente de convertir en élément appelable. */ +int convert_to_callable(PyObject *, void *); + /* Indique si une routine Python existe ou non. */ bool has_python_method(PyObject *, const char *); diff --git a/src/analysis/project.c b/src/analysis/project.c index e01a126..8474610 100644 --- a/src/analysis/project.c +++ b/src/analysis/project.c @@ -38,6 +38,7 @@ #include "../core/logs.h" #include "../core/params.h" #include "../core/queue.h" +#include "../glibext/chrysamarshal.h" #include "../glibext/delayed-int.h" @@ -66,6 +67,7 @@ struct _GStudyProjectClass /* Signaux */ + void (* contents_available) (GStudyProject, GLoadedContent **, guint); void (* content_added) (GStudyProject *, GLoadedContent *); void (* content_removed) (GStudyProject *, GLoadedContent *); @@ -92,9 +94,6 @@ static void g_study_project_finalize(GStudyProject *); /* Assure l'intégration de contenus listés dans du XML. */ static void g_study_project_recover_binary_contents(GStudyProject *, xmlDoc *, xmlXPathContext *); -/* Réceptionne la recette d'une analyse de contenu. */ -static void on_loaded_content_analyzed(GLoadedContent *, gboolean, GStudyProject *); - /* ------------------------ CHARGEMENTS DE CONTENUS BINAIRES ------------------------ */ @@ -124,6 +123,9 @@ typedef struct _GLoadingHandler GCond wait_cond; /* Réveil d'attente de fin */ GMutex mutex; /* Encadrement des accès */ + filter_loadable_cb filter; /* Filtre des contenus ? */ + void *data; /* Données utiles au filtrage */ + } GLoadingHandler; /* Chargement de contenus binaires (classe) */ @@ -150,7 +152,7 @@ static void g_loading_handler_dispose(GLoadingHandler *); static void g_loading_handler_finalize(GLoadingHandler *); /* Crée une tâche de chargement de contenu bianire. */ -static GLoadingHandler *g_loading_handler_new_discovering(GStudyProject *, GBinContent *); +static GLoadingHandler *g_loading_handler_new_discovering(GStudyProject *, GBinContent *, filter_loadable_cb, void *); /* Crée une tâche de chargement de contenu bianire. */ static GLoadingHandler *g_loading_handler_new_recovering(GStudyProject *, xmlDoc *, xmlXPathContext *); @@ -199,6 +201,14 @@ static void g_study_project_class_init(GStudyProjectClass *klass) object->dispose = (GObjectFinalizeFunc/* ! */)g_study_project_dispose; object->finalize = (GObjectFinalizeFunc)g_study_project_finalize; + g_signal_new("contents-available", + G_TYPE_STUDY_PROJECT, + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET(GStudyProjectClass, contents_available), + NULL, NULL, + g_cclosure_user_marshal_VOID__POINTER_UINT, + G_TYPE_NONE, 2, G_TYPE_POINTER, G_TYPE_UINT); + g_signal_new("content-added", G_TYPE_STUDY_PROJECT, G_SIGNAL_RUN_LAST, @@ -545,6 +555,8 @@ static void g_study_project_recover_binary_contents(GStudyProject *project, xmlD * * * Paramètres : project = projet dont le contenu est à compléter. * * content = contenu binaire à mémoriser pour le projet. * +* filter = procédure de filtrage de contenus chargés. * +* data = données utiles à la procédure de filtre. * * * * Description : Assure l'intégration de contenus binaires dans un projet. * * * @@ -554,11 +566,11 @@ static void g_study_project_recover_binary_contents(GStudyProject *project, xmlD * * ******************************************************************************/ -void g_study_project_discover_binary_content(GStudyProject *project, GBinContent *content) +void g_study_project_discover_binary_content(GStudyProject *project, GBinContent *content, filter_loadable_cb filter, void *data) { GLoadingHandler *handler; /* Encadrement du chargement */ - handler = g_loading_handler_new_discovering(project, content); + handler = g_loading_handler_new_discovering(project, content, filter, data); g_work_queue_schedule_work(get_work_queue(), G_DELAYED_WORK(handler), LOADING_WORK_GROUP); @@ -579,7 +591,7 @@ void g_study_project_discover_binary_content(GStudyProject *project, GBinContent * * ******************************************************************************/ -static void on_loaded_content_analyzed(GLoadedContent *content, gboolean success, GStudyProject *project) +void on_loaded_content_analyzed(GLoadedContent *content, gboolean success, GStudyProject *project) { const char *desc; /* Description du contenu */ @@ -908,6 +920,8 @@ static void g_loading_handler_finalize(GLoadingHandler *handler) * * * Paramètres : project = projet dont le contenu est à compléter. * * content = contenu binaire à mémoriser pour le projet. * +* filter = procédure de filtrage de contenus chargés. * +* data = données utiles à la procédure de filtre. * * * * Description : Crée une tâche de chargement de contenu bianire. * * * @@ -917,7 +931,7 @@ static void g_loading_handler_finalize(GLoadingHandler *handler) * * ******************************************************************************/ -static GLoadingHandler *g_loading_handler_new_discovering(GStudyProject *project, GBinContent *content) +static GLoadingHandler *g_loading_handler_new_discovering(GStudyProject *project, GBinContent *content, filter_loadable_cb filter, void *data) { GLoadingHandler *result; /* Tâche à retourner */ GContentExplorer *explorer; /* Explorateur de contenus */ @@ -935,6 +949,9 @@ static GLoadingHandler *g_loading_handler_new_discovering(GStudyProject *project result->resolved = 0; + result->filter = filter; + result->data = data; + explorer = get_current_content_explorer(); g_mutex_lock(&result->mutex); @@ -993,6 +1010,9 @@ static GLoadingHandler *g_loading_handler_new_recovering(GStudyProject *project, result->resolved = 0; + result->filter = NULL; + result->data = NULL; + explorer = get_current_content_explorer(); explored = 0; @@ -1211,6 +1231,7 @@ static void on_new_content_resolved(GContentResolver *resolver, wgroup_id_t wid, { GLoadedContent **available; /* Contenus chargés valables */ size_t count; /* Quantité de ces contenus */ + bool keep; /* Conservation finale de liste*/ size_t i; /* Boucle de parcours */ GBinContent *content; /* Contenu brut à manipuler */ const gchar *hash; /* Empreinte d'un contenu */ @@ -1223,6 +1244,8 @@ static void on_new_content_resolved(GContentResolver *resolver, wgroup_id_t wid, { available = g_content_resolver_get_all(resolver, wid, &count); + keep = false; + /* Rechargement à partir d'XML ? */ if (handler->xdoc != NULL) { @@ -1295,19 +1318,39 @@ static void on_new_content_resolved(GContentResolver *resolver, wgroup_id_t wid, */ g_object_ref(G_OBJECT(available[i])); - g_signal_connect(available[i], "analyzed", - G_CALLBACK(on_loaded_content_analyzed), handler->project); + } - g_loaded_content_analyze(available[i]); + if (is_batch_mode()) + { + for (i = 0; i < count; i++) + { + if (handler->filter == NULL || handler->filter(available[i], handler->data)) + { + g_signal_connect(available[i], "analyzed", + G_CALLBACK(on_loaded_content_analyzed), handler->project); - g_object_unref(G_OBJECT(available[i])); + g_loaded_content_analyze(available[i]); + + } + + g_object_unref(G_OBJECT(available[i])); + + } + + } + + else + { + g_signal_emit_by_name(handler->project, "contents-available", available, count); + + keep = true; } } /* Dans tous les cas... */ - if (available != NULL) + if (available != NULL && !keep) free(available); /* Si c'était la dernière résolution... */ diff --git a/src/analysis/project.h b/src/analysis/project.h index c634fb2..9b42a47 100644 --- a/src/analysis/project.h +++ b/src/analysis/project.h @@ -74,8 +74,14 @@ const char *g_study_project_get_filename(const GStudyProject *); /* ------------------------ INTEGRATION DE CONTENUS BINAIRES ------------------------ */ +/* Filtre sur les contenus chargeables */ +typedef bool (* filter_loadable_cb) (GLoadedContent *, void *); + /* Assure l'intégration de contenus binaires dans un projet. */ -void g_study_project_discover_binary_content(GStudyProject *, GBinContent *); +void g_study_project_discover_binary_content(GStudyProject *, GBinContent *, filter_loadable_cb, void *); + +/* Réceptionne la recette d'une analyse de contenu. */ +void on_loaded_content_analyzed(GLoadedContent *, gboolean, GStudyProject *); #define g_study_project_lock_contents(p) \ _g_study_project_lock_unlock_contents(p, true) diff --git a/src/gui/editor.c b/src/gui/editor.c index 16b7a59..b52ec9d 100644 --- a/src/gui/editor.c +++ b/src/gui/editor.c @@ -46,6 +46,7 @@ #include "../common/extstr.h" #include "../core/global.h" #include "../core/params.h" +#include "../glibext/chrysamarshal.h" #include "../glibext/signal.h" #include "../gtkext/easygtk.h" #include "../gtkext/gtkdisplaypanel.h" @@ -129,8 +130,11 @@ static void notify_editor_project_change(GStudyProject *, bool); /* Assure un positionnement initial idéal. */ static gboolean scroll_for_the_first_time(GtkWidget *, GdkEvent *, GLoadedContent *); +/* Présente une possibilité de sélection des contenus chargés. */ +static void on_editor_contents_available(GStudyProject *, GLoadedContent **, guint, void *); + /* Affiche le contenu qui vient de rejoindre un projet donné. */ -void on_editor_loaded_content_added(GStudyProject *, GLoadedContent *, void *); +static void on_editor_loaded_content_added(GStudyProject *, GLoadedContent *, void *); /* Recherche et retirer de l'affichage un contenu chargé. */ static void remove_loaded_content_from_editor(GtkWidget *, GLoadedContent *); @@ -905,9 +909,15 @@ static void notify_editor_project_change(GStudyProject *project, bool new) contents = _g_study_project_get_contents(project, &count); if (new) + { + g_signal_connect_to_main(project, "contents-available", G_CALLBACK(on_editor_contents_available), NULL, + g_cclosure_user_marshal_VOID__POINTER_UINT); + g_signal_connect_to_main(project, "content-added", G_CALLBACK(on_editor_loaded_content_added), NULL, g_cclosure_marshal_VOID__OBJECT); + } + g_study_project_unlock_contents(project); if (new) @@ -934,6 +944,41 @@ static void notify_editor_project_change(GStudyProject *project, bool new) /****************************************************************************** * * +* Paramètres : project = project impliqué dans l'opération. * +* contents = nouveaux contenus à éventuellement charger. * +* count = taille de la liste fournie. * +* unused = adresse non utilisée ici. * +* * +* Description : Présente une possibilité de sélection des contenus chargés. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void on_editor_contents_available(GStudyProject *project, GLoadedContent **contents, guint count, void *unused) +{ + guint i; /* Boucle de parcours */ + + for (i = 0; i < count; i++) + { + g_signal_connect(contents[i], "analyzed", G_CALLBACK(on_loaded_content_analyzed), project); + + g_loaded_content_analyze(contents[i]); + + g_object_unref(G_OBJECT(contents[i])); + + } + + if (contents != NULL) + free(contents); + +} + + +/****************************************************************************** +* * * Paramètres : project = project impliqué dans l'opération. * * content = nouveau contenu à présenter dans l'éditeur. * * unused = adresse non utilisée ici. * @@ -946,7 +991,7 @@ static void notify_editor_project_change(GStudyProject *project, bool new) * * ******************************************************************************/ -void on_editor_loaded_content_added(GStudyProject *project, GLoadedContent *content, void *unused) +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 */ diff --git a/src/gui/menus/project.c b/src/gui/menus/project.c index a6a078b..80eff6f 100644 --- a/src/gui/menus/project.c +++ b/src/gui/menus/project.c @@ -205,7 +205,7 @@ static void mcb_project_add_binary_file(GtkMenuItem *menuitem, GMenuBar *bar) if (content != NULL) { - g_study_project_discover_binary_content(project, content); + g_study_project_discover_binary_content(project, content, NULL, NULL); g_object_unref(G_OBJECT(content)); } diff --git a/src/main.c b/src/main.c index f00a61c..92df3fa 100644 --- a/src/main.c +++ b/src/main.c @@ -479,7 +479,7 @@ static int open_binaries(char **files, int count) if (content != NULL) { - g_study_project_discover_binary_content(project, content); + g_study_project_discover_binary_content(project, content, NULL, NULL); g_object_unref(G_OBJECT(content)); } -- cgit v0.11.2-87-g4458