/* OpenIDA - Outil d'analyse de fichiers binaires * gbufferline.c - représentation de fragments de texte en ligne * * Copyright (C) 2010-2012 Cyrille Bagard * * This file is part of OpenIDA. * * 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 /* 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); /* 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 *, GFontCache *, 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 */ 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 */ PangoAttrList *attribs[RTT_COUNT]; /* Décorateurs pour tampons */ }; /* 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. * * * * 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) { 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) x -= width; else result = column->segments[i]; } 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. * * fcache = gestionnaire des polices pour l'impression. * * 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, GFontCache *fcache, 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, fcache, &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) { PangoAttribute *attrib; /* Propriété de rendu */ /* RTT_RAW */ class->attribs[RTT_RAW] = pango_attr_list_new(); attrib = pango_attr_foreground_new(0, 0, 0); pango_attr_list_insert(class->attribs[RTT_RAW], attrib); /* RTT_COMMENT */ class->attribs[RTT_COMMENT] = pango_attr_list_new(); attrib = pango_attr_foreground_new(14335, 45311, 23551); pango_attr_list_insert(class->attribs[RTT_COMMENT], attrib); /* RTT_INDICATION */ class->attribs[RTT_INDICATION] = pango_attr_list_new(); attrib = pango_attr_foreground_new(33410, 33410, 33410); pango_attr_list_insert(class->attribs[RTT_INDICATION], attrib); attrib = pango_attr_style_new(PANGO_STYLE_ITALIC); pango_attr_list_insert(class->attribs[RTT_INDICATION], attrib); /* RTT_RAW_CODE */ class->attribs[RTT_RAW_CODE] = pango_attr_list_new(); attrib = pango_attr_foreground_new(48895, 48895, 48895); pango_attr_list_insert(class->attribs[RTT_RAW_CODE], attrib); /* RTT_INSTRUCTION */ class->attribs[RTT_INSTRUCTION] = pango_attr_list_new(); attrib = pango_attr_foreground_new(0, 0, 0); pango_attr_list_insert(class->attribs[RTT_INSTRUCTION], attrib); /* RTT_IMMEDIATE */ class->attribs[RTT_IMMEDIATE] = pango_attr_list_new(); attrib = pango_attr_foreground_new(41215, 8447, 61695); pango_attr_list_insert(class->attribs[RTT_IMMEDIATE], attrib); /* RTT_REGISTER */ class->attribs[RTT_REGISTER] = pango_attr_list_new(); //attrib = pango_attr_foreground_new(23551, 23551, 51455); attrib = pango_attr_foreground_new(16895, 16895, 53759); pango_attr_list_insert(class->attribs[RTT_REGISTER], attrib); /* RTT_PUNCT */ class->attribs[RTT_PUNCT] = pango_attr_list_new(); attrib = pango_attr_foreground_new(0, 0, 0); pango_attr_list_insert(class->attribs[RTT_PUNCT], attrib); attrib = pango_attr_weight_new(PANGO_WEIGHT_BOLD); pango_attr_list_insert(class->attribs[RTT_PUNCT], attrib); /* RTT_HOOK */ class->attribs[RTT_HOOK] = pango_attr_list_new(); attrib = pango_attr_foreground_new(0, 0, 0); pango_attr_list_insert(class->attribs[RTT_HOOK], attrib); attrib = pango_attr_weight_new(PANGO_WEIGHT_BOLD); pango_attr_list_insert(class->attribs[RTT_HOOK], attrib); /* RTT_SIGNS */ class->attribs[RTT_SIGNS] = pango_attr_list_new(); attrib = pango_attr_foreground_new(0, 0, 0); pango_attr_list_insert(class->attribs[RTT_SIGNS], attrib); attrib = pango_attr_weight_new(PANGO_WEIGHT_SEMIBOLD); pango_attr_list_insert(class->attribs[RTT_SIGNS], attrib); /* RTT_LTGT */ class->attribs[RTT_LTGT] = pango_attr_list_new(); /* RTT_SECTION */ class->attribs[RTT_SECTION] = pango_attr_list_new(); attrib = pango_attr_foreground_new(51200, 2560, 2560); pango_attr_list_insert(class->attribs[RTT_SECTION], attrib); /* attrib = pango_attr_foreground_new(56832, 26880, 43008); pango_attr_list_insert(class->attribs[RTT_SECTION], attrib); attrib = pango_attr_weight_new(PANGO_WEIGHT_BOLD); pango_attr_list_insert(class->attribs[RTT_SECTION], attrib); */ /* RTT_SEGMENT */ class->attribs[RTT_SEGMENT] = pango_attr_list_new(); /* RTT_STRING */ class->attribs[RTT_STRING] = pango_attr_list_new(); attrib = pango_attr_foreground_new(52224, 32256, 0); pango_attr_list_insert(class->attribs[RTT_STRING], attrib); /* RTT_VAR_NAME */ class->attribs[RTT_VAR_NAME] = pango_attr_list_new(); attrib = pango_attr_foreground_new(0, 0, 0); pango_attr_list_insert(class->attribs[RTT_VAR_NAME], attrib); /* RTT_KEY_WORD */ class->attribs[RTT_KEY_WORD] = pango_attr_list_new(); attrib = pango_attr_foreground_new(0, 0, 0); pango_attr_list_insert(class->attribs[RTT_KEY_WORD], attrib); /* RTT_ERROR */ class->attribs[RTT_ERROR] = pango_attr_list_new(); attrib = pango_attr_foreground_new(65535, 0, 0); pango_attr_list_insert(class->attribs[RTT_ERROR], attrib); attrib = pango_attr_weight_new(PANGO_WEIGHT_BOLD); pango_attr_list_insert(class->attribs[RTT_ERROR], attrib); } /****************************************************************************** * * * 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. * * * * Description : Crée une nouvelle représentation de fragments de texte. * * * * Retour : Composant GTK créé. * * * * Remarques : - * * * ******************************************************************************/ GBufferLine *g_buffer_line_new(vmpa_t addr) { GBufferLine *result; /* Composant à retourner */ result = g_object_new(G_TYPE_BUFFER_LINE, NULL); result->addr = addr; 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 par la procédure. * * * * 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) { GBufferSegment *result; /* Trouvaille à retourner */ BufferLineColumn i; /* Boucle de parcours */ result = NULL; for (i = BLC_ADDRESS; i < BLC_COUNT; i++) if (x < max_widths[i]) break; else x -= (max_widths[i] + COL_MARGIN); if (i < BLC_COUNT) result = get_segment_at(&line->columns[i], x); return result; } /****************************************************************************** * * * 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) { GBufferLineClass *class; /* Stockage de briques de base */ GBufferSegment *segment; /* Portion de texte à ajouter */ if (column == BLC_LAST_USED) column = line->last_used; else line->last_used = column; if (length == 0) return; class = G_BUFFER_LINE_GET_CLASS(line); segment = g_buffer_segment_new(class->attribs[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.* * fcache = gestionnaire des polices pour l'impression. * * 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, GFontCache *fcache, const gint max_widths[BLC_COUNT], gint x_init, gint y, bool addr, bool code) { gint x; /* Point de départ d'impression*/ BufferLineColumn i; /* Boucle de parcours */ 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, fcache, 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"); } }