/* OpenIDA - Outil d'analyse de fichiers binaires
* gcodebuffer.h - prototypes pour l'affichage d'un fragment de code d'assemblage
*
* Copyright (C) 2010 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 "gcodebuffer.h"
#include
#include
/* -------------------------- TAMPON POUR CODE DESASSEMBLE -------------------------- */
/* Tampon pour code désassemblé (instance) */
struct _GCodeBuffer
{
GObject parent; /* A laisser en premier */
GBufferLine **lines; /* Liste des lignes intégrées */
size_t count; /* Quantité en cache */
size_t used; /* Quantité utilisée */
};
/* Tampon pour code désassemblé (classe) */
struct _GCodeBufferClass
{
GObjectClass parent; /* A laisser en premier */
};
/* Taille des allocations de masse */
#define LINE_ALLOC_BULK 20
/* Procède à l'initialisation d'une classe de tampon de code. */
static void g_code_buffer_class_init(GCodeBufferClass *);
/* Procède à l'initialisation d'un tampon pour code désassemblé. */
static void g_code_buffer_init(GCodeBuffer *);
/* ---------------------- VUE PARTICULIERE D'UN TAMPON DE CODE ---------------------- */
/* Vue d'un tampon pour code désassemblé (instance) */
struct _GBufferView
{
GObject parent; /* A laisser en premier */
GCodeBuffer *buffer; /* Tampon de code visualisé */
size_t first; /* Première ligne intégrée */
size_t last; /* Dernière ligne intégrée */
gint line_height; /* Hauteur maximale des lignes */
gint max_widths[BLC_COUNT]; /* Taille cachée des colonnes */
gint left_margin; /* Marge gauche + espace */
gint left_text; /* Début d'impression du code */
buffer_line_draw_fc drawing_extra; /* Fonction d'accompagnement */
void *drawing_data; /* Donnée utilisateur */
};
/* Vue d'un tampon pour code désassemblé (classe) */
struct _GBufferViewClass
{
GObjectClass parent; /* A laisser en premier */
};
#define WIDTHS_CACHED(view) ((view)->max_widths[0] != -1)
/* 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 *);
/* Réinitialise le cache des largeurs de colonne calculées. */
static void g_buffer_view_reset_required_widths(GBufferView *);
/* Calcule les dimensions requises par une visualisation. */
static void g_buffer_view_compute_required_widths(GBufferView *);
/* ---------------------------------------------------------------------------------- */
/* TAMPON POUR CODE DESASSEMBLE */
/* ---------------------------------------------------------------------------------- */
/* Détermine le type du composant de tampon pour code désassemblé. */
G_DEFINE_TYPE(GCodeBuffer, g_code_buffer, G_TYPE_OBJECT);
/******************************************************************************
* *
* Paramètres : class = classe de composant GTK à initialiser. *
* *
* Description : Procède à l'initialisation d'une classe de tampon de code. *
* *
* Retour : - *
* *
* Remarques : - *
* *
******************************************************************************/
static void g_code_buffer_class_init(GCodeBufferClass *class)
{
}
/******************************************************************************
* *
* Paramètres : buffer = composant GTK à initialiser. *
* *
* Description : Procède à l'initialisation d'un tampon pour code désassemblé.*
* *
* Retour : - *
* *
* Remarques : - *
* *
******************************************************************************/
static void g_code_buffer_init(GCodeBuffer *buffer)
{
}
/******************************************************************************
* *
* Paramètres : - *
* *
* Description : Crée un nouveau composant de tampon pour code désassemblé. *
* *
* Retour : Composant GTK créé. *
* *
* Remarques : - *
* *
******************************************************************************/
GCodeBuffer *g_code_buffer_new(void)
{
GCodeBuffer *result; /* Composant à retourner */
result = g_object_new(G_TYPE_CODE_BUFFER, NULL);
return result;
}
/******************************************************************************
* *
* Paramètres : buffer = composant GTK à mettre à jour. *
* *
* Description : Ajoute une nouvelle ligne à un tampon pour code désassemblé. *
* *
* Retour : - *
* *
* Remarques : - *
* *
******************************************************************************/
GBufferLine *g_code_buffer_append_new_line(GCodeBuffer *buffer)
{
GBufferLine *result; /* Instance à retourner */
if (buffer->used == buffer->count)
{
buffer->count += LINE_ALLOC_BULK;
buffer->lines = (GBufferLine **)realloc(buffer->lines,
buffer->count * sizeof(GBufferLine *));
}
result = g_buffer_line_new();
buffer->lines[buffer->used++] = result;
return result;
}
/* ---------------------------------------------------------------------------------- */
/* VUE PARTICULIERE D'UN TAMPON DE CODE */
/* ---------------------------------------------------------------------------------- */
/* 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)
{
}
/******************************************************************************
* *
* Paramètres : buffer = composant GTK à initialiser. *
* *
* Description : Procède à l'initialisation d'une vue d'un tampon pour code. *
* *
* Retour : - *
* *
* Remarques : - *
* *
******************************************************************************/
static void g_buffer_view_init(GBufferView *buffer)
{
}
/******************************************************************************
* *
* Paramètres : buffer = tamon à représenter à l'écran. *
* *
* 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)
{
GBufferView *result; /* Composant à retourner */
result = g_object_new(G_TYPE_BUFFER_VIEW, NULL);
result->buffer = buffer;
result->first = 0;
result->last = buffer->used;
g_buffer_view_reset_required_widths(result);
return result;
}
/******************************************************************************
* *
* Paramètres : view = visualisation à consulter. *
* *
* Description : Réinitialise le cache des largeurs de colonne calculées. *
* *
* Retour : - *
* *
* Remarques : - *
* *
******************************************************************************/
static void g_buffer_view_reset_required_widths(GBufferView *view)
{
unsigned int i; /* Boucle de parcours */
for (i = 0; i < BLC_COUNT; i++)
view->max_widths[i] = -1;
}
/******************************************************************************
* *
* Paramètres : view = visualisation à consulter. *
* *
* Description : Calcule les dimensions requises par une visualisation. *
* *
* Retour : - *
* *
* Remarques : - *
* *
******************************************************************************/
static void g_buffer_view_compute_required_widths(GBufferView *view)
{
GBufferLine **lines; /* Liste des lignes à traiter */
size_t i; /* Boucle de parcours #1 */
unsigned int j; /* Boucle de parcours #2 */
gint width; /* Largeur d'une colonne */
lines = view->buffer->lines;
view->line_height = 17;
view->left_margin = 2 * view->line_height;
view->left_text = 2.5 * view->line_height;
for (i = view->first; i < view->last; i++)
for (j = 0; j < BLC_COUNT; j++)
{
width = g_buffer_line_get_width(lines[i], j);
view->max_widths[j] = MAX(view->max_widths[j], width);
}
}
/******************************************************************************
* *
* 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)
{
if (!WIDTHS_CACHED(view))
g_buffer_view_compute_required_widths(view);
return view->line_height;
}
/******************************************************************************
* *
* Paramètres : view = visualisation à consulter. *
* width = largeur requise pour une pleine visualisation. [OUT]*
* height = hauteur requise pour une pleine visualisation. [OUT]*
* *
* Description : Fournit les dimensions requises par une visualisation. *
* *
* Retour : - *
* *
* Remarques : - *
* *
******************************************************************************/
void g_buffer_view_get_size(GBufferView *view, gint *width, gint *height)
{
unsigned int i; /* Boucle de parcours */
*width = 0;
*height = view->line_height;
if (!WIDTHS_CACHED(view))
g_buffer_view_compute_required_widths(view);
for (i = 0; i < BLC_COUNT; i++)
*width += view->max_widths[i];
*height *= (view->last - view->first);
}
/******************************************************************************
* *
* Paramètres : view = visualisation à mettre à jour. *
* method = procédure à appeler à chaque dessin de ligne. *
* data = donnée utilisateur à passer lors des appels. *
* *
* Description : Définit à une procédure à appeler lors des dessins de ligne. *
* *
* Retour : - *
* *
* Remarques : - *
* *
******************************************************************************/
void g_buffer_view_define_extra_drawing(GBufferView *view, buffer_line_draw_fc method, void *data)
{
view->drawing_extra = method;
view->drawing_data = data;
}
/******************************************************************************
* *
* Paramètres : view = visualisation à représenter. *
* event = informations liées à l'événement. *
* gc = contexte graphique à utiliser pour les pinceaux. *
* fake_x = abscisse réelle du point 0 à l'écran. *
* fake_y = ordonnée réelle du point 0 à l'écran. *
* *
* Description : Imprime la visualisation du tempon de code désassemblé. *
* *
* Retour : - *
* *
* Remarques : - *
* *
******************************************************************************/
void g_buffer_view_draw(const GBufferView *view, const GdkEventExpose *event, GdkGC *gc, gint fake_x, gint fake_y)
{
GdkDrawable *drawable; /* Surface de dessin */
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 */
GBufferLine **lines; /* Liste des lignes à traiter */
size_t i; /* Boucle de parcours */
drawable = GDK_DRAWABLE(event->window);
real_x = fake_x + view->left_text;
real_y = fake_y + event->area.y;
first = (real_y / view->line_height);
last = first + (event->area.height / view->line_height);
if (event->area.height % view->line_height > 0) last++;
last = MIN(last, view->buffer->used > 0 ? view->buffer->used - 1 : 0);
y = event->area.y - (real_y % view->line_height);
lines = view->buffer->lines;
if (view->buffer->used > 0)
for (i = first; i <= last; i++)
{
/* TODO : skip if... */
if (view->drawing_extra != NULL)
view->drawing_extra(lines[i], drawable, gc, fake_x, y, view->drawing_data);
g_buffer_line_draw(lines[i], drawable, gc, view->max_widths, real_x, y);
y += view->line_height;
}
}
/******************************************************************************
* *
* Paramètres : view = visualisation à consulter. *
* y = ordonnée comprise dans la ligne recherchée. *
* *
* 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)
{
gint lheight; /* Hauteur d'une ligne */
size_t index; /* Indice attendu */
lheight = g_buffer_view_get_line_height(view);
index = y / lheight;
/* FIXME : à placer côté tampon ? */
return (index < view->buffer->used ? view->buffer->lines[index] : NULL);
}