summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCyrille Bagard <nocbos@gmail.com>2025-03-13 00:19:58 (GMT)
committerCyrille Bagard <nocbos@gmail.com>2025-03-13 00:19:58 (GMT)
commit733d0cdb8677fe09310125bcaeb058a1a9c56b4d (patch)
tree17b8d9a151068dac695d25e39e875933ff9aaa40
parent8287d20061887e9fd33e038e8f9bf86cf13f2780 (diff)
Rebuild a generic storage for GObjects using a ZIP format.
-rw-r--r--plugins/pychrysalide/glibext/Makefile.am2
-rw-r--r--plugins/pychrysalide/glibext/module.c4
-rw-r--r--plugins/pychrysalide/glibext/serialize.c141
-rw-r--r--plugins/pychrysalide/glibext/serialize.h12
-rw-r--r--plugins/pychrysalide/glibext/storage.c225
-rw-r--r--plugins/pychrysalide/glibext/storage.h12
-rw-r--r--src/Makefile.am2
-rw-r--r--src/common/cpp.h7
-rw-r--r--src/glibext/Makefile.am8
-rw-r--r--src/glibext/serialize-int.h18
-rw-r--r--src/glibext/serialize.c28
-rw-r--r--src/glibext/serialize.h38
-rw-r--r--src/glibext/storage-int.h21
-rw-r--r--src/glibext/storage.c994
-rw-r--r--src/glibext/storage.h70
-rw-r--r--src/glibext/tpmem-int.h78
-rw-r--r--src/glibext/tpmem.c224
-rw-r--r--src/glibext/tpmem.h41
-rw-r--r--system/magic/storage40
-rw-r--r--tests/glibext/storage.py75
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)