/* Chrysalide - Outil d'analyse de fichiers binaires * plugin.c - interactions avec un greffon donné * * Copyright (C) 2009-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 "plugin.h" #include #include #include #include #include #include #include #include "pglist.h" #include "plugin-int.h" #include "../common/compiler.h" #include "../common/extstr.h" #include "../common/pathname.h" #include "../common/xdg.h" /* Initialise la classe des greffons. */ static void g_plugin_module_class_init(GPluginModuleClass *); /* Initialise une instance de greffon. */ static void g_plugin_module_init(GPluginModule *); /* Supprime toutes les références externes. */ static void g_plugin_module_dispose(GPluginModule *); /* Procède à la libération totale de la mémoire. */ static void g_plugin_module_finalize(GPluginModule *); /* Indique le type défini pour un greffon. */ G_DEFINE_TYPE(GPluginModule, g_plugin_module, G_TYPE_OBJECT); /****************************************************************************** * * * Paramètres : class = classe à initialiser. * * * * Description : Initialise la classe des greffons. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ static void g_plugin_module_class_init(GPluginModuleClass *class) { GObjectClass *object; /* Autre version de la classe */ object = G_OBJECT_CLASS(class); object->dispose = (GObjectFinalizeFunc/* ! */)g_plugin_module_dispose; object->finalize = (GObjectFinalizeFunc)g_plugin_module_finalize; class->get_filename = NULL; class->get_modname = NULL; class->enable = NULL; class->disable = NULL; } /****************************************************************************** * * * Paramètres : plugin = instance à initialiser. * * * * Description : Initialise une instance de greffon. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ static void g_plugin_module_init(GPluginModule *plugin) { plugin->name = NULL; plugin->desc = NULL; plugin->version = NULL; plugin->url = NULL; plugin->required = NULL; plugin->required_count = 0; plugin->flags = PSF_NONE; plugin->dependencies = NULL; } /****************************************************************************** * * * Paramètres : plugin = instance d'objet GLib à traiter. * * * * Description : Supprime toutes les références externes. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ static void g_plugin_module_dispose(GPluginModule *plugin) { size_t i; /* Boucle de parcours */ GPluginModule *dependency; /* Module nécessaire */ GPluginModuleClass *class; /* Classe de l'instance active */ lock_plugin_list_for_reading(); for (i = 0; i < plugin->required_count; i++) { dependency = get_plugin_by_name(plugin->required[i], NULL); /* Si le chargement a bien été complet avant la sortie... */ if (dependency != NULL) { /* Un coup pour l'appel à get_plugin_by_name(). */ unref_object(dependency); /* Un coup pour la dépendance */ unref_object(dependency); } } unlock_plugin_list_for_reading(); class = G_PLUGIN_MODULE_GET_CLASS(plugin); if (class->disable != NULL) class->disable(plugin); G_OBJECT_CLASS(g_plugin_module_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_plugin_module_finalize(GPluginModule *plugin) { size_t i; /* Boucle de parcours */ if (plugin->name != NULL) free(plugin->name); if (plugin->desc != NULL) free(plugin->desc); if (plugin->version != NULL) free(plugin->version); if (plugin->url != NULL) free(plugin->url); for (i = 0; i < plugin->required_count; i++) free(plugin->required[i]); if (plugin->required != NULL) free(plugin->required); if (plugin->dependencies != NULL) delete_bit_field(plugin->dependencies); G_OBJECT_CLASS(g_plugin_module_parent_class)->finalize(G_OBJECT(plugin)); } /****************************************************************************** * * * Paramètres : plugin = instance à initialiser pleinement. * * name = nom du greffon pour référence, principalement. * * desc = présentation éventuelle à destination humaine. * * version = indication de version éventuelle. * * url = référence vers une ressource en ligne. * * required = liste de dépendances éventuelles ou NULL. * * count = taille de cette liste. * * * * Description : Met en place un greffon. * * * * Retour : Bilan de l'opération. * * * * Remarques : - * * * ******************************************************************************/ bool g_plugin_module_create(GPluginModule *plugin, const char *name, const char *desc, const char *version, const char *url, const char * const *required, size_t count) { bool result; /* Bilan à retourner */ size_t i; /* Boucle de parcours #1 */ size_t k; /* Boucle de parcours #2 */ /* Validations préalables */ assert(name != NULL); result = (name != NULL); if (result && plugin->abi_version != CURRENT_ABI_VERSION) { result = false; log_variadic_message(LMT_ERROR, _("ABI mismatch detected: %08x (plugin) vs %08x (core)"), plugin->abi_version, CURRENT_ABI_VERSION); } /* Mémorisation des informations */ if (result) { plugin->name = strdup(name); if (desc != NULL) plugin->desc = strdup(desc); if (version != NULL) plugin->version = strdup(version); if (url != NULL) plugin->url = strdup(url); if (count > 0) { plugin->required = malloc(count * sizeof(char *)); plugin->required_count = 0; for (i = 0; i < count; i++) { for (k = 0; k < plugin->required_count; k++) if (strcmp(required[i], plugin->required[k]) == 0) break; if (k < plugin->required_count) continue; plugin->required[plugin->required_count++] = strdup(required[i]); } plugin->required = realloc(plugin->required, plugin->required_count * sizeof(char *)); } } return result; } /****************************************************************************** * * * Paramètres : plugin = greffon à consulter. * * * * Description : Indique le nom associé à un greffon. * * * * Retour : Désignation interne de l'extension, pour référence(s). * * * * Remarques : - * * * ******************************************************************************/ const char *g_plugin_module_get_name(const GPluginModule *plugin) { const char *result; /* Valeur finale à renvoyer */ result = plugin->name; return result; } /****************************************************************************** * * * Paramètres : plugin = greffon à consulter. * * * * Description : Fournit une description fonctionnelle d'un greffon. * * * * Retour : Description textuelle associée à une extension ou NULL. * * * * Remarques : - * * * ******************************************************************************/ const char *g_plugin_module_get_desc(const GPluginModule *plugin) { const char *result; /* Valeur finale à renvoyer */ result = plugin->desc; return result; } /****************************************************************************** * * * Paramètres : plugin = greffon à consulter. * * * * Description : Fournit la version d'un greffon et de ses fonctionnalités. * * * * Retour : Version sous forme de chaîne de caractères ou NULL. * * * * Remarques : - * * * ******************************************************************************/ const char *g_plugin_module_get_version(const GPluginModule *plugin) { const char *result; /* Valeur finale à renvoyer */ result = plugin->version; return result; } /****************************************************************************** * * * Paramètres : plugin = greffon à consulter. * * * * Description : Fournit l'URL des ressources en ligne liées à un greffon. * * * * Retour : URL de renvoi associée à une extension ou NULL. * * * * Remarques : - * * * ******************************************************************************/ const char *g_plugin_module_get_url(const GPluginModule *plugin) { const char *result; /* Valeur finale à renvoyer */ result = plugin->url; return result; } /****************************************************************************** * * * Paramètres : plugin = greffon à consulter. * * count = taille de la liste fournie. [OUT] * * * * Description : Fournit la liste des dépendances d'un greffon donné. * * * * Retour : Liste des noms d'extensions requises pour une extension. * * * * Remarques : - * * * ******************************************************************************/ const char * const *g_plugin_module_get_requirements(const GPluginModule *plugin, size_t *count) { const char * const *result; /* Valeur finale à renvoyer */ result = CONST_ARRAY_CAST(plugin->required, char); *count = plugin->required_count; return result; } /****************************************************************************** * * * Paramètres : plugin = greffon à consulter. * * * * Description : Pointe le fichier contenant le greffon manipulé. * * * * Retour : Chemin d'accès au greffon. * * * * Remarques : - * * * ******************************************************************************/ char *g_plugin_module_get_filename(const GPluginModule *plugin) { char *result; /* Chemin d'accès à renvoyer */ GPluginModuleClass *class; /* Classe de l'instance active */ class = G_PLUGIN_MODULE_GET_CLASS(plugin); result = class->get_filename(plugin); return result; } /****************************************************************************** * * * Paramètres : plugin = greffon à valider. * * * * Description : Fournit le nom brut associé au greffon. * * * * Retour : Désignation brute du greffon. * * * * Remarques : - * * * ******************************************************************************/ char *g_plugin_module_get_modname(const GPluginModule *plugin) { char *result; /* Désignation brute à renvoyer*/ GPluginModuleClass *class; /* Classe de l'instance active */ class = G_PLUGIN_MODULE_GET_CLASS(plugin); result = class->get_modname(plugin); return result; } /****************************************************************************** * * * Paramètres : plugin = greffon à consulter. * * * * Description : Fournit des indications sur l'état du greffon. * * * * Retour : Fanions portant des indications. * * * * Remarques : - * * * ******************************************************************************/ PluginStatusFlags g_plugin_module_get_flags(const GPluginModule *plugin) { return plugin->flags; } /****************************************************************************** * * * Paramètres : plugin = greffon à modifier. * * flags = fanions à ajouter brutalement au greffon. * * * * Description : Ajoute des indications sur l'état du greffon. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ void g_plugin_module_override_flags(GPluginModule *plugin, PluginStatusFlags flags) { plugin->flags |= flags; } /****************************************************************************** * * * Paramètres : plugin = greffon à mettre à jour. * * list = ensemble des greffons disponibles. * * count = taille de cet ensemble. * * * * Description : Met à jour l'ensemble des dépendances du greffon. * * * * Retour : true si la liste des dépendances a évolué. * * * * Remarques : - * * * ******************************************************************************/ bool g_plugin_module_resolve_dependencies(GPluginModule *plugin, GPluginModule **list, size_t count) { bool result; /* Bilan à faire remonter */ bitfield_t *new; /* Nouvelle définition */ size_t i; /* Boucle de parcours */ GPluginModule *dependency; /* Module nécessaire */ size_t index; /* Indice de greffon visé */ result = false; if (plugin->dependencies == NULL) plugin->dependencies = create_bit_field(count, false); #ifndef NDEBUG else assert(count == get_bit_field_size(plugin->dependencies)); #endif if ((plugin->flags & (PSF_UNKNOW_DEP | PSF_DEP_LOOP)) == 0) { /* Collecte des dépendances */ new = dup_bit_field(plugin->dependencies); for (i = 0; i < plugin->required_count; i++) { dependency = get_plugin_by_name(plugin->required[i], &index); if (dependency == NULL) plugin->flags |= PSF_UNKNOW_DEP; else { if (dependency->dependencies == NULL) dependency->dependencies = create_bit_field(count, false); set_in_bit_field(new, index); or_bit_field(new, dependency->dependencies); /** * Si la référence pour dépendance a déjà été prise. */ if (test_in_bit_field(plugin->dependencies, index)) unref_object(dependency); } } /* Mise à jour du suivi */ if (compare_bit_fields(plugin->dependencies, new) != 0) { copy_bit_field(plugin->dependencies, new); result = true; } delete_bit_field(new); /* Vérification sanitaire */ dependency = get_plugin_by_name(plugin->name, &index); assert(dependency != NULL); assert(dependency == plugin); if (test_in_bit_field(plugin->dependencies, index)) plugin->flags |= PSF_DEP_LOOP; unref_object(dependency); } return result; } /****************************************************************************** * * * Paramètres : plugin = greffon à valider. * * list = ensemble des greffons disponibles. * * count = taille de cet ensemble. * * * * Description : Termine le chargement du greffon préparé. * * * * Retour : Bilan du chargement effectif. * * * * Remarques : - * * * ******************************************************************************/ bool g_plugin_module_load(GPluginModule *plugin, GPluginModule **list, size_t count) { bool result; /* Bilan à retourner */ PluginStatusFlags flags; /* Fanions de greffon */ size_t i; /* Boucle de parcours */ GPluginModule *dependency; /* Module nécessaire */ char *filename; /* Chemin d'accès au greffon */ GPluginModuleClass *class; /* Classe de l'instance active */ char *tmp; /* Chaîne modifiable */ char *dir; /* Pointeur vers répertoire */ /* Si un essai précédent a déjà échoué ou réussi... */ flags = g_plugin_module_get_flags(plugin); if (flags & BROKEN_PLUGIN_STATUS) return false; if (flags & PSF_LOADED) return true; /* Chargement des dépendances */ result = true; filename = g_plugin_module_get_filename(plugin); for (i = 0; i < plugin->required_count && result; i++) { dependency = get_plugin_by_name(plugin->required[i], NULL); assert(dependency != NULL); result = g_plugin_module_load(dependency, list, count); unref_object(dependency); } if (!result) { log_variadic_message(LMT_ERROR, _("Some dependencies failed to load for plugin '%s'"), filename); plugin->flags |= PSF_FAILURE; goto failure; } /* Chargement du greffon courant */ class = G_PLUGIN_MODULE_GET_CLASS(plugin); if (class->enable != NULL) { result = class->enable(plugin); if (!result) { log_variadic_message(LMT_ERROR, _("Plugin '%s' failed to load itself..."), filename); plugin->flags |= PSF_FAILURE; goto failure; } } /* Message de bilan */ tmp = strdup(filename); dir = dirname(tmp); log_variadic_message(LMT_PROCESS, _("Loaded the '%s' file as plugin from the '%s' directory"), strrchr(filename, G_DIR_SEPARATOR) + 1, dir); free(tmp); plugin->flags |= PSF_LOADED; failure: free(filename); return result; } /****************************************************************************** * * * Paramètres : plugin = greffon à consulter. * * final = fin imposée du nom de fichier final. * * create = amorce la création des répertoire ? * * * * Description : Construit le nom d'un fichier de configuration du greffon. * * * * Retour : Chemin d'accès déterminé, ou NULL en cas d'erreur. * * * * Remarques : - * * * ******************************************************************************/ char *g_plugin_module_build_config_filename(const GPluginModule *plugin, const char *final, bool create) { char *result; /* Chaîne à retourner */ char *modname; /* Désignation brute de greffon*/ char *suffix; /* Fin du répertoire personnel */ bool status; /* Bilan d'une création */ modname = g_plugin_module_get_modname(plugin); suffix = strdup("chrysalide"); suffix = stradd(suffix, G_DIR_SEPARATOR_S); suffix = stradd(suffix, "plugins"); suffix = stradd(suffix, G_DIR_SEPARATOR_S); suffix = stradd(suffix, modname); suffix = stradd(suffix, G_DIR_SEPARATOR_S); suffix = stradd(suffix, final); result = get_xdg_config_dir(suffix, true); free(suffix); free(modname); if (create) { status = mkpath(result); if (!status) { free(result); result = NULL; } } return result; } /****************************************************************************** * * * Paramètres : plugin = greffon à consulter. * * * * Description : Fournit la configuration mise en place pour le greffon. * * * * Retour : Configuration dédiée à l'extension. * * * * Remarques : - * * * ******************************************************************************/ #if 0 GGenConfig *g_plugin_module_get_config(const GPluginModule *plugin) { GGenConfig *result; /* Configuration à faire suivre*/ result = plugin->config; if (result != NULL) g_object_ref(G_OBJECT(result)); return result; } #endif /****************************************************************************** * * * Paramètres : plugin = greffon à consulter. * * msg = message à faire apparaître à l'écran. * * * * Description : Présente dans le journal un message simple. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ void g_plugin_module_log_simple_message(const GPluginModule *plugin, LogMessageType type, const char *msg) { size_t len; /* Taille tampon disponible */ char *buffer; /* Tampon du msg reconstitué */ len = 4 + strlen(plugin->name) + 6 + strlen(msg) + 1; buffer = calloc(len, sizeof(char)); strcpy(buffer, "["); strcat(buffer, plugin->name); strcat(buffer, "] "); strcat(buffer, msg); log_simple_message(type, buffer); free(buffer); } /****************************************************************************** * * * Paramètres : plugin = greffon à consulter. * * type = espèce du message à ajouter. * * fmt = format du message à faire apparaître à l'écran. * * ... = éventuels arguments venant compléter le message. * * * * Description : Présente dans le journal un message complexe. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ void g_plugin_module_log_variadic_message(const GPluginModule *plugin, LogMessageType type, const char *fmt, ...) { va_list ap; /* Liste d'arguments variable */ char *buffer; /* Tampon du msg reconstitué */ va_start(ap, fmt); buffer = build_variadic_message(fmt, ap); va_end(ap); if (buffer != NULL) { g_plugin_module_log_simple_message(plugin, type, buffer); free(buffer); } } #if 0 /****************************************************************************** * * * Paramètres : plugin = greffon à manipuler. * * action = type d'action attendue. * * type = type d'objet à mettre en place. * * * * Description : Crée une instance à partir d'un type dynamique externe. * * * * Retour : Instance d'objet gérée par l'extension ou NULL. * * * * Remarques : - * * * ******************************************************************************/ gpointer g_plugin_module_build_type_instance(GPluginModule *plugin, PluginAction action, GType type) { gpointer result; /* Instance à retourner */ GPluginModuleClass *class; /* Classe de l'instance active */ class = G_PLUGIN_MODULE_GET_CLASS(plugin); result = class->build_instance(plugin, action, type); 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. * * resources = liste de ressources à constituer. [OUT] * * count = taille de cette liste. [OUT] * * * * Description : Complète une liste de resources pour thème. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ void g_plugin_module_include_theme(const GPluginModule *plugin, PluginAction action, gboolean dark, char ***resources, size_t *count) { GPluginModuleClass *class; /* Classe de l'instance active */ class = G_PLUGIN_MODULE_GET_CLASS(plugin); class->include_theme(plugin, action, dark, resources, count); } /****************************************************************************** * * * Paramètres : plugin = greffon à manipuler. * * action = type d'action attendue. * * item = nouveau panneau créé. * * * * Description : Rend compte de la création d'un panneau. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ void g_plugin_module_notify_panel_creation(const GPluginModule *plugin, PluginAction action, GPanelItem *item) { GPluginModuleClass *class; /* Classe de l'instance active */ class = G_PLUGIN_MODULE_GET_CLASS(plugin); class->notify_panel(plugin, action, item); } /****************************************************************************** * * * Paramètres : plugin = greffon à manipuler. * * action = type d'action attendue. * * item = panneau marqué par un changement d'affichage. * * dock = indique une accroche et non un décrochage. * * * * Description : Rend compte d'un affichage ou d'un retrait de panneau. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ void g_plugin_module_notify_panel_docking(const GPluginModule *plugin, PluginAction action, GPanelItem *item, bool dock) { GPluginModuleClass *class; /* Classe de l'instance active */ class = G_PLUGIN_MODULE_GET_CLASS(plugin); class->notify_docking(plugin, action, item, dock); } #endif /****************************************************************************** * * * Paramètres : plugin = greffon à manipuler. * * action = type d'action attendue. * * content = contenu binaire à traiter. * * wid = identifiant du groupe de traitement. * * status = barre de statut à tenir informée. * * * * Description : Procède à une opération liée à un contenu binaire. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ void g_plugin_module_handle_binary_content(const GPluginModule *plugin, PluginAction action, GBinContent *content, wgroup_id_t wid, GtkStatusStack *status) { GPluginModuleClass *class; /* Classe de l'instance active */ class = G_PLUGIN_MODULE_GET_CLASS(plugin); class->handle_content(plugin, action, content, wid, status); } /****************************************************************************** * * * Paramètres : plugin = greffon à manipuler. * * action = type d'action attendue. * * content = contenu chargé à traiter. * * gid = identifiant du groupe de traitement. * * status = barre de statut à tenir informée. * * * * Description : Procède à une opération liée à un contenu chargé. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ void g_plugin_module_handle_loaded_content(const GPluginModule *plugin, PluginAction action, GLoadedContent *content, wgroup_id_t gid, GtkStatusStack *status) { GPluginModuleClass *class; /* Classe de l'instance active */ class = G_PLUGIN_MODULE_GET_CLASS(plugin); return class->handle_loaded(plugin, action, content, gid, status); } /****************************************************************************** * * * Paramètres : plugin = greffon à manipuler. * * action = type d'action attendue. * * format = format de binaire à manipuler pendant l'opération. * * gid = groupe de travail dédié. * * status = barre de statut à tenir informée. * * * * Description : Procède à une opération liée à l'analyse d'un format. * * * * Retour : Bilan de l'exécution du traitement. * * * * Remarques : - * * * ******************************************************************************/ bool g_plugin_module_handle_known_format_analysis(const GPluginModule *plugin, PluginAction action, GKnownFormat *format, wgroup_id_t gid, GtkStatusStack *status) { bool result; /* Bilan à retourner */ GPluginModuleClass *class; /* Classe de l'instance active */ class = G_PLUGIN_MODULE_GET_CLASS(plugin); result = class->handle_fmt_analysis(plugin, action, format, gid, status); return result; } /****************************************************************************** * * * Paramètres : plugin = greffon à manipuler. * * action = type d'action attendue. * * format = format de binaire à manipuler pendant l'opération. * * info = informations à constituer en avance de phase. * * status = barre de statut à tenir informée. * * * * Description : Procède à un préchargement de format de fichier. * * * * Retour : Bilan de l'exécution du traitement. * * * * Remarques : - * * * ******************************************************************************/ bool g_plugin_module_preload_binary_format(const GPluginModule *plugin, PluginAction action, GBinFormat *format, GPreloadInfo *info, GtkStatusStack *status) { GPluginModuleClass *class; /* Classe de l'instance active */ class = G_PLUGIN_MODULE_GET_CLASS(plugin); return class->preload_format(plugin, action, format, info, status); } /****************************************************************************** * * * Paramètres : plugin = greffon à manipuler. * * action = type d'action attendue. * * format = format de binaire à manipuler pendant l'opération. * * * * Description : Procède au rattachement d'éventuelles infos de débogage. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ void g_plugin_module_attach_debug_format(const GPluginModule *plugin, PluginAction action, GExeFormat *format) { GPluginModuleClass *class; /* Classe de l'instance active */ class = G_PLUGIN_MODULE_GET_CLASS(plugin); class->attach_debug(plugin, action, format); } /****************************************************************************** * * * Paramètres : plugin = greffon à manipuler. * * action = type d'action attendue. * * binary = binaire dont le contenu est en cours de traitement. * * status = barre de statut à tenir informée. * * context = contexte de désassemblage. * * * * Description : Exécute une action pendant un désassemblage de binaire. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ void g_plugin_module_process_disassembly_event(const GPluginModule *plugin, PluginAction action, GLoadedBinary *binary, GtkStatusStack *status, GProcContext *context) { GPluginModuleClass *class; /* Classe de l'instance active */ class = G_PLUGIN_MODULE_GET_CLASS(plugin); class->process_disass(plugin, action, binary, status, context); } /****************************************************************************** * * * Paramètres : plugin = greffon à manipuler. * * action = type d'action attendue. * * content = élément chargé à consulter. * * version = précise si les versions doivent être recherchées. * * names = désignations humaines correspondantes, à libérer. * * count = nombre de types d'obscurcissement trouvés. [OUT] * * * * Description : Effectue la détection d'effets d'outils externes. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ void g_plugin_module_detect_external_tools(const GPluginModule *plugin, PluginAction action, const GLoadedContent *content, bool version, char ***names, size_t *count) { GPluginModuleClass *class; /* Classe de l'instance active */ class = G_PLUGIN_MODULE_GET_CLASS(plugin); class->detect(plugin, action, content, version, names, count); } #endif