/* Chrysalide - Outil d'analyse de fichiers binaires * hexview.c - affichage de contenus de binaire * * Copyright (C) 2016-2024 Cyrille Bagard * * This file is part of Chrysalide. * * Chrysalide 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. * * Chrysalide 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 Chrysalide. If not, see . */ #include "hexview.h" #include "area.h" #include "contentview-int.h" /* ------------------------- BASES D'UN COMPOSANT GRAPHIQUE ------------------------- */ /* Composant d'affichage d'octets bruts et imprimables (instance) */ struct _GtkHexView { GtkContentView parent; /* A laisser en premier */ union { #define _CHILDREN_COUNT 4 GtkWidget *children[_CHILDREN_COUNT];/* Sous-composants d'affichage*/ struct { GtkWidget *offsets; /* Affichage des positions */ GtkWidget *hex; /* Affichage des octets brut */ GtkWidget *ascii; /* Affichage des imprimables */ GtkWidget *vscroll; /* Barre de défilement */ }; }; bool need_vscrolling; /* Besoin de défilement ? */ }; /* Composant d'affichage d'octets bruts et imprimables (classe) */ struct _GtkHexViewClass { GtkContentViewClass parent; /* A laisser en premier */ }; /* Procède à l'initialisation de l'afficheur générique. */ static void gtk_hex_view_class_init(GtkHexViewClass *); /* Procède à l'initialisation de l'afficheur générique. */ static void gtk_hex_view_init(GtkHexView *); /* Supprime toutes les références externes. */ static void gtk_hex_view_dispose(GtkHexView *); /* Procède à la libération totale de la mémoire. */ static void gtk_hex_view_finalize(GtkHexView *); void demo_snapshot (GtkWidget *widget, GtkSnapshot *snapshot, GtkWidget *parent); /* --------------------- IMPLEMENTATION DES FONCTIONS DE CLASSE --------------------- */ /* Prend acte de la taille allouée au composant d'affichage. */ static void gtk_hex_view_size_allocate(GtkWidget *, int, int, int); /* Fournit le mode de calcul pour déterminer la taille. */ static GtkSizeRequestMode gtk_hex_view_get_request_mode(GtkWidget *); /* Fournit les mesures mainimale et idéale du composant. */ static void gtk_hex_view_measure(GtkWidget *, GtkOrientation, int, int *, int *, int *, int *); /* ---------------------------------------------------------------------------------- */ /* BASES D'UN COMPOSANT GRAPHIQUE */ /* ---------------------------------------------------------------------------------- */ /* Détermine le type du composant d'affichage générique. */ G_DEFINE_TYPE(GtkHexView, gtk_hex_view, GTK_TYPE_CONTENT_VIEW); /****************************************************************************** * * * Paramètres : class = classe GTK à initialiser. * * * * Description : Procède à l'initialisation de l'afficheur générique. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ static void gtk_hex_view_class_init(GtkHexViewClass *class) { GObjectClass *object; /* Plus haut niveau équivalent */ GtkWidgetClass *widget; /* Classe de haut niveau */ object = G_OBJECT_CLASS(class); object->dispose = (GObjectFinalizeFunc/* ! */)gtk_hex_view_dispose; object->finalize = (GObjectFinalizeFunc)gtk_hex_view_finalize; widget = GTK_WIDGET_CLASS(class); gtk_widget_class_set_css_name(widget, "GtkHexView"); g_type_ensure(GTK_TYPE_COMPOSING_AREA); gtk_widget_class_set_template_from_resource(widget, "/re/chrysalide/framework/gtkext/hexview.ui"); gtk_widget_class_bind_template_child(widget, GtkHexView, offsets); gtk_widget_class_bind_template_child(widget, GtkHexView, hex); gtk_widget_class_bind_template_child(widget, GtkHexView, ascii); gtk_widget_class_bind_template_child(widget, GtkHexView, vscroll); widget->size_allocate = gtk_hex_view_size_allocate; widget->get_request_mode = gtk_hex_view_get_request_mode; widget->measure = gtk_hex_view_measure; } /****************************************************************************** * * * Paramètres : view = composant GTK à initialiser. * * * * Description : Procède à l'initialisation de l'afficheur générique. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ static void gtk_hex_view_init(GtkHexView *view) { gtk_widget_init_template(GTK_WIDGET(view)); g_raw_scan_cache_register_snapshot(GTK_COMPOSING_AREA(view->offsets), demo_snapshot, GTK_WIDGET(view)); g_raw_scan_cache_register_snapshot(GTK_COMPOSING_AREA(view->hex), demo_snapshot, GTK_WIDGET(view)); g_raw_scan_cache_register_snapshot(GTK_COMPOSING_AREA(view->ascii), demo_snapshot, GTK_WIDGET(view)); view->need_vscrolling = true; } /****************************************************************************** * * * Paramètres : view = instance d'objet GLib à traiter. * * * * Description : Supprime toutes les références externes. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ static void gtk_hex_view_dispose(GtkHexView *view) { gtk_widget_dispose_template(GTK_WIDGET(view), GTK_TYPE_HEX_VIEW); G_OBJECT_CLASS(gtk_hex_view_parent_class)->dispose(G_OBJECT(view)); } /****************************************************************************** * * * Paramètres : view = instance d'objet GLib à traiter. * * * * Description : Procède à la libération totale de la mémoire. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ static void gtk_hex_view_finalize(GtkHexView *view) { G_OBJECT_CLASS(gtk_hex_view_parent_class)->finalize(G_OBJECT(view)); } void demo_snapshot (GtkWidget *widget, GtkSnapshot *snapshot, GtkWidget *parent) { GdkRGBA red, green, yellow, blue; float w, h; gdk_rgba_parse (&red, "red"); gdk_rgba_parse (&green, "green"); gdk_rgba_parse (&yellow, "yellow"); gdk_rgba_parse (&blue, "blue"); w = gtk_widget_get_width (widget) / 2.0; h = gtk_widget_get_height (widget) / 2.0; h /= 2.0; gtk_snapshot_append_color (snapshot, &red, &GRAPHENE_RECT_INIT(0, 0, w, h)); gtk_snapshot_append_color (snapshot, &green, &GRAPHENE_RECT_INIT(w, 0, w, h)); gtk_snapshot_append_color (snapshot, &yellow, &GRAPHENE_RECT_INIT(0, h, w, h)); gtk_snapshot_append_color (snapshot, &blue, &GRAPHENE_RECT_INIT(w, h, w, h)); cairo_t *cr; int x; x = 0; cr = gtk_snapshot_append_cairo(snapshot, &GRAPHENE_RECT_INIT(0, 0, w * 2, h * 2)); g_token_style_draw_text(GTK_CONTENT_VIEW(parent)->style, TRT_RAW_FULL, cr, &x, 0, "A.A", 3); g_token_style_draw_text(GTK_CONTENT_VIEW(parent)->style, TRT_RAW_NULL, cr, &x, 0, "A.A", 3); cairo_destroy(cr); } bool g_buffer_view_allocate_widths(void *ptr, int width, int height, int fill, int *out); bool g_buffer_view_allocate_widths(void *ptr, int width, int height, int fill, int *out) { int i; /* Boucle de parcours */ for (i = 0; i < fill; i++) { if (i == 0) { out[0] = 40; } else if ((i + 1) == fill) { out[i] = width; } else { out[i] = 230; } width -= out[i]; } return false; } int g_buffer_view_measure_height(void *ptr, int width); int g_buffer_view_measure_height(void *ptr, int width) { int result; /* Mesure à retourner */ if (width == -1) result = 1; else result = 5000 / width; result *= 16; return result; } /* ---------------------------------------------------------------------------------- */ /* IMPLEMENTATION DES FONCTIONS DE CLASSE */ /* ---------------------------------------------------------------------------------- */ /****************************************************************************** * * * Paramètres : widget = composant GTK à examiner. * * width = largeur affectée au composant graphique. * * height = hauteur affectée au composant graphique. * * baseline = ligne de base affectée au composant graphique. * * * * Description : Prend acte de la taille allouée au composant d'affichage. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ static void gtk_hex_view_size_allocate(GtkWidget *widget, int width, int height, int baseline) { GtkHexView *view; /* Version spécialisée */ int vscroll_width; /* Largeur idéale de la barre */ GtkAllocation allocated; /* Zone allouée */ size_t i; /* Boucle de parcours */ int sub_widths[_CHILDREN_COUNT - 1]; /* Sous-largeurs calculées */ view = GTK_HEX_VIEW(widget); allocated.y = 0; allocated.height = height; /* Barre de défilement ? */ view->need_vscrolling = g_buffer_view_allocate_widths(NULL, width, height, _CHILDREN_COUNT - 1, sub_widths); gtk_widget_set_visible(view->vscroll, view->need_vscrolling); if (view->need_vscrolling) { gtk_widget_remove_css_class(widget, "without_vscroll"); gtk_widget_add_css_class(widget, "with_vscroll"); } else { gtk_widget_remove_css_class(widget, "with_vscroll"); gtk_widget_add_css_class(widget, "without_vscroll"); } /** * Validité de la consistence des feuilles CSS : le changement de classe * ne doit pas faire évoluer les tailles. */ assert(view->need_vscrolling == g_buffer_view_allocate_widths(NULL, width, height, _CHILDREN_COUNT - 1, sub_widths)); if (view->need_vscrolling) { gtk_widget_measure(view->vscroll, GTK_ORIENTATION_HORIZONTAL, height, &vscroll_width, NULL, NULL, NULL); allocated.x = width - vscroll_width; allocated.width = vscroll_width; gtk_widget_size_allocate(view->vscroll, &allocated, baseline); width -= vscroll_width; } /* Placement des composants d'affichage */ g_buffer_view_allocate_widths(NULL, width, height, _CHILDREN_COUNT - 1, sub_widths); allocated.x = 0; for (i = 0; i < (_CHILDREN_COUNT - 1); i++) { allocated.width = sub_widths[i]; gtk_widget_size_allocate(view->children[i], &allocated, baseline); allocated.x += sub_widths[i]; } } /****************************************************************************** * * * Paramètres : widget = composant GTK à consulter. * * * * Description : Fournit le mode de calcul pour déterminer la taille. * * * * Retour : Mode de calcul adapté au composant graphique. * * * * Remarques : - * * * ******************************************************************************/ static GtkSizeRequestMode gtk_hex_view_get_request_mode(GtkWidget *widget) { GtkSizeRequestMode result; /* Configuration à remonter */ result = GTK_SIZE_REQUEST_HEIGHT_FOR_WIDTH; return result; } /****************************************************************************** * * * Paramètres : widget = composant GTK à examiner. * * orientation = direction à observer pour les calculs. * * for_size = taille de la direction opposée. * * minimum = taille minimale pour le composant. [OUT] * * natural = taille idéale pour le composant. [OUT] * * min_baseline = ligne de base minimale. [OUT] * * nat_baseline = ligne de base idéale. [OUT] * * * * Description : Fournit les mesures mainimale et idéale du composant. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ static void gtk_hex_view_measure(GtkWidget *widget, GtkOrientation orientation, int for_size, int *minimum, int *natural, int *min_baseline, int *nat_baseline) { GtkHexView *view; /* Version spécialisée */ int requested; /* Taille requise à priori */ size_t i; /* Boucle de parcours */ int min; /* Valeur minimale locale */ int nat; /* Valeur idéale locale */ view = GTK_HEX_VIEW(widget); /* Demande de hauteur minimale / idéale */ if (orientation == GTK_ORIENTATION_VERTICAL) { requested = g_buffer_view_measure_height(NULL, for_size); if (minimum != NULL) *minimum = requested; if (natural != NULL) *natural = requested; for (i = 0; i < _CHILDREN_COUNT; i++) { gtk_widget_measure(view->children[i], GTK_ORIENTATION_VERTICAL, -1, &min, &nat, NULL, NULL); if (minimum != NULL && min > *minimum) *minimum = min; if (natural != NULL && nat > *natural) *natural = nat; } } /* Demande de largeur minimale / idéale */ else { if (minimum != NULL) *minimum = 0; if (natural != NULL) *natural = 0; for (i = 0; i < _CHILDREN_COUNT; i++) { gtk_widget_measure(view->children[i], GTK_ORIENTATION_HORIZONTAL, -1, &min, &nat, NULL, NULL); if (minimum != NULL) *minimum += min; if (natural != NULL) *natural += nat; } } if (min_baseline != NULL) *min_baseline = -1; if (nat_baseline != NULL) *nat_baseline = -1; }