/* Chrysalide - Outil d'analyse de fichiers binaires * binportion.c - représentation graphique de portions de binaire * * Copyright (C) 2013 Cyrille Bagard * * This file is part of Chrysalide. * * OpenIDA is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * OpenIDA is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Foobar. If not, see . */ #include "gbinportion.h" #include #include #include #include #include #include "../common/extstr.h" /* ------------------------------- PORTION DE BINAIRE ------------------------------- */ /* Portion de données binaires quelconques (instance) */ struct _GBinPortion { GObject parent; /* A laisser en premier */ const unsigned int *level; /* Profondeur de la portion */ char *code; /* Code de la couleur de fond */ char *desc; /* Désignation humaine */ mrange_t range; /* Emplacement dans le code */ PortionAccessRights rights; /* Droits d'accès */ }; /* Portion de données binaires quelconques (classe) */ struct _GBinPortionClass { GObjectClass parent; /* A laisser en premier */ }; /* Initialise la classe des portions de données binaires. */ static void g_binary_portion_class_init(GBinPortionClass *); /* Initialise une instance de portion de données binaires. */ static void g_binary_portion_init(GBinPortion *); /* Supprime toutes les références externes. */ static void g_binary_portion_dispose(GBinPortion *); /* Procède à la libération totale de la mémoire. */ static void g_binary_portion_finalize(GBinPortion *); /* Définit le niveau de profondeur pour une branche de portions. */ static void g_binary_portion_set_level(GBinPortion *, const unsigned int *); /* Détermine l'aire d'une sous-portion. */ static bool g_binary_portion_compute_sub_area(const GBinPortion *, phys_t, const GdkRectangle *, GdkRectangle *); /* Détermine si une portion contient une adresse donnée. */ static bool g_portion_layer_contains_addr(const GBinPortion *, const vmpa2t *); /* -------------------------- COUCHES DE PORTIONS BINAIRES -------------------------- */ /* Couche de portions binaires quelconques (instance) */ struct _GPortionLayer { GObject parent; /* A laisser en premier */ phys_t length; /* Taille de portion globale */ const char *name; /* Désignation de la couche */ unsigned int level; /* Profondeur de la portion */ GPortionLayer *sub_layer; /* Eventuelle couche inférieure*/ GBinPortion **portions; /* Portions incluses */ size_t count; /* Quantité d'inclusions */ }; /* Couche de portions binaires quelconques (classe) */ struct _GPortionLayerClass { GObjectClass parent; /* A laisser en premier */ }; /* Initialise la classe des couches de portions binaires. */ static void g_portion_layer_class_init(GPortionLayerClass *); /* Initialise une instance de couche de portions binaires. */ static void g_portion_layer_init(GPortionLayer *); /* Supprime toutes les références externes. */ static void g_portion_layer_dispose(GPortionLayer *); /* Procède à la libération totale de la mémoire. */ static void g_portion_layer_finalize(GPortionLayer *); /* ---------------------------------------------------------------------------------- */ /* PORTION DE BINAIRE */ /* ---------------------------------------------------------------------------------- */ /* Indique le type défini par la GLib pour les portions de données binaires. */ G_DEFINE_TYPE(GBinPortion, g_binary_portion, G_TYPE_OBJECT); /****************************************************************************** * * * Paramètres : klass = classe à initialiser. * * * * Description : Initialise la classe des portions de données binaires. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ static void g_binary_portion_class_init(GBinPortionClass *klass) { GObjectClass *object; /* Autre version de la classe */ object = G_OBJECT_CLASS(klass); object->dispose = (GObjectFinalizeFunc/* ! */)g_binary_portion_dispose; object->finalize = (GObjectFinalizeFunc)g_binary_portion_finalize; } /****************************************************************************** * * * Paramètres : portion = instance à initialiser. * * * * Description : Initialise une instance de portion de données binaires. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ static void g_binary_portion_init(GBinPortion *portion) { portion->level = NULL; } /****************************************************************************** * * * Paramètres : portion = instance d'objet GLib à traiter. * * * * Description : Supprime toutes les références externes. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ static void g_binary_portion_dispose(GBinPortion *portion) { G_OBJECT_CLASS(g_binary_portion_parent_class)->dispose(G_OBJECT(portion)); } /****************************************************************************** * * * Paramètres : portion = instance d'objet GLib à traiter. * * * * Description : Procède à la libération totale de la mémoire. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ static void g_binary_portion_finalize(GBinPortion *portion) { free(portion->code); if (portion->desc != NULL) free(portion->desc); G_OBJECT_CLASS(g_binary_portion_parent_class)->finalize(G_OBJECT(portion)); } /****************************************************************************** * * * Paramètres : code = désignation humaine de la couleur de fond. * * * * Description : Crée une description de partie de code vierge. * * * * Retour : Instance mise en place. * * * * Remarques : - * * * ******************************************************************************/ GBinPortion *g_binary_portion_new(const char *code) { GBinPortion *result; /* Structure à retourner */ result = g_object_new(G_TYPE_BIN_PORTION, NULL); result->code = strdup(code); return result; } /****************************************************************************** * * * Paramètres : portion = description de partie à mettre à jour. * * level = niveau de profondeur à associer. * * * * Description : Définit le niveau de profondeur pour une branche de portions.* * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ static void g_binary_portion_set_level(GBinPortion *portion, const unsigned int *level) { portion->level = level; } /****************************************************************************** * * * Paramètres : a = premières informations à consulter. * * b = secondes informations à consulter. * * * * Description : Etablit la comparaison ascendante entre deux portions. * * * * Retour : Bilan : -1 (a < b), 0 (a == b) ou 1 (a > b). * * * * Remarques : - * * * ******************************************************************************/ int g_binary_portion_compare(const GBinPortion **a, const GBinPortion **b) { int result; /* Bilan à retourner */ const vmpa2t *addr_a; /* Adresse de la portion 'a' */ const vmpa2t *addr_b; /* Adresse de la portion 'b' */ const unsigned int *level_a; /* Niveau de la portion 'a' */ const unsigned int *level_b; /* Niveau de la portion 'b' */ addr_a = get_mrange_addr(&(*a)->range); addr_b = get_mrange_addr(&(*b)->range); result = cmp_vmpa(addr_a, addr_b); if (result == 0) { level_a = (*a)->level; level_b = (*b)->level; if (level_a != NULL && level_b != NULL) { if (*level_a < *level_b) result = -1; else if (*level_a > *level_b) result = 1; } } return result; } /****************************************************************************** * * * Paramètres : portion = description de partie à mettre à jour. * * desc = nom à donner à la partie. * * * * Description : Attribue une description humaine à une partie de code. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ void g_binary_portion_set_desc(GBinPortion *portion, const char *desc) { if (portion->desc != NULL) free(portion->desc); portion->desc = strdup(desc); } /****************************************************************************** * * * Paramètres : portion = description de partie à consulter. * * * * Description : Fournit la description attribuée à une partie de code. * * * * Retour : Nom donné à la partie. * * * * Remarques : - * * * ******************************************************************************/ const char *g_binary_portion_get_desc(const GBinPortion *portion) { return portion->desc; } /****************************************************************************** * * * Paramètres : portion = description de partie à mettre à jour. * * addr = emplacement de la section à conserver. * * size = taille de la section à conserver. * * * * Description : Définit les valeurs utiles d'une partie de code binaire. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ void g_binary_portion_set_values(GBinPortion *portion, const vmpa2t *addr, phys_t size) { init_mrange(&portion->range, addr, size); } /****************************************************************************** * * * Paramètres : portion = description de partie à mettre à jour. * * * * Description : Fournit l'emplacement d'une partie de code binaire. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ const mrange_t *g_binary_portion_get_range(const GBinPortion *portion) { return &portion->range; } /****************************************************************************** * * * Paramètres : portion = description de partie à mettre à jour. * * rights = droits d'accès de la partie. * * * * Description : Définit les droits associés à une partie de code. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ void g_binary_portion_set_rights(GBinPortion *portion, PortionAccessRights rights) { portion->rights = rights; } /****************************************************************************** * * * Paramètres : portion = description de partie à consulter. * * * * Description : Fournit les droits associés à une partie de code. * * * * Retour : Droits d'accès de la partie. * * * * Remarques : - * * * ******************************************************************************/ PortionAccessRights g_binary_portion_get_rights(const GBinPortion *portion) { return portion->rights; } /****************************************************************************** * * * Paramètres : portion = portion mère à consulter. * * full = taille totale de la couche parente. * * area = étendue de représentation de la portion mère. * * sub_area = étendue de représentation de la portion fille. * * * * Description : Détermine l'aire d'une sous-portion. * * * * Retour : true si la sous-surface a été calculée correctement. * * * * Remarques : - * * * ******************************************************************************/ static bool g_binary_portion_compute_sub_area(const GBinPortion *portion, phys_t full, const GdkRectangle *area, GdkRectangle *sub_area) { phys_t length; /* Taille de la portion */ phys_t start; /* Position de départ */ length = get_mrange_length(&portion->range); /* On saute les portions comme le segment GNU_STACK... */ if (length == 0) return false; start = get_phy_addr(get_mrange_addr(&portion->range)); sub_area->y = area->y; sub_area->height = area->height; sub_area->x = area->x + (start * area->width) / full; sub_area->width = (length * area->width) / full; return true; } /****************************************************************************** * * * Paramètres : portion = portion mère à consulter. * * addr = adresse du point de recherche. * * * * Description : Détermine si une portion contient une adresse donnée. * * * * Retour : true ou false selon le résultat. * * * * Remarques : - * * * ******************************************************************************/ static bool g_portion_layer_contains_addr(const GBinPortion *portion, const vmpa2t *addr) { bool result; /* Bilan à retourner */ result = false; /* Portion non allouée en mémoire -> adresse nulle ; on écarte */ if (get_virt_addr(get_mrange_addr(&portion->range)) == 0) goto not_found; result = mrange_contains_addr(&portion->range, addr); not_found: return result; } /****************************************************************************** * * * Paramètres : portion = description de partie à consulter. * * buffer = espace où placer ledit contenu. * * msize = taille idéale des positions et adresses; * * * * Description : Insère dans un tampon une description de portion. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ void g_binary_portion_print(const GBinPortion *portion, GCodeBuffer *buffer, MemoryDataSize msize) { mrange_t range; /* Couverture à fournir */ GBufferLine *line; /* Nouvelle ligne à éditer */ char rights[64]; /* Traduction en texte */ /* On ne traite pas les portions anonymes ! */ if (portion->desc == NULL) return; init_mrange(&range, get_mrange_addr(&portion->range), 0); line = g_code_buffer_prepare_new_line(buffer, &range); g_buffer_line_fill_mrange(line, msize, msize); g_buffer_line_add_flag(line, BLF_WIDTH_MANAGER); g_code_buffer_append_new_line(buffer, line); /* Séparation */ line = g_code_buffer_prepare_new_line(buffer, &range); g_buffer_line_fill_mrange(line, msize, msize); g_buffer_line_start_merge_at(line, BLC_ASSEMBLY_HEAD); g_buffer_line_insert_text(line, BLC_ASSEMBLY_HEAD, "; ======================================================", 56, RTT_COMMENT); g_code_buffer_append_new_line(buffer, line); /* Retour à la ligne */ line = g_code_buffer_prepare_new_line(buffer, &range); g_buffer_line_fill_mrange(line, msize, msize); g_buffer_line_start_merge_at(line, BLC_ASSEMBLY_HEAD); g_buffer_line_insert_text(line, BLC_ASSEMBLY_HEAD, "; ", 2, RTT_COMMENT); g_code_buffer_append_new_line(buffer, line); /* Description */ line = g_code_buffer_prepare_new_line(buffer, &range); g_buffer_line_fill_mrange(line, msize, msize); g_buffer_line_start_merge_at(line, BLC_ASSEMBLY_HEAD); g_buffer_line_insert_text(line, BLC_ASSEMBLY_HEAD, "; ", 2, RTT_COMMENT); g_buffer_line_insert_text(line, BLC_ASSEMBLY_HEAD, portion->desc, strlen(portion->desc), RTT_COMMENT); snprintf(rights, sizeof(rights), " (%s%s%s%s)", _("rights: "), portion->rights & PAC_READ ? "r" : "-", portion->rights & PAC_WRITE ? "w" : "-", portion->rights & PAC_EXEC ? "x" : "-"); g_buffer_line_insert_text(line, BLC_ASSEMBLY_HEAD, rights, strlen(rights), RTT_COMMENT); g_code_buffer_append_new_line(buffer, line); /* Retour à la ligne */ line = g_code_buffer_prepare_new_line(buffer, &range); g_buffer_line_fill_mrange(line, msize, msize); g_buffer_line_start_merge_at(line, BLC_ASSEMBLY_HEAD); g_buffer_line_insert_text(line, BLC_ASSEMBLY_HEAD, "; ", 2, RTT_COMMENT); g_code_buffer_append_new_line(buffer, line); line = g_code_buffer_prepare_new_line(buffer, &range); g_buffer_line_fill_mrange(line, msize, msize); g_code_buffer_append_new_line(buffer, line); } /****************************************************************************** * * * Paramètres : portion = description de partie à mettre à jour. * * tooltip = astuce à compléter. [OUT] * * * * Description : Prépare une astuce concernant une portion pour son affichage.* * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ void g_binary_portion_query_tooltip(GBinPortion *portion, GtkTooltip *tooltip) { char *markup; /* Description à construire */ VMPA_BUFFER(value); /* Traduction en texte */ /* Nom */ if (portion->desc != NULL) { markup = strdup(""); markup = stradd(markup, portion->desc); markup = stradd(markup, "\n"); markup = stradd(markup, "\n"); } else markup = strdup(""); markup = stradd(markup, "taille : "); mrange_length_to_string(&portion->range, MDS_UNDEFINED, value, NULL); markup = stradd(markup, value); markup = stradd(markup, "\n"); /* Localisation */ markup = stradd(markup, ""); markup = stradd(markup, _("Localisation")); markup = stradd(markup, "\n"); markup = stradd(markup, _("physical: from ")); mrange_phys_to_string(&portion->range, MDS_UNDEFINED, true, value, NULL); markup = stradd(markup, value); markup = stradd(markup, _(" to ")); mrange_phys_to_string(&portion->range, MDS_UNDEFINED, false, value, NULL); markup = stradd(markup, value); markup = stradd(markup, "\n"); markup = stradd(markup, _("memory: from ")); mrange_virt_to_string(&portion->range, MDS_UNDEFINED, true, value, NULL); markup = stradd(markup, value); markup = stradd(markup, _(" to ")); mrange_virt_to_string(&portion->range, MDS_UNDEFINED, false, value, NULL); markup = stradd(markup, value); markup = stradd(markup, "\n\n"); /* Droits d'accès */ markup = stradd(markup, ""); markup = stradd(markup, _("Rights")); markup = stradd(markup, "\n"); snprintf(value, 2 * VMPA_MAX_SIZE, "%s%s%s", portion->rights & PAC_READ ? "r" : "-", portion->rights & PAC_WRITE ? "w" : "-", portion->rights & PAC_EXEC ? "x" : "-"); markup = stradd(markup, value); /* Impression finale */ gtk_tooltip_set_markup(tooltip, markup); free(markup); } /****************************************************************************** * * * Paramètres : portion = description de partie à consulter. * * cr = contexte graphique pour le dessin. * * area = étendue mise à disposition. * * * * Description : Représente la portion sur une bande dédiée. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ void g_binary_portion_draw(const GBinPortion *portion, GtkStyleContext *context, cairo_t *cr, const GdkRectangle *area) { //cairo_set_line_width(cr, 1.0); cairo_set_antialias(cr, CAIRO_ANTIALIAS_NONE); gtk_style_context_save(context); gtk_style_context_add_class(context, portion->code); gtk_render_background(context, cr, area->x, area->y, area->width, area->height); gtk_render_frame(context, cr, area->x, area->y, area->width, area->height); gtk_style_context_restore(context); } /* ---------------------------------------------------------------------------------- */ /* COUCHES DE PORTIONS BINAIRES */ /* ---------------------------------------------------------------------------------- */ /* Indique le type défini par la GLib pour les couches de portions binaires. */ G_DEFINE_TYPE(GPortionLayer, g_portion_layer, G_TYPE_OBJECT); /****************************************************************************** * * * Paramètres : klass = classe à initialiser. * * * * Description : Initialise la classe des couches de portions binaires. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ static void g_portion_layer_class_init(GPortionLayerClass *klass) { GObjectClass *object; /* Autre version de la classe */ object = G_OBJECT_CLASS(klass); object->dispose = (GObjectFinalizeFunc/* ! */)g_portion_layer_dispose; object->finalize = (GObjectFinalizeFunc)g_portion_layer_finalize; } /****************************************************************************** * * * Paramètres : layer = instance à initialiser. * * * * Description : Initialise une instance de couche de portions binaires. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ static void g_portion_layer_init(GPortionLayer *layer) { layer->level = 0; } /****************************************************************************** * * * Paramètres : layer = instance d'objet GLib à traiter. * * * * Description : Supprime toutes les références externes. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ static void g_portion_layer_dispose(GPortionLayer *layer) { size_t i; /* Boucle de parcours */ if (layer->sub_layer != NULL) g_object_unref(G_OBJECT(layer->sub_layer)); for (i = 0; i < layer->count; i++) g_object_unref(G_OBJECT(layer->portions[i])); G_OBJECT_CLASS(g_portion_layer_parent_class)->dispose(G_OBJECT(layer)); } /****************************************************************************** * * * Paramètres : layer = instance d'objet GLib à traiter. * * * * Description : Procède à la libération totale de la mémoire. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ static void g_portion_layer_finalize(GPortionLayer *layer) { if (layer->portions != NULL) free(layer->portions); G_OBJECT_CLASS(g_portion_layer_parent_class)->finalize(G_OBJECT(layer)); } /****************************************************************************** * * * Paramètres : length = * name = désignation pouvant servir de suffixe aux portions. * * * * Description : Crée une nouvelle couche de portions binaires. * * * * Retour : Instance mise en place. * * * * Remarques : - * * * ******************************************************************************/ GPortionLayer *g_portion_layer_new(phys_t length, const char *name) { GPortionLayer *result; /* Structure à retourner */ result = g_object_new(G_TYPE_BIN_PORTION, NULL); result->length = length; result->name = name; return result; } /****************************************************************************** * * * Paramètres : layer = couche rassemblant des portions à modifier. * * Paramètres : sub = couche inférieure à rattacher à la couche courante. * * * * Description : Attache une couche à une autre en tant que couche inférieure.* * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ void g_portion_layer_attach_sub(GPortionLayer *layer, GPortionLayer *sub) { void set_layers_length(GPortionLayer *parent, GPortionLayer *child) { if (child->length == NO_LENGTH_YET) { assert(parent->length != NO_LENGTH_YET); child->length = parent->length; if (child->sub_layer != NULL) set_layers_length(child, child->sub_layer); } } void set_layers_depth(GPortionLayer *parent, GPortionLayer *child) { child->level = parent->level + 1; if (child->sub_layer != NULL) set_layers_length(child, child->sub_layer); } set_layers_length(layer, sub); set_layers_depth(layer, sub); layer->sub_layer = sub; } /****************************************************************************** * * * Paramètres : layer = couche rassemblant les portions d'un même niveau. * * portion = portion à inclure dans la définition courante. * * * * Description : Procède à l'inclusion d'une portion dans une couche. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ void g_portion_layer_include(GPortionLayer *layer, GBinPortion *portion) { GPortionLayer *sub; /* Sous couche indispensable */ bool conflict; /* Conflit dû aux débordements */ const mrange_t *range; /* Emplacement de la portion */ size_t i; /* Boucle de parcours */ const mrange_t *other; /* Emplacements déjà occupés */ /** * On prend ici en compte le genre de situations suivantes : * * [21] .bss NOBITS 00088240 07823c 0018c8 00 WA 0 0 8 * [22] __libc_freeres_ptrs NOBITS 00089b08 07823c 000018 00 WA 0 0 4 * [23] .comment PROGBITS 00000000 07823c 000022 01 MS 0 0 1 * * Pendant le désassemblage, la procédure n'aime pas trop les intersections * de zones mémoire. */ conflict = false; range = g_binary_portion_get_range(portion); for (i = 0; i < layer->count && !conflict; i++) { other = g_binary_portion_get_range(layer->portions[i]); conflict = mrange_intersects_mrange(range, other); } /* La portion recouvre-t-elle une portion déjà existante ? */ if (conflict) { if (layer->sub_layer == NULL) { sub = g_portion_layer_new(layer->length, layer->name); g_portion_layer_attach_sub(layer, sub); } g_portion_layer_include(layer->sub_layer, portion); } /* Sinon on l'intègre dans la couche courante */ else { layer->portions = (GBinPortion **)realloc(layer->portions, ++layer->count * sizeof(GBinPortion *)); layer->portions[layer->count - 1] = portion; g_binary_portion_set_level(portion, &layer->level); qsort(layer->portions, layer->count, sizeof(GBinPortion *), (__compar_fn_t)g_binary_portion_compare); } } /****************************************************************************** * * * Paramètres : layer = couche première à parcourir intégralement. * * count = nombre de portions trouvées et renvoyées. [OUT] * * * * Description : Fournit une liste triée de portions d'un binaire. * * * * Retour : Liste de définitions de zones à libérer après usage. * * * * Remarques : - * * * ******************************************************************************/ GBinPortion **g_portion_layer_collect_all_portions(const GPortionLayer *layer, size_t *count) { GBinPortion **result; /* Liste construite à renvoyer */ GBinPortion **do_collect(const GPortionLayer *l, GBinPortion **lst, size_t *c) { size_t start; /* Indice de départ des ajouts */ size_t i; /* Boucle de parcours */ start = *c; *c += l->count; lst = (GBinPortion **)realloc(lst, *c * sizeof(GBinPortion *)); for (i = 0; i < l->count; i++) lst[start + i] = l->portions[i]; return lst; } *count = 0; result = do_collect(layer, NULL, count); qsort(result, *count, sizeof(GBinPortion *), (__compar_fn_t)g_binary_portion_compare); return result; } /****************************************************************************** * * * Paramètres : layer = couche de portions à parcourir pour les recherches. * * x = abscisse du point de recherche. * * area = étendue de portion mère, puis celle trouvée. [OUT] * * * * Description : Recherche la portion présente à un point donné. * * * * Retour : Portion trouvée à l'endroit indiqué. * * * * Remarques : - * * * ******************************************************************************/ GBinPortion *g_portion_layer_find_portion_at_pos(const GPortionLayer *layer, gint x, GdkRectangle *area) { GBinPortion *result; /* Portion à retourner */ size_t i; /* Boucle de parcours */ GBinPortion *sub; /* Portion incluse à traiter */ GdkRectangle sub_area; /* Etendue d'une sous-portion */ if (layer->sub_layer != NULL) result = g_portion_layer_find_portion_at_pos(layer->sub_layer, x, area); else result = NULL; for (i = 0; i < layer->count && result == NULL; i++) { sub = layer->portions[i]; if (!g_binary_portion_compute_sub_area(sub, layer->length, area, &sub_area)) continue; if (sub_area.x <= x && x < (sub_area.x + sub_area.width)) { result = sub; *area = sub_area; } } return result; } /****************************************************************************** * * * Paramètres : layer = couche de portions à parcourir pour les recherches. * * addr = adresse du point de recherche. * * area = étendue de portion mère, puis celle trouvée. [OUT] * * * * Description : Recherche la portion présente à une adresse donnée. * * * * Retour : Portion trouvée à l'endroit indiqué. * * * * Remarques : - * * * ******************************************************************************/ GBinPortion *g_portion_layer_find_portion_at_addr(const GPortionLayer *layer, const vmpa2t *addr, GdkRectangle *area) { GBinPortion *result; /* Portion à retourner */ size_t i; /* Boucle de parcours #1 */ GBinPortion *sub; /* Portion incluse à traiter */ GdkRectangle sub_area; /* Etendue d'une sous-portion */ if (layer->sub_layer != NULL) result = g_portion_layer_find_portion_at_addr(layer->sub_layer, addr, area); else result = NULL; for (i = 0; i < layer->count && result == NULL; i++) { sub = layer->portions[i]; if (!g_portion_layer_contains_addr(sub, addr)) continue; if (!g_binary_portion_compute_sub_area(sub, layer->length, area, &sub_area)) continue; result = sub; *area = sub_area; } return result; } /****************************************************************************** * * * Paramètres : layer = couche de portions à parcourir pour les recherches. * * x = abscisse du point de recherche. * * area = étendue de représentation de la portion mère. * * addr = adresse correspondante. [OUT] * * * * Description : Fournit la position correspondant à une adresse donnée. * * * * Retour : Succès de la traduction. * * * * Remarques : - * * * ******************************************************************************/ bool g_portion_layer_get_addr_from_pos(GPortionLayer *layer, gint x, const GdkRectangle *area, vmpa2t *addr) { GdkRectangle owner_area; /* Aire de contenance */ GBinPortion *owner; /* Conteneur propriétaire */ owner_area = *area; owner = g_portion_layer_find_portion_at_pos(layer, x, &owner_area); if (owner == NULL) return false; copy_vmpa(addr, get_mrange_addr(&owner->range)); advance_vmpa(addr, (get_mrange_length(&owner->range) * (x - owner_area.x)) / owner_area.width); return true; } /****************************************************************************** * * * Paramètres : layer = couche de portions à parcourir pour les recherches. * * addr = adresse du point de recherche. * * area = étendue de représentation de la portion mère. * * x = position correspondante. [OUT] * * * * Description : Fournit l'adresse correspondant à une position donnée. * * * * Retour : Succès de la traduction. * * * * Remarques : - * * * ******************************************************************************/ bool g_portion_layer_get_pos_from_addr(GPortionLayer *layer, const vmpa2t *addr, const GdkRectangle *area, gint *x) { GdkRectangle owner_area; /* Aire de contenance */ GBinPortion *owner; /* Conteneur propriétaire */ phys_t diff; /* Décallage à appliquer */ owner_area = *area; owner = g_portion_layer_find_portion_at_addr(layer, addr, &owner_area); if (owner == NULL) return false; diff = compute_vmpa_diff(addr, get_mrange_addr(&owner->range)); *x = owner_area.x + (diff * owner_area.width) / get_mrange_length(&owner->range); return true; } /****************************************************************************** * * * Paramètres : layer = première couche amorçant la visite. * * visitor = fonction à appeler à chaque étape de la descente. * * data = adresse pointant vers des données de l'utilisateur.* * * * Description : Parcours un ensemble de portions binaires. * * * * Retour : true si la visite a été jusqu'à son terme, false sinon. * * * * Remarques : - * * * ******************************************************************************/ bool g_portion_layer_visit(const GPortionLayer *layer, visit_portion_fc visitor, void *data) { bool result; /* Etat à retourner */ size_t i; /* Boucle de parcours */ if (layer->sub_layer != NULL) result = g_portion_layer_visit(layer->sub_layer, visitor, data); else result = true; for (i = 0; i < layer->count && result; i++) result = visitor(layer->portions[i], data); return result; } /****************************************************************************** * * * Paramètres : layer = couche de portions à consulter. * * x = abscisse du point de recherche. * * y = ordonnée du point de recherche. * * area = étendue de représentation de la portion mère. * * tooltip = astuce à compléter. [OUT] * * * * Description : Prépare une astuce concernant une portion pour son affichage.* * * * Retour : TRUE pour valider l'affichage. * * * * Remarques : - * * * ******************************************************************************/ gboolean g_portion_layer_query_tooltip(const GPortionLayer *layer, gint x, gint y, const GdkRectangle *area, GtkTooltip *tooltip) { GBinPortion *selected; /* Portion à décrire ici */ selected = g_portion_layer_find_portion_at_pos(layer, x, (GdkRectangle []) { *area }); if (selected == NULL) return FALSE; g_binary_portion_query_tooltip(selected, tooltip); return TRUE; } /****************************************************************************** * * * Paramètres : layer = couche de portions à consulter. * * cr = contexte graphique pour le dessin. * * area = étendue mise à disposition. * * * * Description : Représente une couche de portions sur une bande dédiée. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ void g_portion_layer_draw(const GPortionLayer *layer, GtkStyleContext *context, cairo_t *cr, const GdkRectangle *area) { size_t i; /* Boucle de parcours */ GBinPortion *sub; /* Portion incluse à montrer */ GdkRectangle sub_area; /* Etendue d'une sous-portion */ for (i = 0; i < layer->count; i++) { sub = layer->portions[i]; if (!g_binary_portion_compute_sub_area(sub, layer->length, area, &sub_area)) continue; g_binary_portion_draw(sub, context, cr, &sub_area); } if (layer->sub_layer != NULL) g_portion_layer_draw(layer->sub_layer, context, cr, area); }