diff options
Diffstat (limited to 'src/gtkext')
-rw-r--r-- | src/gtkext/graph/cluster.c | 1498 | ||||
-rw-r--r-- | src/gtkext/graph/cluster.h | 9 | ||||
-rw-r--r-- | src/gtkext/graph/edge.h | 3 |
3 files changed, 1035 insertions, 475 deletions
diff --git a/src/gtkext/graph/cluster.c b/src/gtkext/graph/cluster.c index 17af9ce..869851c 100644 --- a/src/gtkext/graph/cluster.c +++ b/src/gtkext/graph/cluster.c @@ -38,9 +38,39 @@ +/* ------------------------- LIEN SORTANT D'UN BLOC DE CODE ------------------------- */ + + +/* Détails sur le départ d'un lien */ +typedef struct _leaving_link_t +{ + GGraphCluster *owner; /* Propriétés du lien */ + + GdkPoint start; /* Point de départ d'un lien */ + size_t index; /* Indice sur ligne de départ */ + +} leaving_link_t; + + +/* Crée un point d'attache pour un lien sortant. */ +static leaving_link_t *create_leaving_link(GGraphCluster *, size_t); + +/* Détruit un point d'attache pour un lien sortant. */ +static void delete_leaving_link(leaving_link_t *); + +/* Calcule l'abscisse d'un lien à son départ d'un bloc. */ +static gint compute_leaving_link_position(const leaving_link_t *); + + + +/* ------------------------- LIEN ENTRANT D'UN BLOC DE CODE ------------------------- */ + + /* Définition du tracé d'un lien */ -typedef struct _incoming_edge +typedef struct _incoming_link_t { + GGraphCluster *owner; /* Propriétés du lien */ + InstructionLinkType type; /* Complexité du tracé */ const size_t *hslot; /* Couche horizontale réservée */ @@ -49,19 +79,24 @@ typedef struct _incoming_edge GGraphEdge *edge; /* Lien complet en préparation */ - GGraphCluster *origin; /* Bloc de départ du lien */ - const size_t *leaving_index; /* Indice du point de départ */ + const leaving_link_t *other; /* Autre extrémité du lien */ -} incoming_edge; +} incoming_link_t; -/* Détails sur le départ d'un lien */ -typedef struct _leaving_edge -{ - GdkPoint start; /* Point de départ d'un lien */ - size_t index; /* Indice sur ligne de départ */ +/* Crée un point d'attache pour un lien entrant simple. */ +static incoming_link_t *create_incoming_link(GGraphCluster *, InstructionLinkType, const leaving_link_t *); + +/* Détruit un point d'attache pour un lien entrant. */ +static void delete_incoming_link(incoming_link_t *); + +/* Compare deux liens entrants. */ +static int cmp_incoming_links(const incoming_link_t **, const incoming_link_t **); + + + +/* ---------------------- DESCENDANTS DIRECTS CLASSES PAR RANG ---------------------- */ -} leaving_edge; /* Réservation pour les lignes horizontales */ typedef struct _hspace_booking @@ -72,10 +107,8 @@ typedef struct _hspace_booking } hspace_booking; /* Découpage vertical */ -typedef struct _graph_rank +typedef struct _graph_rank_t { - size_t level; /* Niveau des blocs */ - hspace_booking **right2left; /* Réservations de D -> G */ size_t r2l_count; /* Quantité de ces réservations*/ @@ -85,7 +118,79 @@ typedef struct _graph_rank GGraphCluster **clusters; /* Ensembles de blocs */ size_t count; /* Nombre de ces ensembles */ -} graph_rank; +} graph_rank_t; + + +/* Initialise la gestion d'un ensemble de blocs de même rang. */ +static void init_graph_rank(graph_rank_t *, GGraphCluster *); + +/* Termine la gestion d'un ensemble de blocs de même rang. */ +static void exit_graph_rank(graph_rank_t *); + +/* Fournit le rang d'un ensemble de blocs. */ +static size_t get_graph_rank(const graph_rank_t *); + +/* Etend un ensemble de blocs de même rang. */ +static void extend_graph_rank(graph_rank_t *, GGraphCluster *); + +/* Compare deux rangées de blocs de code. */ +static int cmp_graph_rank(const graph_rank_t *, const graph_rank_t *); + +/* Etend un ensemble de blocs de même rang. */ +static void extend_graph_rank(graph_rank_t *, GGraphCluster *); + +/* Détermine l'emplacement requis d'un ensemble de blocs. */ +static void compute_graph_rank_needed_alloc(const graph_rank_t *, bool, GtkAllocation *); + +/* Affine l'abscisse d'un ensemble de blocs de même rang. */ +static void _place_graph_rank_clusters(GGraphCluster **, size_t, gint, int); + +/* Organise la disposition d'un ensemble de blocs basiques. */ +static void dispatch_x_graph_rank(const graph_rank_t *); + +/* Décalle vers la droite un ensemble de blocs basiques. */ +static void offset_x_graph_rank(const graph_rank_t *, gint); + + + +/* ------------------------ ENCADREMENTS D'ESPACES VERTICAUX ------------------------ */ + + +/* Réservations d'espaces latéraux */ +typedef struct _vspace_booking_t +{ + leaving_link_t *from; /* Bloc de départ du lien */ + incoming_link_t *to; /* Bloc d'arrivée du lien */ + + GdkPoint pts[2]; /* Coordonnées des points */ + +} vspace_booking_t; + +/* Réservations d'espaces latéraux */ +typedef struct _vspace_manager_t +{ + vspace_booking_t *pending; /* Besoins exprimés */ + size_t pending_count; /* Nombre de ces besoins */ + + vspace_booking_t **left; /* Lignes disposées à gauche */ + size_t left_count; /* Quantité de ces lignes */ + + vspace_booking_t **right; /* Lignes disposées à droite */ + size_t right_count; /* Quantité de ces lignes */ + +} vspace_manager_t; + + +/* Initialise les réservations liens verticaux. */ +static void init_vspace_manager(vspace_manager_t *); + +/* Termine les réservations liens verticaux. */ +static void exit_vspace_manager(vspace_manager_t *); + + + +/* -------------------------- DEFINITION D'UN CHEF DE FILE -------------------------- */ + /* Mise en disposition de blocs en graphique (instance) */ struct _GGraphCluster @@ -101,23 +206,25 @@ struct _GGraphCluster //////////////////////////////////////// - incoming_edge **top_anchors; /* Accroches supérieures */ + incoming_link_t **top_anchors; /* Accroches supérieures */ size_t ta_count; /* Quantité de ces accroches */ GCodeBlock *block; /* Bloc d'origine représenté */ GtkWidget *display; /* Vue graphique associée */ GtkAllocation alloc; /* Emplacement final du bloc */ - leaving_edge **bottom_anchors; /* Accroches inférieures */ + leaving_link_t **bottom_anchors; /* Accroches inférieures */ size_t ba_count; /* Quantité de ces accroches */ bool has_straight; /* Présence d'une ligne droite */ size_t straight_level; /* Rang atteint en ligne droite*/ size_t straight_index; /* Indice du lien vertical */ - graph_rank *ranks; /* Répartition verticale */ + graph_rank_t *ranks; /* Répartition verticale */ size_t ranks_count; /* Nombre de divisions */ + vspace_manager_t vspaces; /* Gestion des liens latéraux */ + }; /* Mise en disposition de blocs en graphique (classe) */ @@ -151,13 +258,13 @@ static void g_graph_cluster_dispose(GGraphCluster *); static void g_graph_cluster_finalize(GGraphCluster *); /* Complète un graphique avec un sous-ensemble de blocs. */ -static void g_graph_cluster_add_sub(GGraphCluster *, GGraphCluster *, GCodeBlock *); +static void g_graph_cluster_add_sub(GGraphCluster *, GGraphCluster *); -/* Organisation la disposition d'un ensemble de blocs basiques. */ -static void g_graph_cluster_dispatch_x(GGraphCluster *); +/* Met en place les embryons de liens nécessaires. */ +static void g_graph_cluster_define_links(GGraphCluster *, GHashTable *); -/* Détermine une position pour un ensemble de blocs basiques. */ -//static void g_graph_cluster_set_x(GGraphCluster *, gint); +/* Organise la disposition d'un ensemble de blocs basiques. */ +static void g_graph_cluster_dispatch_x(GGraphCluster *); /* Décalle vers la droite un ensemble de blocs basiques. */ static void g_graph_cluster_offset_x(GGraphCluster *, gint); @@ -172,9 +279,6 @@ static void g_graph_cluster_set_y(GGraphCluster *, gint); /* Recherche le bloc basique à l'extrémité d'un lien. */ //static GGraphCluster *g_graph_cluster_find_lower_dest_cluster(const GGraphCluster *, const GArchInstruction *); -/* Met en place les embryons de liens nécessaires. */ -static void g_graph_cluster_define_links(GGraphCluster *, GHashTable *); - /* Calcule l'abscisse d'un lien à son départ d'un bloc. */ static gint g_graph_cluster_compute_leaving_link_position(const GGraphCluster *, size_t); @@ -192,42 +296,61 @@ static void g_graph_cluster_resolve_links(const GGraphCluster *); +/* ------------------------- CALCUL DE REPARTITION DE BLOCS ------------------------- */ + + +/* Liste de blocs restants à traiter */ +typedef struct _pending_blocks +{ + size_t count; /* Taille de la liste */ + GCodeBlock *list[0]; /* Liste de blocs à traiter */ +} pending_blocks; + + +/* Met en place un ensemble de blocs sous forme graphique. */ +static GGraphCluster *setup_graph_clusters(GLoadedBinary *, const GBlockList *, size_t , segcnt_list *, pending_blocks *, GHashTable *); -/* Indique le type défini par la GLib pour les mises en disposition graphique. */ -G_DEFINE_TYPE(GGraphCluster, g_graph_cluster, G_TYPE_OBJECT); + +/* ---------------------------------------------------------------------------------- */ +/* LIEN SORTANT D'UN BLOC DE CODE */ +/* ---------------------------------------------------------------------------------- */ /****************************************************************************** * * -* Paramètres : klass = classe à initialiser. * +* Paramètres : owner = propriétaire du bloc de rattachement. * +* index = indice dans les liens de sortie. * * * -* Description : Initialise la classe des mises en disposition graphique. * +* Description : Crée un point d'attache pour un lien sortant. * * * -* Retour : - * +* Retour : Structure mise en place. * * * * Remarques : - * * * ******************************************************************************/ -static void g_graph_cluster_class_init(GGraphClusterClass *klass) +static leaving_link_t *create_leaving_link(GGraphCluster *owner, size_t index) { - GObjectClass *object; /* Autre version de la classe */ + leaving_link_t *result; /* Structure à retourner */ - object = G_OBJECT_CLASS(klass); + result = malloc(sizeof(leaving_link_t)); - object->dispose = (GObjectFinalizeFunc/* ! */)g_graph_cluster_dispose; - object->finalize = (GObjectFinalizeFunc)g_graph_cluster_finalize; + result->owner = owner; + + result->index = index; + + return result; } /****************************************************************************** * * -* Paramètres : cluster = instance à initialiser. * +* Paramètres : link = structure à libérer de la mémoire. * * * -* Description : Initialise une mise en disposition de blocs en graphique. * +* Description : Détruit un point d'attache pour un lien sortant. * * * * Retour : - * * * @@ -235,39 +358,87 @@ static void g_graph_cluster_class_init(GGraphClusterClass *klass) * * ******************************************************************************/ -static void g_graph_cluster_init(GGraphCluster *cluster) +static void delete_leaving_link(leaving_link_t *link) { + free(link); } /****************************************************************************** * * -* Paramètres : cluster = instance d'objet GLib à traiter. * +* Paramètres : link = information sur un lien à consulter. * * * -* Description : Supprime toutes les références externes. * +* Description : Calcule l'abscisse d'un lien à son départ d'un bloc. * * * -* Retour : - * +* Retour : Abscisse à attribuer à un départ de lien. * * * * Remarques : - * * * ******************************************************************************/ -static void g_graph_cluster_dispose(GGraphCluster *cluster) +static gint compute_leaving_link_position(const leaving_link_t *link) { - g_object_unref(G_OBJECT(cluster->block)); - g_object_unref(G_OBJECT(cluster->display)); + gint result; /* Position à retourner */ - G_OBJECT_CLASS(g_graph_cluster_parent_class)->dispose(G_OBJECT(cluster)); + result = g_graph_cluster_compute_leaving_link_position(link->owner, link->index); + + return result; } + +/* ---------------------------------------------------------------------------------- */ +/* LIEN ENTRANT D'UN BLOC DE CODE */ +/* ---------------------------------------------------------------------------------- */ + + /****************************************************************************** * * -* Paramètres : cluster = instance d'objet GLib à traiter. * +* Paramètres : owner = propriétaire du bloc de rattachement. * +* type = type de lien simple attendu. * +* other = point de départ du lien formé. * * * -* Description : Procède à la libération totale de la mémoire. * +* Description : Crée un point d'attache pour un lien entrant simple. * +* * +* Retour : Structure mise en place. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static incoming_link_t *create_incoming_link(GGraphCluster *owner, InstructionLinkType type, const leaving_link_t *other) +{ + incoming_link_t *result; /* Structure à retourner */ + + result = malloc(sizeof(incoming_link_t)); + + result->owner = owner; + + result->type = type; + + if (type == ILT_JUMP_IF_TRUE) + result->edge = g_graph_edge_new_true(&other->start, &result->y, &result->end); + + else if (type == ILT_JUMP_IF_FALSE) + result->edge = g_graph_edge_new_false(&other->start, &result->y, &result->end); + + else + result->edge = g_graph_edge_new(&other->start, &result->y, &result->end); + + result->other = other; + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : link = structure à libérer de la mémoire. * +* * +* Description : Détruit un point d'attache pour un lien entrant. * * * * Retour : - * * * @@ -275,75 +446,90 @@ static void g_graph_cluster_dispose(GGraphCluster *cluster) * * ******************************************************************************/ -static void g_graph_cluster_finalize(GGraphCluster *cluster) +static void delete_incoming_link(incoming_link_t *link) { - G_OBJECT_CLASS(g_graph_cluster_parent_class)->finalize(G_OBJECT(cluster)); + free(link); } /****************************************************************************** * * -* Paramètres : block = premier bloc du groupe. * -* highlighted = gestionnaire de surbrillance pour segments. * -* binary = binaire charger dont le code est à représenter.* +* Paramètres : a = premier lien entrant à comparer. * +* b = second lien entrant à comparer. * * * -* Description : * +* Description : Compare deux liens entrants. * * * -* Retour : Adresse de la structure mise en place. * +* Retour : Bilan de comparaison. * * * * Remarques : - * * * ******************************************************************************/ -GGraphCluster *g_graph_cluster_new(GCodeBlock *block, segcnt_list *highlighted, GLoadedBinary *binary) +static int cmp_incoming_links(const incoming_link_t **a, const incoming_link_t **b) { - GGraphCluster *result; /* Structure à retourner */ - GBufferView *view; /* Partie affichée du tampon */ - GtkRequisition requisition; /* Taille à l'écran actuelle */ + int result; /* Bilan à retourner */ + gint pos_a; /* Point de départ pour A */ + gint pos_b; /* Point de départ pour B */ - result = g_object_new(G_TYPE_GRAPH_CLUSTER, NULL); + pos_a = compute_leaving_link_position((*a)->other); - /* Encapsulation du bloc d'entrée */ + pos_b = compute_leaving_link_position((*b)->other); - result->block = block; - g_object_ref(G_OBJECT(block)); + if (pos_a < pos_b) + result = -1; - view = g_code_block_get_view(result->block, highlighted); + else if (pos_a > pos_b) + result = 1; - result->display = gtk_block_display_new(view); - gtk_widget_show(result->display); + else + result = 0; - g_loaded_panel_set_content(G_LOADED_PANEL(result->display), G_LOADED_CONTENT(binary)); + return result; - gtk_block_display_override_view_index(GTK_BLOCK_DISPLAY(result->display), BVW_GRAPH); +} - gtk_display_panel_show_border(GTK_DISPLAY_PANEL(result->display), true); - /* Détermination d'une position initiale centrée */ - gtk_widget_get_preferred_size(result->display, NULL, &requisition); +/* ---------------------------------------------------------------------------------- */ +/* DESCENDANTS DIRECTS CLASSES PAR RANG */ +/* ---------------------------------------------------------------------------------- */ - result->alloc.x = -requisition.width / 2; - result->alloc.y = 0; - result->alloc.width = requisition.width; - result->alloc.height = requisition.height; +/****************************************************************************** +* * +* Paramètres : grank = structure à initialiser. [OUT] * +* cluster = chef de file d'un ensemble de blocs. * +* * +* Description : Initialise la gestion d'un ensemble de blocs de même rang. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ - printf("BLOCK INIT :: %d <> %d\n", result->alloc.x, result->alloc.width); +static void init_graph_rank(graph_rank_t *grank, GGraphCluster *cluster) +{ + grank->right2left = NULL; + grank->r2l_count = 0; - return result; + grank->left2right = NULL; + grank->l2r_count = 0; + + grank->clusters = malloc(sizeof(GGraphCluster *)); + grank->count = 1; + + grank->clusters[0] = cluster; } /****************************************************************************** * * -* Paramètres : cluster = graphique de blocs à compléter. * -* sub = sous-ensemble à intégrer. * -* block = bloc basique de départ du sous-ensemble. * +* Paramètres : grank = structure à vider. * * * -* Description : Complète un graphique avec un sous-ensemble de blocs. * +* Description : Termine la gestion d'un ensemble de blocs de même rang. * * * * Retour : - * * * @@ -351,72 +537,94 @@ GGraphCluster *g_graph_cluster_new(GCodeBlock *block, segcnt_list *highlighted, * * ******************************************************************************/ -static void g_graph_cluster_add_sub(GGraphCluster *cluster, GGraphCluster *sub, GCodeBlock *block) +static void exit_graph_rank(graph_rank_t *grank) { - size_t level; /* Niveau du nouvel ensemble */ size_t i; /* Boucle de parcours */ - graph_rank new; /* Nouvel étage à insérer */ - graph_rank *rank; /* Nouvel étage à compléter */ - level = g_code_block_get_rank(block); + for (i = 0; i < grank->r2l_count; i++) + free(grank->right2left[i]); - for (i = 0; i < cluster->ranks_count; i++) - if (cluster->ranks[i].level == level) - break; + if (grank->right2left != NULL) + free(grank->right2left); - if (i == cluster->ranks_count) - { - new.level = level; + for (i = 0; i < grank->l2r_count; i++) + free(grank->left2right[i]); - new.right2left = NULL; - new.r2l_count = 0; + if (grank->left2right != NULL) + free(grank->left2right); - new.left2right = NULL; - new.l2r_count = 0; + assert(grank->clusters != NULL); - new.clusters = (GGraphCluster **)calloc(1, sizeof(GGraphCluster *)); - new.count = 1; + free(grank->clusters); - new.clusters[0] = sub; +} - int cmp_graph_rank(const graph_rank *a, const graph_rank *b) - { - if (a->level < b->level) - return -1; - else if (a->level > b->level) - return 1; +/****************************************************************************** +* * +* Paramètres : grank = ensemble de même rang à consulter. * +* * +* Description : Fournit le rang d'un ensemble de blocs. * +* * +* Retour : Rang d'un ensemble de blocs de même rang. * +* * +* Remarques : - * +* * +******************************************************************************/ - else - return 0; +static size_t get_graph_rank(const graph_rank_t *grank) +{ + size_t result; /* Rang à retourner */ - } + result = g_code_block_get_rank(grank->clusters[0]->block); - cluster->ranks = qinsert(cluster->ranks, &cluster->ranks_count, - sizeof(graph_rank), (__compar_fn_t)cmp_graph_rank, &new); + return result; - } +} - else - { - rank = &cluster->ranks[i]; - rank->count++; - rank->clusters = (GGraphCluster **)realloc(rank->clusters, - sizeof(GGraphCluster *) * rank->count); +/****************************************************************************** +* * +* Paramètres : a = premier ensemble de même rang à comparer. * +* b = second ensemble de même rang à comparer. * +* * +* Description : Compare deux rangées de blocs de code. * +* * +* Retour : Bilan de comparaison. * +* * +* Remarques : - * +* * +******************************************************************************/ - rank->clusters[rank->count - 1] = sub; +static int cmp_graph_rank(const graph_rank_t *a, const graph_rank_t *b) +{ + int result; /* Bilan à retourner */ + size_t level_a; /* Niveau de l'ensemble A */ + size_t level_b; /* Niveau de l'ensemble B */ - } + level_a = get_graph_rank(a); + level_b = get_graph_rank(b); + + if (level_a < level_b) + result = -1; + + else if (level_a > level_b) + result = 1; + + else + result = 0; + + return result; } /****************************************************************************** * * -* Paramètres : cluster = graphique de blocs à manipuler. * +* Paramètres : grank = structure à compléter. * +* cluster = chef de file d'un ensemble de blocs. * * * -* Description : Organisation la disposition d'un ensemble de blocs basiques. * +* Description : Etend un ensemble de blocs de même rang. * * * * Retour : - * * * @@ -424,152 +632,185 @@ static void g_graph_cluster_add_sub(GGraphCluster *cluster, GGraphCluster *sub, * * ******************************************************************************/ -static void g_graph_cluster_dispatch_x(GGraphCluster *cluster) +static void extend_graph_rank(graph_rank_t *grank, GGraphCluster *cluster) { - size_t k; /* Boucle de parcours #1 */ - const graph_rank *rank; /* Accès confortable au rang */ - size_t j; /* Boucle de parcours #2 */ - gint start; /* Position initiale de départ */ - size_t rcount; /* Nombre d'ensembles présents */ - size_t mid; /* Position centrale de départ */ + grank->count++; + grank->clusters = realloc(grank->clusters, sizeof(GGraphCluster *) * grank->count); - /** - * A ce point, tous les blocs parents sont placés. - * On est donc en mesure de réorganiser les points d'arrivée - * des liens afin d'éviter les croisements : un lien qui vient - * de la gauche ne doit pas arriver tout à droite ! - */ + grank->clusters[grank->count - 1] = cluster; - int compare_incoming_edges(const incoming_edge **a, const incoming_edge **b) - { - int result; /* Bilan à retourner */ - gint pos_a; /* Point de départ pour A */ - gint pos_b; /* Point de départ pour B */ +} - pos_a = g_graph_cluster_compute_leaving_link_position((*a)->origin, *(*a)->leaving_index); - pos_b = g_graph_cluster_compute_leaving_link_position((*b)->origin, *(*b)->leaving_index); +/****************************************************************************** +* * +* Paramètres : grank = ensemble de descendants d'un même rang. * +* last = indique s'il s'agit du dernier étage de l'ensemble. * +* alloc = emplacement idéal pour l'affichage. [OUT] * +* * +* Description : Détermine l'emplacement requis d'un ensemble de blocs. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ - if (pos_a < pos_b) - result = -1; +static void compute_graph_rank_needed_alloc(const graph_rank_t *grank, bool last, GtkAllocation *alloc) +{ + GtkAllocation needed; /* Taille requise */ - else if (pos_a > pos_b) - result = 1; + switch (grank->count) + { + case 1: - else - result = 0; + g_graph_cluster_compute_needed_alloc(grank->clusters[0], &needed); - return result; + if (needed.x < alloc->x) + { + alloc->width += (alloc->x - needed.x); + alloc->x = needed.x; + } - } + if ((needed.x + needed.width) > (alloc->x + alloc->width)) + alloc->width += needed.x + needed.width - alloc->x - alloc->width; - qsort(cluster->top_anchors, cluster->ta_count, sizeof(incoming_edge *), (__compar_fn_t)compare_incoming_edges); + /* La hauteur maximale n'est présente qu'avec le dernier morceau */ + if (last) + { + if ((needed.y + needed.height) > (alloc->y + alloc->height)) + alloc->height += needed.y + needed.height - alloc->y - alloc->height; + } - /** - * Il est désormais temps de placer tous les blocs de code inférieurs. - */ + break; - void place_sub(GGraphCluster **iter, size_t loop, gint base, int dir) - { - size_t i; /* Boucle de parcours #2 */ - GtkAllocation needed; /* Taille requise */ + default: - assert(dir == -1 || dir == 1); + assert(grank->count >= 2); - for (i = 0; i < loop; i++, iter += dir) - { - g_graph_cluster_dispatch_x(*iter); + g_graph_cluster_compute_needed_alloc(grank->clusters[0], &needed); - g_graph_cluster_compute_needed_alloc(*iter, &needed); + if (needed.x < alloc->x) + { + alloc->width += (alloc->x - needed.x); + alloc->x = needed.x; + } - if (dir > 0) - g_graph_cluster_offset_x(*iter, base - needed.x); - else - g_graph_cluster_offset_x(*iter, base - needed.x - needed.width); + /* La hauteur maximale n'est présente qu'avec le dernier morceau */ + if (last) + { + if ((needed.y + needed.height) > (alloc->y + alloc->height)) + alloc->height += needed.y + needed.height - alloc->y - alloc->height; + } - base += dir * (needed.width + HORIZONTAL_MARGIN); + g_graph_cluster_compute_needed_alloc(grank->clusters[grank->count - 1], &needed); - } + if ((needed.x + needed.width) > (alloc->x + alloc->width)) + alloc->width += needed.x + needed.width - alloc->x - alloc->width; - } + /* La hauteur maximale n'est présente qu'avec le dernier morceau */ + if (last) + { + if ((needed.y + needed.height) > (alloc->y + alloc->height)) + alloc->height += needed.y + needed.height - alloc->y - alloc->height; + } + break; - for (k = 0; k < cluster->ranks_count; k++) - { - rank = &cluster->ranks[k]; + } - /* Répartition autour d'une ligne verticale */ - if (cluster->has_straight) - { - start = g_graph_cluster_compute_leaving_link_position(cluster, cluster->straight_index); +} - if (rank->level < cluster->straight_level) - { - /* Répartition à gauche du lien */ - for (j = rank->count; j > 0; j--) - if (*rank->clusters[j - 1]->parent_index < cluster->straight_index) - break; +/****************************************************************************** +* * +* Paramètres : iter = début de la boucle de parcours. * +* loop = nombre d'itérations à mener. * +* base = position de base sur l'axe des abscisses. * +* dir = direction du parcours. * +* * +* Description : Affine l'abscisse d'un ensemble de blocs de même rang. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ - start -= HORIZONTAL_MARGIN / 2; +static void _place_graph_rank_clusters(GGraphCluster **iter, size_t loop, gint base, int dir) +{ + size_t i; /* Boucle de parcours */ + GtkAllocation needed; /* Taille requise */ - place_sub(rank->clusters, j, start, -1); + assert(dir == -1 || dir == 1); - /* Répartition à droite du lien */ + for (i = 0; i < loop; i++, iter += dir) + { + g_graph_cluster_dispatch_x(*iter); - for (j = 0; j < rank->count; j++) - if (*rank->clusters[j]->parent_index > cluster->straight_index) - break; + g_graph_cluster_compute_needed_alloc(*iter, &needed); - start += HORIZONTAL_MARGIN; + if (dir > 0) + g_graph_cluster_offset_x(*iter, base - needed.x); + else + g_graph_cluster_offset_x(*iter, base - needed.x - needed.width); - place_sub(rank->clusters + j, rank->count - j, start, 1); + base += dir * (needed.width + HORIZONTAL_MARGIN); - } + } - } +} - /* Répartition homogène */ - else - { - rcount = rank->count; - if (rcount % 2 == 1) - { - if (rcount > 1) - { - mid = rcount / 2; +/****************************************************************************** +* * +* Paramètres : grank = ensemble de blocs de même rang à manipuler. * +* * +* Description : Organise la disposition d'un ensemble de blocs basiques. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ - start = rank->clusters[mid]->alloc.x - HORIZONTAL_MARGIN; +static void dispatch_x_graph_rank(const graph_rank_t *grank) +{ + size_t mid; /* Position centrale de départ */ + gint start; /* Position initiale de départ */ - place_sub(rank->clusters + mid - 1, mid, start, -1); + if (grank->count % 2 == 1) + { + if (grank->count > 1) + { + mid = grank->count / 2; - start *= -1; + start = grank->clusters[mid]->alloc.x - HORIZONTAL_MARGIN; - place_sub(rank->clusters + mid + 1, mid, start, 1); + _place_graph_rank_clusters(grank->clusters + mid - 1, mid, start, -1); - } + start *= -1; - else - g_graph_cluster_dispatch_x(rank->clusters[0]); + _place_graph_rank_clusters(grank->clusters + mid + 1, mid, start, 1); - } + } - else - { - mid = rcount / 2 - 1; + else + g_graph_cluster_dispatch_x(grank->clusters[0]); - start = - HORIZONTAL_MARGIN / 2; + } - place_sub(rank->clusters + mid, mid + 1, start, -1); + else + { + mid = grank->count / 2 - 1; - start *= -1; + start = - HORIZONTAL_MARGIN / 2; - place_sub(rank->clusters + mid + 1, mid + 1, start, 1); + _place_graph_rank_clusters(grank->clusters + mid, mid + 1, start, -1); - } + start *= -1; - } + _place_graph_rank_clusters(grank->clusters + mid + 1, mid + 1, start, 1); } @@ -578,33 +819,38 @@ static void g_graph_cluster_dispatch_x(GGraphCluster *cluster) /****************************************************************************** * * -* Paramètres : cluster = graphique de blocs à actualiser. * -* x = position finale sur l'axe des abscisses. * +* Paramètres : grank = ensemble de blocs de même rang à actualiser. * +* offset = décalage à appliquer. * * * -* Description : Détermine une position pour un ensemble de blocs basiques. * +* Description : Décalle vers la droite un ensemble de blocs basiques. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ -/* -static void g_graph_cluster_set_x(GGraphCluster *cluster, gint x) + +static void offset_x_graph_rank(const graph_rank_t *grank, gint offset) { - g_graph_cluster_offset_x(cluster, -cluster->alloc.x); + size_t i; /* Boucle de parcours */ - g_graph_cluster_offset_x(cluster, x); + for (i = 0; i < grank->count; i++) + g_graph_cluster_offset_x(grank->clusters[i], offset); } -*/ + + + +/* ---------------------------------------------------------------------------------- */ +/* ENCADREMENTS D'ESPACES VERTICAUX */ +/* ---------------------------------------------------------------------------------- */ /****************************************************************************** * * -* Paramètres : cluster = graphique de blocs à actualiser. * -* offset = décalage à appliquer. * +* Paramètres : manager = structure à initialiser. * * * -* Description : Décalle vers la droite un ensemble de blocs basiques. * +* Description : Initialise les réservations liens verticaux. * * * * Retour : - * * * @@ -612,26 +858,25 @@ static void g_graph_cluster_set_x(GGraphCluster *cluster, gint x) * * ******************************************************************************/ -static void g_graph_cluster_offset_x(GGraphCluster *cluster, gint offset) +static void init_vspace_manager(vspace_manager_t *manager) { - size_t i; /* Boucle de parcours #1 */ - size_t j; /* Boucle de parcours #2 */ + manager->pending = NULL; + manager->pending_count = 0; - cluster->alloc.x += offset; + manager->left = NULL; + manager->left_count = 0; - for (i = 0; i < cluster->ranks_count; i++) - for (j = 0; j < cluster->ranks[i].count; j++) - g_graph_cluster_offset_x(cluster->ranks[i].clusters[j], offset); + manager->right = NULL; + manager->right_count = 0; } /****************************************************************************** * * -* Paramètres : cluster = graphique de blocs à actualiser. * -* base = position ordonnée à appliquer. * +* Paramètres : manager = structure à vider. * * * -* Description : Décalle vers le bas un ensemble de blocs basiques. * +* Description : Termine les réservations liens verticaux. * * * * Retour : - * * * @@ -639,72 +884,59 @@ static void g_graph_cluster_offset_x(GGraphCluster *cluster, gint offset) * * ******************************************************************************/ -static void g_graph_cluster_set_y(GGraphCluster *cluster, gint base) +static void exit_vspace_manager(vspace_manager_t *manager) { - size_t i; /* Boucle de parcours #1 */ - const graph_rank *rank; /* Accès simplifié à la rangée */ - gint max; /* Hauteur maximale rencontrée */ - size_t j; /* Boucle de parcours #2 */ - GGraphCluster *sub; /* Sous-ensemble traité */ - GtkAllocation alloc; /* Allocation courante */ - - cluster->alloc.y = base; - - base += cluster->alloc.height; - - for (i = 0; i < cluster->ranks_count; i++) - { - rank = &cluster->ranks[i]; - - /* On ajoute l'espace vertical pour les lignes horizontales */ - - if (rank->r2l_count > rank->l2r_count) - max = rank->r2l_count; - else - max = rank->l2r_count; + if (manager->pending != NULL) + free(manager->pending); - base += VERTICAL_MARGIN; + if (manager->left != NULL) + free(manager->left); - /** - * Comme les liens purement verticaux n'entrainent pas de réservation, - * il n'y a potentiellement pas toujours d'espace à ajouter. - */ + if (manager->right != NULL) + free(manager->right); - if (max > 0) - base += ((max - 1) * LINK_MARGIN); +} - /* On ajoute l'espace requis pour l'affichage des blocs */ - base += VERTICAL_MARGIN; - max = 0; +/* ---------------------------------------------------------------------------------- */ +/* DEFINITION D'UN CHEF DE FILE */ +/* ---------------------------------------------------------------------------------- */ - for (j = 0; j < rank->count; j++) - { - sub = rank->clusters[j]; - g_graph_cluster_set_y(sub, base); +/* Indique le type défini par la GLib pour les mises en disposition graphique. */ +G_DEFINE_TYPE(GGraphCluster, g_graph_cluster, G_TYPE_OBJECT); - g_graph_cluster_compute_needed_alloc(sub, &alloc); - if ((alloc.y + alloc.height) > max) - max = alloc.y + alloc.height; +/****************************************************************************** +* * +* Paramètres : klass = classe à initialiser. * +* * +* Description : Initialise la classe des mises en disposition graphique. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ - } +static void g_graph_cluster_class_init(GGraphClusterClass *klass) +{ + GObjectClass *object; /* Autre version de la classe */ - base = max; + object = G_OBJECT_CLASS(klass); - } + object->dispose = (GObjectFinalizeFunc/* ! */)g_graph_cluster_dispose; + object->finalize = (GObjectFinalizeFunc)g_graph_cluster_finalize; } /****************************************************************************** * * -* Paramètres : cluster = encapsulation à consulter. * -* alloc = emplacement idéal pour l'affichage. * +* Paramètres : cluster = instance à initialiser. * * * -* Description : Détermine l'emplacement requis d'un ensemble de blocs. * +* Description : Initialise une mise en disposition de blocs en graphique. * * * * Retour : - * * * @@ -712,196 +944,168 @@ static void g_graph_cluster_set_y(GGraphCluster *cluster, gint base) * * ******************************************************************************/ -void g_graph_cluster_compute_needed_alloc(const GGraphCluster *cluster, GtkAllocation *alloc) +static void g_graph_cluster_init(GGraphCluster *cluster) { - GtkAllocation needed; /* Taille requise */ - size_t i; /* Boucle de parcours */ - size_t rcount; /* Nombre d'ensembles présents */ - - *alloc = cluster->alloc; - - for (i = 0; i < cluster->ranks_count; i++) - { - rcount = cluster->ranks[i].count; - - switch (rcount) - { - case 1: - - g_graph_cluster_compute_needed_alloc(cluster->ranks[i].clusters[0], &needed); - - if (needed.x < alloc->x) - { - alloc->width += (alloc->x - needed.x); - alloc->x = needed.x; - } + init_vspace_manager(&cluster->vspaces); - if ((needed.x + needed.width) > (alloc->x + alloc->width)) - alloc->width += needed.x + needed.width - alloc->x - alloc->width; - - /* La hauteur maximale n'est présente qu'avec le dernier morceau */ - if ((i + 1) == cluster->ranks_count) - { - if ((needed.y + needed.height) > (alloc->y + alloc->height)) - alloc->height += needed.y + needed.height - alloc->y - alloc->height; - } - - break; - - default: - - assert(rcount >= 2); - - g_graph_cluster_compute_needed_alloc(cluster->ranks[i].clusters[0], &needed); - - if (needed.x < alloc->x) - { - alloc->width += (alloc->x - needed.x); - alloc->x = needed.x; - } - - /* La hauteur maximale n'est présente qu'avec le dernier morceau */ - if ((i + 1) == cluster->ranks_count) - { - if ((needed.y + needed.height) > (alloc->y + alloc->height)) - alloc->height += needed.y + needed.height - alloc->y - alloc->height; - } - - g_graph_cluster_compute_needed_alloc(cluster->ranks[i].clusters[rcount - 1], &needed); - - if ((needed.x + needed.width) > (alloc->x + alloc->width)) - alloc->width += needed.x + needed.width - alloc->x - alloc->width; +} - /* La hauteur maximale n'est présente qu'avec le dernier morceau */ - if ((i + 1) == cluster->ranks_count) - { - if ((needed.y + needed.height) > (alloc->y + alloc->height)) - alloc->height += needed.y + needed.height - alloc->y - alloc->height; - } - break; +/****************************************************************************** +* * +* Paramètres : cluster = instance d'objet GLib à traiter. * +* * +* Description : Supprime toutes les références externes. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ - } +static void g_graph_cluster_dispose(GGraphCluster *cluster) +{ + g_clear_object(&cluster->block); + g_clear_object(&cluster->display); - } + G_OBJECT_CLASS(g_graph_cluster_parent_class)->dispose(G_OBJECT(cluster)); } /****************************************************************************** * * -* Paramètres : cluster = encapsulation à consulter. * +* Paramètres : cluster = instance d'objet GLib à traiter. * * * -* Description : Fournit le composant graphique principal du groupe. * +* Description : Procède à la libération totale de la mémoire. * * * -* Retour : Composant graphique principal utilisé. * +* Retour : - * * * * Remarques : - * * * ******************************************************************************/ -GtkWidget *g_graph_cluster_get_widget(GGraphCluster *cluster) +static void g_graph_cluster_finalize(GGraphCluster *cluster) { - GtkWidget *result; + size_t i; /* Boucle de parcours */ - result = cluster->display; + for (i = 0; i < cluster->ta_count; i++) + delete_incoming_link(cluster->top_anchors[i]); - g_object_ref(G_OBJECT(result)); + if (cluster->top_anchors != NULL) + free(cluster->top_anchors); - return result; + for (i = 0; i < cluster->ba_count; i++) + delete_leaving_link(cluster->bottom_anchors[i]); + + if (cluster->bottom_anchors != NULL) + free(cluster->bottom_anchors); + + for (i = 0; i < cluster->ranks_count; i++) + exit_graph_rank(&cluster->ranks[i]); + + if (cluster->ranks != NULL) + free(cluster->ranks); + + exit_vspace_manager(&cluster->vspaces); + + G_OBJECT_CLASS(g_graph_cluster_parent_class)->finalize(G_OBJECT(cluster)); } /****************************************************************************** * * -* Paramètres : cluster = encapsulation à traiter. * -* display = support de destination finale. * +* Paramètres : block = premier bloc du groupe. * +* highlighted = gestionnaire de surbrillance pour segments. * +* binary = binaire charger dont le code est à représenter.* * * -* Description : Dispose chaque noeud sur la surface de destination donnée. * +* Description : * * * -* Retour : - * +* Retour : Adresse de la structure mise en place. * * * * Remarques : - * * * ******************************************************************************/ -void g_graph_cluster_place(GGraphCluster *cluster, GtkGraphDisplay *display) +GGraphCluster *g_graph_cluster_new(GCodeBlock *block, segcnt_list *highlighted, GLoadedBinary *binary) { - size_t i; /* Boucle de parcours #1 */ - size_t j; /* Boucle de parcours #2 */ - - g_object_ref(G_OBJECT(cluster->display)); - gtk_graph_display_put(display, cluster->display, &cluster->alloc); - - for (i = 0; i < cluster->ta_count; i++) - { - g_object_ref(G_OBJECT(cluster->top_anchors[i]->edge)); - gtk_graph_display_add_edge(display, cluster->top_anchors[i]->edge); - } + GGraphCluster *result; /* Structure à retourner */ + GBufferView *view; /* Partie affichée du tampon */ + GtkRequisition requisition; /* Taille à l'écran actuelle */ - for (i = 0; i < cluster->ranks_count; i++) - for (j = 0; j < cluster->ranks[i].count; j++) - g_graph_cluster_place(cluster->ranks[i].clusters[j], display); + result = g_object_new(G_TYPE_GRAPH_CLUSTER, NULL); -} + /* Encapsulation du bloc d'entrée */ + result->block = block; + g_object_ref(G_OBJECT(block)); + view = g_code_block_get_view(result->block, highlighted); + result->display = gtk_block_display_new(view); + gtk_widget_show(result->display); + g_loaded_panel_set_content(G_LOADED_PANEL(result->display), G_LOADED_CONTENT(binary)); + gtk_block_display_override_view_index(GTK_BLOCK_DISPLAY(result->display), BVW_GRAPH); + gtk_display_panel_show_border(GTK_DISPLAY_PANEL(result->display), true); + /* Détermination d'une position initiale centrée */ -////////////////////////////////////////////////////////// + gtk_widget_get_preferred_size(result->display, NULL, &requisition); + result->alloc.x = -requisition.width / 2; + result->alloc.y = 0; + result->alloc.width = requisition.width; + result->alloc.height = requisition.height; + return result; +} /****************************************************************************** * * -* Paramètres : cluster = graphique de blocs à consulter ou remonter. * -* first = première instruction du bloc basique recherché. * +* Paramètres : cluster = graphique de blocs à compléter. * +* sub = sous-ensemble à intégrer. * * * -* Description : Recherche le bloc basique à l'extrémité d'un lien. * +* Description : Complète un graphique avec un sous-ensemble de blocs. * * * -* Retour : Bloc graphique de destination pour un lien ou NULL si échec. * +* Retour : - * * * * Remarques : - * * * ******************************************************************************/ -#if 0 -static GGraphCluster *g_graph_cluster_find_lower_dest_cluster(const GGraphCluster *cluster, const GArchInstruction *first) + +static void g_graph_cluster_add_sub(GGraphCluster *cluster, GGraphCluster *sub) { - GGraphCluster *result; /* Trouvaille à retourner */ - size_t i; /* Boucle de parcours #1 */ - const graph_rank *rank; /* Confort d'accès */ - size_t j; /* Boucle de parcours #2 */ - GArchInstruction *instr; /* Instruction à comparer */ + size_t level; /* Niveau du nouvel ensemble */ + size_t i; /* Boucle de parcours */ + graph_rank_t new; /* Nouvel étage à insérer */ - result = NULL; + level = g_code_block_get_rank(sub->block); - for (i = 0; i < cluster->ranks_count && result == NULL; i++) - { - rank = &cluster->ranks[i]; - - for (j = 0; j < rank->count && result == NULL; j++) - { - g_basic_block_get_boundaries(rank->clusters[j]->block, &instr, NULL); + for (i = 0; i < cluster->ranks_count; i++) + if (get_graph_rank(&cluster->ranks[i]) == level) + break; - if (instr == first) - result = rank->clusters[j]; + if (i == cluster->ranks_count) + { + init_graph_rank(&new, sub); - } + cluster->ranks = qinsert(cluster->ranks, &cluster->ranks_count, + sizeof(graph_rank_t), (__compar_fn_t)cmp_graph_rank, &new); } - return result; + else + extend_graph_rank(&cluster->ranks[i], sub); } -#endif + /****************************************************************************** * * @@ -923,11 +1127,11 @@ static void g_graph_cluster_define_links(GGraphCluster *cluster, GHashTable *all size_t i; /* Boucle de parcours #1 */ const block_link_t *dest; /* Bloc visé par une autre */ GGraphCluster *target; /* Bloc ciblé par un lien */ - leaving_edge *leaving; /* Point de départ d'un lien */ + leaving_link_t *leaving; /* Point de départ d'un lien */ size_t target_level; /* Rang du bloc ciblé */ size_t j; /* Boucle de parcours #2 */ size_t k; /* Boucle de parcours #3 */ - incoming_edge *incoming; /* Définitions d'arrivée */ + incoming_link_t *incoming; /* Définitions d'arrivée */ /* Au niveau du bloc courant */ @@ -953,10 +1157,11 @@ static void g_graph_cluster_define_links(GGraphCluster *cluster, GHashTable *all /* Point de départ */ - leaving = (leaving_edge *)calloc(1, sizeof(leaving_edge)); + leaving = create_leaving_link(cluster, cluster->ba_count); + + cluster->bottom_anchors = realloc(cluster->bottom_anchors, + ++cluster->ba_count * sizeof(leaving_link_t *)); - cluster->bottom_anchors = (leaving_edge **)realloc(cluster->bottom_anchors, - ++cluster->ba_count * sizeof(leaving_edge *)); cluster->bottom_anchors[cluster->ba_count - 1] = leaving; /* Est-ce un lien qui doit être vertical ? */ @@ -970,7 +1175,7 @@ static void g_graph_cluster_define_links(GGraphCluster *cluster, GHashTable *all for (k = 0; k < cluster->ranks[j].count && target_level == -1; k++) if (cluster->ranks[j].clusters[k] == target) { - target_level = cluster->ranks[j].level; + target_level = get_graph_rank(&cluster->ranks[j]); if (target_level > (level + 1) && target_level > cluster->straight_level) { @@ -988,29 +1193,93 @@ static void g_graph_cluster_define_links(GGraphCluster *cluster, GHashTable *all /* Point d'arrivée */ - incoming = (incoming_edge *)calloc(1, sizeof(incoming_edge)); + incoming = create_incoming_link(target, dest->type, leaving); + + target->top_anchors = realloc(target->top_anchors, + ++target->ta_count * sizeof(incoming_link_t *)); - target->top_anchors = (incoming_edge **)realloc(target->top_anchors, - ++target->ta_count * sizeof(incoming_edge *)); target->top_anchors[target->ta_count - 1] = incoming; /* Etablissement d'un embryon de lien */ - leaving->index = cluster->ba_count - 1; - incoming->type = dest->type; - if (incoming->type == ILT_JUMP_IF_TRUE) - incoming->edge = g_graph_edge_new_true(&leaving->start, &incoming->y, &incoming->end); + /* FIXME : trop de boucles ! */ - else if (incoming->type == ILT_JUMP_IF_FALSE) - incoming->edge = g_graph_edge_new_false(&leaving->start, &incoming->y, &incoming->end); + target_level = -1; - else - incoming->edge = g_graph_edge_new(&leaving->start, &incoming->y, &incoming->end); + for (j = 0; j < cluster->ranks_count && target_level == -1; j++) + for (k = 0; k < cluster->ranks[j].count && target_level == -1; k++) + if (cluster->ranks[j].clusters[k] == target) + { + target_level = 0; + target->parent_index = &leaving->index; + } + + + + + break; + + + case ILT_LOOP: + + + + + + target = G_GRAPH_CLUSTER(g_hash_table_lookup(all, dest->linked)); + assert(target != NULL); + + /* Point de départ */ + + leaving = create_leaving_link(cluster, cluster->ba_count); + + cluster->bottom_anchors = realloc(cluster->bottom_anchors, + ++cluster->ba_count * sizeof(leaving_link_t *)); + + cluster->bottom_anchors[cluster->ba_count - 1] = leaving; + + /* Est-ce un lien qui doit être vertical ? */ + + + /* FIXME : trop de boucles ! */ + + target_level = -1; + + for (j = 0; j < cluster->ranks_count && target_level == -1; j++) + for (k = 0; k < cluster->ranks[j].count && target_level == -1; k++) + if (cluster->ranks[j].clusters[k] == target) + { + target_level = get_graph_rank(&cluster->ranks[j]); + + if (target_level > (level + 1) && target_level > cluster->straight_level) + { + cluster->has_straight = true; + cluster->straight_level = target_level; + cluster->straight_index = cluster->ba_count - 1; + } + + } + + + + + + + /* Point d'arrivée */ + + incoming = create_incoming_link(target, dest->type, leaving); + + target->top_anchors = realloc(target->top_anchors, + ++target->ta_count * sizeof(incoming_link_t *)); + + target->top_anchors[target->ta_count - 1] = incoming; + + /* Etablissement d'un embryon de lien */ - incoming->origin = cluster; - incoming->leaving_index = &leaving->index; + incoming->edge = g_graph_edge_new_loop(&leaving->start, &leaving->start, + &incoming->y, &incoming->end); /* FIXME : trop de boucles ! */ @@ -1028,10 +1297,11 @@ static void g_graph_cluster_define_links(GGraphCluster *cluster, GHashTable *all - break; - case ILT_LOOP: + + + /* TODO */ //assert(false); @@ -1057,7 +1327,7 @@ static void g_graph_cluster_define_links(GGraphCluster *cluster, GHashTable *all if (cluster->has_straight) { size_t center; - leaving_edge *tmp; + leaving_link_t *tmp; if (cluster->ba_count % 2 == 0) center = cluster->ba_count / 2 - 1; @@ -1070,7 +1340,7 @@ static void g_graph_cluster_define_links(GGraphCluster *cluster, GHashTable *all memmove(cluster->bottom_anchors + cluster->straight_index, cluster->bottom_anchors + cluster->straight_index + 1, - (center - cluster->straight_index) * sizeof(leaving_edge *)); + (center - cluster->straight_index) * sizeof(leaving_link_t *)); cluster->bottom_anchors[center] = tmp; @@ -1087,7 +1357,7 @@ static void g_graph_cluster_define_links(GGraphCluster *cluster, GHashTable *all memmove(cluster->bottom_anchors + center + 1, cluster->bottom_anchors + center, - (cluster->straight_index - center) * sizeof(leaving_edge *)); + (cluster->straight_index - center) * sizeof(leaving_link_t *)); cluster->bottom_anchors[center] = tmp; @@ -1111,6 +1381,323 @@ static void g_graph_cluster_define_links(GGraphCluster *cluster, GHashTable *all /****************************************************************************** * * +* Paramètres : cluster = graphique de blocs à manipuler. * +* * +* Description : Organise la disposition d'un ensemble de blocs basiques. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_graph_cluster_dispatch_x(GGraphCluster *cluster) +{ + size_t k; /* Boucle de parcours #1 */ + const graph_rank_t *rank; /* Accès confortable au rang */ + size_t j; /* Boucle de parcours #2 */ + gint start; /* Position initiale de départ */ + + /** + * A ce point, tous les blocs parents sont placés. + * On est donc en mesure de réorganiser les points d'arrivée + * des liens afin d'éviter les croisements : un lien qui vient + * de la gauche ne doit pas arriver tout à droite ! + */ + + qsort(cluster->top_anchors, cluster->ta_count, sizeof(incoming_link_t *), (__compar_fn_t)cmp_incoming_links); + + /** + * Il est désormais temps de placer tous les blocs de code inférieurs. + */ + + + for (k = 0; k < cluster->ranks_count; k++) + { + rank = &cluster->ranks[k]; + + /* Répartition autour d'une ligne verticale */ + if (cluster->has_straight) + { + start = g_graph_cluster_compute_leaving_link_position(cluster, cluster->straight_index); + + if (get_graph_rank(rank) < cluster->straight_level) + { + /* Répartition à gauche du lien */ + + for (j = rank->count; j > 0; j--) + if (*rank->clusters[j - 1]->parent_index < cluster->straight_index) + break; + + start -= HORIZONTAL_MARGIN / 2; + + _place_graph_rank_clusters(rank->clusters, j, start, -1); + + /* Répartition à droite du lien */ + + for (j = 0; j < rank->count; j++) + if (*rank->clusters[j]->parent_index > cluster->straight_index) + break; + + start += HORIZONTAL_MARGIN; + + _place_graph_rank_clusters(rank->clusters + j, rank->count - j, start, 1); + + } + + } + + /* Répartition homogène */ + else + dispatch_x_graph_rank(rank); + + } + +} + + +/****************************************************************************** +* * +* Paramètres : cluster = graphique de blocs à actualiser. * +* offset = décalage à appliquer. * +* * +* Description : Décalle vers la droite un ensemble de blocs basiques. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_graph_cluster_offset_x(GGraphCluster *cluster, gint offset) +{ + size_t i; /* Boucle de parcours */ + + cluster->alloc.x += offset; + + for (i = 0; i < cluster->ranks_count; i++) + offset_x_graph_rank(&cluster->ranks[i], offset); + +} + + +/****************************************************************************** +* * +* Paramètres : cluster = graphique de blocs à actualiser. * +* base = position ordonnée à appliquer. * +* * +* Description : Décalle vers le bas un ensemble de blocs basiques. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_graph_cluster_set_y(GGraphCluster *cluster, gint base) +{ + size_t i; /* Boucle de parcours #1 */ + const graph_rank_t *rank; /* Accès simplifié à la rangée */ + gint max; /* Hauteur maximale rencontrée */ + size_t j; /* Boucle de parcours #2 */ + GGraphCluster *sub; /* Sous-ensemble traité */ + GtkAllocation alloc; /* Allocation courante */ + + cluster->alloc.y = base; + + base += cluster->alloc.height; + + for (i = 0; i < cluster->ranks_count; i++) + { + rank = &cluster->ranks[i]; + + /* On ajoute l'espace vertical pour les lignes horizontales */ + + if (rank->r2l_count > rank->l2r_count) + max = rank->r2l_count; + else + max = rank->l2r_count; + + base += VERTICAL_MARGIN; + + /** + * Comme les liens purement verticaux n'entrainent pas de réservation, + * il n'y a potentiellement pas toujours d'espace à ajouter. + */ + + if (max > 0) + base += ((max - 1) * LINK_MARGIN); + + /* On ajoute l'espace requis pour l'affichage des blocs */ + + base += VERTICAL_MARGIN; + + max = 0; + + for (j = 0; j < rank->count; j++) + { + sub = rank->clusters[j]; + + g_graph_cluster_set_y(sub, base); + + g_graph_cluster_compute_needed_alloc(sub, &alloc); + + if ((alloc.y + alloc.height) > max) + max = alloc.y + alloc.height; + + } + + base = max; + + } + +} + + +/****************************************************************************** +* * +* Paramètres : cluster = encapsulation à consulter. * +* alloc = emplacement idéal pour l'affichage. * +* * +* Description : Détermine l'emplacement requis d'un ensemble de blocs. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +void g_graph_cluster_compute_needed_alloc(const GGraphCluster *cluster, GtkAllocation *alloc) +{ + size_t i; /* Boucle de parcours */ + + *alloc = cluster->alloc; + + for (i = 0; i < cluster->ranks_count; i++) + compute_graph_rank_needed_alloc(&cluster->ranks[i], (i + 1) == cluster->ranks_count, alloc); + +} + + +/****************************************************************************** +* * +* Paramètres : cluster = encapsulation à consulter. * +* * +* Description : Fournit le composant graphique principal du groupe. * +* * +* Retour : Composant graphique principal utilisé. * +* * +* Remarques : - * +* * +******************************************************************************/ + +GtkWidget *g_graph_cluster_get_widget(GGraphCluster *cluster) +{ + GtkWidget *result; + + result = cluster->display; + + g_object_ref(G_OBJECT(result)); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : cluster = encapsulation à traiter. * +* display = support de destination finale. * +* * +* Description : Dispose chaque noeud sur la surface de destination donnée. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +void g_graph_cluster_place(GGraphCluster *cluster, GtkGraphDisplay *display) +{ + size_t i; /* Boucle de parcours #1 */ + size_t j; /* Boucle de parcours #2 */ + + g_object_ref(G_OBJECT(cluster->display)); + gtk_graph_display_put(display, cluster->display, &cluster->alloc); + + for (i = 0; i < cluster->ta_count; i++) + { + g_object_ref(G_OBJECT(cluster->top_anchors[i]->edge)); + gtk_graph_display_add_edge(display, cluster->top_anchors[i]->edge); + } + + for (i = 0; i < cluster->ranks_count; i++) + for (j = 0; j < cluster->ranks[i].count; j++) + g_graph_cluster_place(cluster->ranks[i].clusters[j], display); + +} + + + + + + + + +////////////////////////////////////////////////////////// + + + + + + +/****************************************************************************** +* * +* Paramètres : cluster = graphique de blocs à consulter ou remonter. * +* first = première instruction du bloc basique recherché. * +* * +* Description : Recherche le bloc basique à l'extrémité d'un lien. * +* * +* Retour : Bloc graphique de destination pour un lien ou NULL si échec. * +* * +* Remarques : - * +* * +******************************************************************************/ +#if 0 +static GGraphCluster *g_graph_cluster_find_lower_dest_cluster(const GGraphCluster *cluster, const GArchInstruction *first) +{ + GGraphCluster *result; /* Trouvaille à retourner */ + size_t i; /* Boucle de parcours #1 */ + const graph_rank_t *rank; /* Confort d'accès */ + size_t j; /* Boucle de parcours #2 */ + GArchInstruction *instr; /* Instruction à comparer */ + + result = NULL; + + for (i = 0; i < cluster->ranks_count && result == NULL; i++) + { + rank = &cluster->ranks[i]; + + for (j = 0; j < rank->count && result == NULL; j++) + { + g_basic_block_get_boundaries(rank->clusters[j]->block, &instr, NULL); + + if (instr == first) + result = rank->clusters[j]; + + } + + } + + return result; + +} +#endif + + + +/****************************************************************************** +* * * Paramètres : cluster = graphique de blocs à consulter. * * index = indice du lien à considérer. * * * @@ -1269,7 +1856,7 @@ static void g_graph_cluster_compute_link_x_positions(GGraphCluster *cluster) static void g_graph_cluster_book_hspace_for_links(GGraphCluster *cluster) { size_t i; /* Boucle de parcours #1 */ - graph_rank *rank; /* Rangée à manipuler */ + graph_rank_t *rank; /* Rangée à manipuler */ size_t j; /* Boucle de parcours #2 */ GGraphCluster *sub; /* Bloc inférieur à manipuler */ size_t k; /* Boucle de parcours #3 */ @@ -1398,7 +1985,7 @@ static void g_graph_cluster_compute_link_y_positions(GGraphCluster *cluster) { gint y; /* Ordonnée d'application */ size_t i; /* Boucle de parcours #1 */ - incoming_edge *incoming; /* Raccourci pour le confort */ + incoming_link_t *incoming; /* Raccourci pour le confort */ size_t j; /* Boucle de parcours #2 */ /* Du côté des départs... */ @@ -1470,36 +2057,9 @@ static void g_graph_cluster_resolve_links(const GGraphCluster *cluster) - - - - - - - - - - - - - -/* Liste de blocs restants à traiter */ -typedef struct _pending_blocks -{ - size_t count; /* Taille de la liste */ - GCodeBlock *list[0]; /* Liste de blocs à traiter */ - -} pending_blocks; - - - - - -/* Met en place un ensemble de blocs sous forme graphique. */ -static GGraphCluster *setup_graph_clusters(GLoadedBinary *, const GBlockList *, size_t , segcnt_list *, pending_blocks *, GHashTable *); - - - +/* ---------------------------------------------------------------------------------- */ +/* CALCUL DE REPARTITION DE BLOCS */ +/* ---------------------------------------------------------------------------------- */ /****************************************************************************** @@ -1645,7 +2205,7 @@ static GGraphCluster *setup_graph_clusters(GLoadedBinary *binary, const GBlockLi sub = setup_graph_clusters(binary, list, next, highlighted, pending, all); - g_graph_cluster_add_sub(result, sub, block); + g_graph_cluster_add_sub(result, sub); } @@ -1661,14 +2221,11 @@ static GGraphCluster *setup_graph_clusters(GLoadedBinary *binary, const GBlockLi } - - - /****************************************************************************** * * -* Paramètres : blocXXXXXXXXXXXXXXXXXXXXks = ensemble des blocs basiques déjà découpés. * -* views = morceaux de codXXXXXXXXXXXXXXXXXxe à afficher de façon organisée. * -* count = quantité de ces morceaux de code.XXXXXXXXXXXXXXXXXX * +* Paramètres : binary = binaire charger dont le code est à représenter.* +* list = ensemble de blocs basiques à manipuler. * +* highlighted = gestionnaire de surbrillance pour segments. * * * * Description : Construit un graphique à partir de blocs basiques. * * * @@ -1686,12 +2243,15 @@ GGraphCluster *bootstrap_graph_cluster(GLoadedBinary *binary, const GBlockList * pending_blocks *pending; /* Suivi des blocs à traiter */ GtkAllocation needed; /* Taille requise */ + /* Création des éléments */ all = g_hash_table_new(NULL, NULL); count = g_block_list_count_blocks(list); - pending = (pending_blocks *)calloc(1, sizeof(pending_blocks) + count * sizeof(GCodeBlock *)); + pending = malloc(sizeof(pending_blocks) + count * sizeof(GCodeBlock *)); + + pending->count = 0; result = setup_graph_clusters(binary, list, 0, highlighted, pending, all); @@ -1699,12 +2259,6 @@ GGraphCluster *bootstrap_graph_cluster(GLoadedBinary *binary, const GBlockList * g_graph_cluster_define_links(result, all); - - //show_tree(result, 0); - //printf("--------------\n"); - - - /* Positionnements dans l'espace */ g_graph_cluster_dispatch_x(result); diff --git a/src/gtkext/graph/cluster.h b/src/gtkext/graph/cluster.h index 11ce66e..00c6d82 100644 --- a/src/gtkext/graph/cluster.h +++ b/src/gtkext/graph/cluster.h @@ -25,13 +25,15 @@ #define _GTKEXT_GRAPH_CLUSTER_H - #include "../gtkgraphdisplay.h" #include "../../analysis/binary.h" #include "../../analysis/disass/block.h" +/* -------------------------- DEFINITION D'UN CHEF DE FILE -------------------------- */ + + #define G_TYPE_GRAPH_CLUSTER g_graph_cluster_get_type() #define G_GRAPH_CLUSTER(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_GRAPH_CLUSTER, GGraphCluster)) #define G_IS_GRAPH_CLUSTER(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_GRAPH_CLUSTER)) @@ -64,10 +66,11 @@ void g_graph_cluster_place(GGraphCluster *, GtkGraphDisplay *); +/* ------------------------- CALCUL DE REPARTITION DE BLOCS ------------------------- */ -GGraphCluster *bootstrap_graph_cluster(GLoadedBinary *binary, const GBlockList *list, segcnt_list *highlighted); - +/* Construit un graphique à partir de blocs basiques. */ +GGraphCluster *bootstrap_graph_cluster(GLoadedBinary *, const GBlockList *, segcnt_list *); diff --git a/src/gtkext/graph/edge.h b/src/gtkext/graph/edge.h index 4dbc195..d000eb5 100644 --- a/src/gtkext/graph/edge.h +++ b/src/gtkext/graph/edge.h @@ -75,6 +75,9 @@ GGraphEdge *_g_graph_edge_new(const GdkPoint *, const GdkPoint **, size_t, const #define g_graph_edge_new_false(start, y, end) \ _g_graph_edge_new(start, (const GdkPoint *[]) { y }, 1, end, EGC_RED) +#define g_graph_edge_new_loop(start, yt, yb, end) \ + _g_graph_edge_new(start, (const GdkPoint *[]) { yt, yb }, 2, end, EGC_BLUE) + /* Fournit les abscisses des points extrèmes de la ligne. */ void g_graph_edge_get_x_borders(const GGraphEdge *, gint *, gint *); |