/* 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); } }