diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/core/params.c | 3 | ||||
-rw-r--r-- | src/core/params.h | 1 | ||||
-rw-r--r-- | src/gtkext/gtkdockable-int.h | 12 | ||||
-rw-r--r-- | src/gtkext/gtkdockable.c | 65 | ||||
-rw-r--r-- | src/gtkext/tmgt.c | 118 | ||||
-rw-r--r-- | src/gtkext/tmgt.h | 5 | ||||
-rw-r--r-- | src/gui/panels/Makefile.am | 1 | ||||
-rw-r--r-- | src/gui/panels/bintree.c | 922 | ||||
-rw-r--r-- | src/gui/panels/bintree.ui | 59 | ||||
-rw-r--r-- | src/gui/panels/bookmarks.c | 55 | ||||
-rw-r--r-- | src/gui/panels/gresource.xml | 1 | ||||
-rw-r--r-- | src/gui/panels/panel-int.h | 14 | ||||
-rw-r--r-- | src/gui/panels/panel.c | 102 | ||||
-rw-r--r-- | src/gui/panels/panel.h | 12 | ||||
-rw-r--r-- | src/gui/panels/strings.c | 1015 | ||||
-rw-r--r-- | src/gui/panels/strings.ui | 93 | ||||
-rw-r--r-- | src/gui/panels/symbols.c | 185 |
17 files changed, 1969 insertions, 694 deletions
diff --git a/src/core/params.c b/src/core/params.c index ce8b9ce..1a724eb 100644 --- a/src/core/params.c +++ b/src/core/params.c @@ -195,9 +195,6 @@ bool load_main_config_parameters(void) param = g_generic_config_create_param(config, MPK_ELLIPSIS_TAB, CPT_INTEGER, 35); if (param == NULL) return false; - param = g_generic_config_create_param(config, MPK_DISPLAY_ON_SEL, CPT_BOOLEAN, false); - if (param == NULL) return false; - param = g_generic_config_create_param(config, MPK_WELCOME_STARTUP, CPT_BOOLEAN, true); if (param == NULL) return false; diff --git a/src/core/params.h b/src/core/params.h index 4535b04..6fa39b2 100644 --- a/src/core/params.h +++ b/src/core/params.h @@ -59,7 +59,6 @@ #define MPK_MAXIMIZED "gui.editor.start_maximized" #define MPK_ELLIPSIS_HEADER "gui.editor.panels.ellipsis_header" #define MPK_ELLIPSIS_TAB "gui.editor.panels.ellipsis_tab" -#define MPK_DISPLAY_ON_SEL "gui.editor.panels.display_on_selection" #define MPK_WELCOME_STARTUP "gui.editor.panels.welcome.show_at_startup" #define MPK_WELCOME_CHECK "gui.editor.panels.welcome.check_version" #define MPK_SELECTION_LINE "gui.editor.views.selection_line" diff --git a/src/gtkext/gtkdockable-int.h b/src/gtkext/gtkdockable-int.h index d9dbbd5..d4cd2d1 100644 --- a/src/gtkext/gtkdockable-int.h +++ b/src/gtkext/gtkdockable-int.h @@ -32,6 +32,12 @@ +/* Indique si le composant représenté à du contenu à fouiller. */ +typedef bool (* can_dockable_search_fc) (const GtkDockable *); + +/* Indique si le composant peut être désencapsulé manuellement. */ +typedef bool (* can_dockable_be_closed_fc) (const GtkDockable *); + /* Fournit le nom court du composant encapsulable. */ typedef const char * (* get_dockable_name_fc) (const GtkDockable *); @@ -42,7 +48,7 @@ typedef const char * (* get_dockable_desc_fc) (const GtkDockable *); typedef GtkWidget * (* get_dockable_widget_fc) (const GtkDockable *); /* Démarre l'actualisation du filtrage des paramètres. */ -typedef void (* update_filtered_data_fc) (GtkDockable *, const regex_t *); +typedef void (* update_filtered_data_fc) (GtkDockable *, char *); /* Elément accepté dans les rassemblements (interface) */ @@ -50,8 +56,8 @@ struct _GtkDockableIface { GTypeInterface base_iface; /* A laisser en premier */ - bool can_search; /* Contenu fouillable ? */ - bool can_be_closed; /* Fermeture possible ? */ + can_dockable_search_fc can_search; /* Contenu fouillable ? */ + can_dockable_be_closed_fc can_be_closed;/* Fermeture possible ? */ get_dockable_name_fc get_name; /* Nom pour titre */ get_dockable_desc_fc get_desc; /* Description humaine */ diff --git a/src/gtkext/gtkdockable.c b/src/gtkext/gtkdockable.c index cad9b43..3056402 100644 --- a/src/gtkext/gtkdockable.c +++ b/src/gtkext/gtkdockable.c @@ -33,6 +33,7 @@ #include "easygtk.h" #include "gtkdockable-int.h" +#include "tmgt.h" @@ -197,11 +198,14 @@ const char *gtk_dockable_get_desc(const GtkDockable *dockable) bool gtk_dockable_can_search(const GtkDockable *dockable) { + bool result; /* Indication à retourner */ GtkDockableIface *iface; /* Interface utilisée */ iface = GTK_DOCKABLE_GET_IFACE(dockable); - return iface->can_search; + result = iface->can_search(dockable); + + return result; } @@ -220,11 +224,14 @@ bool gtk_dockable_can_search(const GtkDockable *dockable) bool gtk_dockable_can_be_closed(const GtkDockable *dockable) { + bool result; /* Indication à retourner */ GtkDockableIface *iface; /* Interface utilisée */ iface = GTK_DOCKABLE_GET_IFACE(dockable); - return iface->can_be_closed; + result = iface->can_be_closed(dockable); + + return result; } @@ -256,7 +263,7 @@ GtkWidget *gtk_dockable_build_widget(GtkDockable *dockable) /* Encapsulation avec un panneau coulissant ? */ - if (iface->can_search) + if (gtk_dockable_can_search(dockable)) { revealer = gtk_revealer_new(); gtk_widget_show(revealer); @@ -305,7 +312,7 @@ GtkWidget *gtk_dockable_decompose(GtkDockable *dockable, GtkWidget **support) result = iface->get_widget(dockable); - if (iface->can_search) + if (gtk_dockable_can_search(dockable)) result = gtk_widget_get_parent(result); /* GtkBox */ if (support != NULL) @@ -407,56 +414,12 @@ static GtkWidget *build_search_area(GtkDockable *dockable, GtkWidget **search) static void on_dockable_search_changed(GtkSearchEntry *entry, GtkDockable *dockable) { - regex_t *filter; /* Expression régulière */ - const gchar *text; /* Texte de l'utilisateur */ - GtkStyleContext *context; /* Contexte du thème actuel */ - int ret; /* Bilan de mise en place */ + char *filter; /* Nouveau filtre à considérer */ GtkDockableIface *iface; /* Interface utilisée */ - filter = g_object_get_data(G_OBJECT(entry), "preg_filter"); - - text = gtk_entry_get_text(GTK_ENTRY(entry)); - - context = gtk_widget_get_style_context(GTK_WIDGET(entry)); - - /* Mise en place d'une nouvelle règle */ - if (strlen(text) > 0) - { - if (filter == NULL) - { - void destroy_filter(regex_t *preg) - { - regfree(preg); - free(preg); - } - - filter = (regex_t *)calloc(1, sizeof(regex_t)); - g_object_set_data_full(G_OBJECT(entry), "preg_filter", filter, (GDestroyNotify)destroy_filter); - - } - else - regfree(filter); - - ret = regcomp(filter, text, REG_EXTENDED); - - if (ret != 0) - { - gtk_style_context_add_class(context, "filter-error"); - return; - } - - } - - /* Suppresion de toute règle existante */ - else if (filter != NULL) - { - g_object_set_data(G_OBJECT(entry), "preg_filter", NULL); - filter = NULL; - } - - /* Mises à jour */ + filter = NULL; - gtk_style_context_remove_class(context, "filter-error"); + update_regex_on_search_entry_changed(entry, &filter); iface = GTK_DOCKABLE_GET_IFACE(dockable); diff --git a/src/gtkext/tmgt.c b/src/gtkext/tmgt.c index 536adb0..7e815f6 100644 --- a/src/gtkext/tmgt.c +++ b/src/gtkext/tmgt.c @@ -24,6 +24,7 @@ #include "tmgt.h" +#include <assert.h> #include <malloc.h> #include <string.h> @@ -45,41 +46,52 @@ * * ******************************************************************************/ -void update_regex_on_search_entry_changed(GtkSearchEntry *entry, regex_t **filter) +void update_regex_on_search_entry_changed(GtkSearchEntry *entry, char **filter) { const gchar *text; /* Texte de l'utilisateur */ - GtkStyleContext *context; /* Contexte du thème actuel */ + bool has_error; /* Détecttion d'une erreur */ + regex_t exp; /* Expression régulière créée */ int ret; /* Bilan de mise en place */ + GtkStyleContext *context; /* Contexte du thème actuel */ if (*filter != NULL) - { - regfree(*filter); free(*filter); - *filter = NULL; - } + + /* Validation et exportation des résultats */ text = gtk_entry_get_text(GTK_ENTRY(entry)); - context = gtk_widget_get_style_context(GTK_WIDGET(entry)); + if (strlen(text) == 0) + { + has_error = false; + *filter = NULL; + } - if (strlen(text) > 0) + else { - *filter = (regex_t *)calloc(1, sizeof(regex_t)); - ret = regcomp(*filter, text, REG_EXTENDED | REG_ICASE); + ret = regcomp(&exp, text, REG_EXTENDED | REG_ICASE); - if (ret != 0) - { - free(*filter); - *filter = NULL; + has_error = (ret != 0); - gtk_style_context_add_class(context, "filter-error"); - return; + if (has_error) + *filter = NULL; + else + { + *filter = strdup(text); + regfree(&exp); } } - gtk_style_context_remove_class(context, "filter-error"); + /* Indication à l'écran */ + + context = gtk_widget_get_style_context(GTK_WIDGET(entry)); + + if (has_error) + gtk_style_context_add_class(context, "filter-error"); + else + gtk_style_context_remove_class(context, "filter-error"); } @@ -103,10 +115,11 @@ bool is_content_matching(const regex_t *filter, const char *content, regmatch_t bool result; /* Bilan à retourner */ int ret; /* Bilan du filtrage */ - memset(match, 0, sizeof(regmatch_t)); - if (filter == NULL) + { + memset(match, 0, sizeof(regmatch_t)); result = true; + } else { @@ -199,3 +212,70 @@ char *build_highlighted_name(const char *raw, const regmatch_t *match, size_t st return result; } + + +/****************************************************************************** +* * +* Paramètres : store = organisation des données sous forme arborescente. * +* iter = position du noeud courant à traiter. * +* show = visibilité à obtenir pour le noeud final. * +* * +* Description : Met à jour l'affichage des noeuds en fonction des besoin. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +void update_node_visibility(GtkTreeStore *store, GtkTreeIter *iter, gint column, bool show) +{ + GtkTreeModel *model; /* Autre vision du gestionnaire*/ + gint matched_col; /* Colonne de visibilité */ + gint points_col; /* Colonne des points */ + guint points; /* Compteur de besoins */ + GtkTreeIter parent; /* Position de noeuf parent */ + gboolean further; /* Poursuite de remontée */ + + model = GTK_TREE_MODEL(store); + + matched_col = column; + points_col = column + 1; + + /* Enumération des besoins */ + + gtk_tree_model_get(model, iter, points_col, &points, -1); + + if (show) + points++; + + else + { + assert(points > 0); + points--; + } + + gtk_tree_store_set(store, iter, points_col, points, -1); + + /* Adaptation de l'affichage */ + + if (show) + { + if (points == 1) + gtk_tree_store_set(store, iter, matched_col, true, -1); + } + + else + { + if (points == 0) + gtk_tree_store_set(store, iter, matched_col, false, -1); + } + + /* Eventuel étage supérieur */ + + further = gtk_tree_model_iter_parent(model, &parent, iter); + + if (further) + update_node_visibility(store, &parent, column, show); + +} diff --git a/src/gtkext/tmgt.h b/src/gtkext/tmgt.h index 189e704..3f3a4f3 100644 --- a/src/gtkext/tmgt.h +++ b/src/gtkext/tmgt.h @@ -32,7 +32,7 @@ /* Met à jour un filtre selon un contenu recherché. */ -void update_regex_on_search_entry_changed(GtkSearchEntry *, regex_t **); +void update_regex_on_search_entry_changed(GtkSearchEntry *, char **); /* Détermine si un contenu correspond à un filtre donné. */ bool is_content_matching(const regex_t *, const char *, regmatch_t *); @@ -40,6 +40,9 @@ 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); +/* Met à jour l'affichage des noeuds en fonction des besoin. */ +void update_node_visibility(GtkTreeStore *, GtkTreeIter *, gint, bool); + #endif /* _COMMON_TMGT_H */ diff --git a/src/gui/panels/Makefile.am b/src/gui/panels/Makefile.am index de4c37d..b273f82 100644 --- a/src/gui/panels/Makefile.am +++ b/src/gui/panels/Makefile.am @@ -6,6 +6,7 @@ noinst_LTLIBRARIES = libguipanels.la UI_FILES = \ bintree.ui \ errors.ui \ + strings.ui \ symbols.ui \ welcome.ui diff --git a/src/gui/panels/bintree.c b/src/gui/panels/bintree.c index c2caef7..642a71c 100644 --- a/src/gui/panels/bintree.c +++ b/src/gui/panels/bintree.c @@ -25,6 +25,7 @@ #include "bintree.h" +#include <assert.h> #include <malloc.h> #include <regex.h> @@ -33,11 +34,15 @@ #include "panel-int.h" +#include "updating-int.h" #include "../core/global.h" +#include "../../core/queue.h" #include "../../gtkext/tmgt.h" +/* -------------------------- PARTIE PRINCIPALE DU PANNEAU -------------------------- */ + /* Origine de la dernière ouverture/fermeture reproductible */ typedef enum _UserActionType { @@ -47,18 +52,16 @@ typedef enum _UserActionType } UserActionType; - /* Panneau de présentation des portions (instance) */ struct _GBintreePanel { GPanelItem parent; /* A laisser en premier */ GLoadedBinary *binary; /* Binaire représenté */ - regex_t *filter; /* Filtre appliqué ou NULL */ UserActionType last; /* Dernière action */ - GtkTreeIter *top; /* Transfert de racine */ + size_t count; /* Quantité de portions utiles */ }; @@ -73,6 +76,8 @@ struct _GBintreePanelClass /* 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 */ @@ -80,45 +85,122 @@ typedef enum _BinaryTreeColumn BTC_RIGHTS, /* Droits d'accès */ BTC_MATCHED, /* Correspondance établie ? */ - BTC_PORTION /* Elément interne représenté */ + 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 *); +/* 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_binary(GBintreePanel *, GLoadedBinary *); + + + +/* -------------------------- AFFICHAGE SOUS FORME D'ARBRE -------------------------- */ + + /* Parcourt un ensemble de portions. */ -static bool populate_tree_with_portion(GBinPortion *, GBinPortion *, BinaryPortionVisit, GBintreePanel *); +static bool populate_tree_with_portion(GBinPortion *, GBinPortion *, BinaryPortionVisit, bintree_update_data *); /* Réagit à un changement d'affichage principal de contenu. */ -static void update_panel_with_binary_portions(GBintreePanel *, GLoadedBinary *); +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 *, gint, const regmatch_t *); + + + +/* ------------------------- FILTRAGE DES SYMBOLES PRESENTS ------------------------- */ -/* 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 *); +/* 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 *); -/* Réagit au changement de sélection des portions. */ -static void on_bintree_selection_changed(GtkTreeSelection *, gpointer); +/* ---------------------- 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 */ + +}; + + +#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(GBintreePanel, g_bintree_panel, G_TYPE_PANEL_ITEM); +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)); /****************************************************************************** @@ -137,6 +219,7 @@ static void g_bintree_panel_class_init(GBintreePanelClass *klass) { GObjectClass *object; /* Autre version de la classe */ GEditorItemClass *editem; /* Encore une autre vision... */ + GPanelItemClass *panel; /* Version parente de la classe*/ object = G_OBJECT_CLASS(klass); @@ -145,7 +228,11 @@ static void g_bintree_panel_class_init(GBintreePanelClass *klass) editem = G_EDITOR_ITEM_CLASS(klass); - editem->update_binary = (update_item_binary_fc)update_panel_with_binary_portions; + editem->update_binary = (update_item_binary_fc)change_bintree_panel_current_binary; + + panel = G_PANEL_ITEM_CLASS(klass); + + panel->gid = setup_tiny_global_work_group(1); } @@ -187,7 +274,6 @@ static void g_bintree_panel_init(GBintreePanel *panel) /* Compléments propres */ panel->binary = NULL; - panel->filter = NULL; panel->last = UAT_EXPAND; @@ -251,6 +337,30 @@ static void g_bintree_panel_init(GBintreePanel *panel) /****************************************************************************** * * +* 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. * @@ -285,12 +395,6 @@ static void g_bintree_panel_dispose(GBintreePanel *panel) 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)); } @@ -321,122 +425,216 @@ GPanelItem *g_bintree_panel_new(void) /****************************************************************************** * * -* 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. * +* Paramètres : button = bouton de réglage de l'affichage. * +* treeview = arborescence dont l'affichage est à moduler. * * * -* Description : Parcourt un ensemble de portions. * +* Description : Modifie la profondeur affichée des portions présentes. * * * -* Retour : true pour continuer la visite. * +* Retour : - * * * * Remarques : - * * * ******************************************************************************/ -static bool populate_tree_with_portion(GBinPortion *portion, GBinPortion *parent, BinaryPortionVisit visit, GBintreePanel *panel) +static void on_depth_spin_value_changed(GtkSpinButton *button, const 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 */ + gint max_depth; /* Profondeur maximale */ GtkBuilder *builder; /* Constructeur utilisé */ + GtkTreeView *treeview; /* Arborescence constituée */ GtkTreeStore *store; /* Modèle de gestion */ - GtkTreeIter iter; /* Point d'insertion */ - GtkTreeIter *save; /* Sauvegarde d'une position */ - if (parent == NULL) - return true; + max_depth = gtk_spin_button_get_value_as_int(button); - /* Insertion de la portion courante */ + gboolean apply_max_depth(GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, gpointer unused) + { + gint depth; /* Profondeur du point courant */ - if (visit == BPV_ENTER || visit == BPV_SHOW) + 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 = G_PANEL_ITEM(panel)->builder; + + 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); + +} + + +/****************************************************************************** +* * +* 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)) { - /* Etiquette */ + 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. * +* binary = nouvelle instance de binaire analysé. * +* * +* Description : Réagit à un changement d'affichage principal de contenu. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void change_bintree_panel_current_binary(GBintreePanel *panel, GLoadedBinary *binary) +{ + GtkBuilder *builder; /* Constructeur utilisé */ + GtkTreeStore *store; /* Modèle de gestion */ + + /* 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)); - desc = g_binary_portion_get_desc(portion); + /* Réinitialisation */ - fmatched = is_content_matching(panel->filter, desc, &match); - node_caption = build_highlighted_name(desc, &match, 0); + builder = G_PANEL_ITEM(panel)->builder; - /* Point de départ */ + store = GTK_TREE_STORE(gtk_builder_get_object(builder, "store")); - range = g_binary_portion_get_range(portion); + gtk_tree_store_clear(store); - vmpa2_phys_to_string(get_mrange_addr(range), MDS_UNDEFINED, offset, NULL); + /* Si le panneau actif représente un binaire, actualisation de l'affichage */ - fmatched |= is_content_matching(panel->filter, offset, &match); - node_start = build_highlighted_name(offset, &match, 0); + if (binary != NULL) + run_panel_update(G_UPDATABLE_PANEL(panel), PUI_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); +/* ---------------------------------------------------------------------------------- */ +/* AFFICHAGE SOUS FORME D'ARBRE */ +/* ---------------------------------------------------------------------------------- */ - /* Droits nominaux */ - rights = g_binary_portion_get_rights(portion); +/****************************************************************************** +* * +* 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 : - * +* * +******************************************************************************/ - hrights[0] = (rights & PAC_READ ? 'r' : '-'); - hrights[1] = (rights & PAC_WRITE ? 'w' : '-'); - hrights[2] = (rights & PAC_EXEC ? 'x' : '-'); - hrights[3] = '\0'; +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 */ - fmatched |= is_content_matching(panel->filter, hrights, &match); - node_rights = build_highlighted_name(hrights, &match, 0); + if (parent == NULL) + return true; + + panel = data->panel; - /* Intégration */ + /* Insertion de la portion courante */ + if (visit == BPV_ENTER || visit == BPV_SHOW) + { icon = NULL; builder = G_PANEL_ITEM(panel)->builder; store = GTK_TREE_STORE(gtk_builder_get_object(builder, "store")); - gtk_tree_store_append(store, &iter, panel->top); + gtk_tree_store_append(store, &iter, data->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, + BTC_ICON, icon, + BTC_CAPTION, NULL, + BTC_START, NULL, + BTC_END, NULL, + BTC_RIGHTS, NULL, + BTC_MATCHED, false, + BTC_MATCH_POINTS, 0, -1); - free(node_caption); - free(node_start); - free(node_end); - free(node_rights); - if (icon != NULL) cairo_surface_destroy(icon); + update_bintree_node(data, store, &iter, portion); + + } /* Définition de la hiérarchie */ if (visit == BPV_ENTER) { - save = gtk_tree_iter_copy(panel->top); + save = gtk_tree_iter_copy(data->top); g_object_set_data_full(G_OBJECT(portion), "_save", save, (GDestroyNotify)gtk_tree_iter_free); - *panel->top = iter; + *data->top = iter; } @@ -444,7 +642,7 @@ static bool populate_tree_with_portion(GBinPortion *portion, GBinPortion *parent { save = g_object_get_data(G_OBJECT(portion), "_save"); - *panel->top = *save; + *data->top = *save; g_object_set_data(G_OBJECT(portion), "_save", NULL); @@ -458,7 +656,9 @@ static bool populate_tree_with_portion(GBinPortion *portion, GBinPortion *parent /****************************************************************************** * * * Paramètres : panel = panneau à mettre à jour. * -* binary = nouvelle instance de binaire analysé. * +* 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. * * * @@ -468,7 +668,7 @@ static bool populate_tree_with_portion(GBinPortion *portion, GBinPortion *parent * * ******************************************************************************/ -static void update_panel_with_binary_portions(GBintreePanel *panel, GLoadedBinary *binary) +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 */ @@ -479,44 +679,31 @@ static void update_panel_with_binary_portions(GBintreePanel *panel, GLoadedBinar 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; - builder = G_PANEL_ITEM(panel)->builder; store = GTK_TREE_STORE(gtk_builder_get_object(builder, "store")); - gtk_tree_store_clear(store); + /* Constitution de l'arborescence */ - /* Chargement */ + format = g_loaded_binary_get_format(panel->binary); - if (binary != NULL) - { - g_object_ref(G_OBJECT(binary)); - - format = g_loaded_binary_get_format(binary); - - portions = g_exe_format_get_portions(format); + portions = g_exe_format_get_portions(format); - gtk_tree_store_append(store, &top, NULL); + 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); + gtk_tree_store_set(store, &top, + BTC_ICON, NULL, + BTC_CAPTION, g_loaded_binary_get_name(panel->binary, false), + -1); - panel->top = ⊤ - g_binary_portion_visit(portions, (visit_portion_fc)populate_tree_with_portion, panel); + data->panel = panel; + data->top = ⊤ - g_object_unref(G_OBJECT(portions)); + g_binary_portion_visit(portions, (visit_portion_fc)populate_tree_with_portion, data); - g_object_unref(G_OBJECT(format)); + g_object_unref(G_OBJECT(portions)); - } + g_object_unref(G_OBJECT(format)); /* Détermination de la profondeur maximale */ @@ -556,23 +743,23 @@ static void update_panel_with_binary_portions(GBintreePanel *panel, GLoadedBinar break; case UAT_DEPTH: - on_depth_spin_value_changed(depth_spin, treeview); + on_depth_spin_value_changed(depth_spin, panel); 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. * +* 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 : Modifie la profondeur affichée des portions présentes. * +* Description : Met en surbrillance les éléments recherchés dans les noms. * * * * Retour : - * * * @@ -580,35 +767,61 @@ static void update_panel_with_binary_portions(GBintreePanel *panel, GLoadedBinar * * ******************************************************************************/ -static void on_depth_spin_value_changed(GtkSpinButton *button, GtkTreeView *treeview) +static void update_bintree_column_in_tree_view(GtkTreeStore *store, GtkTreeIter *iter, GBinPortion *portion, gint column, const regmatch_t *match) { - gint max_depth; /* Profondeur maximale */ - GtkTreeModel *model; /* Modèle de gestion */ - - max_depth = gtk_spin_button_get_value_as_int(button); + 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 */ - gboolean apply_max_depth(GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, gpointer unused) + switch (column) { - gint depth; /* Profondeur du point courant */ + case BTC_CAPTION: + content = g_binary_portion_get_desc(portion); + break; - depth = gtk_tree_store_iter_depth(GTK_TREE_STORE(model), iter); + 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; - if (depth < max_depth) - gtk_tree_view_expand_to_path(treeview, path); + 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; - return FALSE; + 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; } - gtk_tree_view_collapse_all(treeview); + value = build_highlighted_name(content, match, 0); - model = gtk_tree_view_get_model(treeview); + gtk_tree_store_set(store, iter, column, value, -1); - gtk_tree_model_foreach(model, (GtkTreeModelForeachFunc)apply_max_depth, NULL); + free(value); } + +/* ---------------------------------------------------------------------------------- */ +/* FILTRAGE DES SYMBOLES PRESENTS */ +/* ---------------------------------------------------------------------------------- */ + + /****************************************************************************** * * * Paramètres : entry = zone de texte avec un nouveau filtre d'affichage. * @@ -624,71 +837,74 @@ static void on_depth_spin_value_changed(GtkSpinButton *button, GtkTreeView *tree static void on_search_entry_changed(GtkSearchEntry *entry, GBintreePanel *panel) { - update_regex_on_search_entry_changed(entry, &panel->filter); + update_regex_on_search_entry_changed(entry, &G_PANEL_ITEM(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)); - } + run_panel_update(G_UPDATABLE_PANEL(panel), PUI_1); } /****************************************************************************** * * -* Paramètres : store = gestionnaire de contenu d'une arborescence donnée. * +* 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 : Parcourt un arbre en place et retire les branches filtrées. * +* Description : Détermine si un noeud de l'arborescence doit être filtré. * * * -* Retour : - * +* Retour : Bilan du filtrage. * * * * Remarques : - * * * ******************************************************************************/ -static void apply_filter_on_portions(GtkTreeStore *store) +static bool update_bintree_node(const bintree_update_data *data, GtkTreeStore *store, GtkTreeIter *iter, GBinPortion *portion) { - GtkTreeIter root; /* Racine de l'arboresence */ + 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 */ - 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 ? */ + caption_matched = is_bintree_column_matching(data, portion, BTC_CAPTION, &match); - model = GTK_TREE_MODEL(store); + if (caption_matched) + update_bintree_column_in_tree_view(store, iter, portion, BTC_CAPTION, &match); - children_count = gtk_tree_model_iter_n_children(model, iter); + start_matched = is_bintree_column_matching(data, portion, BTC_START, &match); - for (i = children_count; i > 0; i--) - if (gtk_tree_model_iter_nth_child(model, &child, iter, i - 1)) - check_portion_iter(&child); + if (start_matched) + update_bintree_column_in_tree_view(store, iter, portion, BTC_START, &match); - children_count = gtk_tree_model_iter_n_children(model, iter); + end_matched = is_bintree_column_matching(data, portion, BTC_END, &match); - gtk_tree_model_get(model, iter, BTC_MATCHED, &fmatched, -1); + if (end_matched) + update_bintree_column_in_tree_view(store, iter, portion, BTC_END, &match); - if (!fmatched && children_count == 0) - gtk_tree_store_remove(store, iter); + 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); - if (gtk_tree_model_get_iter_first(GTK_TREE_MODEL(store), &root)) - check_portion_iter(&root); + result = (caption_matched || start_matched || end_matched || rights_matched); + + gtk_tree_store_set(store, iter, BTC_MATCHED, result, -1); + + return result; } /****************************************************************************** * * -* Paramètres : selection = sélection modifiée. * -* unused = adresse non utilisée ici. * +* 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 : Réagit au changement de sélection des portions. * +* Description : Exécute un nouveau filtrage des symboles affichés. * * * * Retour : - * * * @@ -696,33 +912,377 @@ static void apply_filter_on_portions(GtkTreeStore *store) * * ******************************************************************************/ -static void on_bintree_selection_changed(GtkTreeSelection *selection, gpointer unused) +static void do_filtering_on_portions(const GBintreePanel *panel, GtkStatusStack *status, activity_id_t id, bintree_update_data *data) { - 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 */ + GtkBuilder *builder; /* Constructeur utilisé */ + GtkTreeStore *store; /* Modèle de gestion */ - if (gtk_tree_selection_get_selected(selection, &model, &iter)) + + gboolean filter_portion_panel_iter(GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, gpointer unused) { - gtk_tree_model_get(model, &iter, BTC_PORTION, &portion, -1); + 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) { - range = g_binary_portion_get_range(portion); + matched = update_bintree_node(data, store, iter, portion); - panel = get_current_view(); + gtk_tree_model_get(model, iter, BTC_MATCHED, &shown, -1); - if (GTK_IS_DISPLAY_PANEL(panel)) - gtk_display_panel_request_move(GTK_DISPLAY_PANEL(panel), get_mrange_addr(range)); + if (!matched) + { + if (shown) + update_node_visibility(store, iter, BTC_MATCHED, false); + } - g_object_unref(G_OBJECT(panel)); + 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 = G_PANEL_ITEM(panel)->builder; + + store = GTK_TREE_STORE(gtk_builder_get_object(builder, "store")); + + gtk_tree_model_foreach(GTK_TREE_MODEL(store), (GtkTreeModelForeachFunc)filter_portion_panel_iter, NULL); + +} + + + +/* ---------------------------------------------------------------------------------- */ +/* 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 */ + int ret; /* Bilan de mise en place */ + GtkBuilder *builder; /* Constructeur utilisé */ + GtkTreeView *treeview; /* Arborescence graphique */ + + *data = malloc(sizeof(bintree_update_data)); + + switch (uid) + { + case PUI_0: + + *count = 1; + (*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)); + + ret = regcomp((*data)->filter, G_PANEL_ITEM(panel)->filter, REG_EXTENDED | REG_ICASE); + assert(ret == 0); + + } + + else + (*data)->filter = NULL; + + /* Mémorisation de tous les noeuds ouverts */ + + builder = G_PANEL_ITEM(panel)->builder; + + 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); + + 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 = G_PANEL_ITEM(panel)->builder; + + 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); + } + +} + + +/****************************************************************************** +* * +* 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 = G_PANEL_ITEM(panel)->builder; + + 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); + } + 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); + } diff --git a/src/gui/panels/bintree.ui b/src/gui/panels/bintree.ui index aa5a112..90aac50 100644 --- a/src/gui/panels/bintree.ui +++ b/src/gui/panels/bintree.ui @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8"?> -<!-- Generated with glade 3.20.0 --> +<!-- Generated with glade 3.21.0 --> <interface> <requires lib="gtk+" version="3.12"/> <object class="GtkAdjustment" id="adjustment1"> @@ -19,9 +19,11 @@ </object> <object class="GtkTreeStore" id="store"> <columns> + <!-- column-name portion --> + <column type="GObject"/> <!-- column-name icon --> <column type="CairoSurface"/> - <!-- column-name name --> + <!-- column-name caption --> <column type="gchararray"/> <!-- column-name start --> <column type="gchararray"/> @@ -31,10 +33,13 @@ <column type="gchararray"/> <!-- column-name matched --> <column type="gboolean"/> - <!-- column-name portion --> - <column type="GObject"/> + <!-- column-name match_points --> + <column type="guint"/> </columns> </object> + <object class="GtkTreeModelFilter" id="filter"> + <property name="child_model">store</property> + </object> <object class="GtkOffscreenWindow" id="offscreenwindow1"> <property name="can_focus">False</property> <property name="margin_left">8</property> @@ -120,7 +125,7 @@ <property name="progress_pulse_step">1</property> <property name="adjustment">adjustment1</property> <property name="numeric">True</property> - <signal name="value-changed" handler="on_depth_spin_value_changed" object="treeview" swapped="no"/> + <signal name="value-changed" handler="on_depth_spin_value_changed" swapped="no"/> </object> </child> </object> @@ -168,22 +173,45 @@ </packing> </child> <child> - <object class="GtkScrolledWindow" id="scrolledwindow1"> + <object class="GtkStack" id="stack"> <property name="visible">True</property> - <property name="can_focus">True</property> - <property name="shadow_type">in</property> + <property name="can_focus">False</property> <child> - <object class="GtkTreeView" id="treeview"> + <object class="GtkScrolledWindow" id="content"> <property name="visible">True</property> <property name="can_focus">True</property> - <property name="model">store</property> - <property name="headers_visible">False</property> - <child internal-child="selection"> - <object class="GtkTreeSelection" id="treeview-selection1"> - <signal name="changed" handler="on_bintree_selection_changed" swapped="no"/> + <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">filter</property> + <property name="headers_visible">False</property> + <property name="search_column">1</property> + <child internal-child="selection"> + <object class="GtkTreeSelection"> + <signal name="changed" handler="on_bintree_selection_changed" swapped="no"/> + </object> + </child> </object> </child> </object> + <packing> + <property name="name">page0</property> + <property name="title" translatable="yes">page0</property> + </packing> + </child> + <child> + <object class="GtkSpinner" id="mask"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="active">True</property> + </object> + <packing> + <property name="name">page1</property> + <property name="title" translatable="yes">page1</property> + <property name="position">1</property> + </packing> </child> </object> <packing> @@ -194,5 +222,8 @@ </child> </object> </child> + <child type="titlebar"> + <placeholder/> + </child> </object> </interface> diff --git a/src/gui/panels/bookmarks.c b/src/gui/panels/bookmarks.c index b7d0bc3..104e519 100644 --- a/src/gui/panels/bookmarks.c +++ b/src/gui/panels/bookmarks.c @@ -41,6 +41,7 @@ #include "../../common/cpp.h" #include "../../common/extstr.h" #include "../../core/params.h" +#include "../../core/queue.h" #include "../../glibext/chrysamarshal.h" #include "../../glibext/signal.h" #include "../../gtkext/easygtk.h" @@ -99,9 +100,6 @@ static void g_bookmarks_panel_class_init(GBookmarksPanelClass *); /* Initialise une instance de panneau de paramètres de config. */ static void g_bookmarks_panel_init(GBookmarksPanel *); -/* Procède à l'initialisation de l'interface de rassemblement. */ -static void g_bookmarks_panel_dockable_interface_init(GtkDockableInterface *); - /* Supprime toutes les références externes. */ static void g_bookmarks_panel_dispose(GBookmarksPanel *); @@ -145,7 +143,7 @@ static void on_param_value_edited(GtkCellRendererText *, gchar *, gchar *, GtkTr /* Démarre l'actualisation du filtrage des paramètres. */ -static void update_filtered_bookmarks(GBookmarksPanel *, const regex_t *); +static void update_filtered_bookmarks(GBookmarksPanel *); /* Détermine si un signet doit être filtré ou non. */ static bool is_bookmark_filtered(GBookmarksPanel *, const char *, const char *, const char *); @@ -181,8 +179,7 @@ static void mcb_bookmarks_panel_filter(GtkMenuItem *, GBookmarksPanel *); /* Indique le type définit pour un panneau d'affichage des signets liés à un binaire. */ -G_DEFINE_TYPE_WITH_CODE(GBookmarksPanel, g_bookmarks_panel, G_TYPE_PANEL_ITEM, - G_IMPLEMENT_INTERFACE(GTK_TYPE_DOCKABLE, g_bookmarks_panel_dockable_interface_init)); +G_DEFINE_TYPE(GBookmarksPanel, g_bookmarks_panel, G_TYPE_PANEL_ITEM); /****************************************************************************** @@ -201,6 +198,7 @@ static void g_bookmarks_panel_class_init(GBookmarksPanelClass *klass) { GObjectClass *object; /* Autre version de la classe */ GEditorItemClass *editem; /* Encore une autre vision... */ + GPanelItemClass *panel; /* Version parente de la classe*/ gchar *filename; /* Chemin d'accès à utiliser */ object = G_OBJECT_CLASS(klass); @@ -212,6 +210,15 @@ static void g_bookmarks_panel_class_init(GBookmarksPanelClass *klass) editem->update_binary = (update_item_binary_fc)reload_bookmarks_into_treeview; + panel = G_PANEL_ITEM_CLASS(klass); + + panel->can_search = true; + panel->can_be_closed = true; + + panel->update_filtered = (update_filtered_fc)update_filtered_bookmarks; + + panel->gid = setup_tiny_global_work_group(1); + filename = find_pixmap_file("bookmark.png"); assert(filename != NULL); @@ -349,35 +356,6 @@ static void g_bookmarks_panel_init(GBookmarksPanel *panel) /****************************************************************************** * * -* Paramètres : iface = interface GTK à initialiser. * -* * -* Description : Procède à l'initialisation de l'interface de rassemblement. * -* * -* Retour : - * -* * -* Remarques : - * -* * -******************************************************************************/ - -static void g_bookmarks_panel_dockable_interface_init(GtkDockableInterface *iface) -{ - GtkDockableInterface *parent_iface; /* Définition précédente */ - - parent_iface = (GtkDockableInterface *)g_type_interface_peek_parent(iface); - - iface->can_search = true; - iface->can_be_closed = true; - - iface->get_name = parent_iface->get_name; - iface->get_desc = parent_iface->get_desc; - iface->get_widget = parent_iface->get_widget; - iface->update_filtered = (update_filtered_data_fc)update_filtered_bookmarks; - -} - - -/****************************************************************************** -* * * Paramètres : panel = instance d'objet GLib à traiter. * * * * Description : Supprime toutes les références externes. * @@ -966,7 +944,6 @@ static void on_param_value_edited(GtkCellRendererText *renderer, gchar *path, gc /****************************************************************************** * * * Paramètres : panel = panneau assurant l'affichage des paramètres. * -* preg = expression régulière compilée à utiliser. * * * * Description : Démarre l'actualisation du filtrage des paramètres. * * * @@ -976,11 +953,9 @@ static void on_param_value_edited(GtkCellRendererText *renderer, gchar *path, gc * * ******************************************************************************/ -static void update_filtered_bookmarks(GBookmarksPanel *panel, const regex_t *preg) +static void update_filtered_bookmarks(GBookmarksPanel *panel) { - panel->filter = preg; - - reload_bookmarks_into_treeview(panel, panel->binary); + //reload_bookmarks_into_treeview(panel, panel->binary); } diff --git a/src/gui/panels/gresource.xml b/src/gui/panels/gresource.xml index 214e546..b6f6cf9 100644 --- a/src/gui/panels/gresource.xml +++ b/src/gui/panels/gresource.xml @@ -8,6 +8,7 @@ <file compressed="true">../../../pixmaps/symbol_class_classic.png</file> <file compressed="true">bintree.ui</file> <file compressed="true">errors.ui</file> + <file compressed="true">strings.ui</file> <file compressed="true">symbols.ui</file> <file compressed="true">welcome.ui</file> </gresource> diff --git a/src/gui/panels/panel-int.h b/src/gui/panels/panel-int.h index 8f5f42f..3f5213d 100644 --- a/src/gui/panels/panel-int.h +++ b/src/gui/panels/panel-int.h @@ -41,10 +41,13 @@ /* Place un panneau dans l'ensemble affiché. */ -typedef void (* ack_dock_process_fc) (GPanelItem *item); +typedef void (* ack_dock_process_fc) (GPanelItem *); /* Supprime un panneau de l'ensemble affiché. */ -typedef void (* ack_undock_process_fc) (GPanelItem *item); +typedef void (* ack_undock_process_fc) (GPanelItem *); + +/* Démarre l'actualisation du filtrage du contenu. */ +typedef void (* update_filtered_fc) (GPanelItem *); /* Elément réactif pour panneaux de l'éditeur (instance) */ @@ -63,6 +66,8 @@ struct _GPanelItem bool docked; /* Panneau inscrusté ? */ + char *filter; /* Eventuel filtre textuel */ + /** * La gestion générique du constructeur repose sur quelques * prérequis quant à l'enregistrement de composants : @@ -92,9 +97,14 @@ struct _GPanelItemClass bool unique; /* Panneau instanciable ? */ const char *bindings; /* Raccourci clavier éventuel */ + bool can_search; /* Contenu fouillable ? */ + bool can_be_closed; /* Fermeture possible ? */ + ack_dock_process_fc ack_dock; /* Prise en compte d'accroche */ ack_undock_process_fc ack_undock; /* Prise en compte de décroche */ + update_filtered_fc update_filtered; /* Lancement du filtrage */ + wgroup_id_t gid; /* Groupe de travail dédié */ /* Signaux */ diff --git a/src/gui/panels/panel.c b/src/gui/panels/panel.c index 424e779..78f70f3 100644 --- a/src/gui/panels/panel.c +++ b/src/gui/panels/panel.c @@ -54,6 +54,12 @@ static void g_panel_item_dispose(GPanelItem *); /* Procède à la libération totale de la mémoire. */ static void g_panel_item_finalize(GPanelItem *); +/* Détermine si un panneau peut être filtré. */ +static bool gtk_panel_item_can_search(const GPanelItem *); + +/* Détermine si un panneau peut être fermé. */ +static bool gtk_panel_item_can_be_closed(const GPanelItem *); + /* Fournit le nom court du composant encapsulable. */ static const char *gtk_panel_item_get_name(const GPanelItem *); @@ -63,6 +69,9 @@ static const char *gtk_panel_item_get_desc(const GPanelItem *); /* Fournit le composant graphique intégrable dans un ensemble. */ static GtkWidget *gtk_panel_item_get_widget(GPanelItem *); +/* Démarre l'actualisation du filtrage du contenu. */ +static void gtk_panel_item_update_filtered(GPanelItem *, char *); + /* Construit la chaîne d'accès à un élément de configuration. */ static char *gtk_panel_item_build_configuration_key(const GPanelItem *, const char *); @@ -123,6 +132,9 @@ static void g_panel_item_class_init(GPanelItemClass *klass) g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0); + klass->can_search = false; + klass->can_be_closed = false; + } @@ -144,6 +156,8 @@ static void g_panel_item_init(GPanelItem *item) item->personality = PIP_INVALID; + item->filter = NULL; + g_atomic_int_set(&item->switched, 0); } @@ -163,13 +177,12 @@ static void g_panel_item_init(GPanelItem *item) static void g_panel_item_dockable_interface_init(GtkDockableInterface *iface) { - iface->can_search = false; - iface->can_be_closed = true; - + iface->can_search = (can_dockable_search_fc)gtk_panel_item_can_search; + iface->can_be_closed = (can_dockable_search_fc)gtk_panel_item_can_be_closed; iface->get_name = (get_dockable_name_fc)gtk_panel_item_get_name; iface->get_desc = (get_dockable_desc_fc)gtk_panel_item_get_desc; iface->get_widget = (get_dockable_widget_fc)gtk_panel_item_get_widget; - iface->update_filtered = (update_filtered_data_fc)NULL; + iface->update_filtered = (update_filtered_data_fc)gtk_panel_item_update_filtered; } @@ -212,6 +225,9 @@ static void g_panel_item_finalize(GPanelItem *item) { free(item->path); + if (item->filter != NULL) + free(item->filter); + if (item->surface != NULL) cairo_surface_destroy(item->surface); @@ -306,6 +322,58 @@ GtkBuilder *g_panel_item_build(GPanelItem *item, const char *name) * * * Paramètres : item = instance GTK dont l'interface est à consulter. * * * +* Description : Détermine si un panneau peut être filtré. * +* * +* Retour : Bilan de la consultation. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static bool gtk_panel_item_can_search(const GPanelItem *item) +{ + bool result; /* Indication à retourner */ + GPanelItemClass *class; /* Classe de l'élément visé */ + + class = G_PANEL_ITEM_GET_CLASS(item); + + result = class->can_search; + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : item = instance GTK dont l'interface est à consulter. * +* * +* Description : Détermine si un panneau peut être fermé. * +* * +* Retour : Bilan de la consultation. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static bool gtk_panel_item_can_be_closed(const GPanelItem *item) +{ + bool result; /* Indication à retourner */ + GPanelItemClass *class; /* Classe de l'élément visé */ + + class = G_PANEL_ITEM_GET_CLASS(item); + + result = class->can_be_closed; + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : item = instance GTK dont l'interface est à consulter. * +* * * Description : Fournit le nom court du composant encapsulable. * * * * Retour : Désignation humaine pour titre d'onglet ou de fenêtre. * @@ -361,6 +429,32 @@ static GtkWidget *gtk_panel_item_get_widget(GPanelItem *item) /****************************************************************************** * * +* Paramètres : item = instance GTK dont l'interface est à sollicitée. * +* * +* Description : Démarre l'actualisation du filtrage du contenu. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void gtk_panel_item_update_filtered(GPanelItem *item, char *filter) +{ + assert(gtk_panel_item_can_search(item)); + + if (item->filter != NULL) + free(item->filter); + + item->filter = filter; + + G_PANEL_ITEM_GET_CLASS(item)->update_filtered(item); + +} + + +/****************************************************************************** +* * * Paramètres : item = instance GTK à consulter. * * attrib = élément de configuration à inclure dans le résultat.* * * diff --git a/src/gui/panels/panel.h b/src/gui/panels/panel.h index bdeffcc..4a92409 100644 --- a/src/gui/panels/panel.h +++ b/src/gui/panels/panel.h @@ -34,12 +34,12 @@ -#define G_TYPE_PANEL_ITEM g_panel_item_get_type() -#define G_PANEL_ITEM(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), g_panel_item_get_type(), GPanelItem)) -#define G_IS_PANEL_ITEM(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), g_panel_item_get_type())) -#define G_PANEL_ITEM_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_PANEL_ITEM, GPanelItemClass)) -#define G_IS_PANEL_ITEM_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_PANEL_ITEM)) -#define G_PANEL_ITEM_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_PANEL_ITEM, GPanelItemClass)) +#define G_TYPE_PANEL_ITEM g_panel_item_get_type() +#define G_PANEL_ITEM(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_PANEL_ITEM, GPanelItem)) +#define G_IS_PANEL_ITEM(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_PANEL_ITEM)) +#define G_PANEL_ITEM_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_PANEL_ITEM, GPanelItemClass)) +#define G_IS_PANEL_ITEM_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_PANEL_ITEM)) +#define G_PANEL_ITEM_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_PANEL_ITEM, GPanelItemClass)) /* Elément réactif pour panneaux de l'éditeur (instance) */ diff --git a/src/gui/panels/strings.c b/src/gui/panels/strings.c index 7420ffe..4828038 100644 --- a/src/gui/panels/strings.c +++ b/src/gui/panels/strings.c @@ -25,19 +25,23 @@ #include "strings.h" +#include <assert.h> #include <string.h> #include <inttypes.h> #include "panel-int.h" +#include "updating-int.h" #include "../core/global.h" #include "../dialogs/gotox.h" #include "../../common/extstr.h" #include "../../core/params.h" +#include "../../core/queue.h" #include "../../format/format.h" #include "../../format/symiter.h" #include "../../gtkext/easygtk.h" #include "../../gtkext/gtkdockable-int.h" +#include "../../gtkext/tmgt.h" @@ -49,16 +53,14 @@ struct _GStringsPanel { GPanelItem parent; /* A laisser en premier */ - GtkTreeView *treeview; /* Composant d'affichage */ - const regex_t *filter; /* Filtre appliqué ou NULL */ + GLoadedBinary *binary; /* Binaire en cours d'analyse */ GtkMenu *menu; /* Menu contextuel pour param. */ - GLoadedBinary *binary; /* Binaire en cours d'analyse */ + size_t count; /* Quantité de symboles utiles */ }; - /* Panneau d'aperçu de graphiques (classe) */ struct _GStringsPanelClass { @@ -70,27 +72,34 @@ struct _GStringsPanelClass /* Colonnes de la liste des symboles */ typedef enum _StringsColumn { - STC_STRING, /* Elément GLib représenté */ + STC_SYMBOL, /* Symbole représenté */ STC_PHYSICAL, /* Adresse phyisque */ STC_VIRTUAL, /* Adresse virtuelle */ STC_AREA, /* Zone de localisation */ STC_NAME, /* Désignation humaine */ STC_VALUE, /* Chaîne de caractères */ + STC_ORIGINAL, /* Version brute d'origine */ + + STC_MATCHED, /* Correspondance établie ? */ STC_COUNT /* Nombre de colonnes */ } StringsColumn; +/* Données utiles à la mise à jour */ +typedef struct _strings_update_data strings_update_data; + + /* Initialise la classe des panneaux d'affichage de chaînes. */ static void g_strings_panel_class_init(GStringsPanelClass *); /* Initialise une instance de panneau d'affichage des chaînes. */ static void g_strings_panel_init(GStringsPanel *); -/* Procède à l'initialisation de l'interface de rassemblement. */ -static void g_strings_panel_dockable_interface_init(GtkDockableInterface *); +/* Procède à l'initialisation de l'interface de mise à jour. */ +static void g_strings_panel_updatable_interface_init(GUpdatablePanelInterface *); /* Supprime toutes les références externes. */ static void g_strings_panel_dispose(GStringsPanel *); @@ -98,14 +107,6 @@ static void g_strings_panel_dispose(GStringsPanel *); /* Procède à la libération totale de la mémoire. */ static void g_strings_panel_finalize(GStringsPanel *); - - -/* ------------------------- AFFICHAGE A L'AIDE D'UNE LISTE ------------------------- */ - - -/* Réagit à un changement d'affichage principal de contenu. */ -static void change_strings_panel_current_binary(GStringsPanel *, GLoadedBinary *); - /* Réagit au changement de sélection des chaînes textuelles. */ static void on_strings_selection_change(GtkTreeSelection *, gpointer); @@ -116,18 +117,38 @@ static gint compare_strings_list_columns(GtkTreeModel *, GtkTreeIter *, GtkTreeI static gboolean on_key_pressed_over_strings(GtkTreeView *, GdkEventKey *, GStringsPanel *); /* Réagit à une édition de l'étiquette d'une chaîne textuelle. */ -static void on_string_value_edited(GtkCellRendererText *, gchar *, gchar *, GtkTreeStore *); +static void on_string_name_edited(GtkCellRendererText *, gchar *, gchar *, GtkTreeModel *); +/* Réagit à un changement d'affichage principal de contenu. */ +static void change_strings_panel_current_binary(GStringsPanel *, GLoadedBinary *); -/* ------------------------- FILTRAGE DES SYMBOLES PRESENTS ------------------------- */ + +/* ------------------------- AFFICHAGE A L'AIDE D'UNE LISTE ------------------------- */ + + +/* Réagit à un changement d'affichage principal de contenu. */ +static void reload_strings_for_new_list_view(const GStringsPanel *, GtkStatusStack *, activity_id_t, strings_update_data *); + +/* Met en surbrillance les éléments recherchés dans les noms. */ +static void update_string_label_in_list_view(GtkListStore *, GtkTreeIter *, const regmatch_t *); + +/* Met en surbrillance les éléments recherchés dans les valeurs. */ +static void update_string_value_in_list_view(GtkListStore *, GtkTreeIter *, const regmatch_t *); + + + +/* ------------------------- FILTRAGE DES CHAINES PRESENTES ------------------------- */ /* Démarre l'actualisation du filtrage des chaînes. */ -static void update_filtered_strings(GStringsPanel *, const regex_t *); +static void update_filtered_strings(GStringsPanel *); + +/* Détermine si un noeud de l'arborescence doit être filtré. */ +static void update_string_node(const strings_update_data *, GtkListStore *, GtkTreeIter *); -/* Détermine si une chaîne textuelle doit être filtrée ou non. */ -static bool is_string_filtered(GStringsPanel *, const char *, const char *); +/* Exécute un nouveau filtrage des chaînes affichées. */ +static void do_filtering_on_strings(const GStringsPanel *, GtkStatusStack *, activity_id_t, strings_update_data *); @@ -141,7 +162,7 @@ static gboolean on_button_event_over_strings(GtkWidget *, GdkEventButton *, GStr static GtkMenu *build_strings_panel_menu(GStringsPanel *); /* Fournit le signet sélectionné dans la liste. */ -static GBinSymbol *get_selected_panel_symbol(GtkTreeView *, GtkTreeIter *); +static GBinSymbol *get_selected_panel_symbol(GStringsPanel *, GtkTreeIter *); /* Réagit avec le menu "Editer le nom". */ static void mcb_strings_panel_edit(GtkMenuItem *, GStringsPanel *); @@ -156,6 +177,41 @@ static void mcb_strings_panel_find_refs(GtkMenuItem *, GStringsPanel *); static void mcb_strings_panel_filter(GtkMenuItem *, GStringsPanel *); +/* ---------------------- MECANISMES DE MISE A JOUR DE PANNEAU ---------------------- */ + + +/* Données utiles à la mise à jour */ +struct _strings_update_data +{ + size_t count; /* Qté d'inscriptions réalisées*/ + + regex_t *filter; /* Filtre appliqué ou NULL */ + +}; + + +/* Détermine si un nom de symbole doit être filtré ou non. */ +static bool is_string_name_matching(const strings_update_data *, GtkTreeModel *, GtkTreeIter *, regmatch_t *); + +/* Détermine si une valeur de symbole doit être filtrée ou non. */ +static bool is_string_value_matching(const strings_update_data *, GtkTreeModel *, GtkTreeIter *, regmatch_t *); + +/* Prépare une opération de mise à jour de panneau. */ +static const char *g_strings_panel_setup(const GStringsPanel *, unsigned int, size_t *, strings_update_data **); + +/* Bascule l'affichage d'un panneau avant mise à jour. */ +static void g_strings_panel_introduce(const GStringsPanel *, unsigned int, strings_update_data *); + +/* Réalise une opération de mise à jour de panneau. */ +static void g_strings_panel_process(const GStringsPanel *, unsigned int, GtkStatusStack *, activity_id_t, strings_update_data *); + +/* Bascule l'affichage d'un panneau après mise à jour. */ +static void g_strings_panel_conclude(GStringsPanel *, unsigned int, strings_update_data *); + +/* Supprime les données dynamiques utilisées à la mise à jour. */ +static void g_strings_panel_clean_data(GUpdatablePanel *, unsigned int, strings_update_data *); + + /* ---------------------------------------------------------------------------------- */ /* PARTIE PRINCIPALE DU PANNEAU */ @@ -164,7 +220,7 @@ static void mcb_strings_panel_filter(GtkMenuItem *, GStringsPanel *); /* Indique le type définit pour un panneau d'affichage des chaînes. */ G_DEFINE_TYPE_WITH_CODE(GStringsPanel, g_strings_panel, G_TYPE_PANEL_ITEM, - G_IMPLEMENT_INTERFACE(GTK_TYPE_DOCKABLE, g_strings_panel_dockable_interface_init)); + G_IMPLEMENT_INTERFACE(G_TYPE_UPDATABLE_PANEL, g_strings_panel_updatable_interface_init)); /****************************************************************************** @@ -199,6 +255,13 @@ static void g_strings_panel_class_init(GStringsPanelClass *klass) panel->unique = true; panel->bindings = "<Shift>F12"; + panel->can_search = true; + panel->can_be_closed = true; + + panel->update_filtered = (update_filtered_fc)update_filtered_strings; + + panel->gid = setup_tiny_global_work_group(1); + } @@ -218,14 +281,13 @@ static void g_strings_panel_init(GStringsPanel *panel) { GEditorItem *base; /* Version basique d'instance */ GPanelItem *pitem; /* Version parente du panneau */ - GObject *ref; /* Espace de référencement */ - GtkTreeStore *store; /* Modèle de gestion */ - GtkWidget *treeview; /* Affichage de la liste */ + GtkBuilder *builder; /* Constructeur utilisé */ + GtkTreeModelFilter *filter; /* Filtre pour l'arborescence */ + GtkTreeView *treeview; /* Affichage de la liste */ GtkCellRenderer *renderer; /* Moteur de rendu de colonne */ GtkTreeViewColumn *column; /* Colonne de la liste */ + GtkTreeModel *model; /* Modèle de gestion de liste */ GtkTreeSortable *sortable; /* Autre vision de la liste */ - GtkTreeSelection *select; /* Sélection dans la liste */ - bool display; /* Affichage si sélection ? */ /* Eléments de base */ @@ -242,37 +304,15 @@ static void g_strings_panel_init(GStringsPanel *panel) /* Représentation graphique */ - base->widget = gtk_scrolled_window_new(NULL, NULL); - gtk_widget_show(base->widget); - - gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(base->widget), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); - gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(base->widget), GTK_SHADOW_IN); - - ref = G_OBJECT(base->widget); - g_object_set_data(ref, "panel", panel); - - /* Partie chaînes */ - - store = gtk_tree_store_new(STC_COUNT, G_TYPE_OBJECT, - G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING); - - treeview = gtk_tree_view_new_with_model(GTK_TREE_MODEL(store)); - panel->treeview = GTK_TREE_VIEW(treeview); - - g_signal_connect(G_OBJECT(treeview), "button-press-event", - G_CALLBACK(on_button_event_over_strings), panel); - g_signal_connect(G_OBJECT(treeview), "button-release-event", - G_CALLBACK(on_button_event_over_strings), panel); - g_signal_connect(G_OBJECT(treeview), "key-press-event", - G_CALLBACK(on_key_pressed_over_strings), panel); + builder = g_panel_item_build(pitem, "strings"); - gtk_widget_show(treeview); - gtk_container_add(GTK_CONTAINER(base->widget), treeview); - - g_object_unref(G_OBJECT(store)); + filter = GTK_TREE_MODEL_FILTER(gtk_builder_get_object(builder, "filter")); + gtk_tree_model_filter_set_visible_column(filter, STC_MATCHED); /* Cellules d'affichage */ + treeview = GTK_TREE_VIEW(gtk_builder_get_object(builder, "treeview")); + renderer = gtk_cell_renderer_text_new(); column = gtk_tree_view_column_new_with_attributes(_("Physical address"), renderer, "text", STC_PHYSICAL, @@ -295,9 +335,11 @@ static void g_strings_panel_init(GStringsPanel *panel) gtk_tree_view_column_set_sort_column_id(column, STC_AREA); gtk_tree_view_append_column(GTK_TREE_VIEW(treeview), column); + model = GTK_TREE_MODEL(gtk_builder_get_object(builder, "store")); + renderer = gtk_cell_renderer_text_new(); g_object_set(G_OBJECT(renderer), "editable", TRUE, NULL); - g_signal_connect(renderer, "edited", G_CALLBACK(on_string_value_edited), store); + g_signal_connect(renderer, "edited", G_CALLBACK(on_string_name_edited), model); column = gtk_tree_view_column_new_with_attributes(_("Name"), renderer, "text", STC_NAME, NULL); @@ -313,7 +355,7 @@ static void g_strings_panel_init(GStringsPanel *panel) /* Tri de la liste */ - sortable = GTK_TREE_SORTABLE(store); + sortable = GTK_TREE_SORTABLE(gtk_builder_get_object(builder, "store")); gtk_tree_sortable_set_sort_func(sortable, STC_PHYSICAL, compare_strings_list_columns, GINT_TO_POINTER(STC_PHYSICAL), NULL); @@ -332,15 +374,15 @@ static void g_strings_panel_init(GStringsPanel *panel) gtk_tree_sortable_set_sort_column_id(sortable, STC_VIRTUAL, GTK_SORT_ASCENDING); - /* Prise en compte de la sélection */ + /* Connexion des signaux */ - select = gtk_tree_view_get_selection(GTK_TREE_VIEW(treeview)); - gtk_tree_selection_set_mode(select, GTK_SELECTION_SINGLE); + gtk_builder_add_callback_symbols(builder, + "on_button_event_over_strings", G_CALLBACK(on_button_event_over_strings), + "on_key_pressed_over_strings", G_CALLBACK(on_key_pressed_over_strings), + "on_strings_selection_change", G_CALLBACK(on_strings_selection_change), + NULL); - g_generic_config_get_value(get_main_configuration(), MPK_DISPLAY_ON_SEL, &display); - - if (display) - g_signal_connect(G_OBJECT(select), "changed", G_CALLBACK(on_strings_selection_change), NULL); + gtk_builder_connect_signals(builder, panel); /* Préparation du menu contextuel */ @@ -351,9 +393,9 @@ static void g_strings_panel_init(GStringsPanel *panel) /****************************************************************************** * * -* Paramètres : iface = interface GTK à initialiser. * +* Paramètres : iface = interface GLib à initialiser. * * * -* Description : Procède à l'initialisation de l'interface de rassemblement. * +* Description : Procède à l'initialisation de l'interface de mise à jour. * * * * Retour : - * * * @@ -361,19 +403,14 @@ static void g_strings_panel_init(GStringsPanel *panel) * * ******************************************************************************/ -static void g_strings_panel_dockable_interface_init(GtkDockableInterface *iface) +static void g_strings_panel_updatable_interface_init(GUpdatablePanelInterface *iface) { - GtkDockableInterface *parent_iface; /* Définition précédente */ - - parent_iface = (GtkDockableInterface *)g_type_interface_peek_parent(iface); - - iface->can_search = true; - iface->can_be_closed = true; - - iface->get_name = parent_iface->get_name; - iface->get_desc = parent_iface->get_desc; - iface->get_widget = parent_iface->get_widget; - iface->update_filtered = (update_filtered_data_fc)update_filtered_strings; + iface->setup = (setup_updatable_cb)g_strings_panel_setup; + iface->get_group = (get_updatable_group_cb)g_panel_item_get_group; + iface->introduce = (introduce_updatable_cb)g_strings_panel_introduce; + iface->process = (process_updatable_cb)g_strings_panel_process; + iface->conclude = (conclude_updatable_cb)g_strings_panel_conclude; + iface->clean = (clean_updatable_data_cb)g_strings_panel_clean_data; } @@ -442,143 +479,6 @@ GPanelItem *g_strings_panel_new(void) } - -/* ---------------------------------------------------------------------------------- */ -/* AFFICHAGE A L'AIDE D'UNE LISTE */ -/* ---------------------------------------------------------------------------------- */ - - -/****************************************************************************** -* * -* 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 change_strings_panel_current_binary(GStringsPanel *panel, GLoadedBinary *binary) -{ - GtkTreeStore *store; /* Modèle de gestion */ - GArchProcessor *proc; /* Architecture du binaire */ - MemoryDataSize msize; /* Taille par défaut */ - GExeFormat *format; /* Format de travail */ - GBinPortion *portions; /* Couche première de portions */ - GBinContent *content; /* Contenu binaire en mémoire */ - sym_iter_t *siter; /* Parcours des symboles */ - GBinSymbol *symbol; /* Symbole manipulé */ - const mrange_t *range; /* Couverture mémoire */ - const vmpa2t *addr; /* Adressse liée à la chaîne */ - VMPA_BUFFER(phys); /* Position physique */ - VMPA_BUFFER(virt); /* Adresse virtuelle */ - GBinPortion *portion; /* Zone mémoire d'appartenance */ - const char *area; /* Description de la zone */ - const char *label; /* Etiquette liée au symbole */ - vmpa2t pos; /* Tête de lecture modifiable */ - char *text; /* Version imprimable du texte */ - GtkTreeIter iter; /* Point d'insertion */ - - /* 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)); - - store = GTK_TREE_STORE(gtk_tree_view_get_model(panel->treeview)); - gtk_tree_store_clear(store); - - /* Si le panneau actif ne représente pas un binaire... */ - - if (binary == NULL) return; - - /* Actualisation de l'affichage */ - - proc = g_loaded_binary_get_processor(binary); - msize = g_arch_processor_get_memory_size(proc); - g_object_unref(G_OBJECT(proc)); - - format = g_loaded_binary_get_format(binary); - portions = g_exe_format_get_portions(format); - content = g_binary_format_get_content(G_BIN_FORMAT(format)); - - siter = create_symbol_iterator(G_BIN_FORMAT(format), 0); - - for (symbol = get_symbol_iterator_current(siter); - symbol != NULL; - symbol = get_symbol_iterator_next(siter)) - { - if (g_binary_symbol_get_target_type(symbol) != STP_RO_STRING) - goto cspcb_next; - - range = g_binary_symbol_get_range(symbol); - addr = get_mrange_addr(range); - - vmpa2_phys_to_string(addr, msize, phys, NULL); - vmpa2_virt_to_string(addr, msize, virt, NULL); - - portion = g_binary_portion_find_at_addr(portions, addr, (GdkRectangle []) { }); - area = g_binary_portion_get_desc(portion); - g_object_unref(G_OBJECT(portion)); - - label = g_binary_symbol_get_label(symbol); - - text = (char *)calloc(get_mrange_length(range) + 1, sizeof(char)); - - copy_vmpa(&pos, addr); - - if (!g_binary_content_read_raw(content, &pos, get_mrange_length(range), (uint8_t *)text)) - { - free(text); - goto cspcb_next; - } - - if (is_string_filtered(panel, label, text)) - { - free(text); - goto cspcb_next; - } - - text = strrpl(text, "&", "&"); - text = strrpl(text, "<", "<"); - text = strrpl(text, ">", ">"); - text = strrpl(text, "\r", "<b>\\r</b>"); - text = strrpl(text, "\n", "<b>\\n</b>"); - - gtk_tree_store_append(store, &iter, NULL); - gtk_tree_store_set(store, &iter, - STC_STRING, symbol, - STC_PHYSICAL, phys, - STC_VIRTUAL, virt, - STC_AREA, area, - STC_NAME, label, - STC_VALUE, text, - -1); - - free(text); - - cspcb_next: - - g_object_unref(G_OBJECT(symbol)); - - } - - delete_symbol_iterator(siter); - - g_object_unref(G_OBJECT(content)); - g_object_unref(G_OBJECT(portions)); - g_object_unref(G_OBJECT(format)); - -} - - /****************************************************************************** * * * Paramètres : selection = sélection modifiée. * @@ -602,7 +502,7 @@ static void on_strings_selection_change(GtkTreeSelection *selection, gpointer un if (gtk_tree_selection_get_selected(selection, &model, &iter)) { - gtk_tree_model_get(model, &iter, STC_STRING, &symbol, -1); + gtk_tree_model_get(model, &iter, STC_SYMBOL, &symbol, -1); addr = get_mrange_addr(g_binary_symbol_get_range(symbol)); @@ -703,7 +603,7 @@ static gboolean on_key_pressed_over_strings(GtkTreeView *treeview, GdkEventKey * * Paramètres : renderer = moteur de rendu pour la cellule. * * path = chemin d'accès vers la cellule éditée. * * new = nouvelle valeur sous forme de texte à valider. * -* store = gestionnaire des données de la liste affichée. * +* model = gestionnaire des données de la liste affichée. * * * * Description : Réagit à une édition de l'étiquette d'une chaîne textuelle. * * * @@ -713,7 +613,7 @@ static gboolean on_key_pressed_over_strings(GtkTreeView *treeview, GdkEventKey * * * ******************************************************************************/ -static void on_string_value_edited(GtkCellRendererText *renderer, gchar *path, gchar *new, GtkTreeStore *store) +static void on_string_name_edited(GtkCellRendererText *renderer, gchar *path, gchar *new, GtkTreeModel *model) { GtkTreePath *tree_path; /* Chemin d'accès natif */ GtkTreeIter iter; /* Point de la modification */ @@ -722,10 +622,10 @@ static void on_string_value_edited(GtkCellRendererText *renderer, gchar *path, g tree_path = gtk_tree_path_new_from_string(path); if (tree_path == NULL) return; - if (!gtk_tree_model_get_iter(GTK_TREE_MODEL(store), &iter, tree_path)) + if (!gtk_tree_model_get_iter(model, &iter, tree_path)) goto opve_bad_iter; - gtk_tree_model_get(GTK_TREE_MODEL(store), &iter, STC_STRING, &symbol, -1); + gtk_tree_model_get(model, &iter, STC_SYMBOL, &symbol, -1); g_binary_symbol_set_alt_label(symbol, new); @@ -738,18 +638,64 @@ static void on_string_value_edited(GtkCellRendererText *renderer, gchar *path, g } +/****************************************************************************** +* * +* 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 change_strings_panel_current_binary(GStringsPanel *panel, GLoadedBinary *binary) +{ + GtkBuilder *builder; /* Constructeur utilisé */ + GtkListStore *store; /* Modèle de gestion */ + + /* 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 = G_PANEL_ITEM(panel)->builder; + + store = GTK_LIST_STORE(gtk_builder_get_object(builder, "store")); + + gtk_list_store_clear(store); + + /* Si le panneau actif représente un binaire, actualisation de l'affichage */ + + if (binary != NULL) + run_panel_update(G_UPDATABLE_PANEL(panel), PUI_0); + +} + + /* ---------------------------------------------------------------------------------- */ -/* FILTRAGE DES SYMBOLES PRESENTS */ +/* AFFICHAGE A L'AIDE D'UNE LISTE */ /* ---------------------------------------------------------------------------------- */ /****************************************************************************** * * -* Paramètres : panel = panneau assurant l'affichage des paramètres. * -* preg = expression régulière compilée à utiliser. * +* 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 : Démarre l'actualisation du filtrage des chaînes. * +* Description : Réagit à un changement d'affichage principal de contenu. * * * * Retour : - * * * @@ -757,50 +703,289 @@ static void on_string_value_edited(GtkCellRendererText *renderer, gchar *path, g * * ******************************************************************************/ -static void update_filtered_strings(GStringsPanel *panel, const regex_t *preg) +static void reload_strings_for_new_list_view(const GStringsPanel *panel, GtkStatusStack *status, activity_id_t id, strings_update_data *data) { - panel->filter = preg; + GtkBuilder *builder; /* Constructeur utilisé */ + GtkListStore *store; /* Modèle de gestion */ + GArchProcessor *proc; /* Architecture utilisée */ + MemoryDataSize size; /* Taille des localisations */ + GExeFormat *format; /* Format associé au binaire */ + GBinPortion *portions; /* Couche première de portions */ + GBinContent *content; /* Contenu binaire en mémoire */ + sym_iter_t *siter; /* Parcours des symboles */ + GBinSymbol *symbol; /* Symbole manipulé */ + const mrange_t *range; /* Couverture mémoire */ + const vmpa2t *addr; /* Adressse liée à la chaîne */ + VMPA_BUFFER(phys); /* Position physique */ + VMPA_BUFFER(virt); /* Adresse virtuelle */ + GBinPortion *portion; /* Zone mémoire d'appartenance */ + const char *area; /* Description de la zone */ + char *text; /* Texte original référencé */ + vmpa2t pos; /* Tête de lecture modifiable */ + GtkTreeIter iter; /* Point d'insertion */ + + builder = G_PANEL_ITEM(panel)->builder; + + store = GTK_LIST_STORE(gtk_builder_get_object(builder, "store")); + + proc = g_loaded_binary_get_processor(panel->binary); + size = g_arch_processor_get_memory_size(proc); + g_object_unref(G_OBJECT(proc)); + + format = g_loaded_binary_get_format(panel->binary); + portions = g_exe_format_get_portions(format); + content = g_binary_format_get_content(G_BIN_FORMAT(format)); + + siter = create_symbol_iterator(G_BIN_FORMAT(format), 0); + + for (symbol = get_symbol_iterator_current(siter); + symbol != NULL; + symbol = get_symbol_iterator_next(siter)) + { + if (g_binary_symbol_get_target_type(symbol) != STP_RO_STRING) + goto rsfnlv_next; + + range = g_binary_symbol_get_range(symbol); + addr = get_mrange_addr(range); + + vmpa2_phys_to_string(addr, size, phys, NULL); + vmpa2_virt_to_string(addr, size, virt, NULL); + + portion = g_binary_portion_find_at_addr(portions, addr, (GdkRectangle []) { }); + area = g_binary_portion_get_desc(portion); + g_object_unref(G_OBJECT(portion)); + + text = (char *)calloc(get_mrange_length(range) + 1, sizeof(char)); + + copy_vmpa(&pos, addr); + + if (!g_binary_content_read_raw(content, &pos, get_mrange_length(range), (uint8_t *)text)) + { + free(text); + goto rsfnlv_next; + } + + addr = get_mrange_addr(g_binary_symbol_get_range(symbol)); + vmpa2_virt_to_string(addr, size, virt, NULL); + + gtk_list_store_append(store, &iter); + gtk_list_store_set(store, &iter, + STC_SYMBOL, symbol, + STC_PHYSICAL, phys, + STC_VIRTUAL, virt, + STC_AREA, area, + STC_NAME, NULL, + STC_VALUE, NULL, + STC_ORIGINAL, text, + STC_MATCHED, false, + -1); + + update_string_node(data, store, &iter); + + data->count++; + + free(text); - change_strings_panel_current_binary(panel, panel->binary); + rsfnlv_next: + + g_object_unref(G_OBJECT(symbol)); + + gtk_status_stack_update_activity_value(status, id, 1); + + } + + delete_symbol_iterator(siter); + + g_object_unref(G_OBJECT(content)); + g_object_unref(G_OBJECT(portions)); + g_object_unref(G_OBJECT(format)); } /****************************************************************************** * * -* Paramètres : panel = panneau assurant l'affichage des paramètres. * -* label = étiquette liée au symbole à traiter. * -* value = chaîne de caractères représentée par le symbole. * +* Paramètres : store = gestionnaire de données pour une arborescence. * +* iter = position des données traitées. * +* match = correspondance avec un objet recherché. * * * -* Description : Détermine si une chaîne textuelle doit être filtrée ou non. * +* Description : Met en surbrillance les éléments recherchés dans les noms. * * * -* Retour : true si le symbole ne doit pas être affiché, false sinon. * +* Retour : - * * * * Remarques : - * * * ******************************************************************************/ -static bool is_string_filtered(GStringsPanel *panel, const char *label, const char *value) +static void update_string_label_in_list_view(GtkListStore *store, GtkTreeIter *iter, const regmatch_t *match) { - bool result; /* Bilan à retourner */ + GtkTreeModel *model; /* Autre vision du gestionnaire*/ + char *original; /* Etiquette brute d'origine */ + char *value; /* Etiquette mise en relief */ + + model = GTK_TREE_MODEL(store); + + gtk_tree_model_get(model, iter, STC_ORIGINAL, &original, -1); + + original = strrpl(original, "&", "&"); + original = strrpl(original, "<", "<"); + original = strrpl(original, ">", ">"); + original = strrpl(original, "\r", "<b>\\r</b>"); + original = strrpl(original, "\n", "<b>\\n</b>"); + + value = build_highlighted_name(original, match, 0); + + gtk_list_store_set(store, iter, STC_VALUE, value, -1); + + free(original); + free(value); + +} + + +/****************************************************************************** +* * +* Paramètres : store = gestionnaire de données pour une arborescence. * +* iter = position des données traitées. * +* match = correspondance avec un objet recherché. * +* * +* Description : Met en surbrillance les éléments recherchés dans les valeurs.* +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void update_string_value_in_list_view(GtkListStore *store, GtkTreeIter *iter, const regmatch_t *match) +{ + GtkTreeModel *model; /* Autre vision du gestionnaire*/ + char *original; /* Etiquette brute d'origine */ + char *value; /* Etiquette mise en relief */ + + model = GTK_TREE_MODEL(store); + + gtk_tree_model_get(model, iter, STC_ORIGINAL, &original, -1); + + original = strrpl(original, "&", "&"); + original = strrpl(original, "<", "<"); + original = strrpl(original, ">", ">"); + original = strrpl(original, "\r", "<b>\\r</b>"); + original = strrpl(original, "\n", "<b>\\n</b>"); + + value = build_highlighted_name(original, match, 0); + + gtk_list_store_set(store, iter, STC_VALUE, value, -1); + + free(original); + free(value); + +} + + + +/* ---------------------------------------------------------------------------------- */ +/* FILTRAGE DES CHAINES PRESENTES */ +/* ---------------------------------------------------------------------------------- */ + + +/****************************************************************************** +* * +* Paramètres : panel = panneau assurant l'affichage des chaînes. * +* * +* Description : Démarre l'actualisation du filtrage des chaînes. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void update_filtered_strings(GStringsPanel *panel) +{ + 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. * +* * +* Description : Détermine si un noeud de l'arborescence doit être filtré. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void update_string_node(const strings_update_data *data, GtkListStore *store, GtkTreeIter *iter) +{ + GtkTreeModel *model; /* Autre vision du gestionnaire*/ regmatch_t match; /* Récupération des trouvailles*/ - int ret; /* Bilan du filtrage */ + bool name_matched; /* Correspondance de sélection */ + bool value_matched; /* Correspondance de sélection */ + + model = GTK_TREE_MODEL(store); + + name_matched = is_string_name_matching(data, model, iter, &match); + + if (name_matched) + update_string_label_in_list_view(store, iter, &match); + + value_matched = is_string_value_matching(data, model, iter, &match); + + if (value_matched) + update_string_value_in_list_view(store, iter, &match); + + if (name_matched || value_matched) + gtk_list_store_set(GTK_LIST_STORE(model), iter, STC_MATCHED, true, -1); + else + gtk_list_store_set(GTK_LIST_STORE(model), iter, STC_MATCHED, false, -1); + +} + - if (panel->filter == NULL) - return false; +/****************************************************************************** +* * +* Paramètres : panel = panneau assurant l'affichage des chaînes. * +* 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 chaînes affichées. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void do_filtering_on_strings(const GStringsPanel *panel, GtkStatusStack *status, activity_id_t id, strings_update_data *data) +{ + GtkBuilder *builder; /* Constructeur utilisé */ + GtkListStore *store; /* Modèle de gestion */ - result = true; - if (label != NULL) + gboolean filter_string_panel_iter(GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, gpointer unused) { - ret = regexec(panel->filter, label, 1, &match, 0); - result &= (ret == REG_NOMATCH); + update_string_node(data, store, iter); + + gtk_status_stack_update_activity_value(status, id, 1); + + return FALSE; + } - ret = regexec(panel->filter, value, 1, &match, 0); - result &= (ret == REG_NOMATCH); - return result; + builder = G_PANEL_ITEM(panel)->builder; + + store = GTK_LIST_STORE(gtk_builder_get_object(builder, "store")); + + gtk_tree_model_foreach(GTK_TREE_MODEL(store), (GtkTreeModelForeachFunc)filter_string_panel_iter, NULL); } @@ -845,7 +1030,7 @@ static gboolean on_button_event_over_strings(GtkWidget *widget, GdkEventButton * if (gtk_tree_selection_get_selected(selection, &model, &iter)) { - gtk_tree_model_get(model, &iter, STC_STRING, &symbol, -1); + gtk_tree_model_get(model, &iter, STC_SYMBOL, &symbol, -1); addr = get_mrange_addr(g_binary_symbol_get_range(symbol)); @@ -918,8 +1103,8 @@ static GtkMenu *build_strings_panel_menu(GStringsPanel *panel) /****************************************************************************** * * -* Paramètres : treeview = liste d'affichage à consulter. * -* save = zone de conservation du point de trouvaille. [OUT]* +* Paramètres : panel = panneau concerné par l'opération. * +* save = zone de conservation du point de trouvaille. [OUT] * * * * Description : Fournit le signet sélectionné dans la liste. * * * @@ -929,19 +1114,25 @@ static GtkMenu *build_strings_panel_menu(GStringsPanel *panel) * * ******************************************************************************/ -static GBinSymbol *get_selected_panel_symbol(GtkTreeView *treeview, GtkTreeIter *save) +static GBinSymbol *get_selected_panel_symbol(GStringsPanel *panel, GtkTreeIter *save) { GBinSymbol *result; /* Chaîne textuelle à renvoyer */ + GtkBuilder *builder; /* Constructeur utilisé */ + GtkTreeView *treeview; /* Arborescence graphique */ GtkTreeSelection *selection; /* Représentation de sélection */ GtkTreeModel *model; /* Gestionnaire des données */ GtkTreeIter iter; /* Point de la sélection */ result = NULL; + builder = G_PANEL_ITEM(panel)->builder; + + 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, STC_STRING, &result, -1); + gtk_tree_model_get(model, &iter, STC_SYMBOL, &result, -1); if (save != NULL) *save = iter; @@ -968,17 +1159,23 @@ static void mcb_strings_panel_edit(GtkMenuItem *menuitem, GStringsPanel *panel) { GtkTreeIter iter; /* Point de la sélection */ GBinSymbol *symbol; /* Symbole sélectionné */ + GtkBuilder *builder; /* Constructeur utilisé */ + GtkTreeView *treeview; /* Arborescence graphique */ GtkTreeModel *model; /* Gestionnaire de données */ GtkTreePath *path; /* Chemin d'accès à ce point */ - symbol = get_selected_panel_symbol(panel->treeview, &iter); + symbol = get_selected_panel_symbol(panel, &iter); if (symbol == NULL) return; - model = gtk_tree_view_get_model(panel->treeview); + builder = G_PANEL_ITEM(panel)->builder; + + treeview = GTK_TREE_VIEW(gtk_builder_get_object(builder, "treeview")); + + model = gtk_tree_view_get_model(treeview); path = gtk_tree_model_get_path(model, &iter); - gtk_tree_view_set_cursor(panel->treeview, path, - gtk_tree_view_get_column(panel->treeview, STC_NAME - STC_PHYSICAL), + gtk_tree_view_set_cursor(treeview, path, + gtk_tree_view_get_column(treeview, STC_NAME - STC_PHYSICAL), TRUE); gtk_tree_path_free(path); @@ -1003,13 +1200,19 @@ static void mcb_strings_panel_edit(GtkMenuItem *menuitem, GStringsPanel *panel) static void mcb_strings_panel_copy(GtkMenuItem *menuitem, GStringsPanel *panel) { + GtkBuilder *builder; /* Constructeur utilisé */ + GtkTreeView *treeview; /* Arborescence graphique */ GtkTreeSelection *selection; /* Sélection de l'arbre */ GtkTreeIter iter; /* Point de sélection */ GtkTreeModel *model; /* Modèle de gestion */ gchar *string; /* Chaîne sélectionnée */ GtkClipboard *clipboard; /* Presse-papiers d'arrivée */ - selection = gtk_tree_view_get_selection(panel->treeview); + builder = G_PANEL_ITEM(panel)->builder; + + 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)) { @@ -1055,7 +1258,7 @@ static void mcb_strings_panel_find_refs(GtkMenuItem *menuitem, GStringsPanel *pa vmpa2t *addr; /* Adresse de destination */ GLoadedPanel *display; /* Afficheur effectif de code */ - symbol = get_selected_panel_symbol(panel->treeview, NULL); + symbol = get_selected_panel_symbol(panel, NULL); if (symbol == NULL) return; range = g_binary_symbol_get_range(symbol); @@ -1119,7 +1322,7 @@ static void mcb_strings_panel_filter(GtkMenuItem *menuitem, GStringsPanel *panel #if 0 GCfgParam *param; /* Paramètre sélectionné */ - param = get_selected_panel_symbol(panel->treeview, NULL); + param = get_selected_panel_symbol(panel, NULL); if (param == NULL) return; g_config_param_make_empty(param); @@ -1127,3 +1330,305 @@ static void mcb_strings_panel_filter(GtkMenuItem *menuitem, GStringsPanel *panel g_object_unref(G_OBJECT(param)); #endif } + + + +/* ---------------------------------------------------------------------------------- */ +/* MECANISMES DE MISE A JOUR DE PANNEAU */ +/* ---------------------------------------------------------------------------------- */ + + +/****************************************************************************** +* * +* Paramètres : data = données complémentaire à manipuler. * +* model = gestionnaire de l'ensemble des données. * +* iter = localisation des données à analyser. * +* match = récupération des trouvailles. [OUT] * +* * +* Description : Détermine si un nom de symbole doit être filtré ou non. * +* * +* Retour : true si le symbol ne doit pas être affiché, false sinon. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static bool is_string_name_matching(const strings_update_data *data, GtkTreeModel *model, GtkTreeIter *iter, regmatch_t *match) +{ + bool result; /* Bilan à retourner */ + GBinSymbol *symbol; /* Symbole manipulé */ +#ifndef NDEBUG + SymbolType type; /* Type associé au symbole */ +#endif + const char *label; /* Etiquette à analyser */ + + gtk_tree_model_get(model, iter, STC_SYMBOL, &symbol, -1); + assert(symbol != NULL); + +#ifndef NDEBUG + + type = g_binary_symbol_get_target_type(symbol); + + assert(type == STP_RO_STRING); + +#endif + + label = g_binary_symbol_get_label(symbol); + + if (label == NULL) + result = false; + else + result = is_content_matching(data->filter, label, match); + + g_object_unref(G_OBJECT(symbol)); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : data = données complémentaire à manipuler. * +* model = gestionnaire de l'ensemble des données. * +* iter = localisation des données à analyser. * +* match = récupération des trouvailles. [OUT] * +* * +* Description : Détermine si une valeur de symbole doit être filtrée ou non. * +* * +* Retour : true si le symbol ne doit pas être affiché, false sinon. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static bool is_string_value_matching(const strings_update_data *data, GtkTreeModel *model, GtkTreeIter *iter, regmatch_t *match) +{ + bool result; /* Bilan à retourner */ + char *original; /* Etiquette brute d'origine */ + + gtk_tree_model_get(model, iter, STC_ORIGINAL, &original, -1); + + result = is_content_matching(data->filter, original, match); + + free(original); + + 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_strings_panel_setup(const GStringsPanel *panel, unsigned int uid, size_t *count, strings_update_data **data) +{ + const char *result; /* Message à retourner */ + GBinFormat *format; /* Format du binaire */ + int ret; /* Bilan de mise en place */ + + *data = malloc(sizeof(strings_update_data)); + + switch (uid) + { + case PUI_0: + + format = G_BIN_FORMAT(g_loaded_binary_get_format(panel->binary)); + + g_binary_format_lock_symbols_rd(format); + *count = g_binary_format_count_symbols(format); + g_binary_format_unlock_symbols_rd(format); + + g_object_unref(G_OBJECT(format)); + + (*data)->count = 0; + + result = _("Loading strings available in the binary format..."); + + break; + + case PUI_1: + + *count = panel->count; + (*data)->count = panel->count; + + result = _("Filtering strings available 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)); + + ret = regcomp((*data)->filter, G_PANEL_ITEM(panel)->filter, REG_EXTENDED | REG_ICASE); + assert(ret == 0); + + } + + else + (*data)->filter = NULL; + + 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_strings_panel_introduce(const GStringsPanel *panel, unsigned int uid, strings_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 = G_PANEL_ITEM(panel)->builder; + + 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); + } + +} + + +/****************************************************************************** +* * +* 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_strings_panel_process(const GStringsPanel *panel, unsigned int uid, GtkStatusStack *status, activity_id_t id, strings_update_data *data) +{ + switch (uid) + { + case PUI_0: + reload_strings_for_new_list_view(panel, status, id, data); + break; + + case PUI_1: + do_filtering_on_strings(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_strings_panel_conclude(GStringsPanel *panel, unsigned int uid, strings_update_data *data) +{ + GtkBuilder *builder; /* Constructeur utilisé */ + GtkTreeView *treeview; /* Arborescence graphique */ + GtkTreeModel *model; /* Source de données associée */ + + 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 = G_PANEL_ITEM(panel)->builder; + + 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); + + 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_strings_panel_clean_data(GUpdatablePanel *panel, unsigned int uid, strings_update_data *data) +{ + if (data->filter != NULL) + { + regfree(data->filter); + free(data->filter); + } + +} diff --git a/src/gui/panels/strings.ui b/src/gui/panels/strings.ui new file mode 100644 index 0000000..fb8764f --- /dev/null +++ b/src/gui/panels/strings.ui @@ -0,0 +1,93 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- Generated with glade 3.21.0 --> +<interface> + <requires lib="gtk+" version="3.20"/> + <object class="GtkOffscreenWindow"> + <property name="can_focus">False</property> + <child> + <object class="GtkBox" id="box"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="orientation">vertical</property> + <child> + <object class="GtkStack" id="stack"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <child> + <object class="GtkScrolledWindow" id="content"> + <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="name">treeview</property> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="model">filter</property> + <property name="headers_visible">False</property> + <property name="search_column">2</property> + <signal name="button-press-event" handler="on_button_event_over_strings" swapped="no"/> + <signal name="button-release-event" handler="on_button_event_over_strings" swapped="no"/> + <signal name="key-press-event" handler="on_key_pressed_over_strings" swapped="no"/> + <child internal-child="selection"> + <object class="GtkTreeSelection"> + <signal name="changed" handler="on_strings_selection_change" swapped="no"/> + </object> + </child> + </object> + </child> + </object> + <packing> + <property name="name">page0</property> + <property name="title" translatable="yes">page0</property> + </packing> + </child> + <child> + <object class="GtkSpinner" id="mask"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="active">True</property> + </object> + <packing> + <property name="name">page1</property> + <property name="title" translatable="yes">page1</property> + <property name="position">1</property> + </packing> + </child> + </object> + <packing> + <property name="expand">True</property> + <property name="fill">True</property> + <property name="position">0</property> + </packing> + </child> + </object> + </child> + <child type="titlebar"> + <placeholder/> + </child> + </object> + <object class="GtkListStore" id="store"> + <columns> + <!-- column-name symbol --> + <column type="GObject"/> + <!-- column-name physical --> + <column type="gchararray"/> + <!-- column-name virtual --> + <column type="gchararray"/> + <!-- column-name area --> + <column type="gchararray"/> + <!-- column-name name --> + <column type="gchararray"/> + <!-- column-name value --> + <column type="gchararray"/> + <!-- column-name original --> + <column type="gchararray"/> + <!-- column-name matched --> + <column type="gboolean"/> + </columns> + </object> + <object class="GtkTreeModelFilter" id="filter"> + <property name="child_model">store</property> + </object> +</interface> diff --git a/src/gui/panels/symbols.c b/src/gui/panels/symbols.c index fe295e0..fab82a9 100644 --- a/src/gui/panels/symbols.c +++ b/src/gui/panels/symbols.c @@ -62,8 +62,6 @@ struct _GSymbolsPanel size_t count; /* Quantité de symboles utiles */ - regex_t *filter; /* Filtre appliqué ou NULL */ - }; /* Panneau d'affichage des symboles (classe) */ @@ -92,10 +90,11 @@ typedef enum _SymbolsColumn SBC_EXPAND, /* Affichage des classes */ SBC_MATCHED, /* Correspondance établie ? */ - SBC_MATCH_POINTS /* Nombre de demandeurs */ + SBC_MATCH_POINTS, /* Nombre de demandeurs */ -} SymbolsColumn; + SBC_COUNT /* Nombre de colonnes */ +} SymbolsColumn; /* Données utiles à la mise à jour */ @@ -109,7 +108,7 @@ static void g_symbols_panel_class_init(GSymbolsPanelClass *); static void g_symbols_panel_init(GSymbolsPanel *); /* Procède à l'initialisation de l'interface de mise à jour. */ -static void g_symbols_panel_interface_init(GUpdatablePanelInterface *); +static void g_symbols_panel_updatable_interface_init(GUpdatablePanelInterface *); /* Supprime toutes les références externes. */ static void g_symbols_panel_dispose(GSymbolsPanel *); @@ -177,15 +176,9 @@ static void update_symbol_name_in_tree_view(const GSymbolsPanel *, GtkTreeStore /* Démarre l'actualisation du filtrage des symboles. */ static void on_symbols_filter_changed(GtkSearchEntry *, GSymbolsPanel *); -/* Met à jour l'affichage des noeuds en fonction des besoin. */ -static void update_symbol_visibility(GtkTreeStore *, GtkTreeIter *, bool); - /* Exécute un nouveau filtrage des symboles affichés. */ static void do_filtering_on_symbols(const GSymbolsPanel *, GtkStatusStack *, activity_id_t, symbols_update_data *); -/* Détermine si un nom de symbole doit être filtré ou non. */ -static bool is_symbol_matching(const GSymbolsPanel *, const GBinSymbol *, regmatch_t *); - /* ---------------------- MECANISMES DE MISE A JOUR DE PANNEAU ---------------------- */ @@ -195,6 +188,8 @@ struct _symbols_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 */ @@ -205,6 +200,9 @@ struct _symbols_update_data #define EXPAND_ALLOC_RANGE 10 +/* Détermine si un nom de symbole doit être filtré ou non. */ +static bool is_symbol_matching(const symbols_update_data *, const GBinSymbol *, regmatch_t *); + /* Prépare une opération de mise à jour de panneau. */ static const char *g_symbols_panel_setup(const GSymbolsPanel *, unsigned int, size_t *, symbols_update_data **); @@ -229,7 +227,7 @@ static void g_symbols_panel_clean_data(GUpdatablePanel *, unsigned int, symbols_ /* Indique le type définit pour un panneau d'affichage des symboles. */ G_DEFINE_TYPE_WITH_CODE(GSymbolsPanel, g_symbols_panel, G_TYPE_PANEL_ITEM, - G_IMPLEMENT_INTERFACE(G_TYPE_UPDATABLE_PANEL, g_symbols_panel_interface_init)); + G_IMPLEMENT_INTERFACE(G_TYPE_UPDATABLE_PANEL, g_symbols_panel_updatable_interface_init)); /****************************************************************************** @@ -248,8 +246,8 @@ static void g_symbols_panel_class_init(GSymbolsPanelClass *klass) { GObjectClass *object; /* Autre version de la classe */ GEditorItemClass *editem; /* Encore une autre vision... */ - gchar *filename; /* Chemin d'accès à utiliser */ GPanelItemClass *panel; /* Version parente de la classe*/ + gchar *filename; /* Chemin d'accès à utiliser */ object = G_OBJECT_CLASS(klass); @@ -260,6 +258,13 @@ static void g_symbols_panel_class_init(GSymbolsPanelClass *klass) editem->update_binary = (update_item_binary_fc)change_symbols_panel_current_binary; + panel = G_PANEL_ITEM_CLASS(klass); + + panel->unique = true; + panel->bindings = "<Shift>F3"; + + panel->gid = setup_tiny_global_work_group(1); + filename = find_pixmap_file("symbol_routine_classic.png"); assert(filename != NULL); @@ -288,13 +293,6 @@ static void g_symbols_panel_class_init(GSymbolsPanelClass *klass) g_free(filename); - panel = G_PANEL_ITEM_CLASS(klass); - - panel->unique = true; - panel->bindings = "<Shift>F3"; - - panel->gid = setup_tiny_global_work_group(1); - } @@ -315,8 +313,8 @@ static void g_symbols_panel_init(GSymbolsPanel *panel) GEditorItem *base; /* Version basique d'instance */ GPanelItem *pitem; /* Version parente du panneau */ GtkBuilder *builder; /* Constructeur utilisé */ - GtkTreeView *treeview; /* Affichage de la liste */ GtkTreeModelFilter *filter; /* Filtre pour l'arborescence */ + GtkTreeView *treeview; /* Affichage de la liste */ GtkCellRenderer *renderer; /* Moteur de rendu de colonne */ GtkTreeViewColumn *column; /* Colonne de la liste */ @@ -399,7 +397,7 @@ static void g_symbols_panel_init(GSymbolsPanel *panel) * * ******************************************************************************/ -static void g_symbols_panel_interface_init(GUpdatablePanelInterface *iface) +static void g_symbols_panel_updatable_interface_init(GUpdatablePanelInterface *iface) { iface->setup = (setup_updatable_cb)g_symbols_panel_setup; iface->get_group = (get_updatable_group_cb)g_panel_item_get_group; @@ -447,12 +445,6 @@ static void g_symbols_panel_dispose(GSymbolsPanel *panel) static void g_symbols_panel_finalize(GSymbolsPanel *panel) { - if (panel->filter != NULL) - { - regfree(panel->filter); - free(panel->filter); - } - G_OBJECT_CLASS(g_symbols_panel_parent_class)->finalize(G_OBJECT(panel)); } @@ -738,7 +730,7 @@ static void reload_symbols_for_new_list_view(const GSymbolsPanel *panel, GtkStat const char *original; /* Etiquette brute d'origine */ char *name; /* Etiquette mise en relief */ const vmpa2t *addr; /* Localisation d'un symbole */ - char virt[VMPA_MAX_LEN]; /* Version humainement lisible */ + VMPA_BUFFER(virt); /* Version humainement lisible */ GtkTreeIter iter; /* Point d'insertion */ builder = G_PANEL_ITEM(panel)->builder; @@ -774,7 +766,7 @@ static void reload_symbols_for_new_list_view(const GSymbolsPanel *panel, GtkStat if (icon == NULL) goto rsfnlv_next; - matched = is_symbol_matching(panel, symbol, &match); + matched = is_symbol_matching(data, symbol, &match); original = g_binary_symbol_get_label(symbol); @@ -798,7 +790,7 @@ static void reload_symbols_for_new_list_view(const GSymbolsPanel *panel, GtkStat -1); if (matched) - update_symbol_visibility(store, &iter, true); + update_node_visibility(store, &iter, SBC_MATCHED, true); data->count++; @@ -809,6 +801,8 @@ static void reload_symbols_for_new_list_view(const GSymbolsPanel *panel, GtkStat g_object_unref(G_OBJECT(symbol)); + gtk_status_stack_update_activity_value(status, id, 1); + } delete_symbol_iterator(siter); @@ -1050,7 +1044,7 @@ static void reload_symbols_for_new_tree_view(const GSymbolsPanel *panel, GtkStat if (icon == NULL) goto rsfntv_next; - matched = is_symbol_matching(panel, symbol, &match); + matched = is_symbol_matching(data, symbol, &match); if (find_parent_for_symbol(panel, symbol, &parent, &match, &last)) { @@ -1086,7 +1080,7 @@ static void reload_symbols_for_new_tree_view(const GSymbolsPanel *panel, GtkStat -1); if (matched) - update_symbol_visibility(store, &iter, true); + update_node_visibility(store, &iter, SBC_MATCHED, true); data->count++; @@ -1097,6 +1091,8 @@ static void reload_symbols_for_new_tree_view(const GSymbolsPanel *panel, GtkStat g_object_unref(G_OBJECT(symbol)); + gtk_status_stack_update_activity_value(status, id, 1); + } delete_symbol_iterator(siter); @@ -1310,7 +1306,7 @@ static void update_symbol_name_in_tree_view(const GSymbolsPanel *panel, GtkTreeS static void on_symbols_filter_changed(GtkSearchEntry *entry, GSymbolsPanel *panel) { - update_regex_on_search_entry_changed(entry, &panel->filter); + update_regex_on_search_entry_changed(entry, &G_PANEL_ITEM(panel)->filter); run_panel_update(G_UPDATABLE_PANEL(panel), PUI_1); @@ -1319,68 +1315,6 @@ static void on_symbols_filter_changed(GtkSearchEntry *entry, GSymbolsPanel *pane /****************************************************************************** * * -* Paramètres : store = organisation des données sous forme arborescente. * -* iter = position du noeud courant à traiter. * -* show = visibilité à obtenir pour le noeud final. * -* * -* Description : Met à jour l'affichage des noeuds en fonction des besoin. * -* * -* Retour : - * -* * -* Remarques : - * -* * -******************************************************************************/ - -static void update_symbol_visibility(GtkTreeStore *store, GtkTreeIter *iter, bool show) -{ - GtkTreeModel *model; /* Autre vision du gestionnaire*/ - guint points; /* Compteur de besoins */ - GtkTreeIter parent; /* Position de noeuf parent */ - gboolean further; /* Poursuite de remontée */ - - model = GTK_TREE_MODEL(store); - - /* Enumération des besoins */ - - gtk_tree_model_get(model, iter, SBC_MATCH_POINTS, &points, -1); - - if (show) - points++; - - else - { - assert(points > 0); - points--; - } - - gtk_tree_store_set(store, iter, SBC_MATCH_POINTS, points, -1); - - /* Adaptation de l'affichage */ - - if (show) - { - if (points == 1) - gtk_tree_store_set(store, iter, SBC_MATCHED, true, -1); - } - - else - { - if (points == 0) - gtk_tree_store_set(store, iter, SBC_MATCHED, false, -1); - } - - /* Eventuel étage supérieur */ - - further = gtk_tree_model_iter_parent(model, &parent, iter); - - if (further) - update_symbol_visibility(store, &parent, show); - -} - - -/****************************************************************************** -* * * Paramètres : panel = panneau assurant l'affichage des symboles. * * status = barre de statut à tenir informée. * * id = identifiant pour le suivi de la progression. * @@ -1413,30 +1347,34 @@ static void do_filtering_on_symbols(const GSymbolsPanel *panel, GtkStatusStack * if (symbol != NULL) { - matched = is_symbol_matching(panel, symbol, &match); + matched = is_symbol_matching(data, symbol, &match); + + if (matched) + { + if (*as_list) + update_symbol_name_in_list_view(store, iter, &match); + else + update_symbol_name_in_tree_view(panel, store, symbol, &match); + } gtk_tree_model_get(model, iter, SBC_MATCHED, &shown, -1); if (!matched) { if (shown) - update_symbol_visibility(store, iter, false); + update_node_visibility(store, iter, SBC_MATCHED, false); } else { - if (*as_list) - update_symbol_name_in_list_view(store, iter, &match); - else - update_symbol_name_in_tree_view(panel, store, symbol, &match); - if (!shown) - update_symbol_visibility(store, iter, true); - + update_node_visibility(store, iter, SBC_MATCHED, true); } g_object_unref(G_OBJECT(symbol)); + gtk_status_stack_update_activity_value(status, id, 1); + } return FALSE; @@ -1456,9 +1394,15 @@ static void do_filtering_on_symbols(const GSymbolsPanel *panel, GtkStatusStack * } + +/* ---------------------------------------------------------------------------------- */ +/* MECANISMES DE MISE A JOUR DE PANNEAU */ +/* ---------------------------------------------------------------------------------- */ + + /****************************************************************************** * * -* Paramètres : panel = panneau assurant l'affichage des symboles. * +* Paramètres : data = données complémentaire à manipuler. * * symbol = symbole à traiter. * * match = récupération des trouvailles. [OUT] * * * @@ -1470,7 +1414,7 @@ static void do_filtering_on_symbols(const GSymbolsPanel *panel, GtkStatusStack * * * ******************************************************************************/ -static bool is_symbol_matching(const GSymbolsPanel *panel, const GBinSymbol *symbol, regmatch_t *match) +static bool is_symbol_matching(const symbols_update_data *data, const GBinSymbol *symbol, regmatch_t *match) { bool result; /* Bilan à retourner */ #ifndef NDEBUG @@ -1485,19 +1429,13 @@ static bool is_symbol_matching(const GSymbolsPanel *panel, const GBinSymbol *sym #endif - result = is_content_matching(panel->filter, g_binary_symbol_get_label(symbol), match); + result = is_content_matching(data->filter, g_binary_symbol_get_label(symbol), match); return result; } - -/* ---------------------------------------------------------------------------------- */ -/* MECANISMES DE MISE A JOUR DE PANNEAU */ -/* ---------------------------------------------------------------------------------- */ - - /****************************************************************************** * * * Paramètres : panel = panneau ciblé par une mise à jour. * @@ -1517,6 +1455,7 @@ static const char *g_symbols_panel_setup(const GSymbolsPanel *panel, unsigned in { const char *result; /* Message à retourner */ GBinFormat *format; /* Format du binaire */ + int ret; /* Bilan de mise en place */ GtkBuilder *builder; /* Constructeur utilisé */ GtkTreeView *treeview; /* Arborescence graphique */ @@ -1556,6 +1495,18 @@ static const char *g_symbols_panel_setup(const GSymbolsPanel *panel, unsigned in } + if (G_PANEL_ITEM(panel)->filter != NULL) + { + (*data)->filter = (regex_t *)malloc(sizeof(regex_t)); + + ret = regcomp((*data)->filter, G_PANEL_ITEM(panel)->filter, REG_EXTENDED | REG_ICASE); + assert(ret == 0); + + } + + else + (*data)->filter = NULL; + /* Mémorisation de tous les noeuds ouverts */ builder = G_PANEL_ITEM(panel)->builder; @@ -1742,6 +1693,12 @@ static void g_symbols_panel_clean_data(GUpdatablePanel *panel, unsigned int uid, { 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]); |