From 5958d9b25f806df73cd0634de2c9475eb6497e8c Mon Sep 17 00:00:00 2001
From: Cyrille Bagard <nocbos@gmail.com>
Date: Sun, 4 Jul 2021 19:06:28 +0200
Subject: Store and load binary contents on demand.

---
 .../pychrysalide/analysis/contents/encapsulated.c  |   4 +
 plugins/pychrysalide/analysis/contents/file.c      |  10 +-
 plugins/pychrysalide/analysis/contents/memory.c    |   4 +
 .../pychrysalide/analysis/contents/restricted.c    |   4 +
 plugins/pychrysalide/analysis/storage/storage.c    | 115 +++-
 src/analysis/content.c                             |   4 +-
 src/analysis/contents/Makefile.am                  |   1 +
 src/analysis/contents/encapsulated.c               | 168 +++++
 src/analysis/contents/file.c                       | 748 ++-------------------
 src/analysis/contents/memory-int.h                 |  56 ++
 src/analysis/contents/memory.c                     | 431 ++++++++++--
 src/analysis/contents/restricted.c                 |  89 +++
 src/analysis/storage/serialize.c                   |   2 +-
 src/analysis/storage/storage-int.h                 |   2 +-
 src/analysis/storage/storage.c                     | 349 +++++++++-
 src/analysis/storage/storage.h                     |  10 +-
 src/analysis/storage/tpmem.c                       |  22 +-
 src/analysis/type.c                                |   1 +
 src/analysis/types/array.c                         |   1 +
 src/analysis/types/basic.c                         |   1 +
 src/analysis/types/cse.c                           |   1 +
 src/analysis/types/encaps.c                        |   1 +
 src/analysis/types/expr.c                          |   1 +
 src/analysis/types/override.c                      |   1 +
 src/analysis/types/proto.c                         |   1 +
 src/analysis/types/template.c                      |   1 +
 tests/analysis/storage/storage.py                  |  81 +++
 27 files changed, 1286 insertions(+), 823 deletions(-)
 create mode 100644 src/analysis/contents/memory-int.h
 create mode 100644 tests/analysis/storage/storage.py

diff --git a/plugins/pychrysalide/analysis/contents/encapsulated.c b/plugins/pychrysalide/analysis/contents/encapsulated.c
index ef26caa..03fce54 100644
--- a/plugins/pychrysalide/analysis/contents/encapsulated.c
+++ b/plugins/pychrysalide/analysis/contents/encapsulated.c
@@ -32,6 +32,7 @@
 
 
 #include "../content.h"
+#include "../storage/serialize.h"
 #include "../../access.h"
 #include "../../helpers.h"
 
@@ -310,6 +311,9 @@ bool ensure_python_encaps_content_is_registered(void)
 
         dict = PyModule_GetDict(module);
 
+        if (!ensure_python_serializable_object_is_registered())
+            return false;
+
         if (!register_class_for_pygobject(dict, G_TYPE_ENCAPS_CONTENT, type, &PyGObject_Type))
             return false;
 
diff --git a/plugins/pychrysalide/analysis/contents/file.c b/plugins/pychrysalide/analysis/contents/file.c
index 93a1ce8..4786cdb 100644
--- a/plugins/pychrysalide/analysis/contents/file.c
+++ b/plugins/pychrysalide/analysis/contents/file.c
@@ -31,6 +31,8 @@
 #include <analysis/contents/file.h>
 
 
+#include "memory.h"
+#include "../storage/serialize.h"
 #include "../../access.h"
 #include "../../helpers.h"
 
@@ -196,7 +198,13 @@ bool ensure_python_file_content_is_registered(void)
 
         dict = PyModule_GetDict(module);
 
-        if (!register_class_for_pygobject(dict, G_TYPE_FILE_CONTENT, type, &PyGObject_Type))
+        if (!ensure_python_memory_content_is_registered())
+            return false;
+
+        if (!ensure_python_serializable_object_is_registered())
+            return false;
+
+        if (!register_class_for_pygobject(dict, G_TYPE_FILE_CONTENT, type, get_python_memory_content_type()))
             return false;
 
     }
diff --git a/plugins/pychrysalide/analysis/contents/memory.c b/plugins/pychrysalide/analysis/contents/memory.c
index 8926300..37b098d 100644
--- a/plugins/pychrysalide/analysis/contents/memory.c
+++ b/plugins/pychrysalide/analysis/contents/memory.c
@@ -31,6 +31,7 @@
 #include <analysis/contents/memory.h>
 
 
+#include "../storage/serialize.h"
 #include "../../access.h"
 #include "../../helpers.h"
 
@@ -164,6 +165,9 @@ bool ensure_python_memory_content_is_registered(void)
 
         dict = PyModule_GetDict(module);
 
+        if (!ensure_python_serializable_object_is_registered())
+            return false;
+
         if (!register_class_for_pygobject(dict, G_TYPE_MEMORY_CONTENT, type, &PyGObject_Type))
             return false;
 
diff --git a/plugins/pychrysalide/analysis/contents/restricted.c b/plugins/pychrysalide/analysis/contents/restricted.c
index bbe364a..703f79b 100644
--- a/plugins/pychrysalide/analysis/contents/restricted.c
+++ b/plugins/pychrysalide/analysis/contents/restricted.c
@@ -35,6 +35,7 @@
 
 
 #include "../content.h"
+#include "../storage/serialize.h"
 #include "../../access.h"
 #include "../../helpers.h"
 #include "../../arch/vmpa.h"
@@ -200,6 +201,9 @@ bool ensure_python_restricted_content_is_registered(void)
 
         dict = PyModule_GetDict(module);
 
+        if (!ensure_python_serializable_object_is_registered())
+            return false;
+
         if (!register_class_for_pygobject(dict, G_TYPE_RESTRICTED_CONTENT, type, &PyGObject_Type))
             return false;
 
diff --git a/plugins/pychrysalide/analysis/storage/storage.c b/plugins/pychrysalide/analysis/storage/storage.c
index 107980e..7c03be0 100644
--- a/plugins/pychrysalide/analysis/storage/storage.c
+++ b/plugins/pychrysalide/analysis/storage/storage.c
@@ -33,7 +33,6 @@
 
 
 #include "serialize.h"
-#include "../loaded.h"
 #include "../../access.h"
 #include "../../helpers.h"
 #include "../../common/packed.h"
@@ -54,8 +53,11 @@ static int py_object_storage_init(PyObject *, PyObject *, PyObject *);
 /* -------------------------- TAMPON POUR CODE DESASSEMBLE -------------------------- */
 
 
-/* Ajoute le support d'un nouveau groupe d'objets construits. */
-static PyObject *py_object_storage_add_backend(PyObject *, PyObject *);
+/* Charge le support d'une conservation d'objets en place. */
+static PyObject *py_object_storage_load(PyObject *, PyObject *);
+
+/* Sauvegarde le support d'une conservation d'objets en place. */
+static PyObject *py_object_storage_store(PyObject *, PyObject *);
 
 /* Charge un objet à partir de données rassemblées. */
 static PyObject *py_object_storage_load_object(PyObject *, PyObject *);
@@ -152,7 +154,7 @@ static PyObject *py_object_storage_new(PyTypeObject *type, PyObject *args, PyObj
 
 static int py_object_storage_init(PyObject *self, PyObject *args, PyObject *kwds)
 {
-    GLoadedContent *loaded;                 /* Contenu chargé et traité    */
+    const char *hash;                       /* Empreinte de contenu        */
     int ret;                                /* Bilan de lecture des args.  */
     GObjectStorage *storage;                /* Mécanismes natifs           */
 
@@ -162,14 +164,14 @@ static int py_object_storage_init(PyObject *self, PyObject *args, PyObject *kwds
     "\n"                                                                \
     "Instances can be created using the following constructor:\n"       \
     "\n"                                                                \
-    "    ObjectStorage(loaded)"                                         \
+    "    ObjectStorage(hash)"                                           \
     "\n"                                                                \
-    "Where *loaded* is a pychrysalide.analysis.LoadedContent instance"  \
-    " linked to the objects which can apply for a storage process."
+    "Where *hash* should a string built from the checksum of the"       \
+    " relative binary content linked to the storage.pychrysalide."
 
     /* Récupération des paramètres */
 
-    ret = PyArg_ParseTuple(args, "O&", convert_to_loaded_content, &loaded);
+    ret = PyArg_ParseTuple(args, "s", &hash);
     if (!ret) return -1;
 
     /* Initialisation d'un objet GLib */
@@ -181,8 +183,7 @@ static int py_object_storage_init(PyObject *self, PyObject *args, PyObject *kwds
 
     storage = G_OBJECT_STORAGE(pygobject_get(self));
 
-    storage->loaded = loaded;
-    g_object_ref(G_OBJECT(loaded));
+    storage->hash = strdup(hash);
 
     return 0;
 
@@ -200,7 +201,61 @@ static int py_object_storage_init(PyObject *self, PyObject *args, PyObject *kwds
 *  Paramètres  : self = classe représentant une mémorisation de types.        *
 *                args = arguments fournis à l'appel.                          *
 *                                                                             *
-*  Description : Ajoute le support d'un nouveau groupe d'objets construits.   *
+*  Description : Charge le support d'une conservation d'objets en place.      *
+*                                                                             *
+*  Retour      : Gestionnaire de conservations construit ou None si erreur.   *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static PyObject *py_object_storage_load(PyObject *self, PyObject *args)
+{
+    PyObject *result;                       /* Emplacement à retourner     */
+    packed_buffer_t *pbuf;                  /* Tampon de données à employer*/
+    int ret;                                /* Bilan de lecture des args.  */
+    GObjectStorage *storage;                /* Mécanismes natifs           */
+
+#define OBJECT_STORAGE_LOAD_METHOD PYTHON_METHOD_DEF                    \
+(                                                                       \
+    load, "pbuf, /",                                                    \
+    METH_STATIC | METH_VARARGS, py_object_storage,                      \
+    "Construct a new storage from a buffer.\n"                          \
+    "\n"                                                                \
+    "The *pbuf* has to be an instance of type"                          \
+    " pychrysalide.common.PackedBuffer.\n"                              \
+    "\n"                                                                \
+    "The result is a new pychrysalide.analysis.storage.ObjectStorage"   \
+    " object on success, *None* otherwise."                             \
+)
+
+    ret = PyArg_ParseTuple(args, "O&", convert_to_packed_buffer, &pbuf);
+    if (!ret) return NULL;
+
+    storage = g_object_storage_load(pbuf);
+
+    if (storage == NULL)
+    {
+        result = Py_None;
+        Py_INCREF(result);
+    }
+    else
+    {
+        result = pygobject_new(G_OBJECT(storage));
+        g_object_unref(G_OBJECT(storage));
+    }
+
+    return result;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : self = classe représentant une mémorisation de types.        *
+*                args = arguments fournis à l'appel.                          *
+*                                                                             *
+*  Description : Sauvegarde le support d'une conservation d'objets en place.  *
 *                                                                             *
 *  Retour      : Bilan de l'opération.                                        *
 *                                                                             *
@@ -208,37 +263,32 @@ static int py_object_storage_init(PyObject *self, PyObject *args, PyObject *kwds
 *                                                                             *
 ******************************************************************************/
 
-static PyObject *py_object_storage_add_backend(PyObject *self, PyObject *args)
+static PyObject *py_object_storage_store(PyObject *self, PyObject *args)
 {
-    PyObject *result;                       /* Bilan à retourner           */
-    const char *name;                       /* Désignation de groupe       */
-    const char *filename;                   /* Nom de fichier à associer   */
+    PyObject *result;                       /* Emplacement à retourner     */
+    packed_buffer_t *pbuf;                  /* Tampon de données à employer*/
     int ret;                                /* Bilan de lecture des args.  */
     GObjectStorage *storage;                /* Mécanismes natifs           */
     bool status;                            /* Bilan de l'opération        */
 
-#define OBJECT_STORAGE_ADD_BACKEND_METHOD PYTHON_METHOD_DEF         \
-(                                                                   \
-    add_backend, "$self, name, /, filename",                        \
-    METH_VARARGS, py_object_storage,                                \
-    "Add storage support for a new kind of GLib objects.\n"         \
-    "\n"                                                            \
-    "The *name* is a string label for the group of target objects"  \
-    " and the optional *filename* points to a file used to load"    \
-    " objects.\n"                                                   \
-    "\n"                                                            \
-    "The result is a boolean value indicating the status of"        \
-    " the operation: True for success, False for failure."          \
+#define OBJECT_STORAGE_STORE_METHOD PYTHON_METHOD_DEF       \
+(                                                           \
+    store, "$self, pbuf, /",                                \
+    METH_VARARGS, py_object_storage,                        \
+    "Save a storage into a buffer.\n"                       \
+    "\n"                                                    \
+    "The *pbuf* has to be an instance of type"              \
+    " pychrysalide.common.PackedBuffer.\n"                  \
+    "\n"                                                    \
+    "The result is *True* on success, *False* otherwise."   \
 )
 
-    filename = NULL;
-
-    ret = PyArg_ParseTuple(args, "s|s", &name, &filename);
+    ret = PyArg_ParseTuple(args, "O&", convert_to_packed_buffer, &pbuf);
     if (!ret) return NULL;
 
     storage = G_OBJECT_STORAGE(pygobject_get(self));
 
-    status = g_object_storage_add_backend(storage, name, filename);
+    status = g_object_storage_store(storage, pbuf);
 
     result = status ? Py_True : Py_False;
     Py_INCREF(result);
@@ -488,7 +538,8 @@ static PyObject *py_object_storage_pack_object(PyObject *self, PyObject *args)
 PyTypeObject *get_python_object_storage_type(void)
 {
     static PyMethodDef py_object_storage_methods[] = {
-        OBJECT_STORAGE_ADD_BACKEND_METHOD,
+        OBJECT_STORAGE_LOAD_METHOD,
+        OBJECT_STORAGE_STORE_METHOD,
         OBJECT_STORAGE_LOAD_OBJECT_METHOD,
         OBJECT_STORAGE_UNPACK_OBJECT_METHOD,
         OBJECT_STORAGE_STORE_OBJECT_METHOD,
diff --git a/src/analysis/content.c b/src/analysis/content.c
index 8b83261..d16619a 100644
--- a/src/analysis/content.c
+++ b/src/analysis/content.c
@@ -32,7 +32,7 @@
 
 
 #include "content-int.h"
-#include "contents/file.h"
+#include "contents/file.h" // REMME
 
 
 
@@ -42,7 +42,7 @@ static void g_binary_content_default_init(GBinContentInterface *);
 
 
 /* Détermine le type d'une interface pour la lecture de binaire. */
-G_DEFINE_INTERFACE(GBinContent, g_binary_content, G_TYPE_OBJECT)
+G_DEFINE_INTERFACE(GBinContent, g_binary_content, G_TYPE_OBJECT);
 
 
 /******************************************************************************
diff --git a/src/analysis/contents/Makefile.am b/src/analysis/contents/Makefile.am
index 4978de6..66e3cac 100644
--- a/src/analysis/contents/Makefile.am
+++ b/src/analysis/contents/Makefile.am
@@ -4,6 +4,7 @@ noinst_LTLIBRARIES  = libanalysiscontents.la
 libanalysiscontents_la_SOURCES =		\
 	encapsulated.h encapsulated.c		\
 	file.h file.c						\
+	memory-int.h						\
 	memory.h memory.c					\
 	restricted.h restricted.c
 
diff --git a/src/analysis/contents/encapsulated.c b/src/analysis/contents/encapsulated.c
index 59b0c9e..fa31aa4 100644
--- a/src/analysis/contents/encapsulated.c
+++ b/src/analysis/contents/encapsulated.c
@@ -29,6 +29,8 @@
 
 
 #include "../content-int.h"
+#include "../db/misc/rlestr.h"
+#include "../storage/serialize-int.h"
 #include "../../common/extstr.h"
 
 
@@ -61,6 +63,9 @@ static void g_encaps_content_class_init(GEncapsContentClass *);
 /* Initialise une instance de contenu de données encapsulé. */
 static void g_encaps_content_init(GEncapsContent *);
 
+/* Procède à l'initialisation de l'interface de sérialisation. */
+static void g_encaps_content_serializable_init(GSerializableObjectInterface *);
+
 /* Procède à l'initialisation de l'interface de lecture. */
 static void g_encaps_content_interface_init(GBinContentInterface *);
 
@@ -70,6 +75,12 @@ static void g_encaps_content_dispose(GEncapsContent *);
 /* Procède à la libération totale de la mémoire. */
 static void g_encaps_content_finalize(GEncapsContent *);
 
+/* Charge un contenu depuis une mémoire tampon. */
+static bool g_encaps_content_load(GEncapsContent *, GObjectStorage *, packed_buffer_t *);
+
+/* Sauvegarde un contenu dans une mémoire tampon. */
+static bool g_encaps_content_store(const GEncapsContent *, GObjectStorage *, packed_buffer_t *);
+
 /* Donne l'origine d'un contenu binaire. */
 static GBinContent *g_encaps_content_get_root(GEncapsContent *);
 
@@ -125,6 +136,7 @@ static bool g_encaps_content_read_leb128(const GEncapsContent *, vmpa2t *, leb12
 
 /* Indique le type défini par la GLib pour les contenus encapsulés. */
 G_DEFINE_TYPE_WITH_CODE(GEncapsContent, g_encaps_content, G_TYPE_OBJECT,
+                        G_IMPLEMENT_INTERFACE(G_TYPE_SERIALIZABLE_OBJECT, g_encaps_content_serializable_init)
                         G_IMPLEMENT_INTERFACE(G_TYPE_BIN_CONTENT, g_encaps_content_interface_init));
 
 
@@ -180,6 +192,26 @@ static void g_encaps_content_init(GEncapsContent *content)
 *                                                                             *
 *  Paramètres  : iface = interface GLib à initialiser.                        *
 *                                                                             *
+*  Description : Procède à l'initialisation de l'interface de sérialisation.  *
+*                                                                             *
+*  Retour      : -                                                            *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static void g_encaps_content_serializable_init(GSerializableObjectInterface *iface)
+{
+    iface->load = (load_serializable_object_cb)g_encaps_content_load;
+    iface->store = (store_serializable_object_cb)g_encaps_content_store;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : iface = interface GLib à initialiser.                        *
+*                                                                             *
 *  Description : Procède à l'initialisation de l'interface de lecture.        *
 *                                                                             *
 *  Retour      : -                                                            *
@@ -382,6 +414,142 @@ GBinContent *g_encaps_content_new_from_xml(xmlXPathContextPtr context, const cha
 
 /******************************************************************************
 *                                                                             *
+*  Paramètres  : content = é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_encaps_content_load(GEncapsContent *content, GObjectStorage *storage, packed_buffer_t *pbuf)
+{
+    bool result;                            /* Bilan à retourner           */
+    rle_string str;                         /* Chaîne à charger            */
+
+    content->base = G_BIN_CONTENT(g_object_storage_unpack_object(storage, "contents", pbuf));
+    result = (content->base != NULL);
+
+    setup_empty_rle_string(&str);
+
+    if (result)
+        result = unpack_rle_string(&str, pbuf);
+
+    if (result)
+    {
+        result = (get_rle_string(&str) != NULL);
+
+        if (result)
+            content->path = strdup(get_rle_string(&str));
+
+        exit_rle_string(&str);
+
+    }
+
+    if (result)
+    {
+        content->endpoint = G_BIN_CONTENT(g_object_storage_unpack_object(storage, "contents", pbuf));
+        result = (content->endpoint != NULL);
+    }
+
+    if (result)
+        result = unpack_rle_string(&str, pbuf);
+
+    if (result)
+    {
+        result = (get_rle_string(&str) != NULL);
+
+        if (result)
+            content->full_desc = strdup(get_rle_string(&str));
+
+        exit_rle_string(&str);
+
+    }
+
+    if (result)
+        result = unpack_rle_string(&str, pbuf);
+
+    if (result)
+    {
+        result = (get_rle_string(&str) != NULL);
+
+        if (result)
+            content->desc = strdup(get_rle_string(&str));
+
+        exit_rle_string(&str);
+
+    }
+
+    return result;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : content = é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_encaps_content_store(const GEncapsContent *content, GObjectStorage *storage, packed_buffer_t *pbuf)
+{
+    bool result;                            /* Bilan à retourner           */
+    rle_string str;                         /* Chaîne à conserver          */
+
+    result = g_object_storage_pack_object(storage, "contents", G_SERIALIZABLE_OBJECT(content->base), pbuf);
+
+    if (result)
+    {
+        init_static_rle_string(&str, content->path);
+
+        result = pack_rle_string(&str, pbuf);
+
+        exit_rle_string(&str);
+
+    }
+
+    if (result)
+        result = g_object_storage_pack_object(storage, "contents", G_SERIALIZABLE_OBJECT(content->endpoint), pbuf);
+
+    if (result)
+    {
+        init_static_rle_string(&str, content->full_desc);
+
+        result = pack_rle_string(&str, pbuf);
+
+        exit_rle_string(&str);
+
+    }
+
+    if (result)
+    {
+        init_static_rle_string(&str, content->desc);
+
+        result = pack_rle_string(&str, pbuf);
+
+        exit_rle_string(&str);
+
+    }
+
+    return result;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
 *  Paramètres  : content = contenu binaire à consulter.                       *
 *                                                                             *
 *  Description : Donne l'origine d'un contenu binaire.                        *
diff --git a/src/analysis/contents/file.c b/src/analysis/contents/file.c
index 7bb0be8..69bf510 100644
--- a/src/analysis/contents/file.c
+++ b/src/analysis/contents/file.c
@@ -32,9 +32,10 @@
 #include <sys/stat.h>
 
 
+#include "memory-int.h"
 #include "../content-int.h"
-#include "../../common/extstr.h"
-#include "../../common/pathname.h"
+#include "../db/misc/rlestr.h"
+#include "../storage/serialize-int.h"
 #include "../../core/logs.h"
 
 
@@ -42,21 +43,16 @@
 /* Contenu de données binaires issues d'un fichier (instance) */
 struct _GFileContent
 {
-    GObject parent;                         /* A laisser en premier        */
-
-    GContentAttributes *attribs;            /* Attributs liés au contenu   */
+    GMemoryContent parent;                  /* A laisser en premier        */
 
     char *filename;                         /* Fichier chargé en mémoire   */
 
-    bin_t *data;                            /* Contenu binaire représenté  */
-    mrange_t range;                         /* Couverture du binaire       */
-
 };
 
 /* Contenu de données binaires issues d'un fichier (classe) */
 struct _GFileContentClass
 {
-    GObjectClass parent;                    /* A laisser en premier        */
+    GMemoryContentClass parent;             /* A laisser en premier        */
 
 };
 
@@ -67,8 +63,8 @@ static void g_file_content_class_init(GFileContentClass *);
 /* Initialise une instance de contenu de données binaires. */
 static void g_file_content_init(GFileContent *);
 
-/* Procède à l'initialisation de l'interface de lecture. */
-static void g_file_content_interface_init(GBinContentInterface *);
+/* Procède à l'initialisation de l'interface de sérialisation. */
+static void g_file_content_serializable_init(GSerializableObjectInterface *);
 
 /* Supprime toutes les références externes. */
 static void g_file_content_dispose(GFileContent *);
@@ -76,68 +72,17 @@ static void g_file_content_dispose(GFileContent *);
 /* Procède à la libération totale de la mémoire. */
 static void g_file_content_finalize(GFileContent *);
 
-/* Associe un ensemble d'attributs au contenu binaire. */
-static void g_file_content_set_attributes(GFileContent *, GContentAttributes *);
-
-/* Fournit l'ensemble des attributs associés à un contenu. */
-static GContentAttributes *g_file_content_get_attributes(const GFileContent *);
-
-/* Donne l'origine d'un contenu binaire. */
-static GBinContent *g_file_content_get_root(GFileContent *);
-
-/* Fournit le nom associé au contenu binaire. */
-static char *g_file_content_describe(const GFileContent *, bool);
-
-/* Ecrit une sauvegarde de contenu binaire dans un fichier XML. */
-static bool g_file_content_save(const GFileContent *, xmlDocPtr, xmlXPathContextPtr, const char *, const char *);
-
-/* Fournit une empreinte unique (SHA256) pour les données. */
-static void g_file_content_compute_checksum(GFileContent *, GChecksum *);
-
-/* Détermine le nombre d'octets lisibles. */
-static phys_t g_file_content_compute_size(const GFileContent *);
-
-/* Détermine la position initiale d'un contenu. */
-static void g_file_content_compute_start_pos(const GFileContent *, vmpa2t *);
-
-/* Détermine la position finale d'un contenu. */
-static void g_file_content_compute_end_pos(const GFileContent *, vmpa2t *);
-
-/* Avance la tête de lecture d'une certaine quantité de données. */
-static bool g_file_content_seek(const GFileContent *, vmpa2t *, phys_t);
-
-/* Donne accès à une portion des données représentées. */
-static const bin_t *g_file_content_get_raw_access(const GFileContent *, vmpa2t *, phys_t);
+/* Charge un contenu depuis une mémoire tampon. */
+static bool g_file_content_load(GFileContent *, GObjectStorage *, packed_buffer_t *);
 
-/* Fournit une portion des données représentées. */
-static bool g_file_content_read_raw(const GFileContent *, vmpa2t *, phys_t, bin_t *);
-
-/* Lit un nombre non signé sur quatre bits. */
-static bool g_file_content_read_u4(const GFileContent *, vmpa2t *, bool *, uint8_t *);
-
-/* Lit un nombre non signé sur un octet. */
-static bool g_file_content_read_u8(const GFileContent *, vmpa2t *, uint8_t *);
-
-/* Lit un nombre non signé sur deux octets. */
-static bool g_file_content_read_u16(const GFileContent *, vmpa2t *, SourceEndian, uint16_t *);
-
-/* Lit un nombre non signé sur quatre octets. */
-static bool g_file_content_read_u32(const GFileContent *, vmpa2t *, SourceEndian, uint32_t *);
-
-/* Lit un nombre non signé sur huit octets. */
-static bool g_file_content_read_u64(const GFileContent *, vmpa2t *, SourceEndian, uint64_t *);
-
-/* Lit un nombre non signé encodé au format LEB128. */
-static bool g_file_content_read_uleb128(const GFileContent *, vmpa2t *, uleb128_t *);
-
-/* Lit un nombre signé encodé au format LEB128. */
-static bool g_file_content_read_leb128(const GFileContent *, vmpa2t *, leb128_t *);
+/* Sauvegarde un contenu dans une mémoire tampon. */
+static bool g_file_content_store(const GFileContent *, GObjectStorage *, packed_buffer_t *);
 
 
 
 /* Indique le type défini par la GLib pour les contenus de données. */
-G_DEFINE_TYPE_WITH_CODE(GFileContent, g_file_content, G_TYPE_OBJECT,
-                        G_IMPLEMENT_INTERFACE(G_TYPE_BIN_CONTENT, g_file_content_interface_init));
+G_DEFINE_TYPE_WITH_CODE(GFileContent, g_file_content, G_TYPE_MEMORY_CONTENT,
+                        G_IMPLEMENT_INTERFACE(G_TYPE_SERIALIZABLE_OBJECT, g_file_content_serializable_init));
 
 
 /******************************************************************************
@@ -178,20 +123,7 @@ static void g_file_content_class_init(GFileContentClass *klass)
 
 static void g_file_content_init(GFileContent *content)
 {
-    GContentAttributes *empty;              /* Jeu d'attributs vide        */
-    vmpa2t dummy;                           /* Localisation nulle          */
-
-    content->attribs = NULL;
-
-    empty = g_content_attributes_new("");
-
-    g_binary_content_set_attributes(G_BIN_CONTENT(content), empty);
-
     content->filename = NULL;
-    content->data = NULL;
-
-    init_vmpa(&dummy, VMPA_NO_PHYSICAL, VMPA_NO_VIRTUAL);
-    init_mrange(&content->range, &dummy, 0);
 
 }
 
@@ -200,7 +132,7 @@ static void g_file_content_init(GFileContent *content)
 *                                                                             *
 *  Paramètres  : iface = interface GLib à initialiser.                        *
 *                                                                             *
-*  Description : Procède à l'initialisation de l'interface de lecture.        *
+*  Description : Procède à l'initialisation de l'interface de sérialisation.  *
 *                                                                             *
 *  Retour      : -                                                            *
 *                                                                             *
@@ -208,36 +140,10 @@ static void g_file_content_init(GFileContent *content)
 *                                                                             *
 ******************************************************************************/
 
-static void g_file_content_interface_init(GBinContentInterface *iface)
+static void g_file_content_serializable_init(GSerializableObjectInterface *iface)
 {
-    iface->set_attribs = (set_content_attributes)g_file_content_set_attributes;
-    iface->get_attribs = (get_content_attributes)g_file_content_get_attributes;
-
-    iface->get_root = (get_content_root_fc)g_file_content_get_root;
-
-    iface->describe = (describe_content_fc)g_file_content_describe;
-
-    iface->save = (save_content_fc)g_file_content_save;
-
-    iface->compute_checksum = (compute_checksum_fc)g_file_content_compute_checksum;
-
-    iface->compute_size = (compute_size_fc)g_file_content_compute_size;
-    iface->compute_start_pos = (compute_start_pos_fc)g_file_content_compute_start_pos;
-    iface->compute_end_pos = (compute_end_pos_fc)g_file_content_compute_end_pos;
-
-    iface->seek = (seek_fc)g_file_content_seek;
-
-    iface->get_raw_access = (get_raw_access_fc)g_file_content_get_raw_access;
-
-    iface->read_raw = (read_raw_fc)g_file_content_read_raw;
-    iface->read_u4 = (read_u4_fc)g_file_content_read_u4;
-    iface->read_u8 = (read_u8_fc)g_file_content_read_u8;
-    iface->read_u16 = (read_u16_fc)g_file_content_read_u16;
-    iface->read_u32 = (read_u32_fc)g_file_content_read_u32;
-    iface->read_u64 = (read_u64_fc)g_file_content_read_u64;
-
-    iface->read_uleb128 = (read_uleb128_fc)g_file_content_read_uleb128;
-    iface->read_leb128 = (read_leb128_fc)g_file_content_read_leb128;
+    iface->load = (load_serializable_object_cb)g_file_content_load;
+    iface->store = (store_serializable_object_cb)g_file_content_store;
 
 }
 
@@ -256,8 +162,6 @@ static void g_file_content_interface_init(GBinContentInterface *iface)
 
 static void g_file_content_dispose(GFileContent *content)
 {
-    g_clear_object(&content->attribs);
-
     G_OBJECT_CLASS(g_file_content_parent_class)->dispose(G_OBJECT(content));
 
 }
@@ -279,9 +183,6 @@ static void g_file_content_finalize(GFileContent *content)
 {
     free(content->filename);
 
-    if (content->data != NULL)
-        free(content->data);
-
     G_OBJECT_CLASS(g_file_content_parent_class)->finalize(G_OBJECT(content));
 
 }
@@ -306,7 +207,7 @@ GBinContent *g_file_content_new(const char *filename)
     struct stat info;                       /* Informations sur le fichier */
     int ret;                                /* Bilan d'un appel            */
     void *content;                          /* Contenu brut du fichier     */
-    vmpa2t base;                            /* Localisation des données    */
+    GMemoryContent *base;                   /* Structure parente           */
 
     /* Récupération des données */
 
@@ -314,7 +215,7 @@ GBinContent *g_file_content_new(const char *filename)
     if (fd == -1)
     {
         LOG_ERROR_N("open");
-        goto gbcnff_error;
+        goto file_error;
     }
 
     ret = fstat(fd, &info);
@@ -322,7 +223,7 @@ GBinContent *g_file_content_new(const char *filename)
     {
         close(fd);
         LOG_ERROR_N("fstat");
-        goto gbcnff_error;
+        goto file_error;
     }
 
     content = mmap(NULL, info.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
@@ -330,7 +231,7 @@ GBinContent *g_file_content_new(const char *filename)
     {
         close(fd);
         LOG_ERROR_N("mmap");
-        goto gbcnff_error;
+        goto file_error;
     }
 
     /* Constitution du contenu officiel */
@@ -339,18 +240,19 @@ GBinContent *g_file_content_new(const char *filename)
 
     result->filename = strdup(filename);
 
-    result->data = (bin_t *)malloc(info.st_size);
-    memcpy(result->data, content, info.st_size);
+    base = G_MEMORY_CONTENT(result);
+
+    base->data = malloc(info.st_size);
+    memcpy(base->data, content, info.st_size);
+
+    base->length = info.st_size;
 
     munmap(content, info.st_size);
     close(fd);
 
-    init_vmpa(&base, 0, VMPA_NO_VIRTUAL);
-    init_mrange(&result->range, &base, info.st_size);
-
     return G_BIN_CONTENT(result);
 
- gbcnff_error:
+ file_error:
 
     return NULL;
 
@@ -373,6 +275,11 @@ GBinContent *g_file_content_new(const char *filename)
 
 GBinContent *g_file_content_new_from_xml(xmlXPathContextPtr context, const char *path, const char *base)
 {
+    return NULL;
+
+#if 0
+
+
     GBinContent *result;                    /* Adresse à retourner         */
     char *access;                           /* Chemin pour une sous-config.*/
     char *filename;                         /* Chemin du binaire à charger */
@@ -406,322 +313,17 @@ GBinContent *g_file_content_new_from_xml(xmlXPathContextPtr context, const char
     }
 
     return result;
-
-}
-
-
-/******************************************************************************
-*                                                                             *
-*  Paramètres  : content = contenu binaire à actualiser.                      *
-*                attribs = jeu d'attributs à lier au contenu courant.         *
-*                                                                             *
-*  Description : Associe un ensemble d'attributs au contenu binaire.          *
-*                                                                             *
-*  Retour      : -                                                            *
-*                                                                             *
-*  Remarques   : -                                                            *
-*                                                                             *
-******************************************************************************/
-
-static void g_file_content_set_attributes(GFileContent *content, GContentAttributes *attribs)
-{
-    content->attribs = attribs;
-
-}
-
-
-/******************************************************************************
-*                                                                             *
-*  Paramètres  : content = contenu binaire à consulter.                       *
-*                                                                             *
-*  Description : Fournit l'ensemble des attributs associés à un contenu.      *
-*                                                                             *
-*  Retour      : Jeu d'attributs liés au contenu courant.                     *
-*                                                                             *
-*  Remarques   : -                                                            *
-*                                                                             *
-******************************************************************************/
-
-static GContentAttributes *g_file_content_get_attributes(const GFileContent *content)
-{
-    GContentAttributes *result;             /* Instance à retourner        */
-
-    result = content->attribs;
-
-    return result;
-
-}
-
-
-/******************************************************************************
-*                                                                             *
-*  Paramètres  : content = contenu binaire à consulter.                       *
-*                                                                             *
-*  Description : Donne l'origine d'un contenu binaire.                        *
-*                                                                             *
-*  Retour      : Contenu à l'origine du contenu courant.                      *
-*                                                                             *
-*  Remarques   : -                                                            *
-*                                                                             *
-******************************************************************************/
-
-static GBinContent *g_file_content_get_root(GFileContent *content)
-{
-    GBinContent *result;                    /* Contenu en place à renvoyer */
-
-    result = G_BIN_CONTENT(content);
-
-    return result;
-
+#endif
 }
 
 
 /******************************************************************************
 *                                                                             *
-*  Paramètres  : content = contenu binaire à consulter.                       *
-*                full    = précise s'il s'agit d'une version longue ou non.   *
-*                                                                             *
-*  Description : Fournit le nom associé au contenu binaire.                   *
+*  Paramètres  : content = élément GLib à constuire.                          *
+*                storage = conservateur de données à manipuler ou NULL.       *
+*                pbuf    = zone tampon à lire.                                *
 *                                                                             *
-*  Retour      : Nom de fichier avec chemin absolu au besoin.                 *
-*                                                                             *
-*  Remarques   : -                                                            *
-*                                                                             *
-******************************************************************************/
-
-static char *g_file_content_describe(const GFileContent *content, bool full)
-{
-    char *result;                           /* Description à retourner     */
-    const char *sep;                        /* Caractère de séparation     */
-
-    if (full)
-        result = strdup(content->filename);
-
-    else
-    {
-        sep = strrchr(content->filename, G_DIR_SEPARATOR);
-
-        if (sep == NULL)
-            result = strdup(content->filename);
-
-        else
-            result = strdup(++sep);
-
-    }
-
-    return result;
-
-}
-
-
-/******************************************************************************
-*                                                                             *
-*  Paramètres  : content = contenu binaire à traiter.                         *
-*                xdoc    = structure XML en cours d'édition.                  *
-*                context = contexte à utiliser pour les recherches.           *
-*                path    = chemin d'accès réservé au binaire.                 *
-*                base    = référence au lieu d'enregistrement du projet.      *
-*                                                                             *
-*  Description : Ecrit une sauvegarde de contenu binaire dans un fichier XML. *
-*                                                                             *
-*  Retour      : true si l'opération a bien tourné, false sinon.              *
-*                                                                             *
-*  Remarques   : -                                                            *
-*                                                                             *
-******************************************************************************/
-
-static bool g_file_content_save(const GFileContent *content, xmlDocPtr xdoc, xmlXPathContextPtr context, const char *path, const char *base)
-{
-    bool result;                            /* Bilan à faire remonter      */
-    char *access;                           /* Chemin d'accès à un élément */
-    char *relative;                         /* Chemin d'accès relatif      */
-
-    /* Type */
-
-    result = add_string_attribute_to_node(xdoc, context, path, "type", "file");
-    if (!result) goto gfcs_exit;
-
-    /* Nom du fichier associé */
-
-    access = strdup(path);
-    access = stradd(access, "/Filename");
-
-    relative = build_relative_filename(base, content->filename);
-
-    result = add_content_to_node(xdoc, context, access, relative);
-
-    free(relative);
-    free(access);
-
- gfcs_exit:
-
-    return result;
-
-}
-
-
-/******************************************************************************
-*                                                                             *
-*  Paramètres  : content  = contenu binaire à venir lire.                     *
-*                checksum = empreinte de zone mémoire à compléter.            *
-*                                                                             *
-*  Description : Calcule une empreinte unique (SHA256) pour les données.      *
-*                                                                             *
-*  Retour      : -                                                            *
-*                                                                             *
-*  Remarques   : -                                                            *
-*                                                                             *
-******************************************************************************/
-
-static void g_file_content_compute_checksum(GFileContent *content, GChecksum *checksum)
-{
-    g_checksum_update(checksum, content->data, get_mrange_length(&content->range));
-
-}
-
-
-/******************************************************************************
-*                                                                             *
-*  Paramètres  : content = contenu binaire à venir lire.                      *
-*                                                                             *
-*  Description : Détermine le nombre d'octets lisibles.                       *
-*                                                                             *
-*  Retour      : Quantité représentée.                                        *
-*                                                                             *
-*  Remarques   : -                                                            *
-*                                                                             *
-******************************************************************************/
-
-static phys_t g_file_content_compute_size(const GFileContent *content)
-{
-    phys_t result;                          /* Quantité trouvée à retourner*/
-
-    result = get_mrange_length(&content->range);
-
-    return result;
-
-}
-
-
-/******************************************************************************
-*                                                                             *
-*  Paramètres  : content = contenu binaire à venir lire.                      *
-*                pos     = position initiale. [OUT]                           *
-*                                                                             *
-*  Description : Détermine la position initiale d'un contenu.                 *
-*                                                                             *
-*  Retour      : -                                                            *
-*                                                                             *
-*  Remarques   : -                                                            *
-*                                                                             *
-******************************************************************************/
-
-static void g_file_content_compute_start_pos(const GFileContent *content, vmpa2t *pos)
-{
-    copy_vmpa(pos, get_mrange_addr(&content->range));
-
-}
-
-
-/******************************************************************************
-*                                                                             *
-*  Paramètres  : content = contenu binaire à venir lire.                      *
-*                pos     = position finale (exclusive). [OUT]                 *
-*                                                                             *
-*  Description : Détermine la position finale d'un contenu.                   *
-*                                                                             *
-*  Retour      : -                                                            *
-*                                                                             *
-*  Remarques   : -                                                            *
-*                                                                             *
-******************************************************************************/
-
-static void g_file_content_compute_end_pos(const GFileContent *content, vmpa2t *pos)
-{
-    compute_mrange_end_addr(&content->range, pos);
-
-}
-
-
-/******************************************************************************
-*                                                                             *
-*  Paramètres  : content = contenu binaire à venir lire.                      *
-*                addr    = position de la tête de lecture.                    *
-*                length  = quantité d'octets à provisionner.                  *
-*                                                                             *
-*  Description : Avance la tête de lecture d'une certaine quantité de données.*
-*                                                                             *
-*  Retour      : Bilan de l'opération : true en cas de succès, false sinon.   *
-*                                                                             *
-*  Remarques   : -                                                            *
-*                                                                             *
-******************************************************************************/
-
-static bool g_file_content_seek(const GFileContent *content, vmpa2t *addr, phys_t length)
-{
-    bool result;                            /* Bilan à retourner           */
-    phys_t offset;                          /* Emplacement de départ       */
-
-    result = false;
-
-    offset = get_phy_addr(addr);
-
-    if (length > get_mrange_length(&content->range))
-        goto gfcs_done;
-
-    if (offset > (get_mrange_length(&content->range) - length))
-        goto gfcs_done;
-
-    advance_vmpa(addr, length);
-
-    result = true;
-
- gfcs_done:
-
-    return result;
-
-}
-
-
-/******************************************************************************
-*                                                                             *
-*  Paramètres  : content = contenu binaire à venir lire.                      *
-*                addr    = position de la tête de lecture.                    *
-*                length  = quantité d'octets à lire.                          *
-*                                                                             *
-*  Description : Donne accès à une portion des données représentées.          *
-*                                                                             *
-*  Retour      : Pointeur vers les données à lire ou NULL en cas d'échec.     *
-*                                                                             *
-*  Remarques   : -                                                            *
-*                                                                             *
-******************************************************************************/
-
-static const bin_t *g_file_content_get_raw_access(const GFileContent *content, vmpa2t *addr, phys_t length)
-{
-    const bin_t *result;                    /* Données utiles à renvoyer   */
-    phys_t offset;                          /* Emplacement de départ       */
-    bool allowed;                           /* Capacité d'avancer ?        */
-
-    offset = get_phy_addr(addr);
-
-    allowed = g_file_content_seek(content, addr, length);
-
-    result = (allowed ? &content->data[offset] : NULL);
-
-    return result;
-
-}
-
-
-/******************************************************************************
-*                                                                             *
-*  Paramètres  : content = contenu binaire à venir lire.                      *
-*                addr    = position de la tête de lecture.                    *
-*                length  = quantité d'octets à lire.                          *
-*                out     = réceptacle disponible pour ces données. [OUT]      *
-*                                                                             *
-*  Description : Fournit une portion des données représentées.                *
+*  Description : Charge un contenu depuis une mémoire tampon.                 *
 *                                                                             *
 *  Retour      : Bilan de l'opération.                                        *
 *                                                                             *
@@ -729,210 +331,31 @@ static const bin_t *g_file_content_get_raw_access(const GFileContent *content, v
 *                                                                             *
 ******************************************************************************/
 
-static bool g_file_content_read_raw(const GFileContent *content, vmpa2t *addr, phys_t length, bin_t *out)
-{
-    bool result;                            /* Bilan à remonter            */
-    const bin_t *data;                      /* Pointeur vers données utiles*/
-
-    data = g_file_content_get_raw_access(content, addr, length);
-
-    if (data != NULL)
-    {
-        result = true;
-        memcpy(out, data, length);
-    }
-    else
-        result = false;
-
-    return result;
-
-}
-
-
-/******************************************************************************
-*                                                                             *
-*  Paramètres  : content = contenu binaire à venir lire.                      *
-*                addr    = position de la tête de lecture.                    *
-*                low     = position éventuelle des 4 bits visés. [OUT]        *
-*                val     = lieu d'enregistrement de la lecture. [OUT]         *
-*                                                                             *
-*  Description : Lit un nombre non signé sur quatre bits.                     *
-*                                                                             *
-*  Retour      : Bilan de l'opération : true en cas de succès, false sinon.   *
-*                                                                             *
-*  Remarques   : -                                                            *
-*                                                                             *
-******************************************************************************/
-
-static bool g_file_content_read_u4(const GFileContent *content, vmpa2t *addr, bool *low, uint8_t *val)
-{
-    bool result;                            /* Bilan de lecture à renvoyer */
-    phys_t pos;                             /* Tête de lecture courante    */
-    phys_t length;                          /* Taille de la surface dispo. */
-
-    pos = get_phy_addr(addr);
-
-    if (pos == VMPA_NO_PHYSICAL)
-        return false;
-
-    length = get_mrange_length(&content->range);
-
-    result = read_u4(val, content->data, &pos, length, low);
-
-    if (result)
-        advance_vmpa(addr, pos - get_phy_addr(addr));
-
-    return result;
-
-}
-
-
-
-/******************************************************************************
-*                                                                             *
-*  Paramètres  : content = contenu binaire à venir lire.                      *
-*                addr    = position de la tête de lecture.                    *
-*                val     = lieu d'enregistrement de la lecture. [OUT]         *
-*                                                                             *
-*  Description : Lit un nombre non signé sur un octet.                        *
-*                                                                             *
-*  Retour      : Bilan de l'opération : true en cas de succès, false sinon.   *
-*                                                                             *
-*  Remarques   : -                                                            *
-*                                                                             *
-******************************************************************************/
-
-static bool g_file_content_read_u8(const GFileContent *content, vmpa2t *addr, uint8_t *val)
+static bool g_file_content_load(GFileContent *content, GObjectStorage *storage, packed_buffer_t *pbuf)
 {
-    bool result;                            /* Bilan de lecture à renvoyer */
-    phys_t pos;                             /* Tête de lecture courante    */
-    phys_t length;                          /* Taille de la surface dispo. */
-
-    pos = get_phy_addr(addr);
+    bool result;                            /* Bilan à retourner           */
+    GSerializableObjectIface *parent_iface; /* Interface du niveau parent  */
+    rle_string str;                         /* Chaîne à charger            */
 
-    if (pos == VMPA_NO_PHYSICAL)
-        return false;
+    parent_iface = g_type_interface_peek(g_file_content_parent_class, G_TYPE_SERIALIZABLE_OBJECT);
 
-    length = get_mrange_length(&content->range);
+    result = parent_iface->load(G_SERIALIZABLE_OBJECT(content), storage, pbuf);
 
-    result = read_u8(val, content->data, &pos, length);
+    setup_empty_rle_string(&str);
 
     if (result)
-        advance_vmpa(addr, pos - get_phy_addr(addr));
-
-    return result;
-
-}
-
-
-/******************************************************************************
-*                                                                             *
-*  Paramètres  : content = contenu binaire à venir lire.                      *
-*                addr    = position de la tête de lecture.                    *
-*                endian  = ordre des bits dans la source.                     *
-*                val     = lieu d'enregistrement de la lecture. [OUT]         *
-*                                                                             *
-*  Description : Lit un nombre non signé sur deux octets.                     *
-*                                                                             *
-*  Retour      : Bilan de l'opération : true en cas de succès, false sinon.   *
-*                                                                             *
-*  Remarques   : -                                                            *
-*                                                                             *
-******************************************************************************/
-
-static bool g_file_content_read_u16(const GFileContent *content, vmpa2t *addr, SourceEndian endian, uint16_t *val)
-{
-    bool result;                            /* Bilan de lecture à renvoyer */
-    phys_t pos;                             /* Tête de lecture courante    */
-    phys_t length;                          /* Taille de la surface dispo. */
-
-    pos = get_phy_addr(addr);
-
-    if (pos == VMPA_NO_PHYSICAL)
-        return false;
-
-    length = get_mrange_length(&content->range);
-
-    result = read_u16(val, content->data, &pos, length, endian);
+        result = unpack_rle_string(&str, pbuf);
 
     if (result)
-        advance_vmpa(addr, pos - get_phy_addr(addr));
-
-    return result;
-
-}
-
-
-/******************************************************************************
-*                                                                             *
-*  Paramètres  : content = contenu binaire à venir lire.                      *
-*                addr    = position de la tête de lecture.                    *
-*                endian  = ordre des bits dans la source.                     *
-*                val     = lieu d'enregistrement de la lecture. [OUT]         *
-*                                                                             *
-*  Description : Lit un nombre non signé sur quatre octets.                   *
-*                                                                             *
-*  Retour      : Bilan de l'opération : true en cas de succès, false sinon.   *
-*                                                                             *
-*  Remarques   : -                                                            *
-*                                                                             *
-******************************************************************************/
-
-static bool g_file_content_read_u32(const GFileContent *content, vmpa2t *addr, SourceEndian endian, uint32_t *val)
-{
-    bool result;                            /* Bilan de lecture à renvoyer */
-    phys_t pos;                             /* Tête de lecture courante    */
-    phys_t length;                          /* Taille de la surface dispo. */
-
-    pos = get_phy_addr(addr);
-
-    if (pos == VMPA_NO_PHYSICAL)
-        return false;
-
-    length = get_mrange_length(&content->range);
-
-    result = read_u32(val, content->data, &pos, length, endian);
-
-    if (result)
-        advance_vmpa(addr, pos - get_phy_addr(addr));
-
-    return result;
-
-}
-
-
-/******************************************************************************
-*                                                                             *
-*  Paramètres  : content = contenu binaire à venir lire.                      *
-*                addr    = position de la tête de lecture.                    *
-*                endian  = ordre des bits dans la source.                     *
-*                val     = lieu d'enregistrement de la lecture. [OUT]         *
-*                                                                             *
-*  Description : Lit un nombre non signé sur huit octets.                     *
-*                                                                             *
-*  Retour      : Bilan de l'opération : true en cas de succès, false sinon.   *
-*                                                                             *
-*  Remarques   : -                                                            *
-*                                                                             *
-******************************************************************************/
-
-static bool g_file_content_read_u64(const GFileContent *content, vmpa2t *addr, SourceEndian endian, uint64_t *val)
-{
-    bool result;                            /* Bilan de lecture à renvoyer */
-    phys_t pos;                             /* Tête de lecture courante    */
-    phys_t length;                          /* Taille de la surface dispo. */
-
-    pos = get_phy_addr(addr);
-
-    if (pos == VMPA_NO_PHYSICAL)
-        return false;
+    {
+        result = (get_rle_string(&str) != NULL);
 
-    length = get_mrange_length(&content->range);
+        if (result)
+            content->filename = strdup(get_rle_string(&str));
 
-    result = read_u64(val, content->data, &pos, length, endian);
+        exit_rle_string(&str);
 
-    if (result)
-        advance_vmpa(addr, pos - get_phy_addr(addr));
+    }
 
     return result;
 
@@ -941,72 +364,37 @@ static bool g_file_content_read_u64(const GFileContent *content, vmpa2t *addr, S
 
 /******************************************************************************
 *                                                                             *
-*  Paramètres  : content = contenu binaire à venir lire.                      *
-*                addr    = position de la tête de lecture.                    *
-*                val     = lieu d'enregistrement de la lecture. [OUT]         *
+*  Paramètres  : content = élément GLib à consulter.                          *
+*                storage = conservateur de données à manipuler ou NULL.       *
+*                pbuf    = zone tampon à remplir.                             *
 *                                                                             *
-*  Description : Lit un nombre non signé encodé au format LEB128.             *
+*  Description : Sauvegarde un contenu dans une mémoire tampon.               *
 *                                                                             *
-*  Retour      : Bilan de l'opération : true en cas de succès, false sinon.   *
+*  Retour      : Bilan de l'opération.                                        *
 *                                                                             *
 *  Remarques   : -                                                            *
 *                                                                             *
 ******************************************************************************/
 
-static bool g_file_content_read_uleb128(const GFileContent *content, vmpa2t *addr, uleb128_t *val)
+static bool g_file_content_store(const GFileContent *content, GObjectStorage *storage, packed_buffer_t *pbuf)
 {
-    bool result;                            /* Bilan de lecture à renvoyer */
-    phys_t pos;                             /* Tête de lecture courante    */
-    phys_t length;                          /* Taille de la surface dispo. */
-
-    pos = get_phy_addr(addr);
-
-    if (pos == VMPA_NO_PHYSICAL)
-        return false;
+    bool result;                            /* Bilan à retourner           */
+    GSerializableObjectIface *parent_iface; /* Interface du niveau parent  */
+    rle_string str;                         /* Chaîne à conserver          */
 
-    length = get_mrange_length(&content->range);
+    parent_iface = g_type_interface_peek(g_file_content_parent_class, G_TYPE_SERIALIZABLE_OBJECT);
 
-    result = read_uleb128(val, content->data, &pos, length);
+    result = parent_iface->store(G_SERIALIZABLE_OBJECT(content), storage, pbuf);
 
     if (result)
-        advance_vmpa(addr, pos - get_phy_addr(addr));
-
-    return result;
-
-}
-
-
-/******************************************************************************
-*                                                                             *
-*  Paramètres  : content = contenu binaire à venir lire.                      *
-*                addr    = position de la tête de lecture.                    *
-*                val     = lieu d'enregistrement de la lecture. [OUT]         *
-*                                                                             *
-*  Description : Lit un nombre signé encodé au format LEB128.                 *
-*                                                                             *
-*  Retour      : Bilan de l'opération : true en cas de succès, false sinon.   *
-*                                                                             *
-*  Remarques   : -                                                            *
-*                                                                             *
-******************************************************************************/
-
-static bool g_file_content_read_leb128(const GFileContent *content, vmpa2t *addr, leb128_t *val)
-{
-    bool result;                            /* Bilan de lecture à renvoyer */
-    phys_t pos;                             /* Tête de lecture courante    */
-    phys_t length;                          /* Taille de la surface dispo. */
-
-    pos = get_phy_addr(addr);
-
-    if (pos == VMPA_NO_PHYSICAL)
-        return false;
+    {
+        init_static_rle_string(&str, content->filename);
 
-    length = get_mrange_length(&content->range);
+        result = pack_rle_string(&str, pbuf);
 
-    result = read_leb128(val, content->data, &pos, length);
+        exit_rle_string(&str);
 
-    if (result)
-        advance_vmpa(addr, pos - get_phy_addr(addr));
+    }
 
     return result;
 
diff --git a/src/analysis/contents/memory-int.h b/src/analysis/contents/memory-int.h
new file mode 100644
index 0000000..621e4a6
--- /dev/null
+++ b/src/analysis/contents/memory-int.h
@@ -0,0 +1,56 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * memory-int.h - prototypes internes pour le chargement de données binaires à partir de la mémoire
+ *
+ * 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/>.
+ */
+
+
+#ifndef _ANALYSIS_CONTENTS_MEMORY_INT_H
+#define _ANALYSIS_CONTENTS_MEMORY_INT_H
+
+
+#include "memory.h"
+
+
+
+/* Contenu de données binaires résidant en mémoire (instance) */
+struct _GMemoryContent
+{
+    GObject parent;                         /* A laisser en premier        */
+
+    GContentAttributes *attribs;            /* Attributs liés au contenu   */
+
+    bin_t *data;                            /* Contenu binaire représenté  */
+    phys_t length;                          /* Taille totale du contenu    */
+
+    char *full_desc;                        /* Description de l'ensemble   */
+    char *desc;                             /* Description de l'ensemble   */
+
+};
+
+/* Contenu de données binaires résidant en mémoire (classe) */
+struct _GMemoryContentClass
+{
+    GObjectClass parent;                    /* A laisser en premier        */
+
+};
+
+
+
+#endif  /* _ANALYSIS_CONTENTS_MEMORY_INT_H */
diff --git a/src/analysis/contents/memory.c b/src/analysis/contents/memory.c
index a37a7d4..5d90694 100644
--- a/src/analysis/contents/memory.c
+++ b/src/analysis/contents/memory.c
@@ -33,37 +33,24 @@
 #include <i18n.h>
 
 
-#include "file.h"
+#include "memory-int.h"
 #include "../content-int.h"
+#include "../db/misc/rlestr.h"
+#include "../storage/serialize-int.h"
 #include "../../common/extstr.h"
-#include "../../common/io.h"
+#include "../../core/logs.h"
 
 
 
-/* Contenu de données binaires résidant en mémoire (instance) */
-struct _GMemoryContent
-{
-    GObject parent;                         /* A laisser en premier        */
-
-    char *storage;                          /* Conservation des données    */
-    GBinContent *backend;                   /* Exploitation des données    */
-
-};
-
-/* Contenu de données binaires résidant en mémoire (classe) */
-struct _GMemoryContentClass
-{
-    GObjectClass parent;                    /* A laisser en premier        */
-
-};
-
-
 /* Initialise la classe des contenus de données en mémoire. */
 static void g_memory_content_class_init(GMemoryContentClass *);
 
 /* Initialise une instance de contenu de données en mémoire. */
 static void g_memory_content_init(GMemoryContent *);
 
+/* Procède à l'initialisation de l'interface de sérialisation. */
+static void g_memory_content_serializable_init(GSerializableObjectInterface *);
+
 /* Procède à l'initialisation de l'interface de lecture. */
 static void g_memory_content_interface_init(GBinContentInterface *);
 
@@ -73,6 +60,18 @@ static void g_memory_content_dispose(GMemoryContent *);
 /* Procède à la libération totale de la mémoire. */
 static void g_memory_content_finalize(GMemoryContent *);
 
+/* Charge un contenu depuis une mémoire tampon. */
+static bool g_memory_content_load(GMemoryContent *, GObjectStorage *, packed_buffer_t *);
+
+/* Sauvegarde un contenu dans une mémoire tampon. */
+static bool g_memory_content_store(const GMemoryContent *, GObjectStorage *, packed_buffer_t *);
+
+/* Associe un ensemble d'attributs au contenu binaire. */
+static void g_memory_content_set_attributes(GMemoryContent *, GContentAttributes *);
+
+/* Fournit l'ensemble des attributs associés à un contenu. */
+static GContentAttributes *g_memory_content_get_attributes(const GMemoryContent *);
+
 /* Donne l'origine d'un contenu binaire. */
 static GBinContent *g_memory_content_get_root(GMemoryContent *);
 
@@ -128,6 +127,7 @@ static bool g_memory_content_read_leb128(const GMemoryContent *, vmpa2t *, leb12
 
 /* Indique le type défini par la GLib pour les contenus de données en mémoire. */
 G_DEFINE_TYPE_WITH_CODE(GMemoryContent, g_memory_content, G_TYPE_OBJECT,
+                        G_IMPLEMENT_INTERFACE(G_TYPE_SERIALIZABLE_OBJECT, g_memory_content_serializable_init)
                         G_IMPLEMENT_INTERFACE(G_TYPE_BIN_CONTENT, g_memory_content_interface_init));
 
 
@@ -169,8 +169,39 @@ static void g_memory_content_class_init(GMemoryContentClass *klass)
 
 static void g_memory_content_init(GMemoryContent *content)
 {
-    content->storage = NULL;
-    content->backend = NULL;
+    GContentAttributes *empty;              /* Jeu d'attributs vide        */
+
+    content->attribs = NULL;
+
+    empty = g_content_attributes_new("");
+
+    g_binary_content_set_attributes(G_BIN_CONTENT(content), empty);
+
+    content->data = NULL;
+    content->length = 0;
+
+    content->full_desc = strdup("In-memory content");
+    content->desc = strdup("In-memory content");
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : iface = interface GLib à initialiser.                        *
+*                                                                             *
+*  Description : Procède à l'initialisation de l'interface de sérialisation.  *
+*                                                                             *
+*  Retour      : -                                                            *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static void g_memory_content_serializable_init(GSerializableObjectInterface *iface)
+{
+    iface->load = (load_serializable_object_cb)g_memory_content_load;
+    iface->store = (store_serializable_object_cb)g_memory_content_store;
 
 }
 
@@ -189,6 +220,9 @@ static void g_memory_content_init(GMemoryContent *content)
 
 static void g_memory_content_interface_init(GBinContentInterface *iface)
 {
+    iface->set_attribs = (set_content_attributes)g_memory_content_set_attributes;
+    iface->get_attribs = (get_content_attributes)g_memory_content_get_attributes;
+
     iface->get_root = (get_content_root_fc)g_memory_content_get_root;
 
     iface->describe = (describe_content_fc)g_memory_content_describe;
@@ -232,8 +266,7 @@ static void g_memory_content_interface_init(GBinContentInterface *iface)
 
 static void g_memory_content_dispose(GMemoryContent *content)
 {
-    if (content->backend)
-        g_object_unref(G_OBJECT(content->backend));
+    g_clear_object(&content->attribs);
 
     G_OBJECT_CLASS(g_memory_content_parent_class)->dispose(G_OBJECT(content));
 
@@ -254,11 +287,14 @@ static void g_memory_content_dispose(GMemoryContent *content)
 
 static void g_memory_content_finalize(GMemoryContent *content)
 {
-    if (content->storage != NULL)
-    {
-        unlink(content->storage);
-        free(content->storage);
-    }
+    if (content->data != NULL)
+        free(content->data);
+
+    if (content->desc != NULL)
+        free(content->desc);
+
+    if (content->full_desc != NULL)
+        free(content->full_desc);
 
     G_OBJECT_CLASS(g_memory_content_parent_class)->finalize(G_OBJECT(content));
 
@@ -280,29 +316,22 @@ static void g_memory_content_finalize(GMemoryContent *content)
 
 GBinContent *g_memory_content_new(const bin_t *data, phys_t size)
 {
-    GMemoryContent *result;                 /* Structure à retourner      */
-    int fd;                                 /* Descripteur du fichier      */
-    bool status;                            /* Bilan des écritures         */
-
-    result = g_object_new(G_TYPE_MEMORY_CONTENT, NULL);
-
-    fd = make_tmp_file("memcnt", "bin", &result->storage);
-    if (fd == -1) goto gmcn_error;
-
-    status = safe_write(fd, data, size);
+    GMemoryContent *result;                 /* Structure à retourner       */
+    bin_t *allocated;                       /* Zone de réception           */
 
-    close(fd);
-
-    if (!status) goto gmcn_error;
-
-    result->backend = g_file_content_new(result->storage);
-    if (result->backend == NULL) goto gmcn_error;
+    allocated = malloc(size);
+    if (allocated == NULL)
+    {
+        LOG_ERROR_N("malloc");
+        return NULL;
+    }
 
-    return G_BIN_CONTENT(result);
+    memcpy(allocated, data, size);
 
- gmcn_error:
+    result = g_object_new(G_TYPE_MEMORY_CONTENT, NULL);
 
-    g_object_unref(G_OBJECT(result));
+    result->data = allocated;
+    result->length = size;
 
     return NULL;
 
@@ -325,6 +354,10 @@ GBinContent *g_memory_content_new(const bin_t *data, phys_t size)
 
 GBinContent *g_memory_content_new_from_xml(xmlXPathContextPtr context, const char *path, const char *base)
 {
+    return NULL;
+
+#if 0
+
     GBinContent *result;                    /* Adresse à retourner         */
     char *access;                           /* Chemin pour une sous-config.*/
     char *encoded;                          /* Données encodées à charger  */
@@ -359,6 +392,167 @@ GBinContent *g_memory_content_new_from_xml(xmlXPathContextPtr context, const cha
     }
 
     return result;
+#endif
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : content = é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_memory_content_load(GMemoryContent *content, GObjectStorage *storage, packed_buffer_t *pbuf)
+{
+    bool result;                            /* Bilan à retourner           */
+    uleb128_t length;                       /* Quantité de données à suivre*/
+    rle_string str;                         /* Chaîne à charger            */
+
+    result = unpack_uleb128(&length, pbuf);
+
+    if (result)
+    {
+        content->data = malloc(length);
+        result = (content->data != NULL);
+    }
+
+    if (result)
+    {
+        content->length = length;
+        result = extract_packed_buffer(pbuf, content->data, length, false);
+    }
+
+    setup_empty_rle_string(&str);
+
+    if (result)
+        result = unpack_rle_string(&str, pbuf);
+
+    if (result)
+    {
+        result = (get_rle_string(&str) != NULL);
+
+        if (result)
+            content->full_desc = strdup(get_rle_string(&str));
+
+        exit_rle_string(&str);
+
+    }
+
+    if (result)
+        result = unpack_rle_string(&str, pbuf);
+
+    if (result)
+    {
+        result = (get_rle_string(&str) != NULL);
+
+        if (result)
+            content->desc = strdup(get_rle_string(&str));
+
+        exit_rle_string(&str);
+
+    }
+
+    return result;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : content = é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_memory_content_store(const GMemoryContent *content, GObjectStorage *storage, packed_buffer_t *pbuf)
+{
+    bool result;                            /* Bilan à retourner           */
+    rle_string str;                         /* Chaîne à conserver          */
+
+    result = pack_uleb128((uleb128_t []){ content->length }, pbuf);
+
+    if (result)
+        result = extend_packed_buffer(pbuf, content->data, content->length, false);
+
+    if (result)
+    {
+        init_static_rle_string(&str, content->full_desc);
+
+        result = pack_rle_string(&str, pbuf);
+
+        exit_rle_string(&str);
+
+    }
+
+    if (result)
+    {
+        init_static_rle_string(&str, content->desc);
+
+        result = pack_rle_string(&str, pbuf);
+
+        exit_rle_string(&str);
+
+    }
+
+    return result;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : content = contenu binaire à actualiser.                      *
+*                attribs = jeu d'attributs à lier au contenu courant.         *
+*                                                                             *
+*  Description : Associe un ensemble d'attributs au contenu binaire.          *
+*                                                                             *
+*  Retour      : -                                                            *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static void g_memory_content_set_attributes(GMemoryContent *content, GContentAttributes *attribs)
+{
+    content->attribs = attribs;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : content = contenu binaire à consulter.                       *
+*                                                                             *
+*  Description : Fournit l'ensemble des attributs associés à un contenu.      *
+*                                                                             *
+*  Retour      : Jeu d'attributs liés au contenu courant.                     *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static GContentAttributes *g_memory_content_get_attributes(const GMemoryContent *content)
+{
+    GContentAttributes *result;             /* Instance à retourner        */
+
+    result = content->attribs;
+
+    return result;
 
 }
 
@@ -403,7 +597,10 @@ static char *g_memory_content_describe(const GMemoryContent *content, bool full)
 {
     char *result;                           /* Description à retourner     */
 
-    result = strdup("In-memory content");
+    result = (full ? content->full_desc : content->desc);
+
+    if (result != NULL)
+        result = strdup(result);
 
     return result;
 
@@ -428,6 +625,10 @@ static char *g_memory_content_describe(const GMemoryContent *content, bool full)
 
 static bool g_memory_content_save(const GMemoryContent *content, xmlDocPtr xdoc, xmlXPathContextPtr context, const char *path, const char *base)
 {
+    return false;
+
+#if 0
+
     bool result;                            /* Bilan à faire remonter      */
     char *access;                           /* Chemin d'accès à un élément */
     vmpa2t start;                           /* Tête de lecture initiale    */
@@ -463,7 +664,7 @@ static bool g_memory_content_save(const GMemoryContent *content, xmlDocPtr xdoc,
  gmcs_exit:
 
     return result;
-
+#endif
 }
 
 
@@ -482,11 +683,7 @@ static bool g_memory_content_save(const GMemoryContent *content, xmlDocPtr xdoc,
 
 static void g_memory_content_compute_checksum(GMemoryContent *content, GChecksum *checksum)
 {
-    GBinContentIface *iface;                /* Interface utilisée          */
-
-    iface = G_BIN_CONTENT_GET_IFACE(content->backend);
-
-    iface->compute_checksum(content->backend, checksum);
+    g_checksum_update(checksum, content->data, content->length);
 
 }
 
@@ -507,7 +704,7 @@ static phys_t g_memory_content_compute_size(const GMemoryContent *content)
 {
     phys_t result;                          /* Quantité trouvée à retourner*/
 
-    result = g_binary_content_compute_size(content->backend);
+    result = content->length;
 
     return result;
 
@@ -529,7 +726,7 @@ static phys_t g_memory_content_compute_size(const GMemoryContent *content)
 
 static void g_memory_content_compute_start_pos(const GMemoryContent *content, vmpa2t *pos)
 {
-    g_binary_content_compute_start_pos(content->backend, pos);
+    init_vmpa(pos, 0, VMPA_NO_VIRTUAL);
 
 }
 
@@ -549,7 +746,9 @@ static void g_memory_content_compute_start_pos(const GMemoryContent *content, vm
 
 static void g_memory_content_compute_end_pos(const GMemoryContent *content, vmpa2t *pos)
 {
-    g_binary_content_compute_end_pos(content->backend, pos);
+    g_memory_content_compute_start_pos(content, pos);
+
+    advance_vmpa(pos, content->length);
 
 }
 
@@ -571,8 +770,23 @@ static void g_memory_content_compute_end_pos(const GMemoryContent *content, vmpa
 static bool g_memory_content_seek(const GMemoryContent *content, vmpa2t *addr, phys_t length)
 {
     bool result;                            /* Bilan à retourner           */
+    phys_t offset;                          /* Emplacement de départ       */
+
+    result = false;
+
+    offset = get_phy_addr(addr);
+
+    if (length > content->length)
+        goto done;
 
-    result = g_binary_content_seek(content->backend, addr, length);
+    if (offset > (content->length - length))
+        goto done;
+
+    advance_vmpa(addr, length);
+
+    result = true;
+
+ done:
 
     return result;
 
@@ -596,8 +810,14 @@ static bool g_memory_content_seek(const GMemoryContent *content, vmpa2t *addr, p
 static const bin_t *g_memory_content_get_raw_access(const GMemoryContent *content, vmpa2t *addr, phys_t length)
 {
     const bin_t *result;                    /* Données utiles à renvoyer   */
+    phys_t offset;                          /* Emplacement de départ       */
+    bool allowed;                           /* Capacité d'avancer ?        */
 
-    result = g_binary_content_get_raw_access(content->backend, addr, length);
+    offset = get_phy_addr(addr);
+
+    allowed = g_memory_content_seek(content, addr, length);
+
+    result = (allowed ? &content->data[offset] : NULL);
 
     return result;
 
@@ -622,8 +842,17 @@ static const bin_t *g_memory_content_get_raw_access(const GMemoryContent *conten
 static bool g_memory_content_read_raw(const GMemoryContent *content, vmpa2t *addr, phys_t length, bin_t *out)
 {
     bool result;                            /* Bilan à remonter            */
+    const bin_t *data;                      /* Pointeur vers données utiles*/
+
+    data = g_memory_content_get_raw_access(content, addr, length);
 
-    result = g_binary_content_read_raw(content->backend, addr, length, out);
+    if (data != NULL)
+    {
+        result = true;
+        memcpy(out, data, length);
+    }
+    else
+        result = false;
 
     return result;
 
@@ -648,8 +877,17 @@ static bool g_memory_content_read_raw(const GMemoryContent *content, vmpa2t *add
 static bool g_memory_content_read_u4(const GMemoryContent *content, vmpa2t *addr, bool *low, uint8_t *val)
 {
     bool result;                            /* Bilan de lecture à renvoyer */
+    phys_t pos;                             /* Tête de lecture courante    */
+
+    pos = get_phy_addr(addr);
 
-    result = g_binary_content_read_u4(content->backend, addr, low, val);
+    if (pos == VMPA_NO_PHYSICAL)
+        return false;
+
+    result = read_u4(val, content->data, &pos, content->length, low);
+
+    if (result)
+        advance_vmpa(addr, pos - get_phy_addr(addr));
 
     return result;
 
@@ -674,8 +912,20 @@ static bool g_memory_content_read_u4(const GMemoryContent *content, vmpa2t *addr
 static bool g_memory_content_read_u8(const GMemoryContent *content, vmpa2t *addr, uint8_t *val)
 {
     bool result;                            /* Bilan de lecture à renvoyer */
+    phys_t pos;                             /* Tête de lecture courante    */
+    phys_t length;                          /* Taille de la surface dispo. */
+
+    pos = get_phy_addr(addr);
 
-    result = g_binary_content_read_u8(content->backend, addr, val);
+    if (pos == VMPA_NO_PHYSICAL)
+        return false;
+
+    length = length;
+
+    result = read_u8(val, content->data, &pos, content->length);
+
+    if (result)
+        advance_vmpa(addr, pos - get_phy_addr(addr));
 
     return result;
 
@@ -700,8 +950,17 @@ static bool g_memory_content_read_u8(const GMemoryContent *content, vmpa2t *addr
 static bool g_memory_content_read_u16(const GMemoryContent *content, vmpa2t *addr, SourceEndian endian, uint16_t *val)
 {
     bool result;                            /* Bilan de lecture à renvoyer */
+    phys_t pos;                             /* Tête de lecture courante    */
+
+    pos = get_phy_addr(addr);
+
+    if (pos == VMPA_NO_PHYSICAL)
+        return false;
+
+    result = read_u16(val, content->data, &pos, content->length, endian);
 
-    result = g_binary_content_read_u16(content->backend, addr, endian, val);
+    if (result)
+        advance_vmpa(addr, pos - get_phy_addr(addr));
 
     return result;
 
@@ -726,8 +985,17 @@ static bool g_memory_content_read_u16(const GMemoryContent *content, vmpa2t *add
 static bool g_memory_content_read_u32(const GMemoryContent *content, vmpa2t *addr, SourceEndian endian, uint32_t *val)
 {
     bool result;                            /* Bilan de lecture à renvoyer */
+    phys_t pos;                             /* Tête de lecture courante    */
 
-    result = g_binary_content_read_u32(content->backend, addr, endian, val);
+    pos = get_phy_addr(addr);
+
+    if (pos == VMPA_NO_PHYSICAL)
+        return false;
+
+    result = read_u32(val, content->data, &pos, content->length, endian);
+
+    if (result)
+        advance_vmpa(addr, pos - get_phy_addr(addr));
 
     return result;
 
@@ -752,8 +1020,17 @@ static bool g_memory_content_read_u32(const GMemoryContent *content, vmpa2t *add
 static bool g_memory_content_read_u64(const GMemoryContent *content, vmpa2t *addr, SourceEndian endian, uint64_t *val)
 {
     bool result;                            /* Bilan de lecture à renvoyer */
+    phys_t pos;                             /* Tête de lecture courante    */
+
+    pos = get_phy_addr(addr);
+
+    if (pos == VMPA_NO_PHYSICAL)
+        return false;
+
+    result = read_u64(val, content->data, &pos, content->length, endian);
 
-    result = g_binary_content_read_u64(content->backend, addr, endian, val);
+    if (result)
+        advance_vmpa(addr, pos - get_phy_addr(addr));
 
     return result;
 
@@ -777,8 +1054,17 @@ static bool g_memory_content_read_u64(const GMemoryContent *content, vmpa2t *add
 static bool g_memory_content_read_uleb128(const GMemoryContent *content, vmpa2t *addr, uleb128_t *val)
 {
     bool result;                            /* Bilan de lecture à renvoyer */
+    phys_t pos;                             /* Tête de lecture courante    */
 
-    result = g_binary_content_read_uleb128(content->backend, addr, val);
+    pos = get_phy_addr(addr);
+
+    if (pos == VMPA_NO_PHYSICAL)
+        return false;
+
+    result = read_uleb128(val, content->data, &pos, content->length);
+
+    if (result)
+        advance_vmpa(addr, pos - get_phy_addr(addr));
 
     return result;
 
@@ -802,8 +1088,17 @@ static bool g_memory_content_read_uleb128(const GMemoryContent *content, vmpa2t
 static bool g_memory_content_read_leb128(const GMemoryContent *content, vmpa2t *addr, leb128_t *val)
 {
     bool result;                            /* Bilan de lecture à renvoyer */
+    phys_t pos;                             /* Tête de lecture courante    */
+
+    pos = get_phy_addr(addr);
+
+    if (pos == VMPA_NO_PHYSICAL)
+        return false;
+
+    result = read_leb128(val, content->data, &pos, content->length);
 
-    result = g_binary_content_read_leb128(content->backend, addr, val);
+    if (result)
+        advance_vmpa(addr, pos - get_phy_addr(addr));
 
     return result;
 
diff --git a/src/analysis/contents/restricted.c b/src/analysis/contents/restricted.c
index ded96c7..3e9cbbb 100644
--- a/src/analysis/contents/restricted.c
+++ b/src/analysis/contents/restricted.c
@@ -29,6 +29,8 @@
 
 
 #include "../content-int.h"
+#include "../db/misc/rlestr.h"
+#include "../storage/serialize-int.h"
 
 
 
@@ -57,6 +59,9 @@ static void g_restricted_content_class_init(GRestrictedContentClass *);
 /* Initialise une instance de contenu de données binaires. */
 static void g_restricted_content_init(GRestrictedContent *);
 
+/* Procède à l'initialisation de l'interface de sérialisation. */
+static void g_restricted_content_serializable_init(GSerializableObjectInterface *);
+
 /* Procède à l'initialisation de l'interface de lecture. */
 static void g_restricted_content_interface_init(GBinContentInterface *);
 
@@ -66,6 +71,12 @@ static void g_restricted_content_dispose(GRestrictedContent *);
 /* Procède à la libération totale de la mémoire. */
 static void g_restricted_content_finalize(GRestrictedContent *);
 
+/* Charge un contenu depuis une mémoire tampon. */
+static bool g_restricted_content_load(GRestrictedContent *, GObjectStorage *, packed_buffer_t *);
+
+/* Sauvegarde un contenu dans une mémoire tampon. */
+static bool g_restricted_content_store(const GRestrictedContent *, GObjectStorage *, packed_buffer_t *);
+
 /* Donne l'origine d'un contenu binaire. */
 static GBinContent *g_restricted_content_get_root(GRestrictedContent *);
 
@@ -115,6 +126,7 @@ static bool g_restricted_content_read_leb128(const GRestrictedContent *, vmpa2t
 
 /* Indique le type défini par la GLib pour les contenus de données. */
 G_DEFINE_TYPE_WITH_CODE(GRestrictedContent, g_restricted_content, G_TYPE_OBJECT,
+                        G_IMPLEMENT_INTERFACE(G_TYPE_SERIALIZABLE_OBJECT, g_restricted_content_serializable_init)
                         G_IMPLEMENT_INTERFACE(G_TYPE_BIN_CONTENT, g_restricted_content_interface_init));
 
 
@@ -170,6 +182,26 @@ static void g_restricted_content_init(GRestrictedContent *content)
 *                                                                             *
 *  Paramètres  : iface = interface GLib à initialiser.                        *
 *                                                                             *
+*  Description : Procède à l'initialisation de l'interface de sérialisation.  *
+*                                                                             *
+*  Retour      : -                                                            *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static void g_restricted_content_serializable_init(GSerializableObjectInterface *iface)
+{
+    iface->load = (load_serializable_object_cb)g_restricted_content_load;
+    iface->store = (store_serializable_object_cb)g_restricted_content_store;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : iface = interface GLib à initialiser.                        *
+*                                                                             *
 *  Description : Procède à l'initialisation de l'interface de lecture.        *
 *                                                                             *
 *  Retour      : -                                                            *
@@ -305,6 +337,63 @@ GBinContent *g_restricted_content_new_ro(const GBinContent *content, const mrang
 
 /******************************************************************************
 *                                                                             *
+*  Paramètres  : content = é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_restricted_content_load(GRestrictedContent *content, GObjectStorage *storage, packed_buffer_t *pbuf)
+{
+    bool result;                            /* Bilan à retourner           */
+
+    content->internal = G_BIN_CONTENT(g_object_storage_unpack_object(storage, "contents", pbuf));
+    result = (content->internal != NULL);
+
+    if (result)
+        result = unpack_mrange(&content->range, pbuf);
+
+    return result;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : content = é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_restricted_content_store(const GRestrictedContent *content, GObjectStorage *storage, packed_buffer_t *pbuf)
+{
+    bool result;                            /* Bilan à retourner           */
+
+    result = g_object_storage_pack_object(storage, "contents", G_SERIALIZABLE_OBJECT(content->internal), pbuf);
+
+    if (result)
+        result = pack_mrange(&content->range, pbuf);
+
+    return result;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
 *  Paramètres  : content = contenu binaire à consulter.                       *
 *                                                                             *
 *  Description : Donne l'origine d'un contenu binaire.                        *
diff --git a/src/analysis/storage/serialize.c b/src/analysis/storage/serialize.c
index 312cfce..d1b0502 100644
--- a/src/analysis/storage/serialize.c
+++ b/src/analysis/storage/serialize.c
@@ -59,7 +59,7 @@ static void g_serializable_object_default_init(GSerializableObjectInterface *ifa
 *                                                                             *
 *  Paramètres  : object  = élément GLib à constuire.                          *
 *                storage = conservateur de données à manipuler ou NULL.       *
-*                pbuf    = zone tampon à remplir.                             *
+*                pbuf    = zone tampon à lire.                                *
 *                                                                             *
 *  Description : Charge un objet depuis une mémoire tampon.                   *
 *                                                                             *
diff --git a/src/analysis/storage/storage-int.h b/src/analysis/storage/storage-int.h
index 7e01cbc..4883aa8 100644
--- a/src/analysis/storage/storage-int.h
+++ b/src/analysis/storage/storage-int.h
@@ -46,7 +46,7 @@ struct _GObjectStorage
 
     GTypeMemory *tpmem;                     /* Mémorisation de types       */
 
-    GLoadedContent *loaded;                 /* Contenu principal           */
+    char *hash;                             /* Empreinte du contenu        */
 
     storage_backend_t *backends;            /* Gestionnaires existants     */
     size_t count;                           /* Quantité de gestionnaires   */
diff --git a/src/analysis/storage/storage.c b/src/analysis/storage/storage.c
index 395d26d..e286641 100644
--- a/src/analysis/storage/storage.c
+++ b/src/analysis/storage/storage.c
@@ -31,10 +31,17 @@
 
 
 #include "storage-int.h"
+#include "../db/misc/rlestr.h"
+#include "../../common/io.h"
+#include "../../common/leb128.h"
 #include "../../core/logs.h"
 
 
 
+#define STORAGE_MAGIC "CSTR"
+#define STORAGE_NUMBER "\x00\x01"
+
+
 /* Initialise la classe des conservations d'objets en place. */
 static void g_object_storage_class_init(GObjectStorageClass *);
 
@@ -50,6 +57,15 @@ static void g_object_storage_finalize(GObjectStorage *);
 /* Retrouve l'encadrement pour un nouveau groupe d'objets. */
 static storage_backend_t *g_object_storage_find_backend(GObjectStorage *, const char *);
 
+/* Ajoute le support d'un nouveau groupe d'objets construits. */
+static bool g_object_storage_add_backend(GObjectStorage *, const char *, storage_backend_t **);
+
+/* Extrait d'un tampon des enregistrements spécifiques. */
+static bool g_object_storage_load_backend(GObjectStorage *, packed_buffer_t *);
+
+/* Place dans un tampon les données liées à des enregistrements. */
+static bool pack_storage_backend(const storage_backend_t *, packed_buffer_t *);
+
 
 
 /* Indique le type défini pour une conservation d'objets construits. */
@@ -96,7 +112,7 @@ static void g_object_storage_init(GObjectStorage *storage)
 {
     storage->tpmem = g_type_memory_new();
 
-    storage->loaded = NULL;
+    storage->hash = NULL;
 
     storage->backends = NULL;
     storage->count = 0;
@@ -121,8 +137,6 @@ static void g_object_storage_dispose(GObjectStorage *storage)
 {
     g_clear_object(&storage->tpmem);
 
-    g_clear_object(&storage->loaded);
-
     G_OBJECT_CLASS(g_object_storage_parent_class)->dispose(G_OBJECT(storage));
 
 }
@@ -177,6 +191,9 @@ static void g_object_storage_finalize(GObjectStorage *storage)
 
     g_mutex_clear(&storage->mutex);
 
+    if (storage->hash != NULL)
+        free(storage->hash);
+
     G_OBJECT_CLASS(g_object_storage_parent_class)->finalize(G_OBJECT(storage));
 
 }
@@ -194,14 +211,131 @@ static void g_object_storage_finalize(GObjectStorage *storage)
 *                                                                             *
 ******************************************************************************/
 
-GObjectStorage *g_object_storage_new(GLoadedContent *loaded)
+GObjectStorage *g_object_storage_new(const char *hash)
 {
-    GObjectStorage *result;                    /* Structure à retourner       */
+    GObjectStorage *result;                 /* Structure à retourner       */
 
     result = g_object_new(G_TYPE_OBJECT_STORAGE, NULL);
 
-    result->loaded = loaded;
-    g_object_ref(G_OBJECT(loaded));
+    result->hash = strdup(hash);
+
+    return result;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : pbuf = zone tampon à lire.                                   *
+*                                                                             *
+*  Description : Charge le support d'une conservation d'objets en place.      *
+*                                                                             *
+*  Retour      : Gestionnaire de conservations construit ou NULL si erreur.   *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+GObjectStorage *g_object_storage_load(packed_buffer_t *pbuf)
+{
+    GObjectStorage *result;                 /* Structure à retourner       */
+    char header[6];                         /* Entête attendue des données */
+    bool status;                            /* Bilan d'une extraction      */
+    rle_string str;                         /* Chaîne à conserver          */
+    uleb128_t count;                        /* Nombre de groupes à charger */
+    uleb128_t i;                            /* Boucle de parcours          */
+
+    result = NULL;
+
+    status = extract_packed_buffer(pbuf, header, 6, false);
+    if (!status) goto quick_exit;
+
+    if (strncmp(header, STORAGE_MAGIC STORAGE_NUMBER, 6) != 0)
+        goto quick_exit;
+
+    setup_empty_rle_string(&str);
+
+    status = unpack_rle_string(&str, pbuf);
+    if (!status) goto quick_exit;
+
+    if (get_rle_string(&str) == NULL)
+    {
+        exit_rle_string(&str);
+        goto quick_exit;
+    }
+
+    result = g_object_new(G_TYPE_OBJECT_STORAGE, NULL);
+
+    result->hash = strdup(get_rle_string(&str));
+
+    exit_rle_string(&str);
+
+    status = g_type_memory_load_types(result->tpmem, pbuf);
+    if (!status) goto exit_while_loading;
+
+    status = unpack_uleb128(&count, pbuf);
+
+    for (i = 0; i < count && status; i++)
+        status = g_object_storage_load_backend(result, pbuf);
+
+ exit_while_loading:
+
+    if (!status)
+    {
+        g_object_unref(G_OBJECT(result));
+        result = NULL;
+    }
+
+ quick_exit:
+
+    return result;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : storage = gestionnaire de conservations à manipuler.         *
+*                pbuf    = zone tampon à remplir. [OUT]                       *
+*                                                                             *
+*  Description : Sauvegarde le support d'une conservation d'objets en place.  *
+*                                                                             *
+*  Retour      : Bilan de l'opération.                                        *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+bool g_object_storage_store(GObjectStorage *storage, packed_buffer_t *pbuf)
+{
+    bool result;                            /* Bilan à retourner           */
+    rle_string str;                         /* Chaîne à conserver          */
+    size_t i;                               /* Boucle de parcours          */
+
+    result = extend_packed_buffer(pbuf, STORAGE_MAGIC STORAGE_NUMBER, 6, false);
+
+    if (result)
+    {
+        init_static_rle_string(&str, storage->hash);
+
+        result = pack_rle_string(&str, pbuf);
+
+        exit_rle_string(&str);
+
+    }
+
+    g_mutex_lock(&storage->mutex);
+
+    if (result)
+        result = g_type_memory_store_types(storage->tpmem, pbuf);
+
+    if (result)
+        result = pack_uleb128((uleb128_t []){ storage->count }, pbuf);
+
+    for (i = 0; i < storage->count && result; i++)
+        result = pack_storage_backend(&storage->backends[i], pbuf);
+
+    g_mutex_unlock(&storage->mutex);
 
     return result;
 
@@ -244,9 +378,9 @@ static storage_backend_t *g_object_storage_find_backend(GObjectStorage *storage,
 
 /******************************************************************************
 *                                                                             *
-*  Paramètres  : storage  = gestionnaire de conservations à compléter.        *
-*                name     = désignation d'un nouveau groupe d'objets.         *
-*                filename = éventuel nom de fichier à utiliser ou NULL.       *
+*  Paramètres  : storage = gestionnaire de conservations à compléter.         *
+*                name    = désignation d'un nouveau groupe d'objets.          *
+*                backend = support mis en place pour les enregistrements.     *
 *                                                                             *
 *  Description : Ajoute le support d'un nouveau groupe d'objets construits.   *
 *                                                                             *
@@ -256,45 +390,116 @@ static storage_backend_t *g_object_storage_find_backend(GObjectStorage *storage,
 *                                                                             *
 ******************************************************************************/
 
-bool g_object_storage_add_backend(GObjectStorage *storage, const char *name, const char *filename)
+static bool g_object_storage_add_backend(GObjectStorage *storage, const char *name, storage_backend_t **backend)
 {
     bool result;                            /* Bilan à retourner           */
-    GBinContent *content;                   /* Contenu binaire traité      */
-    const gchar *checksum;                  /* Empreinte de ce contenu     */
     char *prefix;                           /* Début de nom de fichier     */
-    storage_backend_t backend;              /* Informations à intégrer     */
+    char *filename;                         /* Chemin d'accès aux données  */
+    int fd;                                 /* Descripteur de flux ouvert  */
 
     result = false;
 
-    g_mutex_lock(&storage->mutex);
+    *backend = NULL;
+
+    assert(!g_mutex_trylock(&storage->mutex));
 
     if (g_object_storage_find_backend(storage, name) != NULL)
         goto exit;
 
     /* Préparatifs */
 
-    content = g_loaded_content_get_content(storage->loaded);
+    asprintf(&prefix, "%s-%s", storage->hash, name);
 
-    checksum = g_binary_content_get_checksum(content);
+    fd = make_tmp_file(prefix, "cache", &filename);
 
-    asprintf(&prefix, "%s-%s", checksum, name);
+    free(prefix);
 
-    g_object_unref(G_OBJECT(content));
+    if (fd == -1)
+        goto exit;
 
-    backend.fd = make_tmp_file(prefix, "cache", &backend.filename);
+    /* Inscription en bonne et due forme */
 
-    free(prefix);
+    storage->backends = realloc(storage->backends, ++storage->count * sizeof(storage_backend_t));
+
+    *backend = &storage->backends[storage->count - 1];
+
+    (*backend)->name = strdup(name);
 
-    if (backend.fd == -1)
+    (*backend)->filename = filename;
+    (*backend)->fd = fd;
+
+    result = true;
+
+ exit:
+
+    return result;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : storage = gestionnaire de conservations à compléter.         *
+*                pbuf    = zone tampon à lire.                                *
+*                                                                             *
+*  Description : Extrait d'un tampon des enregistrements spécifiques.         *
+*                                                                             *
+*  Retour      : Bilan de l'opération.                                        *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static bool g_object_storage_load_backend(GObjectStorage *storage, packed_buffer_t *pbuf)
+{
+    bool result;                            /* Bilan à retourner           */
+    rle_string str;                         /* Chaîne à conserver          */
+    bool status;                            /* Bilan de lecture de contenu */
+    storage_backend_t *backend;             /* Informations à intégrer     */
+    uleb128_t length;                       /* Taille des données à charger*/
+    off_t moved;                            /* Nouvelle position établie   */
+
+    result = false;
+
+    g_mutex_lock(&storage->mutex);
+
+    /* Récupération du nom et création du support */
+
+    setup_empty_rle_string(&str);
+
+    status = unpack_rle_string(&str, pbuf);
+    if (!status) goto exit;
+
+    if (get_rle_string(&str) == NULL)
+    {
+        exit_rle_string(&str);
         goto exit;
+    }
 
-    /* Inscription en bonne et due forme */
+    status = g_object_storage_add_backend(storage, get_rle_string(&str), &backend);
 
-    backend.name = strdup(name);
+    exit_rle_string(&str);
 
-    storage->backends = realloc(storage->backends, ++storage->count * sizeof(storage_backend_t));
+    if (!status) goto exit;
+
+    /* Récupération du contenu */
+
+    status = unpack_uleb128(&length, pbuf);
+    if (!status) goto exit;
 
-    storage->backends[storage->count - 1] = backend;
+    status = safe_write(backend->fd, pbuf->data + pbuf->pos, length);
+    if (!status) goto exit;
+
+    advance_packed_buffer(pbuf, length);
+
+    moved = lseek(backend->fd, 0, SEEK_SET);
+    if (moved == ((off_t)-1))
+    {
+        LOG_ERROR_N("lseek");
+        goto exit;
+    }
+
+    result = true;
 
  exit:
 
@@ -307,6 +512,93 @@ bool g_object_storage_add_backend(GObjectStorage *storage, const char *name, con
 
 /******************************************************************************
 *                                                                             *
+*  Paramètres  : backend = stockage des enregistrements spécifiques.          *
+*                pbuf    = zone tampon à remplir. [OUT]                       *
+*                                                                             *
+*  Description : Place dans un tampon les données liées à des enregistrements.*
+*                                                                             *
+*  Retour      : Bilan de l'opération.                                        *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static bool pack_storage_backend(const storage_backend_t *backend, packed_buffer_t *pbuf)
+{
+    bool result;                            /* Bilan à retourner           */
+    rle_string str;                         /* Chaîne à conserver          */
+    bool status;                            /* Bilan de lecture de contenu */
+    off_t current;                          /* Position courante           */
+    off_t moved;                            /* Nouvelle position établie   */
+    void *data;                             /* Données à transférer        */
+
+    result = false;
+
+    /* Inscription du nom */
+
+    init_static_rle_string(&str, backend->name);
+
+    status = pack_rle_string(&str, pbuf);
+
+    exit_rle_string(&str);
+
+    if (!status) goto exit;
+
+    /* Inscription du contenu */
+
+    current = lseek(backend->fd, 0, SEEK_CUR);
+    if (current == ((off_t)-1))
+    {
+        LOG_ERROR_N("lseek");
+        goto exit;
+    }
+
+    moved = lseek(backend->fd, 0, SEEK_SET);
+    if (moved == ((off_t)-1))
+    {
+        LOG_ERROR_N("lseek");
+        goto exit;
+    }
+
+    data = malloc(current);
+    if (data == NULL)
+    {
+        LOG_ERROR_N("malloc");
+        goto restore;
+    }
+
+    status = safe_read(backend->fd, data, current);
+    if (!status) goto free_mem;
+
+    status = pack_uleb128((uleb128_t []){ current }, pbuf);
+    if (!status) goto free_mem;
+
+    status = extend_packed_buffer(pbuf, data, current, false);
+
+ free_mem:
+
+    free(data);
+
+ restore:
+
+    moved = lseek(backend->fd, current, SEEK_SET);
+    if (moved == ((off_t)-1))
+    {
+        LOG_ERROR_N("lseek");
+        goto exit;
+    }
+
+    result = status;
+
+ exit:
+
+    return result;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
 *  Paramètres  : storage = gestionnaire à manipuler.                          *
 *                name    = désignation d'un nouveau groupe d'objets.          *
 *                pos     = tête de lecture avant écriture.                    *
@@ -343,7 +635,7 @@ GSerializableObject *g_object_storage_load_object(GObjectStorage *storage, const
 
         if (new == pos)
         {
-            reset_packed_buffer(&pbuf);
+            init_packed_buffer(&pbuf);
             status = read_packed_buffer(&pbuf, backend->fd);
         }
 
@@ -448,6 +740,9 @@ bool g_object_storage_store_object(GObjectStorage *storage, const char *name, co
 
     backend = g_object_storage_find_backend(storage, name);
 
+    if (backend == NULL)
+        g_object_storage_add_backend(storage, name, &backend);
+
     if (backend != NULL)
     {
         if (pos == NULL)
diff --git a/src/analysis/storage/storage.h b/src/analysis/storage/storage.h
index fd5d91f..43860af 100644
--- a/src/analysis/storage/storage.h
+++ b/src/analysis/storage/storage.h
@@ -31,7 +31,6 @@
 
 #include "serialize.h"
 #include "tpmem.h"
-#include "../loaded.h"
 
 
 
@@ -54,10 +53,13 @@ typedef struct _GObjectStorageClass GObjectStorageClass;
 GType g_object_storage_get_type(void);
 
 /* Crée le support d'une conservation d'objets en place. */
-GObjectStorage *g_object_storage_new(GLoadedContent *);
+GObjectStorage *g_object_storage_new(const char *);
 
-/* Ajoute le support d'un nouveau groupe d'objets construits. */
-bool g_object_storage_add_backend(GObjectStorage *, const char *, const char *);
+/* Charge le support d'une conservation d'objets en place. */
+GObjectStorage *g_object_storage_load(packed_buffer_t *);
+
+/* Sauvegarde le support d'une conservation d'objets en place. */
+bool g_object_storage_store(GObjectStorage *, packed_buffer_t *);
 
 /* Charge un objet à partir de données rassemblées. */
 GSerializableObject *g_object_storage_load_object(GObjectStorage *, const char *, off64_t);
diff --git a/src/analysis/storage/tpmem.c b/src/analysis/storage/tpmem.c
index cda8223..0703aeb 100644
--- a/src/analysis/storage/tpmem.c
+++ b/src/analysis/storage/tpmem.c
@@ -65,7 +65,7 @@ struct _GTypeMemory
     GObject parent;                         /* A laisser en premier        */
 
     gtype_ref_info_t *gtypes;               /* Types des objets reconnus   */
-    uint64_t count;                           /* Quantité de ces objets      */
+    size_t count;                           /* Quantité de ces objets      */
     GMutex mutex;                           /* Contrôle d'accès à la liste */
 
 };
@@ -248,11 +248,19 @@ bool g_type_memory_load_types(GTypeMemory *tpmem, packed_buffer_t *pbuf)
         assert(tpmem->gtypes == NULL);
         tpmem->gtypes = calloc(count, sizeof(gtype_ref_info_t));
 
+        setup_empty_rle_string(&str);
+
         for (i = 0; i < tpmem->count && result; i++)
         {
             result = unpack_rle_string(&str, pbuf);
             if (!result) break;
 
+            if (get_rle_string(&str) == NULL)
+            {
+                exit_rle_string(&str);
+                break;
+            }
+
             tpmem->gtypes[i].gtype = g_type_from_name(get_rle_string(&str));
             result = (tpmem->gtypes[i].gtype != 0);
 
@@ -291,12 +299,12 @@ bool g_type_memory_load_types(GTypeMemory *tpmem, packed_buffer_t *pbuf)
 GObject *g_type_memory_create_object(GTypeMemory *tpmem, packed_buffer_t *pbuf)
 {
     GObject *result;                        /* Nouvelle instance à renvoyer*/
-    uint64_t index;                         /* Indice du point d'insertion */
+    uleb128_t index;                        /* Indice du point d'insertion */
     bool status;                            /* Bilan d'une récupération    */
 
     result = NULL;
 
-    status = extract_packed_buffer(pbuf, &index, sizeof(uint64_t), true);
+    status = unpack_uleb128(&index, pbuf);
 
     if (status)
     {
@@ -318,7 +326,7 @@ GObject *g_type_memory_create_object(GTypeMemory *tpmem, packed_buffer_t *pbuf)
 *                                                                             *
 *  Paramètres  : tpmem = mémoire à manipuler.                                 *
 *                obj   = instance dont le type est à mémoriser.               *
-*                pbuf  = zone tampon à remplir.                               *
+*                pbuf  = zone tampon à remplir. [OUT]                         *
 *                                                                             *
 *  Description : Sauvegarde le type d'un objet instancié.                     *
 *                                                                             *
@@ -332,7 +340,7 @@ bool g_type_memory_store_object_gtype(GTypeMemory *tpmem, GObject *obj, packed_b
 {
     bool result;                            /* Bilan à retourner           */
     GType gtype;                            /* Type à enregistrer          */
-    uint64_t index;                         /* Indice du point d'insertion */
+    size_t index;                           /* Indice du point d'insertion */
 
     gtype = G_TYPE_FROM_INSTANCE(obj);
 
@@ -369,7 +377,7 @@ bool g_type_memory_store_object_gtype(GTypeMemory *tpmem, GObject *obj, packed_b
 
         g_mutex_unlock(&tpmem->mutex);
 
-        result = extend_packed_buffer(pbuf, &index, sizeof(uint64_t), true);
+        result = pack_uleb128((uleb128_t []){ index }, pbuf);
 
     }
 
@@ -381,7 +389,7 @@ bool g_type_memory_store_object_gtype(GTypeMemory *tpmem, GObject *obj, packed_b
 /******************************************************************************
 *                                                                             *
 *  Paramètres  : tpmem = mémoire à consulter.                                 *
-*                pbuf  = zone tampon à remplir.                               *
+*                pbuf  = zone tampon à remplir. [OUT]                         *
 *                                                                             *
 *  Description : Enregistre tous les types mémorisés dans un tampon.          *
 *                                                                             *
diff --git a/src/analysis/type.c b/src/analysis/type.c
index 8a24531..ca14fdc 100644
--- a/src/analysis/type.c
+++ b/src/analysis/type.c
@@ -32,6 +32,7 @@
 #include "type-int.h"
 #include "storage/serialize.h"
 #include "../common/extstr.h"
+#include "../common/leb128.h"
 
 
 
diff --git a/src/analysis/types/array.c b/src/analysis/types/array.c
index bc3382b..e1e3a38 100644
--- a/src/analysis/types/array.c
+++ b/src/analysis/types/array.c
@@ -31,6 +31,7 @@
 
 #include "../type-int.h"
 #include "../../common/extstr.h"
+#include "../../common/leb128.h"
 
 
 
diff --git a/src/analysis/types/basic.c b/src/analysis/types/basic.c
index e72ee95..75b47c7 100644
--- a/src/analysis/types/basic.c
+++ b/src/analysis/types/basic.c
@@ -29,6 +29,7 @@
 
 
 #include "../type-int.h"
+#include "../../common/leb128.h"
 
 
 
diff --git a/src/analysis/types/cse.c b/src/analysis/types/cse.c
index 6f538a5..7c78c9f 100644
--- a/src/analysis/types/cse.c
+++ b/src/analysis/types/cse.c
@@ -29,6 +29,7 @@
 
 
 #include "../type-int.h"
+#include "../../common/leb128.h"
 
 
 
diff --git a/src/analysis/types/encaps.c b/src/analysis/types/encaps.c
index bde6ba8..72d89ef 100644
--- a/src/analysis/types/encaps.c
+++ b/src/analysis/types/encaps.c
@@ -30,6 +30,7 @@
 
 #include "../type-int.h"
 #include "../../common/extstr.h"
+#include "../../common/leb128.h"
 
 
 
diff --git a/src/analysis/types/expr.c b/src/analysis/types/expr.c
index b6f8168..84d70d6 100644
--- a/src/analysis/types/expr.c
+++ b/src/analysis/types/expr.c
@@ -29,6 +29,7 @@
 
 
 #include "../type-int.h"
+#include "../../common/leb128.h"
 
 
 
diff --git a/src/analysis/types/override.c b/src/analysis/types/override.c
index 17453b6..df9748a 100644
--- a/src/analysis/types/override.c
+++ b/src/analysis/types/override.c
@@ -31,6 +31,7 @@
 
 #include "../type-int.h"
 #include "../../common/extstr.h"
+#include "../../common/leb128.h"
 
 
 
diff --git a/src/analysis/types/proto.c b/src/analysis/types/proto.c
index d19a104..aad073a 100644
--- a/src/analysis/types/proto.c
+++ b/src/analysis/types/proto.c
@@ -31,6 +31,7 @@
 
 #include "../type-int.h"
 #include "../../common/extstr.h"
+#include "../../common/leb128.h"
 
 
 
diff --git a/src/analysis/types/template.c b/src/analysis/types/template.c
index 4a8292a..163747f 100644
--- a/src/analysis/types/template.c
+++ b/src/analysis/types/template.c
@@ -31,6 +31,7 @@
 
 #include "../type-int.h"
 #include "../../common/extstr.h"
+#include "../../common/leb128.h"
 
 
 
diff --git a/tests/analysis/storage/storage.py b/tests/analysis/storage/storage.py
new file mode 100644
index 0000000..612d500
--- /dev/null
+++ b/tests/analysis/storage/storage.py
@@ -0,0 +1,81 @@
+
+from chrysacase import ChrysalideTestCase
+from pychrysalide import core
+from pychrysalide.analysis.contents import FileContent
+from pychrysalide.analysis.storage import ObjectStorage
+from pychrysalide.common import PackedBuffer
+import os
+import shutil
+import tempfile
+
+
+class TestObjectStorage(ChrysalideTestCase):
+    """TestCase for analysis.storage."""
+
+    @classmethod
+    def setUpClass(cls):
+
+        super(TestObjectStorage, cls).setUpClass()
+
+        cls._tmp_path = tempfile.mkdtemp()
+
+        config = core.get_main_configuration()
+        param = config.search(core.MainParameterKeys.TMPDIR)
+
+        cls._old_tmpdir = param.value
+        param.value = cls._tmp_path
+
+        cls.log('Using temporary directory "%s"' % cls._tmp_path)
+
+
+    @classmethod
+    def tearDownClass(cls):
+
+        super(TestObjectStorage, cls).tearDownClass()
+
+        config = core.get_main_configuration()
+        param = config.search(core.MainParameterKeys.TMPDIR)
+
+        param.value = cls._old_tmpdir
+
+        # import os
+        # os.system('ls -laihR %s' % cls._tmp_path)
+
+        cls.log('Delete directory "%s"' % cls._tmp_path)
+
+        shutil.rmtree(cls._tmp_path)
+
+
+    def testFileContentStorage(self):
+        """Store and load file binary content."""
+
+        storage = ObjectStorage('my-storage-hash')
+        self.assertIsNotNone(storage)
+
+        filename = os.path.join(self._tmp_path, 'test.bin')
+
+        with open(filename, 'wb') as fd:
+            fd.write(b'ABC')
+
+        cnt = FileContent(filename)
+        self.assertIsNotNone(cnt)
+
+        ret = storage.store_object('contents', cnt)
+        self.assertEqual(ret, 0)
+
+        pbuf = PackedBuffer()
+
+        ret = storage.store(pbuf)
+        self.assertTrue(ret)
+
+        self.assertTrue(pbuf.payload_length > 0)
+
+        pbuf.rewind()
+
+        storage2 = ObjectStorage.load(pbuf)
+        self.assertIsNotNone(storage2)
+
+        cnt2 = storage2.load_object('contents', 0)
+        self.assertIsNotNone(cnt2)
+
+        self.assertEqual(cnt.data, cnt2.data)
-- 
cgit v0.11.2-87-g4458