/* OpenIDA - Outil d'analyse de fichiers binaires
* virtual.c - encapsulation graphique des blocs virtuels
*
* Copyright (C) 2013 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 "virtual.h"
#include
#include
#include "flow.h"
#include "../node-int.h"
/* Encapsulation graphique d'un bloc virtuel (instance) */
struct _GVirtualNode
{
GGraphNode parent; /* A laisser en premier */
GVirtualBlock *block; /* Bloc virtuel associé */
gint x; /* Abscisse du noeud */
gint y; /* Ordonnée du noeud */
GGraphNode **children; /* Noeuds englobés */
size_t count; /* Quantité de ces noeuds */
};
/* Encapsulation graphique d'un bloc virtuel (classe) */
struct _GVirtualNodeClass
{
GGraphNodeClass parent; /* A laisser en premier */
};
/* Initialise la classe des encapsulations de blocs virtuels. */
static void g_virtual_node_class_init(GVirtualNodeClass *);
/* Initialise une encapsulation de bloc virtuel. */
static void g_virtual_node_init(GVirtualNode *);
/* Supprime toutes les références externes. */
static void g_virtual_node_dispose(GVirtualNode *);
/* Procède à la libération totale de la mémoire. */
static void g_virtual_node_finalize(GVirtualNode *);
/* Fournit le rang du noeud dans le graphique. */
static unsigned int g_virtual_node_get_rank(const GVirtualNode *);
/* Altère la position du noeud d'encapsulation. */
static void g_virtual_node_set_position(GVirtualNode *, gint *, gint *);
/* Fournit la position du noeud d'encapsulation. */
static void g_virtual_node_get_position(const GVirtualNode *, gint *, gint *);
/* Indique l'espace requis pour un noeud d'encapsulation. */
static GtkAllocation g_virtual_node_get_allocation(const GVirtualNode *);
/* Parcourt tous les blocs d'instructions dans un ordre donné. */
static bool g_virtual_node_visit_flow_nodes(GVirtualNode *, graph_node_visitor_cb, void *);
/* Définit les abscisses relatives du contenu d'un noeud. */
static void g_virtual_node_setup_x_line(GVirtualNode *);
/* Indique le type définit par la GLib pour l'encapsulation d'un bloc virtuel. */
G_DEFINE_TYPE(GVirtualNode, g_virtual_node, G_TYPE_GRAPH_NODE);
/******************************************************************************
* *
* Paramètres : klass = classe à initialiser. *
* *
* Description : Initialise la classe des encapsulations de blocs virtuels. *
* *
* Retour : - *
* *
* Remarques : - *
* *
******************************************************************************/
static void g_virtual_node_class_init(GVirtualNodeClass *klass)
{
GObjectClass *object; /* Autre version de la classe */
object = G_OBJECT_CLASS(klass);
object->dispose = (GObjectFinalizeFunc/* ! */)g_virtual_node_dispose;
object->finalize = (GObjectFinalizeFunc)g_virtual_node_finalize;
}
/******************************************************************************
* *
* Paramètres : node = instance à initialiser. *
* *
* Description : Initialise une encapsulation de bloc virtuel. *
* *
* Retour : - *
* *
* Remarques : - *
* *
******************************************************************************/
static void g_virtual_node_init(GVirtualNode *node)
{
GGraphNode *base; /* Version basique */
base = G_GRAPH_NODE(node);
base->get_rank = (get_node_rank_fc)g_virtual_node_get_rank;
base->set_pos = (node_set_pos_fc)g_virtual_node_set_position;
base->get_pos = (node_get_pos_fc)g_virtual_node_get_position;
base->get_alloc = (node_get_alloc_fc)g_virtual_node_get_allocation;
base->visit = (visit_flow_nodes_fc)g_virtual_node_visit_flow_nodes;
node->x = UNINITIALIZED_NODE_POS;
node->y = UNINITIALIZED_NODE_POS;
}
/******************************************************************************
* *
* Paramètres : node = instance d'objet GLib à traiter. *
* *
* Description : Supprime toutes les références externes. *
* *
* Retour : - *
* *
* Remarques : - *
* *
******************************************************************************/
static void g_virtual_node_dispose(GVirtualNode *node)
{
size_t i; /* Boucle de parcours */
g_object_unref(G_OBJECT(node->block));
for (i = 0; i < node->count; i++)
g_object_unref(G_OBJECT(node->children[i]));
if (node->children != NULL)
free(node->children);
G_OBJECT_CLASS(g_virtual_node_parent_class)->dispose(G_OBJECT(node));
}
/******************************************************************************
* *
* Paramètres : node = instance d'objet GLib à traiter. *
* *
* Description : Procède à la libération totale de la mémoire. *
* *
* Retour : - *
* *
* Remarques : - *
* *
******************************************************************************/
static void g_virtual_node_finalize(GVirtualNode *node)
{
G_OBJECT_CLASS(g_virtual_node_parent_class)->finalize(G_OBJECT(node));
}
/******************************************************************************
* *
* Paramètres : block = bloc virtuel représenté graphiquement. *
* view = morceau d'affichage à représenter. *
* *
* Description : Encapsule graphiquement un bloc virtuel. *
* *
* Retour : Adresse de la structure mise en place. *
* *
* Remarques : - *
* *
******************************************************************************/
GGraphNode *g_virtual_node_new(GVirtualBlock *block)
{
GVirtualNode *result; /* Structure à retourner */
result = g_object_new(G_TYPE_VIRTUAL_NODE, NULL);
g_object_ref(G_OBJECT(block));
result->block = block;
return G_GRAPH_NODE(result);
}
/******************************************************************************
* *
* Paramètres : node = noeud graphique à consulter. *
* *
* Description : Fournit le rang du noeud dans le graphique. *
* *
* Retour : Indice supérieur ou égal à zéro. *
* *
* Remarques : - *
* *
******************************************************************************/
static unsigned int g_virtual_node_get_rank(const GVirtualNode *node)
{
/* BUG_ON(node->count == 0) */
return g_graph_node_get_rank(node->children[0]);
}
/******************************************************************************
* *
* Paramètres : node = noeud graphique à manipuler. *
* x = éventuelle abscisse à intégrer ou NULL. *
* y = éventuelle ordonnée à intégrer ou NULL. *
* *
* Description : Altère la position du noeud d'encapsulation. *
* *
* Retour : - *
* *
* Remarques : - *
* *
******************************************************************************/
static void g_virtual_node_set_position(GVirtualNode *node, gint *x, gint *y)
{
if (x != NULL) node->x = *x;
if (y != NULL) node->y = *y;
}
/******************************************************************************
* *
* Paramètres : node = noeud graphique à consulter. *
* x = éventuelle abscisse à recevoir ou NULL. [OUT] *
* y = éventuelle ordonnée à recevoir ou NULL. [OUT] *
* *
* Description : Fournit la position du noeud d'encapsulation. *
* *
* Retour : - *
* *
* Remarques : - *
* *
******************************************************************************/
static void g_virtual_node_get_position(const GVirtualNode *node, gint *x, gint *y)
{
if (x != NULL) *x = node->x;
if (y != NULL) *y = node->y;
}
/******************************************************************************
* *
* Paramètres : node = noeud graphique à consulter. *
* *
* Description : Indique l'espace requis pour un noeud d'encapsulation. *
* *
* Retour : Espace constitué, entièrement ou non. *
* *
* Remarques : - *
* *
******************************************************************************/
static GtkAllocation g_virtual_node_get_allocation(const GVirtualNode *node)
{
GtkAllocation result; /* Valeurs à retourner */
size_t i; /* Boucle de parcours */
GtkAllocation alloc; /* Allocation d'un sous-noeud */
result.x = node->x;
result.y = node->y;
result.width = 0;
result.height = 0;
for (i = 0; i < node->count; i++)
{
alloc = g_graph_node_get_allocation(node->children[i]);
result.width += alloc.width;
result.height += alloc.height;
}
if (node->count > 1)
{
result.width += (node->count - 1) * NODE_TOP_MARGIN;
result.height += (node->count - 1) * NODE_TOP_MARGIN;
}
return result;
}
/******************************************************************************
* *
* Paramètres : node = noeud graphique démarrant la visite. *
* callback = ensemble de blocs à parcourir. *
* data = donnée utilisateur à associer au parcours. *
* *
* Description : Parcourt tous les blocs d'instructions dans un ordre donné. *
* *
* Retour : true si le parcours a été jusqu'à son terme, false sinon. *
* *
* Remarques : - *
* *
******************************************************************************/
static bool g_virtual_node_visit_flow_nodes(GVirtualNode *node, graph_node_visitor_cb callback, void *data)
{
bool result; /* Bilan à retourner */
size_t i; /* Boucle de parcours */
result = true;
for (i = 0; i < node->count && result; i++)
result = g_graph_node_visit_flow_nodes(node->children[i], callback, data);
return result;
}
/******************************************************************************
* *
* Paramètres : node = noeud d'encapsulation à compléter. *
* child = sous-noeud à insérer. *
* *
* Description : Ajoute un noeud au groupe courant. *
* *
* Retour : - *
* *
* Remarques : - *
* *
******************************************************************************/
void g_virtual_node_add_child(GVirtualNode *node, GGraphNode *child)
{
node->children = (GGraphNode **)realloc(node->children,
++node->count * sizeof(GGraphNode *));
node->children[node->count - 1] = child;
g_object_ref(G_OBJECT(child));
}
/******************************************************************************
* *
* Paramètres : node = noeud d'encapsulation à consulter. *
* *
* Description : Compte le nombre de noeuds contenus dans le groupe courant. *
* *
* Retour : Quantité normalement non nulle. *
* *
* Remarques : - *
* *
******************************************************************************/
size_t g_virtual_node_count_children(const GVirtualNode *node)
{
return node->count;
}
/******************************************************************************
* *
* Paramètres : node = noeud d'encapsulation à consulter. *
* index = indice du sous-bloc recherché. *
* *
* Description : Renvoie un des noeuds contenus dans le groupe courant. *
* *
* Retour : Un des blocs du groupe. *
* *
* Remarques : - *
* *
******************************************************************************/
GGraphNode *g_virtual_node_get_child(const GVirtualNode *node, size_t index)
{
if (index >= node->count)
return NULL;
else
return node->children[index];
}
/******************************************************************************
* *
* Paramètres : node = noeud d'encapsulation à traiter. *
* *
* Description : Organise le contenu du noeud selon l'axe des abscisses. *
* *
* Retour : - *
* *
* Remarques : - *
* *
******************************************************************************/
void g_virtual_node_organize_x_line(GVirtualNode *node)
{
size_t i; /* Boucle de parcours */
gint min; /* Valeur minimale rencontrée */
gint x; /* Position d'un sous-noeud */
g_virtual_node_setup_x_line(node);
min = 0;
for (i = 0; i < node->count; i++)
{
g_graph_node_get_position(node->children[i], &x, NULL);
min = MIN(min, x);
}
printf("min =%d\n", min);
min = -min + GRAPH_LEFT_MARGIN;
g_virtual_node_offset_x_line(node, min);
}
/******************************************************************************
* *
* Paramètres : node = noeud d'encapsulation à traiter. *
* *
* Description : Définit les abscisses relatives du contenu d'un noeud. *
* *
* Retour : - *
* *
* Remarques : - *
* *
******************************************************************************/
static void g_virtual_node_setup_x_line(GVirtualNode *node)
{
unsigned int rank_0; /* Rang du premier sous-noeud */
unsigned int rank_1; /* Rang du second sous-noeud */
size_t i; /* Boucle de parcours */
GGraphNode *child; /* Raccourci confortable */
gint last_pos; /* Dernière position */
GtkAllocation alloc; /* Espace pour l'affichage */
/* Si le rang d'entrée contient tous les éléments... */
if (node->count > 1)
{
rank_0 = g_graph_node_get_rank(node->children[0]);
rank_1 = g_graph_node_get_rank(node->children[1]);
if (rank_0 == rank_1)
{
g_graph_node_set_position(node->children[0], (gint []) { -(alloc.width / 2) }, NULL);
for (i = 1; i < node->count; i++)
{
/* Récupération de la position précédente */
child = node->children[i - 1];
g_graph_node_get_position(child, &last_pos, NULL);
alloc = g_graph_node_get_allocation(child);
last_pos += alloc.width + NODE_LEFT_MARGIN;
/* Application sur le noeud courant */
child = node->children[i];
alloc = g_graph_node_get_allocation(child);
g_graph_node_set_position(child, &last_pos, NULL);
}
}
}
for (i = 0; i < node->count; i++)
{
child = node->children[i];
/* Emplacement du fils */
if (!g_graph_node_has_x_position(child))
{
alloc = g_graph_node_get_allocation(child);
printf("alloc ? %d\n", alloc.width);
g_graph_node_set_position(child, (gint []) { -(alloc.width / 2) }, NULL);
}
/* Définitions éventuelles des emplacements liés */
if (G_IS_FLOW_NODE(child))
{
;
}
else if (G_IS_VIRTUAL_NODE(child))
g_virtual_node_organize_x_line(G_VIRTUAL_NODE(child));
/*else BUG_ON(1); */
}
}
/******************************************************************************
* *
* Paramètres : node = noeud d'encapsulation à traiter. *
* xoffset = valeur du décallage. *
* *
* Description : Procède à un décallage du contenu sur l'axe des abscisses. *
* *
* Retour : - *
* *
* Remarques : - *
* *
******************************************************************************/
void g_virtual_node_offset_x_line(GVirtualNode *node, gint xoffset)
{
size_t i; /* Boucle de parcours */
gint x; /* Position d'un sous-noeud */
GGraphNode *child; /* Raccourci confortable */
for (i = 0; i < node->count; i++)
{
child = node->children[i];
g_graph_node_get_position(child, &x, NULL);
printf("[%p] old=%d... ", child, x);
x += xoffset;
g_graph_node_set_position(child, &x, NULL);
printf("next=%d...\n", x);
}
}