From 19516ffcca14abb082c5109125b7249bdc7fc199 Mon Sep 17 00:00:00 2001 From: Cyrille Bagard Date: Thu, 23 Jul 2020 13:21:16 +0200 Subject: Renamed some files. --- plugins/pychrysalide/glibext/buffercache.c | 4 +- plugins/pychrysalide/glibext/bufferline.c | 4 +- plugins/pychrysalide/glibext/bufferview.c | 4 +- plugins/pychrysalide/glibext/constants.c | 2 +- src/analysis/binary.h | 2 +- src/analysis/block.h | 2 +- src/analysis/db/items/comment.h | 2 +- src/analysis/disass/output.h | 2 +- src/arch/operand.h | 2 +- src/arch/operands/feeder.h | 2 +- src/arch/register.h | 2 +- src/glibext/Makefile.am | 12 +- src/glibext/buffercache-int.h | 96 ++ src/glibext/buffercache.c | 1725 ++++++++++++++++++++++++++++ src/glibext/buffercache.h | 133 +++ src/glibext/bufferline.c | 1558 +++++++++++++++++++++++++ src/glibext/bufferline.h | 218 ++++ src/glibext/bufferview.c | 1285 +++++++++++++++++++++ src/glibext/bufferview.h | 115 ++ src/glibext/gbuffercache-int.h | 96 -- src/glibext/gbuffercache.c | 1725 ---------------------------- src/glibext/gbuffercache.h | 133 --- src/glibext/gbufferline.c | 1558 ------------------------- src/glibext/gbufferline.h | 218 ---- src/glibext/gbufferview.c | 1285 --------------------- src/glibext/gbufferview.h | 115 -- src/glibext/generators/hex.c | 2 +- src/glibext/generators/prologue.c | 2 +- src/glibext/generators/rborder.c | 2 +- src/glibext/gwidthtracker.c | 1271 -------------------- src/glibext/gwidthtracker.h | 95 -- src/glibext/linegen.h | 2 +- src/glibext/widthtracker.c | 1271 ++++++++++++++++++++ src/glibext/widthtracker.h | 95 ++ src/gtkext/gtkblockdisplay.h | 2 +- src/gtkext/gtkbufferdisplay.h | 2 +- 36 files changed, 6522 insertions(+), 6522 deletions(-) create mode 100644 src/glibext/buffercache-int.h create mode 100644 src/glibext/buffercache.c create mode 100644 src/glibext/buffercache.h create mode 100644 src/glibext/bufferline.c create mode 100644 src/glibext/bufferline.h create mode 100644 src/glibext/bufferview.c create mode 100644 src/glibext/bufferview.h delete mode 100644 src/glibext/gbuffercache-int.h delete mode 100644 src/glibext/gbuffercache.c delete mode 100644 src/glibext/gbuffercache.h delete mode 100644 src/glibext/gbufferline.c delete mode 100644 src/glibext/gbufferline.h delete mode 100644 src/glibext/gbufferview.c delete mode 100644 src/glibext/gbufferview.h delete mode 100644 src/glibext/gwidthtracker.c delete mode 100644 src/glibext/gwidthtracker.h create mode 100644 src/glibext/widthtracker.c create mode 100644 src/glibext/widthtracker.h diff --git a/plugins/pychrysalide/glibext/buffercache.c b/plugins/pychrysalide/glibext/buffercache.c index fec5844..019d981 100644 --- a/plugins/pychrysalide/glibext/buffercache.c +++ b/plugins/pychrysalide/glibext/buffercache.c @@ -1,6 +1,6 @@ /* Chrysalide - Outil d'analyse de fichiers binaires - * buffercache.c - équivalent Python du fichier "glibext/gbuffercache.c" + * buffercache.c - équivalent Python du fichier "glibext/buffercache.c" * * Copyright (C) 2018-2019 Cyrille Bagard * @@ -28,7 +28,7 @@ #include -#include +#include #include diff --git a/plugins/pychrysalide/glibext/bufferline.c b/plugins/pychrysalide/glibext/bufferline.c index af3cf1d..dc59b85 100644 --- a/plugins/pychrysalide/glibext/bufferline.c +++ b/plugins/pychrysalide/glibext/bufferline.c @@ -1,6 +1,6 @@ /* Chrysalide - Outil d'analyse de fichiers binaires - * bufferline.c - équivalent Python du fichier "glibext/gbufferline.h" + * bufferline.c - équivalent Python du fichier "glibext/bufferline.h" * * Copyright (C) 2018-2019 Cyrille Bagard * @@ -31,7 +31,7 @@ #include -#include +#include #include diff --git a/plugins/pychrysalide/glibext/bufferview.c b/plugins/pychrysalide/glibext/bufferview.c index 725dd1a..98cc10a 100644 --- a/plugins/pychrysalide/glibext/bufferview.c +++ b/plugins/pychrysalide/glibext/bufferview.c @@ -1,6 +1,6 @@ /* Chrysalide - Outil d'analyse de fichiers binaires - * bufferview.c - équivalent Python du fichier "glibext/gbufferview.c" + * bufferview.c - équivalent Python du fichier "glibext/bufferview.c" * * Copyright (C) 2019 Cyrille Bagard * @@ -28,7 +28,7 @@ #include -#include +#include #include "../access.h" diff --git a/plugins/pychrysalide/glibext/constants.c b/plugins/pychrysalide/glibext/constants.c index a7938cb..3f657e2 100644 --- a/plugins/pychrysalide/glibext/constants.c +++ b/plugins/pychrysalide/glibext/constants.c @@ -26,9 +26,9 @@ #include +#include #include #include -#include #include diff --git a/src/analysis/binary.h b/src/analysis/binary.h index 178d186..194ccd0 100644 --- a/src/analysis/binary.h +++ b/src/analysis/binary.h @@ -36,7 +36,7 @@ #include "../arch/processor.h" #include "../format/debuggable.h" #include "../format/executable.h" -#include "../glibext/gbuffercache.h" +#include "../glibext/buffercache.h" diff --git a/src/analysis/block.h b/src/analysis/block.h index f902db0..63f0be0 100644 --- a/src/analysis/block.h +++ b/src/analysis/block.h @@ -33,7 +33,7 @@ #include "../arch/instruction.h" #include "../arch/vmpa.h" #include "../common/bits.h" -#include "../glibext/gbufferview.h" +#include "../glibext/bufferview.h" #include "../glibext/linesegment.h" diff --git a/src/analysis/db/items/comment.h b/src/analysis/db/items/comment.h index 4eb1160..7049b28 100644 --- a/src/analysis/db/items/comment.h +++ b/src/analysis/db/items/comment.h @@ -30,7 +30,7 @@ #include "../../../arch/vmpa.h" -#include "../../../glibext/gbufferline.h" +#include "../../../glibext/bufferline.h" diff --git a/src/analysis/disass/output.h b/src/analysis/disass/output.h index 6b00250..20729d2 100644 --- a/src/analysis/disass/output.h +++ b/src/analysis/disass/output.h @@ -28,7 +28,7 @@ #include "../binary.h" #include "../human/lang.h" #include "../../format/preload.h" -#include "../../glibext/gbuffercache.h" +#include "../../glibext/buffercache.h" #include "../../gtkext/gtkstatusstack.h" diff --git a/src/arch/operand.h b/src/arch/operand.h index 5789169..faeab49 100644 --- a/src/arch/operand.h +++ b/src/arch/operand.h @@ -30,7 +30,7 @@ #include "../common/packed.h" #include "../format/format.h" -#include "../glibext/gbufferline.h" +#include "../glibext/bufferline.h" diff --git a/src/arch/operands/feeder.h b/src/arch/operands/feeder.h index 7cea504..d2b2cff 100644 --- a/src/arch/operands/feeder.h +++ b/src/arch/operands/feeder.h @@ -31,7 +31,7 @@ #include "../../common/packed.h" #include "../../format/format.h" -#include "../../glibext/gbufferline.h" +#include "../../glibext/bufferline.h" diff --git a/src/arch/register.h b/src/arch/register.h index 48e8eff..10fa428 100644 --- a/src/arch/register.h +++ b/src/arch/register.h @@ -29,7 +29,7 @@ #include -#include "../glibext/gbufferline.h" +#include "../glibext/bufferline.h" diff --git a/src/glibext/Makefile.am b/src/glibext/Makefile.am index 4739fef..118ca39 100644 --- a/src/glibext/Makefile.am +++ b/src/glibext/Makefile.am @@ -4,6 +4,10 @@ BUILT_SOURCES = chrysamarshal.h chrysamarshal.c noinst_LTLIBRARIES = libglibext.la libglibext_la_SOURCES = \ + buffercache-int.h \ + buffercache.h buffercache.c \ + bufferline.h bufferline.c \ + bufferview.h bufferview.c \ chrysamarshal.h chrysamarshal.c \ configuration.h configuration.c \ delayed-int.h \ @@ -11,17 +15,12 @@ libglibext_la_SOURCES = \ gbinarycursor.h gbinarycursor.c \ gbinportion-int.h \ gbinportion.h gbinportion.c \ - gbuffercache-int.h \ - gbuffercache.h gbuffercache.c \ - gbufferline.h gbufferline.c \ - gbufferview.h gbufferview.c \ gdisplayoptions.h gdisplayoptions.c \ glinecursor-int.h \ glinecursor.h glinecursor.c \ gloadedpanel-int.h \ gloadedpanel.h gloadedpanel.c \ gnhash.h gnhash.c \ - gwidthtracker.h gwidthtracker.c \ linecolumn.h linecolumn.c \ linegen-int.h \ linegen.h linegen.c \ @@ -29,7 +28,8 @@ libglibext_la_SOURCES = \ objhole.h \ proto.h \ seq.h seq.c \ - signal.h signal.c + signal.h signal.c \ + widthtracker.h widthtracker.c libglibext_la_LIBADD = \ generators/libglibextgenerators.la diff --git a/src/glibext/buffercache-int.h b/src/glibext/buffercache-int.h new file mode 100644 index 0000000..3dfd5e2 --- /dev/null +++ b/src/glibext/buffercache-int.h @@ -0,0 +1,96 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * buffercache-int.h - définitions internes d'affichage à la demande d'un ensemble de lignes + * + * Copyright (C) 2020 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 . + */ + + +#ifndef _GLIBEXT_BUFFERCACHE_INT_H +#define _GLIBEXT_BUFFERCACHE_INT_H + + +#include "buffercache.h" + + + +/* --------------------- FONCTIONS AUXILIAIRES DE MANIPULATIONS --------------------- */ + + +/* Informations rattachées à la génération d'une ligne */ +typedef struct _generator_link +{ + GLineGenerator *instance; /* Fournisseur de contenu */ + size_t repeat; /* Compteur de successions */ + +} generator_link; + +/* Suivi interne de l'état d'une ligne */ +typedef struct _cache_info +{ + union + { + generator_link generator; /* Générateur unique */ + generator_link *generators; /* Liste de générateurs */ + }; + size_t count; /* Taille de cette liste */ + + GBufferLine *line; /* Ligne en place ou NULL */ + + BufferLineFlags extra_flags; /* Propriétés supplémentaires */ + +} cache_info; + + + +/* -------------------------- TAMPON POUR CODE DESASSEMBLE -------------------------- */ + + +/* Tampon pour gestion de lignes optimisée (instance) */ +struct _GBufferCache +{ + GObject parent; /* A laisser en premier */ + + GBinContent *content; /* Contenu binaire global */ + + cache_info *lines; /* Liste des lignes intégrées */ + size_t count; /* Quantité en cache */ + size_t used; /* Quantité utilisée */ + + GWidthTracker *tracker; /* Suivi des largeurs */ + +}; + +/* Tampon pour gestion de lignes optimisée (classe) */ +struct _GBufferCacheClass +{ + GObjectClass parent; /* A laisser en premier */ + + gint line_height; /* Hauteur maximale des lignes */ + gint left_margin; /* Marge gauche + espace */ + gint text_pos; /* Début d'impression du code */ + + /* Signaux */ + + void (* size_changed) (GBufferCache *, bool, size_t, size_t); + +}; + + + +#endif /* _GLIBEXT_BUFFERCACHE_INT_H */ diff --git a/src/glibext/buffercache.c b/src/glibext/buffercache.c new file mode 100644 index 0000000..16d96dc --- /dev/null +++ b/src/glibext/buffercache.c @@ -0,0 +1,1725 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * buffercache.c - affichage à la demande d'un ensemble de lignes + * + * Copyright (C) 2016-2019 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 "buffercache.h" + + +#include +#include +#include + + +#include "buffercache-int.h" +#include "chrysamarshal.h" + + + +/* --------------------- FONCTIONS AUXILIAIRES DE MANIPULATIONS --------------------- */ + + +/* Gros verrou global pour alléger les structures... */ +G_LOCK_DEFINE_STATIC(_line_update); + + +/* Met en place un nouvel ensemble d'information sur une ligne. */ +static void init_cache_info(cache_info *, GLineGenerator *, size_t, BufferLineFlags); + +/* Libère la mémoire occupée par des informations sur une ligne. */ +static void release_cache_info(cache_info *); + +/* Ajoute un générateur aux informations sur une ligne. */ +static void extend_cache_info(cache_info *, GLineGenerator *, BufferLineFlags); + +/* Retire un générateur aux informations d'une ligne. */ +static void remove_from_cache_info(cache_info *, GLineGenerator *); + +/* Retrouve l'emplacement correspondant à une position de ligne. */ +static void get_cache_info_cursor(const cache_info *, size_t, gint, GLineCursor **); + +/* Suivit les variations du compteur de références d'une ligne. */ +static void on_line_ref_toggle(cache_info *, GBufferLine *, gboolean); + +/* Fournit la ligne de tampon correspondant aux générateurs. */ +static GBufferLine *get_cache_info_line(cache_info *, size_t, const GBinContent *); + +/* Force la réinitialisation d'une éventuelle ligne cachée. */ +static void _reset_cache_info_line_unlocked(cache_info *); + +/* Force la réinitialisation d'une éventuelle ligne cachée. */ +static void reset_cache_info_line(cache_info *); + + + +/* -------------------------- TAMPON POUR CODE DESASSEMBLE -------------------------- */ + + +/* Taille des allocations de masse */ +#define LINE_ALLOC_BULK 1000 + + +/* Procède à l'initialisation d'une classe de tampon de lignes. */ +static void g_buffer_cache_class_init(GBufferCacheClass *); + +/* Procède à l'initialisation d'un tampon de gestion de lignes. */ +static void g_buffer_cache_init(GBufferCache *); + +/* Supprime toutes les références externes. */ +static void g_buffer_cache_dispose(GBufferCache *); + +/* Procède à la libération totale de la mémoire. */ +static void g_buffer_cache_finalize(GBufferCache *); + +/* Calcule l'indice d'apparition d'un générateur dans le tampon. */ +static size_t g_buffer_cache_compute_repetition(GBufferCache *, size_t, GLineGenerator *); + + + +/* ---------------------------------------------------------------------------------- */ +/* FONCTIONS AUXILIAIRES DE MANIPULATIONS */ +/* ---------------------------------------------------------------------------------- */ + + +/****************************************************************************** +* * +* Paramètres : info = informations concernant une ligne à constituer. * +* generator = générateur à associer à toutes les lignes. * +* repeat = compteur de répétition entre les lignes. * +* flags = propriétés supplémentaires à associer à la ligne.* +* * +* Description : Met en place un nouvel ensemble d'information sur une ligne. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void init_cache_info(cache_info *info, GLineGenerator *generator, size_t repeat, BufferLineFlags flags) +{ + info->generator.instance = generator; + info->generator.repeat = repeat; + + g_object_ref(G_OBJECT(generator)); + + info->count = 1; + + info->line = NULL; + + info->extra_flags = flags; + +} + + +/****************************************************************************** +* * +* Paramètres : info = informations concernant une ligne à constituer. * +* * +* Description : Libère la mémoire occupée par des informations sur une ligne.* +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void release_cache_info(cache_info *info) +{ + size_t i; /* Boucle de parcours */ + + if (info->count == 1) + g_object_unref(G_OBJECT(info->generator.instance)); + + else + for (i = 0; i < info->count; i++) + g_object_unref(G_OBJECT(info->generators[i].instance)); + + reset_cache_info_line(info); + +} + + +/****************************************************************************** +* * +* Paramètres : info = informations concernant une ligne à actualiser. * +* generator = générateur à associer à toutes les lignes. * +* flags = propriétés supplémentaires à associer à la ligne.* +* * +* Description : Ajoute un générateur aux informations sur une ligne. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void extend_cache_info(cache_info *info, GLineGenerator *generator, BufferLineFlags flags) +{ + generator_link first; /* Générateur déjà en place */ + generator_link *new; /* Nouveau générateur placé */ + + if (info->count == 1) + { + first = info->generator; + + info->generators = (generator_link *)calloc(2, sizeof(generator_link)); + + info->generators[0] = first; + info->count = 2; + + new = &info->generators[1]; + + } + else + { + info->generators = (generator_link *)realloc(info->generators, + ++info->count * sizeof(generator_link)); + + new = &info->generators[info->count - 1]; + + } + + new->instance = generator; + new->repeat = 0; + + g_object_ref(G_OBJECT(generator)); + + reset_cache_info_line(info); + + /** + * On peut rajouter des indications, mais, en cas de retrait d'un générateur, + * on ne saura pas forcément lesquelles retirer puisque qu'on ne trace pas + * leur origine. + * + * On considère donc que seul le premier générateur (le principal) a le + * droit de poser des fanions. + */ + + assert(flags == BLF_NONE); + +} + + +/****************************************************************************** +* * +* Paramètres : info = informations concernant une ligne à actualiser. * +* generator = générateur à dissocier de toutes les lignes. * +* * +* Description : Retire un générateur aux informations d'une ligne. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void remove_from_cache_info(cache_info *info, GLineGenerator *generator) +{ + generator_link *link; /* Accès simplifié */ + size_t i; /* Boucle de parcours */ + generator_link *old; /* Mémorisation avant opérat° */ + + if (info->count == 1) + { + link = &info->generator; + + assert(link->instance == generator); + + g_object_unref(G_OBJECT(generator)); + + info->count = 0; + + } + + else + { + for (i = 0; i < info->count; i++) + { + link = &info->generators[i]; + + if (link->instance == generator) + { + if ((i + 1) < info->count) + memmove(&info->generators[i], &info->generators[i + 1], + (info->count - i - 1) * sizeof(generator_link)); + + if (info->count == 2) + { + old = info->generators; + + info->count = 1; + info->generator = info->generators[0]; + + free(old); + + } + else + info->generators = (generator_link *)realloc(info->generators, + --info->count * sizeof(generator_link)); + + g_object_unref(G_OBJECT(generator)); + + break; + + } + + } + +#ifndef NDEBUG + + /** + * Attention : si l'élément était en dernière position, + * l'indice de parcours est désormais égal au nombre de générateurs présents ! + */ + assert(i <= info->count); + + for ( ; i < info->count; i++) + { + link = &info->generators[i]; + + assert(link->instance != generator); + + } + +#endif + + } + + reset_cache_info_line(info); + +} + + +/****************************************************************************** +* * +* Paramètres : info = informations sur une ligne à venir consulter. * +* index = indice de la ligne visée par la consultation. * +* x = position géographique sur la ligne concernée. * +* cursor = emplacement à constituer. [OUT] * +* * +* Description : Retrouve l'emplacement correspondant à une position de ligne.* +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void get_cache_info_cursor(const cache_info *info, size_t index, gint x, GLineCursor **cursor) +{ + const generator_link *generator; /* Générateur retenu */ + + if (info->count == 1) + generator = &info->generator; + else + generator = &info->generators[0]; + + *cursor = g_line_generator_compute_cursor(generator->instance, x, index, generator->repeat); + +} + + +/****************************************************************************** +* * +* Paramètres : info = informations sur une ligne à venir manipuler. * +* line = tampon de lignes à venir supprimer au besoin. * +* last = indication sur la valeur du compteur de références. * +* * +* Description : Suivit les variations du compteur de références d'une ligne. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void on_line_ref_toggle(cache_info *info, GBufferLine *line, gboolean last) +{ + if (last) + { + G_LOCK(_line_update); + + assert(info->line != NULL); + + _reset_cache_info_line_unlocked(info); + + G_UNLOCK(_line_update); + + } + +} + + +/****************************************************************************** +* * +* Paramètres : info = informations sur une ligne à venir manipuler. * +* index = indice de la ligne à constituer. * +* content = éventuel contenu binaire brut à imprimer. * +* * +* Description : Fournit la ligne de tampon correspondant aux générateurs. * +* * +* Retour : Ligne déjà en place ou créée pour le besoin. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static GBufferLine *get_cache_info_line(cache_info *info, size_t index, const GBinContent *content) +{ + GBufferLine *result; /* Construction à retourner */ + size_t i; /* Boucle de parcours */ + + G_LOCK(_line_update); + + result = info->line; + + if (result == NULL) + { + result = g_buffer_line_new(UNUSED_MRANGE_PTR, 0/* !! */); + + g_object_add_toggle_ref(G_OBJECT(result), (GToggleNotify)on_line_ref_toggle, info); + + if (info->count == 1) + g_line_generator_print(info->generator.instance, result, index, + info->generator.repeat, content); + + else + for (i = 0; i < info->count; i++) + g_line_generator_print(info->generators[i].instance, result, index, + info->generators[i].repeat, content); + + info->line = result; + + } + + else + g_object_ref(G_OBJECT(result)); + + G_UNLOCK(_line_update); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : info = informations sur une ligne à venir manipuler. * +* * +* Description : Force la réinitialisation d'une éventuelle ligne cachée. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void _reset_cache_info_line_unlocked(cache_info *info) +{ + if (info->line != NULL) + { + g_object_remove_toggle_ref(G_OBJECT(info->line), (GToggleNotify)on_line_ref_toggle, info); + + info->line = NULL; + + } + +} + + +/****************************************************************************** +* * +* Paramètres : info = informations sur une ligne à venir manipuler. * +* * +* Description : Force la réinitialisation d'une éventuelle ligne cachée. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void reset_cache_info_line(cache_info *info) +{ + G_LOCK(_line_update); + + _reset_cache_info_line_unlocked(info); + + G_UNLOCK(_line_update); + +} + + + +/* ---------------------------------------------------------------------------------- */ +/* TAMPON POUR CODE DESASSEMBLE */ +/* ---------------------------------------------------------------------------------- */ + + +/* Détermine le type du composant de tampon pour gestion de lignes optimisée. */ +G_DEFINE_TYPE(GBufferCache, g_buffer_cache, G_TYPE_OBJECT); + + +/****************************************************************************** +* * +* Paramètres : class = classe de composant GLib à initialiser. * +* * +* Description : Procède à l'initialisation d'une classe de tampon de lignes. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_buffer_cache_class_init(GBufferCacheClass *class) +{ + GObjectClass *object; /* Autre version de la classe */ + + object = G_OBJECT_CLASS(class); + + object->dispose = (GObjectFinalizeFunc/* ! */)g_buffer_cache_dispose; + object->finalize = (GObjectFinalizeFunc)g_buffer_cache_finalize; + + class->line_height = 17; + class->left_margin = 2 * class->line_height; + class->text_pos = 2.5 * class->line_height; + + /* Signaux */ + + g_signal_new("size-changed", + G_TYPE_BUFFER_CACHE, + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET(GBufferCacheClass, size_changed), + NULL, NULL, + g_cclosure_user_marshal_VOID__BOOLEAN_ULONG_ULONG, + G_TYPE_NONE, 3, G_TYPE_BOOLEAN, G_TYPE_ULONG, G_TYPE_ULONG); + +} + + +/****************************************************************************** +* * +* Paramètres : cache = composant GLib à initialiser. * +* * +* Description : Procède à l'initialisation d'un tampon de gestion de lignes. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_buffer_cache_init(GBufferCache *cache) +{ + cache->content = NULL; + + cache->lines = NULL; + cache->count = 0; + cache->used = 0; + + cache->tracker = g_width_tracker_new(cache); + +} + + +/****************************************************************************** +* * +* Paramètres : cache = instance d'objet GLib à traiter. * +* * +* Description : Supprime toutes les références externes. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_buffer_cache_dispose(GBufferCache *cache) +{ + size_t i; /* Boucle de parcours #1 */ + cache_info *info; /* Accès direct à une ligne */ + size_t j; /* Boucle de parcours #2 */ + + g_clear_object(&cache->content); + + for (i = 0; i < cache->used; i++) + { + info = &cache->lines[i]; + + if (info->count == 1) + g_clear_object(&info->generator.instance); + + else + for (j = 0; j < info->count; j++) + g_clear_object(&info->generators[j].instance); + + g_clear_object(&info->line); + + } + + g_clear_object(&cache->tracker); + + G_OBJECT_CLASS(g_buffer_cache_parent_class)->dispose(G_OBJECT(cache)); + +} + + +/****************************************************************************** +* * +* Paramètres : cache = instance d'objet GLib à traiter. * +* * +* Description : Procède à la libération totale de la mémoire. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_buffer_cache_finalize(GBufferCache *cache) +{ + size_t i; /* Boucle de parcours */ + cache_info *info; /* Accès direct à une ligne */ + + for (i = 0; i < cache->used; i++) + { + info = &cache->lines[i]; + + if (info->count > 1) + free(info->generators); + + } + + if (cache->lines != NULL) + free(cache->lines); + + G_OBJECT_CLASS(g_buffer_cache_parent_class)->finalize(G_OBJECT(cache)); + +} + + +/****************************************************************************** +* * +* Paramètres : content = éventuel contenu binaire brut à référencer. * +* * +* Description : Crée un nouveau composant de tampon pour code désassemblé. * +* * +* Retour : Composant GLib créé. * +* * +* Remarques : - * +* * +******************************************************************************/ + +GBufferCache *g_buffer_cache_new(GBinContent *content) +{ + GBufferCache *result; /* Composant à retourner */ + + result = g_object_new(G_TYPE_BUFFER_CACHE, NULL); + + if (content != NULL) + { + result->content = content; + g_object_ref(G_OBJECT(content)); + } + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : cache = tampon de lignes à consulter. * +* * +* Description : Fournit la hauteur d'impression d'une ligne visualisée. * +* * +* Retour : Hauteur de ligne en pixels. * +* * +* Remarques : - * +* * +******************************************************************************/ + +gint g_buffer_cache_get_line_height(const GBufferCache *cache) +{ + GBufferCacheClass *class; /* Classe des tampons */ + + class = G_BUFFER_CACHE_GET_CLASS(cache); + + return class->line_height; + +} + + +/****************************************************************************** +* * +* Paramètres : cache = tampon de lignes à consulter. * +* * +* Description : Indique l'éventuel contenu binaire associé au cache. * +* * +* Retour : Eventuel contenu renseigné ou NULL. * +* * +* Remarques : - * +* * +******************************************************************************/ + +GBinContent *g_buffer_cache_get_content(const GBufferCache *cache) +{ + GBinContent *result; /* Contenu à retourner */ + + result = cache->content; + + if (result != NULL) + g_object_ref(G_OBJECT(result)); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : cache = tampon de lignes à consulter. * +* * +* Description : Fournit la taille réservée pour la marge gauche. * +* * +* Retour : Largeur en pixels. * +* * +* Remarques : - * +* * +******************************************************************************/ + +gint g_buffer_cache_get_left_margin(const GBufferCache *cache) +{ + GBufferCacheClass *class; /* Classe des tampons */ + + class = G_BUFFER_CACHE_GET_CLASS(cache); + + return class->left_margin; + +} + + +/****************************************************************************** +* * +* Paramètres : cache = tampon de lignes à consulter. * +* * +* Description : Fournit la position de départ pour l'impression de texte. * +* * +* Retour : Position en pixels. * +* * +* Remarques : - * +* * +******************************************************************************/ + +gint g_buffer_cache_get_text_position(const GBufferCache *cache) +{ + GBufferCacheClass *class; /* Classe des tampons */ + + class = G_BUFFER_CACHE_GET_CLASS(cache); + + return class->text_pos; + +} + + +/****************************************************************************** +* * +* Paramètres : cache = instance GLib à consulter. * +* * +* Description : Compte le nombre de lignes rassemblées dans un tampon. * +* * +* Retour : Nombre de lignes constituant le tampon. * +* * +* Remarques : - * +* * +******************************************************************************/ + +size_t g_buffer_cache_count_lines(const GBufferCache *cache) +{ + return cache->used; + +} + + +/****************************************************************************** +* * +* Paramètres : cache = composant GLib à consulter. * +* * +* Description : Fournit un lien vers la structure de suivi de largeurs. * +* * +* Retour : Gestionnaire de largeurs de lignes. * +* * +* Remarques : - * +* * +******************************************************************************/ + +GWidthTracker *g_buffer_cache_get_width_tracker(const GBufferCache *cache) +{ + GWidthTracker *result; /* Instance à retourner * */ + + result = cache->tracker; + + g_object_ref(G_OBJECT(result)); + + return result; + +} + + + + + +/****************************************************************************** +* * +* Paramètres : cache = instance GLib à consulter. * +* index = indice de la ligne où se trouve le générateur. * +* generator = générateur associé à au moins une ligne. * +* * +* Description : Calcule l'indice d'apparition d'un générateur dans le tampon.* +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static size_t g_buffer_cache_compute_repetition(GBufferCache *cache, size_t index, GLineGenerator *generator) +{ + size_t result; /* Compteur à retourner */ + cache_info *info; /* Accès direct à une ligne */ + size_t i; /* Boucle de parcours */ + + result = 0; + + if (index > 0) + { + info = &cache->lines[index - 1]; + + if (info->count == 1) + { + if (info->generator.instance == generator) + result = info->generator.repeat + 1; + + } + + else + for (i = 0; i < info->count; i++) + if (info->generators[i].instance == generator) + { + result = info->generators[i].repeat + 1; + break; + } + + } + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : cache = instance GLib à modifier. * +* index = point d'insertion, puis de sauvegarde. * +* generator = générateur à insérer dans les lignes. * +* flags = propriétés supplémentaires à associer à la ligne.* +* before = précise l'emplacement final des nouvelles lignes.* +* after = précise l'emplacement final des nouvelles lignes.* +* * +* Description : Insère un générateur dans des lignes à une position donnée. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +void g_buffer_cache_insert_at(GBufferCache *cache, size_t index, GLineGenerator *generator, BufferLineFlags flags, bool before, bool after) +{ +#ifndef NDEBUG + GLineCursor *gen_cursor; /* Position du générateur */ + GLineCursor *line_cursor; /* Position de la ligne */ + int ret; /* Bilan de comparaison */ +#endif + size_t needed; /* Emplacements nécessaires */ + size_t i; /* Boucle de parcours */ + + assert(index < cache->used); + + assert(!(before && after)); + +#ifndef NDEBUG + + if (!before && !after) + { + gen_cursor = g_line_generator_compute_cursor(generator, 0, index, 0); + + get_cache_info_cursor(&cache->lines[index], index, 0, &line_cursor); + + ret = g_line_cursor_compare(gen_cursor, line_cursor); + + g_object_unref(G_OBJECT(line_cursor)); + g_object_unref(G_OBJECT(gen_cursor)); + + assert(ret == 0); + + } + +#endif + + /* Cas particulier d'ajout en fin de cache... */ + if (after && (index + 1) == cache->used) + { + g_buffer_cache_append(cache, generator, flags); + goto gbcia_done; + } + + /* Adaptation de l'espace */ + + needed = g_line_generator_count_lines(generator); + + if (before || after) + { + if ((cache->used + needed) >= cache->count) + { + cache->count += needed + LINE_ALLOC_BULK; + cache->lines = (cache_info *)realloc(cache->lines, cache->count * sizeof(cache_info)); + } + } + + else if (needed > 1) + { + if ((cache->used + needed - 1) >= cache->count) + { + cache->count += needed - 1 + LINE_ALLOC_BULK; + cache->lines = (cache_info *)realloc(cache->lines, cache->count * sizeof(cache_info)); + } + } + + /* Insertion du générateur */ + + if (after) + index++; + + if (before || after) + { + memmove(&cache->lines[index + needed], &cache->lines[index], (cache->used - index) * sizeof(cache_info)); + + for (i = 0; i < needed; i++) + init_cache_info(&cache->lines[index + i], generator, i, flags); + + cache->used += needed; + + g_width_tracker_update_added(cache->tracker, index, needed); + + g_signal_emit_by_name(cache, "size-changed", true, index, needed); + + } + + else + { + extend_cache_info(&cache->lines[index], generator, flags); + + g_width_tracker_update(cache->tracker, index); + + if (needed > 1) + { + /* On déborde sur les lignes suivantes, donc on crée de l'espace ! */ + + memmove(&cache->lines[index + 1], + &cache->lines[index + 1 + needed - 1], (cache->used - index - 1) * sizeof(cache_info)); + + for (i = 1; i < needed; i++) + init_cache_info(&cache->lines[index + i], generator, i, BLF_NONE); + + cache->used += needed - 1; + + g_width_tracker_update_added(cache->tracker, index + 1, needed - 1); + + } + + g_signal_emit_by_name(cache, "size-changed", true, index, needed - 1); + + } + + gbcia_done: + + ; + +} + + +/****************************************************************************** +* * +* Paramètres : cache = instance GLib à modifier. * +* index = point de suppression. * +* * +* Description : Retire une ligne du tampon. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +void g_buffer_cache_delete_at(GBufferCache *cache, size_t index) +{ + cache_info *info; /* Accès direct à une ligne */ + + assert(index < cache->used); + + info = &cache->lines[index]; + + release_cache_info(info); + + if ((index + 1) < cache->used) + memmove(&cache->lines[index], &cache->lines[index + 1], + (cache->used - index - 1) * sizeof(cache_info)); + + cache->used--; + + g_width_tracker_update_deleted(cache->tracker, index, index); + + g_signal_emit_by_name(cache, "size-changed", false, index, 1); + +} + + +/****************************************************************************** +* * +* Paramètres : cache = instance GLib à modifier. * +* index = point d'insertion, puis de sauvegarde. * +* type = type de générateurs à retirer des lignes visées. * +* before = précise l'emplacement final de l'élément visé. * +* after = précise l'emplacement final de l'élément visé. * +* * +* Description : Retire un type de générateur de lignes. * +* * +* Retour : Générateur éventuellement trouvé ou NULL si aucun. * +* * +* Remarques : - * +* * +******************************************************************************/ + +GLineGenerator *g_buffer_cache_delete_type_at(GBufferCache *cache, size_t index, GType type, bool before, bool after) +{ + GLineGenerator *result; /* Prédécesseur à retourner */ + cache_info *info; /* Accès direct à une ligne */ + generator_link *link; /* Accès simplifié */ + size_t i; /* Boucle de parcours */ + size_t count; /* Emplacements occupés */ + size_t delete; /* Indice de suppression */ + + assert(index < cache->used); + + assert(!(before && after)); + + result = NULL; + + /* Recherche d'un générateur correspondant */ + + if (before) + info = &cache->lines[index - 1]; + else if (after) + info = &cache->lines[index + 1]; + else + info = &cache->lines[index]; + + if (info->count == 1) + { + link = &info->generator; + + if (G_OBJECT_TYPE(link->instance) == type) + result = link->instance; + + } + + else + for (i = 0; i < info->count && result == NULL; i++) + { + link = &info->generators[i]; + + if (G_OBJECT_TYPE(link->instance) == type) + result = link->instance; + + } + + /* Retrait de l'instance trouvée */ + + if (result != NULL) + { + count = g_line_generator_count_lines(result); + +#ifndef NDEBUG + if (!before && !after) + assert(count == 1); +#endif + + g_object_ref(G_OBJECT(result)); + + /* Suppression de l'élément */ + + for (i = 0; i < count; i++) + { + if (before) + info = &cache->lines[index - 1 - i]; + else if (after) + info = &cache->lines[index + 1 + i]; + else + info = &cache->lines[index]; + + remove_from_cache_info(info, result); + + } + + /* Suppression des lignes associées */ + + for (i = 0; i < count; i++) + { + if (before) + delete = index - 1; + else if (after) + delete = index + 1; + else + delete = index; + + info = &cache->lines[delete]; + + if (info->count == 0) + { + release_cache_info(info); + + if ((delete + 1) < cache->used) + memmove(&cache->lines[delete], &cache->lines[delete + 1], + (cache->used - delete - 1) * sizeof(cache_info)); + + cache->used--; + + g_width_tracker_update_deleted(cache->tracker, delete, delete); + + g_signal_emit_by_name(cache, "size-changed", false, delete, 1); + + } + + } + + } + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : cache = instance GLib à modifier. * +* generator = générateur à associer à toutes les lignes. * +* flags = propriétés supplémentaires à associer à la ligne.* +* * +* Description : Ajoute en fin de tampon un générateur de lignes. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +void g_buffer_cache_append(GBufferCache *cache, GLineGenerator *generator, BufferLineFlags flags) +{ + size_t count; /* Nombre de lignes générées */ + size_t index; /* Point d'insertion */ + size_t i; /* Boucle de parcours */ + cache_info *info; /* Accès direct à une ligne */ + + count = g_line_generator_count_lines(generator); + + assert(count > 0); + + assert((flags != BLF_NONE && count == 1) || flags == BLF_NONE); + + if ((cache->used + count) > cache->count) + { + cache->count += count + LINE_ALLOC_BULK; + cache->lines = (cache_info *)realloc(cache->lines, cache->count * sizeof(cache_info)); + } + + index = cache->used; + + for (i = 0; i < count; i++) + { + info = &cache->lines[index + i]; + + info->generator.instance = generator; + info->generator.repeat = g_buffer_cache_compute_repetition(cache, index + i, generator); + + g_object_ref(G_OBJECT(generator)); + + info->count = 1; + + info->line = NULL; + + info->extra_flags = flags; + + } + + cache->used += count; + + g_width_tracker_update_added(cache->tracker, index, count); + + g_signal_emit_by_name(cache, "size-changed", true, index, count); + +} + + +/****************************************************************************** +* * +* Paramètres : cache = instance GLib à modifier. * +* count = quantité totale de lignes à avoir à disposition. * +* generator = générateur à associer à toutes les lignes. * +* * +* Description : Etend un tampon avec un générateur de lignes unique. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +void g_buffer_cache_extend_with(GBufferCache *cache, size_t count, GLineGenerator *generator) +{ + size_t index; /* Point d'insertion */ + size_t i; /* Boucle de parcours */ + cache_info *info; /* Accès direct à une ligne */ + size_t added; /* Nombre d'ajouts effectués */ + + assert(count >= cache->used); + + if (count > cache->count) + { + cache->lines = (cache_info *)realloc(cache->lines, count * sizeof(cache_info)); + cache->count = count; + } + + index = cache->used; + + for (i = index; i < count; i++) + { + info = &cache->lines[i]; + + info->generator.instance = generator; + info->generator.repeat = g_buffer_cache_compute_repetition(cache, i, generator); + + g_object_ref(G_OBJECT(generator)); + + info->count = 1; + + info->line = NULL; + + } + + added = count - cache->used; + + cache->used = count; + + if (added > 0) + { + g_width_tracker_update_added(cache->tracker, index, added); + + g_signal_emit_by_name(cache, "size-changed", true, index, added); + + } + +} + + +/****************************************************************************** +* * +* Paramètres : cache = instance GLib à modifier. * +* max = nombre maximal de lignes à conserver. * +* * +* Description : Réduit le tampon à une quantité de lignes précise. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +void g_buffer_cache_truncate(GBufferCache *cache, size_t max) +{ + size_t i; /* Boucle de parcours #1 */ + cache_info *info; /* Accès direct à une ligne */ + size_t j; /* Boucle de parcours #2 */ + size_t removed; /* Nombre de retraits effectués*/ + + for (i = max; i < cache->used; i++) + { + info = &cache->lines[i]; + + if (info->count == 1) + g_object_unref(G_OBJECT(info->generator.instance)); + + else + { + for (j = 0; j < info->count; j++) + g_object_unref(G_OBJECT(info->generators[j].instance)); + + free(info->generators); + + } + + reset_cache_info_line(info); + + } + + if (max < cache->used) + { + removed = cache->used - max; + + cache->used = max; + + g_width_tracker_update_deleted(cache->tracker, max, max + removed - 1); + + g_signal_emit_by_name(cache, "size-changed", false, max, removed); + + } + +} + + +/****************************************************************************** +* * +* Paramètres : cache = tampon de lignes à venir consulter. * +* index = indice de la ligne visée par la consultation. * +* x = position géographique sur la ligne concernée. * +* cursor = emplacement à constituer. [OUT] * +* * +* Description : Retrouve l'emplacement correspondant à une position de ligne.* +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +void g_buffer_cache_get_line_cursor(const GBufferCache *cache, size_t index, gint x, GLineCursor **cursor) +{ + assert(index < cache->used); + + get_cache_info_cursor(&cache->lines[index], index, x, cursor); + +} + + +/****************************************************************************** +* * +* Paramètres : cache = tampon de lignes à venir consulter. * +* index = indice de la ligne visée par la consultation. * +* * +* Description : Détermine l'ensemble des propriétés attachées à une ligne. * +* * +* Retour : Somme de toutes les propriétés enregistrées. * +* * +* Remarques : - * +* * +******************************************************************************/ + +BufferLineFlags g_buffer_cache_get_line_flags(const GBufferCache *cache, size_t index) +{ + BufferLineFlags result; /* Somme à renvoyer */ + cache_info *info; /* Accès direct à une ligne */ + const generator_link *generator; /* Générateur retenu */ + size_t i; /* Boucle de parcours */ + + // TODO : check lock + + assert(index < cache->used); + + info = &cache->lines[index]; + + result = info->extra_flags; + + if (info->count == 1) + { + generator = &info->generator; + result |= g_line_generator_get_flags(generator->instance, index, generator->repeat); + } + + else + for (i = 0; i < info->count; i++) + { + generator = &info->generators[i]; + result |= g_line_generator_get_flags(generator->instance, index, generator->repeat); + } + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : cache = tampon de lignes à consulter. * +* index = indice de la ligne recherchée. * +* * +* Description : Retrouve une ligne au sein d'un tampon avec un indice. * +* * +* Retour : Line retrouvée ou NULL en cas d'échec. * +* * +* Remarques : - * +* * +******************************************************************************/ + +GBufferLine *g_buffer_cache_find_line_by_index(const GBufferCache *cache, size_t index) +{ + GBufferLine *result; /* Ligne trouvée à retourner */ + + if (index < cache->used) + result = get_cache_info_line(&cache->lines[index], index, cache->content); + else + result = NULL; + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : cache = tampon de lignes à venir consulter. * +* index = indice de la ligne à mesurer. * +* summary = largeurs maximales à faire évoluer. * +* * +* Description : Fait remonter les largeurs requises par une ligne donnée. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +void g_buffer_cache_collect_widths(GBufferCache *cache, size_t index, line_width_summary *summary) +{ + GBufferLine *line; /* Ligne éphémère à mesurer */ + + line = get_cache_info_line(&cache->lines[index], index, cache->content); + + g_buffer_line_collect_widths(line, summary); + + g_object_unref(G_OBJECT(line)); + +} + + +/****************************************************************************** +* * +* Paramètres : cache = visualisation à représenter. * +* cr = contexte graphique dédié à la procédure. * +* first = première ligne à dessiner. * +* last = dernière ligne à dessiner. * +* area = position et surface à traiter. * +* options = règles d'affichage des colonnes modulables. * +* offsets = décalages supplémentaires à appliquer. * +* selected = ordonnée d'une ligne sélectionnée ou NULL. * +* list = liste de contenus à mettre en évidence. * +* * +* Description : Imprime une partie choisie du tampon contenant des lignes. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +void g_buffer_cache_draw(const GBufferCache *cache, cairo_t *cr, size_t first, size_t last, const cairo_rectangle_int_t *area, const GDisplayOptions *options, const line_width_summary *offsets, const gint *selected, const segcnt_list *list) +{ + GBufferCacheClass *class; /* Classe des tampons */ + gint y; /* Point de départ en ordonnée */ + bool wait_selection; /* Sélection déjà passée ? */ + size_t i; /* Boucle de parcours */ + cache_info *info; /* Accès direct à une ligne */ + line_width_summary summary; /* Résumé concis des largeurs */ + GBufferLine *line; /* Ligne à venir dessiner */ + + class = G_BUFFER_CACHE_GET_CLASS(cache); + + y = 0; + + wait_selection = true; + + if (cache->used > 0) + for (i = first; i <= last; i++) + { + /* Si sélection, on sousligne la ligne concernée */ + if (wait_selection && selected != NULL && *selected == y) + { + cairo_set_source_rgba(cr, 1.0, 1.0, 1.0, 0.05); + + cairo_rectangle(cr, area->x, y, area->width, class->line_height); + cairo_fill(cr); + + wait_selection = false; + + } + + info = &cache->lines[i]; + + if (i == first || (g_buffer_cache_get_line_flags(cache, i) & BLF_WIDTH_MANAGER)) + g_width_tracker_get_local_width_summary(cache->tracker, i, &summary); + + line = get_cache_info_line(info, i, cache->content); + + g_buffer_line_draw(line, cr, &summary, class->text_pos, y, options, offsets, list); + + g_object_unref(G_OBJECT(line)); + + y += class->line_height; + + } + +} + + +/****************************************************************************** +* * +* Paramètres : cache = tampon de lignes à consulter. * +* cursor = emplacement à retrouver dans le tampon. * +* first = indique si on l'arrête à la première ou la dernière.* +* start = borne inférieure des recherches (incluse). * +* end = borne supérieure des recherches (incluse). * +* * +* Description : Indique l'indice correspondant à une adresse donnée. * +* * +* Retour : Indice des infos à l'adresse demandée, ou nombre de lignes. * +* * +* Remarques : - * +* * +******************************************************************************/ + +size_t _g_buffer_cache_find_index_by_cursor(const GBufferCache *cache, const GLineCursor *cursor, bool first, size_t start, size_t end) +{ + size_t result; /* Indice à retourner */ + cache_info *found; /* Eventuel élément trouvé */ + + int find_containing_generator(const GLineCursor *c, const cache_info *i) + { + const generator_link *generator; /* Générateur retenu */ + + if (i->count == 1) + generator = &i->generator; + else + generator = &i->generators[0]; + + return g_line_generator_contain_cursor(generator->instance, + i - cache->lines, generator->repeat, c); + + } + + found = (cache_info *)bsearch(cursor, &cache->lines[start], end - start + 1, + sizeof(cache_info), (__compar_fn_t)find_containing_generator); + + if (found == NULL) + result = cache->used; + + else + { + result = (found - cache->lines); + assert(start <= result && result <= end); + + /* On s'assure d'un arrêt sur la bonne ligne */ + + if (first) + for (; result > start; result--) + { + found = &cache->lines[result - 1]; + + if (find_containing_generator(cursor, found) != 0) + break; + + } + + else + for (; result < end; result++) + { + found = &cache->lines[result + 1]; + + if (find_containing_generator(cursor, found) != 0) + break; + + } + + } + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : cache = tampon de lignes à consulter. * +* cursor = emplacement à retrouver dans le tampon. * +* first = indique si on l'arrête à la première ou la dernière.* +* * +* Description : Indique l'indice correspondant à une adresse donnée. * +* * +* Retour : Indice des infos à l'adresse demandée, ou nombre de lignes. * +* * +* Remarques : - * +* * +******************************************************************************/ + +size_t g_buffer_cache_find_index_by_cursor(const GBufferCache *cache, const GLineCursor *cursor, bool first) +{ + size_t result; /* Indice à retourner */ + + if (cache->used == 0) + result = 0; + else + result = _g_buffer_cache_find_index_by_cursor(cache, cursor, first, 0, cache->used - 1); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : cache = tampon de lignes à consulter. * +* start = point de départ du parcours. * +* flag = propriétés à retrouver si possible. * +* * +* Description : Avance autant que possible vers une ligne idéale. * +* * +* Retour : Indice de la ligne recherchée, si elle existe. * +* * +* Remarques : - * +* * +******************************************************************************/ + +size_t g_buffer_cache_look_for_flag(const GBufferCache *cache, size_t start, BufferLineFlags flag) +{ + size_t result; /* Indice de ligne à retourner */ + GLineCursor *init; /* Localisation de départ */ + size_t i; /* Boucle de parcours */ + GLineCursor *next; /* Localisation suivante */ + int ret; /* Bilan de comparaison */ + + // TODO : check lock + + assert(start < cache->used); + + result = start; + + get_cache_info_cursor(&cache->lines[start], start, 0, &init); + + for (i = start + 1; i < cache->used; i++) + { + get_cache_info_cursor(&cache->lines[i], i, 0, &next); + + ret = g_line_cursor_compare(init, next); + + g_object_unref(G_OBJECT(next)); + + if (ret != 0) + break; + + if ((g_buffer_cache_get_line_flags(cache, i) & flag) != 0) + { + result = i; + break; + } + + } + + g_object_unref(G_OBJECT(init)); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : cache = tampon de lignes à consulter. * +* cursor = emplacement à présenter à l'écran. * +* first = borne inférieure des recherches (incluse). * +* last = borne supérieure des recherches (incluse). * +* code = s'arrête si possible à une ligne avec code. * +* x = position horizontale au sein du composant. [OUT] * +* y = position verticale au sein du composant. [OUT] * +* * +* Description : Indique la position d'affichage d'une adresse donnée. * +* * +* Retour : true si l'adresse fait partie du composant, false sinon. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool g_buffer_cache_get_cursor_coordinates(const GBufferCache *cache, const GLineCursor *cursor, size_t first, size_t last, bool code, gint *x, gint *y) +{ + bool result; /* Bilan à retourner */ + size_t index; /* Indice de correspondance */ + gint lheight; /* Hauteur d'une ligne */ + const cache_info *info; /* Infos sur une ligne donnée */ + const generator_link *generator; /* Générateur retenu */ + + index = _g_buffer_cache_find_index_by_cursor(cache, cursor, true, first, last); + + result = (index < cache->used); + + if (result) + { + lheight = G_BUFFER_CACHE_GET_CLASS(cache)->line_height; + + *x = 0; + *y = (index - first) * G_BUFFER_CACHE_GET_CLASS(cache)->line_height; + + for (; code && index <= last; index++) + { + if (g_buffer_cache_get_line_flags(cache, index) & BLF_HAS_CODE) + break; + + if (index == last) + break; + + info = &cache->lines[index + 1]; + + if (info->count == 1) + generator = &info->generator; + else + generator = &info->generators[0]; + + if (!g_line_generator_contain_cursor(generator->instance, index + 1, generator->repeat, cursor)) + break; + + *y += lheight; + + } + + } + + return result; + +} diff --git a/src/glibext/buffercache.h b/src/glibext/buffercache.h new file mode 100644 index 0000000..5094b53 --- /dev/null +++ b/src/glibext/buffercache.h @@ -0,0 +1,133 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * buffercache.h - prototypes pour l'affichage à la demande d'un ensemble de lignes + * + * Copyright (C) 2016-2019 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 . + */ + + +#ifndef _GLIBEXT_BUFFERCACHE_H +#define _GLIBEXT_BUFFERCACHE_H + + +#include +#include +#include + + +#include "gdisplayoptions.h" +#include "linegen.h" +#include "widthtracker.h" + + + +/* -------------------------- TAMPON POUR CODE DESASSEMBLE -------------------------- */ + + +#define G_TYPE_BUFFER_CACHE g_buffer_cache_get_type() +#define G_BUFFER_CACHE(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_BUFFER_CACHE, GBufferCache)) +#define G_BUFFER_CACHE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_BUFFER_CACHE, GBufferCacheClass)) +#define G_IS_BUFFER_CACHE(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_BUFFER_CACHE)) +#define G_IS_BUFFER_CACHE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_BUFFER_CACHE)) +#define G_BUFFER_CACHE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_BUFFER_CACHE, GBufferCacheClass)) + + +/* Tampon pour gestion de lignes optimisée (instance) */ +typedef struct _GBufferCache GBufferCache; + +/* Tampon pour gestion de lignes optimisée (classe) */ +typedef struct _GBufferCacheClass GBufferCacheClass; + + +/* Détermine le type du composant de tampon pour gestion de lignes optimisée. */ +GType g_buffer_cache_get_type(void); + +/* Crée un nouveau composant de tampon pour code désassemblé. */ +GBufferCache *g_buffer_cache_new(GBinContent *); + +/* Indique l'éventuel contenu binaire associé au cache. */ +GBinContent *g_buffer_cache_get_content(const GBufferCache *); + +/* Fournit la hauteur d'impression d'une ligne visualisée. */ +gint g_buffer_cache_get_line_height(const GBufferCache *); + +/* Fournit la taille réservée pour la marge gauche. */ +gint g_buffer_cache_get_left_margin(const GBufferCache *); + +/* Fournit la position de départ pour l'impression de texte. */ +gint g_buffer_cache_get_text_position(const GBufferCache *); + +/* Compte le nombre de lignes rassemblées dans un tampon. */ +size_t g_buffer_cache_count_lines(const GBufferCache *); + +/* Fournit un lien vers la structure de suivi de largeurs. */ +GWidthTracker *g_buffer_cache_get_width_tracker(const GBufferCache *); + +/* Insère un générateur dans des lignes à une position donnée. */ +void g_buffer_cache_insert_at(GBufferCache *, size_t, GLineGenerator *, BufferLineFlags, bool, bool); + +/* Retire une ligne du tampon. */ +void g_buffer_cache_delete_at(GBufferCache *, size_t); + +/* Retire un type de générateur de lignes. */ +GLineGenerator *g_buffer_cache_delete_type_at(GBufferCache *, size_t, GType, bool, bool); + +/* Ajoute en fin de tampon un générateur de lignes. */ +void g_buffer_cache_append(GBufferCache *, GLineGenerator *, BufferLineFlags); + +/* Etend un tampon avec un générateur de lignes unique. */ +void g_buffer_cache_extend_with(GBufferCache *, size_t, GLineGenerator *); + +/* Réduit le tampon à une quantité de lignes précise. */ +void g_buffer_cache_truncate(GBufferCache *, size_t); + +/* Retrouve l'emplacement correspondant à une position de ligne. */ +void g_buffer_cache_get_line_cursor(const GBufferCache *, size_t, gint, GLineCursor **); + +/* Détermine l'ensemble des propriétés attachées à une ligne. */ +BufferLineFlags g_buffer_cache_get_line_flags(const GBufferCache *, size_t); + +#define g_buffer_cache_lock(c) +#define g_buffer_cache_unlock(c) + +#define g_buffer_cache_throw_update_at_index(c, i) // check locked + +/* Retrouve une ligne au sein d'un tampon avec un indice. */ +GBufferLine *g_buffer_cache_find_line_by_index(const GBufferCache *, size_t); + +/* Fait remonter les largeurs requises par une ligne donnée. */ +void g_buffer_cache_collect_widths(GBufferCache *, size_t, line_width_summary *); + +/* Imprime une partie choisie du tampon contenant des lignes. */ +void g_buffer_cache_draw(const GBufferCache *, cairo_t *, size_t, size_t, const cairo_rectangle_int_t *, const GDisplayOptions *, const line_width_summary *, const gint *, const segcnt_list *); + +/* Indique l'indice correspondant à une adresse donnée. */ +size_t _g_buffer_cache_find_index_by_cursor(const GBufferCache *, const GLineCursor *, bool, size_t, size_t); + +/* Indique l'indice correspondant à une adresse donnée. */ +size_t g_buffer_cache_find_index_by_cursor(const GBufferCache *, const GLineCursor *, bool); + +/* Avance autant que possible vers une ligne idéale. */ +size_t g_buffer_cache_look_for_flag(const GBufferCache *, size_t, BufferLineFlags); + +/* Indique la position d'affichage d'une adresse donnée. */ +bool g_buffer_cache_get_cursor_coordinates(const GBufferCache *, const GLineCursor *, size_t, size_t, bool, gint *, gint *); + + + +#endif /* _GLIBEXT_BUFFERCACHE_H */ diff --git a/src/glibext/bufferline.c b/src/glibext/bufferline.c new file mode 100644 index 0000000..b9413e2 --- /dev/null +++ b/src/glibext/bufferline.c @@ -0,0 +1,1558 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * bufferline.c - représentation de fragments de texte en ligne + * + * Copyright (C) 2010-2019 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 "bufferline.h" + + +#include +#include +#include + + +#include "chrysamarshal.h" +#include "linecolumn.h" +#include "../common/extstr.h" +#include "../core/paths.h" + + + +/* ---------------------------- GESTION DE LINE COMPLETE ---------------------------- */ + + +/* Mémorisation des origines de texte */ +typedef struct _content_origin +{ + col_coord_t coord; /* Localisation d'attachement */ + + GObject *creator; /* Origine de la création */ + +} content_origin; + +/* Représentation de fragments de texte en ligne (instance) */ +struct _GBufferLine +{ + GObject parent; /* A laisser en premier */ + + mrange_t range; /* Couverture geographique */ + BufferLineColumn main_column; /* Colonne principale */ + + line_column columns[BLC_COUNT]; /* Répartition du texte */ + BufferLineColumn merge_start; /* Début de la zone globale */ + BufferLineColumn last_used; /* Dernière colonne utilisée */ + + BufferLineFlags flags; /* Drapeaux particuliers */ + + content_origin *origins; /* Mémorisation des origines */ + size_t ocount; /* Nombre de ces mémorisations */ + + union + { + struct + { + gint max_widths[BLC_COUNT]; /* Taille cachée des colonnes */ + gint merged_width; /* Largeur cumulée avant fusion*/ + }; + }; + +}; + +/* Représentation de fragments de texte en ligne (classe) */ +struct _GBufferLineClass +{ + GObjectClass parent; /* A laisser en premier */ + + cairo_surface_t *entrypoint_img; /* Image pour les entrées */ + cairo_surface_t *bookmark_img; /* Image pour les signets */ + + /* Signaux */ + + void (* content_changed) (GBufferLine *, line_segment *); + + void (* flip_flag) (GBufferLine *, BufferLineFlags, BufferLineFlags); + +}; + + +/* Procède à l'initialisation d'une classe de représentation. */ +static void g_buffer_line_class_init(GBufferLineClass *); + +/* Procède à l'initialisation d'une représentation de fragments. */ +static void g_buffer_line_init(GBufferLine *); + +/* Supprime toutes les références externes. */ +static void g_buffer_line_dispose(GBufferLine *); + +/* Procède à la libération totale de la mémoire. */ +static void g_buffer_line_finalize(GBufferLine *); + + + +/* ---------------------------------------------------------------------------------- */ +/* GESTION DE LINE COMPLETE */ +/* ---------------------------------------------------------------------------------- */ + + +/* Détermine le type de la représentation de fragments de texte en ligne. */ +G_DEFINE_TYPE(GBufferLine, g_buffer_line, G_TYPE_OBJECT); + + + +/****************************************************************************** +* * +* Paramètres : class = classe de composant GTK à initialiser. * +* * +* Description : Procède à l'initialisation d'une classe de représentation. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_buffer_line_class_init(GBufferLineClass *class) +{ + GObjectClass *object; /* Autre version de la classe */ + gchar *filename; /* Chemin d'accès à utiliser */ + + object = G_OBJECT_CLASS(class); + + object->dispose = (GObjectFinalizeFunc/* ! */)g_buffer_line_dispose; + object->finalize = (GObjectFinalizeFunc)g_buffer_line_finalize; + + filename = find_pixmap_file("entrypoint.png"); + assert(filename != NULL); + + class->entrypoint_img = cairo_image_surface_create_from_png(filename); + + g_free(filename); + + filename = find_pixmap_file("bookmark.png"); + assert(filename != NULL); + + class->bookmark_img = cairo_image_surface_create_from_png(filename); + + g_free(filename); + + g_signal_new("content-changed", + G_TYPE_BUFFER_LINE, + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET(GBufferLineClass, content_changed), + NULL, NULL, + g_cclosure_marshal_VOID__OBJECT, + G_TYPE_NONE, 1, G_TYPE_OBJECT); + + g_signal_new("flip-flag", + G_TYPE_BUFFER_LINE, + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET(GBufferLineClass, flip_flag), + NULL, NULL, + g_cclosure_user_marshal_VOID__ENUM_ENUM, + G_TYPE_NONE, 2, G_TYPE_UINT, G_TYPE_UINT); + +} + + +/****************************************************************************** +* * +* Paramètres : line = composant GTK à initialiser. * +* * +* Description : Procède à l'initialisation d'une représentation de fragments.* +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_buffer_line_init(GBufferLine *line) +{ + BufferLineColumn i; /* Boucle de parcours */ + + for (i = 0; i < BLC_COUNT; i++) + init_line_column(&line->columns[i]); + + line->merge_start = BLC_COUNT; + line->last_used = BLC_COUNT; + +} + + +/****************************************************************************** +* * +* Paramètres : line = instance d'objet GLib à traiter. * +* * +* Description : Supprime toutes les références externes. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_buffer_line_dispose(GBufferLine *line) +{ + size_t i; /* Boucle de parcours */ + + for (i = 0; i < line->ocount; i++) + g_object_unref(G_OBJECT(line->origins[i].creator)); + + G_OBJECT_CLASS(g_buffer_line_parent_class)->dispose(G_OBJECT(line)); + +} + + +/****************************************************************************** +* * +* Paramètres : line = instance d'objet GLib à traiter. * +* * +* Description : Procède à la libération totale de la mémoire. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_buffer_line_finalize(GBufferLine *line) +{ + BufferLineColumn i; /* Boucle de parcours */ + + for (i = 0; i < BLC_COUNT; i++) + reset_line_column(&line->columns[i]); + + if (line->origins != NULL) + free(line->origins); + + G_OBJECT_CLASS(g_buffer_line_parent_class)->finalize(G_OBJECT(line)); + +} + + +/****************************************************************************** +* * +* Paramètres : range = emplacement où va se situer la ligne. * +* main = colonne à référencer comme étant la principale. * +* * +* Description : Crée une nouvelle représentation de fragments de texte. * +* * +* Retour : Composant GTK créé. * +* * +* Remarques : - * +* * +******************************************************************************/ + +GBufferLine *g_buffer_line_new(const mrange_t *range, BufferLineColumn main) +{ + GBufferLine *result; /* Composant à retourner */ + + result = g_object_new(G_TYPE_BUFFER_LINE, NULL); + + copy_mrange(&result->range, range); + result->main_column = main; + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : line = ligne à venir consulter. * +* * +* Description : Indique la zone mémoire où se situe la ligne. * +* * +* Retour : Emplacement mémoire virtuel ou physique. * +* * +* Remarques : - * +* * +******************************************************************************/ + +const mrange_t *g_buffer_line_get_range(const GBufferLine *line) +{ + return &line->range; + +} + + +/****************************************************************************** +* * +* Paramètres : line = ligne à venir compléter. * +* size = taille souhaitée de l'impression des positions. * +* addr = localisation physique à venir représenter. * +* * +* Description : Construit le tronc commun d'une ligne autour de sa position. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +void g_buffer_line_fill_phys(GBufferLine *line, MemoryDataSize size, const vmpa2t *addr) +{ + VMPA_BUFFER(position); /* Emplacement au format texte */ + size_t len; /* Taille de l'élément inséré */ + size_t i; /* Boucle de parcours #1 */ + + vmpa2_phys_to_string(addr, size, position, &len); + + for (i = 2; i < len; i++) + if (position[i] != '0') break; + + if (i == len) + i = len - 1; + + if (i > 0) + g_buffer_line_append_text(line, BLC_PHYSICAL, position, i, RTT_PHYS_ADDR_PAD, NULL); + + g_buffer_line_append_text(line, BLC_PHYSICAL, &position[i], len - i, RTT_PHYS_ADDR, NULL); + +} + + +/****************************************************************************** +* * +* Paramètres : line = ligne à venir compléter. * +* size = taille souhaitée de l'impression des positions. * +* addr = localisation virtuelle à venir représenter. * +* * +* Description : Construit le tronc commun d'une ligne autour de sa position. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +void g_buffer_line_fill_virt(GBufferLine *line, MemoryDataSize size, const vmpa2t *addr) +{ + VMPA_BUFFER(position); /* Emplacement au format texte */ + size_t len; /* Taille de l'élément inséré */ + size_t i; /* Boucle de parcours #1 */ + + vmpa2_virt_to_string(addr, size, position, &len); + + if (has_virt_addr(addr)) + { + for (i = 2; i < len; i++) + if (position[i] != '0') break; + + if (i == len) + i = len - 1; + + if (i > 0) + g_buffer_line_append_text(line, BLC_VIRTUAL, position, i, RTT_VIRT_ADDR_PAD, NULL); + + g_buffer_line_append_text(line, BLC_VIRTUAL, &position[i], len - i, RTT_VIRT_ADDR, NULL); + + } + + else + g_buffer_line_append_text(line, BLC_VIRTUAL, position, len, RTT_VIRT_ADDR_PAD, NULL); + +} + + +/****************************************************************************** +* * +* Paramètres : line = ligne à venir compléter. * +* addr = localisation à afficher. * +* psize = taille souhaitée de l'impression des positions. * +* vsize = taille souhaitée de l'impression des adresses. * +* * +* Description : Construit le tronc commun d'une ligne autour de sa position. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +void g_buffer_line_fill_vmpa(GBufferLine *line, const vmpa2t *addr, MemoryDataSize psize, MemoryDataSize vsize) +{ + g_buffer_line_fill_phys(line, psize, addr); + + g_buffer_line_fill_virt(line, vsize, addr); + +} + + +/****************************************************************************** +* * +* Paramètres : line = ligne à venir compléter. * +* content = contenu binaire global à venir lire. * +* range = localisation des données à venir lire et présenter.* +* max = taille maximale de la portion binaire en octets. * +* * +* Description : Construit le tronc commun d'une ligne autour de son contenu. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +void g_buffer_line_fill_content(GBufferLine *line, const GBinContent *content, const mrange_t *range, phys_t max) +{ + phys_t length; /* Taille de la couverture */ + bool truncated; /* Indique si le code est coupé*/ + size_t required; /* Taille de traitement requise*/ + char static_buffer[64]; /* Petit tampon local rapide */ + char *bin_code; /* Tampon utilisé pour le code */ + vmpa2t pos; /* Boucle de parcours #1 */ + phys_t i; /* Boucle de parcours #2 */ + char *iter; /* Boucle de parcours #3 */ + int ret; /* Progression dans l'écriture */ + uint8_t byte; /* Octet à représenter */ + + static const char *charset = "0123456789abcdef"; + + /* Détermination du réceptacle */ + + length = get_mrange_length(range); + + truncated = (max != VMPA_NO_PHYSICAL && length > max); + + if (truncated) + { + length = max; + required = length * 3 + 4 /* "..." */ + 1; + } + else + required = length * 3 + 1; + + if (required <= sizeof(static_buffer)) + bin_code = static_buffer; + else + bin_code = (char *)calloc(required, sizeof(char)); + + /* Code brut */ + + copy_vmpa(&pos, get_mrange_addr(range)); + + for (i = 0, iter = bin_code; i < length; i++, iter += ret) + { + if (i == 0) + ret = 0; + else + { + iter[0] = ' '; + ret = 1; + } + + if (!g_binary_content_read_u8(content, &pos, &byte)) + { + iter[ret + 0] = '?'; + iter[ret + 1] = '?'; + } + else + { + iter[ret + 0] = charset[byte >> 4]; + iter[ret + 1] = charset[byte & 0x0f]; + } + + ret += 2; + + } + + if (truncated) + { + strcpy(iter, "..."); + iter += 3; + } + else + *iter = '\0'; + + /* Conclusion */ + + g_buffer_line_append_text(line, BLC_BINARY, bin_code, iter - bin_code, RTT_RAW_CODE, NULL); + + if (bin_code != static_buffer) + free(bin_code); + +} + + +/****************************************************************************** +* * +* Paramètres : line = ligne à venir consulter. * +* column = indice de la colonne visée par les recherches. * +* * +* Description : Recherche le premier créateur enregistré dans des segments. * +* * +* Retour : Créateur trouvé à déréférencer par la suite ou NULL si échec.* +* * +* Remarques : - * +* * +******************************************************************************/ + +GObject *g_buffer_line_find_first_segment_creator(const GBufferLine *line, BufferLineColumn column) +{ + GObject *result; /* Trouvaille à retourner */ + size_t i; /* Boucle de parcours */ + + assert(column < BLC_COUNT); + + result = NULL; + + for (i = 0; i < line->ocount && result == NULL; i++) + { + if (line->origins[i].coord.column == column) + result = line->origins[i].creator; + } + + if (result != NULL) + g_object_ref(G_OBJECT(result)); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : line = ligne à venir compléter. * +* column = colonne de la ligne visée par l'insertion. * +* text = texte à insérer dans l'existant. * +* length = taille du texte à traiter. * +* type = type de décorateur à utiliser. * +* creator = instance GLib quelconque à associer. * +* * +* Description : Ajoute du texte à formater dans une ligne donnée. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +void g_buffer_line_append_text(GBufferLine *line, size_t column, const char *text, size_t length, RenderingTagType type, GObject *creator) +{ + size_t index; /* Indice d'insertion */ + content_origin *origin; /* Définition d'une origine */ + + assert(length > 0); + + if (column == -1) + column = BLC_LAST_USED; + + if (column == BLC_MAIN) + column = BLC_ASSEMBLY;//line->main_column; + + if (column == BLC_LAST_USED) + column = line->last_used; + else + line->last_used = column; + + index = append_text_to_line_column(&line->columns[column], text, length, type); + + if (creator != NULL) + { + line->origins = (content_origin *)realloc(line->origins, ++line->ocount * sizeof(content_origin)); + + origin = &line->origins[line->ocount - 1]; + + origin->coord.column = column; + origin->coord.index = index; + + origin->creator = creator; + g_object_ref(G_OBJECT(creator)); + + } + +} + + +/****************************************************************************** +* * +* Paramètres : line = ligne à venir compléter. * +* creator = instance GLib quelconque identifiant un segment. * +* text = texte à insérer dans l'existant. * +* length = taille du texte à traiter. * +* * +* Description : Remplace du texte dans une ligne donnée. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool g_buffer_line_replace_text(GBufferLine *line, const GObject *creator, const char *text, size_t length) +{ + bool result; /* Bilan à retourner */ + size_t i; /* Boucle de parcours */ + const col_coord_t *coord; /* Emplacement du contenu visé */ + + result = false; + + for (i = 0; i < line->ocount && !result; i++) + { + if (line->origins[i].creator == creator) + { + coord = &line->origins[i].coord; + + replace_text_in_line_column(&line->columns[coord->column], coord->index, text, length); + + g_signal_emit_by_name(line, "content-changed", NULL); + + result = true; + + } + + } + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : line = ligne à venir consulter. * +* first = première colonne à parcourir. * +* end = colonne de fin de parcours. * +* * +* Description : Indique si du texte est présent dans une ligne de tampon. * +* * +* Retour : true pour indiquer la présence de texte, false pour du vide. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool g_buffer_line_has_text(const GBufferLine *line, BufferLineColumn first, BufferLineColumn end) +{ + bool result; /* Bilan à retourner */ + BufferLineColumn i; /* Boucle de parcours */ + + result = false; + + assert(first < end); + + for (i = first; i < end && !result; i++) + result = (line->columns[i].count > 0); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : line = ligne à venir consulter. * +* first = première colonne à parcourir. * +* end = colonne de fin de parcours. * +* markup = indique si le texte doit être décoré ou non. * +* * +* Description : Donne le texte représenté par une ligne de tampon. * +* * +* Retour : Texte à libérer de la mémoire après usage. * +* * +* Remarques : - * +* * +******************************************************************************/ + +char *g_buffer_line_get_text(const GBufferLine *line, BufferLineColumn first, BufferLineColumn end, bool markup) +{ + char *result; /* Construction à retourner */ + BufferLineColumn i; /* Boucle de parcours */ + char *extra; /* Contenu à intégrer au texte */ + + result = NULL; + + assert(first < end); + + for (i = first; i < end; i++) + { + if (i > first && result != NULL) + result = stradd(result, " "); + + extra = get_line_column_text(&line->columns[i], markup); + + /* Si la colonne était vide, suivante ! */ + if (extra == NULL) continue; + + if (result == NULL) + result = extra; + + else + { + result = stradd(result, extra); + free(extra); + } + + } + + return result; + +} + +/****************************************************************************** +* * +* Paramètres : line = ligne à venir modifier. * +* first = première colonne à parcourir. * +* end = colonne de fin de parcours. * +* * +* Description : Supprime du texte représenté par une ligne de tampon. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +void g_buffer_line_delete_text(GBufferLine *line, BufferLineColumn first, BufferLineColumn end) +{ + BufferLineColumn i; /* Boucle de parcours #1 */ + + assert(first < end); + + for (i = first; i < end; i++) + reset_line_column(&line->columns[i]); + +} + + +/****************************************************************************** +* * +* Paramètres : line = ligne à venir consulter. * +* * +* Description : Fournit la colonne à partir de laquelle une fusion opère. * +* * +* Retour : Début de la première (et unique) zone globale. * +* * +* Remarques : - * +* * +******************************************************************************/ + +BufferLineColumn g_buffer_line_get_merge_start(const GBufferLine *line) +{ + return line->merge_start; + +} + + +/****************************************************************************** +* * +* Paramètres : line = ligne à venir compléter. * +* start = début de la première (et unique) zone globale. * +* * +* Description : Définit la colonne à partir de laquelle la fusion opère. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +void g_buffer_line_start_merge_at(GBufferLine *line, BufferLineColumn start) +{ + if (start == BLC_LAST_USED) + line->merge_start = line->last_used; + else + line->merge_start = start; + +} + + +/****************************************************************************** +* * +* Paramètres : line = ligne à venir compléter. * +* flag = propriété à intégrer. * +* * +* Description : Ajoute une propriété particulière à une ligne donnée. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +void g_buffer_line_add_flag(GBufferLine *line, BufferLineFlags flag) +{ + if ((line->flags & flag) == 0) + { + g_signal_emit_by_name(line, "flip-flag", line->flags, flag); + + line->flags |= flag; + + } + +} + + +/****************************************************************************** +* * +* Paramètres : line = ligne à venir consulter. * +* * +* Description : Renseigne sur les propriétés particulières liées à une ligne.* +* * +* Retour : Propriétés intégrées. * +* * +* Remarques : - * +* * +******************************************************************************/ + +BufferLineFlags g_buffer_line_get_flags(const GBufferLine *line) +{ + return line->flags; + +} + + +/****************************************************************************** +* * +* Paramètres : line = ligne à venir compléter. * +* flag = propriété à supprimer. * +* * +* Description : Retire une propriété particulière à une ligne donnée. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +void g_buffer_line_remove_flag(GBufferLine *line, BufferLineFlags flag) +{ + if ((line->flags & flag) != 0) + { + g_signal_emit_by_name(line, "flip-flag", line->flags, flag); + + line->flags &= ~flag; + + } + +} + + +/****************************************************************************** +* * +* Paramètres : line = ligne de texte à manipuler. * +* ctx = éléments à disposition pour l'exportation. * +* type = type d'exportation attendue. * +* display = règles d'affichage des colonnes modulables. * +* * +* Description : Exporte la ligne de texte représentée. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +void g_buffer_line_export(GBufferLine *line, buffer_export_context *ctx, BufferExportType type, const bool *display) +{ + BufferLineColumn i; /* Boucle de parcours */ + int col_span; /* Fusion de colonnes ? */ + + switch (type) + { + case BET_HTML: + dprintf(ctx->fd, "\t\n"); + break; + default: + break; + } + + for (i = 0; i < BLC_COUNT; i++) + { + if (i < BLC_DISPLAY && !display[i]) continue; + + switch (type) + { + case BET_TEXT: + if (i > 0) dprintf(ctx->fd, "%s", ctx->sep); + break; + default: + break; + } + + /** + * Pour la signification des différentes valeurs assignées, + * se référer au code de export_line_column_segments(). + * + * En gros : + * - 1 = rien de spécial. + * - >1 = il s'agit de la première cellule fusionnée de la ligne. + * - 0 = fusion déjà faite, on ne peut que rajouter du contenu dedans. + * - <1 = il s'agit de la dernière cellule fusionnée de la ligne. + * + * On considère qu'une fusion ne peut pas se réaliser sur la dernière + * cellule uniquement (ce qui a du sens : c'est inutile). + */ + + if (i < line->merge_start) + col_span = 1; + + else if (i == line->merge_start) + col_span = BLC_COUNT - i; + + else + col_span = ((i + 1) == BLC_COUNT ? -1 : 0); + + export_line_column_segments(&line->columns[i], ctx, type, col_span); + + } + + switch (type) + { + case BET_TEXT: + dprintf(ctx->fd, "\n"); + break; + case BET_HTML: + dprintf(ctx->fd, "\n"); + break; + default: + break; + } + +} + + + +/*----------------------------------------------------------------------------------- */ +/* MANIPULATION DES LARGEURS REQUISES */ +/* ---------------------------------------------------------------------------------- */ + + +/****************************************************************************** +* * +* Paramètres : line = ligne à venir consulter. * +* summary = largeurs maximales à faire évoluer. * +* * +* Description : Fait remonter les largeurs requises par une ligne donnée. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +void g_buffer_line_collect_widths(GBufferLine *line, line_width_summary *summary) +{ + gint merged_width; /* Largeur cumulée avant fusion*/ + BufferLineColumn i; /* Boucle de parcours */ + gint width; /* Largeur d'une colonne */ + + merged_width = 0; + + for (i = 0; i < BLC_COUNT; i++) + { + width = get_column_width(&line->columns[i]); + + if (i < line->merge_start) + summary->max_widths[i] = MAX(summary->max_widths[i], width); + + if (i >= BLC_DISPLAY) + { + merged_width += width; + + if (i < line->merge_start && (i + 1) < BLC_COUNT) + merged_width += COL_MARGIN; + + } + + } + + if (line->merge_start != BLC_COUNT) + summary->merged_width = MAX(summary->merged_width, merged_width); + +} + + +/****************************************************************************** +* * +* Paramètres : line = ligne à venir consulter. * +* index = indice de la colonne visée. * +* summary = résumé des largeurs maximales. * +* offsets = décalages supplémentaires à appliquer. * +* * +* Description : Fournit la largeur d'une colonne finalement appliquée. * +* * +* Retour : Largeur globale ou spécifique, selon l'indice communiqué. * +* * +* Remarques : - * +* * +******************************************************************************/ + +gint g_buffer_line_compute_max_width(const GBufferLine *line, BufferLineColumn index, const line_width_summary *summary, const line_width_summary *offsets) +{ + gint result; /* Largeur à retourner */ + + assert(index < BLC_COUNT); + + if (index >= line->merge_start) + result = get_column_width(&line->columns[index]); + + else + result = summary->max_widths[index]; + + if (result < offsets->max_widths[index]) + result = offsets->max_widths[index]; + + return result; + +} + + + + +/****************************************************************************** +* * +* Paramètres : line = ligne à venir consulter. * +* coord = coordonnées interne du segment à retrouver. * +* * +* Description : Fournit le segment présent à une position donnée. * +* * +* Retour : Segment trouvé ou NULL si hors borne. * +* * +* Remarques : - * +* * +******************************************************************************/ + +line_segment *g_buffer_line_get_segment_from_coord(const GBufferLine *line, const col_coord_t *coord) +{ + line_segment *result; /* Trouvaille à retourner */ + + if (coord->column < BLC_COUNT) + result = get_line_column_content_from_index(&line->columns[coord->column], coord->index); + else + result = NULL; + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : line = ligne à venir consulter. * +* summary = résumé des largeurs maximales. * +* options = règles d'affichage des colonnes modulables. * +* offsets = décalages supplémentaires à appliquer. * +* base = position jusqu'au segment trouvé. [OUT] * +* offset = position à la colonne visée. [OUT] * +* dir = direction d'un éventuel déplacement en cours. * +* force = accepte les segments en bordure au pire. * +* coord = cordonnées à usage interne à renseigner. [OUT] * +* * +* Description : Fournit les coordonnées correspondant à une abscisse donnée. * +* * +* Retour : true si des coordonnées valides ont été renseignées. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool g_buffer_line_get_coord_at(const GBufferLine *line, const line_width_summary *summary, const GDisplayOptions *options, const line_width_summary *offsets, gint *base, gint *offset, GdkScrollDirection dir, bool force, col_coord_t *coord) +{ + bool result; /* Bilan à retourner */ + BufferLineColumn last; /* Dernière colonne remplie */ + gint last_base; /* Dernière abscisse associée */ + size_t count; /* Qté de colonnes en option */ + size_t i; /* Boucle de parcours */ + gint width; /* Largeur d'une colonne donnée*/ + gint limit; /* Limite d'appartenance */ + gint consumed; /* Distance vers le segment */ + gint old_base; /* Somme de toutes les largeurs*/ + + result = false; + + *base = 0; + + last = BLC_COUNT; + last_base = 0; + + /* On cible déjà la colonne idéale */ + + count = g_display_options_count(options); + + for (i = 0; i < BLC_COUNT; i++) + { + if (i < count) + { + if (!g_display_options_get(options, i)) + continue; + } + + /* Mémorisation de la dernière colonne contenant quelque chose... */ + if (get_column_width(&line->columns[i]) > 0) + { + last = i; + last_base = *base; + } + + if (i < line->merge_start) + { + width = g_buffer_line_compute_max_width(line, i, summary, offsets); + + /* Si la colonne n'est absolument pas visible, on ne s'arrête pas dessus ! */ + if (width == 0) continue; + + if ((i + 1) < BLC_COUNT) limit = width + COL_MARGIN / 2; + else limit = width; + + if (*offset <= limit) break; + else + { + *offset -= width + COL_MARGIN; + *base += width + COL_MARGIN; + } + + } + else + { + width = get_column_width(&line->columns[i]); + + if (*offset <= width) break; + else + { + *offset -= width; + *base += width; + } + + } + + + } + + /* Si l'abscisse fournie tombe encore dans une colonne... */ + + if (i < BLC_COUNT) + { + /* Il y a bien du contenu dans cette colonne */ + + if (get_column_width(&line->columns[i]) > 0) + { + /** + * Si la position était au milieu d'une marge, la sélection a pu pousser + * jusqu'à la colonne suivante, plus proche. + * Relativment à la base de cette dernière, la position est donc devenue négative. + */ + if (*offset < 0) *offset = 0; + + result = get_line_column_content_index_at(&line->columns[i], offset, dir, &consumed, &coord->index); + + if (result) + { + coord->column = i; + + *base += consumed; + + } + + } + + /* La position fournie tombe dans une colonne vide ! */ + + else + { + if (force || get_column_width(&line->columns[i]) == 0) + { + result = false; + *offset = 0; + + old_base = *base; + + for (i++; i < BLC_COUNT && !result; i++) + { + if ((i - 1) < line->merge_start) + { + width = g_buffer_line_compute_max_width(line, i - 1, summary, offsets); + + if (width > 0) + *base += (width + COL_MARGIN); + + } + else + *base += get_column_width(&line->columns[i - 1]); + + result = get_line_column_first_content_index(&line->columns[i], &coord->index); + + if (result) + coord->column = i; + + } + + if (!result) + { + *base = old_base; + goto use_right_border; + } + + } + + } + + } + + else /* if (i == BLC_COUNT) */ + { + if (force) + { + use_right_border: + + if (last != BLC_COUNT) + { + result = get_line_column_last_content_index(&line->columns[last], &coord->index); + + if (result) + { + coord->column = last; + + *base = last_base; + *offset = get_column_width(&line->columns[last]); + + } + + } + + /* Il n'y a rien sur la ligne ! */ + else + { + result = true; + + *base = 0; + *offset = 0; + + coord->column = BLC_COUNT; + coord->index = -1; + + } + + } + else + result = false; + + } + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : line = ligne à venir consulter. * +* summary = résumé des largeurs maximales. * +* options = règles d'affichage des colonnes modulables. * +* offsets = décalages supplémentaires à appliquer. * +* base = position jusqu'au segment trouvé. [OUT] * +* offset = position à la colonne visée. [OUT] * +* dir = direction d'un éventuel déplacement en cours. * +* force = accepte les segments en bordure au pire. * +* * +* Description : Donne le segment présent à une abscisse donnée. * +* * +* Retour : Segment trouvé ou NULL si hors borne. * +* * +* Remarques : - * +* * +******************************************************************************/ + +line_segment *g_buffer_line_get_segment_at(const GBufferLine *line, const line_width_summary *summary, const GDisplayOptions *options, const line_width_summary *offsets, gint *base, gint *offset, GdkScrollDirection dir, bool force) +{ + line_segment *result; /* Trouvaille à retourner */ + col_coord_t coord; /* Emplacement du contenu visé */ + bool status; /* Bilan de la localisation */ + + status = g_buffer_line_get_coord_at(line, summary, options, offsets, base, offset, dir, force, &coord); + + if (status) + result = g_buffer_line_get_segment_from_coord(line, &coord); + else + result = NULL; + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : line = ligne à venir consulter. * +* summary = résumé des largeurs maximales. * +* options = règles d'affichage des colonnes modulables. * +* offsets = décalages supplémentaires à appliquer. * +* base = position jusqu'au segment trouvé. [OUT] * +* offset = position à la colonne visée. [OUT] * +* dir = direction d'un éventuel déplacement en cours. * +* force = accepte les segments en bordure au pire. * +* * +* Description : Donne le créateur présent à une abscisse donnée. * +* * +* Retour : Créateur trouvé ou NULL si hors borne. * +* * +* Remarques : - * +* * +******************************************************************************/ + +GObject *g_buffer_line_get_creator_at(const GBufferLine *line, const line_width_summary *summary, const GDisplayOptions *options, const line_width_summary *offsets, gint *base, gint *offset, GdkScrollDirection dir, bool force) +{ + GObject *result; /* Trouvaille à retourner */ + col_coord_t target; /* Emplacement du contenu visé */ + bool status; /* Bilan de la localisation */ + size_t i; /* Boucle de parcours */ + const col_coord_t *coord; /* Emplacement du contenu visé */ + + result = NULL; + + status = g_buffer_line_get_coord_at(line, summary, options, offsets, base, offset, dir, force, &target); + + if (status) + { + for (i = 0; i < line->ocount && result == NULL; i++) + { + coord = &line->origins[i].coord; + + if (coord->column == target.column && coord->index == target.index) + result = line->origins[i].creator; + + } + + if (result != NULL) + g_object_ref(G_OBJECT(result)); + + } + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : line = ligne à venir consulter. * +* coord = cordonnées à consulter puis renseigner. [OUT] * +* summary = résumé des largeurs maximales. * +* options = règles d'affichage des colonnes modulables. * +* offsets = décalages supplémentaires à appliquer. * +* dir = orientation des recherches. * +* offset = décalage pour amener à l'extrémité nouvelle. [OUT] * +* * +* Description : Fournit des coordonnées voisines selon une direction donnée. * +* * +* Retour : true si des coordonnées valides ont été renseignées. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool g_buffer_line_find_near_coord(const GBufferLine *line, col_coord_t *coord, const line_width_summary *summary, const GDisplayOptions *options, const line_width_summary *offsets, GdkScrollDirection dir, gint *offset) +{ + bool result; /* Bilan à retourner */ + size_t count; /* Qté de colonnes en option */ + size_t i; /* Boucle de parcours #1 */ + bool displayed; /* Confort de lecture */ + size_t k; /* Boucle de parcours #2 */ + gint width; /* Largeur d'une colonne donnée*/ + + result = false; + + /* Recherche dans la colonne de départ */ + + i = coord->column; + + if (i == BLC_COUNT) return false; + + result = find_near_segment(&line->columns[i], &coord->index, dir); + + /* Recherche dans la direction des colonnes voisines */ + + count = g_display_options_count(options); + + if (!result) + switch (dir) + { + case GDK_SCROLL_LEFT: + + /* Si on a atteint la première colonne sans trouver... */ + if (i == 0) break; + + /* On s'assure que la colonne précédente est visible et peuplée */ + for (; i > BLC_FIRST && !result; i--) + { + displayed = (i <= count ? g_display_options_get(options, i - 1) : true); + + if (displayed) + { + result = get_line_column_first_content_index(&line->columns[i - 1], &coord->index); + + if (result) + coord->column = i - 1; + + } + + } + + break; + + case GDK_SCROLL_RIGHT: + + /* On s'assure que la colonne suivante est visible et peuplée */ + for (; (i + 1) < BLC_COUNT && !result; i++) + { + displayed = ((i + 1) < count ? g_display_options_get(options, i + 1) : true); + + if (displayed) + { + result = get_line_column_first_content_index(&line->columns[i + 1], &coord->index); + + if (result) + coord->column = i + 1; + + } + + } + + break; + + default: + break; + + } + + /* Calcul de la position finale */ + + if (result) + { + *offset = 0; + + for (k = 0; k < i; k++) + { + displayed = (k < count ? g_display_options_get(options, k) : true); + + if (displayed) + { + width = g_buffer_line_compute_max_width(line, k, summary, offsets); + + if (width > 0) + { + *offset += width; + if (k < line->merge_start) *offset += COL_MARGIN; + } + + } + + } + + switch (dir) + { + case GDK_SCROLL_LEFT: + *offset += get_column_width(&line->columns[i]); + break; + + case GDK_SCROLL_RIGHT: + /**offset += 0;*/ + break; + + default: + break; + + } + + } + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : line = ligne de texte à manipuler. * +* cairo = contexte graphique à utiliser pour les pinceaux. * +* summary = résumé des largeurs maximales. * +* x_init = abscisse du point d'impression de départ. * +* y = ordonnée du point d'impression. * +* options = règles d'affichage des colonnes modulables. * +* offsets = décalages supplémentaires à appliquer. * +* list = liste de contenus à mettre en évidence. * +* * +* Description : Imprime la ligne de texte représentée. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +void g_buffer_line_draw(GBufferLine *line, cairo_t *cairo, const line_width_summary *summary, gint x_init, gint y, const GDisplayOptions *options, const line_width_summary *offsets, const segcnt_list *list) +{ + GBufferLineClass *class; /* Stockage de briques de base */ + bool has_src_surface; /* Note une présence définie */ + gint x; /* Point de départ d'impression*/ + size_t count; /* Qté de colonnes en option */ + size_t i; /* Boucle de parcours */ + gint max_width; /* Largeur maximale de colonne */ + + if (line->flags != BLF_NONE && line->flags != BLF_HAS_CODE) + { + class = G_BUFFER_LINE_GET_CLASS(line); + + if (line->flags & BLF_ENTRYPOINT) + { + cairo_set_source_surface(cairo, class->entrypoint_img, 5, y); + has_src_surface = true; + } + else if (line->flags & BLF_BOOKMARK) + { + cairo_set_source_surface(cairo, class->bookmark_img, 5, y); + has_src_surface = true; + } + else + has_src_surface = false; + + if (has_src_surface) + cairo_paint(cairo); + + } + + x = x_init; + + count = g_display_options_count(options); + + for (i = 0; i < BLC_COUNT; i++) + { + if (i < count) + { + if (!g_display_options_get(options, i)) + continue; + } + + draw_line_column_segments(&line->columns[i], cairo, x, y, list); + + if (i < line->merge_start) + { + max_width = g_buffer_line_compute_max_width(line, i, summary, offsets); + + if (max_width > 0) + x += max_width + COL_MARGIN; + + } + + } + +} diff --git a/src/glibext/bufferline.h b/src/glibext/bufferline.h new file mode 100644 index 0000000..95db203 --- /dev/null +++ b/src/glibext/bufferline.h @@ -0,0 +1,218 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * bufferline.h - prototypes pour la représentation de fragments de texte en ligne + * + * Copyright (C) 2010-2018 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 . + */ + + +#ifndef _GLIBEXT_BUFFERLINE_H +#define _GLIBEXT_BUFFERLINE_H + + +#include +#include + + +#include "gdisplayoptions.h" +#include "linesegment.h" +#include "../analysis/content.h" +#include "../arch/vmpa.h" + + + +#define G_TYPE_BUFFER_LINE g_buffer_line_get_type() +#define G_BUFFER_LINE(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_BUFFER_LINE, GBufferLine)) +#define G_BUFFER_LINE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_BUFFER_LINE, GBufferLineClass)) +#define G_IS_BUFFER_LINE(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_BUFFER_LINE)) +#define G_IS_BUFFER_LINE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_BUFFER_LINE)) +#define G_BUFFER_LINE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_BUFFER_LINE, GBufferLineClass)) + + +/* Représentation de fragments de texte en ligne (instance) */ +typedef struct _GBufferLine GBufferLine; + +/* Représentation de fragments de texte en ligne (classe) */ +typedef struct _GBufferLineClass GBufferLineClass; + + +/* Désignation des colonnes d'une ligne */ +typedef enum _BufferLineColumn +{ + BLC_PHYSICAL, /* Position physique */ + BLC_VIRTUAL, /* Adresse virtuelle */ + BLC_BINARY, /* Contenu sous forme binaire */ + BLC_ASSEMBLY_LABEL, /* Etiquette dans les données */ + BLC_ASSEMBLY_HEAD, /* Instruction pour assembleur */ + BLC_ASSEMBLY, /* Code pour assembleur */ + BLC_COMMENTS, /* Commentaires éventuels */ + + BLC_COUNT, + + BLC_LAST_USED, /* Dernière colonne utilisée */ + BLC_INVALID, /* Valeur de non-initialisation*/ + BLC_MAIN /* Colonne principale (cf. imm)*/ + +} BufferLineColumn; + +/* Première colonne de l'ensemble */ +#define BLC_FIRST BLC_PHYSICAL + +/* Première colonne toujours affichée */ +#define BLC_DISPLAY BLC_ASSEMBLY_LABEL + + +/* Confort pour l'insertion de texte */ +#define SL(str) str, strlen(str) + +/* Espace entre les colonnes */ +#define COL_MARGIN 23 + + +/* Propriétés particulières supplémentaires */ +typedef enum _BufferLineFlags +{ + BLF_NONE = 0 << 0, /* Aucune */ + BLF_HAS_CODE = 1 << 0, /* La ligne contient du code */ + BLF_IS_LABEL = 1 << 1, /* Etiquette pour symbole */ + BLF_ENTRYPOINT = 1 << 2, /* Représentation d'une entrée */ + BLF_BOOKMARK = 1 << 3, /* Signet associé */ + BLF_WIDTH_MANAGER = 1 << 4, /* Début de groupe des largeurs*/ + + BLF_ALL = ((1 << 5) - 1) + +} BufferLineFlags; + + +/* Détermine le type de la représentation de fragments de texte en ligne. */ +GType g_buffer_line_get_type(void); + +/* Crée une nouvelle représentation de fragments de texte. */ +GBufferLine *g_buffer_line_new(const mrange_t *, BufferLineColumn); + +/* Indique la zone mémoire où se situe la ligne. */ +const mrange_t *g_buffer_line_get_range(const GBufferLine *); + +/* Construit le tronc commun d'une ligne autour de sa position. */ +void g_buffer_line_fill_phys(GBufferLine *, MemoryDataSize, const vmpa2t *); + +/* Construit le tronc commun d'une ligne autour de sa position. */ +void g_buffer_line_fill_virt(GBufferLine *, MemoryDataSize, const vmpa2t *); + +/* Construit le tronc commun d'une ligne autour de sa position. */ +void g_buffer_line_fill_vmpa(GBufferLine *, const vmpa2t *, MemoryDataSize, MemoryDataSize); + +/* Construit le tronc commun d'une ligne autour de son contenu. */ +void g_buffer_line_fill_content(GBufferLine *, const GBinContent *, const mrange_t *, phys_t); + +/* Recherche le premier créateur enregistré dans des segments. */ +GObject *g_buffer_line_find_first_segment_creator(const GBufferLine *, BufferLineColumn); + +/* Ajoute du texte à formater dans une ligne donnée. */ +void g_buffer_line_append_text(GBufferLine *, size_t, const char *, size_t, RenderingTagType, GObject *); + +/* Remplace du texte dans une ligne donnée. */ +bool g_buffer_line_replace_text(GBufferLine *, const GObject *, const char *, size_t); + +/* Indique si du texte est présent dans une ligne de tampon. */ +bool g_buffer_line_has_text(const GBufferLine *, BufferLineColumn, BufferLineColumn); + +/* Donne le texte représenté par une ligne de tampon. */ +char *g_buffer_line_get_text(const GBufferLine *, BufferLineColumn, BufferLineColumn, bool); + +/* Supprime du texte représenté par une ligne de tampon. */ +void g_buffer_line_delete_text(GBufferLine *, BufferLineColumn, BufferLineColumn); + +/* Fournit la colonne à partir de laquelle une fusion opère. */ +BufferLineColumn g_buffer_line_get_merge_start(const GBufferLine *); + +/* Définit la colonne à partir de laquelle la fusion opère. */ +void g_buffer_line_start_merge_at(GBufferLine *, BufferLineColumn); + +/* Ajoute une propriété particulière à une ligne donnée. */ +void g_buffer_line_add_flag(GBufferLine *, BufferLineFlags); + +/* Renseigne sur les propriétés particulières liées à une ligne. */ +BufferLineFlags g_buffer_line_get_flags(const GBufferLine *); + +/* Retire une propriété particulière à une ligne donnée. */ +void g_buffer_line_remove_flag(GBufferLine *, BufferLineFlags); + +/* Exporte la ligne de texte représentée. */ +void g_buffer_line_export(GBufferLine *, buffer_export_context *, BufferExportType, const bool *); + + +/* Petite aide pour la détection de commentaire */ +#define g_buffer_line_has_comment(ln) \ + ({ \ + bool __result; \ + __result = g_buffer_line_has_text(ln, BLC_COMMENTS, BLC_COUNT); \ + __result |= (g_buffer_line_get_merge_start(ln) == BLC_DISPLAY \ + && !(g_buffer_line_get_flags(ln) & BLF_IS_LABEL)); \ + __result; \ + }) + + + +/* ----------------------- MANIPULATION DES LARGEURS REQUISES ----------------------- */ + + +/* Mémorisation des largeurs pour un groupe de lignes */ +typedef struct _line_width_summary +{ + gint max_widths[BLC_COUNT]; /* Taille cachée des colonnes */ + gint merged_width; /* Largeur cumulée avant fusion*/ + +} line_width_summary; + +/* Identification d'un contenu de colonne */ +typedef struct _col_coord_t +{ + BufferLineColumn column; /* Colonne concernée */ + size_t index; /* Indice d'insertion */ + +} col_coord_t; + + +/* Fait remonter les largeurs requises par une ligne donnée. */ +void g_buffer_line_collect_widths(GBufferLine *, line_width_summary *); + +/* Fournit la largeur d'une colonne finalement appliquée. */ +gint g_buffer_line_compute_max_width(const GBufferLine *, BufferLineColumn, const line_width_summary *, const line_width_summary *); + +/* Fournit le segment présent à une position donnée. */ +line_segment *g_buffer_line_get_segment_from_coord(const GBufferLine *, const col_coord_t *); + +/* Fournit les coordonnées correspondant à une abscisse donnée. */ +bool g_buffer_line_get_coord_at(const GBufferLine *, const line_width_summary *, const GDisplayOptions *, const line_width_summary *, gint *, gint *, GdkScrollDirection, bool, col_coord_t *); + +/* Donne le segment présent à une abscisse donnée. */ +line_segment *g_buffer_line_get_segment_at(const GBufferLine *, const line_width_summary *, const GDisplayOptions *, const line_width_summary *, gint *, gint *, GdkScrollDirection, bool); + +/* Donne le créateur présent à une abscisse donnée. */ +GObject *g_buffer_line_get_creator_at(const GBufferLine *, const line_width_summary *, const GDisplayOptions *, const line_width_summary *, gint *, gint *, GdkScrollDirection, bool); + +/* Fournit des coordonnées voisines selon une direction donnée. */ +bool g_buffer_line_find_near_coord(const GBufferLine *, col_coord_t *, const line_width_summary *, const GDisplayOptions *, const line_width_summary *, GdkScrollDirection, gint *); + +/* Imprime la ligne de texte représentée. */ +void g_buffer_line_draw(GBufferLine *, cairo_t *, const line_width_summary *, gint, gint, const GDisplayOptions *, const line_width_summary *, const segcnt_list *); + + + +#endif /* _GLIBEXT_BUFFERLINE_H */ diff --git a/src/glibext/bufferview.c b/src/glibext/bufferview.c new file mode 100644 index 0000000..e40715e --- /dev/null +++ b/src/glibext/bufferview.c @@ -0,0 +1,1285 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * bufferview.c - affichage d'une vue particulière d'un tampon de lignes + * + * Copyright (C) 2016-2019 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 "bufferview.h" + + +#include + + + +/* Vue d'un tampon pour code désassemblé (instance) */ +struct _GBufferView +{ + GObject parent; /* A laisser en premier */ + + GBufferCache *cache; /* Tampon du contenu visualisé */ + + segcnt_list *highlighted; /* Segments mis en évidence */ + + bool unrestricted; /* Validité des informations */ + GLineCursor *start; /* Première ligne intégrée */ + GLineCursor *end; /* Dernière ligne intégrée */ + + size_t first; /* Indice de la première ligne */ + size_t last; /* Indice de la dernière ligne */ + + GWidthTracker *tracker; /* Suivi des largeurs */ + +}; + +/* Vue d'un tampon pour code désassemblé (classe) */ +struct _GBufferViewClass +{ + GObjectClass parent; /* A laisser en premier */ + + /* Signaux */ + + void (* need_redraw) (GBufferView *); + +}; + + +/* Procède à l'initialisation d'une classe de vue de tampon. */ +static void g_buffer_view_class_init(GBufferViewClass *); + +/* Procède à l'initialisation d'une vue d'un tampon pour code. */ +static void g_buffer_view_init(GBufferView *); + +/* Supprime toutes les références externes. */ +static void g_buffer_view_dispose(GBufferView *); + +/* Procède à la libération totale de la mémoire. */ +static void g_buffer_view_finalize(GBufferView *); + +/* Accompagne une variation de la quantité de lignes du tampon. */ +static void on_buffer_cache_size_changed(const GBufferCache *, bool, size_t, size_t, GBufferView *); + +/* Calcule la position idéale de curseur pour un point donné. */ +bool _g_buffer_view_compute_caret_full(GBufferView *, gint, GBufferLine *, size_t, const GDisplayOptions *, const line_width_summary *, cairo_rectangle_int_t *, GLineCursor **); + +/* Déplace le curseur au sein d'une vue de tampon. */ +static bool _g_buffer_view_move_caret(GBufferView *, const GBufferLine *, size_t, cairo_rectangle_int_t *, bool, GdkScrollDirection, const GDisplayOptions *, const line_width_summary *); + + +/* Fournit la ligne présente à une ordonnée donnée. */ +static GBufferLine *g_buffer_view_find_line_at(GBufferView *, gint, size_t *); + + + + + + + +/* Détermine le type de la vue d'un tampon pour code désassemblé. */ +G_DEFINE_TYPE(GBufferView, g_buffer_view, G_TYPE_OBJECT); + + +/****************************************************************************** +* * +* Paramètres : class = classe de composant GTK à initialiser. * +* * +* Description : Procède à l'initialisation d'une classe de vue de tampon. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_buffer_view_class_init(GBufferViewClass *class) +{ + GObjectClass *object; /* Autre version de la classe */ + + object = G_OBJECT_CLASS(class); + + object->dispose = (GObjectFinalizeFunc/* ! */)g_buffer_view_dispose; + object->finalize = (GObjectFinalizeFunc)g_buffer_view_finalize; + + /* Sigaux */ + + g_signal_new("need-redraw", + G_TYPE_BUFFER_VIEW, + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET(GBufferViewClass, need_redraw), + NULL, NULL, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, 0); + +} + + +/****************************************************************************** +* * +* Paramètres : view = composant GLib à initialiser. * +* * +* Description : Procède à l'initialisation d'une vue d'un tampon pour code. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_buffer_view_init(GBufferView *view) +{ + view->cache = NULL; + + view->highlighted = NULL; + + /** + * Inversion du statut pour forcer l'actualisation lors de la création. + */ + view->unrestricted = false; + + view->start = NULL; + view->end = NULL; + + view->first = 0; + view->last = 0; + + view->tracker = NULL; + +} + + +/****************************************************************************** +* * +* Paramètres : view = instance d'objet GLib à traiter. * +* * +* Description : Supprime toutes les références externes. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_buffer_view_dispose(GBufferView *view) +{ + g_clear_object(&view->cache); + + g_clear_object(&view->start); + g_clear_object(&view->end); + + g_clear_object(&view->tracker); + + G_OBJECT_CLASS(g_buffer_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 g_buffer_view_finalize(GBufferView *view) +{ + if (view->highlighted != NULL) + unref_segment_content_list(view->highlighted); + + G_OBJECT_CLASS(g_buffer_view_parent_class)->finalize(G_OBJECT(view)); + +} + + +/****************************************************************************** +* * +* Paramètres : buffer = tampon à représenter à l'écran. * +* highlighted = gestionnaire de surbrillance pour segments. * +* * +* Description : Crée une nouvelle vue d'un tampon pour code désassemblé. * +* * +* Retour : Composant GTK créé. * +* * +* Remarques : - * +* * +******************************************************************************/ + +GBufferView *g_buffer_view_new(GBufferCache *cache, segcnt_list *highlighted) +{ + GBufferView *result; /* Composant à retourner */ + + result = g_object_new(G_TYPE_BUFFER_VIEW, NULL); + + result->cache = cache; + g_object_ref_sink(G_OBJECT(cache)); + + g_buffer_view_restrict(result, NULL, NULL); + + g_signal_connect(cache, "size-changed", G_CALLBACK(on_buffer_cache_size_changed), result); + + if (highlighted != NULL) + { + ref_segment_content_list(highlighted); + result->highlighted = highlighted; + } + else + result->highlighted = init_segment_content_list(); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : cache = tampon de lignes cohérentes à manipuler. * +* added = indication sur la variation de la taille du tampon. * +* index = indice de la première ligne à traiter. * +* count = nombre de lignes à traiter. * +* view = vue active du tampon de lignes concerné. * +* * +* Description : Accompagne une variation de la quantité de lignes du tampon. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void on_buffer_cache_size_changed(const GBufferCache *cache, bool added, size_t index, size_t count, GBufferView *view) +{ + //size_t i; /* Boucle de parcours */ + //GBufferLine *line; /* Ligne à manipuler */ + //const vmpa2t *addr; /* Localisation de ligne */ + + /** + * Il n'y a pas besoin de verrou ici car la fonction est appelée directement par le tampon. + * D'autre part, on considère qu'il y a toujours une ligne aux adresses de borne, si la vue est bornée. + */ + + if (added) + { + if (view->unrestricted) + view->last += count; + + else + { +#if 0 + + /* Avant la zone représentée ? */ + if (index < view->first) + { + view->first += count; + view->last += count; + } + + /* Juste avant la zone représentée ? */ + else if (view->first == index) + for (i = 0; i < count; i++) + { + g_buffer_cache_get_line_addr(const GBufferCache *, size_t, gint, vmpa2t *); + + line = g_code_buffer_find_line_by_index(buffer, index + i); + addr = get_mrange_addr(g_buffer_line_get_range(line)); + + if (cmp_vmpa(&view->start, addr) == 0) + { + view->first++; + view->last++; + } + else + break; + + } + + /* Dans la zone représentée ? */ + else if (view->first < index && index <= view->last) + view->last += count; + + /* Juste après la vue représentée ? */ + else if ((view->last + 1) == index) + for (i = 0; i < count; i++) + { + g_buffer_cache_get_line_addr(const GBufferCache *, size_t, gint, vmpa2t *); + + line = g_code_buffer_find_line_by_index(buffer, index + i); + addr = get_mrange_addr(g_buffer_line_get_range(line)); + + if (cmp_vmpa(&view->end, addr) == 0) + view->last++; + else + break; + + } + + //g_width_tracker_update_added(view->int_tracker, index, count); +#endif + + } + + } + + else + { + if (view->unrestricted) + view->last -= count; + + else + { + /* Avant la zone représentée ? */ + if (index <= view->first) + { + view->first -= count; + view->last -= count; + } + + /* Dans la zone représentée ? */ + else if (view->first < index && index <= view->last) + view->last -= count; + + } + + //g_width_tracker_update_deleted(view->int_tracker, index, index + count - 1); + + } + + //g_signal_emit_by_name(view, "need-redraw"); + +} + + +/****************************************************************************** +* * +* Paramètres : view = visualisateur à consulter. * +* * +* Description : Fournit le tampon de code lié à un visualisateur donné. * +* * +* Retour : Tampon de code associé au gestionnaire d'affichage. * +* * +* Remarques : - * +* * +******************************************************************************/ + +GBufferCache *g_buffer_view_get_cache(const GBufferView *view) +{ + GBufferCache *result; /* Instance à retourner */ + + result = view->cache; + + g_object_ref(G_OBJECT(result)); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : view = visualisateur à mettre à jour. * +* first = première ligne à imprimer. * +* last = première ligne hors cadre. * +* * +* Description : Restreint le champ d'application de l'affichage. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +void g_buffer_view_restrict(GBufferView *view, GLineCursor *start, GLineCursor *end) +{ + bool state; /* Nouvel état à proclamer */ + GWidthTracker *template; /* Suivi déjà en place */ + + state = (start == NULL || end == NULL); + + if (view->unrestricted != state) + { + view->unrestricted = state; + + template = g_buffer_cache_get_width_tracker(view->cache); + + /* Vérification pour le cas particulier du démarrage */ + if (view->tracker != NULL) + g_object_unref(G_OBJECT(view->tracker)); + + if (view->unrestricted) + { + view->first = 0; + view->last = g_buffer_cache_count_lines(view->cache) - 1; + + view->tracker = template; + + } + + else + { + g_object_ref_sink(G_OBJECT(start)); + g_object_ref_sink(G_OBJECT(end)); + + view->start = start; + view->end = end; + + view->first = g_buffer_cache_find_index_by_cursor(view->cache, start, true); + view->last = g_buffer_cache_find_index_by_cursor(view->cache, end, false); + + view->tracker = g_width_tracker_new_restricted(template, view->first, view->last); + + g_object_unref(G_OBJECT(template)); + + } + + } + +} + + +/****************************************************************************** +* * +* Paramètres : view = visualisateur à consulter. * +* first = première ligne à imprimer ou NULL. [OUT] * +* last = première ligne hors cadre ou NULL. [OUT] * +* * +* Description : Indique le champ d'application de l'affichage. * +* * +* Retour : true si des restrictions particulières sont en place. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool g_buffer_view_get_restrictions(const GBufferView *view, GLineCursor **start, GLineCursor **end) +{ + if (!view->unrestricted) + { + if (start != NULL) + { + *start = view->start; + g_object_ref(G_OBJECT(*start)); + } + + if (end != NULL) + { + *end = view->end; + g_object_ref(G_OBJECT(*end)); + } + + } + else + { + if (start != NULL) *start = NULL; + if (end != NULL) *end = NULL; + } + + return !view->unrestricted; + +} + + + + + + + + + +/****************************************************************************** +* * +* Paramètres : view = visualisation à consulter. * +* options = règles d'affichage des colonnes modulables. * +* * +* Description : Fournit la largeur requise par une visualisation. * +* * +* Retour : Dimension calculée. * +* * +* Remarques : - * +* * +******************************************************************************/ + +gint g_buffer_view_get_width(GBufferView *view, const GDisplayOptions *options) +{ + gint result; /* Taille à retourner */ + + result = g_buffer_cache_get_text_position(view->cache); + + result += g_width_tracker_get_width(view->tracker, options); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : view = visualisation à consulter. * +* options = règles d'affichage des colonnes modulables. * +* * +* Description : Fournit la largeur requise pour dépasser les marges gauches. * +* * +* Retour : Dimension calculée. * +* * +* Remarques : - * +* * +******************************************************************************/ + +gint g_buffer_view_get_margin(GBufferView *view, const GDisplayOptions *options) +{ + gint result; /* Taille à retourner */ + + result = g_buffer_cache_get_text_position(view->cache); + + result += g_width_tracker_get_margin(view->tracker, options); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : view = visualisation à consulter. * +* * +* Description : Fournit la hauteur requise par une visualisation. * +* * +* Retour : Dimension calculée. * +* * +* Remarques : - * +* * +******************************************************************************/ + +gint g_buffer_view_get_height(const GBufferView *view) +{ + gint result; /* Taille à retourner */ + + result = g_buffer_cache_get_line_height(view->cache); + + result *= (view->last - view->first + 1); + + return result; + +} + + + + + + + + + + + + + +/****************************************************************************** +* * +* Paramètres : view = vue de tampon à mettre à jour. * +* x = abscisse proposée pour le nouvel emplacement. * +* y = ordonnée proposée pour le nouvel emplacement. * +* options = règles d'affichage des colonnes modulables. * +* offsets = décalages supplémentaires à appliquer. * +* caret = position du curseur à construire. [OUT] * +* cursor = emplacement correspondant à cette position. [OUT] * +* * +* Description : Calcule la position idéale de curseur pour un point donné. * +* * +* Retour : true si les deux derniers arguments ont pu être constitués. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool g_buffer_view_compute_caret_full(GBufferView *view, gint x, gint y, const GDisplayOptions *options, const line_width_summary *offsets, cairo_rectangle_int_t *caret, GLineCursor **cursor) +{ + bool result; /* Bilan à retourner */ + gint lheight; /* Hauteur d'une ligne */ + size_t index; /* Indice de ligne de tampon */ + GBufferLine *line; /* Ligne à la position courante*/ + + result = false; + + /* Détermination de la ligne courante */ + + lheight = g_buffer_cache_get_line_height(view->cache); + index = y / lheight; + + index += view->first; + + if (index > view->last) + goto gbvccf_done; + + line = g_buffer_cache_find_line_by_index(view->cache, index); + + assert(line != NULL); + + /* Calcul d'une position */ + + result = _g_buffer_view_compute_caret_full(view, x, line, index, options, offsets, caret, cursor); + + g_object_unref(G_OBJECT(line)); + + gbvccf_done: + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : view = vue de tampon à mettre à jour. * +* x = abscisse proposée pour le nouvel emplacement. * +* line = ligne correspondant à la position. * +* index = indice de cette même ligne dans le tampon. * +* options = règles d'affichage des colonnes modulables. * +* offsets = décalages supplémentaires à appliquer. * +* caret = position du curseur à construire. [OUT] * +* cursor = emplacement correspondant à cette position. [OUT] * +* * +* Description : Calcule la position idéale de curseur pour un point donné. * +* * +* Retour : true si les deux derniers arguments ont pu être constitués. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool _g_buffer_view_compute_caret_full(GBufferView *view, gint x, GBufferLine *line, size_t index, const GDisplayOptions *options, const line_width_summary *offsets, cairo_rectangle_int_t *caret, GLineCursor **cursor) +{ + bool result; /* Bilan à retourner */ + gint text_pos; /* Abscisse de départ du texte */ + line_width_summary summary; /* Résumé concis des largeurs */ + gint base; /* Position absolue de segment */ + bool status; /* Bilan de la localisation */ + gint lheight; /* Hauteur d'une ligne */ + + result = false; + + /* Zone d'intervention bornée ! */ + + text_pos = g_buffer_cache_get_text_position(view->cache); + + if (x < text_pos) + goto gbvccf_done; + + /* Calcul d'une position */ + + g_width_tracker_get_local_width_summary(view->tracker, index, &summary); + + x -= text_pos; + + status = g_buffer_line_get_coord_at(line, &summary, options, offsets, &base, &x, + GDK_SCROLL_LEFT, true, (col_coord_t []) { { 0 } }); + + if (!status) + goto gbvccf_done; + + /* Transmission des informations */ + + lheight = g_buffer_cache_get_line_height(view->cache); + + caret->x = text_pos + base + x; + + caret->y = (index - view->first) * lheight; + + caret->width = 2; + caret->height = lheight; + + g_buffer_cache_get_line_cursor(view->cache, index, caret->x, cursor); + + result = true; + + gbvccf_done: + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : view = vue de tampon à manipuler. * +* line = ligne à venir consulter. * +* index = indice de cette même ligne dans le tampon. * +* caret = position du curseur à faire évoluer. * +* ctrl = indique la demande d'un parcours rapide. * +* dir = direction du parcours. * +* options = règles d'affichage des colonnes modulables. * +* offsets = décalages supplémentaires à appliquer. * +* * +* Description : Déplace le curseur au sein d'une vue de tampon. * +* * +* Retour : true si un déplacement a été effectué, false sinon. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static bool _g_buffer_view_move_caret(GBufferView *view, const GBufferLine *line, size_t index, cairo_rectangle_int_t *caret, bool ctrl, GdkScrollDirection dir, const GDisplayOptions *options, const line_width_summary *offsets) +{ + bool result; /* Bilan à retourner */ + gint text_pos; /* Abscisse de départ du texte */ + gint offset; /* Point de travail modifiable */ + line_width_summary summary; /* Résumé concis des largeurs */ + gint base; /* Position absolue de segment */ + col_coord_t coord; /* Coordonnées en interne */ + line_segment *segment; /* Bribe de texte trouvée */ + + + result = false; + + /* Zone d'intervention bornée ! */ + + text_pos = g_buffer_cache_get_text_position(view->cache); + + if (caret->x < text_pos) + goto gbvmc_done; + + offset = caret->x - text_pos; + + g_width_tracker_get_local_width_summary(view->tracker, index, &summary); + + /* Déplacement au sein du segment courant ? */ + + result = g_buffer_line_get_coord_at(line, &summary, options, offsets, &base, &offset, dir, false, &coord); + + if (result) + { + segment = g_buffer_line_get_segment_from_coord(line, &coord); + + result = move_caret_on_line_segment(segment, &offset, ctrl, dir); + + release_line_segment(segment); + + } + + /* Tentative de déplacement chez le segment voisin ? */ + + if (!result) + { + base = 0; + + result = g_buffer_line_find_near_coord(line, &coord, &summary, options, offsets, dir, &offset); + + } + + /* Mise à jour éventuelle */ + + if (result) + caret->x = text_pos + base + offset; + + gbvmc_done: + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : view = vue de tampon à mettre à jour. * +* ctrl = indique la demande d'un parcours rapide. * +* dir = direction du parcours. * +* options = règles d'affichage des colonnes modulables. * +* offsets = décalages supplémentaires à appliquer. * +* caret = position du curseur à faire évoluer. [OUT] * +* cursor = emplacement correspondant à cette position. [OUT] * +* * +* Description : Déplace le curseur au sein d'une vue de tampon. * +* * +* Retour : true si les deux derniers arguments ont pu être constitués. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool g_buffer_view_move_caret(GBufferView *view, bool ctrl, GdkScrollDirection dir, const GDisplayOptions *options, const line_width_summary *offsets, cairo_rectangle_int_t *caret, GLineCursor **cursor) +{ + bool result; /* Bilan à retourner */ + size_t index; /* Indice de ligne de tampon */ + GBufferLine *line; /* Ligne sous le pointeur */ + size_t first; /* Première ligne intégrée */ + size_t last; /* Dernière ligne intégrée */ + GBufferLine *other; /* Ligne voisine à visiter */ + bool moved; /* Mémorisation d'une évolut° */ + gint text_pos; /* Abscisse de départ du texte */ + + result = false; + + line = g_buffer_view_find_line_at(view, caret->y, &index); + if (line == NULL) goto gbvmc_done; + + first = view->first; + last = view->last; + + switch (dir) + { + case GDK_SCROLL_UP: + + if (index > first) + { + index--; + + other = g_buffer_cache_find_line_by_index(view->cache, index); + assert(other != NULL); + + result = _g_buffer_view_compute_caret_full(view, caret->x, other, index, + options, offsets, caret, cursor); + + g_object_unref(G_OBJECT(other)); + + } + + break; + + case GDK_SCROLL_DOWN: + + if (index < last) + { + index++; + + other = g_buffer_cache_find_line_by_index(view->cache, index); + assert(other != NULL); + + result = _g_buffer_view_compute_caret_full(view, caret->x, other, index, + options, offsets, caret, cursor); + + g_object_unref(G_OBJECT(other)); + + } + + break; + + case GDK_SCROLL_LEFT: + + moved = _g_buffer_view_move_caret(view, line, index, caret, ctrl, GDK_SCROLL_LEFT, options, offsets); + + if (moved) + { + g_buffer_cache_get_line_cursor(view->cache, index, caret->x, cursor); + result = true; + } + + else if (index > first) + { + index--; + + other = g_buffer_cache_find_line_by_index(view->cache, index); + assert(other != NULL); + + result = _g_buffer_view_compute_caret_full(view, INT_MAX, other, index, + options, offsets, caret, cursor); + + g_object_unref(G_OBJECT(other)); + + } + + break; + + case GDK_SCROLL_RIGHT: + + moved = _g_buffer_view_move_caret(view, line, index, caret, ctrl, GDK_SCROLL_RIGHT, options, offsets); + + if (moved) + { + g_buffer_cache_get_line_cursor(view->cache, index, caret->x, cursor); + result = true; + } + + else if (index < last) + { + index++; + + text_pos = g_buffer_cache_get_text_position(view->cache); + + other = g_buffer_cache_find_line_by_index(view->cache, index); + assert(other != NULL); + + result = _g_buffer_view_compute_caret_full(view, text_pos, other, index, + options, offsets, caret, cursor); + + g_object_unref(G_OBJECT(other)); + + } + + break; + + default: /* GDK_SCROLL_SMOOTH */ + break; + + } + + g_object_unref(G_OBJECT(line)); + + gbvmc_done: + + return result; + +} + + + + + + + + +/****************************************************************************** +* * +* Paramètres : view = vue de tampon à mettre à jour. * +* x = abscisse de la zone principale à traiter. * +* y = ordonnée de la zone principale à traiter. * +* options = règles d'affichage des colonnes modulables. * +* offsets = décalages supplémentaires à appliquer. * +* * +* Description : Trouve le créateur à l'origine d'un emplacement donné. * +* * +* Retour : Créateur trouvé ou NULL si aucun. * +* * +* Remarques : - * +* * +******************************************************************************/ + +GObject *g_buffer_view_find_creator(GBufferView *view, gint x, gint y, const GDisplayOptions *options, const line_width_summary *offsets) +{ + GObject *result; /* Trouvaille à faire remonter */ + gint text_pos; /* Abscisse de départ du texte */ + gint lheight; /* Hauteur d'une ligne */ + size_t index; /* Indice de ligne de tampon */ + GBufferLine *line; /* Ligne à la position courante*/ + line_width_summary summary; /* Résumé concis des largeurs */ + + result = NULL; + + /* Zone d'intervention bornée ! */ + + text_pos = g_buffer_cache_get_text_position(view->cache); + + if (x < text_pos) + goto gbvfc_done; + + /* Détermination de la ligne concernée */ + + lheight = g_buffer_cache_get_line_height(view->cache); + index = y / lheight; + + index += view->first; + + if (index > view->last) + goto gbvfc_done; + + line = g_buffer_cache_find_line_by_index(view->cache, index); + + assert(line != NULL); + + /* Recherche d'un segment et de son empreinte */ + + g_width_tracker_get_local_width_summary(view->tracker, index, &summary); + + x -= text_pos; + + result = g_buffer_line_get_creator_at(line, &summary, options, offsets, + (gint []) { 0 }, &x, GDK_SCROLL_LEFT, false); + + g_object_unref(G_OBJECT(line)); + + gbvfc_done: + + return result; + +} + + + + + + + + +/****************************************************************************** +* * +* Paramètres : view = vue de tampon à mettre à jour. * +* * +* Description : Supprime toute mise en évidence de segments. * +* * +* Retour : true si un besoin d'actualisation d'affichage se fait sentir.* +* * +* Remarques : - * +* * +******************************************************************************/ + +bool g_buffer_view_unhighlight_segments(GBufferView *view) +{ + bool result; /* Bilan d'action à renvoyer */ + + result = reset_segment_content_list(view->highlighted); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : view = vue de tampon à mettre à jour. * +* x = abscisse de la zone principale à traiter. * +* y = ordonnée de la zone principale à traiter. * +* options = règles d'affichage des colonnes modulables. * +* offsets = décalages supplémentaires à appliquer. * +* * +* Description : Surligne tous les segments similaires à celui sous la souris.* +* * +* Retour : true si un besoin d'actualisation d'affichage se fait sentir.* +* * +* Remarques : - * +* * +******************************************************************************/ + +bool g_buffer_view_highlight_segments(GBufferView *view, gint x, gint y, const GDisplayOptions *options, const line_width_summary *offsets) +{ + bool result; /* Besoin à faire remonter */ + gint text_pos; /* Abscisse de départ du texte */ + gint lheight; /* Hauteur d'une ligne */ + size_t index; /* Indice de ligne de tampon */ + GBufferLine *line; /* Ligne à la position courante*/ + line_width_summary summary; /* Résumé concis des largeurs */ + line_segment *segment; /* Segment sélectionnable */ + + /* Réinitialisation */ + + if (view->highlighted != NULL) + result = g_buffer_view_unhighlight_segments(view); + else + result = false; + + /* Zone d'intervention bornée ! */ + + text_pos = g_buffer_cache_get_text_position(view->cache); + + if (x < text_pos) + goto gbvhs_done; + + /* Détermination de la ligne concernée */ + + lheight = g_buffer_cache_get_line_height(view->cache); + index = y / lheight; + + index += view->first; + + if (index > view->last) + goto gbvhs_done; + + line = g_buffer_cache_find_line_by_index(view->cache, index); + + assert(line != NULL); + + /* Recherche d'un segment et de son empreinte */ + + g_width_tracker_get_local_width_summary(view->tracker, index, &summary); + + x -= text_pos; + + segment = g_buffer_line_get_segment_at(line, &summary, options, offsets, + (gint []) { 0 }, &x, GDK_SCROLL_LEFT, true); + + g_object_unref(G_OBJECT(line)); + + /* Conclusion */ + + if (segment != NULL) + { + result |= add_segment_content_to_selection_list(view->highlighted, segment); + release_line_segment(segment); + } + + if (result) + g_signal_emit_by_name(view, "need-redraw"); + + gbvhs_done: + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : view = visualisation à représenter. * +* cr = contexte graphique dédié à la procédure. * +* virt_y = ordonnée réelle du point 0 à l'écran. * +* area = position et surface à traiter. * +* options = règles d'affichage des colonnes modulables. * +* offsets = décalages supplémentaires à appliquer. * +* selected = ordonnée d'une ligne sélectionnée ou NULL. * +* scale = échelle appliquée à la surface de rendu. * +* export = indique si la vue est en cours d'exportation. * +* * +* Description : Imprime la visualisation du tampon de lignes quelconques. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +void g_buffer_view_draw(const GBufferView *view, cairo_t *cr, gint virt_y, const cairo_rectangle_int_t *area, const GDisplayOptions *options, const line_width_summary *offsets, gint *selected, double scale, bool export) +{ + gint line_height; /* Hauteur d'une ligne */ + gint cr_y; /* Ordonnée pour le dessin */ + size_t first; /* Première ligne visée */ + size_t last; /* Dernière ligne visée */ + segcnt_list *highlighted; /* Segments mis en évidence */ + + line_height = g_buffer_cache_get_line_height(view->cache) * scale; + + line_height = MAX(line_height, 1); + + /* Indice et point de départ */ + + first = view->first; + first += (virt_y / line_height); + + cr_y = area->y - (virt_y % line_height); + + /* Indice de d'arrivée */ + + last = first + (area->height / line_height); + if (area->height % line_height > 0) last++; + + last = MIN(last, view->last); + + /* Phase de dessin ! */ + + /** + * Le contexte n'est pas sauvegardé avant modification ici car + * l'appelant l'a fait pour nous avant sa translation sur les abscisses. + */ + + cairo_translate(cr, 0, cr_y); + + if (selected != NULL) + *selected -= cr_y; + + if (export) + highlighted = init_segment_content_list(); + else + highlighted = view->highlighted; + + g_buffer_cache_draw(view->cache, cr, first, last, area, options, offsets, selected, highlighted); + + if (export) + unref_segment_content_list(highlighted); + +} + + + + + + + + + + + + + + + +/****************************************************************************** +* * +* Paramètres : view = visualisation à consulter. * +* y = ordonnée comprise dans la ligne recherchée. * +* idx = indice de la ligne trouvée ou NULL. [OUT] * +* * +* Description : Fournit la ligne présente à une ordonnée donnée. * +* * +* Retour : Ligne retrouvée ou NULL si aucune. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static GBufferLine *g_buffer_view_find_line_at(GBufferView *view, gint y, size_t *idx) +{ + GBufferLine *result; /* Ligne trouvée à retourner */ + gint lheight; /* Hauteur d'une ligne */ + size_t index; /* Indice attendu */ + + lheight = g_buffer_cache_get_line_height(view->cache); + index = y / lheight; + + index += view->first; + + if (index <= view->last) + result = g_buffer_cache_find_line_by_index(view->cache, index); + else + result = NULL; + + if (result != NULL && idx != NULL) + *idx = index; + + return result; + +} + + + + + + + + + + + + + + + +/****************************************************************************** +* * +* Paramètres : view = visualisation à consulter. * +* cursor = emplacement à présenter à l'écran. * +* code = s'arrête si possible à une ligne avec code. * +* x = position horizontale au sein du composant. [OUT] * +* y = position verticale au sein du composant. [OUT] * +* * +* Description : Indique la position d'affichage d'une adresse donnée. * +* * +* Retour : true si l'adresse fait partie du composant, false sinon. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool g_buffer_view_get_cursor_coordinates(GBufferView *view, const GLineCursor *cursor, bool code, gint *x, gint *y) +{ + bool result; /* Bilan à retourner */ + + result = g_buffer_cache_get_cursor_coordinates(view->cache, cursor, view->first, view->last, code, x, y); + + return result; + +} diff --git a/src/glibext/bufferview.h b/src/glibext/bufferview.h new file mode 100644 index 0000000..01da713 --- /dev/null +++ b/src/glibext/bufferview.h @@ -0,0 +1,115 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * bufferview.h - prototypes pour l'affichage d'une vue particulière d'un tampon de lignes + * + * Copyright (C) 2016-2019 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 . + */ + + +#ifndef _GLIBEXT_BUFFERVIEW_H +#define _GLIBEXT_BUFFERVIEW_H + + +#include + + +#include "buffercache.h" +#include "gdisplayoptions.h" + + + +#define G_TYPE_BUFFER_VIEW (g_buffer_view_get_type()) +#define G_BUFFER_VIEW(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_BUFFER_VIEW, GBufferView)) +#define G_BUFFER_VIEW_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_BUFFER_VIEW, GBufferViewClass)) +#define G_IS_BUFFER_VIEW(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_BUFFER_VIEW)) +#define G_IS_BUFFER_VIEW_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_BUFFER_VIEW)) +#define G_BUFFER_VIEW_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_BUFFER_VIEW, GBufferViewClass)) + + +/* Vue d'un tampon pour code désassemblé (instance) */ +typedef struct _GBufferView GBufferView; + +/* Vue d'un tampon pour code désassemblé (classe) */ +typedef struct _GBufferViewClass GBufferViewClass; + + +/* Détermine le type de la vue d'un tampon pour lignes générées. */ +GType g_buffer_view_get_type(void); + +/* Crée une nouvelle vue d'un tampon pour lignes générées. */ +GBufferView *g_buffer_view_new(GBufferCache *, segcnt_list *); + +/* Fournit le tampon de code lié à un visualisateur donné. */ +GBufferCache *g_buffer_view_get_cache(const GBufferView *); + +/* Restreint le champ d'application de l'affichage. */ +void g_buffer_view_restrict(GBufferView *, GLineCursor *, GLineCursor *); + +/* Indique le champ d'application de l'affichage. */ +bool g_buffer_view_get_restrictions(const GBufferView *, GLineCursor **, GLineCursor **); + + + +/* Fournit la largeur requise par une visualisation. */ +gint g_buffer_view_get_width(GBufferView *, const GDisplayOptions *); + +/* Fournit la largeur requise pour dépasser les marges gauches. */ +gint g_buffer_view_get_margin(GBufferView *, const GDisplayOptions *); + +/* Fournit la hauteur requise par une visualisation. */ +gint g_buffer_view_get_height(const GBufferView *); + + + + + +/* Calcule la position idéale de curseur pour un point donné. */ +bool g_buffer_view_compute_caret_full(GBufferView *, gint, gint, const GDisplayOptions *, const line_width_summary *, cairo_rectangle_int_t *, GLineCursor **); + +/* Déplace le curseur au sein d'une vue de tampon. */ +bool g_buffer_view_move_caret(GBufferView *, bool, GdkScrollDirection, const GDisplayOptions *, const line_width_summary *, cairo_rectangle_int_t *, GLineCursor **); + + + +/* Trouve le créateur à l'origine d'un emplacement donné. */ +GObject *g_buffer_view_find_creator(GBufferView *, gint, gint, const GDisplayOptions *, const line_width_summary *); + + + +/* Supprime toute mise en évidence de segments. */ +bool g_buffer_view_unhighlight_segments(GBufferView *); + +/* Surligne tous les segments similaires à celui sous la souris. */ +bool g_buffer_view_highlight_segments(GBufferView *, gint, gint, const GDisplayOptions *, const line_width_summary *); + +/* Imprime la visualisation du tampon de lignes quelconques. */ +void g_buffer_view_draw(const GBufferView *, cairo_t *, gint, const cairo_rectangle_int_t *, const GDisplayOptions *, const line_width_summary *, gint *, double, bool); + + + + + + +/* Indique la position d'affichage d'une adresse donnée. */ +bool g_buffer_view_get_cursor_coordinates(GBufferView *, const GLineCursor *, bool, gint *, gint *); + + + + + +#endif /* _GLIBEXT_BUFFERVIEW_H */ diff --git a/src/glibext/gbuffercache-int.h b/src/glibext/gbuffercache-int.h deleted file mode 100644 index 6886fb0..0000000 --- a/src/glibext/gbuffercache-int.h +++ /dev/null @@ -1,96 +0,0 @@ - -/* Chrysalide - Outil d'analyse de fichiers binaires - * gbuffercache-int.h - définitions internes d'affichage à la demande d'un ensemble de lignes - * - * Copyright (C) 2020 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 . - */ - - -#ifndef _GLIBEXT_GBUFFERCACHE_INT_H -#define _GLIBEXT_GBUFFERCACHE_INT_H - - -#include "gbuffercache.h" - - - -/* --------------------- FONCTIONS AUXILIAIRES DE MANIPULATIONS --------------------- */ - - -/* Informations rattachées à la génération d'une ligne */ -typedef struct _generator_link -{ - GLineGenerator *instance; /* Fournisseur de contenu */ - size_t repeat; /* Compteur de successions */ - -} generator_link; - -/* Suivi interne de l'état d'une ligne */ -typedef struct _cache_info -{ - union - { - generator_link generator; /* Générateur unique */ - generator_link *generators; /* Liste de générateurs */ - }; - size_t count; /* Taille de cette liste */ - - GBufferLine *line; /* Ligne en place ou NULL */ - - BufferLineFlags extra_flags; /* Propriétés supplémentaires */ - -} cache_info; - - - -/* -------------------------- TAMPON POUR CODE DESASSEMBLE -------------------------- */ - - -/* Tampon pour gestion de lignes optimisée (instance) */ -struct _GBufferCache -{ - GObject parent; /* A laisser en premier */ - - GBinContent *content; /* Contenu binaire global */ - - cache_info *lines; /* Liste des lignes intégrées */ - size_t count; /* Quantité en cache */ - size_t used; /* Quantité utilisée */ - - GWidthTracker *tracker; /* Suivi des largeurs */ - -}; - -/* Tampon pour gestion de lignes optimisée (classe) */ -struct _GBufferCacheClass -{ - GObjectClass parent; /* A laisser en premier */ - - gint line_height; /* Hauteur maximale des lignes */ - gint left_margin; /* Marge gauche + espace */ - gint text_pos; /* Début d'impression du code */ - - /* Signaux */ - - void (* size_changed) (GBufferCache *, bool, size_t, size_t); - -}; - - - -#endif /* _GLIBEXT_GBUFFERCACHE_INT_H */ diff --git a/src/glibext/gbuffercache.c b/src/glibext/gbuffercache.c deleted file mode 100644 index b54de26..0000000 --- a/src/glibext/gbuffercache.c +++ /dev/null @@ -1,1725 +0,0 @@ - -/* Chrysalide - Outil d'analyse de fichiers binaires - * gbuffercache.c - affichage à la demande d'un ensemble de lignes - * - * Copyright (C) 2016-2019 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 "gbuffercache.h" - - -#include -#include -#include - - -#include "gbuffercache-int.h" -#include "chrysamarshal.h" - - - -/* --------------------- FONCTIONS AUXILIAIRES DE MANIPULATIONS --------------------- */ - - -/* Gros verrou global pour alléger les structures... */ -G_LOCK_DEFINE_STATIC(_line_update); - - -/* Met en place un nouvel ensemble d'information sur une ligne. */ -static void init_cache_info(cache_info *, GLineGenerator *, size_t, BufferLineFlags); - -/* Libère la mémoire occupée par des informations sur une ligne. */ -static void release_cache_info(cache_info *); - -/* Ajoute un générateur aux informations sur une ligne. */ -static void extend_cache_info(cache_info *, GLineGenerator *, BufferLineFlags); - -/* Retire un générateur aux informations d'une ligne. */ -static void remove_from_cache_info(cache_info *, GLineGenerator *); - -/* Retrouve l'emplacement correspondant à une position de ligne. */ -static void get_cache_info_cursor(const cache_info *, size_t, gint, GLineCursor **); - -/* Suivit les variations du compteur de références d'une ligne. */ -static void on_line_ref_toggle(cache_info *, GBufferLine *, gboolean); - -/* Fournit la ligne de tampon correspondant aux générateurs. */ -static GBufferLine *get_cache_info_line(cache_info *, size_t, const GBinContent *); - -/* Force la réinitialisation d'une éventuelle ligne cachée. */ -static void _reset_cache_info_line_unlocked(cache_info *); - -/* Force la réinitialisation d'une éventuelle ligne cachée. */ -static void reset_cache_info_line(cache_info *); - - - -/* -------------------------- TAMPON POUR CODE DESASSEMBLE -------------------------- */ - - -/* Taille des allocations de masse */ -#define LINE_ALLOC_BULK 1000 - - -/* Procède à l'initialisation d'une classe de tampon de lignes. */ -static void g_buffer_cache_class_init(GBufferCacheClass *); - -/* Procède à l'initialisation d'un tampon de gestion de lignes. */ -static void g_buffer_cache_init(GBufferCache *); - -/* Supprime toutes les références externes. */ -static void g_buffer_cache_dispose(GBufferCache *); - -/* Procède à la libération totale de la mémoire. */ -static void g_buffer_cache_finalize(GBufferCache *); - -/* Calcule l'indice d'apparition d'un générateur dans le tampon. */ -static size_t g_buffer_cache_compute_repetition(GBufferCache *, size_t, GLineGenerator *); - - - -/* ---------------------------------------------------------------------------------- */ -/* FONCTIONS AUXILIAIRES DE MANIPULATIONS */ -/* ---------------------------------------------------------------------------------- */ - - -/****************************************************************************** -* * -* Paramètres : info = informations concernant une ligne à constituer. * -* generator = générateur à associer à toutes les lignes. * -* repeat = compteur de répétition entre les lignes. * -* flags = propriétés supplémentaires à associer à la ligne.* -* * -* Description : Met en place un nouvel ensemble d'information sur une ligne. * -* * -* Retour : - * -* * -* Remarques : - * -* * -******************************************************************************/ - -static void init_cache_info(cache_info *info, GLineGenerator *generator, size_t repeat, BufferLineFlags flags) -{ - info->generator.instance = generator; - info->generator.repeat = repeat; - - g_object_ref(G_OBJECT(generator)); - - info->count = 1; - - info->line = NULL; - - info->extra_flags = flags; - -} - - -/****************************************************************************** -* * -* Paramètres : info = informations concernant une ligne à constituer. * -* * -* Description : Libère la mémoire occupée par des informations sur une ligne.* -* * -* Retour : - * -* * -* Remarques : - * -* * -******************************************************************************/ - -static void release_cache_info(cache_info *info) -{ - size_t i; /* Boucle de parcours */ - - if (info->count == 1) - g_object_unref(G_OBJECT(info->generator.instance)); - - else - for (i = 0; i < info->count; i++) - g_object_unref(G_OBJECT(info->generators[i].instance)); - - reset_cache_info_line(info); - -} - - -/****************************************************************************** -* * -* Paramètres : info = informations concernant une ligne à actualiser. * -* generator = générateur à associer à toutes les lignes. * -* flags = propriétés supplémentaires à associer à la ligne.* -* * -* Description : Ajoute un générateur aux informations sur une ligne. * -* * -* Retour : - * -* * -* Remarques : - * -* * -******************************************************************************/ - -static void extend_cache_info(cache_info *info, GLineGenerator *generator, BufferLineFlags flags) -{ - generator_link first; /* Générateur déjà en place */ - generator_link *new; /* Nouveau générateur placé */ - - if (info->count == 1) - { - first = info->generator; - - info->generators = (generator_link *)calloc(2, sizeof(generator_link)); - - info->generators[0] = first; - info->count = 2; - - new = &info->generators[1]; - - } - else - { - info->generators = (generator_link *)realloc(info->generators, - ++info->count * sizeof(generator_link)); - - new = &info->generators[info->count - 1]; - - } - - new->instance = generator; - new->repeat = 0; - - g_object_ref(G_OBJECT(generator)); - - reset_cache_info_line(info); - - /** - * On peut rajouter des indications, mais, en cas de retrait d'un générateur, - * on ne saura pas forcément lesquelles retirer puisque qu'on ne trace pas - * leur origine. - * - * On considère donc que seul le premier générateur (le principal) a le - * droit de poser des fanions. - */ - - assert(flags == BLF_NONE); - -} - - -/****************************************************************************** -* * -* Paramètres : info = informations concernant une ligne à actualiser. * -* generator = générateur à dissocier de toutes les lignes. * -* * -* Description : Retire un générateur aux informations d'une ligne. * -* * -* Retour : - * -* * -* Remarques : - * -* * -******************************************************************************/ - -static void remove_from_cache_info(cache_info *info, GLineGenerator *generator) -{ - generator_link *link; /* Accès simplifié */ - size_t i; /* Boucle de parcours */ - generator_link *old; /* Mémorisation avant opérat° */ - - if (info->count == 1) - { - link = &info->generator; - - assert(link->instance == generator); - - g_object_unref(G_OBJECT(generator)); - - info->count = 0; - - } - - else - { - for (i = 0; i < info->count; i++) - { - link = &info->generators[i]; - - if (link->instance == generator) - { - if ((i + 1) < info->count) - memmove(&info->generators[i], &info->generators[i + 1], - (info->count - i - 1) * sizeof(generator_link)); - - if (info->count == 2) - { - old = info->generators; - - info->count = 1; - info->generator = info->generators[0]; - - free(old); - - } - else - info->generators = (generator_link *)realloc(info->generators, - --info->count * sizeof(generator_link)); - - g_object_unref(G_OBJECT(generator)); - - break; - - } - - } - -#ifndef NDEBUG - - /** - * Attention : si l'élément était en dernière position, - * l'indice de parcours est désormais égal au nombre de générateurs présents ! - */ - assert(i <= info->count); - - for ( ; i < info->count; i++) - { - link = &info->generators[i]; - - assert(link->instance != generator); - - } - -#endif - - } - - reset_cache_info_line(info); - -} - - -/****************************************************************************** -* * -* Paramètres : info = informations sur une ligne à venir consulter. * -* index = indice de la ligne visée par la consultation. * -* x = position géographique sur la ligne concernée. * -* cursor = emplacement à constituer. [OUT] * -* * -* Description : Retrouve l'emplacement correspondant à une position de ligne.* -* * -* Retour : - * -* * -* Remarques : - * -* * -******************************************************************************/ - -static void get_cache_info_cursor(const cache_info *info, size_t index, gint x, GLineCursor **cursor) -{ - const generator_link *generator; /* Générateur retenu */ - - if (info->count == 1) - generator = &info->generator; - else - generator = &info->generators[0]; - - *cursor = g_line_generator_compute_cursor(generator->instance, x, index, generator->repeat); - -} - - -/****************************************************************************** -* * -* Paramètres : info = informations sur une ligne à venir manipuler. * -* line = tampon de lignes à venir supprimer au besoin. * -* last = indication sur la valeur du compteur de références. * -* * -* Description : Suivit les variations du compteur de références d'une ligne. * -* * -* Retour : - * -* * -* Remarques : - * -* * -******************************************************************************/ - -static void on_line_ref_toggle(cache_info *info, GBufferLine *line, gboolean last) -{ - if (last) - { - G_LOCK(_line_update); - - assert(info->line != NULL); - - _reset_cache_info_line_unlocked(info); - - G_UNLOCK(_line_update); - - } - -} - - -/****************************************************************************** -* * -* Paramètres : info = informations sur une ligne à venir manipuler. * -* index = indice de la ligne à constituer. * -* content = éventuel contenu binaire brut à imprimer. * -* * -* Description : Fournit la ligne de tampon correspondant aux générateurs. * -* * -* Retour : Ligne déjà en place ou créée pour le besoin. * -* * -* Remarques : - * -* * -******************************************************************************/ - -static GBufferLine *get_cache_info_line(cache_info *info, size_t index, const GBinContent *content) -{ - GBufferLine *result; /* Construction à retourner */ - size_t i; /* Boucle de parcours */ - - G_LOCK(_line_update); - - result = info->line; - - if (result == NULL) - { - result = g_buffer_line_new(UNUSED_MRANGE_PTR, 0/* !! */); - - g_object_add_toggle_ref(G_OBJECT(result), (GToggleNotify)on_line_ref_toggle, info); - - if (info->count == 1) - g_line_generator_print(info->generator.instance, result, index, - info->generator.repeat, content); - - else - for (i = 0; i < info->count; i++) - g_line_generator_print(info->generators[i].instance, result, index, - info->generators[i].repeat, content); - - info->line = result; - - } - - else - g_object_ref(G_OBJECT(result)); - - G_UNLOCK(_line_update); - - return result; - -} - - -/****************************************************************************** -* * -* Paramètres : info = informations sur une ligne à venir manipuler. * -* * -* Description : Force la réinitialisation d'une éventuelle ligne cachée. * -* * -* Retour : - * -* * -* Remarques : - * -* * -******************************************************************************/ - -static void _reset_cache_info_line_unlocked(cache_info *info) -{ - if (info->line != NULL) - { - g_object_remove_toggle_ref(G_OBJECT(info->line), (GToggleNotify)on_line_ref_toggle, info); - - info->line = NULL; - - } - -} - - -/****************************************************************************** -* * -* Paramètres : info = informations sur une ligne à venir manipuler. * -* * -* Description : Force la réinitialisation d'une éventuelle ligne cachée. * -* * -* Retour : - * -* * -* Remarques : - * -* * -******************************************************************************/ - -static void reset_cache_info_line(cache_info *info) -{ - G_LOCK(_line_update); - - _reset_cache_info_line_unlocked(info); - - G_UNLOCK(_line_update); - -} - - - -/* ---------------------------------------------------------------------------------- */ -/* TAMPON POUR CODE DESASSEMBLE */ -/* ---------------------------------------------------------------------------------- */ - - -/* Détermine le type du composant de tampon pour gestion de lignes optimisée. */ -G_DEFINE_TYPE(GBufferCache, g_buffer_cache, G_TYPE_OBJECT); - - -/****************************************************************************** -* * -* Paramètres : class = classe de composant GLib à initialiser. * -* * -* Description : Procède à l'initialisation d'une classe de tampon de lignes. * -* * -* Retour : - * -* * -* Remarques : - * -* * -******************************************************************************/ - -static void g_buffer_cache_class_init(GBufferCacheClass *class) -{ - GObjectClass *object; /* Autre version de la classe */ - - object = G_OBJECT_CLASS(class); - - object->dispose = (GObjectFinalizeFunc/* ! */)g_buffer_cache_dispose; - object->finalize = (GObjectFinalizeFunc)g_buffer_cache_finalize; - - class->line_height = 17; - class->left_margin = 2 * class->line_height; - class->text_pos = 2.5 * class->line_height; - - /* Signaux */ - - g_signal_new("size-changed", - G_TYPE_BUFFER_CACHE, - G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET(GBufferCacheClass, size_changed), - NULL, NULL, - g_cclosure_user_marshal_VOID__BOOLEAN_ULONG_ULONG, - G_TYPE_NONE, 3, G_TYPE_BOOLEAN, G_TYPE_ULONG, G_TYPE_ULONG); - -} - - -/****************************************************************************** -* * -* Paramètres : cache = composant GLib à initialiser. * -* * -* Description : Procède à l'initialisation d'un tampon de gestion de lignes. * -* * -* Retour : - * -* * -* Remarques : - * -* * -******************************************************************************/ - -static void g_buffer_cache_init(GBufferCache *cache) -{ - cache->content = NULL; - - cache->lines = NULL; - cache->count = 0; - cache->used = 0; - - cache->tracker = g_width_tracker_new(cache); - -} - - -/****************************************************************************** -* * -* Paramètres : cache = instance d'objet GLib à traiter. * -* * -* Description : Supprime toutes les références externes. * -* * -* Retour : - * -* * -* Remarques : - * -* * -******************************************************************************/ - -static void g_buffer_cache_dispose(GBufferCache *cache) -{ - size_t i; /* Boucle de parcours #1 */ - cache_info *info; /* Accès direct à une ligne */ - size_t j; /* Boucle de parcours #2 */ - - g_clear_object(&cache->content); - - for (i = 0; i < cache->used; i++) - { - info = &cache->lines[i]; - - if (info->count == 1) - g_clear_object(&info->generator.instance); - - else - for (j = 0; j < info->count; j++) - g_clear_object(&info->generators[j].instance); - - g_clear_object(&info->line); - - } - - g_clear_object(&cache->tracker); - - G_OBJECT_CLASS(g_buffer_cache_parent_class)->dispose(G_OBJECT(cache)); - -} - - -/****************************************************************************** -* * -* Paramètres : cache = instance d'objet GLib à traiter. * -* * -* Description : Procède à la libération totale de la mémoire. * -* * -* Retour : - * -* * -* Remarques : - * -* * -******************************************************************************/ - -static void g_buffer_cache_finalize(GBufferCache *cache) -{ - size_t i; /* Boucle de parcours */ - cache_info *info; /* Accès direct à une ligne */ - - for (i = 0; i < cache->used; i++) - { - info = &cache->lines[i]; - - if (info->count > 1) - free(info->generators); - - } - - if (cache->lines != NULL) - free(cache->lines); - - G_OBJECT_CLASS(g_buffer_cache_parent_class)->finalize(G_OBJECT(cache)); - -} - - -/****************************************************************************** -* * -* Paramètres : content = éventuel contenu binaire brut à référencer. * -* * -* Description : Crée un nouveau composant de tampon pour code désassemblé. * -* * -* Retour : Composant GLib créé. * -* * -* Remarques : - * -* * -******************************************************************************/ - -GBufferCache *g_buffer_cache_new(GBinContent *content) -{ - GBufferCache *result; /* Composant à retourner */ - - result = g_object_new(G_TYPE_BUFFER_CACHE, NULL); - - if (content != NULL) - { - result->content = content; - g_object_ref(G_OBJECT(content)); - } - - return result; - -} - - -/****************************************************************************** -* * -* Paramètres : cache = tampon de lignes à consulter. * -* * -* Description : Fournit la hauteur d'impression d'une ligne visualisée. * -* * -* Retour : Hauteur de ligne en pixels. * -* * -* Remarques : - * -* * -******************************************************************************/ - -gint g_buffer_cache_get_line_height(const GBufferCache *cache) -{ - GBufferCacheClass *class; /* Classe des tampons */ - - class = G_BUFFER_CACHE_GET_CLASS(cache); - - return class->line_height; - -} - - -/****************************************************************************** -* * -* Paramètres : cache = tampon de lignes à consulter. * -* * -* Description : Indique l'éventuel contenu binaire associé au cache. * -* * -* Retour : Eventuel contenu renseigné ou NULL. * -* * -* Remarques : - * -* * -******************************************************************************/ - -GBinContent *g_buffer_cache_get_content(const GBufferCache *cache) -{ - GBinContent *result; /* Contenu à retourner */ - - result = cache->content; - - if (result != NULL) - g_object_ref(G_OBJECT(result)); - - return result; - -} - - -/****************************************************************************** -* * -* Paramètres : cache = tampon de lignes à consulter. * -* * -* Description : Fournit la taille réservée pour la marge gauche. * -* * -* Retour : Largeur en pixels. * -* * -* Remarques : - * -* * -******************************************************************************/ - -gint g_buffer_cache_get_left_margin(const GBufferCache *cache) -{ - GBufferCacheClass *class; /* Classe des tampons */ - - class = G_BUFFER_CACHE_GET_CLASS(cache); - - return class->left_margin; - -} - - -/****************************************************************************** -* * -* Paramètres : cache = tampon de lignes à consulter. * -* * -* Description : Fournit la position de départ pour l'impression de texte. * -* * -* Retour : Position en pixels. * -* * -* Remarques : - * -* * -******************************************************************************/ - -gint g_buffer_cache_get_text_position(const GBufferCache *cache) -{ - GBufferCacheClass *class; /* Classe des tampons */ - - class = G_BUFFER_CACHE_GET_CLASS(cache); - - return class->text_pos; - -} - - -/****************************************************************************** -* * -* Paramètres : cache = instance GLib à consulter. * -* * -* Description : Compte le nombre de lignes rassemblées dans un tampon. * -* * -* Retour : Nombre de lignes constituant le tampon. * -* * -* Remarques : - * -* * -******************************************************************************/ - -size_t g_buffer_cache_count_lines(const GBufferCache *cache) -{ - return cache->used; - -} - - -/****************************************************************************** -* * -* Paramètres : cache = composant GLib à consulter. * -* * -* Description : Fournit un lien vers la structure de suivi de largeurs. * -* * -* Retour : Gestionnaire de largeurs de lignes. * -* * -* Remarques : - * -* * -******************************************************************************/ - -GWidthTracker *g_buffer_cache_get_width_tracker(const GBufferCache *cache) -{ - GWidthTracker *result; /* Instance à retourner * */ - - result = cache->tracker; - - g_object_ref(G_OBJECT(result)); - - return result; - -} - - - - - -/****************************************************************************** -* * -* Paramètres : cache = instance GLib à consulter. * -* index = indice de la ligne où se trouve le générateur. * -* generator = générateur associé à au moins une ligne. * -* * -* Description : Calcule l'indice d'apparition d'un générateur dans le tampon.* -* * -* Retour : - * -* * -* Remarques : - * -* * -******************************************************************************/ - -static size_t g_buffer_cache_compute_repetition(GBufferCache *cache, size_t index, GLineGenerator *generator) -{ - size_t result; /* Compteur à retourner */ - cache_info *info; /* Accès direct à une ligne */ - size_t i; /* Boucle de parcours */ - - result = 0; - - if (index > 0) - { - info = &cache->lines[index - 1]; - - if (info->count == 1) - { - if (info->generator.instance == generator) - result = info->generator.repeat + 1; - - } - - else - for (i = 0; i < info->count; i++) - if (info->generators[i].instance == generator) - { - result = info->generators[i].repeat + 1; - break; - } - - } - - return result; - -} - - -/****************************************************************************** -* * -* Paramètres : cache = instance GLib à modifier. * -* index = point d'insertion, puis de sauvegarde. * -* generator = générateur à insérer dans les lignes. * -* flags = propriétés supplémentaires à associer à la ligne.* -* before = précise l'emplacement final des nouvelles lignes.* -* after = précise l'emplacement final des nouvelles lignes.* -* * -* Description : Insère un générateur dans des lignes à une position donnée. * -* * -* Retour : - * -* * -* Remarques : - * -* * -******************************************************************************/ - -void g_buffer_cache_insert_at(GBufferCache *cache, size_t index, GLineGenerator *generator, BufferLineFlags flags, bool before, bool after) -{ -#ifndef NDEBUG - GLineCursor *gen_cursor; /* Position du générateur */ - GLineCursor *line_cursor; /* Position de la ligne */ - int ret; /* Bilan de comparaison */ -#endif - size_t needed; /* Emplacements nécessaires */ - size_t i; /* Boucle de parcours */ - - assert(index < cache->used); - - assert(!(before && after)); - -#ifndef NDEBUG - - if (!before && !after) - { - gen_cursor = g_line_generator_compute_cursor(generator, 0, index, 0); - - get_cache_info_cursor(&cache->lines[index], index, 0, &line_cursor); - - ret = g_line_cursor_compare(gen_cursor, line_cursor); - - g_object_unref(G_OBJECT(line_cursor)); - g_object_unref(G_OBJECT(gen_cursor)); - - assert(ret == 0); - - } - -#endif - - /* Cas particulier d'ajout en fin de cache... */ - if (after && (index + 1) == cache->used) - { - g_buffer_cache_append(cache, generator, flags); - goto gbcia_done; - } - - /* Adaptation de l'espace */ - - needed = g_line_generator_count_lines(generator); - - if (before || after) - { - if ((cache->used + needed) >= cache->count) - { - cache->count += needed + LINE_ALLOC_BULK; - cache->lines = (cache_info *)realloc(cache->lines, cache->count * sizeof(cache_info)); - } - } - - else if (needed > 1) - { - if ((cache->used + needed - 1) >= cache->count) - { - cache->count += needed - 1 + LINE_ALLOC_BULK; - cache->lines = (cache_info *)realloc(cache->lines, cache->count * sizeof(cache_info)); - } - } - - /* Insertion du générateur */ - - if (after) - index++; - - if (before || after) - { - memmove(&cache->lines[index + needed], &cache->lines[index], (cache->used - index) * sizeof(cache_info)); - - for (i = 0; i < needed; i++) - init_cache_info(&cache->lines[index + i], generator, i, flags); - - cache->used += needed; - - g_width_tracker_update_added(cache->tracker, index, needed); - - g_signal_emit_by_name(cache, "size-changed", true, index, needed); - - } - - else - { - extend_cache_info(&cache->lines[index], generator, flags); - - g_width_tracker_update(cache->tracker, index); - - if (needed > 1) - { - /* On déborde sur les lignes suivantes, donc on crée de l'espace ! */ - - memmove(&cache->lines[index + 1], - &cache->lines[index + 1 + needed - 1], (cache->used - index - 1) * sizeof(cache_info)); - - for (i = 1; i < needed; i++) - init_cache_info(&cache->lines[index + i], generator, i, BLF_NONE); - - cache->used += needed - 1; - - g_width_tracker_update_added(cache->tracker, index + 1, needed - 1); - - } - - g_signal_emit_by_name(cache, "size-changed", true, index, needed - 1); - - } - - gbcia_done: - - ; - -} - - -/****************************************************************************** -* * -* Paramètres : cache = instance GLib à modifier. * -* index = point de suppression. * -* * -* Description : Retire une ligne du tampon. * -* * -* Retour : - * -* * -* Remarques : - * -* * -******************************************************************************/ - -void g_buffer_cache_delete_at(GBufferCache *cache, size_t index) -{ - cache_info *info; /* Accès direct à une ligne */ - - assert(index < cache->used); - - info = &cache->lines[index]; - - release_cache_info(info); - - if ((index + 1) < cache->used) - memmove(&cache->lines[index], &cache->lines[index + 1], - (cache->used - index - 1) * sizeof(cache_info)); - - cache->used--; - - g_width_tracker_update_deleted(cache->tracker, index, index); - - g_signal_emit_by_name(cache, "size-changed", false, index, 1); - -} - - -/****************************************************************************** -* * -* Paramètres : cache = instance GLib à modifier. * -* index = point d'insertion, puis de sauvegarde. * -* type = type de générateurs à retirer des lignes visées. * -* before = précise l'emplacement final de l'élément visé. * -* after = précise l'emplacement final de l'élément visé. * -* * -* Description : Retire un type de générateur de lignes. * -* * -* Retour : Générateur éventuellement trouvé ou NULL si aucun. * -* * -* Remarques : - * -* * -******************************************************************************/ - -GLineGenerator *g_buffer_cache_delete_type_at(GBufferCache *cache, size_t index, GType type, bool before, bool after) -{ - GLineGenerator *result; /* Prédécesseur à retourner */ - cache_info *info; /* Accès direct à une ligne */ - generator_link *link; /* Accès simplifié */ - size_t i; /* Boucle de parcours */ - size_t count; /* Emplacements occupés */ - size_t delete; /* Indice de suppression */ - - assert(index < cache->used); - - assert(!(before && after)); - - result = NULL; - - /* Recherche d'un générateur correspondant */ - - if (before) - info = &cache->lines[index - 1]; - else if (after) - info = &cache->lines[index + 1]; - else - info = &cache->lines[index]; - - if (info->count == 1) - { - link = &info->generator; - - if (G_OBJECT_TYPE(link->instance) == type) - result = link->instance; - - } - - else - for (i = 0; i < info->count && result == NULL; i++) - { - link = &info->generators[i]; - - if (G_OBJECT_TYPE(link->instance) == type) - result = link->instance; - - } - - /* Retrait de l'instance trouvée */ - - if (result != NULL) - { - count = g_line_generator_count_lines(result); - -#ifndef NDEBUG - if (!before && !after) - assert(count == 1); -#endif - - g_object_ref(G_OBJECT(result)); - - /* Suppression de l'élément */ - - for (i = 0; i < count; i++) - { - if (before) - info = &cache->lines[index - 1 - i]; - else if (after) - info = &cache->lines[index + 1 + i]; - else - info = &cache->lines[index]; - - remove_from_cache_info(info, result); - - } - - /* Suppression des lignes associées */ - - for (i = 0; i < count; i++) - { - if (before) - delete = index - 1; - else if (after) - delete = index + 1; - else - delete = index; - - info = &cache->lines[delete]; - - if (info->count == 0) - { - release_cache_info(info); - - if ((delete + 1) < cache->used) - memmove(&cache->lines[delete], &cache->lines[delete + 1], - (cache->used - delete - 1) * sizeof(cache_info)); - - cache->used--; - - g_width_tracker_update_deleted(cache->tracker, delete, delete); - - g_signal_emit_by_name(cache, "size-changed", false, delete, 1); - - } - - } - - } - - return result; - -} - - -/****************************************************************************** -* * -* Paramètres : cache = instance GLib à modifier. * -* generator = générateur à associer à toutes les lignes. * -* flags = propriétés supplémentaires à associer à la ligne.* -* * -* Description : Ajoute en fin de tampon un générateur de lignes. * -* * -* Retour : - * -* * -* Remarques : - * -* * -******************************************************************************/ - -void g_buffer_cache_append(GBufferCache *cache, GLineGenerator *generator, BufferLineFlags flags) -{ - size_t count; /* Nombre de lignes générées */ - size_t index; /* Point d'insertion */ - size_t i; /* Boucle de parcours */ - cache_info *info; /* Accès direct à une ligne */ - - count = g_line_generator_count_lines(generator); - - assert(count > 0); - - assert((flags != BLF_NONE && count == 1) || flags == BLF_NONE); - - if ((cache->used + count) > cache->count) - { - cache->count += count + LINE_ALLOC_BULK; - cache->lines = (cache_info *)realloc(cache->lines, cache->count * sizeof(cache_info)); - } - - index = cache->used; - - for (i = 0; i < count; i++) - { - info = &cache->lines[index + i]; - - info->generator.instance = generator; - info->generator.repeat = g_buffer_cache_compute_repetition(cache, index + i, generator); - - g_object_ref(G_OBJECT(generator)); - - info->count = 1; - - info->line = NULL; - - info->extra_flags = flags; - - } - - cache->used += count; - - g_width_tracker_update_added(cache->tracker, index, count); - - g_signal_emit_by_name(cache, "size-changed", true, index, count); - -} - - -/****************************************************************************** -* * -* Paramètres : cache = instance GLib à modifier. * -* count = quantité totale de lignes à avoir à disposition. * -* generator = générateur à associer à toutes les lignes. * -* * -* Description : Etend un tampon avec un générateur de lignes unique. * -* * -* Retour : - * -* * -* Remarques : - * -* * -******************************************************************************/ - -void g_buffer_cache_extend_with(GBufferCache *cache, size_t count, GLineGenerator *generator) -{ - size_t index; /* Point d'insertion */ - size_t i; /* Boucle de parcours */ - cache_info *info; /* Accès direct à une ligne */ - size_t added; /* Nombre d'ajouts effectués */ - - assert(count >= cache->used); - - if (count > cache->count) - { - cache->lines = (cache_info *)realloc(cache->lines, count * sizeof(cache_info)); - cache->count = count; - } - - index = cache->used; - - for (i = index; i < count; i++) - { - info = &cache->lines[i]; - - info->generator.instance = generator; - info->generator.repeat = g_buffer_cache_compute_repetition(cache, i, generator); - - g_object_ref(G_OBJECT(generator)); - - info->count = 1; - - info->line = NULL; - - } - - added = count - cache->used; - - cache->used = count; - - if (added > 0) - { - g_width_tracker_update_added(cache->tracker, index, added); - - g_signal_emit_by_name(cache, "size-changed", true, index, added); - - } - -} - - -/****************************************************************************** -* * -* Paramètres : cache = instance GLib à modifier. * -* max = nombre maximal de lignes à conserver. * -* * -* Description : Réduit le tampon à une quantité de lignes précise. * -* * -* Retour : - * -* * -* Remarques : - * -* * -******************************************************************************/ - -void g_buffer_cache_truncate(GBufferCache *cache, size_t max) -{ - size_t i; /* Boucle de parcours #1 */ - cache_info *info; /* Accès direct à une ligne */ - size_t j; /* Boucle de parcours #2 */ - size_t removed; /* Nombre de retraits effectués*/ - - for (i = max; i < cache->used; i++) - { - info = &cache->lines[i]; - - if (info->count == 1) - g_object_unref(G_OBJECT(info->generator.instance)); - - else - { - for (j = 0; j < info->count; j++) - g_object_unref(G_OBJECT(info->generators[j].instance)); - - free(info->generators); - - } - - reset_cache_info_line(info); - - } - - if (max < cache->used) - { - removed = cache->used - max; - - cache->used = max; - - g_width_tracker_update_deleted(cache->tracker, max, max + removed - 1); - - g_signal_emit_by_name(cache, "size-changed", false, max, removed); - - } - -} - - -/****************************************************************************** -* * -* Paramètres : cache = tampon de lignes à venir consulter. * -* index = indice de la ligne visée par la consultation. * -* x = position géographique sur la ligne concernée. * -* cursor = emplacement à constituer. [OUT] * -* * -* Description : Retrouve l'emplacement correspondant à une position de ligne.* -* * -* Retour : - * -* * -* Remarques : - * -* * -******************************************************************************/ - -void g_buffer_cache_get_line_cursor(const GBufferCache *cache, size_t index, gint x, GLineCursor **cursor) -{ - assert(index < cache->used); - - get_cache_info_cursor(&cache->lines[index], index, x, cursor); - -} - - -/****************************************************************************** -* * -* Paramètres : cache = tampon de lignes à venir consulter. * -* index = indice de la ligne visée par la consultation. * -* * -* Description : Détermine l'ensemble des propriétés attachées à une ligne. * -* * -* Retour : Somme de toutes les propriétés enregistrées. * -* * -* Remarques : - * -* * -******************************************************************************/ - -BufferLineFlags g_buffer_cache_get_line_flags(const GBufferCache *cache, size_t index) -{ - BufferLineFlags result; /* Somme à renvoyer */ - cache_info *info; /* Accès direct à une ligne */ - const generator_link *generator; /* Générateur retenu */ - size_t i; /* Boucle de parcours */ - - // TODO : check lock - - assert(index < cache->used); - - info = &cache->lines[index]; - - result = info->extra_flags; - - if (info->count == 1) - { - generator = &info->generator; - result |= g_line_generator_get_flags(generator->instance, index, generator->repeat); - } - - else - for (i = 0; i < info->count; i++) - { - generator = &info->generators[i]; - result |= g_line_generator_get_flags(generator->instance, index, generator->repeat); - } - - return result; - -} - - -/****************************************************************************** -* * -* Paramètres : cache = tampon de lignes à consulter. * -* index = indice de la ligne recherchée. * -* * -* Description : Retrouve une ligne au sein d'un tampon avec un indice. * -* * -* Retour : Line retrouvée ou NULL en cas d'échec. * -* * -* Remarques : - * -* * -******************************************************************************/ - -GBufferLine *g_buffer_cache_find_line_by_index(const GBufferCache *cache, size_t index) -{ - GBufferLine *result; /* Ligne trouvée à retourner */ - - if (index < cache->used) - result = get_cache_info_line(&cache->lines[index], index, cache->content); - else - result = NULL; - - return result; - -} - - -/****************************************************************************** -* * -* Paramètres : cache = tampon de lignes à venir consulter. * -* index = indice de la ligne à mesurer. * -* summary = largeurs maximales à faire évoluer. * -* * -* Description : Fait remonter les largeurs requises par une ligne donnée. * -* * -* Retour : - * -* * -* Remarques : - * -* * -******************************************************************************/ - -void g_buffer_cache_collect_widths(GBufferCache *cache, size_t index, line_width_summary *summary) -{ - GBufferLine *line; /* Ligne éphémère à mesurer */ - - line = get_cache_info_line(&cache->lines[index], index, cache->content); - - g_buffer_line_collect_widths(line, summary); - - g_object_unref(G_OBJECT(line)); - -} - - -/****************************************************************************** -* * -* Paramètres : cache = visualisation à représenter. * -* cr = contexte graphique dédié à la procédure. * -* first = première ligne à dessiner. * -* last = dernière ligne à dessiner. * -* area = position et surface à traiter. * -* options = règles d'affichage des colonnes modulables. * -* offsets = décalages supplémentaires à appliquer. * -* selected = ordonnée d'une ligne sélectionnée ou NULL. * -* list = liste de contenus à mettre en évidence. * -* * -* Description : Imprime une partie choisie du tampon contenant des lignes. * -* * -* Retour : - * -* * -* Remarques : - * -* * -******************************************************************************/ - -void g_buffer_cache_draw(const GBufferCache *cache, cairo_t *cr, size_t first, size_t last, const cairo_rectangle_int_t *area, const GDisplayOptions *options, const line_width_summary *offsets, const gint *selected, const segcnt_list *list) -{ - GBufferCacheClass *class; /* Classe des tampons */ - gint y; /* Point de départ en ordonnée */ - bool wait_selection; /* Sélection déjà passée ? */ - size_t i; /* Boucle de parcours */ - cache_info *info; /* Accès direct à une ligne */ - line_width_summary summary; /* Résumé concis des largeurs */ - GBufferLine *line; /* Ligne à venir dessiner */ - - class = G_BUFFER_CACHE_GET_CLASS(cache); - - y = 0; - - wait_selection = true; - - if (cache->used > 0) - for (i = first; i <= last; i++) - { - /* Si sélection, on sousligne la ligne concernée */ - if (wait_selection && selected != NULL && *selected == y) - { - cairo_set_source_rgba(cr, 1.0, 1.0, 1.0, 0.05); - - cairo_rectangle(cr, area->x, y, area->width, class->line_height); - cairo_fill(cr); - - wait_selection = false; - - } - - info = &cache->lines[i]; - - if (i == first || (g_buffer_cache_get_line_flags(cache, i) & BLF_WIDTH_MANAGER)) - g_width_tracker_get_local_width_summary(cache->tracker, i, &summary); - - line = get_cache_info_line(info, i, cache->content); - - g_buffer_line_draw(line, cr, &summary, class->text_pos, y, options, offsets, list); - - g_object_unref(G_OBJECT(line)); - - y += class->line_height; - - } - -} - - -/****************************************************************************** -* * -* Paramètres : cache = tampon de lignes à consulter. * -* cursor = emplacement à retrouver dans le tampon. * -* first = indique si on l'arrête à la première ou la dernière.* -* start = borne inférieure des recherches (incluse). * -* end = borne supérieure des recherches (incluse). * -* * -* Description : Indique l'indice correspondant à une adresse donnée. * -* * -* Retour : Indice des infos à l'adresse demandée, ou nombre de lignes. * -* * -* Remarques : - * -* * -******************************************************************************/ - -size_t _g_buffer_cache_find_index_by_cursor(const GBufferCache *cache, const GLineCursor *cursor, bool first, size_t start, size_t end) -{ - size_t result; /* Indice à retourner */ - cache_info *found; /* Eventuel élément trouvé */ - - int find_containing_generator(const GLineCursor *c, const cache_info *i) - { - const generator_link *generator; /* Générateur retenu */ - - if (i->count == 1) - generator = &i->generator; - else - generator = &i->generators[0]; - - return g_line_generator_contain_cursor(generator->instance, - i - cache->lines, generator->repeat, c); - - } - - found = (cache_info *)bsearch(cursor, &cache->lines[start], end - start + 1, - sizeof(cache_info), (__compar_fn_t)find_containing_generator); - - if (found == NULL) - result = cache->used; - - else - { - result = (found - cache->lines); - assert(start <= result && result <= end); - - /* On s'assure d'un arrêt sur la bonne ligne */ - - if (first) - for (; result > start; result--) - { - found = &cache->lines[result - 1]; - - if (find_containing_generator(cursor, found) != 0) - break; - - } - - else - for (; result < end; result++) - { - found = &cache->lines[result + 1]; - - if (find_containing_generator(cursor, found) != 0) - break; - - } - - } - - return result; - -} - - -/****************************************************************************** -* * -* Paramètres : cache = tampon de lignes à consulter. * -* cursor = emplacement à retrouver dans le tampon. * -* first = indique si on l'arrête à la première ou la dernière.* -* * -* Description : Indique l'indice correspondant à une adresse donnée. * -* * -* Retour : Indice des infos à l'adresse demandée, ou nombre de lignes. * -* * -* Remarques : - * -* * -******************************************************************************/ - -size_t g_buffer_cache_find_index_by_cursor(const GBufferCache *cache, const GLineCursor *cursor, bool first) -{ - size_t result; /* Indice à retourner */ - - if (cache->used == 0) - result = 0; - else - result = _g_buffer_cache_find_index_by_cursor(cache, cursor, first, 0, cache->used - 1); - - return result; - -} - - -/****************************************************************************** -* * -* Paramètres : cache = tampon de lignes à consulter. * -* start = point de départ du parcours. * -* flag = propriétés à retrouver si possible. * -* * -* Description : Avance autant que possible vers une ligne idéale. * -* * -* Retour : Indice de la ligne recherchée, si elle existe. * -* * -* Remarques : - * -* * -******************************************************************************/ - -size_t g_buffer_cache_look_for_flag(const GBufferCache *cache, size_t start, BufferLineFlags flag) -{ - size_t result; /* Indice de ligne à retourner */ - GLineCursor *init; /* Localisation de départ */ - size_t i; /* Boucle de parcours */ - GLineCursor *next; /* Localisation suivante */ - int ret; /* Bilan de comparaison */ - - // TODO : check lock - - assert(start < cache->used); - - result = start; - - get_cache_info_cursor(&cache->lines[start], start, 0, &init); - - for (i = start + 1; i < cache->used; i++) - { - get_cache_info_cursor(&cache->lines[i], i, 0, &next); - - ret = g_line_cursor_compare(init, next); - - g_object_unref(G_OBJECT(next)); - - if (ret != 0) - break; - - if ((g_buffer_cache_get_line_flags(cache, i) & flag) != 0) - { - result = i; - break; - } - - } - - g_object_unref(G_OBJECT(init)); - - return result; - -} - - -/****************************************************************************** -* * -* Paramètres : cache = tampon de lignes à consulter. * -* cursor = emplacement à présenter à l'écran. * -* first = borne inférieure des recherches (incluse). * -* last = borne supérieure des recherches (incluse). * -* code = s'arrête si possible à une ligne avec code. * -* x = position horizontale au sein du composant. [OUT] * -* y = position verticale au sein du composant. [OUT] * -* * -* Description : Indique la position d'affichage d'une adresse donnée. * -* * -* Retour : true si l'adresse fait partie du composant, false sinon. * -* * -* Remarques : - * -* * -******************************************************************************/ - -bool g_buffer_cache_get_cursor_coordinates(const GBufferCache *cache, const GLineCursor *cursor, size_t first, size_t last, bool code, gint *x, gint *y) -{ - bool result; /* Bilan à retourner */ - size_t index; /* Indice de correspondance */ - gint lheight; /* Hauteur d'une ligne */ - const cache_info *info; /* Infos sur une ligne donnée */ - const generator_link *generator; /* Générateur retenu */ - - index = _g_buffer_cache_find_index_by_cursor(cache, cursor, true, first, last); - - result = (index < cache->used); - - if (result) - { - lheight = G_BUFFER_CACHE_GET_CLASS(cache)->line_height; - - *x = 0; - *y = (index - first) * G_BUFFER_CACHE_GET_CLASS(cache)->line_height; - - for (; code && index <= last; index++) - { - if (g_buffer_cache_get_line_flags(cache, index) & BLF_HAS_CODE) - break; - - if (index == last) - break; - - info = &cache->lines[index + 1]; - - if (info->count == 1) - generator = &info->generator; - else - generator = &info->generators[0]; - - if (!g_line_generator_contain_cursor(generator->instance, index + 1, generator->repeat, cursor)) - break; - - *y += lheight; - - } - - } - - return result; - -} diff --git a/src/glibext/gbuffercache.h b/src/glibext/gbuffercache.h deleted file mode 100644 index 79158c4..0000000 --- a/src/glibext/gbuffercache.h +++ /dev/null @@ -1,133 +0,0 @@ - -/* Chrysalide - Outil d'analyse de fichiers binaires - * gbuffercache.h - prototypes pour l'affichage à la demande d'un ensemble de lignes - * - * Copyright (C) 2016-2019 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 . - */ - - -#ifndef _GLIBEXT_GBUFFERCACHE_H -#define _GLIBEXT_GBUFFERCACHE_H - - -#include -#include -#include - - -#include "gdisplayoptions.h" -#include "gwidthtracker.h" -#include "linegen.h" - - - -/* -------------------------- TAMPON POUR CODE DESASSEMBLE -------------------------- */ - - -#define G_TYPE_BUFFER_CACHE g_buffer_cache_get_type() -#define G_BUFFER_CACHE(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_BUFFER_CACHE, GBufferCache)) -#define G_BUFFER_CACHE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_BUFFER_CACHE, GBufferCacheClass)) -#define G_IS_BUFFER_CACHE(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_BUFFER_CACHE)) -#define G_IS_BUFFER_CACHE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_BUFFER_CACHE)) -#define G_BUFFER_CACHE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_BUFFER_CACHE, GBufferCacheClass)) - - -/* Tampon pour gestion de lignes optimisée (instance) */ -typedef struct _GBufferCache GBufferCache; - -/* Tampon pour gestion de lignes optimisée (classe) */ -typedef struct _GBufferCacheClass GBufferCacheClass; - - -/* Détermine le type du composant de tampon pour gestion de lignes optimisée. */ -GType g_buffer_cache_get_type(void); - -/* Crée un nouveau composant de tampon pour code désassemblé. */ -GBufferCache *g_buffer_cache_new(GBinContent *); - -/* Indique l'éventuel contenu binaire associé au cache. */ -GBinContent *g_buffer_cache_get_content(const GBufferCache *); - -/* Fournit la hauteur d'impression d'une ligne visualisée. */ -gint g_buffer_cache_get_line_height(const GBufferCache *); - -/* Fournit la taille réservée pour la marge gauche. */ -gint g_buffer_cache_get_left_margin(const GBufferCache *); - -/* Fournit la position de départ pour l'impression de texte. */ -gint g_buffer_cache_get_text_position(const GBufferCache *); - -/* Compte le nombre de lignes rassemblées dans un tampon. */ -size_t g_buffer_cache_count_lines(const GBufferCache *); - -/* Fournit un lien vers la structure de suivi de largeurs. */ -GWidthTracker *g_buffer_cache_get_width_tracker(const GBufferCache *); - -/* Insère un générateur dans des lignes à une position donnée. */ -void g_buffer_cache_insert_at(GBufferCache *, size_t, GLineGenerator *, BufferLineFlags, bool, bool); - -/* Retire une ligne du tampon. */ -void g_buffer_cache_delete_at(GBufferCache *, size_t); - -/* Retire un type de générateur de lignes. */ -GLineGenerator *g_buffer_cache_delete_type_at(GBufferCache *, size_t, GType, bool, bool); - -/* Ajoute en fin de tampon un générateur de lignes. */ -void g_buffer_cache_append(GBufferCache *, GLineGenerator *, BufferLineFlags); - -/* Etend un tampon avec un générateur de lignes unique. */ -void g_buffer_cache_extend_with(GBufferCache *, size_t, GLineGenerator *); - -/* Réduit le tampon à une quantité de lignes précise. */ -void g_buffer_cache_truncate(GBufferCache *, size_t); - -/* Retrouve l'emplacement correspondant à une position de ligne. */ -void g_buffer_cache_get_line_cursor(const GBufferCache *, size_t, gint, GLineCursor **); - -/* Détermine l'ensemble des propriétés attachées à une ligne. */ -BufferLineFlags g_buffer_cache_get_line_flags(const GBufferCache *, size_t); - -#define g_buffer_cache_lock(c) -#define g_buffer_cache_unlock(c) - -#define g_buffer_cache_throw_update_at_index(c, i) // check locked - -/* Retrouve une ligne au sein d'un tampon avec un indice. */ -GBufferLine *g_buffer_cache_find_line_by_index(const GBufferCache *, size_t); - -/* Fait remonter les largeurs requises par une ligne donnée. */ -void g_buffer_cache_collect_widths(GBufferCache *, size_t, line_width_summary *); - -/* Imprime une partie choisie du tampon contenant des lignes. */ -void g_buffer_cache_draw(const GBufferCache *, cairo_t *, size_t, size_t, const cairo_rectangle_int_t *, const GDisplayOptions *, const line_width_summary *, const gint *, const segcnt_list *); - -/* Indique l'indice correspondant à une adresse donnée. */ -size_t _g_buffer_cache_find_index_by_cursor(const GBufferCache *, const GLineCursor *, bool, size_t, size_t); - -/* Indique l'indice correspondant à une adresse donnée. */ -size_t g_buffer_cache_find_index_by_cursor(const GBufferCache *, const GLineCursor *, bool); - -/* Avance autant que possible vers une ligne idéale. */ -size_t g_buffer_cache_look_for_flag(const GBufferCache *, size_t, BufferLineFlags); - -/* Indique la position d'affichage d'une adresse donnée. */ -bool g_buffer_cache_get_cursor_coordinates(const GBufferCache *, const GLineCursor *, size_t, size_t, bool, gint *, gint *); - - - -#endif /* _GLIBEXT_GBUFFERCACHE_H */ diff --git a/src/glibext/gbufferline.c b/src/glibext/gbufferline.c deleted file mode 100644 index e3482aa..0000000 --- a/src/glibext/gbufferline.c +++ /dev/null @@ -1,1558 +0,0 @@ - -/* Chrysalide - Outil d'analyse de fichiers binaires - * gbufferline.c - représentation de fragments de texte en ligne - * - * Copyright (C) 2010-2019 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 "gbufferline.h" - - -#include -#include -#include - - -#include "chrysamarshal.h" -#include "linecolumn.h" -#include "../common/extstr.h" -#include "../core/paths.h" - - - -/* ---------------------------- GESTION DE LINE COMPLETE ---------------------------- */ - - -/* Mémorisation des origines de texte */ -typedef struct _content_origin -{ - col_coord_t coord; /* Localisation d'attachement */ - - GObject *creator; /* Origine de la création */ - -} content_origin; - -/* Représentation de fragments de texte en ligne (instance) */ -struct _GBufferLine -{ - GObject parent; /* A laisser en premier */ - - mrange_t range; /* Couverture geographique */ - BufferLineColumn main_column; /* Colonne principale */ - - line_column columns[BLC_COUNT]; /* Répartition du texte */ - BufferLineColumn merge_start; /* Début de la zone globale */ - BufferLineColumn last_used; /* Dernière colonne utilisée */ - - BufferLineFlags flags; /* Drapeaux particuliers */ - - content_origin *origins; /* Mémorisation des origines */ - size_t ocount; /* Nombre de ces mémorisations */ - - union - { - struct - { - gint max_widths[BLC_COUNT]; /* Taille cachée des colonnes */ - gint merged_width; /* Largeur cumulée avant fusion*/ - }; - }; - -}; - -/* Représentation de fragments de texte en ligne (classe) */ -struct _GBufferLineClass -{ - GObjectClass parent; /* A laisser en premier */ - - cairo_surface_t *entrypoint_img; /* Image pour les entrées */ - cairo_surface_t *bookmark_img; /* Image pour les signets */ - - /* Signaux */ - - void (* content_changed) (GBufferLine *, line_segment *); - - void (* flip_flag) (GBufferLine *, BufferLineFlags, BufferLineFlags); - -}; - - -/* Procède à l'initialisation d'une classe de représentation. */ -static void g_buffer_line_class_init(GBufferLineClass *); - -/* Procède à l'initialisation d'une représentation de fragments. */ -static void g_buffer_line_init(GBufferLine *); - -/* Supprime toutes les références externes. */ -static void g_buffer_line_dispose(GBufferLine *); - -/* Procède à la libération totale de la mémoire. */ -static void g_buffer_line_finalize(GBufferLine *); - - - -/* ---------------------------------------------------------------------------------- */ -/* GESTION DE LINE COMPLETE */ -/* ---------------------------------------------------------------------------------- */ - - -/* Détermine le type de la représentation de fragments de texte en ligne. */ -G_DEFINE_TYPE(GBufferLine, g_buffer_line, G_TYPE_OBJECT); - - - -/****************************************************************************** -* * -* Paramètres : class = classe de composant GTK à initialiser. * -* * -* Description : Procède à l'initialisation d'une classe de représentation. * -* * -* Retour : - * -* * -* Remarques : - * -* * -******************************************************************************/ - -static void g_buffer_line_class_init(GBufferLineClass *class) -{ - GObjectClass *object; /* Autre version de la classe */ - gchar *filename; /* Chemin d'accès à utiliser */ - - object = G_OBJECT_CLASS(class); - - object->dispose = (GObjectFinalizeFunc/* ! */)g_buffer_line_dispose; - object->finalize = (GObjectFinalizeFunc)g_buffer_line_finalize; - - filename = find_pixmap_file("entrypoint.png"); - assert(filename != NULL); - - class->entrypoint_img = cairo_image_surface_create_from_png(filename); - - g_free(filename); - - filename = find_pixmap_file("bookmark.png"); - assert(filename != NULL); - - class->bookmark_img = cairo_image_surface_create_from_png(filename); - - g_free(filename); - - g_signal_new("content-changed", - G_TYPE_BUFFER_LINE, - G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET(GBufferLineClass, content_changed), - NULL, NULL, - g_cclosure_marshal_VOID__OBJECT, - G_TYPE_NONE, 1, G_TYPE_OBJECT); - - g_signal_new("flip-flag", - G_TYPE_BUFFER_LINE, - G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET(GBufferLineClass, flip_flag), - NULL, NULL, - g_cclosure_user_marshal_VOID__ENUM_ENUM, - G_TYPE_NONE, 2, G_TYPE_UINT, G_TYPE_UINT); - -} - - -/****************************************************************************** -* * -* Paramètres : line = composant GTK à initialiser. * -* * -* Description : Procède à l'initialisation d'une représentation de fragments.* -* * -* Retour : - * -* * -* Remarques : - * -* * -******************************************************************************/ - -static void g_buffer_line_init(GBufferLine *line) -{ - BufferLineColumn i; /* Boucle de parcours */ - - for (i = 0; i < BLC_COUNT; i++) - init_line_column(&line->columns[i]); - - line->merge_start = BLC_COUNT; - line->last_used = BLC_COUNT; - -} - - -/****************************************************************************** -* * -* Paramètres : line = instance d'objet GLib à traiter. * -* * -* Description : Supprime toutes les références externes. * -* * -* Retour : - * -* * -* Remarques : - * -* * -******************************************************************************/ - -static void g_buffer_line_dispose(GBufferLine *line) -{ - size_t i; /* Boucle de parcours */ - - for (i = 0; i < line->ocount; i++) - g_object_unref(G_OBJECT(line->origins[i].creator)); - - G_OBJECT_CLASS(g_buffer_line_parent_class)->dispose(G_OBJECT(line)); - -} - - -/****************************************************************************** -* * -* Paramètres : line = instance d'objet GLib à traiter. * -* * -* Description : Procède à la libération totale de la mémoire. * -* * -* Retour : - * -* * -* Remarques : - * -* * -******************************************************************************/ - -static void g_buffer_line_finalize(GBufferLine *line) -{ - BufferLineColumn i; /* Boucle de parcours */ - - for (i = 0; i < BLC_COUNT; i++) - reset_line_column(&line->columns[i]); - - if (line->origins != NULL) - free(line->origins); - - G_OBJECT_CLASS(g_buffer_line_parent_class)->finalize(G_OBJECT(line)); - -} - - -/****************************************************************************** -* * -* Paramètres : range = emplacement où va se situer la ligne. * -* main = colonne à référencer comme étant la principale. * -* * -* Description : Crée une nouvelle représentation de fragments de texte. * -* * -* Retour : Composant GTK créé. * -* * -* Remarques : - * -* * -******************************************************************************/ - -GBufferLine *g_buffer_line_new(const mrange_t *range, BufferLineColumn main) -{ - GBufferLine *result; /* Composant à retourner */ - - result = g_object_new(G_TYPE_BUFFER_LINE, NULL); - - copy_mrange(&result->range, range); - result->main_column = main; - - return result; - -} - - -/****************************************************************************** -* * -* Paramètres : line = ligne à venir consulter. * -* * -* Description : Indique la zone mémoire où se situe la ligne. * -* * -* Retour : Emplacement mémoire virtuel ou physique. * -* * -* Remarques : - * -* * -******************************************************************************/ - -const mrange_t *g_buffer_line_get_range(const GBufferLine *line) -{ - return &line->range; - -} - - -/****************************************************************************** -* * -* Paramètres : line = ligne à venir compléter. * -* size = taille souhaitée de l'impression des positions. * -* addr = localisation physique à venir représenter. * -* * -* Description : Construit le tronc commun d'une ligne autour de sa position. * -* * -* Retour : - * -* * -* Remarques : - * -* * -******************************************************************************/ - -void g_buffer_line_fill_phys(GBufferLine *line, MemoryDataSize size, const vmpa2t *addr) -{ - VMPA_BUFFER(position); /* Emplacement au format texte */ - size_t len; /* Taille de l'élément inséré */ - size_t i; /* Boucle de parcours #1 */ - - vmpa2_phys_to_string(addr, size, position, &len); - - for (i = 2; i < len; i++) - if (position[i] != '0') break; - - if (i == len) - i = len - 1; - - if (i > 0) - g_buffer_line_append_text(line, BLC_PHYSICAL, position, i, RTT_PHYS_ADDR_PAD, NULL); - - g_buffer_line_append_text(line, BLC_PHYSICAL, &position[i], len - i, RTT_PHYS_ADDR, NULL); - -} - - -/****************************************************************************** -* * -* Paramètres : line = ligne à venir compléter. * -* size = taille souhaitée de l'impression des positions. * -* addr = localisation virtuelle à venir représenter. * -* * -* Description : Construit le tronc commun d'une ligne autour de sa position. * -* * -* Retour : - * -* * -* Remarques : - * -* * -******************************************************************************/ - -void g_buffer_line_fill_virt(GBufferLine *line, MemoryDataSize size, const vmpa2t *addr) -{ - VMPA_BUFFER(position); /* Emplacement au format texte */ - size_t len; /* Taille de l'élément inséré */ - size_t i; /* Boucle de parcours #1 */ - - vmpa2_virt_to_string(addr, size, position, &len); - - if (has_virt_addr(addr)) - { - for (i = 2; i < len; i++) - if (position[i] != '0') break; - - if (i == len) - i = len - 1; - - if (i > 0) - g_buffer_line_append_text(line, BLC_VIRTUAL, position, i, RTT_VIRT_ADDR_PAD, NULL); - - g_buffer_line_append_text(line, BLC_VIRTUAL, &position[i], len - i, RTT_VIRT_ADDR, NULL); - - } - - else - g_buffer_line_append_text(line, BLC_VIRTUAL, position, len, RTT_VIRT_ADDR_PAD, NULL); - -} - - -/****************************************************************************** -* * -* Paramètres : line = ligne à venir compléter. * -* addr = localisation à afficher. * -* psize = taille souhaitée de l'impression des positions. * -* vsize = taille souhaitée de l'impression des adresses. * -* * -* Description : Construit le tronc commun d'une ligne autour de sa position. * -* * -* Retour : - * -* * -* Remarques : - * -* * -******************************************************************************/ - -void g_buffer_line_fill_vmpa(GBufferLine *line, const vmpa2t *addr, MemoryDataSize psize, MemoryDataSize vsize) -{ - g_buffer_line_fill_phys(line, psize, addr); - - g_buffer_line_fill_virt(line, vsize, addr); - -} - - -/****************************************************************************** -* * -* Paramètres : line = ligne à venir compléter. * -* content = contenu binaire global à venir lire. * -* range = localisation des données à venir lire et présenter.* -* max = taille maximale de la portion binaire en octets. * -* * -* Description : Construit le tronc commun d'une ligne autour de son contenu. * -* * -* Retour : - * -* * -* Remarques : - * -* * -******************************************************************************/ - -void g_buffer_line_fill_content(GBufferLine *line, const GBinContent *content, const mrange_t *range, phys_t max) -{ - phys_t length; /* Taille de la couverture */ - bool truncated; /* Indique si le code est coupé*/ - size_t required; /* Taille de traitement requise*/ - char static_buffer[64]; /* Petit tampon local rapide */ - char *bin_code; /* Tampon utilisé pour le code */ - vmpa2t pos; /* Boucle de parcours #1 */ - phys_t i; /* Boucle de parcours #2 */ - char *iter; /* Boucle de parcours #3 */ - int ret; /* Progression dans l'écriture */ - uint8_t byte; /* Octet à représenter */ - - static const char *charset = "0123456789abcdef"; - - /* Détermination du réceptacle */ - - length = get_mrange_length(range); - - truncated = (max != VMPA_NO_PHYSICAL && length > max); - - if (truncated) - { - length = max; - required = length * 3 + 4 /* "..." */ + 1; - } - else - required = length * 3 + 1; - - if (required <= sizeof(static_buffer)) - bin_code = static_buffer; - else - bin_code = (char *)calloc(required, sizeof(char)); - - /* Code brut */ - - copy_vmpa(&pos, get_mrange_addr(range)); - - for (i = 0, iter = bin_code; i < length; i++, iter += ret) - { - if (i == 0) - ret = 0; - else - { - iter[0] = ' '; - ret = 1; - } - - if (!g_binary_content_read_u8(content, &pos, &byte)) - { - iter[ret + 0] = '?'; - iter[ret + 1] = '?'; - } - else - { - iter[ret + 0] = charset[byte >> 4]; - iter[ret + 1] = charset[byte & 0x0f]; - } - - ret += 2; - - } - - if (truncated) - { - strcpy(iter, "..."); - iter += 3; - } - else - *iter = '\0'; - - /* Conclusion */ - - g_buffer_line_append_text(line, BLC_BINARY, bin_code, iter - bin_code, RTT_RAW_CODE, NULL); - - if (bin_code != static_buffer) - free(bin_code); - -} - - -/****************************************************************************** -* * -* Paramètres : line = ligne à venir consulter. * -* column = indice de la colonne visée par les recherches. * -* * -* Description : Recherche le premier créateur enregistré dans des segments. * -* * -* Retour : Créateur trouvé à déréférencer par la suite ou NULL si échec.* -* * -* Remarques : - * -* * -******************************************************************************/ - -GObject *g_buffer_line_find_first_segment_creator(const GBufferLine *line, BufferLineColumn column) -{ - GObject *result; /* Trouvaille à retourner */ - size_t i; /* Boucle de parcours */ - - assert(column < BLC_COUNT); - - result = NULL; - - for (i = 0; i < line->ocount && result == NULL; i++) - { - if (line->origins[i].coord.column == column) - result = line->origins[i].creator; - } - - if (result != NULL) - g_object_ref(G_OBJECT(result)); - - return result; - -} - - -/****************************************************************************** -* * -* Paramètres : line = ligne à venir compléter. * -* column = colonne de la ligne visée par l'insertion. * -* text = texte à insérer dans l'existant. * -* length = taille du texte à traiter. * -* type = type de décorateur à utiliser. * -* creator = instance GLib quelconque à associer. * -* * -* Description : Ajoute du texte à formater dans une ligne donnée. * -* * -* Retour : - * -* * -* Remarques : - * -* * -******************************************************************************/ - -void g_buffer_line_append_text(GBufferLine *line, size_t column, const char *text, size_t length, RenderingTagType type, GObject *creator) -{ - size_t index; /* Indice d'insertion */ - content_origin *origin; /* Définition d'une origine */ - - assert(length > 0); - - if (column == -1) - column = BLC_LAST_USED; - - if (column == BLC_MAIN) - column = BLC_ASSEMBLY;//line->main_column; - - if (column == BLC_LAST_USED) - column = line->last_used; - else - line->last_used = column; - - index = append_text_to_line_column(&line->columns[column], text, length, type); - - if (creator != NULL) - { - line->origins = (content_origin *)realloc(line->origins, ++line->ocount * sizeof(content_origin)); - - origin = &line->origins[line->ocount - 1]; - - origin->coord.column = column; - origin->coord.index = index; - - origin->creator = creator; - g_object_ref(G_OBJECT(creator)); - - } - -} - - -/****************************************************************************** -* * -* Paramètres : line = ligne à venir compléter. * -* creator = instance GLib quelconque identifiant un segment. * -* text = texte à insérer dans l'existant. * -* length = taille du texte à traiter. * -* * -* Description : Remplace du texte dans une ligne donnée. * -* * -* Retour : Bilan de l'opération. * -* * -* Remarques : - * -* * -******************************************************************************/ - -bool g_buffer_line_replace_text(GBufferLine *line, const GObject *creator, const char *text, size_t length) -{ - bool result; /* Bilan à retourner */ - size_t i; /* Boucle de parcours */ - const col_coord_t *coord; /* Emplacement du contenu visé */ - - result = false; - - for (i = 0; i < line->ocount && !result; i++) - { - if (line->origins[i].creator == creator) - { - coord = &line->origins[i].coord; - - replace_text_in_line_column(&line->columns[coord->column], coord->index, text, length); - - g_signal_emit_by_name(line, "content-changed", NULL); - - result = true; - - } - - } - - return result; - -} - - -/****************************************************************************** -* * -* Paramètres : line = ligne à venir consulter. * -* first = première colonne à parcourir. * -* end = colonne de fin de parcours. * -* * -* Description : Indique si du texte est présent dans une ligne de tampon. * -* * -* Retour : true pour indiquer la présence de texte, false pour du vide. * -* * -* Remarques : - * -* * -******************************************************************************/ - -bool g_buffer_line_has_text(const GBufferLine *line, BufferLineColumn first, BufferLineColumn end) -{ - bool result; /* Bilan à retourner */ - BufferLineColumn i; /* Boucle de parcours */ - - result = false; - - assert(first < end); - - for (i = first; i < end && !result; i++) - result = (line->columns[i].count > 0); - - return result; - -} - - -/****************************************************************************** -* * -* Paramètres : line = ligne à venir consulter. * -* first = première colonne à parcourir. * -* end = colonne de fin de parcours. * -* markup = indique si le texte doit être décoré ou non. * -* * -* Description : Donne le texte représenté par une ligne de tampon. * -* * -* Retour : Texte à libérer de la mémoire après usage. * -* * -* Remarques : - * -* * -******************************************************************************/ - -char *g_buffer_line_get_text(const GBufferLine *line, BufferLineColumn first, BufferLineColumn end, bool markup) -{ - char *result; /* Construction à retourner */ - BufferLineColumn i; /* Boucle de parcours */ - char *extra; /* Contenu à intégrer au texte */ - - result = NULL; - - assert(first < end); - - for (i = first; i < end; i++) - { - if (i > first && result != NULL) - result = stradd(result, " "); - - extra = get_line_column_text(&line->columns[i], markup); - - /* Si la colonne était vide, suivante ! */ - if (extra == NULL) continue; - - if (result == NULL) - result = extra; - - else - { - result = stradd(result, extra); - free(extra); - } - - } - - return result; - -} - -/****************************************************************************** -* * -* Paramètres : line = ligne à venir modifier. * -* first = première colonne à parcourir. * -* end = colonne de fin de parcours. * -* * -* Description : Supprime du texte représenté par une ligne de tampon. * -* * -* Retour : - * -* * -* Remarques : - * -* * -******************************************************************************/ - -void g_buffer_line_delete_text(GBufferLine *line, BufferLineColumn first, BufferLineColumn end) -{ - BufferLineColumn i; /* Boucle de parcours #1 */ - - assert(first < end); - - for (i = first; i < end; i++) - reset_line_column(&line->columns[i]); - -} - - -/****************************************************************************** -* * -* Paramètres : line = ligne à venir consulter. * -* * -* Description : Fournit la colonne à partir de laquelle une fusion opère. * -* * -* Retour : Début de la première (et unique) zone globale. * -* * -* Remarques : - * -* * -******************************************************************************/ - -BufferLineColumn g_buffer_line_get_merge_start(const GBufferLine *line) -{ - return line->merge_start; - -} - - -/****************************************************************************** -* * -* Paramètres : line = ligne à venir compléter. * -* start = début de la première (et unique) zone globale. * -* * -* Description : Définit la colonne à partir de laquelle la fusion opère. * -* * -* Retour : - * -* * -* Remarques : - * -* * -******************************************************************************/ - -void g_buffer_line_start_merge_at(GBufferLine *line, BufferLineColumn start) -{ - if (start == BLC_LAST_USED) - line->merge_start = line->last_used; - else - line->merge_start = start; - -} - - -/****************************************************************************** -* * -* Paramètres : line = ligne à venir compléter. * -* flag = propriété à intégrer. * -* * -* Description : Ajoute une propriété particulière à une ligne donnée. * -* * -* Retour : - * -* * -* Remarques : - * -* * -******************************************************************************/ - -void g_buffer_line_add_flag(GBufferLine *line, BufferLineFlags flag) -{ - if ((line->flags & flag) == 0) - { - g_signal_emit_by_name(line, "flip-flag", line->flags, flag); - - line->flags |= flag; - - } - -} - - -/****************************************************************************** -* * -* Paramètres : line = ligne à venir consulter. * -* * -* Description : Renseigne sur les propriétés particulières liées à une ligne.* -* * -* Retour : Propriétés intégrées. * -* * -* Remarques : - * -* * -******************************************************************************/ - -BufferLineFlags g_buffer_line_get_flags(const GBufferLine *line) -{ - return line->flags; - -} - - -/****************************************************************************** -* * -* Paramètres : line = ligne à venir compléter. * -* flag = propriété à supprimer. * -* * -* Description : Retire une propriété particulière à une ligne donnée. * -* * -* Retour : - * -* * -* Remarques : - * -* * -******************************************************************************/ - -void g_buffer_line_remove_flag(GBufferLine *line, BufferLineFlags flag) -{ - if ((line->flags & flag) != 0) - { - g_signal_emit_by_name(line, "flip-flag", line->flags, flag); - - line->flags &= ~flag; - - } - -} - - -/****************************************************************************** -* * -* Paramètres : line = ligne de texte à manipuler. * -* ctx = éléments à disposition pour l'exportation. * -* type = type d'exportation attendue. * -* display = règles d'affichage des colonnes modulables. * -* * -* Description : Exporte la ligne de texte représentée. * -* * -* Retour : - * -* * -* Remarques : - * -* * -******************************************************************************/ - -void g_buffer_line_export(GBufferLine *line, buffer_export_context *ctx, BufferExportType type, const bool *display) -{ - BufferLineColumn i; /* Boucle de parcours */ - int col_span; /* Fusion de colonnes ? */ - - switch (type) - { - case BET_HTML: - dprintf(ctx->fd, "\t\n"); - break; - default: - break; - } - - for (i = 0; i < BLC_COUNT; i++) - { - if (i < BLC_DISPLAY && !display[i]) continue; - - switch (type) - { - case BET_TEXT: - if (i > 0) dprintf(ctx->fd, "%s", ctx->sep); - break; - default: - break; - } - - /** - * Pour la signification des différentes valeurs assignées, - * se référer au code de export_line_column_segments(). - * - * En gros : - * - 1 = rien de spécial. - * - >1 = il s'agit de la première cellule fusionnée de la ligne. - * - 0 = fusion déjà faite, on ne peut que rajouter du contenu dedans. - * - <1 = il s'agit de la dernière cellule fusionnée de la ligne. - * - * On considère qu'une fusion ne peut pas se réaliser sur la dernière - * cellule uniquement (ce qui a du sens : c'est inutile). - */ - - if (i < line->merge_start) - col_span = 1; - - else if (i == line->merge_start) - col_span = BLC_COUNT - i; - - else - col_span = ((i + 1) == BLC_COUNT ? -1 : 0); - - export_line_column_segments(&line->columns[i], ctx, type, col_span); - - } - - switch (type) - { - case BET_TEXT: - dprintf(ctx->fd, "\n"); - break; - case BET_HTML: - dprintf(ctx->fd, "\n"); - break; - default: - break; - } - -} - - - -/*----------------------------------------------------------------------------------- */ -/* MANIPULATION DES LARGEURS REQUISES */ -/* ---------------------------------------------------------------------------------- */ - - -/****************************************************************************** -* * -* Paramètres : line = ligne à venir consulter. * -* summary = largeurs maximales à faire évoluer. * -* * -* Description : Fait remonter les largeurs requises par une ligne donnée. * -* * -* Retour : - * -* * -* Remarques : - * -* * -******************************************************************************/ - -void g_buffer_line_collect_widths(GBufferLine *line, line_width_summary *summary) -{ - gint merged_width; /* Largeur cumulée avant fusion*/ - BufferLineColumn i; /* Boucle de parcours */ - gint width; /* Largeur d'une colonne */ - - merged_width = 0; - - for (i = 0; i < BLC_COUNT; i++) - { - width = get_column_width(&line->columns[i]); - - if (i < line->merge_start) - summary->max_widths[i] = MAX(summary->max_widths[i], width); - - if (i >= BLC_DISPLAY) - { - merged_width += width; - - if (i < line->merge_start && (i + 1) < BLC_COUNT) - merged_width += COL_MARGIN; - - } - - } - - if (line->merge_start != BLC_COUNT) - summary->merged_width = MAX(summary->merged_width, merged_width); - -} - - -/****************************************************************************** -* * -* Paramètres : line = ligne à venir consulter. * -* index = indice de la colonne visée. * -* summary = résumé des largeurs maximales. * -* offsets = décalages supplémentaires à appliquer. * -* * -* Description : Fournit la largeur d'une colonne finalement appliquée. * -* * -* Retour : Largeur globale ou spécifique, selon l'indice communiqué. * -* * -* Remarques : - * -* * -******************************************************************************/ - -gint g_buffer_line_compute_max_width(const GBufferLine *line, BufferLineColumn index, const line_width_summary *summary, const line_width_summary *offsets) -{ - gint result; /* Largeur à retourner */ - - assert(index < BLC_COUNT); - - if (index >= line->merge_start) - result = get_column_width(&line->columns[index]); - - else - result = summary->max_widths[index]; - - if (result < offsets->max_widths[index]) - result = offsets->max_widths[index]; - - return result; - -} - - - - -/****************************************************************************** -* * -* Paramètres : line = ligne à venir consulter. * -* coord = coordonnées interne du segment à retrouver. * -* * -* Description : Fournit le segment présent à une position donnée. * -* * -* Retour : Segment trouvé ou NULL si hors borne. * -* * -* Remarques : - * -* * -******************************************************************************/ - -line_segment *g_buffer_line_get_segment_from_coord(const GBufferLine *line, const col_coord_t *coord) -{ - line_segment *result; /* Trouvaille à retourner */ - - if (coord->column < BLC_COUNT) - result = get_line_column_content_from_index(&line->columns[coord->column], coord->index); - else - result = NULL; - - return result; - -} - - -/****************************************************************************** -* * -* Paramètres : line = ligne à venir consulter. * -* summary = résumé des largeurs maximales. * -* options = règles d'affichage des colonnes modulables. * -* offsets = décalages supplémentaires à appliquer. * -* base = position jusqu'au segment trouvé. [OUT] * -* offset = position à la colonne visée. [OUT] * -* dir = direction d'un éventuel déplacement en cours. * -* force = accepte les segments en bordure au pire. * -* coord = cordonnées à usage interne à renseigner. [OUT] * -* * -* Description : Fournit les coordonnées correspondant à une abscisse donnée. * -* * -* Retour : true si des coordonnées valides ont été renseignées. * -* * -* Remarques : - * -* * -******************************************************************************/ - -bool g_buffer_line_get_coord_at(const GBufferLine *line, const line_width_summary *summary, const GDisplayOptions *options, const line_width_summary *offsets, gint *base, gint *offset, GdkScrollDirection dir, bool force, col_coord_t *coord) -{ - bool result; /* Bilan à retourner */ - BufferLineColumn last; /* Dernière colonne remplie */ - gint last_base; /* Dernière abscisse associée */ - size_t count; /* Qté de colonnes en option */ - size_t i; /* Boucle de parcours */ - gint width; /* Largeur d'une colonne donnée*/ - gint limit; /* Limite d'appartenance */ - gint consumed; /* Distance vers le segment */ - gint old_base; /* Somme de toutes les largeurs*/ - - result = false; - - *base = 0; - - last = BLC_COUNT; - last_base = 0; - - /* On cible déjà la colonne idéale */ - - count = g_display_options_count(options); - - for (i = 0; i < BLC_COUNT; i++) - { - if (i < count) - { - if (!g_display_options_get(options, i)) - continue; - } - - /* Mémorisation de la dernière colonne contenant quelque chose... */ - if (get_column_width(&line->columns[i]) > 0) - { - last = i; - last_base = *base; - } - - if (i < line->merge_start) - { - width = g_buffer_line_compute_max_width(line, i, summary, offsets); - - /* Si la colonne n'est absolument pas visible, on ne s'arrête pas dessus ! */ - if (width == 0) continue; - - if ((i + 1) < BLC_COUNT) limit = width + COL_MARGIN / 2; - else limit = width; - - if (*offset <= limit) break; - else - { - *offset -= width + COL_MARGIN; - *base += width + COL_MARGIN; - } - - } - else - { - width = get_column_width(&line->columns[i]); - - if (*offset <= width) break; - else - { - *offset -= width; - *base += width; - } - - } - - - } - - /* Si l'abscisse fournie tombe encore dans une colonne... */ - - if (i < BLC_COUNT) - { - /* Il y a bien du contenu dans cette colonne */ - - if (get_column_width(&line->columns[i]) > 0) - { - /** - * Si la position était au milieu d'une marge, la sélection a pu pousser - * jusqu'à la colonne suivante, plus proche. - * Relativment à la base de cette dernière, la position est donc devenue négative. - */ - if (*offset < 0) *offset = 0; - - result = get_line_column_content_index_at(&line->columns[i], offset, dir, &consumed, &coord->index); - - if (result) - { - coord->column = i; - - *base += consumed; - - } - - } - - /* La position fournie tombe dans une colonne vide ! */ - - else - { - if (force || get_column_width(&line->columns[i]) == 0) - { - result = false; - *offset = 0; - - old_base = *base; - - for (i++; i < BLC_COUNT && !result; i++) - { - if ((i - 1) < line->merge_start) - { - width = g_buffer_line_compute_max_width(line, i - 1, summary, offsets); - - if (width > 0) - *base += (width + COL_MARGIN); - - } - else - *base += get_column_width(&line->columns[i - 1]); - - result = get_line_column_first_content_index(&line->columns[i], &coord->index); - - if (result) - coord->column = i; - - } - - if (!result) - { - *base = old_base; - goto use_right_border; - } - - } - - } - - } - - else /* if (i == BLC_COUNT) */ - { - if (force) - { - use_right_border: - - if (last != BLC_COUNT) - { - result = get_line_column_last_content_index(&line->columns[last], &coord->index); - - if (result) - { - coord->column = last; - - *base = last_base; - *offset = get_column_width(&line->columns[last]); - - } - - } - - /* Il n'y a rien sur la ligne ! */ - else - { - result = true; - - *base = 0; - *offset = 0; - - coord->column = BLC_COUNT; - coord->index = -1; - - } - - } - else - result = false; - - } - - return result; - -} - - -/****************************************************************************** -* * -* Paramètres : line = ligne à venir consulter. * -* summary = résumé des largeurs maximales. * -* options = règles d'affichage des colonnes modulables. * -* offsets = décalages supplémentaires à appliquer. * -* base = position jusqu'au segment trouvé. [OUT] * -* offset = position à la colonne visée. [OUT] * -* dir = direction d'un éventuel déplacement en cours. * -* force = accepte les segments en bordure au pire. * -* * -* Description : Donne le segment présent à une abscisse donnée. * -* * -* Retour : Segment trouvé ou NULL si hors borne. * -* * -* Remarques : - * -* * -******************************************************************************/ - -line_segment *g_buffer_line_get_segment_at(const GBufferLine *line, const line_width_summary *summary, const GDisplayOptions *options, const line_width_summary *offsets, gint *base, gint *offset, GdkScrollDirection dir, bool force) -{ - line_segment *result; /* Trouvaille à retourner */ - col_coord_t coord; /* Emplacement du contenu visé */ - bool status; /* Bilan de la localisation */ - - status = g_buffer_line_get_coord_at(line, summary, options, offsets, base, offset, dir, force, &coord); - - if (status) - result = g_buffer_line_get_segment_from_coord(line, &coord); - else - result = NULL; - - return result; - -} - - -/****************************************************************************** -* * -* Paramètres : line = ligne à venir consulter. * -* summary = résumé des largeurs maximales. * -* options = règles d'affichage des colonnes modulables. * -* offsets = décalages supplémentaires à appliquer. * -* base = position jusqu'au segment trouvé. [OUT] * -* offset = position à la colonne visée. [OUT] * -* dir = direction d'un éventuel déplacement en cours. * -* force = accepte les segments en bordure au pire. * -* * -* Description : Donne le créateur présent à une abscisse donnée. * -* * -* Retour : Créateur trouvé ou NULL si hors borne. * -* * -* Remarques : - * -* * -******************************************************************************/ - -GObject *g_buffer_line_get_creator_at(const GBufferLine *line, const line_width_summary *summary, const GDisplayOptions *options, const line_width_summary *offsets, gint *base, gint *offset, GdkScrollDirection dir, bool force) -{ - GObject *result; /* Trouvaille à retourner */ - col_coord_t target; /* Emplacement du contenu visé */ - bool status; /* Bilan de la localisation */ - size_t i; /* Boucle de parcours */ - const col_coord_t *coord; /* Emplacement du contenu visé */ - - result = NULL; - - status = g_buffer_line_get_coord_at(line, summary, options, offsets, base, offset, dir, force, &target); - - if (status) - { - for (i = 0; i < line->ocount && result == NULL; i++) - { - coord = &line->origins[i].coord; - - if (coord->column == target.column && coord->index == target.index) - result = line->origins[i].creator; - - } - - if (result != NULL) - g_object_ref(G_OBJECT(result)); - - } - - return result; - -} - - -/****************************************************************************** -* * -* Paramètres : line = ligne à venir consulter. * -* coord = cordonnées à consulter puis renseigner. [OUT] * -* summary = résumé des largeurs maximales. * -* options = règles d'affichage des colonnes modulables. * -* offsets = décalages supplémentaires à appliquer. * -* dir = orientation des recherches. * -* offset = décalage pour amener à l'extrémité nouvelle. [OUT] * -* * -* Description : Fournit des coordonnées voisines selon une direction donnée. * -* * -* Retour : true si des coordonnées valides ont été renseignées. * -* * -* Remarques : - * -* * -******************************************************************************/ - -bool g_buffer_line_find_near_coord(const GBufferLine *line, col_coord_t *coord, const line_width_summary *summary, const GDisplayOptions *options, const line_width_summary *offsets, GdkScrollDirection dir, gint *offset) -{ - bool result; /* Bilan à retourner */ - size_t count; /* Qté de colonnes en option */ - size_t i; /* Boucle de parcours #1 */ - bool displayed; /* Confort de lecture */ - size_t k; /* Boucle de parcours #2 */ - gint width; /* Largeur d'une colonne donnée*/ - - result = false; - - /* Recherche dans la colonne de départ */ - - i = coord->column; - - if (i == BLC_COUNT) return false; - - result = find_near_segment(&line->columns[i], &coord->index, dir); - - /* Recherche dans la direction des colonnes voisines */ - - count = g_display_options_count(options); - - if (!result) - switch (dir) - { - case GDK_SCROLL_LEFT: - - /* Si on a atteint la première colonne sans trouver... */ - if (i == 0) break; - - /* On s'assure que la colonne précédente est visible et peuplée */ - for (; i > BLC_FIRST && !result; i--) - { - displayed = (i <= count ? g_display_options_get(options, i - 1) : true); - - if (displayed) - { - result = get_line_column_first_content_index(&line->columns[i - 1], &coord->index); - - if (result) - coord->column = i - 1; - - } - - } - - break; - - case GDK_SCROLL_RIGHT: - - /* On s'assure que la colonne suivante est visible et peuplée */ - for (; (i + 1) < BLC_COUNT && !result; i++) - { - displayed = ((i + 1) < count ? g_display_options_get(options, i + 1) : true); - - if (displayed) - { - result = get_line_column_first_content_index(&line->columns[i + 1], &coord->index); - - if (result) - coord->column = i + 1; - - } - - } - - break; - - default: - break; - - } - - /* Calcul de la position finale */ - - if (result) - { - *offset = 0; - - for (k = 0; k < i; k++) - { - displayed = (k < count ? g_display_options_get(options, k) : true); - - if (displayed) - { - width = g_buffer_line_compute_max_width(line, k, summary, offsets); - - if (width > 0) - { - *offset += width; - if (k < line->merge_start) *offset += COL_MARGIN; - } - - } - - } - - switch (dir) - { - case GDK_SCROLL_LEFT: - *offset += get_column_width(&line->columns[i]); - break; - - case GDK_SCROLL_RIGHT: - /**offset += 0;*/ - break; - - default: - break; - - } - - } - - return result; - -} - - -/****************************************************************************** -* * -* Paramètres : line = ligne de texte à manipuler. * -* cairo = contexte graphique à utiliser pour les pinceaux. * -* summary = résumé des largeurs maximales. * -* x_init = abscisse du point d'impression de départ. * -* y = ordonnée du point d'impression. * -* options = règles d'affichage des colonnes modulables. * -* offsets = décalages supplémentaires à appliquer. * -* list = liste de contenus à mettre en évidence. * -* * -* Description : Imprime la ligne de texte représentée. * -* * -* Retour : - * -* * -* Remarques : - * -* * -******************************************************************************/ - -void g_buffer_line_draw(GBufferLine *line, cairo_t *cairo, const line_width_summary *summary, gint x_init, gint y, const GDisplayOptions *options, const line_width_summary *offsets, const segcnt_list *list) -{ - GBufferLineClass *class; /* Stockage de briques de base */ - bool has_src_surface; /* Note une présence définie */ - gint x; /* Point de départ d'impression*/ - size_t count; /* Qté de colonnes en option */ - size_t i; /* Boucle de parcours */ - gint max_width; /* Largeur maximale de colonne */ - - if (line->flags != BLF_NONE && line->flags != BLF_HAS_CODE) - { - class = G_BUFFER_LINE_GET_CLASS(line); - - if (line->flags & BLF_ENTRYPOINT) - { - cairo_set_source_surface(cairo, class->entrypoint_img, 5, y); - has_src_surface = true; - } - else if (line->flags & BLF_BOOKMARK) - { - cairo_set_source_surface(cairo, class->bookmark_img, 5, y); - has_src_surface = true; - } - else - has_src_surface = false; - - if (has_src_surface) - cairo_paint(cairo); - - } - - x = x_init; - - count = g_display_options_count(options); - - for (i = 0; i < BLC_COUNT; i++) - { - if (i < count) - { - if (!g_display_options_get(options, i)) - continue; - } - - draw_line_column_segments(&line->columns[i], cairo, x, y, list); - - if (i < line->merge_start) - { - max_width = g_buffer_line_compute_max_width(line, i, summary, offsets); - - if (max_width > 0) - x += max_width + COL_MARGIN; - - } - - } - -} diff --git a/src/glibext/gbufferline.h b/src/glibext/gbufferline.h deleted file mode 100644 index 11790fe..0000000 --- a/src/glibext/gbufferline.h +++ /dev/null @@ -1,218 +0,0 @@ - -/* Chrysalide - Outil d'analyse de fichiers binaires - * gbufferline.h - prototypes pour la représentation de fragments de texte en ligne - * - * Copyright (C) 2010-2018 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 . - */ - - -#ifndef _GLIBEXT_GBUFFERLINE_H -#define _GLIBEXT_GBUFFERLINE_H - - -#include -#include - - -#include "gdisplayoptions.h" -#include "linesegment.h" -#include "../analysis/content.h" -#include "../arch/vmpa.h" - - - -#define G_TYPE_BUFFER_LINE g_buffer_line_get_type() -#define G_BUFFER_LINE(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_BUFFER_LINE, GBufferLine)) -#define G_BUFFER_LINE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_BUFFER_LINE, GBufferLineClass)) -#define G_IS_BUFFER_LINE(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_BUFFER_LINE)) -#define G_IS_BUFFER_LINE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_BUFFER_LINE)) -#define G_BUFFER_LINE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_BUFFER_LINE, GBufferLineClass)) - - -/* Représentation de fragments de texte en ligne (instance) */ -typedef struct _GBufferLine GBufferLine; - -/* Représentation de fragments de texte en ligne (classe) */ -typedef struct _GBufferLineClass GBufferLineClass; - - -/* Désignation des colonnes d'une ligne */ -typedef enum _BufferLineColumn -{ - BLC_PHYSICAL, /* Position physique */ - BLC_VIRTUAL, /* Adresse virtuelle */ - BLC_BINARY, /* Contenu sous forme binaire */ - BLC_ASSEMBLY_LABEL, /* Etiquette dans les données */ - BLC_ASSEMBLY_HEAD, /* Instruction pour assembleur */ - BLC_ASSEMBLY, /* Code pour assembleur */ - BLC_COMMENTS, /* Commentaires éventuels */ - - BLC_COUNT, - - BLC_LAST_USED, /* Dernière colonne utilisée */ - BLC_INVALID, /* Valeur de non-initialisation*/ - BLC_MAIN /* Colonne principale (cf. imm)*/ - -} BufferLineColumn; - -/* Première colonne de l'ensemble */ -#define BLC_FIRST BLC_PHYSICAL - -/* Première colonne toujours affichée */ -#define BLC_DISPLAY BLC_ASSEMBLY_LABEL - - -/* Confort pour l'insertion de texte */ -#define SL(str) str, strlen(str) - -/* Espace entre les colonnes */ -#define COL_MARGIN 23 - - -/* Propriétés particulières supplémentaires */ -typedef enum _BufferLineFlags -{ - BLF_NONE = 0 << 0, /* Aucune */ - BLF_HAS_CODE = 1 << 0, /* La ligne contient du code */ - BLF_IS_LABEL = 1 << 1, /* Etiquette pour symbole */ - BLF_ENTRYPOINT = 1 << 2, /* Représentation d'une entrée */ - BLF_BOOKMARK = 1 << 3, /* Signet associé */ - BLF_WIDTH_MANAGER = 1 << 4, /* Début de groupe des largeurs*/ - - BLF_ALL = ((1 << 5) - 1) - -} BufferLineFlags; - - -/* Détermine le type de la représentation de fragments de texte en ligne. */ -GType g_buffer_line_get_type(void); - -/* Crée une nouvelle représentation de fragments de texte. */ -GBufferLine *g_buffer_line_new(const mrange_t *, BufferLineColumn); - -/* Indique la zone mémoire où se situe la ligne. */ -const mrange_t *g_buffer_line_get_range(const GBufferLine *); - -/* Construit le tronc commun d'une ligne autour de sa position. */ -void g_buffer_line_fill_phys(GBufferLine *, MemoryDataSize, const vmpa2t *); - -/* Construit le tronc commun d'une ligne autour de sa position. */ -void g_buffer_line_fill_virt(GBufferLine *, MemoryDataSize, const vmpa2t *); - -/* Construit le tronc commun d'une ligne autour de sa position. */ -void g_buffer_line_fill_vmpa(GBufferLine *, const vmpa2t *, MemoryDataSize, MemoryDataSize); - -/* Construit le tronc commun d'une ligne autour de son contenu. */ -void g_buffer_line_fill_content(GBufferLine *, const GBinContent *, const mrange_t *, phys_t); - -/* Recherche le premier créateur enregistré dans des segments. */ -GObject *g_buffer_line_find_first_segment_creator(const GBufferLine *, BufferLineColumn); - -/* Ajoute du texte à formater dans une ligne donnée. */ -void g_buffer_line_append_text(GBufferLine *, size_t, const char *, size_t, RenderingTagType, GObject *); - -/* Remplace du texte dans une ligne donnée. */ -bool g_buffer_line_replace_text(GBufferLine *, const GObject *, const char *, size_t); - -/* Indique si du texte est présent dans une ligne de tampon. */ -bool g_buffer_line_has_text(const GBufferLine *, BufferLineColumn, BufferLineColumn); - -/* Donne le texte représenté par une ligne de tampon. */ -char *g_buffer_line_get_text(const GBufferLine *, BufferLineColumn, BufferLineColumn, bool); - -/* Supprime du texte représenté par une ligne de tampon. */ -void g_buffer_line_delete_text(GBufferLine *, BufferLineColumn, BufferLineColumn); - -/* Fournit la colonne à partir de laquelle une fusion opère. */ -BufferLineColumn g_buffer_line_get_merge_start(const GBufferLine *); - -/* Définit la colonne à partir de laquelle la fusion opère. */ -void g_buffer_line_start_merge_at(GBufferLine *, BufferLineColumn); - -/* Ajoute une propriété particulière à une ligne donnée. */ -void g_buffer_line_add_flag(GBufferLine *, BufferLineFlags); - -/* Renseigne sur les propriétés particulières liées à une ligne. */ -BufferLineFlags g_buffer_line_get_flags(const GBufferLine *); - -/* Retire une propriété particulière à une ligne donnée. */ -void g_buffer_line_remove_flag(GBufferLine *, BufferLineFlags); - -/* Exporte la ligne de texte représentée. */ -void g_buffer_line_export(GBufferLine *, buffer_export_context *, BufferExportType, const bool *); - - -/* Petite aide pour la détection de commentaire */ -#define g_buffer_line_has_comment(ln) \ - ({ \ - bool __result; \ - __result = g_buffer_line_has_text(ln, BLC_COMMENTS, BLC_COUNT); \ - __result |= (g_buffer_line_get_merge_start(ln) == BLC_DISPLAY \ - && !(g_buffer_line_get_flags(ln) & BLF_IS_LABEL)); \ - __result; \ - }) - - - -/* ----------------------- MANIPULATION DES LARGEURS REQUISES ----------------------- */ - - -/* Mémorisation des largeurs pour un groupe de lignes */ -typedef struct _line_width_summary -{ - gint max_widths[BLC_COUNT]; /* Taille cachée des colonnes */ - gint merged_width; /* Largeur cumulée avant fusion*/ - -} line_width_summary; - -/* Identification d'un contenu de colonne */ -typedef struct _col_coord_t -{ - BufferLineColumn column; /* Colonne concernée */ - size_t index; /* Indice d'insertion */ - -} col_coord_t; - - -/* Fait remonter les largeurs requises par une ligne donnée. */ -void g_buffer_line_collect_widths(GBufferLine *, line_width_summary *); - -/* Fournit la largeur d'une colonne finalement appliquée. */ -gint g_buffer_line_compute_max_width(const GBufferLine *, BufferLineColumn, const line_width_summary *, const line_width_summary *); - -/* Fournit le segment présent à une position donnée. */ -line_segment *g_buffer_line_get_segment_from_coord(const GBufferLine *, const col_coord_t *); - -/* Fournit les coordonnées correspondant à une abscisse donnée. */ -bool g_buffer_line_get_coord_at(const GBufferLine *, const line_width_summary *, const GDisplayOptions *, const line_width_summary *, gint *, gint *, GdkScrollDirection, bool, col_coord_t *); - -/* Donne le segment présent à une abscisse donnée. */ -line_segment *g_buffer_line_get_segment_at(const GBufferLine *, const line_width_summary *, const GDisplayOptions *, const line_width_summary *, gint *, gint *, GdkScrollDirection, bool); - -/* Donne le créateur présent à une abscisse donnée. */ -GObject *g_buffer_line_get_creator_at(const GBufferLine *, const line_width_summary *, const GDisplayOptions *, const line_width_summary *, gint *, gint *, GdkScrollDirection, bool); - -/* Fournit des coordonnées voisines selon une direction donnée. */ -bool g_buffer_line_find_near_coord(const GBufferLine *, col_coord_t *, const line_width_summary *, const GDisplayOptions *, const line_width_summary *, GdkScrollDirection, gint *); - -/* Imprime la ligne de texte représentée. */ -void g_buffer_line_draw(GBufferLine *, cairo_t *, const line_width_summary *, gint, gint, const GDisplayOptions *, const line_width_summary *, const segcnt_list *); - - - -#endif /* _GLIBEXT_GBUFFERLINE_H */ diff --git a/src/glibext/gbufferview.c b/src/glibext/gbufferview.c deleted file mode 100644 index 0df96cc..0000000 --- a/src/glibext/gbufferview.c +++ /dev/null @@ -1,1285 +0,0 @@ - -/* Chrysalide - Outil d'analyse de fichiers binaires - * gbufferview.c - affichage d'une vue particulière d'un tampon de lignes - * - * Copyright (C) 2016-2019 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 "gbufferview.h" - - -#include - - - -/* Vue d'un tampon pour code désassemblé (instance) */ -struct _GBufferView -{ - GObject parent; /* A laisser en premier */ - - GBufferCache *cache; /* Tampon du contenu visualisé */ - - segcnt_list *highlighted; /* Segments mis en évidence */ - - bool unrestricted; /* Validité des informations */ - GLineCursor *start; /* Première ligne intégrée */ - GLineCursor *end; /* Dernière ligne intégrée */ - - size_t first; /* Indice de la première ligne */ - size_t last; /* Indice de la dernière ligne */ - - GWidthTracker *tracker; /* Suivi des largeurs */ - -}; - -/* Vue d'un tampon pour code désassemblé (classe) */ -struct _GBufferViewClass -{ - GObjectClass parent; /* A laisser en premier */ - - /* Signaux */ - - void (* need_redraw) (GBufferView *); - -}; - - -/* Procède à l'initialisation d'une classe de vue de tampon. */ -static void g_buffer_view_class_init(GBufferViewClass *); - -/* Procède à l'initialisation d'une vue d'un tampon pour code. */ -static void g_buffer_view_init(GBufferView *); - -/* Supprime toutes les références externes. */ -static void g_buffer_view_dispose(GBufferView *); - -/* Procède à la libération totale de la mémoire. */ -static void g_buffer_view_finalize(GBufferView *); - -/* Accompagne une variation de la quantité de lignes du tampon. */ -static void on_buffer_cache_size_changed(const GBufferCache *, bool, size_t, size_t, GBufferView *); - -/* Calcule la position idéale de curseur pour un point donné. */ -bool _g_buffer_view_compute_caret_full(GBufferView *, gint, GBufferLine *, size_t, const GDisplayOptions *, const line_width_summary *, cairo_rectangle_int_t *, GLineCursor **); - -/* Déplace le curseur au sein d'une vue de tampon. */ -static bool _g_buffer_view_move_caret(GBufferView *, const GBufferLine *, size_t, cairo_rectangle_int_t *, bool, GdkScrollDirection, const GDisplayOptions *, const line_width_summary *); - - -/* Fournit la ligne présente à une ordonnée donnée. */ -static GBufferLine *g_buffer_view_find_line_at(GBufferView *, gint, size_t *); - - - - - - - -/* Détermine le type de la vue d'un tampon pour code désassemblé. */ -G_DEFINE_TYPE(GBufferView, g_buffer_view, G_TYPE_OBJECT); - - -/****************************************************************************** -* * -* Paramètres : class = classe de composant GTK à initialiser. * -* * -* Description : Procède à l'initialisation d'une classe de vue de tampon. * -* * -* Retour : - * -* * -* Remarques : - * -* * -******************************************************************************/ - -static void g_buffer_view_class_init(GBufferViewClass *class) -{ - GObjectClass *object; /* Autre version de la classe */ - - object = G_OBJECT_CLASS(class); - - object->dispose = (GObjectFinalizeFunc/* ! */)g_buffer_view_dispose; - object->finalize = (GObjectFinalizeFunc)g_buffer_view_finalize; - - /* Sigaux */ - - g_signal_new("need-redraw", - G_TYPE_BUFFER_VIEW, - G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET(GBufferViewClass, need_redraw), - NULL, NULL, - g_cclosure_marshal_VOID__VOID, - G_TYPE_NONE, 0); - -} - - -/****************************************************************************** -* * -* Paramètres : view = composant GLib à initialiser. * -* * -* Description : Procède à l'initialisation d'une vue d'un tampon pour code. * -* * -* Retour : - * -* * -* Remarques : - * -* * -******************************************************************************/ - -static void g_buffer_view_init(GBufferView *view) -{ - view->cache = NULL; - - view->highlighted = NULL; - - /** - * Inversion du statut pour forcer l'actualisation lors de la création. - */ - view->unrestricted = false; - - view->start = NULL; - view->end = NULL; - - view->first = 0; - view->last = 0; - - view->tracker = NULL; - -} - - -/****************************************************************************** -* * -* Paramètres : view = instance d'objet GLib à traiter. * -* * -* Description : Supprime toutes les références externes. * -* * -* Retour : - * -* * -* Remarques : - * -* * -******************************************************************************/ - -static void g_buffer_view_dispose(GBufferView *view) -{ - g_clear_object(&view->cache); - - g_clear_object(&view->start); - g_clear_object(&view->end); - - g_clear_object(&view->tracker); - - G_OBJECT_CLASS(g_buffer_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 g_buffer_view_finalize(GBufferView *view) -{ - if (view->highlighted != NULL) - unref_segment_content_list(view->highlighted); - - G_OBJECT_CLASS(g_buffer_view_parent_class)->finalize(G_OBJECT(view)); - -} - - -/****************************************************************************** -* * -* Paramètres : buffer = tampon à représenter à l'écran. * -* highlighted = gestionnaire de surbrillance pour segments. * -* * -* Description : Crée une nouvelle vue d'un tampon pour code désassemblé. * -* * -* Retour : Composant GTK créé. * -* * -* Remarques : - * -* * -******************************************************************************/ - -GBufferView *g_buffer_view_new(GBufferCache *cache, segcnt_list *highlighted) -{ - GBufferView *result; /* Composant à retourner */ - - result = g_object_new(G_TYPE_BUFFER_VIEW, NULL); - - result->cache = cache; - g_object_ref_sink(G_OBJECT(cache)); - - g_buffer_view_restrict(result, NULL, NULL); - - g_signal_connect(cache, "size-changed", G_CALLBACK(on_buffer_cache_size_changed), result); - - if (highlighted != NULL) - { - ref_segment_content_list(highlighted); - result->highlighted = highlighted; - } - else - result->highlighted = init_segment_content_list(); - - return result; - -} - - -/****************************************************************************** -* * -* Paramètres : cache = tampon de lignes cohérentes à manipuler. * -* added = indication sur la variation de la taille du tampon. * -* index = indice de la première ligne à traiter. * -* count = nombre de lignes à traiter. * -* view = vue active du tampon de lignes concerné. * -* * -* Description : Accompagne une variation de la quantité de lignes du tampon. * -* * -* Retour : - * -* * -* Remarques : - * -* * -******************************************************************************/ - -static void on_buffer_cache_size_changed(const GBufferCache *cache, bool added, size_t index, size_t count, GBufferView *view) -{ - //size_t i; /* Boucle de parcours */ - //GBufferLine *line; /* Ligne à manipuler */ - //const vmpa2t *addr; /* Localisation de ligne */ - - /** - * Il n'y a pas besoin de verrou ici car la fonction est appelée directement par le tampon. - * D'autre part, on considère qu'il y a toujours une ligne aux adresses de borne, si la vue est bornée. - */ - - if (added) - { - if (view->unrestricted) - view->last += count; - - else - { -#if 0 - - /* Avant la zone représentée ? */ - if (index < view->first) - { - view->first += count; - view->last += count; - } - - /* Juste avant la zone représentée ? */ - else if (view->first == index) - for (i = 0; i < count; i++) - { - g_buffer_cache_get_line_addr(const GBufferCache *, size_t, gint, vmpa2t *); - - line = g_code_buffer_find_line_by_index(buffer, index + i); - addr = get_mrange_addr(g_buffer_line_get_range(line)); - - if (cmp_vmpa(&view->start, addr) == 0) - { - view->first++; - view->last++; - } - else - break; - - } - - /* Dans la zone représentée ? */ - else if (view->first < index && index <= view->last) - view->last += count; - - /* Juste après la vue représentée ? */ - else if ((view->last + 1) == index) - for (i = 0; i < count; i++) - { - g_buffer_cache_get_line_addr(const GBufferCache *, size_t, gint, vmpa2t *); - - line = g_code_buffer_find_line_by_index(buffer, index + i); - addr = get_mrange_addr(g_buffer_line_get_range(line)); - - if (cmp_vmpa(&view->end, addr) == 0) - view->last++; - else - break; - - } - - //g_width_tracker_update_added(view->int_tracker, index, count); -#endif - - } - - } - - else - { - if (view->unrestricted) - view->last -= count; - - else - { - /* Avant la zone représentée ? */ - if (index <= view->first) - { - view->first -= count; - view->last -= count; - } - - /* Dans la zone représentée ? */ - else if (view->first < index && index <= view->last) - view->last -= count; - - } - - //g_width_tracker_update_deleted(view->int_tracker, index, index + count - 1); - - } - - //g_signal_emit_by_name(view, "need-redraw"); - -} - - -/****************************************************************************** -* * -* Paramètres : view = visualisateur à consulter. * -* * -* Description : Fournit le tampon de code lié à un visualisateur donné. * -* * -* Retour : Tampon de code associé au gestionnaire d'affichage. * -* * -* Remarques : - * -* * -******************************************************************************/ - -GBufferCache *g_buffer_view_get_cache(const GBufferView *view) -{ - GBufferCache *result; /* Instance à retourner */ - - result = view->cache; - - g_object_ref(G_OBJECT(result)); - - return result; - -} - - -/****************************************************************************** -* * -* Paramètres : view = visualisateur à mettre à jour. * -* first = première ligne à imprimer. * -* last = première ligne hors cadre. * -* * -* Description : Restreint le champ d'application de l'affichage. * -* * -* Retour : - * -* * -* Remarques : - * -* * -******************************************************************************/ - -void g_buffer_view_restrict(GBufferView *view, GLineCursor *start, GLineCursor *end) -{ - bool state; /* Nouvel état à proclamer */ - GWidthTracker *template; /* Suivi déjà en place */ - - state = (start == NULL || end == NULL); - - if (view->unrestricted != state) - { - view->unrestricted = state; - - template = g_buffer_cache_get_width_tracker(view->cache); - - /* Vérification pour le cas particulier du démarrage */ - if (view->tracker != NULL) - g_object_unref(G_OBJECT(view->tracker)); - - if (view->unrestricted) - { - view->first = 0; - view->last = g_buffer_cache_count_lines(view->cache) - 1; - - view->tracker = template; - - } - - else - { - g_object_ref_sink(G_OBJECT(start)); - g_object_ref_sink(G_OBJECT(end)); - - view->start = start; - view->end = end; - - view->first = g_buffer_cache_find_index_by_cursor(view->cache, start, true); - view->last = g_buffer_cache_find_index_by_cursor(view->cache, end, false); - - view->tracker = g_width_tracker_new_restricted(template, view->first, view->last); - - g_object_unref(G_OBJECT(template)); - - } - - } - -} - - -/****************************************************************************** -* * -* Paramètres : view = visualisateur à consulter. * -* first = première ligne à imprimer ou NULL. [OUT] * -* last = première ligne hors cadre ou NULL. [OUT] * -* * -* Description : Indique le champ d'application de l'affichage. * -* * -* Retour : true si des restrictions particulières sont en place. * -* * -* Remarques : - * -* * -******************************************************************************/ - -bool g_buffer_view_get_restrictions(const GBufferView *view, GLineCursor **start, GLineCursor **end) -{ - if (!view->unrestricted) - { - if (start != NULL) - { - *start = view->start; - g_object_ref(G_OBJECT(*start)); - } - - if (end != NULL) - { - *end = view->end; - g_object_ref(G_OBJECT(*end)); - } - - } - else - { - if (start != NULL) *start = NULL; - if (end != NULL) *end = NULL; - } - - return !view->unrestricted; - -} - - - - - - - - - -/****************************************************************************** -* * -* Paramètres : view = visualisation à consulter. * -* options = règles d'affichage des colonnes modulables. * -* * -* Description : Fournit la largeur requise par une visualisation. * -* * -* Retour : Dimension calculée. * -* * -* Remarques : - * -* * -******************************************************************************/ - -gint g_buffer_view_get_width(GBufferView *view, const GDisplayOptions *options) -{ - gint result; /* Taille à retourner */ - - result = g_buffer_cache_get_text_position(view->cache); - - result += g_width_tracker_get_width(view->tracker, options); - - return result; - -} - - -/****************************************************************************** -* * -* Paramètres : view = visualisation à consulter. * -* options = règles d'affichage des colonnes modulables. * -* * -* Description : Fournit la largeur requise pour dépasser les marges gauches. * -* * -* Retour : Dimension calculée. * -* * -* Remarques : - * -* * -******************************************************************************/ - -gint g_buffer_view_get_margin(GBufferView *view, const GDisplayOptions *options) -{ - gint result; /* Taille à retourner */ - - result = g_buffer_cache_get_text_position(view->cache); - - result += g_width_tracker_get_margin(view->tracker, options); - - return result; - -} - - -/****************************************************************************** -* * -* Paramètres : view = visualisation à consulter. * -* * -* Description : Fournit la hauteur requise par une visualisation. * -* * -* Retour : Dimension calculée. * -* * -* Remarques : - * -* * -******************************************************************************/ - -gint g_buffer_view_get_height(const GBufferView *view) -{ - gint result; /* Taille à retourner */ - - result = g_buffer_cache_get_line_height(view->cache); - - result *= (view->last - view->first + 1); - - return result; - -} - - - - - - - - - - - - - -/****************************************************************************** -* * -* Paramètres : view = vue de tampon à mettre à jour. * -* x = abscisse proposée pour le nouvel emplacement. * -* y = ordonnée proposée pour le nouvel emplacement. * -* options = règles d'affichage des colonnes modulables. * -* offsets = décalages supplémentaires à appliquer. * -* caret = position du curseur à construire. [OUT] * -* cursor = emplacement correspondant à cette position. [OUT] * -* * -* Description : Calcule la position idéale de curseur pour un point donné. * -* * -* Retour : true si les deux derniers arguments ont pu être constitués. * -* * -* Remarques : - * -* * -******************************************************************************/ - -bool g_buffer_view_compute_caret_full(GBufferView *view, gint x, gint y, const GDisplayOptions *options, const line_width_summary *offsets, cairo_rectangle_int_t *caret, GLineCursor **cursor) -{ - bool result; /* Bilan à retourner */ - gint lheight; /* Hauteur d'une ligne */ - size_t index; /* Indice de ligne de tampon */ - GBufferLine *line; /* Ligne à la position courante*/ - - result = false; - - /* Détermination de la ligne courante */ - - lheight = g_buffer_cache_get_line_height(view->cache); - index = y / lheight; - - index += view->first; - - if (index > view->last) - goto gbvccf_done; - - line = g_buffer_cache_find_line_by_index(view->cache, index); - - assert(line != NULL); - - /* Calcul d'une position */ - - result = _g_buffer_view_compute_caret_full(view, x, line, index, options, offsets, caret, cursor); - - g_object_unref(G_OBJECT(line)); - - gbvccf_done: - - return result; - -} - - -/****************************************************************************** -* * -* Paramètres : view = vue de tampon à mettre à jour. * -* x = abscisse proposée pour le nouvel emplacement. * -* line = ligne correspondant à la position. * -* index = indice de cette même ligne dans le tampon. * -* options = règles d'affichage des colonnes modulables. * -* offsets = décalages supplémentaires à appliquer. * -* caret = position du curseur à construire. [OUT] * -* cursor = emplacement correspondant à cette position. [OUT] * -* * -* Description : Calcule la position idéale de curseur pour un point donné. * -* * -* Retour : true si les deux derniers arguments ont pu être constitués. * -* * -* Remarques : - * -* * -******************************************************************************/ - -bool _g_buffer_view_compute_caret_full(GBufferView *view, gint x, GBufferLine *line, size_t index, const GDisplayOptions *options, const line_width_summary *offsets, cairo_rectangle_int_t *caret, GLineCursor **cursor) -{ - bool result; /* Bilan à retourner */ - gint text_pos; /* Abscisse de départ du texte */ - line_width_summary summary; /* Résumé concis des largeurs */ - gint base; /* Position absolue de segment */ - bool status; /* Bilan de la localisation */ - gint lheight; /* Hauteur d'une ligne */ - - result = false; - - /* Zone d'intervention bornée ! */ - - text_pos = g_buffer_cache_get_text_position(view->cache); - - if (x < text_pos) - goto gbvccf_done; - - /* Calcul d'une position */ - - g_width_tracker_get_local_width_summary(view->tracker, index, &summary); - - x -= text_pos; - - status = g_buffer_line_get_coord_at(line, &summary, options, offsets, &base, &x, - GDK_SCROLL_LEFT, true, (col_coord_t []) { { 0 } }); - - if (!status) - goto gbvccf_done; - - /* Transmission des informations */ - - lheight = g_buffer_cache_get_line_height(view->cache); - - caret->x = text_pos + base + x; - - caret->y = (index - view->first) * lheight; - - caret->width = 2; - caret->height = lheight; - - g_buffer_cache_get_line_cursor(view->cache, index, caret->x, cursor); - - result = true; - - gbvccf_done: - - return result; - -} - - -/****************************************************************************** -* * -* Paramètres : view = vue de tampon à manipuler. * -* line = ligne à venir consulter. * -* index = indice de cette même ligne dans le tampon. * -* caret = position du curseur à faire évoluer. * -* ctrl = indique la demande d'un parcours rapide. * -* dir = direction du parcours. * -* options = règles d'affichage des colonnes modulables. * -* offsets = décalages supplémentaires à appliquer. * -* * -* Description : Déplace le curseur au sein d'une vue de tampon. * -* * -* Retour : true si un déplacement a été effectué, false sinon. * -* * -* Remarques : - * -* * -******************************************************************************/ - -static bool _g_buffer_view_move_caret(GBufferView *view, const GBufferLine *line, size_t index, cairo_rectangle_int_t *caret, bool ctrl, GdkScrollDirection dir, const GDisplayOptions *options, const line_width_summary *offsets) -{ - bool result; /* Bilan à retourner */ - gint text_pos; /* Abscisse de départ du texte */ - gint offset; /* Point de travail modifiable */ - line_width_summary summary; /* Résumé concis des largeurs */ - gint base; /* Position absolue de segment */ - col_coord_t coord; /* Coordonnées en interne */ - line_segment *segment; /* Bribe de texte trouvée */ - - - result = false; - - /* Zone d'intervention bornée ! */ - - text_pos = g_buffer_cache_get_text_position(view->cache); - - if (caret->x < text_pos) - goto gbvmc_done; - - offset = caret->x - text_pos; - - g_width_tracker_get_local_width_summary(view->tracker, index, &summary); - - /* Déplacement au sein du segment courant ? */ - - result = g_buffer_line_get_coord_at(line, &summary, options, offsets, &base, &offset, dir, false, &coord); - - if (result) - { - segment = g_buffer_line_get_segment_from_coord(line, &coord); - - result = move_caret_on_line_segment(segment, &offset, ctrl, dir); - - release_line_segment(segment); - - } - - /* Tentative de déplacement chez le segment voisin ? */ - - if (!result) - { - base = 0; - - result = g_buffer_line_find_near_coord(line, &coord, &summary, options, offsets, dir, &offset); - - } - - /* Mise à jour éventuelle */ - - if (result) - caret->x = text_pos + base + offset; - - gbvmc_done: - - return result; - -} - - -/****************************************************************************** -* * -* Paramètres : view = vue de tampon à mettre à jour. * -* ctrl = indique la demande d'un parcours rapide. * -* dir = direction du parcours. * -* options = règles d'affichage des colonnes modulables. * -* offsets = décalages supplémentaires à appliquer. * -* caret = position du curseur à faire évoluer. [OUT] * -* cursor = emplacement correspondant à cette position. [OUT] * -* * -* Description : Déplace le curseur au sein d'une vue de tampon. * -* * -* Retour : true si les deux derniers arguments ont pu être constitués. * -* * -* Remarques : - * -* * -******************************************************************************/ - -bool g_buffer_view_move_caret(GBufferView *view, bool ctrl, GdkScrollDirection dir, const GDisplayOptions *options, const line_width_summary *offsets, cairo_rectangle_int_t *caret, GLineCursor **cursor) -{ - bool result; /* Bilan à retourner */ - size_t index; /* Indice de ligne de tampon */ - GBufferLine *line; /* Ligne sous le pointeur */ - size_t first; /* Première ligne intégrée */ - size_t last; /* Dernière ligne intégrée */ - GBufferLine *other; /* Ligne voisine à visiter */ - bool moved; /* Mémorisation d'une évolut° */ - gint text_pos; /* Abscisse de départ du texte */ - - result = false; - - line = g_buffer_view_find_line_at(view, caret->y, &index); - if (line == NULL) goto gbvmc_done; - - first = view->first; - last = view->last; - - switch (dir) - { - case GDK_SCROLL_UP: - - if (index > first) - { - index--; - - other = g_buffer_cache_find_line_by_index(view->cache, index); - assert(other != NULL); - - result = _g_buffer_view_compute_caret_full(view, caret->x, other, index, - options, offsets, caret, cursor); - - g_object_unref(G_OBJECT(other)); - - } - - break; - - case GDK_SCROLL_DOWN: - - if (index < last) - { - index++; - - other = g_buffer_cache_find_line_by_index(view->cache, index); - assert(other != NULL); - - result = _g_buffer_view_compute_caret_full(view, caret->x, other, index, - options, offsets, caret, cursor); - - g_object_unref(G_OBJECT(other)); - - } - - break; - - case GDK_SCROLL_LEFT: - - moved = _g_buffer_view_move_caret(view, line, index, caret, ctrl, GDK_SCROLL_LEFT, options, offsets); - - if (moved) - { - g_buffer_cache_get_line_cursor(view->cache, index, caret->x, cursor); - result = true; - } - - else if (index > first) - { - index--; - - other = g_buffer_cache_find_line_by_index(view->cache, index); - assert(other != NULL); - - result = _g_buffer_view_compute_caret_full(view, INT_MAX, other, index, - options, offsets, caret, cursor); - - g_object_unref(G_OBJECT(other)); - - } - - break; - - case GDK_SCROLL_RIGHT: - - moved = _g_buffer_view_move_caret(view, line, index, caret, ctrl, GDK_SCROLL_RIGHT, options, offsets); - - if (moved) - { - g_buffer_cache_get_line_cursor(view->cache, index, caret->x, cursor); - result = true; - } - - else if (index < last) - { - index++; - - text_pos = g_buffer_cache_get_text_position(view->cache); - - other = g_buffer_cache_find_line_by_index(view->cache, index); - assert(other != NULL); - - result = _g_buffer_view_compute_caret_full(view, text_pos, other, index, - options, offsets, caret, cursor); - - g_object_unref(G_OBJECT(other)); - - } - - break; - - default: /* GDK_SCROLL_SMOOTH */ - break; - - } - - g_object_unref(G_OBJECT(line)); - - gbvmc_done: - - return result; - -} - - - - - - - - -/****************************************************************************** -* * -* Paramètres : view = vue de tampon à mettre à jour. * -* x = abscisse de la zone principale à traiter. * -* y = ordonnée de la zone principale à traiter. * -* options = règles d'affichage des colonnes modulables. * -* offsets = décalages supplémentaires à appliquer. * -* * -* Description : Trouve le créateur à l'origine d'un emplacement donné. * -* * -* Retour : Créateur trouvé ou NULL si aucun. * -* * -* Remarques : - * -* * -******************************************************************************/ - -GObject *g_buffer_view_find_creator(GBufferView *view, gint x, gint y, const GDisplayOptions *options, const line_width_summary *offsets) -{ - GObject *result; /* Trouvaille à faire remonter */ - gint text_pos; /* Abscisse de départ du texte */ - gint lheight; /* Hauteur d'une ligne */ - size_t index; /* Indice de ligne de tampon */ - GBufferLine *line; /* Ligne à la position courante*/ - line_width_summary summary; /* Résumé concis des largeurs */ - - result = NULL; - - /* Zone d'intervention bornée ! */ - - text_pos = g_buffer_cache_get_text_position(view->cache); - - if (x < text_pos) - goto gbvfc_done; - - /* Détermination de la ligne concernée */ - - lheight = g_buffer_cache_get_line_height(view->cache); - index = y / lheight; - - index += view->first; - - if (index > view->last) - goto gbvfc_done; - - line = g_buffer_cache_find_line_by_index(view->cache, index); - - assert(line != NULL); - - /* Recherche d'un segment et de son empreinte */ - - g_width_tracker_get_local_width_summary(view->tracker, index, &summary); - - x -= text_pos; - - result = g_buffer_line_get_creator_at(line, &summary, options, offsets, - (gint []) { 0 }, &x, GDK_SCROLL_LEFT, false); - - g_object_unref(G_OBJECT(line)); - - gbvfc_done: - - return result; - -} - - - - - - - - -/****************************************************************************** -* * -* Paramètres : view = vue de tampon à mettre à jour. * -* * -* Description : Supprime toute mise en évidence de segments. * -* * -* Retour : true si un besoin d'actualisation d'affichage se fait sentir.* -* * -* Remarques : - * -* * -******************************************************************************/ - -bool g_buffer_view_unhighlight_segments(GBufferView *view) -{ - bool result; /* Bilan d'action à renvoyer */ - - result = reset_segment_content_list(view->highlighted); - - return result; - -} - - -/****************************************************************************** -* * -* Paramètres : view = vue de tampon à mettre à jour. * -* x = abscisse de la zone principale à traiter. * -* y = ordonnée de la zone principale à traiter. * -* options = règles d'affichage des colonnes modulables. * -* offsets = décalages supplémentaires à appliquer. * -* * -* Description : Surligne tous les segments similaires à celui sous la souris.* -* * -* Retour : true si un besoin d'actualisation d'affichage se fait sentir.* -* * -* Remarques : - * -* * -******************************************************************************/ - -bool g_buffer_view_highlight_segments(GBufferView *view, gint x, gint y, const GDisplayOptions *options, const line_width_summary *offsets) -{ - bool result; /* Besoin à faire remonter */ - gint text_pos; /* Abscisse de départ du texte */ - gint lheight; /* Hauteur d'une ligne */ - size_t index; /* Indice de ligne de tampon */ - GBufferLine *line; /* Ligne à la position courante*/ - line_width_summary summary; /* Résumé concis des largeurs */ - line_segment *segment; /* Segment sélectionnable */ - - /* Réinitialisation */ - - if (view->highlighted != NULL) - result = g_buffer_view_unhighlight_segments(view); - else - result = false; - - /* Zone d'intervention bornée ! */ - - text_pos = g_buffer_cache_get_text_position(view->cache); - - if (x < text_pos) - goto gbvhs_done; - - /* Détermination de la ligne concernée */ - - lheight = g_buffer_cache_get_line_height(view->cache); - index = y / lheight; - - index += view->first; - - if (index > view->last) - goto gbvhs_done; - - line = g_buffer_cache_find_line_by_index(view->cache, index); - - assert(line != NULL); - - /* Recherche d'un segment et de son empreinte */ - - g_width_tracker_get_local_width_summary(view->tracker, index, &summary); - - x -= text_pos; - - segment = g_buffer_line_get_segment_at(line, &summary, options, offsets, - (gint []) { 0 }, &x, GDK_SCROLL_LEFT, true); - - g_object_unref(G_OBJECT(line)); - - /* Conclusion */ - - if (segment != NULL) - { - result |= add_segment_content_to_selection_list(view->highlighted, segment); - release_line_segment(segment); - } - - if (result) - g_signal_emit_by_name(view, "need-redraw"); - - gbvhs_done: - - return result; - -} - - -/****************************************************************************** -* * -* Paramètres : view = visualisation à représenter. * -* cr = contexte graphique dédié à la procédure. * -* virt_y = ordonnée réelle du point 0 à l'écran. * -* area = position et surface à traiter. * -* options = règles d'affichage des colonnes modulables. * -* offsets = décalages supplémentaires à appliquer. * -* selected = ordonnée d'une ligne sélectionnée ou NULL. * -* scale = échelle appliquée à la surface de rendu. * -* export = indique si la vue est en cours d'exportation. * -* * -* Description : Imprime la visualisation du tampon de lignes quelconques. * -* * -* Retour : - * -* * -* Remarques : - * -* * -******************************************************************************/ - -void g_buffer_view_draw(const GBufferView *view, cairo_t *cr, gint virt_y, const cairo_rectangle_int_t *area, const GDisplayOptions *options, const line_width_summary *offsets, gint *selected, double scale, bool export) -{ - gint line_height; /* Hauteur d'une ligne */ - gint cr_y; /* Ordonnée pour le dessin */ - size_t first; /* Première ligne visée */ - size_t last; /* Dernière ligne visée */ - segcnt_list *highlighted; /* Segments mis en évidence */ - - line_height = g_buffer_cache_get_line_height(view->cache) * scale; - - line_height = MAX(line_height, 1); - - /* Indice et point de départ */ - - first = view->first; - first += (virt_y / line_height); - - cr_y = area->y - (virt_y % line_height); - - /* Indice de d'arrivée */ - - last = first + (area->height / line_height); - if (area->height % line_height > 0) last++; - - last = MIN(last, view->last); - - /* Phase de dessin ! */ - - /** - * Le contexte n'est pas sauvegardé avant modification ici car - * l'appelant l'a fait pour nous avant sa translation sur les abscisses. - */ - - cairo_translate(cr, 0, cr_y); - - if (selected != NULL) - *selected -= cr_y; - - if (export) - highlighted = init_segment_content_list(); - else - highlighted = view->highlighted; - - g_buffer_cache_draw(view->cache, cr, first, last, area, options, offsets, selected, highlighted); - - if (export) - unref_segment_content_list(highlighted); - -} - - - - - - - - - - - - - - - -/****************************************************************************** -* * -* Paramètres : view = visualisation à consulter. * -* y = ordonnée comprise dans la ligne recherchée. * -* idx = indice de la ligne trouvée ou NULL. [OUT] * -* * -* Description : Fournit la ligne présente à une ordonnée donnée. * -* * -* Retour : Ligne retrouvée ou NULL si aucune. * -* * -* Remarques : - * -* * -******************************************************************************/ - -static GBufferLine *g_buffer_view_find_line_at(GBufferView *view, gint y, size_t *idx) -{ - GBufferLine *result; /* Ligne trouvée à retourner */ - gint lheight; /* Hauteur d'une ligne */ - size_t index; /* Indice attendu */ - - lheight = g_buffer_cache_get_line_height(view->cache); - index = y / lheight; - - index += view->first; - - if (index <= view->last) - result = g_buffer_cache_find_line_by_index(view->cache, index); - else - result = NULL; - - if (result != NULL && idx != NULL) - *idx = index; - - return result; - -} - - - - - - - - - - - - - - - -/****************************************************************************** -* * -* Paramètres : view = visualisation à consulter. * -* cursor = emplacement à présenter à l'écran. * -* code = s'arrête si possible à une ligne avec code. * -* x = position horizontale au sein du composant. [OUT] * -* y = position verticale au sein du composant. [OUT] * -* * -* Description : Indique la position d'affichage d'une adresse donnée. * -* * -* Retour : true si l'adresse fait partie du composant, false sinon. * -* * -* Remarques : - * -* * -******************************************************************************/ - -bool g_buffer_view_get_cursor_coordinates(GBufferView *view, const GLineCursor *cursor, bool code, gint *x, gint *y) -{ - bool result; /* Bilan à retourner */ - - result = g_buffer_cache_get_cursor_coordinates(view->cache, cursor, view->first, view->last, code, x, y); - - return result; - -} diff --git a/src/glibext/gbufferview.h b/src/glibext/gbufferview.h deleted file mode 100644 index 2930cf9..0000000 --- a/src/glibext/gbufferview.h +++ /dev/null @@ -1,115 +0,0 @@ - -/* Chrysalide - Outil d'analyse de fichiers binaires - * gbufferview.h - prototypes pour l'affichage d'une vue particulière d'un tampon de lignes - * - * Copyright (C) 2016-2019 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 . - */ - - -#ifndef _GLIBEXT_GBUFFERVIEW_H -#define _GLIBEXT_GBUFFERVIEW_H - - -#include - - -#include "gbuffercache.h" -#include "gdisplayoptions.h" - - - -#define G_TYPE_BUFFER_VIEW (g_buffer_view_get_type()) -#define G_BUFFER_VIEW(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_BUFFER_VIEW, GBufferView)) -#define G_BUFFER_VIEW_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_BUFFER_VIEW, GBufferViewClass)) -#define G_IS_BUFFER_VIEW(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_BUFFER_VIEW)) -#define G_IS_BUFFER_VIEW_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_BUFFER_VIEW)) -#define G_BUFFER_VIEW_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_BUFFER_VIEW, GBufferViewClass)) - - -/* Vue d'un tampon pour code désassemblé (instance) */ -typedef struct _GBufferView GBufferView; - -/* Vue d'un tampon pour code désassemblé (classe) */ -typedef struct _GBufferViewClass GBufferViewClass; - - -/* Détermine le type de la vue d'un tampon pour lignes générées. */ -GType g_buffer_view_get_type(void); - -/* Crée une nouvelle vue d'un tampon pour lignes générées. */ -GBufferView *g_buffer_view_new(GBufferCache *, segcnt_list *); - -/* Fournit le tampon de code lié à un visualisateur donné. */ -GBufferCache *g_buffer_view_get_cache(const GBufferView *); - -/* Restreint le champ d'application de l'affichage. */ -void g_buffer_view_restrict(GBufferView *, GLineCursor *, GLineCursor *); - -/* Indique le champ d'application de l'affichage. */ -bool g_buffer_view_get_restrictions(const GBufferView *, GLineCursor **, GLineCursor **); - - - -/* Fournit la largeur requise par une visualisation. */ -gint g_buffer_view_get_width(GBufferView *, const GDisplayOptions *); - -/* Fournit la largeur requise pour dépasser les marges gauches. */ -gint g_buffer_view_get_margin(GBufferView *, const GDisplayOptions *); - -/* Fournit la hauteur requise par une visualisation. */ -gint g_buffer_view_get_height(const GBufferView *); - - - - - -/* Calcule la position idéale de curseur pour un point donné. */ -bool g_buffer_view_compute_caret_full(GBufferView *, gint, gint, const GDisplayOptions *, const line_width_summary *, cairo_rectangle_int_t *, GLineCursor **); - -/* Déplace le curseur au sein d'une vue de tampon. */ -bool g_buffer_view_move_caret(GBufferView *, bool, GdkScrollDirection, const GDisplayOptions *, const line_width_summary *, cairo_rectangle_int_t *, GLineCursor **); - - - -/* Trouve le créateur à l'origine d'un emplacement donné. */ -GObject *g_buffer_view_find_creator(GBufferView *, gint, gint, const GDisplayOptions *, const line_width_summary *); - - - -/* Supprime toute mise en évidence de segments. */ -bool g_buffer_view_unhighlight_segments(GBufferView *); - -/* Surligne tous les segments similaires à celui sous la souris. */ -bool g_buffer_view_highlight_segments(GBufferView *, gint, gint, const GDisplayOptions *, const line_width_summary *); - -/* Imprime la visualisation du tampon de lignes quelconques. */ -void g_buffer_view_draw(const GBufferView *, cairo_t *, gint, const cairo_rectangle_int_t *, const GDisplayOptions *, const line_width_summary *, gint *, double, bool); - - - - - - -/* Indique la position d'affichage d'une adresse donnée. */ -bool g_buffer_view_get_cursor_coordinates(GBufferView *, const GLineCursor *, bool, gint *, gint *); - - - - - -#endif /* _GLIBEXT_GBUFFERVIEW_H */ diff --git a/src/glibext/generators/hex.c b/src/glibext/generators/hex.c index 13a76e3..b261f36 100644 --- a/src/glibext/generators/hex.c +++ b/src/glibext/generators/hex.c @@ -28,8 +28,8 @@ #include +#include "../bufferline.h" #include "../gbinarycursor.h" -#include "../gbufferline.h" #include "../linegen-int.h" #include "../linesegment.h" #include "../../core/params.h" diff --git a/src/glibext/generators/prologue.c b/src/glibext/generators/prologue.c index 3295e73..5829fde 100644 --- a/src/glibext/generators/prologue.c +++ b/src/glibext/generators/prologue.c @@ -28,8 +28,8 @@ #include +#include "../bufferline.h" #include "../gbinarycursor.h" -#include "../gbufferline.h" #include "../linegen-int.h" #include "../linesegment.h" #include "../../format/executable.h" diff --git a/src/glibext/generators/rborder.c b/src/glibext/generators/rborder.c index 8509376..8ff1271 100644 --- a/src/glibext/generators/rborder.c +++ b/src/glibext/generators/rborder.c @@ -29,8 +29,8 @@ #include +#include "../bufferline.h" #include "../gbinarycursor.h" -#include "../gbufferline.h" #include "../linegen-int.h" #include "../linesegment.h" diff --git a/src/glibext/gwidthtracker.c b/src/glibext/gwidthtracker.c deleted file mode 100644 index c9aff7b..0000000 --- a/src/glibext/gwidthtracker.c +++ /dev/null @@ -1,1271 +0,0 @@ - -/* Chrysalide - Outil d'analyse de fichiers binaires - * gwidthtracker.c - suivi des largeurs associées à un ensemble de lignes - * - * Copyright (C) 2016-2019 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 "gwidthtracker.h" - - -#include -#include -#include -#include - - -#include - - -#include "delayed-int.h" -#include "gbuffercache.h" -#include "../core/global.h" -#include "../core/nproc.h" - - - -/* --------------------------- PRISE DE MESURES INITIALES --------------------------- */ - - -/* Procédure de mise à jour des mesures de largeurs (instance) */ -typedef struct _GWidthUpdate -{ - GDelayedWork parent; /* A laisser en premier */ - - activity_id_t id; /* Groupe de progression */ - - GWidthTracker *tracker; /* Gestionnaire à manipuler */ - - size_t start; /* Premier indice à traiter */ - size_t end; /* Premier indice à écarter */ - - line_width_summary summary; /* Largeurs requises suivies */ - -} GWidthUpdate; - -/* Procédure de mise à jour des mesures de largeurs (classe) */ -typedef struct _GWidthUpdateClass -{ - GDelayedWorkClass parent; /* A laisser en premier */ - -} GWidthUpdateClass; - - -#define G_TYPE_WIDTH_UPDATE g_width_update_get_type() -#define G_WIDTH_UPDATE(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_WIDTH_UPDATE, GWidthUpdate)) -#define G_IS_WIDTH_UPDATE(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_WIDTH_UPDATE)) -#define G_WIDTH_UPDATE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_WIDTH_UPDATE, GWidthUpdateClass)) -#define G_IS_WIDTH_UPDATE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_WIDTH_UPDATE)) -#define G_WIDTH_UPDATE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_WIDTH_UPDATE, GWidthUpdateClass)) - - -/* Initialise la classe des tâches de mesures de largeurs. */ -static void g_width_update_class_init(GWidthUpdateClass *); - -/* Initialise une tâche de mesures de largeurs. */ -static void g_width_update_init(GWidthUpdate *); - -/* Supprime toutes les références externes. */ -static void g_width_update_dispose(GWidthUpdate *); - -/* Procède à la libération totale de la mémoire. */ -static void g_width_update_finalize(GWidthUpdate *); - -/* Indique le type défini pour les tâches de mesures de largeurs. */ -GType g_width_update_get_type(void); - -/* Crée une tâche de mesures de largeurs. */ -static GWidthUpdate *g_width_update_new(activity_id_t, GWidthTracker *, size_t, size_t); - -/* Assure les mesures initiales d'un ensemble de lignes. */ -static void g_width_update_process(GWidthUpdate *, GtkStatusStack *); - -/* Récupère les données obtenues lors d'une mesure globale. */ -static void g_width_update_collect(GWidthUpdate *, line_width_summary *); - - - -/* ---------------------------- RASSEMBLEMENT DE MESURES ---------------------------- */ - - -/* Portions de largeurs communes */ -typedef struct _common_metrics -{ - size_t first; /* Premier indice de portion */ - size_t last; /* Dernier indice de portion */ - - line_width_summary summary; /* Compilation de largeurs */ - bool cached; /* Mise en cache des calculs */ - -} common_metrics; - - -/* Gestionnaire de largeurs associées aux lignes (instance) */ -struct _GWidthTracker -{ - GObject parent; /* A laisser en premier */ - - GBufferCache *cache; /* Ensemble complet de lignes */ - - common_metrics *portions; /* Portions représentées */ - size_t count; /* Quantité de ces portions */ - - line_width_summary summary; /* Largeurs requises suivies */ - bool cached; /* Mise en cache des calculs */ - -}; - -/* Gestionnaire de largeurs associées aux lignes (classe) */ -struct _GWidthTrackerClass -{ - GObjectClass parent; /* A laisser en premier */ - -}; - - -/* Procède à l'initialisation d'une classe de suivi de largeurs. */ -static void g_width_tracker_class_init(GWidthTrackerClass *); - -/* Procède à l'initialisation d'un suivi de largeurs de lignes. */ -static void g_width_tracker_init(GWidthTracker *); - -/* Supprime toutes les références externes. */ -static void g_width_tracker_dispose(GWidthTracker *); - -/* Procède à la libération totale de la mémoire. */ -static void g_width_tracker_finalize(GWidthTracker *); - -/* Recherche la portion contenant un indice de ligne donné. */ -static size_t g_width_tracker_find_metrics(const GWidthTracker *, size_t); - -/* Prend en compte une évolution du volume de lignes. */ -static void g_width_tracker_update_ranges(GWidthTracker *, size_t, size_t); - -/* Réinitialise les largeurs requises par une portion de lignes.* */ -static void g_width_tracker_reset_widths(GWidthTracker *, size_t); - -/* Recalcule les largeurs requises par une portion de lignes. */ -static const line_width_summary *g_width_tracker_get_up_to_date_widths(GWidthTracker *, size_t); - -/* Calcule les largeurs requises par un ensemble de lignes. */ -static void g_width_tracker_ensure_valid_required_widths(GWidthTracker *); - - - -/* ---------------------------------------------------------------------------------- */ -/* PRISE DE MESURES INITIALES */ -/* ---------------------------------------------------------------------------------- */ - - -/* Indique le type défini pour les tâches de mesures de largeurs. */ -G_DEFINE_TYPE(GWidthUpdate, g_width_update, G_TYPE_DELAYED_WORK); - - -/****************************************************************************** -* * -* Paramètres : klass = classe à initialiser. * -* * -* Description : Initialise la classe des tâches de mesures de largeurs. * -* * -* Retour : - * -* * -* Remarques : - * -* * -******************************************************************************/ - -static void g_width_update_class_init(GWidthUpdateClass *klass) -{ - GObjectClass *object; /* Autre version de la classe */ - GDelayedWorkClass *work; /* Version en classe parente */ - - object = G_OBJECT_CLASS(klass); - - object->dispose = (GObjectFinalizeFunc/* ! */)g_width_update_dispose; - object->finalize = (GObjectFinalizeFunc)g_width_update_finalize; - - work = G_DELAYED_WORK_CLASS(klass); - - work->run = (run_task_fc)g_width_update_process; - -} - - -/****************************************************************************** -* * -* Paramètres : update = instance à initialiser. * -* * -* Description : Initialise une tâche de mesures de largeurs. * -* * -* Retour : - * -* * -* Remarques : - * -* * -******************************************************************************/ - -static void g_width_update_init(GWidthUpdate *update) -{ - memset(&update->summary, 0, sizeof(line_width_summary)); - -} - - -/****************************************************************************** -* * -* Paramètres : update = instance d'objet GLib à traiter. * -* * -* Description : Supprime toutes les références externes. * -* * -* Retour : - * -* * -* Remarques : - * -* * -******************************************************************************/ - -static void g_width_update_dispose(GWidthUpdate *update) -{ - g_clear_object(&update->tracker); - - G_OBJECT_CLASS(g_width_update_parent_class)->dispose(G_OBJECT(update)); - -} - - -/****************************************************************************** -* * -* Paramètres : update = instance d'objet GLib à traiter. * -* * -* Description : Procède à la libération totale de la mémoire. * -* * -* Retour : - * -* * -* Remarques : - * -* * -******************************************************************************/ - -static void g_width_update_finalize(GWidthUpdate *update) -{ - G_OBJECT_CLASS(g_width_update_parent_class)->finalize(G_OBJECT(update)); - -} - - -/****************************************************************************** -* * -* Paramètres : id = identifiant pour signaler la progression courante. * -* tracker = gestionnaire de largeurs à consulter. * -* start = indice de la première ligne à traiter. * -* end = indice de la première ligne à éviter. * -* * -* Description : Crée une tâche de mesures de largeurs. * -* * -* Retour : Tâche créée. * -* * -* Remarques : - * -* * -******************************************************************************/ - -static GWidthUpdate *g_width_update_new(activity_id_t id, GWidthTracker *tracker, size_t start, size_t end) -{ - GWidthUpdate *result; /* Tâche à retourner */ - - result = g_object_new(G_TYPE_WIDTH_UPDATE, NULL); - - result->id = id; - - g_object_ref(G_OBJECT(tracker)); - result->tracker = tracker; - - result->start = start; - result->end = end; - - return result; - -} - - -/****************************************************************************** -* * -* Paramètres : update = opération de mesures à mener. * -* status = barre de statut à tenir informée. * -* * -* Description : Assure les mesures initiales d'un ensemble de lignes. * -* * -* Retour : - * -* * -* Remarques : - * -* * -******************************************************************************/ - -static void g_width_update_process(GWidthUpdate *update, GtkStatusStack *status) -{ - line_width_summary *local; /* Valeurs collectées */ - size_t i; /* Boucle de parcours #1 */ - const line_width_summary *summary; /* Valeurs à intégrer */ - BufferLineColumn k; /* Boucle de parcours #2 */ - - local = &update->summary; - - for (i = update->start; i < update->end; i++) - { - summary = g_width_tracker_get_up_to_date_widths(update->tracker, i); - - for (k = 0; k < BLC_COUNT; k++) - local->max_widths[k] = MAX(local->max_widths[k], summary->max_widths[k]); - - local->merged_width = MAX(local->merged_width, summary->merged_width); - - gtk_status_stack_update_activity_value(status, update->id, 1); - - } - -} - - -/****************************************************************************** -* * -* Paramètres : update = opération de mesures menée à bien. * -* global = lieu de centralisation des données globales. * -* * -* Description : Récupère les données obtenues lors d'une mesure globale. * -* * -* Retour : - * -* * -* Remarques : - * -* * -******************************************************************************/ - -static void g_width_update_collect(GWidthUpdate *update, line_width_summary *global) -{ - line_width_summary *local; /* Valeurs collectées */ - BufferLineColumn i; /* Boucle de parcours */ - - local = &update->summary; - - for (i = 0; i < BLC_COUNT; i++) - global->max_widths[i] = MAX(global->max_widths[i], local->max_widths[i]); - - global->merged_width = MAX(global->merged_width, local->merged_width); - -} - - - -/* ---------------------------------------------------------------------------------- */ -/* RASSEMBLEMENT DE MESURES */ -/* ---------------------------------------------------------------------------------- */ - - -/* Détermine le type du gestionnaire de largeurs associées aux lignes. */ -G_DEFINE_TYPE(GWidthTracker, g_width_tracker, G_TYPE_OBJECT); - - -/****************************************************************************** -* * -* Paramètres : class = classe de composant GTK à initialiser. * -* * -* Description : Procède à l'initialisation d'une classe de suivi de largeurs.* -* * -* Retour : - * -* * -* Remarques : - * -* * -******************************************************************************/ - -static void g_width_tracker_class_init(GWidthTrackerClass *class) -{ - GObjectClass *object; /* Autre version de la classe */ - - object = G_OBJECT_CLASS(class); - - object->dispose = (GObjectFinalizeFunc/* ! */)g_width_tracker_dispose; - object->finalize = (GObjectFinalizeFunc)g_width_tracker_finalize; - -} - - -/****************************************************************************** -* * -* Paramètres : tracker = composant GLib à initialiser. * -* * -* Description : Procède à l'initialisation d'un suivi de largeurs de lignes. * -* * -* Retour : - * -* * -* Remarques : - * -* * -******************************************************************************/ - -static void g_width_tracker_init(GWidthTracker *tracker) -{ - tracker->portions = NULL; - tracker->count = 0; - - memset(&tracker->summary, 0, sizeof(line_width_summary)); - tracker->cached = false; - -} - - -/****************************************************************************** -* * -* Paramètres : tracker = instance d'objet GLib à traiter. * -* * -* Description : Supprime toutes les références externes. * -* * -* Retour : - * -* * -* Remarques : - * -* * -******************************************************************************/ - -static void g_width_tracker_dispose(GWidthTracker *tracker) -{ - g_object_unref(G_OBJECT(tracker->cache)); - - G_OBJECT_CLASS(g_width_tracker_parent_class)->dispose(G_OBJECT(tracker)); - -} - - -/****************************************************************************** -* * -* Paramètres : tracker = instance d'objet GLib à traiter. * -* * -* Description : Procède à la libération totale de la mémoire. * -* * -* Retour : - * -* * -* Remarques : - * -* * -******************************************************************************/ - -static void g_width_tracker_finalize(GWidthTracker *tracker) -{ - G_OBJECT_CLASS(g_width_tracker_parent_class)->finalize(G_OBJECT(tracker)); - -} - - -/****************************************************************************** -* * -* Paramètres : buffer = tampon contenant les lignes à surveiller. * -* first = adresse contenant l'indice de la première ligne. * -* last = adresse contenant l'indice de la dernière ligne. * -* * -* Description : Crée un nouveau suivi de largeurs au sein de lignes. * -* * -* Retour : Composant GLib créé. * -* * -* Remarques : - * -* * -******************************************************************************/ - -GWidthTracker *g_width_tracker_new(GBufferCache *cache) -{ - GWidthTracker *result; /* Composant à retourner */ - - result = g_object_new(G_TYPE_WIDTH_TRACKER, NULL); - - g_object_ref(G_OBJECT(cache)); - result->cache = cache; - - return result; - -} - - -/****************************************************************************** -* * -* Paramètres : buffer = tampon contenant les lignes à surveiller. * -* first = indice de la première ligne d'une zone réduite. * -* last = indice de la dernière ligne d'une zone réduite. * -* * -* Description : Crée un nouveau suivi de largeurs au sein de lignes. * -* * -* Retour : Composant GLib créé. * -* * -* Remarques : - * -* * -******************************************************************************/ - -GWidthTracker *g_width_tracker_new_restricted(const GWidthTracker *template, size_t first, size_t last) -{ - GWidthTracker *result; /* Composant à retourner */ - size_t start; /* Début de la zone à copier */ - size_t end; /* Fin de cette même zone */ - size_t i; /* Boucle de parcours */ - - result = g_object_new(G_TYPE_WIDTH_TRACKER, NULL); - - g_object_ref(G_OBJECT(template->cache)); - result->cache = template->cache; - - start = g_width_tracker_find_metrics(template, first); - assert(start < template->count); - - end = g_width_tracker_find_metrics(template, last); - assert(end < template->count); - - result->count = end - start + 1; - result->portions = (common_metrics *)calloc(result->count, sizeof(common_metrics)); - - for (i = 0; i < result->count; i++) - memcpy(&result->portions[i], &template->portions[start + i], sizeof(common_metrics)); - - if (result->portions[0].first != first) - { - result->portions[0].first = first; - g_width_tracker_reset_widths(result, 0); - } - - if (result->portions[result->count - 1].last != last) - { - result->portions[result->count - 1].last = last; - g_width_tracker_reset_widths(result, result->count - 1); - } - - return result; - -} - - -/****************************************************************************** -* * -* Paramètres : tracker = gestionnaire de suivi à consulter. * -* index = indice d'une ligne dont la portion est inconnue. * -* * -* Description : Recherche la portion contenant un indice de ligne donné. * -* * -* Retour : Indice de portion trouvée ou le nombre de portions sinon. * -* * -* Remarques : - * -* * -******************************************************************************/ - -static size_t g_width_tracker_find_metrics(const GWidthTracker *tracker, size_t index) -{ - size_t result; /* Indice trouvé à retourner */ - common_metrics *found; /* Portion trouvée ou NULL */ - - int look_for_metrics(const size_t *idx, const common_metrics *m) - { - int status; - - if (*idx < m->first) - status = -1; - - else if (*idx > m->last) - status = 1; - - else - status = 0; - - return status; - - } - - found = bsearch(&index, tracker->portions, tracker->count, - sizeof(common_metrics), (__compar_fn_t)look_for_metrics); - - if (found == NULL) - result = tracker->count; - else - result = found - tracker->portions; - - return result; - -} - - -/****************************************************************************** -* * -* Paramètres : tracker = gestionnaire de largeurs de lignes à mettre jour. * -* start = première ligne à traiter. * -* diff = nombre de lignes ajoutées ou supprimées. * -* * -* Description : Prend en compte une évolution du volume de lignes. * -* * -* Retour : - * -* * -* Remarques : - * -* * -******************************************************************************/ - -static void g_width_tracker_update_ranges(GWidthTracker *tracker, size_t start, size_t diff) -{ - size_t i; /* Boucle de parcours */ - - for (i = start; i < tracker->count; i++) - { -#ifndef NDEBUG - if ((i + 1) < tracker->count) - assert((tracker->portions[i].last + 1) == tracker->portions[i + 1].first); -#endif - - tracker->portions[i].first += diff; - tracker->portions[i].last += diff; - - } - -} - - -/****************************************************************************** -* * -* Paramètres : tracker = gestionnaire de largeurs de lignes à mettre jour. * -* index = indice de portion à marquer pour réinitialisation. * -* * -* Description : Réinitialise les largeurs requises par une portion de lignes.* -* * -* Retour : - * -* * -* Remarques : - * -* * -******************************************************************************/ - -static void g_width_tracker_reset_widths(GWidthTracker *tracker, size_t index) -{ - common_metrics *portion; /* Portion à actualiser */ - BufferLineColumn k; /* Boucle de parcours */ - - assert(index < tracker->count); - - portion = &tracker->portions[index]; - - /* Réinitialisation globale ? */ - - if (portion->cached) - { - for (k = 0; k < BLC_COUNT && tracker->cached; k++) - tracker->cached &= (tracker->summary.max_widths[k] != portion->summary.max_widths[k]); - - tracker->cached &= (tracker->summary.merged_width != portion->summary.merged_width); - - } - - /* Réinitialisation locale */ - - portion->cached = false; - -} - - -/****************************************************************************** -* * -* Paramètres : tracker = gestionnaire de largeurs de lignes à mettre jour. * -* index = indice de la portion à rafraîchir. * -* * -* Description : Recalcule les largeurs requises par une portion de lignes. * -* * -* Retour : Accès en lecture seule au résumé à jour. * -* * -* Remarques : - * -* * -******************************************************************************/ - -static const line_width_summary *g_width_tracker_get_up_to_date_widths(GWidthTracker *tracker, size_t index) -{ - common_metrics *portion; /* Portion à actualiser */ - size_t i; /* Boucle de parcours */ - - assert(index < tracker->count); - - portion = &tracker->portions[index]; - - if (!portion->cached) - { - /* Réinitialisation locale */ - - memset(&portion->summary, 0, sizeof(line_width_summary)); - - /* Collecte */ - - for (i = portion->first; i <= portion->last; i++) - g_buffer_cache_collect_widths(tracker->cache, i, &portion->summary); - - /* Marquage pour mémoire */ - - portion->cached = true; - - } - - return &portion->summary; - -} - - -/****************************************************************************** -* * -* Paramètres : tracker = gestionnaire de largeurs de lignes à mettre jour. * -* index = position de la première des lignes à ajouter. * -* * -* Description : Prend acte d'un changement sur une ligne pour les largeurs. * -* * -* Retour : - * -* * -* Remarques : - * -* * -******************************************************************************/ - -void g_width_tracker_update(GWidthTracker *tracker, size_t index) -{ - size_t current; /* Indice de portion visée */ - - current = g_width_tracker_find_metrics(tracker, index); - - g_width_tracker_reset_widths(tracker, current); - -} - - -/****************************************************************************** -* * -* Paramètres : tracker = gestionnaire de largeurs de lignes à mettre jour. * -* index = position de la première des lignes à ajouter. * -* count = quantité de lignes devant être ajoutées. * -* * -* Description : Prend acte de l'ajout de lignes pour les largeurs. * -* * -* Retour : - * -* * -* Remarques : - * -* * -******************************************************************************/ - -void g_width_tracker_update_added(GWidthTracker *tracker, size_t index, size_t count) -{ - size_t current; /* Indice de portion visée */ - common_metrics *portion; /* Portion sélectionnée */ - size_t i; /* Boucle de parcours */ - size_t dest; /* Destination d'une recopie */ - size_t src; /* Source d'une recopie */ - - /* Cas particulier du premier ajout */ - if (tracker->count == 0) - { - assert(index == 0); - - tracker->portions = (common_metrics *)calloc(1, sizeof(common_metrics)); - tracker->count = 1; - - tracker->portions[0].first = 0; - tracker->portions[0].last = count - 1; - - g_width_tracker_reset_widths(tracker, 0); - - return; - - } - - current = g_width_tracker_find_metrics(tracker, index); - - /* Si la ligne est rajoutée en fin d'ensemble */ - if (current == tracker->count) - { - current = tracker->count - 1; - portion = &tracker->portions[current]; - - assert(index == (portion->last + 1)); - - } - else - portion = &tracker->portions[current]; - - portion->last += count; - - g_width_tracker_reset_widths(tracker, current); - - /* Suite impérative : accroître les indices ! */ - - g_width_tracker_update_ranges(tracker, current + 1, count); - - /* Un découpage s'impose-t-il quelque part ? */ - - for (i = index + count - 1; i >= index; i--) - { - if (g_buffer_cache_get_line_flags(tracker->cache, i) & BLF_WIDTH_MANAGER) - { - /* Insertion d'une nouvelle place */ - - tracker->count++; - - tracker->portions = (common_metrics *)realloc(tracker->portions, - tracker->count * sizeof(common_metrics)); - - portion = &tracker->portions[current]; - - dest = current + 2; - src = current + 1; - - if ((tracker->count - src) > 0) - memmove(&tracker->portions[dest], &tracker->portions[src], - (tracker->count - src - 1) * sizeof(common_metrics)); - - /* Insertion au début */ - if (i == portion->first) - { - assert(i == index); - - tracker->portions[current + 1].first = i + 1; - tracker->portions[current + 1].last = portion->last; - - tracker->portions[current + 1].cached = false; - - portion->first = i; - portion->last = i; - - } - - /* Insertion au sein de la portion ou à la fin */ - else - { - tracker->portions[current + 1].first = i; - tracker->portions[current + 1].last = portion->last; - - tracker->portions[current + 1].cached = false; - - portion->last = i - 1; - - } - - assert((tracker->portions[current].last + 1) == tracker->portions[current + 1].first); - - /* Mise à jour des largeurs */ - - g_width_tracker_reset_widths(tracker, current); - - g_width_tracker_reset_widths(tracker, current + 1); - - } - - } - -} - - -/****************************************************************************** -* * -* Paramètres : tracker = gestionnaire de largeurs de lignes à mettre jour. * -* start = première ligne devant être supprimée. * -* end = dernière ligne devant être supprimée. * -* * -* Description : Prend acte de la suppression de lignes pour les largeurs. * -* * -* Retour : - * -* * -* Remarques : - * -* * -******************************************************************************/ - -void g_width_tracker_update_deleted(GWidthTracker *tracker, size_t start, size_t end) -{ - size_t first; /* Première portion concernée */ - size_t last; /* Dernière portion concernée */ - size_t diff; /* Nombre de lignes supprimées */ - bool keep_first; /* Conservation de portion #1 */ - size_t dest; /* Destination du transfert */ - bool keep_last; /* Conservation de portion #2 */ - size_t src; /* Source du transfert */ - size_t update; /* Début de la série en rafale */ - - first = g_width_tracker_find_metrics(tracker, start); - assert(first < tracker->count); - - last = g_width_tracker_find_metrics(tracker, end); - assert(last < tracker->count); - - diff = end - start + 1; - - /* Suppression de portions inutiles ? */ - - keep_first = (tracker->portions[first].first < start); - - dest = (keep_first ? first + 1 : first); - - keep_last = (end < tracker->portions[last].last); - - src = (keep_last ? last : last + 1); - - if (src > dest) - { - if (src < tracker->count) - memmove(&tracker->portions[dest], &tracker->portions[src], - (tracker->count - src) * sizeof(common_metrics)); - - tracker->count -= (src - dest); - - tracker->portions = (common_metrics *)realloc(tracker->portions, - tracker->count * sizeof(common_metrics)); - - } - - /* Si une fusion s'impose */ - - if (keep_first && keep_last && last != first) - { - tracker->portions[first].last = tracker->portions[first + 1].last; - - if ((first - 2) < tracker->count) - memmove(&tracker->portions[first + 1], &tracker->portions[first + 2], - (tracker->count - first - 2) * sizeof(common_metrics)); - - tracker->count--; - - tracker->portions = (common_metrics *)realloc(tracker->portions, - tracker->count * sizeof(common_metrics)); - - keep_last = false; - - } - - /* Avant toute chose : faire décroître les indices ! */ - - if (keep_first && keep_last) - { - tracker->portions[first].last -= diff; - update = first + 1; - } - - else - { - if (keep_first) - { - tracker->portions[first].last = start - 1; - update = first + 1; - } - else - update = first; - - if (keep_last) - tracker->portions[update].first = end + 1; - - } - - g_width_tracker_update_ranges(tracker, update, -diff); - - /* Mise à jour des largeurs aux extrémités */ - - if (keep_first) - g_width_tracker_reset_widths(tracker, first); - - if (keep_last && !keep_first) - g_width_tracker_reset_widths(tracker, update); - -} - - -/****************************************************************************** -* * -* Paramètres : tracker = suivi de largeurs dont le cache est à construire. * -* gid = groupe de travail impliqué. * -* status = barre de statut à tenir informée. * -* * -* Description : Calcule les largeurs requises par un ensemble de lignes. * -* * -* Retour : - * -* * -* Remarques : - * -* * -******************************************************************************/ - -void g_width_tracker_build_initial_cache(GWidthTracker *tracker, wgroup_id_t gid, GtkStatusStack *status) -{ - guint runs_count; /* Qté d'exécutions parallèles */ - GWidthUpdate **updates; /* Mesures à suivre */ - size_t run_size; /* Volume réparti par exécution*/ - GWorkQueue *queue; /* Gestionnaire de différés */ - activity_id_t id; /* Identifiant de progression */ - guint i; /* Boucle de parcours */ - size_t start; /* Début de zone de traitement */ - bool closing; /* Détection de fin en amont */ - size_t end; /* Fin de zone de traitement */ - - assert(!tracker->cached); - - /* Lancement des traitements */ - - run_size = compute_run_size(tracker->count, &runs_count); - - updates = (GWidthUpdate **)calloc(runs_count, sizeof(GWidthUpdate *)); - - queue = get_work_queue(); - - id = gtk_status_stack_add_activity(status, _("Computing width of all lines for rendering"), tracker->count); - - for (i = 0; i < runs_count; i++) - { - start = i * run_size; - - closing = ((i + 1) == runs_count); - - if (closing) - end = tracker->count; - else - end = start + run_size; - - updates[i] = g_width_update_new(id, tracker, start, end); - - g_object_ref(G_OBJECT(updates[i])); - g_work_queue_schedule_work(queue, G_DELAYED_WORK(updates[i]), gid); - - } - - g_work_queue_wait_for_completion(queue, gid); - - /* Récupération des aires */ - - memset(&tracker->summary, 0, sizeof(line_width_summary)); - - for (i = 0; i < runs_count; i++) - { - g_width_update_collect(updates[i], &tracker->summary); - - g_object_unref(G_OBJECT(updates[i])); - - } - - /* Fin */ - - free(updates); - - gtk_status_stack_remove_activity(status, id); - - tracker->cached = true; - -} - - -/****************************************************************************** -* * -* Paramètres : tracker = suivi de largeurs à mettre à jour si besoin est. * -* * -* Description : Calcule les largeurs requises par un ensemble de lignes. * -* * -* Retour : - * -* * -* Remarques : - * -* * -******************************************************************************/ - -static void g_width_tracker_ensure_valid_required_widths(GWidthTracker *tracker) -{ - line_width_summary *global; /* Valeurs collectées */ - size_t i; /* Boucle de parcours #1 */ - const line_width_summary *summary; /* Valeurs à intégrer */ - BufferLineColumn k; /* Boucle de parcours #2 */ - - if (!tracker->cached) - { - global = &tracker->summary; - - /* Réinitialisation */ - - memset(global, 0, sizeof(line_width_summary)); - - /* Collecte */ - - for (i = 0; i < tracker->count; i++) - { - summary = g_width_tracker_get_up_to_date_widths(tracker, i); - - for (k = 0; k < BLC_COUNT; k++) - global->max_widths[k] = MAX(global->max_widths[k], summary->max_widths[k]); - - global->merged_width = MAX(global->merged_width, summary->merged_width); - - } - - tracker->cached = true; - - } - -} - - -/****************************************************************************** -* * -* Paramètres : tracker = suivi de largeurs à consulter. * -* * -* Description : Fournit un bon résumé des largeurs en vigueur. * -* * -* Retour : Ensemble des largeurs collectées. * -* * -* Remarques : - * -* * -******************************************************************************/ - -const line_width_summary *g_width_tracker_get_width_summary(GWidthTracker *tracker) -{ - g_width_tracker_ensure_valid_required_widths(tracker); - - return &tracker->summary; - -} - - -/****************************************************************************** -* * -* Paramètres : tracker = suivi de largeurs à consulter. * -* index = indice de la ligne dont la portion est recherchée. * -* summary = ensemble ciblé de largeurs collectées. [OUT] * -* * -* Description : Fournit un résumé local des largeurs en vigueur. * -* * -* Retour : - * -* * -* Remarques : - * -* * -******************************************************************************/ - -void g_width_tracker_get_local_width_summary(GWidthTracker *tracker, size_t index, line_width_summary *summary) -{ - size_t current; /* Indice de portion visée */ - const line_width_summary *local; /* Valeurs à intégrer */ - BufferLineColumn i; /* Boucle de parcours */ - - g_width_tracker_ensure_valid_required_widths(tracker); - - current = g_width_tracker_find_metrics(tracker, index); - assert(current < tracker->count); - - local = g_width_tracker_get_up_to_date_widths(tracker, current); - - for (i = BLC_FIRST; i < BLC_DISPLAY; i++) - summary->max_widths[i] = tracker->summary.max_widths[i]; - - for (i = BLC_DISPLAY; i < BLC_COUNT; i++) - summary->max_widths[i] = local->max_widths[i]; - - summary->merged_width = local->merged_width; - -} - - -/****************************************************************************** -* * -* Paramètres : tracker = suivi de largeurs à consulter. * -* options = règles d'affichage des colonnes modulables. * -* * -* Description : Fournit la largeur requise par une visualisation. * -* * -* Retour : Dimension calculée. * -* * -* Remarques : - * -* * -******************************************************************************/ - -gint g_width_tracker_get_width(GWidthTracker *tracker, const GDisplayOptions *options) -{ - gint result; /* Taille à retourner */ - const line_width_summary *summary; /* Accès rapide aux mesures */ - gint col_width; /* Calcul selon les colonnes */ - gint full_width; /* Calcul selon les fusions */ - size_t count; /* Qté de colonnes en option */ - size_t i; /* Boucle de parcours */ - - g_width_tracker_ensure_valid_required_widths(tracker); - - result = 0; - - summary = &tracker->summary; - - col_width = 0; - full_width = 0; - - count = g_display_options_count(options); - - /* Première méthode */ - - for (i = 0; i < BLC_COUNT; i++) - { - if (i < count) - { - if (!g_display_options_get(options, i)) - continue; - } - - col_width += summary->max_widths[i]; - - if ((i + 1) < BLC_COUNT) - col_width += COL_MARGIN; - - } - - /* Seconde méthode */ - - for (i = 0; i < count; i++) - { - if (!g_display_options_get(options, i)) - continue; - - full_width += summary->max_widths[i] + COL_MARGIN; - - } - - full_width += summary->merged_width; - - /* Mise en concurrence et poursuite... */ - - result += + MAX(col_width, full_width); - - return result; - -} - - -/****************************************************************************** -* * -* Paramètres : tracker = suivi de largeurs à consulter. * -* display = règles d'affichage des colonnes modulables. * -* * -* Description : Fournit la largeur requise pour dépasser les marges gauches. * -* * -* Retour : Dimension calculée. * -* * -* Remarques : - * -* * -******************************************************************************/ - -gint g_width_tracker_get_margin(GWidthTracker *tracker, const GDisplayOptions *options) -{ - gint result; /* Taille à retourner */ - const line_width_summary *summary; /* Accès rapide aux mesures */ - size_t count; /* Qté de colonnes en option */ - size_t i; /* Boucle de parcours */ - - g_width_tracker_ensure_valid_required_widths(tracker); - - result = 0; - - summary = &tracker->summary; - - count = g_display_options_count(options); - - for (i = 0; i < count; i++) - { - if (!g_display_options_get(options, i)) - continue; - - result += summary->max_widths[i] + COL_MARGIN; - - } - - return result; - -} diff --git a/src/glibext/gwidthtracker.h b/src/glibext/gwidthtracker.h deleted file mode 100644 index 610c736..0000000 --- a/src/glibext/gwidthtracker.h +++ /dev/null @@ -1,95 +0,0 @@ - -/* Chrysalide - Outil d'analyse de fichiers binaires - * gwidthtracker.h - prototypes pour le suivi des largeurs associées à un ensemble de lignes - * - * Copyright (C) 2016-2018 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 . - */ - - -#ifndef _GLIBEXT_GWIDTHTRACKER_H -#define _GLIBEXT_GWIDTHTRACKER_H - - -#include -#include - - -#include "delayed.h" -#include "gbufferline.h" -#include "gdisplayoptions.h" - - - -/* ---------------------------- RASSEMBLEMENT DE MESURES ---------------------------- */ - - -/* gbuffercache.h : Tampon pour gestion de lignes optimisée (instance) */ -typedef struct _GBufferCache GBufferCache; - - -#define G_TYPE_WIDTH_TRACKER (g_width_tracker_get_type()) -#define G_WIDTH_TRACKER(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_WIDTH_TRACKER, GWidthTracker)) -#define G_WIDTH_TRACKER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_WIDTH_TRACKER, GWidthTrackerClass)) -#define G_IS_WIDTH_TRACKER(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_WIDTH_TRACKER)) -#define G_IS_WIDTH_TRACKER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_WIDTH_TRACKER)) -#define G_WIDTH_TRACKER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_WIDTH_TRACKER, GWidthTrackerClass)) - - -/* Gestionnaire de largeurs associées aux lignes (instance) */ -typedef struct _GWidthTracker GWidthTracker; - -/* Gestionnaire de largeurs associées aux lignes (classe) */ -typedef struct _GWidthTrackerClass GWidthTrackerClass; - - -/* Détermine le type du gestionnaire de largeurs associées aux lignes. */ -GType g_width_tracker_get_type(void); - -/* Crée un nouveau suivi de largeurs au sein de lignes. */ -GWidthTracker *g_width_tracker_new(GBufferCache *); - -/* Crée un nouveau suivi de largeurs au sein de lignes. */ -GWidthTracker *g_width_tracker_new_restricted(const GWidthTracker *, size_t, size_t); - -/* Prend acte d'un changement sur une ligne pour les largeurs. */ -void g_width_tracker_update(GWidthTracker *, size_t); - -/* Prend acte de l'ajout de lignes pour les largeurs. */ -void g_width_tracker_update_added(GWidthTracker *, size_t, size_t); - -/* Prend acte de la suppression de lignes pour les largeurs. */ -void g_width_tracker_update_deleted(GWidthTracker *, size_t, size_t); - -/* Calcule les largeurs requises par un ensemble de lignes. */ -void g_width_tracker_build_initial_cache(GWidthTracker *, wgroup_id_t, GtkStatusStack *); - -/* Fournit un bon résumé des largeurs en vigueur. */ -const line_width_summary *g_width_tracker_get_width_summary(GWidthTracker *); - -/* Fournit un résumé local des largeurs en vigueur. */ -void g_width_tracker_get_local_width_summary(GWidthTracker *, size_t, line_width_summary *); - -/* Fournit la largeur requise par une visualisation. */ -gint g_width_tracker_get_width(GWidthTracker *, const GDisplayOptions *); - -/* Fournit la largeur requise pour dépasser les marges gauches. */ -gint g_width_tracker_get_margin(GWidthTracker *, const GDisplayOptions *); - - - -#endif /* _GLIBEXT_GWIDTHTRACKER_H */ diff --git a/src/glibext/linegen.h b/src/glibext/linegen.h index 74a889a..d40a598 100644 --- a/src/glibext/linegen.h +++ b/src/glibext/linegen.h @@ -28,7 +28,7 @@ #include -#include "gbufferline.h" +#include "bufferline.h" #include "glinecursor.h" #include "../analysis/content.h" diff --git a/src/glibext/widthtracker.c b/src/glibext/widthtracker.c new file mode 100644 index 0000000..274b53c --- /dev/null +++ b/src/glibext/widthtracker.c @@ -0,0 +1,1271 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * widthtracker.c - suivi des largeurs associées à un ensemble de lignes + * + * Copyright (C) 2016-2019 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 "widthtracker.h" + + +#include +#include +#include +#include + + +#include + + +#include "buffercache.h" +#include "delayed-int.h" +#include "../core/global.h" +#include "../core/nproc.h" + + + +/* --------------------------- PRISE DE MESURES INITIALES --------------------------- */ + + +/* Procédure de mise à jour des mesures de largeurs (instance) */ +typedef struct _GWidthUpdate +{ + GDelayedWork parent; /* A laisser en premier */ + + activity_id_t id; /* Groupe de progression */ + + GWidthTracker *tracker; /* Gestionnaire à manipuler */ + + size_t start; /* Premier indice à traiter */ + size_t end; /* Premier indice à écarter */ + + line_width_summary summary; /* Largeurs requises suivies */ + +} GWidthUpdate; + +/* Procédure de mise à jour des mesures de largeurs (classe) */ +typedef struct _GWidthUpdateClass +{ + GDelayedWorkClass parent; /* A laisser en premier */ + +} GWidthUpdateClass; + + +#define G_TYPE_WIDTH_UPDATE g_width_update_get_type() +#define G_WIDTH_UPDATE(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_WIDTH_UPDATE, GWidthUpdate)) +#define G_IS_WIDTH_UPDATE(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_WIDTH_UPDATE)) +#define G_WIDTH_UPDATE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_WIDTH_UPDATE, GWidthUpdateClass)) +#define G_IS_WIDTH_UPDATE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_WIDTH_UPDATE)) +#define G_WIDTH_UPDATE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_WIDTH_UPDATE, GWidthUpdateClass)) + + +/* Initialise la classe des tâches de mesures de largeurs. */ +static void g_width_update_class_init(GWidthUpdateClass *); + +/* Initialise une tâche de mesures de largeurs. */ +static void g_width_update_init(GWidthUpdate *); + +/* Supprime toutes les références externes. */ +static void g_width_update_dispose(GWidthUpdate *); + +/* Procède à la libération totale de la mémoire. */ +static void g_width_update_finalize(GWidthUpdate *); + +/* Indique le type défini pour les tâches de mesures de largeurs. */ +GType g_width_update_get_type(void); + +/* Crée une tâche de mesures de largeurs. */ +static GWidthUpdate *g_width_update_new(activity_id_t, GWidthTracker *, size_t, size_t); + +/* Assure les mesures initiales d'un ensemble de lignes. */ +static void g_width_update_process(GWidthUpdate *, GtkStatusStack *); + +/* Récupère les données obtenues lors d'une mesure globale. */ +static void g_width_update_collect(GWidthUpdate *, line_width_summary *); + + + +/* ---------------------------- RASSEMBLEMENT DE MESURES ---------------------------- */ + + +/* Portions de largeurs communes */ +typedef struct _common_metrics +{ + size_t first; /* Premier indice de portion */ + size_t last; /* Dernier indice de portion */ + + line_width_summary summary; /* Compilation de largeurs */ + bool cached; /* Mise en cache des calculs */ + +} common_metrics; + + +/* Gestionnaire de largeurs associées aux lignes (instance) */ +struct _GWidthTracker +{ + GObject parent; /* A laisser en premier */ + + GBufferCache *cache; /* Ensemble complet de lignes */ + + common_metrics *portions; /* Portions représentées */ + size_t count; /* Quantité de ces portions */ + + line_width_summary summary; /* Largeurs requises suivies */ + bool cached; /* Mise en cache des calculs */ + +}; + +/* Gestionnaire de largeurs associées aux lignes (classe) */ +struct _GWidthTrackerClass +{ + GObjectClass parent; /* A laisser en premier */ + +}; + + +/* Procède à l'initialisation d'une classe de suivi de largeurs. */ +static void g_width_tracker_class_init(GWidthTrackerClass *); + +/* Procède à l'initialisation d'un suivi de largeurs de lignes. */ +static void g_width_tracker_init(GWidthTracker *); + +/* Supprime toutes les références externes. */ +static void g_width_tracker_dispose(GWidthTracker *); + +/* Procède à la libération totale de la mémoire. */ +static void g_width_tracker_finalize(GWidthTracker *); + +/* Recherche la portion contenant un indice de ligne donné. */ +static size_t g_width_tracker_find_metrics(const GWidthTracker *, size_t); + +/* Prend en compte une évolution du volume de lignes. */ +static void g_width_tracker_update_ranges(GWidthTracker *, size_t, size_t); + +/* Réinitialise les largeurs requises par une portion de lignes.* */ +static void g_width_tracker_reset_widths(GWidthTracker *, size_t); + +/* Recalcule les largeurs requises par une portion de lignes. */ +static const line_width_summary *g_width_tracker_get_up_to_date_widths(GWidthTracker *, size_t); + +/* Calcule les largeurs requises par un ensemble de lignes. */ +static void g_width_tracker_ensure_valid_required_widths(GWidthTracker *); + + + +/* ---------------------------------------------------------------------------------- */ +/* PRISE DE MESURES INITIALES */ +/* ---------------------------------------------------------------------------------- */ + + +/* Indique le type défini pour les tâches de mesures de largeurs. */ +G_DEFINE_TYPE(GWidthUpdate, g_width_update, G_TYPE_DELAYED_WORK); + + +/****************************************************************************** +* * +* Paramètres : klass = classe à initialiser. * +* * +* Description : Initialise la classe des tâches de mesures de largeurs. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_width_update_class_init(GWidthUpdateClass *klass) +{ + GObjectClass *object; /* Autre version de la classe */ + GDelayedWorkClass *work; /* Version en classe parente */ + + object = G_OBJECT_CLASS(klass); + + object->dispose = (GObjectFinalizeFunc/* ! */)g_width_update_dispose; + object->finalize = (GObjectFinalizeFunc)g_width_update_finalize; + + work = G_DELAYED_WORK_CLASS(klass); + + work->run = (run_task_fc)g_width_update_process; + +} + + +/****************************************************************************** +* * +* Paramètres : update = instance à initialiser. * +* * +* Description : Initialise une tâche de mesures de largeurs. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_width_update_init(GWidthUpdate *update) +{ + memset(&update->summary, 0, sizeof(line_width_summary)); + +} + + +/****************************************************************************** +* * +* Paramètres : update = instance d'objet GLib à traiter. * +* * +* Description : Supprime toutes les références externes. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_width_update_dispose(GWidthUpdate *update) +{ + g_clear_object(&update->tracker); + + G_OBJECT_CLASS(g_width_update_parent_class)->dispose(G_OBJECT(update)); + +} + + +/****************************************************************************** +* * +* Paramètres : update = instance d'objet GLib à traiter. * +* * +* Description : Procède à la libération totale de la mémoire. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_width_update_finalize(GWidthUpdate *update) +{ + G_OBJECT_CLASS(g_width_update_parent_class)->finalize(G_OBJECT(update)); + +} + + +/****************************************************************************** +* * +* Paramètres : id = identifiant pour signaler la progression courante. * +* tracker = gestionnaire de largeurs à consulter. * +* start = indice de la première ligne à traiter. * +* end = indice de la première ligne à éviter. * +* * +* Description : Crée une tâche de mesures de largeurs. * +* * +* Retour : Tâche créée. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static GWidthUpdate *g_width_update_new(activity_id_t id, GWidthTracker *tracker, size_t start, size_t end) +{ + GWidthUpdate *result; /* Tâche à retourner */ + + result = g_object_new(G_TYPE_WIDTH_UPDATE, NULL); + + result->id = id; + + g_object_ref(G_OBJECT(tracker)); + result->tracker = tracker; + + result->start = start; + result->end = end; + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : update = opération de mesures à mener. * +* status = barre de statut à tenir informée. * +* * +* Description : Assure les mesures initiales d'un ensemble de lignes. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_width_update_process(GWidthUpdate *update, GtkStatusStack *status) +{ + line_width_summary *local; /* Valeurs collectées */ + size_t i; /* Boucle de parcours #1 */ + const line_width_summary *summary; /* Valeurs à intégrer */ + BufferLineColumn k; /* Boucle de parcours #2 */ + + local = &update->summary; + + for (i = update->start; i < update->end; i++) + { + summary = g_width_tracker_get_up_to_date_widths(update->tracker, i); + + for (k = 0; k < BLC_COUNT; k++) + local->max_widths[k] = MAX(local->max_widths[k], summary->max_widths[k]); + + local->merged_width = MAX(local->merged_width, summary->merged_width); + + gtk_status_stack_update_activity_value(status, update->id, 1); + + } + +} + + +/****************************************************************************** +* * +* Paramètres : update = opération de mesures menée à bien. * +* global = lieu de centralisation des données globales. * +* * +* Description : Récupère les données obtenues lors d'une mesure globale. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_width_update_collect(GWidthUpdate *update, line_width_summary *global) +{ + line_width_summary *local; /* Valeurs collectées */ + BufferLineColumn i; /* Boucle de parcours */ + + local = &update->summary; + + for (i = 0; i < BLC_COUNT; i++) + global->max_widths[i] = MAX(global->max_widths[i], local->max_widths[i]); + + global->merged_width = MAX(global->merged_width, local->merged_width); + +} + + + +/* ---------------------------------------------------------------------------------- */ +/* RASSEMBLEMENT DE MESURES */ +/* ---------------------------------------------------------------------------------- */ + + +/* Détermine le type du gestionnaire de largeurs associées aux lignes. */ +G_DEFINE_TYPE(GWidthTracker, g_width_tracker, G_TYPE_OBJECT); + + +/****************************************************************************** +* * +* Paramètres : class = classe de composant GTK à initialiser. * +* * +* Description : Procède à l'initialisation d'une classe de suivi de largeurs.* +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_width_tracker_class_init(GWidthTrackerClass *class) +{ + GObjectClass *object; /* Autre version de la classe */ + + object = G_OBJECT_CLASS(class); + + object->dispose = (GObjectFinalizeFunc/* ! */)g_width_tracker_dispose; + object->finalize = (GObjectFinalizeFunc)g_width_tracker_finalize; + +} + + +/****************************************************************************** +* * +* Paramètres : tracker = composant GLib à initialiser. * +* * +* Description : Procède à l'initialisation d'un suivi de largeurs de lignes. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_width_tracker_init(GWidthTracker *tracker) +{ + tracker->portions = NULL; + tracker->count = 0; + + memset(&tracker->summary, 0, sizeof(line_width_summary)); + tracker->cached = false; + +} + + +/****************************************************************************** +* * +* Paramètres : tracker = instance d'objet GLib à traiter. * +* * +* Description : Supprime toutes les références externes. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_width_tracker_dispose(GWidthTracker *tracker) +{ + g_object_unref(G_OBJECT(tracker->cache)); + + G_OBJECT_CLASS(g_width_tracker_parent_class)->dispose(G_OBJECT(tracker)); + +} + + +/****************************************************************************** +* * +* Paramètres : tracker = instance d'objet GLib à traiter. * +* * +* Description : Procède à la libération totale de la mémoire. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_width_tracker_finalize(GWidthTracker *tracker) +{ + G_OBJECT_CLASS(g_width_tracker_parent_class)->finalize(G_OBJECT(tracker)); + +} + + +/****************************************************************************** +* * +* Paramètres : buffer = tampon contenant les lignes à surveiller. * +* first = adresse contenant l'indice de la première ligne. * +* last = adresse contenant l'indice de la dernière ligne. * +* * +* Description : Crée un nouveau suivi de largeurs au sein de lignes. * +* * +* Retour : Composant GLib créé. * +* * +* Remarques : - * +* * +******************************************************************************/ + +GWidthTracker *g_width_tracker_new(GBufferCache *cache) +{ + GWidthTracker *result; /* Composant à retourner */ + + result = g_object_new(G_TYPE_WIDTH_TRACKER, NULL); + + g_object_ref(G_OBJECT(cache)); + result->cache = cache; + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : buffer = tampon contenant les lignes à surveiller. * +* first = indice de la première ligne d'une zone réduite. * +* last = indice de la dernière ligne d'une zone réduite. * +* * +* Description : Crée un nouveau suivi de largeurs au sein de lignes. * +* * +* Retour : Composant GLib créé. * +* * +* Remarques : - * +* * +******************************************************************************/ + +GWidthTracker *g_width_tracker_new_restricted(const GWidthTracker *template, size_t first, size_t last) +{ + GWidthTracker *result; /* Composant à retourner */ + size_t start; /* Début de la zone à copier */ + size_t end; /* Fin de cette même zone */ + size_t i; /* Boucle de parcours */ + + result = g_object_new(G_TYPE_WIDTH_TRACKER, NULL); + + g_object_ref(G_OBJECT(template->cache)); + result->cache = template->cache; + + start = g_width_tracker_find_metrics(template, first); + assert(start < template->count); + + end = g_width_tracker_find_metrics(template, last); + assert(end < template->count); + + result->count = end - start + 1; + result->portions = (common_metrics *)calloc(result->count, sizeof(common_metrics)); + + for (i = 0; i < result->count; i++) + memcpy(&result->portions[i], &template->portions[start + i], sizeof(common_metrics)); + + if (result->portions[0].first != first) + { + result->portions[0].first = first; + g_width_tracker_reset_widths(result, 0); + } + + if (result->portions[result->count - 1].last != last) + { + result->portions[result->count - 1].last = last; + g_width_tracker_reset_widths(result, result->count - 1); + } + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : tracker = gestionnaire de suivi à consulter. * +* index = indice d'une ligne dont la portion est inconnue. * +* * +* Description : Recherche la portion contenant un indice de ligne donné. * +* * +* Retour : Indice de portion trouvée ou le nombre de portions sinon. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static size_t g_width_tracker_find_metrics(const GWidthTracker *tracker, size_t index) +{ + size_t result; /* Indice trouvé à retourner */ + common_metrics *found; /* Portion trouvée ou NULL */ + + int look_for_metrics(const size_t *idx, const common_metrics *m) + { + int status; + + if (*idx < m->first) + status = -1; + + else if (*idx > m->last) + status = 1; + + else + status = 0; + + return status; + + } + + found = bsearch(&index, tracker->portions, tracker->count, + sizeof(common_metrics), (__compar_fn_t)look_for_metrics); + + if (found == NULL) + result = tracker->count; + else + result = found - tracker->portions; + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : tracker = gestionnaire de largeurs de lignes à mettre jour. * +* start = première ligne à traiter. * +* diff = nombre de lignes ajoutées ou supprimées. * +* * +* Description : Prend en compte une évolution du volume de lignes. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_width_tracker_update_ranges(GWidthTracker *tracker, size_t start, size_t diff) +{ + size_t i; /* Boucle de parcours */ + + for (i = start; i < tracker->count; i++) + { +#ifndef NDEBUG + if ((i + 1) < tracker->count) + assert((tracker->portions[i].last + 1) == tracker->portions[i + 1].first); +#endif + + tracker->portions[i].first += diff; + tracker->portions[i].last += diff; + + } + +} + + +/****************************************************************************** +* * +* Paramètres : tracker = gestionnaire de largeurs de lignes à mettre jour. * +* index = indice de portion à marquer pour réinitialisation. * +* * +* Description : Réinitialise les largeurs requises par une portion de lignes.* +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_width_tracker_reset_widths(GWidthTracker *tracker, size_t index) +{ + common_metrics *portion; /* Portion à actualiser */ + BufferLineColumn k; /* Boucle de parcours */ + + assert(index < tracker->count); + + portion = &tracker->portions[index]; + + /* Réinitialisation globale ? */ + + if (portion->cached) + { + for (k = 0; k < BLC_COUNT && tracker->cached; k++) + tracker->cached &= (tracker->summary.max_widths[k] != portion->summary.max_widths[k]); + + tracker->cached &= (tracker->summary.merged_width != portion->summary.merged_width); + + } + + /* Réinitialisation locale */ + + portion->cached = false; + +} + + +/****************************************************************************** +* * +* Paramètres : tracker = gestionnaire de largeurs de lignes à mettre jour. * +* index = indice de la portion à rafraîchir. * +* * +* Description : Recalcule les largeurs requises par une portion de lignes. * +* * +* Retour : Accès en lecture seule au résumé à jour. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static const line_width_summary *g_width_tracker_get_up_to_date_widths(GWidthTracker *tracker, size_t index) +{ + common_metrics *portion; /* Portion à actualiser */ + size_t i; /* Boucle de parcours */ + + assert(index < tracker->count); + + portion = &tracker->portions[index]; + + if (!portion->cached) + { + /* Réinitialisation locale */ + + memset(&portion->summary, 0, sizeof(line_width_summary)); + + /* Collecte */ + + for (i = portion->first; i <= portion->last; i++) + g_buffer_cache_collect_widths(tracker->cache, i, &portion->summary); + + /* Marquage pour mémoire */ + + portion->cached = true; + + } + + return &portion->summary; + +} + + +/****************************************************************************** +* * +* Paramètres : tracker = gestionnaire de largeurs de lignes à mettre jour. * +* index = position de la première des lignes à ajouter. * +* * +* Description : Prend acte d'un changement sur une ligne pour les largeurs. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +void g_width_tracker_update(GWidthTracker *tracker, size_t index) +{ + size_t current; /* Indice de portion visée */ + + current = g_width_tracker_find_metrics(tracker, index); + + g_width_tracker_reset_widths(tracker, current); + +} + + +/****************************************************************************** +* * +* Paramètres : tracker = gestionnaire de largeurs de lignes à mettre jour. * +* index = position de la première des lignes à ajouter. * +* count = quantité de lignes devant être ajoutées. * +* * +* Description : Prend acte de l'ajout de lignes pour les largeurs. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +void g_width_tracker_update_added(GWidthTracker *tracker, size_t index, size_t count) +{ + size_t current; /* Indice de portion visée */ + common_metrics *portion; /* Portion sélectionnée */ + size_t i; /* Boucle de parcours */ + size_t dest; /* Destination d'une recopie */ + size_t src; /* Source d'une recopie */ + + /* Cas particulier du premier ajout */ + if (tracker->count == 0) + { + assert(index == 0); + + tracker->portions = (common_metrics *)calloc(1, sizeof(common_metrics)); + tracker->count = 1; + + tracker->portions[0].first = 0; + tracker->portions[0].last = count - 1; + + g_width_tracker_reset_widths(tracker, 0); + + return; + + } + + current = g_width_tracker_find_metrics(tracker, index); + + /* Si la ligne est rajoutée en fin d'ensemble */ + if (current == tracker->count) + { + current = tracker->count - 1; + portion = &tracker->portions[current]; + + assert(index == (portion->last + 1)); + + } + else + portion = &tracker->portions[current]; + + portion->last += count; + + g_width_tracker_reset_widths(tracker, current); + + /* Suite impérative : accroître les indices ! */ + + g_width_tracker_update_ranges(tracker, current + 1, count); + + /* Un découpage s'impose-t-il quelque part ? */ + + for (i = index + count - 1; i >= index; i--) + { + if (g_buffer_cache_get_line_flags(tracker->cache, i) & BLF_WIDTH_MANAGER) + { + /* Insertion d'une nouvelle place */ + + tracker->count++; + + tracker->portions = (common_metrics *)realloc(tracker->portions, + tracker->count * sizeof(common_metrics)); + + portion = &tracker->portions[current]; + + dest = current + 2; + src = current + 1; + + if ((tracker->count - src) > 0) + memmove(&tracker->portions[dest], &tracker->portions[src], + (tracker->count - src - 1) * sizeof(common_metrics)); + + /* Insertion au début */ + if (i == portion->first) + { + assert(i == index); + + tracker->portions[current + 1].first = i + 1; + tracker->portions[current + 1].last = portion->last; + + tracker->portions[current + 1].cached = false; + + portion->first = i; + portion->last = i; + + } + + /* Insertion au sein de la portion ou à la fin */ + else + { + tracker->portions[current + 1].first = i; + tracker->portions[current + 1].last = portion->last; + + tracker->portions[current + 1].cached = false; + + portion->last = i - 1; + + } + + assert((tracker->portions[current].last + 1) == tracker->portions[current + 1].first); + + /* Mise à jour des largeurs */ + + g_width_tracker_reset_widths(tracker, current); + + g_width_tracker_reset_widths(tracker, current + 1); + + } + + } + +} + + +/****************************************************************************** +* * +* Paramètres : tracker = gestionnaire de largeurs de lignes à mettre jour. * +* start = première ligne devant être supprimée. * +* end = dernière ligne devant être supprimée. * +* * +* Description : Prend acte de la suppression de lignes pour les largeurs. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +void g_width_tracker_update_deleted(GWidthTracker *tracker, size_t start, size_t end) +{ + size_t first; /* Première portion concernée */ + size_t last; /* Dernière portion concernée */ + size_t diff; /* Nombre de lignes supprimées */ + bool keep_first; /* Conservation de portion #1 */ + size_t dest; /* Destination du transfert */ + bool keep_last; /* Conservation de portion #2 */ + size_t src; /* Source du transfert */ + size_t update; /* Début de la série en rafale */ + + first = g_width_tracker_find_metrics(tracker, start); + assert(first < tracker->count); + + last = g_width_tracker_find_metrics(tracker, end); + assert(last < tracker->count); + + diff = end - start + 1; + + /* Suppression de portions inutiles ? */ + + keep_first = (tracker->portions[first].first < start); + + dest = (keep_first ? first + 1 : first); + + keep_last = (end < tracker->portions[last].last); + + src = (keep_last ? last : last + 1); + + if (src > dest) + { + if (src < tracker->count) + memmove(&tracker->portions[dest], &tracker->portions[src], + (tracker->count - src) * sizeof(common_metrics)); + + tracker->count -= (src - dest); + + tracker->portions = (common_metrics *)realloc(tracker->portions, + tracker->count * sizeof(common_metrics)); + + } + + /* Si une fusion s'impose */ + + if (keep_first && keep_last && last != first) + { + tracker->portions[first].last = tracker->portions[first + 1].last; + + if ((first - 2) < tracker->count) + memmove(&tracker->portions[first + 1], &tracker->portions[first + 2], + (tracker->count - first - 2) * sizeof(common_metrics)); + + tracker->count--; + + tracker->portions = (common_metrics *)realloc(tracker->portions, + tracker->count * sizeof(common_metrics)); + + keep_last = false; + + } + + /* Avant toute chose : faire décroître les indices ! */ + + if (keep_first && keep_last) + { + tracker->portions[first].last -= diff; + update = first + 1; + } + + else + { + if (keep_first) + { + tracker->portions[first].last = start - 1; + update = first + 1; + } + else + update = first; + + if (keep_last) + tracker->portions[update].first = end + 1; + + } + + g_width_tracker_update_ranges(tracker, update, -diff); + + /* Mise à jour des largeurs aux extrémités */ + + if (keep_first) + g_width_tracker_reset_widths(tracker, first); + + if (keep_last && !keep_first) + g_width_tracker_reset_widths(tracker, update); + +} + + +/****************************************************************************** +* * +* Paramètres : tracker = suivi de largeurs dont le cache est à construire. * +* gid = groupe de travail impliqué. * +* status = barre de statut à tenir informée. * +* * +* Description : Calcule les largeurs requises par un ensemble de lignes. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +void g_width_tracker_build_initial_cache(GWidthTracker *tracker, wgroup_id_t gid, GtkStatusStack *status) +{ + guint runs_count; /* Qté d'exécutions parallèles */ + GWidthUpdate **updates; /* Mesures à suivre */ + size_t run_size; /* Volume réparti par exécution*/ + GWorkQueue *queue; /* Gestionnaire de différés */ + activity_id_t id; /* Identifiant de progression */ + guint i; /* Boucle de parcours */ + size_t start; /* Début de zone de traitement */ + bool closing; /* Détection de fin en amont */ + size_t end; /* Fin de zone de traitement */ + + assert(!tracker->cached); + + /* Lancement des traitements */ + + run_size = compute_run_size(tracker->count, &runs_count); + + updates = (GWidthUpdate **)calloc(runs_count, sizeof(GWidthUpdate *)); + + queue = get_work_queue(); + + id = gtk_status_stack_add_activity(status, _("Computing width of all lines for rendering"), tracker->count); + + for (i = 0; i < runs_count; i++) + { + start = i * run_size; + + closing = ((i + 1) == runs_count); + + if (closing) + end = tracker->count; + else + end = start + run_size; + + updates[i] = g_width_update_new(id, tracker, start, end); + + g_object_ref(G_OBJECT(updates[i])); + g_work_queue_schedule_work(queue, G_DELAYED_WORK(updates[i]), gid); + + } + + g_work_queue_wait_for_completion(queue, gid); + + /* Récupération des aires */ + + memset(&tracker->summary, 0, sizeof(line_width_summary)); + + for (i = 0; i < runs_count; i++) + { + g_width_update_collect(updates[i], &tracker->summary); + + g_object_unref(G_OBJECT(updates[i])); + + } + + /* Fin */ + + free(updates); + + gtk_status_stack_remove_activity(status, id); + + tracker->cached = true; + +} + + +/****************************************************************************** +* * +* Paramètres : tracker = suivi de largeurs à mettre à jour si besoin est. * +* * +* Description : Calcule les largeurs requises par un ensemble de lignes. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_width_tracker_ensure_valid_required_widths(GWidthTracker *tracker) +{ + line_width_summary *global; /* Valeurs collectées */ + size_t i; /* Boucle de parcours #1 */ + const line_width_summary *summary; /* Valeurs à intégrer */ + BufferLineColumn k; /* Boucle de parcours #2 */ + + if (!tracker->cached) + { + global = &tracker->summary; + + /* Réinitialisation */ + + memset(global, 0, sizeof(line_width_summary)); + + /* Collecte */ + + for (i = 0; i < tracker->count; i++) + { + summary = g_width_tracker_get_up_to_date_widths(tracker, i); + + for (k = 0; k < BLC_COUNT; k++) + global->max_widths[k] = MAX(global->max_widths[k], summary->max_widths[k]); + + global->merged_width = MAX(global->merged_width, summary->merged_width); + + } + + tracker->cached = true; + + } + +} + + +/****************************************************************************** +* * +* Paramètres : tracker = suivi de largeurs à consulter. * +* * +* Description : Fournit un bon résumé des largeurs en vigueur. * +* * +* Retour : Ensemble des largeurs collectées. * +* * +* Remarques : - * +* * +******************************************************************************/ + +const line_width_summary *g_width_tracker_get_width_summary(GWidthTracker *tracker) +{ + g_width_tracker_ensure_valid_required_widths(tracker); + + return &tracker->summary; + +} + + +/****************************************************************************** +* * +* Paramètres : tracker = suivi de largeurs à consulter. * +* index = indice de la ligne dont la portion est recherchée. * +* summary = ensemble ciblé de largeurs collectées. [OUT] * +* * +* Description : Fournit un résumé local des largeurs en vigueur. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +void g_width_tracker_get_local_width_summary(GWidthTracker *tracker, size_t index, line_width_summary *summary) +{ + size_t current; /* Indice de portion visée */ + const line_width_summary *local; /* Valeurs à intégrer */ + BufferLineColumn i; /* Boucle de parcours */ + + g_width_tracker_ensure_valid_required_widths(tracker); + + current = g_width_tracker_find_metrics(tracker, index); + assert(current < tracker->count); + + local = g_width_tracker_get_up_to_date_widths(tracker, current); + + for (i = BLC_FIRST; i < BLC_DISPLAY; i++) + summary->max_widths[i] = tracker->summary.max_widths[i]; + + for (i = BLC_DISPLAY; i < BLC_COUNT; i++) + summary->max_widths[i] = local->max_widths[i]; + + summary->merged_width = local->merged_width; + +} + + +/****************************************************************************** +* * +* Paramètres : tracker = suivi de largeurs à consulter. * +* options = règles d'affichage des colonnes modulables. * +* * +* Description : Fournit la largeur requise par une visualisation. * +* * +* Retour : Dimension calculée. * +* * +* Remarques : - * +* * +******************************************************************************/ + +gint g_width_tracker_get_width(GWidthTracker *tracker, const GDisplayOptions *options) +{ + gint result; /* Taille à retourner */ + const line_width_summary *summary; /* Accès rapide aux mesures */ + gint col_width; /* Calcul selon les colonnes */ + gint full_width; /* Calcul selon les fusions */ + size_t count; /* Qté de colonnes en option */ + size_t i; /* Boucle de parcours */ + + g_width_tracker_ensure_valid_required_widths(tracker); + + result = 0; + + summary = &tracker->summary; + + col_width = 0; + full_width = 0; + + count = g_display_options_count(options); + + /* Première méthode */ + + for (i = 0; i < BLC_COUNT; i++) + { + if (i < count) + { + if (!g_display_options_get(options, i)) + continue; + } + + col_width += summary->max_widths[i]; + + if ((i + 1) < BLC_COUNT) + col_width += COL_MARGIN; + + } + + /* Seconde méthode */ + + for (i = 0; i < count; i++) + { + if (!g_display_options_get(options, i)) + continue; + + full_width += summary->max_widths[i] + COL_MARGIN; + + } + + full_width += summary->merged_width; + + /* Mise en concurrence et poursuite... */ + + result += + MAX(col_width, full_width); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : tracker = suivi de largeurs à consulter. * +* display = règles d'affichage des colonnes modulables. * +* * +* Description : Fournit la largeur requise pour dépasser les marges gauches. * +* * +* Retour : Dimension calculée. * +* * +* Remarques : - * +* * +******************************************************************************/ + +gint g_width_tracker_get_margin(GWidthTracker *tracker, const GDisplayOptions *options) +{ + gint result; /* Taille à retourner */ + const line_width_summary *summary; /* Accès rapide aux mesures */ + size_t count; /* Qté de colonnes en option */ + size_t i; /* Boucle de parcours */ + + g_width_tracker_ensure_valid_required_widths(tracker); + + result = 0; + + summary = &tracker->summary; + + count = g_display_options_count(options); + + for (i = 0; i < count; i++) + { + if (!g_display_options_get(options, i)) + continue; + + result += summary->max_widths[i] + COL_MARGIN; + + } + + return result; + +} diff --git a/src/glibext/widthtracker.h b/src/glibext/widthtracker.h new file mode 100644 index 0000000..b7bb8a4 --- /dev/null +++ b/src/glibext/widthtracker.h @@ -0,0 +1,95 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * widthtracker.h - prototypes pour le suivi des largeurs associées à un ensemble de lignes + * + * Copyright (C) 2016-2018 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 . + */ + + +#ifndef _GLIBEXT_WIDTHTRACKER_H +#define _GLIBEXT_WIDTHTRACKER_H + + +#include +#include + + +#include "bufferline.h" +#include "delayed.h" +#include "gdisplayoptions.h" + + + +/* ---------------------------- RASSEMBLEMENT DE MESURES ---------------------------- */ + + +/* gbuffercache.h : Tampon pour gestion de lignes optimisée (instance) */ +typedef struct _GBufferCache GBufferCache; + + +#define G_TYPE_WIDTH_TRACKER (g_width_tracker_get_type()) +#define G_WIDTH_TRACKER(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_WIDTH_TRACKER, GWidthTracker)) +#define G_WIDTH_TRACKER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_WIDTH_TRACKER, GWidthTrackerClass)) +#define G_IS_WIDTH_TRACKER(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_WIDTH_TRACKER)) +#define G_IS_WIDTH_TRACKER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_WIDTH_TRACKER)) +#define G_WIDTH_TRACKER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_WIDTH_TRACKER, GWidthTrackerClass)) + + +/* Gestionnaire de largeurs associées aux lignes (instance) */ +typedef struct _GWidthTracker GWidthTracker; + +/* Gestionnaire de largeurs associées aux lignes (classe) */ +typedef struct _GWidthTrackerClass GWidthTrackerClass; + + +/* Détermine le type du gestionnaire de largeurs associées aux lignes. */ +GType g_width_tracker_get_type(void); + +/* Crée un nouveau suivi de largeurs au sein de lignes. */ +GWidthTracker *g_width_tracker_new(GBufferCache *); + +/* Crée un nouveau suivi de largeurs au sein de lignes. */ +GWidthTracker *g_width_tracker_new_restricted(const GWidthTracker *, size_t, size_t); + +/* Prend acte d'un changement sur une ligne pour les largeurs. */ +void g_width_tracker_update(GWidthTracker *, size_t); + +/* Prend acte de l'ajout de lignes pour les largeurs. */ +void g_width_tracker_update_added(GWidthTracker *, size_t, size_t); + +/* Prend acte de la suppression de lignes pour les largeurs. */ +void g_width_tracker_update_deleted(GWidthTracker *, size_t, size_t); + +/* Calcule les largeurs requises par un ensemble de lignes. */ +void g_width_tracker_build_initial_cache(GWidthTracker *, wgroup_id_t, GtkStatusStack *); + +/* Fournit un bon résumé des largeurs en vigueur. */ +const line_width_summary *g_width_tracker_get_width_summary(GWidthTracker *); + +/* Fournit un résumé local des largeurs en vigueur. */ +void g_width_tracker_get_local_width_summary(GWidthTracker *, size_t, line_width_summary *); + +/* Fournit la largeur requise par une visualisation. */ +gint g_width_tracker_get_width(GWidthTracker *, const GDisplayOptions *); + +/* Fournit la largeur requise pour dépasser les marges gauches. */ +gint g_width_tracker_get_margin(GWidthTracker *, const GDisplayOptions *); + + + +#endif /* _GLIBEXT_WIDTHTRACKER_H */ diff --git a/src/gtkext/gtkblockdisplay.h b/src/gtkext/gtkblockdisplay.h index 2b523c4..2effb9b 100644 --- a/src/gtkext/gtkblockdisplay.h +++ b/src/gtkext/gtkblockdisplay.h @@ -29,7 +29,7 @@ #include -#include "../glibext/gbufferview.h" +#include "../glibext/bufferview.h" diff --git a/src/gtkext/gtkbufferdisplay.h b/src/gtkext/gtkbufferdisplay.h index 2aec5a8..8f2d63c 100644 --- a/src/gtkext/gtkbufferdisplay.h +++ b/src/gtkext/gtkbufferdisplay.h @@ -29,7 +29,7 @@ #include -#include "../glibext/gbufferview.h" +#include "../glibext/bufferview.h" -- cgit v0.11.2-87-g4458