/* Chrysalide - Outil d'analyse de fichiers binaires * gbufferline.c - représentation de fragments de texte en ligne * * Copyright (C) 2010-2014 Cyrille Bagard * * This file is part of Chrysalide. * * OpenIDA 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. * * OpenIDA 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 "gbufferline.h" #include #include /* Récupération du langage par défaut ; FIXME ? */ #include "../common/extstr.h" #include "../gtkext/support.h" #include /* FIXME : à virer */ /* ---------------------------- REGROUPEMENT PAR COLONNE ---------------------------- */ /* Informations sur le contenu d'une colonne */ typedef struct _buffer_line_column { GBufferSegment **segments; size_t count; int max_width; /* Largeur max. de l'espace */ } buffer_line_column; /* Réinitialise une colonne de ligne. */ static void reset_column(buffer_line_column *); /* Fournit la quantité de pixels requise pour l'impression. */ static gint get_column_width(buffer_line_column *); /* Ajoute un fragment de texte à une colonne de ligne. */ static void add_segment_to_column(buffer_line_column *, GBufferSegment *); /* Donne le segment d'une colonne présent à une abscisse donnée. */ static GBufferSegment *get_segment_at(const buffer_line_column *, gint *, bool); /* Met en surbrillance des segments similaires. */ 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); /* ---------------------------- GESTION DE LINE COMPLETE ---------------------------- */ /* Représentation de fragments de texte en ligne (instance) */ struct _GBufferLine { GObject parent; /* A laisser en premier */ vmpa_t addr; /* Adresse geographique */ BufferLineColumn main_column; /* Colonne principale */ buffer_line_column columns[BLC_COUNT]; /* Répartition du texte */ BufferLineColumn merge_start; /* Début de la zone globale */ BufferLineColumn last_used; /* Dernière colonne utilisée */ }; /* Représentation de fragments de texte en ligne (classe) */ struct _GBufferLineClass { GObjectClass parent; /* A laisser en premier */ cairo_surface_t *bookmark_img; /* Image pour les signets */ }; /* Procède à l'initialisation d'une classe de représentation. */ static void g_buffer_line_class_init(GBufferLineClass *); /* Procède à l'initialisation d'une représentation de fragments. */ static void g_buffer_line_init(GBufferLine *); /* ---------------------------------------------------------------------------------- */ /* REGROUPEMENT PAR COLONNE */ /* ---------------------------------------------------------------------------------- */ /****************************************************************************** * * * Paramètres : column = colonne de ligne à mettre à jour. * * * * Description : Réinitialise une colonne de ligne. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ static void reset_column(buffer_line_column *column) { column->max_width = -1; } /****************************************************************************** * * * Paramètres : column = colonne de ligne à consulter. * * * * Description : Fournit la quantité de pixels requise pour l'impression. * * * * Retour : Largeur requise par la colonne, en pixel. * * * * Remarques : - * * * ******************************************************************************/ static gint get_column_width(buffer_line_column *column) { size_t i; /* Boucle de parcours */ if (column->max_width == -1) { column->max_width = 0; for (i = 0; i < column->count; i++) column->max_width += g_buffer_segment_get_width(column->segments[i]); } return column->max_width; } /****************************************************************************** * * * Paramètres : column = colonne de ligne à venir compléter. * * segment = fragment de texte à ajouter à la colonne. * * * * Description : Ajoute un fragment de texte à une colonne de ligne. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ static void add_segment_to_column(buffer_line_column *column, GBufferSegment *segment) { /* FIXME : à remplacer */ column->segments = (GBufferSegment **)realloc(column->segments, ++column->count * sizeof(GBufferSegment *)); column->segments[column->count - 1] = segment; } /****************************************************************************** * * * Paramètres : column = colonne de ligne de texte à consulter. * * x = position de recherche à ajuster. [OUT] * * force = accepte les segments en bordure au pire. * * * * Description : Donne le segment d'une colonne présent à une abscisse donnée.* * * * Retour : Segment trouvé ou NULL si hors borne. * * * * Remarques : - * * * ******************************************************************************/ static GBufferSegment *get_segment_at(const buffer_line_column *column, gint *x, bool force) { GBufferSegment *result; /* Trouvaille à retourner */ size_t i; /* Boucle de parcours */ gint width; /* Largeur à retirer */ result = NULL; for (i = 0; i < column->count && result == NULL; i++) { width = g_buffer_segment_get_width(column->segments[i]); if (width > *x || ((i + 1) == column->count && force)) result = column->segments[i]; else *x -= width; } return result; } /****************************************************************************** * * * Paramètres : column = colonne de ligne de texte à consulter. * * list = liste de segments identiques à constituer. * * ref = segment de référence à comparer avec les autres. * * * * Description : Met en surbrillance des segments similaires. * * * * Retour : Liste de segments identiques complétée. * * * * Remarques : - * * * ******************************************************************************/ GSList *highlight_all_same_segments(const buffer_line_column *column, GSList *list, const GBufferSegment *ref) { size_t i; /* Boucle de parcours */ for (i = 0; i < column->count; i++) if (g_buffer_segment_compare(column->segments[i], ref)) { g_buffer_segment_set_style(column->segments[i], SRS_HIGHLIGHT_SAME); g_object_ref(G_OBJECT(column->segments[i])); list = g_slist_prepend(list, column->segments[i]); } return list; } /****************************************************************************** * * * Paramètres : column = colonne de ligne de texte à manipuler. * * cairo = contexte graphique à utiliser pour les pinceaux. * * x_init = abscisse du point d'impression de départ. * * y = ordonnée du point d'impression. * * * * Description : Imprime le contenu d'une colonne de ligne de texte. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ static void draw_segments_of_column(buffer_line_column *column, cairo_t *cairo, gint x_init, gint y) { gint x; size_t i; x = x_init; for (i = 0; i < column->count; i++) g_buffer_segment_draw(column->segments[i], cairo, &x, y); } /* ---------------------------------------------------------------------------------- */ /* GESTION DE LINE COMPLETE */ /* ---------------------------------------------------------------------------------- */ /* Détermine le type de la représentation de fragments de texte en ligne. */ G_DEFINE_TYPE(GBufferLine, g_buffer_line, G_TYPE_OBJECT); /****************************************************************************** * * * Paramètres : class = classe de composant GTK à initialiser. * * * * Description : Procède à l'initialisation d'une classe de représentation. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ static void g_buffer_line_class_init(GBufferLineClass *class) { gchar *filename; /* Chemin d'accès à utiliser */ filename = find_pixmap_file("bookmark.png"); /* assert(filename != NULL); */ class->bookmark_img = cairo_image_surface_create_from_png(filename); g_free(filename); } /****************************************************************************** * * * Paramètres : line = composant GTK à initialiser. * * * * Description : Procède à l'initialisation d'une représentation de fragments.* * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ static void g_buffer_line_init(GBufferLine *line) { BufferLineColumn i; /* Boucle de parcours */ for (i = BLC_ADDRESS; i < BLC_COUNT; i++) reset_column(&line->columns[i]); line->merge_start = BLC_COUNT; line->last_used = BLC_COUNT; } /****************************************************************************** * * * Paramètres : addr = adresse où va se situer la ligne. * * main = colonne à référencer comme étant la principale. * * * * Description : Crée une nouvelle représentation de fragments de texte. * * * * Retour : Composant GTK créé. * * * * Remarques : - * * * ******************************************************************************/ GBufferLine *g_buffer_line_new(vmpa_t addr, BufferLineColumn main) { GBufferLine *result; /* Composant à retourner */ result = g_object_new(G_TYPE_BUFFER_LINE, NULL); result->addr = addr; result->main_column = main; return result; } /****************************************************************************** * * * Paramètres : line = ligne à venir consulter. * * * * Description : Indique l'adresse à laquelle se situe la ligne. * * * * Retour : Adresse mémoire ou physique. * * * * Remarques : - * * * ******************************************************************************/ vmpa_t g_buffer_line_get_address(const GBufferLine *line) { return line->addr; } /****************************************************************************** * * * Paramètres : line = ligne à venir compléter. * * index = index de la colonne visée par la procédure. * * segment = fragment de texte à ajouter à la colonne. * * * * Description : Ajoute un fragment de texte à une colonne de ligne. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ void g_buffer_line_add_segment(GBufferLine *line, BufferLineColumn index, GBufferSegment *segment) { add_segment_to_column(&line->columns[index], segment); } /****************************************************************************** * * * Paramètres : line = ligne à venir consulter. * * max_widths = largeurs de colonne à respecter. * * x = position à la colonne visée. [OUT] * * force = accepte les segments en bordure au pire. * * * * Description : Donne le segment présent à une abscisse donnée. * * * * Retour : Segment trouvé ou NULL si hors borne. * * * * Remarques : - * * * ******************************************************************************/ GBufferSegment *g_buffer_line_get_segment_at(const GBufferLine *line, const gint max_widths[BLC_COUNT], gint *x, bool force) { GBufferSegment *result; /* Trouvaille à retourner */ BufferLineColumn i; /* Boucle de parcours */ result = NULL; for (i = BLC_ADDRESS; i < BLC_COUNT; i++) { /* FIXME : addr/code */ if (*x < max_widths[i]) break; else *x -= (max_widths[i] + COL_MARGIN); } if (i == BLC_COUNT && force) { i = BLC_COUNT - 1; *x += (max_widths[i] + COL_MARGIN); } if (i < BLC_COUNT) result = get_segment_at(&line->columns[i], x, force); return result; } /****************************************************************************** * * * Paramètres : line = ligne à venir consulter. * * caret = position du curseur à faire évoluer. * * ctrl = indique la demande d'un parcours rapide. * * dir = direction du parcours. * * addr = indique si les positions doivent être affichées. * * code = indique si le code binaire doit être affiché. * * * * Description : Déplace le curseur au sein d'une vue de tampon. * * * * Retour : true si un déplacement a été effectué, false sinon. * * * * Remarques : - * * * ******************************************************************************/ bool g_buffer_line_move_caret(const GBufferLine *line, GdkRectangle *caret, bool ctrl, GdkScrollDirection dir, bool addr, bool code) { caret->x += (dir == GDK_SCROLL_RIGHT ? 10 : -10); return true; return false; } /****************************************************************************** * * * Paramètres : line = ligne à venir consulter. * * list = liste de segments identiques à constituer. * * ref = segment de référence à comparer avec tous les autres. * * * * Description : Met en surbrillance des segments similaires. * * * * Retour : Liste de segments identiques complétée. * * * * Remarques : - * * * ******************************************************************************/ GSList *g_buffer_line_highlight_all_same_segments(const GBufferLine *line, GSList *list, const GBufferSegment *ref) { BufferLineColumn i; /* Boucle de parcours */ for (i = BLC_ADDRESS; i < BLC_COUNT; i++) list = highlight_all_same_segments(&line->columns[i], list, ref); return list; } /****************************************************************************** * * * Paramètres : line = ligne à venir compléter. * * column = colonne de la ligne visée par l'insertion. * * text = texte à insérer dans l'existant. * * length = taille du texte à traiter. * * type = type de décorateur à utiliser. * * * * Description : Ajoute du texte à formater dans une ligne donnée. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ void g_buffer_line_insert_text(GBufferLine *line, BufferLineColumn column, const char *text, size_t length, RenderingTagType type) { GBufferSegment *segment; /* Portion de texte à ajouter */ if (column == BLC_MAIN) column = line->main_column; if (column == BLC_LAST_USED) column = line->last_used; else line->last_used = column; if (length == 0) return; segment = g_buffer_segment_new(type, text, length); g_buffer_line_add_segment(line, column, segment); } /****************************************************************************** * * * Paramètres : line = ligne à venir consulter. * * * * Description : Donne le texte représenté par une ligne de tampon. * * * * Retour : Texte à libérer de la mémoire après usage. * * * * Remarques : - * * * ******************************************************************************/ char *g_buffer_line_get_text(const GBufferLine *line) { char *result; /* Construction à retourner */ BufferLineColumn i; /* Boucle de parcours #1 */ size_t j; /* Boucle de parcours #2 */ result = NULL; for (i = BLC_ASSEMBLY_HEAD; i < BLC_COUNT; i++) for (j = 0; j < line->columns[i].count; j++) if (result == NULL) { result = strdup(g_buffer_segment_get_text(line->columns[i].segments[j])); result = stradd(result, " "); } else result = stradd(result, g_buffer_segment_get_text(line->columns[i].segments[j])); return result; } /****************************************************************************** * * * Paramètres : line = ligne à venir compléter. * * index = index de la colonne visée par la procédure. * * * * Description : Fournit la largeur requise pour une colonne de ligne donnée. * * * * Retour : Largeur en pixel requise. * * * * Remarques : - * * * ******************************************************************************/ gint g_buffer_line_get_column_width(GBufferLine *line, BufferLineColumn index) { gint result; /* Largeur à retourner */ if (index >= line->merge_start) result = 0; else result = get_column_width(&line->columns[index]); return result; } /****************************************************************************** * * * Paramètres : line = ligne à venir compléter. * * merge = précise la première colonne marquant la fusion. [OUT]* * addr = indique si les positions doivent être affichées. * * code = indique si le code binaire doit être affiché. * * * * Description : Fournit la dernière largeur d'une ligne avec fusion. * * * * Retour : Largeur en pixel requise. * * * * Remarques : - * * * ******************************************************************************/ gint g_buffer_line_get_merge_width(GBufferLine *line, BufferLineColumn *merge, bool addr, bool code) { gint result; /* Largeur à retourner */ result = 0; *merge = line->merge_start; if (line->merge_start < BLC_COUNT) result = get_column_width(&line->columns[line->merge_start]); return result; } /****************************************************************************** * * * Paramètres : line = ligne à venir compléter. * * start = début de la première (et unique) zone globale. * * * * Description : Définit la colonne à partir de laquelle la fusion opère. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ void g_buffer_line_start_merge_at(GBufferLine *line, BufferLineColumn start) { if (start == BLC_LAST_USED) line->merge_start = line->last_used; else line->merge_start = start; } /****************************************************************************** * * * Paramètres : line = ligne de texte à manipuler. * * cairo = contexte graphique à utiliser pour les pinceaux.* * max_widths = largeurs de colonne à respecter. * * x_init = abscisse du point d'impression de départ. * * y = ordonnée du point d'impression. * * addr = indique si les positions doivent être affichées.* * code = indique si le code binaire doit être affiché. * * * * Description : Imprime la ligne de texte représentée. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ void g_buffer_line_draw(GBufferLine *line, cairo_t *cairo, const gint max_widths[BLC_COUNT], gint x_init, gint y, bool addr, bool code) { GBufferLineClass *class; /* Stockage de briques de base */ gint x; /* Point de départ d'impression*/ BufferLineColumn i; /* Boucle de parcours */ class = G_BUFFER_LINE_GET_CLASS(line); cairo_set_source_surface(cairo, class->bookmark_img, 5, y); cairo_paint(cairo); x = x_init; for (i = BLC_ADDRESS; i < BLC_COUNT; i++) { if (i == BLC_ADDRESS && !addr) continue; if (i == BLC_BINARY && !code) continue; draw_segments_of_column(&line->columns[i], cairo, x, y); if (i < line->merge_start) x += max_widths[i] + COL_MARGIN; } } /****************************************************************************** * * * Paramètres : line = ligne de texte à manipuler. * * fd = flux ouvert en écriture. * * type = type d'exportation attendue. * * addr = indique si les positions doivent être affichées. * * code = indique si le code binaire doit être affiché. * * content = indique si le gros du contenu doit être affiché. * * * * Description : Exporte la ligne de texte représentée. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ void g_buffer_line_export(GBufferLine *line, int fd, BufferExportType type, bool addr, bool code, bool content) { BufferLineColumn i; /* Boucle de parcours */ for (i = BLC_ADDRESS; i < BLC_COUNT; i++) { if (i == BLC_ADDRESS && !addr) continue; if (i == BLC_BINARY && !code) continue; if (!(i == BLC_ADDRESS || i == BLC_BINARY) && !content) continue; dprintf(fd, "TODO\n"); } }