/* Chrysalide - Outil d'analyse de fichiers binaires
* project.c - gestion d'un groupe de fichiers binaires
*
* Copyright (C) 2008-2014 Cyrille Bagard
*
* This file is part of Chrysalide.
*
* OpenIDA 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.
*
* OpenIDA 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 "project.h"
#include
#include
#include
#include
#include "../common/xml.h"
#include "../core/formats.h"
#include "../core/params.h"
#include "../glibext/signal.h"
#include "../gtkext/easygtk.h"
#include "../glibext/delayed-int.h"
#include "../gtkext/gtkblockview.h"
#include "../gtkext/gtkgraphview.h"
#include "../gtkext/gtksourceview.h"
#include "../gui/panels/log.h"
#include "../gui/panels/panel.h"
/* ------------------------- DEFINITION D'UN PROJET INTERNE ------------------------- */
/* Conservation d'un contenu chargé */
typedef struct _loaded_content
{
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 */
GtkViewPanel *views[BVW_COUNT]; /* Composants pour l'affichage */
GtkWidget *scrollwindows[BVW_COUNT]; /* Supports pour l'affichage */
GEditorItem *item; /* Support d'affichage final */
} loaded_binary;
/* Projet d'étude regroupant les binaires analysés (instance) */
struct _GStudyProject
{
GObject parent; /* A laisser en premier */
GObject *ref; /* Espace de référencement */
char *filename; /* Lieu d'enregistrement */
loaded_content *contents; /* Contenus binaires chargés */
size_t contents_count; /* Nombre de ces contenus */
GMutex cnt_mutex; /* Modification de la liste */
loaded_binary **binaries; /* Fichiers binaires associés */
size_t binaries_count; /* Nombre de ces fichiers */
GMutex bin_mutex; /* Modification de la liste */
};
/* Projet d'étude regroupant les binaires analysés (classe) */
struct _GStudyProjectClass
{
GObjectClass parent; /* A laisser en premier */
};
/* Initialise la classe des projets d'étude. */
static void g_study_project_class_init(GStudyProjectClass *);
/*Initialise une instance de projet d'étude. */
static void g_study_project_init(GStudyProject *);
/* Supprime de l'écran un projet en place. */
static void g_study_project_hide(const GStudyProject *);
/* ----------------------- 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 *, GtkExtStatusBar *);
/* ---------------------------------------------------------------------------------- */
/* DEFINITION D'UN PROJET INTERNE */
/* ---------------------------------------------------------------------------------- */
/* Indique le type défini pour un projet d'étude. */
G_DEFINE_TYPE(GStudyProject, g_study_project, G_TYPE_OBJECT);
/******************************************************************************
* *
* Paramètres : klass = classe à initialiser. *
* *
* Description : Initialise la classe des projets d'étude. *
* *
* Retour : - *
* *
* Remarques : - *
* *
******************************************************************************/
static void g_study_project_class_init(GStudyProjectClass *klass)
{
}
/******************************************************************************
* *
* Paramètres : project = instance à initialiser. *
* *
* Description : Initialise une instance de projet d'étude. *
* *
* Retour : - *
* *
* Remarques : - *
* *
******************************************************************************/
static void g_study_project_init(GStudyProject *project)
{
g_mutex_init(&project->cnt_mutex);
g_mutex_init(&project->bin_mutex);
}
/******************************************************************************
* *
* Paramètres : - *
* *
* Description : Crée un nouveau projet vierge. *
* *
* Retour : Instance mise en place. *
* *
* Remarques : - *
* *
******************************************************************************/
GStudyProject *g_study_project_new(GObject *ref)
{
GStudyProject *result; /* Composant à retourner */
result = g_object_new(G_TYPE_STUDY_PROJECT, NULL);
g_object_ref(ref);
result->ref = ref;
return result;
}
/******************************************************************************
* *
* Paramètres : filename = chemin d'accès au fichier à charger. *
* *
* Description : Crée un projet à partir du contenu XML d'un fichier. *
* *
* Retour : - *
* *
* Remarques : - *
* *
******************************************************************************/
GStudyProject *g_study_project_open(GObject *ref, const char *filename)
{
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*/
GLoadedBinary *binary; /* Représentation à intégrer */
if (!open_xml_file(filename, &xdoc, &context)) return NULL;
result = g_study_project_new(ref);
result->filename = strdup(filename);
/* Préparations aux traitements parallèles */
root_contents = 0;
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 */
xobject = get_node_xpath_object(context, "/ChrysalideProject/Contents/Content");
for (i = 0; i < XPATH_OBJ_NODES_COUNT(xobject); i++)
{
access_len = strlen("/ChrysalideProject/Contents/Content[position()=") + SIZE_T_MAXLEN + strlen("]") + 1;
access = calloc(access_len, sizeof(char));
snprintf(access, access_len, "/ChrysalideProject/Contents/Content[position()=%u]", i + 1);
content = g_binary_content_new_from_xml(context, access, filename);
status = get_node_prop_long_value(context, access, "state", &state);
free(access);
if (content == NULL)
{
log_variadic_message(LMT_ERROR, _("Unable to load the binary content #%u ; skipping..."), i);
continue;
}
if (!status)
{
log_variadic_message(LMT_ERROR, _("Bad state for content '%s' ; skipping..."),
g_binary_content_describe(content, true));
continue;
}
/* Le contenu peut être un conteneur ? */
if (state == PCS_ROOT)
{
dstudy = g_delayed_study_new(result, content, state);
g_signal_connect(dstudy, "work-completed", G_CALLBACK(ack_content_processing), sema);
g_delayed_study_preload_only(dstudy);
root_contents++;
study_new_content(dstudy);
}
}
if(xobject != NULL)
xmlXPathFreeObject(xobject);
/* Attente pour la réception de contenus supplémentaires éventuels */
for (i = 0; i < root_contents; i++)
g_async_queue_pop(sema);
g_async_queue_unref(sema);
/* Chargement des binaires analysés */
xobject = get_node_xpath_object(context, "/ChrysalideProject/Binaries/Binary");
for (i = 0; i < XPATH_OBJ_NODES_COUNT(xobject); i++)
{
access_len = strlen("/ChrysalideProject/Binaries/Binary[position()=") + SIZE_T_MAXLEN + strlen("]") + 1;
access = calloc(access_len, sizeof(char));
snprintf(access, access_len, "/ChrysalideProject/Binaries/Binary[position()=%u]", i + 1);
binary = g_loaded_binary_new_from_xml(context, access, result);
free(access);
if (binary != NULL)
{
g_signal_connect_to_main(binary, "disassembly-done",
G_CALLBACK(g_study_project_add_loaded_binary), result,
g_cclosure_marshal_VOID__VOID);
g_loaded_binary_analyse(binary);
}
}
if(xobject != NULL)
xmlXPathFreeObject(xobject);
/* Fin du chargement */
close_xml_file(xdoc, context);
return result;
}
/******************************************************************************
* *
* 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 i; /* Boucle de parcours */
size_t access_len; /* Taille d'un chemin interne */
char *access; /* Chemin pour une sous-config.*/
result = create_new_xml_file(&xdoc, &context);
result &= (ensure_node_exist(xdoc, context, "/ChrysalideProject") != NULL);
final = filename != NULL ? filename : project->filename;
/* Enregistrement des contenus binaires attachés */
for (i = 0; i < project->contents_count && result; i++)
{
if (project->contents[i].state == PCS_INTERNAL) continue;
access_len = strlen("/ChrysalideProject/Contents/Content[position()=") + SIZE_T_MAXLEN + strlen("]") + 1;
access = calloc(access_len, sizeof(char));
snprintf(access, access_len, "/ChrysalideProject/Contents/Content[position()=%zu]", i + 1);
result = g_binary_content_save(project->contents[i].content, xdoc, context, access, final);
if (result)
result = add_long_attribute_to_node(xdoc, context, access, "state", project->contents[i].state);
free(access);
}
/* Enregistrement des binaires analysés */
for (i = 0; i < project->binaries_count && result; i++)
{
access_len = strlen("/ChrysalideProject/Binaries/Binary[position()=") + SIZE_T_MAXLEN + strlen("]") + 1;
access = calloc(access_len, sizeof(char));
snprintf(access, access_len, "/ChrysalideProject/Binaries/Binary[position()=%zu]", i + 1);
result = g_loaded_binary_save(project->binaries[i]->binary, xdoc, context, access);
free(access);
}
/* Sauvegarde finale */
result &= save_xml_file(xdoc, final);
if (result && filename != NULL)
{
if (project->filename != NULL) free(project->filename);
project->filename = strdup(filename);
}
close_xml_file(xdoc, context);
return result;
}
/******************************************************************************
* *
* 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;
}
/******************************************************************************
* *
* 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. *
* *
* Retour : - *
* *
* Remarques : - *
* *
******************************************************************************/
void g_study_project_add_binary_content(GStudyProject *project, GBinContent *content, ProjectContentState state)
{
loaded_content *new; /* Nouveau contenu à définir */
g_mutex_lock(&project->cnt_mutex);
project->contents = (loaded_content *)realloc(project->contents,
++project->contents_count * sizeof(loaded_content));
new = &project->contents[project->contents_count - 1];
g_object_ref(G_OBJECT(content));
new->content = content;
new->state = state;
g_mutex_unlock(&project->cnt_mutex);
}
/******************************************************************************
* *
* Paramètres : project = projet dont le contenu est à compléter. *
* hash = empreinte du contenu à retrouver. *
* *
* Description : Recherche un contenu binaire du projet selon son empreinte. *
* *
* Retour : Contenu avec propriété transférée ou NULL en cas d'échec. *
* *
* Remarques : - *
* *
******************************************************************************/
GBinContent *g_study_project_find_binary_content_by_hash(GStudyProject *project, const char *hash)
{
GBinContent *result; /* Trouvaille à retourner */
size_t i; /* Boucle de parcours */
GBinContent *iter; /* Contenu binaire analysé */
const gchar *other; /* Autre empreinte à comparer */
result = NULL;
g_mutex_lock(&project->cnt_mutex);
for (i = 0; i < project->contents_count && result == NULL; i++)
{
iter = project->contents[i].content;
other = g_binary_content_get_cheksum(iter);
if (strcmp(hash, other) == 0)
{
g_object_ref(G_OBJECT(iter));
result = iter;
}
}
g_mutex_unlock(&project->cnt_mutex);
return result;
}
/******************************************************************************
* *
* Paramètres : binary = élément binaire tout juste désassemblé. *
* project = projet dont le contenu est à compléter. *
* *
* Description : Assure l'intégration d'un élément binaire dans un projet. *
* *
* Retour : - *
* *
* Remarques : - *
* *
******************************************************************************/
void g_study_project_add_loaded_binary(GLoadedBinary *binary, GStudyProject *project)
{
size_t index; /* Indice du nouveau binaire */
index = g_study_project_attach_binary(project, binary);
gboolean scroll_for_the_first_time(GtkWidget *widget, GdkEvent *event, GLoadedBinary *binary)
{
GBinFormat *format; /* Format associé au binaire */
GBinSymbol *symbol; /* Point d'entrée trouvé */
const mrange_t *range; /* Emplacement de ce point */
g_signal_handlers_disconnect_by_func(widget, G_CALLBACK(scroll_for_the_first_time), binary);
format = G_BIN_FORMAT(g_loaded_binary_get_format(binary));
/* TODO : se rabattre sur des symboles identifiés comme point d'entrée si on ne trouve pas les principaux ci dessous */
if (g_binary_format_find_symbol_by_label(format, "main", &symbol)
|| g_binary_format_find_symbol_by_label(format, "_start", &symbol)
|| g_binary_format_find_symbol_by_label(format, "entry_point", &symbol))
{
range = g_binary_symbol_get_range(symbol);
gtk_view_panel_scroll_to_address(GTK_VIEW_PANEL(widget), get_mrange_addr(range), SPT_CENTER);
}
return FALSE;
}
g_signal_connect(project->binaries[index]->views[BVW_BLOCK], "size-allocate",
G_CALLBACK(scroll_for_the_first_time), binary);
g_panel_item_dock(G_PANEL_ITEM(project->binaries[index]->item));
}
/******************************************************************************
* *
* Paramètres : project = project à effacer de la mémoire. *
* binary = fichier binaire à associer au projet actuel. *
* *
* Description : Attache un fichier donné à un projet donné. *
* *
* Retour : Emplacement de l'élément créé. *
* *
* Remarques : - *
* *
******************************************************************************/
size_t g_study_project_attach_binary(GStudyProject *project, GLoadedBinary *binary)
{
size_t result; /* Indice à retourner */
loaded_binary *loaded; /* Structure à renvoyer */
BinaryView i; /* Boucle de parcours */
GtkWidget *view; /* Affichage du binaire */
GtkWidget *scroll; /* Surface d'exposition */
const char *name; /* Titre associé au binaire */
const char *lname; /* Description du binaire */
loaded = (loaded_binary *)calloc(1, sizeof(loaded_binary));
loaded->binary = binary;
for (i = 0; i < BVW_COUNT; i++)
{
/* Préparation du support visuel */
switch (i)
{
case BVW_BLOCK:
view = gtk_block_view_new(/*MRD_BLOCK*/);
break;
case BVW_GRAPH:
view = gtk_graph_view_new();
break;
case BVW_SOURCE:
view = gtk_source_view_new();
break;
default: /* GCC ! */
break;
}
manage_editor_items_view(GTK_VIEW_PANEL(view), true);
gtk_widget_show(view);
loaded->views[i] = GTK_VIEW_PANEL(view);
gtk_view_panel_attach_binary(loaded->views[i], binary, i);
/* Intégration finale dans un support défilant */
scroll = qck_create_scrolled_window(NULL, NULL);
gtk_container_add(GTK_CONTAINER(scroll), view);
loaded->scrollwindows[i] = scroll;
}
/* Support graphique final */
scroll = loaded->scrollwindows[BVW_BLOCK];
name = g_loaded_binary_get_name(binary, false);
lname = g_loaded_binary_get_name(binary, true);
loaded->item = g_panel_item_new(project->ref, name, lname, scroll, "M");
/* Enregistrement dans le projet */
g_mutex_lock(&project->bin_mutex);
project->binaries = (loaded_binary **)realloc(project->binaries,
++project->binaries_count * sizeof(loaded_binary *));
result = project->binaries_count - 1;
project->binaries[result] = loaded;
g_mutex_unlock(&project->bin_mutex);
update_project_area(project);
return result;
}
/******************************************************************************
* *
* Paramètres : project = project à effacer de la mémoire. *
* binary = fichier binaire à dissocier au projet actuel. *
* *
* Description : Détache un fichier donné à un projet donné. *
* *
* Retour : - *
* *
* Remarques : - *
* *
******************************************************************************/
void g_study_project_detach_binary(GStudyProject *project, GLoadedBinary *binary)
{
//GtkDockPanel *dpanel; /* Support de panneaux */
//GDockItem *ditem; /* Support d'affichage utilisé */
size_t i; /* Boucle de parcours */
//dpanel = GTK_DOCK_PANEL(g_object_get_data(project->ref, "binpanel"));
//ditem = gtk_dock_panel_get_item_from_binary(project, binary); FIXME !!
//gtk_dock_panel_remove_item(dpanel, ditem);
//manage_editor_items_view(GObject *ref, GtkViewPanel *view, bool created)
for (i = 0; i < project->binaries_count; i++)
if (project->binaries[i]->binary == binary) break;
if ((i + 1) < project->binaries_count)
memmove(&project->binaries[i], &project->binaries[i + 1], (project->binaries_count - i - 1) * sizeof(loaded_binary *));
project->binaries = (loaded_binary **)realloc(project->binaries,
--project->binaries_count * sizeof(loaded_binary *));
update_project_area(project);
}
/******************************************************************************
* *
* Paramètres : project = projet à consulter. *
* binary = binaire chargé, encadré et concerné. *
* kind = type d'affichage requis. *
* view = afficheur effectif quelconque. [OUT] *
* *
* Description : Fournit un support d'affichage donné pour un binaire chargé. *
* *
* Retour : Composant GTK dédié à un affichage particulier. *
* *
* Remarques : - *
* *
******************************************************************************/
GtkWidget *g_study_project_get_view_for_binary(const GStudyProject *project, const GLoadedBinary *binary, BinaryView kind, GtkViewPanel **view)
{
GtkWidget *result; /* Composant GTK à retourner */
size_t i; /* Boucle de parcours */
result = NULL;
*view = NULL;
for (i = 0; i < project->binaries_count; i++)
if (project->binaries[i]->binary == binary)
{
result = project->binaries[i]->scrollwindows[kind];
*view = project->binaries[i]->views[kind];
break;
}
return result;
}
/******************************************************************************
* *
* Paramètres : project = projet dont le contenu est à afficher. *
* *
* Description : Met en place un projet à l'écran. *
* *
* Retour : - *
* *
* Remarques : - *
* *
******************************************************************************/
void g_study_project_display(const GStudyProject *project)
{
size_t i; /* Boucle de parcours */
for (i = 0; i < project->binaries_count; i++)
g_panel_item_dock(G_PANEL_ITEM(project->binaries[i]->item));
}
/******************************************************************************
* *
* Paramètres : project = projet dont le contenu est à cacher. *
* *
* Description : Supprime de l'écran un projet en place. *
* *
* Retour : - *
* *
* Remarques : - *
* *
******************************************************************************/
static void g_study_project_hide(const GStudyProject *project)
{
size_t i; /* Boucle de parcours */
for (i = 0; i < project->binaries_count; i++)
g_panel_item_undock(G_PANEL_ITEM(project->binaries[i]->item));
}
/******************************************************************************
* *
* Paramètres : project = projet dont le contenu est à afficher. *
* count = nombre de binaires pris en compte. [OUT] *
* *
* Description : Fournit l'ensemble des binaires associés à un projet. *
* *
* Retour : Liste à libérer de la mémoire. *
* *
* Remarques : - *
* *
******************************************************************************/
GLoadedBinary **g_study_project_get_binaries(const GStudyProject *project, size_t *count)
{
GLoadedBinary **result; /* Tableau à retourner */
size_t i; /* Boucle de parcours */
*count = project->binaries_count;
result = (GLoadedBinary **)calloc(*count, sizeof(GLoadedBinary *));
for (i = 0; i < *count; i++)
{
result[i] = project->binaries[i]->binary;
g_object_ref(G_OBJECT(result[i]));
}
return result;
}
/* ---------------------------------------------------------------------------------- */
/* GESTION GLOBALISEE DES PROJETS */
/* ---------------------------------------------------------------------------------- */
/******************************************************************************
* *
* Paramètres : project = éventuel adresse à renvoyer désormais. *
* *
* Description : Fournit l'adresse du projet courant. *
* *
* Retour : Adresse du projet ouvert ou NULL si aucun (!). *
* *
* Remarques : - *
* *
******************************************************************************/
GStudyProject *_get_current_study_project(GStudyProject *project)
{
static GStudyProject *result = NULL; /* Adresse à retourner */
if (project != NULL)
{
if (result != NULL)
{
g_study_project_hide(result);
g_object_unref(G_OBJECT(result));
}
result = project;
}
return result;
}
/******************************************************************************
* *
* Paramètres : - *
* *
* Description : Fournit le gestionnaire des projets connus. *
* *
* Retour : Instance de gestion unique. *
* *
* Remarques : - *
* *
******************************************************************************/
GtkRecentManager *get_projects_manager(void)
{
static GtkRecentManager *result = NULL; /* Singleton à retourner */
if (result == NULL)
{
result = gtk_recent_manager_get_default();
//gtk_recent_manager_purge_items(result, NULL);
}
return result;
}
/******************************************************************************
* *
* Paramètres : project = projet à traiter. *
* *
* Description : Place un projet au sommet de la pile des projets récents. *
* *
* Retour : - *
* *
* Remarques : - *
* *
******************************************************************************/
void push_project_into_recent_list(const GStudyProject *project)
{
GtkRecentManager *manager; /* Gestionnaire global */
char *qualified; /* Chemin avec 'file://' */
GtkRecentData recent; /* Données complètes */
if (project->filename == NULL)
return;
/* Constitution de la liste des projets récents */
/* Constitution de la liste des projets récents */
manager = get_projects_manager();
qualified = (char *)calloc(strlen("file://") + strlen(project->filename) + 1, sizeof(char));
strcpy(qualified, "file://");
strcat(qualified, project->filename);
memset(&recent, 0, sizeof(GtkRecentData));
recent.mime_type = "application/chrysalide.project";
recent.app_name = "Chrysalide";
recent.app_exec = "chrysalide %f";
gtk_recent_manager_add_full(manager, qualified, &recent);
free(qualified);
/* Pour la prochaine ouverture du programme... */
g_generic_config_set_value(get_main_configuration(), MPK_LAST_PROJECT, project->filename);
}
/* ---------------------------------------------------------------------------------- */
/* 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. *
* statusbar = 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, GtkExtStatusBar *statusbar)
{
FormatMatchStatus status; /* Statut d'une reconnaissance */
char *target; /* Sous-traitance requise */
GLoadedBinary *binary; /* Représentation chargée */
status = find_matching_format(dstudy->content, NULL, &target);
switch (status)
{
case FMS_MATCHED:
if (dstudy->only_preload)
g_study_project_add_binary_content(dstudy->project, dstudy->content, dstudy->state);
else
{
binary = g_loaded_binary_new(dstudy->content);
if (binary != NULL)
{
g_study_project_add_binary_content(dstudy->project, dstudy->content, dstudy->state);
g_signal_connect_to_main(binary, "disassembly-done",
G_CALLBACK(g_study_project_add_loaded_binary),
dstudy->project, g_cclosure_marshal_VOID__VOID);
g_loaded_binary_analyse(binary);
}
}
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);
}