summaryrefslogtreecommitdiff
path: root/src/analysis/project.c
diff options
context:
space:
mode:
authorCyrille Bagard <nocbos@gmail.com>2018-04-21 22:00:00 (GMT)
committerCyrille Bagard <nocbos@gmail.com>2018-04-21 22:00:00 (GMT)
commit8eb95d316f7b6fbad0ff798abfe7f70f89e812d2 (patch)
tree4f310c7ffdb94d48fff236e63c7e6f0ed9f1dee1 /src/analysis/project.c
parent315146a49b5570294ca20beca720c4e3f74a86bd (diff)
Improved the way file formats are detected and loaded.
Diffstat (limited to 'src/analysis/project.c')
-rw-r--r--src/analysis/project.c846
1 files changed, 680 insertions, 166 deletions
diff --git a/src/analysis/project.c b/src/analysis/project.c
index 09b4aad..88b468a 100644
--- a/src/analysis/project.c
+++ b/src/analysis/project.c
@@ -25,7 +25,6 @@
#include <assert.h>
-#include <inttypes.h>
#include <malloc.h>
#include <string.h>
@@ -33,40 +32,33 @@
#include <i18n.h>
-#include "loaded.h"
#include "loading.h"
#include "../common/xml.h"
#include "../core/global.h"
#include "../core/logs.h"
#include "../core/params.h"
-#include "../glibext/delayed-int.h"
-#include "../gui/core/panels.h"
-#include "../gui/panels/panel.h"
-#include "../format/format.h"
/* ------------------------- DEFINITION D'UN PROJET INTERNE ------------------------- */
-/* Conservation d'un contenu chargé */
-typedef struct _loaded_content
+/* Suivi du chargement de contenus binaires */
+typedef struct _loading_params
{
- GBinContent *content; /* Contenu binaire en place */
- ProjectContentState state; /* Renseigne le type de contenu*/
-
-} loaded_content;
-
-/* Conservation d'un binaire chargé */
-typedef struct _loaded_binary
-{
- GLoadedBinary *binary; /* Binaire en question */
+ union
+ {
+ const gid_t *exp_gid; /* Identifiant d'exploration */
+ const gid_t **exp_gids; /* Identifiants d'exploration */
+ };
+ size_t exp_count; /* Quantitié d'identifiants */
- GPanelItem **items; /* Supports d'affichage final */
- size_t count; /* Nombre de ces supports */
+ size_t resolved; /* Compteur de résolutions */
-} loaded_binary;
+ xmlDoc *xdoc; /* Structure XML chargée ? */
+ xmlXPathContext *context; /* Eventuel contexte XML */
+} loading_params;
/* Projet d'étude regroupant les binaires analysés (instance) */
struct _GStudyProject
@@ -75,6 +67,10 @@ 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 */
@@ -101,6 +97,38 @@ static void g_study_project_class_init(GStudyProjectClass *);
/*Initialise une instance de projet d'étude. */
static void g_study_project_init(GStudyProject *);
+/* Supprime toutes les références externes. */
+static void g_study_project_dispose(GStudyProject *);
+
+/* Procède à la libération totale de la mémoire. */
+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 *);
+
+/* Efface le suivi d'une phase d'intégration obsolète. */
+static void g_study_project_destroy_content_loading(GStudyProject *, loading_params *);
+
+/* Retrouve les infos de chargements liées à une exploration. */
+static loading_params *g_study_project_find_exploration(GStudyProject *, gid_t, const gid_t **);
+
+/* Assure l'intégration de contenus listés dans du XML. */
+static void g_study_project_recover_binary_contents(GStudyProject *, xmlDoc *, xmlXPathContext *);
+
+/* Note la fin d'une phase d'exploration de contenu. */
+static void on_new_content_explored(GContentExplorer *, gid_t, GStudyProject *);
+
+/* Note la fin d'une phase de resolution de contenu. */
+static void on_new_content_resolved(GContentResolver *, gid_t, GStudyProject *);
+
+/* Réceptionne la recette d'une analyse de contenu. */
+static void on_loaded_content_analyzed(GLoadedContent *, gboolean, GStudyProject *);
+
/* ---------------------------------------------------------------------------------- */
@@ -126,6 +154,13 @@ G_DEFINE_TYPE(GStudyProject, g_study_project, G_TYPE_OBJECT);
static void g_study_project_class_init(GStudyProjectClass *klass)
{
+ GObjectClass *object; /* Autre version de la classe */
+
+ object = G_OBJECT_CLASS(klass);
+
+ object->dispose = (GObjectFinalizeFunc/* ! */)g_study_project_dispose;
+ object->finalize = (GObjectFinalizeFunc)g_study_project_finalize;
+
g_signal_new("content-added",
G_TYPE_STUDY_PROJECT,
G_SIGNAL_RUN_LAST,
@@ -159,8 +194,104 @@ 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));
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : binary = instance d'objet GLib à traiter. *
+* *
+* Description : Supprime toutes les références externes. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+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++)
+ g_object_unref(G_OBJECT(project->contents[i]));
+
+ if (project->contents != NULL)
+ free(project->contents);
+
+ g_mutex_unlock(&project->mutex);
+
+ g_mutex_clear(&project->mutex);
+
+ G_OBJECT_CLASS(g_study_project_parent_class)->dispose(G_OBJECT(project));
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : binary = instance d'objet GLib à traiter. *
+* *
+* Description : Procède à la libération totale de la mémoire. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_study_project_finalize(GStudyProject *project)
+{
+ if (project->filename != NULL)
+ free(project->filename);
+
+ G_OBJECT_CLASS(g_study_project_parent_class)->finalize(G_OBJECT(project));
+
}
@@ -201,25 +332,9 @@ GStudyProject *g_study_project_new(void)
GStudyProject *g_study_project_open(const char *filename)
{
- return NULL;
-
-#if 0
-
GStudyProject *result; /* Adresse à retourner */
- xmlDocPtr xdoc; /* Structure XML chargée */
- xmlXPathContextPtr context; /* Contexte pour les XPath */
- unsigned int root_contents; /* Quantité de contenus majeurs*/
- GAsyncQueue *sema; /* Sémaphore taisant son nom */
- xmlXPathObjectPtr xobject; /* Cible d'une recherche */
- unsigned int i; /* Boucle de parcours */
- size_t access_len; /* Taille d'un chemin interne */
- char *access; /* Chemin pour une sous-config.*/
- GBinContent *content; /* Contenu binaire retrouvé */
- long state; /* Etat de ce contenu binaire */
- bool status; /* Bilan d'une lecture */
- GDelayedStudy *dstudy; /* Etude complémentaire à mener*/
- GBinaryLoader *loader; /* Dispositif de chargement */
- GWorkQueue *queue; /* Gestionnaire de différés */
+ xmlDoc *xdoc; /* Structure XML chargée */
+ xmlXPathContext *context; /* Contexte pour les XPath */
if (!open_xml_file(filename, &xdoc, &context)) return NULL;
@@ -227,186 +342,416 @@ GStudyProject *g_study_project_open(const char *filename)
result->filename = strdup(filename);
- /* Préparations aux traitements parallèles */
+ g_study_project_recover_binary_contents(result, xdoc, context);
- root_contents = 0;
+ return result;
- sema = g_async_queue_new();
+}
- void ack_content_processing(GDelayedStudy *dstudy, GAsyncQueue *aqueue)
- {
- g_async_queue_push(aqueue, GINT_TO_POINTER(1));
- }
- /* Chargement des contenus binaires attachés */
+/******************************************************************************
+* *
+* Paramètres : project = project à sauvegarder. *
+* filename = nom de fichier à utiliser ou NULL pour l'existant.*
+* *
+* Description : Procède à l'enregistrement d'un projet donné. *
+* *
+* Retour : true si l'enregistrement s'est déroule sans encombre. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool g_study_project_save(GStudyProject *project, const char *filename)
+{
+ bool result; /* Bilan à retourner */
+ xmlDocPtr xdoc; /* Document XML à créer */
+ xmlXPathContextPtr context; /* Contexte pour les recherches*/
+ const char *final; /* Lieu d'enregistrement final */
+ size_t root_count; /* Quantité d'origines */
+ size_t i; /* Boucle de parcours */
+ GBinContent *content; /* Contenu brut à manipuler */
+ GBinContent *root; /* Contenu d'origine à traiter */
+ 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 */
+
+ /* Forme générale */
+
+ result = create_new_xml_file(&xdoc, &context);
+
+ if (result)
+ result = (ensure_node_exist(xdoc, context, "/ChrysalideProject") != NULL);
+
+ if (result)
+ result = add_string_attribute_to_node(xdoc, context, "/ChrysalideProject", "version", PROJECT_XML_VERSION);
+
+ if (result)
+ result = (ensure_node_exist(xdoc, context, "/ChrysalideProject/RootContents") != NULL);
+
+ if (result)
+ result = (ensure_node_exist(xdoc, context, "/ChrysalideProject/LoadedContents") != NULL);
+
+ final = filename != NULL ? filename : project->filename;
+
+ /* Inscriptions des contenus */
+
+ root_count = 0;
- xobject = get_node_xpath_object(context, "/ChrysalideProject/Contents/Content");
+ g_mutex_lock(&project->mutex);
- for (i = 0; i < XPATH_OBJ_NODES_COUNT(xobject); i++)
+ for (i = 0; i < project->count && result; i++)
{
- access_len = strlen("/ChrysalideProject/Contents/Content[position()=") + SIZE_T_MAXLEN + strlen("]") + 1;
+ content = g_loaded_content_get_content(project->contents[i]);
- access = calloc(access_len, sizeof(char));
- snprintf(access, access_len, "/ChrysalideProject/Contents/Content[position()=%u]", i + 1);
+ /* Racine */
- content = g_binary_content_new_from_xml(context, access, filename);
- status = get_node_prop_long_value(context, access, "state", &state);
+ root = g_binary_content_get_root(content);
- free(access);
+ hash = g_binary_content_get_checksum(root);
- if (content == NULL)
- {
- log_variadic_message(LMT_ERROR, _("Unable to load the binary content #%u ; skipping..."), i);
- continue;
- }
+ asprintf(&access, "/ChrysalideProject/RootContents/Content[@hash='%s']", hash);
- if (!status)
- {
- log_variadic_message(LMT_ERROR, _("Bad state for content '%s' ; skipping..."),
- g_binary_content_describe(content, true));
- continue;
- }
+ xobject = get_node_xpath_object(context, access);
- /* Le contenu peut être un conteneur ? */
- if (state == PCS_ROOT)
+ free(access);
+
+ if (XPATH_OBJ_NODES_COUNT(xobject) == 0)
{
- dstudy = g_delayed_study_new(result, content, state);
- g_signal_connect(dstudy, "work-completed", G_CALLBACK(ack_content_processing), sema);
+ asprintf(&access, "/ChrysalideProject/RootContents/Content[position()=%zu]", ++root_count);
+
+ if (result)
+ result = (ensure_node_exist(xdoc, context, access) != NULL);
- g_delayed_study_preload_only(dstudy);
+ if (result)
+ {
+ hash = g_binary_content_get_checksum(content);
+ result = add_string_attribute_to_node(xdoc, context, access, "hash", hash);
+ }
- root_contents++;
+ if (result)
+ result = g_binary_content_save(root, xdoc, context, access, final);
- study_new_content(dstudy);
+ free(access);
}
- }
+ if(xobject != NULL)
+ xmlXPathFreeObject(xobject);
- if(xobject != NULL)
- xmlXPathFreeObject(xobject);
+ /* Charge utile */
- /* Attente pour la réception de contenus supplémentaires éventuels */
+ asprintf(&access, "/ChrysalideProject/LoadedContents/Content[position()=%zu]", i + 1);
- for (i = 0; i < root_contents; i++)
- g_async_queue_pop(sema);
+ if (result)
+ result = (ensure_node_exist(xdoc, context, access) != NULL);
- g_async_queue_unref(sema);
+ if (result)
+ {
+ hash = g_binary_content_get_checksum(content);
+ result = add_string_attribute_to_node(xdoc, context, access, "hash", hash);
+ }
- /* Chargement des binaires analysés */
+ if (result)
+ {
+ format = g_loaded_content_get_format_name(project->contents[i]);
+ result = add_string_attribute_to_node(xdoc, context, access, "format", format);
+ }
- xobject = get_node_xpath_object(context, "/ChrysalideProject/Binaries/Binary");
+ if (result)
+ result = g_loaded_content_save(project->contents[i], xdoc, context, access);
- for (i = 0; i < XPATH_OBJ_NODES_COUNT(xobject); i++)
- {
- access_len = strlen("/ChrysalideProject/Binaries/Binary[position()=") + SIZE_T_MAXLEN + strlen("]") + 1;
+ free(access);
- access = calloc(access_len, sizeof(char));
- snprintf(access, access_len, "/ChrysalideProject/Binaries/Binary[position()=%u]", i + 1);
+ g_object_unref(G_OBJECT(content));
- loader = g_binary_loader_new_from_xml(filename, access, result);
+ }
- free(access);
+ g_mutex_unlock(&project->mutex);
- queue = get_work_queue();
- g_work_queue_schedule_work(queue, G_DELAYED_WORK(loader), DEFAULT_WORK_GROUP);
+ /* Sauvegarde finale */
- }
+ if (result)
+ result = save_xml_file(xdoc, final);
- if(xobject != NULL)
- xmlXPathFreeObject(xobject);
+ if (result && filename != NULL)
+ {
+ if (project->filename != NULL) free(project->filename);
+ project->filename = strdup(filename);
- /* Fin du chargement */
+ }
close_xml_file(xdoc, context);
return result;
-#endif
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : project = project à consulter. *
+* *
+* Description : Indique le chemin du fichier destiné à la sauvegarde. *
+* *
+* Retour : Chemin de fichier pour l'enregistrement ou NULL si indéfini. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+const char *g_study_project_get_filename(const GStudyProject *project)
+{
+ return project->filename;
}
+
+/* ---------------------------------------------------------------------------------- */
+/* INTEGRATION DE CONTENUS BINAIRES */
+/* ---------------------------------------------------------------------------------- */
+
+
/******************************************************************************
* *
-* Paramètres : project = project à sauvegarder. *
-* filename = nom de fichier à utiliser ou NULL pour l'existant.*
+* Paramètres : project = projet dont le contenu est à compléter. *
* *
-* Description : Procède à l'enregistrement d'un projet donné. *
+* Description : Prépare le suivi d'une nouvelle phase d'intégration. *
* *
-* Retour : true si l'enregistrement s'est déroule sans encombre. *
+* Retour : Nouvelle structure de suivi prête à être complétée. *
* *
* Remarques : - *
* *
******************************************************************************/
-bool g_study_project_save(GStudyProject *project, const char *filename)
+static loading_params *g_study_project_prepare_content_loading(GStudyProject *project)
{
- return false;
+ loading_params *result; /* Trouvaille à retourner */
-#if 0
+ assert(!g_mutex_trylock(&project->ld_mutex));
- bool result; /* Bilan à retourner */
- xmlDocPtr xdoc; /* Document XML à créer */
- xmlXPathContextPtr context; /* Contexte pour les recherches*/
- const char *final; /* Lieu d'enregistrement final */
- size_t i; /* Boucle de parcours */
- char *access; /* Chemin pour une sous-config.*/
+ project->ld_params = (loading_params *)realloc(project->ld_params,
+ ++project->ld_count * sizeof(loading_params));
- result = create_new_xml_file(&xdoc, &context);
+ result = &project->ld_params[project->ld_count - 1];
- if (result)
- result = (ensure_node_exist(xdoc, context, "/ChrysalideProject") != NULL);
+ return result;
- final = filename != NULL ? filename : project->filename;
+}
+
+/******************************************************************************
+* *
+* Paramètres : project = projet dont le contenu est à compléter. *
+* params = paramètres de chargemeent à supprimer. *
+* *
+* Description : Efface le suivi d'une phase d'intégration obsolète. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_study_project_destroy_content_loading(GStudyProject *project, loading_params *params)
+{
+ 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));
- /* Enregistrement des binaires analysés */
+ /* Supression des groupes de travail */
- for (i = 0; i < project->binaries_count && result; i++)
+ explorer = get_current_content_explorer();
+ resolver = get_current_content_resolver();
+
+ if (params->exp_count == 1)
{
- asprintf(&access, "/ChrysalideProject/Binaries/Binary[position()=%zu]", i + 1);
+ g_content_resolver_delete_group(resolver, *params->exp_gid);
+ g_content_explorer_delete_group(explorer, *params->exp_gid);
+ }
- result = g_loaded_binary_save(project->binaries[i]->binary, xdoc, context, access, final);
+ else
+ {
+ for (i = 0; i < params->exp_count; i++)
+ {
+ g_content_resolver_delete_group(resolver, *params->exp_gids[i]);
+ g_content_explorer_delete_group(explorer, *params->exp_gids[i]);
+ }
- free(access);
+ free(params->exp_gids);
}
- /* Sauvegarde finale */
+ g_object_unref(G_OBJECT(explorer));
+ g_object_unref(G_OBJECT(resolver));
- result &= save_xml_file(xdoc, final);
+ /* Fermture de l'éventuel fichier XML de chargement */
- if (result && filename != NULL)
+ if (params->xdoc != NULL)
+ close_xml_file(params->xdoc, params->context);
+
+ /* 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));
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : project = projet dont le contenu est à consulter. *
+* gid = identifiant du groupe d'exploration recherché. *
+* ptr = pointeur vers la valeur d'origine externe. *
+* *
+* Description : Retrouve les infos de chargements liées à une exploration. *
+* *
+* Retour : Informations trouvées ou NULL en cas d'échec. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static loading_params *g_study_project_find_exploration(GStudyProject *project, gid_t gid, const gid_t **ptr)
+{
+ loading_params *result; /* Trouvaille à retourner */
+ const gid_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++)
{
- if (project->filename != NULL) free(project->filename);
- project->filename = strdup(filename);
+ if (project->ld_params[i].exp_count == 1)
+ {
+ value = project->ld_params[i].exp_gid;
+
+ if (*value == gid)
+ result = &project->ld_params[i];
+
+ }
+
+ else
+ for (k = 0; k < project->ld_params[i].exp_count && result == NULL; k++)
+ {
+ value = project->ld_params[i].exp_gids[k];
+
+ if (*value == gid)
+ result = &project->ld_params[i];
+
+ }
}
- close_xml_file(xdoc, context);
+ if (ptr != NULL)
+ {
+ assert(result == NULL || value != NULL);
+ *ptr = (result == NULL ? NULL : value);
+ }
return result;
-#endif
-
}
/******************************************************************************
* *
-* Paramètres : project = project à consulter. *
+* Paramètres : project = projet dont le contenu est à compléter. *
+* xdoc = structure XML en cours d'édition. *
+* context = contexte à utiliser pour les recherches. *
* *
-* Description : Indique le chemin du fichier destiné à la sauvegarde. *
+* Description : Assure l'intégration de contenus listés dans du XML. *
* *
-* Retour : Chemin de fichier pour l'enregistrement ou NULL si indéfini. *
+* Retour : - *
* *
* Remarques : - *
* *
******************************************************************************/
-const char *g_study_project_get_filename(const GStudyProject *project)
+static void g_study_project_recover_binary_contents(GStudyProject *project, xmlDoc *xdoc, xmlXPathContext *context)
{
- return project->filename;
+ 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);
+
+ if (count > 1)
+ params->exp_gids = (const gid_t **)malloc(count * sizeof(gid_t *));
+
+ params->resolved = 0;
+
+ params->xdoc = xdoc;
+ params->context = context;
+
+ explored = 0;
+
+ 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;
+ }
+
+ if (count == 1)
+ {
+ params->exp_gid = g_content_explorer_create_group(explorer, content);
+ explored++;
+ }
+ else
+ params->exp_gids[explored++] = g_content_explorer_create_group(explorer, content);
+
+ g_object_unref(G_OBJECT(content));
+
+ }
+
+ params->exp_count = explored;
+
+ g_mutex_unlock(&project->ld_mutex);
+
+ g_object_unref(G_OBJECT(explorer));
+
+ }
+
+ if(xobject != NULL)
+ xmlXPathFreeObject(xobject);
}
@@ -415,9 +760,8 @@ const char *g_study_project_get_filename(const GStudyProject *project)
* *
* Paramètres : project = projet dont le contenu est à compléter. *
* content = contenu binaire à mémoriser pour le projet. *
-* state = état du contenu à conserver. *
* *
-* Description : Assure l'intégration d'un contenu binaire dans un projet. *
+* Description : Assure l'intégration de contenus binaires dans un projet. *
* *
* Retour : - *
* *
@@ -425,77 +769,246 @@ const char *g_study_project_get_filename(const GStudyProject *project)
* *
******************************************************************************/
-void g_study_project_add_binary_content(GStudyProject *project, GBinContent *content, ProjectContentState state)
+void g_study_project_discover_binary_content(GStudyProject *project, GBinContent *content)
{
-#if 0
+ loading_params *params; /* Informations de chargement */
+ GContentExplorer *explorer; /* Explorateur de contenus */
- loaded_content *new; /* Nouveau contenu à définir */
+ explorer = get_current_content_explorer();
- g_mutex_lock(&project->cnt_mutex);
+ g_mutex_lock(&project->ld_mutex);
- project->contents = (loaded_content *)realloc(project->contents,
- ++project->contents_count * sizeof(loaded_content));
+ params = g_study_project_prepare_content_loading(project);
- new = &project->contents[project->contents_count - 1];
+ params->exp_gid = g_content_explorer_create_group(explorer, content);
+ params->exp_count = 1;
- g_object_ref(G_OBJECT(content));
+ params->resolved = 0;
- new->content = content;
- new->state = state;
+ params->xdoc = NULL;
+ params->context = NULL;
- g_mutex_unlock(&project->cnt_mutex);
+ g_mutex_unlock(&project->ld_mutex);
-#endif
+ g_object_unref(G_OBJECT(explorer));
}
/******************************************************************************
* *
-* Paramètres : project = projet dont le contenu est à compléter. *
-* hash = empreinte du contenu à retrouver. *
+* Paramètres : explorer = gestionnaire d'explorations à consulter. *
+* gid = groupe d'exploration concerné. *
+* project = projet avide des résultats des opérations. *
* *
-* Description : Recherche un contenu binaire du projet selon son empreinte. *
+* Description : Note la fin d'une phase d'exploration de contenu. *
* *
-* Retour : Contenu avec propriété transférée ou NULL en cas d'échec. *
+* Retour : - *
* *
* Remarques : - *
* *
******************************************************************************/
-GBinContent *g_study_project_find_binary_content_by_hash(GStudyProject *project, const char *hash)
+static void on_new_content_explored(GContentExplorer *explorer, gid_t gid, GStudyProject *project)
{
- return NULL;
+ const gid_t *gid_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 */
+ const wgroup_id_t *wid; /* Groupe de tâches */
+ GContentResolver *resolver; /* Resolveur de contenus */
+ size_t i; /* Boucle de parcours */
-#if 0
+ g_mutex_lock(&project->ld_mutex);
+
+ params = g_study_project_find_exploration(project, gid, &gid_ptr);
+
+ /* S'il s'agit bien d'une exploration nouvelle */
+ if (params != NULL)
+ {
+ wid = g_content_explorer_get_group_work_id(explorer, gid);
+
+ available = g_content_explorer_get_all(explorer, gid, &count);
+ assert(count > 0);
+
+ resolver = get_current_content_resolver();
+
+ g_content_resolver_create_group(resolver, wid, gid_ptr, available, count);
+
+ g_object_unref(G_OBJECT(resolver));
+
+ for (i = 0; i < count; i++)
+ g_object_unref(G_OBJECT(available[i]));
- GBinContent *result; /* Trouvaille à retourner */
+ free(available);
+
+ }
+
+ g_mutex_unlock(&project->ld_mutex);
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : resolver = gestionnaire de résolutions à consulter. *
+* gid = groupe d'exploration concerné. *
+* project = projet avide des résultats des opérations. *
+* *
+* Description : Note la fin d'une phase de resolution de contenu. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void on_new_content_resolved(GContentResolver *resolver, gid_t gid, GStudyProject *project)
+{
+ loading_params *params; /* Informations de chargement */
+ GLoadedContent **available; /* Contenus chargés valables */
+ size_t count; /* Quantité de ces contenus */
size_t i; /* Boucle de parcours */
- GBinContent *iter; /* Contenu binaire analysé */
- const gchar *other; /* Autre empreinte à comparer */
+ 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 */
- result = NULL;
+ g_mutex_lock(&project->ld_mutex);
- g_mutex_lock(&project->cnt_mutex);
+ params = g_study_project_find_exploration(project, gid, NULL);
- for (i = 0; i < project->contents_count && result == NULL; i++)
+ /* S'il s'agit bien d'une exploration nouvelle */
+ if (params != NULL)
{
- iter = project->contents[i].content;
- other = g_binary_content_get_checksum(iter);
+ available = g_content_resolver_get_all(resolver, gid, &count);
- if (strcmp(hash, other) == 0)
+ /* Rechargement à partir d'XML ? */
+ if (params->xdoc != NULL)
{
- g_object_ref(G_OBJECT(iter));
- result = iter;
+ assert(params->context != NULL);
+
+ 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(params->context, access);
+
+ if (XPATH_OBJ_NODES_COUNT(xobject) > 0)
+ {
+
+ 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);
+
+ 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);
+
+ 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), 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... */
+ if (++params->resolved == params->exp_count)
+ g_study_project_destroy_content_loading(project, params);
+
}
- g_mutex_unlock(&project->cnt_mutex);
+ g_mutex_unlock(&project->ld_mutex);
- return result;
+}
-#endif
+
+/******************************************************************************
+* *
+* Paramètres : content = contenu chargé et analysé. *
+* success = bilan d'une analyse menée. *
+* project = projet avide des résultats des opérations. *
+* *
+* Description : Réceptionne la recette d'une analyse de contenu. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void on_loaded_content_analyzed(GLoadedContent *content, gboolean success, GStudyProject *project)
+{
+ const char *desc; /* Description du contenu */
+
+ if (success)
+ g_study_project_attach_content(project, content);
+
+ else
+ {
+ desc = g_loaded_content_describe(content, true);
+ log_variadic_message(LMT_ERROR, _("Failed to load '%s'"), desc);
+ }
+
+ g_object_ref(G_OBJECT(content));
}
@@ -521,6 +1034,7 @@ void g_study_project_attach_content(GStudyProject *project, GLoadedContent *cont
++project->count * sizeof(GLoadedContent *));
project->contents[project->count - 1] = content;
+ g_object_ref(G_OBJECT(content));
g_mutex_unlock(&project->mutex);
@@ -732,7 +1246,7 @@ void push_project_into_recent_list(const GStudyProject *project)
recent.mime_type = "application/chrysalide.project";
recent.app_name = "Chrysalide";
- recent.app_exec = "chrysalide %f";
+ recent.app_exec = "chrysalide -p %f";
gtk_recent_manager_add_full(manager, qualified, &recent);