From 733d0cdb8677fe09310125bcaeb058a1a9c56b4d Mon Sep 17 00:00:00 2001
From: Cyrille Bagard <nocbos@gmail.com>
Date: Thu, 13 Mar 2025 01:19:58 +0100
Subject: Rebuild a generic storage for GObjects using a ZIP format.

---
 plugins/pychrysalide/glibext/Makefile.am |   2 +
 plugins/pychrysalide/glibext/module.c    |   4 +
 plugins/pychrysalide/glibext/serialize.c | 141 ++---
 plugins/pychrysalide/glibext/serialize.h |  12 +-
 plugins/pychrysalide/glibext/storage.c   | 225 ++-----
 plugins/pychrysalide/glibext/storage.h   |  12 +-
 src/Makefile.am                          |   2 +-
 src/common/cpp.h                         |   7 +
 src/glibext/Makefile.am                  |   8 +-
 src/glibext/serialize-int.h              |  18 +-
 src/glibext/serialize.c                  |  28 +-
 src/glibext/serialize.h                  |  38 +-
 src/glibext/storage-int.h                |  21 +-
 src/glibext/storage.c                    | 994 ++++++++++++++++++++-----------
 src/glibext/storage.h                    |  70 +--
 src/glibext/tpmem-int.h                  |  78 +++
 src/glibext/tpmem.c                      | 224 +++----
 src/glibext/tpmem.h                      |  41 +-
 system/magic/storage                     |  40 ++
 tests/glibext/storage.py                 |  75 ++-
 20 files changed, 1109 insertions(+), 931 deletions(-)
 create mode 100644 src/glibext/tpmem-int.h
 create mode 100644 system/magic/storage

diff --git a/plugins/pychrysalide/glibext/Makefile.am b/plugins/pychrysalide/glibext/Makefile.am
index af1d9f2..3a5fab2 100644
--- a/plugins/pychrysalide/glibext/Makefile.am
+++ b/plugins/pychrysalide/glibext/Makefile.am
@@ -27,7 +27,9 @@ libpychrysaglibext_la_SOURCES =				\
 	objhole.h objhole.c						\
 	portion.h portion.c						\
 	secstorage.h secstorage.c				\
+	serialize.h serialize.c					\
 	singleton.h singleton.c					\
+	storage.h storage.c						\
 	strbuilder.h strbuilder.c				\
 	work.h work.c							\
 	workqueue.h workqueue.c
diff --git a/plugins/pychrysalide/glibext/module.c b/plugins/pychrysalide/glibext/module.c
index 6ce0709..bbe357d 100644
--- a/plugins/pychrysalide/glibext/module.c
+++ b/plugins/pychrysalide/glibext/module.c
@@ -44,7 +44,9 @@
 #include "objhole.h"
 #include "portion.h"
 #include "secstorage.h"
+#include "serialize.h"
 #include "singleton.h"
+#include "storage.h"
 #include "strbuilder.h"
 #include "work.h"
 #include "workqueue.h"
@@ -116,12 +118,14 @@ bool populate_glibext_module(void)
 
     if (result) result = ensure_python_comparable_object_is_registered();
     if (result) result = ensure_python_hashable_object_is_registered();
+    if (result) result = ensure_python_serializable_object_is_registered();
     if (result) result = ensure_python_singleton_candidate_is_registered();
     if (result) result = ensure_python_string_builder_is_registered();
 
     if (result) result = ensure_python_thick_object_is_registered();
     if (result) result = ensure_python_binary_portion_is_registered();
     if (result) result = ensure_python_generic_work_is_registered();
+    if (result) result = ensure_python_object_storage_is_registered();
     if (result) result = ensure_python_secret_storage_is_registered();
     if (result) result = ensure_python_singleton_factory_is_registered();
     if (result) result = ensure_python_work_queue_is_registered();
diff --git a/plugins/pychrysalide/glibext/serialize.c b/plugins/pychrysalide/glibext/serialize.c
index 40fcef7..61f359f 100644
--- a/plugins/pychrysalide/glibext/serialize.c
+++ b/plugins/pychrysalide/glibext/serialize.c
@@ -1,8 +1,8 @@
 
 /* Chrysalide - Outil d'analyse de fichiers binaires
- * serialize.c - équivalent Python du fichier "analysis/storage/serialize.h"
+ * serialize.c - équivalent Python du fichier "glibext/serialize.h"
  *
- * Copyright (C) 2020 Cyrille Bagard
+ * Copyright (C) 2020-2025 Cyrille Bagard
  *
  *  This file is part of Chrysalide.
  *
@@ -28,13 +28,12 @@
 #include <pygobject.h>
 
 
-#include <analysis/storage/serialize-int.h>
+#include <glibext/serialize-int.h>
 
 
 #include "storage.h"
-#include "../../access.h"
-#include "../../helpers.h"
-#include "../../common/packed.h"
+#include "../access.h"
+#include "../helpers.h"
 
 
 
@@ -42,23 +41,23 @@
 
 
 /* Procède à l'initialisation de l'interface de génération. */
-static void py_serializable_object_interface_init(GSerializableObjectIface *, gpointer *);
+static void py_serializable_object_interface_init(GSerializableObjectInterface *, gpointer *);
 
-/* Charge un objet depuis une mémoire tampon. */
-static bool py_serializable_object_load_wrapper(GSerializableObject *, GObjectStorage *, packed_buffer_t *);
+/* Charge un objet depuis un flux de données. */
+static bool py_serializable_object_load_wrapper(GSerializableObject *, GObjectStorage *, int);
 
-/* Sauvegarde un objet dans une mémoire tampon. */
-static bool py_serializable_object_store_wrapper(const GSerializableObject *, GObjectStorage *, packed_buffer_t *);
+/* Sauvegarde un objet dans un flux de données. */
+static bool py_serializable_object_store_wrapper(const GSerializableObject *, GObjectStorage *, int);
 
 
 
 /* ------------------------- CONNEXION AVEC L'API DE PYTHON ------------------------- */
 
 
-/* Charge un objet depuis une mémoire tampon. */
+/* Charge un objet depuis un flux de données. */
 static bool py_serializable_object_load(PyObject *, PyObject *);
 
-/* Sauvegarde un objet dans une mémoire tampon. */
+/* Sauvegarde un objet dans un flux de données. */
 static bool py_serializable_object_store(PyObject *, PyObject *);
 
 
@@ -81,7 +80,7 @@ static bool py_serializable_object_store(PyObject *, PyObject *);
 *                                                                             *
 ******************************************************************************/
 
-static void py_serializable_object_interface_init(GSerializableObjectIface *iface, gpointer *unused)
+static void py_serializable_object_interface_init(GSerializableObjectInterface *iface, gpointer *unused)
 {
 
 #define SERIALIZABLE_OBJECT_DOC                                             \
@@ -94,8 +93,8 @@ static void py_serializable_object_interface_init(GSerializableObjectIface *ifac
     "        ...\n"                                                         \
     "\n"                                                                    \
     "The following methods have to be defined for new implementations:\n"   \
-    "* pychrysalide.analysis.storage.SerializableObject._load();\n"         \
-    "* pychrysalide.analysis.storage.SerializableObject._store();\n"
+    "* pychrysalide.glibext.SerializableObject._load();\n"         \
+    "* pychrysalide.glibext.SerializableObject._store();\n"
 
     iface->load = py_serializable_object_load_wrapper;
     iface->store = py_serializable_object_store_wrapper;
@@ -106,10 +105,10 @@ static void py_serializable_object_interface_init(GSerializableObjectIface *ifac
 /******************************************************************************
 *                                                                             *
 *  Paramètres  : object  = instruction d'assemblage à consulter.              *
-*                storage = conservateur de données à manipuler ou NULL.       *
-*                pbuf    = zone tampon à remplir.                             *
+*                storage = conservateur de données à manipuler.               *
+*                fd      = flux ouvert en lecture.                            *
 *                                                                             *
-*  Description : Charge un objet depuis une mémoire tampon.                   *
+*  Description : Charge un objet depuis un flux de données.                   *
 *                                                                             *
 *  Retour      : Bilan de l'opération.                                        *
 *                                                                             *
@@ -117,25 +116,24 @@ static void py_serializable_object_interface_init(GSerializableObjectIface *ifac
 *                                                                             *
 ******************************************************************************/
 
-static bool py_serializable_object_load_wrapper(GSerializableObject *object, GObjectStorage *storage, packed_buffer_t *pbuf)
+static bool py_serializable_object_load_wrapper(GSerializableObject *object, GObjectStorage *storage, int fd)
 {
     bool result;                            /* Bilan à retourner           */
     PyGILState_STATE gstate;                /* Sauvegarde d'environnement  */
-    PyObject *storage_obj;                  /* Objet Python à emmployer    */
     PyObject *args;                         /* Arguments pour l'appel      */
     PyObject *pyobj;                        /* Objet Python concerné       */
     PyObject *pyret;                        /* Bilan de consultation       */
 
 #define SERIALIZABLE_OBJECT_LOAD_WRAPPER PYTHON_WRAPPER_DEF                     \
 (                                                                               \
-    _load, "$self, storage, pbuf, /",                                           \
+    _load, "$self, storage, fd, /",                                             \
     METH_VARARGS,                                                               \
-    "Abstract method used to load an object definition from buffered data.\n"   \
+    "Abstract method used to load an object definition from a data stream.\n"   \
     "\n"                                                                        \
-    "The *storage* is a pychrysalide.analysis.storage.ObjectStorage instance"   \
-    " provided to store inner objects, if relevant, or None. The *pbuf*"        \
-    " argument points to a pychrysalide.common.PackedBuffer object containing"  \
-    " the data to process.\n"                                                   \
+    "The *storage* is a pychrysalide.glibext.ObjectStorage instance"            \
+    " provided to store inner objects. The *fd* argument is an integer value"   \
+    " provided as a file descriptor which as to be kept open after"             \
+    " processing.\n"                                                            \
     "\n"                                                                        \
     "The result is a boolean indicating the status of the operation."           \
 )
@@ -148,17 +146,9 @@ static bool py_serializable_object_load_wrapper(GSerializableObject *object, GOb
 
     if (has_python_method(pyobj, "_load"))
     {
-        if (storage == NULL)
-        {
-            storage_obj = Py_None;
-            Py_INCREF(storage_obj);
-        }
-        else
-            storage_obj = pygobject_new(G_OBJECT(storage));
-
         args = PyTuple_New(2);
-        PyTuple_SetItem(args, 0, storage_obj);
-        PyTuple_SetItem(args, 1, build_from_internal_packed_buffer(pbuf));
+        PyTuple_SetItem(args, 0, pygobject_new(G_OBJECT(storage)));
+        PyTuple_SetItem(args, 1, PyLong_FromLong(fd));
 
         pyret = run_python_method(pyobj, "_load", args);
 
@@ -182,10 +172,10 @@ static bool py_serializable_object_load_wrapper(GSerializableObject *object, GOb
 /******************************************************************************
 *                                                                             *
 *  Paramètres  : object  = instruction d'assemblage à consulter.              *
-*                storage = conservateur de données à manipuler ou NULL.       *
-*                pbuf    = zone tampon à remplir.                             *
+*                storage = conservateur de données à manipuler.               *
+*                fd      = flux ouvert en écriture.                           *
 *                                                                             *
-*  Description : Sauvegarde un objet dans une mémoire tampon.                 *
+*  Description : Sauvegarde un objet dans un flux de données.                 *
 *                                                                             *
 *  Retour      : Bilan de l'opération.                                        *
 *                                                                             *
@@ -193,25 +183,24 @@ static bool py_serializable_object_load_wrapper(GSerializableObject *object, GOb
 *                                                                             *
 ******************************************************************************/
 
-static bool py_serializable_object_store_wrapper(const GSerializableObject *object, GObjectStorage *storage, packed_buffer_t *pbuf)
+static bool py_serializable_object_store_wrapper(const GSerializableObject *object, GObjectStorage *storage, int fd)
 {
     bool result;                            /* Bilan à retourner           */
     PyGILState_STATE gstate;                /* Sauvegarde d'environnement  */
-    PyObject *storage_obj;                  /* Objet Python à emmployer    */
     PyObject *args;                         /* Arguments pour l'appel      */
     PyObject *pyobj;                        /* Objet Python concerné       */
     PyObject *pyret;                        /* Bilan de consultation       */
 
 #define SERIALIZABLE_OBJECT_STORE_WRAPPER PYTHON_WRAPPER_DEF                    \
 (                                                                               \
-    _store, "$self, storage, pbuf, /",                                          \
+    _store, "$self, storage, fd, /",                                            \
     METH_VARARGS,                                                               \
-    "Abstract method used to store an object definition into buffered data.\n"  \
+    "Abstract method used to store an object definition into a data stream.\n"  \
     "\n"                                                                        \
-    "The *storage* is a pychrysalide.analysis.storage.ObjectStorage instance"   \
-    " provided to store inner objects, if relevant, or None. The *pbuf*"        \
-    " argument points to a pychrysalide.common.PackedBuffer object containing"  \
-    " the data to process.\n"                                                   \
+    "The *storage* is a pychrysalide.glibext.ObjectStorage instance"            \
+    " provided to store inner objects. The *fd* argument is an integer value"   \
+    " provided as a file descriptor which as to be kept open after"             \
+    " processing.\n"                                                            \
     "\n"                                                                        \
     "The result is a boolean indicating the status of the operation."           \
 )
@@ -224,17 +213,9 @@ static bool py_serializable_object_store_wrapper(const GSerializableObject *obje
 
     if (has_python_method(pyobj, "_store"))
     {
-        if (storage == NULL)
-        {
-            storage_obj = Py_None;
-            Py_INCREF(storage_obj);
-        }
-        else
-            storage_obj = pygobject_new(G_OBJECT(storage));
-
         args = PyTuple_New(2);
-        PyTuple_SetItem(args, 0, storage_obj);
-        PyTuple_SetItem(args, 1, build_from_internal_packed_buffer(pbuf));
+        PyTuple_SetItem(args, 0, pygobject_new(G_OBJECT(storage)));
+        PyTuple_SetItem(args, 1, PyLong_FromLong(fd));
 
         pyret = run_python_method(pyobj, "_store", args);
 
@@ -266,7 +247,7 @@ static bool py_serializable_object_store_wrapper(const GSerializableObject *obje
 *  Paramètres  : self = classe représentant un générateur à manipuler.        *
 *                args = arguments fournis à l'appel.                          *
 *                                                                             *
-*  Description : Charge un objet depuis une mémoire tampon.                   *
+*  Description : Charge un objet depuis un flux de données.                   *
 *                                                                             *
 *  Retour      : Bilan de l'opération.                                        *
 *                                                                             *
@@ -278,32 +259,30 @@ static bool py_serializable_object_load(PyObject *self, PyObject *args)
 {
     PyObject *result;                       /* Bilan à retourner           */
     GObjectStorage *storage;                /* Conservateur à manipuler    */
-    packed_buffer_t *pbuf;                  /* Tampon de données à employer*/
+    int fd;                                 /* Flux ouvert (en lecture)    */
     int ret;                                /* Bilan de lecture des args.  */
     GSerializableObject *object;            /* Version native              */
     bool status;                            /* Bilan de l'opération        */
 
 #define SERIALIZABLE_OBJECT_LOAD_METHOD PYTHON_METHOD_DEF                       \
 (                                                                               \
-    load, "$self, storage, pbuf, /",                                            \
+    load, "$self, storage, fd, /",                                              \
     METH_VARARGS, py_serializable_object,                                       \
-    "Load an object definition from buffered data.\n"                           \
+    "Load an object definition from a data stream.\n"                           \
     "\n"                                                                        \
-    "The *storage* is a pychrysalide.analysis.storage.ObjectStorage instance"   \
-    " provided to store inner objects, if relevant, or None. The *pbuf*"        \
-    " argument points to a pychrysalide.common.PackedBuffer object containing"  \
-    " the data to process.\n"                                                   \
+    "The *storage* is a pychrysalide.glibext.ObjectStorage instance"            \
+    " provided to store inner objects. The *fd* argument is an integer value"   \
+    " used as a file descriptor for writing data\n"                             \
     "\n"                                                                        \
     "The result is a boolean indicating the status of the operation."           \
 )
 
-    ret = PyArg_ParseTuple(args, "O&O&", convert_to_object_storage_or_none, &storage,
-                           convert_to_packed_buffer, &pbuf);
+    ret = PyArg_ParseTuple(args, "O&i", convert_to_object_storage, &storage, &fd);
     if (!ret) return NULL;
 
     object = G_SERIALIZABLE_OBJECT(pygobject_get(self));
 
-    status = g_serializable_object_load(object, storage, pbuf);
+    status = g_serializable_object_load(object, storage, fd);
 
     result = status ? Py_True : Py_False;
     Py_INCREF(result);
@@ -318,7 +297,7 @@ static bool py_serializable_object_load(PyObject *self, PyObject *args)
 *  Paramètres  : self = classe représentant un générateur à manipuler.        *
 *                args = arguments fournis à l'appel.                          *
 *                                                                             *
-*  Description : Sauvegarde un objet dans une mémoire tampon.                 *
+*  Description : Sauvegarde un objet dans un flux de données.                 *
 *                                                                             *
 *  Retour      : Bilan de l'opération.                                        *
 *                                                                             *
@@ -330,32 +309,30 @@ static bool py_serializable_object_store(PyObject *self, PyObject *args)
 {
     PyObject *result;                       /* Bilan à retourner           */
     GObjectStorage *storage;                /* Conservateur à manipuler    */
-    packed_buffer_t *pbuf;                  /* Tampon de données à employer*/
+    int fd;                                 /* Flux ouvert (en lecture)    */
     int ret;                                /* Bilan de lecture des args.  */
     GSerializableObject *object;            /* Version native              */
     bool status;                            /* Bilan de l'opération        */
 
 #define SERIALIZABLE_OBJECT_STORE_METHOD PYTHON_METHOD_DEF                      \
 (                                                                               \
-    store, "$self, storage, pbuf, /",                                           \
+    store, "$self, storage, fd, /",                                             \
     METH_VARARGS, py_serializable_object,                                       \
-    "Store an object definition into buffered data.\n"                          \
+    "Store an object definition into a data stream.\n"                          \
     "\n"                                                                        \
-    "The *storage* is a pychrysalide.analysis.storage.ObjectStorage instance"   \
-    " provided to store inner objects, if relevant, or None. The *pbuf*"        \
-    " argument points to a pychrysalide.common.PackedBuffer object containing"  \
-    " the data to process.\n"                                                   \
+    "The *storage* is a pychrysalide.glibext.ObjectStorage instance"            \
+    " provided to store inner objects. The *fd* argument is an integer value"   \
+    " used as a file descriptor for writing data\n"                             \
     "\n"                                                                        \
     "The result is a boolean indicating the status of the operation."           \
 )
 
-    ret = PyArg_ParseTuple(args, "O&O&", convert_to_object_storage_or_none, &storage,
-                           convert_to_packed_buffer, &pbuf);
+    ret = PyArg_ParseTuple(args, "O&i", convert_to_object_storage, &storage, &fd);
     if (!ret) return NULL;
 
     object = G_SERIALIZABLE_OBJECT(pygobject_get(self));
 
-    status = g_serializable_object_store(object, storage, pbuf);
+    status = g_serializable_object_store(object, storage, fd);
 
     result = status ? Py_True : Py_False;
     Py_INCREF(result);
@@ -395,7 +372,7 @@ PyTypeObject *get_python_serializable_object_type(void)
 
         PyVarObject_HEAD_INIT(NULL, 0)
 
-        .tp_name        = "pychrysalide.analysis.storage.SerializableObject",
+        .tp_name        = "pychrysalide.glibext.SerializableObject",
         .tp_basicsize   = sizeof(PyObject),
 
         .tp_flags       = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
@@ -442,7 +419,7 @@ bool ensure_python_serializable_object_is_registered(void)
 
     if (!PyType_HasFeature(type, Py_TPFLAGS_READY))
     {
-        module = get_access_to_python_module("pychrysalide.analysis.storage");
+        module = get_access_to_python_module("pychrysalide.glibext");
 
         dict = PyModule_GetDict(module);
 
diff --git a/plugins/pychrysalide/glibext/serialize.h b/plugins/pychrysalide/glibext/serialize.h
index 7e831e5..90688ba 100644
--- a/plugins/pychrysalide/glibext/serialize.h
+++ b/plugins/pychrysalide/glibext/serialize.h
@@ -1,8 +1,8 @@
 
 /* Chrysalide - Outil d'analyse de fichiers binaires
- * serialize.h - prototypes pour l'équivalent Python du fichier "analysis/storage/serialize.h"
+ * serialize.h - prototypes pour l'équivalent Python du fichier "glibext/serialize.h"
  *
- * Copyright (C) 2020 Cyrille Bagard
+ * Copyright (C) 2020-2025 Cyrille Bagard
  *
  *  This file is part of Chrysalide.
  *
@@ -22,8 +22,8 @@
  */
 
 
-#ifndef _PLUGINS_PYCHRYSALIDE_ANALYSIS_STORAGE_SERIALIZE_H
-#define _PLUGINS_PYCHRYSALIDE_ANALYSIS_STORAGE_SERIALIZE_H
+#ifndef _PLUGINS_PYCHRYSALIDE_GLIBEXT_SERIALIZE_H
+#define _PLUGINS_PYCHRYSALIDE_GLIBEXT_SERIALIZE_H
 
 
 #include <Python.h>
@@ -34,7 +34,7 @@
 /* Fournit un accès à une définition de type à diffuser. */
 PyTypeObject *get_python_serializable_object_type(void);
 
-/* Prend en charge l'objet 'pychrysalide.analysis.storage.SerializableObject'. */
+/* Prend en charge l'objet 'pychrysalide.glibext.SerializableObject'. */
 bool ensure_python_serializable_object_is_registered(void);
 
 /* Tente de convertir en objet adapté à une mise en cache. */
@@ -42,4 +42,4 @@ int convert_to_serializable_object(PyObject *, void *);
 
 
 
-#endif  /* _PLUGINS_PYCHRYSALIDE_ANALYSIS_STORAGE_SERIALIZE_H */
+#endif  /* _PLUGINS_PYCHRYSALIDE_GLIBEXT_SERIALIZE_H */
diff --git a/plugins/pychrysalide/glibext/storage.c b/plugins/pychrysalide/glibext/storage.c
index c54fe0f..4764700 100644
--- a/plugins/pychrysalide/glibext/storage.c
+++ b/plugins/pychrysalide/glibext/storage.c
@@ -1,8 +1,8 @@
 
 /* Chrysalide - Outil d'analyse de fichiers binaires
- * storage.c - équivalent Python du fichier "analysis/storage/storage.c"
+ * storage.c - équivalent Python du fichier "glibext/storage.c"
  *
- * Copyright (C) 2020 Cyrille Bagard
+ * Copyright (C) 2020-2025 Cyrille Bagard
  *
  *  This file is part of Chrysalide.
  *
@@ -25,25 +25,23 @@
 #include "storage.h"
 
 
+#include <assert.h>
 #include <pygobject.h>
 
 
-#include <analysis/storage/storage-int.h>
-#include <plugins/dt.h>
+#include <glibext/storage-int.h>
 
 
 #include "serialize.h"
-#include "../../access.h"
-#include "../../helpers.h"
-#include "../../common/packed.h"
+#include "../access.h"
+#include "../helpers.h"
 
 
 
 /* ------------------------ GLUE POUR CREATION DEPUIS PYTHON ------------------------ */
 
 
-/* Accompagne la création d'une instance dérivée en Python. */
-static PyObject *py_object_storage_new(PyTypeObject *, PyObject *, PyObject *);
+CREATE_DYN_CONSTRUCTOR(object_storage, G_TYPE_OBJECT_STORAGE);
 
 /* Initialise une instance sur la base du dérivé de GObject. */
 static int py_object_storage_init(PyObject *, PyObject *, PyObject *);
@@ -68,9 +66,6 @@ static PyObject *py_object_storage_unpack_object(PyObject *, PyObject *);
 /* Sauvegarde un object sous forme de données rassemblées. */
 static PyObject *py_object_storage_store_object(PyObject *, PyObject *);
 
-/* Sauvegarde un object interne sous forme de données. */
-static PyObject *py_object_storage_pack_object(PyObject *, PyObject *);
-
 
 
 /* ---------------------------------------------------------------------------------- */
@@ -80,66 +75,6 @@ static PyObject *py_object_storage_pack_object(PyObject *, PyObject *);
 
 /******************************************************************************
 *                                                                             *
-*  Paramètres  : type = type du nouvel objet à mettre en place.               *
-*                args = éventuelle liste d'arguments.                         *
-*                kwds = éventuel dictionnaire de valeurs mises à disposition. *
-*                                                                             *
-*  Description : Accompagne la création d'une instance dérivée en Python.     *
-*                                                                             *
-*  Retour      : Nouvel objet Python mis en place ou NULL en cas d'échec.     *
-*                                                                             *
-*  Remarques   : -                                                            *
-*                                                                             *
-******************************************************************************/
-
-static PyObject *py_object_storage_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
-{
-    PyObject *result;                       /* Objet à retourner           */
-    PyTypeObject *base;                     /* Type de base à dériver      */
-    bool first_time;                        /* Evite les multiples passages*/
-    GType gtype;                            /* Nouveau type de processeur  */
-    bool status;                            /* Bilan d'un enregistrement   */
-
-    /* Validations diverses */
-
-    base = get_python_object_storage_type();
-
-    if (type == base)
-        goto simple_way;
-
-    /* Mise en place d'un type dédié */
-
-    first_time = (g_type_from_name(type->tp_name) == 0);
-
-    gtype = build_dynamic_type(G_TYPE_OBJECT_STORAGE, type->tp_name, NULL, NULL, NULL);
-
-    if (first_time)
-    {
-        status = register_class_for_dynamic_pygobject(gtype, type);
-
-        if (!status)
-        {
-            result = NULL;
-            goto exit;
-        }
-
-    }
-
-    /* On crée, et on laisse ensuite la main à PyGObject_Type.tp_init() */
-
- simple_way:
-
-    result = PyType_GenericNew(type, args, kwds);
-
- exit:
-
-    return result;
-
-}
-
-
-/******************************************************************************
-*                                                                             *
 *  Paramètres  : self = objet à initialiser (théoriquement).                  *
 *                args = arguments fournis à l'appel.                          *
 *                kwds = arguments de type key=val fournis.                    *
@@ -154,7 +89,9 @@ static PyObject *py_object_storage_new(PyTypeObject *type, PyObject *args, PyObj
 
 static int py_object_storage_init(PyObject *self, PyObject *args, PyObject *kwds)
 {
-    const char *hash;                       /* Empreinte de contenu        */
+    const char *type;                       /* Type global de conservation */
+    unsigned char version;                  /* Version de ce type          */
+    const char *uid;                        /* Identifiant de distinction  */
     int ret;                                /* Bilan de lecture des args.  */
     GObjectStorage *storage;                /* Mécanismes natifs           */
 
@@ -164,14 +101,15 @@ static int py_object_storage_init(PyObject *self, PyObject *args, PyObject *kwds
     "\n"                                                                \
     "Instances can be created using the following constructor:\n"       \
     "\n"                                                                \
-    "    ObjectStorage(hash)"                                           \
+    "    ObjectStorage(type, version uid)"                              \
     "\n"                                                                \
-    "Where *hash* should a string built from the checksum of the"       \
-    " relative binary content linked to the storage.pychrysalide."
+    "Where *type* is a short string describing the storage kind,"       \
+    " *version* provides a version control for this type and *uid* is"  \
+    " an arbitrary unique identifier used for creating temporary files."
 
     /* Récupération des paramètres */
 
-    ret = PyArg_ParseTuple(args, "s", &hash);
+    ret = PyArg_ParseTuple(args, "sbs", &type, &version, &uid);
     if (!ret) return -1;
 
     /* Initialisation d'un objet GLib */
@@ -183,7 +121,8 @@ static int py_object_storage_init(PyObject *self, PyObject *args, PyObject *kwds
 
     storage = G_OBJECT_STORAGE(pygobject_get(self));
 
-    storage->hash = strdup(hash);
+    if (!g_object_storage_create(storage, type, version, uid))
+        return -1;
 
     return 0;
 
@@ -212,27 +151,27 @@ static int py_object_storage_init(PyObject *self, PyObject *args, PyObject *kwds
 static PyObject *py_object_storage_load(PyObject *self, PyObject *args)
 {
     PyObject *result;                       /* Emplacement à retourner     */
-    packed_buffer_t *pbuf;                  /* Tampon de données à employer*/
+    const char *filename;                   /* Fichier de source à traiter */
     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."                             \
+#define OBJECT_STORAGE_LOAD_METHOD PYTHON_METHOD_DEF            \
+(                                                               \
+    load, "filename, /",                                        \
+    METH_STATIC | METH_VARARGS, py_object_storage,              \
+    "Construct a new storage from a filename.\n"                \
+    "\n"                                                        \
+    "The *filename* argument points to the source file to"      \
+    " read.\n"                                                  \
+    "\n"                                                        \
+    "The result is a new pychrysalide.glibext.ObjectStorage"    \
+    " object on success, *None* otherwise."                     \
 )
 
-    ret = PyArg_ParseTuple(args, "O&", convert_to_packed_buffer, &pbuf);
+    ret = PyArg_ParseTuple(args, "s", &filename);
     if (!ret) return NULL;
 
-    storage = g_object_storage_load(pbuf);
+    storage = g_object_storage_load(filename);
 
     if (storage == NULL)
     {
@@ -242,7 +181,7 @@ static PyObject *py_object_storage_load(PyObject *self, PyObject *args)
     else
     {
         result = pygobject_new(G_OBJECT(storage));
-        g_object_unref(G_OBJECT(storage));
+        unref_object(storage);
     }
 
     return result;
@@ -266,29 +205,29 @@ static PyObject *py_object_storage_load(PyObject *self, PyObject *args)
 static PyObject *py_object_storage_store(PyObject *self, PyObject *args)
 {
     PyObject *result;                       /* Emplacement à retourner     */
-    packed_buffer_t *pbuf;                  /* Tampon de données à employer*/
+    const char *filename;                   /* Fichier de destination      */
     int ret;                                /* Bilan de lecture des args.  */
     GObjectStorage *storage;                /* Mécanismes natifs           */
     bool status;                            /* Bilan de l'opération        */
 
 #define OBJECT_STORAGE_STORE_METHOD PYTHON_METHOD_DEF       \
 (                                                           \
-    store, "$self, pbuf, /",                                \
+    store, "$self, filename, /",                            \
     METH_VARARGS, py_object_storage,                        \
-    "Save a storage into a buffer.\n"                       \
+    "Save a storage into a file.\n"                         \
     "\n"                                                    \
-    "The *pbuf* has to be an instance of type"              \
-    " pychrysalide.common.PackedBuffer.\n"                  \
+    "The *filename* argument points to the destination"     \
+    " file to write.\n"                                     \
     "\n"                                                    \
     "The result is *True* on success, *False* otherwise."   \
 )
 
-    ret = PyArg_ParseTuple(args, "O&", convert_to_packed_buffer, &pbuf);
+    ret = PyArg_ParseTuple(args, "s", &filename);
     if (!ret) return NULL;
 
     storage = G_OBJECT_STORAGE(pygobject_get(self));
 
-    status = g_object_storage_store(storage, pbuf);
+    status = g_object_storage_store(storage, filename);
 
     result = status ? Py_True : Py_False;
     Py_INCREF(result);
@@ -331,7 +270,7 @@ static PyObject *py_object_storage_load_object(PyObject *self, PyObject *args)
     " the data to unserialize.\n"                                       \
     "\n"                                                                \
     "The result is a pychrysalide.analysis.storage.SerializableObject"  \
-    " instancet in case of success, or None in case of failure."        \
+    " instancet in case of success, or *None* in case of failure."      \
 )
 
     ret = PyArg_ParseTuple(args, "sK", &name, &pos);
@@ -370,31 +309,32 @@ static PyObject *py_object_storage_load_object(PyObject *self, PyObject *args)
 static PyObject *py_object_storage_unpack_object(PyObject *self, PyObject *args)
 {
     PyObject *result;                       /* Bilan à retourner           */
-    const char *name;                       /* Désignation de groupe       */
-    packed_buffer_t *pbuf;                  /* Tampon de données à employer*/
+    const char *name;                       /* Désignation de groupe #0    */
+    const char *target_name;                /* Désignation de groupe #1    */
     int ret;                                /* Bilan de lecture des args.  */
     GObjectStorage *storage;                /* Mécanismes natifs           */
     GSerializableObject *object;            /* Objet reconstruit ou NULL   */
 
 #define OBJECT_STORAGE_UNPACK_OBJECT_METHOD PYTHON_METHOD_DEF           \
 (                                                                       \
-    unpack_object, "$self, name, pbuf, /",                              \
+    unpack_object, "$self, name, target_name, /",                       \
     METH_VARARGS, py_object_storage,                                    \
-    "Load an object from a buffer with a location pointing to data.\n"  \
+    "Load an object from a reference to serialized data.\n"             \
     "\n"                                                                \
-    "The *name* is a string label for the group of target objects and"  \
-    " *pbuf* has to be a pychrysalide.common.PackedBuffer instance.\n"  \
+    "The *name* is a string label for the group containing a position"  \
+    " pointing to a target object to load. The *target_name* is a"      \
+    " string label for the group of this target object.\n"              \
     "\n"                                                                \
     "The result is a pychrysalide.analysis.storage.SerializableObject"  \
-    " instancet in case of success, or None in case of failure."        \
+    " instancet in case of success, or *None* in case of failure."      \
 )
 
-    ret = PyArg_ParseTuple(args, "sO&", &name, convert_to_packed_buffer, &pbuf);
+    ret = PyArg_ParseTuple(args, "sO&", &name, &target_name);
     if (!ret) return NULL;
 
     storage = G_OBJECT_STORAGE(pygobject_get(self));
 
-    object = g_object_storage_unpack_object(storage, name, pbuf);
+    object = g_object_storage_unpack_object(storage, name, target_name);
 
     if (object != NULL)
         result = pygobject_new(G_OBJECT(object));
@@ -443,7 +383,7 @@ static PyObject *py_object_storage_store_object(PyObject *self, PyObject *args)
     " pychrysalide.analysis.storage.SerializableObject instance.\n" \
     "\n"                                                            \
     "The result is the position of the data for stored object,"     \
-    " provided as an integer offset, in case of success or None"    \
+    " provided as an integer offset, in case of success or *None*"  \
     " in case of failure."                                          \
 )
 
@@ -469,62 +409,6 @@ static PyObject *py_object_storage_store_object(PyObject *self, PyObject *args)
 
 /******************************************************************************
 *                                                                             *
-*  Paramètres  : self = classe représentant une mémorisation de types.        *
-*                args = arguments fournis à l'appel.                          *
-*                                                                             *
-*  Description : Sauvegarde un object interne sous forme de données.          *
-*                                                                             *
-*  Retour      : Bilan de l'opération.                                        *
-*                                                                             *
-*  Remarques   : -                                                            *
-*                                                                             *
-******************************************************************************/
-
-static PyObject *py_object_storage_pack_object(PyObject *self, PyObject *args)
-{
-    PyObject *result;                       /* Emplacement à retourner     */
-    const char *name;                       /* Désignation de groupe       */
-    GSerializableObject *object;            /* Objet à traiter             */
-    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_PACK_OBJECT_METHOD PYTHON_METHOD_DEF         \
-(                                                                   \
-    pack_object, "$self, name, object, pbuf/",                      \
-    METH_VARARGS, py_object_storage,                                \
-    "Save an object as serialized data and store the location of"   \
-    " the data intro a buffer.\n"                                   \
-    "\n"                                                            \
-    "The *name* is a string label for the group of target objects," \
-    " the processed *object* has to be a"                           \
-    " pychrysalide.analysis.storage.SerializableObject instance"    \
-    " and *pbuf* is expected to be a"                               \
-    " pychrysalide.common.PackedBuffer instance.\n"                 \
-    "\n"                                                            \
-    "The status of the operation is returned as a boolean value:"   \
-    " *True* for success, *False* for failure."                     \
-)
-
-    ret = PyArg_ParseTuple(args, "sO&O&", &name, convert_to_serializable_object, &object,
-                           convert_to_packed_buffer, &pbuf);
-    if (!ret) return NULL;
-
-    storage = G_OBJECT_STORAGE(pygobject_get(self));
-
-    status = g_object_storage_pack_object(storage, name, object, pbuf);
-
-    result = status ? Py_True : Py_False;
-    Py_INCREF(result);
-
-    return result;
-
-}
-
-
-/******************************************************************************
-*                                                                             *
 *  Paramètres  : -                                                            *
 *                                                                             *
 *  Description : Fournit un accès à une définition de type à diffuser.        *
@@ -543,7 +427,6 @@ PyTypeObject *get_python_object_storage_type(void)
         OBJECT_STORAGE_LOAD_OBJECT_METHOD,
         OBJECT_STORAGE_UNPACK_OBJECT_METHOD,
         OBJECT_STORAGE_STORE_OBJECT_METHOD,
-        OBJECT_STORAGE_PACK_OBJECT_METHOD,
         { NULL }
     };
 
@@ -555,7 +438,7 @@ PyTypeObject *get_python_object_storage_type(void)
 
         PyVarObject_HEAD_INIT(NULL, 0)
 
-        .tp_name        = "pychrysalide.analysis.storage.ObjectStorage",
+        .tp_name        = "pychrysalide.glibext.ObjectStorage",
         .tp_basicsize   = sizeof(PyGObject),
 
         .tp_flags       = Py_TPFLAGS_DEFAULT,
@@ -579,7 +462,7 @@ PyTypeObject *get_python_object_storage_type(void)
 *                                                                             *
 *  Paramètres  : module = module dont la définition est à compléter.          *
 *                                                                             *
-*  Description : Prend en charge l'objet 'pychrysalide....ObjectStorage'.     *
+*  Description : Prend en charge l'objet 'pychrysalide.glibext.ObjectStorage'.*
 *                                                                             *
 *  Retour      : Bilan de l'opération.                                        *
 *                                                                             *
@@ -597,7 +480,7 @@ bool ensure_python_object_storage_is_registered(void)
 
     if (!PyType_HasFeature(type, Py_TPFLAGS_READY))
     {
-        module = get_access_to_python_module("pychrysalide.analysis.storage");
+        module = get_access_to_python_module("pychrysalide.glibext");
 
         dict = PyModule_GetDict(module);
 
diff --git a/plugins/pychrysalide/glibext/storage.h b/plugins/pychrysalide/glibext/storage.h
index a0a2c18..681f99a 100644
--- a/plugins/pychrysalide/glibext/storage.h
+++ b/plugins/pychrysalide/glibext/storage.h
@@ -1,8 +1,8 @@
 
 /* Chrysalide - Outil d'analyse de fichiers binaires
- * storage.h - prototypes pour l'équivalent Python du fichier "analysis/storage/storage.h"
+ * storage.h - prototypes pour l'équivalent Python du fichier "glibext/storage.h"
  *
- * Copyright (C) 2020 Cyrille Bagard
+ * Copyright (C) 2020-2025 Cyrille Bagard
  *
  *  This file is part of Chrysalide.
  *
@@ -22,8 +22,8 @@
  */
 
 
-#ifndef _PLUGINS_PYCHRYSALIDE_ANALYSIS_STORAGE_STORAGE_H
-#define _PLUGINS_PYCHRYSALIDE_ANALYSIS_STORAGE_STORAGE_H
+#ifndef _PLUGINS_PYCHRYSALIDE_GLIBEXT_STORAGE_H
+#define _PLUGINS_PYCHRYSALIDE_GLIBEXT_STORAGE_H
 
 
 #include <Python.h>
@@ -34,7 +34,7 @@
 /* Fournit un accès à une définition de type à diffuser. */
 PyTypeObject *get_python_object_storage_type(void);
 
-/* Prend en charge l'objet 'pychrysalide.analysis.storage.ObjectStorage'. */
+/* Prend en charge l'objet 'pychrysalide.glibext.ObjectStorage'. */
 bool ensure_python_object_storage_is_registered(void);
 
 /* Tente de convertir en conservateur d'objets. */
@@ -45,4 +45,4 @@ int convert_to_object_storage_or_none(PyObject *, void *);
 
 
 
-#endif  /* _PLUGINS_PYCHRYSALIDE_ANALYSIS_STORAGE_STORAGE_H */
+#endif  /* _PLUGINS_PYCHRYSALIDE_GLIBEXT_STORAGE_H */
diff --git a/src/Makefile.am b/src/Makefile.am
index c50af8f..cfd1a4d 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -86,7 +86,7 @@ libchrysacore4_la_LIBADD =					\
 	plugins/libplugins.la
 
 libchrysacore4_la_LDFLAGS =					\
-	$(TOOLKIT_LIBS) $(LIBSSL_LIBS) $(LIBJSONGLIB_LIBS)
+	$(TOOLKIT_LIBS) $(LIBSSL_LIBS) $(LIBJSONGLIB_LIBS) $(LIBZIP_LIBS)
 
 if BUILD_CURL_SUPPORT
 
diff --git a/src/common/cpp.h b/src/common/cpp.h
index 2644281..9616db3 100644
--- a/src/common/cpp.h
+++ b/src/common/cpp.h
@@ -43,6 +43,13 @@
 
 
 /**
+ * Facilite la transmission d'arguement pour des fonctions
+ * comme strncmp() et Cie.
+ */
+#define SL(str) str, strlen(str)
+
+
+/**
  * Détermine la taille de la plus longue chaîne de caractères
  * correspondant à un type donné.
  */
diff --git a/src/glibext/Makefile.am b/src/glibext/Makefile.am
index 81d13d2..f946665 100644
--- a/src/glibext/Makefile.am
+++ b/src/glibext/Makefile.am
@@ -49,10 +49,16 @@ libglibext_la_SOURCES =						\
 	portion.h portion.c						\
 	secstorage-int.h						\
 	secstorage.h secstorage.c				\
+	serialize-int.h							\
+	serialize.h serialize.c					\
 	singleton-int.h							\
 	singleton.h singleton.c					\
+	storage-int.h							\
+	storage.h storage.c						\
 	strbuilder-int.h						\
 	strbuilder.h strbuilder.c				\
+	tpmem-int.h								\
+	tpmem.h tpmem.c							\
 	work-int.h								\
 	work.h work.c							\
 	workgroup-int.h							\
@@ -60,7 +66,7 @@ libglibext_la_SOURCES =						\
 	workqueue-int.h							\
 	workqueue.h workqueue.c
 
-libglibext_la_CFLAGS = $(TOOLKIT_CFLAGS)
+libglibext_la_CFLAGS = $(TOOLKIT_CFLAGS) $(LIBZIP_CFLAGS)
 
 
 RES_FILES =									\
diff --git a/src/glibext/serialize-int.h b/src/glibext/serialize-int.h
index de8d3e3..df9c597 100644
--- a/src/glibext/serialize-int.h
+++ b/src/glibext/serialize-int.h
@@ -2,7 +2,7 @@
 /* Chrysalide - Outil d'analyse de fichiers binaires
  * serialize-int.h - définitions internes propres aux objets entreposables dans un cache
  *
- * Copyright (C) 2020 Cyrille Bagard
+ * Copyright (C) 2020-2025 Cyrille Bagard
  *
  *  This file is part of Chrysalide.
  *
@@ -21,8 +21,8 @@
  */
 
 
-#ifndef _ANALYSIS_STORAGE_SERIALIZE_INT_H
-#define _ANALYSIS_STORAGE_SERIALIZE_INT_H
+#ifndef _GLIBEXT_SERIALIZE_INT_H
+#define _GLIBEXT_SERIALIZE_INT_H
 
 
 #include "serialize.h"
@@ -33,14 +33,14 @@
 
 
 /* Charge un objet depuis une mémoire tampon. */
-typedef bool (* load_serializable_object_cb) (GSerializableObject *, GObjectStorage *, packed_buffer_t *);
+typedef bool (* load_serializable_object_cb) (GSerializableObject *, GObjectStorage *, int);
 
 /* Sauvegarde un objet dans une mémoire tampon. */
-typedef bool (* store_serializable_object_cb) (const GSerializableObject *, GObjectStorage *, packed_buffer_t *);
+typedef bool (* store_serializable_object_cb) (const GSerializableObject *, GObjectStorage *, int);
 
 
 /* Intermédiaire pour la mise en cache d'objet (interface) */
-struct _GSerializableObjectIface
+struct _GSerializableObjectInterface
 {
     GTypeInterface base_iface;              /* A laisser en premier        */
 
@@ -50,9 +50,5 @@ struct _GSerializableObjectIface
 };
 
 
-/* Redéfinition */
-typedef GSerializableObjectIface GSerializableObjectInterface;
 
-
-
-#endif  /* _ANALYSIS_STORAGE_SERIALIZE_INT_H */
+#endif  /* _GLIBEXT_SERIALIZE_INT_H */
diff --git a/src/glibext/serialize.c b/src/glibext/serialize.c
index d1b0502..b43f0c2 100644
--- a/src/glibext/serialize.c
+++ b/src/glibext/serialize.c
@@ -2,7 +2,7 @@
 /* Chrysalide - Outil d'analyse de fichiers binaires
  * serialize.h - objets entreposables dans un cache
  *
- * Copyright (C) 2020 Cyrille Bagard
+ * Copyright (C) 2020-2025 Cyrille Bagard
  *
  *  This file is part of Chrysalide.
  *
@@ -51,6 +51,8 @@ G_DEFINE_INTERFACE(GSerializableObject, g_serializable_object, G_TYPE_OBJECT)
 
 static void g_serializable_object_default_init(GSerializableObjectInterface *iface)
 {
+    iface->load = NULL;
+    iface->store = NULL;
 
 }
 
@@ -58,10 +60,10 @@ 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 à lire.                                *
+*                storage = conservateur de données à manipuler.               *
+*                fd      = flux ouvert en lecture.                            *
 *                                                                             *
-*  Description : Charge un objet depuis une mémoire tampon.                   *
+*  Description : Charge un objet depuis un flux de données.                   *
 *                                                                             *
 *  Retour      : Bilan de l'opération.                                        *
 *                                                                             *
@@ -69,14 +71,14 @@ static void g_serializable_object_default_init(GSerializableObjectInterface *ifa
 *                                                                             *
 ******************************************************************************/
 
-bool g_serializable_object_load(GSerializableObject *object, GObjectStorage *storage, packed_buffer_t *pbuf)
+bool g_serializable_object_load(GSerializableObject *object, GObjectStorage *storage, int fd)
 {
     bool result;                            /* Bilan à retourner           */
-    GSerializableObjectIface *iface;        /* Interface utilisée          */
+    GSerializableObjectInterface *iface;    /* Interface utilisée          */
 
     iface = G_SERIALIZABLE_OBJECT_GET_IFACE(object);
 
-    result = iface->load(object, storage, pbuf);
+    result = iface->load(object, storage, fd);
 
     return result;
 
@@ -86,10 +88,10 @@ bool g_serializable_object_load(GSerializableObject *object, GObjectStorage *sto
 /******************************************************************************
 *                                                                             *
 *  Paramètres  : object  = élément GLib à consulter.                          *
-*                storage = conservateur de données à manipuler ou NULL.       *
-*                pbuf    = zone tampon à remplir.                             *
+*                storage = conservateur de données à manipuler.               *
+*                fd      = flux ouvert en écriture.                           *
 *                                                                             *
-*  Description : Sauvegarde un objet dans une mémoire tampon.                 *
+*  Description : Sauvegarde un objet dans un flux de données.                 *
 *                                                                             *
 *  Retour      : Bilan de l'opération.                                        *
 *                                                                             *
@@ -97,14 +99,14 @@ bool g_serializable_object_load(GSerializableObject *object, GObjectStorage *sto
 *                                                                             *
 ******************************************************************************/
 
-bool g_serializable_object_store(const GSerializableObject *object, GObjectStorage *storage, packed_buffer_t *pbuf)
+bool g_serializable_object_store(const GSerializableObject *object, GObjectStorage *storage, int fd)
 {
     bool result;                            /* Bilan à retourner           */
-    GSerializableObjectIface *iface;        /* Interface utilisée          */
+    GSerializableObjectInterface *iface;    /* Interface utilisée          */
 
     iface = G_SERIALIZABLE_OBJECT_GET_IFACE(object);
 
-    result = iface->store(object, storage, pbuf);
+    result = iface->store(object, storage, fd);
 
     return result;
 
diff --git a/src/glibext/serialize.h b/src/glibext/serialize.h
index 93a4496..c95ac30 100644
--- a/src/glibext/serialize.h
+++ b/src/glibext/serialize.h
@@ -2,7 +2,7 @@
 /* Chrysalide - Outil d'analyse de fichiers binaires
  * serialize.h - prototypes pour les objets entreposables dans un cache
  *
- * Copyright (C) 2020 Cyrille Bagard
+ * Copyright (C) 2020-2025 Cyrille Bagard
  *
  *  This file is part of Chrysalide.
  *
@@ -21,44 +21,32 @@
  */
 
 
-#ifndef _ANALYSIS_STORAGE_SERIALIZE_H
-#define _ANALYSIS_STORAGE_SERIALIZE_H
+#ifndef _GLIBEXT_SERIALIZE_H
+#define _GLIBEXT_SERIALIZE_H
 
 
-#include <glib-object.h>
+#include <stdbool.h>
 
 
-#include "../../common/packed.h"
+#include "helpers.h"
 
 
 
-#define G_TYPE_SERIALIZABLE_OBJECT             g_serializable_object_get_type()
-#define G_SERIALIZABLE_OBJECT(obj)             (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_SERIALIZABLE_OBJECT, GSerializableObject))
-#define G_SERIALIZABLE_OBJECT_CLASS(vtable)    (G_TYPE_CHECK_CLASS_CAST((vtable), G_TYPE_SERIALIZABLE_OBJECT, GSerializableObjectIface))
-#define G_IS_SERIALIZABLE_OBJECT(obj)          (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_SERIALIZABLE_OBJECT))
-#define G_IS_SERIALIZABLE_OBJECT_CLASS(vtable) (G_TYPE_CHECK_CLASS_TYPE((vtable), G_TYPE_SERIALIZABLE_OBJECT))
-#define G_SERIALIZABLE_OBJECT_GET_IFACE(inst)  (G_TYPE_INSTANCE_GET_INTERFACE((inst), G_TYPE_SERIALIZABLE_OBJECT, GSerializableObjectIface))
+#define G_TYPE_SERIALIZABLE_OBJECT (g_serializable_object_get_type())
 
+DECLARE_INTERFACE(GSerializableObject, g_serializable_object, G, SERIALIZABLE_OBJECT);
 
-/* Intermédiaire pour la mise en cache d'objet (coquille vide) */
-typedef struct _GSerializableObject GSerializableObject;
-
-/* Intermédiaire pour la mise en cache d'objet (interface) */
-typedef struct _GSerializableObjectIface GSerializableObjectIface;
-
-
-/* Détermine le type d'une interface pour la mise en cache d'objet. */
-GType g_serializable_object_get_type(void) G_GNUC_CONST;
 
 /* storage.h : définition d'une conservation d'objets construits */
 typedef struct _GObjectStorage GObjectStorage;
 
-/* Charge un objet depuis une mémoire tampon. */
-bool g_serializable_object_load(GSerializableObject *, GObjectStorage *, packed_buffer_t *);
 
-/* Sauvegarde un objet dans une mémoire tampon. */
-bool g_serializable_object_store(const GSerializableObject *, GObjectStorage *, packed_buffer_t *);
+/* Charge un objet depuis un flux de données. */
+bool g_serializable_object_load(GSerializableObject *, GObjectStorage *, int);
+
+/* Sauvegarde un objet dans un flux de données. */
+bool g_serializable_object_store(const GSerializableObject *, GObjectStorage *, int);
 
 
 
-#endif  /* _ANALYSIS_STORAGE_SERIALIZE_H */
+#endif  /* _GLIBEXT_SERIALIZE_H */
diff --git a/src/glibext/storage-int.h b/src/glibext/storage-int.h
index 4883aa8..e4bac7a 100644
--- a/src/glibext/storage-int.h
+++ b/src/glibext/storage-int.h
@@ -2,7 +2,7 @@
 /* Chrysalide - Outil d'analyse de fichiers binaires
  * storage.h - prototypes internes pour la conservation sur disque d'objets construits
  *
- * Copyright (C) 2020 Cyrille Bagard
+ * Copyright (C) 2020-2025 Cyrille Bagard
  *
  *  This file is part of Chrysalide.
  *
@@ -21,11 +21,13 @@
  */
 
 
-#ifndef _ANALYSIS_STORAGE_STORAGE_INT_H
-#define _ANALYSIS_STORAGE_STORAGE_INT_H
+#ifndef _GLIBEXT_STORAGE_INT_H
+#define _GLIBEXT_STORAGE_INT_H
 
 
 #include "storage.h"
+#include "tpmem.h"
+#include "../common/szbin.h"
 
 
 
@@ -44,9 +46,12 @@ struct _GObjectStorage
 {
     GObject parent;                         /* A laisser en premier        */
 
-    GTypeMemory *tpmem;                     /* Mémorisation de types       */
+    sized_binary_t type;                    /* Type de conservation        */
+    uint8_t version;                        /* Version correspondante      */
+
+    sized_binary_t uid;                     /* Identifiant de distinction  */
 
-    char *hash;                             /* Empreinte du contenu        */
+    GTypeMemory *tpmem;                     /* Mémorisation de types       */
 
     storage_backend_t *backends;            /* Gestionnaires existants     */
     size_t count;                           /* Quantité de gestionnaires   */
@@ -62,5 +67,9 @@ struct _GObjectStorageClass
 };
 
 
+/* Met en place un support d'une conservation d'objets en place. */
+bool g_object_storage_create(GObjectStorage *, const char *, uint8_t, const char *);
+
+
 
-#endif  /* _ANALYSIS_STORAGE_STORAGE_INT_H */
+#endif  /* _GLIBEXT_STORAGE_INT_H */
diff --git a/src/glibext/storage.c b/src/glibext/storage.c
index 610a0f6..0e6620b 100644
--- a/src/glibext/storage.c
+++ b/src/glibext/storage.c
@@ -2,7 +2,7 @@
 /* Chrysalide - Outil d'analyse de fichiers binaires
  * storage.c - conservation hors mémoire d'objets choisis
  *
- * Copyright (C) 2020 Cyrille Bagard
+ * Copyright (C) 2020-2025 Cyrille Bagard
  *
  *  This file is part of Chrysalide.
  *
@@ -28,20 +28,23 @@
 #include <malloc.h>
 #include <string.h>
 #include <unistd.h>
-#include <stdarg.h>
+#include <zip.h>
 
 
 #include "storage-int.h"
-#include "../db/misc/rlestr.h"
-#include "../../common/io.h"
-#include "../../common/leb128.h"
-#include "../../common/pathname.h"
-#include "../../core/logs.h"
+#include "../common/cpp.h"
+#include "../common/pathname.h"
+#include "../core/logs.h"
 
 
-
-#define STORAGE_MAGIC "CSTR"
-#define STORAGE_NUMBER "\x00\x01"
+/**
+ * Historique du format :
+ *
+ *   - 09/03/25 : 1.0 (version initiale)
+ *
+ */
+#define STORAGE_MAGIC "COBSTR"
+#define STORAGE_NUMBER "\x01\x00"
 
 
 /* Initialise la classe des conservations d'objets en place. */
@@ -51,10 +54,13 @@ static void g_object_storage_class_init(GObjectStorageClass *);
 static void g_object_storage_init(GObjectStorage *);
 
 /* Supprime toutes les références externes. */
-static void g_object_storage_dispose(GObjectStorage *);
+static void g_object_storage_dispose(GObject *);
 
 /* Procède à la libération totale de la mémoire. */
-static void g_object_storage_finalize(GObjectStorage *);
+static void g_object_storage_finalize(GObject *);
+
+/* Assure l'inexistence d'un groupe avec un nom donné. */
+static bool g_object_storage_has_no_backend_named(GObjectStorage *, const char *);
 
 /* Retrouve l'encadrement pour un nouveau groupe d'objets. */
 static storage_backend_t *g_object_storage_find_backend(GObjectStorage *, const char *);
@@ -62,11 +68,8 @@ static storage_backend_t *g_object_storage_find_backend(GObjectStorage *, const
 /* 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 *);
+/* Charge un objet à partir de données rassemblées. */
+static GSerializableObject *g_object_storage_load_object_unlocked(GObjectStorage *, const char *, off64_t);
 
 
 
@@ -92,8 +95,8 @@ static void g_object_storage_class_init(GObjectStorageClass *klass)
 
     object = G_OBJECT_CLASS(klass);
 
-    object->dispose = (GObjectFinalizeFunc/* ! */)g_object_storage_dispose;
-    object->finalize = (GObjectFinalizeFunc)g_object_storage_finalize;
+    object->dispose = g_object_storage_dispose;
+    object->finalize = g_object_storage_finalize;
 
 }
 
@@ -112,9 +115,12 @@ static void g_object_storage_class_init(GObjectStorageClass *klass)
 
 static void g_object_storage_init(GObjectStorage *storage)
 {
-    storage->tpmem = g_type_memory_new();
+    init_sized_binary(&storage->type);
+    storage->version = 0;
 
-    storage->hash = NULL;
+    init_sized_binary(&storage->uid);
+
+    storage->tpmem = g_type_memory_new();
 
     storage->backends = NULL;
     storage->count = 0;
@@ -125,7 +131,7 @@ static void g_object_storage_init(GObjectStorage *storage)
 
 /******************************************************************************
 *                                                                             *
-*  Paramètres  : storage = instance d'objet GLib à traiter.                   *
+*  Paramètres  : object = instance d'objet GLib à traiter.                    *
 *                                                                             *
 *  Description : Supprime toutes les références externes.                     *
 *                                                                             *
@@ -135,18 +141,22 @@ static void g_object_storage_init(GObjectStorage *storage)
 *                                                                             *
 ******************************************************************************/
 
-static void g_object_storage_dispose(GObjectStorage *storage)
+static void g_object_storage_dispose(GObject *object)
 {
+    GObjectStorage *storage;                /* Version spécialisée         */
+
+    storage = G_OBJECT_STORAGE(object);
+
     g_clear_object(&storage->tpmem);
 
-    G_OBJECT_CLASS(g_object_storage_parent_class)->dispose(G_OBJECT(storage));
+    G_OBJECT_CLASS(g_object_storage_parent_class)->dispose(object);
 
 }
 
 
 /******************************************************************************
 *                                                                             *
-*  Paramètres  : storage = instance d'objet GLib à traiter.                   *
+*  Paramètres  : object = instance d'objet GLib à traiter.                    *
 *                                                                             *
 *  Description : Procède à la libération totale de la mémoire.                *
 *                                                                             *
@@ -156,18 +166,27 @@ static void g_object_storage_dispose(GObjectStorage *storage)
 *                                                                             *
 ******************************************************************************/
 
-static void g_object_storage_finalize(GObjectStorage *storage)
+static void g_object_storage_finalize(GObject *object)
 {
+    GObjectStorage *storage;                /* Version spécialisée         */
     size_t i;                               /* Boucle de parcours          */
     storage_backend_t *backend;             /* Gestionnaire à manipuler    */
     int ret;                                /* Bilan d'un appel            */
 
+    storage = G_OBJECT_STORAGE(object);
+
     g_mutex_lock(&storage->mutex);
 
     for (i = 0; i < storage->count; i++)
     {
         backend = &storage->backends[i];
 
+        /**
+         * Chargement incomplet depuis g_object_storage_load().
+         */
+        if (backend->name == NULL)
+            break;
+
         if (backend->fd != -1)
             close(backend->fd);
         else
@@ -193,17 +212,20 @@ static void g_object_storage_finalize(GObjectStorage *storage)
 
     g_mutex_clear(&storage->mutex);
 
-    if (storage->hash != NULL)
-        free(storage->hash);
+    exit_sized_binary(&storage->type);
+
+    exit_sized_binary(&storage->uid);
 
-    G_OBJECT_CLASS(g_object_storage_parent_class)->finalize(G_OBJECT(storage));
+    G_OBJECT_CLASS(g_object_storage_parent_class)->finalize(object);
 
 }
 
 
 /******************************************************************************
 *                                                                             *
-*  Paramètres  : loaded = contenu binaire à associer.                         *
+*  Paramètres  : type    = type global à indiquer dans une conservation.      *
+*                version = numéro de version associé.                         *
+*                uid     = identifiant arbitraire mais unique pour distinguer.*
 *                                                                             *
 *  Description : Crée le support d'une conservation d'objets en place.        *
 *                                                                             *
@@ -213,13 +235,14 @@ static void g_object_storage_finalize(GObjectStorage *storage)
 *                                                                             *
 ******************************************************************************/
 
-GObjectStorage *g_object_storage_new(const char *hash)
+GObjectStorage *g_object_storage_new(const char *type, uint8_t version, const char *uid)
 {
     GObjectStorage *result;                 /* Structure à retourner       */
 
     result = g_object_new(G_TYPE_OBJECT_STORAGE, NULL);
 
-    result->hash = strdup(hash);
+    if (!g_object_storage_create(result, type, version, uid))
+        g_clear_object(&result);
 
     return result;
 
@@ -228,7 +251,39 @@ GObjectStorage *g_object_storage_new(const char *hash)
 
 /******************************************************************************
 *                                                                             *
-*  Paramètres  : pbuf = zone tampon à lire.                                   *
+*  Paramètres  : storage = stockage d'objets à initialiser.                   *
+*                type    = type global à indiquer dans une conservation.      *
+*                version = numéro de version associé.                         *
+*                uid     = identifiant arbitraire mais unique pour distinguer.*
+*                                                                             *
+*  Description : Met en place un support d'une conservation d'objets en place.*
+*                                                                             *
+*  Retour      : Bilan de l'opération.                                        *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+bool g_object_storage_create(GObjectStorage *storage, const char *type, uint8_t version, const char *uid)
+{
+    bool result;                            /* Bilan à retourner           */
+
+    result = true;
+
+    dup_into_sized_binary(&storage->type, type, strlen(type));
+
+    storage->version = version;
+
+    dup_into_sized_binary(&storage->uid, uid, strlen(uid) + 1);
+
+    return result;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : filename = fichier de source à traiter.                      *
 *                                                                             *
 *  Description : Charge le support d'une conservation d'objets en place.      *
 *                                                                             *
@@ -238,140 +293,297 @@ GObjectStorage *g_object_storage_new(const char *hash)
 *                                                                             *
 ******************************************************************************/
 
-GObjectStorage *g_object_storage_load(packed_buffer_t *pbuf)
+GObjectStorage *g_object_storage_load(const char *filename)
 {
     GObjectStorage *result;                 /* Structure à retourner       */
-    char header[6];                         /* Entête attendue des données */
+    GObjectStorage *storage;                /* Structure en construction   */
+    int err;                                /* Eventuel code d'erreur      */
+    zip_t *archive;                         /* Archive ZIP à manipuler     */
+    zip_error_t error;                      /* Suivi des erreurs obtenues  */
+    char *tpmem_filename;                   /* Chemin d'accès pour types   */
+    zip_int64_t entries_count;              /* Nombre d'éléments ZIP       */
+    void *data;                             /* Données (décompressées)     */
+    zip_stat_t stats;                       /* Information sur les données */
+    zip_file_t *file;                       /* Echantillon à extraire      */
+    zip_int64_t got;                        /* Nombre d'octets lus         */
+    int ret;                                /* Bilan d'un appel            */
+    const void *pos;                        /* Tête de lecture             */
+    const void *max;                        /* Fin des données lisibles    */
     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          */
+    char *prefix;                           /* Début de nom de fichier     */
+    int fd;                                 /* Descripteur de flux ouvert  */
+    off_t moved;                            /* Nouvelle position établie   */
+    zip_int64_t i;                          /* Boucle de parcours          */
+    storage_backend_t *backend;             /* Informations à intégrer     */
+    const char *slash;                      /* Pointeur vers un caractère /*/
 
     result = NULL;
 
-    status = extract_packed_buffer(pbuf, header, 6, false);
-    if (!status) goto quick_exit;
+    storage = g_object_new(G_TYPE_OBJECT_STORAGE, NULL);
 
-    if (strncmp(header, STORAGE_MAGIC STORAGE_NUMBER, 6) != 0)
-        goto quick_exit;
+    archive = zip_open(filename, ZIP_RDONLY, &err);
+    if (archive == NULL)
+    {
+        zip_error_init_with_code(&error, err);
+        LOG_ERROR_ZIP("zip_open", &error);
+        goto exit;
+    }
+
+    zip_error_init(&error);
+
+    tpmem_filename = NULL;
+
+    /* Validation du nombre d'entrées */
+
+    entries_count = zip_get_num_entries(archive,  ZIP_FL_UNCHANGED);
 
-    setup_empty_rle_string(&str);
+    if (entries_count < 2)
+        goto exit_with_archive;
 
-    status = unpack_rle_string(&str, pbuf);
-    if (!status) goto quick_exit;
+    data = NULL;
 
-    if (get_rle_string(&str) == NULL)
+    /* Extraction de la partie de contrôle */
+
+    ret = zip_stat_index(archive, 0, ZIP_FL_UNCHANGED, &stats);
+    if (ret != 0)
     {
-        exit_rle_string(&str);
-        goto quick_exit;
+        LOG_ERROR_ZIP("zip_stat_index", zip_get_error(archive));
+        goto exit_with_archive;
     }
 
-    result = g_object_new(G_TYPE_OBJECT_STORAGE, NULL);
-
-    result->hash = strdup(get_rle_string(&str));
+    if ((stats.valid & (ZIP_STAT_NAME | ZIP_STAT_SIZE)) != (ZIP_STAT_NAME | ZIP_STAT_SIZE))
+        goto exit_with_archive;
 
-    exit_rle_string(&str);
+    if (strcmp(stats.name, "control") != 0)
+        goto exit_with_archive;
 
-    status = g_type_memory_load_types(result->tpmem, pbuf);
-    if (!status) goto exit_while_loading;
+    if (stats.size < (6 + 2 + 1 + 1 + 1))
+        goto exit_with_archive;
 
-    status = unpack_uleb128(&count, pbuf);
+    file = zip_fopen_index(archive, 0, ZIP_FL_UNCHANGED);
+    if (file == NULL)
+    {
+        LOG_ERROR_ZIP("zip_fopen_index", zip_get_error(archive));
+        goto exit_with_archive;
+    }
 
-    for (i = 0; i < count && status; i++)
-        status = g_object_storage_load_backend(result, pbuf);
+    data = malloc(stats.size);
 
- exit_while_loading:
+    got = zip_fread(file, data, stats.size);
 
-    if (!status)
+    ret = zip_fclose(file);
+    if (ret != 0)
     {
-        g_object_unref(G_OBJECT(result));
-        result = NULL;
+        zip_error_set(&error, ret, 0);
+        LOG_ERROR_ZIP("zip_fclose", &error);
+        goto exit_with_data;
     }
 
- quick_exit:
+    if (got != stats.size)
+        goto exit_with_data;
 
-    return result;
+    if (memcmp(data, STORAGE_MAGIC, 6) != 0)
+        goto exit_with_data;
 
-}
+    if (memcmp(((uint8_t *)data) + 6, STORAGE_NUMBER, 2) != 0)
+        goto exit_with_data;
 
+    pos = (uint8_t *)data + 8;
+    max = (uint8_t *)data + got;
 
-/******************************************************************************
-*                                                                             *
-*  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   : -                                                            *
-*                                                                             *
-******************************************************************************/
+    status = unpack_sized_binary(&storage->type, &pos, max);
+    if (!status) goto exit_with_data;
 
-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          */
+    if (pos >= max)
+        goto exit_with_data;
 
-    result = extend_packed_buffer(pbuf, STORAGE_MAGIC STORAGE_NUMBER, 6, false);
+    storage->version = *(uint8_t *)pos;
+    pos = (uint8_t *)pos + 1;
 
-    if (result)
+    unpack_sized_binary_as_string(&storage->uid, &pos, max);
+    if (!status) goto exit_with_data;
+
+    if (pos != max)
+        goto exit_with_data;
+
+    free(data);
+    data = NULL;
+
+    /* Extraction de la conservation des types */
+
+    ret = zip_stat_index(archive, 1, ZIP_FL_UNCHANGED, &stats);
+    if (ret != 0)
     {
-        init_static_rle_string(&str, storage->hash);
+        LOG_ERROR_ZIP("zip_stat_index", zip_get_error(archive));
+        goto exit_with_archive;
+    }
 
-        result = pack_rle_string(&str, pbuf);
+    if ((stats.valid & (ZIP_STAT_NAME | ZIP_STAT_SIZE)) != (ZIP_STAT_NAME | ZIP_STAT_SIZE))
+        goto exit_with_archive;
 
-        exit_rle_string(&str);
+    if (strcmp(stats.name, "types") != 0)
+        goto exit_with_archive;
 
+    file = zip_fopen_index(archive, 1, ZIP_FL_UNCHANGED);
+    if (file == NULL)
+    {
+        LOG_ERROR_ZIP("zip_fopen_index", zip_get_error(archive));
+        goto exit_with_archive;
     }
 
-    g_mutex_lock(&storage->mutex);
+    data = malloc(stats.size);
 
-    if (result)
-        result = g_type_memory_store_types(storage->tpmem, pbuf);
+    got = zip_fread(file, data, stats.size);
 
-    if (result)
-        result = pack_uleb128((uleb128_t []){ storage->count }, pbuf);
+    ret = zip_fclose(file);
+    if (ret != 0)
+    {
+        zip_error_set(&error, ret, 0);
+        LOG_ERROR_ZIP("zip_fclose", &error);
+        goto exit_with_data;
+    }
 
-    for (i = 0; i < storage->count && result; i++)
-        result = pack_storage_backend(&storage->backends[i], pbuf);
+    asprintf(&prefix, "%s-types", storage->uid.static_data);
 
-    g_mutex_unlock(&storage->mutex);
+    fd = make_tmp_file(prefix, "cache", &tpmem_filename);
 
-    return result;
+    free(prefix);
 
-}
+    if (fd == -1)
+        goto exit_with_data;
 
+    status = safe_write(fd, data, stats.size);
+    if (!status)
+    {
+        close(fd);
+        goto exit_with_data;
+    }
 
-/******************************************************************************
-*                                                                             *
-*  Paramètres  : storage = gestionnaire de conservations à compléter.         *
-*                name    = désignation d'un nouveau groupe d'objets.          *
-*                                                                             *
-*  Description : Retrouve l'encadrement pour un nouveau groupe d'objets.      *
-*                                                                             *
-*  Retour      : Informations liées à un groupe ou NULL en cas d'échec.       *
-*                                                                             *
-*  Remarques   : -                                                            *
-*                                                                             *
-******************************************************************************/
+    moved = lseek(fd, 0, SEEK_SET);
+    if (moved == ((off_t)-1))
+    {
+        LOG_ERROR_N("lseek");
+        close(fd);
+        goto exit_with_data;
+    }
 
-static storage_backend_t *g_object_storage_find_backend(GObjectStorage *storage, const char *name)
-{
-    storage_backend_t *result;              /* Encadrement à retourner     */
-    size_t i;                               /* Boucle de parcours          */
+    status = g_type_memory_load(storage->tpmem, fd);
 
-    assert(!g_mutex_trylock(&storage->mutex));
+    close(fd);
 
-    for (i = 0; i < storage->count; i++)
-        if (strcmp(storage->backends[i].name, name) == 0)
-            break;
+    if (!status)
+        goto exit_with_data;
 
-    if (i == storage->count)
-        result = NULL;
-    else
-        result = &storage->backends[i];
+    free(data);
+    data = NULL;
+
+    /* Extraction des différents objects restants */
+
+    if (entries_count > 2)
+    {
+        storage->count = entries_count - 2;
+        storage->backends = calloc(storage->count, sizeof(storage_backend_t));
+
+        for (i = 2; i < entries_count; i++)
+        {
+            backend = &storage->backends[i - 2];
+
+            ret = zip_stat_index(archive, i, ZIP_FL_UNCHANGED, &stats);
+            if (ret != 0)
+            {
+                LOG_ERROR_ZIP("zip_stat_index", zip_get_error(archive));
+                goto exit_with_archive;
+            }
+
+            if ((stats.valid & (ZIP_STAT_NAME | ZIP_STAT_SIZE)) != (ZIP_STAT_NAME | ZIP_STAT_SIZE))
+                goto exit_with_archive;
+
+            if (strncmp(stats.name, SL("backends/")) != 0)
+                goto exit_with_archive;
+
+            slash = strchr(stats.name, '/');
+
+            if (slash == NULL)
+                goto exit_with_archive;
+
+            if (strchr(slash + 1, '/') != NULL)
+                goto exit_with_archive;
+
+            if (!g_object_storage_has_no_backend_named(storage, slash + 1))
+                goto exit_with_archive;
+
+            file = zip_fopen_index(archive, i, ZIP_FL_UNCHANGED);
+            if (file == NULL)
+            {
+                LOG_ERROR_ZIP("zip_fopen_index", zip_get_error(archive));
+                goto exit_with_archive;
+            }
+
+            data = malloc(stats.size);
+
+            got = zip_fread(file, data, stats.size);
+
+            ret = zip_fclose(file);
+            if (ret != 0)
+            {
+                zip_error_set(&error, ret, 0);
+                LOG_ERROR_ZIP("zip_fclose", &error);
+                goto exit_with_data;
+            }
+
+            backend->name = strdup(slash + 1);
+
+            asprintf(&prefix, "%s-%s", storage->uid.static_data, backend->name);
+
+            backend->fd = make_tmp_file(prefix, "cache", &backend->filename);
+
+            free(prefix);
+
+            if (backend->fd == -1)
+                goto exit_with_data;
+
+            status = safe_write(backend->fd, data, stats.size);
+            if (!status) goto exit_with_data;
+
+            moved = lseek(backend->fd, 0, SEEK_SET);
+            if (moved == ((off_t)-1))
+            {
+                LOG_ERROR_N("lseek");
+                goto exit_with_data;
+            }
+
+            free(data);
+            data = NULL;
+
+        }
+
+    }
+
+    /* Clôture des opérations */
+
+    result = storage;
+    ref_object(storage);
+
+ exit_with_data:
+
+    if (data != NULL)
+        free(data);
+
+ exit_with_archive:
+
+    ret = zip_close(archive);
+
+    if (ret != 0)
+        LOG_ERROR_ZIP("zip_close", zip_get_error(archive));
+
+    if (tpmem_filename != NULL)
+        unlink(tpmem_filename);
+
+    zip_error_fini(&error);
+
+ exit:
+
+    unref_object(storage);
 
     return result;
 
@@ -380,11 +592,10 @@ 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.          *
-*                backend = support mis en place pour les enregistrements.     *
+*  Paramètres  : storage  = gestionnaire de conservations à manipuler.        *
+*                filename = fichier de destination à constituer.              *
 *                                                                             *
-*  Description : Ajoute le support d'un nouveau groupe d'objets construits.   *
+*  Description : Sauvegarde le support d'une conservation d'objets en place.  *
 *                                                                             *
 *  Retour      : Bilan de l'opération.                                        *
 *                                                                             *
@@ -392,46 +603,199 @@ static storage_backend_t *g_object_storage_find_backend(GObjectStorage *storage,
 *                                                                             *
 ******************************************************************************/
 
-static bool g_object_storage_add_backend(GObjectStorage *storage, const char *name, storage_backend_t **backend)
+bool g_object_storage_store(GObjectStorage *storage, const char *filename)
 {
     bool result;                            /* Bilan à retourner           */
+    int err;                                /* Eventuel code d'erreur      */
+    zip_t *archive;                         /* Archive ZIP à manipuler     */
+    zip_error_t error;                      /* Suivi des erreurs obtenues  */
+    char *tpmem_filename;                   /* Chemin d'accès pour types   */
+    void *type_buf;                         /* Données pour le type        */
+    size_t type_buflen;                     /* Quantité de ces données     */
+    void *uid_buf;                          /* Données pour l'identifiant  */
+    size_t uid_buflen;                      /* Quantité de ces données     */
+    size_t control_len;                     /* Taille des premières données*/
+    uint8_t *control;                       /* Premières données du fichier*/
+    zip_source_t *zip_data;                 /* Données ZIP à intégrer      */
+    zip_int64_t index;                      /* Nouvel index du contenu     */
+    int ret;                                /* Bilan d'un appel            */
     char *prefix;                           /* Début de nom de fichier     */
-    char *filename;                         /* Chemin d'accès aux données  */
     int fd;                                 /* Descripteur de flux ouvert  */
+    bool status;                            /* Bilan d'une écriture        */
+    size_t i;                               /* Boucle de parcours          */
+    char *zip_name;                         /* Destination pour l'archive  */
 
     result = false;
 
-    *backend = NULL;
+    archive = zip_open(filename, ZIP_CREATE | ZIP_TRUNCATE, &err);
+    if (archive == NULL)
+    {
+        zip_error_init_with_code(&error, err);
+        LOG_ERROR_ZIP("zip_open", &error);
+        goto exit;
+    }
 
-    assert(!g_mutex_trylock(&storage->mutex));
+    zip_error_init(&error);
 
-    if (g_object_storage_find_backend(storage, name) != NULL)
-        goto exit;
+    tpmem_filename = NULL;
 
-    /* Préparatifs */
+    /* Fichier de contrôle */
 
-    asprintf(&prefix, "%s-%s", storage->hash, name);
+    type_buf = pack_sized_binary(&storage->type, &type_buflen);
 
-    fd = make_tmp_file(prefix, "cache", &filename);
+    uid_buf = pack_sized_binary_as_string(&storage->uid, &uid_buflen);
+
+    assert((sizeof(STORAGE_MAGIC) - 1 + sizeof(STORAGE_NUMBER) - 1) == 8);
+
+    control_len = 8 + type_buflen + 1 + uid_buflen;
+    control = malloc(control_len * sizeof(uint8_t));
+
+    memcpy(control, STORAGE_MAGIC, 6);
+    memcpy(control + 6, STORAGE_NUMBER, 2);
+
+    memcpy(control + 8, type_buf, type_buflen);
+
+    control[8 + type_buflen] = storage->version;
+
+    memcpy(control + 8 + type_buflen + 1, uid_buf, uid_buflen);
+
+    zip_data = zip_source_buffer_create(control, control_len, 0, &error);
+    if (zip_data == NULL)
+    {
+        LOG_ERROR_ZIP("zip_source_buffer_create", &error);
+        goto exit_with_control;
+    }
+
+    index = zip_file_add(archive, "control", zip_data, ZIP_FL_ENC_UTF_8);
+    if (index == -1)
+    {
+        zip_source_free(zip_data);
+        LOG_ERROR_ZIP("zip_file_add", zip_get_error(archive));
+        goto exit_with_control;
+    }
+
+    ret = zip_set_file_compression(archive, index, ZIP_CM_STORE, 0 /* comp_flags */);
+    if (ret == -1)
+    {
+        LOG_ERROR_ZIP("zip_set_file_compression", zip_get_error(archive));
+        goto exit_with_control;
+    }
+
+    /* Composants de la conservation */
+
+    g_mutex_lock(&storage->mutex);
+
+    /* Conservation des types */
+
+    asprintf(&prefix, "%s-types", storage->uid.static_data);
+
+    fd = make_tmp_file(prefix, "cache", &tpmem_filename);
 
     free(prefix);
 
     if (fd == -1)
-        goto exit;
+        goto exit_with_lock;
 
-    /* Inscription en bonne et due forme */
+    status = g_type_memory_store(storage->tpmem, fd);
 
-    storage->backends = realloc(storage->backends, ++storage->count * sizeof(storage_backend_t));
+    close(fd);
 
-    *backend = &storage->backends[storage->count - 1];
+    if (!status)
+        goto exit_with_lock;
 
-    (*backend)->name = strdup(name);
+    zip_data = zip_source_file_create(tpmem_filename, 0, -1 /* ZIP_LENGTH_TO_END */, &error);
+    if (zip_data == NULL)
+    {
+        LOG_ERROR_ZIP("zip_source_file_create", &error);
+        goto exit_with_lock;
+    }
 
-    (*backend)->filename = filename;
-    (*backend)->fd = fd;
+    index = zip_file_add(archive, "types", zip_data, ZIP_FL_ENC_UTF_8);
+    if (index == -1)
+    {
+        zip_source_free(zip_data);
+        LOG_ERROR_ZIP("zip_file_add", zip_get_error(archive));
+        goto exit_with_lock;
+    }
+
+    ret = zip_set_file_compression(archive, index, ZIP_CM_DEFLATE, 9 /* comp_flags */);
+    if (ret == -1)
+    {
+        LOG_ERROR_ZIP("zip_set_file_compression", zip_get_error(archive));
+        goto exit_with_lock;
+    }
+
+    /* Conservation des objets */
+
+    for (i = 0; i < storage->count; i++)
+    {
+        zip_data = zip_source_file_create(storage->backends[i].filename, 0, -1 /* ZIP_LENGTH_TO_END */, &error);
+        if (zip_data == NULL)
+        {
+            LOG_ERROR_ZIP("zip_source_file_create", &error);
+            goto exit_with_lock;
+        }
+
+        /**
+         * Pas besoin de distinguer les chemins UNIX et Windows ici.
+         *
+         * Cf. https://pkware.cachefly.net/webdocs/casestudies/APPNOTE.TXT :
+         *
+         * 4.4.17 file name: (Variable)
+         *
+         *    The path stored MUST NOT contain a drive or
+         *    device letter, or a leading slash.  All slashes
+         *    MUST be forward slashes '/' as opposed to
+         *    backwards slashes '\' for compatibility with Amiga
+         *    and UNIX file systems etc.  If input came from standard
+         *    input, there is no file name field.
+         *
+         */
+
+        asprintf(&zip_name, "backends/%s", storage->backends[i].name);
+
+        index = zip_file_add(archive, zip_name, zip_data, ZIP_FL_ENC_UTF_8);
+
+        free(zip_name);
+
+        if (index == -1)
+        {
+            zip_source_free(zip_data);
+            LOG_ERROR_ZIP("zip_file_add", zip_get_error(archive));
+            goto exit_with_lock;
+        }
+
+        ret = zip_set_file_compression(archive, index, ZIP_CM_DEFLATE, 9 /* comp_flags */);
+        if (ret == -1)
+        {
+            LOG_ERROR_ZIP("zip_set_file_compression", zip_get_error(archive));
+            goto exit_with_lock;
+        }
+
+    }
 
     result = true;
 
+    /* Clôture des opérations */
+
+ exit_with_lock:
+
+    g_mutex_unlock(&storage->mutex);
+
+ exit_with_control:
+
+    ret = zip_close(archive);
+
+    if (ret != 0)
+        LOG_ERROR_ZIP("zip_close", zip_get_error(archive));
+
+    free(control);
+
+    if (tpmem_filename != NULL)
+        unlink(tpmem_filename);
+
+    zip_error_fini(&error);
+
  exit:
 
     return result;
@@ -441,71 +805,67 @@ static bool g_object_storage_add_backend(GObjectStorage *storage, const char *na
 
 /******************************************************************************
 *                                                                             *
-*  Paramètres  : storage = gestionnaire de conservations à compléter.         *
-*                pbuf    = zone tampon à lire.                                *
+*  Paramètres  : storage = gestionnaire de conservations à consulter.         *
+*                name    = désignation d'un nouveau groupe d'objets.          *
 *                                                                             *
-*  Description : Extrait d'un tampon des enregistrements spécifiques.         *
+*  Description : Assure l'inexistence d'un groupe avec un nom donné.          *
 *                                                                             *
-*  Retour      : Bilan de l'opération.                                        *
+*  Retour      : Bilan des recherches.                                        *
 *                                                                             *
 *  Remarques   : -                                                            *
 *                                                                             *
 ******************************************************************************/
 
-static bool g_object_storage_load_backend(GObjectStorage *storage, packed_buffer_t *pbuf)
+static bool g_object_storage_has_no_backend_named(GObjectStorage *storage, const char *name)
 {
     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);
+    size_t i;                               /* Boucle de parcours          */
 
-    status = unpack_rle_string(&str, pbuf);
-    if (!status) goto exit;
+    result = true;
 
-    if (get_rle_string(&str) == NULL)
+    for (i = 0; i < storage->count && result; i++)
     {
-        exit_rle_string(&str);
-        goto exit;
-    }
-
-    status = g_object_storage_add_backend(storage, get_rle_string(&str), &backend);
+        if (storage->backends[i].name == NULL)
+            break;
 
-    exit_rle_string(&str);
+        if (strcmp(storage->backends[i].name, name) == 0)
+            result = false;
 
-    if (!status) goto exit;
+    }
 
-    /* Récupération du contenu */
+    return result;
 
-    status = unpack_uleb128(&length, pbuf);
-    if (!status) goto exit;
+}
 
-    status = safe_write(backend->fd, pbuf->data + pbuf->pos, length);
-    if (!status) goto exit;
 
-    advance_packed_buffer(pbuf, length);
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : storage = gestionnaire de conservations à compléter.         *
+*                name    = désignation d'un nouveau groupe d'objets.          *
+*                                                                             *
+*  Description : Retrouve l'encadrement pour un nouveau groupe d'objets.      *
+*                                                                             *
+*  Retour      : Informations liées à un groupe ou NULL en cas d'échec.       *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
 
-    moved = lseek(backend->fd, 0, SEEK_SET);
-    if (moved == ((off_t)-1))
-    {
-        LOG_ERROR_N("lseek");
-        goto exit;
-    }
+static storage_backend_t *g_object_storage_find_backend(GObjectStorage *storage, const char *name)
+{
+    storage_backend_t *result;              /* Encadrement à retourner     */
+    size_t i;                               /* Boucle de parcours          */
 
-    result = true;
+    assert(!g_mutex_trylock(&storage->mutex));
 
- exit:
+    for (i = 0; i < storage->count; i++)
+        if (strcmp(storage->backends[i].name, name) == 0)
+            break;
 
-    g_mutex_unlock(&storage->mutex);
+    if (i == storage->count)
+        result = NULL;
+    else
+        result = &storage->backends[i];
 
     return result;
 
@@ -514,10 +874,11 @@ static bool g_object_storage_load_backend(GObjectStorage *storage, packed_buffer
 
 /******************************************************************************
 *                                                                             *
-*  Paramètres  : backend = stockage des enregistrements spécifiques.          *
-*                pbuf    = zone tampon à remplir. [OUT]                       *
+*  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 : Place dans un tampon les données liées à des enregistrements.*
+*  Description : Ajoute le support d'un nouveau groupe d'objets construits.   *
 *                                                                             *
 *  Retour      : Bilan de l'opération.                                        *
 *                                                                             *
@@ -525,72 +886,45 @@ static bool g_object_storage_load_backend(GObjectStorage *storage, packed_buffer
 *                                                                             *
 ******************************************************************************/
 
-static bool pack_storage_backend(const storage_backend_t *backend, packed_buffer_t *pbuf)
+static bool g_object_storage_add_backend(GObjectStorage *storage, const char *name, storage_backend_t **backend)
 {
     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        */
+    char *prefix;                           /* Début de nom de fichier     */
+    char *filename;                         /* Chemin d'accès aux données  */
+    int fd;                                 /* Descripteur de flux ouvert  */
 
     result = false;
 
-    /* Inscription du nom */
+    *backend = NULL;
 
-    init_static_rle_string(&str, backend->name);
+    assert(!g_mutex_trylock(&storage->mutex));
 
-    status = pack_rle_string(&str, pbuf);
+    if (g_object_storage_find_backend(storage, name) != NULL)
+        goto exit;
 
-    exit_rle_string(&str);
+    /* Préparatifs */
 
-    if (!status) goto exit;
+    asprintf(&prefix, "%s-%s", storage->uid.static_data, name);
 
-    /* Inscription du contenu */
+    fd = make_tmp_file(prefix, "cache", &filename);
 
-    current = lseek(backend->fd, 0, SEEK_CUR);
-    if (current == ((off_t)-1))
-    {
-        LOG_ERROR_N("lseek");
-        goto exit;
-    }
+    free(prefix);
 
-    moved = lseek(backend->fd, 0, SEEK_SET);
-    if (moved == ((off_t)-1))
-    {
-        LOG_ERROR_N("lseek");
+    if (fd == -1)
         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);
+    /* Inscription en bonne et due forme */
 
- free_mem:
+    storage->backends = realloc(storage->backends, ++storage->count * sizeof(storage_backend_t));
 
-    free(data);
+    *backend = &storage->backends[storage->count - 1];
 
- restore:
+    (*backend)->name = strdup(name);
 
-    moved = lseek(backend->fd, current, SEEK_SET);
-    if (moved == ((off_t)-1))
-    {
-        LOG_ERROR_N("lseek");
-        goto exit;
-    }
+    (*backend)->filename = filename;
+    (*backend)->fd = fd;
 
-    result = status;
+    result = true;
 
  exit:
 
@@ -602,7 +936,7 @@ static bool pack_storage_backend(const storage_backend_t *backend, packed_buffer
 /******************************************************************************
 *                                                                             *
 *  Paramètres  : storage = gestionnaire à manipuler.                          *
-*                name    = désignation d'un nouveau groupe d'objets.          *
+*                name    = désignation d'un groupe d'objets à consulter.      *
 *                pos     = tête de lecture avant écriture.                    *
 *                                                                             *
 *  Description : Charge un objet à partir de données rassemblées.             *
@@ -613,56 +947,44 @@ static bool pack_storage_backend(const storage_backend_t *backend, packed_buffer
 *                                                                             *
 ******************************************************************************/
 
-GSerializableObject *g_object_storage_load_object(GObjectStorage *storage, const char *name, off64_t pos)
+static GSerializableObject *g_object_storage_load_object_unlocked(GObjectStorage *storage, const char *name, off64_t pos)
 {
     GSerializableObject *result;            /* Instance à retourner        */
-    bool status;                            /* Bilan d'une opération       */
     storage_backend_t *backend;             /* Informations à consulter    */
-    packed_buffer_t pbuf;                   /* Tampon des données à lire   */
     off64_t new;                            /* Nouvelle position de lecture*/
+    bool status;                            /* Bilan d'une opération       */
 
     result = NULL;
 
-    /* Chargement */
-
-    status = false;
+    assert(!g_mutex_trylock(&storage->mutex));
 
-    g_mutex_lock(&storage->mutex);
+    /* Chargement */
 
     backend = g_object_storage_find_backend(storage, name);
+    if (backend == NULL) goto exit;
 
-    if (backend != NULL)
+    new = lseek64(backend->fd, pos, SEEK_SET);
+    if (new == (off_t)-1)
     {
-        new = lseek64(backend->fd, pos, SEEK_SET);
-
-        if (new == pos)
-        {
-            init_packed_buffer(&pbuf);
-            status = read_packed_buffer(&pbuf, backend->fd);
-        }
-
+        LOG_ERROR_N("lseek64");
+        goto exit;
     }
 
-    g_mutex_unlock(&storage->mutex);
-
-    if (!status)
-        goto exit;
+    assert (new == pos);
 
     /* Phase de conversion */
 
-    result = G_SERIALIZABLE_OBJECT(g_type_memory_create_object(storage->tpmem, &pbuf));
+    result = G_SERIALIZABLE_OBJECT(g_type_memory_create_object_from_gtype(storage->tpmem, backend->fd));
 
     if (result)
     {
-        status = g_serializable_object_load(result, storage, &pbuf);
+        status = g_serializable_object_load(result, storage, backend->fd);
 
         if (!status)
             g_clear_object(&result);
 
     }
 
-    exit_packed_buffer(&pbuf);
-
  exit:
 
     return result;
@@ -673,10 +995,10 @@ GSerializableObject *g_object_storage_load_object(GObjectStorage *storage, const
 /******************************************************************************
 *                                                                             *
 *  Paramètres  : storage = gestionnaire à manipuler.                          *
-*                name    = désignation d'un nouveau groupe d'objets.          *
-*                pbuf    = zone tampon à parcourir.                           *
+*                name    = désignation d'un groupe d'objets à consulter.      *
+*                pos     = tête de lecture avant écriture.                    *
 *                                                                             *
-*  Description : Charge un objet interne à partir de données rassemblées.     *
+*  Description : Charge un objet à partir de données rassemblées.             *
 *                                                                             *
 *  Retour      : Objet restauré en mémoire ou NULL en cas d'échec.            *
 *                                                                             *
@@ -684,18 +1006,15 @@ GSerializableObject *g_object_storage_load_object(GObjectStorage *storage, const
 *                                                                             *
 ******************************************************************************/
 
-GSerializableObject *g_object_storage_unpack_object(GObjectStorage *storage, const char *name, packed_buffer_t *pbuf)
+GSerializableObject *g_object_storage_load_object(GObjectStorage *storage, const char *name, off64_t pos)
 {
     GSerializableObject *result;            /* Instance à retourner        */
-    uint64_t pos;                           /* Localisation des données    */
-    bool status;                            /* Bilan d'une opération       */
 
-    result = NULL;
+    g_mutex_lock(&storage->mutex);
 
-    status = extract_packed_buffer(pbuf, &pos, sizeof(uint64_t), true);
+    result = g_object_storage_load_object_unlocked(storage, name, pos);
 
-    if (status)
-        result = g_object_storage_load_object(storage, name, pos);
+    g_mutex_unlock(&storage->mutex);
 
     return result;
 
@@ -704,60 +1023,70 @@ GSerializableObject *g_object_storage_unpack_object(GObjectStorage *storage, con
 
 /******************************************************************************
 *                                                                             *
-*  Paramètres  : storage  = gestionnaire à manipuler.                         *
-*                name     = désignation d'un nouveau groupe d'objets.         *
-*                pbuf     = zone tampon à parcourir.                          *
-*                expected = type d'objet attendu.                             *
-*                ...      = élément restauré ou NULL en cas d'échec. [OUT]    *
+*  Paramètres  : storage     = gestionnaire à manipuler.                      *
+*                name        = désignation d'un groupe d'objets à consulter.  *
+*                target_name = désignation d'un second groupe d'objets ciblé. *
 *                                                                             *
-*  Description : Charge un objet interne à partir de données rassemblées.     *
+*  Description : Charge un objet interne à partir d'une référence embarquée.  *
 *                                                                             *
-*  Retour      : Bilan de l'opération.                                        *
+*  Retour      : Objet restauré en mémoire ou NULL en cas d'échec.            *
 *                                                                             *
 *  Remarques   : -                                                            *
 *                                                                             *
 ******************************************************************************/
 
-bool g_object_storage_unpack_object_2(GObjectStorage *storage, const char *name, packed_buffer_t *pbuf, GType expected, ...)
+GSerializableObject *g_object_storage_unpack_object(GObjectStorage *storage, const char *name, const char *target_name)
 {
-    bool result;                            /* Bilan d'une opération       */
-    uint64_t pos;                           /* Localisation des données    */
-    GSerializableObject *instance;          /* Objet rechargé à valider    */
-    va_list ap;                             /* Liste d'arguments variables */
-    void **object;                          /* Lieu d'enregistrement final */
+    GSerializableObject *result;            /* Instance à retourner        */
+    storage_backend_t *backend;             /* Informations à consulter    */
+    uleb128_t pos;                          /* Localisation des données    */
+    bool status;                            /* Bilan d'une opération       */
+    off64_t saved;                          /* Sauvegarde de position      */
+    off64_t new;                            /* Nouvelle position de lecture*/
 
-    result = extract_packed_buffer(pbuf, &pos, sizeof(uint64_t), true);
+    result = NULL;
 
-    if (result)
-    {
-        if (pos == 0)
-            *object = NULL;
+    g_mutex_lock(&storage->mutex);
 
-        else
-        {
-            instance = g_object_storage_load_object(storage, name, pos);
+    /* Récupération de la position */
 
-            result = G_TYPE_CHECK_INSTANCE_TYPE(instance, expected);
+    backend = g_object_storage_find_backend(storage, name);
+    if (backend == NULL) goto exit;
 
-            if (result)
-            {
-                va_start(ap, expected);
+    status = load_uleb128(&pos, backend->fd);
+    if (!status) goto exit;
 
-                object = va_arg(ap, void **);
+    saved = lseek64(backend->fd, 0, SEEK_CUR);
+    if (saved == (off_t)-1)
+    {
+        LOG_ERROR_N("lseek64");
+        goto exit;
+    }
 
-                *object = instance;
+    /* Chargement */
 
-                va_end(ap);
+    result = g_object_storage_load_object_unlocked(storage, target_name, pos);
 
-            }
+    if (result == NULL) goto exit;
 
-            else
-                g_clear_object(&instance);
+    /* Restauration de la position courante */
 
-        }
+    new = lseek64(backend->fd, saved, SEEK_SET);
+    if (new == (off_t)-1)
+    {
+        LOG_ERROR_N("lseek64");
+
+        g_clear_object(&result);
+        goto exit;
 
     }
 
+    assert (new == saved);
+
+ exit:
+
+    g_mutex_unlock(&storage->mutex);
+
     return result;
 
 }
@@ -766,7 +1095,7 @@ bool g_object_storage_unpack_object_2(GObjectStorage *storage, const char *name,
 /******************************************************************************
 *                                                                             *
 *  Paramètres  : storage = gestionnaire à manipuler.                          *
-*                name    = désignation d'un nouveau groupe d'objets.          *
+*                name    = désignation d'un groupe d'objets, nouveau ou non.  *
 *                object  = objet sérialisable à traiter.                      *
 *                pos     = tête de lecture avant écriture. [OUT]              *
 *                                                                             *
@@ -781,22 +1110,9 @@ bool g_object_storage_unpack_object_2(GObjectStorage *storage, const char *name,
 bool g_object_storage_store_object(GObjectStorage *storage, const char *name, const GSerializableObject *object, off64_t *pos)
 {
     bool result;                            /* Bilan à retourner           */
-    packed_buffer_t pbuf;                   /* Tampon des données à écrire */
     storage_backend_t *backend;             /* Informations à consulter    */
     off64_t tmp;                            /* Conservation éphémère       */
 
-    /* Phase de conversion */
-
-    init_packed_buffer(&pbuf);
-
-    result = g_type_memory_store_object_gtype(storage->tpmem, G_OBJECT(object), &pbuf);
-    if (!result) goto exit;
-
-    result = g_serializable_object_store(object, storage, &pbuf);
-    if (!result) goto exit;
-
-    /* Enregistrement */
-
     result = false;
 
     g_mutex_lock(&storage->mutex);
@@ -814,54 +1130,18 @@ bool g_object_storage_store_object(GObjectStorage *storage, const char *name, co
         *pos = lseek64(backend->fd, 0, SEEK_CUR);
 
         if (*pos != (off64_t)-1)
-            result = write_packed_buffer(&pbuf, backend->fd);
-
-    }
-
-    g_mutex_unlock(&storage->mutex);
-
-    /* Sortie propre */
-
- exit:
-
-    exit_packed_buffer(&pbuf);
-
-    return result;
-
-}
-
-
-/******************************************************************************
-*                                                                             *
-*  Paramètres  : storage = gestionnaire à manipuler.                          *
-*                name    = désignation d'un nouveau groupe d'objets.          *
-*                pbuf    = zone tampon à remplir.                             *
-*                                                                             *
-*  Description : Sauvegarde un object interne sous forme de données.          *
-*                                                                             *
-*  Retour      : Bilan de l'opération.                                        *
-*                                                                             *
-*  Remarques   : -                                                            *
-*                                                                             *
-******************************************************************************/
-
-bool g_object_storage_pack_object(GObjectStorage *storage, const char *name, const GSerializableObject *object, packed_buffer_t *pbuf)
-{
-    bool result;                            /* Bilan à retourner           */
-    off64_t pos;                            /* Localisation des données    */
-
-    if (object == NULL)
-        result = extend_packed_buffer(pbuf, (uint64_t []){ 0 }, sizeof(uint64_t), true);
+        {
+            result = g_type_memory_store_object_gtype(storage->tpmem, G_OBJECT(object), backend->fd);
 
-    else
-    {
-        result = g_object_storage_store_object(storage, name, object, &pos);
+            if (result)
+                result = g_serializable_object_store(object, storage, backend->fd);
 
-        if (result)
-            result = extend_packed_buffer(pbuf, (uint64_t []){ pos }, sizeof(uint64_t), true);
+        }
 
     }
 
+    g_mutex_unlock(&storage->mutex);
+
     return result;
 
 }
diff --git a/src/glibext/storage.h b/src/glibext/storage.h
index cc0caad..8231a31 100644
--- a/src/glibext/storage.h
+++ b/src/glibext/storage.h
@@ -2,7 +2,7 @@
 /* Chrysalide - Outil d'analyse de fichiers binaires
  * storage.h - prototypes pour la conservation sur disque d'objets construits
  *
- * Copyright (C) 2020 Cyrille Bagard
+ * Copyright (C) 2020-2025 Cyrille Bagard
  *
  *  This file is part of Chrysalide.
  *
@@ -21,69 +21,61 @@
  */
 
 
-#ifndef _ANALYSIS_STORAGE_STORAGE_H
-#define _ANALYSIS_STORAGE_STORAGE_H
+#ifndef _GLIBEXT_STORAGE_H
+#define _GLIBEXT_STORAGE_H
 
 
-#include <glib-object.h>
-#include <stdbool.h>
+#include <stdint.h>
 
 
+#include "helpers.h"
 #include "serialize.h"
-#include "tpmem.h"
 
 
 
-#define G_TYPE_OBJECT_STORAGE            g_object_storage_get_type()
-#define G_OBJECT_STORAGE(obj)            (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_OBJECT_STORAGE, GObjectStorage))
-#define G_IS_OBJECT_STORAGE(obj)         (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_OBJECT_STORAGE))
-#define G_OBJECT_STORAGE_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_OBJECT_STORAGE, GObjectStorageClass))
-#define G_IS_OBJECT_STORAGE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_OBJECT_STORAGE))
-#define G_OBJECT_STORAGE_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_OBJECT_STORAGE, GObjectStorageClass))
+#define G_TYPE_OBJECT_STORAGE (g_object_storage_get_type())
 
+DECLARE_GTYPE(GObjectStorage, g_object_storage, G, OBJECT_STORAGE);
 
-/* Définition d'une conservation d'objets construits (instance) */
-typedef struct _GObjectStorage GObjectStorage;
-
-/* Définition d'une conservation d'objets construits (classe) */
-typedef struct _GObjectStorageClass GObjectStorageClass;
-
-
-/* Indique le type défini pour une conservation d'objets construits. */
-GType g_object_storage_get_type(void);
 
 /* Crée le support d'une conservation d'objets en place. */
-GObjectStorage *g_object_storage_new(const char *);
-
-#define get_storage_linked_format(s)                            \
-    ({                                                          \
-        void*__result;                                          \
-        __result = g_object_get_data(G_OBJECT(s), "format");    \
-        g_object_ref(G_OBJECT(__result));                       \
-        __result;                                               \
-    })
+GObjectStorage *g_object_storage_new(const char *, uint8_t, const char *);
 
 /* Charge le support d'une conservation d'objets en place. */
-GObjectStorage *g_object_storage_load(packed_buffer_t *);
+GObjectStorage *g_object_storage_load(const char *);
 
 /* Sauvegarde le support d'une conservation d'objets en place. */
-bool g_object_storage_store(GObjectStorage *, packed_buffer_t *);
+bool g_object_storage_store(GObjectStorage *, const char *);
 
 /* Charge un objet à partir de données rassemblées. */
 GSerializableObject *g_object_storage_load_object(GObjectStorage *, const char *, off64_t);
 
-/* Charge un objet interne à partir de données rassemblées. */
-GSerializableObject *g_object_storage_unpack_object(GObjectStorage *, const char *, packed_buffer_t *);
+/* Charge un objet interne à partir d'une référence embarquée. */
+GSerializableObject *g_object_storage_unpack_object(GObjectStorage *, const char *, const char *);
 
 /* Sauvegarde un object sous forme de données rassemblées. */
 bool g_object_storage_store_object(GObjectStorage *, const char *, const GSerializableObject *, off64_t *);
 
-/* Charge un objet interne à partir de données rassemblées. */
-bool g_object_storage_unpack_object_2(GObjectStorage *, const char *, packed_buffer_t *, GType, ...);
 
-/* Sauvegarde un object interne sous forme de données. */
-bool g_object_storage_pack_object(GObjectStorage *, const char *, const GSerializableObject *, packed_buffer_t *);
+
+
+#if 0
+
+/**
+ * TODO : REMME ?
+ */
+
+#define get_storage_linked_format(s)                            \
+    ({                                                          \
+        void*__result;                                          \
+        __result = g_object_get_data(G_OBJECT(s), "format");    \
+        g_object_ref(G_OBJECT(__result));                       \
+        __result;                                               \
+    })
+
+#endif
+
 
 
 
-#endif  /* _ANALYSIS_STORAGE_STORAGE_H */
+#endif  /* _GLIBEXT_STORAGE_H */
diff --git a/src/glibext/tpmem-int.h b/src/glibext/tpmem-int.h
new file mode 100644
index 0000000..b1b7eec
--- /dev/null
+++ b/src/glibext/tpmem-int.h
@@ -0,0 +1,78 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * tpmem-int.h - définitions internes propres à la mémorisation des types d'objets mis en cache
+ *
+ * Copyright (C) 2020-2025 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 _GLIBEXT_TPMEM_INT_H
+#define _GLIBEXT_TPMEM_INT_H
+
+
+#include "tpmem.h"
+
+
+/* Conservation d'une référence sur un type */
+typedef struct _gtype_ref_info_t
+{
+    GType gtype;                            /* Type pour la GLib           */
+    gpointer gclass;                        /* Lien vers sa classe         */
+
+    /**
+     * La GLib n'est pas très claire sur la taille de GType comme le montre le
+     * code issu de <sources>/gobject/gtype.h :
+     *
+     *    #if     GLIB_SIZEOF_SIZE_T != GLIB_SIZEOF_LONG || !defined __cplusplus
+     *    typedef gsize                           GType;
+     *    #else   // for historic reasons, C++ links against gulong GTypes
+     *    typedef gulong                          GType;
+     *    #endif
+     *
+     * Et :
+     *
+     *    typedef unsigned $glib_size_type_define gsize;
+     *
+     * On prend donc le parti de conserver ces types sous forme de valeurs 64 bits
+     * lors des enregistrements.
+     */
+
+} gtype_ref_info_t;
+
+
+/* Définition d'une mémoire de types d'objets (instance) */
+struct _GTypeMemory
+{
+    GObject parent;                         /* A laisser en premier        */
+
+    gtype_ref_info_t *gtypes;               /* Types des objets reconnus   */
+    size_t count;                           /* Quantité de ces objets      */
+    GMutex mutex;                           /* Contrôle d'accès à la liste */
+
+};
+
+/* Définition d'une mémoire de types d'objets (classe) */
+struct _GTypeMemoryClass
+{
+    GObjectClass parent;                    /* A laisser en premier        */
+
+};
+
+
+
+#endif  /* _GLIBEXT_TPMEM_INT_H */
diff --git a/src/glibext/tpmem.c b/src/glibext/tpmem.c
index 0703aeb..14b5e33 100644
--- a/src/glibext/tpmem.c
+++ b/src/glibext/tpmem.c
@@ -2,7 +2,7 @@
 /* Chrysalide - Outil d'analyse de fichiers binaires
  * tpmem.c - mémorisation des types d'objets mis en cache
  *
- * Copyright (C) 2020 Cyrille Bagard
+ * Copyright (C) 2020-2025 Cyrille Bagard
  *
  *  This file is part of Chrysalide.
  *
@@ -25,59 +25,14 @@
 
 
 #include <assert.h>
-#include <stdint.h>
 
 
-#include "../db/misc/rlestr.h"
-#include "../../arch/operands/target.h"
-#include "../../core/logs.h"
+#include "tpmem-int.h"
+#include "../common/szbin.h"
+#include "../core/logs.h"
 
 
 
-/* Conservation d'une référence sur un type */
-typedef struct _gtype_ref_info_t
-{
-    GType gtype;                            /* Type pour la GLib           */
-    gpointer gclass;                        /* Lien vers sa classe         */
-
-    /**
-     * La GLib n'est pas très claire sur la taille de GType :
-     *
-     *    #if     GLIB_SIZEOF_SIZE_T != GLIB_SIZEOF_LONG || !defined __cplusplus
-     *    typedef gsize                           GType;
-     *    #else   // for historic reasons, C++ links against gulong GTypes
-     *    typedef gulong                          GType;
-     *    #endif
-     *
-     * Et :
-     *
-     *    typedef unsigned $glib_size_type_define gsize;
-     *
-     * On prend donc le parti de conserver ces types sous forme de valeurs 64 bits
-     * lors des enregistrements.
-     */
-
-} gtype_ref_info_t;
-
-/* Définition d'une mémoire de types d'objets (instance) */
-struct _GTypeMemory
-{
-    GObject parent;                         /* A laisser en premier        */
-
-    gtype_ref_info_t *gtypes;               /* Types des objets reconnus   */
-    size_t count;                           /* Quantité de ces objets      */
-    GMutex mutex;                           /* Contrôle d'accès à la liste */
-
-};
-
-/* Définition d'une mémoire de types d'objets (classe) */
-struct _GTypeMemoryClass
-{
-    GObjectClass parent;                    /* A laisser en premier        */
-
-};
-
-
 /* Initialise la classe des mémoires de types d'objets. */
 static void g_type_memory_class_init(GTypeMemoryClass *);
 
@@ -85,10 +40,10 @@ static void g_type_memory_class_init(GTypeMemoryClass *);
 static void g_type_memory_init(GTypeMemory *);
 
 /* Supprime toutes les références externes. */
-static void g_type_memory_dispose(GTypeMemory *);
+static void g_type_memory_dispose(GObject *);
 
 /* Procède à la libération totale de la mémoire. */
-static void g_type_memory_finalize(GTypeMemory *);
+static void g_type_memory_finalize(GObject *);
 
 
 
@@ -114,8 +69,8 @@ static void g_type_memory_class_init(GTypeMemoryClass *klass)
 
     object = G_OBJECT_CLASS(klass);
 
-    object->dispose = (GObjectFinalizeFunc/* ! */)g_type_memory_dispose;
-    object->finalize = (GObjectFinalizeFunc)g_type_memory_finalize;
+    object->dispose = g_type_memory_dispose;
+    object->finalize = g_type_memory_finalize;
 
 }
 
@@ -143,7 +98,7 @@ static void g_type_memory_init(GTypeMemory *tpmem)
 
 /******************************************************************************
 *                                                                             *
-*  Paramètres  : tpmem = instance d'objet GLib à traiter.                     *
+*  Paramètres  : object = instance d'objet GLib à traiter.                    *
 *                                                                             *
 *  Description : Supprime toutes les références externes.                     *
 *                                                                             *
@@ -153,10 +108,13 @@ static void g_type_memory_init(GTypeMemory *tpmem)
 *                                                                             *
 ******************************************************************************/
 
-static void g_type_memory_dispose(GTypeMemory *tpmem)
+static void g_type_memory_dispose(GObject *object)
 {
+    GTypeMemory *tpmem;                     /* Version spécialisée         */
     uint64_t i;                             /* Boucle de parcours          */
 
+    tpmem = G_TYPE_MEMORY(object);
+
     g_mutex_lock(&tpmem->mutex);
 
     for (i = 0; i < tpmem->count; i++)
@@ -167,14 +125,14 @@ static void g_type_memory_dispose(GTypeMemory *tpmem)
 
     g_mutex_clear(&tpmem->mutex);
 
-    G_OBJECT_CLASS(g_type_memory_parent_class)->dispose(G_OBJECT(tpmem));
+    G_OBJECT_CLASS(g_type_memory_parent_class)->dispose(object);
 
 }
 
 
 /******************************************************************************
 *                                                                             *
-*  Paramètres  : tpmem = instance d'objet GLib à traiter.                     *
+*  Paramètres  : object = instance d'objet GLib à traiter.                    *
 *                                                                             *
 *  Description : Procède à la libération totale de la mémoire.                *
 *                                                                             *
@@ -184,12 +142,16 @@ static void g_type_memory_dispose(GTypeMemory *tpmem)
 *                                                                             *
 ******************************************************************************/
 
-static void g_type_memory_finalize(GTypeMemory *tpmem)
+static void g_type_memory_finalize(GObject *object)
 {
+    GTypeMemory *tpmem;                     /* Version spécialisée         */
+
+    tpmem = G_TYPE_MEMORY(object);
+
     if (tpmem->gtypes != NULL)
         free(tpmem->gtypes);
 
-    G_OBJECT_CLASS(g_type_memory_parent_class)->finalize(G_OBJECT(tpmem));
+    G_OBJECT_CLASS(g_type_memory_parent_class)->finalize(object);
 
 }
 
@@ -220,7 +182,7 @@ GTypeMemory *g_type_memory_new(void)
 /******************************************************************************
 *                                                                             *
 *  Paramètres  : tpmem = mémoire à compléter.                                 *
-*                pbuf  = zone tampon à lire.                                  *
+*                fd    = flux ouvert en lecture.                              *
 *                                                                             *
 *  Description : Apprend tous les types mémorisés dans un tampon.             *
 *                                                                             *
@@ -230,14 +192,14 @@ GTypeMemory *g_type_memory_new(void)
 *                                                                             *
 ******************************************************************************/
 
-bool g_type_memory_load_types(GTypeMemory *tpmem, packed_buffer_t *pbuf)
+bool g_type_memory_load(GTypeMemory *tpmem, int fd)
 {
     bool result;                            /* Bilan à enregistrer         */
     uleb128_t count;                        /* Nombre d'éléments détectés  */
     uleb128_t i;                            /* Boucle de parcours          */
-    rle_string str;                         /* Chaîne à charger            */
+    sized_binary_t str;                     /* Chaîne à charger            */
 
-    result = unpack_uleb128(&count, pbuf);
+    result = load_uleb128(&count, fd);
 
     if (result)
     {
@@ -248,35 +210,27 @@ 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);
+            result = load_sized_binary_as_string(&str, fd);
             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));
+            tpmem->gtypes[i].gtype = g_type_from_name(str.data);
             result = (tpmem->gtypes[i].gtype != 0);
 
             if (!result)
-                log_variadic_message(LMT_ERROR, "Unknown type: '%s'", get_rle_string(&str));
+                log_variadic_message(LMT_ERROR, "Unknown type: '%s'", str.data);
 
             else
                 tpmem->gtypes[i].gclass = g_type_class_ref(tpmem->gtypes[i].gtype);
 
-            exit_rle_string(&str);
+            exit_sized_binary(&str);
 
         }
 
-    }
+        g_mutex_unlock(&tpmem->mutex);
 
-    g_mutex_unlock(&tpmem->mutex);
+    }
 
     return result;
 
@@ -285,38 +239,40 @@ bool g_type_memory_load_types(GTypeMemory *tpmem, packed_buffer_t *pbuf)
 
 /******************************************************************************
 *                                                                             *
-*  Paramètres  : tpmem = mémoire à manipuler.                                 *
-*                pbuf  = zone tampon à venir lire.                            *
+*  Paramètres  : tpmem = mémoire à consulter.                                 *
+*                fd    = flux ouvert en écriture.                             *
 *                                                                             *
-*  Description : Crée une nouvelle instance d'objet à partir de son type.     *
+*  Description : Enregistre tous les types mémorisés dans un tampon.          *
 *                                                                             *
-*  Retour      : Instance issue de l'opération ou NULL.                       *
+*  Retour      : Bilan de l'opération.                                        *
 *                                                                             *
 *  Remarques   : -                                                            *
 *                                                                             *
 ******************************************************************************/
 
-GObject *g_type_memory_create_object(GTypeMemory *tpmem, packed_buffer_t *pbuf)
+bool g_type_memory_store(GTypeMemory *tpmem, int fd)
 {
-    GObject *result;                        /* Nouvelle instance à renvoyer*/
-    uleb128_t index;                        /* Indice du point d'insertion */
-    bool status;                            /* Bilan d'une récupération    */
+    bool result;                            /* Bilan à enregistrer         */
+    uint64_t i;                             /* Boucle de parcours          */
+    const gchar *name;                      /* Désignation d'un type       */
+    sized_binary_t str;                     /* Chaîne à conserver          */
 
-    result = NULL;
+    g_mutex_lock(&tpmem->mutex);
 
-    status = unpack_uleb128(&index, pbuf);
+    result = store_uleb128((uleb128_t []){ tpmem->count }, fd);
 
-    if (status)
+    for (i = 0; i < tpmem->count && result; i++)
     {
-        g_mutex_lock(&tpmem->mutex);
+        name = g_type_name(tpmem->gtypes[i].gtype);
 
-        if (index < tpmem->count)
-            result = g_object_new(tpmem->gtypes[index].gtype, NULL);
+        setup_sized_binary_from_static_string(&str, name);
 
-        g_mutex_unlock(&tpmem->mutex);
+        store_sized_binary_as_string(&str, fd);
 
     }
 
+    g_mutex_unlock(&tpmem->mutex);
+
     return result;
 
 }
@@ -325,60 +281,35 @@ 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. [OUT]                         *
+*                fd    = flux ouvert en lecture.                              *
 *                                                                             *
-*  Description : Sauvegarde le type d'un objet instancié.                     *
+*  Description : Crée une nouvelle instance d'objet à partir de son type.     *
 *                                                                             *
-*  Retour      : Bilan de l'opération.                                        *
+*  Retour      : Instance issue de l'opération ou NULL.                       *
 *                                                                             *
 *  Remarques   : -                                                            *
 *                                                                             *
 ******************************************************************************/
 
-bool g_type_memory_store_object_gtype(GTypeMemory *tpmem, GObject *obj, packed_buffer_t *pbuf)
+GObject *g_type_memory_create_object_from_gtype(GTypeMemory *tpmem, int fd)
 {
-    bool result;                            /* Bilan à retourner           */
-    GType gtype;                            /* Type à enregistrer          */
-    size_t index;                           /* Indice du point d'insertion */
-
-    gtype = G_TYPE_FROM_INSTANCE(obj);
+    GObject *result;                        /* Nouvelle instance à renvoyer*/
+    uleb128_t index;                        /* Indice du point d'insertion */
+    bool status;                            /* Bilan d'une récupération    */
 
-    /**
-     * Pour quelques explications sur l'esquive suivante, se rapporter aux
-     * commentaires de g_target_operand_unserialize().
-     *
-     * Dans la situation présente, on ne doit pas enregistrer le type dans le tampon,
-     * car l'opérande va relancer l'opération entière (avec un opérande temporaire),
-     * ce qui conduirait à l'enregistrement de deux types successifs dans les données.
-     */
+    result = NULL;
 
-    if (gtype == G_TYPE_TARGET_OPERAND)
-        result = true;
+    status = load_uleb128(&index, fd);
 
-    else
+    if (status)
     {
         g_mutex_lock(&tpmem->mutex);
 
-        for (index = 0; index < tpmem->count; index++)
-            if (tpmem->gtypes[index].gtype == gtype)
-                break;
-
-        if (index == tpmem->count)
-        {
-            tpmem->gtypes = realloc(tpmem->gtypes, ++tpmem->count * sizeof(gtype_ref_info_t));
-
-            assert(tpmem->count > 0);
-
-            tpmem->gtypes[index].gtype = gtype;
-            tpmem->gtypes[index].gclass = g_type_class_ref(gtype);
-
-        }
+        if (index < tpmem->count)
+            result = g_object_new(tpmem->gtypes[index].gtype, NULL);
 
         g_mutex_unlock(&tpmem->mutex);
 
-        result = pack_uleb128((uleb128_t []){ index }, pbuf);
-
     }
 
     return result;
@@ -388,10 +319,11 @@ bool g_type_memory_store_object_gtype(GTypeMemory *tpmem, GObject *obj, packed_b
 
 /******************************************************************************
 *                                                                             *
-*  Paramètres  : tpmem = mémoire à consulter.                                 *
-*                pbuf  = zone tampon à remplir. [OUT]                         *
+*  Paramètres  : tpmem = mémoire à manipuler.                                 *
+*                obj   = instance dont le type est à mémoriser.               *
+*                fd    = flux ouvert en écriture.                             *
 *                                                                             *
-*  Description : Enregistre tous les types mémorisés dans un tampon.          *
+*  Description : Sauvegarde le type d'un objet instancié.                     *
 *                                                                             *
 *  Retour      : Bilan de l'opération.                                        *
 *                                                                             *
@@ -399,31 +331,33 @@ bool g_type_memory_store_object_gtype(GTypeMemory *tpmem, GObject *obj, packed_b
 *                                                                             *
 ******************************************************************************/
 
-bool g_type_memory_store_types(GTypeMemory *tpmem, packed_buffer_t *pbuf)
+bool g_type_memory_store_object_gtype(GTypeMemory *tpmem, GObject *obj, int fd)
 {
-    bool result;                            /* Bilan à enregistrer         */
-    uint64_t i;                             /* Boucle de parcours          */
-    const gchar *name;                      /* Désignation d'un type       */
-    rle_string str;                         /* Chaîne à conserver          */
+    bool result;                            /* Bilan à retourner           */
+    GType gtype;                            /* Type à enregistrer          */
+    size_t index;                           /* Indice du point d'insertion */
+
+    gtype = G_TYPE_FROM_INSTANCE(obj);
 
     g_mutex_lock(&tpmem->mutex);
 
-    result = pack_uleb128((uleb128_t []){ tpmem->count }, pbuf);
+    for (index = 0; index < tpmem->count; index++)
+        if (tpmem->gtypes[index].gtype == gtype)
+            break;
 
-    for (i = 0; i < tpmem->count && result; i++)
+    if (index == tpmem->count)
     {
-        name = g_type_name(tpmem->gtypes[i].gtype);
-
-        init_static_rle_string(&str, name);
+        tpmem->gtypes = realloc(tpmem->gtypes, ++tpmem->count * sizeof(gtype_ref_info_t));
 
-        result = pack_rle_string(&str, pbuf);
-
-        exit_rle_string(&str);
+        tpmem->gtypes[index].gtype = gtype;
+        tpmem->gtypes[index].gclass = g_type_class_ref(gtype);
 
     }
 
     g_mutex_unlock(&tpmem->mutex);
 
+    result = store_uleb128((uleb128_t []){ index }, fd);
+
     return result;
 
 }
diff --git a/src/glibext/tpmem.h b/src/glibext/tpmem.h
index 34cbde6..ccb8323 100644
--- a/src/glibext/tpmem.h
+++ b/src/glibext/tpmem.h
@@ -2,7 +2,7 @@
 /* Chrysalide - Outil d'analyse de fichiers binaires
  * tpmem.h - prototypes pour la mémorisation des types d'objets mis en cache
  *
- * Copyright (C) 2020 Cyrille Bagard
+ * Copyright (C) 2020-2025 Cyrille Bagard
  *
  *  This file is part of Chrysalide.
  *
@@ -21,50 +21,37 @@
  */
 
 
-#ifndef _ANALYSIS_STORAGE_TPMEM_H
-#define _ANALYSIS_STORAGE_TPMEM_H
+#ifndef _GLIBEXT_TPMEM_H
+#define _GLIBEXT_TPMEM_H
 
 
-#include <glib-object.h>
+#include <stdbool.h>
 
 
-#include "../../common/packed.h"
+#include "helpers.h"
 
 
 
-#define G_TYPE_TYPE_MEMORY            g_type_memory_get_type()
-#define G_TYPE_MEMORY(obj)            (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_TYPE_MEMORY, GTypeMemory))
-#define G_IS_TYPE_MEMORY(obj)         (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_TYPE_MEMORY))
-#define G_TYPE_MEMORY_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_TYPE_MEMORY, GTypeMemoryClass))
-#define G_IS_TYPE_MEMORY_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_TYPE_MEMORY))
-#define G_TYPE_MEMORY_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_TYPE_MEMORY, GTypeMemoryClass))
+#define G_TYPE_TYPE_MEMORY (g_type_memory_get_type())
 
+DECLARE_GTYPE(GTypeMemory, g_type_memory, G, TYPE_MEMORY);
 
-/* Définition d'une mémoire de types d'objets (instance) */
-typedef struct _GTypeMemory GTypeMemory;
-
-/* Définition d'une mémoire de types d'objets (classe) */
-typedef struct _GTypeMemoryClass GTypeMemoryClass;
-
-
-/* Indique le type défini pour une mémoire de types d'objets. */
-GType g_type_memory_get_type(void);
 
 /* Crée une mémoire pour types d'objets. */
 GTypeMemory *g_type_memory_new(void);
 
 /* Apprend tous les types mémorisés dans un tampon. */
-bool g_type_memory_load_types(GTypeMemory *, packed_buffer_t *);
+bool g_type_memory_load(GTypeMemory *, int);
+
+/* Enregistre tous les types mémorisés dans un tampon. */
+bool g_type_memory_store(GTypeMemory *, int);
 
 /* Crée une nouvelle instance d'objet à partir de son type. */
-GObject *g_type_memory_create_object(GTypeMemory *, packed_buffer_t *);
+GObject *g_type_memory_create_object_from_gtype(GTypeMemory *, int);
 
 /* Sauvegarde le type d'un objet instancié. */
-bool g_type_memory_store_object_gtype(GTypeMemory *, GObject *, packed_buffer_t *);
-
-/* Enregistre tous les types mémorisés dans un tampon. */
-bool g_type_memory_store_types(GTypeMemory *, packed_buffer_t *);
+bool g_type_memory_store_object_gtype(GTypeMemory *, GObject *, int);
 
 
 
-#endif  /* _ANALYSIS_STORAGE_TPMEM_H */
+#endif  /* _GLIBEXT_TPMEM_H */
diff --git a/system/magic/storage b/system/magic/storage
new file mode 100644
index 0000000..b7698d1
--- /dev/null
+++ b/system/magic/storage
@@ -0,0 +1,40 @@
+
+# 4.3.7  Local file header:
+# Cf. https://pkware.cachefly.net/webdocs/casestudies/APPNOTE.TXT
+
+# local file header signature     4 bytes  (0x04034b50)
+# version needed to extract       2 bytes
+# general purpose bit flag        2 bytes
+# compression method              2 bytes
+# last mod file time              2 bytes
+# last mod file date              2 bytes
+# crc-32                          4 bytes
+# compressed size                 4 bytes
+# uncompressed size               4 bytes
+# file name length                2 bytes
+# extra field length              2 bytes
+
+
+# ZIP local file header #1
+
+0               string          PK\003\004
+
+# First entry: control (file name length = 7)
+
+>0x1a           uleshort        7
+>>0x1e          string          control
+
+# Content of control
+
+>>>&(0x1c.h)    string          COBSTR          Chrysalide GObject storage
+>>>>&0          string          \001\000        (version 1.0)
+
+# Storage for PythonNotebook
+
+>>>>>&0         byte            14
+>>>>>>&0        string          PythonNotebook  - PythonNotebook
+
+>>>>>>>&0       byte            1               v1
+
+!:mime          application/vnd.chrysalide.notebook
+!:ext           cnb
diff --git a/tests/glibext/storage.py b/tests/glibext/storage.py
index 612d500..b60377a 100644
--- a/tests/glibext/storage.py
+++ b/tests/glibext/storage.py
@@ -1,11 +1,8 @@
 
 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
+from pychrysalide.glibext import ObjectStorage, SerializableObject
+import gi
 import os
-import shutil
 import tempfile
 
 
@@ -17,15 +14,9 @@ class TestObjectStorage(ChrysalideTestCase):
 
         super(TestObjectStorage, cls).setUpClass()
 
-        cls._tmp_path = tempfile.mkdtemp()
+        _, cls._tmp_filename = tempfile.mkstemp()
 
-        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)
+        cls.log('Using temporary filename "%s"' % cls._tmp_filename)
 
 
     @classmethod
@@ -33,49 +24,51 @@ class TestObjectStorage(ChrysalideTestCase):
 
         super(TestObjectStorage, cls).tearDownClass()
 
-        config = core.get_main_configuration()
-        param = config.search(core.MainParameterKeys.TMPDIR)
+        cls.log('Delete filename "%s"' % cls._tmp_filename)
 
-        param.value = cls._old_tmpdir
+        os.unlink(cls._tmp_filename)
 
-        # import os
-        # os.system('ls -laihR %s' % cls._tmp_path)
 
-        cls.log('Delete directory "%s"' % cls._tmp_path)
+    def testGenericStorage(self):
+        """Store and load basic objects."""
 
-        shutil.rmtree(cls._tmp_path)
 
+        class SimpleObject(gi._gi.GObject, SerializableObject):
 
-    def testFileContentStorage(self):
-        """Store and load file binary content."""
+            def __init__(self, b=None):
+                super().__init__()
+                self._b = b
 
-        storage = ObjectStorage('my-storage-hash')
-        self.assertIsNotNone(storage)
+            def _load(self, storage, fd):
+                assert(self._b is None)
+                self._b = os.read(fd, 1)[0]
+                return True
 
-        filename = os.path.join(self._tmp_path, 'test.bin')
+            def _store(self, storage, fd):
+                os.write(fd, bytes([ self._b ]))
+                return True
 
-        with open(filename, 'wb') as fd:
-            fd.write(b'ABC')
+            def __eq__(self, other):
+                return self._b == other._b
 
-        cnt = FileContent(filename)
-        self.assertIsNotNone(cnt)
 
-        ret = storage.store_object('contents', cnt)
-        self.assertEqual(ret, 0)
+        # Store
+
+        storage = ObjectStorage('TestStorage', 0, 'my-storage-hash')
+        self.assertIsNotNone(storage)
 
-        pbuf = PackedBuffer()
+        so = SimpleObject(0x23)
 
-        ret = storage.store(pbuf)
-        self.assertTrue(ret)
+        pos = storage.store_object('simple', so)
+        self.assertIsNotNone(pos)
 
-        self.assertTrue(pbuf.payload_length > 0)
+        status = storage.store(self._tmp_filename)
+        self.assertTrue(status)
 
-        pbuf.rewind()
+        # Reload
 
-        storage2 = ObjectStorage.load(pbuf)
-        self.assertIsNotNone(storage2)
+        storage2 = ObjectStorage.load(self._tmp_filename)
 
-        cnt2 = storage2.load_object('contents', 0)
-        self.assertIsNotNone(cnt2)
+        so2 = storage2.load_object('simple', pos)
 
-        self.assertEqual(cnt.data, cnt2.data)
+        self.assertEqual(so, so2)
-- 
cgit v0.11.2-87-g4458