From acc7b5f33e93bae3bf43e8f029976b7f74260b52 Mon Sep 17 00:00:00 2001 From: Cyrille Bagard Date: Sun, 9 Apr 2017 09:52:59 +0200 Subject: Provided a tree panel to inspect binary content. --- ChangeLog | 31 ++ src/glibext/gbinportion.c | 55 ++++ src/glibext/gbinportion.h | 6 + src/gtkext/Makefile.am | 3 +- src/gtkext/tmgt.c | 204 ++++++++++++ src/gtkext/tmgt.h | 45 +++ src/gui/core/panels.c | 4 + src/gui/panels/Makefile.am | 2 + src/gui/panels/bintree.c | 724 +++++++++++++++++++++++++++++++++++++++++++ src/gui/panels/bintree.h | 62 ++++ src/gui/panels/bintree.ui | 191 ++++++++++++ src/gui/panels/gresource.xml | 3 + src/gui/panels/symbols.c | 144 +-------- 13 files changed, 1338 insertions(+), 136 deletions(-) create mode 100644 src/gtkext/tmgt.c create mode 100644 src/gtkext/tmgt.h create mode 100644 src/gui/panels/bintree.c create mode 100644 src/gui/panels/bintree.h create mode 100644 src/gui/panels/bintree.ui diff --git a/ChangeLog b/ChangeLog index b141036..5e243a0 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,34 @@ +17-04-09 Cyrille Bagard + + * src/glibext/gbinportion.c: + * src/glibext/gbinportion.h: + Enable icon for portions. + + * src/gtkext/Makefile.am: + Add the 'tmgt.[ch]' files to libgtkext_la_SOURCES. + + * src/gtkext/tmgt.c: + * src/gtkext/tmgt.h: + New entries: provide common helpers for managing treeviews. + + * src/gui/core/panels.c: + Register the new binary tree panel. + + * src/gui/panels/Makefile.am: + Add the 'bintree.ui' file to UI_FILES and the 'bintree.[ch]' files + to libguipanels_la_SOURCES. + + * src/gui/panels/bintree.c: + * src/gui/panels/bintree.h: + * src/gui/panels/bintree.ui: + New entries: provide a tree panel to inspect binary content. + + * src/gui/panels/gresource.xml: + Register the new UI and its icons. + + * src/gui/panels/symbols.c: + Update code. + 17-03-31 Cyrille Bagard * plugins/readelf/Makefile.am: diff --git a/src/glibext/gbinportion.c b/src/glibext/gbinportion.c index caaec43..b94b0f6 100644 --- a/src/glibext/gbinportion.c +++ b/src/glibext/gbinportion.c @@ -51,6 +51,8 @@ struct _GBinPortion char *code; /* Code de la couleur de fond */ + cairo_surface_t *icon; /* Image de représentation */ + char *desc; /* Désignation humaine */ char **text; /* Lignes brutes à représenter */ size_t lcount; /* Quantité de ces lignes */ @@ -239,6 +241,9 @@ static void g_binary_portion_finalize(GBinPortion *portion) free(portion->code); + if (portion->icon != NULL) + cairo_surface_destroy(portion->icon); + if (portion->desc != NULL) free(portion->desc); @@ -314,6 +319,56 @@ int g_binary_portion_compare(const GBinPortion **a, const GBinPortion **b) /****************************************************************************** * * * Paramètres : portion = description de partie à mettre à jour. * +* icon = image miniature de représentation à associer. * +* * +* Description : Attribue à la portion une éventuelle image de représentation.* +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +void g_binary_portion_set_icon(GBinPortion *portion, cairo_surface_t *icon) +{ + if (icon != NULL) + portion->icon = cairo_surface_reference(icon); + + else + portion->icon = NULL; + +} + + +/****************************************************************************** +* * +* Paramètres : portion = description de partie à consulter. * +* * +* Description : Fournit une éventuelle image de représentation de portion. * +* * +* Retour : Image miniature de représentation associée. * +* * +* Remarques : - * +* * +******************************************************************************/ + +cairo_surface_t *g_binary_portion_get_icon(const GBinPortion *portion) +{ + cairo_surface_t *result; + + result = portion->icon; + + if (result != NULL) + cairo_surface_reference(result); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : portion = description de partie à mettre à jour. * * desc = nom à donner à la partie. * * * * Description : Attribue une description humaine à une partie de code. * diff --git a/src/glibext/gbinportion.h b/src/glibext/gbinportion.h index 27e7dc5..9f22e3d 100644 --- a/src/glibext/gbinportion.h +++ b/src/glibext/gbinportion.h @@ -84,6 +84,12 @@ GBinPortion *g_binary_portion_new(const char *, const vmpa2t *, phys_t); /* Etablit la comparaison ascendante entre deux portions. */ int g_binary_portion_compare(const GBinPortion **, const GBinPortion **); +/* Attribue à la portion une éventuelle image de représentation. */ +void g_binary_portion_set_icon(GBinPortion *, cairo_surface_t *); + +/* Fournit une éventuelle image de représentation de portion. */ +cairo_surface_t *g_binary_portion_get_icon(const GBinPortion *); + /* Attribue une description humaine à une partie de code. */ void g_binary_portion_set_desc(GBinPortion *, const char *); diff --git a/src/gtkext/Makefile.am b/src/gtkext/Makefile.am index d874ac1..07fe3a9 100644 --- a/src/gtkext/Makefile.am +++ b/src/gtkext/Makefile.am @@ -15,7 +15,8 @@ libgtkext_la_SOURCES = \ gtkdockstation.h gtkdockstation.c \ gtkgraphdisplay.h gtkgraphdisplay.c \ gtkstatusstack.h gtkstatusstack.c \ - support.h support.c + support.h support.c \ + tmgt.h tmgt.c libgtkext_la_LIBADD = \ graph/libgtkextgraph.la diff --git a/src/gtkext/tmgt.c b/src/gtkext/tmgt.c new file mode 100644 index 0000000..ce6f9a8 --- /dev/null +++ b/src/gtkext/tmgt.c @@ -0,0 +1,204 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * tmgt.c - compléments utiles à la mise en place d'arborescences + * + * Copyright (C) 2017 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 Foobar. If not, see . + */ + + +#include "tmgt.h" + + +#include +#include + + +#include "../common/extstr.h" + + + +/****************************************************************************** +* * +* Paramètres : entry = zone de texte avec un nouveau filtre d'affichage. * +* filter = expression régulière de filtrage à constituer. [OUT]* +* * +* Description : Met à jour un filtre selon un contenu recherché. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +void update_regex_on_search_entry_changed(GtkSearchEntry *entry, regex_t **filter) +{ + const gchar *text; /* Texte de l'utilisateur */ + int ret; /* Bilan de mise en place */ + GdkRGBA error; /* Couleur d'erreur */ + + if (*filter != NULL) + { + regfree(*filter); + free(*filter); + *filter = NULL; + } + + text = gtk_entry_get_text(GTK_ENTRY(entry)); + + if (strlen(text) > 0) + { + *filter = (regex_t *)calloc(1, sizeof(regex_t)); + ret = regcomp(*filter, text, REG_EXTENDED | REG_ICASE); + + if (ret != 0) + { + free(*filter); + *filter = NULL; + + error.red = 1.0; + error.green = 0.0; + error.blue = 0.0; + error.alpha = 1.0; + gtk_widget_override_color(GTK_WIDGET(entry), GTK_STATE_NORMAL, &error); + + return; + + } + + } + + gtk_widget_override_color(GTK_WIDGET(entry), GTK_STATE_NORMAL, NULL); + +} + + +/****************************************************************************** +* * +* Paramètres : filter = expression régulière servant de filtre. * +* content = contenu textuel à analyser. * +* match = zone pointant vers une correspondance. [OUT] * +* * +* Description : Détermine si un contenu correspond à un filtre donné. * +* * +* Retour : true si le contenu est qualifié pour un affichage, ou false. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool is_content_matching(const regex_t *filter, const char *content, regmatch_t *match) +{ + bool result; /* Bilan à retourner */ + int ret; /* Bilan du filtrage */ + + memset( match, 0, sizeof(regmatch_t)); + + if (filter == NULL) + result = true; + + else + { + ret = regexec(filter, content, 1, match, 0); + result = (ret != REG_NOMATCH); + } + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : raw = bribe de texte à traiter. * +* match = portion de texte à mettre en évidence. * +* start = position du texte brute dans l'étiquette complète. * +* * +* Description : Met en évidence le texte recherché en cas de correspondance. * +* * +* Retour : Texte final destiné à être inséré, à libérer après usage. * +* * +* Remarques : - * +* * +******************************************************************************/ + +char *build_highlighted_name(const char *raw, const regmatch_t *match, size_t start) +{ + char *result; /* Construction à retourner */ + size_t len; /* Taille du texte d'entrée */ + regmatch_t selection; /* Sélection relative au texte */ + char *valid; /* Retouche partielle */ + + len = strlen(raw); + + /* Si aucune sélection ou texte hors champ... */ + + if ((match->rm_eo - match->rm_so) == 0 || (start + len) <= match->rm_so || match->rm_eo < start) + { + result = strdup(raw); + result = strrpl(result, "<", "<"); + } + + /* Sinon, il y a forcément correspondance quelque part ! */ + + else + { + /* Adaptations */ + + if (match->rm_so < start) + selection.rm_so = 0; + else + selection.rm_so = match->rm_so - start; + + selection.rm_eo = match->rm_eo - start; + + if (selection.rm_eo > len) + selection.rm_eo = len; + + /* Impressions */ + + if (selection.rm_so > 0) + { + result = strndup(raw, selection.rm_so); + result = strrpl(result, "<", "<"); + } + else + result = NULL; + + result = stradd(result, ""); + + valid = strndup(&raw[selection.rm_so], selection.rm_eo - selection.rm_so); + valid = strrpl(valid, "<", "<"); + + result = stradd(result, valid); + + free(valid); + + result = stradd(result, ""); + + valid = strdup(&raw[selection.rm_eo]); + valid = strrpl(valid, "<", "<"); + + result = stradd(result, valid); + + free(valid); + + } + + return result; + +} diff --git a/src/gtkext/tmgt.h b/src/gtkext/tmgt.h new file mode 100644 index 0000000..eeeb848 --- /dev/null +++ b/src/gtkext/tmgt.h @@ -0,0 +1,45 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * tmgt.h - prototypes pour des compléments utiles à la mise en place d'arborescences + * + * Copyright (C) 2017 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 Foobar. If not, see . + */ + + +#ifndef _COMMON_TMGT_H +#define _COMMON_TMGT_H + + +#include +#include +#include + + + +/* Met à jour un filtre selon un contenu recherché. */ +void update_regex_on_search_entry_changed(GtkSearchEntry *, regex_t **); + +/* Détermine si un contenu correspond à un filtre donné. */ +bool is_content_matching(const regex_t *, const char *, regmatch_t *); + +/* Met en évidence le texte recherché en cas de correspondance. */ +char *build_highlighted_name(const char *, const regmatch_t *, size_t); + + + +#endif /* _COMMON_TMGT_H */ diff --git a/src/gui/core/panels.c b/src/gui/core/panels.c index bd85be9..3d1a512 100644 --- a/src/gui/core/panels.c +++ b/src/gui/core/panels.c @@ -25,6 +25,7 @@ #include "panels.h" +#include "../panels/bintree.h" #include "../panels/bookmarks.h" #include "../panels/glance.h" #include "../panels/history.h" @@ -87,6 +88,9 @@ void load_main_panels(GObject *ref) item = g_bookmarks_panel_new(); register_panel_item(item, ref, config); + item = g_bintree_panel_new(); + register_panel_item(item, ref, config); + } diff --git a/src/gui/panels/Makefile.am b/src/gui/panels/Makefile.am index bd4572d..7dc1cc5 100644 --- a/src/gui/panels/Makefile.am +++ b/src/gui/panels/Makefile.am @@ -4,9 +4,11 @@ BUILT_SOURCES = resources.h resources.c noinst_LTLIBRARIES = libguipanels.la UI_FILES = \ + bintree.ui \ welcome.ui libguipanels_la_SOURCES = \ + bintree.h bintree.c \ bookmarks.h bookmarks.c \ glance.h glance.c \ history.h history.c \ diff --git a/src/gui/panels/bintree.c b/src/gui/panels/bintree.c new file mode 100644 index 0000000..9963f94 --- /dev/null +++ b/src/gui/panels/bintree.c @@ -0,0 +1,724 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * bintree.c - panneau d'accueil par défaut + * + * Copyright (C) 2012-2017 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 "panel-int.h" +#include "../../gtkext/tmgt.h" + + + +/* 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 */ + + GtkBuilder *builder; /* Constructeur utilisé */ + + GLoadedBinary *binary; /* Binaire représenté */ + regex_t *filter; /* Filtre appliqué ou NULL */ + + UserActionType last; /* Dernière action */ + + GtkTreeIter *top; /* Transfert de racine */ + +}; + +/* 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_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_PORTION /* Elément interne représenté */ + +} BinaryTreeColumn; + + +/* 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 *); + +/* 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 *); + +/* Parcourt un ensemble de portions. */ +static bool populate_tree_with_portion(GBinPortion *, GBinPortion *, BinaryPortionVisit, GBintreePanel *); + +/* Réagit à un changement d'affichage principal de contenu. */ +static void update_panel_with_binary_portions(GBintreePanel *, GLoadedBinary *); + +/* Modifie la profondeur affichée des portions présentes. */ +static void on_depth_spin_value_changed(GtkSpinButton *, GtkTreeView *); + +/* Prend note du changement de filtre sur les portions. */ +static void on_search_entry_changed(GtkSearchEntry *, GBintreePanel *); + +/* Parcourt un arbre en place et retire les branches filtrées. */ +static void apply_filter_on_portions(GtkTreeStore *); + +/* Réagit au changement de sélection des portions. */ +static void on_bintree_selection_changed(GtkTreeSelection *, GBintreePanel *); + + + +/* Indique le type défini pour un panneau d'affichage des portions. */ +G_DEFINE_TYPE(GBintreePanel, g_bintree_panel, G_TYPE_PANEL_ITEM); + + +/****************************************************************************** +* * +* Paramètres : klass = classe à initialiser. * +* * +* Description : Initialise la classe des panneaux d'affichage des portions. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_bintree_panel_class_init(GBintreePanelClass *klass) +{ + GObjectClass *object; /* Autre version de la classe */ + GEditorItemClass *editem; /* Encore une autre vision... */ + + object = G_OBJECT_CLASS(klass); + + object->dispose = (GObjectFinalizeFunc/* ! */)g_bintree_panel_dispose; + object->finalize = (GObjectFinalizeFunc)g_bintree_panel_finalize; + + editem = G_EDITOR_ITEM_CLASS(klass); + + editem->update_binary = (update_item_binary_fc)update_panel_with_binary_portions; + +} + + +/****************************************************************************** +* * +* 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) +{ + GEditorItem *base; /* Version basique d'instance */ + GPanelItem *pitem; /* Version parente du panneau */ + GtkTreeView *treeview; /* Affichage de la liste */ + GtkCellRenderer *renderer; /* Moteur de rendu de colonne */ + GtkTreeViewColumn *column; /* Colonne de la liste */ + + /* Eléments de base */ + + base = G_EDITOR_ITEM(panel); + + base->name = PANEL_BINTREE_ID; + + pitem = G_PANEL_ITEM(panel); + + pitem->personality = PIP_SINGLETON; + pitem->lname = _("Binary tree"); + pitem->dock_at_startup = true; + pitem->path = strdup("eN"); + + /* Compléments propres */ + + panel->binary = NULL; + panel->filter = NULL; + + panel->last = UAT_EXPAND; + + /* Représentation graphique */ + + panel->builder = gtk_builder_new_from_resource("/org/chrysalide/gui/panels/bintree.ui"); + + base->widget = GTK_WIDGET(gtk_builder_get_object(panel->builder, "box")); + g_object_ref(G_OBJECT(base->widget)); + gtk_widget_unparent(base->widget); + + /* Liste des projets récents */ + + treeview = GTK_TREE_VIEW(gtk_builder_get_object(panel->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(panel->builder, + "gtk_tree_view_collapse_all", G_CALLBACK(gtk_tree_view_collapse_all), + "gtk_tree_view_expand_all", G_CALLBACK(gtk_tree_view_expand_all), + "on_depth_spin_value_changed", G_CALLBACK(on_depth_spin_value_changed), + "on_search_entry_changed", G_CALLBACK(on_search_entry_changed), + "on_bintree_selection_changed", G_CALLBACK(on_bintree_selection_changed), + NULL); + + gtk_builder_connect_signals(panel->builder, panel); + +} + + +/****************************************************************************** +* * +* 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) +{ + g_object_unref(G_OBJECT(panel->builder)); + + 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) +{ + if (panel->filter != NULL) + { + regfree(panel->filter); + free(panel->filter); + } + + G_OBJECT_CLASS(g_bintree_panel_parent_class)->finalize(G_OBJECT(panel)); + +} + + +/****************************************************************************** +* * +* 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 : 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, GBintreePanel *panel) +{ + const char *desc; /* Description d'origine */ + bool fmatched; /* Correspondance rencontrée ? */ + regmatch_t match; /* Position d'un filtre */ + char *node_caption; /* Etiquette de nouveau noeud */ + const mrange_t *range; /* Espace de portion à traiter */ + VMPA_BUFFER(offset); /* Décalage physique */ + char *node_start; /* Position pour nouveau noeud */ + vmpa2t end; /* Zone de construction temp. */ + char *node_end; /* Bordure pour nouveau noeud */ + PortionAccessRights rights; /* Droits d'accès à analyser */ + char hrights[4]; /* Version humainement lisible */ + char *node_rights; /* Droits pour nouveau noeud */ + cairo_surface_t *icon; /* Miniature de décoration */ + GtkTreeStore *store; /* Modèle de gestion */ + GtkTreeIter iter; /* Point d'insertion */ + GtkTreeIter *save; /* Sauvegarde d'une position */ + + if (parent == NULL) + return true; + + /* Insertion de la portion courante */ + + if (visit == BPV_ENTER || visit == BPV_SHOW) + { + /* Etiquette */ + + desc = g_binary_portion_get_desc(portion); + + fmatched = is_content_matching(panel->filter, desc, &match); + node_caption = build_highlighted_name(desc, &match, 0); + + /* Point de départ */ + + range = g_binary_portion_get_range(portion); + + vmpa2_phys_to_string(get_mrange_addr(range), MDS_UNDEFINED, offset, NULL); + + fmatched |= is_content_matching(panel->filter, offset, &match); + node_start = build_highlighted_name(offset, &match, 0); + + /* Point d'arrivée */ + + compute_mrange_end_addr(range, &end); + + vmpa2_phys_to_string(&end, MDS_UNDEFINED, offset, NULL); + + fmatched |= is_content_matching(panel->filter, offset, &match); + node_end = build_highlighted_name(offset, &match, 0); + + /* Droits nominaux */ + + 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'; + + fmatched |= is_content_matching(panel->filter, hrights, &match); + node_rights = build_highlighted_name(hrights, &match, 0); + + /* Intégration */ + + icon = NULL; + + store = GTK_TREE_STORE(gtk_builder_get_object(panel->builder, "store")); + + gtk_tree_store_append(store, &iter, panel->top); + + gtk_tree_store_set(store, &iter, + BTC_ICON, icon, + BTC_CAPTION, node_caption, + BTC_START, node_start, + BTC_END, node_end, + BTC_RIGHTS, node_rights, + BTC_MATCHED, fmatched, + BTC_PORTION, portion, + -1); + + free(node_caption); + free(node_start); + free(node_end); + free(node_rights); + + if (icon != NULL) + cairo_surface_destroy(icon); + + } + + /* Définition de la hiérarchie */ + + if (visit == BPV_ENTER) + { + save = gtk_tree_iter_copy(panel->top); + + g_object_set_data_full(G_OBJECT(portion), "_save", save, (GDestroyNotify)gtk_tree_iter_free); + + *panel->top = iter; + + } + + else if (visit == BPV_EXIT) + { + save = g_object_get_data(G_OBJECT(portion), "_save"); + + *panel->top = *save; + + g_object_set_data(G_OBJECT(portion), "_save", NULL); + + } + + return true; + +} + + +/****************************************************************************** +* * +* Paramètres : panel = panneau à mettre à jour. * +* binary = nouvelle instance de binaire analysé. * +* * +* Description : Réagit à un changement d'affichage principal de contenu. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void update_panel_with_binary_portions(GBintreePanel *panel, GLoadedBinary *binary) +{ + GtkTreeStore *store; /* Modèle de gestion */ + GExeFormat *format; /* Format du binaire */ + GBinPortion *portions; /* Couche première de portions */ + GtkTreeIter top; /* Racine de l'arborescence */ + gint max_depth; /* Profondeur maximale */ + GtkSpinButton *depth_spin; /* Bouton de variation */ + GtkTreeView *treeview; /* Arborescence constituée */ + + /* Réinitialisation */ + + if (panel->binary != NULL) + g_object_unref(G_OBJECT(panel->binary)); + + panel->binary = binary; + + store = GTK_TREE_STORE(gtk_builder_get_object(panel->builder, "store")); + + gtk_tree_store_clear(store); + + /* Chargement */ + + if (binary != NULL) + { + g_object_ref(G_OBJECT(binary)); + + format = g_loaded_binary_get_format(binary); + + portions = g_exe_format_get_portions(format); + + gtk_tree_store_append(store, &top, NULL); + + gtk_tree_store_set(store, &top, + BTC_ICON, NULL, + BTC_CAPTION, g_loaded_binary_get_name(binary, false), + -1); + + panel->top = ⊤ + g_binary_portion_visit(portions, (visit_portion_fc)populate_tree_with_portion, panel); + + 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(panel->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(panel->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, treeview); + break; + + } + + if (panel->filter != NULL) + apply_filter_on_portions(store); + +} + + +/****************************************************************************** +* * +* 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, GtkTreeView *treeview) +{ + gint max_depth; /* Profondeur maximale */ + GtkTreeModel *model; /* 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; + + } + + gtk_tree_view_collapse_all(treeview); + + model = gtk_tree_view_get_model(treeview); + + gtk_tree_model_foreach(model, (GtkTreeModelForeachFunc)apply_max_depth, NULL); + +} + + +/****************************************************************************** +* * +* 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, &panel->filter); + + if (panel->binary != NULL) + { + g_object_ref(G_OBJECT(panel->binary)); + update_panel_with_binary_portions(panel, panel->binary); + g_object_unref(G_OBJECT(panel->binary)); + } + +} + + +/****************************************************************************** +* * +* Paramètres : store = gestionnaire de contenu d'une arborescence donnée. * +* * +* Description : Parcourt un arbre en place et retire les branches filtrées. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void apply_filter_on_portions(GtkTreeStore *store) +{ + GtkTreeIter root; /* Racine de l'arboresence */ + + void check_portion_iter(GtkTreeIter *iter) + { + GtkTreeModel *model; /* Version alternative */ + gint children_count; /* Nombre d'enfants présents */ + gint i; /* Boucle de parcours */ + GtkTreeIter child; /* Pointeur vers la descendance*/ + gboolean fmatched; /* Correspondance immédiate ? */ + + model = GTK_TREE_MODEL(store); + + children_count = gtk_tree_model_iter_n_children(model, iter); + + for (i = children_count; i > 0; i--) + if (gtk_tree_model_iter_nth_child(model, &child, iter, i - 1)) + check_portion_iter(&child); + + children_count = gtk_tree_model_iter_n_children(model, iter); + + gtk_tree_model_get(model, iter, BTC_MATCHED, &fmatched, -1); + + if (!fmatched && children_count == 0) + gtk_tree_store_remove(store, iter); + + } + + if (gtk_tree_model_get_iter_first(GTK_TREE_MODEL(store), &root)) + check_portion_iter(&root); + +} + + +/****************************************************************************** +* * +* Paramètres : selection = sélection modifiée. * +* panel = structure contenant les informations maîtresses. * +* * +* Description : Réagit au changement de sélection des portions. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void on_bintree_selection_changed(GtkTreeSelection *selection, GBintreePanel *panel) +{ + GtkTreeIter iter; /* Point de sélection */ + GtkTreeModel *model; /* Modèle de gestion */ + GBinPortion *portion; /* Portion à traiter */ + const mrange_t *range; /* Couverture dudit symbole */ + GtkDisplayPanel *display; /* 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); + + display = g_editor_item_get_current_view(G_EDITOR_ITEM(panel)); + gtk_display_panel_request_move(display, get_mrange_addr(range)); + + g_object_unref(G_OBJECT(portion)); + + } + + } + +} diff --git a/src/gui/panels/bintree.h b/src/gui/panels/bintree.h new file mode 100644 index 0000000..8168481 --- /dev/null +++ b/src/gui/panels/bintree.h @@ -0,0 +1,62 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * bintree.h - prototypes pour le panneau d'accueil par défaut + * + * Copyright (C) 2012-2017 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 + */ + + +#ifndef _GUI_PANELS_BINTREE_H +#define _GUI_PANELS_BINTREE_H + + +#include + + +#include "panel.h" + + + +#define PANEL_BINTREE_ID _("Bintree") + + +#define G_TYPE_BINTREE_PANEL g_bintree_panel_get_type() +#define G_BINTREE_PANEL(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), g_bintree_panel_get_type(), GBintreePanel)) +#define G_IS_BINTREE_PANEL(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), g_bintree_panel_get_type())) +#define G_BINTREE_PANEL_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_BINTREE_PANEL, GBintreePanelClass)) +#define G_IS_BINTREE_PANEL_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_BINTREE_PANEL)) +#define G_BINTREE_PANEL_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_BINTREE_PANEL, GBintreePanelClass)) + + +/* Panneau de présentation des portions (instance) */ +typedef struct _GBintreePanel GBintreePanel; + +/* Panneau de présentation des portions (classe) */ +typedef struct _GBintreePanelClass GBintreePanelClass; + + +/* Indique le type défini pour un panneau d'affichage des portions. */ +GType g_bintree_panel_get_type(void); + +/* Crée un panneau présentant l'arborescence des portions. */ +GPanelItem *g_bintree_panel_new(void); + + + +#endif /* _GUI_PANELS_BINTREE_H */ diff --git a/src/gui/panels/bintree.ui b/src/gui/panels/bintree.ui new file mode 100644 index 0000000..2348e8d --- /dev/null +++ b/src/gui/panels/bintree.ui @@ -0,0 +1,191 @@ + + + + + + 100 + 1 + 2 + + + True + False + ../../../pixmaps/tbutton_collapse.png + + + True + False + ../../../pixmaps/tbutton_expand.png + + + + + + + + + + + + + + + + + + + + + False + 8 + 8 + 8 + 8 + + + True + False + vertical + 8 + + + True + False + + + True + False + center + True + collapse_img + + + + False + False + + + + + True + False + center + True + expand_img + + + + False + False + + + + + True + False + + + False + True + + + + + True + False + + + True + False + 8 + Depth: + + + + + False + True + + + + + True + False + + + True + True + 2 + 1 + 1 + adjustment1 + True + + + + + + False + True + + + + + True + False + + + False + True + + + + + True + False + + + True + True + edit-find-symbolic + False + False + filter... + + + + + + True + True + + + + + False + True + 0 + + + + + True + True + store + False + + + + + + + + False + True + 1 + + + + + + diff --git a/src/gui/panels/gresource.xml b/src/gui/panels/gresource.xml index 58d47e2..a14b8ae 100644 --- a/src/gui/panels/gresource.xml +++ b/src/gui/panels/gresource.xml @@ -1,6 +1,9 @@ + ../../../pixmaps/tbutton_collapse.png + ../../../pixmaps/tbutton_expand.png + bintree.ui welcome.ui diff --git a/src/gui/panels/symbols.c b/src/gui/panels/symbols.c index 8c95bf6..e73a847 100644 --- a/src/gui/panels/symbols.c +++ b/src/gui/panels/symbols.c @@ -37,10 +37,10 @@ #include "panel-int.h" -#include "../../common/extstr.h" #include "../../format/format.h" #include "../../gtkext/easygtk.h" #include "../../gtkext/support.h" +#include "../../gtkext/tmgt.h" @@ -153,10 +153,7 @@ static void on_symbols_filter_changed(GtkSearchEntry *, GSymbolsPanel *); static void do_filtering_on_symbols(GSymbolsPanel *); /* Détermine si un nom de symbole doit être filtré ou non. */ -static bool is_symbol_filtered(GSymbolsPanel *, const GBinSymbol *, regmatch_t *); - -/* Met en évidence le texte recherché en cas de correspondance. */ -static char *build_highlighted_name(const char *, const regmatch_t *, size_t); +static bool is_symbol_matching(GSymbolsPanel *, const GBinSymbol *, regmatch_t *); @@ -670,7 +667,7 @@ static void reload_symbols_for_new_list_view(GSymbolsPanel *panel) for (i = 0; i < sym_count; i++) { - if (is_symbol_filtered(panel, symbols[i], &match)) + if (!is_symbol_matching(panel, symbols[i], &match)) continue; switch (g_binary_symbol_get_target_type(symbols[i])) @@ -872,7 +869,7 @@ static void reload_symbols_for_new_tree_view(GSymbolsPanel *panel) for (i = 0; i < sym_count; i++) { - if (is_symbol_filtered(panel, symbols[i], &match)) + if (!is_symbol_matching(panel, symbols[i], &match)) continue; if (find_parent_for_symbol(panel, symbols[i], &parent, &match, &last)) @@ -1017,42 +1014,7 @@ static gboolean show_all_classes_in_tree_view(GtkTreeModel *model, GtkTreePath * static void on_symbols_filter_changed(GtkSearchEntry *entry, GSymbolsPanel *panel) { - const gchar *text; /* Texte de l'utilisateur */ - int ret; /* Bilan de mise en place */ - GdkRGBA error; /* Couleur d'erreur */ - - if (panel->filter != NULL) - { - regfree(panel->filter); - free(panel->filter); - panel->filter = NULL; - } - - text = gtk_entry_get_text(GTK_ENTRY(entry)); - - if (strlen(text) > 0) - { - panel->filter = (regex_t *)calloc(1, sizeof(regex_t)); - ret = regcomp(panel->filter, text, REG_EXTENDED | REG_ICASE); - - if (ret != 0) - { - free(panel->filter); - panel->filter = NULL; - - error.red = 1.0; - error.green = 0.0; - error.blue = 0.0; - error.alpha = 1.0; - gtk_widget_override_color(GTK_WIDGET(entry), GTK_STATE_NORMAL, &error); - - return; - - } - - } - - gtk_widget_override_color(GTK_WIDGET(entry), GTK_STATE_NORMAL, NULL); + update_regex_on_search_entry_changed(entry, &panel->filter); do_filtering_on_symbols(panel); @@ -1094,106 +1056,18 @@ static void do_filtering_on_symbols(GSymbolsPanel *panel) * * ******************************************************************************/ -static bool is_symbol_filtered(GSymbolsPanel *panel, const GBinSymbol *symbol, regmatch_t *match) +static bool is_symbol_matching(GSymbolsPanel *panel, const GBinSymbol *symbol, regmatch_t *match) { + bool result; /* Bilan à retourner */ SymbolType type; /* Type associé au symbole */ - int ret; /* Bilan du filtrage */ type = g_binary_symbol_get_target_type(symbol); if (type != STP_ROUTINE && type != STP_ENTRY_POINT && type != STP_OBJECT) - return true; - - memset(match, 0, sizeof(regmatch_t)); - - if (panel->filter == NULL) - return false; - - ret = regexec(panel->filter, g_binary_symbol_get_label(symbol), 1, match, 0); - if (ret == REG_NOMATCH) - return true; - - return false; - -} - - -/****************************************************************************** -* * -* Paramètres : raw = bribe de texte à traiter. * -* match = portion de texte à mettre en évidence. * -* start = position du texte brute dans l'étiquette complète. * -* * -* Description : Met en évidence le texte recherché en cas de correspondance. * -* * -* Retour : Texte final destiné à être inséré, à libérer après usage. * -* * -* Remarques : - * -* * -******************************************************************************/ - -static char *build_highlighted_name(const char *raw, const regmatch_t *match, size_t start) -{ - char *result; /* Construction à retourner */ - size_t len; /* Taille du texte d'entrée */ - regmatch_t selection; /* Sélection relative au texte */ - char *valid; /* Retouche partielle */ - - len = strlen(raw); - - /* Si aucune sélection ou texte hors champ... */ - - if ((match->rm_eo - match->rm_so) == 0 || (start + len) <= match->rm_so || match->rm_eo < start) - { - result = strdup(raw); - result = strrpl(result, "<", "<"); - } - - /* Sinon, il y a forcément correspondance quelque part ! */ + result = false; else - { - /* Adaptations */ - - if (match->rm_so < start) - selection.rm_so = 0; - else - selection.rm_so = match->rm_so - start; - - selection.rm_eo = match->rm_eo - start; - - if (selection.rm_eo > len) - selection.rm_eo = len; - - /* Impressions */ - - if (selection.rm_so > 0) - { - result = strndup(raw, selection.rm_so); - result = strrpl(result, "<", "<"); - } - else - result = NULL; - - result = stradd(result, ""); - - valid = strndup(&raw[selection.rm_so], selection.rm_eo - selection.rm_so); - valid = strrpl(valid, "<", "<"); - - result = stradd(result, valid); - - free(valid); - - result = stradd(result, ""); - - valid = strdup(&raw[selection.rm_eo]); - valid = strrpl(valid, "<", "<"); - - result = stradd(result, valid); - - free(valid); - - } + result = is_content_matching(panel->filter, g_binary_symbol_get_label(symbol), match); return result; -- cgit v0.11.2-87-g4458