From e28ba4839188307f94293af4e29ed6e774c0a499 Mon Sep 17 00:00:00 2001 From: Cyrille Bagard Date: Thu, 15 Jan 2015 14:57:19 +0000 Subject: Exported disassembled content in plain text or HTML format properly. git-svn-id: svn://svn.gna.org/svn/chrysalide/trunk@455 abbe820e-26c8-41b2-8c08-b7b2b41f8b0a --- ChangeLog | 19 ++ src/dialogs/export.c | 573 +++++++++++++++++++++++++++++++++---------- src/glibext/gbufferline.c | 136 ++++++++-- src/glibext/gbufferline.h | 2 +- src/glibext/gbuffersegment.c | 130 +++++++++- src/glibext/gbuffersegment.h | 51 +++- src/glibext/gcodebuffer.c | 72 ++++++ src/glibext/gcodebuffer.h | 5 +- 8 files changed, 831 insertions(+), 157 deletions(-) diff --git a/ChangeLog b/ChangeLog index f902da1..b02c2cb 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,22 @@ +15-01-15 Cyrille Bagard + + * src/dialogs/export.c: + Export disassembled content in plain text or HTML format properly. + + * src/glibext/gbufferline.c: + * src/glibext/gbufferline.h: + Update the export routines. + + * src/glibext/gbuffersegment.c: + Fix a bug in pattern slant (mismatch 'italic' vs 'oblique'). Fix a bug + when storing the segment text: only keep the submitted length. Update + the export routines. + + * src/glibext/gbuffersegment.h: + * src/glibext/gcodebuffer.c: + * src/glibext/gcodebuffer.h: + Update the export routines. + 15-01-14 Cyrille Bagard * src/arch/arm/v7/arm.c: diff --git a/src/dialogs/export.c b/src/dialogs/export.c index 76cdcfd..5667730 100644 --- a/src/dialogs/export.c +++ b/src/dialogs/export.c @@ -24,6 +24,7 @@ #include "export.h" +#include #include #include #include @@ -33,6 +34,7 @@ #include +#include "../common/extstr.h" #include "../gtkext/easygtk.h" @@ -40,41 +42,28 @@ /* ------------------------ PARTIE PRINCIPALE DE L'ASSISTANT ------------------------ */ -/* Conservation des informations utiles */ -struct _export_data -{ - int fd; /* Flux ouvert en écriture */ - BufferExportType type; /* Type d'exportation */ - - bool addr; /* Affichage des adresses */ - bool code; /* Affichage du code binaire */ - bool content; /* Affichage du contenu humain */ - -}; - - /* Ferme l'assistant sans dérouler la procédure. */ static void export_assistant_cancel(GtkAssistant *, gpointer); /* Ferme l'assistant et déroule la procédure. */ static void export_assistant_close(GtkAssistant *, GObject *); -/* Assure l'exportation en différé. */ -static bool export_buffer_line(GCodeBuffer *, GBufferLine *, struct _export_data *); +/* ----------------------- DEFINITION DU FORMAT D'EXPORTATION ----------------------- */ -/* -------------------- DEFINITION DES REGLAGES DE L'EXPORTATION -------------------- */ +/* Ajoute le panneau de choix du format d'exportation. */ +static void register_format_panel(GtkAssistant *); -/* Ajoute le panneau de choix du type de sortie. */ -static void register_output_panel(GtkAssistant *); +/* Réagit un changement du format pour l'exportation. */ +static void on_export_format_changed(GtkComboBox *, GtkAssistant *); -/* Réagit un changement du nom de fichier pour l'exportation. */ -static void on_export_filename_changed(GtkEntry *, GtkAssistant *); +/* Interdit un champ de texte vide pour les options de texte. */ +static void forbid_text_empty_entry(GtkEntry *, GtkAssistant *); -/* Sélectionne ou non un nouveau fichier de sortie. */ -static void on_filename_browsing_clicked(GtkButton *, GObject *); +/* Interdit un champ de texte vide pour les options HTML. */ +static void forbid_html_empty_entry(GtkEntry *, GtkAssistant *); @@ -85,6 +74,21 @@ static void on_filename_browsing_clicked(GtkButton *, GObject *); static void register_content_panel(GtkAssistant *); + +/* ------------------------ DEFINITION DE LA SORTIE ATTENDUE ------------------------ */ + + +/* Ajoute le panneau de choix du type de sortie. */ +static void register_output_panel(GtkAssistant *); + +/* Réagit un changement du nom de fichier pour l'exportation. */ +static void on_export_filename_changed(GtkEntry *, GtkAssistant *); + +/* Sélectionne ou non un nouveau fichier de sortie. */ +static void on_filename_browsing_clicked(GtkButton *, GObject *); + + + /* ---------------------------------------------------------------------------------- */ /* PARTIE PRINCIPALE DE L'ASSISTANT */ /* ---------------------------------------------------------------------------------- */ @@ -109,7 +113,7 @@ void run_export_assistant(GLoadedBinary *binary, GtkWindow *parent) GObject *ref; /* Espace de référencement */ assistant = gtk_assistant_new(); - gtk_widget_set_size_request(assistant, 450, 300); + gtk_widget_set_size_request(assistant, 500, 350); gtk_window_set_position(GTK_WINDOW(assistant), GTK_WIN_POS_CENTER); gtk_window_set_title(GTK_WINDOW(assistant), _("Export assistant")); @@ -119,8 +123,9 @@ void run_export_assistant(GLoadedBinary *binary, GtkWindow *parent) ref = G_OBJECT(assistant); g_object_set_data(ref, "binary", binary); - register_output_panel(GTK_ASSISTANT(assistant)); + register_format_panel(GTK_ASSISTANT(assistant)); register_content_panel(GTK_ASSISTANT(assistant)); + register_output_panel(GTK_ASSISTANT(assistant)); g_signal_connect(G_OBJECT(assistant), "cancel", G_CALLBACK(export_assistant_cancel), NULL); g_signal_connect(G_OBJECT(assistant), "close", G_CALLBACK(export_assistant_close), ref); @@ -145,6 +150,14 @@ void run_export_assistant(GLoadedBinary *binary, GtkWindow *parent) static void export_assistant_cancel(GtkAssistant *assistant, gpointer data) { + GObject *support; /* Support interne à supprimer */ + + support = G_OBJECT(g_object_get_data(G_OBJECT(assistant), "text_options")); + if (support != NULL) g_object_unref(support); + + support = G_OBJECT(g_object_get_data(G_OBJECT(assistant), "html_options")); + if (support != NULL) g_object_unref(support); + gtk_widget_destroy(GTK_WIDGET(assistant)); } @@ -165,94 +178,121 @@ static void export_assistant_cancel(GtkAssistant *assistant, gpointer data) static void export_assistant_close(GtkAssistant *assistant, GObject *ref) { + GtkComboBox *combo; /* Selection du format */ + BufferExportType type; /* Type d'exportation requise */ + buffer_export_context ctx; /* Contexte à constituer */ GtkEntry *entry; /* Zone de saisie */ const gchar *filename; /* Chemin d'accès du fichier */ - int fd; /* Descripteur de la sortie */ - struct _export_data *export; /* Informations à faire suivre */ GtkToggleButton *checkbutton; /* Coche à retrouver */ + bool display[BLC_DISPLAY]; /* Affichage à garantir */ GLoadedBinary *binary; /* Binaire chargé à parcourir */ GCodeBuffer *buffer; /* Tampon de code à traiter */ + GBufferView *view; /* Vue à exporter */ + GObject *support; /* Support interne à supprimer */ + + /* Type d'exportation */ + + combo = GTK_COMBO_BOX(g_object_get_data(ref, "format")); + + type = (BufferExportType)gtk_combo_box_get_active(combo); /* Fichier de sortie */ entry = GTK_ENTRY(g_object_get_data(ref, "filename")); filename = gtk_entry_get_text(entry); - fd = open(filename, O_CREAT | O_WRONLY, S_IRUSR | S_IWUSR); - if (fd == -1) + switch (type) { - perror("open"); - return; + case BET_TEXT: + case BET_HTML: + ctx.fd = open(filename, O_CREAT | O_WRONLY | O_TRUNC, S_IRUSR | S_IWUSR); + if (ctx.fd == -1) + { + perror("open"); + return; + } + break; + + default: + assert(false); + break; + } - export = (struct _export_data *)calloc(1, sizeof(struct _export_data)); + /* Eléments à afficher */ - export->fd = fd; + checkbutton = GTK_TOGGLE_BUTTON(g_object_get_data(ref, "physical_off")); + display[BLC_PHYSICAL] = gtk_toggle_button_get_active(checkbutton); - /* Type d'exportation */ + checkbutton = GTK_TOGGLE_BUTTON(g_object_get_data(ref, "virtual_addr")); + display[BLC_VIRTUAL] = gtk_toggle_button_get_active(checkbutton); - export->type = BET_TEXT; + checkbutton = GTK_TOGGLE_BUTTON(g_object_get_data(ref, "binary_code")); + display[BLC_BINARY] = gtk_toggle_button_get_active(checkbutton); - /* Eléments à afficher */ + /* Options éventuelles */ - checkbutton = GTK_TOGGLE_BUTTON(g_object_get_data(ref, "virtual_addr")); - export->addr = gtk_toggle_button_get_active(checkbutton); + switch (type) + { + case BET_TEXT: + entry = GTK_ENTRY(g_object_get_data(ref, "text_separator")); + ctx.sep = gtk_entry_get_text(entry); + if (strcmp(ctx.sep, "\\t") == 0) ctx.sep = "\t"; + break; - checkbutton = GTK_TOGGLE_BUTTON(g_object_get_data(ref, "binary_code")); - export->code = gtk_toggle_button_get_active(checkbutton); + case BET_HTML: + entry = GTK_ENTRY(g_object_get_data(ref, "html_font_name")); + ctx.font_name = gtk_entry_get_text(entry); + + entry = GTK_ENTRY(g_object_get_data(ref, "html_bg_color")); + ctx.bg_color = gtk_entry_get_text(entry); + + break; - checkbutton = GTK_TOGGLE_BUTTON(g_object_get_data(ref, "assembly_code")); - export->content = gtk_toggle_button_get_active(checkbutton); + default: + break; + + } /* Programmation de la tâche */ binary = G_LOADED_BINARY(g_object_get_data(ref, "binary")); buffer = g_loaded_binary_get_disassembled_buffer(binary); + view = g_buffer_view_new(buffer); - g_buffer_code_scan(buffer, 0, VMPA_MAX, _("Exporting binary lines..."), - (process_line_fc)export_buffer_line, export); + g_buffer_view_export(view, &ctx, type, display); - gtk_widget_destroy(GTK_WIDGET(assistant)); + /* Conclusion */ -} + switch (type) + { + case BET_TEXT: + case BET_HTML: + close(ctx.fd); + break; + default: + break; -/****************************************************************************** -* * -* Paramètres : buffer = tampon de code contenant toutes les lignes. * -* line = ligne dont le contenu est à exporter. * -* export = informations utiles à la manoeuvre. * -* * -* Description : Assure l'exportation en différé. * -* * -* Retour : - * -* * -* Remarques : - * -* * -******************************************************************************/ - -static bool export_buffer_line(GCodeBuffer *buffer, GBufferLine *line, struct _export_data *export) -{ - /* Si les traitements sont terminés... */ - if (line == NULL) - { - close(export->fd); - free(export); } - else - g_buffer_line_export(line, export->fd, export->type, - true/* FIX%E */, export->addr, export->code, export->content); + g_object_unref(view); + + support = G_OBJECT(g_object_get_data(G_OBJECT(assistant), "text_options")); + if (support != NULL) g_object_unref(support); - return true; + support = G_OBJECT(g_object_get_data(G_OBJECT(assistant), "html_options")); + if (support != NULL) g_object_unref(support); + + gtk_widget_destroy(GTK_WIDGET(assistant)); } /* ---------------------------------------------------------------------------------- */ -/* DEFINITION DES REGLAGES DE L'EXPORTATION */ +/* DEFINITION DU FORMAT D'EXPORTATION */ /* ---------------------------------------------------------------------------------- */ @@ -260,7 +300,7 @@ static bool export_buffer_line(GCodeBuffer *buffer, GBufferLine *line, struct _e * * * Paramètres : assistant = fenêtre à compléter et référencement global. * * * -* Description : Ajoute le panneau de choix du type de sortie. * +* Description : Ajoute le panneau de choix du format d'exportation. * * * * Retour : - * * * @@ -268,17 +308,15 @@ static bool export_buffer_line(GCodeBuffer *buffer, GBufferLine *line, struct _e * * ******************************************************************************/ -static void register_output_panel(GtkAssistant *assistant) +static void register_format_panel(GtkAssistant *assistant) { GtkWidget *alignment; /* Disposition sur le support */ GtkWidget *vbox; /* Support principal #1 */ GtkWidget *hbox; /* Support principal #2 */ GtkWidget *label; /* Etiquette d'indication */ GtkWidget *combobox; /* Sélection du format */ - GtkWidget *entry; /* Zone de saisie de texte */ - GtkWidget *button; /* Sélection de fichier */ - GLoadedBinary *binary; /* Binaire chargé à parcourir */ - const char *filename; /* Chemin d'accès par défaut */ + GtkWidget *options; /* Zone d'options */ + GtkWidget *content; /* Accueil desdites options */ alignment = qck_create_padded_alignment(8, 8, 8, 8); @@ -295,45 +333,173 @@ static void register_output_panel(GtkAssistant *assistant) label = qck_create_label(NULL, NULL, _("Format: ")); gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0); - combobox = qck_create_combobox(NULL, NULL, G_CALLBACK(NULL), NULL); + combobox = qck_create_combobox(G_OBJECT(assistant), "format", G_CALLBACK(on_export_format_changed), assistant); gtk_box_pack_start(GTK_BOX(hbox), combobox, TRUE, TRUE, 0); gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combobox), _("Simple text")); + gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combobox), _("HTML")); - gtk_combo_box_set_active(GTK_COMBO_BOX(combobox), 0); - - /* Fichier de sortie */ - - hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 8); - gtk_widget_show(hbox); - gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0); + /* Eventuelles options */ - label = qck_create_label(NULL, NULL, _("File: ")); - gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0); + options = qck_create_frame(_("Options"), &content, 0, 12, 12, 0); + gtk_box_pack_start(GTK_BOX(vbox), options, FALSE, FALSE, 0); - entry = qck_create_entry(G_OBJECT(assistant), "filename", NULL); - gtk_box_pack_start(GTK_BOX(hbox), entry, TRUE, TRUE, 0); - - button = qck_create_button(NULL, NULL, "...", G_CALLBACK(on_filename_browsing_clicked), assistant); - gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, FALSE, 0); + g_object_set_data(G_OBJECT(assistant), "options", content); /* Intégration */ + gtk_combo_box_set_active(GTK_COMBO_BOX(combobox), 1); + gtk_assistant_append_page(assistant, alignment); - gtk_assistant_set_page_title(assistant, alignment, _("Output")); + gtk_assistant_set_page_title(assistant, alignment, _("Format")); gtk_assistant_set_page_type(assistant, alignment, GTK_ASSISTANT_PAGE_INTRO); gtk_assistant_set_page_complete(assistant, alignment, TRUE); - /* Choix par défaut */ +} - binary = G_LOADED_BINARY(g_object_get_data(G_OBJECT(assistant), "binary")); - filename = g_loaded_binary_get_name(binary, true); - gtk_entry_set_text(GTK_ENTRY(entry), filename); - gtk_editable_insert_text(GTK_EDITABLE(entry), ".txt", -1, (gint []) { strlen(filename) }); +/****************************************************************************** +* * +* Paramètres : combo = liste dont la sélection vient de changer. * +* assistant = fenêtre affichée et référencement global. * +* * +* Description : Réagit un changement du format pour l'exportation. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ - g_signal_connect(G_OBJECT(entry), "changed", G_CALLBACK(on_export_filename_changed), assistant); +static void on_export_format_changed(GtkComboBox *combo, GtkAssistant *assistant) +{ + BufferExportType selected; /* Format attendu */ + GtkContainer *content; /* Accueil des options */ + GtkWidget *old; /* Ancien support à remplacer */ + GtkWidget *vbox; /* Support principal #1 */ + GtkWidget *hbox; /* Support principal #2 */ + GtkWidget *label; /* Etiquette d'indication */ + GtkWidget *entry; /* Zone de saisie de valeur */ + char *filename; /* Chemin à venir modifier */ + char *dot; /* Dernière occurence de point */ + + selected = (BufferExportType)gtk_combo_box_get_active(combo); + + content = GTK_CONTAINER(g_object_get_data(G_OBJECT(assistant), "options")); + + old = gtk_bin_get_child(GTK_BIN(content)); + if (old != NULL) + { + g_object_ref(G_OBJECT(old)); + gtk_container_remove(content, old); + } + + switch (selected) + { + case BET_TEXT: + + hbox = GTK_WIDGET(g_object_get_data(G_OBJECT(assistant), "text_options")); + + if (hbox == NULL) + { + hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 8); + g_object_ref(G_OBJECT(hbox)); + gtk_widget_show(hbox); + g_object_set_data(G_OBJECT(assistant), "text_options", hbox); + + label = qck_create_label(NULL, NULL, _("String between columns: ")); + gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0); + + entry = qck_create_entry(G_OBJECT(assistant), "text_separator", NULL); + g_signal_connect(G_OBJECT(entry), "changed", G_CALLBACK(forbid_text_empty_entry), assistant); + gtk_box_pack_start(GTK_BOX(hbox), entry, TRUE, TRUE, 0); + gtk_entry_set_text(GTK_ENTRY(entry), "\\t"); + + } + + gtk_container_add(content, hbox); + + break; + + case BET_HTML: + + vbox = GTK_WIDGET(g_object_get_data(G_OBJECT(assistant), "html_options")); + + if (vbox == NULL) + { + vbox = gtk_box_new(GTK_ORIENTATION_VERTICAL, 8); + g_object_ref(G_OBJECT(vbox)); + gtk_widget_show(vbox); + g_object_set_data(G_OBJECT(assistant), "html_options", vbox); + + hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 8); + gtk_widget_show(hbox); + gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0); + + label = qck_create_label(NULL, NULL, _("HTML table font name: ")); + gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0); + + entry = qck_create_entry(G_OBJECT(assistant), "html_font_name", NULL); + g_signal_connect(G_OBJECT(entry), "changed", G_CALLBACK(forbid_html_empty_entry), assistant); + gtk_box_pack_start(GTK_BOX(hbox), entry, TRUE, TRUE, 0); + gtk_entry_set_text(GTK_ENTRY(entry), "monospace"); + + hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 8); + gtk_widget_show(hbox); + gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0); + + label = qck_create_label(NULL, NULL, _("HTML table background color: ")); + gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0); + + entry = qck_create_entry(G_OBJECT(assistant), "html_bg_color", NULL); + g_signal_connect(G_OBJECT(entry), "changed", G_CALLBACK(forbid_html_empty_entry), assistant); + gtk_box_pack_start(GTK_BOX(hbox), entry, TRUE, TRUE, 0); + gtk_entry_set_text(GTK_ENTRY(entry), "#2c2c2c"); + + } + + gtk_container_add(content, vbox); + + break; + + default: + break; + + } + + /* Mise à jour de l'extension du fichier de sortie, si possible */ + + entry = GTK_WIDGET(g_object_get_data(G_OBJECT(assistant), "filename")); + + if (entry != NULL) + { + filename = strdup(gtk_entry_get_text(GTK_ENTRY(entry))); + + dot = strrchr(filename, '.'); + if (dot == NULL) goto oefc_no_dot; + + *dot = '\0'; + + switch (selected) + { + case BET_TEXT: + filename = stradd(filename, ".txt"); + break; + case BET_HTML: + filename = stradd(filename, ".html"); + break; + default: + break; + } + + gtk_entry_set_text(GTK_ENTRY(entry), filename); + + oefc_no_dot: + + free(filename); + + } } @@ -343,7 +509,7 @@ static void register_output_panel(GtkAssistant *assistant) * Paramètres : entry = zone de texte dont le contenu vient de changer. * * assistant = fenêtre affichée et référencement global. * * * -* Description : Réagit un changement du nom de fichier pour l'exportation. * +* Description : Interdit un champ de texte vide pour les options HTML. * * * * Retour : - * * * @@ -351,7 +517,7 @@ static void register_output_panel(GtkAssistant *assistant) * * ******************************************************************************/ -static void on_export_filename_changed(GtkEntry *entry, GtkAssistant *assistant) +static void forbid_text_empty_entry(GtkEntry *entry, GtkAssistant *assistant) { const gchar *text; /* Texte saisi dans la zone */ gint num; /* Etape courante */ @@ -369,10 +535,10 @@ static void on_export_filename_changed(GtkEntry *entry, GtkAssistant *assistant) /****************************************************************************** * * -* Paramètres : button = bouton d'édition de la sélection. * -* ref = espace de référencement principal. * +* Paramètres : _entry = zone de texte dont le contenu vient de changer. * +* assistant = fenêtre affichée et référencement global. * * * -* Description : Sélectionne ou non un nouveau fichier de sortie. * +* Description : Interdit un champ de texte vide pour les options de texte. * * * * Retour : - * * * @@ -380,32 +546,46 @@ static void on_export_filename_changed(GtkEntry *entry, GtkAssistant *assistant) * * ******************************************************************************/ -static void on_filename_browsing_clicked(GtkButton *button, GObject *ref) +static void forbid_html_empty_entry(GtkEntry *_entry, GtkAssistant *assistant) { - GtkWidget *dialog; /* Boîte à afficher */ - gchar *filename; /* Nom du fichier à intégrer */ - GtkEntry *entry; /* Zone de saisie à maj. */ + bool status; /* Etat final à remonter */ + GtkEntry *entry; /* Zone de texte générique */ + const gchar *text; /* Texte saisi dans la zone */ + gint num; /* Etape courante */ + GtkWidget *page; /* Support de cette étape */ - dialog = gtk_file_chooser_dialog_new(_("Choose an output filename"), GTK_WINDOW(ref), - GTK_FILE_CHOOSER_ACTION_SAVE, - _("_Cancel"), GTK_RESPONSE_CANCEL, - _("_Save"), GTK_RESPONSE_ACCEPT, - NULL); + status = true; - entry = GTK_ENTRY(g_object_get_data(ref, "filename")); - gtk_file_chooser_set_filename(GTK_FILE_CHOOSER(dialog), gtk_entry_get_text(entry)); + /* Police de caractère */ - if (gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT) - { - filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dialog)); + entry = GTK_ENTRY(g_object_get_data(G_OBJECT(assistant), "html_font_name")); + text = gtk_entry_get_text(entry); - gtk_entry_set_text(GTK_ENTRY(entry), filename); + status &= (strlen(text) > 0); - g_free(filename); + /* Couleur de fond */ + + entry = GTK_ENTRY(g_object_get_data(G_OBJECT(assistant), "html_bg_color")); + + if (entry != NULL) + { + text = gtk_entry_get_text(entry); + + status &= (strlen(text) > 0); } - gtk_widget_destroy(dialog); + /* Mise à jour graphique */ + + num = gtk_assistant_get_current_page(assistant); + + if (num != -1) + { + page = gtk_assistant_get_nth_page(assistant, num); + + gtk_assistant_set_page_complete(assistant, page, status); + + } } @@ -445,22 +625,22 @@ static void register_content_panel(GtkAssistant *assistant) /* Eléments à afficher */ - frame = qck_create_frame(_("Items to display"), &subalign, 0, 0, 12, 0); + frame = qck_create_frame(_("Items to display"), &subalign, 0, 12, 12, 0); gtk_box_pack_start(GTK_BOX(vbox), frame, FALSE, FALSE, 0); sub_vbox = gtk_box_new(GTK_ORIENTATION_VERTICAL, 8); gtk_widget_show(sub_vbox); gtk_container_add(GTK_CONTAINER(subalign), sub_vbox); - checkbutton = qck_create_check_button(G_OBJECT(assistant), "virtual_addr", _("Virtual address"), NULL, NULL); + checkbutton = qck_create_check_button(G_OBJECT(assistant), "physical_off", _("Physical offset"), NULL, NULL); gtk_box_pack_start(GTK_BOX(sub_vbox), checkbutton, FALSE, FALSE, 0); gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(checkbutton), TRUE); - checkbutton = qck_create_check_button(G_OBJECT(assistant), "binary_code", _("Binary code"), NULL, NULL); + checkbutton = qck_create_check_button(G_OBJECT(assistant), "virtual_addr", _("Virtual address"), NULL, NULL); gtk_box_pack_start(GTK_BOX(sub_vbox), checkbutton, FALSE, FALSE, 0); gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(checkbutton), TRUE); - checkbutton = qck_create_check_button(G_OBJECT(assistant), "assembly_code", _("Assembly code"), NULL, NULL); + checkbutton = qck_create_check_button(G_OBJECT(assistant), "binary_code", _("Binary code"), NULL, NULL); gtk_box_pack_start(GTK_BOX(sub_vbox), checkbutton, FALSE, FALSE, 0); gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(checkbutton), TRUE); @@ -468,8 +648,151 @@ static void register_content_panel(GtkAssistant *assistant) gtk_assistant_append_page(assistant, alignment); gtk_assistant_set_page_title(assistant, alignment, _("Exported content")); + gtk_assistant_set_page_type(assistant, alignment, GTK_ASSISTANT_PAGE_CONTENT); + + gtk_assistant_set_page_complete(assistant, alignment, TRUE); + +} + + + +/* ---------------------------------------------------------------------------------- */ +/* DEFINITION DE LA SORTIE ATTENDUE */ +/* ---------------------------------------------------------------------------------- */ + + +/****************************************************************************** +* * +* Paramètres : assistant = fenêtre à compléter et référencement global. * +* * +* Description : Ajoute le panneau de choix du type de sortie. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void register_output_panel(GtkAssistant *assistant) +{ + GtkWidget *alignment; /* Disposition sur le support */ + GtkWidget *vbox; /* Support principal #1 */ + GtkWidget *label; /* Etiquette d'indication */ + GtkWidget *hbox; /* Support principal #2 */ + GtkWidget *entry; /* Zone de saisie de texte */ + GtkWidget *button; /* Sélection de fichier */ + GLoadedBinary *binary; /* Binaire chargé à parcourir */ + const char *filename; /* Chemin d'accès par défaut */ + + alignment = qck_create_padded_alignment(8, 8, 8, 8); + + vbox = gtk_box_new(GTK_ORIENTATION_VERTICAL, 8); + gtk_widget_show(vbox); + gtk_container_add(GTK_CONTAINER(alignment), vbox); + + /* Fichier de sortie */ + + label = qck_create_label(NULL, NULL, _("File: ")); + gtk_box_pack_start(GTK_BOX(vbox), label, FALSE, FALSE, 0); + + hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 8); + gtk_widget_show(hbox); + gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0); + + entry = qck_create_entry(G_OBJECT(assistant), "filename", NULL); + gtk_box_pack_start(GTK_BOX(hbox), entry, TRUE, TRUE, 0); + + button = qck_create_button(NULL, NULL, "...", G_CALLBACK(on_filename_browsing_clicked), assistant); + gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, FALSE, 0); + + /* Intégration */ + + gtk_assistant_append_page(assistant, alignment); + gtk_assistant_set_page_title(assistant, alignment, _("Output")); gtk_assistant_set_page_type(assistant, alignment, GTK_ASSISTANT_PAGE_CONFIRM); gtk_assistant_set_page_complete(assistant, alignment, TRUE); + /* Choix par défaut */ + + binary = G_LOADED_BINARY(g_object_get_data(G_OBJECT(assistant), "binary")); + filename = g_loaded_binary_get_name(binary, true); + + gtk_entry_set_text(GTK_ENTRY(entry), filename); + gtk_editable_insert_text(GTK_EDITABLE(entry), ".html", -1, (gint []) { strlen(filename) }); + + g_signal_connect(G_OBJECT(entry), "changed", G_CALLBACK(on_export_filename_changed), assistant); + +} + + +/****************************************************************************** +* * +* Paramètres : entry = zone de texte dont le contenu vient de changer. * +* assistant = fenêtre affichée et référencement global. * +* * +* Description : Réagit un changement du nom de fichier pour l'exportation. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void on_export_filename_changed(GtkEntry *entry, GtkAssistant *assistant) +{ + const gchar *text; /* Texte saisi dans la zone */ + gint num; /* Etape courante */ + GtkWidget *page; /* Support de cette étape */ + + text = gtk_entry_get_text(entry); + + num = gtk_assistant_get_current_page(assistant); + page = gtk_assistant_get_nth_page(assistant, num); + + gtk_assistant_set_page_complete(assistant, page, (strlen(text) > 0)); + +} + + +/****************************************************************************** +* * +* Paramètres : button = bouton d'édition de la sélection. * +* ref = espace de référencement principal. * +* * +* Description : Sélectionne ou non un nouveau fichier de sortie. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void on_filename_browsing_clicked(GtkButton *button, GObject *ref) +{ + GtkWidget *dialog; /* Boîte à afficher */ + gchar *filename; /* Nom du fichier à intégrer */ + GtkEntry *entry; /* Zone de saisie à maj. */ + + dialog = gtk_file_chooser_dialog_new(_("Choose an output filename"), GTK_WINDOW(ref), + GTK_FILE_CHOOSER_ACTION_SAVE, + _("_Cancel"), GTK_RESPONSE_CANCEL, + _("_Save"), GTK_RESPONSE_ACCEPT, + NULL); + + entry = GTK_ENTRY(g_object_get_data(ref, "filename")); + gtk_file_chooser_set_filename(GTK_FILE_CHOOSER(dialog), gtk_entry_get_text(entry)); + + if (gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT) + { + filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dialog)); + + gtk_entry_set_text(GTK_ENTRY(entry), filename); + + g_free(filename); + + } + + gtk_widget_destroy(dialog); + } diff --git a/src/glibext/gbufferline.c b/src/glibext/gbufferline.c index 6b5ab18..54f5fb6 100644 --- a/src/glibext/gbufferline.c +++ b/src/glibext/gbufferline.c @@ -51,7 +51,6 @@ typedef struct _buffer_line_column } buffer_line_column; - /* Réinitialise une colonne de ligne. */ static void reset_column(buffer_line_column *); @@ -71,11 +70,14 @@ static GBufferSegment *get_segment_at(const buffer_line_column *, gint *, GdkScr static GBufferSegment *find_near_segment(const buffer_line_column *, GBufferSegment *, GdkScrollDirection, bool *); /* Met en surbrillance des segments similaires. */ -GSList *highlight_all_same_segments(const buffer_line_column *, GSList *, const GBufferSegment *); +static GSList *highlight_all_same_segments(const buffer_line_column *, GSList *, const GBufferSegment *); /* Imprime le contenu d'une colonne de ligne de texte. */ static void draw_segments_of_column(buffer_line_column *, cairo_t *, gint, gint); +/* Exporte la ligne de texte représentée. */ +static void export_segments_of_column(buffer_line_column *, buffer_export_context *, BufferExportType, int); + /* ---------------------------- GESTION DE LINE COMPLETE ---------------------------- */ @@ -313,7 +315,7 @@ static GBufferSegment *find_near_segment(const buffer_line_column *column, GBuff * * ******************************************************************************/ -GSList *highlight_all_same_segments(const buffer_line_column *column, GSList *list, const GBufferSegment *ref) +static GSList *highlight_all_same_segments(const buffer_line_column *column, GSList *list, const GBufferSegment *ref) { size_t i; /* Boucle de parcours */ @@ -347,8 +349,8 @@ GSList *highlight_all_same_segments(const buffer_line_column *column, GSList *li static void draw_segments_of_column(buffer_line_column *column, cairo_t *cairo, gint x_init, gint y) { - gint x; - size_t i; + gint x; /* Abscisse d'impression */ + size_t i; /* Boucle de parcours */ x = x_init; @@ -358,6 +360,59 @@ static void draw_segments_of_column(buffer_line_column *column, cairo_t *cairo, } +/****************************************************************************** +* * +* Paramètres : column = colonne de ligne de texte à manipuler. * +* ctx = éléments à disposition pour l'exportation. * +* type = type d'exportation attendue. * +* span = fusion de colonnes au sein des cellules ? * +* * +* Description : Exporte la ligne de texte représentée. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void export_segments_of_column(buffer_line_column *column, buffer_export_context *ctx, BufferExportType type, int span) +{ + size_t i; /* Boucle de parcours */ + + switch (type) + { + case BET_HTML: + switch (span) + { + case 0: + break; + case 1: + dprintf(ctx->fd, "\t\t"); + break; + default: + if (span > 0) dprintf(ctx->fd, "\t\t", span); + break; + } + break; + default: + break; + } + + for (i = 0; i < column->count; i++) + g_buffer_segment_export(column->segments[i], ctx, type); + + switch (type) + { + case BET_HTML: + if (span < 0 || span == 1) dprintf(ctx->fd, "\n"); + break; + default: + break; + } + +} + + /* ---------------------------------------------------------------------------------- */ /* GESTION DE LINE COMPLETE */ @@ -1117,16 +1172,12 @@ void g_buffer_line_draw(GBufferLine *line, cairo_t *cairo, const gint max_widths } - /****************************************************************************** * * * Paramètres : line = ligne de texte à manipuler. * -* fd = flux ouvert en écriture. * +* ctx = éléments à disposition pour l'exportation. * * type = type d'exportation attendue. * -* phys = indique si les positions doivent être affichées. * -* virt = indique si les adresses doivent être affichées. * -* code = indique si le code binaire doit être affiché. * -* content = indique si le gros du contenu doit être affiché. * +* display = règles d'affichage des colonnes modulables. * * * * Description : Exporte la ligne de texte représentée. * * * @@ -1136,19 +1187,70 @@ void g_buffer_line_draw(GBufferLine *line, cairo_t *cairo, const gint max_widths * * ******************************************************************************/ -void g_buffer_line_export(GBufferLine *line, int fd, BufferExportType type, bool phys, bool virt, bool code, bool content) +void g_buffer_line_export(GBufferLine *line, buffer_export_context *ctx, BufferExportType type, const bool *display) { BufferLineColumn i; /* Boucle de parcours */ + int col_span; /* Fusion de colonnes ? */ + + switch (type) + { + case BET_HTML: + dprintf(ctx->fd, "\t\n"); + break; + default: + break; + } for (i = 0; i < BLC_COUNT; i++) { - if (i == BLC_PHYSICAL && !phys) continue; - if (i == BLC_VIRTUAL && !virt) continue; - if (i == BLC_BINARY && !code) continue; - if (!(i == BLC_PHYSICAL || i == BLC_VIRTUAL || i == BLC_BINARY) && !content) continue; + if (i < BLC_DISPLAY && !display[i]) continue; + + switch (type) + { + case BET_TEXT: + if (i > 0) dprintf(ctx->fd, ctx->sep); + break; + default: + break; + } + + /** + * Pour la signification des différentes valeurs assignées, + * se référer au code de export_segments_of_column(). + * + * En gros : + * - 1 = rien de spécial. + * - >1 = il s'agit de la première cellule fusionnée de la ligne. + * - 0 = fusion déjà faite, on ne peut que rajouter du contenu dedans. + * - <1 = il s'agit de la dernière cellule fusionnée de la ligne. + * + * On considère qu'une fusion ne peut pas se réaliser sur la dernière + * cellule uniquement (ce qui a du sens : c'est inutile). + */ - dprintf(fd, "TODO\n"); + if (i < line->merge_start) + col_span = 1; + else if (i == line->merge_start) + col_span = BLC_COUNT - i; + + else + col_span = ((i + 1) == BLC_COUNT ? -1 : 0); + + export_segments_of_column(&line->columns[i], ctx, type, col_span); + + } + + switch (type) + { + case BET_TEXT: + dprintf(ctx->fd, "\n"); + break; + case BET_HTML: + dprintf(ctx->fd, "\n"); + break; + default: + break; } } diff --git a/src/glibext/gbufferline.h b/src/glibext/gbufferline.h index f6ee171..9b35f0b 100644 --- a/src/glibext/gbufferline.h +++ b/src/glibext/gbufferline.h @@ -130,7 +130,7 @@ void g_buffer_line_start_merge_at(GBufferLine *, BufferLineColumn); void g_buffer_line_draw(GBufferLine *, cairo_t *, const gint [BLC_COUNT], gint, gint, const bool *); /* Exporte la ligne de texte représentée. */ -void g_buffer_line_export(GBufferLine *, int, BufferExportType, bool, bool, bool, bool); +void g_buffer_line_export(GBufferLine *, buffer_export_context *, BufferExportType, const bool *); diff --git a/src/glibext/gbuffersegment.c b/src/glibext/gbuffersegment.c index 3d9e5a9..1ebb543 100644 --- a/src/glibext/gbuffersegment.c +++ b/src/glibext/gbuffersegment.c @@ -200,7 +200,7 @@ static void g_buffer_segment_class_init(GBufferSegmentClass *class) void define_rendering_pattern(GtkStyleContext *ctx, const char *name, rendering_pattern_t *pattern) { - GdkRGBA *tmp_color; + GdkRGBA *tmp_color; /* Description d'une couleur */ PangoFontDescription *font_desc; /* Description d'une police */ gtk_style_context_save(ctx); @@ -219,10 +219,10 @@ static void g_buffer_segment_class_init(GBufferSegmentClass *class) case PANGO_STYLE_NORMAL: pattern->slant = CAIRO_FONT_SLANT_NORMAL; break; - case PANGO_STYLE_OBLIQUE: + case PANGO_STYLE_ITALIC: pattern->slant = CAIRO_FONT_SLANT_ITALIC; break; - case PANGO_STYLE_ITALIC: + case PANGO_STYLE_OBLIQUE: pattern->slant = CAIRO_FONT_SLANT_OBLIQUE; break; } @@ -303,7 +303,7 @@ GBufferSegment *g_buffer_segment_new(RenderingTagType type, const char *text, si result = g_object_new(G_TYPE_BUFFER_SEGMENT, NULL); - result->text = strdup(text); + result->text = strndup(text, length); result->hash = fnv_64a_hash(text); class = G_BUFFER_SEGMENT_GET_CLASS(result); @@ -640,3 +640,125 @@ void g_buffer_segment_draw(GBufferSegment *segment, cairo_t *cairo, gint *x, gin *x += segment->x_advance; } + + +/****************************************************************************** +* * +* Paramètres : ctx = éléments à disposition pour l'exportation. * +* type = type d'exportation attendue. * +* * +* Description : Exporte tous les styles utilisés par des segments. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +void g_buffer_segment_export_style(buffer_export_context *ctx, BufferExportType type) +{ + GBufferSegment *dummy; /* Segment servant de sujet */ + GBufferSegmentClass *class; /* Classe des segments */ + size_t i; /* Boucle de parcours */ + const rendering_pattern_t *pattern; /* Modèle à transcrire */ + + dummy = g_object_new(G_TYPE_BUFFER_SEGMENT, NULL); + class = G_BUFFER_SEGMENT_GET_CLASS(dummy); + + for (i = 0; i < RTT_COUNT; i++) + { + pattern = &class->patterns[i]; + + switch (type) + { + case BET_HTML: + + dprintf(ctx->fd, ".%s {\n", _segment_names[i]); + + if (pattern->foreground.has_color) + dprintf(ctx->fd, "\tcolor: #%02hhx%02hhx%02hhx;\n", + (unsigned char)(pattern->foreground.color.red * 255), + (unsigned char)(pattern->foreground.color.green * 255), + (unsigned char)(pattern->foreground.color.blue * 255)); + + switch (pattern->slant) + { + case CAIRO_FONT_SLANT_ITALIC: + dprintf(ctx->fd, "\tfont-style: italic;\n"); + break; + case CAIRO_FONT_SLANT_OBLIQUE: + dprintf(ctx->fd, "\tfont-style: oblique;\n"); + break; + default: + dprintf(ctx->fd, "\tfont-style: normal;\n"); + break; + } + + switch (pattern->weight) + { + case CAIRO_FONT_WEIGHT_BOLD: + dprintf(ctx->fd, "\tfont-weight: bold;\n"); + break; + default: + dprintf(ctx->fd, "\tfont-weight: normal;\n"); + break; + } + + dprintf(ctx->fd, "}\n"); + + break; + + default: + break; + + } + + } + + g_object_unref(G_OBJECT(dummy)); + +} + + +/****************************************************************************** +* * +* Paramètres : segment = fragment de texte à manipuler. * +* ctx = éléments à disposition pour l'exportation. * +* type = type d'exportation attendue. * +* * +* Description : Exporte le fragment de texte représenté. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +void g_buffer_segment_export(const GBufferSegment *segment, buffer_export_context *ctx, BufferExportType type) +{ + GBufferSegmentClass *class; /* Classe des segments */ + size_t index; /* Indice du modèle de rendu */ + + switch (type) + { + case BET_HTML: + class = G_BUFFER_SEGMENT_GET_CLASS(segment); + index = (segment->pattern - class->patterns); + dprintf(ctx->fd, "", _segment_names[index]); + break; + default: + break; + } + + dprintf(ctx->fd, "%s", segment->text); + + switch (type) + { + case BET_HTML: + dprintf(ctx->fd, ""); + break; + default: + break; + } + +} diff --git a/src/glibext/gbuffersegment.h b/src/glibext/gbuffersegment.h index f5cd4b2..10ae374 100644 --- a/src/glibext/gbuffersegment.h +++ b/src/glibext/gbuffersegment.h @@ -91,15 +91,6 @@ typedef enum _SegRenderingStyle } SegRenderingStyle; -/* Types d'exportation */ -typedef enum _BufferExportType -{ - BET_TEXT, - - BET_COUNT - -} BufferExportType; - /* Fragment de caractères aux propriétés communes (instance) */ typedef struct _GBufferSegment GBufferSegment; @@ -136,6 +127,48 @@ void g_buffer_segment_set_style(GBufferSegment *, SegRenderingStyle); /* Imprime le fragment de texte représenté. */ void g_buffer_segment_draw(GBufferSegment *, cairo_t *, gint *, gint); +/* Types d'exportation */ +typedef enum _BufferExportType +{ + BET_TEXT, /* Exportation en texte brut */ + BET_HTML, /* Exportation en HTML */ + + BET_COUNT + +} BufferExportType; + +/* Elements sur lesquels une exportation peut s'appuyer */ +typedef struct _buffer_export_context +{ + union + { + int fd; /* Flux ouvert en écriture */ + + }; + + union + { + /* BET_TEXT */ + const char *sep; /* Séparation entre colonnes */ + + /* BET_HTML */ + struct + { + const char *font_name; /* Police d'impression */ + const char *bg_color; /* Fond du tableau HTML */ + + }; + + }; + +} buffer_export_context; + +/* Exporte tous les styles utilisés par des segments. */ +void g_buffer_segment_export_style(buffer_export_context *, BufferExportType); + +/* Exporte le fragment de texte représenté. */ +void g_buffer_segment_export(const GBufferSegment *, buffer_export_context *, BufferExportType); + #endif /* _GLIBEXT_GBUFFERSEGMENT_H */ diff --git a/src/glibext/gcodebuffer.c b/src/glibext/gcodebuffer.c index eab418e..d13c9d6 100644 --- a/src/glibext/gcodebuffer.c +++ b/src/glibext/gcodebuffer.c @@ -1572,6 +1572,78 @@ void g_buffer_view_draw(const GBufferView *view, cairo_t *cr, gint fake_x, gint /****************************************************************************** * * +* Paramètres : view = visualisation à représenter. * +* ctx = éléments à disposition pour l'exportation. * +* type = type d'exportation attendue. * +* display = règles d'affichage des colonnes modulables. * +* * +* Description : Exporte le contenu du tampon de code désassemblé. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +void g_buffer_view_export(const GBufferView *view, buffer_export_context *ctx, BufferExportType type, const bool *display) +{ + size_t start; /* Première ligne visée */ + size_t end; /* Dernière ligne avant limite */ + GBufferLine **lines; /* Liste des lignes à traiter */ + size_t i; /* Boucle de parcours */ + + start = g_code_buffer_get_index_from_address(view->buffer, view->start, true); + end = g_code_buffer_get_index_from_address(view->buffer, view->end, false); + + lines = view->buffer->lines; + + switch (type) + { + case BET_HTML: + dprintf(ctx->fd, "\n"); + dprintf(ctx->fd, "\n"); + dprintf(ctx->fd, "\t\n"); + dprintf(ctx->fd, "\n"); + dprintf(ctx->fd, "\n"); + dprintf(ctx->fd, "\n"); + dprintf(ctx->fd, "\n"); + break; + default: + break; + } + + if (view->buffer->used > 0) + for (i = start; i <= end; i++) + g_buffer_line_export(lines[i], ctx, type, display); + + switch (type) + { + case BET_HTML: + dprintf(ctx->fd, "
\n"); + dprintf(ctx->fd, "\n"); + dprintf(ctx->fd, "\n"); + break; + default: + break; + } + +} + + +/****************************************************************************** +* * * Paramètres : view = visualisation à consulter. * * y = ordonnée comprise dans la ligne recherchée. * * idx = indice de la ligne trouvée ou NULL. [OUT] * diff --git a/src/glibext/gcodebuffer.h b/src/glibext/gcodebuffer.h index ece7c59..62b725c 100644 --- a/src/glibext/gcodebuffer.h +++ b/src/glibext/gcodebuffer.h @@ -82,7 +82,7 @@ void g_code_buffer_dec_indentation(GCodeBuffer *); typedef bool (* process_line_fc) (GCodeBuffer *, GBufferLine *, void *); /* Exporte dans un fichier le tampon de code désassemblé. */ -void g_buffer_code_scan(GCodeBuffer *, vmpa_t, vmpa_t, const char *, process_line_fc, void *); +void g_buffer_code_scan(GCodeBuffer *, vmpa_t, vmpa_t, const char *, process_line_fc, void *) __attribute__ ((deprecated)); @@ -143,6 +143,9 @@ void g_buffer_view_highlight_segments(GBufferView *, gint, gint); /* Imprime la visualisation du tampon de code désassemblé. */ void g_buffer_view_draw(const GBufferView *, cairo_t *, gint, gint, const cairo_rectangle_int_t *, const bool *); +/* Exporte le contenu du tampon de code désassemblé. */ +void g_buffer_view_export(const GBufferView *, buffer_export_context *, BufferExportType, const bool *); + /* Fournit la ligne présente à une ordonnée donnée. */ GBufferLine *g_buffer_view_find_line_at(GBufferView *, gint, size_t *); -- cgit v0.11.2-87-g4458