/* Chrysalide - Outil d'analyse de fichiers binaires * loading.c - reconnaissance de contenus binaires * * Copyright (C) 2017 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 Foobar. If not, see . */ #include "loading.h" #include "../core/formats.h" #include "../glibext/delayed-int.h" #include "../gui/panels/log.h" /* ----------------------- AMORCE POUR CHARGEMENT DE CONTENUS ----------------------- */ /* Ensembles binaires à désassembler (instance) */ struct _GDelayedStudy { GDelayedWork parent; /* A laisser en premier */ GStudyProject *project; /* Projet de rattachement */ GBinContent *content; /* Contenu binaire à traiter */ ProjectContentState state; /* Renseigne le type de contenu*/ bool only_preload; /* Enregistrement seulement ? */ }; /* Ensembles binaires à désassembler (classe) */ struct _GDelayedStudyClass { GDelayedWorkClass parent; /* A laisser en premier */ }; /* Initialise la classe des intégrations de binaires à étudier. */ static void g_delayed_study_class_init(GDelayedStudyClass *); /* Initialise une intégration de binaire à étudier. */ static void g_delayed_study_init(GDelayedStudy *); /* Supprime toutes les références externes. */ static void g_delayed_study_dispose(GDelayedStudy *); /* Procède à la libération totale de la mémoire. */ static void g_delayed_study_finalize(GDelayedStudy *); /* Prépare une intégration de binaire au projet courant. */ static void g_delayed_study_process(GDelayedStudy *, GtkStatusStack *); /* ----------------------- CHARGEMENT DE BINAIRE NON BLOQUANT ----------------------- */ #define G_TYPE_BINARY_LOADER g_binary_loader_get_type() #define G_BINARY_LOADER(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_BINARY_LOADER, GBinaryLoader)) #define G_IS_BINARY_LOADER(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_BINARY_LOADER)) #define G_BINARY_LOADER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_BINARY_LOADER, GBinaryLoaderClass)) #define G_IS_BINARY_LOADER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_BINARY_LOADER)) #define G_BINARY_LOADER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_BINARY_LOADER, GBinaryLoaderClass)) /* Chargement non bloquant d'un binaire (instance) */ struct _GBinaryLoader { GDelayedWork parent; /* A laisser en premier */ bool from_content; /* Sélection de champs */ union { GBinContent *content; /* Contenu brut à disposition */ struct { char *filename; /* Chemin vers l'ensemble XML */ char *path; /* Chemin de la définition XML */ }; }; GStudyProject *project; /* Accès aux contenus liés */ GLoadedBinary *binary; /* Résultat du chargement */ }; /* Chargement non bloquant d'un binaire (classe) */ struct _GBinaryLoaderClass { GDelayedWorkClass parent; /* A laisser en premier */ }; /* Indique le type défini pour le chargement non bloquant d'un binaire. */ GType g_binary_loader_get_type(void); /* Initialise la classe des tâches de chargement non bloquant. */ static void g_binary_loader_class_init(GBinaryLoaderClass *); /* Initialise une tâche de chargement non bloquant d'un binaire. */ static void g_binary_loader_init(GBinaryLoader *); /* Supprime toutes les références externes. */ static void g_binary_loader_dispose(GBinaryLoader *); /* Procède à la libération totale de la mémoire. */ static void g_binary_loader_finalize(GBinaryLoader *); /* Réalise le chargement effectif d'un binaire. */ static void g_binary_loader_process(GBinaryLoader *, GtkStatusStack *); /* ---------------------------------------------------------------------------------- */ /* AMORCE POUR CHARGEMENT DE CONTENUS */ /* ---------------------------------------------------------------------------------- */ /* Indique le type défini pour les tâches de préparations d'étude. */ G_DEFINE_TYPE(GDelayedStudy, g_delayed_study, G_TYPE_DELAYED_WORK); /****************************************************************************** * * * Paramètres : klass = classe à initialiser. * * * * Description : Initialise la classe des intégrations de binaires à étudier. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ static void g_delayed_study_class_init(GDelayedStudyClass *klass) { GObjectClass *object; /* Autre version de la classe */ GDelayedWorkClass *work; /* Version en classe parente */ object = G_OBJECT_CLASS(klass); work = G_DELAYED_WORK_CLASS(klass); object->dispose = (GObjectFinalizeFunc/* ! */)g_delayed_study_dispose; object->finalize = (GObjectFinalizeFunc)g_delayed_study_finalize; work->run = (run_task_fc)g_delayed_study_process; } /****************************************************************************** * * * Paramètres : dstudy = instance à initialiser. * * * * Description : Initialise une intégration de binaire à étudier. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ static void g_delayed_study_init(GDelayedStudy *dstudy) { dstudy->only_preload = false; } /****************************************************************************** * * * Paramètres : binary = instance d'objet GLib à traiter. * * * * Description : Supprime toutes les références externes. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ static void g_delayed_study_dispose(GDelayedStudy *dstudy) { g_object_unref(G_OBJECT(dstudy->project)); g_object_unref(G_OBJECT(dstudy->content)); G_OBJECT_CLASS(g_delayed_study_parent_class)->dispose(G_OBJECT(dstudy)); } /****************************************************************************** * * * Paramètres : binary = instance d'objet GLib à traiter. * * * * Description : Procède à la libération totale de la mémoire. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ static void g_delayed_study_finalize(GDelayedStudy *dstudy) { G_OBJECT_CLASS(g_delayed_study_parent_class)->finalize(G_OBJECT(dstudy)); } /****************************************************************************** * * * Paramètres : project = projet dont le contenu est à compléter. * * content = contenu binaire chargé à analyser. * * state = état du contenu à conserver. * * * * Description : Crée une tâche d'intégration de contenu binaire. * * * * Retour : Tâche créée. * * * * Remarques : L'appelant perd la propriété du contenu. * * * ******************************************************************************/ GDelayedStudy *g_delayed_study_new(GStudyProject *project, GBinContent *content, ProjectContentState state) { GDelayedStudy *result; /* Tâche à retourner */ result = g_object_new(G_TYPE_DELAYED_STUDY, NULL); g_object_ref(G_OBJECT(project)); result->project = project; g_object_ref(G_OBJECT(content)); result->content = content; result->state = state; return result; } /****************************************************************************** * * * Paramètres : dstudy = intégration à mener. * * status = barre de statut à tenir informée. * * * * Description : Prépare une intégration de binaire au projet courant. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ static void g_delayed_study_process(GDelayedStudy *dstudy, GtkStatusStack *status) { FormatMatchStatus mstatus; /* Statut d'une reconnaissance */ char *target; /* Sous-traitance requise */ GBinaryLoader *loader; /* Dispositif de chargement */ GWorkQueue *queue; /* Gestionnaire de différés */ mstatus = find_matching_format(dstudy->content, NULL, &target); switch (mstatus) { case FMS_MATCHED: if (dstudy->only_preload) g_study_project_add_binary_content(dstudy->project, dstudy->content, dstudy->state); else { loader = g_binary_loader_new(dstudy->content, dstudy->project); queue = get_work_queue(); g_work_queue_schedule_work(queue, G_DELAYED_WORK(loader), DEFAULT_WORK_GROUP); } break; case FMS_FORWARDED: /** * L'émetteur de ce type de réponse a pour charge de * reprogrammer lui même l'analyse de nouveaux contenus. */ log_variadic_message(LMT_PROCESS, _("binary '%s' contains other binaries..."), g_binary_content_describe(dstudy->content, true)); if (dstudy->state == PCS_ROOT) g_study_project_add_binary_content(dstudy->project, dstudy->content, PCS_ROOT); break; default: /** * Les jeux sont faits pour le contenu binaire courant. */ log_variadic_message(LMT_PROCESS, _("Unknown binary format for '%s'..."), g_binary_content_describe(dstudy->content, true)); break; } } /****************************************************************************** * * * Paramètres : dstudy = tâche d'analyse de contenu pour projet à mener. * * * * Description : Limite l'étude et l'intégration d'un contenu binaire. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ void g_delayed_study_preload_only(GDelayedStudy *dstudy) { dstudy->only_preload = true; } /****************************************************************************** * * * Paramètres : content = contenu binaire chargé à analyser. * * state = état du contenu à conserver. * * * * Description : Programme l'étude et l'intégration d'un contenu binaire. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ void qck_study_new_content(GBinContent *content, ProjectContentState state) { GDelayedStudy *dstudy; /* Etude à conduire */ dstudy = g_delayed_study_new(get_current_project(), content, state); study_new_content(dstudy); } /****************************************************************************** * * * Paramètres : content = contenu binaire chargé à analyser. * * state = état du contenu à conserver. * * * * Description : Programme l'étude et l'intégration d'un contenu binaire. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ void study_new_content(GDelayedStudy *dstudy) { GWorkQueue *queue; /* Gestionnaire de différés */ queue = get_work_queue(); g_work_queue_schedule_work(queue, G_DELAYED_WORK(dstudy), DEFAULT_WORK_GROUP); } /* ---------------------------------------------------------------------------------- */ /* CHARGEMENT DE BINAIRE NON BLOQUANT */ /* ---------------------------------------------------------------------------------- */ /* Indique le type défini pour le chargement non bloquant d'un binaire. */ G_DEFINE_TYPE(GBinaryLoader, g_binary_loader, G_TYPE_DELAYED_WORK); /****************************************************************************** * * * Paramètres : klass = classe à initialiser. * * * * Description : Initialise la classe des tâches de chargement non bloquant. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ static void g_binary_loader_class_init(GBinaryLoaderClass *klass) { GObjectClass *object; /* Autre version de la classe */ GDelayedWorkClass *work; /* Version en classe parente */ object = G_OBJECT_CLASS(klass); object->dispose = (GObjectFinalizeFunc/* ! */)g_binary_loader_dispose; object->finalize = (GObjectFinalizeFunc)g_binary_loader_finalize; work = G_DELAYED_WORK_CLASS(klass); work->run = (run_task_fc)g_binary_loader_process; } /****************************************************************************** * * * Paramètres : loader = instance à initialiser. * * * * Description : Initialise une tâche de chargement non bloquant d'un binaire.* * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ static void g_binary_loader_init(GBinaryLoader *loader) { loader->binary = NULL; } /****************************************************************************** * * * Paramètres : loader = instance d'objet GLib à traiter. * * * * Description : Supprime toutes les références externes. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ static void g_binary_loader_dispose(GBinaryLoader *loader) { if (loader->from_content) g_object_unref(G_OBJECT(loader->content)); g_object_unref(G_OBJECT(loader->project)); if (loader->binary != NULL) g_object_unref(G_OBJECT(loader->binary)); G_OBJECT_CLASS(g_binary_loader_parent_class)->dispose(G_OBJECT(loader)); } /****************************************************************************** * * * Paramètres : loader = instance d'objet GLib à traiter. * * * * Description : Procède à la libération totale de la mémoire. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ static void g_binary_loader_finalize(GBinaryLoader *loader) { if (!loader->from_content) { free(loader->filename); free(loader->path); } G_OBJECT_CLASS(g_binary_loader_parent_class)->finalize(G_OBJECT(loader)); } /****************************************************************************** * * * Paramètres : content = contenu binaire chargé en mémoire. * * project = projet dans lequel venir ajouter des contenus. * * * * Description : Prépare le chargement non bloqué d'un contenu binaire. * * * * Retour : Instance de binaire chargé ou NULL en cas d'échec. * * * * Remarques : - * * * ******************************************************************************/ GBinaryLoader *g_binary_loader_new(GBinContent *content, GStudyProject *project) { GBinaryLoader *result; /* Tâche à retourner */ result = g_object_new(G_TYPE_BINARY_LOADER, NULL); result->from_content = true; result->content = content; g_object_ref(G_OBJECT(content)); result->project = project; g_object_ref(G_OBJECT(project)); return result; } /****************************************************************************** * * * Paramètres : filename = chemin d'accès au fichier à charger. * * path = chemin d'accès au noeud XML à lire. * * project = projet dans lequel venir rechercher les contenus. * * * * Description : Prépare le chargement non bloqué d'un contenu XML. * * * * Retour : Instance de binaire chargé ou NULL en cas d'échec. * * * * Remarques : - * * * ******************************************************************************/ GBinaryLoader *g_binary_loader_new_from_xml(const char *filename, const char *path, GStudyProject *project) { GBinaryLoader *result; /* Tâche à retourner */ result = g_object_new(G_TYPE_BINARY_LOADER, NULL); result->from_content = false; result->filename = strdup(filename); result->path = strdup(path); result->project = project; g_object_ref(G_OBJECT(project)); return result; } /****************************************************************************** * * * Paramètres : loader = encadrement du chargement à mener. * * status = barre de statut à tenir informée. * * * * Description : Réalise le chargement effectif d'un binaire. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ static void g_binary_loader_process(GBinaryLoader *loader, GtkStatusStack *status) { xmlDocPtr xdoc; /* Structure XML chargée */ xmlXPathContextPtr context; /* Contexte pour les XPath */ /* Tentative de chargement de binaire */ if (loader->from_content) loader->binary = g_loaded_binary_new(loader->content); else { if (open_xml_file(loader->filename, &xdoc, &context)) { loader->binary = g_loaded_binary_new_from_xml(context, loader->path, loader->project); close_xml_file(xdoc, context); } } /* Poursuites qui peuvent être traitées dans la foulée */ if (loader->binary != NULL) { /* Si le contenu n'a pas déjà été ajouté au projet au moment du chargement de ce dernier... */ if (loader->from_content) g_study_project_add_binary_content(loader->project, loader->content, PCS_ROOT/* FIXME : dstudy->state*/); ack_loaded_binary(loader, loader->project); } } /****************************************************************************** * * * Paramètres : loader = encadrement du chargement à consulter. * * * * Description : Retourne l'instance du binaire chargé en cas de succès. * * * * Retour : Instance mise en place ou NULL. * * * * Remarques : - * * * ******************************************************************************/ GLoadedBinary *g_binary_loader_get_result(const GBinaryLoader *loader) { GLoadedBinary *result; /* Chargement à faire suivre */ result = loader->binary; if (result != NULL) g_object_ref(G_OBJECT(result)); return result; }