/* Chrysalide - Outil d'analyse de fichiers binaires * strings.c - panneau d'affichage des chaînes de caractères * * Copyright (C) 2008-2012 Cyrille Bagard * * This file is part of Chrysalide. * * Chrysalide is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * Chrysalide is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "strings.h" #include #include #include "panel-int.h" #include "../dialogs/gotox.h" #include "../../common/extstr.h" #include "../../core/params.h" #include "../../format/format.h" #include "../../gtkext/easygtk.h" #include "../../gtkext/gtkdockable-int.h" /* -------------------------- PARTIE PRINCIPALE DU PANNEAU -------------------------- */ /* Panneau d'aperçu de graphiques (instance) */ struct _GStringsPanel { GPanelItem parent; /* A laisser en premier */ GtkTreeView *treeview; /* Composant d'affichage */ const regex_t *filter; /* Filtre appliqué ou NULL */ GtkMenu *menu; /* Menu contextuel pour param. */ GLoadedBinary *binary; /* Binaire en cours d'analyse */ }; /* Panneau d'aperçu de graphiques (classe) */ struct _GStringsPanelClass { GPanelItemClass parent; /* A laisser en premier */ }; /* Colonnes de la liste des symboles */ typedef enum _StringsColumn { STC_STRING, /* Elément GLib 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_COUNT /* Nombre de colonnes */ } StringsColumn; /* 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 *); /* Supprime toutes les références externes. */ 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 *, GStringsPanel *); /* Etablit une comparaison entre deux chaînes de caractères. */ static gint compare_strings_list_columns(GtkTreeModel *, GtkTreeIter *, GtkTreeIter *, gpointer); /* Réagit à une pression sur et simule l'édition. */ 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 *); /* ------------------------- FILTRAGE DES SYMBOLES PRESENTS ------------------------- */ /* Démarre l'actualisation du filtrage des chaînes. */ static void update_filtered_strings(GStringsPanel *, const regex_t *); /* Détermine si une chaîne textuelle doit être filtrée ou non. */ static bool is_string_filtered(GStringsPanel *, const char *, const char *); /* ------------------------ ATTRIBUTION D'UN MENU CONTEXTUEL ------------------------ */ /* Assure la gestion des clics de souris sur les signets. */ static gboolean on_button_event_over_strings(GtkWidget *, GdkEventButton *, GStringsPanel *); /* Construit le menu contextuel pour les signets. */ static GtkMenu *build_strings_panel_menu(GStringsPanel *); /* Fournit le signet sélectionné dans la liste. */ static GBinSymbol *get_selected_panel_symbol(GtkTreeView *, GtkTreeIter *); /* Réagit avec le menu "Editer le nom". */ static void mcb_strings_panel_edit(GtkMenuItem *, GStringsPanel *); /* Réagit avec le menu "Copier dans le presse-papiers". */ static void mcb_strings_panel_copy(GtkMenuItem *, GStringsPanel *); /* Réagit avec le menu "Trouver les références...". */ static void mcb_strings_panel_find_refs(GtkMenuItem *, GStringsPanel *); /* Réagit avec le menu "Filtrer...". */ static void mcb_strings_panel_filter(GtkMenuItem *, GStringsPanel *); /* ---------------------------------------------------------------------------------- */ /* PARTIE PRINCIPALE DU PANNEAU */ /* ---------------------------------------------------------------------------------- */ /* 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)) /****************************************************************************** * * * Paramètres : klass = classe à initialiser. * * * * Description : Initialise la classe des panneaux d'affichage de chaînes. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ static void g_strings_panel_class_init(GStringsPanelClass *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); object->dispose = (GObjectFinalizeFunc/* ! */)g_strings_panel_dispose; object->finalize = (GObjectFinalizeFunc)g_strings_panel_finalize; editem = G_EDITOR_ITEM_CLASS(klass); editem->update_binary = (update_item_binary_fc)change_strings_panel_current_binary; panel = G_PANEL_ITEM_CLASS(klass); panel->unique = true; panel->bindings = "F12"; } /****************************************************************************** * * * Paramètres : panel = instance à initialiser. * * * * Description : Initialise une instance de panneau d'affichage des chaînes. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ 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 */ GtkCellRenderer *renderer; /* Moteur de rendu de colonne */ GtkTreeViewColumn *column; /* Colonne de la 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 */ base = G_EDITOR_ITEM(panel); base->name = PANEL_STRINGS_ID; pitem = G_PANEL_ITEM(panel); pitem->personality = PIP_SINGLETON; pitem->lname = _("Strings"); pitem->dock_at_startup = false; pitem->path = strdup("N"); /* 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); gtk_widget_show(treeview); gtk_container_add(GTK_CONTAINER(base->widget), treeview); g_object_unref(G_OBJECT(store)); /* Cellules d'affichage */ renderer = gtk_cell_renderer_text_new(); column = gtk_tree_view_column_new_with_attributes(_("Physical address"), renderer, "text", STC_PHYSICAL, NULL); gtk_tree_view_column_set_sort_column_id(column, STC_PHYSICAL); gtk_tree_view_append_column(GTK_TREE_VIEW(treeview), column); renderer = gtk_cell_renderer_text_new(); column = gtk_tree_view_column_new_with_attributes(_("Virtual address"), renderer, "text", STC_VIRTUAL, NULL); gtk_tree_view_column_set_sort_column_id(column, STC_VIRTUAL); gtk_tree_view_append_column(GTK_TREE_VIEW(treeview), column); renderer = gtk_cell_renderer_text_new(); g_object_set(renderer, "xpad", 16, NULL); column = gtk_tree_view_column_new_with_attributes(_("Area"), renderer, "text", STC_AREA, NULL); gtk_tree_view_column_set_sort_column_id(column, STC_AREA); gtk_tree_view_append_column(GTK_TREE_VIEW(treeview), column); 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); column = gtk_tree_view_column_new_with_attributes(_("Name"), renderer, "text", STC_NAME, NULL); gtk_tree_view_column_set_sort_column_id(column, STC_NAME); gtk_tree_view_append_column(GTK_TREE_VIEW(treeview), column); renderer = gtk_cell_renderer_text_new(); column = gtk_tree_view_column_new_with_attributes(_("Value"), renderer, "markup", STC_VALUE, NULL); gtk_tree_view_column_set_sort_column_id(column, STC_VALUE); gtk_tree_view_append_column(GTK_TREE_VIEW(treeview), column); /* Tri de la liste */ sortable = GTK_TREE_SORTABLE(store); gtk_tree_sortable_set_sort_func(sortable, STC_PHYSICAL, compare_strings_list_columns, GINT_TO_POINTER(STC_PHYSICAL), NULL); gtk_tree_sortable_set_sort_func(sortable, STC_VIRTUAL, compare_strings_list_columns, GINT_TO_POINTER(STC_VIRTUAL), NULL); gtk_tree_sortable_set_sort_func(sortable, STC_AREA, compare_strings_list_columns, GINT_TO_POINTER(STC_AREA), NULL); gtk_tree_sortable_set_sort_func(sortable, STC_NAME, compare_strings_list_columns, GINT_TO_POINTER(STC_NAME), NULL); gtk_tree_sortable_set_sort_func(sortable, STC_VALUE, compare_strings_list_columns, GINT_TO_POINTER(STC_VALUE), NULL); gtk_tree_sortable_set_sort_column_id(sortable, STC_VIRTUAL, GTK_SORT_ASCENDING); /* Prise en compte de la sélection */ select = gtk_tree_view_get_selection(GTK_TREE_VIEW(treeview)); gtk_tree_selection_set_mode(select, GTK_SELECTION_SINGLE); 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), panel); /* Préparation du menu contextuel */ panel->menu = build_strings_panel_menu(panel); } /****************************************************************************** * * * Paramètres : iface = interface GTK à initialiser. * * * * Description : Procède à l'initialisation de l'interface de rassemblement. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ static void g_strings_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_strings; } /****************************************************************************** * * * Paramètres : panel = instance d'objet GLib à traiter. * * * * Description : Supprime toutes les références externes. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ static void g_strings_panel_dispose(GStringsPanel *panel) { if (panel->binary != NULL) g_object_unref(G_OBJECT(panel->binary)); G_OBJECT_CLASS(g_strings_panel_parent_class)->dispose(G_OBJECT(panel)); } /****************************************************************************** * * * Paramètres : panel = instance d'objet GLib à traiter. * * * * Description : Procède à la libération totale de la mémoire. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ static void g_strings_panel_finalize(GStringsPanel *panel) { G_OBJECT_CLASS(g_strings_panel_parent_class)->finalize(G_OBJECT(panel)); } /****************************************************************************** * * * Paramètres : - * * * * Description : Crée un panneau d'affichage des chaînes. * * * * Retour : Adresse de la structure mise en place. * * * * Remarques : - * * * ******************************************************************************/ GPanelItem *g_strings_panel_new(void) { GPanelItem *result; /* Structure à retourner */ result = g_object_new(G_TYPE_STRINGS_PANEL, NULL); return result; } /* ---------------------------------------------------------------------------------- */ /* 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 */ GPortionLayer *layer; /* Couche première de portions */ GBinContent *content; /* Contenu binaire en mémoire */ size_t count; /* Nombre des chaînes */ GBinSymbol **symbols; /* Liste des chaînes trouvées */ size_t i; /* Boucle de parcours */ 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); layer = g_exe_format_get_main_layer(format); content = g_binary_format_get_content(G_BIN_FORMAT(format)); symbols = g_binary_format_get_symbols(G_BIN_FORMAT(format), &count); for (i = 0; i < count; i++) { if (g_binary_symbol_get_target_type(symbols[i]) != STP_RO_STRING) continue; range = g_binary_symbol_get_range(symbols[i]); addr = get_mrange_addr(range); vmpa2_phys_to_string(addr, msize, phys, NULL); vmpa2_virt_to_string(addr, msize, virt, NULL); portion = g_portion_layer_find_portion_at_addr(layer, addr, (GdkRectangle []) { }); area = g_binary_portion_get_desc(portion); label = g_binary_symbol_get_label(symbols[i]); 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); continue; } if (is_string_filtered(panel, label, text)) { free(text); continue; } text = strrpl(text, "&", "&"); text = strrpl(text, "<", "<"); text = strrpl(text, ">", ">"); text = strrpl(text, "\r", "\\r"); text = strrpl(text, "\n", "\\n"); gtk_tree_store_append(store, &iter, NULL); gtk_tree_store_set(store, &iter, STC_STRING, symbols[i], STC_PHYSICAL, phys, STC_VIRTUAL, virt, STC_AREA, area, STC_NAME, label, STC_VALUE, text, -1); free(text); } g_object_unref(G_OBJECT(content)); g_object_unref(G_OBJECT(layer)); g_object_unref(G_OBJECT(format)); } /****************************************************************************** * * * Paramètres : selection = sélection modifiée. * * panel = structure contenant les informations maîtresses. * * * * Description : Réagit au changement de sélection des chaînes textuelles. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ static void on_strings_selection_change(GtkTreeSelection *selection, GStringsPanel *panel) { GtkTreeIter iter; /* Point de sélection */ GtkTreeModel *model; /* Modèle de gestion */ GBinSymbol *symbol; /* Symbole en cours d'étude */ const vmpa2t *addr; /* Adressse associée au signet */ GtkDisplayPanel *display; /* Afficheur effectif de code */ if (gtk_tree_selection_get_selected(selection, &model, &iter)) { gtk_tree_model_get(model, &iter, STC_STRING, &symbol, -1); addr = get_mrange_addr(g_binary_symbol_get_range(symbol)); display = g_editor_item_get_current_view(G_EDITOR_ITEM(panel)); gtk_display_panel_request_move(display, addr); g_object_unref(G_OBJECT(symbol)); } } /****************************************************************************** * * * Paramètres : model = gestionnaire du tableau de données. * * a = première ligne de données à traiter. * * b = seconde ligne de données à traiter. * * column = indice de la colonne à considérer, encodée. * * * * Description : Etablit une comparaison entre deux chaînes de caractères. * * * * Retour : Indication de tri entre les deux lignes fournies. * * * * Remarques : - * * * ******************************************************************************/ static gint compare_strings_list_columns(GtkTreeModel *model, GtkTreeIter *a, GtkTreeIter *b, gpointer column) { gint result; /* Valeur calculée à retourner */ gchar *value_a; /* Cellule de la ligne 'a' */ gchar *value_b; /* Cellule de la ligne 'b' */ gtk_tree_model_get(model, a, GPOINTER_TO_INT(column), &value_a, -1); gtk_tree_model_get(model, b, GPOINTER_TO_INT(column), &value_b, -1); if (value_a == NULL || value_b == NULL) { if (value_a == NULL && value_b == NULL) result = 0; else result = (value_a == NULL ? -1 : 1); } else result = g_utf8_collate(value_a, value_b); g_free(value_a); g_free(value_b); return result; } /****************************************************************************** * * * Paramètres : treeview = composant graphique présentant les paramètres. * * event = informations liées à l'événement. * * panel = panneau d'affichage sur lequel s'appuyer. * * * * Description : Réagit à une pression sur et simule l'édition. * * * * Retour : FALSE pour poursuivre la propagation de l'événement. * * * * Remarques : - * * * ******************************************************************************/ static gboolean on_key_pressed_over_strings(GtkTreeView *treeview, GdkEventKey *event, GStringsPanel *panel) { const gchar *accelerator; /* Combinaison de raccourci */ guint accel_key; /* Touche de raccourci */ GdkModifierType accel_mod; /* Modifiateurs attendus aussi */ if (!g_generic_config_get_value(get_main_configuration(), MPK_KEYBINDINGS_EDIT, &accelerator)) return FALSE; if (accelerator == NULL) return FALSE; gtk_accelerator_parse(accelerator, &accel_key, &accel_mod); if (event->keyval == accel_key && event->state == accel_mod) mcb_strings_panel_edit(NULL, panel); return FALSE; } /****************************************************************************** * * * 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. * * * * Description : Réagit à une édition de l'étiquette d'une chaîne textuelle. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ static void on_string_value_edited(GtkCellRendererText *renderer, gchar *path, gchar *new, GtkTreeStore *store) { GtkTreePath *tree_path; /* Chemin d'accès natif */ GtkTreeIter iter; /* Point de la modification */ GBinSymbol *symbol; /* Symbole à actualiser */ 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)) goto opve_bad_iter; gtk_tree_model_get(GTK_TREE_MODEL(store), &iter, STC_STRING, &symbol, -1); g_binary_symbol_set_alt_label(symbol, new); g_object_unref(G_OBJECT(symbol)); opve_bad_iter: gtk_tree_path_free(tree_path); } /* ---------------------------------------------------------------------------------- */ /* FILTRAGE DES SYMBOLES PRESENTS */ /* ---------------------------------------------------------------------------------- */ /****************************************************************************** * * * 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 chaînes. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ static void update_filtered_strings(GStringsPanel *panel, const regex_t *preg) { panel->filter = preg; change_strings_panel_current_binary(panel, panel->binary); } /****************************************************************************** * * * 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. * * * * Description : Détermine si une chaîne textuelle doit être filtrée ou non. * * * * Retour : true si le symbole ne doit pas être affiché, false sinon. * * * * Remarques : - * * * ******************************************************************************/ static bool is_string_filtered(GStringsPanel *panel, const char *label, const char *value) { bool result; /* Bilan à retourner */ regmatch_t match; /* Récupération des trouvailles*/ int ret; /* Bilan du filtrage */ if (panel->filter == NULL) return false; result = true; if (label != NULL) { ret = regexec(panel->filter, label, 1, &match, 0); result &= (ret == REG_NOMATCH); } ret = regexec(panel->filter, value, 1, &match, 0); result &= (ret == REG_NOMATCH); return result; } /* ---------------------------------------------------------------------------------- */ /* ATTRIBUTION D'UN MENU CONTEXTUEL */ /* ---------------------------------------------------------------------------------- */ /****************************************************************************** * * * Paramètres : widget = composant GTK visé par l'opération. * * event = informations liées à l'événement. * * panel = informations liées au panneau associé. * * * * Description : Assure la gestion des clics de souris sur les signets. * * * * Retour : FALSE pour poursuivre la propagation de l'événement. * * * * Remarques : - * * * ******************************************************************************/ static gboolean on_button_event_over_strings(GtkWidget *widget, GdkEventButton *event, GStringsPanel *panel) { GtkTreeSelection *selection; /* Sélection courante */ GtkTreeIter iter; /* Point de sélection */ GtkTreeModel *model; /* Modèle de gestion */ GBinSymbol *symbol; /* Symbole en cours d'étude */ const vmpa2t *addr; /* Adressse associée au signet */ GtkDisplayPanel *display; /* Afficheur effectif de code */ switch (event->button) { case 1: if (event->type != GDK_2BUTTON_PRESS) break; selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(widget)); if (gtk_tree_selection_get_selected(selection, &model, &iter)) { gtk_tree_model_get(model, &iter, STC_STRING, &symbol, -1); addr = get_mrange_addr(g_binary_symbol_get_range(symbol)); display = g_editor_item_get_current_view(G_EDITOR_ITEM(panel)); gtk_display_panel_request_move(display, addr); g_object_unref(G_OBJECT(symbol)); } break; case 3: if (event->type == GDK_BUTTON_RELEASE) gtk_menu_popup(panel->menu, NULL, NULL, NULL, NULL, event->button, event->time); break; } return FALSE; } /****************************************************************************** * * * Paramètres : panel = panneau d'affichage des signets liés à un binaire. * * * * Description : Construit le menu contextuel pour les signets. * * * * Retour : Panneau de menus mis en place. * * * * Remarques : - * * * ******************************************************************************/ static GtkMenu *build_strings_panel_menu(GStringsPanel *panel) { GtkWidget *result; /* Support à retourner */ GtkWidget *submenuitem; /* Sous-élément de menu */ result = gtk_menu_new(); submenuitem = qck_create_menu_item(NULL, NULL, _("_Edit name"), NULL, NULL); gtk_container_add(GTK_CONTAINER(result), submenuitem); submenuitem = qck_create_menu_item(NULL, NULL, _("_Copy to clipboard"), G_CALLBACK(mcb_strings_panel_copy), panel); gtk_container_add(GTK_CONTAINER(result), submenuitem); submenuitem = qck_create_menu_item(NULL, NULL, _("_Find references..."), G_CALLBACK(mcb_strings_panel_find_refs), panel); gtk_container_add(GTK_CONTAINER(result), submenuitem); submenuitem = qck_create_menu_separator(); gtk_container_add(GTK_CONTAINER(result), submenuitem); submenuitem = qck_create_menu_item(NULL, NULL, _("Filter..."), G_CALLBACK(mcb_strings_panel_filter), panel); gtk_container_add(GTK_CONTAINER(result), submenuitem); return GTK_MENU(result); } /****************************************************************************** * * * Paramètres : treeview = liste d'affichage à consulter. * * save = zone de conservation du point de trouvaille. [OUT]* * * * Description : Fournit le signet sélectionné dans la liste. * * * * Retour : Signet en cours d'édition ou NULL en cas de soucis. * * * * Remarques : Le résultat non nul est à déréférencer après usage. * * * ******************************************************************************/ static GBinSymbol *get_selected_panel_symbol(GtkTreeView *treeview, GtkTreeIter *save) { GBinSymbol *result; /* Chaîne textuelle à renvoyer */ GtkTreeSelection *selection; /* Représentation de sélection */ GtkTreeModel *model; /* Gestionnaire des données */ GtkTreeIter iter; /* Point de la sélection */ result = NULL; 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); if (save != NULL) *save = iter; return result; } /****************************************************************************** * * * Paramètres : menuitem = élément de menu sélectionné. * * panel = panneau d'affichage des signets liés à un binaire.* * * * Description : Réagit avec le menu "Editer le nom". * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ static void mcb_strings_panel_edit(GtkMenuItem *menuitem, GStringsPanel *panel) { GtkTreeIter iter; /* Point de la sélection */ GBinSymbol *symbol; /* Symbole sélectionné */ GtkTreeModel *model; /* Gestionnaire de données */ GtkTreePath *path; /* Chemin d'accès à ce point */ symbol = get_selected_panel_symbol(panel->treeview, &iter); if (symbol == NULL) return; model = gtk_tree_view_get_model(panel->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), TRUE); gtk_tree_path_free(path); g_object_unref(G_OBJECT(symbol)); } /****************************************************************************** * * * Paramètres : menuitem = élément de menu sélectionné. * * treeview = arbre contenant la sélection à exporter. * * * * Description : Réagit avec le menu "Copier dans le presse-papiers". * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ static void mcb_strings_panel_copy(GtkMenuItem *menuitem, GStringsPanel *panel) { 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); if (gtk_tree_selection_get_selected(selection, &model, &iter)) { gtk_tree_model_get(model, &iter, STC_VALUE, &string, -1); if (string != NULL) { clipboard = gtk_clipboard_get_for_display(gdk_display_get_default(), GDK_SELECTION_PRIMARY); gtk_clipboard_set_text(clipboard, string, strlen(string)); g_free(string); } } } /****************************************************************************** * * * Paramètres : menuitem = élément de menu sélectionné. * * panel = panneau d'affichage des signets liés à un binaire.* * * * Description : Réagit avec le menu "Trouver les références...". * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ static void mcb_strings_panel_find_refs(GtkMenuItem *menuitem, GStringsPanel *panel) { GBinSymbol *symbol; /* Symbole sélectionné */ const mrange_t *range; /* Couverture en mémoire */ GLoadedBinary *binary; /* Représentation binaire */ GArchProcessor *proc; /* Processeur de l'architecture*/ GArchInstruction *instr; /* Point de croisements */ GObject *ref; /* Espace de référencements */ GtkWidget *dialog; /* Boîte de dialogue à montrer */ vmpa2t *addr; /* Adresse de destination */ GtkDisplayPanel *display; /* Afficheur effectif de code */ symbol = get_selected_panel_symbol(panel->treeview, NULL); if (symbol == NULL) return; range = g_binary_symbol_get_range(symbol); binary = g_editor_item_get_current_binary(G_EDITOR_ITEM(panel)); proc = g_loaded_binary_get_processor(binary); /** * Se rapporter aux commentaires de mcb_edition_list_xrefs() pour les questions * concernant l'usage d'une adresse d'instruction au lieu de son emplacement. */ instr = g_arch_processor_find_instr_by_address(proc, get_mrange_addr(range)); ref = g_editor_item_get_global_ref(G_EDITOR_ITEM(panel)); dialog = create_gotox_dialog_for_cross_references(GTK_WINDOW(ref), binary, instr, true); if (gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_OK) { addr = get_address_from_gotox_dialog(dialog); display = g_editor_item_get_current_view(G_EDITOR_ITEM(panel)); gtk_display_panel_request_move(display, addr); delete_vmpa(addr); } gtk_widget_destroy(dialog); if (instr != NULL) g_object_unref(G_OBJECT(instr)); g_object_unref(G_OBJECT(proc)); g_object_unref(G_OBJECT(symbol)); } /****************************************************************************** * * * Paramètres : menuitem = élément de menu sélectionné. * * panel = panneau d'affichage des signets liés à un binaire.* * * * Description : Réagit avec le menu "Filtrer...". * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ 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); if (param == NULL) return; g_config_param_make_empty(param); g_object_unref(G_OBJECT(param)); #endif }