/* Chrysalide - Outil d'analyse de fichiers binaires * bintree.c - panneau d'accueil par défaut * * Copyright (C) 2017-2019 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 this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "bintree.h" #include #include #include #include #include "updating-int.h" #include "../agroup.h" #include "../panel-int.h" #include "../core/global.h" #include "../../core/queue.h" #include "../../gtkext/easygtk.h" #include "../../gtkext/gtkdisplaypanel.h" #include "../../gtkext/named.h" #include "../../gtkext/tmgt.h" /* -------------------------- PARTIE PRINCIPALE DU PANNEAU -------------------------- */ /* Origine de la dernière ouverture/fermeture reproductible */ typedef enum _UserActionType { UAT_COLLAPSE, /* Fermeture totale */ UAT_EXPAND, /* Ouverture totale */ UAT_DEPTH, /* Descente contrôlée */ } UserActionType; /* Panneau de présentation des portions (instance) */ struct _GBintreePanel { GPanelItem parent; /* A laisser en premier */ GLoadedBinary *binary; /* Binaire représenté */ UserActionType last; /* Dernière action */ size_t count; /* Quantité de portions utiles */ }; /* Panneau de présentation des portions (classe) */ struct _GBintreePanelClass { GPanelItemClass parent; /* A laisser en premier */ }; /* Colonnes de la liste des messages */ typedef enum _BinaryTreeColumn { BTC_PORTION, /* Elément interne représenté */ BTC_ICON, /* Image de représentation */ BTC_CAPTION, /* Désignation de l'élément */ BTC_START, /* Position de départ */ BTC_END, /* Position d'arrivée */ BTC_RIGHTS, /* Droits d'accès */ BTC_MATCHED, /* Correspondance établie ? */ BTC_MATCH_POINTS, /* Nombre de demandeurs */ BTC_COUNT /* Nombre de colonnes */ } BinaryTreeColumn; /* Données utiles à la mise à jour */ typedef struct _bintree_update_data bintree_update_data; /* Initialise la classe des panneaux d'affichage des portions. */ static void g_bintree_panel_class_init(GBintreePanelClass *); /* Initialise une instance de panneau d'affichage des portions. */ static void g_bintree_panel_init(GBintreePanel *); /* Procède à l'initialisation de l'interface de mise à jour. */ static void g_bintree_panel_updatable_interface_init(GUpdatablePanelInterface *); /* Supprime toutes les références externes. */ static void g_bintree_panel_dispose(GBintreePanel *); /* Procède à la libération totale de la mémoire. */ static void g_bintree_panel_finalize(GBintreePanel *); /* Fournit le nom interne attribué à l'élément réactif. */ static char *g_bintree_panel_class_get_key(const GBintreePanelClass *); /* Indique le chemin initial de la localisation d'un panneau. */ static char *g_bintree_panel_class_get_path(const GBintreePanelClass *); /* Modifie la profondeur affichée des portions présentes. */ static void on_depth_spin_value_changed(GtkSpinButton *, const GBintreePanel *); /* Réagit au changement de sélection des portions. */ static void on_bintree_selection_changed(GtkTreeSelection *, gpointer); /* Réagit à un changement d'affichage principal de contenu. */ static void change_bintree_panel_current_content(GBintreePanel *, GLoadedContent *, GLoadedContent *); /* -------------------------- AFFICHAGE SOUS FORME D'ARBRE -------------------------- */ /* Parcourt un ensemble de portions. */ static bool populate_tree_with_portion(GBinPortion *, GBinPortion *, BinaryPortionVisit, bintree_update_data *); /* Réagit à un changement d'affichage principal de contenu. */ static void reload_portions_for_new_tree_view(const GBintreePanel *, GtkStatusStack *, activity_id_t, bintree_update_data *); /* Met en surbrillance les éléments recherchés dans les noms. */ static void update_bintree_column_in_tree_view(GtkTreeStore *, GtkTreeIter *, GBinPortion *, BinaryTreeColumn, const regmatch_t *); /* ------------------------- FILTRAGE DES SYMBOLES PRESENTS ------------------------- */ /* Prend note du changement de filtre sur les portions. */ static void on_search_entry_changed(GtkSearchEntry *, GBintreePanel *); /* Détermine si un noeud de l'arborescence doit être filtré. */ static bool update_bintree_node(const bintree_update_data *, GtkTreeStore *, GtkTreeIter *, GBinPortion *); /* Exécute un nouveau filtrage des symboles affichés. */ static void do_filtering_on_portions(const GBintreePanel *, GtkStatusStack *, activity_id_t, bintree_update_data *); /* ---------------------- MECANISMES DE MISE A JOUR DE PANNEAU ---------------------- */ /* Données utiles à la mise à jour */ struct _bintree_update_data { size_t count; /* Qté d'inscriptions réalisées*/ regex_t *filter; /* Filtre appliqué ou NULL */ char **expanded; /* Chemins des noeuds ouverts */ size_t ecount; /* Nombre de ces chemins */ size_t eallocated; /* Espace alloué effectivement */ const GBintreePanel *panel; /* Transfert de panneau */ GtkTreeIter *top; /* Transfert de racine */ GtkStatusStack *status; /* Transfert de statut */ activity_id_t id; /* Transfert d'activité */ }; #define EXPAND_ALLOC_RANGE 10 /* Détermine si une valeur de portion doit être filtrée ou non. */ static bool is_bintree_column_matching(const bintree_update_data *, GBinPortion *, gint, regmatch_t *); /* Prépare une opération de mise à jour de panneau. */ static const char *g_bintree_panel_setup(const GBintreePanel *, unsigned int, size_t *, bintree_update_data **); /* Bascule l'affichage d'un panneau avant mise à jour. */ static void g_bintree_panel_introduce(const GBintreePanel *, unsigned int, bintree_update_data *); /* Réalise une opération de mise à jour de panneau. */ static void g_bintree_panel_process(const GBintreePanel *, unsigned int, GtkStatusStack *, activity_id_t, bintree_update_data *); /* Bascule l'affichage d'un panneau après mise à jour. */ static void g_bintree_panel_conclude(GBintreePanel *, unsigned int, bintree_update_data *); /* Supprime les données dynamiques utilisées à la mise à jour. */ static void g_bintree_panel_clean_data(GUpdatablePanel *, unsigned int, bintree_update_data *); /* ---------------------------------------------------------------------------------- */ /* PARTIE PRINCIPALE DU PANNEAU */ /* ---------------------------------------------------------------------------------- */ /* Indique le type défini pour un panneau d'affichage des portions. */ G_DEFINE_TYPE_WITH_CODE(GBintreePanel, g_bintree_panel, G_TYPE_PANEL_ITEM, G_IMPLEMENT_INTERFACE(G_TYPE_UPDATABLE_PANEL, g_bintree_panel_updatable_interface_init)); /****************************************************************************** * * * Paramètres : class = classe à initialiser. * * * * Description : Initialise la classe des panneaux d'affichage des portions. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ static void g_bintree_panel_class_init(GBintreePanelClass *class) { GObjectClass *object; /* Autre version de la classe */ GEditorItemClass *item; /* Encore une autre vision... */ GPanelItemClass *panel; /* Version parente de la classe*/ object = G_OBJECT_CLASS(class); object->dispose = (GObjectFinalizeFunc/* ! */)g_bintree_panel_dispose; object->finalize = (GObjectFinalizeFunc)g_bintree_panel_finalize; item = G_EDITOR_ITEM_CLASS(class); item->get_key = (get_item_key_fc)g_bintree_panel_class_get_key; item->change_content = (change_item_content_fc)change_bintree_panel_current_content; panel = G_PANEL_ITEM_CLASS(class); panel->get_path = (get_panel_path_fc)g_bintree_panel_class_get_path; panel->gid = setup_tiny_global_work_group(1); } /****************************************************************************** * * * Paramètres : panel = instance à initialiser. * * * * Description : Initialise une instance de panneau d'affichage des portions. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ static void g_bintree_panel_init(GBintreePanel *panel) { GPanelItem *pitem; /* Version parente du panneau */ GtkBuilder *builder; /* Constructeur utilisé */ GtkTreeView *treeview; /* Affichage de la liste */ GtkCellRenderer *renderer; /* Moteur de rendu de colonne */ GtkTreeViewColumn *column; /* Colonne de la liste */ /* Eléments de base */ pitem = G_PANEL_ITEM(panel); pitem->widget = G_NAMED_WIDGET(gtk_built_named_widget_new_for_panel(_("Binary tree"), _("Tree of the binary layout"), PANEL_BINTREE_ID)); /* Compléments propres */ panel->binary = NULL; panel->last = UAT_EXPAND; /* Représentation graphique */ builder = gtk_built_named_widget_get_builder(GTK_BUILT_NAMED_WIDGET(pitem->widget)); /* Liste des portions binaires */ treeview = GTK_TREE_VIEW(gtk_builder_get_object(builder, "treeview")); column = gtk_tree_view_column_new(); gtk_tree_view_append_column(treeview, column); gtk_tree_view_set_expander_column(treeview, column); renderer = gtk_cell_renderer_pixbuf_new(); gtk_tree_view_column_pack_start(column, renderer, FALSE); gtk_tree_view_column_add_attribute(column, renderer, "surface", BTC_ICON); renderer = gtk_cell_renderer_text_new(); gtk_tree_view_column_pack_start(column, renderer, TRUE); gtk_tree_view_column_add_attribute(column, renderer, "markup", BTC_CAPTION); column = gtk_tree_view_column_new(); gtk_tree_view_append_column(treeview, column); renderer = gtk_cell_renderer_text_new(); g_object_set(G_OBJECT(renderer), "xalign", 1.0, NULL); gtk_tree_view_column_pack_start(column, renderer, TRUE); gtk_tree_view_column_add_attribute(column, renderer, "markup", BTC_START); column = gtk_tree_view_column_new(); gtk_tree_view_append_column(treeview, column); renderer = gtk_cell_renderer_text_new(); g_object_set(G_OBJECT(renderer), "xalign", 1.0, NULL); gtk_tree_view_column_pack_start(column, renderer, TRUE); gtk_tree_view_column_add_attribute(column, renderer, "markup", BTC_END); column = gtk_tree_view_column_new(); gtk_tree_view_append_column(treeview, column); renderer = gtk_cell_renderer_text_new(); gtk_tree_view_column_pack_start(column, renderer, TRUE); gtk_tree_view_column_add_attribute(column, renderer, "markup", BTC_RIGHTS); /* Connexion des signaux */ gtk_builder_add_callback_symbols(builder, BUILDER_CALLBACK(gtk_tree_view_collapse_all), BUILDER_CALLBACK(gtk_tree_view_expand_all), BUILDER_CALLBACK(on_depth_spin_value_changed), BUILDER_CALLBACK(on_search_entry_changed), BUILDER_CALLBACK(on_bintree_selection_changed), NULL); gtk_builder_connect_signals(builder, panel); g_object_unref(G_OBJECT(builder)); } /****************************************************************************** * * * Paramètres : iface = interface GLib à initialiser. * * * * Description : Procède à l'initialisation de l'interface de mise à jour. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ static void g_bintree_panel_updatable_interface_init(GUpdatablePanelInterface *iface) { iface->setup = (setup_updatable_cb)g_bintree_panel_setup; iface->get_group = (get_updatable_group_cb)g_panel_item_get_group; iface->introduce = (introduce_updatable_cb)g_bintree_panel_introduce; iface->process = (process_updatable_cb)g_bintree_panel_process; iface->conclude = (conclude_updatable_cb)g_bintree_panel_conclude; iface->clean = (clean_updatable_data_cb)g_bintree_panel_clean_data; } /****************************************************************************** * * * Paramètres : panel = instance d'objet GLib à traiter. * * * * Description : Supprime toutes les références externes. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ static void g_bintree_panel_dispose(GBintreePanel *panel) { if (panel->binary != NULL) g_object_unref(G_OBJECT(panel->binary)); G_OBJECT_CLASS(g_bintree_panel_parent_class)->dispose(G_OBJECT(panel)); } /****************************************************************************** * * * Paramètres : panel = instance d'objet GLib à traiter. * * * * Description : Procède à la libération totale de la mémoire. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ static void g_bintree_panel_finalize(GBintreePanel *panel) { G_OBJECT_CLASS(g_bintree_panel_parent_class)->finalize(G_OBJECT(panel)); } /****************************************************************************** * * * Paramètres : class = classe à consulter. * * * * Description : Fournit le nom interne attribué à l'élément réactif. * * * * Retour : Désignation (courte) de l'élément de l'éditeur. * * * * Remarques : - * * * ******************************************************************************/ static char *g_bintree_panel_class_get_key(const GBintreePanelClass *class) { char *result; /* Description à renvoyer */ result = strdup(PANEL_BINTREE_ID); return result; } /****************************************************************************** * * * Paramètres : class = classe à consulter. * * * * Description : Indique le chemin initial de la localisation d'un panneau. * * * * Retour : Chemin fixé associé à la position initiale. * * * * Remarques : - * * * ******************************************************************************/ static char *g_bintree_panel_class_get_path(const GBintreePanelClass *class) { char *result; /* Emplacement à retourner */ result = strdup("MEN"); return result; } /****************************************************************************** * * * Paramètres : - * * * * Description : Crée un panneau présentant l'arborescence des portions. * * * * Retour : Adresse de la structure mise en place. * * * * Remarques : - * * * ******************************************************************************/ GPanelItem *g_bintree_panel_new(void) { GBintreePanel *result; /* Structure à retourner */ result = g_object_new(G_TYPE_BINTREE_PANEL, NULL); return G_PANEL_ITEM(result); } /****************************************************************************** * * * Paramètres : button = bouton de réglage de l'affichage. * * treeview = arborescence dont l'affichage est à moduler. * * * * Description : Modifie la profondeur affichée des portions présentes. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ static void on_depth_spin_value_changed(GtkSpinButton *button, const GBintreePanel *panel) { gint max_depth; /* Profondeur maximale */ GtkBuilder *builder; /* Constructeur utilisé */ GtkTreeView *treeview; /* Arborescence constituée */ GtkTreeStore *store; /* Modèle de gestion */ max_depth = gtk_spin_button_get_value_as_int(button); gboolean apply_max_depth(GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, gpointer unused) { gint depth; /* Profondeur du point courant */ depth = gtk_tree_store_iter_depth(GTK_TREE_STORE(model), iter); if (depth < max_depth) gtk_tree_view_expand_to_path(treeview, path); return FALSE; } builder = gtk_built_named_widget_get_builder(GTK_BUILT_NAMED_WIDGET(G_PANEL_ITEM(panel)->widget)); treeview = GTK_TREE_VIEW(gtk_builder_get_object(builder, "treeview")); gtk_tree_view_collapse_all(treeview); store = GTK_TREE_STORE(gtk_builder_get_object(builder, "store")); gtk_tree_model_foreach(GTK_TREE_MODEL(store), (GtkTreeModelForeachFunc)apply_max_depth, NULL); g_object_unref(G_OBJECT(builder)); } /****************************************************************************** * * * Paramètres : selection = sélection modifiée. * * unused = adresse non utilisée ici. * * * * Description : Réagit au changement de sélection des portions. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ static void on_bintree_selection_changed(GtkTreeSelection *selection, gpointer unused) { GtkTreeIter iter; /* Point de sélection */ GtkTreeModel *model; /* Modèle de gestion */ GBinPortion *portion; /* Portion à traiter */ const mrange_t *range; /* Couverture dudit symbole */ GLoadedPanel *panel; /* Afficheur effectif de code */ if (gtk_tree_selection_get_selected(selection, &model, &iter)) { gtk_tree_model_get(model, &iter, BTC_PORTION, &portion, -1); if (portion != NULL) { range = g_binary_portion_get_range(portion); panel = get_current_view(); if (GTK_IS_DISPLAY_PANEL(panel)) gtk_display_panel_request_move(GTK_DISPLAY_PANEL(panel), get_mrange_addr(range)); g_object_unref(G_OBJECT(panel)); g_object_unref(G_OBJECT(portion)); } } } /****************************************************************************** * * * Paramètres : panel = panneau à mettre à jour. * * old = ancien contenu chargé analysé. * * new = nouveau contenu chargé à analyser. * * * * Description : Réagit à un changement d'affichage principal de contenu. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ static void change_bintree_panel_current_content(GBintreePanel *panel, GLoadedContent *old, GLoadedContent *new) { GLoadedBinary *binary; /* Autre version de l'instance */ GtkBuilder *builder; /* Constructeur utilisé */ GtkTreeStore *store; /* Modèle de gestion */ if (G_IS_LOADED_BINARY(new)) binary = G_LOADED_BINARY(new); else binary = NULL; /* Basculement du binaire utilisé */ if (panel->binary != NULL) g_object_unref(G_OBJECT(panel->binary)); panel->binary = binary; if (panel->binary != NULL) g_object_ref(G_OBJECT(panel->binary)); /* Réinitialisation */ builder = gtk_built_named_widget_get_builder(GTK_BUILT_NAMED_WIDGET(G_PANEL_ITEM(panel)->widget)); store = GTK_TREE_STORE(gtk_builder_get_object(builder, "store")); gtk_tree_store_clear(store); g_object_unref(G_OBJECT(builder)); /* Si le panneau actif représente un binaire, actualisation de l'affichage */ if (binary != NULL) run_panel_update(G_UPDATABLE_PANEL(panel), PUI_0); } /* ---------------------------------------------------------------------------------- */ /* AFFICHAGE SOUS FORME D'ARBRE */ /* ---------------------------------------------------------------------------------- */ /****************************************************************************** * * * Paramètres : panel = portion de binaire à traiter. * * parent = portion parent de la portion visitée. * * visit = indication sur le sens de la visite. * * panel = lien vers toutes les autres informations utiles. * * * * Description : Parcourt un ensemble de portions. * * * * Retour : true pour continuer la visite. * * * * Remarques : - * * * ******************************************************************************/ static bool populate_tree_with_portion(GBinPortion *portion, GBinPortion *parent, BinaryPortionVisit visit, bintree_update_data *data) { const GBintreePanel *panel; /* Panneau à compléter */ cairo_surface_t *icon; /* Miniature de décoration */ GtkBuilder *builder; /* Constructeur utilisé */ GtkTreeStore *store; /* Modèle de gestion */ GtkTreeIter iter; /* Point d'insertion */ GtkTreeIter *save; /* Sauvegarde d'une position */ if (parent == NULL) return true; panel = data->panel; /* Insertion de la portion courante */ if (visit == BPV_ENTER || visit == BPV_SHOW) { icon = NULL; builder = gtk_built_named_widget_get_builder(GTK_BUILT_NAMED_WIDGET(G_PANEL_ITEM(panel)->widget)); store = GTK_TREE_STORE(gtk_builder_get_object(builder, "store")); gtk_tree_store_append(store, &iter, data->top); gtk_tree_store_set(store, &iter, BTC_PORTION, portion, BTC_ICON, icon, BTC_CAPTION, NULL, BTC_START, NULL, BTC_END, NULL, BTC_RIGHTS, NULL, BTC_MATCHED, false, BTC_MATCH_POINTS, 0, -1); if (icon != NULL) cairo_surface_destroy(icon); update_bintree_node(data, store, &iter, portion); g_object_unref(G_OBJECT(builder)); gtk_status_stack_update_activity_value(data->status, data->id, 1); } /* Définition de la hiérarchie */ if (visit == BPV_ENTER) { save = gtk_tree_iter_copy(data->top); g_object_set_data_full(G_OBJECT(portion), "_save", save, (GDestroyNotify)gtk_tree_iter_free); *data->top = iter; } else if (visit == BPV_EXIT) { save = g_object_get_data(G_OBJECT(portion), "_save"); *data->top = *save; g_object_set_data(G_OBJECT(portion), "_save", NULL); } return true; } /****************************************************************************** * * * Paramètres : panel = panneau à mettre à jour. * * status = barre de statut à tenir informée. * * id = identifiant pour le suivi de la progression. * * data = données complémentaire à manipuler. * * * * Description : Réagit à un changement d'affichage principal de contenu. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ static void reload_portions_for_new_tree_view(const GBintreePanel *panel, GtkStatusStack *status, activity_id_t id, bintree_update_data *data) { GtkBuilder *builder; /* Constructeur utilisé */ GtkTreeStore *store; /* Modèle de gestion */ GExeFormat *format; /* Format du binaire */ GBinPortion *portions; /* Couche première de portions */ size_t count; /* Compteur de portions */ GtkTreeIter top; /* Racine de l'arborescence */ char *desc; /* Description de contenu */ gint max_depth; /* Profondeur maximale */ GtkSpinButton *depth_spin; /* Bouton de variation */ GtkTreeView *treeview; /* Arborescence constituée */ builder = gtk_built_named_widget_get_builder(GTK_BUILT_NAMED_WIDGET(G_PANEL_ITEM(panel)->widget)); store = GTK_TREE_STORE(gtk_builder_get_object(builder, "store")); /* Constitution de l'arborescence */ format = g_loaded_binary_get_format(panel->binary); portions = g_exe_format_get_portions(format); count = g_binary_portion_count(portions); gtk_status_stack_extend_activity(status, id, count); gtk_tree_store_append(store, &top, NULL); desc = g_loaded_content_describe(G_LOADED_CONTENT(panel->binary), false); gtk_tree_store_set(store, &top, BTC_ICON, NULL, BTC_CAPTION, desc, -1); free(desc); data->panel = panel; data->top = ⊤ data->status = status; data->id = id; g_binary_portion_visit(portions, (visit_portion_fc)populate_tree_with_portion, data); g_object_unref(G_OBJECT(portions)); g_object_unref(G_OBJECT(format)); /* Détermination de la profondeur maximale */ gboolean compute_max_depth(GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, gint *max) { gint depth; /* Profondeur du point courant */ depth = gtk_tree_store_iter_depth(GTK_TREE_STORE(model), iter); if (depth > *max) *max = depth; return FALSE; } max_depth = 0; gtk_tree_model_foreach(GTK_TREE_MODEL(store), (GtkTreeModelForeachFunc)compute_max_depth, &max_depth); depth_spin = GTK_SPIN_BUTTON(gtk_builder_get_object(builder, "depth_spin")); gtk_spin_button_set_range(depth_spin, 0, max_depth); /* Restauration au mieux de l'affichage */ treeview = GTK_TREE_VIEW(gtk_builder_get_object(builder, "treeview")); switch (panel->last) { case UAT_COLLAPSE: gtk_tree_view_collapse_all(treeview); break; case UAT_EXPAND: gtk_tree_view_expand_all(treeview); break; case UAT_DEPTH: on_depth_spin_value_changed(depth_spin, panel); break; } g_object_unref(G_OBJECT(builder)); } /****************************************************************************** * * * Paramètres : store = gestionnaire de l'ensemble des données. * * iter = localisation des données à analyser. * * portion = portion de binaire concernée par l'analyse. * * column = colonne visée par l'analyse. * * match = portion de texte à mettre en évidence. * * * * Description : Met en surbrillance les éléments recherchés dans les noms. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ static void update_bintree_column_in_tree_view(GtkTreeStore *store, GtkTreeIter *iter, GBinPortion *portion, BinaryTreeColumn column, const regmatch_t *match) { const char *content; /* Contenu brut d'origine */ const mrange_t *range; /* Espace de portion à traiter */ VMPA_BUFFER(offset); /* Localisation quelconque */ vmpa2t end; /* Zone de construction temp. */ PortionAccessRights rights; /* Droits d'accès à analyser */ char hrights[4]; /* Version humainement lisible */ char *value; /* Etiquette mise en relief */ switch (column) { case BTC_CAPTION: content = g_binary_portion_get_desc(portion); break; case BTC_START: range = g_binary_portion_get_range(portion); vmpa2_phys_to_string(get_mrange_addr(range), MDS_UNDEFINED, offset, NULL); content = offset; break; case BTC_END: range = g_binary_portion_get_range(portion); compute_mrange_end_addr(range, &end); vmpa2_phys_to_string(&end, MDS_UNDEFINED, offset, NULL); content = offset; break; case BTC_RIGHTS: rights = g_binary_portion_get_rights(portion); hrights[0] = (rights & PAC_READ ? 'r' : '-'); hrights[1] = (rights & PAC_WRITE ? 'w' : '-'); hrights[2] = (rights & PAC_EXEC ? 'x' : '-'); hrights[3] = '\0'; content = hrights; break; default: assert(false); content = NULL; break; } value = build_highlighted_name(content, match, 0); gtk_tree_store_set(store, iter, column, value, -1); free(value); } /* ---------------------------------------------------------------------------------- */ /* FILTRAGE DES SYMBOLES PRESENTS */ /* ---------------------------------------------------------------------------------- */ /****************************************************************************** * * * Paramètres : entry = zone de texte avec un nouveau filtre d'affichage. * * panel = panneau contenant les informations globales. * * * * Description : Prend note du changement de filtre sur les portions. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ static void on_search_entry_changed(GtkSearchEntry *entry, GBintreePanel *panel) { update_regex_on_search_entry_changed(entry, &G_PANEL_ITEM(panel)->filter); run_panel_update(G_UPDATABLE_PANEL(panel), PUI_1); } /****************************************************************************** * * * Paramètres : data = données complémentaire à manipuler. * * store = gestionnaire de l'ensemble des données. * * iter = localisation des données à analyser. * * portion = portion binaire présente à la position courante. * * * * Description : Détermine si un noeud de l'arborescence doit être filtré. * * * * Retour : Bilan du filtrage. * * * * Remarques : - * * * ******************************************************************************/ static bool update_bintree_node(const bintree_update_data *data, GtkTreeStore *store, GtkTreeIter *iter, GBinPortion *portion) { bool result; /* Bilan à retourner */ regmatch_t match; /* Récupération des trouvailles*/ bool caption_matched; /* Correspondance de sélection */ bool start_matched; /* Correspondance de sélection */ bool end_matched; /* Correspondance de sélection */ bool rights_matched; /* Correspondance de sélection */ caption_matched = is_bintree_column_matching(data, portion, BTC_CAPTION, &match); if (caption_matched) update_bintree_column_in_tree_view(store, iter, portion, BTC_CAPTION, &match); start_matched = is_bintree_column_matching(data, portion, BTC_START, &match); if (start_matched) update_bintree_column_in_tree_view(store, iter, portion, BTC_START, &match); end_matched = is_bintree_column_matching(data, portion, BTC_END, &match); if (end_matched) update_bintree_column_in_tree_view(store, iter, portion, BTC_END, &match); rights_matched = is_bintree_column_matching(data, portion, BTC_RIGHTS, &match); if (rights_matched) update_bintree_column_in_tree_view(store, iter, portion, BTC_RIGHTS, &match); result = (caption_matched || start_matched || end_matched || rights_matched); gtk_tree_store_set(store, iter, BTC_MATCHED, result, -1); return result; } /****************************************************************************** * * * Paramètres : panel = panneau assurant l'affichage des symboles. * * status = barre de statut à tenir informée. * * id = identifiant pour le suivi de la progression. * * data = données complémentaire à manipuler. * * * * Description : Exécute un nouveau filtrage des symboles affichés. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ static void do_filtering_on_portions(const GBintreePanel *panel, GtkStatusStack *status, activity_id_t id, bintree_update_data *data) { GtkBuilder *builder; /* Constructeur utilisé */ GtkTreeStore *store; /* Modèle de gestion */ gboolean filter_portion_panel_iter(GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, gpointer unused) { GBinPortion *portion; /* Portion à traiter */ bool matched; /* Correspondance de sélection */ gboolean shown; /* Visibilité actuelle */ gtk_tree_model_get(model, iter, BTC_PORTION, &portion, -1); if (portion != NULL) { matched = update_bintree_node(data, store, iter, portion); gtk_tree_model_get(model, iter, BTC_MATCHED, &shown, -1); if (!matched) { if (shown) update_node_visibility(store, iter, BTC_MATCHED, false); } else { if (!shown) update_node_visibility(store, iter, BTC_MATCHED, true); } g_object_unref(G_OBJECT(portion)); gtk_status_stack_update_activity_value(status, id, 1); } return FALSE; } builder = gtk_built_named_widget_get_builder(GTK_BUILT_NAMED_WIDGET(G_PANEL_ITEM(panel)->widget)); store = GTK_TREE_STORE(gtk_builder_get_object(builder, "store")); gtk_tree_model_foreach(GTK_TREE_MODEL(store), (GtkTreeModelForeachFunc)filter_portion_panel_iter, NULL); g_object_unref(G_OBJECT(builder)); } /* ---------------------------------------------------------------------------------- */ /* MECANISMES DE MISE A JOUR DE PANNEAU */ /* ---------------------------------------------------------------------------------- */ /****************************************************************************** * * * Paramètres : data = données complémentaire à manipuler. * * portion = portion de binaire concernée par l'analyse. * * column = colonne visée par l'analyse. * * match = récupération des trouvailles. [OUT] * * * * Description : Détermine si une valeur de portion doit être filtrée ou non. * * * * Retour : true si le symbol ne doit pas être affiché, false sinon. * * * * Remarques : - * * * ******************************************************************************/ static bool is_bintree_column_matching(const bintree_update_data *data, GBinPortion *portion, gint column, regmatch_t *match) { bool result; /* Bilan à retourner */ const char *content; /* Contenu à analyser */ const mrange_t *range; /* Espace de portion à traiter */ VMPA_BUFFER(offset); /* Localisation quelconque */ vmpa2t end; /* Zone de construction temp. */ PortionAccessRights rights; /* Droits d'accès à analyser */ char hrights[4]; /* Version humainement lisible */ switch (column) { case BTC_CAPTION: content = g_binary_portion_get_desc(portion); break; case BTC_START: range = g_binary_portion_get_range(portion); vmpa2_phys_to_string(get_mrange_addr(range), MDS_UNDEFINED, offset, NULL); content = offset; break; case BTC_END: range = g_binary_portion_get_range(portion); compute_mrange_end_addr(range, &end); vmpa2_phys_to_string(&end, MDS_UNDEFINED, offset, NULL); content = offset; break; case BTC_RIGHTS: rights = g_binary_portion_get_rights(portion); hrights[0] = (rights & PAC_READ ? 'r' : '-'); hrights[1] = (rights & PAC_WRITE ? 'w' : '-'); hrights[2] = (rights & PAC_EXEC ? 'x' : '-'); hrights[3] = '\0'; content = hrights; break; } result = is_content_matching(data->filter, content, match); return result; } /****************************************************************************** * * * Paramètres : panel = panneau ciblé par une mise à jour. * * uid = identifiant de la phase de traitement. * * count = nombre d'étapes à prévoir dans le traitement. [OUT] * * data = données sur lesquelles s'appuyer ensuite. [OUT] * * * * Description : Prépare une opération de mise à jour de panneau. * * * * Retour : Description du message d'information. * * * * Remarques : - * * * ******************************************************************************/ static const char *g_bintree_panel_setup(const GBintreePanel *panel, unsigned int uid, size_t *count, bintree_update_data **data) { const char *result; /* Message à retourner */ #ifndef NDEBUG int ret; /* Bilan de mise en place */ #endif GtkBuilder *builder; /* Constructeur utilisé */ GtkTreeView *treeview; /* Arborescence graphique */ *data = malloc(sizeof(bintree_update_data)); switch (uid) { case PUI_0: *count = 0; (*data)->count = 0; result = _("Loading portions contained in the binary format..."); break; case PUI_1: *count = panel->count; (*data)->count = panel->count; result = _("Filtering portions contained in the binary format..."); break; default: /* Pour GCC... */ assert(false); result = ""; break; } if (G_PANEL_ITEM(panel)->filter != NULL) { (*data)->filter = (regex_t *)malloc(sizeof(regex_t)); #ifndef NDEBUG ret = regcomp((*data)->filter, G_PANEL_ITEM(panel)->filter, REG_EXTENDED | REG_ICASE); assert(ret == 0); #else regcomp((*data)->filter, G_PANEL_ITEM(panel)->filter, REG_EXTENDED | REG_ICASE); #endif } else (*data)->filter = NULL; /* Mémorisation de tous les noeuds ouverts */ builder = gtk_built_named_widget_get_builder(GTK_BUILT_NAMED_WIDGET(G_PANEL_ITEM(panel)->widget)); treeview = GTK_TREE_VIEW(gtk_builder_get_object(builder, "treeview")); void keep_track_of_expanded(GtkTreeView *tv, GtkTreePath *path, bintree_update_data *sud) { if (sud->ecount == sud->eallocated) { sud->eallocated += EXPAND_ALLOC_RANGE; sud->expanded = (char **)realloc(sud->expanded, sud->eallocated * sizeof(char *)); } sud->expanded[sud->ecount] = gtk_tree_path_to_string(path); sud->ecount++; } (*data)->expanded = NULL; (*data)->ecount = 0; (*data)->eallocated = 0; gtk_tree_view_map_expanded_rows(treeview, (GtkTreeViewMappingFunc)keep_track_of_expanded, *data); g_object_unref(G_OBJECT(builder)); return result; } /****************************************************************************** * * * Paramètres : panel = panneau ciblé par une mise à jour. * * uid = identifiant de la phase de traitement. * * data = données préparées par l'appelant. * * * * Description : Bascule l'affichage d'un panneau avant mise à jour. * * * * Retour : - * * * * Remarques : Cette fonction est appelée depuis le contexte principal. * * * ******************************************************************************/ static void g_bintree_panel_introduce(const GBintreePanel *panel, unsigned int uid, bintree_update_data *data) { GtkBuilder *builder; /* Constructeur utilisé */ GtkTreeView *treeview; /* Arborescence graphique */ GtkTreeModel *model; /* Source de données associée */ /* Basculement de l'affichage hors ligne */ g_panel_item_switch_to_updating_mask(G_PANEL_ITEM(panel)); builder = gtk_built_named_widget_get_builder(GTK_BUILT_NAMED_WIDGET(G_PANEL_ITEM(panel)->widget)); treeview = GTK_TREE_VIEW(gtk_builder_get_object(builder, "treeview")); model = gtk_tree_view_get_model(treeview); if (model != NULL) { g_object_ref(G_OBJECT(model)); gtk_tree_view_set_model(treeview, NULL); } g_object_unref(G_OBJECT(builder)); } /****************************************************************************** * * * Paramètres : panel = panneau ciblé par une mise à jour. * * uid = identifiant de la phase de traitement. * * status = barre de statut à tenir informée. * * id = identifiant pour le suivi de la progression. * * data = données préparées par l'appelant. * * * * Description : Réalise une opération de mise à jour de panneau. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ static void g_bintree_panel_process(const GBintreePanel *panel, unsigned int uid, GtkStatusStack *status, activity_id_t id, bintree_update_data *data) { switch (uid) { case PUI_0: reload_portions_for_new_tree_view(panel, status, id, data); break; case PUI_1: do_filtering_on_portions(panel, status, id, data); break; } } /****************************************************************************** * * * Paramètres : panel = panneau ciblé par une mise à jour. * * uid = identifiant de la phase de traitement. * * data = données préparées par l'appelant. * * * * Description : Bascule l'affichage d'un panneau après mise à jour. * * * * Retour : - * * * * Remarques : Cette fonction est appelée depuis le contexte principal. * * * ******************************************************************************/ static void g_bintree_panel_conclude(GBintreePanel *panel, unsigned int uid, bintree_update_data *data) { GtkBuilder *builder; /* Constructeur utilisé */ GtkTreeView *treeview; /* Arborescence graphique */ GtkTreeModel *model; /* Source de données associée */ size_t i; /* Boucle de parcours */ GtkTreePath *path; /* Chemin d'accès à un noeud */ if (g_atomic_int_get(&G_PANEL_ITEM(panel)->switched) > 1) goto skip_this_step; /* Mise à jour des compteurs */ panel->count = data->count; /* Basculement de l'affichage en ligne */ builder = gtk_built_named_widget_get_builder(GTK_BUILT_NAMED_WIDGET(G_PANEL_ITEM(panel)->widget)); treeview = GTK_TREE_VIEW(gtk_builder_get_object(builder, "treeview")); model = GTK_TREE_MODEL(gtk_builder_get_object(builder, "filter")); g_object_ref(G_OBJECT(model)); gtk_tree_view_set_model(treeview, model); for (i = 0; i < data->ecount; i++) { path = gtk_tree_path_new_from_string(data->expanded[i]); gtk_tree_view_expand_to_path(treeview, path); gtk_tree_path_free(path); } g_object_unref(G_OBJECT(builder)); skip_this_step: g_panel_item_switch_to_updated_content(G_PANEL_ITEM(panel)); } /****************************************************************************** * * * Paramètres : panel = panneau ciblé par une mise à jour. * * uid = identifiant de la phase de traitement. * * data = données en place à nettoyer avant suppression. * * * * Description : Supprime les données dynamiques utilisées à la mise à jour. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ static void g_bintree_panel_clean_data(GUpdatablePanel *panel, unsigned int uid, bintree_update_data *data) { size_t i; /* Boucle de parcours */ if (data->filter != NULL) { regfree(data->filter); free(data->filter); } for (i = 0; i < data->ecount; i++) g_free(data->expanded[i]); if (data->expanded != NULL) free(data->expanded); }