diff options
-rw-r--r-- | plugins/pychrysalide/common/Makefile.am | 1 | ||||
-rw-r--r-- | plugins/pychrysalide/common/module.c | 2 | ||||
-rw-r--r-- | plugins/pychrysalide/common/packed.c | 651 | ||||
-rw-r--r-- | plugins/pychrysalide/common/packed.h | 51 | ||||
-rw-r--r-- | src/arch/storage.c | 2 | ||||
-rw-r--r-- | src/common/packed.c | 106 | ||||
-rw-r--r-- | src/common/packed.h | 43 | ||||
-rw-r--r-- | tests/common/packed.py | 59 |
8 files changed, 871 insertions, 44 deletions
diff --git a/plugins/pychrysalide/common/Makefile.am b/plugins/pychrysalide/common/Makefile.am index e4c337f..138014c 100644 --- a/plugins/pychrysalide/common/Makefile.am +++ b/plugins/pychrysalide/common/Makefile.am @@ -5,6 +5,7 @@ libpychrysacommon_la_SOURCES = \ bits.h bits.c \ fnv1a.h fnv1a.c \ module.h module.c \ + packed.h packed.c \ pathname.h pathname.c libpychrysacommon_la_LDFLAGS = diff --git a/plugins/pychrysalide/common/module.c b/plugins/pychrysalide/common/module.c index 44c06c5..e8cda4f 100644 --- a/plugins/pychrysalide/common/module.c +++ b/plugins/pychrysalide/common/module.c @@ -27,6 +27,7 @@ #include "bits.h" #include "fnv1a.h" +#include "packed.h" #include "pathname.h" #include "../helpers.h" @@ -89,6 +90,7 @@ bool populate_common_module(void) if (result) result = ensure_python_bitfield_is_registered(); if (result) result = ensure_python_fnv1a_is_registered(); + if (result) result = ensure_python_packed_buffer_is_registered(); if (result) result = ensure_python_pathname_is_registered(); assert(result); diff --git a/plugins/pychrysalide/common/packed.c b/plugins/pychrysalide/common/packed.c new file mode 100644 index 0000000..c7fa296 --- /dev/null +++ b/plugins/pychrysalide/common/packed.c @@ -0,0 +1,651 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * packed.c - équivalent Python du fichier "common/packed.c" + * + * Copyright (C) 2020 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 this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +#include "packed.h" + + +#include <assert.h> + + +#include "../access.h" +#include "../helpers.h" + + + +/* Rassemblement de données d'un paquet */ +typedef struct _py_packed_buffer_t +{ + PyObject_HEAD /* A laisser en premier */ + + packed_buffer_t *native; /* Tampon de données lié */ + +} py_packed_buffer_t; + + +/* Libère de la mémoire un objet Python 'py_packed_buffer_t'. */ +static void py_packed_buffer_dealloc(py_packed_buffer_t *); + +/* Initialise un objet Python de type 'py_packed_buffer_t'. */ +static int py_packed_buffer_init(py_packed_buffer_t *, PyObject *, PyObject *); + +/* Rembobine le paquet de données à son départ. */ +static PyObject *py_packed_buffer_rewind(PyObject *, PyObject *); + +/* Ajoute des données à un paquet en amont à un envoi. */ +static PyObject *py_packed_buffer_extend(PyObject *, PyObject *); + +/* Récupère des données depuis un paquet après une réception. */ +static PyObject *py_packed_buffer_peek(PyObject *, PyObject *); + +/* Avance la tête de lecture dans les données d'un paquet. */ +static PyObject *py_packed_buffer_advance(PyObject *, PyObject *); + +/* Récupère des données depuis un paquet après une réception. */ +static PyObject *py_packed_buffer_extract(PyObject *, PyObject *); + +/* Indique le nombre d'octets de la charge utile d'un paquet. */ +static PyObject *py_packed_buffer_get_payload_length(PyObject *, void *); + +/* Détermine si des données sont disponibles en lecture. */ +static PyObject *py_packed_buffer_has_more_data(PyObject *, void *); + + + +/****************************************************************************** +* * +* Paramètres : self = tampon de données à supprimer. * +* * +* Description : Libère de la mémoire un objet Python 'py_packed_buffer_t'. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void py_packed_buffer_dealloc(py_packed_buffer_t *self) +{ + exit_packed_buffer(self->native); + + Py_TYPE(self)->tp_free((PyObject *)self); + +} + + +/****************************************************************************** +* * +* Paramètres : self = instance d'objet à initialiser. * +* args = arguments passés pour l'appel. * +* kwds = mots clefs éventuellement fournis en complément. * +* * +* Description : Initialise un objet Python de type 'py_packed_buffer_t'. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static int py_packed_buffer_init(py_packed_buffer_t *self, PyObject *args, PyObject *kwds) +{ + int result; /* Bilan à retourner */ + +#define PACKED_BUFFER_DOC \ + "The PackedBuffer is mainly used as helper for the storage of GLib" \ + " objects over the network or into files.\n" \ + "\n" \ + "The same kind of features as the Python *struct* module are" \ + " provided to store and retrieve data.\n" \ + "\n" \ + "Instances can be created using the following constructor:\n" \ + "\n" \ + " PackedBuffer()" + + self->native = malloc(sizeof(packed_buffer_t)); + + init_packed_buffer(self->native); + + result = 0; + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : self = tampon de données à consulter. * +* args = arguments fournis pour la conduite de l'opération. * +* * +* Description : Rembobine le paquet de données à son départ. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static PyObject *py_packed_buffer_rewind(PyObject *self, PyObject *args) +{ + PyObject *result; /* Bilan à faire remonter */ + py_packed_buffer_t *pybuf; /* Instance à manipuler */ + +#define PACKED_BUFFER_REWIND_METHOD PYTHON_METHOD_DEF \ +( \ + rewind, "$self, /", \ + METH_NOARGS, py_packed_buffer, \ + "Rewind the reader head to the beginning of the buffer." \ +) + + pybuf = (py_packed_buffer_t *)self; + + rewind_packed_buffer(pybuf->native); + + result = Py_None; + Py_INCREF(result); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : self = tampon de données à consulter. * +* args = arguments fournis pour la conduite de l'opération. * +* * +* Description : Ajoute des données à un paquet en amont à un envoi. * +* * +* Retour : True. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static PyObject *py_packed_buffer_extend(PyObject *self, PyObject *args) +{ + PyObject *result; /* Bilan à faire remonter */ + const char *data; /* Données à intégrer */ + Py_ssize_t length; /* Taille des données contenues*/ + int ntoh; /* Conversion à réaliser ? */ + int ret; /* Bilan de lecture des args. */ + py_packed_buffer_t *pybuf; /* Instance à manipuler */ + bool status; /* Bilan de l'opération */ + +#define PACKED_BUFFER_EXTEND_METHOD PYTHON_METHOD_DEF \ +( \ + extend, "$self, data, /, ntoh=False", \ + METH_VARARGS, py_packed_buffer, \ + "Append data to a buffer.\n" \ + "\n" \ + "The data must be bytes. The *ntoh* parameter forces the data" \ + " to be converted from the network order to the host order.\n" \ + "\n" \ + "This conversion is only relevant for 2, 4 and 8 bytes" \ + " quantities.\n" \ + "\n" \ + "The method returns True if the operation succeeded." \ +) + + ntoh = 0; + + ret = PyArg_ParseTuple(args, "s#|p", &data, &length, &ntoh); + if (!ret) return NULL; + + pybuf = (py_packed_buffer_t *)self; + + status = extend_packed_buffer(pybuf->native, data, length, ntoh); + + result = status ? Py_True : Py_False; + Py_INCREF(result); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : self = tampon de données à consulter. * +* args = arguments fournis pour la conduite de l'opération. * +* * +* Description : Récupère des données depuis un paquet après une réception. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static PyObject *py_packed_buffer_peek(PyObject *self, PyObject *args) +{ + PyObject *result; /* Bilan à faire remonter */ + int len; /* Ampleur de progression */ + int ntoh; /* Conversion à réaliser ? */ + int ret; /* Bilan de lecture des args. */ + py_packed_buffer_t *pybuf; /* Instance à manipuler */ + void *data; /* Données obtenues */ + bool status; /* Bilan de l'opération */ + +#define PACKED_BUFFER_PEEK_METHOD PYTHON_METHOD_DEF \ +( \ + peek, "$self, len, /, ntoh=False", \ + METH_VARARGS, py_packed_buffer, \ + "Extract data from a buffer. The reader head remains untouched" \ + " during the operation.\n" \ + "\n" \ + "The *len* argument defines the quantity of data to retrieve" \ + " and the *ntoh* parameter forces the data to be converted" \ + " from the network order to the host order.\n" \ + "\n" \ + "This conversion is only relevant for 2, 4 and 8 bytes" \ + " quantities.\n" \ + "\n" \ + "The method returns data as bytes or None in case of error." \ +) + + ntoh = 0; + + ret = PyArg_ParseTuple(args, "n|p", &len, &ntoh); + if (!ret) return NULL; + + result = NULL; + + data = malloc(len); + + if (data != NULL) + { + pybuf = (py_packed_buffer_t *)self; + + status = peek_packed_buffer(pybuf->native, data, len, ntoh); + + if (status) + result = PyBytes_FromStringAndSize(data, len); + + free(data); + + } + + if (result == NULL) + { + result = Py_None; + Py_INCREF(result); + } + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : self = tampon de données à consulter. * +* args = arguments fournis pour la conduite de l'opération. * +* * +* Description : Avance la tête de lecture dans les données d'un paquet. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static PyObject *py_packed_buffer_advance(PyObject *self, PyObject *args) +{ + PyObject *result; /* Bilan à faire remonter */ + int len; /* Ampleur de progression */ + int ret; /* Bilan de lecture des args. */ + py_packed_buffer_t *pybuf; /* Instance à manipuler */ + +#define PACKED_BUFFER_ADVANCE_METHOD PYTHON_METHOD_DEF \ +( \ + advance, "$self, len, /", \ + METH_VARARGS, py_packed_buffer, \ + "Advance the reader head inside the buffer.\n" \ + "\n" \ + "The *len* argument defines the quantity of data to skip." \ +) + + ret = PyArg_ParseTuple(args, "n", &len); + if (!ret) return NULL; + + pybuf = (py_packed_buffer_t *)self; + + advance_packed_buffer(pybuf->native, len); + + result = Py_None; + Py_INCREF(result); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : self = tampon de données à consulter. * +* args = arguments fournis pour la conduite de l'opération. * +* * +* Description : Récupère des données depuis un paquet après une réception. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static PyObject *py_packed_buffer_extract(PyObject *self, PyObject *args) +{ + PyObject *result; /* Bilan à faire remonter */ + int len; /* Ampleur de progression */ + int ntoh; /* Conversion à réaliser ? */ + int ret; /* Bilan de lecture des args. */ + py_packed_buffer_t *pybuf; /* Instance à manipuler */ + void *data; /* Données obtenues */ + bool status; /* Bilan de l'opération */ + +#define PACKED_BUFFER_EXTRACT_METHOD PYTHON_METHOD_DEF \ +( \ + extract, "$self, len, /, ntoh=False", \ + METH_VARARGS, py_packed_buffer, \ + "Extract data from a buffer.\n" \ + "\n" \ + "The *len* argument defines the quantity of data to retrieve" \ + " and the *ntoh* parameter forces the data to be converted" \ + " from the network order to the host order.\n" \ + "\n" \ + "This conversion is only relevant for 2, 4 and 8 bytes" \ + " quantities.\n" \ + "\n" \ + "The method returns data as bytes or None in case of error." \ +) + + ntoh = 0; + + ret = PyArg_ParseTuple(args, "n|p", &len, &ntoh); + if (!ret) return NULL; + + result = NULL; + + data = malloc(len); + + if (data != NULL) + { + pybuf = (py_packed_buffer_t *)self; + + status = extract_packed_buffer(pybuf->native, data, len, ntoh); + + if (status) + result = PyBytes_FromStringAndSize(data, len); + + free(data); + + } + + if (result == NULL) + { + result = Py_None; + Py_INCREF(result); + } + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : self = classe représentant un tampon de données. * +* closure = adresse non utilisée ici. * +* * +* Description : Indique le nombre d'octets de la charge utile d'un paquet. * +* * +* Retour : Quantité de données utiles. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static PyObject *py_packed_buffer_get_payload_length(PyObject *self, void *closure) +{ + PyObject *result; /* Conversion à retourner */ + py_packed_buffer_t *pybuf; /* Instance à manipuler */ + size_t length; /* Quantité de données portées */ + +#define PACKED_BUFFER_PAYLOAD_LENGTH_ATTRIB PYTHON_GET_DEF_FULL \ +( \ + payload_length, py_packed_buffer, \ + "Size of the full data carried by the buffer." \ +) + + pybuf = (py_packed_buffer_t *)self; + + length = get_packed_buffer_payload_length(pybuf->native); + + result = PyLong_FromSize_t(length); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : self = classe représentant un tampon de données. * +* closure = adresse non utilisée ici. * +* * +* Description : Détermine si des données sont disponibles en lecture. * +* * +* Retour : True si des données peuvent être dépilées, False sinon. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static PyObject *py_packed_buffer_has_more_data(PyObject *self, void *closure) +{ + PyObject *result; /* Conversion à retourner */ + py_packed_buffer_t *pybuf; /* Instance à manipuler */ + bool status; /* Bilan de la consultation */ + +#define PACKED_BUFFER_HAS_MORE_DATA_ATTRIB PYTHON_HAS_DEF_FULL \ +( \ + more_data, py_packed_buffer, \ + "Tell if the buffer has more data for further reading." \ +) + + pybuf = (py_packed_buffer_t *)self; + + status = has_more_data_in_packed_buffer(pybuf->native); + + result = status ? Py_True : Py_False; + Py_INCREF(result); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : - * +* * +* Description : Fournit un accès à une définition de type à diffuser. * +* * +* Retour : Définition d'objet pour Python. * +* * +* Remarques : - * +* * +******************************************************************************/ + +PyTypeObject *get_python_packed_buffer_type(void) +{ + static PyMethodDef py_packed_buffer_methods[] = { + PACKED_BUFFER_REWIND_METHOD, + PACKED_BUFFER_EXTEND_METHOD, + PACKED_BUFFER_PEEK_METHOD, + PACKED_BUFFER_ADVANCE_METHOD, + PACKED_BUFFER_EXTRACT_METHOD, + { NULL } + }; + + static PyGetSetDef py_packed_buffer_getseters[] = { + PACKED_BUFFER_PAYLOAD_LENGTH_ATTRIB, + PACKED_BUFFER_HAS_MORE_DATA_ATTRIB, + { NULL } + }; + + static PyTypeObject py_packed_buffer_type = { + + PyVarObject_HEAD_INIT(NULL, 0) + + .tp_name = "pychrysalide.common.PackedBuffer", + .tp_basicsize = sizeof(py_packed_buffer_t), + + .tp_dealloc = (destructor)py_packed_buffer_dealloc, + + .tp_flags = Py_TPFLAGS_DEFAULT, + + .tp_doc = PACKED_BUFFER_DOC, + + .tp_methods = py_packed_buffer_methods, + .tp_getset = py_packed_buffer_getseters, + + .tp_init = (initproc)py_packed_buffer_init, + .tp_new = PyType_GenericNew, + + }; + + return &py_packed_buffer_type; + +} + + +/****************************************************************************** +* * +* Paramètres : module = module dont la définition est à compléter. * +* * +* Description : Prend en charge l'objet 'pychrysalide.common.PackedBuffer'. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool ensure_python_packed_buffer_is_registered(void) +{ + PyTypeObject *type; /* Type Python 'PackedBuffer' */ + PyObject *module; /* Module à recompléter */ + + type = get_python_packed_buffer_type(); + + if (!PyType_HasFeature(type, Py_TPFLAGS_READY)) + { + if (PyType_Ready(type) != 0) + return false; + + module = get_access_to_python_module("pychrysalide.common"); + + if (!register_python_module_object(module, type)) + return false; + + } + + return true; + +} + + +/****************************************************************************** +* * +* Paramètres : pbuf = structure interne à copier en objet Python. * +* * +* Description : Convertit une structure 'packed_buffer_t' en objet Python. * +* * +* Retour : Object Python résultant de la conversion opérée. * +* * +* Remarques : - * +* * +******************************************************************************/ + +PyObject *build_from_internal_packed_buffer(const packed_buffer_t *pbuf) +{ + PyObject *result; /* Instance à retourner */ + PyTypeObject *type; /* Type à instancier */ + + type = get_python_packed_buffer_type(); + + result = PyObject_CallObject((PyObject *)type, NULL); + + copy_packed_buffer(((py_packed_buffer_t *)result)->native, pbuf); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : arg = argument quelconque à tenter de convertir. * +* dst = destination des valeurs récupérées en cas de succès. * +* * +* Description : Tente de convertir en tampon de données. * +* * +* Retour : Bilan de l'opération, voire indications supplémentaires. * +* * +* Remarques : - * +* * +******************************************************************************/ + +int convert_to_packed_buffer(PyObject *arg, void *dst) +{ + int result; /* Bilan à retourner */ + + result = PyObject_IsInstance(arg, (PyObject *)get_python_packed_buffer_type()); + + switch (result) + { + case -1: + /* L'exception est déjà fixée par Python */ + result = 0; + break; + + case 0: + PyErr_SetString(PyExc_TypeError, "unable to convert the provided argument to packed buffer"); + break; + + case 1: + *((packed_buffer_t **)dst) = ((py_packed_buffer_t *)arg)->native; + break; + + default: + assert(false); + break; + + } + + return result; + +} diff --git a/plugins/pychrysalide/common/packed.h b/plugins/pychrysalide/common/packed.h new file mode 100644 index 0000000..ee67704 --- /dev/null +++ b/plugins/pychrysalide/common/packed.h @@ -0,0 +1,51 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * packed.h - prototypes pour l'équivalent Python du fichier "common/packed.h" + * + * Copyright (C) 2020 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 this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +#ifndef _PLUGINS_PYCHRYSALIDE_COMMON_PACKED_H +#define _PLUGINS_PYCHRYSALIDE_COMMON_PACKED_H + + +#include <Python.h> +#include <stdbool.h> + + +#include <common/packed.h> + + + +/* Fournit un accès à une définition de type à diffuser. */ +PyTypeObject *get_python_packed_buffer_type(void); + +/* Prend en charge l'objet 'pychrysalide.common.PackedBuffer'. */ +bool ensure_python_packed_buffer_is_registered(void); + +/* Convertit une structure 'packed_buffer_t' en objet Python. */ +PyObject *build_from_internal_packed_buffer(const packed_buffer_t *); + +/* Tente de convertir en tampon de données. */ +int convert_to_packed_buffer(PyObject *, void *); + + + +#endif /* _PLUGINS_PYCHRYSALIDE_COMMON_PACKED_H */ diff --git a/src/arch/storage.c b/src/arch/storage.c index 0995f4d..269228c 100644 --- a/src/arch/storage.c +++ b/src/arch/storage.c @@ -1007,7 +1007,7 @@ static bool g_asm_storage_compress(const GAsmStorage *storage) static bool g_asm_storage_read_types(GAsmStorage *storage) { bool result; /* Bilan à enregistrer */ - packed_buffer pbuf; /* Tampon des données à écrire */ + packed_buffer pbuf; /* Tampon des données à lire */ size_t i; /* Boucle de parcours */ unsigned char len; /* Taille d'un nom de type */ char *name; /* Désignation d'un type */ diff --git a/src/common/packed.c b/src/common/packed.c index b8638b3..117b557 100644 --- a/src/common/packed.c +++ b/src/common/packed.c @@ -51,7 +51,7 @@ * * ******************************************************************************/ -void init_packed_buffer(packed_buffer *pbuf) +void init_packed_buffer(packed_buffer_t *pbuf) { pbuf->allocated = PACKET_BLOCK_SIZE; pbuf->data = malloc(pbuf->allocated * sizeof(uint8_t)); @@ -65,6 +65,27 @@ void init_packed_buffer(packed_buffer *pbuf) * * * Paramètres : pbuf = paquet de données à réinitialiser. [OUT] * * * +* Description : Rembobine le paquet de données à son départ. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +void rewind_packed_buffer(packed_buffer_t *pbuf) +{ + pbuf->pos = sizeof(uint32_t); + + assert(pbuf->pos <= pbuf->allocated); + +} + + +/****************************************************************************** +* * +* Paramètres : pbuf = paquet de données à réinitialiser. [OUT] * +* * * Description : Réinitialise un paquet réseau pour une constitution. * * * * Retour : - * @@ -73,10 +94,11 @@ void init_packed_buffer(packed_buffer *pbuf) * * ******************************************************************************/ -void reset_packed_buffer(packed_buffer *pbuf) +void reset_packed_buffer(packed_buffer_t *pbuf) { pbuf->used = 0; - pbuf->pos = sizeof(uint32_t); + + rewind_packed_buffer(pbuf); assert(pbuf->pos <= pbuf->allocated); @@ -95,17 +117,49 @@ void reset_packed_buffer(packed_buffer *pbuf) * * ******************************************************************************/ -void exit_packed_buffer(packed_buffer *pbuf) +void exit_packed_buffer(packed_buffer_t *pbuf) { #ifndef NDEBUG assert(pbuf->data != NULL); #endif - free(pbuf->data); + if (pbuf->data) + { + free(pbuf->data); + pbuf->data = NULL; + } + +} + -#ifndef NDEBUG - pbuf->data = NULL; -#endif +/****************************************************************************** +* * +* Paramètres : dest = tampon de données à constituer. * +* src = tampon de données à copier. * +* * +* Description : Copie les données d'un tampon dans un autre. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +void copy_packed_buffer(packed_buffer_t *dest, const packed_buffer_t *src) +{ + size_t len; /* Taille des données à copier */ + + exit_packed_buffer(dest); + + len = dest->allocated * sizeof(uint8_t); + + dest->allocated = src->allocated; + dest->data = malloc(len); + + memcpy(dest->data, src->data, len); + + dest->used = src->used; + dest->pos = src->pos; } @@ -122,7 +176,7 @@ void exit_packed_buffer(packed_buffer *pbuf) * * ******************************************************************************/ -size_t get_packed_buffer_payload_length(const packed_buffer *pbuf) +size_t get_packed_buffer_payload_length(const packed_buffer_t *pbuf) { size_t result; /* Quantité à renvoyer */ @@ -145,7 +199,7 @@ size_t get_packed_buffer_payload_length(const packed_buffer *pbuf) * * ******************************************************************************/ -bool has_more_data_in_packed_buffer(const packed_buffer *pbuf) +bool has_more_data_in_packed_buffer(const packed_buffer_t *pbuf) { bool result; /* Bilan à retourner */ @@ -159,7 +213,7 @@ bool has_more_data_in_packed_buffer(const packed_buffer *pbuf) /****************************************************************************** * * * Paramètres : pbuf = paquet de données à compléter. * -* buf = nouvelles données à ajouter. * +* data = nouvelles données à ajouter. * * len = quantité de ces données. * * hton = indique si une conversion est à réaliser. * * * @@ -171,7 +225,7 @@ bool has_more_data_in_packed_buffer(const packed_buffer *pbuf) * * ******************************************************************************/ -bool extend_packed_buffer(packed_buffer *pbuf, const void *buf, size_t len, bool hton) +bool extend_packed_buffer(packed_buffer_t *pbuf, const void *data, size_t len, bool hton) { uint16_t tmp16; /* Valeur intermédiaire 16b */ uint32_t tmp32; /* Valeur intermédiaire 32b */ @@ -193,21 +247,21 @@ bool extend_packed_buffer(packed_buffer *pbuf, const void *buf, size_t len, bool switch (len) { case 1: - *((uint8_t *)(pbuf->data + pbuf->pos)) = *((uint8_t *)buf); + *((uint8_t *)(pbuf->data + pbuf->pos)) = *((uint8_t *)data); break; case 2: - tmp16 = htobe16(*(uint16_t *)buf); + tmp16 = htobe16(*(uint16_t *)data); *((uint16_t *)(pbuf->data + pbuf->pos)) = tmp16; break; case 4: - tmp32 = htobe32(*(uint32_t *)buf); + tmp32 = htobe32(*(uint32_t *)data); *((uint32_t *)(pbuf->data + pbuf->pos)) = tmp32; break; case 8: - tmp64 = htobe64(*(uint64_t *)buf); + tmp64 = htobe64(*(uint64_t *)data); *((uint64_t *)(pbuf->data + pbuf->pos)) = tmp64; break; @@ -221,7 +275,7 @@ bool extend_packed_buffer(packed_buffer *pbuf, const void *buf, size_t len, bool */ assert(!hton); - memcpy(pbuf->data + pbuf->pos, buf, len); + memcpy(pbuf->data + pbuf->pos, data, len); break; } @@ -249,7 +303,7 @@ bool extend_packed_buffer(packed_buffer *pbuf, const void *buf, size_t len, bool * * ******************************************************************************/ -bool peek_packed_buffer(packed_buffer *pbuf, void *buf, size_t len, bool ntoh) +bool peek_packed_buffer(packed_buffer_t *pbuf, void *buf, size_t len, bool ntoh) { bool result; /* Bilan à retourner */ uint16_t tmp16; /* Valeur intermédiaire 16b */ @@ -322,7 +376,7 @@ bool peek_packed_buffer(packed_buffer *pbuf, void *buf, size_t len, bool ntoh) * * ******************************************************************************/ -void advance_packed_buffer(packed_buffer *pbuf, size_t len) +void advance_packed_buffer(packed_buffer_t *pbuf, size_t len) { pbuf->pos += len; @@ -346,7 +400,7 @@ void advance_packed_buffer(packed_buffer *pbuf, size_t len) * * ******************************************************************************/ -bool extract_packed_buffer(packed_buffer *pbuf, void *buf, size_t len, bool ntoh) +bool extract_packed_buffer(packed_buffer_t *pbuf, void *buf, size_t len, bool ntoh) { bool result; /* Bilan à retourner */ @@ -373,7 +427,7 @@ bool extract_packed_buffer(packed_buffer *pbuf, void *buf, size_t len, bool ntoh * * ******************************************************************************/ -bool read_packed_buffer(packed_buffer *pbuf, int fd) +bool read_packed_buffer(packed_buffer_t *pbuf, int fd) { bool result; /* Bilan à retourner */ uint32_t used; /* Taille de charge utile */ @@ -414,7 +468,7 @@ bool read_packed_buffer(packed_buffer *pbuf, int fd) * * ******************************************************************************/ -bool write_packed_buffer(packed_buffer *pbuf, int fd) +bool write_packed_buffer(packed_buffer_t *pbuf, int fd) { bool result; /* Bilan à retourner */ @@ -440,7 +494,7 @@ bool write_packed_buffer(packed_buffer *pbuf, int fd) * * ******************************************************************************/ -bool recv_packed_buffer(packed_buffer *pbuf, int fd) +bool recv_packed_buffer(packed_buffer_t *pbuf, int fd) { bool result; /* Bilan à retourner */ uint32_t used; /* Taille de charge utile */ @@ -481,7 +535,7 @@ bool recv_packed_buffer(packed_buffer *pbuf, int fd) * * ******************************************************************************/ -bool send_packed_buffer(packed_buffer *pbuf, int fd) +bool send_packed_buffer(packed_buffer_t *pbuf, int fd) { bool result; /* Bilan à retourner */ @@ -507,7 +561,7 @@ bool send_packed_buffer(packed_buffer *pbuf, int fd) * * ******************************************************************************/ -bool ssl_recv_packed_buffer(packed_buffer *pbuf, SSL *fd) +bool ssl_recv_packed_buffer(packed_buffer_t *pbuf, SSL *fd) { bool result; /* Bilan à retourner */ uint32_t used; /* Taille de charge utile */ @@ -555,7 +609,7 @@ bool ssl_recv_packed_buffer(packed_buffer *pbuf, SSL *fd) * * ******************************************************************************/ -bool ssl_send_packed_buffer(packed_buffer *pbuf, SSL *fd) +bool ssl_send_packed_buffer(packed_buffer_t *pbuf, SSL *fd) { bool result; /* Bilan à retourner */ int quantity; /* Nombre de données à traiter */ diff --git a/src/common/packed.h b/src/common/packed.h index 5bc4fbb..f43b999 100644 --- a/src/common/packed.h +++ b/src/common/packed.h @@ -36,7 +36,7 @@ /* Rassemblement de données d'un paquet */ -typedef struct _packed_buffer +typedef struct _packed_buffer_t { uint8_t *data; /* Données à traiter */ size_t allocated; /* Taille allouée */ @@ -44,53 +44,62 @@ typedef struct _packed_buffer size_t used; /* Quantité de données utiles */ size_t pos; /* Tête de lecture/écriture */ -} packed_buffer; +} packed_buffer_t; + + +typedef struct _packed_buffer_t packed_buffer; /* REMME */ /* Initialise un paquet réseau pour une constitution. */ -void init_packed_buffer(packed_buffer *); +void init_packed_buffer(packed_buffer_t *); + +/* Rembobine le paquet de données à son départ. */ +void rewind_packed_buffer(packed_buffer_t *); /* Réinitialise un paquet réseau pour une constitution. */ -void reset_packed_buffer(packed_buffer *); +void reset_packed_buffer(packed_buffer_t *); /* Efface les données contenues par un paquet réseau. */ -void exit_packed_buffer(packed_buffer *); +void exit_packed_buffer(packed_buffer_t *); + +/* Copie les données d'un tampon dans un autre. */ +void copy_packed_buffer(packed_buffer_t *, const packed_buffer_t *); /* Indique le nombre d'octets de la charge utile d'un paquet. */ -size_t get_packed_buffer_payload_length(const packed_buffer *); +size_t get_packed_buffer_payload_length(const packed_buffer_t *); /* Détermine si des données sont disponibles en lecture. */ -bool has_more_data_in_packed_buffer(const packed_buffer *); +bool has_more_data_in_packed_buffer(const packed_buffer_t *); /* Ajoute des données à un paquet en amont à un envoi. */ -bool extend_packed_buffer(packed_buffer *, const void *, size_t, bool); +bool extend_packed_buffer(packed_buffer_t *, const void *, size_t, bool); /* Récupère des données depuis un paquet après une réception. */ -bool peek_packed_buffer(packed_buffer *, void *, size_t, bool); +bool peek_packed_buffer(packed_buffer_t *, void *, size_t, bool); /* Avance la tête de lecture dans les données d'un paquet. */ -void advance_packed_buffer(packed_buffer *, size_t); +void advance_packed_buffer(packed_buffer_t *, size_t); /* Récupère des données depuis un paquet après une réception. */ -bool extract_packed_buffer(packed_buffer *, void *, size_t, bool); +bool extract_packed_buffer(packed_buffer_t *, void *, size_t, bool); /* Lit des données depuis un flux local. */ -bool read_packed_buffer(packed_buffer *, int); +bool read_packed_buffer(packed_buffer_t *, int); /* Ecrit des données dans un flux local. */ -bool write_packed_buffer(packed_buffer *, int); +bool write_packed_buffer(packed_buffer_t *, int); /* Réceptionne des données depuis un flux réseau. */ -bool recv_packed_buffer(packed_buffer *, int); +bool recv_packed_buffer(packed_buffer_t *, int); /* Envoie des données au travers un flux réseau. */ -bool send_packed_buffer(packed_buffer *, int); +bool send_packed_buffer(packed_buffer_t *, int); /* Réceptionne des données depuis un flux réseau chiffré. */ -bool ssl_recv_packed_buffer(packed_buffer *, SSL *); +bool ssl_recv_packed_buffer(packed_buffer_t *, SSL *); /* Envoie des données au travers un flux réseau chiffré. */ -bool ssl_send_packed_buffer(packed_buffer *, SSL *); +bool ssl_send_packed_buffer(packed_buffer_t *, SSL *); diff --git a/tests/common/packed.py b/tests/common/packed.py new file mode 100644 index 0000000..25918d2 --- /dev/null +++ b/tests/common/packed.py @@ -0,0 +1,59 @@ + +# Tests pour valider les tampons de données + + +from chrysacase import ChrysalideTestCase +from pychrysalide.common import PackedBuffer + + +class TestPackedBuffers(ChrysalideTestCase): + """TestCase for common.PackedBuffer*""" + + def testPackedBufferConstructor(self): + """Validate new packed buffers.""" + + pbuf = PackedBuffer() + self.assertIsNotNone(pbuf) + + + def testPackedBufferData(self): + """Play with packed buffer data.""" + + pbuf = PackedBuffer() + + data = b'0123456789' + + pbuf.extend(data, False) + pbuf.extend(data) + + self.assertEqual(pbuf.payload_length, 2 * len(data)) + + self.assertFalse(pbuf.more_data) + + pbuf.rewind() + + self.assertTrue(pbuf.more_data) + + got = pbuf.peek(1) + self.assertEqual(got, b'0') + + got = pbuf.peek(2) + self.assertEqual(got, b'01') + + pbuf.advance(3) + + got = pbuf.peek(2) + self.assertEqual(got, b'34') + + pbuf.advance(8) + + got = pbuf.peek(2) + self.assertEqual(got, b'12') + + pbuf.rewind() + + got = pbuf.extract(4) + self.assertEqual(got, b'0123') + + got = pbuf.extract(8, True) + self.assertEqual(got, b'10987654') |