/* Chrysalide - Outil d'analyse de fichiers binaires
* bookmark.c - boîte de dialogue pour les sauts à une adresse donnée
*
* Copyright (C) 2012-2014 Cyrille Bagard
*
* This file is part of Chrysalide.
*
* Chrysalide is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* Chrysalide is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Foobar. If not, see .
*/
#include "bookmark.h"
#include
#include
#include
#include "../../analysis/db/items/bookmark.h"
#include "../../gtkext/easygtk.h"
/* Filtre les adresses en hexadécimal pendant l'édition. */
static void filter_addresses(GtkEntry *, const gchar *, gint, gint *, gpointer);
/* Clôture l'édition d'une adresse. */
static void validate_addresses(GtkEntry *, GtkDialog *);
/******************************************************************************
* *
* Paramètres : entry = composant GTK concerné par la procédure. *
* text = nouveau texte inséré. *
* length = taille de ce texte. *
* position = point d'insertion. *
* data = adresse non utilisée ici. *
* *
* Description : Filtre les adresses en hexadécimal pendant l'édition. *
* *
* Retour : - *
* *
* Remarques : - *
* *
******************************************************************************/
static void filter_addresses(GtkEntry *entry, const gchar *text, gint length, gint *position, gpointer data)
{
gboolean has_hex; /* Préfixe '0x' déjà présent ? */
gchar *filtered; /* Contenu nouveau approuvé */
gint count; /* Nouvelle taille validée */
gint i; /* Boucle de parcours */
/**
* On cherche à empêcher l'édition avant un '0x' présent,
* ce qui viendrait fausser le fitrage.
*/
has_hex = g_str_has_prefix(gtk_entry_get_text(entry), "0x");
filtered = g_new(gchar, length);
count = 0;
for (i = 0; i < length; i++)
switch (text[i])
{
case '0' ... '9':
case 'a' ... 'f':
if (!has_hex || ((i + *position) >= 2))
filtered[count++] = text[i];
break;
case 'A' ... 'F':
if (!has_hex || ((i + *position) >= 2))
filtered[count++] = tolower(text[i]);
break;
case 'x':
case 'X':
if ((i + *position) == 1)
filtered[count++] = 'x';
break;
}
if (count > 0)
{
g_signal_handlers_block_by_func(G_OBJECT(entry), G_CALLBACK(filter_addresses), data);
gtk_editable_insert_text(GTK_EDITABLE(entry), filtered, count, position);
g_signal_handlers_unblock_by_func(G_OBJECT(entry), G_CALLBACK(filter_addresses), data);
}
g_signal_stop_emission_by_name(G_OBJECT(entry), "insert_text");
g_free(filtered);
}
/******************************************************************************
* *
* Paramètres : entry = composant GTK concerné par la procédure. *
* dialog = boîte de dialogue à valider. *
* *
* Description : Clôture l'édition d'une adresse. *
* *
* Retour : - *
* *
* Remarques : - *
* *
******************************************************************************/
static void validate_addresses(GtkEntry *entry, GtkDialog *dialog)
{
gtk_dialog_response(dialog, GTK_RESPONSE_OK);
}
/******************************************************************************
* *
* Paramètres : parent = fenêtre parente à surpasser. *
* addr = localisation du point à consigner. *
* *
* Description : Construit la fenêtre de création de signet. *
* *
* Retour : Adresse de la fenêtre mise en place. *
* *
* Remarques : - *
* *
******************************************************************************/
GtkWidget *create_bookmark_dialog(GtkWindow *parent, const vmpa2t *addr)
{
GtkWidget *result; /* Fenêtre à renvoyer */
GtkWidget *dlgvbox; /* Zone principale de la boîte */
GtkWidget *vbox; /* Support à construire #1 */
GtkWidget *frame; /* Support avec encadrement */
GtkWidget *sub_vbox; /* Support à construire #2 */
GtkWidget *hbox; /* Support à construire #3 */
GtkWidget *label; /* Message d'introduction */
GtkWidget *entry; /* Zone de saisie principale */
GtkWidget *radio; /* Définition de localisation */
VMPA_BUFFER(target); /* Désignation humaine de cible*/
result = gtk_dialog_new();
gtk_window_set_title(GTK_WINDOW(result), _("Add a bookmark"));
gtk_window_set_position(GTK_WINDOW(result), GTK_WIN_POS_CENTER);
gtk_window_set_modal(GTK_WINDOW(result), TRUE);
gtk_window_set_type_hint(GTK_WINDOW(result), GDK_WINDOW_TYPE_HINT_DIALOG);
dlgvbox = gtk_dialog_get_content_area(GTK_DIALOG(result));
gtk_widget_show(dlgvbox);
vbox = gtk_box_new(GTK_ORIENTATION_VERTICAL, 8);
gtk_widget_show(vbox);
gtk_box_pack_start(GTK_BOX(dlgvbox), vbox, TRUE, TRUE, 0);
gtk_container_set_border_width(GTK_CONTAINER(vbox), 8);
/* Localisation dans l'espace */
sub_vbox = gtk_box_new(GTK_ORIENTATION_VERTICAL, 8);
gtk_widget_show(sub_vbox);
frame = qck_create_frame(_("Localisation"), sub_vbox, 8, 0, 12, 0);
gtk_box_pack_start(GTK_BOX(vbox), frame, FALSE, FALSE, 0);
/* 1) Adresse */
hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 8);
gtk_widget_show(hbox);
gtk_box_pack_start(GTK_BOX(sub_vbox), hbox, FALSE, TRUE, 0);
label = qck_create_label(NULL, NULL, _("Target:"));
gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0);
entry = qck_create_entry(G_OBJECT(result), "addr", NULL);
//g_signal_connect(G_OBJECT(entry), "changed", G_CALLBACK(forbid_text_empty_entry), assistant);
gtk_box_pack_start(GTK_BOX(hbox), entry, FALSE, TRUE, 0);
/* 2) Type d'adresse */
hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 8);
gtk_widget_show(hbox);
gtk_box_pack_start(GTK_BOX(vbox), hbox, TRUE, TRUE, 0);
gtk_container_set_border_width(GTK_CONTAINER(hbox), 8);
radio = qck_create_radio_button(G_OBJECT(result), "phys", _("Value is physical offset"),
NULL, NULL, NULL);
gtk_box_pack_start(GTK_BOX(hbox), radio, TRUE, TRUE, 0);
radio = qck_create_radio_button(G_OBJECT(result), "virt", _("Value is virtual address"),
GTK_RADIO_BUTTON(radio), NULL, NULL);
gtk_box_pack_start(GTK_BOX(hbox), radio, TRUE, TRUE, 0);
/* Commentaire éventuel */
entry = qck_create_entry(G_OBJECT(result), "comment", NULL);
frame = qck_create_frame(_("Optional comment"), entry, 8, 0, 12, 0);
gtk_box_pack_start(GTK_BOX(vbox), frame, FALSE, FALSE, 0);
/* Zone de validation */
gtk_dialog_add_button(GTK_DIALOG(result), _("_Cancel"), GTK_RESPONSE_CANCEL);
gtk_dialog_add_button(GTK_DIALOG(result), _("_Ok"), GTK_RESPONSE_OK);
/* Remplissage avec les valeurs fournies */
entry = GTK_WIDGET(g_object_get_data(G_OBJECT(result), "addr"));
if (addr != NULL && has_virt_addr(addr))
{
vmpa2_virt_to_string(addr, MDS_UNDEFINED, target, NULL);
radio = GTK_WIDGET(g_object_get_data(G_OBJECT(result), "virt"));
}
else if (addr != NULL && has_phys_addr(addr))
{
vmpa2_virt_to_string(addr, MDS_UNDEFINED, target, NULL);
radio = GTK_WIDGET(g_object_get_data(G_OBJECT(result), "virt"));
}
else
radio = NULL;
if (radio == NULL)
{
gtk_entry_set_text(GTK_ENTRY(entry), "0x");
gtk_editable_set_position(GTK_EDITABLE(entry), -1);
gtk_widget_grab_focus(entry);
}
else
{
gtk_entry_set_text(GTK_ENTRY(entry), target);
gtk_editable_set_position(GTK_EDITABLE(entry), -1);
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(radio), TRUE);
}
if (radio != NULL)
{
entry = GTK_WIDGET(g_object_get_data(G_OBJECT(result), "comment"));
gtk_widget_grab_focus(entry);
}
return result;
}
/******************************************************************************
* *
* Paramètres : dialog = boîte de dialogue ayant reçu une validation. *
* *
* Description : Fournit le signet conçu via la saisie de l'utilisateur. *
* *
* Retour : Adresse reccueillie par la boîte de dialogue. *
* *
* Remarques : - *
* *
******************************************************************************/
GDbItem *get_item_from_bookmark_dialog(GtkWidget *dialog)
{
GDbItem *result; /* Signet nouveau à retourner */
GObject *ref; /* Espace de référencements */
vmpa2t *orig; /* Copie de valeur originale */
vmpa2t addr; /* Localisation finale utilisée*/
GtkWidget *entry; /* Zone de saisie principale */
const gchar *text; /* Adresse en version texte */
GtkToggleButton *radio; /* Définition de localisation */
ref = G_OBJECT(dialog);
/* Si la valeur d'origine a été conservée intacte... */
orig = (vmpa2t *)g_object_get_data(ref, "orig");
if (orig == NULL)
{
entry = GTK_WIDGET(g_object_get_data(ref, "addr"));
text = gtk_entry_get_text(GTK_ENTRY(entry));
radio = GTK_TOGGLE_BUTTON(g_object_get_data(ref, "phys"));
if (gtk_toggle_button_get_active(radio))
orig = string_to_vmpa_phy(text);
else
orig = string_to_vmpa_virt(text);
}
copy_vmpa(&addr, orig);
delete_vmpa(orig);
/* Récupération du commentaire éventuel */
entry = GTK_WIDGET(g_object_get_data(ref, "comment"));
text = gtk_entry_get_text(GTK_ENTRY(entry));
/* Mise en place du signet défini */
if (strlen(text) > 0)
result = G_DB_ITEM(g_db_bookmark_new(&addr, text));
else
result = G_DB_ITEM(g_db_bookmark_new(&addr, NULL));
return result;
}