diff options
Diffstat (limited to 'plugins/pychrysalide/common')
-rw-r--r-- | plugins/pychrysalide/common/Makefile.am | 26 | ||||
-rw-r--r-- | plugins/pychrysalide/common/bits.c | 301 | ||||
-rw-r--r-- | plugins/pychrysalide/common/bits.h | 3 | ||||
-rw-r--r-- | plugins/pychrysalide/common/itoa.c | 124 | ||||
-rw-r--r-- | plugins/pychrysalide/common/itoa.h | 39 | ||||
-rw-r--r-- | plugins/pychrysalide/common/module.c | 2 |
6 files changed, 480 insertions, 15 deletions
diff --git a/plugins/pychrysalide/common/Makefile.am b/plugins/pychrysalide/common/Makefile.am index 3f1b0b6..b5249b9 100644 --- a/plugins/pychrysalide/common/Makefile.am +++ b/plugins/pychrysalide/common/Makefile.am @@ -1,25 +1,21 @@ noinst_LTLIBRARIES = libpychrysacommon.la -libpychrysacommon_la_SOURCES = \ - bits.h bits.c \ - fnv1a.h fnv1a.c \ - hex.h hex.c \ - leb128.h leb128.c \ - module.h module.c \ - packed.h packed.c \ - pathname.h pathname.c \ +libpychrysacommon_la_SOURCES = \ + bits.h bits.c \ + fnv1a.h fnv1a.c \ + hex.h hex.c \ + itoa.h itoa.c \ + leb128.h leb128.c \ + module.h module.c \ + packed.h packed.c \ + pathname.h pathname.c \ pearson.h pearson.c -libpychrysacommon_la_LDFLAGS = +libpychrysacommon_la_CFLAGS = $(TOOLKIT_CFLAGS) $(LIBXML_CFLAGS) $(LIBPYTHON_INTERPRETER_CFLAGS) $(LIBPYGOBJECT_CFLAGS) \ + -I$(top_srcdir)/src -DNO_IMPORT_PYGOBJECT devdir = $(includedir)/chrysalide/$(subdir) dev_HEADERS = $(libpychrysacommon_la_SOURCES:%c=) - - -AM_CPPFLAGS = $(LIBGTK_CFLAGS) $(LIBXML_CFLAGS) $(LIBPYTHON_INTERPRETER_CFLAGS) $(LIBPYGOBJECT_CFLAGS) \ - -I$(top_srcdir)/src -DNO_IMPORT_PYGOBJECT - -AM_CFLAGS = $(DEBUG_CFLAGS) $(WARNING_FLAGS) $(COMPLIANCE_FLAGS) diff --git a/plugins/pychrysalide/common/bits.c b/plugins/pychrysalide/common/bits.c index 73fd55b..a127251 100644 --- a/plugins/pychrysalide/common/bits.c +++ b/plugins/pychrysalide/common/bits.c @@ -65,6 +65,9 @@ static PyObject *py_bitfield_richcompare(PyObject *, PyObject *, int); /* Crée une copie d'un champ de bits classique. */ static PyObject *py_bitfield_dup(PyObject *, PyObject *); +/* Redimensionne un champ de bits. */ +static PyObject *py_bitfield_resize(PyObject *, PyObject *); + /* Bascule à 0 un champ de bits dans son intégralité. */ static PyObject *py_bitfield_reset_all(PyObject *, PyObject *); @@ -77,6 +80,9 @@ static PyObject *py_bitfield_reset(PyObject *, PyObject *); /* Bascule à 1 une partie d'un champ de bits. */ static PyObject *py_bitfield_set(PyObject *, PyObject *); +/* Réalise une opération OU logique entre deux champs de bits. */ +static PyObject *py_bitfield_or_at(PyObject *, PyObject *); + /* Détermine si un bit est à 1 dans un champ de bits. */ static PyObject *py_bitfield_test(PyObject *, PyObject *); @@ -86,6 +92,15 @@ static PyObject *py_bitfield_test_none(PyObject *, PyObject *); /* Détermine si un ensemble de bits est à 1 dans un champ. */ static PyObject *py_bitfield_test_all(PyObject *, PyObject *); +/* Teste l'état à 0 de bits selon un masque de bits. */ +static PyObject *py_bitfield_test_zeros_with(PyObject *, PyObject *); + +/* Teste l'état à 1 de bits selon un masque de bits. */ +static PyObject *py_bitfield_test_ones_with(PyObject *, PyObject *); + +/* Recherche un prochain bit défini dans un champ de bits. */ +static PyObject *py_bitfield_find_next_set(PyObject *, PyObject *); + /* Indique la taille d'un champ de bits donné. */ static PyObject *py_bitfield_get_size(PyObject *, void *); @@ -399,6 +414,47 @@ static PyObject *py_bitfield_dup(PyObject *self, PyObject *args) /****************************************************************************** * * +* Paramètres : self = champ de bits à dupliquer. * +* args = non utilisé ici. * +* * +* Description : Redimensionne un champ de bits. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static PyObject *py_bitfield_resize(PyObject *self, PyObject *args) +{ + unsigned long length; /* Nouvelle taille à respecter */ + int ret; /* Bilan de lecture des args. */ + py_bitfield_t *bf; /* Instance à manipuler */ + +#define BITFIELD_RESIZE_METHOD PYTHON_METHOD_DEF \ +( \ + resize, "$self, length, /", \ + METH_VARARGS, py_bitfield, \ + "Resize a bitfield and fix its new size to *length*.\n" \ + "\n" \ + "The new bits get initialized to the same state used at the" \ + " bitfield creation." \ +) + + ret = PyArg_ParseTuple(args, "k", &length); + if (!ret) return NULL; + + bf = (py_bitfield_t *)self; + + resize_bit_field(&bf->native, length); + + Py_RETURN_NONE; + +} + + +/****************************************************************************** +* * * Paramètres : self = champ de bits à modifier. * * args = non utilisé ici. * * * @@ -552,6 +608,49 @@ static PyObject *py_bitfield_set(PyObject *self, PyObject *args) * Paramètres : self = champ de bits à consulter. * * args = arguments fournis pour la conduite de l'opération. * * * +* Description : Réalise une opération OU logique entre deux champs de bits. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static PyObject *py_bitfield_or_at(PyObject *self, PyObject *args) +{ + bitfield_t *src; /* Seconde champ de bits */ + unsigned long first; /* Indice du premier bit testé */ + int ret; /* Bilan de lecture des args. */ + py_bitfield_t *bf; /* Instance à manipuler */ + +#define BITFIELD_OR_AT_METHOD PYTHON_METHOD_DEF \ +( \ + or_at, "$self, src, first, /", \ + METH_VARARGS, py_bitfield, \ + "Perform an OR operation with another bitfield.\n" \ + "\n" \ + "The *src* argument is expected to be another" \ + " pychrysalide.common.BitField instance. The area to" \ + " process starts at bit *first* from *src*." \ +) + + ret = PyArg_ParseTuple(args, "O&k", convert_to_bitfield, &src, &first); + if (!ret) return NULL; + + bf = (py_bitfield_t *)self; + + or_bit_field_at(bf->native, src, first); + + Py_RETURN_NONE; + +} + + +/****************************************************************************** +* * +* Paramètres : self = champ de bits à consulter. * +* args = arguments fournis pour la conduite de l'opération. * +* * * Description : Détermine si un bit est à 1 dans un champ de bits. * * * * Retour : true si le bit correspondant est à l'état haut. * @@ -695,6 +794,158 @@ static PyObject *py_bitfield_test_all(PyObject *self, PyObject *args) /****************************************************************************** * * +* Paramètres : self = champ de bits à consulter. * +* args = arguments fournis pour la conduite de l'opération. * +* * +* Description : Teste l'état à 0 de bits selon un masque de bits. * +* * +* Retour : true si les bits visés sont à l'état bas. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static PyObject *py_bitfield_test_zeros_with(PyObject *self, PyObject *args) +{ + PyObject *result; /* Bilan à faire remonter */ + unsigned long first; /* Indice du premier bit testé */ + bitfield_t *mask; /* Champ de bits natif */ + int ret; /* Bilan de lecture des args. */ + py_bitfield_t *bf; /* Instance à manipuler */ + bool status; /* Bilan d'analyse */ + +#define BITFIELD_TEST_ZEROS_WITH_METHOD PYTHON_METHOD_DEF \ +( \ + test_zeros_with, "$self, first, mask, /", \ + METH_VARARGS, py_bitfield, \ + "Test a range of bits against another bit field.\n" \ + "\n" \ + "The area to process starts at bit *first* and the" \ + " test relies on bits set within the *mask* object.\n" \ + "\n" \ + "The result is a boolean value: True if all tested" \ + " bits are unset, False otherwise." \ +) + + ret = PyArg_ParseTuple(args, "kO&", &first, convert_to_bitfield, &mask); + if (!ret) return NULL; + + bf = (py_bitfield_t *)self; + + status = test_zeros_within_bit_field(bf->native, first, mask); + + result = status ? Py_True : Py_False; + Py_INCREF(result); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : self = champ de bits à consulter. * +* args = arguments fournis pour la conduite de l'opération. * +* * +* Description : Teste l'état à 1 de bits selon un masque de bits. * +* * +* Retour : true si les bits visés sont à l'état haut. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static PyObject *py_bitfield_test_ones_with(PyObject *self, PyObject *args) +{ + PyObject *result; /* Bilan à faire remonter */ + unsigned long first; /* Indice du premier bit testé */ + bitfield_t *mask; /* Champ de bits natif */ + int ret; /* Bilan de lecture des args. */ + py_bitfield_t *bf; /* Instance à manipuler */ + bool status; /* Bilan d'analyse */ + +#define BITFIELD_TEST_ONES_WITH_METHOD PYTHON_METHOD_DEF \ +( \ + test_ones_with, "$self, first, mask, /", \ + METH_VARARGS, py_bitfield, \ + "Test a range of bits against another bit field.\n" \ + "\n" \ + "The area to process starts at bit *first* and the" \ + " test relies on bits set within the *mask* object.\n" \ + "\n" \ + "The result is a boolean value: True if all tested" \ + " bits are set, False otherwise." \ +) + + ret = PyArg_ParseTuple(args, "kO&", &first, convert_to_bitfield, &mask); + if (!ret) return NULL; + + bf = (py_bitfield_t *)self; + + status = test_ones_within_bit_field(bf->native, first, mask); + + result = status ? Py_True : Py_False; + Py_INCREF(result); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : self = champ de bits à consulter. * +* args = arguments fournis pour la conduite de l'opération. * +* * +* Description : Recherche un prochain bit défini dans un champ de bits. * +* * +* Retour : Position d'un bit à 1 ou taille du champ si plus aucun. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static PyObject *py_bitfield_find_next_set(PyObject *self, PyObject *args) +{ + PyObject *result; /* Bilan à faire remonter */ + unsigned long prev; /* Indice d'un bit à écarter */ + int ret; /* Bilan de lecture des args. */ + py_bitfield_t *bf; /* Instance à manipuler */ + size_t found; /* Indice de bit trouvé */ + +#define BITFIELD_FIND_NEXT_SET_METHOD PYTHON_METHOD_DEF \ +( \ + find_next_set, "$self, /, prev=None", \ + METH_VARARGS, py_bitfield, \ + "Find the index of the next set bit in the bit field.\n"\ + "\n" \ + "If provided, the *prev* argument is the position of" \ + " a previously found bit, which gets discarded for the" \ + " current call.\n" \ + "\n" \ + "The result is a integer value: a valid index inside" \ + " the bit field, or the bit field size if no set bit" \ + " is found." \ +) + + prev = (unsigned long)-1; + + ret = PyArg_ParseTuple(args, "|k", &prev); + if (!ret) return NULL; + + bf = (py_bitfield_t *)self; + + found = find_next_set_in_bit_field(bf->native, prev == (unsigned long)-1 ? NULL : (size_t []) { prev }); + + result = PyLong_FromSize_t(found); + + return result; + +} + + +/****************************************************************************** +* * * Paramètres : self = classe représentant une instruction. * * closure = adresse non utilisée ici. * * * @@ -791,13 +1042,18 @@ PyTypeObject *get_python_bitfield_type(void) static PyMethodDef py_bitfield_methods[] = { BITFIELD_DUP_METHOD, + BITFIELD_RESIZE_METHOD, BITFIELD_RESET_ALL_METHOD, BITFIELD_SET_ALL_METHOD, BITFIELD_RESET_METHOD, BITFIELD_SET_METHOD, + BITFIELD_OR_AT_METHOD, BITFIELD_TEST_METHOD, BITFIELD_TEST_NONE_METHOD, BITFIELD_TEST_ALL_METHOD, + BITFIELD_TEST_ZEROS_WITH_METHOD, + BITFIELD_TEST_ONES_WITH_METHOD, + BITFIELD_FIND_NEXT_SET_METHOD, { NULL } }; @@ -876,6 +1132,51 @@ bool ensure_python_bitfield_is_registered(void) /****************************************************************************** * * +* 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 champ de bits. * +* * +* Retour : Bilan de l'opération, voire indications supplémentaires. * +* * +* Remarques : - * +* * +******************************************************************************/ + +int convert_to_bitfield(PyObject *arg, void *dst) +{ + int result; /* Bilan à retourner */ + + result = PyObject_IsInstance(arg, (PyObject *)get_python_bitfield_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 bit field"); + break; + + case 1: + *((bitfield_t **)dst) = ((py_bitfield_t *)arg)->native; + break; + + default: + assert(false); + break; + + } + + return result; + +} + + +/****************************************************************************** +* * * Paramètres : field = structure interne à copier en objet Python. * * * * Description : Convertit une structure de type 'bitfield_t' en objet Python.* diff --git a/plugins/pychrysalide/common/bits.h b/plugins/pychrysalide/common/bits.h index 6ddaaa5..804c3b5 100644 --- a/plugins/pychrysalide/common/bits.h +++ b/plugins/pychrysalide/common/bits.h @@ -40,6 +40,9 @@ PyTypeObject *get_python_bitfield_type(void); /* Prend en charge l'objet 'pychrysalide.common.BitField'. */ bool ensure_python_bitfield_is_registered(void); +/* Tente de convertir en champ de bits. */ +int convert_to_bitfield(PyObject *, void *); + /* Convertit une structure de type 'bitfield_t' en objet Python. */ PyObject *build_from_internal_bitfield(const bitfield_t *); diff --git a/plugins/pychrysalide/common/itoa.c b/plugins/pychrysalide/common/itoa.c new file mode 100644 index 0000000..107b047 --- /dev/null +++ b/plugins/pychrysalide/common/itoa.c @@ -0,0 +1,124 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * itoa.c - équivalent Python du fichier "common/itoa.c" + * + * Copyright (C) 2023 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 "itoa.h" + + +#include <common/itoa.h> + + +#include "../access.h" +#include "../helpers.h" + + + +/* Détermine l'empreinte Itoa d'une chaîne de caractères. */ +static PyObject *py_itoa(PyObject *, PyObject *); + + + +/****************************************************************************** +* * +* Paramètres : self = NULL car méthode statique. * +* args = arguments fournis lors de l'appel à la fonction. * +* * +* Description : Convertit une valeur en une forme textuelle. * +* * +* Retour : Chaîne de caractères mises en place. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static PyObject *py_itoa(PyObject *self, PyObject *args) +{ + PyObject *result; /* Instance à retourner */ + long long n; /* Valeur à transformer */ + unsigned char base; /* Base de travail */ + int ret; /* Bilan de lecture des args. */ + char *strval; /* Valeur sous forme de chaîne */ + +#define ITOA_METHOD PYTHON_METHOD_DEF \ +( \ + itoa, "n, /, base=10", \ + METH_VARARGS, py, \ + "Construct a string representation of an integer *n* according" \ + " to a given *base*.\n" \ + "\n" \ + "Both arguments are expected to be integer values; the result" \ + " is a string or None in case of failure." \ +) + + base = 10; + + ret = PyArg_ParseTuple(args, "L|b", &n, &base); + if (!ret) return NULL; + + strval = itoa(n, base); + + if (strval != NULL) + { + result = PyUnicode_FromString(strval); + free(strval); + } + else + { + result = Py_None; + Py_INCREF(result); + } + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : - * +* * +* Description : Définit une extension du module 'common' à compléter. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool populate_common_module_with_itoa(void) +{ + bool result; /* Bilan à retourner */ + PyObject *module; /* Module à recompléter */ + + static PyMethodDef py_itoa_methods[] = { + ITOA_METHOD, + { NULL } + }; + + module = get_access_to_python_module("pychrysalide.common"); + + result = register_python_module_methods(module, py_itoa_methods); + + return result; + +} diff --git a/plugins/pychrysalide/common/itoa.h b/plugins/pychrysalide/common/itoa.h new file mode 100644 index 0000000..a66e767 --- /dev/null +++ b/plugins/pychrysalide/common/itoa.h @@ -0,0 +1,39 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * itoa.h - prototypes pour l'équivalent Python du fichier "common/itoa.c" + * + * Copyright (C) 2023 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_ITOA_H +#define _PLUGINS_PYCHRYSALIDE_COMMON_ITOA_H + + +#include <Python.h> +#include <stdbool.h> + + + +/* Définit une extension du module 'common' à compléter. */ +bool populate_common_module_with_itoa(void); + + + +#endif /* _PLUGINS_PYCHRYSALIDE_COMMON_ITOA_H */ diff --git a/plugins/pychrysalide/common/module.c b/plugins/pychrysalide/common/module.c index 6ced1b7..a0042ee 100644 --- a/plugins/pychrysalide/common/module.c +++ b/plugins/pychrysalide/common/module.c @@ -28,6 +28,7 @@ #include "bits.h" #include "fnv1a.h" #include "hex.h" +#include "itoa.h" #include "leb128.h" #include "packed.h" #include "pathname.h" @@ -99,6 +100,7 @@ bool populate_common_module(void) if (result) result = populate_common_module_with_fnv1a(); if (result) result = populate_common_module_with_hex(); + if (result) result = populate_common_module_with_itoa(); if (result) result = populate_common_module_with_leb128(); if (result) result = populate_common_module_with_pathname(); if (result) result = populate_common_module_with_pearson(); |