From 5dcc4df15a8d84b214bb3f6f0fcfe30f21cb0972 Mon Sep 17 00:00:00 2001
From: Cyrille Bagard <nocbos@gmail.com>
Date: Thu, 28 May 2020 09:14:16 +0200
Subject: Saved the first steps for a new loading process.

---
 plugins/dex/format.c          |  14 +-
 plugins/elf/format.c          |   9 +-
 src/gui/dialogs/Makefile.am   |   2 +
 src/gui/dialogs/gresource.xml |   1 +
 src/gui/dialogs/loading.c     | 517 ++++++++++++++++++++++++++++++++++++++++++
 src/gui/dialogs/loading.h     |  44 ++++
 src/gui/dialogs/loading.ui    | 320 ++++++++++++++++++++++++++
 src/gui/editor.c              |  15 +-
 8 files changed, 908 insertions(+), 14 deletions(-)
 create mode 100644 src/gui/dialogs/loading.c
 create mode 100644 src/gui/dialogs/loading.h
 create mode 100644 src/gui/dialogs/loading.ui

diff --git a/plugins/dex/format.c b/plugins/dex/format.c
index 84ddb4d..ccf21a8 100644
--- a/plugins/dex/format.c
+++ b/plugins/dex/format.c
@@ -250,6 +250,7 @@ static void g_dex_format_finalize(GDexFormat *format)
 GExeFormat *g_dex_format_new(GBinContent *content)
 {
     GDexFormat *result;                     /* Structure à retourner       */
+    vmpa2t pos;                             /* Position de tête de lecture */
 
     if (!check_dex_format(content))
         return NULL;
@@ -260,6 +261,14 @@ GExeFormat *g_dex_format_new(GBinContent *content)
 
     result->pool = g_dex_pool_new(result);
 
+    init_vmpa(&pos, 0, VMPA_NO_VIRTUAL);
+
+    if (!read_dex_header(result, &pos, &result->header))
+    {
+        g_object_unref(G_OBJECT(result));
+        return NULL;
+    }
+
     return G_EXE_FORMAT(result);
 
 }
@@ -341,11 +350,6 @@ static bool g_dex_format_analyze(GDexFormat *format, wgroup_id_t gid, GtkStatusS
     base = G_BIN_FORMAT(format);
     exe = G_EXE_FORMAT(format);
 
-    init_vmpa(&pos, 0, VMPA_NO_VIRTUAL);
-
-    if (!read_dex_header(format, &pos, &format->header))
-        goto gdfa_error;
-
     /* Vérification des tailles fournies */
 
     size = g_binary_content_compute_size(G_KNOWN_FORMAT(base)->content);
diff --git a/plugins/elf/format.c b/plugins/elf/format.c
index 75b9a6c..9cf48ce 100644
--- a/plugins/elf/format.c
+++ b/plugins/elf/format.c
@@ -255,6 +255,12 @@ GExeFormat *g_elf_format_new(GBinContent *content)
 
     g_known_format_set_content(G_KNOWN_FORMAT(result), content);
 
+    if (!read_elf_header(result, &result->header, &result->is_32b, &result->endian))
+    {
+        g_object_unref(G_OBJECT(result));
+        return NULL;
+    }
+
     return G_EXE_FORMAT(result);
 
 }
@@ -331,9 +337,6 @@ static bool g_elf_format_analyze(GElfFormat *format, wgroup_id_t gid, GtkStatusS
     base = G_BIN_FORMAT(format);
     exe = G_EXE_FORMAT(format);
 
-    if (!read_elf_header(format, &format->header, &format->is_32b, &format->endian))
-        goto error;
-
     /* Vérification des tailles d'entrée de table */
 
     if (ELF_HDR(format, format->header, e_phentsize) != ELF_SIZEOF_PHDR(format))
diff --git a/src/gui/dialogs/Makefile.am b/src/gui/dialogs/Makefile.am
index 575defd..7d3518c 100644
--- a/src/gui/dialogs/Makefile.am
+++ b/src/gui/dialogs/Makefile.am
@@ -7,6 +7,7 @@ UI_FILES =								\
 	bookmark.ui							\
 	export_graph.ui						\
 	identity.ui							\
+	loading.ui							\
 	preferences.ui						\
 	prefs_fgraph.ui						\
 	prefs_labels.ui						\
@@ -21,6 +22,7 @@ libguidialogs_la_SOURCES =				\
 	goto.h goto.c						\
 	gotox.h gotox.c						\
 	identity.h identity.c				\
+	loading.h loading.c					\
 	plugins.h plugins.c					\
 	preferences.h preferences.c			\
 	prefs_fgraph.h prefs_fgraph.c		\
diff --git a/src/gui/dialogs/gresource.xml b/src/gui/dialogs/gresource.xml
index bf81af4..f54d5b4 100644
--- a/src/gui/dialogs/gresource.xml
+++ b/src/gui/dialogs/gresource.xml
@@ -4,6 +4,7 @@
         <file compressed="true">bookmark.ui</file>
         <file compressed="true">export_graph.ui</file>
         <file compressed="true">identity.ui</file>
+        <file compressed="true">loading.ui</file>
         <file compressed="true">preferences.ui</file>
         <file compressed="true">prefs_fgraph.ui</file>
         <file compressed="true">prefs_labels.ui</file>
diff --git a/src/gui/dialogs/loading.c b/src/gui/dialogs/loading.c
new file mode 100644
index 0000000..62992fa
--- /dev/null
+++ b/src/gui/dialogs/loading.c
@@ -0,0 +1,517 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * loading.c - fenêtre de chargement de nouveaux contenus
+ *
+ * Copyright (C) 2020 Cyrille Bagard
+ *
+ *  This file is part of Chrysalide.
+ *
+ *  Chrysalide is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  Chrysalide is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with Chrysalide.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#include "loading.h"
+
+
+#include <assert.h>
+#include <malloc.h>
+#include <stdio.h>
+#include <gdk/gdkkeysyms.h>
+
+
+#include <i18n.h>
+
+
+#include "../../analysis/binary.h"
+#include "../../core/processors.h"
+
+
+
+/* Colonnes de la liste des contenus chargés */
+typedef enum _LoadedContentColumn
+{
+    LCC_NAME,                               /* Désignation humaine         */
+    LCC_CONTENT,                            /* Contenu chargé              */
+    LCC_PROJECT,                            /* Cadre du chargement         */
+    LCC_RECOGNIZED,                       /* Binaire brut ?              */
+
+} LoadedContentColumn;
+
+
+/* Réagit à un changement de sélection des contenus chargés. */
+static void on_loaded_selection_changed(GtkTreeSelection *, GtkBuilder *);
+
+/* Réagit à un changement de mode de chargement. */
+static void on_load_mode_toggled(GtkToggleButton *, GtkBuilder *);
+
+/* Réagit à une pression de la touche "Echappe". */
+static gboolean on_key_press_event(GtkWidget *, GdkEventKey *, GtkBuilder *);
+
+/* Réagit à un clic sur la bouton "Annuler". */
+static void on_cancel_clicked(GtkButton *, GtkBuilder *);
+
+/* Réagit à un clic sur la bouton "Valider". */
+static void on_validate_clicked(GtkButton *, GtkBuilder *);
+
+/* Actualise les moyens affichés dans la boîte de chargement. */
+static void update_loading_dialog(GtkBuilder *);
+
+/* Actualise le décompte des différents types de binaires. */
+static void update_loading_dialog_counter(GtkBuilder *);
+
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : parent = fenêtre principale de l'éditeur.                    *
+*                outb   = constructeur à détruire après usage. [OUT]          *
+*                                                                             *
+*  Description : Construit une boîte de dialogue dédiée aux chargements.      *
+*                                                                             *
+*  Retour      : Adresse de la fenêtre mise en place.                         *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+GtkWidget *create_loading_dialog(GtkWindow *parent, GtkBuilder **outb)
+{
+    GtkWidget *result;                      /* Fenêtre à renvoyer          */
+    GtkBuilder *builder;                    /* Constructeur utilisé        */
+    GtkTreeModelFilter *filter;             /* Modèle filtrant             */
+
+    builder = gtk_builder_new_from_resource("/org/chrysalide/gui/dialogs/loading.ui");
+    *outb = builder;
+
+    result = GTK_WIDGET(gtk_builder_get_object(builder, "window"));
+
+    gtk_window_set_transient_for(GTK_WINDOW(result), parent);
+
+    filter = GTK_TREE_MODEL_FILTER(gtk_builder_get_object(builder, "filtered_store"));
+    gtk_tree_model_filter_set_visible_column(filter, LCC_RECOGNIZED);
+
+    /* Connexion des signaux */
+
+    gtk_builder_add_callback_symbols(builder,
+                                     "on_loaded_selection_changed", G_CALLBACK(on_loaded_selection_changed),
+                                     "on_load_mode_toggled", G_CALLBACK(on_load_mode_toggled),
+                                     "on_key_press_event", G_CALLBACK(on_key_press_event),
+                                     "on_cancel_clicked", G_CALLBACK(on_cancel_clicked),
+                                     "on_validate_clicked", G_CALLBACK(on_validate_clicked),
+                                     NULL);
+
+    gtk_builder_connect_signals(builder, builder);
+
+    return result;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : selection = gestionnaire de sélection impacté.               *
+*                builder   = constructeur à utiliser.                         *
+*                                                                             *
+*  Description : Réagit à un changement de sélection des contenus chargés.    *
+*                                                                             *
+*  Retour      : -                                                            *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static void on_loaded_selection_changed(GtkTreeSelection *selection, GtkBuilder *builder)
+{
+    GtkTreeModel *model;                    /* Modèle de gestion           */
+    GtkTreeIter iter;                       /* Point de sélection          */
+    gboolean state;                         /* Présence d'une sélection    */
+    GtkWidget *widget;                      /* Composant à actualiser      */
+    const char *id;                         /* Identifiant d'architecture  */
+    GLoadedContent *loaded;                 /* Contenu chargé              */
+    GExeFormat *format;                     /* Format binaire reconnu      */
+    GtkComboBox *combobox;                  /* Sélection d'architecture    */
+
+    /* Mise à jour des accès */
+
+    state = gtk_tree_selection_get_selected(selection, &model, &iter);
+
+    widget = GTK_WIDGET(gtk_builder_get_object(builder, "load_all"));
+    gtk_widget_set_sensitive(widget, state);
+
+    widget = GTK_WIDGET(gtk_builder_get_object(builder, "load_one"));
+    gtk_widget_set_sensitive(widget, state);
+
+    on_load_mode_toggled(NULL, builder);
+
+    widget = GTK_WIDGET(gtk_builder_get_object(builder, "ok_button"));
+    gtk_widget_set_sensitive(widget, state);
+
+    /* Mise à jour de l'architecture */
+
+    id = "none";
+
+    if (state)
+    {
+        gtk_tree_model_get(model, &iter, LCC_CONTENT, &loaded, -1);
+
+        if (G_IS_LOADED_BINARY(loaded))
+        {
+            format = g_loaded_binary_get_format(G_LOADED_BINARY(loaded));
+
+            id = g_exe_format_get_target_machine(format);
+
+            g_object_unref(G_OBJECT(format));
+
+        }
+
+        g_object_unref(G_OBJECT(loaded));
+
+    }
+
+    combobox = GTK_COMBO_BOX(gtk_builder_get_object(builder, "arch_sel"));
+
+    gtk_combo_box_set_active_id(combobox, id);
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : button  = bouton à l'origine de la procédure.                *
+*                builder = espace de référencement global.                    *
+*                                                                             *
+*  Description : Réagit à un changement de mode de chargement.                *
+*                                                                             *
+*  Retour      : -                                                            *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static void on_load_mode_toggled(GtkToggleButton *button, GtkBuilder *builder)
+{
+    GtkToggleButton *all_button;            /* Selection de mode           */
+    gboolean state;                         /* Chargement fin ?            */
+    GtkTreeView *treeview;                  /* Vue en arboresence          */
+    GtkTreeSelection *selection;            /* Sélection associée          */
+    GtkWidget *widget;                      /* Composant à actualiser      */
+
+    all_button = GTK_TOGGLE_BUTTON(gtk_builder_get_object(builder, "load_all"));
+
+    state = !gtk_toggle_button_get_active(all_button);
+
+    if (state)
+    {
+        treeview = GTK_TREE_VIEW(gtk_builder_get_object(builder, "treeview"));
+        selection = gtk_tree_view_get_selection(treeview);
+
+        state = gtk_tree_selection_get_selected(selection, NULL, NULL);
+
+    }
+
+    widget = GTK_WIDGET(gtk_builder_get_object(builder, "arch_label"));
+    gtk_widget_set_sensitive(widget, state);
+
+    widget = GTK_WIDGET(gtk_builder_get_object(builder, "arch_sel"));
+    gtk_widget_set_sensitive(widget, state);
+
+    widget = GTK_WIDGET(gtk_builder_get_object(builder, "config_and_run"));
+    gtk_widget_set_sensitive(widget, state);
+
+    widget = GTK_WIDGET(gtk_builder_get_object(builder, "process_remaining"));
+    gtk_widget_set_sensitive(widget, state);
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : widget  = composant graphique visé par la procédure.         *
+*                event   = informations liées à l'événement.                  *
+*                builder = espace de référencement global.                    *
+*                                                                             *
+*  Description : Réagit à une pression de la touche "Echappe".                *
+*                                                                             *
+*  Retour      : TRUE pour indiquer une prise en compte, FALSE sinon.         *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static gboolean on_key_press_event(GtkWidget *widget, GdkEventKey *event, GtkBuilder *builder)
+{
+    gboolean result;                        /* Bilan à retourner           */
+
+    if (event->keyval == GDK_KEY_Escape)
+    {
+        on_cancel_clicked(NULL, builder);
+        result = TRUE;
+    }
+
+    else
+        result = FALSE;
+
+    return result;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : button  = bouton à l'origine de la procédure.                *
+*                builder = espace de référencement global.                    *
+*                                                                             *
+*  Description : Réagit à un clic sur la bouton "Annuler".                    *
+*                                                                             *
+*  Retour      : -                                                            *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static void on_cancel_clicked(GtkButton *button, GtkBuilder *builder)
+{
+    GtkWidget *window;                      /* Fenêtre à cacher            */
+
+
+
+
+    /* Disparition de la fenêtre */
+
+    window = GTK_WIDGET(gtk_builder_get_object(builder, "window"));
+
+    gtk_widget_hide(window);
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : button  = bouton à l'origine de la procédure.                *
+*                builder = espace de référencement global.                    *
+*                                                                             *
+*  Description : Réagit à un clic sur la bouton "Valider".                    *
+*                                                                             *
+*  Retour      : -                                                            *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static void on_validate_clicked(GtkButton *button, GtkBuilder *builder)
+{
+    GtkTreeView *treeview;                  /* Vue en arboresence          */
+    GtkTreeSelection *selection;            /* Sélection associée          */
+    GtkTreeModel *model;                    /* Modèle de gestion           */
+    GtkTreeIter iter;                       /* Point de sélection          */
+    GLoadedContent *loaded;                 /* Contenu chargé              */
+    GStudyProject *project;                 /* projet associé              */
+
+    treeview = GTK_TREE_VIEW(gtk_builder_get_object(builder, "treeview"));
+    selection = gtk_tree_view_get_selection(treeview);
+
+    if (gtk_tree_selection_get_selected(selection, &model, &iter))
+    {
+        gtk_tree_model_get(model, &iter, LCC_CONTENT, &loaded, LCC_PROJECT, &project, -1);
+
+        g_signal_connect(loaded, "analyzed", G_CALLBACK(on_loaded_content_analyzed), project);
+
+        g_loaded_content_analyze(loaded, true, true);
+
+        g_object_unref(G_OBJECT(loaded));
+
+    }
+
+
+
+    /* Disparition de la fenêtre ? */
+
+    if (true)
+        on_cancel_clicked(NULL, builder);
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : builder = constructeur à utiliser.                           *
+*                                                                             *
+*  Description : Actualise les moyens affichés dans la boîte de chargement.   *
+*                                                                             *
+*  Retour      : -                                                            *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static void update_loading_dialog(GtkBuilder *builder)
+{
+    GtkComboBoxText *combobox;              /* Sélection d'architecture    */
+    char **keys;                            /* Liste des architectures     */
+    size_t count;                           /* Taille de cette liste       */
+    size_t i;                               /* Boucle de parcours          */
+    GArchProcessor *proc;                   /* Processeur à consulter      */
+    char *desc;                             /* Description humaine         */
+
+    /* Mise à jour de la liste des architectures */
+
+    combobox = GTK_COMBO_BOX_TEXT(gtk_builder_get_object(builder, "arch_sel"));
+
+    gtk_combo_box_text_remove_all(combobox);
+
+    gtk_combo_box_text_append(combobox, "none", _("None"));
+
+    keys = get_all_processor_keys(&count);
+
+    for (i = 0; i < count; i++)
+    {
+        proc = get_arch_processor_for_key(keys[i]);
+
+        desc = g_arch_processor_get_desc(proc);
+
+        gtk_combo_box_text_append(combobox, keys[i], desc);
+
+        g_object_unref(G_OBJECT(proc));
+        free(keys[i]);
+
+    }
+
+    if (keys != NULL)
+        free(keys);
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : builder = constructeur à utiliser.                           *
+*                                                                             *
+*  Description : Actualise le décompte des différents types de binaires.      *
+*                                                                             *
+*  Retour      : -                                                            *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static void update_loading_dialog_counter(GtkBuilder *builder)
+{
+
+    unsigned int recognized_counter;        /* Compteur de reconnus        */
+    unsigned int total_counter;             /* Compteur de binaires        */
+    GtkTreeModel *model;                    /* Modèle de gestion           */
+    GtkTreeIter iter;                       /* Point de sélection          */
+    gboolean valid;                         /* Validité de l'itérateur     */
+    gboolean recognized;                    /* Nature du contenu           */
+    char *msg;                              /* Message à faire apparaître  */
+    GtkLabel *label;                        /* Etiquette à mettre à jour   */
+
+    recognized_counter = 0;
+    total_counter = 0;
+
+    model = GTK_TREE_MODEL(gtk_builder_get_object(builder, "store"));
+
+    for (valid = gtk_tree_model_get_iter_first(model, &iter);
+         valid;
+         valid = gtk_tree_model_iter_next(model, &iter))
+    {
+        gtk_tree_model_get(model, &iter, LCC_RECOGNIZED, &recognized, -1);
+
+        if (recognized)
+            recognized_counter++;
+
+        total_counter++;
+
+    }
+
+    asprintf(&msg, "(%u / %u)", total_counter - recognized_counter, total_counter);
+
+    label = GTK_LABEL(gtk_builder_get_object(builder, "hidden_counter"));
+    gtk_label_set_text(label, msg);
+
+    free(msg);
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : builder = constructeur à utiliser.                           *
+*                content = nouveau contenu chargé à intégrer.                 *
+*                project = project impliqué dans l'opération.                 *
+*                                                                             *
+*  Description : Ajoute un binaire à la liste à charger.                      *
+*                                                                             *
+*  Retour      : -                                                            *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+void add_content_to_loading_dialog(GtkBuilder *builder, GLoadedContent *content, GStudyProject *project)
+{
+    GtkListStore *store;                    /* Modèle de gestion           */
+    char *name;                             /* Désignation complète        */
+    gboolean recognized;                    /* Nature du contenu           */
+    GtkTreeIter iter;                       /* Point d'insertion           */
+    GtkTreeView *treeview;                  /* Vue en arboresence          */
+    GtkTreeSelection *selection;            /* Gestionnaire de sélection   */
+    GtkTreeModelFilter *filter;             /* Modèle filtrant             */
+    GtkTreeIter filtered_iter;              /* Point d'insertion           */
+    gboolean status;                        /* Bilan d'une conversion      */
+
+    /* Mise à jour de l'interface (#0) */
+
+    update_loading_dialog(builder);
+
+    /* Inscription */
+
+    asprintf(&name, "%s (%s)",
+             g_loaded_content_describe(content, false),
+             g_loaded_content_get_format_name(content));
+
+    recognized = TRUE;
+
+    store = GTK_LIST_STORE(gtk_builder_get_object(builder, "store"));
+
+    gtk_list_store_append(store, &iter);
+    gtk_list_store_set(store, &iter,
+                       LCC_NAME, name,
+                       LCC_CONTENT, content,
+                       LCC_PROJECT, project,
+                       LCC_RECOGNIZED, recognized,
+                       -1);
+
+    free(name);
+
+    treeview = GTK_TREE_VIEW(gtk_builder_get_object(builder, "treeview"));
+    selection = gtk_tree_view_get_selection(treeview);
+
+    if (!gtk_tree_selection_get_selected(selection, NULL, NULL))
+    {
+        filter = GTK_TREE_MODEL_FILTER(gtk_builder_get_object(builder, "filtered_store"));
+
+        status = gtk_tree_model_filter_convert_child_iter_to_iter(filter, &filtered_iter, &iter);
+        assert(status);
+
+        if (status)
+            gtk_tree_selection_select_iter(selection, &filtered_iter);
+
+    }
+
+    /* Mise à jour de l'interface (#1) */
+
+    update_loading_dialog_counter(builder);
+
+}
diff --git a/src/gui/dialogs/loading.h b/src/gui/dialogs/loading.h
new file mode 100644
index 0000000..71f84f4
--- /dev/null
+++ b/src/gui/dialogs/loading.h
@@ -0,0 +1,44 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * loading.h - prototypes pour la fenêtre de chargement de nouveaux contenus
+ *
+ * Copyright (C) 2020 Cyrille Bagard
+ *
+ *  This file is part of Chrysalide.
+ *
+ *  Chrysalide is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  Chrysalide is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with Chrysalide.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#ifndef _GUI_DIALOGS_LOADING_H
+#define _GUI_DIALOGS_LOADING_H
+
+
+#include <gtk/gtk.h>
+
+
+#include "../../analysis/loaded.h"
+#include "../../analysis/project.h"
+
+
+
+/* Construit une boîte de dialogue dédiée aux chargements. */
+GtkWidget *create_loading_dialog(GtkWindow *, GtkBuilder **);
+
+/* Ajoute un binaire à la liste à charger. */
+void add_content_to_loading_dialog(GtkBuilder *, GLoadedContent *, GStudyProject *);
+
+
+
+#endif  /* _GUI_DIALOGS_LOADING_H */
diff --git a/src/gui/dialogs/loading.ui b/src/gui/dialogs/loading.ui
new file mode 100644
index 0000000..a9ec7aa
--- /dev/null
+++ b/src/gui/dialogs/loading.ui
@@ -0,0 +1,320 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Generated with glade 3.22.1 -->
+<interface>
+  <requires lib="gtk+" version="3.20"/>
+  <object class="GtkListStore" id="store">
+    <columns>
+      <!-- column-name name -->
+      <column type="gchararray"/>
+      <!-- column-name content -->
+      <column type="GObject"/>
+      <!-- column-name project -->
+      <column type="GObject"/>
+      <!-- column-name unrecognized -->
+      <column type="gboolean"/>
+    </columns>
+  </object>
+  <object class="GtkTreeModelFilter" id="filtered_store">
+    <property name="child_model">store</property>
+  </object>
+  <object class="GtkWindow" id="window">
+    <property name="can_focus">False</property>
+    <property name="title" translatable="yes">New loading</property>
+    <property name="modal">True</property>
+    <property name="window_position">center</property>
+    <property name="default_width">540</property>
+    <property name="default_height">430</property>
+    <signal name="delete-event" handler="gtk_widget_hide_on_delete" swapped="no"/>
+    <signal name="key-press-event" handler="on_key_press_event" swapped="no"/>
+    <child>
+      <placeholder/>
+    </child>
+    <child>
+      <object class="GtkBox">
+        <property name="visible">True</property>
+        <property name="can_focus">False</property>
+        <property name="margin_left">8</property>
+        <property name="margin_right">8</property>
+        <property name="margin_top">8</property>
+        <property name="margin_bottom">8</property>
+        <property name="orientation">vertical</property>
+        <property name="spacing">8</property>
+        <child>
+          <object class="GtkFrame">
+            <property name="visible">True</property>
+            <property name="can_focus">False</property>
+            <property name="label_xalign">0</property>
+            <property name="shadow_type">none</property>
+            <child>
+              <object class="GtkAlignment">
+                <property name="visible">True</property>
+                <property name="can_focus">False</property>
+                <property name="left_padding">12</property>
+                <child>
+                  <object class="GtkBox">
+                    <property name="visible">True</property>
+                    <property name="can_focus">False</property>
+                    <property name="orientation">vertical</property>
+                    <property name="spacing">4</property>
+                    <child>
+                      <object class="GtkScrolledWindow">
+                        <property name="visible">True</property>
+                        <property name="can_focus">True</property>
+                        <property name="shadow_type">in</property>
+                        <child>
+                          <object class="GtkTreeView" id="treeview">
+                            <property name="visible">True</property>
+                            <property name="can_focus">True</property>
+                            <property name="model">filtered_store</property>
+                            <property name="headers_visible">False</property>
+                            <property name="reorderable">True</property>
+                            <child internal-child="selection">
+                              <object class="GtkTreeSelection">
+                                <signal name="changed" handler="on_loaded_selection_changed" swapped="no"/>
+                              </object>
+                            </child>
+                            <child>
+                              <object class="GtkTreeViewColumn">
+                                <property name="title" translatable="yes">column</property>
+                                <child>
+                                  <object class="GtkCellRendererText"/>
+                                  <attributes>
+                                    <attribute name="text">0</attribute>
+                                  </attributes>
+                                </child>
+                              </object>
+                            </child>
+                          </object>
+                        </child>
+                      </object>
+                      <packing>
+                        <property name="expand">True</property>
+                        <property name="fill">True</property>
+                        <property name="position">0</property>
+                      </packing>
+                    </child>
+                    <child>
+                      <object class="GtkBox">
+                        <property name="visible">True</property>
+                        <property name="can_focus">False</property>
+                        <child>
+                          <object class="GtkCheckButton" id="hide_unrecognized">
+                            <property name="label" translatable="yes">Hide unrecognized contents</property>
+                            <property name="visible">True</property>
+                            <property name="can_focus">True</property>
+                            <property name="receives_default">False</property>
+                            <property name="active">True</property>
+                            <property name="draw_indicator">True</property>
+                          </object>
+                          <packing>
+                            <property name="expand">False</property>
+                            <property name="fill">True</property>
+                            <property name="position">0</property>
+                          </packing>
+                        </child>
+                        <child>
+                          <object class="GtkLabel" id="hidden_counter">
+                            <property name="visible">True</property>
+                            <property name="can_focus">False</property>
+                            <property name="label" translatable="yes">(0 / 0)</property>
+                          </object>
+                          <packing>
+                            <property name="expand">False</property>
+                            <property name="fill">True</property>
+                            <property name="position">1</property>
+                          </packing>
+                        </child>
+                      </object>
+                      <packing>
+                        <property name="expand">False</property>
+                        <property name="fill">True</property>
+                        <property name="position">1</property>
+                      </packing>
+                    </child>
+                  </object>
+                </child>
+              </object>
+            </child>
+            <child type="label">
+              <object class="GtkLabel">
+                <property name="visible">True</property>
+                <property name="can_focus">False</property>
+                <property name="label" translatable="yes">Available contents</property>
+              </object>
+            </child>
+          </object>
+          <packing>
+            <property name="expand">True</property>
+            <property name="fill">True</property>
+            <property name="position">0</property>
+          </packing>
+        </child>
+        <child>
+          <object class="GtkRadioButton" id="load_all">
+            <property name="label" translatable="yes">Load all contents at once with default options</property>
+            <property name="visible">True</property>
+            <property name="can_focus">True</property>
+            <property name="receives_default">False</property>
+            <property name="margin_top">8</property>
+            <property name="active">True</property>
+            <property name="draw_indicator">True</property>
+            <signal name="toggled" handler="on_load_mode_toggled" swapped="no"/>
+          </object>
+          <packing>
+            <property name="expand">False</property>
+            <property name="fill">True</property>
+            <property name="position">1</property>
+          </packing>
+        </child>
+        <child>
+          <object class="GtkRadioButton" id="load_one">
+            <property name="label" translatable="yes">Load one content with specific options</property>
+            <property name="visible">True</property>
+            <property name="can_focus">True</property>
+            <property name="receives_default">False</property>
+            <property name="active">True</property>
+            <property name="draw_indicator">True</property>
+            <property name="group">load_all</property>
+          </object>
+          <packing>
+            <property name="expand">False</property>
+            <property name="fill">True</property>
+            <property name="position">2</property>
+          </packing>
+        </child>
+        <child>
+          <object class="GtkAlignment">
+            <property name="visible">True</property>
+            <property name="can_focus">False</property>
+            <property name="left_padding">24</property>
+            <child>
+              <object class="GtkBox">
+                <property name="visible">True</property>
+                <property name="can_focus">False</property>
+                <property name="orientation">vertical</property>
+                <property name="spacing">8</property>
+                <child>
+                  <object class="GtkBox">
+                    <property name="visible">True</property>
+                    <property name="can_focus">False</property>
+                    <property name="spacing">8</property>
+                    <child>
+                      <object class="GtkLabel" id="arch_label">
+                        <property name="visible">True</property>
+                        <property name="sensitive">False</property>
+                        <property name="can_focus">False</property>
+                        <property name="label" translatable="yes">Set architecture:</property>
+                      </object>
+                      <packing>
+                        <property name="expand">False</property>
+                        <property name="fill">True</property>
+                        <property name="position">0</property>
+                      </packing>
+                    </child>
+                    <child>
+                      <object class="GtkComboBoxText" id="arch_sel">
+                        <property name="visible">True</property>
+                        <property name="sensitive">False</property>
+                        <property name="can_focus">False</property>
+                      </object>
+                      <packing>
+                        <property name="expand">True</property>
+                        <property name="fill">True</property>
+                        <property name="position">1</property>
+                      </packing>
+                    </child>
+                  </object>
+                  <packing>
+                    <property name="expand">False</property>
+                    <property name="fill">True</property>
+                    <property name="position">0</property>
+                  </packing>
+                </child>
+                <child>
+                  <object class="GtkCheckButton" id="config_and_run">
+                    <property name="label" translatable="yes">Configure and run the analysis</property>
+                    <property name="visible">True</property>
+                    <property name="sensitive">False</property>
+                    <property name="can_focus">True</property>
+                    <property name="receives_default">False</property>
+                    <property name="active">True</property>
+                    <property name="draw_indicator">True</property>
+                  </object>
+                  <packing>
+                    <property name="expand">False</property>
+                    <property name="fill">True</property>
+                    <property name="position">1</property>
+                  </packing>
+                </child>
+                <child>
+                  <object class="GtkCheckButton" id="process_remaining">
+                    <property name="label" translatable="yes">Process the remaining contents</property>
+                    <property name="visible">True</property>
+                    <property name="can_focus">True</property>
+                    <property name="receives_default">False</property>
+                    <property name="active">True</property>
+                    <property name="draw_indicator">True</property>
+                  </object>
+                  <packing>
+                    <property name="expand">False</property>
+                    <property name="fill">True</property>
+                    <property name="position">2</property>
+                  </packing>
+                </child>
+              </object>
+            </child>
+          </object>
+          <packing>
+            <property name="expand">False</property>
+            <property name="fill">True</property>
+            <property name="position">3</property>
+          </packing>
+        </child>
+        <child>
+          <object class="GtkButtonBox">
+            <property name="visible">True</property>
+            <property name="can_focus">False</property>
+            <property name="spacing">8</property>
+            <property name="layout_style">end</property>
+            <child>
+              <object class="GtkButton">
+                <property name="label">gtk-cancel</property>
+                <property name="visible">True</property>
+                <property name="can_focus">True</property>
+                <property name="receives_default">True</property>
+                <property name="use_stock">True</property>
+                <signal name="clicked" handler="on_cancel_clicked" swapped="no"/>
+              </object>
+              <packing>
+                <property name="expand">True</property>
+                <property name="fill">True</property>
+                <property name="position">0</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkButton" id="ok_button">
+                <property name="label">gtk-ok</property>
+                <property name="visible">True</property>
+                <property name="can_focus">True</property>
+                <property name="has_focus">True</property>
+                <property name="receives_default">True</property>
+                <property name="use_stock">True</property>
+                <signal name="clicked" handler="on_validate_clicked" swapped="no"/>
+              </object>
+              <packing>
+                <property name="expand">True</property>
+                <property name="fill">True</property>
+                <property name="position">1</property>
+              </packing>
+            </child>
+          </object>
+          <packing>
+            <property name="expand">False</property>
+            <property name="fill">True</property>
+            <property name="position">4</property>
+          </packing>
+        </child>
+      </object>
+    </child>
+  </object>
+</interface>
diff --git a/src/gui/editor.c b/src/gui/editor.c
index f45acbd..bdd9a78 100644
--- a/src/gui/editor.c
+++ b/src/gui/editor.c
@@ -36,6 +36,7 @@
 
 #include "agroup.h"
 #include "status.h"
+#include "dialogs/loading.h"
 #include "menus/file.h"
 #include "menus/menubar.h"
 #include "core/core.h"
@@ -59,7 +60,9 @@
 
 
 
-
+/* Fenêtre de chargement de binaires */
+static GtkWidget *_load_dialog = NULL;
+static GtkBuilder *_load_dialog_builder = NULL;
 
 
 
@@ -308,7 +311,9 @@ GtkWidget *create_editor(void)
     change_editor_items_current_content(NULL);
     change_editor_items_current_view(NULL);
 
+    /* Préparation des fenêtres complémentaires */
 
+    _load_dialog = create_loading_dialog(GTK_WINDOW(result), &_load_dialog_builder);
 
     return result;
 
@@ -323,7 +328,7 @@ GtkWidget *create_editor(void)
 *                                                                             *
 *  Description : Quitte le programme en sortie de la boucle de GTK.           *
 *                                                                             *
-*  Retour      : -                                                            *
+*  Retour      : TRUE pour éviter la fermeture, FALSE sinon.                  *
 *                                                                             *
 *  Remarques   : -                                                            *
 *                                                                             *
@@ -897,11 +902,9 @@ static void notify_editor_project_change(GStudyProject *project, bool new)
 
 static void on_editor_content_available(GStudyProject *project, GLoadedContent *content, void *unused)
 {
-    g_object_ref(G_OBJECT(content));
-
-    g_signal_connect(content, "analyzed", G_CALLBACK(on_loaded_content_analyzed), project);
+    add_content_to_loading_dialog(_load_dialog_builder, content, project);
 
-    g_loaded_content_analyze(content, true, true);
+    gtk_widget_show(_load_dialog);
 
 }
 
-- 
cgit v0.11.2-87-g4458