From c1b34ed255813ad28bf69fc28592d4cd253f7248 Mon Sep 17 00:00:00 2001
From: Cyrille Bagard <nocbos@gmail.com>
Date: Sun, 5 Oct 2008 11:53:24 +0000
Subject: Added a basic support of project files.

git-svn-id: svn://svn.gna.org/svn/chrysalide/trunk@33 abbe820e-26c8-41b2-8c08-b7b2b41f8b0a
---
 ChangeLog          |  33 +++
 src/Makefile.am    |   7 +-
 src/binary.c       | 227 +++++++++++++++++++++
 src/binary.h       |  34 ++++
 src/dlg_sections.c | 218 ++++++++++++++++++++
 src/dlg_sections.h |  42 ++++
 src/easygtk.c      | 353 ++++++++++++++++++++++++++++++++
 src/easygtk.h      |  65 ++++++
 src/editor.c       | 366 +++++++++++++++++++++++++++++++++-
 src/project.c      | 431 ++++++++++++++++++++++++++++++++++++++++
 src/project.h      |  88 ++++++++
 src/xdg.c          | 103 ++++++++++
 src/xdg.h          |  34 ++++
 src/xml.c          | 574 +++++++++++++++++++++++++++++++++++++++++++++++++++++
 src/xml.h          |  96 +++++++++
 15 files changed, 2668 insertions(+), 3 deletions(-)
 create mode 100644 src/dlg_sections.c
 create mode 100644 src/dlg_sections.h
 create mode 100644 src/easygtk.c
 create mode 100644 src/easygtk.h
 create mode 100644 src/project.c
 create mode 100644 src/project.h
 create mode 100644 src/xdg.c
 create mode 100644 src/xdg.h
 create mode 100644 src/xml.c
 create mode 100644 src/xml.h

diff --git a/ChangeLog b/ChangeLog
index b457000..d56fd56 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,36 @@
+2008-10-05  Cyrille Bagard <nocbos@gmail.com>
+
+	* src/binary.c:
+	* src/binary.h:
+	Load and unload binaries with basic properties attached.
+
+	* src/dlg_sections.c:
+	* src/dlg_sections.h:
+	New entries: not [yet] used ; provide a way to select sections to process.
+
+	* src/easygtk.c:
+	* src/easygtk.h:
+	New entries: make easy to use the GTK functions.
+
+	* src/editor.c:
+	Update the code. Add menus to the GUI.
+
+	* src/Makefile.am:
+	Add dlg_sections.[ch] easygtk.[ch], project.[ch], xdg.[ch] and xml.[ch]
+	to openida_SOURCES.
+
+	* src/project.c:
+	* src/project.h:
+	New entries: define a basic support of OpenIDA projects.
+
+	* src/xdg.c:
+	* src/xdg.h:
+	New entries: support some points of the Freedesktop standards.
+
+	* src/xml.c:
+	* src/xml.h:
+	New entries: provide reading and writing facilities for XML data.
+
 2008-09-20  Cyrille Bagard <nocbos@gmail.com>
 
 	* src/arch/operand.h:
diff --git a/src/Makefile.am b/src/Makefile.am
index 603ba36..b1e31cd 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -3,10 +3,15 @@ bin_PROGRAMS=openida
 
 openida_SOURCES = 						\
 	binary.h binary.c					\
+	dlg_sections.h dlg_sections.c		\
+	easygtk.h easygtk.c					\
 	editor.c							\
 	gtksnippet.h gtksnippet.c			\
 	gtkcodeview.h gtkcodeview.c			\
-	pan_symbols.h pan_symbols.c
+	pan_symbols.h pan_symbols.c			\
+	project.h project.c					\
+	xdg.h xdg.c							\
+	xml.h xml.c
 
 
 INCLUDES = -I$(top_srcdir) -I$(top_srcdir)/intl $(LIBGTK_CFLAGS) $(LIBXML_CFLAGS) `pkg-config --cflags gthread-2.0`
diff --git a/src/binary.c b/src/binary.c
index 1bc87cb..8de0bdb 100644
--- a/src/binary.c
+++ b/src/binary.c
@@ -26,6 +26,7 @@
 
 #include <fcntl.h>
 #include <stdlib.h>
+#include <string.h>
 #include <unistd.h>
 #include <sys/mman.h>
 #include <sys/stat.h>
@@ -48,6 +49,13 @@
 extern bool find_line_info(const uint8_t *content, off_t *size);
 
 
+
+/* Charge en mémoire le contenu d'un fichier à partir d'XML. */
+openida_binary *load_binary_file_from_xml(xmlXPathObjectPtr);
+
+
+
+
 /* Charge en mémoire le contenu d'un fichier. */
 uint8_t *map_binary_file(const char *, size_t *);
 
@@ -55,6 +63,225 @@ uint8_t *map_binary_file(const char *, size_t *);
 
 
 
+/* Description d'un fichier binaire */
+struct _openida_binary
+{
+    char *filename;                         /* Fichier chargé en mémoire   */
+
+
+};
+
+
+
+
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : filename = nom du fichier à charger.                         *
+*                                                                             *
+*  Description : Charge en mémoire le contenu d'un fichier.                   *
+*                                                                             *
+*  Retour      : Adresse de la représentation ou NULL en cas d'échec.         *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+openida_binary *load_binary_file(const char *filename)
+{
+    openida_binary *result;                 /* Adresse à retourner         */
+
+    result = (openida_binary *)calloc(1, sizeof(openida_binary));
+
+    result->filename = strdup(filename);
+
+
+
+
+
+    return result;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : xpathObj = point de lecture de tous les éléments.            *
+*                                                                             *
+*  Description : Charge en mémoire le contenu d'un fichier à partir d'XML.    *
+*                                                                             *
+*  Retour      : Adresse de la représentation ou NULL en cas d'échec.         *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+openida_binary *load_binary_file_from_xml(xmlXPathObjectPtr xpathObj)
+{
+    openida_binary *result;                 /* Adresse à retourner         */
+
+    int i;
+
+    result = (openida_binary *)calloc(1, sizeof(openida_binary));
+
+    for (i = 0; i < XPATH_OBJ_NODES_COUNT(xpathObj); i++)
+        if (xmlStrEqual(NODE_FROM_PATH_OBJ(xpathObj, i)->name, BAD_CAST "Filename"))
+            result->filename = qck_get_node_text_value(NODE_FROM_PATH_OBJ(xpathObj, i));
+
+
+
+
+    return result;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : binary = élément binaire à supprimer de la mémoire.          *
+*                                                                             *
+*  Description : Décharge de la mémoire le contenu d'un fichier.              *
+*                                                                             *
+*  Retour      : -                                                            *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+void unload_binary_file(openida_binary *binary)
+{
+    free(binary->filename);
+
+    free(binary);
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : binary = élément binaire à traiter.                          *
+*                                                                             *
+*  Description : Fournit une description humaine d'un élément binaire.        *
+*                                                                             *
+*  Retour      : Chaîne de caractères humainenement lisible de représentation.*
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+const char *openida_binary_to_string(const openida_binary *binary)
+{
+    return binary->filename;
+
+}
+
+
+
+
+
+
+
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : xpathCtx = contexte à utiliser pour mener les parcours.      *
+*                base     = première partie de l'expression XPath d'accès.    *
+*                index    = indice de la élément dans la liste des voisins.   *
+*                                                                             *
+*  Description : Lit un élément binaire depuis un fichier XML.                *
+*                                                                             *
+*  Retour      : Représentation mise en place à libérer de la mémoire.        *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+openida_binary *read_openida_binary_from_xml(xmlXPathContextPtr xpathCtx, const char *base, unsigned int index)
+{
+    openida_binary *result;                 /* Représentation à retourner  */
+    size_t expr_len;                        /* Taille d'une expression     */
+    char *expr;                             /* Chemin XPath reconstitué    */
+    xmlXPathObjectPtr xpathObj;             /* Cible d'une recherche       */
+    char *value;                            /* Type d'élément rencontré    */
+    size_t sub_expr_len;                    /* Taille d'une expression #2  */
+    char *sub_expr;                         /* Chemin XPath reconstitué #2 */
+    int i;                                  /* Boucle de parcours          */
+
+    result = NULL;
+
+    /* S'occupe en premier lieu du niveau courant */
+
+    expr_len = strlen(base) + strlen("/*[position()=") + strlen("4294967295") /* UINT_MAX */ + strlen("]") + 1;
+
+    expr = (char *)calloc(expr_len, sizeof(char));
+    snprintf(expr, expr_len, "%s/*[position()=%u]", base, index);
+
+    xpathObj = get_node_xpath_object(xpathCtx, expr);
+
+    value = qck_get_node_prop_value(NODE_FROM_PATH_OBJ(xpathObj, 0), "type");
+
+    xmlXPathFreeObject(xpathObj);
+
+    if (value == NULL) goto robfx_err1;
+
+    /* Raffinement au second passage */
+
+    sub_expr_len = expr_len + strlen("/*");
+    sub_expr = (char *)calloc(sub_expr_len, sizeof(char));
+    snprintf(sub_expr, sub_expr_len, "%s/*", expr);
+
+    xpathObj = get_node_xpath_object(xpathCtx, sub_expr);
+
+    if (strcmp(value, "file") == 0) result = load_binary_file_from_xml(xpathObj);
+
+    xmlXPathFreeObject(xpathObj);
+
+    free(sub_expr);
+
+ robfx_err1:
+
+    free(expr);
+
+    return result;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : binary = élément binaire à traiter.                          *
+*                writer = rédacteur dédié à l'écriture.                       *
+*                                                                             *
+*  Description : Ecrit une sauvegarde du binaire dans un fichier XML.         *
+*                                                                             *
+*  Retour      : true si l'opération a bien tourné, false sinon.              *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+bool write_openida_binary_to_xml(const openida_binary *binary, xmlTextWriterPtr writer)
+{
+    bool result;                            /* Bilan à faire remonter      */
+
+    result = open_xml_element(writer, "Binary");
+
+    result &= write_xml_attribute(writer, "type", "file");
+
+    result &= write_xml_element_with_content(writer, "Filename", "%s", binary->filename);
+
+    result &= close_xml_element(writer);
+
+    return result;
+
+}
+
+
+
+
+
 /******************************************************************************
 *                                                                             *
 *  Paramètres  : filename = nom du fichier à charger.                         *
diff --git a/src/binary.h b/src/binary.h
index d2dacc5..e1cc97b 100644
--- a/src/binary.h
+++ b/src/binary.h
@@ -25,11 +25,45 @@
 #define _BINARY_H
 
 
+#include <stdbool.h>
+#include "xml.h"
+
+
+
+/* Description d'un fichier binaire */
+typedef struct _openida_binary openida_binary;
+
+
+/* Charge en mémoire le contenu d'un fichier. */
+openida_binary *load_binary_file(const char *);
+
+/* Décharge de la mémoire le contenu d'un fichier. */
+void unload_binary_file(openida_binary *);
+
+/* Fournit une description humaine d'un élément binaire. */
+const char *openida_binary_to_string(const openida_binary *);
+
+
+
+/* Lit un élément binaire depuis un fichier XML. */
+openida_binary *read_openida_binary_from_xml(xmlXPathContextPtr, const char *, unsigned int);
+
+/* Ecrit une sauvegarde du binaire dans un fichier. */
+bool write_openida_binary_to_xml(const openida_binary *, xmlTextWriterPtr);
+
+
+
+
 #include "gtksnippet.h"
 
 
 
 
+
+
+
+
+
 void fill_snippet(GtkSnippet *snippet, GtkWidget *panel);
 
 
diff --git a/src/dlg_sections.c b/src/dlg_sections.c
new file mode 100644
index 0000000..2aae552
--- /dev/null
+++ b/src/dlg_sections.c
@@ -0,0 +1,218 @@
+
+/* OpenIDA - Outil d'analyse de fichiers binaires
+ * dlg_sections.h - boîte de dialogue permettant une sélection des sections
+ *
+ * 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 <http://www.gnu.org/licenses/>.
+ */
+
+
+#include "dlg_sections.h"
+
+
+#include "easygtk.h"
+
+
+
+#define _(str) str
+
+
+
+
+/* Charge les sections sélectionnées pour le projet courant. */
+void load_project_sections(openida_project *, GObject *);
+
+
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : project = informations sur le project actuellement ouvert.   *
+*                                                                             *
+*  Description : Construit la fenêtre de sélection des sections.              *
+*                                                                             *
+*  Retour      : Adresse de la fenêtre mise en place.                         *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+GtkWidget *create_sections_dialog(openida_project *project)
+{
+    GtkWidget *result;                      /* Fenêtre à renvoyer          */
+
+
+
+
+
+  GtkWidget *vbox1;
+  GtkWidget *hbox1;
+
+
+    GtkWidget *label;                       /* Etiquette à afficher        */
+
+
+  GtkWidget *combobox1;
+
+    GtkWidget *alignment;                   /* Adaptation de disposition   */
+    GtkWidget *frame;                       /* Support avec encadrement    */
+
+  GtkWidget *vbox2;
+  GtkWidget *hbox2;
+  GtkWidget *comboboxentry1;
+  GtkWidget *hbox3;
+  GtkWidget *scrolledwindow1;
+  GtkWidget *treeview1;
+  GtkWidget *vbuttonbox1;
+  GtkWidget *hbuttonbox1;
+
+    GtkWidget *button;                      /* Bouton de commande          */
+
+  result = gtk_window_new(GTK_WINDOW_TOPLEVEL);
+  gtk_widget_set_size_request(result, 400, 300);
+  gtk_container_set_border_width(GTK_CONTAINER(result), 8);
+  gtk_window_set_title(GTK_WINDOW(result), _("Sections selection"));
+  gtk_window_set_position(GTK_WINDOW(result), GTK_WIN_POS_CENTER);
+  gtk_window_set_default_size(GTK_WINDOW(result), 500, 400);
+  gtk_window_set_type_hint(GTK_WINDOW(result), GDK_WINDOW_TYPE_HINT_DIALOG);
+
+  vbox1 = gtk_vbox_new(FALSE, 8);
+  gtk_widget_show(vbox1);
+  gtk_container_add(GTK_CONTAINER(result), vbox1);
+
+  hbox1 = gtk_hbox_new(FALSE, 8);
+  gtk_widget_show(hbox1);
+  gtk_box_pack_start(GTK_BOX(vbox1), hbox1, FALSE, FALSE, 0);
+
+    label = qck_create_label(NULL, NULL, _("Binary :"));
+    gtk_box_pack_start(GTK_BOX(hbox1), label, FALSE, FALSE, 0);
+
+  combobox1 = gtk_combo_box_new_text();
+  gtk_widget_show(combobox1);
+  gtk_box_pack_start(GTK_BOX(hbox1), combobox1, TRUE, TRUE, 0);
+
+
+    frame = qck_create_frame(_("<b>Content to display</b>"), &alignment, 4, 4, 12, 0);
+    gtk_box_pack_start(GTK_BOX(vbox1), frame, TRUE, TRUE, 0);
+
+
+
+
+  vbox2 = gtk_vbox_new(FALSE, 8);
+  gtk_widget_show(vbox2);
+  gtk_container_add(GTK_CONTAINER(alignment), vbox2);
+
+  hbox2 = gtk_hbox_new(FALSE, 8);
+  gtk_widget_show(hbox2);
+  gtk_box_pack_start(GTK_BOX(vbox2), hbox2, FALSE, FALSE, 0);
+
+    label = qck_create_label(NULL, NULL, _("Model :"));
+    gtk_box_pack_start(GTK_BOX(hbox2), label, FALSE, FALSE, 0);
+
+    comboboxentry1 = qck_create_combobox(NULL, NULL, G_CALLBACK(NULL), NULL);
+    gtk_box_pack_start(GTK_BOX(hbox2), comboboxentry1, TRUE, TRUE, 0);
+
+
+    button = qck_create_button_with_img(NULL, NULL, "gtk-add", G_CALLBACK(NULL), NULL);
+    gtk_box_pack_start(GTK_BOX(hbox2), button, FALSE, FALSE, 0);
+
+    button = qck_create_button_with_img(NULL, NULL, "gtk-remove", G_CALLBACK(NULL), NULL);
+    gtk_box_pack_start(GTK_BOX(hbox2), button, FALSE, FALSE, 0);
+
+
+
+
+  hbox3 = gtk_hbox_new(FALSE, 8);
+  gtk_widget_show(hbox3);
+  gtk_box_pack_start(GTK_BOX(vbox2), hbox3, TRUE, TRUE, 0);
+
+  scrolledwindow1 = gtk_scrolled_window_new(NULL, NULL);
+  gtk_widget_show(scrolledwindow1);
+  gtk_box_pack_start(GTK_BOX(hbox3), scrolledwindow1, TRUE, TRUE, 0);
+  gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolledwindow1), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
+  gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(scrolledwindow1), GTK_SHADOW_IN);
+
+  treeview1 = gtk_tree_view_new();
+  gtk_widget_show(treeview1);
+  gtk_container_add(GTK_CONTAINER(scrolledwindow1), treeview1);
+
+  vbuttonbox1 = gtk_vbutton_box_new();
+  gtk_widget_show(vbuttonbox1);
+  gtk_box_pack_start(GTK_BOX(hbox3), vbuttonbox1, FALSE, FALSE, 0);
+  gtk_button_box_set_layout(GTK_BUTTON_BOX(vbuttonbox1), GTK_BUTTONBOX_SPREAD);
+
+
+
+
+    button = qck_create_button_with_img(NULL, NULL, "gtk-add", G_CALLBACK(NULL), NULL);
+    gtk_container_add(GTK_CONTAINER(vbuttonbox1), button);
+
+    button = qck_create_button_with_img(NULL, NULL, "gtk-remove", G_CALLBACK(NULL), NULL);
+    gtk_container_add(GTK_CONTAINER(vbuttonbox1), button);
+
+
+
+
+
+  hbuttonbox1 = gtk_hbutton_box_new();
+  gtk_widget_show(hbuttonbox1);
+  gtk_box_pack_start(GTK_BOX(vbox1), hbuttonbox1, FALSE, FALSE, 0);
+  gtk_button_box_set_layout(GTK_BUTTON_BOX(hbuttonbox1), GTK_BUTTONBOX_END);
+
+
+    button = qck_create_button_from_stock(NULL, NULL, "gtk-ok", G_CALLBACK(NULL), NULL);
+    gtk_container_add(GTK_CONTAINER(hbuttonbox1), button);
+
+    button = qck_create_button_from_stock(NULL, NULL, "gtk-cancel", G_CALLBACK(NULL), NULL);
+    gtk_container_add(GTK_CONTAINER(hbuttonbox1), button);
+
+    return result;
+
+}
+
+
+
+
+
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : project = informations sur le project actuellement ouvert.   *
+*                ref     = espace de référencement principal.                 *
+*                                                                             *
+*  Description : Charge les sections sélectionnées pour le projet courant.    *
+*                                                                             *
+*  Retour      : -                                                            *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+void load_project_sections(openida_project *project, GObject *ref)
+{
+
+
+
+    /*
+    gtk_combo_box_append_text(GTK_COMBO_BOX(combobox), _("Never automatically"));
+    gtk_combo_box_append_text(GTK_COMBO_BOX(combobox), _("When the window gets the focus"));
+    gtk_combo_box_append_text(GTK_COMBO_BOX(combobox), _("On click on the window"));
+
+    */
+
+}
diff --git a/src/dlg_sections.h b/src/dlg_sections.h
new file mode 100644
index 0000000..2541d2b
--- /dev/null
+++ b/src/dlg_sections.h
@@ -0,0 +1,42 @@
+
+/* OpenIDA - Outil d'analyse de fichiers binaires
+ * dlg_sections.h - prototypes pour la boîte de dialogue permettant une sélection des sections
+ *
+ * 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 <http://www.gnu.org/licenses/>.
+ */
+
+
+#ifndef _DLG_SECTIONS_H
+#define _DLG_SECTIONS_H
+
+
+#include <gtk/gtk.h>
+
+
+#include "project.h"
+
+
+
+/* Construit la fenêtre de sélection des sections. */
+GtkWidget *create_sections_dialog(openida_project *);
+
+
+
+
+
+#endif  /* _DLG_SECTIONS_H */
diff --git a/src/easygtk.c b/src/easygtk.c
new file mode 100644
index 0000000..93ba653
--- /dev/null
+++ b/src/easygtk.c
@@ -0,0 +1,353 @@
+
+/* OpenIDA - Outil d'analyse de fichiers binaires
+ * easygtk.c - mise en place rapide de composants GTK
+ *
+ * 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 <http://www.gnu.org/licenses/>.
+ */
+
+
+#include "easygtk.h"
+
+
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : pt = espace imposé à la zone supérieure.                     *
+*                pb = espace imposé à la zone inférieure.                     *
+*                pl = espace imposé à la zone gauche.                         *
+*                pr = espace imposé à la zone droite.                         *
+*                                                                             *
+*  Description : Met en place un aligement dont les bordures sont à ajuster.  *
+*                                                                             *
+*  Retour      : Composant 'GtkWidget' ici créé.                              *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+GtkWidget *qck_create_padded_alignment(guint pt, guint pb, guint pl, guint pr)
+{
+    GtkWidget *result;                      /* Instance à renvoyer         */
+
+    result = gtk_alignment_new(0.5, 0.5, 1, 1);
+    gtk_widget_show(result);
+    gtk_alignment_set_padding(GTK_ALIGNMENT(result), pt, pb, pl, pr);
+
+    return result;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : caption   = contenu de l'étiqutte à placer.                  *
+*                alignment = conteneur réel à utiliser pour la suite. [OUT]   *
+*                pt = espace imposé à la zone supérieure.                     *
+*                pb = espace imposé à la zone inférieure.                     *
+*                pl = espace imposé à la zone gauche.                         *
+*                pr = espace imposé à la zone droite.                         *
+*                                                                             *
+*                                                                             *
+*  Description : Met en place une frame.                                      *
+*                                                                             *
+*  Retour      : Composant 'GtkWidget' ici créé.                              *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+GtkWidget *qck_create_frame(const char *caption, GtkWidget **alignment, guint pt, guint pb, guint pl, guint pr)
+{
+    GtkWidget *result;                      /* Instance à renvoyer         */
+    GtkWidget *label;                       /* Etiquette à utiliser        */
+
+    result = gtk_frame_new(NULL);
+    gtk_widget_show(result);
+
+    gtk_frame_set_shadow_type(GTK_FRAME(result), GTK_SHADOW_NONE);
+
+    label = qck_create_label(NULL, NULL, caption);
+    gtk_frame_set_label_widget(GTK_FRAME(result), label);
+    gtk_label_set_use_markup(GTK_LABEL(label), TRUE);
+
+    *alignment = qck_create_padded_alignment(pt, pb, pl, pr);
+    gtk_container_add(GTK_CONTAINER(result), *alignment);
+
+    return result;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : object  = espace dédié à l'inscription de références.        *
+*                name    = nom à donner au nouveau composant.                 *
+*                caption = intitulé apparaissant sur le composant.            *
+*                                                                             *
+*  Description : Crée un composant 'GtkLabel'.                                *
+*                                                                             *
+*  Retour      : Champ d'indication mis en place.                             *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+GtkWidget *qck_create_label(GObject *object, const char *name, const char *caption)
+{
+    GtkWidget *result;                      /* Résultat à renvoyer         */
+
+    result = gtk_label_new(caption);
+
+    if (G_IS_OBJECT(object) && name != NULL)
+    {
+        gtk_widget_ref(result);
+        g_object_set_data_full(object, name, result, (GtkDestroyNotify)gtk_widget_unref);
+    }
+
+    gtk_widget_show(result);
+
+	return result;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : object  = espace dédié à l'inscription de références.        *
+*                name    = nom à donner au nouveau composant.                 *
+*                caption = intitulé du bouton à créer.                        *
+*                handler = éventuelle fonction de sélection associée.         *
+*                data    = données à transmettre avec l'événement si besoin.  *
+*                                                                             *
+*  Description : Crée et enregistre un composant 'GtkButton'.                 *
+*                                                                             *
+*  Retour      : Simple bouton mis en place.                                  *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+GtkWidget *qck_create_button(GObject *object, const char *name, const char *caption, GCallback handler, gpointer data)
+{
+    GtkWidget *result;                      /* Résultat à renvoyer         */
+
+    result = gtk_button_new_with_label(caption);
+    GTK_WIDGET_SET_FLAGS(result, GTK_CAN_DEFAULT);
+
+    if (G_IS_OBJECT(object) && name != NULL)
+    {
+        gtk_widget_ref(result);
+        g_object_set_data_full(object, name, result, (GtkDestroyNotify)gtk_widget_unref);
+    }
+
+    gtk_widget_show(result);
+
+    if (handler != NULL)
+        g_signal_connect(result, "clicked", handler, data);
+
+	return result;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : object  = espace dédié à l'inscription de références.        *
+*                name    = nom à donner au nouveau composant.                 *
+*                stock   = désignation du type de bouton GTK.                 *
+*                handler = éventuelle fonction de sélection associée.         *
+*                data    = données à transmettre avec l'événement si besoin.  *
+*                                                                             *
+*  Description : Crée et enregistre un composant 'GtkButton'.                 *
+*                                                                             *
+*  Retour      : Simple bouton mis en place.                                  *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+GtkWidget *qck_create_button_from_stock(GObject *object, const char *name, const char *stock, GCallback handler, gpointer data)
+{
+    GtkWidget *result;                      /* Résultat à renvoyer         */
+
+    result = gtk_button_new_from_stock(stock);
+    GTK_WIDGET_SET_FLAGS(result, GTK_CAN_DEFAULT);
+
+    if (G_IS_OBJECT(object) && name != NULL)
+    {
+        gtk_widget_ref(result);
+        g_object_set_data_full(object, name, result, (GtkDestroyNotify)gtk_widget_unref);
+    }
+
+    gtk_widget_show(result);
+
+    if (handler != NULL)
+        g_signal_connect(result, "clicked", handler, data);
+
+	return result;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : object  = espace dédié à l'inscription de références.        *
+*                name    = nom à donner au nouveau composant.                 *
+*                image   = nom de l'image stockée dans GTK.                   *
+*                handler = éventuelle fonction de sélection associée.         *
+*                data    = données à transmettre avec l'événement si besoin.  *
+*                                                                             *
+*  Description : Crée et enregistre un composant 'GtkButton'.                 *
+*                                                                             *
+*  Retour      : Simple bouton mis en place.                                  *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+GtkWidget *qck_create_button_with_img(GObject *object, const char *name, const char *image, GCallback handler, gpointer data)
+{
+    GtkWidget *result;                      /* Résultat à renvoyer         */
+    GtkWidget *render;                      /* Image à ajouter au bouton   */
+
+    result = gtk_button_new();
+    GTK_WIDGET_SET_FLAGS(result, GTK_CAN_DEFAULT);
+
+    render = gtk_image_new_from_stock(image, GTK_ICON_SIZE_BUTTON);
+    gtk_widget_show(render);
+    gtk_container_add(GTK_CONTAINER(result), render);
+
+    if (G_IS_OBJECT(object) && name != NULL)
+    {
+        gtk_widget_ref(result);
+        g_object_set_data_full(object, name, result, (GtkDestroyNotify)gtk_widget_unref);
+    }
+
+    gtk_widget_show(result);
+
+    if (handler != NULL)
+        g_signal_connect(result, "clicked", handler, data);
+
+	return result;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : object  = espace dédié à l'inscription de références.        *
+*                name    = nom à donner au nouveau composant.                 *
+*                handler = éventuelle fonction de sélection associée.         *
+*                data    = données à transmettre avec l'événement si besoin.  *
+*                                                                             *
+*  Description : Crée et enregistre un composant 'GtkComboBox'.               *
+*                                                                             *
+*  Retour      : Composant mis en place.                                      *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+GtkWidget *qck_create_combobox(GObject *object, const char *name, GCallback handler, gpointer data)
+{
+    GtkWidget *result;                      /* Résultat à renvoyer         */
+
+    result = gtk_combo_box_new_text();
+
+    if (G_IS_OBJECT(object) && name != NULL)
+    {
+        gtk_widget_ref(result);
+        g_object_set_data_full(object, name, result, (GtkDestroyNotify)gtk_widget_unref);
+    }
+
+    gtk_widget_show(result);
+
+    if (handler != NULL)
+        g_signal_connect(result, "changed", handler, data);
+
+	return result;
+
+}
+
+
+
+
+
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : object  = espace dédié à l'inscription de références.        *
+*                name    = nom à donner au nouveau composant.                 *
+*                caption = intitulé du menu à créer.                          *
+*                handler = éventuelle fonction de sélection associée.         *
+*                data    = données à transmettre avec l'événement si besoin.  *
+*                                                                             *
+*  Description : Crée et enregistre un composant 'GtkMenuItem'.               *
+*                                                                             *
+*  Retour      : Simple élément de menu mis en place.                         *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+GtkWidget *qck_create_menu_item(GObject *object, const char *name, const char *caption, GCallback handler, gpointer data)
+{
+    GtkWidget *result;                      /* Résultat à renvoyer         */
+
+    result = gtk_menu_item_new_with_mnemonic(caption);
+
+    if (G_IS_OBJECT(object) && name != NULL)
+    {
+        gtk_widget_ref(result);
+        g_object_set_data_full(object, name, result, (GtkDestroyNotify)gtk_widget_unref);
+    }
+
+    gtk_widget_show(result);
+
+    if (handler != NULL)
+        g_signal_connect(result, "activate", handler, data);
+
+	return result;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : -                                                            *
+*                                                                             *
+*  Description : Crée et enregistre un composant 'GtkSeparatorMenuItem'.      *
+*                                                                             *
+*  Retour      : Simple élément de menu mis en place.                         *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+GtkWidget *qck_create_menu_separator(void)
+{
+    GtkWidget *result;                      /* Résultat à renvoyer         */
+
+    result = gtk_separator_menu_item_new();
+    gtk_widget_show(result);
+
+    return result;
+
+}
diff --git a/src/easygtk.h b/src/easygtk.h
new file mode 100644
index 0000000..7499815
--- /dev/null
+++ b/src/easygtk.h
@@ -0,0 +1,65 @@
+
+/* OpenIDA - Outil d'analyse de fichiers binaires
+ * easygtk.h - prototypes pour la mise en place rapide de composants GTK
+ *
+ * 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 <http://www.gnu.org/licenses/>.
+ */
+
+
+#ifndef _EASYGTK_H
+#define _EASYGTK_H
+
+
+#include <gtk/gtk.h>
+
+
+
+/* Met en place un aligement dont les bordures sont à ajuster. */
+GtkWidget *qck_create_padded_alignment(guint, guint, guint, guint);
+
+/* Met en place une frame. */
+GtkWidget *qck_create_frame(const char *, GtkWidget **, guint, guint, guint, guint);
+
+/* Crée un composant 'GtkLabel'. */
+GtkWidget *qck_create_label(GObject *, const char *, const char *);
+
+/* Crée et enregistre un composant 'GtkButton'. */
+GtkWidget *qck_create_button(GObject *, const char *, const char *, GCallback, gpointer);
+
+/* Crée et enregistre un composant 'GtkButton'. */
+GtkWidget *qck_create_button_from_stock(GObject *, const char *, const char *, GCallback, gpointer);
+
+/* Crée et enregistre un composant 'GtkButton'. */
+GtkWidget *qck_create_button_with_img(GObject *, const char *, const char *, GCallback, gpointer);
+
+/* Crée et enregistre un composant 'GtkComboBox'. */
+GtkWidget *qck_create_combobox(GObject *, const char *, GCallback, gpointer);
+
+
+
+
+/* Crée et enregistre un composant 'GtkMenuItem'. */
+GtkWidget *qck_create_menu_item(GObject *, const char *, const char *, GCallback, gpointer);
+
+/* Crée et enregistre un composant 'GtkSeparatorMenuItem'. */
+GtkWidget *qck_create_menu_separator(void);
+
+
+
+
+#endif  /* _EASYGTK_H */
diff --git a/src/editor.c b/src/editor.c
index dbdc2d3..0673110 100644
--- a/src/editor.c
+++ b/src/editor.c
@@ -50,6 +50,8 @@
 
 
 #include "binary.h"
+#include "dlg_sections.h"
+#include "easygtk.h"
 #include "gtksnippet.h"
 #include "gtkcodeview.h"
 #include "pan_symbols.h"
@@ -70,6 +72,36 @@ void destroy_editor(GtkWidget *, gpointer);
 
 
 
+/* Réagit au menu "Fichier -> Enregistrer le projet". */
+void mcb_file_save_project(GtkMenuItem *, gpointer);
+
+/* Réagit au menu "Fichier -> Enregistrer le projet sous...". */
+void mcb_file_save_project_as(GtkMenuItem *, gpointer);
+
+
+
+/* Charge un projet récent et met à jour la liste. */
+void mcb_open_recent_project(GtkMenuItem *, gpointer);
+
+
+
+/* Affiche la boîte d'ajout d'un binaire au projet courant. */
+void mcb_project_add_binary(GtkMenuItem *, gpointer);
+
+/* Retire un binaire du projet courant. */
+void mcb_project_remove_binary(GtkMenuItem *, gpointer);
+
+
+
+/* Affiche la boîte de sélection des sections. */
+void mcb_select_sections(GtkMenuItem *, gpointer);
+
+
+
+/* Met à jour le contenu du menu 'Projet'. */
+void reload_menu_project(GObject *);
+
+
 
 
 /******************************************************************************
@@ -355,6 +387,11 @@ on_button2_clicked                     (GtkButton       *button,
 GtkWidget *create_editor(void)
 {
     GtkWidget *result;                      /* Fenêtre à renvoyer          */
+    GtkWidget *menuboard;                   /* Barre de menus principale   */
+    GtkWidget *menuitem;                    /* Elément de menu             */
+    GtkWidget *menubar;                     /* Support pour éléments       */
+    GtkWidget *submenuitem;                 /* Sous-élément de menu        */
+    GtkWidget *submenubar;                  /* Support pour sous-éléments  */
 
   GtkWidget *vbox1;
   GtkWidget *vpaned1;
@@ -393,6 +430,9 @@ GtkWidget *create_editor(void)
 
   GtkWidget *panel;
 
+  openida_project *project;
+
+
 #if 0
     GtkWidget *vbox;                        /* Support à divisions vert.   */
     GtkWidget *notebook;                    /* Support à onglets           */
@@ -414,12 +454,73 @@ GtkWidget *create_editor(void)
 
 
 
-
-
   vbox1 = gtk_vbox_new (FALSE, 0);
   gtk_widget_show (vbox1);
   gtk_container_add (GTK_CONTAINER (result), vbox1);
 
+
+    /* Intégration des menus */
+
+    menuboard = gtk_menu_bar_new();
+    gtk_widget_show(menuboard);
+    gtk_box_pack_start(GTK_BOX(vbox1), menuboard, FALSE, FALSE, 0);
+
+    menuitem = gtk_menu_item_new_with_mnemonic(_("_File"));
+    gtk_widget_show(menuitem);
+    gtk_container_add(GTK_CONTAINER(menuboard), menuitem);
+
+    menubar = gtk_menu_new();
+    gtk_menu_item_set_submenu(GTK_MENU_ITEM(menuitem), menubar);
+
+    submenuitem = qck_create_menu_item(NULL, NULL, _("Save project"), G_CALLBACK(mcb_file_save_project), result);
+    gtk_container_add(GTK_CONTAINER(menubar), submenuitem);
+
+    submenuitem = qck_create_menu_item(NULL, NULL, _("Save project as..."), G_CALLBACK(mcb_file_save_project_as), result);
+    gtk_container_add(GTK_CONTAINER(menubar), submenuitem);
+
+    submenuitem = qck_create_menu_separator();
+    gtk_container_add(GTK_CONTAINER(menubar), submenuitem);
+
+    submenuitem = qck_create_menu_item(G_OBJECT(result), "menu_recent_prjs", _("Recent projects..."), NULL, NULL);
+    gtk_container_add(GTK_CONTAINER(menubar), submenuitem);
+
+    submenubar = gtk_menu_new();
+    gtk_menu_item_set_submenu(GTK_MENU_ITEM(submenuitem), submenubar);
+
+    menuitem = gtk_menu_item_new_with_mnemonic(_("_Project"));
+    gtk_widget_show(menuitem);
+    gtk_container_add(GTK_CONTAINER(menuboard), menuitem);
+
+    menubar = gtk_menu_new();
+    gtk_menu_item_set_submenu(GTK_MENU_ITEM(menuitem), menubar);
+
+    submenuitem = qck_create_menu_item(NULL, NULL, _("Add a binary..."), G_CALLBACK(mcb_project_add_binary), result);
+    gtk_container_add(GTK_CONTAINER(menubar), submenuitem);
+
+    submenuitem = qck_create_menu_item(G_OBJECT(result), "menu_prj_remove_bin", _("Remove a binary"), NULL, NULL);
+    gtk_container_add(GTK_CONTAINER(menubar), submenuitem);
+
+    submenubar = gtk_menu_new();
+    gtk_menu_item_set_submenu(GTK_MENU_ITEM(submenuitem), submenubar);
+
+    submenuitem = qck_create_menu_separator();
+    gtk_container_add(GTK_CONTAINER(menubar), submenuitem);
+
+    submenuitem = qck_create_menu_item(NULL, NULL, _("Select sections..."), G_CALLBACK(mcb_select_sections), NULL);
+    gtk_container_add(GTK_CONTAINER(menubar), submenuitem);
+
+
+
+    load_recent_openida_projects_list(G_OBJECT(result), G_CALLBACK(mcb_open_recent_project));
+
+
+    project = load_openida_project_from_xml("/home/ocb/test.oip")/*create_empty_openida_project()*/;
+    set_current_openida_project(project);
+
+    reload_menu_project(G_OBJECT(result));
+
+
+
   vpaned1 = gtk_vpaned_new ();
   gtk_widget_show (vpaned1);
   gtk_box_pack_start (GTK_BOX (vbox1), vpaned1, TRUE, TRUE, 0);
@@ -688,5 +789,266 @@ void destroy_editor(GtkWidget *widget, gpointer data)
 
 
 
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : menuitem = élément de menu sélectionné.                      *
+*                data     = adresse de l'espace de référencement global.      *
+*                                                                             *
+*  Description : Réagit au menu "Fichier -> Enregistrer le projet".           *
+*                                                                             *
+*  Retour      : -                                                            *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+void mcb_file_save_project(GtkMenuItem *menuitem, gpointer data)
+{
+    openida_project *project;               /* Projet courant              */
+
+    project = get_current_openida_project();
+
+    if (has_storing_filename(project))
+        write_openida_project_to_xml(project, NULL);
+
+    else
+        mcb_file_save_project_as(menuitem, data);
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : menuitem = élément de menu sélectionné.                      *
+*                data     = adresse de l'espace de référencement global.      *
+*                                                                             *
+*  Description : Réagit au menu "Fichier -> Enregistrer le projet sous...".   *
+*                                                                             *
+*  Retour      : -                                                            *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+void mcb_file_save_project_as(GtkMenuItem *menuitem, gpointer data)
+{
+    GtkWidget *dialog;                      /* Boîte à afficher            */
+    gchar *filename;                        /* Nom du fichier à intégrer   */
+
+    dialog = gtk_file_chooser_dialog_new (_("Save the project as..."), GTK_WINDOW(data),
+                                          GTK_FILE_CHOOSER_ACTION_SAVE,
+                                          GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
+                                          GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT,
+                                          NULL);
+
+    if (gtk_dialog_run(GTK_DIALOG (dialog)) == GTK_RESPONSE_ACCEPT)
+    {
+        filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dialog));
+
+        write_openida_project_to_xml(get_current_openida_project(), filename);
+
+        g_free(filename);
+
+    }
+
+    gtk_widget_destroy(dialog);
+
+}
+
+
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : menuitem = élément de menu sélectionné.                      *
+*                data     = adresse de l'espace de référencement global.      *
+*                                                                             *
+*  Description : Charge un projet récent et met à jour la liste.              *
+*                                                                             *
+*  Retour      : -                                                            *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+void mcb_open_recent_project(GtkMenuItem *menuitem, gpointer data)
+{
+    const gchar *caption;                   /* Etiquette du menu           */
+    openida_project *project;               /* Nouveau projet chargé       */
+
+    caption = gtk_label_get_text(GTK_LABEL(gtk_bin_get_child(GTK_BIN(menuitem))));
+
+    project = load_openida_project_from_xml(caption);
+
+    if (project != NULL)
+    {
+        set_current_openida_project(project);
 
+        /* TODO ... */
 
+    }
+
+}
+
+
+
+
+
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : menuitem = élément de menu sélectionné.                      *
+*                data     = adresse de l'espace de référencement global.      *
+*                                                                             *
+*  Description : Affiche la boîte d'ajout d'un binaire au projet courant.     *
+*                                                                             *
+*  Retour      : -                                                            *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+void mcb_project_add_binary(GtkMenuItem *menuitem, gpointer data)
+{
+    GtkWidget *dialog;                      /* Boîte à afficher            */
+    gchar *filename;                        /* Nom du fichier à intégrer   */
+    openida_binary *binary;                 /* Représentation chargée      */
+
+    dialog = gtk_file_chooser_dialog_new (_("Open a binary file"), GTK_WINDOW(data),
+                                          GTK_FILE_CHOOSER_ACTION_OPEN,
+                                          GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
+                                          GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT,
+                                          NULL);
+
+    if (gtk_dialog_run(GTK_DIALOG (dialog)) == GTK_RESPONSE_ACCEPT)
+    {
+        filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dialog));
+
+        binary = load_binary_file(filename);
+
+        if (binary != NULL)
+        {
+            attach_binary_to_openida_project(get_current_openida_project(), binary);
+            reload_menu_project(G_OBJECT(data));
+        }
+
+        g_free(filename);
+
+    }
+
+    gtk_widget_destroy(dialog);
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : menuitem = élément de menu sélectionné.                      *
+*                data     = adresse de l'espace de référencement global.      *
+*                                                                             *
+*  Description : Retire un binaire du projet courant.                         *
+*                                                                             *
+*  Retour      : -                                                            *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+void mcb_project_remove_binary(GtkMenuItem *menuitem, gpointer data)
+{
+    openida_binary *binary;                 /* Représentation chargée      */
+
+    binary = g_object_get_data(G_OBJECT(menuitem), "binary");
+
+    detach_binary_to_openida_project(get_current_openida_project(), binary);
+    unload_binary_file(binary);
+
+    reload_menu_project(G_OBJECT(data));
+
+}
+
+
+
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : menuitem = élément de menu sélectionné.                      *
+*                data     = adresse de l'espace de référencement global.      *
+*                                                                             *
+*  Description : Affiche la boîte de sélection des sections.                  *
+*                                                                             *
+*  Retour      : -                                                            *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+void mcb_select_sections(GtkMenuItem *menuitem, gpointer data)
+{
+    GtkWidget *dialog;                      /* Boîte de dialogue à montrer */
+
+    dialog = create_sections_dialog(create_empty_openida_project()/* FIXME */);
+    gtk_widget_show(dialog);
+
+}
+
+
+
+
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : ref = espace de référencements global.                       *
+*                                                                             *
+*  Description : Met à jour le contenu du menu 'Projet'.                      *
+*                                                                             *
+*  Retour      : -                                                            *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+void reload_menu_project(GObject *ref)
+{
+    GtkWidget *menuitem;                    /* Menu principal à compléter  */
+    GtkWidget *menubar;                     /* Support pour éléments       */
+    GList *list;                            /* Liste des éléments en place */
+    GList *iter;                            /* Boucle de parcours #1       */
+    size_t count;                           /* Nombre de binaires attachés */
+    const openida_binary **binaries;        /* Liste de ces binaires       */
+    size_t i;                               /* Boucle de parcours #2       */
+    const char *desc;                       /* Description à afficher      */
+    GtkWidget *submenuitem;                 /* Sous-menu à ajouter         */
+
+    menuitem = GTK_WIDGET(g_object_get_data(ref, "menu_prj_remove_bin"));
+    menubar = gtk_menu_item_get_submenu(GTK_MENU_ITEM(menuitem));
+
+    /* Remise à zéro */
+
+    list = gtk_container_get_children(GTK_CONTAINER(menubar));
+
+    for (iter = list; iter != NULL; iter = g_list_next(iter))
+        gtk_container_remove(GTK_CONTAINER(menubar), GTK_WIDGET(iter->data));
+
+    g_list_free(list);
+
+    /* Ajout des entrées */ 
+
+    binaries = get_openida_project_binaries(get_current_openida_project(), &count);
+
+    for (i = 0; i < count; i++)
+    {
+        desc = openida_binary_to_string(binaries[i]);
+
+        submenuitem = qck_create_menu_item(NULL, NULL, desc, G_CALLBACK(mcb_project_remove_binary), ref);
+        g_object_set_data(G_OBJECT(submenuitem), "binary", binaries[i]);
+        gtk_container_add(GTK_CONTAINER(menubar), submenuitem);
+
+    }
+
+    gtk_widget_set_sensitive(menuitem, count > 0);
+
+}
diff --git a/src/project.c b/src/project.c
new file mode 100644
index 0000000..2ec9e09
--- /dev/null
+++ b/src/project.c
@@ -0,0 +1,431 @@
+
+/* 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 <http://www.gnu.org/licenses/>.
+ */
+
+
+#include "project.h"
+
+
+#include <dirent.h>
+#include <malloc.h>
+#include <string.h>
+#include <unistd.h>
+
+
+#include "easygtk.h"
+#include "xdg.h"
+#include "xml.h"
+
+
+
+
+/* Propriétés d'un ensemble de fichiers ouverts */
+struct openida_project
+{
+    char *filename;                         /* Lieu d'enregistrement       */
+
+    openida_binary **binaries;              /* Fichiers binaires associés  */
+    size_t binaries_count;                  /* Nombre de ces fichiers      */
+
+
+
+};
+
+
+
+
+
+
+
+
+/******************************************************************************
+*                                                                             *
+*  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 = (openida_binary **)realloc(project->binaries,
+                                                   ++project->binaries_count * sizeof(openida_binary *));
+
+
+
+
+
+    project->binaries[project->binaries_count - 1] = 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)
+{
+    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 *));
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  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);
+
+}
diff --git a/src/project.h b/src/project.h
new file mode 100644
index 0000000..a08039d
--- /dev/null
+++ b/src/project.h
@@ -0,0 +1,88 @@
+
+/* OpenIDA - Outil d'analyse de fichiers binaires
+ * project.h - prototypes pour la 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 <http://www.gnu.org/licenses/>.
+ */
+
+
+#ifndef _PROJECT_H
+#define _PROJECT_H
+
+
+#include "binary.h"
+
+
+
+/* Propriétés d'un ensemble de fichiers ouverts */
+typedef struct openida_project openida_project;
+
+
+
+#define set_current_openida_project(prj) _get_current_openida_project(prj)
+#define get_current_openida_project() _get_current_openida_project(NULL)
+
+
+/* Fournit l'adresse du projet courant. */
+openida_project *_get_current_openida_project(openida_project *);
+
+/* Crée un projet vide. */
+openida_project *create_empty_openida_project(void);
+
+/* Crée un projet à partir du contenu XML d'un fichier. */
+openida_project *load_openida_project_from_xml(const char *);
+
+/* Ferme un projet et libère la mémoire associée. */
+void close_openida_project(openida_project *);
+
+/* Indique si un projet a tous les éléments pour être sauvé. */
+bool has_storing_filename(const openida_project *);
+
+
+
+/* Procède à l'enregistrement d'un projet donné. */
+bool write_openida_project_to_xml(openida_project *, const char *);
+
+
+
+/* Attache un fichier donné à un projet donné. */
+void attach_binary_to_openida_project(openida_project *, openida_binary *);
+
+/* Détache un fichier donné à un projet donné. */
+void detach_binary_to_openida_project(openida_project *, openida_binary *);
+
+/* Fournit l'ensemble des binaires associés à un projet. */
+const openida_binary **get_openida_project_binaries(const openida_project *, size_t *);
+
+
+
+
+
+/* ---------------------- PARTIE GRAPHIQUE DES [DE]CHARGEMENTS ---------------------- */
+
+
+/* Met en place les menus rechargeant les projets récents. */
+void load_recent_openida_projects_list(GObject *, GCallback *);
+
+
+
+
+
+
+
+#endif  /* _PROJECT_H */
diff --git a/src/xdg.c b/src/xdg.c
new file mode 100644
index 0000000..6541e89
--- /dev/null
+++ b/src/xdg.c
@@ -0,0 +1,103 @@
+
+/* OpenIDA - Outil d'analyse de fichiers binaires
+ * xdg.c - compléments mineurs au support Freedesktop
+ *
+ * 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 <http://www.gnu.org/licenses/>.
+ */
+
+
+#include "xdg.h"
+
+
+#include <dirent.h>
+#include <malloc.h>
+#include <stdlib.h>
+#include <string.h>
+
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : suffix = élément visé dans le répertoire de configuration.   *
+*                                                                             *
+*  Description : Détermine le chemin d'un répertoire selon les specs. XDG.    *
+*                                                                             *
+*  Retour      : Chemin d'accès aux configurations personnelles ou NULL.      *
+*                                                                             *
+*  Remarques   : cf. http://standards.freedesktop.org/basedir-spec/.          *
+*                                                                             *
+******************************************************************************/
+
+char *get_xdg_config_dir(const char *suffix)
+{
+    char *result;                           /* Chemin d'accès à renvoyer   */
+    const char *env;                        /* Valeur de l'environnement   */
+    DIR *directory;                         /* Répertoire avec contenu ?   */
+    struct dirent *entry;                   /* Elément de répertoire       */
+
+    result = NULL;
+
+    env = getenv("XDG_CONFIG_HOME");
+
+    if (env != NULL && env[0] != '\0')
+    {
+        directory = opendir(env);
+        if (directory == NULL) goto default_cfg_dir;
+
+        for (entry = readdir(directory); entry != NULL && result == NULL; entry = readdir(directory))
+        {
+            if (strcmp(entry->d_name, ".") == 0) continue;
+            if (strcmp(entry->d_name, "..") == 0) continue;
+
+            result = (char *)calloc(strlen(env) + 2 + strlen(suffix) + 1, sizeof(char));
+            strcpy(result, env);
+
+            if (env[strlen(env) - 1] != '/')
+                strcat(result, "/");
+
+            strcat(result, ".");
+            strcat(result, suffix);
+
+        }
+
+        closedir(directory);
+
+    }
+
+ default_cfg_dir:
+
+    if (result == NULL)
+    {
+        env = getenv("HOME");
+        if (env == NULL || env[0] == '\0') return NULL;
+
+        result = (char *)calloc(strlen(env) + 1 + strlen(".config/") + strlen(suffix) + 1, sizeof(char));
+
+        strcpy(result, env);
+
+        if (env[strlen(env) - 1] != '/')
+            strcat(result, "/");
+
+        strcat(result, ".config/");
+        strcat(result, suffix);
+
+    }
+
+    return result;
+
+}
diff --git a/src/xdg.h b/src/xdg.h
new file mode 100644
index 0000000..c8cd97d
--- /dev/null
+++ b/src/xdg.h
@@ -0,0 +1,34 @@
+
+/* OpenIDA - Outil d'analyse de fichiers binaires
+ * xdg.h - prototypes pour des compléments mineurs au support Freedesktop
+ *
+ * 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 <http://www.gnu.org/licenses/>.
+ */
+
+
+#ifndef _XDG_H
+#define _XDG_H
+
+
+
+/* Détermine le chemin d'un répertoire selon les specs. XDG. */
+char *get_xdg_config_dir(const char *);
+
+
+
+#endif  /* _XDG_H */
diff --git a/src/xml.c b/src/xml.c
new file mode 100644
index 0000000..baa4eb2
--- /dev/null
+++ b/src/xml.c
@@ -0,0 +1,574 @@
+
+/* Firebox Tools - Outils de configurations pour le WM Firebox
+ * xml.c - lecture ou écriture de documents XML
+ *
+ * Copyright (C) 2006-2007 Cyrille Bagard
+ *
+ *  This file is part of Firebox Tools.
+ *
+ *  Firebox Tools 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 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  Firebox Tools 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 this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+
+#include "xml.h"
+
+
+#include <stdarg.h>
+#include <string.h>
+
+
+#ifdef DEBUG
+#   define XML_LOG fprintf
+#else
+#   define XML_LOG if (FALSE) fprintf
+#endif
+
+
+
+/* ---------------------------------------------------------------------------------- */
+/*                       OPERATIONS DE LECTURE D'UN FICHIER XML                       */
+/* ---------------------------------------------------------------------------------- */
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : filename = nom du fichier à ouvrir.                          *
+*                xdoc     = structure XML chargée. [OUT]                      *
+*                xroot    = noeud premier de l'ensemble des définitions.[OUT] *
+*                xpathCtx = contexte à utiliser pour les recherches. [OUT]    *
+*                                                                             *
+*  Description : Ouvre un fichier XML de façon encadrée.                      *
+*                                                                             *
+*  Retour      : true si l'opération a pu s'effectuer, false sinon.           *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+gboolean open_xml_file(const char *filename, xmlDoc **xdoc, xmlNode **xroot, xmlXPathContextPtr *xpathCtx)
+{
+    *xdoc = xmlParseFile(filename);
+
+    if (*xdoc == NULL)
+    {
+        XML_LOG(stderr, "Can not parse the XML file '%s'\n", filename);
+        return FALSE;
+    }
+
+    *xroot = xmlDocGetRootElement(*xdoc);
+
+    if (*xroot == NULL)
+    {
+        XML_LOG(stderr, "Can not access the root node in '%s'\n", filename);
+        xmlFreeDoc(*xdoc);
+        return FALSE;
+    }
+
+    *xpathCtx = xmlXPathNewContext(*xdoc);
+
+    if (*xpathCtx == NULL)
+    {
+        XML_LOG(stderr, "Unable to create new XPath context\n");
+        xmlFreeDoc(*xdoc);
+        return FALSE;
+    }
+
+    return TRUE;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : xpathCtx = contexte à utiliser pour les recherches.          *
+*                path     = chemin d'accès au noeud visé.                     *
+*                                                                             *
+*  Description : Obtient de façon encadrée l'accès à un noeud défini.         *
+*                                                                             *
+*  Retour      : Adresse de l'accès trouvé.                                   *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+xmlXPathObjectPtr get_node_xpath_object(xmlXPathContextPtr xpathCtx, const char *path)
+{
+    xmlXPathObjectPtr result;               /* Noeud XML à renvoyer        */
+
+    result = xmlXPathEvalExpression(BAD_CAST path, xpathCtx);
+
+    if (result == NULL)
+    {
+        XML_LOG(stderr, "Unable to evaluate xpath expression '%s'\n", path);
+        return NULL;
+    }
+
+    if (result->nodesetval == NULL)
+    {
+        XML_LOG(stderr, "Node '%s' not found\n", path);
+        xmlXPathFreeObject(result);
+        return NULL;
+    }
+
+    return result;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : node = noeud dont une propriété est à lire.                  *
+*                                                                             *
+*  Description : Obtient une valeur placée entre <...> et </...>.             *
+*                                                                             *
+*  Retour      : Valeur sous forme de chaîne de caractères ou NULL.           *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+char *qck_get_node_text_value(xmlNodePtr node)
+{
+    char *result;                           /* Valeur en question renvoyée */
+
+    result = NULL;
+
+    if (node != NULL)
+        if (node->children != NULL)
+            if (node->children->content != NULL)
+                result = strdup((char *)node->children->content);
+
+    if (result == NULL) XML_LOG(stderr, "No text value for node '%s'\n", node->name);
+
+    return result;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : xpathCtx = contexte à utiliser pour les recherches.          *
+*                path     = chemin d'accès au noeud visé.                     *
+*                                                                             *
+*  Description : Obtient une valeur placée entre <...> et </...>.             *
+*                                                                             *
+*  Retour      : Valeur sous forme de chaîne de caractères ou NULL.           *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+char *get_node_text_value(xmlXPathContextPtr xpathCtx, const char *path)
+{
+    char *result;                           /* Valeur en question renvoyée */
+    xmlXPathObjectPtr xpathObj;             /* Point de départ XML         */
+
+    result = NULL;
+
+    xpathObj = get_node_xpath_object(xpathCtx, path);
+    if (xpathObj == NULL) return NULL;
+
+    if (xpathObj->nodesetval->nodeNr > 0)
+        result = qck_get_node_text_value(xpathObj->nodesetval->nodeTab[0]);
+
+    xmlXPathFreeObject(xpathObj);
+
+    return result;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : node = noeud dont une propriété est à lire.                  *
+*                name = nom de la propriété à lire.                           *
+*                                                                             *
+*  Description : Obtient la valeur d'une propriété d'un élément.              *
+*                                                                             *
+*  Retour      : Valeur sous forme de chaîne de caractères ou NULL.           *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+char *qck_get_node_prop_value(xmlNodePtr node, const char *name)
+{
+    char *result;                           /* Valeur en question renvoyée */
+    xmlAttrPtr attrib;                      /* Liste d'attributs présents  */
+
+    result = NULL;
+
+    if (node == NULL) return NULL;
+
+    /* Lecture de la valeur */
+
+    for (attrib = node->properties; attrib != NULL && result == NULL; attrib = attrib->next)
+        if (xmlStrEqual(attrib->name, BAD_CAST name)) result = strdup((char *)attrib->children->content);
+
+    return result;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : xpathCtx = contexte à utiliser pour les recherches.          *
+*                path     = chemin d'accès au noeud à traiter.                *
+*                name     = nom de la propriété à lire.                       *
+*                                                                             *
+*  Description : Obtient la valeur d'une propriété d'un élément.              *
+*                                                                             *
+*  Retour      : Valeur sous forme de chaîne de caractères ou NULL.           *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+char *get_node_prop_value(xmlXPathContextPtr xpathCtx, const char *path, const char *name)
+{
+    char *result;                           /* Valeur en question renvoyée */
+    xmlXPathObjectPtr xpathObj;             /* Point de départ XML         */
+
+    result = NULL;
+
+    xpathObj = get_node_xpath_object(xpathCtx, path);
+    if (xpathObj == NULL) return NULL;
+
+    if (xpathObj->nodesetval->nodeNr > 0)
+        result = qck_get_node_prop_value(xpathObj->nodesetval->nodeTab[0], name);
+
+    xmlXPathFreeObject(xpathObj);
+
+    return result;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : node = noeud de texte avec un lien avec le document XML.     *
+*                                                                             *
+*  Description : Construit un chemin d'accès complet selon le fichier XML.    *
+*                                                                             *
+*  Retour      : Valeur à libérer de la mémoire après usage ou NULL.          *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+char *qck_build_filename_with_doc_url(xmlNodePtr node)
+{
+    char *result;                           /* Construction à retourner    */
+    char *text;                             /* Valeur du texte lu          */
+    char *last;                             /* Point de remplacement       */
+
+    result = NULL;
+
+    text = qck_get_node_text_value(node);
+
+    if (text != NULL)
+    {
+        result = (char *)calloc(xmlStrlen(node->doc->URL) + strlen(text) + 1, sizeof(char));
+
+        strcpy(result, (const char *)node->doc->URL);
+
+        last = strrchr(result, '/');
+        last++;
+
+        strcpy(last, text);
+        free(text);
+
+    }
+
+    return result;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : xpathCtx = contexte à utiliser pour les recherches.          *
+*                path     = chemin d'accès au noeud à traiter.                *
+*                                                                             *
+*  Description : Construit un chemin d'accès complet selon le fichier XML.    *
+*                                                                             *
+*  Retour      : Valeur sous forme de chaîne de caractères ou NULL.           *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+char *build_filename_with_doc_url(xmlXPathContextPtr xpathCtx, const char *path)
+{
+    char *result;                           /* Valeur en question renvoyée */
+    xmlXPathObjectPtr xpathObj;             /* Point de départ XML         */
+
+    result = NULL;
+
+    xpathObj = get_node_xpath_object(xpathCtx, path);
+    if (xpathObj == NULL) return NULL;
+
+    if (xpathObj->nodesetval->nodeNr > 0)
+        result = qck_build_filename_with_doc_url(xpathObj->nodesetval->nodeTab[0]);
+
+    xmlXPathFreeObject(xpathObj);
+
+    return result;
+
+}
+
+
+
+/* ---------------------------------------------------------------------------------- */
+/*                       OPERATIONS D'ECRITURE D'UN FICHIER XML                       */
+/* ---------------------------------------------------------------------------------- */
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : filename = nom du fichier à ouvrir.                          *
+*                                                                             *
+*  Description : Amorce l'écriture d'un nouveau fichier XML.                  *
+*                                                                             *
+*  Retour      : Rédacteur mis en place ou NULL en cas d'erreur.              *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+xmlTextWriterPtr start_writing_xml_file(const char *filename)
+{
+    xmlTextWriterPtr result;                /* Moyen à retourner           */
+    int retval;                             /* Bilan d'une opération       */
+
+    result = xmlNewTextWriterFilename(filename, 0);
+
+    if (result == NULL)
+    {
+        XML_LOG(stderr, "Error creating the xml writer\n");
+        return NULL;
+    }
+
+    retval = xmlTextWriterStartDocument(result, NULL, "UTF-8", "yes");
+    if (retval < 0)
+    {
+        XML_LOG(stderr, "Error at xmlTextWriterStartDocument\n");
+        xmlFreeTextWriter(result);
+        return NULL;
+    }
+
+    retval = xmlTextWriterSetIndent(result, 1);
+    if (retval < 0)
+    {
+        XML_LOG(stderr, "Error setting indentation\n");
+        xmlFreeTextWriter(result);
+        return NULL;
+    }
+
+    retval = xmlTextWriterSetIndentString(result, BAD_CAST "\t");
+    if (retval < 0)
+    {
+        XML_LOG(stderr, "Error setting indentation string\n");
+        xmlFreeTextWriter(result);
+        return NULL;
+    }
+
+    return result;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : writer = rédacteur dédié à l'écriture.                       *
+*                                                                             *
+*  Description : Met fin à l'écriture d'un nouveau fichier XML.               *
+*                                                                             *
+*  Retour      : Bilan de l'opération : true ou false.                        *
+*                                                                             *
+*  Remarques   : Ferme au besoin toutes les balises encore ouvertes.          *
+*                                                                             *
+******************************************************************************/
+
+bool end_writing_xml_file(xmlTextWriterPtr writer)
+{
+    int retval;                             /* Bilan de l'opération        */
+
+    retval = xmlTextWriterEndDocument(writer);
+    if (retval < 0)
+    {
+        XML_LOG(stderr, "Error at xmlTextWriterEndDocument\n");
+        return false;
+    }
+
+    xmlFreeTextWriter(writer);
+
+    return true;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : writer = rédacteur dédié à l'écriture.                       *
+*                name   = nom de la balise à écrire.                          *
+*                                                                             *
+*  Description : Ecrit une balise et ne la referme pas.                       *
+*                                                                             *
+*  Retour      : Bilan de l'opération : true ou false.                        *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+bool open_xml_element(xmlTextWriterPtr writer, const char *name)
+{
+    int retval;                             /* Bilan de l'opération        */
+
+    retval = xmlTextWriterStartElement(writer, BAD_CAST name);
+
+    if (retval < 0)
+        XML_LOG(stderr, "Error at xmlTextWriterWriteFormatElement\n");
+
+    return (retval >= 0);
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : writer = rédacteur dédié à l'écriture.                       *
+*                                                                             *
+*  Description : Ferme la dernière balise laissée ouverte.                    *
+*                                                                             *
+*  Retour      : Bilan de l'opération : true ou false.                        *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+bool close_xml_element(xmlTextWriterPtr writer)
+{
+    int retval;                             /* Bilan de l'opération        */
+
+    retval = xmlTextWriterEndElement(writer);
+
+    if (retval < 0)
+        XML_LOG(stderr, "Error at xmlTextWriterWriteFormatElement\n");
+
+    return (retval >= 0);
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : writer = rédacteur dédié à l'écriture.                       *
+*                name   = nom de la balise à écrire.                          *
+*                format = format de la chaîne à traiter.                      *
+*                ...    = informations à inscrire.                            *
+*                                                                             *
+*  Description : Ecrit une balise avec un contenu textuel.                    *
+*                                                                             *
+*  Retour      : Bilan de l'opération : true ou false.                        *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+bool write_xml_element_with_content(xmlTextWriterPtr writer, const char *name, const char *format, ...)
+{
+    va_list ap;                             /* Liste d'arguments variable  */
+    int retval;                             /* Bilan de l'opération        */
+
+    va_start(ap, format);
+
+    retval = xmlTextWriterWriteVFormatElement(writer, BAD_CAST name, format, ap);
+
+    if (retval < 0)
+        XML_LOG(stderr, "Error at xmlTextWriterWriteFormatElement\n");
+
+    va_end(ap);
+
+    return (retval >= 0);
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : writer = rédacteur dédié à l'écriture.                       *
+*                name   = nom de l'attribut à écrire.                         *
+*                format = format de la chaîne à traiter.                      *
+*                ...    = informations à inscrire.                            *
+*                                                                             *
+*  Description : Ecrit un attribut avec un contenu textuel.                   *
+*                                                                             *
+*  Retour      : Bilan de l'opération : true ou false.                        *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+bool write_xml_attribute(xmlTextWriterPtr writer, const char *name, const char *format, ...)
+{
+    va_list ap;                             /* Liste d'arguments variable  */
+    int retval;                             /* Bilan de l'opération        */
+
+    va_start(ap, format);
+
+    retval = xmlTextWriterWriteVFormatAttribute(writer, BAD_CAST name, format, ap);
+
+    if (retval < 0)
+        XML_LOG(stderr, "Error at xmlTextWriterWriteFormatElement\n");
+
+    va_end(ap);
+
+    return (retval >= 0);
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : writer = rédacteur dédié à l'écriture.                       *
+*                format = format de la chaîne à traiter.                      *
+*                ...    = informations à inscrire.                            *
+*                                                                             *
+*  Description : Ecrit un contenu textuel.                                    *
+*                                                                             *
+*  Retour      : Bilan de l'opération : true ou false.                        *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+bool write_xml_content(xmlTextWriterPtr writer, const char *format, ...)
+{
+    va_list ap;                             /* Liste d'arguments variable  */
+    int retval;                             /* Bilan de l'opération        */
+
+    va_start(ap, format);
+
+    retval = xmlTextWriterWriteVFormatString(writer, format, ap);
+
+    if (retval < 0)
+        XML_LOG(stderr, "Error at xmlTextWriterWriteFormatElement\n");
+
+    va_end(ap);
+
+    return (retval >= 0);
+
+}
diff --git a/src/xml.h b/src/xml.h
new file mode 100644
index 0000000..2d35cc6
--- /dev/null
+++ b/src/xml.h
@@ -0,0 +1,96 @@
+
+/* Firebox Tools - Outils de configurations pour le WM Firebox
+ * xml.h - prototypes pour la lecture ou l'écriture de documents XML
+ *
+ * Copyright (C) 2006-2007 Cyrille Bagard
+ *
+ *  This file is part of Firebox Tools.
+ *
+ *  Firebox Tools 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 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  Firebox Tools 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 this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+
+#ifndef _XML_H
+#define _XML_H
+
+
+#include <stdbool.h>
+#include <glib/gtypes.h>
+#include <libxml/tree.h>
+#include <libxml/xmlwriter.h>
+#include <libxml/xpath.h>
+
+
+
+/* --------------------- OPERATIONS DE LECTURE D'UN FICHIER XML --------------------- */
+
+
+#define XPATH_OBJ_NODES_COUNT(obj) (obj != NULL ? obj->nodesetval->nodeNr : 0)
+#define NODE_FROM_PATH_OBJ(obj, i) obj->nodesetval->nodeTab[i]
+
+
+/* Ouvre un fichier XML de façon encadrée. */
+gboolean open_xml_file(const char *filename, xmlDoc **, xmlNode **, xmlXPathContextPtr *);
+
+/* Obtient de façon encadrée l'accès à un noeud défini. */
+xmlXPathObjectPtr get_node_xpath_object(xmlXPathContextPtr, const char *);
+
+/* Obtient une valeur placée entre <...> et </...>. */
+char *qck_get_node_text_value(xmlNodePtr);
+
+/* Obtient une valeur placée entre <...> et </...>. */
+char *get_node_text_value(xmlXPathContextPtr, const char *);
+
+/* Obtient la valeur d'une propriété d'un élément. */
+char *qck_get_node_prop_value(xmlNodePtr, const char *);
+
+/* Obtient la valeur d'une propriété d'un élément. */
+char *get_node_prop_value(xmlXPathContextPtr, const char *, const char *);
+
+/* Construit un chemin d'accès complet selon le fichier XML. */
+char *qck_build_filename_with_doc_url(xmlNodePtr);
+
+/* Construit un chemin d'accès complet selon le fichier XML. */
+char *build_filename_with_doc_url(xmlXPathContextPtr xpathCtx, const char *path);
+
+
+
+/* --------------------- OPERATIONS D'ECRITURE D'UN FICHIER XML --------------------- */
+
+
+/* Amorce l'écriture d'un nouveau fichier XML. */
+xmlTextWriterPtr start_writing_xml_file(const char *);
+
+/* Met fin à l'écriture d'un nouveau fichier XML. */
+bool end_writing_xml_file(xmlTextWriterPtr);
+
+/* Ecrit une balise et ne la referme pas. */
+bool open_xml_element(xmlTextWriterPtr, const char *);
+
+/* Ferme la dernière balise laissée ouverte. */
+bool close_xml_element(xmlTextWriterPtr);
+
+/* Ecrit une balise avec un contenu textuel. */
+bool write_xml_element_with_content(xmlTextWriterPtr, const char *, const char *, ...);
+
+/* Ecrit un attribut avec un contenu textuel. */
+bool write_xml_attribute(xmlTextWriterPtr, const char *, const char *, ...);
+
+/* Ecrit un contenu textuel. */
+bool write_xml_content(xmlTextWriterPtr, const char *, ...);
+
+
+
+#endif  /* _XML_H */
-- 
cgit v0.11.2-87-g4458