summaryrefslogtreecommitdiff
path: root/src/gtkext
diff options
context:
space:
mode:
authorCyrille Bagard <nocbos@gmail.com>2012-11-02 15:50:07 (GMT)
committerCyrille Bagard <nocbos@gmail.com>2012-11-02 15:50:07 (GMT)
commitf5df6496fa50927d3d274c939a888afde652b7ad (patch)
tree281dbfdfdcb8765fea7036af274c63fb5acde8ff /src/gtkext
parentc3aba0893c29cc098c029306fd7a4c8c1fa2eee2 (diff)
Improved the computing and the rendering of the graphic view.
git-svn-id: svn://svn.gna.org/svn/chrysalide/trunk@277 abbe820e-26c8-41b2-8c08-b7b2b41f8b0a
Diffstat (limited to 'src/gtkext')
-rw-r--r--src/gtkext/Makefile.am5
-rwxr-xr-xsrc/gtkext/graph/Makefile.am18
-rw-r--r--src/gtkext/graph/dot.c267
-rw-r--r--src/gtkext/graph/dot.h51
-rw-r--r--src/gtkext/graph/layout.c229
-rw-r--r--src/gtkext/graph/layout.h41
-rw-r--r--src/gtkext/graph/node.c353
-rw-r--r--src/gtkext/graph/node.h74
-rw-r--r--src/gtkext/gtkgraphview.c8
-rw-r--r--src/gtkext/gtklinkrenderer.c100
-rw-r--r--src/gtkext/gtklinkrenderer.h14
-rw-r--r--src/gtkext/gtkviewpanel.c7
12 files changed, 1155 insertions, 12 deletions
diff --git a/src/gtkext/Makefile.am b/src/gtkext/Makefile.am
index f590693..863c7a8 100644
--- a/src/gtkext/Makefile.am
+++ b/src/gtkext/Makefile.am
@@ -18,6 +18,9 @@ libgtkext_la_SOURCES = \
iodamarshal.h iodamarshal.c \
support.h support.c
+libgtkext_la_LIBADD = \
+ graph/libgtkextgraph.la
+
libgtkext_la_LDFLAGS =
@@ -27,6 +30,8 @@ AM_CPPFLAGS =
AM_CFLAGS = $(DEBUG_CFLAGS) $(WARNING_FLAGS) $(COMPLIANCE_FLAGS)
+SUBDIRS = graph
+
iodamarshal.h: iodamarshal.list
glib-genmarshal --header $< > $@
diff --git a/src/gtkext/graph/Makefile.am b/src/gtkext/graph/Makefile.am
new file mode 100755
index 0000000..a631a90
--- /dev/null
+++ b/src/gtkext/graph/Makefile.am
@@ -0,0 +1,18 @@
+
+noinst_LTLIBRARIES = libgtkextgraph.la
+
+libgtkextgraph_la_SOURCES = \
+ dot.h dot.c \
+ layout.h layout.c \
+ node.h node.c
+
+libgtkextgraph_la_LDFLAGS =
+
+
+INCLUDES = $(LIBGTK_CFLAGS) $(LIBXML_CFLAGS) $(LIBGRAPH_CFLAGS)
+
+AM_CPPFLAGS =
+
+AM_CFLAGS = $(DEBUG_CFLAGS) $(WARNING_FLAGS) $(COMPLIANCE_FLAGS)
+
+SUBDIRS =
diff --git a/src/gtkext/graph/dot.c b/src/gtkext/graph/dot.c
new file mode 100644
index 0000000..396aa93
--- /dev/null
+++ b/src/gtkext/graph/dot.c
@@ -0,0 +1,267 @@
+
+/* OpenIDA - Outil d'analyse de fichiers binaires
+ * dot.c - interactions avec le système dot
+ *
+ * Copyright (C) 2009-2012 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 <http://www.gnu.org/licenses/>.
+ */
+
+
+#include "dot.h"
+
+
+#include <malloc.h>
+#include <graphviz/gvc.h>
+#include <graphviz/types.h>
+
+
+
+/* Graphique selon Graphviz */
+struct _graph_layout
+{
+ GVC_t *context; /* Contexte pour Graphviz */
+ graph_t *graph; /* Graphique construit */
+
+};
+
+
+
+/******************************************************************************
+* *
+* Paramètres : cmds = description textuelle du graphique à représenter. *
+* *
+* Description : Charge un graphique à partir de sa description. *
+* *
+* Retour : Bilan de l'opération. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+graph_layout *create_graph_layout(char *cmds)
+{
+ graph_layout *result; /* Composants à retourner */
+ int ret; /* Bilan d'un appel */
+
+ result = (graph_layout *)calloc(1, sizeof(graph_layout));
+
+ result->context = gvContext();
+ result->graph = agmemread(cmds);
+
+ if (result->graph == NULL) goto cdl_error;
+
+
+
+ //printf("CMDS =======\n%s\n\n=================\n", cmds);
+
+ ret = gvLayout(result->context, result->graph, "dot");
+ if (ret != 0) goto cdl_error;
+
+
+ //printf("ret = %d\n", ret);
+
+ /*
+ ret = gvLayoutJobs(result->context, result->graph);
+ printf("ret = %d\n", ret);
+ ret = gvRenderJobs(result->context, result->graph);
+ printf("ret = %d\n", ret);
+ */
+
+ ret = gvRender(result->context, result->graph, "dot", NULL);
+ if (ret != 0) goto cdl_error;
+
+
+
+ //ret = gvRender(result->context, result->graph, "plain", NULL);
+
+ //printf("ret = %d\n", ret);
+
+
+
+
+
+ return result;
+
+ cdl_error:
+
+ delete_graph_layout(result);
+
+ return NULL;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : layout = graphique à supprimer de la mémoire. *
+* *
+* Description : Décharge un graphique. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+void delete_graph_layout(graph_layout *layout)
+{
+ if (layout->graph != NULL)
+ {
+ gvFreeLayout(layout->context, layout->graph);
+ agclose(layout->graph);
+ }
+
+ gvFreeContext(layout->context);
+
+ free(layout);
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : layout = graphique à supprimer de la mémoire. *
+* view = support de destination. *
+* nodes = liste de noeuds à traiter. *
+* count = taille de la liste. *
+* *
+* Description : Place tous les éléments du graphique à l'écran. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+void place_nodes_of_graph_layout(const graph_layout *layout, GtkGraphView *view, GGraphNode **nodes, size_t count)
+{
+ int height; /* Hauteur du graphique */
+ node_t *iter; /* Boucle de parcours */
+ GGraphNode *node; /* Intermédiaire concerné */
+
+ height = GD_bb(layout->graph).UR.y;
+
+ for (iter = agfstnode(layout->graph); iter != NULL; iter = agnxtnode(layout->graph, iter))
+ {
+ node = find_graph_node_by_name(nodes, count, iter->name);
+ g_graph_node_place(node, view, iter->u.coord.x, height - iter->u.coord.y);
+ }
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : layout = graphique à supprimer de la mémoire. *
+* count = nombre d'éléments mis en place. *
+* nodes = liste de noeuds à consulter. *
+* ncount = taille de la liste des noeuds. *
+* *
+* Description : Charge la définition de tous les liens graphiques. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+GtkLinkRenderer **create_links_from_graph_layout(const graph_layout *layout, size_t *count, GGraphNode **nodes, size_t ncount)
+{
+ GtkLinkRenderer **result; /* Liste à retourner */
+ int height; /* Hauteur du graphique */
+ node_t *niter; /* Boucle de parcours #1 */
+ edge_t *eiter; /* Boucle de parcours #2 */
+ GdkPoint *points; /* Points de ligne relus */
+ size_t points_count; /* Nombre de ces points */
+ splines *lines; /* Lignes déjà tracées */
+ GGraphNode *node; /* Noeud rattaché */
+ int i; /* Boucle de parcours #3 */
+ int k; /* Boucle de parcours #4 */
+ bezier *bez; /* Courbe à reproduire */
+ Agsym_t *attrib; /* Couleur d'un lien */
+ LinkColor color; /* Couleur d'impression */
+
+ result = NULL;
+ *count = 0;
+
+ height = GD_bb(layout->graph).UR.y;
+
+ for (niter = agfstnode(layout->graph); niter != NULL; niter = agnxtnode(layout->graph, niter))
+ for (eiter = agfstout(layout->graph, niter); eiter != NULL; eiter = agnxtout(layout->graph, eiter))
+ {
+ points = NULL;
+ points_count = 0;
+
+ lines = ED_spl(eiter);
+
+ /* Raccordement au point de départ */
+
+ node = find_graph_node_by_name(nodes, ncount, agtail(eiter)->name);
+
+ g_graph_node_connect(node,
+ lines->list[0].list[0].x,
+ height - lines->list[0].list[0].y,
+ &points, &points_count);
+
+ /* Tracé du lien... */
+
+ for (i = 0; i < lines->size; i++)
+ {
+ bez = &lines->list[i];
+
+ points = (GdkPoint *)realloc(points, (points_count + bez->size) * sizeof(GdkPoint));
+
+ for (k = 0; k < bez->size; k++)
+ {
+ points[points_count + k].x = bez->list[k].x;
+ points[points_count + k].y = height - bez->list[k].y;
+ }
+
+ points_count += bez->size;
+
+ }
+
+ /* Raccordement au point d'arrivée */
+
+ node = find_graph_node_by_name(nodes, ncount, aghead(eiter)->name);
+
+ g_graph_node_connect(node,
+ bez->list[k - 1].x,
+ height - bez->list[k - 1].y,
+ &points, &points_count);
+
+ /* Détermination de la couleur */
+
+ attrib = agfindedgeattr(agraphof(agtail(eiter)), "color");
+
+ result = (GtkLinkRenderer **)realloc(result, ++(*count) * sizeof(GtkLinkRenderer *));
+
+ if (eiter->attr[attrib->index][0] == 'g') /* "green" */
+ color = LKC_GREEN;
+ else if (eiter->attr[attrib->index][0] == 'r') /* "red" */
+ color = LKC_RED;
+ else
+ color = LKC_DEFAULT;
+
+ result[*count - 1] = GTK_LINK_RENDERER(gtk_link_renderer_new(color,
+ points, points_count));
+
+ }
+
+ return result;
+
+}
diff --git a/src/gtkext/graph/dot.h b/src/gtkext/graph/dot.h
new file mode 100644
index 0000000..d610e1b
--- /dev/null
+++ b/src/gtkext/graph/dot.h
@@ -0,0 +1,51 @@
+
+/* OpenIDA - Outil d'analyse de fichiers binaires
+ * dot.h - prototypes pour les interactions avec le système dot
+ *
+ * Copyright (C) 2009 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 <http://www.gnu.org/licenses/>.
+ */
+
+
+#ifndef _GRAPH_DOT_H
+#define _GRAPH_DOT_H
+
+
+#include "node.h"
+#include "../gtklinkrenderer.h"
+
+
+
+/* Graphique selon Graphviz */
+typedef struct _graph_layout graph_layout;
+
+
+/* Charge un graphique à partir de sa description. */
+graph_layout *create_graph_layout(char *);
+
+/* Décharge un graphique. */
+void delete_graph_layout(graph_layout *);
+
+/* Place tous les éléments du graphique à l'écran. */
+void place_nodes_of_graph_layout(const graph_layout *, GtkGraphView *, GGraphNode **, size_t);
+
+/* Charge la définition de tous les liens graphiques. */
+GtkLinkRenderer **create_links_from_graph_layout(const graph_layout *, size_t *, GGraphNode **, size_t);
+
+
+
+#endif /* _GRAPH_DOT_H */
diff --git a/src/gtkext/graph/layout.c b/src/gtkext/graph/layout.c
new file mode 100644
index 0000000..69e32cc
--- /dev/null
+++ b/src/gtkext/graph/layout.c
@@ -0,0 +1,229 @@
+
+/* OpenIDA - Outil d'analyse de fichiers binaires
+ * layout.c - mise en place de graphique
+ *
+ * Copyright (C) 2009-2012 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 <http://www.gnu.org/licenses/>.
+ */
+
+
+#include "layout.h"
+
+
+#include <malloc.h>
+#include <string.h>
+#include <gtk/gtkfixed.h>
+
+
+#include "dot.h"
+#include "node.h"
+#include "../gtkbufferview.h"
+#include "../../analysis/binary.h"
+#include "../../common/extstr.h"
+
+
+
+/* Taille maximale des descriptions de liens */
+#define LINKS_DESC_LEN 128
+
+
+/* Etablit tous les liens entre les différents morceaux de code. */
+static char *complete_graph_links(const GtkGraphView *, GtkViewPanel **, size_t, char *);
+
+
+
+/******************************************************************************
+* *
+* Paramètres : view = support où placer les différents éléments. *
+* views = morceaux de code à afficher de façon organisée. *
+* count = quantité de ces morceaux de code. *
+* *
+* Description : Dispose une série de morceaux d'affichage en graphique. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool build_graph_view(GtkGraphView *view, GtkViewPanel **views, size_t count)
+{
+ GGraphNode **nodes; /* Intermédiaires en place */
+ size_t i; /* Boucle de parcours */
+ char *cmds; /* Description à envoyer à dot */
+ graph_layout *layout; /* Graphique construit */
+ GtkLinkRenderer **links; /* Liens graphiques construits */
+ size_t links_count; /* Quantité de ces liens */
+
+ /* Création de la glue */
+
+ nodes = (GGraphNode **)calloc(count, sizeof(GGraphNode *));
+
+ for (i = 0; i < count; i++)
+ nodes[i] = g_graph_node_new(GTK_WIDGET(views[i]));
+
+ /* Définition du graphique */
+
+ cmds = strdup("digraph G {\noverlap=false;\n splines=ortho;\n compound=true;\n");
+
+ for (i = 0; i < count; i++)
+ cmds = g_graph_node_register_for_dot(nodes[i], cmds);
+
+ cmds = complete_graph_links(view, views, count, cmds);
+
+ cmds = stradd(cmds, "}");
+
+ layout = create_graph_layout(cmds);
+
+ /* Affichage du graphique */
+
+ place_nodes_of_graph_layout(layout, view, nodes, count);
+
+ links = create_links_from_graph_layout(layout, &links_count, nodes, count);
+ gtk_graph_view_attach_links(view, links, links_count);
+
+ gtk_widget_queue_draw(GTK_WIDGET(view));
+
+ delete_graph_layout(layout);
+
+ /* TODO : free nodes */
+
+ return true;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : view = support contenant les différentes lignes. *
+* views = morceaux de code à afficher de façon organisée. *
+* count = quantité de ces morceaux de code. *
+* desc = description du graphique à compléter. [OUT] *
+* *
+* Description : Etablit tous les liens entre les différents morceaux de code.*
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static char *complete_graph_links(const GtkGraphView *view, GtkViewPanel **views, size_t count, char *desc)
+{
+ GLoadedBinary *binary; /* Binaire rattaché aux vues */
+ GArchInstruction *instrs; /* Instructions pour assembleur*/
+ GBufferView *buffer; /* Tampon d'une partie de code */
+ vmpa_t end; /* Adresse finale du tampon */
+ size_t i; /* Boucle de parcours #1 */
+ GArchInstruction *last; /* Dernière instruc. d'un bloc */
+ vmpa_t addr; /* Addresse d'instruction */
+ GArchInstruction **dests; /* Instr. visée par une autre */
+ InstructionLinkType *types; /* Type de lien entre lignes */
+ size_t dcount; /* Nombre de liens de dest. */
+ size_t j; /* Boucle de parcours #2 */
+ size_t k; /* Boucle de parcours #3 */
+ char cmd[LINKS_DESC_LEN]; /* Tampon pour l'ajout de liens*/
+ GArchInstruction *next; /* Instruction suivante */
+
+ if (count == 0)
+ return desc;
+
+ binary = gtk_view_panel_get_binary(views[0]);
+ instrs = g_loaded_binary_get_instructions(binary);
+
+ for (i = 0; i < count; i++)
+ {
+ buffer = gtk_buffer_view_get_buffer(GTK_BUFFER_VIEW(views[i]));
+ g_buffer_view_get_restrictions(buffer, NULL, &end);
+
+ last = g_arch_instruction_find_by_address(instrs, end, true);
+ g_arch_instruction_get_location(last, NULL, NULL, &addr);
+
+ if (g_arch_instruction_has_destinations(last))
+ {
+ dcount = g_arch_instruction_get_destinations(last, &dests, &types);
+
+ for (j = 0; j < dcount; j++)
+ {
+ g_arch_instruction_get_location(dests[j], NULL, NULL, &addr);
+
+ for (k = 0; k < count; k++)
+ if (gtk_view_panel_contain_address(views[k], addr))
+ break;
+
+ if (k < count)
+ switch (types[j])
+ {
+ case ILT_JUMP:
+ snprintf(cmd, LINKS_DESC_LEN,
+ "_%p:s -> _%p:n [ltail=cluster_%p, lhead=cluster_%p];\n",
+ views[i], views[k], views[i], views[k]);
+ desc = stradd(desc, cmd);
+ break;
+
+ case ILT_JUMP_IF_TRUE:
+ snprintf(cmd, LINKS_DESC_LEN,
+ "_%p:s -> _%p:n [ltail=cluster_%p, lhead=cluster_%p, " \
+ "color=green];\n",
+ views[i], views[k], views[i], views[k]);
+ desc = stradd(desc, cmd);
+ break;
+
+ case ILT_JUMP_IF_FALSE:
+ snprintf(cmd, LINKS_DESC_LEN,
+ "_%p:s -> _%p:n [ltail=cluster_%p, lhead=cluster_%p, " \
+ "color=red];\n",
+ views[i], views[k], views[i], views[k]);
+ desc = stradd(desc, cmd);
+ break;
+
+ default:
+ break;
+
+ }
+
+ }
+
+ }
+
+ /* Sinon on suit le flux normal */
+ else
+ {
+ next = g_arch_instruction_get_next_iter(instrs, last, VMPA_MAX);
+ if (next == NULL) continue;
+
+ g_arch_instruction_get_location(next, NULL, NULL, &addr);
+
+ for (k = 0; k < count; k++)
+ if (gtk_view_panel_contain_address(views[k], addr))
+ break;
+
+ if (k < count)
+ {
+ snprintf(cmd, LINKS_DESC_LEN,
+ "_%p:s -> _%p:n [ltail=cluster_%p, lhead=cluster_%p];\n",
+ views[i], views[k], views[i], views[k]);
+ desc = stradd(desc, cmd);
+ }
+
+ }
+
+ }
+
+ return desc;
+
+}
diff --git a/src/gtkext/graph/layout.h b/src/gtkext/graph/layout.h
new file mode 100644
index 0000000..ffb227f
--- /dev/null
+++ b/src/gtkext/graph/layout.h
@@ -0,0 +1,41 @@
+
+/* OpenIDA - Outil d'analyse de fichiers binaires
+ * layout.h - prototypes pour la mise en place de graphique
+ *
+ * Copyright (C) 2009-2012 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 <http://www.gnu.org/licenses/>.
+ */
+
+
+#ifndef _GRAPH_LAYOUT_H
+#define _GRAPH_LAYOUT_H
+
+
+#include <stdbool.h>
+
+
+#include "../gtkgraphview.h"
+#include "../gtkviewpanel.h"
+
+
+
+/* Dispose une série de morceaux d'affichage en graphique. */
+bool build_graph_view(GtkGraphView *, GtkViewPanel **, size_t);
+
+
+
+#endif /* _GRAPH_LAYOUT_H */
diff --git a/src/gtkext/graph/node.c b/src/gtkext/graph/node.c
new file mode 100644
index 0000000..f3e6352
--- /dev/null
+++ b/src/gtkext/graph/node.c
@@ -0,0 +1,353 @@
+
+/* OpenIDA - Outil d'analyse de fichiers binaires
+ * node.c - éléments de graphiques chez dot
+ *
+ * Copyright (C) 2009-2012 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 <http://www.gnu.org/licenses/>.
+ */
+
+
+#include "node.h"
+
+
+#include <malloc.h>
+#include <stdio.h>
+#include <string.h>
+
+
+#include "../../common/extstr.h"
+
+
+
+/* -------------------------- GESTION DES NOEUDS A L'UNITE -------------------------- */
+
+
+/* Intermédiaire entre le noeud dot et la bribe de code (instance) */
+struct _GGraphNode
+{
+ GObject parent; /* A laisser en premier */
+
+ GtkWidget *view; /* Morceau de code représenté */
+ char *name; /* Adresse sous forme humaine */
+
+ GtkAllocation alloc; /* Emplacement du bloc rattaché*/
+
+};
+
+
+/* Intermédiaire entre le noeud dot et la bribe de code (classe) */
+struct _GGraphNodeClass
+{
+ GObjectClass parent; /* A laisser en premier */
+
+ double dpi_x; /* Résolution en abscisse */
+ double dpi_y; /* Résolution en ordonnée */
+
+};
+
+
+/* Initialise la classe des intermédiaires avec les noeuds dot. */
+static void g_graph_node_class_init(GGraphNodeClass *);
+
+/* Initialise la classe des intermédiaires avec les noeuds dot. */
+static void g_graph_node_init(GGraphNode *);
+
+
+
+/* ---------------------------------------------------------------------------------- */
+/* GESTION DES NOEUDS A L'UNITE */
+/* ---------------------------------------------------------------------------------- */
+
+
+/* Indique le type définit par la GLib pour le noeud. */
+G_DEFINE_TYPE(GGraphNode, g_graph_node, G_TYPE_OBJECT);
+
+
+/******************************************************************************
+* *
+* Paramètres : klass = classe à initialiser. *
+* *
+* Description : Initialise la classe des intermédiaires avec les noeuds dot. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_graph_node_class_init(GGraphNodeClass *klass)
+{
+ GdkScreen *screen; /* Ecran par défaut */
+ gint width; /* Largeur d'écran en pixels */
+ gint height; /* Hauteur d'écran en pixels */
+ gint width_mm; /* Largeur d'écran en mm. */
+ gint height_mm; /* Hauteur d'écran en mm. */
+
+ screen = gdk_screen_get_default();
+
+ width = gdk_screen_get_width(screen);
+ height = gdk_screen_get_height(screen);
+
+ width_mm = gdk_screen_get_width_mm(screen);
+ height_mm = gdk_screen_get_height_mm(screen);
+
+ /**
+ * Il y a 2.54 centimètres, soit 25.4 millimètres, dans un pouce.
+ * On a donc :
+ *
+ * dpi = N pixels / (M millimètres / (25.4 millimètres / 1 pouce))
+ * = N pixels / (M pouces / 25.4)
+ * = N * 25.4 pixels / M pouces
+ *
+ */
+
+ if (width_mm > 0 && height_mm > 0)
+ {
+ klass->dpi_x = (width * 25.4) / (double)width_mm;
+ klass->dpi_y = (height * 25.4) / (double)height_mm;
+ }
+ else
+ {
+ klass->dpi_x = 96;
+ klass->dpi_y = 96;
+ }
+
+
+ klass->dpi_x = 72;
+ klass->dpi_y = 72;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : node = instance à initialiser. *
+* *
+* Description : Initialise la classe des intermédiaires avec les noeuds dot. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_graph_node_init(GGraphNode *node)
+{
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : view = morceau d'affichage à représenter. *
+* *
+* Description : Constitue un intermédiaire entre un noeud dot et du code. *
+* *
+* Retour : Adresse de la structure mise en place. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+GGraphNode *g_graph_node_new(GtkWidget *view)
+{
+ GGraphNode *result; /* Structure à retourner */
+ size_t len; /* Taille du nom */
+
+ result = g_object_new(G_TYPE_GRAPH_NODE, NULL);
+
+ result->view = view;
+
+ len = 3 + sizeof(GtkWidget *) * 2 + 1;
+
+ result->name = (char *)calloc(len, sizeof(char));
+ snprintf(result->name, len, "_%p", result->view);
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : node = intermédiaire à consulter. *
+* cmds = description pour dot à compléter. *
+* *
+* Description : Déclare l'intermédiaire en tant que noeud pour dot. *
+* *
+* Retour : Description dûment complétée. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+char *g_graph_node_register_for_dot(const GGraphNode *node, char *cmds)
+{
+ GtkRequisition requisition; /* Taille à l'écran requise */
+ char buffer[128];
+
+ gtk_widget_size_request(node->view, &requisition);
+
+ snprintf(buffer, 128, " subgraph cluster%s {\n", node->name);
+ cmds = stradd(cmds, buffer);
+
+ cmds = stradd(cmds, " style=invisible;\n");
+
+ cmds = stradd(cmds, " ");
+ cmds = stradd(cmds, node->name);
+ cmds = stradd(cmds, " [shape=box, fixedsize ");
+
+ snprintf(buffer, 128, ", width=\"%g\"",
+ requisition.width / G_GRAPH_NODE_GET_CLASS(node)->dpi_x);
+ cmds = stradd(cmds, buffer);
+
+ snprintf(buffer, 128, ", height=\"%g\"",
+ requisition.height / G_GRAPH_NODE_GET_CLASS(node)->dpi_y);
+ cmds = stradd(cmds, buffer);
+
+ cmds = stradd(cmds, "];\n");
+
+ cmds = stradd(cmds, " }\n");
+
+ return cmds;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : node = intermédiaire à consulter. *
+* view = support de destination. *
+* x = abscisse du point d'intégration. *
+* y = ordonnée du point d'intégration. *
+* *
+* Description : Place le morceau de code de l'intermédiaire à l'écran. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+void g_graph_node_place(GGraphNode *node, GtkGraphView *view, gint x, gint y)
+{
+ GtkRequisition requisition; /* Taille à l'écran actuelle */
+
+ gtk_widget_size_request(node->view, &requisition);
+
+ x -= requisition.width / 2;
+ y -= requisition.height / 2;
+
+ gtk_graph_view_put(view, node->view, x, y);
+
+ node->alloc.x = x;
+ node->alloc.y = y;
+ node->alloc.width = requisition.width;
+ node->alloc.height = requisition.height;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : node = intermédiaire à consulter. *
+* x = abscisse du point à relier. *
+* y = ordonnée du point à relier. *
+* points = liste de points à mettre à jour. [OUT] *
+* count = taille de cette même liste. [OUT] *
+* *
+* Description : Etablit une jonction ferme avec un noeud. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+void g_graph_node_connect(const GGraphNode *node, gint x, gint y, GdkPoint **points, size_t *count)
+{
+ const GtkAllocation *alloc; /* Emplacement du bloc rattaché*/
+
+ alloc = &node->alloc;
+
+ *points = (GdkPoint *)realloc(*points, ++(*count) * sizeof(GdkPoint));
+
+ /* Si le point est sur la gauche... */
+ if (alloc->y <= y && y < (alloc->y + alloc->height) && x < alloc->x)
+ {
+ (*points)[*count - 1].x = alloc->x;
+ (*points)[*count - 1].y = y;
+ }
+
+ /* Si le point est sur la droite... */
+ else if (alloc->y <= y && y < (alloc->y + alloc->height) && x > (alloc->x + alloc->width))
+ {
+ (*points)[*count - 1].x = alloc->x + alloc->width;
+ (*points)[*count - 1].y = y;
+ }
+
+ /* Si le point est au dessus... */
+ else if (alloc->x <= x && x < (alloc->x + alloc->width) && y < alloc->y)
+ {
+ (*points)[*count - 1].x = x;
+ (*points)[*count - 1].y = alloc->y;
+ }
+
+ /* Si le point est en dessous... */
+ else if (alloc->x <= x && x < (alloc->x + alloc->width) && y > (alloc->y + alloc->height))
+ {
+ (*points)[*count - 1].x = x;
+ (*points)[*count - 1].y = alloc->y + alloc->height;
+ }
+
+}
+
+
+
+/* ---------------------------------------------------------------------------------- */
+/* MANIPULATION D'ENSEMBLES DE NOEUDS */
+/* ---------------------------------------------------------------------------------- */
+
+
+/******************************************************************************
+* *
+* Paramètres : nodes = liste de noeuds à parcourir. *
+* count = taille de la liste. *
+* target = nom du noeud recherché. *
+* *
+* Description : Recherche un noeud donné dans une série de noeuds. *
+* *
+* Retour : Noeud trouvé ou NULL si aucun. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+GGraphNode *find_graph_node_by_name(GGraphNode **nodes, size_t count, const char *target)
+{
+ GGraphNode *result; /* Trouvaille à remonter */
+ size_t i; /* Boucle de parcours */
+
+ result = NULL;
+
+ for (i = 0; i < count && result == NULL; i++)
+ if (strcmp(nodes[i]->name, target) == 0)
+ result = nodes[i];
+
+ return result;
+
+}
diff --git a/src/gtkext/graph/node.h b/src/gtkext/graph/node.h
new file mode 100644
index 0000000..515c92b
--- /dev/null
+++ b/src/gtkext/graph/node.h
@@ -0,0 +1,74 @@
+
+/* OpenIDA - Outil d'analyse de fichiers binaires
+ * node.h - prototypes pour les éléments de graphiques chez dot
+ *
+ * Copyright (C) 2009-2012 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 <http://www.gnu.org/licenses/>.
+ */
+
+
+#ifndef _GRAPH_NODE_H
+#define _GRAPH_NODE_H
+
+
+#include "../gtkgraphview.h"
+
+
+
+/* -------------------------- GESTION DES NOEUDS A L'UNITE -------------------------- */
+
+
+#define G_TYPE_GRAPH_NODE g_graph_node_get_type()
+#define G_GRAPH_NODE(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), g_graph_node_get_type(), GGraphNode))
+#define G_IS_GRAPH_NODE(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), g_graph_node_get_type()))
+#define G_GRAPH_NODE_GET_IFACE(inst) (G_TYPE_INSTANCE_GET_INTERFACE((inst), g_graph_node_get_type(), GGraphNodeIface))
+#define G_GRAPH_NODE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_GRAPH_NODE, GGraphNodeClass))
+
+
+/* Intermédiaire entre le noeud dot et la bribe de code (instance) */
+typedef struct _GGraphNode GGraphNode;
+
+/* Intermédiaire entre le noeud dot et la bribe de code (classe) */
+typedef struct _GGraphNodeClass GGraphNodeClass;
+
+
+/* Indique le type définit par la GLib pour le noeud. */
+GType g_graph_node_get_type(void);
+
+/* Constitue un intermédiaire entre un noeud dot et du code. */
+GGraphNode *g_graph_node_new(GtkWidget *);
+
+/* Déclare l'intermédiaire en tant que noeud pour dot. */
+char *g_graph_node_register_for_dot(const GGraphNode *, char *);
+
+/* Place le morceau de code de l'intermédiaire à l'écran. */
+void g_graph_node_place(GGraphNode *, GtkGraphView *, gint , gint);
+
+/* Etablit une jonction ferme avec un noeud. */
+void g_graph_node_connect(const GGraphNode *, gint, gint, GdkPoint **, size_t *);
+
+
+
+/* ----------------------- MANIPULATION D'ENSEMBLES DE NOEUDS ----------------------- */
+
+
+/* Recherche un noeud donné dans une série de noeuds. */
+GGraphNode *find_graph_node_by_name(GGraphNode **, size_t, const char *);
+
+
+
+#endif /* _GRAPH_NODE_H */
diff --git a/src/gtkext/gtkgraphview.c b/src/gtkext/gtkgraphview.c
index 9fa9135..c0ea347 100644
--- a/src/gtkext/gtkgraphview.c
+++ b/src/gtkext/gtkgraphview.c
@@ -27,7 +27,7 @@
#include "gtkblockview.h"
#include "gtkbufferview.h"
#include "gtkviewpanel-int.h"
-#include "../graph/layout.h"
+#include "graph/layout.h"
@@ -554,8 +554,8 @@ static GtkViewPanel **gtk_graph_view_load_nodes(GtkGraphView *view, GLoadedBinar
list = g_loaded_binary_get_instructions(binary);
buffer = g_loaded_binary_get_disassembled_buffer(binary);
- addr = g_loaded_binary_display_addresses_in_text(binary);
- code = g_loaded_binary_display_code_in_text(binary);
+ addr = g_loaded_binary_display_addresses_in_text(binary, BDT_GRAPH);
+ code = g_loaded_binary_display_code_in_text(binary, BDT_GRAPH);
first = start;
last = first;
@@ -564,7 +564,7 @@ static GtkViewPanel **gtk_graph_view_load_nodes(GtkGraphView *view, GLoadedBinar
iter != NULL;
iter = g_arch_instruction_get_next_iter(list, iter, end))
{
- if (g_arch_instruction_has_sources(iter))
+ if (first != VMPA_MAX && g_arch_instruction_has_sources(iter))
{
result = (GtkViewPanel **)realloc(result, ++(*count) * sizeof(GtkViewPanel *));
diff --git a/src/gtkext/gtklinkrenderer.c b/src/gtkext/gtklinkrenderer.c
index 9332860..2913c19 100644
--- a/src/gtkext/gtklinkrenderer.c
+++ b/src/gtkext/gtklinkrenderer.c
@@ -24,12 +24,16 @@
#include "gtklinkrenderer.h"
+#include <math.h>
+
+
/* Lien entre morceaux de code (instance) */
struct _GtkLinkRenderer
{
GtkObject parent; /* A laisser en premier */
+ LinkColor color; /* Couleur d'impression */
GdkPoint *points; /* Points de la ligne dessinée */
size_t count; /* Quantité de ces points */
@@ -44,12 +48,18 @@ struct _GtkLinkRendererClass
};
+#define ARROW_LENGHT 10
+#define ARROW_DEGREES 10
+
+
/* Initialise la classe générique des liens graphiques. */
static void gtk_link_renderer_class_init(GtkLinkRendererClass *);
/* Initialise une instance de lien graphique entre codes. */
static void gtk_link_renderer_init(GtkLinkRenderer *);
+/* Dessine une flèche au bout du lien représenté. */
+static void draw_link_arrow(cairo_t *, gint, gint, gint, gint);
@@ -95,7 +105,8 @@ static void gtk_link_renderer_init(GtkLinkRenderer *view)
/******************************************************************************
* *
-* Paramètres : points = points consituant la ligne à représenter. *
+* Paramètres : color = couleur d'impression. *
+ù points = points consituant la ligne à représenter. *
* count = nombre de ces points. *
* *
* Description : Crée un nouveau moteur de rendu pour les liens graphiques. *
@@ -106,12 +117,13 @@ static void gtk_link_renderer_init(GtkLinkRenderer *view)
* *
******************************************************************************/
-GtkObject *gtk_link_renderer_new(GdkPoint *points, size_t count)
+GtkObject *gtk_link_renderer_new(LinkColor color, GdkPoint *points, size_t count)
{
GtkLinkRenderer *result; /* Moteur de rendu à retourner */
result = g_object_new(GTK_TYPE_LINK_RENDERER, NULL);
+ result->color = color;
result->points = points;
result->count = count;
@@ -136,6 +148,88 @@ GtkObject *gtk_link_renderer_new(GdkPoint *points, size_t count)
void gtk_link_renderer_draw(const GtkLinkRenderer *renderer, GdkDrawable *drawable, GdkGC *gc)
{
- gdk_draw_lines(drawable, gc, renderer->points, renderer->count);
+ cairo_t *cairo; /* Gestionnaire de rendu */
+ size_t i; /* Boucle de parcours */
+
+ cairo = gdk_cairo_create(drawable);
+
+ switch (renderer->color)
+ {
+ default:
+ case LKC_DEFAULT:
+ cairo_set_source_rgb(cairo, 0, 0, 0);
+ break;
+ case LKC_GREEN:
+ cairo_set_source_rgb(cairo, 0, 0.6, 0);
+ break;
+ case LKC_RED:
+ cairo_set_source_rgb(cairo, 0.8, 0, 0);
+ break;
+ }
+
+ cairo_set_line_width(cairo, 1);
+
+ cairo_move_to(cairo, renderer->points[0].x, renderer->points[0].y);
+
+ for (i = 1; i < renderer->count; i++)
+ cairo_line_to(cairo, renderer->points[i].x, renderer->points[i].y);
+
+ cairo_stroke(cairo);
+
+ draw_link_arrow(cairo,
+ renderer->points[renderer->count - 2].x,
+ renderer->points[renderer->count - 2].y,
+ renderer->points[renderer->count - 1].x,
+ renderer->points[renderer->count - 1].y);
+
+ cairo_destroy(cairo);
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : cairo = gestionnaire de rendu graphique. *
+* start_x = abscisse du début du segment final. *
+* start_y = ordonnée du début du segment final. *
+* end_x = abscisse de fin de segment et pointe de flèche. *
+* end_y = ordonnée de fin de segment et pointe de flèche. *
+* *
+* Description : Dessine une flèche au bout du lien représenté. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void draw_link_arrow(cairo_t *cairo, gint start_x, gint start_y, gint end_x, gint end_y)
+{
+ double angle; /* Angle du triangle à remplir */
+ double factor_x; /* Direction de la flèche #1 */
+ double factor_y; /* Direction de la flèche #2 */
+ double x1; /* Abscisse du point n°1 */
+ double y1; /* Ordonnée du point n°1 */
+ double x2; /* Abscisse du point n°2 */
+ double y2; /* Ordonnée du point n°2 */
+
+ angle = atan2(end_y - start_y, end_x - start_x) + M_PI;
+
+ factor_x = -1;
+ factor_y = -1;
+
+ x1 = end_x + factor_x * ARROW_LENGHT * cos(angle - ARROW_DEGREES);
+ y1 = end_y + factor_y * ARROW_LENGHT * sin(angle - ARROW_DEGREES);
+ x2 = end_x + factor_x * ARROW_LENGHT * cos(angle + ARROW_DEGREES);
+ y2 = end_y + factor_y * ARROW_LENGHT * sin(angle + ARROW_DEGREES);
+
+ cairo_move_to(cairo, end_x, end_y);
+
+ cairo_line_to(cairo, x1, y1);
+ cairo_line_to(cairo, x2, y2);
+
+ cairo_move_to(cairo, end_x, end_y);
+
+ cairo_fill(cairo);
}
diff --git a/src/gtkext/gtklinkrenderer.h b/src/gtkext/gtklinkrenderer.h
index d662454..95cdea6 100644
--- a/src/gtkext/gtklinkrenderer.h
+++ b/src/gtkext/gtklinkrenderer.h
@@ -45,11 +45,23 @@ typedef struct _GtkLinkRenderer GtkLinkRenderer;
typedef struct _GtkLinkRendererClass GtkLinkRendererClass;
+/* Couleur de représentation */
+typedef enum _LinkColor
+{
+ LKC_DEFAULT, /* Noir, par défaut */
+ LKC_GREEN, /* Condition vérifiée */
+ LKC_RED, /* Condition non vérifiée */
+
+ LKC_COUNT
+
+} LinkColor;
+
+
/* Détermine le type du moteur de rendu pour les liens graphiques. */
GType gtk_link_renderer_get_type(void);
/* Crée un nouveau moteur de rendu pour les liens graphiques. */
-GtkObject *gtk_link_renderer_new(GdkPoint *, size_t);
+GtkObject *gtk_link_renderer_new(LinkColor, GdkPoint *, size_t);
/* Dessine les liens graphiques enregistrés dans le moteur. */
void gtk_link_renderer_draw(const GtkLinkRenderer *, GdkDrawable *, GdkGC *);
diff --git a/src/gtkext/gtkviewpanel.c b/src/gtkext/gtkviewpanel.c
index 3ccc0ff..0ab4f72 100644
--- a/src/gtkext/gtkviewpanel.c
+++ b/src/gtkext/gtkviewpanel.c
@@ -293,8 +293,7 @@ static gboolean gtk_view_panel_expose(GtkWidget *widget, GdkEventExpose *event)
GtkViewPanel *panel;
GdkGCValues values; /* Propriétés du contexte */
GtkStyle *style; /* Style associé au composant */
- int width; /* Largeur de l'élément */
- int height; /* Hauteur de l'élément */
+ GtkRequisition req; /* Taille allouée à l'élément */
GtkStateType state; /* Etat du composant */
panel = GTK_VIEW_PANEL(widget);
@@ -304,13 +303,13 @@ static gboolean gtk_view_panel_expose(GtkWidget *widget, GdkEventExpose *event)
gdk_gc_get_values(panel->gc, &values);
style = gtk_widget_get_style(widget);
- gtk_widget_get_size_request(widget, &width, &height);
+ gtk_widget_size_request(widget, &req);
state = gtk_widget_get_state(widget);
gdk_gc_set_foreground(panel->gc, &style->dark[state]);
gdk_draw_rectangle(GDK_DRAWABLE(widget->window), panel->gc,
- FALSE, 0, 0, width - 1, height - 1);
+ FALSE, 0, 0, req.width - 1, req.height - 1);
gdk_gc_set_foreground(panel->gc, &values.foreground);