From e59544bb61b0043d82946918ece144cae2749d53 Mon Sep 17 00:00:00 2001
From: Cyrille Bagard <nocbos@gmail.com>
Date: Mon, 6 Aug 2018 19:38:09 +0200
Subject: Fixed many bugs in the code cache and the width tracker objects.

---
 src/analysis/db/items/comment.c |  36 +++++++-------
 src/glibext/gbuffercache.c      | 102 ++++++++++++++++++++++++++++++----------
 src/glibext/gbuffercache.h      |   5 +-
 src/glibext/gwidthtracker.c     |  67 +++++++++++++++-----------
 4 files changed, 138 insertions(+), 72 deletions(-)

diff --git a/src/analysis/db/items/comment.c b/src/analysis/db/items/comment.c
index 8155fc5..b879d08 100644
--- a/src/analysis/db/items/comment.c
+++ b/src/analysis/db/items/comment.c
@@ -654,24 +654,24 @@ static bool g_db_comment_run(GDbComment *comment, GLoadedBinary *binary, bool ap
     if (comment->inlined)
     {
 
-#define RUN_INLINED_COMMENT(idx, new, old)                                                      \
-        if (apply)                                                                              \
-        {                                                                                       \
-            old = g_buffer_cache_delete_type_at(cache, idx, G_TYPE_DB_COMMENT, false, false);   \
-                                                                                                \
-            g_buffer_cache_insert_at(cache, idx, G_LINE_GENERATOR(new), false, false);          \
-                                                                                                \
-        }                                                                                       \
-        else                                                                                    \
-        {                                                                                       \
-            g_buffer_cache_delete_type_at(cache, idx, G_TYPE_DB_COMMENT, false, false);         \
-                                                                                                \
-            if (old != NULL)                                                                    \
-            {                                                                                   \
-                g_buffer_cache_insert_at(cache, idx, old, false, false);                        \
-                g_object_unref(G_OBJECT(old));                                                  \
-            }                                                                                   \
-                                                                                                \
+#define RUN_INLINED_COMMENT(idx, new, old)                                                          \
+        if (apply)                                                                                  \
+        {                                                                                           \
+            old = g_buffer_cache_delete_type_at(cache, idx, G_TYPE_DB_COMMENT, false, false);       \
+                                                                                                    \
+            g_buffer_cache_insert_at(cache, idx, G_LINE_GENERATOR(new), BLF_NONE, false, false);    \
+                                                                                                    \
+        }                                                                                           \
+        else                                                                                        \
+        {                                                                                           \
+            g_buffer_cache_delete_type_at(cache, idx, G_TYPE_DB_COMMENT, false, false);             \
+                                                                                                    \
+            if (old != NULL)                                                                        \
+            {                                                                                       \
+                g_buffer_cache_insert_at(cache, idx, old, BLF_NONE, false, false);                  \
+                g_object_unref(G_OBJECT(old));                                                      \
+            }                                                                                       \
+                                                                                                    \
         }
 
         /* Commentaire principal */
diff --git a/src/glibext/gbuffercache.c b/src/glibext/gbuffercache.c
index 7293e7c..866d696 100644
--- a/src/glibext/gbuffercache.c
+++ b/src/glibext/gbuffercache.c
@@ -72,7 +72,7 @@ static void init_cache_info(cache_info *, GLineGenerator *, size_t, BufferLineFl
 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 *);
+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 *);
@@ -217,6 +217,7 @@ static void release_cache_info(cache_info *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.         *
 *                                                                             *
@@ -226,7 +227,7 @@ static void release_cache_info(cache_info *info)
 *                                                                             *
 ******************************************************************************/
 
-static void extend_cache_info(cache_info *info, GLineGenerator *generator)
+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é    */
@@ -259,6 +260,17 @@ static void extend_cache_info(cache_info *info, GLineGenerator *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);
+
 }
 
 
@@ -319,6 +331,8 @@ static void remove_from_cache_info(cache_info *info, GLineGenerator *generator)
                     info->generators = (generator_link *)realloc(info->generators,
                                                                  --info->count * sizeof(generator_link));
 
+                g_object_unref(G_OBJECT(generator));
+
                 break;
 
             }
@@ -592,7 +606,7 @@ static void g_buffer_cache_init(GBufferCache *cache)
 static void g_buffer_cache_dispose(GBufferCache *cache)
 {
     size_t i;                               /* Boucle de parcours #1       */
-    cache_info *info;                       /* Accès directe à une ligne   */
+    cache_info *info;                       /* Accès direct à une ligne    */
     size_t j;                               /* Boucle de parcours #2       */
 
     if (cache->content != NULL)
@@ -636,7 +650,7 @@ static void g_buffer_cache_dispose(GBufferCache *cache)
 static void g_buffer_cache_finalize(GBufferCache *cache)
 {
     size_t i;                               /* Boucle de parcours          */
-    cache_info *info;                       /* Accès directe à une ligne   */
+    cache_info *info;                       /* Accès direct à une ligne    */
 
     for (i = 0; i < cache->used; i++)
     {
@@ -817,7 +831,7 @@ GWidthTracker *g_buffer_cache_get_width_tracker(const GBufferCache *cache)
 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 directe à une ligne   */
+    cache_info *info;                       /* Accès direct à une ligne    */
     size_t i;                               /* Boucle de parcours          */
 
     result = 0;
@@ -853,6 +867,7 @@ static size_t g_buffer_cache_compute_repetition(GBufferCache *cache, size_t inde
 *  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.*
 *                                                                             *
@@ -864,7 +879,7 @@ static size_t g_buffer_cache_compute_repetition(GBufferCache *cache, size_t inde
 *                                                                             *
 ******************************************************************************/
 
-void g_buffer_cache_insert_at(GBufferCache *cache, size_t index, GLineGenerator *generator, bool before, bool after)
+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      */
@@ -880,26 +895,27 @@ void g_buffer_cache_insert_at(GBufferCache *cache, size_t index, GLineGenerator
 
 #ifndef NDEBUG
 
-    g_line_generator_compute_cursor(generator, 0, index, 0, &gen_cursor);
+    if (!before && !after)
+    {
+        g_line_generator_compute_cursor(generator, 0, index, 0, &gen_cursor);
 
-    get_cache_info_cursor(&cache->lines[index], index, 0, &line_cursor);
+        get_cache_info_cursor(&cache->lines[index], index, 0, &line_cursor);
 
-    ret = g_line_cursor_compare(gen_cursor, line_cursor);
+        ret = g_line_cursor_compare(gen_cursor, line_cursor);
 
-    g_object_unref(G_OBJECT(gen_cursor));
-    g_object_unref(G_OBJECT(line_cursor));
+        g_object_unref(G_OBJECT(gen_cursor));
+        g_object_unref(G_OBJECT(line_cursor));
 
-    ///////////////////////////////////////
-    if (ret != 0) return;
+        assert(ret == 0);
 
-    assert(ret == 0);
+    }
 
 #endif
 
     /* Cas particulier d'ajout en fin de cache... */
     if (after && (index + 1) == cache->used)
     {
-        g_buffer_cache_append(cache, generator, BLF_NONE);
+        g_buffer_cache_append(cache, generator, flags);
         goto gbcia_done;
     }
 
@@ -932,10 +948,10 @@ void g_buffer_cache_insert_at(GBufferCache *cache, size_t index, GLineGenerator
 
     if (before || after)
     {
-        memmove(&cache->lines[index], &cache->lines[index + needed], (cache->used - index) * sizeof(cache_info));
+        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, BLF_NONE);
+            init_cache_info(&cache->lines[index + i], generator, i, flags);
 
         cache->used += needed;
 
@@ -947,7 +963,7 @@ void g_buffer_cache_insert_at(GBufferCache *cache, size_t index, GLineGenerator
 
     else
     {
-        extend_cache_info(&cache->lines[index], generator);
+        extend_cache_info(&cache->lines[index], generator, flags);
 
         g_width_tracker_update(cache->tracker, index);
 
@@ -980,6 +996,42 @@ void g_buffer_cache_insert_at(GBufferCache *cache, size_t index, GLineGenerator
 
 /******************************************************************************
 *                                                                             *
+*  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.    *
@@ -997,7 +1049,7 @@ void g_buffer_cache_insert_at(GBufferCache *cache, size_t index, GLineGenerator
 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 directe à une ligne   */
+    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        */
@@ -1122,7 +1174,7 @@ void g_buffer_cache_append(GBufferCache *cache, GLineGenerator *generator, Buffe
     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 directe à une ligne   */
+    cache_info *info;                       /* Accès direct à une ligne    */
 
     count = g_line_generator_count_lines(generator);
 
@@ -1157,8 +1209,6 @@ void g_buffer_cache_append(GBufferCache *cache, GLineGenerator *generator, Buffe
 
     cache->used += count;
 
-    g_object_unref(G_OBJECT(generator));
-
     g_width_tracker_update_added(cache->tracker, index, count);
 
     g_signal_emit_by_name(cache, "size-changed", true, index, count);
@@ -1184,7 +1234,7 @@ void g_buffer_cache_extend_with(GBufferCache *cache, size_t count, GLineGenerato
 {
     size_t index;                           /* Point d'insertion           */
     size_t i;                               /* Boucle de parcours          */
-    cache_info *info;                       /* Accès directe à une ligne   */
+    cache_info *info;                       /* Accès direct à une ligne    */
     size_t added;                           /* Nombre d'ajouts effectués   */
 
     assert(count >= cache->used);
@@ -1245,7 +1295,7 @@ void g_buffer_cache_extend_with(GBufferCache *cache, size_t count, GLineGenerato
 void g_buffer_cache_truncate(GBufferCache *cache, size_t max)
 {
     size_t i;                               /* Boucle de parcours #1       */
-    cache_info *info;                       /* Accès directe à une ligne   */
+    cache_info *info;                       /* Accès direct à une ligne    */
     size_t j;                               /* Boucle de parcours #2       */
     size_t removed;                         /* Nombre de retraits effectués*/
 
@@ -1326,7 +1376,7 @@ void g_buffer_cache_get_line_cursor(const GBufferCache *cache, size_t index, gin
 BufferLineFlags g_buffer_cache_get_line_flags(const GBufferCache *cache, size_t index)
 {
     BufferLineFlags result;                 /* Somme à renvoyer            */
-    cache_info *info;                       /* Accès directe à une ligne   */
+    cache_info *info;                       /* Accès direct à une ligne    */
     const generator_link *generator;        /* Générateur retenu           */
     size_t i;                               /* Boucle de parcours          */
 
@@ -1433,7 +1483,7 @@ void g_buffer_cache_draw(const GBufferCache *cache, cairo_t *cr, size_t first, s
     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 directe à une ligne   */
+    cache_info *info;                       /* Accès direct à une ligne    */
     line_width_summary summary;             /* Résumé concis des largeurs  */
     GBufferLine *line;                      /* Ligne à venir dessiner      */
 
diff --git a/src/glibext/gbuffercache.h b/src/glibext/gbuffercache.h
index 7a0d250..077c5f9 100644
--- a/src/glibext/gbuffercache.h
+++ b/src/glibext/gbuffercache.h
@@ -76,7 +76,10 @@ size_t g_buffer_cache_count_lines(const GBufferCache *);
 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 *, bool, bool);
+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);
diff --git a/src/glibext/gwidthtracker.c b/src/glibext/gwidthtracker.c
index 44a7ff0..e116a85 100644
--- a/src/glibext/gwidthtracker.c
+++ b/src/glibext/gwidthtracker.c
@@ -613,8 +613,14 @@ static void g_width_tracker_update_ranges(GWidthTracker *tracker, size_t start,
 
     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;
+
     }
 
 }
@@ -746,7 +752,6 @@ void g_width_tracker_update_added(GWidthTracker *tracker, size_t index, size_t c
 {
     size_t current;                         /* Indice de portion visée     */
     common_metrics *portion;                /* Portion sélectionnée        */
-    size_t next;                            /* Prochaine portion à décaller*/
     size_t i;                               /* Boucle de parcours          */
     size_t dest;                            /* Destination d'une recopie   */
     size_t src;                             /* Source d'une recopie        */
@@ -786,7 +791,9 @@ void g_width_tracker_update_added(GWidthTracker *tracker, size_t index, size_t c
 
     g_width_tracker_reset_widths(tracker, current);
 
-    next = current + 1;
+    /* 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 ? */
 
@@ -810,14 +817,12 @@ void g_width_tracker_update_added(GWidthTracker *tracker, size_t index, size_t c
                 memmove(&tracker->portions[dest], &tracker->portions[src],
                         (tracker->count - src - 1) * sizeof(common_metrics));
 
-            next++;
-
             /* Insertion au début */
             if (i == portion->first)
             {
                 assert(i == index);
 
-                tracker->portions[current + 1].first = portion->first + 1;
+                tracker->portions[current + 1].first = i + 1;
                 tracker->portions[current + 1].last = portion->last;
 
                 tracker->portions[current + 1].cached = false;
@@ -839,6 +844,8 @@ void g_width_tracker_update_added(GWidthTracker *tracker, size_t index, size_t c
 
             }
 
+            assert((tracker->portions[current].last + 1) == tracker->portions[current + 1].first);
+
             /* Mise à jour des largeurs */
 
             g_width_tracker_reset_widths(tracker, current);
@@ -849,10 +856,6 @@ void g_width_tracker_update_added(GWidthTracker *tracker, size_t index, size_t c
 
     }
 
-    /* Suite impérative : accroître les indices ! */
-
-    g_width_tracker_update_ranges(tracker, next, 1);
-
 }
 
 
@@ -879,6 +882,7 @@ void g_width_tracker_update_deleted(GWidthTracker *tracker, size_t start, size_t
     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);
@@ -890,18 +894,19 @@ void g_width_tracker_update_deleted(GWidthTracker *tracker, size_t start, size_t
 
     /* Suppression de portions inutiles ? */
 
-    keep_first = (tracker->portions[first].first < start || end < tracker->portions[first].last);
+    keep_first = (tracker->portions[first].first < start);
 
     dest = (keep_first ? first + 1 : first);
 
-    keep_last = (tracker->portions[last].first < start || end < tracker->portions[last].last);
+    keep_last = (end < tracker->portions[last].last);
 
     src = (keep_last ? last : last + 1);
 
     if (src > dest)
     {
-        memmove(&tracker->portions[dest], &tracker->portions[src],
-                (tracker->count - src) * sizeof(common_metrics));
+        if (src < tracker->count)
+            memmove(&tracker->portions[dest], &tracker->portions[src],
+                    (tracker->count - src) * sizeof(common_metrics));
 
         tracker->count -= (src - dest);
 
@@ -914,10 +919,11 @@ void g_width_tracker_update_deleted(GWidthTracker *tracker, size_t start, size_t
 
     if (keep_first && keep_last && last != first)
     {
-        tracker->portions[first].last = tracker->portions[dest].last;
+        tracker->portions[first].last = tracker->portions[first + 1].last;
 
-        memmove(&tracker->portions[first + 1], &tracker->portions[first + 2],
-                (tracker->count - first - 2) * sizeof(common_metrics));
+        if ((first - 2) < tracker->count)
+            memmove(&tracker->portions[first + 1], &tracker->portions[first + 2],
+                    (tracker->count - first - 2) * sizeof(common_metrics));
 
         tracker->count--;
 
@@ -930,29 +936,36 @@ void g_width_tracker_update_deleted(GWidthTracker *tracker, size_t start, size_t
 
     /* Avant toute chose : faire décroître les indices ! */
 
-    if (keep_first)
+    if (keep_first && keep_last)
     {
-        if (end < tracker->portions[first].last)
-            tracker->portions[first].last -= diff;
-        else
-            tracker->portions[first].last = start - 1;
+        tracker->portions[first].last -= diff;
+        update = first + 1;
     }
 
-    if (keep_last && last != first)
+    else
     {
-        tracker->portions[dest].first = end + 1;
-        tracker->portions[dest].last -= diff;
+        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, keep_last ? dest + 1 : dest, -diff);
+    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 && last != first)
-        g_width_tracker_reset_widths(tracker, dest);
+    if (keep_last && !keep_first)
+        g_width_tracker_reset_widths(tracker, update);
 
 }
 
-- 
cgit v0.11.2-87-g4458