diff options
| author | Cyrille Bagard <nocbos@gmail.com> | 2025-03-13 00:19:58 (GMT) | 
|---|---|---|
| committer | Cyrille Bagard <nocbos@gmail.com> | 2025-03-13 00:19:58 (GMT) | 
| commit | 733d0cdb8677fe09310125bcaeb058a1a9c56b4d (patch) | |
| tree | 17b8d9a151068dac695d25e39e875933ff9aaa40 | |
| parent | 8287d20061887e9fd33e038e8f9bf86cf13f2780 (diff) | |
Rebuild a generic storage for GObjects using a ZIP format.
| -rw-r--r-- | plugins/pychrysalide/glibext/Makefile.am | 2 | ||||
| -rw-r--r-- | plugins/pychrysalide/glibext/module.c | 4 | ||||
| -rw-r--r-- | plugins/pychrysalide/glibext/serialize.c | 141 | ||||
| -rw-r--r-- | plugins/pychrysalide/glibext/serialize.h | 12 | ||||
| -rw-r--r-- | plugins/pychrysalide/glibext/storage.c | 225 | ||||
| -rw-r--r-- | plugins/pychrysalide/glibext/storage.h | 12 | ||||
| -rw-r--r-- | src/Makefile.am | 2 | ||||
| -rw-r--r-- | src/common/cpp.h | 7 | ||||
| -rw-r--r-- | src/glibext/Makefile.am | 8 | ||||
| -rw-r--r-- | src/glibext/serialize-int.h | 18 | ||||
| -rw-r--r-- | src/glibext/serialize.c | 28 | ||||
| -rw-r--r-- | src/glibext/serialize.h | 38 | ||||
| -rw-r--r-- | src/glibext/storage-int.h | 21 | ||||
| -rw-r--r-- | src/glibext/storage.c | 994 | ||||
| -rw-r--r-- | src/glibext/storage.h | 70 | ||||
| -rw-r--r-- | src/glibext/tpmem-int.h | 78 | ||||
| -rw-r--r-- | src/glibext/tpmem.c | 224 | ||||
| -rw-r--r-- | src/glibext/tpmem.h | 41 | ||||
| -rw-r--r-- | system/magic/storage | 40 | ||||
| -rw-r--r-- | tests/glibext/storage.py | 75 | 
20 files changed, 1109 insertions, 931 deletions
| 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) | 
