From 3dc843b3f7991dcd738a30821ff56c7fe13f1094 Mon Sep 17 00:00:00 2001
From: Cyrille Bagard <nocbos@gmail.com>
Date: Wed, 18 Sep 2019 00:06:54 +0200
Subject: Kept tracks of current active DB items.

---
 plugins/pychrysalide/analysis/db/constants.c |  1 +
 plugins/pychrysalide/analysis/db/constants.h |  2 +
 src/analysis/db/cdb.c                        |  9 ++-
 src/analysis/db/client.c                     |  2 +-
 src/analysis/db/collection-int.h             |  3 +-
 src/analysis/db/collection.c                 | 57 +++++++++++++++---
 src/analysis/db/item-int.h                   |  9 +++
 src/analysis/db/item.c                       | 53 +++++++++++++++++
 src/analysis/db/item.h                       | 11 +++-
 src/analysis/db/items/bookmark.c             | 87 +++++++++++++++++++++++++---
 src/arch/vmpa.c                              | 27 +++++++++
 src/arch/vmpa.h                              |  3 +
 src/gui/panels/bookmarks.c                   |  4 +-
 src/gui/panels/history.c                     |  4 +-
 14 files changed, 243 insertions(+), 29 deletions(-)

diff --git a/plugins/pychrysalide/analysis/db/constants.c b/plugins/pychrysalide/analysis/db/constants.c
index 9c628f9..46d0876 100644
--- a/plugins/pychrysalide/analysis/db/constants.c
+++ b/plugins/pychrysalide/analysis/db/constants.c
@@ -93,6 +93,7 @@ bool define_db_item_constants(PyTypeObject *type)
 
     result = add_const_to_group(values, "NONE", DIF_NONE);
     if (result) result = add_const_to_group(values, "ERASER", DIF_ERASER);
+    if (result) result = add_const_to_group(values, "UPDATED", DIF_UPDATED);
     if (result) result = add_const_to_group(values, "VOLATILE", DIF_VOLATILE);
     if (result) result = add_const_to_group(values, "BROKEN", DIF_BROKEN);
 
diff --git a/plugins/pychrysalide/analysis/db/constants.h b/plugins/pychrysalide/analysis/db/constants.h
index cb7edf4..5f0afeb 100644
--- a/plugins/pychrysalide/analysis/db/constants.h
+++ b/plugins/pychrysalide/analysis/db/constants.h
@@ -30,6 +30,8 @@
 #include <stdbool.h>
 
 
+/* Définit les constantes relatives au protocole. */
+bool define_db_protocol_constants(PyTypeObject *);
 
 /* Définit les constantes pour les éléments de base de données. */
 bool define_db_item_constants(PyTypeObject *);
diff --git a/src/analysis/db/cdb.c b/src/analysis/db/cdb.c
index 597242f..a787a19 100644
--- a/src/analysis/db/cdb.c
+++ b/src/analysis/db/cdb.c
@@ -146,7 +146,7 @@ static bool g_cdb_archive_create_db(const GCdbArchive *);
 static bool g_cdb_archive_load_collections(GCdbArchive *);
 
 /* Réagit à une modification au sein d'une collection donnée. */
-static void on_collection_changed(GDbCollection *, DBAction, GDbItem *, GCdbArchive *);
+static void on_collection_extended(GDbCollection *, GDbItem *, GCdbArchive *);
 
 /* Assure le traitement des requêtes de clients. */
 static void *g_cdb_archive_process(GCdbArchive *);
@@ -742,7 +742,7 @@ static bool g_cdb_archive_load_collections(GCdbArchive *archive)
          iter = g_list_next(iter))
     {
         collec = G_DB_COLLECTION(iter->data);
-        g_signal_connect(collec, "content-changed", G_CALLBACK(on_collection_changed), archive);
+        g_signal_connect(collec, "content-extended", G_CALLBACK(on_collection_extended), archive);
 
         if (!g_db_collection_load_all_items(collec, archive->db))
             return false;
@@ -757,7 +757,6 @@ static bool g_cdb_archive_load_collections(GCdbArchive *archive)
 /******************************************************************************
 *                                                                             *
 *  Paramètres  : collec  = collection dont le contenu a évolué.               *
-*                action  = type d'évolution rencontrée.                       *
 *                item    = élément ajouté, modifié ou supprimé.               *
 *                archive = centralisation de tous les savoirs.                *
 *                                                                             *
@@ -769,7 +768,7 @@ static bool g_cdb_archive_load_collections(GCdbArchive *archive)
 *                                                                             *
 ******************************************************************************/
 
-static void on_collection_changed(GDbCollection *collec, DBAction action, GDbItem *item, GCdbArchive *archive)
+static void on_collection_extended(GDbCollection *collec, GDbItem *item, GCdbArchive *archive)
 {
     packed_buffer pbuf;                     /* Tampon d'émission           */
     size_t i;                               /* Boucle de parcours          */
@@ -777,7 +776,7 @@ static void on_collection_changed(GDbCollection *collec, DBAction action, GDbIte
 
     init_packed_buffer(&pbuf);
 
-    status = g_db_collection_pack(collec, &pbuf, action, item);
+    status = g_db_collection_pack(collec, &pbuf, DBA_ADD_ITEM, item);
 
     g_mutex_lock(&archive->clients_access);
 
diff --git a/src/analysis/db/client.c b/src/analysis/db/client.c
index 3197a8c..744fa57 100644
--- a/src/analysis/db/client.c
+++ b/src/analysis/db/client.c
@@ -789,7 +789,7 @@ static void *g_hub_client_update(GHubClient *client)
                     status = extract_packed_buffer(&in_pbuf, &tmp8, sizeof(uint8_t), true);
                     if (!status) goto gdcu_bad_exchange;
 
-                    client->can_get_updates = (tmp8 == 0x1);
+                    client->can_get_updates = (tmp8 == 0x0);
                     break;
 
             }
diff --git a/src/analysis/db/collection-int.h b/src/analysis/db/collection-int.h
index c2d1282..b3b83bb 100644
--- a/src/analysis/db/collection-int.h
+++ b/src/analysis/db/collection-int.h
@@ -60,6 +60,7 @@ struct _GDbCollection
 
     GList *items;                           /* Eléments rassemblés         */
     GList *sorted;                          /* Eléments triés              */
+    GHashTable *last_items;                 /* Statuts courants d'éléments */
     GRWLock params_access;                  /* Verrou de protection        */
 
 };
@@ -76,7 +77,7 @@ struct _GDbCollectionClass
 
     /* Signaux */
 
-    void (* content_changed) (GDbCollection *, DBAction, GDbItem *);
+    void (* content_extended) (GDbCollection *, GDbItem *);
 
 };
 
diff --git a/src/analysis/db/collection.c b/src/analysis/db/collection.c
index 33145a6..f728718 100644
--- a/src/analysis/db/collection.c
+++ b/src/analysis/db/collection.c
@@ -106,13 +106,13 @@ static void g_db_collection_class_init(GDbCollectionClass *klass)
 
     klass->setup_load = (collec_setup_load_fc)_g_db_collection_setup_load;
 
-    g_signal_new("content-changed",
+    g_signal_new("content-extended",
                  G_TYPE_DB_COLLECTION,
                  G_SIGNAL_RUN_LAST,
-                 G_STRUCT_OFFSET(GDbCollectionClass, content_changed),
+                 G_STRUCT_OFFSET(GDbCollectionClass, content_extended),
                  NULL, NULL,
-                 g_cclosure_user_marshal_VOID__ENUM_OBJECT,
-                 G_TYPE_NONE, 2, G_TYPE_UINT, G_TYPE_OBJECT);
+                 g_cclosure_marshal_VOID__OBJECT,
+                 G_TYPE_NONE, 1, G_TYPE_OBJECT);
 
 }
 
@@ -133,6 +133,11 @@ static void g_db_collection_init(GDbCollection *collec)
 {
     collec->binary = NULL;
 
+    collec->last_items = g_hash_table_new_full((GHashFunc)g_db_item_hash_key,
+                                               (GEqualFunc)g_db_item_cmp_key,
+                                               (GDestroyNotify)g_object_unref,
+                                               (GDestroyNotify)g_object_unref);
+
     g_rw_lock_init(&collec->params_access);
 
 }
@@ -654,6 +659,7 @@ bool g_db_collection_has_item(GDbCollection *collec, GDbItem *item)
 bool _g_db_collection_add_item(GDbCollection *collec, GDbItem *item, bool lock)
 {
     bool result;                            /* Bilan à faire remonter      */
+    GDbItem *prev;                          /* Elément similaire précédent */
 
     result = true;
 
@@ -666,7 +672,40 @@ bool _g_db_collection_add_item(GDbCollection *collec, GDbItem *item, bool lock)
     g_object_ref(G_OBJECT(item));
     collec->sorted = g_list_insert_sorted(collec->sorted, item, (GCompareFunc)g_db_item_compare_with_timestamp);
 
-    g_signal_emit_by_name(collec, "content-changed", DBA_ADD_ITEM, item);
+    prev = g_hash_table_lookup(collec->last_items, item);
+
+    if (prev != NULL)
+    {
+        g_object_ref(G_OBJECT(prev));
+
+        if (g_db_item_get_flags(item) & DIF_ERASER)
+            g_hash_table_remove(collec->last_items, prev);
+
+        else
+        {
+            g_db_item_add_flag(item, DIF_UPDATED);
+
+            g_object_ref(G_OBJECT(item));
+            g_object_ref(G_OBJECT(item));
+
+            g_hash_table_replace(collec->last_items, item, item);
+
+        }
+
+        g_object_unref(G_OBJECT(prev));
+
+    }
+
+    else
+    {
+        g_object_ref(G_OBJECT(item));
+        g_object_ref(G_OBJECT(item));
+
+        g_hash_table_add(collec->last_items, item);
+
+    }
+
+    g_signal_emit_by_name(collec, "content-extended", item);
 
     if (lock)
         g_db_collection_wunlock(collec);
@@ -718,7 +757,7 @@ bool _g_db_collection_remove_item(GDbCollection *collec, GDbItem *item, bool loc
         collec->items = g_list_delete_link(collec->items, found);
 
         if (signal)
-            g_signal_emit_by_name(collec, "content-changed", DBA_REM_ITEM, internal);
+            ;//g_signal_emit_by_name(collec, "content-changed", DBA_REM_ITEM, internal);
 
         g_object_unref(G_OBJECT(internal));
         g_object_unref(G_OBJECT(internal));
@@ -816,7 +855,7 @@ bool _g_db_collection_update_item_activity(GDbCollection *collec, GDbItem *item,
 
         result = g_db_item_set_activity(internal, collec->binary, timestamp);
 
-        g_signal_emit_by_name(collec, "content-changed", DBA_CHANGE_STATE, internal);
+        //g_signal_emit_by_name(collec, "content-changed", DBA_CHANGE_STATE, internal);
 
     }
 
@@ -863,7 +902,7 @@ GList *g_db_collection_set_last_active(GDbCollection *collec, timestamp_t timest
             {
                 /* ... */g_db_item_set_activity(item, collec->binary, NULL);
                 /* ... */g_db_collection_store_updated_item(collec, item, db);
-                g_signal_emit_by_name(collec, "content-changed", DBA_CHANGE_STATE, item);
+                //g_signal_emit_by_name(collec, "content-changed", DBA_CHANGE_STATE, item);
             }
 
         }
@@ -911,7 +950,7 @@ bool g_db_collection_set_inactive(GDbCollection *collec, GDbItem *item, timestam
 
     result = g_db_item_set_activity(item, collec->binary, timestamp);
 
-    g_signal_emit_by_name(collec, "content-changed", DBA_CHANGE_STATE, item);
+    //g_signal_emit_by_name(collec, "content-changed", DBA_CHANGE_STATE, item);
 
     return result;
 
diff --git a/src/analysis/db/item-int.h b/src/analysis/db/item-int.h
index a6398f9..8bba8a3 100644
--- a/src/analysis/db/item-int.h
+++ b/src/analysis/db/item-int.h
@@ -36,6 +36,12 @@
 
 
 
+/* Calcule le condensat associé à l'élément vu comme clef. */
+typedef guint (* hash_db_item_key_fc) (const GDbItem *);
+
+/* Compare deux éléments en tant que clefs. */
+typedef gboolean (* cmp_db_item_key_fc) (const GDbItem *, const GDbItem *);
+
 /* Effectue la comparaison entre deux éléments de collection. */
 typedef gint (* cmp_db_item_fc) (GDbItem *, GDbItem *, bool);
 
@@ -84,6 +90,9 @@ struct _GDbItemClass
 
     DBFeatures feature;                     /* Fonctionnalité représentée  */
 
+    hash_db_item_key_fc hash_key;           /* Condensat de l'élément      */
+    cmp_db_item_key_fc cmp_key;             /* Comparaison en tant que clef*/
+
     cmp_db_item_fc cmp;                     /* Comparaison entre éléments  */
 
     unpack_db_item_fc unpack;               /* Réception depuis le réseau  */
diff --git a/src/analysis/db/item.c b/src/analysis/db/item.c
index 2eb31b1..efa2cdf 100644
--- a/src/analysis/db/item.c
+++ b/src/analysis/db/item.c
@@ -205,6 +205,59 @@ void g_db_item_set_server_side(GDbItem *item)
 
 /******************************************************************************
 *                                                                             *
+*  Paramètres  : item = élément de collection à consulter.                    *
+*                                                                             *
+*  Description : Calcule le condensat associé à l'élément vu comme clef.      *
+*                                                                             *
+*  Retour      : Condensat associé à l'élément.                               *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+guint g_db_item_hash_key(const GDbItem *item)
+{
+    guint result;                           /* Valeur "unique" à renvoyer  */
+    GDbItemClass *class;                    /* Classe liée à l'instance    */
+
+    class = G_DB_ITEM_GET_CLASS(item);
+
+    result = class->hash_key(item);
+
+    return result;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : a = premier élément de collection à consulter.               *
+*                b = second élément de collection à consulter.                *
+*                                                                             *
+*  Description : Compare deux éléments en tant que clefs.                     *
+*                                                                             *
+*  Retour      : Bilan de la comparaison.                                     *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+gboolean g_db_item_cmp_key(const GDbItem *a, const GDbItem *b)
+{
+    gboolean result;                        /* Bilan à retourner           */
+    GDbItemClass *class;                    /* Classe liée à l'instance    */
+
+    class = G_DB_ITEM_GET_CLASS(a);
+
+    result = class->cmp_key(a, b);
+
+    return result;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
 *  Paramètres  : a    = premier élément à analyser.                           *
 *                b    = second élément à analyser.                            *
 *                with = précise les horodatages à prendre en compte.          *
diff --git a/src/analysis/db/item.h b/src/analysis/db/item.h
index dfc97fd..395a56f 100644
--- a/src/analysis/db/item.h
+++ b/src/analysis/db/item.h
@@ -45,8 +45,9 @@ typedef enum _DbItemFlags
 {
     DIF_NONE     = (0 << 0),                /* Propriétés par défaut       */
     DIF_ERASER   = (1 << 0),                /* Suppression de l'effet      */
-    DIF_VOLATILE = (1 << 1),                /* Abscence de sauvegarde      */
-    DIF_BROKEN   = (1 << 2),                /* Application impossible      */
+    DIF_UPDATED  = (1 << 1),                /* Mise à jour de l'élément    */
+    DIF_VOLATILE = (1 << 2),                /* Abscence de sauvegarde      */
+    DIF_BROKEN   = (1 << 3),                /* Application impossible      */
 
 } DbItemFlags;
 
@@ -75,6 +76,12 @@ DBFeatures g_db_item_get_feature(const GDbItem *);
 /* Indique à l'élément qu'il se trouve du côté serveur. */
 void g_db_item_set_server_side(GDbItem *);
 
+/* Calcule le condensat associé à l'élément vu comme clef. */
+guint g_db_item_hash_key(const GDbItem *);
+
+/* Compare deux éléments en tant que clefs. */
+gboolean g_db_item_cmp_key(const GDbItem *, const GDbItem *);
+
 /* Effectue la comparaison entre deux éléments de collection. */
 gint g_db_item_cmp(GDbItem *, GDbItem *, bool);
 
diff --git a/src/analysis/db/items/bookmark.c b/src/analysis/db/items/bookmark.c
index 20f98ea..3d66f6b 100644
--- a/src/analysis/db/items/bookmark.c
+++ b/src/analysis/db/items/bookmark.c
@@ -73,6 +73,12 @@ static void g_db_bookmark_dispose(GDbBookmark *);
 /* Procède à la libération totale de la mémoire. */
 static void g_db_bookmark_finalize(GDbBookmark *);
 
+/* Calcule le condensat associé à l'élément vu comme clef. */
+static guint g_db_bookmark_hash_key(const GDbBookmark *);
+
+/* Compare deux éléments en tant que clefs. */
+static gboolean g_db_bookmark_cmp_key(const GDbBookmark *, const GDbBookmark *);
+
 /* Effectue la comparaison entre deux signets de collection. */
 static gint g_db_bookmark_cmp(GDbBookmark *, GDbBookmark *, bool);
 
@@ -178,6 +184,9 @@ static void g_db_bookmark_class_init(GDbBookmarkClass *klass)
 
     item->feature = DBF_BOOKMARKS;
 
+    item->hash_key = (hash_db_item_key_fc)g_db_bookmark_hash_key;
+    item->cmp_key = (cmp_db_item_key_fc)g_db_bookmark_cmp_key;
+
     item->cmp = (cmp_db_item_fc)g_db_bookmark_cmp;
 
     item->unpack = (unpack_db_item_fc)g_db_bookmark_unpack;
@@ -319,6 +328,56 @@ bool g_db_bookmark_fill(GDbBookmark *bookmark, const vmpa2t *addr, const char *c
 
 /******************************************************************************
 *                                                                             *
+*  Paramètres  : bookmark = élément de collection à consulter.                *
+*                                                                             *
+*  Description : Calcule le condensat associé à l'élément vu comme clef.      *
+*                                                                             *
+*  Retour      : Condensat associé à l'élément.                               *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static guint g_db_bookmark_hash_key(const GDbBookmark *bookmark)
+{
+    guint result;                           /* Valeur "unique" à renvoyer  */
+
+    result = hash_vmpa(&bookmark->addr);
+
+    return result;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : a = premier élément de collection à consulter.               *
+*                b = second élément de collection à consulter.                *
+*                                                                             *
+*  Description : Compare deux éléments en tant que clefs.                     *
+*                                                                             *
+*  Retour      : Bilan de la comparaison.                                     *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static gboolean g_db_bookmark_cmp_key(const GDbBookmark *a, const GDbBookmark *b)
+{
+    gboolean result;                        /* Bilan à retourner           */
+    int ret;                                /* Bilan intermédiaire         */
+
+    ret = cmp_vmpa(&a->addr, &b->addr);
+
+    result = (ret == 0);
+
+    return result;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
 *  Paramètres  : a    = premier élément à analyser.                           *
 *                b    = second élément à analyser.                            *
 *                with = précise les horodatages à prendre en compte.          *
@@ -424,22 +483,36 @@ static char *g_db_bookmark_build_label(GDbBookmark *bookmark)
 {
     char *result;                           /* Description à retourner     */
     DbItemFlags flags;                      /* Propriétés de l'élément     */
-    const char *prefix;                     /* Préfixe à ajouter           */
     const char *text;                       /* Commentaire associé         */
+    const char *prefix;                     /* Préfixe à ajouter           */
 
     flags = g_db_item_get_flags(G_DB_ITEM(bookmark));
 
     if (flags & DIF_ERASER)
-        prefix = _("Removed");
+        asprintf(&result, _("Removed bookmark"));
+
+    else if (flags & DIF_UPDATED)
+    {
+        text = get_rle_string(&bookmark->comment);
+
+        if (text != NULL)
+            asprintf(&result, _("Updated bookmark: \"%s\""), text);
+        else
+            asprintf(&result, _("Reset bookmark"));
+    }
+
     else
+    {
         prefix = _("Created");
 
-    text = get_rle_string(&bookmark->comment);
+        text = get_rle_string(&bookmark->comment);
 
-    if (text != NULL)
-        asprintf(&result, _("%s bookmark \"%s\""), prefix, text);
-    else
-        asprintf(&result, _("%s empty bookmark"), prefix);
+        if (text != NULL)
+            asprintf(&result, _("%s bookmark \"%s\""), prefix, text);
+        else
+            asprintf(&result, _("%s empty bookmark"), prefix);
+
+    }
 
     return result;
 
diff --git a/src/arch/vmpa.c b/src/arch/vmpa.c
index 70ea52b..bf97a37 100644
--- a/src/arch/vmpa.c
+++ b/src/arch/vmpa.c
@@ -172,6 +172,33 @@ void copy_vmpa(vmpa2t *dest, const vmpa2t *src)
 
 /******************************************************************************
 *                                                                             *
+*  Paramètres  : addr = position à consulter.                                 *
+*                                                                             *
+*  Description : Calcule une empreinte de localisation dans l'espace mémoire. *
+*                                                                             *
+*  Retour      : Condensat déterminé pour la localisation.                    *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+uint32_t hash_vmpa(const vmpa2t *addr)
+{
+    uint32_t result;                        /* Empreinte à retourner       */
+
+    result = addr->physical;
+    result ^= (addr->physical >> 32);
+
+    result ^= addr->virtual;
+    result ^= (addr->virtual >> 32);
+
+    return result;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
 *  Paramètres  : a = première définition à analyser.                          *
 *                b = seconde définition à analyser.                           *
 *                                                                             *
diff --git a/src/arch/vmpa.h b/src/arch/vmpa.h
index 8dfc646..66f8769 100644
--- a/src/arch/vmpa.h
+++ b/src/arch/vmpa.h
@@ -90,6 +90,9 @@ void delete_vmpa(vmpa2t *);
 /* Copie la définition d'un adressage dans un autre. */
 void copy_vmpa(vmpa2t *, const vmpa2t *);
 
+/* Calcule une empreinte de localisation dans l'espace mémoire. */
+uint32_t hash_vmpa(const vmpa2t *);
+
 /* Compare entre elles deux adresses physiques. */
 int cmp_vmpa_by_phy(const vmpa2t *, const vmpa2t *);
 
diff --git a/src/gui/panels/bookmarks.c b/src/gui/panels/bookmarks.c
index 5fbc2fc..f32f9f5 100644
--- a/src/gui/panels/bookmarks.c
+++ b/src/gui/panels/bookmarks.c
@@ -450,8 +450,8 @@ static void reload_bookmarks_into_treeview(GBookmarksPanel *panel, GLoadedBinary
         g_object_ref(G_OBJECT(binary));
 
         collec = g_loaded_binary_find_collection(binary, DBF_BOOKMARKS);
-        g_signal_connect_to_main(collec, "content-changed", G_CALLBACK(on_collection_content_changed), panel,
-                                 g_cclosure_user_marshal_VOID__ENUM_OBJECT);
+        //g_signal_connect_to_main(collec, "content-changed", G_CALLBACK(on_collection_content_changed), panel,
+        //                         g_cclosure_user_marshal_VOID__ENUM_OBJECT);
 
     }
 
diff --git a/src/gui/panels/history.c b/src/gui/panels/history.c
index 3bdf77e..57e6a14 100644
--- a/src/gui/panels/history.c
+++ b/src/gui/panels/history.c
@@ -350,8 +350,8 @@ static void change_history_panel_current_content(GHistoryPanel *panel, GLoadedCo
 
         }
 
-        g_signal_connect_to_main(collections[k], "content-changed", G_CALLBACK(on_history_changed), panel,
-                                 g_cclosure_user_marshal_VOID__ENUM_OBJECT);
+        //g_signal_connect_to_main(collections[k], "content-changed", G_CALLBACK(on_history_changed), panel,
+        //                         g_cclosure_user_marshal_VOID__ENUM_OBJECT);
 
         g_object_unref(G_OBJECT(collections[k]));
 
-- 
cgit v0.11.2-87-g4458