From 945e0c9ecce02155555387aad672e272f5646362 Mon Sep 17 00:00:00 2001
From: Cyrille Bagard <nocbos@gmail.com>
Date: Thu, 30 Dec 2021 19:28:18 +0100
Subject: Create generic functions to load and store operands.

---
 plugins/arm/v7/operands/limitation.c |   8 -
 plugins/arm/v7/operands/maccess.c    | 127 +--------------
 plugins/arm/v7/operands/offset.c     |  76 ++++-----
 plugins/arm/v7/operands/rotation.c   |  89 +---------
 plugins/arm/v7/operands/shift.c      |  29 +---
 plugins/dalvik/operands/args.c       | 109 +------------
 src/analysis/storage/storage.c       |  75 ++++++++-
 src/analysis/storage/storage.h       |   3 +
 src/arch/Makefile.am                 |   2 +-
 src/arch/operand-int.c               | 308 +++++++++++++++++++++++++++++++++++
 src/arch/operand-int.h               |  42 +++++
 src/arch/operand.c                   |   8 +-
 12 files changed, 483 insertions(+), 393 deletions(-)
 create mode 100644 src/arch/operand-int.c

diff --git a/plugins/arm/v7/operands/limitation.c b/plugins/arm/v7/operands/limitation.c
index b3c6d07..f2e8373 100644
--- a/plugins/arm/v7/operands/limitation.c
+++ b/plugins/arm/v7/operands/limitation.c
@@ -456,15 +456,11 @@ static bool g_armv7_limitation_operand_load(GArmV7LimitationOperand *operand, GO
     {
         extra = GET_ARMV7_LIMITATION_OP_EXTRA(operand);
 
-        LOCK_GOBJECT_EXTRA(extra);
-
         result = unpack_uleb128(&value, pbuf);
 
         if (result)
             extra->type = value;
 
-        UNLOCK_GOBJECT_EXTRA(extra);
-
     }
 
     return result;
@@ -500,12 +496,8 @@ static bool g_armv7_limitation_operand_store(GArmV7LimitationOperand *operand, G
     {
         extra = GET_ARMV7_LIMITATION_OP_EXTRA(operand);
 
-        LOCK_GOBJECT_EXTRA(extra);
-
         result = pack_uleb128((uleb128_t []){ extra->type }, pbuf);
 
-        UNLOCK_GOBJECT_EXTRA(extra);
-
     }
 
     return result;
diff --git a/plugins/arm/v7/operands/maccess.c b/plugins/arm/v7/operands/maccess.c
index 3eb3116..d503b12 100644
--- a/plugins/arm/v7/operands/maccess.c
+++ b/plugins/arm/v7/operands/maccess.c
@@ -99,12 +99,6 @@ static void g_armv7_maccess_operand_update_inner_instances(GArmV7MAccessOperand
 /* Fournit l'empreinte d'un candidat à une centralisation. */
 static guint g_armv7_maccess_operand_hash(const GArmV7MAccessOperand *, bool);
 
-/* Charge un contenu depuis une mémoire tampon. */
-static bool g_armv7_maccess_operand_load(GArmV7MAccessOperand *, GObjectStorage *, packed_buffer_t *);
-
-/* Sauvegarde un contenu dans une mémoire tampon. */
-static bool g_armv7_maccess_operand_store(GArmV7MAccessOperand *, GObjectStorage *, packed_buffer_t *);
-
 
 
 /* ---------------------------------------------------------------------------------- */
@@ -150,8 +144,8 @@ static void g_armv7_maccess_operand_class_init(GArmV7MAccessOperandClass *klass)
     operand->update_inner = (operand_update_inners_fc)g_armv7_maccess_operand_update_inner_instances;
     operand->hash = (operand_hash_fc)g_armv7_maccess_operand_hash;
 
-    operand->load = (load_operand_fc)g_armv7_maccess_operand_load;
-    operand->store = (store_operand_fc)g_armv7_maccess_operand_store;
+    operand->load = g_arch_operand_load_generic_fixed_3;
+    operand->store = g_arch_operand_store_generic_fixed;
 
 }
 
@@ -638,28 +632,28 @@ static void g_armv7_maccess_operand_update_inner_instances(GArmV7MAccessOperand
         switch (i)
         {
             case 0:
-                g_object_unref(G_OBJECT(operand->base));
+                g_clear_object(&operand->base);
                 operand->base = instances[i];
                 break;
 
             case 1:
                 if (operand->offset != NULL)
                 {
-                    g_object_unref(G_OBJECT(operand->offset));
+                    g_clear_object(&operand->offset);
                     operand->offset = instances[i];
                 }
                 else
                 {
                     assert(count == 2);
 
-                    g_object_unref(G_OBJECT(operand->shift));
+                    g_clear_object(&operand->shift);
                     operand->shift = instances[i];
 
                 }
                 break;
 
             case 2:
-                g_object_unref(G_OBJECT(operand->shift));
+                g_clear_object(&operand->shift);
                 operand->shift = instances[i];
                 break;
 
@@ -716,112 +710,3 @@ static guint g_armv7_maccess_operand_hash(const GArmV7MAccessOperand *operand, b
     return result;
 
 }
-
-
-/******************************************************************************
-*                                                                             *
-*  Paramètres  : operand = élément GLib à constuire.                          *
-*                storage = conservateur de données à manipuler ou NULL.       *
-*                pbuf    = zone tampon à lire.                                *
-*                                                                             *
-*  Description : Charge un contenu depuis une mémoire tampon.                 *
-*                                                                             *
-*  Retour      : Bilan de l'opération.                                        *
-*                                                                             *
-*  Remarques   : -                                                            *
-*                                                                             *
-******************************************************************************/
-
-static bool g_armv7_maccess_operand_load(GArmV7MAccessOperand *operand, GObjectStorage *storage, packed_buffer_t *pbuf)
-{
-    bool result;                            /* Bilan à retourner           */
-    GArchOperandClass *parent;              /* Classe parente à consulter  */
-    GSerializableObject *obj;               /* Instance à manipuler        */
-
-    parent = G_ARCH_OPERAND_CLASS(g_armv7_maccess_operand_parent_class);
-
-    result = parent->load(G_ARCH_OPERAND(operand), storage, pbuf);
-
-    if (result)
-    {
-        obj = g_object_storage_unpack_object(storage, "operands", pbuf);
-
-        result = (obj != NULL);
-
-        if (result)
-            operand->base = G_ARCH_OPERAND(obj);
-
-    }
-
-    if (result)
-    {
-        obj = g_object_storage_unpack_object(storage, "operands", pbuf);
-
-        result = (obj != NULL);
-
-        if (result)
-            operand->offset = G_ARCH_OPERAND(obj);
-
-    }
-
-    if (result)
-    {
-        obj = g_object_storage_unpack_object(storage, "operands", pbuf);
-
-        result = (obj != NULL);
-
-        if (result)
-            operand->shift = G_ARCH_OPERAND(obj);
-
-    }
-
-    return result;
-
-}
-
-
-/******************************************************************************
-*                                                                             *
-*  Paramètres  : operand = élément GLib à consulter.                          *
-*                storage = conservateur de données à manipuler ou NULL.       *
-*                pbuf    = zone tampon à remplir.                             *
-*                                                                             *
-*  Description : Sauvegarde un contenu dans une mémoire tampon.               *
-*                                                                             *
-*  Retour      : Bilan de l'opération.                                        *
-*                                                                             *
-*  Remarques   : -                                                            *
-*                                                                             *
-******************************************************************************/
-
-static bool g_armv7_maccess_operand_store(GArmV7MAccessOperand *operand, GObjectStorage *storage, packed_buffer_t *pbuf)
-{
-    bool result;                            /* Bilan à retourner           */
-    GArchOperandClass *parent;              /* Classe parente à consulter  */
-    GSerializableObject *obj;               /* Instance à manipuler        */
-
-    parent = G_ARCH_OPERAND_CLASS(g_armv7_maccess_operand_parent_class);
-
-    result = parent->store(G_ARCH_OPERAND(operand), storage, pbuf);
-
-    if (result)
-    {
-        obj = G_SERIALIZABLE_OBJECT(operand->base);
-        result = g_object_storage_pack_object(storage, "operands", obj, pbuf);
-    }
-
-    if (result)
-    {
-        obj = G_SERIALIZABLE_OBJECT(operand->offset);
-        result = g_object_storage_pack_object(storage, "operands", obj, pbuf);
-    }
-
-    if (result)
-    {
-        obj = G_SERIALIZABLE_OBJECT(operand->shift);
-        result = g_object_storage_pack_object(storage, "operands", obj, pbuf);
-    }
-
-    return result;
-
-}
diff --git a/plugins/arm/v7/operands/offset.c b/plugins/arm/v7/operands/offset.c
index 1634230..79c5cf9 100644
--- a/plugins/arm/v7/operands/offset.c
+++ b/plugins/arm/v7/operands/offset.c
@@ -24,6 +24,7 @@
 #include "offset.h"
 
 
+#include <assert.h>
 #include <stdio.h>
 #include <string.h>
 
@@ -85,11 +86,11 @@ static GArchOperand *g_armv7_offset_operand_get_inner_operand_from_path(const GA
 /* Traduit un opérande en version humainement lisible. */
 static void g_armv7_offset_operand_print(const GArmV7OffsetOperand *, GBufferLine *);
 
-/* Charge un contenu depuis une mémoire tampon. */
-static bool g_armv7_offset_operand_load(GArmV7OffsetOperand *, GObjectStorage *, packed_buffer_t *);
+/* Fournit une liste de candidats embarqués par un candidat. */
+static GArchOperand **g_armv7_offset_operand_list_inner_instances(const GArmV7OffsetOperand *, size_t *);
 
-/* Sauvegarde un contenu dans une mémoire tampon. */
-static bool g_armv7_offset_operand_store(GArmV7OffsetOperand *, GObjectStorage *, packed_buffer_t *);
+/* Met à jour une liste de candidats embarqués par un candidat. */
+static void g_armv7_offset_operand_update_inner_instances(GArmV7OffsetOperand *, GArchOperand **, size_t);
 
 
 
@@ -132,8 +133,11 @@ static void g_armv7_offset_operand_class_init(GArmV7OffsetOperandClass *klass)
 
     operand->print = (operand_print_fc)g_armv7_offset_operand_print;
 
-    operand->load = (load_operand_fc)g_armv7_offset_operand_load;
-    operand->store = (store_operand_fc)g_armv7_offset_operand_store;
+    operand->list_inner = (operand_list_inners_fc)g_armv7_offset_operand_list_inner_instances;
+    operand->update_inner = (operand_update_inners_fc)g_armv7_offset_operand_update_inner_instances;
+
+    operand->load = g_arch_operand_load_generic_fixed_1;
+    operand->store = g_arch_operand_store_generic_fixed;
 
 }
 
@@ -379,38 +383,27 @@ static void g_armv7_offset_operand_print(const GArmV7OffsetOperand *operand, GBu
 
 /******************************************************************************
 *                                                                             *
-*  Paramètres  : operand = élément GLib à constuire.                          *
-*                storage = conservateur de données à manipuler ou NULL.       *
-*                pbuf    = zone tampon à lire.                                *
+*  Paramètres  : operand = objet dont l'instance se veut unique.              *
+*                count   = quantité d'instances à l'unicité internes.         *
 *                                                                             *
-*  Description : Charge un contenu depuis une mémoire tampon.                 *
+*  Description : Fournit une liste de candidats embarqués par un candidat.    *
 *                                                                             *
-*  Retour      : Bilan de l'opération.                                        *
+*  Retour      : Liste de candidats internes ou NULL si aucun.                *
 *                                                                             *
 *  Remarques   : -                                                            *
 *                                                                             *
 ******************************************************************************/
 
-static bool g_armv7_offset_operand_load(GArmV7OffsetOperand *operand, GObjectStorage *storage, packed_buffer_t *pbuf)
+static GArchOperand **g_armv7_offset_operand_list_inner_instances(const GArmV7OffsetOperand *operand, size_t *count)
 {
-    bool result;                            /* Bilan à retourner           */
-    GArchOperandClass *parent;              /* Classe parente à consulter  */
-    GSerializableObject *value;             /* Valeur du décalage          */
-
-    parent = G_ARCH_OPERAND_CLASS(g_armv7_offset_operand_parent_class);
+    GArchOperand **result;                  /* Instances à retourner       */
 
-    result = parent->load(G_ARCH_OPERAND(operand), storage, pbuf);
-
-    if (result)
-    {
-        value = g_object_storage_unpack_object(storage, "operands", pbuf);
+    *count = 1;
 
-        result = (value != NULL);
+    result = malloc(*count * sizeof(GArchOperand *));
 
-        if (result)
-            operand->value = G_ARCH_OPERAND(value);
-
-    }
+    result[0] = operand->value;
+    g_object_ref(G_OBJECT(result[0]));
 
     return result;
 
@@ -419,34 +412,25 @@ static bool g_armv7_offset_operand_load(GArmV7OffsetOperand *operand, GObjectSto
 
 /******************************************************************************
 *                                                                             *
-*  Paramètres  : operand = élément GLib à consulter.                          *
-*                storage = conservateur de données à manipuler ou NULL.       *
-*                pbuf    = zone tampon à remplir.                             *
+*  Paramètres  : operand   = objet dont l'instance se veut unique.            *
+*                instances = liste de candidats internes devenus singletons.  *
+*                count     = quantité d'instances à l'unicité internes.       *
 *                                                                             *
-*  Description : Sauvegarde un contenu dans une mémoire tampon.               *
+*  Description : Met à jour une liste de candidats embarqués par un candidat. *
 *                                                                             *
-*  Retour      : Bilan de l'opération.                                        *
+*  Retour      : -                                                            *
 *                                                                             *
 *  Remarques   : -                                                            *
 *                                                                             *
 ******************************************************************************/
 
-static bool g_armv7_offset_operand_store(GArmV7OffsetOperand *operand, GObjectStorage *storage, packed_buffer_t *pbuf)
+static void g_armv7_offset_operand_update_inner_instances(GArmV7OffsetOperand *operand, GArchOperand **instances, size_t count)
 {
-    bool result;                            /* Bilan à retourner           */
-    GArchOperandClass *parent;              /* Classe parente à consulter  */
-    GSerializableObject *value;             /* Valeur du décalage          */
+    assert(count == 1);
 
-    parent = G_ARCH_OPERAND_CLASS(g_armv7_offset_operand_parent_class);
-
-    result = parent->store(G_ARCH_OPERAND(operand), storage, pbuf);
-
-    if (result)
-    {
-        value = G_SERIALIZABLE_OBJECT(operand->value);
-        result = g_object_storage_pack_object(storage, "operands", value, pbuf);
-    }
+    g_clear_object(&operand->value);
 
-    return result;
+    operand->value = instances[0];
+    g_object_ref(G_OBJECT(instances[0]));
 
 }
diff --git a/plugins/arm/v7/operands/rotation.c b/plugins/arm/v7/operands/rotation.c
index f90c76b..8136401 100644
--- a/plugins/arm/v7/operands/rotation.c
+++ b/plugins/arm/v7/operands/rotation.c
@@ -93,12 +93,6 @@ static GArchOperand **g_armv7_rotation_operand_list_inner_instances(const GArmV7
 /* Met à jour une liste de candidats embarqués par un candidat. */
 static void g_armv7_rotation_operand_update_inner_instances(GArmV7RotationOperand *, GArchOperand **, size_t);
 
-/* Charge un contenu depuis une mémoire tampon. */
-static bool g_armv7_rotation_operand_load(GArmV7RotationOperand *, GObjectStorage *, packed_buffer_t *);
-
-/* Sauvegarde un contenu dans une mémoire tampon. */
-static bool g_armv7_rotation_operand_store(GArmV7RotationOperand *, GObjectStorage *, packed_buffer_t *);
-
 
 
 /* ---------------------------------------------------------------------------------- */
@@ -143,8 +137,8 @@ static void g_armv7_rotation_operand_class_init(GArmV7RotationOperandClass *klas
     operand->list_inner = (operand_list_inners_fc)g_armv7_rotation_operand_list_inner_instances;
     operand->update_inner = (operand_update_inners_fc)g_armv7_rotation_operand_update_inner_instances;
 
-    operand->load = (load_operand_fc)g_armv7_rotation_operand_load;
-    operand->store = (store_operand_fc)g_armv7_rotation_operand_store;
+    operand->load = g_arch_operand_load_generic_fixed_1;
+    operand->store = g_arch_operand_store_generic_fixed;
 
 }
 
@@ -454,82 +448,9 @@ static void g_armv7_rotation_operand_update_inner_instances(GArmV7RotationOperan
 {
     assert(count == 1);
 
-    g_object_unref(G_OBJECT(operand->value));
-    operand->value = instances[0];
-
-}
-
-
-/******************************************************************************
-*                                                                             *
-*  Paramètres  : operand = élément GLib à constuire.                          *
-*                storage = conservateur de données à manipuler ou NULL.       *
-*                pbuf    = zone tampon à lire.                                *
-*                                                                             *
-*  Description : Charge un contenu depuis une mémoire tampon.                 *
-*                                                                             *
-*  Retour      : Bilan de l'opération.                                        *
-*                                                                             *
-*  Remarques   : -                                                            *
-*                                                                             *
-******************************************************************************/
-
-static bool g_armv7_rotation_operand_load(GArmV7RotationOperand *operand, GObjectStorage *storage, packed_buffer_t *pbuf)
-{
-    bool result;                            /* Bilan à retourner           */
-    GArchOperandClass *parent;              /* Classe parente à consulter  */
-    GSerializableObject *value;             /* Valeur de la rotation          */
-
-    parent = G_ARCH_OPERAND_CLASS(g_armv7_rotation_operand_parent_class);
-
-    result = parent->load(G_ARCH_OPERAND(operand), storage, pbuf);
-
-    if (result)
-    {
-        value = g_object_storage_unpack_object(storage, "operands", pbuf);
-
-        result = (value != NULL);
-
-        if (result)
-            operand->value = G_ARCH_OPERAND(value);
-
-    }
-
-    return result;
-
-}
-
-
-/******************************************************************************
-*                                                                             *
-*  Paramètres  : operand = élément GLib à consulter.                          *
-*                storage = conservateur de données à manipuler ou NULL.       *
-*                pbuf    = zone tampon à remplir.                             *
-*                                                                             *
-*  Description : Sauvegarde un contenu dans une mémoire tampon.               *
-*                                                                             *
-*  Retour      : Bilan de l'opération.                                        *
-*                                                                             *
-*  Remarques   : -                                                            *
-*                                                                             *
-******************************************************************************/
-
-static bool g_armv7_rotation_operand_store(GArmV7RotationOperand *operand, GObjectStorage *storage, packed_buffer_t *pbuf)
-{
-    bool result;                            /* Bilan à retourner           */
-    GArchOperandClass *parent;              /* Classe parente à consulter  */
-    GSerializableObject *value;             /* Valeur de la rotation          */
-
-    parent = G_ARCH_OPERAND_CLASS(g_armv7_rotation_operand_parent_class);
-
-    result = parent->store(G_ARCH_OPERAND(operand), storage, pbuf);
-
-    if (result)
-    {
-        value = G_SERIALIZABLE_OBJECT(operand->value);
-        result = g_object_storage_pack_object(storage, "operands", value, pbuf);
-    }
+    g_clear_object(&operand->value);
 
-    return result;
+    operand->value = instances[0];
+    g_object_ref(G_OBJECT(instances[0]));
 
 }
diff --git a/plugins/arm/v7/operands/shift.c b/plugins/arm/v7/operands/shift.c
index 55f2a22..ccdfe5c 100644
--- a/plugins/arm/v7/operands/shift.c
+++ b/plugins/arm/v7/operands/shift.c
@@ -537,8 +537,10 @@ static void g_armv7_shift_operand_update_inner_instances(GArmV7ShiftOperand *ope
 {
     assert(count == 1);
 
-    g_object_unref(G_OBJECT(operand->shift_value));
+    g_clear_object(&operand->shift_value);
+
     operand->shift_value = instances[0];
+    g_object_ref(G_OBJECT(instances[0]));
 
 }
 
@@ -603,7 +605,6 @@ static bool g_armv7_shift_operand_load(GArmV7ShiftOperand *operand, GObjectStora
     GArchOperandClass *parent;              /* Classe parente à consulter  */
     a7shiftop_extra_data_t *extra;          /* Données insérées à modifier */
     uleb128_t value;                        /* Valeur ULEB128 à charger    */
-    GSerializableObject *shift_value;       /* Valeur du décalage          */
 
     parent = G_ARCH_OPERAND_CLASS(g_armv7_shift_operand_parent_class);
 
@@ -613,27 +614,15 @@ static bool g_armv7_shift_operand_load(GArmV7ShiftOperand *operand, GObjectStora
     {
         extra = GET_ARMV7_SHIFT_OP_EXTRA(operand);
 
-        LOCK_GOBJECT_EXTRA(extra);
-
         result = unpack_uleb128(&value, pbuf);
 
         if (result)
             extra->shift_type = value;
 
-        UNLOCK_GOBJECT_EXTRA(extra);
-
     }
 
     if (result)
-    {
-        shift_value = g_object_storage_unpack_object(storage, "operands", pbuf);
-
-        result = (shift_value != NULL);
-
-        if (result)
-            operand->shift_value = G_ARCH_OPERAND(shift_value);
-
-    }
+        result = _g_arch_operand_load_inner_instances(G_ARCH_OPERAND(operand), storage, pbuf, 1);
 
     return result;
 
@@ -659,7 +648,6 @@ static bool g_armv7_shift_operand_store(GArmV7ShiftOperand *operand, GObjectStor
     bool result;                            /* Bilan à retourner           */
     GArchOperandClass *parent;              /* Classe parente à consulter  */
     a7shiftop_extra_data_t *extra;          /* Données insérées à modifier */
-    GSerializableObject *shift_value;       /* Valeur du décalage          */
 
     parent = G_ARCH_OPERAND_CLASS(g_armv7_shift_operand_parent_class);
 
@@ -669,19 +657,12 @@ static bool g_armv7_shift_operand_store(GArmV7ShiftOperand *operand, GObjectStor
     {
         extra = GET_ARMV7_SHIFT_OP_EXTRA(operand);
 
-        LOCK_GOBJECT_EXTRA(extra);
-
         result = pack_uleb128((uleb128_t []){ extra->shift_type }, pbuf);
 
-        UNLOCK_GOBJECT_EXTRA(extra);
-
     }
 
     if (result)
-    {
-        shift_value = G_SERIALIZABLE_OBJECT(operand->shift_value);
-        result = g_object_storage_pack_object(storage, "operands", shift_value, pbuf);
-    }
+        result = _g_arch_operand_store_inner_instances(G_ARCH_OPERAND(operand), storage, pbuf, true);
 
     return result;
 
diff --git a/plugins/dalvik/operands/args.c b/plugins/dalvik/operands/args.c
index 7eec5d7..b1aa59f 100644
--- a/plugins/dalvik/operands/args.c
+++ b/plugins/dalvik/operands/args.c
@@ -97,12 +97,6 @@ static void g_dalvik_args_operand_update_inner_instances(GDalvikArgsOperand *, G
 /* Fournit l'empreinte d'un candidat à une centralisation. */
 static guint g_dalvik_args_operand_hash(const GDalvikArgsOperand *, bool);
 
-/* Charge un contenu depuis une mémoire tampon. */
-static bool g_dalvik_args_operand_load(GDalvikArgsOperand *, GObjectStorage *, packed_buffer_t *);
-
-/* Sauvegarde un contenu dans une mémoire tampon. */
-static bool g_dalvik_args_operand_store(GDalvikArgsOperand *, GObjectStorage *, packed_buffer_t *);
-
 
 
 /* ---------------------------------------------------------------------------------- */
@@ -148,8 +142,8 @@ static void g_dalvik_args_operand_class_init(GDalvikArgsOperandClass *klass)
     operand->update_inner = (operand_update_inners_fc)g_dalvik_args_operand_update_inner_instances;
     operand->hash = (operand_hash_fc)g_dalvik_args_operand_hash;
 
-    operand->load = (load_operand_fc)g_dalvik_args_operand_load;
-    operand->store = (store_operand_fc)g_dalvik_args_operand_store;
+    operand->load = g_arch_operand_load_generic_variadic;
+    operand->store = g_arch_operand_store_generic_variadic;
 
 }
 
@@ -586,15 +580,16 @@ static void g_dalvik_args_operand_update_inner_instances(GDalvikArgsOperand *ope
 {
     size_t i;                               /* Boucle de parcours          */
 
-    assert(count == operand->count);
-
     for (i = 0; i < count; i++)
-    {
         g_object_unref(G_OBJECT(operand->args[i]));
 
+    operand->count = count;
+    operand->args = realloc(operand->args, operand->count * sizeof(GArchOperand *));
+
+    for (i = 0; i < count; i++)
+    {
         operand->args[i] = instances[i];
         g_object_ref(G_OBJECT(instances[i]));
-
     }
 
 }
@@ -635,93 +630,3 @@ static guint g_dalvik_args_operand_hash(const GDalvikArgsOperand *operand, bool
     return result;
 
 }
-
-
-/******************************************************************************
-*                                                                             *
-*  Paramètres  : operand = élément GLib à constuire.                          *
-*                storage = conservateur de données à manipuler ou NULL.       *
-*                pbuf    = zone tampon à lire.                                *
-*                                                                             *
-*  Description : Charge un contenu depuis une mémoire tampon.                 *
-*                                                                             *
-*  Retour      : Bilan de l'opération.                                        *
-*                                                                             *
-*  Remarques   : -                                                            *
-*                                                                             *
-******************************************************************************/
-
-static bool g_dalvik_args_operand_load(GDalvikArgsOperand *operand, GObjectStorage *storage, packed_buffer_t *pbuf)
-{
-    bool result;                            /* Bilan à retourner           */
-    GArchOperandClass *parent;              /* Classe parente à consulter  */
-    uleb128_t value;                        /* Valeur ULEB128 à charger    */
-    size_t i;                               /* Boucle de parcours          */
-    GSerializableObject *arg;               /* Nouvel argument à intégrer  */
-
-    parent = G_ARCH_OPERAND_CLASS(g_dalvik_args_operand_parent_class);
-
-    result = parent->load(G_ARCH_OPERAND(operand), storage, pbuf);
-
-    if (result)
-        result = unpack_uleb128(&value, pbuf);
-
-    if (result)
-    {
-        operand->count = value;
-        operand->args = calloc(operand->count, sizeof(GArchOperand *));
-    }
-
-    for (i = 0; i < operand->count && result; i++)
-    {
-        arg = g_object_storage_unpack_object(storage, "operands", pbuf);
-        if (arg == NULL) break;
-
-        operand->args[operand->count - 1] = G_ARCH_OPERAND(arg);
-
-    }
-
-    result = (i == operand->count);
-
-    return result;
-
-}
-
-
-/******************************************************************************
-*                                                                             *
-*  Paramètres  : operand = élément GLib à consulter.                          *
-*                storage = conservateur de données à manipuler ou NULL.       *
-*                pbuf    = zone tampon à remplir.                             *
-*                                                                             *
-*  Description : Sauvegarde un contenu dans une mémoire tampon.               *
-*                                                                             *
-*  Retour      : Bilan de l'opération.                                        *
-*                                                                             *
-*  Remarques   : -                                                            *
-*                                                                             *
-******************************************************************************/
-
-static bool g_dalvik_args_operand_store(GDalvikArgsOperand *operand, GObjectStorage *storage, packed_buffer_t *pbuf)
-{
-    bool result;                            /* Bilan à retourner           */
-    GArchOperandClass *parent;              /* Classe parente à consulter  */
-    size_t i;                               /* Boucle de parcours          */
-    GSerializableObject *arg;               /* Nouvel argument à intégrer  */
-
-    parent = G_ARCH_OPERAND_CLASS(g_dalvik_args_operand_parent_class);
-
-    result = parent->store(G_ARCH_OPERAND(operand), storage, pbuf);
-
-    if (result)
-        result = pack_uleb128((uleb128_t []){ operand->count }, pbuf);
-
-    for (i = 0; i < operand->count && result; i++)
-    {
-        arg = G_SERIALIZABLE_OBJECT(operand->args[i]);
-        result = g_object_storage_pack_object(storage, "operands", arg, pbuf);
-    }
-
-    return result;
-
-}
diff --git a/src/analysis/storage/storage.c b/src/analysis/storage/storage.c
index e286641..c641a52 100644
--- a/src/analysis/storage/storage.c
+++ b/src/analysis/storage/storage.c
@@ -28,6 +28,7 @@
 #include <malloc.h>
 #include <string.h>
 #include <unistd.h>
+#include <stdarg.h>
 
 
 #include "storage-int.h"
@@ -702,6 +703,67 @@ GSerializableObject *g_object_storage_unpack_object(GObjectStorage *storage, con
 
 /******************************************************************************
 *                                                                             *
+*  Paramètres  : storage  = gestionnaire à manipuler.                         *
+*                name     = désignation d'un nouveau groupe d'objets.         *
+*                pbuf     = zone tampon à parcourir.                          *
+*                expected = type d'objet attendu.                             *
+*                ...      = élément restauré ou NULL en cas d'échec. [OUT]    *
+*                                                                             *
+*  Description : Charge un objet interne à partir de données rassemblées.     *
+*                                                                             *
+*  Retour      : Bilan de l'opération.                                        *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+bool g_object_storage_unpack_object_2(GObjectStorage *storage, const char *name, packed_buffer_t *pbuf, GType expected, ...)
+{
+    bool result;                            /* Bilan d'une opération       */
+    uint64_t pos;                           /* Localisation des données    */
+    GSerializableObject *instance;          /* Objet rechargé à valider    */
+    va_list ap;                             /* Liste d'arguments variables */
+    void **object;                          /* Lieu d'enregistrement final */
+
+    result = extract_packed_buffer(pbuf, &pos, sizeof(uint64_t), true);
+
+    if (result)
+    {
+        if (pos == 0)
+            *object = NULL;
+
+        else
+        {
+            instance = g_object_storage_load_object(storage, name, pos);
+
+            result = G_TYPE_CHECK_INSTANCE_TYPE(instance, expected);
+
+            if (result)
+            {
+                va_start(ap, expected);
+
+                object = va_arg(ap, void **);
+
+                *object = instance;
+
+                va_end(ap);
+
+            }
+
+            else
+                g_clear_object(&instance);
+
+        }
+
+    }
+
+    return result;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
 *  Paramètres  : storage = gestionnaire à manipuler.                          *
 *                name    = désignation d'un nouveau groupe d'objets.          *
 *                object  = objet sérialisable à traiter.                      *
@@ -787,10 +849,17 @@ bool g_object_storage_pack_object(GObjectStorage *storage, const char *name, con
     bool result;                            /* Bilan à retourner           */
     off64_t pos;                            /* Localisation des données    */
 
-    result = g_object_storage_store_object(storage, name, object, &pos);
+    if (object == NULL)
+        result = extend_packed_buffer(pbuf, (uint64_t []){ 0 }, sizeof(uint64_t), true);
 
-    if (result)
-        result = extend_packed_buffer(pbuf, (uint64_t []){ pos }, sizeof(uint64_t), true);
+    else
+    {
+        result = g_object_storage_store_object(storage, name, object, &pos);
+
+        if (result)
+            result = extend_packed_buffer(pbuf, (uint64_t []){ pos }, sizeof(uint64_t), true);
+
+    }
 
     return result;
 
diff --git a/src/analysis/storage/storage.h b/src/analysis/storage/storage.h
index 0d35d78..cc0caad 100644
--- a/src/analysis/storage/storage.h
+++ b/src/analysis/storage/storage.h
@@ -78,6 +78,9 @@ GSerializableObject *g_object_storage_unpack_object(GObjectStorage *, const char
 /* Sauvegarde un object sous forme de données rassemblées. */
 bool g_object_storage_store_object(GObjectStorage *, const char *, const GSerializableObject *, off64_t *);
 
+/* Charge un objet interne à partir de données rassemblées. */
+bool g_object_storage_unpack_object_2(GObjectStorage *, const char *, packed_buffer_t *, GType, ...);
+
 /* Sauvegarde un object interne sous forme de données. */
 bool g_object_storage_pack_object(GObjectStorage *, const char *, const GSerializableObject *, packed_buffer_t *);
 
diff --git a/src/arch/Makefile.am b/src/arch/Makefile.am
index 3ea5713..8a2eea3 100644
--- a/src/arch/Makefile.am
+++ b/src/arch/Makefile.am
@@ -9,7 +9,7 @@ libarch_la_SOURCES =					\
 	instruction-int.h					\
 	instruction.h instruction.c			\
 	link.h link.c						\
-	operand-int.h						\
+	operand-int.h operand-int.c			\
 	operand.h operand.c					\
 	post.h post.c						\
 	processor-int.h						\
diff --git a/src/arch/operand-int.c b/src/arch/operand-int.c
new file mode 100644
index 0000000..51e8d44
--- /dev/null
+++ b/src/arch/operand-int.c
@@ -0,0 +1,308 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * operand-int.c - définition générique interne des opérandes
+ *
+ * Copyright (C) 2021 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 <http://www.gnu.org/licenses/>.
+ */
+
+
+#include "operand-int.h"
+
+
+
+/* ---------------------------------------------------------------------------------- */
+/*                      CONSERVATION ET RECHARGEMENT DES DONNEES                      */
+/* ---------------------------------------------------------------------------------- */
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : operand = élément GLib à consulter.                          *
+*                storage = conservateur de données à manipuler ou NULL.       *
+*                pbuf    = zone tampon à consulter.                           *
+*                count   = quantité d'opérandes à extraire du tampon.         *
+*                                                                             *
+*  Description : Charge une série d'opérandes internes depuis un tampon.      *
+*                                                                             *
+*  Retour      : Bilan de l'opération.                                        *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+bool _g_arch_operand_load_inner_instances(GArchOperand *operand, GObjectStorage *storage, packed_buffer_t *pbuf, size_t count)
+{
+    bool result;                            /* Bilan à retourner           */
+    GArchOperand **instances;               /* Liste d'opérandes à charger */
+    size_t i;                               /* Boucle de parcours          */
+
+    result = true;
+
+    instances = calloc(count, sizeof(GArchOperand *));
+
+    for (i = 0; i < count && result; i++)
+        result = g_object_storage_unpack_object_2(storage, "operands", pbuf, G_TYPE_ARCH_OPERAND, &instances[i]);
+
+    if (result)
+        g_arch_operand_update_inner_instances(operand, instances, count);
+
+    for (i = 0; i < count; i++)
+        g_clear_object(&instances[i]);
+
+    free(instances);
+
+    return result;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : operand = élément GLib à consulter.                          *
+*                storage = conservateur de données à manipuler ou NULL.       *
+*                pbuf    = zone tampon à consulter.                           *
+*                                                                             *
+*  Description : Charge une série d'opérandes internes depuis un tampon.      *
+*                                                                             *
+*  Retour      : Bilan de l'opération.                                        *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+bool g_arch_operand_load_generic_fixed_1(GArchOperand *operand, GObjectStorage *storage, packed_buffer_t *pbuf)
+{
+    bool result;                            /* Bilan à retourner           */
+    GType type;                             /* Type d'opérande manipulé    */
+    GArchOperandClass *parent;              /* Classe parente à consulter  */
+
+    type = G_TYPE_FROM_INSTANCE(operand);
+
+    parent = g_type_class_peek_parent(g_type_class_peek(type));
+
+    result = parent->load(G_ARCH_OPERAND(operand), storage, pbuf);
+
+    if (result)
+        result = _g_arch_operand_load_inner_instances(operand, storage, pbuf, 1);
+
+    return result;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : operand = élément GLib à consulter.                          *
+*                storage = conservateur de données à manipuler ou NULL.       *
+*                pbuf    = zone tampon à consulter.                           *
+*                                                                             *
+*  Description : Charge une série d'opérandes internes depuis un tampon.      *
+*                                                                             *
+*  Retour      : Bilan de l'opération.                                        *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+bool g_arch_operand_load_generic_fixed_3(GArchOperand *operand, GObjectStorage *storage, packed_buffer_t *pbuf)
+{
+    bool result;                            /* Bilan à retourner           */
+    GType type;                             /* Type d'opérande manipulé    */
+    GArchOperandClass *parent;              /* Classe parente à consulter  */
+
+    type = G_TYPE_FROM_INSTANCE(operand);
+
+    parent = g_type_class_peek_parent(g_type_class_peek(type));
+
+    result = parent->load(G_ARCH_OPERAND(operand), storage, pbuf);
+
+    if (result)
+        result = _g_arch_operand_load_inner_instances(operand, storage, pbuf, 3);
+
+    return result;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : operand = élément GLib à consulter.                          *
+*                storage = conservateur de données à manipuler ou NULL.       *
+*                pbuf    = zone tampon à consulter.                           *
+*                                                                             *
+*  Description : Charge une série d'opérandes internes depuis un tampon.      *
+*                                                                             *
+*  Retour      : Bilan de l'opération.                                        *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+bool g_arch_operand_load_generic_variadic(GArchOperand *operand, GObjectStorage *storage, packed_buffer_t *pbuf)
+{
+    bool result;                            /* Bilan à retourner           */
+    GType type;                             /* Type d'opérande manipulé    */
+    GArchOperandClass *parent;              /* Classe parente à consulter  */
+    uleb128_t value;                        /* Valeur ULEB128 à charger    */
+
+    type = G_TYPE_FROM_INSTANCE(operand);
+
+    parent = g_type_class_peek_parent(g_type_class_peek(type));
+
+    result = parent->load(G_ARCH_OPERAND(operand), storage, pbuf);
+
+    if (result)
+        result = unpack_uleb128(&value, pbuf);
+
+    if (result)
+        result = _g_arch_operand_load_inner_instances(operand, storage, pbuf, value);
+
+    return result;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : operand = élément GLib à consulter.                          *
+*                storage = conservateur de données à manipuler ou NULL.       *
+*                pbuf    = zone tampon à remplir.                             *
+*                fixed   = précise si le nombre d'opérande est fixe ou non.   *
+*                                                                             *
+*  Description : Sauvegarde une série d'opérandes internes dans un tampon.    *
+*                                                                             *
+*  Retour      : Bilan de l'opération.                                        *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+bool _g_arch_operand_store_inner_instances(GArchOperand *operand, GObjectStorage *storage, packed_buffer_t *pbuf, bool fixed)
+{
+    bool result;                            /* Bilan à retourner           */
+    size_t count;                           /* Nombre d'opérandes listées  */
+    GArchOperand **instances;               /* Liste d'opérandes à traiter */
+    size_t i;                               /* Boucle de parcours          */
+    GSerializableObject *obj;               /* Objet à conserver           */
+
+    result = true;
+
+    instances = g_arch_operand_list_inner_instances(operand, &count);
+
+    if (!fixed)
+        result = pack_uleb128((uleb128_t []){ count }, pbuf);
+
+    if (instances != NULL)
+    {
+        for (i = 0; i < count && result; i++)
+        {
+            if (instances[i] == NULL)
+                result = g_object_storage_pack_object(storage, "operands", NULL, pbuf);
+
+            else
+            {
+                obj = G_SERIALIZABLE_OBJECT(instances[i]);
+
+                result = g_object_storage_pack_object(storage, "operands", obj, pbuf);
+
+                g_object_unref(G_OBJECT(instances[i]));
+
+            }
+
+        }
+
+        for (; i < count && result; i++)
+            g_clear_object(&instances[i]);
+
+        free(instances);
+
+    }
+
+    return result;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : operand = élément GLib à consulter.                          *
+*                storage = conservateur de données à manipuler ou NULL.       *
+*                pbuf    = zone tampon à remplir.                             *
+*                fixed   = précise si le nombre d'opérande est fixe ou non.   *
+*                                                                             *
+*  Description : Sauvegarde un opérande dans un tampon de façon générique.    *
+*                                                                             *
+*  Retour      : Bilan de l'opération.                                        *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+bool g_arch_operand_store_generic_fixed(GArchOperand *operand, GObjectStorage *storage, packed_buffer_t *pbuf)
+{
+    bool result;                            /* Bilan à retourner           */
+    GType type;                             /* Type d'opérande manipulé    */
+    GArchOperandClass *parent;              /* Classe parente à consulter  */
+
+    type = G_TYPE_FROM_INSTANCE(operand);
+
+    parent = g_type_class_peek_parent(g_type_class_peek(type));
+
+    result = parent->store(G_ARCH_OPERAND(operand), storage, pbuf);
+
+    if (result)
+        result = _g_arch_operand_store_inner_instances(operand, storage, pbuf, true);
+
+    return result;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : operand = élément GLib à consulter.                          *
+*                storage = conservateur de données à manipuler ou NULL.       *
+*                pbuf    = zone tampon à remplir.                             *
+*                fixed   = précise si le nombre d'opérande est fixe ou non.   *
+*                                                                             *
+*  Description : Sauvegarde un opérande dans un tampon de façon générique.    *
+*                                                                             *
+*  Retour      : Bilan de l'opération.                                        *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+bool g_arch_operand_store_generic_variadic(GArchOperand *operand, GObjectStorage *storage, packed_buffer_t *pbuf)
+{
+    bool result;                            /* Bilan à retourner           */
+    GType type;                             /* Type d'opérande manipulé    */
+    GArchOperandClass *parent;              /* Classe parente à consulter  */
+
+    type = G_TYPE_FROM_INSTANCE(operand);
+
+    parent = g_type_class_peek_parent(g_type_class_peek(type));
+
+    result = parent->store(G_ARCH_OPERAND(operand), storage, pbuf);
+
+    if (result)
+        result = _g_arch_operand_store_inner_instances(operand, storage, pbuf, false);
+
+    return result;
+
+}
diff --git a/src/arch/operand-int.h b/src/arch/operand-int.h
index dc505b6..d424e94 100644
--- a/src/arch/operand-int.h
+++ b/src/arch/operand-int.h
@@ -26,6 +26,11 @@
 
 
 #include "operand.h"
+
+
+#include <stdbool.h>
+
+
 #include "../analysis/storage/storage.h"
 #include "../glibext/objhole.h"
 
@@ -143,4 +148,41 @@ bool _g_arch_operand_unset_flag(GArchOperand *, ArchOperandFlag, bool);
 
 
 
+/* ------------------------ CONTROLE DU VOLUME DES INSTANCES ------------------------ */
+
+
+/* Fournit une liste de candidats embarqués par un candidat. */
+GArchOperand **g_arch_operand_list_inner_instances(const GArchOperand *, size_t *);
+
+/* Met à jour une liste de candidats embarqués par un candidat. */
+void g_arch_operand_update_inner_instances(GArchOperand *, GArchOperand **, size_t);
+
+
+
+/* -------------------- CONSERVATION ET RECHARGEMENT DES DONNEES -------------------- */
+
+
+/* Charge une série d'opérandes internes depuis un tampon. */
+bool _g_arch_operand_load_inner_instances(GArchOperand *, GObjectStorage *, packed_buffer_t *, size_t);
+
+/* Charge une série d'opérandes internes depuis un tampon. */
+bool g_arch_operand_load_generic_fixed_1(GArchOperand *, GObjectStorage *, packed_buffer_t *);
+
+/* Charge une série d'opérandes internes depuis un tampon. */
+bool g_arch_operand_load_generic_fixed_3(GArchOperand *, GObjectStorage *, packed_buffer_t *);
+
+/* Charge une série d'opérandes internes depuis un tampon. */
+bool g_arch_operand_load_generic_variadic(GArchOperand *, GObjectStorage *, packed_buffer_t *);
+
+/* Sauvegarde une série d'opérandes internes dans un tampon. */
+bool _g_arch_operand_store_inner_instances(GArchOperand *, GObjectStorage *, packed_buffer_t *, bool);
+
+/* Sauvegarde un opérande dans un tampon de façon générique. */
+bool g_arch_operand_store_generic_fixed(GArchOperand *, GObjectStorage *, packed_buffer_t *);
+
+/* Sauvegarde un opérande dans un tampon de façon générique. */
+bool g_arch_operand_store_generic_variadic(GArchOperand *, GObjectStorage *, packed_buffer_t *);
+
+
+
 #endif  /* _ARCH_OPERAND_INT_H */
diff --git a/src/arch/operand.c b/src/arch/operand.c
index 81aa633..f262373 100644
--- a/src/arch/operand.c
+++ b/src/arch/operand.c
@@ -69,10 +69,10 @@ static int _g_arch_operand_compare(const GArchOperand *, const GArchOperand *, b
 
 
 /* Fournit une liste de candidats embarqués par un candidat. */
-static GArchOperand **g_arch_operand_list_inner_instances(const GArchOperand *, size_t *);
+GArchOperand **g_arch_operand_list_inner_instances(const GArchOperand *, size_t *);
 
 /* Met à jour une liste de candidats embarqués par un candidat. */
-static void g_arch_operand_update_inner_instances(GArchOperand *, GArchOperand **, size_t);
+void g_arch_operand_update_inner_instances(GArchOperand *, GArchOperand **, size_t);
 
 /* Fournit l'empreinte d'un candidat à une centralisation. */
 static guint _g_arch_operand_hash(const GArchOperand *, bool);
@@ -642,7 +642,7 @@ ArchOperandFlag g_arch_operand_get_flags(const GArchOperand *operand)
 *                                                                             *
 ******************************************************************************/
 
-static GArchOperand **g_arch_operand_list_inner_instances(const GArchOperand *operand, size_t *count)
+GArchOperand **g_arch_operand_list_inner_instances(const GArchOperand *operand, size_t *count)
 {
     GArchOperand **result;                  /* Instances à retourner       */
     GArchOperandClass *class;               /* Classe associée à l'objet   */
@@ -677,7 +677,7 @@ static GArchOperand **g_arch_operand_list_inner_instances(const GArchOperand *op
 *                                                                             *
 ******************************************************************************/
 
-static void g_arch_operand_update_inner_instances(GArchOperand *operand, GArchOperand **instances, size_t count)
+void g_arch_operand_update_inner_instances(GArchOperand *operand, GArchOperand **instances, size_t count)
 {
     GArchOperandClass *class;               /* Classe associée à l'objet   */
 
-- 
cgit v0.11.2-87-g4458