/* Chrysalide - Outil d'analyse de fichiers binaires * gbufferview.c - affichage d'une vue particulière d'un tampon de lignes * * Copyright (C) 2016 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 "gbufferview.h" /* Vue d'un tampon pour code désassemblé (instance) */ struct _GBufferView { GObject parent; /* A laisser en premier */ GCodeBuffer *buffer; /* Tampon de code visualisé */ vmpa2t start; /* Première ligne intégrée */ vmpa2t end; /* Dernière ligne intégrée */ size_t first; /* Indice de la première ligne */ size_t last; /* Indice de la dernière ligne */ union { const GWidthTracker *ext_tracker; /* Suivi externe des largeurs */ GWidthTracker *int_tracker; /* Suivi interne des largeurs */ GWidthTracker *tracker; /* Suivi pour usage interne */ }; bool unrestricted; /* Validité des informations */ segcnt_list *highlighted; /* Segments mis en évidence */ bool external; /* Note l'origine de la liste */ }; /* Vue d'un tampon pour code désassemblé (classe) */ struct _GBufferViewClass { GObjectClass parent; /* A laisser en premier */ gint line_height; /* Hauteur maximale des lignes */ gint left_margin; /* Marge gauche + espace */ gint left_text; /* Début d'impression du code */ /* Signaux */ void (* need_redraw) (GBufferView *); }; /* Procède à l'initialisation d'une classe de vue de tampon. */ static void g_buffer_view_class_init(GBufferViewClass *); /* Procède à l'initialisation d'une vue d'un tampon pour code. */ static void g_buffer_view_init(GBufferView *); /* Supprime toutes les références externes. */ static void g_buffer_view_dispose(GBufferView *); /* Procède à la libération totale de la mémoire. */ static void g_buffer_view_finalize(GBufferView *); /* Accompagne une variation de la quantité de lignes du tampon. */ static void on_buffer_size_changed(const GCodeBuffer *, bool, size_t, size_t, GBufferView *); /* Réagit à un changement de contenu d'une ligne donnée. */ static void on_buffer_line_changed(GCodeBuffer *, GBufferLine *, GBufferSegment *, GBufferView *); /* Déplace le curseur au sein d'une vue de tampon. */ static bool _g_buffer_view_move_caret(GBufferView *, const GBufferLine *, size_t, GdkRectangle *, bool, GdkScrollDirection, const bool *); /* Détermine le type de la vue d'un tampon pour code désassemblé. */ G_DEFINE_TYPE(GBufferView, g_buffer_view, G_TYPE_OBJECT); /****************************************************************************** * * * Paramètres : class = classe de composant GTK à initialiser. * * * * Description : Procède à l'initialisation d'une classe de vue de tampon. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ static void g_buffer_view_class_init(GBufferViewClass *class) { GObjectClass *object; /* Autre version de la classe */ object = G_OBJECT_CLASS(class); object->dispose = (GObjectFinalizeFunc/* ! */)g_buffer_view_dispose; object->finalize = (GObjectFinalizeFunc)g_buffer_view_finalize; class->line_height = 17; class->left_margin = 2 * class->line_height; class->left_text = 2.5 * class->line_height; g_signal_new("need-redraw", G_TYPE_BUFFER_VIEW, G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET(GBufferViewClass, need_redraw), NULL, NULL, g_cclosure_marshal_VOID__OBJECT, G_TYPE_NONE, 0); } /****************************************************************************** * * * Paramètres : view = composant GLib à initialiser. * * * * Description : Procède à l'initialisation d'une vue d'un tampon pour code. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ static void g_buffer_view_init(GBufferView *view) { view->unrestricted = true; } /****************************************************************************** * * * Paramètres : view = instance d'objet GLib à traiter. * * * * Description : Supprime toutes les références externes. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ static void g_buffer_view_dispose(GBufferView *view) { g_object_unref(G_OBJECT(view->buffer)); G_OBJECT_CLASS(g_buffer_view_parent_class)->dispose(G_OBJECT(view)); } /****************************************************************************** * * * Paramètres : view = instance d'objet GLib à traiter. * * * * Description : Procède à la libération totale de la mémoire. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ static void g_buffer_view_finalize(GBufferView *view) { if (!view->external) exit_segment_content_list(view->highlighted); G_OBJECT_CLASS(g_buffer_view_parent_class)->finalize(G_OBJECT(view)); } /****************************************************************************** * * * Paramètres : buffer = tampon à représenter à l'écran. * * highlighted = gestionnaire de surbrillance pour segments. * * * * Description : Crée une nouvelle vue d'un tampon pour code désassemblé. * * * * Retour : Composant GTK créé. * * * * Remarques : - * * * ******************************************************************************/ GBufferView *g_buffer_view_new(GCodeBuffer *buffer, segcnt_list *highlighted) { GBufferView *result; /* Composant à retourner */ result = g_object_new(G_TYPE_BUFFER_VIEW, NULL); g_object_ref(G_OBJECT(buffer)); result->buffer = buffer; g_buffer_view_restrict(result, NULL, NULL); g_code_buffer_register_view_callback(buffer, (buffer_size_changed_cb)on_buffer_size_changed, G_OBJECT(result)); g_signal_connect(buffer, "line-changed", G_CALLBACK(on_buffer_line_changed), result); if (highlighted != NULL) result->highlighted = highlighted; else result->highlighted = init_segment_content_list(); result->external = (highlighted != NULL); return result; } /****************************************************************************** * * * Paramètres : buffer = tampon de lignes cohérentes à manipuler. * * added = indication sur la variation de la taille du tampon. * * index = indice de la première ligne à traiter. * * count = nombre de lignes à traiter. * * view = vue active du tampon de lignes concerné. * * * * Description : Accompagne une variation de la quantité de lignes du tampon. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ static void on_buffer_size_changed(const GCodeBuffer *buffer, bool added, size_t index, size_t count, GBufferView *view) { size_t i; /* Boucle de parcours */ GBufferLine *line; /* Ligne à manipuler */ const vmpa2t *addr; /* Localisation de ligne */ /** * Il n'y a pas besoin de verrou ici car la fonction est appelée directement par le tampon. * D'autre part, on considère qu'il y a toujours une ligne aux adresses de borne, si la vue est bornée. */ if (added) { if (view->unrestricted) view->last += count; else { /* Avant la zone représentée ? */ if (index < view->first) { view->first += count; view->last += count; } /* Juste avant la zone représentée ? */ else if (view->first == index) for (i = 0; i < count; i++) { line = g_code_buffer_find_line_by_index(buffer, index + i); addr = get_mrange_addr(g_buffer_line_get_range(line)); if (cmp_vmpa(&view->start, addr) == 0) { view->first++; view->last++; } else break; } /* Dans la zone représentée ? */ else if (view->first < index && index <= view->last) view->last += count; /* Juste après la vue représentée ? */ else if ((view->last + 1) == index) for (i = 0; i < count; i++) { line = g_code_buffer_find_line_by_index(buffer, index + i); addr = get_mrange_addr(g_buffer_line_get_range(line)); if (cmp_vmpa(&view->end, addr) == 0) view->last++; else break; } g_width_tracker_update_added(view->int_tracker, index, count); } } else { if (view->unrestricted) view->last -= count; else { /* Avant la zone représentée ? */ if (index <= view->first) { view->first -= count; view->last -= count; } /* Dans la zone représentée ? */ else if (view->first < index && index <= view->last) view->last -= count; } g_width_tracker_update_deleted(view->int_tracker, index, index + count - 1); } g_signal_emit_by_name(view, "need-redraw"); } /****************************************************************************** * * * Paramètres : buffer = tampon de lignes cohérentes à manipuler. * * line = ligne dont la définition vient d'évoluer. * * segment = éventuel segment qui vient d'évoluer ou NULL. * * view = vue active du tampon de lignes concerné. * * * * Description : Réagit à un changement de contenu d'une ligne donnée. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ static void on_buffer_line_changed(GCodeBuffer *buffer, GBufferLine *line, GBufferSegment *segment, GBufferView *view) { const vmpa2t *addr; /* Localisation de ligne */ addr = get_mrange_addr(g_buffer_line_get_range(line)); if (cmp_vmpa(&view->start, addr) <= 0 && cmp_vmpa(addr, &view->end) <= 0) g_signal_emit_by_name(view, "need-redraw"); } /****************************************************************************** * * * Paramètres : view = visualisateur à mettre à jour. * * first = première ligne à imprimer. * * last = première ligne hors cadre. * * * * Description : Restreint le champ d'application de l'affichage. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ void g_buffer_view_restrict(GBufferView *view, const vmpa2t *start, const vmpa2t *end) { const GWidthTracker *template; /* Suivi déjà en place */ if (!view->unrestricted) g_object_unref(G_OBJECT(view->int_tracker)); view->unrestricted = (start == NULL || end == NULL); template = g_code_buffer_get_width_tracker(view->buffer); if (view->unrestricted) { view->first = 0; view->last = g_code_buffer_count_lines(view->buffer) - 1; view->ext_tracker = template; } else { copy_vmpa(&view->start, start); copy_vmpa(&view->end, end); view->first = g_code_buffer_get_index_from_address(view->buffer, start, true); view->last = g_code_buffer_get_index_from_address(view->buffer, end, false); view->ext_tracker = g_width_tracker_new_restricted(template, view->first, view->last); } } /****************************************************************************** * * * Paramètres : view = visualisateur à mettre à jour. * * first = première ligne à imprimer ou NULL. [OUT] * * last = première ligne hors cadre ou NULL. [OUT] * * * * Description : Indique le champ d'application de l'affichage. * * * * Retour : true si des restrictions particulières sont en place. * * * * Remarques : - * * * ******************************************************************************/ bool g_buffer_view_get_restrictions(GBufferView *view, vmpa2t *start, vmpa2t *end) { if (!view->unrestricted) { if (start != NULL) copy_vmpa(start, &view->start); if (end != NULL) copy_vmpa(end, &view->end); } return !view->unrestricted; } /****************************************************************************** * * * Paramètres : view = visualisateur à consulter. * * * * Description : Fournit le tampon de code lié à un visualisateur donné. * * * * Retour : Tampon de code associé au gestionnaire d'affichage. * * * * Remarques : - * * * ******************************************************************************/ GCodeBuffer *g_buffer_view_get_buffer(const GBufferView *view) { g_object_ref(G_OBJECT(view->buffer)); return view->buffer; } /****************************************************************************** * * * Paramètres : view = visualisation à consulter. * * * * Description : Fournit la hauteur d'impression d'une ligne visualisée. * * * * Retour : Hauteur de ligne en pixel. * * * * Remarques : - * * * ******************************************************************************/ gint g_buffer_view_get_line_height(GBufferView *view) { return G_BUFFER_VIEW_GET_CLASS(view)->line_height; } /****************************************************************************** * * * Paramètres : view = visualisation à consulter. * * display = règles d'affichage des colonnes modulables. * * * * Description : Fournit la largeur requise par une visualisation. * * * * Retour : Dimension calculée. * * * * Remarques : - * * * ******************************************************************************/ gint g_buffer_view_get_width(GBufferView *view, const bool *display) { gint result; /* Taille à retourner */ result = G_BUFFER_VIEW_GET_CLASS(view)->left_text; result += g_width_tracker_get_width(view->tracker, display); return result; } /****************************************************************************** * * * Paramètres : view = visualisation à consulter. * * display = règles d'affichage des colonnes modulables. * * * * Description : Fournit la largeur requise pour dépasser les marges gauches. * * * * Retour : Dimension calculée. * * * * Remarques : - * * * ******************************************************************************/ gint g_buffer_view_get_margin(GBufferView *view, const bool *display) { gint result; /* Taille à retourner */ result = G_BUFFER_VIEW_GET_CLASS(view)->left_text; result += g_width_tracker_get_margin(view->tracker, display); return result; } /****************************************************************************** * * * Paramètres : view = visualisation à consulter. * * * * Description : Fournit la hauteur requise par une visualisation. * * * * Retour : Dimension calculée. * * * * Remarques : - * * * ******************************************************************************/ gint g_buffer_view_get_height(const GBufferView *view) { gint result; /* Taille à retourner */ result = G_BUFFER_VIEW_GET_CLASS(view)->line_height; result *= (view->last - view->first + 1); return result; } /****************************************************************************** * * * Paramètres : view = vue de tampon à mettre à jour. * * x = abscisse de la zone principale à traiter. * * y = ordonnée de la zone principale à traiter. * * display = règles d'affichage des colonnes modulables. * * caret = position du curseur à construire. [OUT] * * * * Description : Calcule la position idéale de curseur pour un point donné. * * * * Retour : Adresse si une a pu être déterminée, NULL sinon. * * * * Remarques : - * * * ******************************************************************************/ const vmpa2t *g_buffer_view_compute_caret(GBufferView *view, gint x, gint y, const bool *display, GdkRectangle *caret) { gint remaining; /* Copie de travail modifiable */ size_t index; /* Indice de ligne de tampon */ GBufferLine *line; /* Ligne à la position courante*/ GBufferSegment *segment; /* Segment présent sur la place*/ GBufferViewClass *class; /* Classe pour les vues */ remaining = x; line = g_buffer_view_find_line_and_segment_at(view, &remaining, y, &index, display, &segment); if (line == NULL) return NULL; if (segment == NULL) printf(" -- no segment\n"); if (segment == NULL) return NULL; printf("\n[BASE] orig = %d tronc = %d reste = %d dernier = %d largeur = %d\n", x, x - remaining, remaining, g_buffer_segment_get_caret_position(segment, remaining), g_buffer_segment_get_width(segment)); printf(" '%s'\n", g_buffer_segment_get_text(segment, false)); class = G_BUFFER_VIEW_GET_CLASS(view); caret->x = /*view->left_text +*/ (x - remaining) + g_buffer_segment_get_caret_position(segment, remaining); caret->y = (index - view->first) * class->line_height; caret->width = 2; caret->height = class->line_height; return get_mrange_addr(g_buffer_line_get_range(line)); } /****************************************************************************** * * * Paramètres : view = vue de tampon à mettre à jour. * * line = ligne correspondant à la position. * * index = indice de cette même ligne dans le tampon. * * x = abscisse de la zone principale à traiter. * * display = règles d'affichage des colonnes modulables. * * caret = position du curseur à construire. [OUT] * * * * Description : Calcule la position idéale de curseur pour un point donné. * * * * Retour : Adresse si une a pu être déterminée, NULL sinon. * * * * Remarques : - * * * ******************************************************************************/ const vmpa2t *g_buffer_view_compute_caret_full(GBufferView *view, GBufferLine *line, size_t index, gint x, const bool *display, GdkRectangle *caret) { GBufferViewClass *class; /* Classe pour les vues */ gint offset; /* Point de travail modifiable */ line_width_summary summary; /* Résumé concis des largeurs */ gint base; /* Position absolue de segment */ GBufferSegment *segment; /* Segment visé par le pointeur*/ class = G_BUFFER_VIEW_GET_CLASS(view); offset = x; offset -= class->left_text; if (offset < 0) return NULL; g_width_tracker_get_local_width_summary(view->tracker, index, &summary); segment = g_buffer_line_get_segment_at(line, &summary, display, &base, &offset, GDK_SCROLL_LEFT, true); if (segment == NULL) return NULL; caret->x = class->left_text + base + offset; printf("caret Y : %zu -> %zu\n", view->first, index); caret->y = (index - view->first) * class->line_height; caret->width = 2; caret->height = class->line_height; return get_mrange_addr(g_buffer_line_get_range(line)); } /****************************************************************************** * * * Paramètres : view = vue de tampon à manipuler. * * line = ligne à venir consulter. * * index = indice de cette même ligne dans le tampon. * * caret = position du curseur à faire évoluer. * * ctrl = indique la demande d'un parcours rapide. * * dir = direction du parcours. * * display = règles d'affichage des colonnes modulables. * * * * Description : Déplace le curseur au sein d'une vue de tampon. * * * * Retour : true si un déplacement a été effectué, false sinon. * * * * Remarques : - * * * ******************************************************************************/ static bool _g_buffer_view_move_caret(GBufferView *view, const GBufferLine *line, size_t index, GdkRectangle *caret, bool ctrl, GdkScrollDirection dir, const bool *display) { bool result; /* Bilan à retourner */ gint offset; /* Point de travail modifiable */ line_width_summary summary; /* Résumé concis des largeurs */ gint base; /* Position absolue de segment */ GBufferSegment *segment; /* Segment visé par le pointeur*/ offset = caret->x; offset -= G_BUFFER_VIEW_GET_CLASS(view)->left_text; if (offset < 0) return false; g_width_tracker_get_local_width_summary(view->tracker, index, &summary); segment = g_buffer_line_get_segment_at(line, &summary, display, &base, &offset, dir, false); if (segment == NULL) printf(" ===== NO SEG...\n"); if (segment == NULL) return false; printf(" ====== FIRST SEG :: %p ('%s')\n", segment, g_buffer_segment_get_text(segment, false)); //if (dir == GDK_SCROLL_LEFT || dir == GDK_SCROLL_RIGHT) result = g_buffer_segment_move_caret(segment, &offset, ctrl, dir); //else //result = true; printf(" ====== MOVE 1 ? %d\n", result); /////////////////// if (!result) { base = 0; segment = g_buffer_line_find_near_segment(line, segment, &summary, display, dir, &offset); printf(" ====== NEAR SEG :: %p ('%s')\n", segment, segment ? g_buffer_segment_get_text(segment, false) : NULL); if (segment != NULL) { result = true; //result = g_buffer_segment_move_caret(segment, &offset, ctrl, dir); /* if (result) caret->x -= COL_MARGIN; */ printf(" ====== MOVE 2 ? %d (offset=%d)\n", result, offset); } } if (result) printf(" ====== NEW CARET: %d -> %d\n", caret->x, G_BUFFER_VIEW_GET_CLASS(view)->left_text + base + offset); else printf(" ====== NO NEW CARET!\n"); if (result) caret->x = G_BUFFER_VIEW_GET_CLASS(view)->left_text + base + offset; return result; } /****************************************************************************** * * * Paramètres : view = vue de tampon à mettre à jour. * * caret = position du curseur à faire évoluer. * * ctrl = indique la demande d'un parcours rapide. * * dir = direction du parcours. * * display = règles d'affichage des colonnes modulables. * * * * Description : Déplace le curseur au sein d'une vue de tampon. * * * * Retour : Adresse si une a pu être déterminée, VMPA_INVALID sinon. * * * * Remarques : - * * * ******************************************************************************/ const vmpa2t *g_buffer_view_move_caret(GBufferView *view, GdkRectangle *caret, bool ctrl, GdkScrollDirection dir, const bool *display) { const vmpa2t *result; /* Actualisation à renvoyer */ size_t index; /* Indice de ligne de tampon */ GBufferLine *line; /* Ligne sous le pointeur */ line_width_summary summary; /* Résumé concis des largeurs */ bool computed; /* Récursivité pris en compte */ gint left_pos; /* Retour à la ligne */ gint right_pos; /* Position d'extrème droite */ BufferLineColumn i; /* Boucle de parcours */ size_t first; /* Première ligne intégrée */ size_t last; /* Dernière ligne intégrée */ bool moved; /* Mémorisation d'une évolut° */ result = NULL; line = g_buffer_view_find_line_at(view, caret->y, &index); if (line == NULL) return NULL; g_width_tracker_get_local_width_summary(view->tracker, index, &summary); computed = false; switch (dir) { case GDK_SCROLL_UP: case GDK_SCROLL_DOWN: break; case GDK_SCROLL_LEFT: case GDK_SCROLL_RIGHT: left_pos = G_BUFFER_VIEW_GET_CLASS(view)->left_text; if (display[BLC_PHYSICAL]) left_pos += summary.max_widths[BLC_PHYSICAL] + COL_MARGIN; if (display[BLC_VIRTUAL]) left_pos += summary.max_widths[BLC_VIRTUAL] + COL_MARGIN; if (display[BLC_BINARY]) left_pos += summary.max_widths[BLC_BINARY] + COL_MARGIN; right_pos = left_pos; for (i = BLC_ASSEMBLY_HEAD; i < BLC_COUNT; i++) right_pos += summary.max_widths[i] + COL_MARGIN; /* gint g_buffer_line_compute_max_width(const GBufferLine *line, BufferLineColumn index, const gint *max_widths) BufferLineColumn g_buffer_line_get_merge_start(const GBufferLine *line) */ left_pos = G_BUFFER_VIEW_GET_CLASS(view)->left_text; break; default: /* GDK_SCROLL_SMOOTH */ break; } first = view->first; last = view->last; switch (dir) { case GDK_SCROLL_UP: if (index > first) { line = g_code_buffer_find_line_by_index(view->buffer, index - 1); result = g_buffer_view_compute_caret_full(view, line, index - 1, caret->x, display, caret); } break; case GDK_SCROLL_DOWN: if (index < last) { line = g_code_buffer_find_line_by_index(view->buffer, index + 1); result = g_buffer_view_compute_caret_full(view, line, index + 1, caret->x, display, caret); } break; case GDK_SCROLL_LEFT: /* line = g_buffer_view_find_line_at(view, caret->y, &index); if (line == NULL) break; */ moved = _g_buffer_view_move_caret(view, line, index, caret, ctrl, GDK_SCROLL_LEFT, display); if (moved) result = get_mrange_addr(g_buffer_line_get_range(line)); else if (index > first) { line = g_code_buffer_find_line_by_index(view->buffer, index - 1); result = g_buffer_view_compute_caret_full(view, line, index - 1, INT_MAX, display, caret); } break; case GDK_SCROLL_RIGHT: /* line = g_buffer_view_find_line_at(view, caret->y, &index); if (line == NULL) break; */ moved = _g_buffer_view_move_caret(view, line, index, caret, ctrl, GDK_SCROLL_RIGHT, display); if (moved) result = get_mrange_addr(g_buffer_line_get_range(line)); else if (index < last) { line = g_code_buffer_find_line_by_index(view->buffer, index + 1); result = g_buffer_view_compute_caret_full(view, line, index + 1, left_pos, display, caret); } break; default: /* GDK_SCROLL_SMOOTH */ break; } /* printf(" --- CARET --- moved = %d index = %d result = %p\n", moved, index, result); */ /* if (result && !computed) result = g_buffer_view_compute_caret_full(view, caret->x, caret->y, caret, display, NULL); */ return result; } /****************************************************************************** * * * Paramètres : view = vue de tampon à mettre à jour. * * * * Description : Supprime toute mise en évidence de segments. * * * * Retour : true si un besoin d'actualisation d'affichage se fait sentir.* * * * Remarques : - * * * ******************************************************************************/ bool g_buffer_view_unhighlight_segments(GBufferView *view) { bool result; /* Bilan d'action à renvoyer */ result = reset_segment_content_list(view->highlighted); return result; } /****************************************************************************** * * * Paramètres : view = vue de tampon à mettre à jour. * * x = abscisse de la zone principale à traiter. * * y = ordonnée de la zone principale à traiter. * * display = règles d'affichage des colonnes modulables. * * * * Description : Surligne tous les segments similaires à celui sous la souris.* * * * Retour : true si un besoin d'actualisation d'affichage se fait sentir.* * * * Remarques : - * * * ******************************************************************************/ bool g_buffer_view_highlight_segments(GBufferView *view, gint x, gint y, const bool *display) { bool need_redraw; /* Besoin d'actualisation ? */ GBufferSegment *segment; /* Segment sélectionnable */ if (view->highlighted != NULL) need_redraw = g_buffer_view_unhighlight_segments(view); else need_redraw = false; g_buffer_view_find_line_and_segment_at(view, &x, y, NULL, display, &segment); if (segment) need_redraw |= add_segment_content_to_selection_list(view->highlighted, segment); if (need_redraw) g_signal_emit_by_name(view, "need-redraw"); return true; } /****************************************************************************** * * * Paramètres : view = visualisation à représenter. * * cr = contexte graphique dédié à la procédure. * * fake_x = abscisse réelle du point 0 à l'écran. * * fake_y = ordonnée réelle du point 0 à l'écran. * * area = position et surface à traiter. * * display = règles d'affichage des colonnes modulables. * * selected = ordonnée d'une ligne sélectionnée ou NULL. * * * * Description : Imprime la visualisation du tampon de code désassemblé. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ void g_buffer_view_draw(const GBufferView *view, cairo_t *cr, gint fake_x, gint fake_y, const cairo_rectangle_int_t *area, const bool *display, const gint *selected) { GBufferViewClass *class; /* Classe pour les vues */ gint real_x; /* Abscisse réelle pour tampon */ gint real_y; /* Ordonnée réelle pour tampon */ size_t first; /* Première ligne visée */ size_t last; /* Dernière ligne visée + 1 */ gint y; /* Point de départ + décallage */ bool wait_selection; /* Sélection déjà passée ? */ gint rel_selected; /* Position relative de sélect°*/ size_t i; /* Boucle de parcours */ GBufferLine *line; /* Ligne à dessiner à l'écran */ line_width_summary summary; /* Résumé concis des largeurs */ class = G_BUFFER_VIEW_GET_CLASS(view); real_x = fake_x + class->left_text; real_y = fake_y + area->y; first = view->first; first += (real_y / class->line_height); last = first + (area->height / class->line_height); if (area->height % class->line_height > 0) last++; last = MIN(last, view->last); y = area->y - (real_y % class->line_height); wait_selection = true; if (selected != NULL) rel_selected = *selected - fake_y; if (g_code_buffer_count_lines(view->buffer) > 0) for (i = first; i <= last; i++) { /* Si sélection, on sousligne la ligne concernée */ if (wait_selection && selected != NULL && rel_selected == y) { cairo_set_source_rgba(cr, 1.0, 1.0, 1.0, 0.05); cairo_rectangle(cr, area->x, y, area->width, class->line_height); cairo_fill(cr); wait_selection = false; } line = g_code_buffer_find_line_by_index(view->buffer, i); if (i == first || (g_buffer_line_get_flags(line) & BLF_WIDTH_MANAGER)) g_width_tracker_get_local_width_summary(view->tracker, i, &summary); g_buffer_line_draw(line, cr, &summary, real_x, y, display, view->highlighted); y += class->line_height; } } /****************************************************************************** * * * Paramètres : view = visualisation à consulter. * * addr = adresse où retrouver la ligne recherchée. * * flags = propriétés à vérifier en tout ou partie. * * idx = indice de la ligne trouvée ou NULL. [OUT] * * * * Description : Retrouve une ligne au sein d'un tampon avec une adresse. * * * * Retour : Line retrouvée ou NULL en cas d'échec. * * * * Remarques : - * * * ******************************************************************************/ GBufferLine *g_buffer_view_find_line_by_addr(const GBufferView *view, const vmpa2t *addr, BufferLineFlags flags, size_t *idx) { GBufferLine *result; /* Ligne trouvée à retourner */ phys_t length; /* Taille de la vue */ mrange_t vrange; /* Couverture de la vue */ bool allowed; /* Rechercher validée ? */ /* Vérification des bornes */ if (!view->unrestricted) { length = compute_vmpa_diff(&view->start, &view->end); init_mrange(&vrange, &view->start, length); allowed = mrange_contains_addr_inclusive(&vrange, addr); } else allowed = true; /* Lancement des recherches ? */ if (allowed) result = g_code_buffer_find_line_by_addr(view->buffer, addr, flags, idx); else result = NULL; return result; } /****************************************************************************** * * * Paramètres : view = visualisation à consulter. * * index = indice de la ligne recherchée. * * * * Description : Retrouve une ligne au sein d'un tampon avec un indice. * * * * Retour : Line retrouvée ou NULL en cas d'échec. * * * * Remarques : - * * * ******************************************************************************/ GBufferLine *g_buffer_view_find_line_by_index(const GBufferView *view, size_t index) { GBufferLine *result; /* Ligne trouvée à retourner */ bool allowed; /* Rechercher validée ? */ /* Vérification des bornes */ allowed = (view->first <= index && index <= view->last); /* Lancement des recherches ? */ if (allowed) result = g_code_buffer_find_line_by_index(view->buffer, index); else result = NULL; return result; } /****************************************************************************** * * * Paramètres : view = visualisation à consulter. * * y = ordonnée comprise dans la ligne recherchée. * * idx = indice de la ligne trouvée ou NULL. [OUT] * * * * Description : Fournit la ligne présente à une ordonnée donnée. * * * * Retour : Ligne retrouvée ou NULL si aucune. * * * * Remarques : - * * * ******************************************************************************/ GBufferLine *g_buffer_view_find_line_at(GBufferView *view, gint y, size_t *idx) { GBufferLine *result; /* Ligne trouvée à retourner */ gint lheight; /* Hauteur d'une ligne */ size_t index; /* Indice attendu */ lheight = g_buffer_view_get_line_height(view); index = y / lheight; index += view->first; if (index <= view->last) result = g_code_buffer_find_line_by_index(view->buffer, index); if (result != NULL && idx != NULL) *idx = index; return result; } /****************************************************************************** * * * Paramètres : view = visualisation à consulter. * * x = abscisse comprise dans le segment recherché. [OUT] * * y = ordonnée comprise dans la ligne recherchée. * * idx = indice de la ligne trouvée ou NULL. [OUT] * * display = règles d'affichage des colonnes modulables. * * segment = portion de texte recherchée ou NULL. [OUT] * * * * Description : Fournit la ligne et son segment présents à une position. * * * * Retour : Ligne retrouvée ou NULL si aucune. * * * * Remarques : - * * * ******************************************************************************/ GBufferLine *g_buffer_view_find_line_and_segment_at(GBufferView *view, gint *x, gint y, size_t *idx, const bool *display, GBufferSegment **segment) { GBufferLine *result; /* Ligne trouvée à retourner */ size_t index; /* Indice de la ligne trouvée */ GBufferViewClass *class; /* Classe pour les vues */ line_width_summary summary; /* Résumé concis des largeurs */ /* Recherche d'une ligne correspondante */ result = g_buffer_view_find_line_at(view, y, &index); if (idx != NULL) *idx = index; /* Recherche du segment visé éventuel */ if (result != NULL && segment != NULL) { class = G_BUFFER_VIEW_GET_CLASS(view); if (*x < class->left_text) *segment = NULL; else { g_width_tracker_get_local_width_summary(view->tracker, index, &summary); *x -= class->left_text; *segment = g_buffer_line_get_segment_at(result, &summary, display, (gint []) { 0 }, x, GDK_SCROLL_LEFT, true); } } return result; } /****************************************************************************** * * * Paramètres : view = visualisation à consulter. * * x = abscisse comprise dans le segment recherché. [OUT] * * y = ordonnée comprise dans la ligne recherchée. * * idx = indice de la ligne trouvée ou NULL. [OUT] * * display = règles d'affichage des colonnes modulables. * * creator = instance à l'origine de la représentation. [OUT] * * * * Description : Fournit la ligne et son segment présents à une position. * * * * Retour : Ligne retrouvée ou NULL si aucune. * * * * Remarques : - * * * ******************************************************************************/ GBufferLine *g_buffer_view_find_line_and_creator_at(GBufferView *view, gint *x, gint y, size_t *idx, const bool *display, GObject **creator) { GBufferLine *result; /* Ligne trouvée à retourner */ size_t index; /* Indice de la ligne trouvée */ GBufferViewClass *class; /* Classe pour les vues */ line_width_summary summary; /* Résumé concis des largeurs */ /* Recherche d'une ligne correspondante */ result = g_buffer_view_find_line_at(view, y, &index); if (idx != NULL) *idx = index; /* Recherche du segment visé éventuel */ if (result != NULL && creator != NULL) { class = G_BUFFER_VIEW_GET_CLASS(view); if (*x < class->left_text) *creator = NULL; else { g_width_tracker_get_local_width_summary(view->tracker, index, &summary); *x -= class->left_text; *creator = g_buffer_line_get_creator_at(result, &summary, display, (gint []) { 0 }, x, GDK_SCROLL_LEFT, true); } } return result; } /****************************************************************************** * * * Paramètres : view = composant GTK à consulter. * * addr = adresse à présenter à l'écran. * * x = position horizontale au sein du composant. [OUT] * * y = position verticale au sein du composant. [OUT] * * code = s'arrête si possible à une ligne avec code. * * * * Description : Indique la position d'affichage d'une adresse donnée. * * * * Retour : true si l'adresse fait partie du composant, false sinon. * * * * Remarques : - * * * ******************************************************************************/ bool g_buffer_view_get_address_coordinates(GBufferView *view, const vmpa2t *addr, gint *x, gint *y, bool code) { bool result; /* Bilan à retourner */ gint lheight; /* Hauteur d'une ligne */ size_t i; /* Boucle de parcours */ GBufferLine *line; /* Ligne à consulter */ const mrange_t *range; /* Emplacement parcouru */ result = false; *x = 0; *y = 0; lheight = g_buffer_view_get_line_height(view); for (i = view->first; i <= view->last; i++) { /** * Si l'adresse recherchée est plus petite que l'adresse de départ, * on va effectuer un parcours complet pour rien. * * On considère cependant que le seul cas où celà peut arriver * est lorsque que des découpages en blocs sont impliqués. * * Les découpages conduisent alors à la formation de petites zones, * rapides à parcourir. */ line = g_code_buffer_find_line_by_index(view->buffer, i); range = g_buffer_line_get_range(line); result = mrange_contains_addr(range, addr); if (result) break; *y += lheight; } if (result && code) for (; i <= view->last; i++) { line = g_code_buffer_find_line_by_index(view->buffer, i); if (g_buffer_line_get_flags(line) & BLF_HAS_CODE) break; if (i == view->last) break; line = g_code_buffer_find_line_by_index(view->buffer, i + 1); range = g_buffer_line_get_range(line); if (!mrange_contains_addr(range, addr)) break; *y += lheight; } return result; }