From 421c9d8b228f4926fabe06a19fda86d9023f1e96 Mon Sep 17 00:00:00 2001 From: Cyrille Bagard Date: Wed, 9 May 2018 15:33:10 +0200 Subject: Loaded binary contents using a dedicated global work group. --- src/analysis/project.c | 989 ++++++++++++++++++++++++++++--------------------- src/core/queue.c | 10 +- src/core/queue.h | 3 +- 3 files changed, 580 insertions(+), 422 deletions(-) diff --git a/src/analysis/project.c b/src/analysis/project.c index d2228e2..13887ee 100644 --- a/src/analysis/project.c +++ b/src/analysis/project.c @@ -37,25 +37,14 @@ #include "../core/global.h" #include "../core/logs.h" #include "../core/params.h" +#include "../core/queue.h" +#include "../glibext/delayed-int.h" /* ------------------------- DEFINITION D'UN PROJET INTERNE ------------------------- */ -/* Suivi du chargement de contenus binaires */ -typedef struct _loading_params -{ - const wgroup_id_t **exp_wids; /* Identifiants d'exploration */ - size_t exp_count; /* Quantitié d'identifiants */ - - size_t resolved; /* Compteur de résolutions */ - - xmlDoc *xdoc; /* Structure XML chargée ? */ - xmlXPathContext *context; /* Eventuel contexte XML */ - -} loading_params; - /* Projet d'étude regroupant les binaires analysés (instance) */ struct _GStudyProject { @@ -63,10 +52,6 @@ struct _GStudyProject char *filename; /* Lieu d'enregistrement */ - loading_params *ld_params; /* Infos d'accompagnement */ - size_t ld_count; /* Quantité de ces infos */ - GMutex ld_mutex; /* Encadrement des accès */ - GLoadedContent **contents; /* Contenus chargés et intégrés*/ size_t count; /* Quantité de ces contenus */ GMutex mutex; /* Encadrement des accès */ @@ -104,26 +89,83 @@ static void g_study_project_finalize(GStudyProject *); /* ------------------------ INTEGRATION DE CONTENUS BINAIRES ------------------------ */ -/* Prépare le suivi d'une nouvelle phase d'intégration. */ -static loading_params *g_study_project_prepare_content_loading(GStudyProject *); +/* Assure l'intégration de contenus listés dans du XML. */ +static void g_study_project_recover_binary_contents(GStudyProject *, xmlDoc *, xmlXPathContext *); -/* Efface le suivi d'une phase d'intégration obsolète. */ -static void g_study_project_destroy_content_loading(GStudyProject *, loading_params *); +/* Réceptionne la recette d'une analyse de contenu. */ +static void on_loaded_content_analyzed(GLoadedContent *, gboolean, GStudyProject *); -/* Retrouve les infos de chargements liées à une exploration. */ -static loading_params *g_study_project_find_exploration(GStudyProject *, wgroup_id_t, const wgroup_id_t **); -/* Assure l'intégration de contenus listés dans du XML. */ -static void g_study_project_recover_binary_contents(GStudyProject *, xmlDoc *, xmlXPathContext *); + +/* ------------------------ CHARGEMENTS DE CONTENUS BINAIRES ------------------------ */ + + +#define G_TYPE_LOADING_HANDLER g_loading_handler_get_type() +#define G_LOADING_HANDLER(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_LOADING_HANDLER, GLoadingHandler)) +#define G_IS_LOADING_HANDLER(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_LOADING_HANDLER)) +#define G_LOADING_HANDLER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_LOADING_HANDLER, GLoadingHandlerClass)) +#define G_IS_LOADING_HANDLER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_LOADING_HANDLER)) +#define G_LOADING_HANDLER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_LOADING_HANDLER, GLoadingHandlerClass)) + + +/* Chargement de contenus binaires (instance) */ +typedef struct _GLoadingHandler +{ + GDelayedWork parent; /* A laisser en premier */ + + GStudyProject *project; /* Projet à compléter */ + + xmlDoc *xdoc; /* Structure XML chargée ? */ + xmlXPathContext *context; /* Eventuel contexte XML */ + + const wgroup_id_t **exp_wids; /* Identifiants d'exploration */ + size_t exp_count; /* Quantitié d'identifiants */ + size_t resolved; /* Compteur de résolutions */ + GCond wait_cond; /* Réveil d'attente de fin */ + GMutex mutex; /* Encadrement des accès */ + +} GLoadingHandler; + +/* Chargement de contenus binaires (classe) */ +typedef struct _GLoadingHandlerClass +{ + GDelayedWorkClass parent; /* A laisser en premier */ + +} GLoadingHandlerClass; + + +/* Indique le type défini pour les tâches de chargement de contenus binaires. */ +GType g_loading_handler_get_type(void); + +/* Initialise la classe des tâches de chargement de contenus. */ +static void g_loading_handler_class_init(GLoadingHandlerClass *); + +/* Initialise une tâche de chargement de contenus binaires. */ +static void g_loading_handler_init(GLoadingHandler *); + +/* Supprime toutes les références externes. */ +static void g_loading_handler_dispose(GLoadingHandler *); + +/* Procède à la libération totale de la mémoire. */ +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 *); + +/* Crée une tâche de chargement de contenu bianire. */ +static GLoadingHandler *g_loading_handler_new_recovering(GStudyProject *, xmlDoc *, xmlXPathContext *); + +/* Assure le chargement de contenus binaires en différé. */ +static void g_loading_handler_process(GLoadingHandler *, GtkStatusStack *); + +/* Détermine si un encadrement est adapté pour un identifiant. */ +static bool g_loading_handler_check(GLoadingHandler *, wgroup_id_t, const wgroup_id_t **); /* Note la fin d'une phase d'exploration de contenu. */ -static void on_new_content_explored(GContentExplorer *, wgroup_id_t, GStudyProject *); +static void on_new_content_explored(GContentExplorer *, wgroup_id_t, GLoadingHandler *); /* Note la fin d'une phase de resolution de contenu. */ -static void on_new_content_resolved(GContentResolver *, wgroup_id_t, GStudyProject *); - -/* Réceptionne la recette d'une analyse de contenu. */ -static void on_loaded_content_analyzed(GLoadedContent *, gboolean, GStudyProject *); +static void on_new_content_resolved(GContentResolver *, wgroup_id_t, GLoadingHandler *); @@ -190,27 +232,12 @@ static void g_study_project_class_init(GStudyProjectClass *klass) static void g_study_project_init(GStudyProject *project) { - GContentExplorer *explorer; /* Explorateur de contenus */ - GContentResolver *resolver; /* Resolveur de contenus */ - project->filename = NULL; - project->ld_params = NULL; - project->ld_count = 0; - g_mutex_init(&project->ld_mutex); - project->contents = NULL; project->count = 0; g_mutex_init(&project->mutex); - explorer = get_current_content_explorer(); - g_signal_connect(explorer, "explored", G_CALLBACK(on_new_content_explored), project); - g_object_unref(G_OBJECT(explorer)); - - resolver = get_current_content_resolver(); - g_signal_connect(resolver, "resolved", G_CALLBACK(on_new_content_resolved), project); - g_object_unref(G_OBJECT(resolver)); - } @@ -228,30 +255,8 @@ static void g_study_project_init(GStudyProject *project) static void g_study_project_dispose(GStudyProject *project) { - GContentExplorer *explorer; /* Explorateur de contenus */ - GContentResolver *resolver; /* Resolveur de contenus */ size_t i; /* Boucle de parcours */ - explorer = get_current_content_explorer(); - g_signal_handlers_disconnect_by_func(explorer, G_CALLBACK(on_new_content_explored), project); - g_object_unref(G_OBJECT(explorer)); - - resolver = get_current_content_resolver(); - g_signal_handlers_disconnect_by_func(resolver, G_CALLBACK(on_new_content_resolved), project); - g_object_unref(G_OBJECT(resolver)); - - g_mutex_lock(&project->ld_mutex); - - while (project->ld_count > 0) - g_study_project_destroy_content_loading(project, project->ld_params); - - if (project->ld_params != NULL) - free(project->ld_params); - - g_mutex_unlock(&project->ld_mutex); - - g_mutex_clear(&project->ld_mutex); - g_mutex_lock(&project->mutex); for (i = 0; i < project->count; i++) @@ -513,36 +518,35 @@ const char *g_study_project_get_filename(const GStudyProject *project) /****************************************************************************** * * * Paramètres : project = projet dont le contenu est à compléter. * +* xdoc = structure XML en cours d'édition. * +* context = contexte à utiliser pour les recherches. * * * -* Description : Prépare le suivi d'une nouvelle phase d'intégration. * +* Description : Assure l'intégration de contenus listés dans du XML. * * * -* Retour : Nouvelle structure de suivi prête à être complétée. * +* Retour : - * * * * Remarques : - * * * ******************************************************************************/ -static loading_params *g_study_project_prepare_content_loading(GStudyProject *project) +static void g_study_project_recover_binary_contents(GStudyProject *project, xmlDoc *xdoc, xmlXPathContext *context) { - loading_params *result; /* Trouvaille à retourner */ - - assert(!g_mutex_trylock(&project->ld_mutex)); + GLoadingHandler *handler; /* Encadrement du chargement */ - project->ld_params = (loading_params *)realloc(project->ld_params, - ++project->ld_count * sizeof(loading_params)); + handler = g_loading_handler_new_recovering(project, xdoc, context); - result = &project->ld_params[project->ld_count - 1]; - - return result; + if (handler != NULL) + g_work_queue_schedule_work(get_work_queue(), G_DELAYED_WORK(handler), LOADING_WORK_GROUP); } + /****************************************************************************** * * * Paramètres : project = projet dont le contenu est à compléter. * -* params = paramètres de chargemeent à supprimer. * +* content = contenu binaire à mémoriser pour le projet. * * * -* Description : Efface le suivi d'une phase d'intégration obsolète. * +* Description : Assure l'intégration de contenus binaires dans un projet. * * * * Retour : - * * * @@ -550,105 +554,57 @@ static loading_params *g_study_project_prepare_content_loading(GStudyProject *pr * * ******************************************************************************/ -static void g_study_project_destroy_content_loading(GStudyProject *project, loading_params *params) +void g_study_project_discover_binary_content(GStudyProject *project, GBinContent *content) { - GContentExplorer *explorer; /* Explorateur de contenus */ - GContentResolver *resolver; /* Resolveur de contenus */ - size_t i; /* Boucle de parcours */ - size_t index; /* Indice des paramètres */ - - assert(!g_mutex_trylock(&project->ld_mutex)); - - /* Supression des groupes de travail */ - - explorer = get_current_content_explorer(); - resolver = get_current_content_resolver(); - - for (i = 0; i < params->exp_count; i++) - { - g_content_resolver_delete_group(resolver, *params->exp_wids[i]); - g_content_explorer_delete_group(explorer, *params->exp_wids[i]); - } - - free(params->exp_wids); - - g_object_unref(G_OBJECT(explorer)); - g_object_unref(G_OBJECT(resolver)); - - /* Fermture de l'éventuel fichier XML de chargement */ + GLoadingHandler *handler; /* Encadrement du chargement */ - if (params->xdoc != NULL) - close_xml_file(params->xdoc, params->context); + handler = g_loading_handler_new_discovering(project, content); - /* Réorganisation de la liste */ - - index = params - project->ld_params; - - if ((index + 1) < project->ld_count) - memmove(&project->ld_params[index], &project->ld_params[index + 1], - (project->ld_count - index - 1) * sizeof(loading_params)); - - project->ld_params = (loading_params *)realloc(project->ld_params, - --project->ld_count * sizeof(loading_params)); + g_work_queue_schedule_work(get_work_queue(), G_DELAYED_WORK(handler), LOADING_WORK_GROUP); } /****************************************************************************** * * -* Paramètres : project = projet dont le contenu est à consulter. * -* wid = identifiant du groupe d'exploration recherché. * -* ptr = pointeur vers la valeur d'origine externe. * +* Paramètres : content = contenu chargé et analysé. * +* success = bilan d'une analyse menée. * +* project = projet avide des résultats des opérations. * * * -* Description : Retrouve les infos de chargements liées à une exploration. * +* Description : Réceptionne la recette d'une analyse de contenu. * * * -* Retour : Informations trouvées ou NULL en cas d'échec. * +* Retour : - * * * * Remarques : - * * * ******************************************************************************/ -static loading_params *g_study_project_find_exploration(GStudyProject *project, wgroup_id_t wid, const wgroup_id_t **ptr) +static void on_loaded_content_analyzed(GLoadedContent *content, gboolean success, GStudyProject *project) { - loading_params *result; /* Trouvaille à retourner */ - const wgroup_id_t *value; /* Raccourci de confort */ - size_t i; /* Boucle de parcours #1 */ - size_t k; /* Boucle de parcours #2 */ - - assert(!g_mutex_trylock(&project->ld_mutex)); - - result = NULL; - - value = NULL; - - for (i = 0; i < project->ld_count && result == NULL; i++) - for (k = 0; k < project->ld_params[i].exp_count && result == NULL; k++) - { - value = project->ld_params[i].exp_wids[k]; - - if (*value == wid) - result = &project->ld_params[i]; + const char *desc; /* Description du contenu */ - } + desc = g_loaded_content_describe(content, true); - if (ptr != NULL) + if (success) { - assert(result == NULL || value != NULL); - *ptr = (result == NULL ? NULL : value); + g_study_project_attach_content(project, content); + log_variadic_message(LMT_INFO, _("Content from '%s' has been analyzed successfully!"), desc); } - return result; + else + log_variadic_message(LMT_ERROR, _("Failed to load '%s'"), desc); + + g_object_ref(G_OBJECT(content)); } /****************************************************************************** * * -* Paramètres : project = projet dont le contenu est à compléter. * -* xdoc = structure XML en cours d'édition. * -* context = contexte à utiliser pour les recherches. * +* Paramètres : project = project à manipuler. * +* content = contenu chargé à associer au projet actuel. * * * -* Description : Assure l'intégration de contenus listés dans du XML. * +* Description : Attache un contenu donné à un projet donné. * * * * Retour : - * * * @@ -656,78 +612,66 @@ static loading_params *g_study_project_find_exploration(GStudyProject *project, * * ******************************************************************************/ -static void g_study_project_recover_binary_contents(GStudyProject *project, xmlDoc *xdoc, xmlXPathContext *context) +void g_study_project_attach_content(GStudyProject *project, GLoadedContent *content) { - loading_params *params; /* Informations de chargement */ - xmlXPathObjectPtr xobject; /* Cible d'une recherche */ - size_t count; /* Nombre de contenus premiers */ - GContentExplorer *explorer; /* Explorateur de contenus */ - size_t explored; /* Qté. d'explorations lancées */ - size_t i; /* Boucle de parcours */ - char *access; /* Chemin pour un contenu */ - GBinContent *content; /* Contenu binaire retrouvé */ - - xobject = get_node_xpath_object(context, "/ChrysalideProject/RootContents/Content"); - - count = XPATH_OBJ_NODES_COUNT(xobject); - - if (count > 0) - { - explorer = get_current_content_explorer(); - - g_mutex_lock(&project->ld_mutex); - - params = g_study_project_prepare_content_loading(project); - - params->exp_wids = (const wgroup_id_t **)malloc(count * sizeof(wgroup_id_t *)); + g_mutex_lock(&project->mutex); - params->resolved = 0; + project->contents = (GLoadedContent **)realloc(project->contents, + ++project->count * sizeof(GLoadedContent *)); - params->xdoc = xdoc; - params->context = context; + project->contents[project->count - 1] = content; + g_object_ref(G_OBJECT(content)); - explored = 0; + g_mutex_unlock(&project->mutex); - for (i = 0; i < XPATH_OBJ_NODES_COUNT(xobject); i++) - { - asprintf(&access, "/ChrysalideProject/RootContents/Content[position()=%zu]", i + 1); + g_signal_emit_by_name(project, "content-added", content); - content = g_binary_content_new_from_xml(context, access, project->filename); +} - free(access); - if (content == NULL) - { - log_variadic_message(LMT_ERROR, _("Unable to load the root content #%zu ; skipping..."), i); - continue; - } +/****************************************************************************** +* * +* Paramètres : project = project à manipuler. * +* content = contenu chargé à dissocier du projet actuel. * +* * +* Description : Détache un contenu donné d'un projet donné. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ - params->exp_wids[explored++] = g_content_explorer_create_group(explorer, content); +void g_study_project_detach_content(GStudyProject *project, GLoadedContent *content) +{ + size_t i; /* Boucle de parcours */ - g_object_unref(G_OBJECT(content)); + g_mutex_lock(&project->mutex); - } + for (i = 0; i < project->count; i++) + if (project->contents[i] == content) break; - params->exp_count = explored; + if ((i + 1) < project->count) + memmove(&project->contents[i], &project->contents[i + 1], + (project->count - i - 1) * sizeof(GLoadedContent *)); - g_mutex_unlock(&project->ld_mutex); + project->contents = (GLoadedContent **)realloc(project->contents, + --project->count * sizeof(GLoadedContent *)); - g_object_unref(G_OBJECT(explorer)); + g_mutex_unlock(&project->mutex); - } + g_signal_emit_by_name(project, "content-removed", content); - if(xobject != NULL) - xmlXPathFreeObject(xobject); + g_object_unref(G_OBJECT(content)); } /****************************************************************************** * * -* Paramètres : project = projet dont le contenu est à compléter. * -* content = contenu binaire à mémoriser pour le projet. * +* Paramètres : project = projet dont le contenu est à afficher. * * * -* Description : Assure l'intégration de contenus binaires dans un projet. * +* Description : Met en place un projet à l'écran. * * * * Retour : - * * * @@ -735,41 +679,30 @@ 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_display(const GStudyProject *project) { - loading_params *params; /* Informations de chargement */ - GContentExplorer *explorer; /* Explorateur de contenus */ - - explorer = get_current_content_explorer(); - - g_mutex_lock(&project->ld_mutex); - - params = g_study_project_prepare_content_loading(project); - - params->exp_wids = (const wgroup_id_t **)malloc(sizeof(wgroup_id_t *)); - params->exp_count = 1; - - params->resolved = 0; - - params->xdoc = NULL; - params->context = NULL; - - params->exp_wids[0] = g_content_explorer_create_group(explorer, content); +#if 0 + size_t i; /* Boucle de parcours #1 */ + loaded_binary *handled; /* Binaire prise en compte */ + size_t j; /* Boucle de parcours #2 */ - g_mutex_unlock(&project->ld_mutex); + for (i = 0; i < project->binaries_count; i++) + { + handled = project->binaries[i]; - g_object_unref(G_OBJECT(explorer)); + for (j = 0; j < handled->count; j++) + g_panel_item_dock(handled->items[j]); + } +#endif } /****************************************************************************** * * -* Paramètres : explorer = gestionnaire d'explorations à consulter. * -* wid = groupe d'exploration concerné. * -* project = projet avide des résultats des opérations. * +* Paramètres : project = projet dont le contenu est à cacher. * * * -* Description : Note la fin d'une phase d'exploration de contenu. * +* Description : Supprime de l'écran un projet en place. * * * * Retour : - * * * @@ -777,182 +710,187 @@ void g_study_project_discover_binary_content(GStudyProject *project, GBinContent * * ******************************************************************************/ -static void on_new_content_explored(GContentExplorer *explorer, wgroup_id_t wid, GStudyProject *project) +void g_study_project_hide(const GStudyProject *project) { - const wgroup_id_t *wid_ptr; /* Référence vers l'origine */ - loading_params *params; /* Informations de chargement */ - GBinContent **available; /* Contenus binaires présents */ - size_t count; /* Quantité de ces contenus */ - GContentResolver *resolver; /* Resolveur de contenus */ - size_t i; /* Boucle de parcours */ +#if 0 + size_t i; /* Boucle de parcours #1 */ + loaded_binary *handled; /* Binaire prise en compte */ + size_t j; /* Boucle de parcours #2 */ - g_mutex_lock(&project->ld_mutex); - - params = g_study_project_find_exploration(project, wid, &wid_ptr); - - /* S'il s'agit bien d'une exploration nouvelle */ - if (params != NULL) + for (i = 0; i < project->binaries_count; i++) { - available = g_content_explorer_get_all(explorer, wid, &count); - assert(count > 0); - - resolver = get_current_content_resolver(); - - g_content_resolver_create_group(resolver, wid_ptr, available, count); - - g_object_unref(G_OBJECT(resolver)); - - for (i = 0; i < count; i++) - g_object_unref(G_OBJECT(available[i])); + handled = project->binaries[i]; - free(available); + for (j = 0; j < handled->count; j++) + g_panel_item_undock(handled->items[j]); } - - g_mutex_unlock(&project->ld_mutex); - +#endif } /****************************************************************************** * * -* Paramètres : resolver = gestionnaire de résolutions à consulter. * -* wid = groupe d'exploration concerné. * -* project = projet avide des résultats des opérations. * +* Paramètres : project = projet dont le contenu est à afficher. * +* count = nombre de contenus pris en compte. [OUT] * * * -* Description : Note la fin d'une phase de resolution de contenu. * +* Description : Fournit l'ensemble des contenus associés à un projet. * * * -* Retour : - * +* Retour : Liste à libérer de la mémoire. * * * * Remarques : - * * * ******************************************************************************/ -static void on_new_content_resolved(GContentResolver *resolver, wgroup_id_t wid, GStudyProject *project) +GLoadedContent **g_study_project_get_contents(GStudyProject *project, size_t *count) { - loading_params *params; /* Informations de chargement */ - GLoadedContent **available; /* Contenus chargés valables */ - size_t count; /* Quantité de ces contenus */ + GLoadedContent **result; /* Tableau à retourner */ 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 *access; /* Chemin pour une sous-config.*/ - xmlXPathObjectPtr xobject; /* Cible d'une recherche */ - bool status; /* Bilan d'une restauration */ - g_mutex_lock(&project->ld_mutex); + g_mutex_lock(&project->mutex); - params = g_study_project_find_exploration(project, wid, NULL); + *count = project->count; + result = (GLoadedContent **)calloc(*count, sizeof(GLoadedContent *)); - /* S'il s'agit bien d'une exploration nouvelle */ - if (params != NULL) + for (i = 0; i < *count; i++) { - available = g_content_resolver_get_all(resolver, wid, &count); + result[i] = project->contents[i]; + g_object_ref(G_OBJECT(result[i])); + } - /* Rechargement à partir d'XML ? */ - if (params->xdoc != NULL) - { - assert(params->context != NULL); + g_mutex_unlock(&project->mutex); - for (i = 0; i < count; i++) - { - content = g_loaded_content_get_content(available[i]); - hash = g_binary_content_get_checksum(content); - g_object_unref(G_OBJECT(content)); + return result; - format = g_loaded_content_get_format_name(available[i]); +} - asprintf(&access, "/ChrysalideProject/LoadedContents/Content[@hash='%s' and @format='%s']", - hash, format); - xobject = get_node_xpath_object(params->context, access); - if (XPATH_OBJ_NODES_COUNT(xobject) > 0) - { +/* ---------------------------------------------------------------------------------- */ +/* CHARGEMENTS DE CONTENUS BINAIRES */ +/* ---------------------------------------------------------------------------------- */ - status = g_loaded_content_restore(available[i], params->xdoc, params->context, access); - if (!status) - log_variadic_message(LMT_ERROR, - _("Unable to reload binary from XML (hash=%s) ; skipping..."), hash); +/* Indique le type défini pour les tâches de chargement de contenus binaires. */ +G_DEFINE_TYPE(GLoadingHandler, g_loading_handler, G_TYPE_DELAYED_WORK); - else - { - /** - * S'il s'agit des résultats de la dernière exploration, - * alors les groupes contenant les éléments chargés vont - * être libéré, potentiellement pendant l'analyse. - * - * On temporise en incrémentant les références. - */ - g_object_ref(G_OBJECT(available[i])); - g_signal_connect(available[i], "analyzed", G_CALLBACK(on_loaded_content_analyzed), project); +/****************************************************************************** +* * +* Paramètres : klass = classe à initialiser. * +* * +* Description : Initialise la classe des tâches de chargement de contenus. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ - g_loaded_content_analyze(available[i]); +static void g_loading_handler_class_init(GLoadingHandlerClass *klass) +{ + GObjectClass *object; /* Autre version de la classe */ + GDelayedWorkClass *work; /* Version en classe parente */ - } + object = G_OBJECT_CLASS(klass); - } + object->dispose = (GObjectFinalizeFunc/* ! */)g_loading_handler_dispose; + object->finalize = (GObjectFinalizeFunc)g_loading_handler_finalize; - free(access); + work = G_DELAYED_WORK_CLASS(klass); - if(xobject != NULL) - xmlXPathFreeObject(xobject); + work->run = (run_task_fc)g_loading_handler_process; - g_object_unref(G_OBJECT(available[i])); +} - } - } +/****************************************************************************** +* * +* Paramètres : handler = instance à initialiser. * +* * +* Description : Initialise une tâche de chargement de contenus binaires. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ - /* Découverte(s) initiale(s) ? */ - else - { - for (i = 0; i < count; i++) - { - /** - * S'il s'agit des résultats de la dernière exploration, - * alors les groupes contenant les éléments chargés vont - * être libéré, potentiellement pendant l'analyse. - * - * On temporise en incrémentant les références. - */ - g_object_ref(G_OBJECT(available[i])); +static void g_loading_handler_init(GLoadingHandler *handler) +{ + GContentExplorer *explorer; /* Explorateur de contenus */ + GContentResolver *resolver; /* Resolveur de contenus */ - g_signal_connect(available[i], "analyzed", G_CALLBACK(on_loaded_content_analyzed), project); + g_cond_init(&handler->wait_cond); + g_mutex_init(&handler->mutex); - g_loaded_content_analyze(available[i]); + explorer = get_current_content_explorer(); + g_signal_connect(explorer, "explored", G_CALLBACK(on_new_content_explored), handler); + g_object_unref(G_OBJECT(explorer)); - g_object_unref(G_OBJECT(available[i])); + resolver = get_current_content_resolver(); + g_signal_connect(resolver, "resolved", G_CALLBACK(on_new_content_resolved), handler); + g_object_unref(G_OBJECT(resolver)); - } +} - } - /* Dans tous les cas... */ - if (available != NULL) - free(available); +/****************************************************************************** +* * +* Paramètres : handler = instance d'objet GLib à traiter. * +* * +* Description : Supprime toutes les références externes. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ - /* Si c'était la dernière résolution... */ - if (++params->resolved == params->exp_count) - g_study_project_destroy_content_loading(project, params); +static void g_loading_handler_dispose(GLoadingHandler *handler) +{ + GContentExplorer *explorer; /* Explorateur de contenus */ + GContentResolver *resolver; /* Resolveur de contenus */ + size_t i; /* Boucle de parcours */ + + /* Supression des groupes de travail */ + explorer = get_current_content_explorer(); + resolver = get_current_content_resolver(); + + g_signal_handlers_disconnect_by_func(explorer, G_CALLBACK(on_new_content_explored), handler); + g_signal_handlers_disconnect_by_func(resolver, G_CALLBACK(on_new_content_resolved), handler); + + g_mutex_lock(&handler->mutex); + + for (i = 0; i < handler->exp_count; i++) + { + g_content_resolver_delete_group(resolver, *handler->exp_wids[i]); + g_content_explorer_delete_group(explorer, *handler->exp_wids[i]); } - g_mutex_unlock(&project->ld_mutex); + g_mutex_unlock(&handler->mutex); + + g_object_unref(G_OBJECT(explorer)); + g_object_unref(G_OBJECT(resolver)); + + /* Nettoyage plus général */ + + g_mutex_clear(&handler->mutex); + g_cond_clear(&handler->wait_cond); + + g_object_unref(G_OBJECT(handler->project)); + + G_OBJECT_CLASS(g_loading_handler_parent_class)->dispose(G_OBJECT(handler)); } /****************************************************************************** * * -* Paramètres : content = contenu chargé et analysé. * -* success = bilan d'une analyse menée. * -* project = projet avide des résultats des opérations. * +* Paramètres : handler = instance d'objet GLib à traiter. * * * -* Description : Réceptionne la recette d'une analyse de contenu. * +* Description : Procède à la libération totale de la mémoire. * * * * Retour : - * * * @@ -960,99 +898,160 @@ static void on_new_content_resolved(GContentResolver *resolver, wgroup_id_t wid, * * ******************************************************************************/ -static void on_loaded_content_analyzed(GLoadedContent *content, gboolean success, GStudyProject *project) +static void g_loading_handler_finalize(GLoadingHandler *handler) { - const char *desc; /* Description du contenu */ - - desc = g_loaded_content_describe(content, true); + free(handler->exp_wids); - if (success) - { - g_study_project_attach_content(project, content); - log_variadic_message(LMT_INFO, _("Content from '%s' has been analyzed successfully!"), desc); - } + /* Fermture de l'éventuel fichier XML de chargement */ - else - log_variadic_message(LMT_ERROR, _("Failed to load '%s'"), desc); + if (handler->xdoc != NULL) + close_xml_file(handler->xdoc, handler->context); - g_object_ref(G_OBJECT(content)); + G_OBJECT_CLASS(g_loading_handler_parent_class)->finalize(G_OBJECT(handler)); } /****************************************************************************** * * -* Paramètres : project = project à manipuler. * -* content = contenu chargé à associer au projet actuel. * +* Paramètres : project = projet dont le contenu est à compléter. * +* content = contenu binaire à mémoriser pour le projet. * * * -* Description : Attache un contenu donné à un projet donné. * +* Description : Crée une tâche de chargement de contenu bianire. * * * -* Retour : - * +* Retour : Tâche créée. * * * * Remarques : - * * * ******************************************************************************/ -void g_study_project_attach_content(GStudyProject *project, GLoadedContent *content) +static GLoadingHandler *g_loading_handler_new_discovering(GStudyProject *project, GBinContent *content) { - g_mutex_lock(&project->mutex); + GLoadingHandler *result; /* Tâche à retourner */ + GContentExplorer *explorer; /* Explorateur de contenus */ - project->contents = (GLoadedContent **)realloc(project->contents, - ++project->count * sizeof(GLoadedContent *)); + result = g_object_new(G_TYPE_LOADING_HANDLER, NULL); - project->contents[project->count - 1] = content; - g_object_ref(G_OBJECT(content)); + result->project = project; + g_object_ref(G_OBJECT(result->project)); - g_mutex_unlock(&project->mutex); + result->xdoc = NULL; + result->context = NULL; - g_signal_emit_by_name(project, "content-added", content); + result->exp_wids = (const wgroup_id_t **)malloc(sizeof(wgroup_id_t *)); + result->exp_count = 1; + + result->resolved = 0; + + explorer = get_current_content_explorer(); + + g_mutex_lock(&result->mutex); + + result->exp_wids[0] = g_content_explorer_create_group(explorer, content); + + g_mutex_unlock(&result->mutex); + + g_object_unref(G_OBJECT(explorer)); + + return result; } /****************************************************************************** * * -* Paramètres : project = project à manipuler. * -* content = contenu chargé à dissocier du projet actuel. * +* Paramètres : project = projet dont le contenu est à compléter. * +* xdoc = structure XML en cours d'édition. * +* context = contexte à utiliser pour les recherches. * * * -* Description : Détache un contenu donné d'un projet donné. * +* Description : Crée une tâche de chargement de contenu bianire. * * * -* Retour : - * +* Retour : Tâche créée. * * * * Remarques : - * * * ******************************************************************************/ -void g_study_project_detach_content(GStudyProject *project, GLoadedContent *content) +static GLoadingHandler *g_loading_handler_new_recovering(GStudyProject *project, xmlDoc *xdoc, xmlXPathContext *context) { + GLoadingHandler *result; /* Tâche à retourner */ + xmlXPathObjectPtr xobject; /* Cible d'une recherche */ + size_t count; /* Nombre de contenus premiers */ + GContentExplorer *explorer; /* Explorateur de contenus */ + size_t explored; /* Qté. d'explorations lancées */ size_t i; /* Boucle de parcours */ + char *access; /* Chemin pour un contenu */ + GBinContent *content; /* Contenu binaire retrouvé */ - g_mutex_lock(&project->mutex); + xobject = get_node_xpath_object(context, "/ChrysalideProject/RootContents/Content"); - for (i = 0; i < project->count; i++) - if (project->contents[i] == content) break; + count = XPATH_OBJ_NODES_COUNT(xobject); - if ((i + 1) < project->count) - memmove(&project->contents[i], &project->contents[i + 1], - (project->count - i - 1) * sizeof(GLoadedContent *)); + if (count > 0) + { + result = g_object_new(G_TYPE_LOADING_HANDLER, NULL); - project->contents = (GLoadedContent **)realloc(project->contents, - --project->count * sizeof(GLoadedContent *)); + result->project = project; + g_object_ref(G_OBJECT(result->project)); - g_mutex_unlock(&project->mutex); + result->xdoc = xdoc; + result->context = context; - g_signal_emit_by_name(project, "content-removed", content); + result->exp_wids = (const wgroup_id_t **)malloc(count * sizeof(wgroup_id_t *)); - g_object_unref(G_OBJECT(content)); + result->resolved = 0; + + explorer = get_current_content_explorer(); + + explored = 0; + + g_mutex_lock(&result->mutex); + + for (i = 0; i < XPATH_OBJ_NODES_COUNT(xobject); i++) + { + asprintf(&access, "/ChrysalideProject/RootContents/Content[position()=%zu]", i + 1); + + content = g_binary_content_new_from_xml(context, access, project->filename); + + free(access); + + if (content == NULL) + { + log_variadic_message(LMT_ERROR, _("Unable to load the root content #%zu ; skipping..."), i); + continue; + } + + result->exp_wids[explored++] = g_content_explorer_create_group(explorer, content); + + g_object_unref(G_OBJECT(content)); + + } + + result->exp_count = explored; + + g_mutex_unlock(&result->mutex); + + g_object_unref(G_OBJECT(explorer)); + + } + + else + result = NULL; + + if(xobject != NULL) + xmlXPathFreeObject(xobject); + + return result; } /****************************************************************************** * * -* Paramètres : project = projet dont le contenu est à afficher. * +* Paramètres : handler = opération de chargement à menuer. * +* status = barre de statut à tenir informée. * * * -* Description : Met en place un projet à l'écran. * +* Description : Assure le chargement de contenus binaires en différé. * * * * Retour : - * * * @@ -1060,30 +1059,70 @@ void g_study_project_detach_content(GStudyProject *project, GLoadedContent *cont * * ******************************************************************************/ -void g_study_project_display(const GStudyProject *project) +static void g_loading_handler_process(GLoadingHandler *handler, GtkStatusStack *status) { -#if 0 - size_t i; /* Boucle de parcours #1 */ - loaded_binary *handled; /* Binaire prise en compte */ - size_t j; /* Boucle de parcours #2 */ + g_mutex_lock(&handler->mutex); - for (i = 0; i < project->binaries_count; i++) + while (handler->resolved < handler->exp_count) + g_cond_wait(&handler->wait_cond, &handler->mutex); + + g_mutex_unlock(&handler->mutex); + +} + + +/****************************************************************************** +* * +* Paramètres : handler = gestionnaire dont contenu est à consulter. * +* wid = identifiant du groupe d'exploration recherché. * +* ptr = pointeur vers la valeur d'origine externe. * +* * +* Description : Détermine si un encadrement est adapté pour un identifiant. * +* * +* Retour : Bilan d'adéquation. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static bool g_loading_handler_check(GLoadingHandler *handler, wgroup_id_t wid, const wgroup_id_t **ptr) +{ + bool result; /* Bilan à retourner */ + const wgroup_id_t *value; /* Raccourci de confort */ + size_t i; /* Boucle de parcours */ + + assert(!g_mutex_trylock(&handler->mutex)); + + result = false; + + value = NULL; + + for (i = 0; i < handler->exp_count && !result; i++) { - handled = project->binaries[i]; + value = handler->exp_wids[i]; - for (j = 0; j < handled->count; j++) - g_panel_item_dock(handled->items[j]); + result = (*value == wid); } -#endif + + if (ptr != NULL) + { + assert(!result || value != NULL); + *ptr = (result ? value : NULL); + } + + return result; + } /****************************************************************************** * * -* Paramètres : project = projet dont le contenu est à cacher. * +* Paramètres : explorer = gestionnaire d'explorations à consulter. * +* wid = groupe d'exploration concerné. * +* handler = gestionnaire avide des résultats des opérations. * * * -* Description : Supprime de l'écran un projet en place. * +* Description : Note la fin d'une phase d'exploration de contenu. * * * * Retour : - * * * @@ -1091,57 +1130,167 @@ void g_study_project_display(const GStudyProject *project) * * ******************************************************************************/ -void g_study_project_hide(const GStudyProject *project) +static void on_new_content_explored(GContentExplorer *explorer, wgroup_id_t wid, GLoadingHandler *handler) { -#if 0 - size_t i; /* Boucle de parcours #1 */ - loaded_binary *handled; /* Binaire prise en compte */ - size_t j; /* Boucle de parcours #2 */ + const wgroup_id_t *wid_ptr; /* Référence vers l'origine */ + GBinContent **available; /* Contenus binaires présents */ + size_t count; /* Quantité de ces contenus */ + GContentResolver *resolver; /* Resolveur de contenus */ + size_t i; /* Boucle de parcours */ - for (i = 0; i < project->binaries_count; i++) + g_mutex_lock(&handler->mutex); + + if (g_loading_handler_check(handler, wid, &wid_ptr)) { - handled = project->binaries[i]; + available = g_content_explorer_get_all(explorer, wid, &count); + assert(count > 0); - for (j = 0; j < handled->count; j++) - g_panel_item_undock(handled->items[j]); + resolver = get_current_content_resolver(); + + g_content_resolver_create_group(resolver, wid_ptr, available, count); + + g_object_unref(G_OBJECT(resolver)); + + for (i = 0; i < count; i++) + g_object_unref(G_OBJECT(available[i])); + + free(available); } -#endif + + g_mutex_unlock(&handler->mutex); + } /****************************************************************************** * * -* Paramètres : project = projet dont le contenu est à afficher. * -* count = nombre de contenus pris en compte. [OUT] * +* Paramètres : resolver = gestionnaire de résolutions à consulter. * +* wid = groupe d'exploration concerné. * +* handler = gestionnaire avide des résultats des opérations. * * * -* Description : Fournit l'ensemble des contenus associés à un projet. * +* Description : Note la fin d'une phase de resolution de contenu. * * * -* Retour : Liste à libérer de la mémoire. * +* Retour : - * * * * Remarques : - * * * ******************************************************************************/ -GLoadedContent **g_study_project_get_contents(GStudyProject *project, size_t *count) +static void on_new_content_resolved(GContentResolver *resolver, wgroup_id_t wid, GLoadingHandler *handler) { - GLoadedContent **result; /* Tableau à retourner */ + GLoadedContent **available; /* Contenus chargés valables */ + size_t count; /* Quantité de ces contenus */ 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 *access; /* Chemin pour une sous-config.*/ + xmlXPathObjectPtr xobject; /* Cible d'une recherche */ + bool status; /* Bilan d'une restauration */ - g_mutex_lock(&project->mutex); - - *count = project->count; - result = (GLoadedContent **)calloc(*count, sizeof(GLoadedContent *)); + g_mutex_lock(&handler->mutex); - for (i = 0; i < *count; i++) + if (g_loading_handler_check(handler, wid, NULL)) { - result[i] = project->contents[i]; - g_object_ref(G_OBJECT(result[i])); - } + available = g_content_resolver_get_all(resolver, wid, &count); - g_mutex_unlock(&project->mutex); + /* Rechargement à partir d'XML ? */ + if (handler->xdoc != NULL) + { + assert(handler->context != NULL); - return result; + for (i = 0; i < count; i++) + { + content = g_loaded_content_get_content(available[i]); + hash = g_binary_content_get_checksum(content); + g_object_unref(G_OBJECT(content)); + + format = g_loaded_content_get_format_name(available[i]); + + asprintf(&access, "/ChrysalideProject/LoadedContents/Content[@hash='%s' and @format='%s']", + hash, format); + + xobject = get_node_xpath_object(handler->context, access); + + if (XPATH_OBJ_NODES_COUNT(xobject) > 0) + { + + status = g_loaded_content_restore(available[i], handler->xdoc, handler->context, access); + + if (!status) + log_variadic_message(LMT_ERROR, + _("Unable to reload binary from XML (hash=%s) ; skipping..."), hash); + + else + { + /** + * S'il s'agit des résultats de la dernière exploration, + * alors les groupes contenant les éléments chargés vont + * être libéré, potentiellement pendant l'analyse. + * + * On temporise en incrémentant les références. + */ + 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]); + + } + + } + + free(access); + + if(xobject != NULL) + xmlXPathFreeObject(xobject); + + g_object_unref(G_OBJECT(available[i])); + + } + + } + + /* Découverte(s) initiale(s) ? */ + else + { + for (i = 0; i < count; i++) + { + /** + * S'il s'agit des résultats de la dernière exploration, + * alors les groupes contenant les éléments chargés vont + * être libéré, potentiellement pendant l'analyse. + * + * On temporise en incrémentant les références. + */ + 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]); + + g_object_unref(G_OBJECT(available[i])); + + } + + } + + /* Dans tous les cas... */ + if (available != NULL) + free(available); + + /* Si c'était la dernière résolution... */ + + handler->resolved++; + + g_cond_broadcast(&handler->wait_cond); + + } + + g_mutex_unlock(&handler->mutex); } diff --git a/src/core/queue.c b/src/core/queue.c index 615e351..79a87b2 100644 --- a/src/core/queue.c +++ b/src/core/queue.c @@ -60,6 +60,13 @@ bool init_global_works(void) g_work_queue_define_work_group(queue); #endif +#ifndef NDEBUG + expected = g_work_queue_define_work_group(queue); + assert(expected == LOADING_WORK_GROUP); +#else + g_work_queue_define_work_group(queue); +#endif + return true; } @@ -105,7 +112,8 @@ void wait_for_all_global_works(void) GWorkQueue *queue; /* Singleton pour tâches */ static const wgroup_id_t group_ids[] = { - DEFAULT_WORK_GROUP + DEFAULT_WORK_GROUP, + LOADING_WORK_GROUP }; queue = get_work_queue(); diff --git a/src/core/queue.h b/src/core/queue.h index 1984fff..bee16a4 100644 --- a/src/core/queue.h +++ b/src/core/queue.h @@ -34,8 +34,9 @@ */ #define DEFAULT_WORK_GROUP 0 +#define LOADING_WORK_GROUP 1 -#define GLOBAL_WORK_GROUPS_COUNT 1 +#define GLOBAL_WORK_GROUPS_COUNT 2 /* Met en place les mécanismes de traitements parallèles. */ -- cgit v0.11.2-87-g4458