/* 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(const buffer_line_column *); /* Ajoute un fragment de texte à une colonne de ligne. */ static void add_segment_to_column(buffer_line_column *, GBufferSegment *); #define get_first_segment(col) ((col)->count > 0 ? (col)->segments[0] : NULL) #define get_last_segment(col) ((col)->count > 0 ? (col)->segments[(col)->count - 1] : NULL) /* Donne le segment d'une colonne présent à une abscisse donnée. */ static GBufferSegment *get_segment_at(const buffer_line_column *, gint *, GdkScrollDirection); /* Fournit le segment voisin d'un autre segment identifié. */ 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 *); /* 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 */ mrange_t range; /* Couverture 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 = 0; } /****************************************************************************** * * * 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(const buffer_line_column *column) { 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; column->max_width += g_buffer_segment_get_width(segment); } /****************************************************************************** * * * Paramètres : column = colonne de ligne de texte à consulter. * * x = position de recherche à ajuster. [OUT] * * dir = direction d'un éventuel déplacement en cours. * * * * 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, GdkScrollDirection dir) { GBufferSegment *result; /* Trouvaille à retourner */ size_t i; /* Boucle de parcours */ gint width; /* Largeur à retirer */ bool included; /* Appartenance à une largeur ?*/ result = NULL; printf(" == gs@ == count = %d width = %d\n", column->count, get_column_width(column)); for (i = 0; i < column->count && result == NULL; i++) { width = g_buffer_segment_get_width(column->segments[i]); printf(" -s- |%d| -> x=%d w=%d\n", i, *x, width); /** * Soit une limite entre deux segments A et B : * * - dans le cas d'un déplacement vers la gauche, on part de cette limite * pour progresser à l'intérieur de A. Donc la limite fait partie de A. * * - dans le cas d'un déplacement vers la droite, on part de cette limite * pour progresser à l'intérieur de B. Donc la limite ne fait pas partie de A. */ if (dir == GDK_SCROLL_LEFT) included = (width >= *x); else included = (width > *x); if (included || (i + 1) == column->count) result = column->segments[i]; else *x -= width; } printf(" == gs@ == > segment = %p\n", result); return result; } /****************************************************************************** * * * Paramètres : column = colonne de ligne de texte à consulter. * * target = segment dont un voisin est à retourner. * * dir = orientation des recherches. * * out = renvoie vers une bordure extérieur au besoin. [OUT] * * * * Description : Fournit le segment voisin d'un autre segment identifié. * * * * Retour : Segment trouvé ou NULL si hors borne ou inconnu. * * * * Remarques : - * * * ******************************************************************************/ static GBufferSegment *find_near_segment(const buffer_line_column *column, GBufferSegment *target, GdkScrollDirection dir, bool *out) { GBufferSegment *result; /* Trouvaille à retourner */ size_t i; /* Boucle de parcours */ result = NULL; *out = false; for (i = 0; i < column->count; i++) if (column->segments[i] == target) break; if (i < column->count) switch (dir) { case GDK_SCROLL_LEFT: *out = (i == 0); if (!*out) result = column->segments[i - 1]; break; case GDK_SCROLL_RIGHT: *out = ((i + 1) == column->count); if (!*out) result = column->segments[i + 1]; break; default: break; } 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 = 0; i < BLC_COUNT; i++) reset_column(&line->columns[i]); line->merge_start = BLC_COUNT; line->last_used = BLC_COUNT; } /****************************************************************************** * * * Paramètres : range = emplacement 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(const mrange_t *range, BufferLineColumn main) { GBufferLine *result; /* Composant à retourner */ result = g_object_new(G_TYPE_BUFFER_LINE, NULL); copy_mrange(&result->range, range); result->main_column = main; return result; } /****************************************************************************** * * * Paramètres : line = ligne à venir consulter. * * * * Description : Indique la zone mémoire où se situe la ligne. * * * * Retour : Emplacement mémoire virtuel ou physique. * * * * Remarques : - * * * ******************************************************************************/ const mrange_t *g_buffer_line_get_range(const GBufferLine *line) { return &line->range; } /****************************************************************************** * * * Paramètres : line = ligne à venir compléter. * * psize = taille souhaitée de l'impression des positions. * * vsize = taille souhaitée de l'impression des adresses. * * * * Description : Construit le tronc commun d'une ligne autour de sa position. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ void g_buffer_line_fill_mrange(GBufferLine *line, MemoryDataSize psize, MemoryDataSize vsize) { size_t len; /* Taille de l'élément inséré */ VMPA_BUFFER(address); /* Adresse au format texte */ /* Adresse physique puis virtuelle */ mrange_phys_to_string(&line->range, psize, true, address, &len); g_buffer_line_insert_text(line, BLC_PHYSICAL, address, len, RTT_RAW); mrange_virt_to_string(&line->range, vsize, true, address, &len); g_buffer_line_insert_text(line, BLC_VIRTUAL, address, len, RTT_RAW); } /****************************************************************************** * * * Paramètres : line = ligne à venir compléter. * * psize = taille souhaitée de l'impression des positions. * * vsize = taille souhaitée de l'impression des adresses. * * content = contenu binaire global. * * length = taille de l'extrait de code à afficher. * * full = la portion est assez courte pour être entière ? * * * * Description : Construit le tronc commun d'une ligne d'instruction. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ void g_buffer_line_fill_for_instr(GBufferLine *line, MemoryDataSize psize, MemoryDataSize vsize, const bin_t *content, off_t length, bool full) { size_t required; /* Taille de traitement requise*/ char static_buffer[64]; /* Petit tampon local rapide */ char *bin_code; /* Tampon utilisé pour le code */ off_t start; /* Début de traitement */ off_t end; /* Limite de traitement */ off_t i; /* Boucle de parcours #1 */ char *iter; /* Boucle de parcours #2 */ int ret; /* Progression dans l'écriture */ bin_t byte; /* Octet à représenter */ static const char *charset = "0123456789abcdef"; /* Adresse physique puis virtuelle */ g_buffer_line_fill_mrange(line, psize, vsize); /* Détermination du réceptacle */ required = length * 3 + 3; if (required <= sizeof(static_buffer)) bin_code = static_buffer; else bin_code = (char *)calloc(required, sizeof(char)); /* Code brut */ start = get_phy_addr(get_mrange_addr(&line->range)); end = start + length; for (i = start, iter = bin_code; i < end; i++, iter += ret) { byte = content[i]; iter[0] = charset[byte >> 4]; iter[1] = charset[byte & 0x0f]; if ((i + 1) < end) { iter[2] = ' '; ret = 3; } else { if (full) { iter[2] = '\0'; ret = 2; } else { strcpy(iter + 2, "..."); ret = 5; } } } /* Conclusion */ g_buffer_line_insert_text(line, BLC_BINARY, bin_code, iter - bin_code, RTT_RAW_CODE); if (bin_code != static_buffer) free(bin_code); } /****************************************************************************** * * * 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. * * display = règles d'affichage des colonnes modulables. * * x = position à la colonne visée. [OUT] * * dir = direction d'un éventuel déplacement en cours. * * 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], const bool *display, gint *x, GdkScrollDirection dir, bool force) { GBufferSegment *result; /* Trouvaille à retourner */ gint old; /* Valeur d'origine de position*/ BufferLineColumn last; /* Dernière colonne remplie */ gint last_x; /* Dernière abscisse associée */ BufferLineColumn i; /* Boucle de parcours */ gint width; /* Largeur d'une colonne donnée*/ result = NULL; old = *x; last = BLC_COUNT; last_x = *x; /* Pour GCC */ printf(" {{ ADDR }} 0x%08x\n", line->range.addr.physical); for (i = 0; i < BLC_COUNT; i++) { printf(" @ (%d) x=%d width=%d max=%d display ? %d\n", i, *x, get_column_width(&line->columns[i]), max_widths[i], i < BLC_DISPLAY ? display[i] : true); if (i < BLC_DISPLAY && !display[i]) continue; /* Mémorisation de la dernière colonne contenant quelque chose... */ if (get_column_width(&line->columns[i]) > 0) { last = i; last_x = *x; } if (i < line->merge_start) { width = max_widths[i]; if (*x <= width) break; else *x -= (max_widths[i] + COL_MARGIN); } else { width = get_column_width(&line->columns[i]); if (*x <= width) break; else *x -= width; } } printf(" -- get segment at -- found index %u (max=%u)\n", i, BLC_COUNT); printf(" last seen = %u\n", last); if (force) { if (i == BLC_COUNT) { /* Re-calcul des largeurs cumulées */ if (last == BLC_COUNT) i = BLC_COUNT; else { *x = old; for (i = 0; i < last; i++) { if (i < line->merge_start) *x -= (max_widths[i] + COL_MARGIN); else *x -= get_column_width(&line->columns[i]); } } printf(" -- get segment at -- last index %u (max=%u) -->> x = %d\n", i, BLC_COUNT, *x); } /* Si on s'est arrêté sur un champ vide... */ else if (i != last) { i = last; *x = last_x; } } if (i < BLC_COUNT) result = get_segment_at(&line->columns[i], x, dir); if (result == NULL) printf(" -- get segment at -- found nothing...\n"); else printf(" -- get segment at -- found %p '%s'...\n", result, g_buffer_segment_get_text(result)); return result; } /****************************************************************************** * * * Paramètres : line = ligne à venir consulter. * * target = segment dont un voisin est à retourner. * * max_widths = largeurs de colonne à respecter. XXXXXXXXXXXXXXX * * display = règles d'affichage des colonnes modulables. * * dir = orientation des recherches. * * offset = décalage pour amener à l'extrémité voisine. [OUT] * * * * Description : Fournit le segment voisin d'un autre segment identifié. * * * * Retour : Segment trouvé dans la ligne ou NULL. * * * * Remarques : - * * * ******************************************************************************/ GBufferSegment *g_buffer_line_find_near_segment(const GBufferLine *line, GBufferSegment *target, const gint max_widths[BLC_COUNT], const bool *display, GdkScrollDirection dir, gint *offset) { GBufferSegment *result; /* Trouvaille à retourner */ BufferLineColumn i; /* Boucle de parcours */ bool out; /* Présence de cible en bordure*/ result = NULL; *offset = 0; for (i = 0; i < BLC_COUNT && result == NULL; i++) { if (i < BLC_DISPLAY && !display[i]) continue; result = find_near_segment(&line->columns[i], target, dir, &out); printf(" [%d] near seg = %p (out ? %d)\n", i, result, out); if (result != NULL) break; if (out) { switch (dir) { case GDK_SCROLL_LEFT: gblfns_loop_left: /* On s'assure que la colonne précédente est visible */ if (i <= BLC_DISPLAY) for (; i > BLC_FIRST; i--) if (display[i - 1]) break; if (i > BLC_FIRST) result = get_last_segment(&line->columns[i - 1]); printf(" [near] (%d) %p\n", i, result); if (result == NULL && i > BLC_FIRST) { printf(" [loop] %u -> %u\n", i, i - 1); i--; *offset -= (max_widths[i] + COL_MARGIN); goto gblfns_loop_left; } if (result != NULL) *offset += g_buffer_segment_get_width(result) - max_widths[i - 1] - COL_MARGIN; break; case GDK_SCROLL_RIGHT: gblfns_loop_right: /* On s'assure que la colonne suivante est visible */ for (; (i + 1) < BLC_DISPLAY; i++) if (display[i + 1]) break; if ((i + 1) < BLC_COUNT) result = get_first_segment(&line->columns[i + 1]); printf(" [near] (%d) %p\n", i, result); if (result == NULL && (i + 1) < BLC_COUNT) { printf(" [loop] %u -> %u\n", i, i + 1); *offset += (max_widths[i] + COL_MARGIN); printf(" -- add %d ~> %d\n", max_widths[i], *offset); i++; goto gblfns_loop_right; } if (result != NULL) { *offset -= g_buffer_segment_get_width(target); *offset += max_widths[i] + COL_MARGIN; printf(" -- add %d ~> %d\n", max_widths[i], *offset); } /* if (result != NULL) *offset += max_widths[i + 1] - g_buffer_segment_get_width(result) + COL_MARGIN; */ break; default: break; } } } 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 = 0; 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]* * display = règles d'affichage des colonnes modulables. * * * * 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, const bool *display) { gint result; /* Largeur à retourner */ result = 0; /* TODO : wtf ?! quelle est l'utilité des arguments booléens ? */ *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. * * display = règles d'affichage des colonnes modulables. * * * * 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, const bool *display) { 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 = 0; i < BLC_COUNT; i++) { if (i < BLC_DISPLAY && !display[i]) 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. * * 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é. * * * * Description : Exporte la ligne de texte représentée. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ void g_buffer_line_export(GBufferLine *line, int fd, BufferExportType type, bool phys, bool virt, bool code, bool content) { BufferLineColumn i; /* Boucle de parcours */ 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; dprintf(fd, "TODO\n"); } }