/* OpenIDA - Outil d'analyse de fichiers binaires
* project.c - gestion d'un groupe de fichiers binaires
*
* Copyright (C) 2008 Cyrille Bagard
*
* This file is part of OpenIDA.
*
* 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 "xdg.h"
#include "xml.h"
#include "gtkext/easygtk.h"
#include "gtkext/gtkblockview.h"
#include "gtkext/gtkgraphview.h"
/* Conservation d'un binaire chargé */
typedef struct _loaded_binary
{
openida_binary *binary; /* Binaire en question */
GtkWidget *views[BVW_COUNT]; /* Composants pour l'affichage */
} loaded_binary;
/* Met en place un nouveau binaire pour un projet. */
loaded_binary *load_openida_binary(openida_binary *);
/* Fournit un support d'affichage donné pour un binaire chargé. */
GtkWidget *get_loaded_binary_view(const loaded_binary *, BinaryView);
/* Propriétés d'un ensemble de fichiers ouverts */
struct openida_project
{
char *filename; /* Lieu d'enregistrement */
loaded_binary **binaries; /* Fichiers binaires associés */
size_t binaries_count; /* Nombre de ces fichiers */
};
/******************************************************************************
* *
* Paramètres : binary = binaire chargé à encadrer. *
* *
* Description : Met en place un nouveau binaire pour un projet. *
* *
* Retour : Adresse de la structure intermédiaire ou NULL si aucune (!). *
* *
* Remarques : - *
* *
******************************************************************************/
loaded_binary *load_openida_binary(openida_binary *binary)
{
loaded_binary *result; /* Structure à renvoyer */
BinaryView i; /* Boucle de parcours */
GtkWidget *scrolledwindow; /* Surface d'exposition */
GtkWidget *view; /* Affichage du binaire */
result = (loaded_binary *)calloc(1, sizeof(loaded_binary));
result->binary = binary;
for (i = 0; i < BVW_COUNT; i++)
{
scrolledwindow = qck_create_scrolled_window(NULL, NULL);
switch (i)
{
default: /* GCC ! */
case BVW_BLOCK:
view = gtk_block_view_new();
break;
case BVW_GRAPH:
view = gtk_graph_view_new();
break;
}
if (i == 0)
gtk_block_view_set_rendering_lines(GTK_BLOCK_VIEW(view), get_openida_binary_lines(binary));
gtk_widget_show(view);
gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(scrolledwindow), view);
result->views[i] = scrolledwindow;
}
return result;
}
/******************************************************************************
* *
* Paramètres : binary = binaire chargé et encadré. *
* view = type d'affichage requis. *
* *
* Description : Fournit un support d'affichage donné pour un binaire chargé. *
* *
* Retour : Composant GTK dédié à un affichage particulier. *
* *
* Remarques : - *
* *
******************************************************************************/
GtkWidget *get_loaded_binary_view(const loaded_binary *binary, BinaryView view)
{
return binary->views[view];
}
/******************************************************************************
* *
* 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 : - *
* *
******************************************************************************/
openida_project *_get_current_openida_project(openida_project *project)
{
static openida_project *result = NULL; /* Adresse à retourner */
if (project != NULL)
{
if (result != NULL) close_openida_project(result);
result = project;
}
return result;
}
/******************************************************************************
* *
* Paramètres : - *
* *
* Description : Crée un projet vide. *
* *
* Retour : - *
* *
* Remarques : - *
* *
******************************************************************************/
openida_project *create_empty_openida_project(void)
{
openida_project *result; /* Adresse à retourner */
result = (openida_project *)calloc(1, sizeof(openida_project));
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 : - *
* *
******************************************************************************/
openida_project *load_openida_project_from_xml(const char *filename)
{
openida_project *result; /* Adresse à retourner */
xmlDoc *xdoc; /* Structure XML chargée */
xmlNode *xroot; /* Noeud premier de la def. */
xmlXPathContextPtr xpathCtx; /* Contexte pour les XPath */
xmlXPathObjectPtr xpathObj; /* Cible d'une recherche */
unsigned int i; /* Boucle de parcours */
openida_binary *binary; /* Représentation à intégrer */
if (!open_xml_file(filename, &xdoc, &xroot, &xpathCtx)) return NULL;
result = (openida_project *)calloc(1, sizeof(openida_project));
xpathObj = get_node_xpath_object(xpathCtx, "/OpenIDAProject/Binaries/*");
printf("nodes :: %d\n", XPATH_OBJ_NODES_COUNT(xpathObj));
for (i = 0; i < XPATH_OBJ_NODES_COUNT(xpathObj); i++)
{
binary = read_openida_binary_from_xml(xpathCtx, "/OpenIDAProject/Binaries", i + 1);
if (binary != NULL)
attach_binary_to_openida_project(result, binary);
}
if(xpathObj != NULL)
xmlXPathFreeObject(xpathObj);
xmlXPathFreeContext(xpathCtx);
xmlFreeDoc(xdoc);
xmlCleanupParser();
return result;
}
/******************************************************************************
* *
* Paramètres : project = project à effacer de la mémoire. *
* *
* Description : Ferme un projet et libère la mémoire associée. *
* *
* Retour : - *
* *
* Remarques : - *
* *
******************************************************************************/
void close_openida_project(openida_project *project)
{
free(project);
}
/******************************************************************************
* *
* Paramètres : project = project à consulter. *
* *
* Description : Indique si un projet a tous les éléments pour être sauvé. *
* *
* Retour : true si aucun nom de fichier n'a à être fourni. *
* *
* Remarques : - *
* *
******************************************************************************/
bool has_storing_filename(const openida_project *project)
{
return (project->filename != NULL);
}
/******************************************************************************
* *
* 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 write_openida_project_to_xml(openida_project *project, const char *filename)
{
bool result; /* Bilan à faire remonter */
xmlTextWriterPtr writer; /* Rédacteur pour la sortie XML*/
size_t i; /* Boucle de parcours */
writer = start_writing_xml_file(filename);
result = open_xml_element(writer, "OpenIDAProject");
/* Enregistrement des éléments binaires attachés */
result &= open_xml_element(writer, "Binaries");
for (i = 0; i < project->binaries_count && result; i++)
write_openida_binary_to_xml(project->binaries[i], writer);
result &= close_xml_element(writer);
result &= close_xml_element(writer);
result &= end_writing_xml_file(writer);
if (result)
{
if (project->filename != NULL) free(project->filename);
project->filename = strdup(filename);
}
return result;
}
/******************************************************************************
* *
* 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 : - *
* *
* Remarques : - *
* *
******************************************************************************/
void attach_binary_to_openida_project(openida_project *project, openida_binary *binary)
{
project->binaries = (loaded_binary **)realloc(project->binaries,
++project->binaries_count * sizeof(loaded_binary *));
project->binaries[project->binaries_count - 1] = load_openida_binary(binary);
}
/******************************************************************************
* *
* 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 detach_binary_to_openida_project(openida_project *project, openida_binary *binary)
{
#if 0
size_t i; /* Boucle de parcours */
for (i = 0; i < project->binaries_count; i++)
if (project->binaries[i] == binary) break;
if ((i + 1) < project->binaries_count)
memmove(&project->binaries[i], &project->binaries[i + 1], (project->binaries_count - i - 1) * sizeof(openida_binary *));
project->binaries = (openida_binary **)realloc(project->binaries,
--project->binaries_count * sizeof(openida_binary *));
#endif
}
/******************************************************************************
* *
* Paramètres : project = projet à consulter. *
* binary = binaire chargé, encadré et concerné. *
* view = type d'affichage requis. *
* *
* Description : Fournit un support d'affichage donné pour un binaire chargé. *
* *
* Retour : Composant GTK dédié à un affichage particulier. *
* *
* Remarques : - *
* *
******************************************************************************/
GtkWidget *get_view_for_openida_project_binary(const openida_project *project, const openida_binary *binary, BinaryView view)
{
GtkWidget *result; /* Composant GTK à retourner */
size_t i; /* Boucle de parcours */
result = NULL;
for (i = 0; i < project->binaries_count; i++)
if (project->binaries[i]->binary == binary)
{
result = get_loaded_binary_view(project->binaries[i], view);
break;
}
return result;
}
/******************************************************************************
* *
* Paramètres : project = project à effacer de la mémoire. *
* count = nombre de binaires pris en compte. [OUT] *
* *
* Description : Fournit l'ensemble des binaires associés à un projet. *
* *
* Retour : - *
* *
* Remarques : - *
* *
******************************************************************************/
const openida_binary **get_openida_project_binaries(const openida_project *project, size_t *count)
{
*count = project->binaries_count;
return project->binaries;
}
/* ---------------------------------------------------------------------------------- */
/* PARTIE GRAPHIQUE DES [DE]CHARGEMENTS */
/* ---------------------------------------------------------------------------------- */
/******************************************************************************
* *
* Paramètres : ref = espace global de référencement. *
* func = fonction à appeler lors d'un clic sur les menus. *
* *
* Description : Met en place les menus rechargeant les projets récents. *
* *
* Retour : - *
* *
* Remarques : - *
* *
******************************************************************************/
void load_recent_openida_projects_list(GObject *ref, GCallback *func)
{
gboolean one_entry; /* Au moins en entrée chargée */
GtkWidget *menuitem; /* Menu principal à compléter */
GtkWidget *menubar; /* Support pour éléments */
char *directory; /* Répertoire prévu pour proj. */
DIR *dir; /* Répertoire avec contenu ? */
struct dirent *entry; /* Elément de répertoire */
char *filename; /* Nom de fichier à ouvrir */
char realfile[PATH_MAX]; /* Nom du fichier pointé */
ssize_t ret; /* Bilan de la lecture */
GtkWidget *submenuitem; /* Sous-menu à ajouter */
one_entry = false;
menuitem = GTK_WIDGET(g_object_get_data(ref, "menu_recent_prjs"));
menubar = gtk_menu_item_get_submenu(GTK_MENU_ITEM(menuitem));
directory = get_xdg_config_dir("openida/recents");
dir = opendir(directory);
/* TODO :: check */
if (dir != NULL)
{
for (entry = readdir(dir); entry != NULL; entry = readdir(dir))
{
if (strcmp(entry->d_name, ".") == 0) continue;
if (strcmp(entry->d_name, "..") == 0) continue;
if (strlen(entry->d_name) <= 4) continue;
if (strcmp(&entry->d_name[strlen(entry->d_name) - 4], ".xml") != 0) continue;
filename = (char *)calloc(strlen(directory) + 2 + strlen(entry->d_name) + 1, sizeof(char));
strcpy(filename, directory);
strcat(filename, "/");
strcat(filename, entry->d_name);
ret = readlink(filename, realfile, PATH_MAX);
/* TODO :: check */
if (ret == -1) goto process_next_recent;
submenuitem = qck_create_menu_item(NULL, NULL, realfile, func, ref);
gtk_container_add(GTK_CONTAINER(menubar), submenuitem);
one_entry = true;
process_next_recent:
free(filename);
}
closedir(dir);
}
free(directory);
recent_list_end:
gtk_widget_set_sensitive(menuitem, one_entry);
}