summaryrefslogtreecommitdiff
path: root/plugins/pychrysalide/glibext/comparable.c
diff options
context:
space:
mode:
authorCyrille Bagard <nocbos@gmail.com>2025-01-26 14:25:51 (GMT)
committerCyrille Bagard <nocbos@gmail.com>2025-01-26 14:25:51 (GMT)
commit56c148de74ed8c78ce54ed24daa83ec2f641e054 (patch)
treed4e43da9d6c729146c77fb30de8fa3767b257afb /plugins/pychrysalide/glibext/comparable.c
parentb1227a2779c9a72cab1295a1419a9c990df6488e (diff)
Define new interfaces for arch operands.
Diffstat (limited to 'plugins/pychrysalide/glibext/comparable.c')
-rw-r--r--plugins/pychrysalide/glibext/comparable.c309
1 files changed, 225 insertions, 84 deletions
diff --git a/plugins/pychrysalide/glibext/comparable.c b/plugins/pychrysalide/glibext/comparable.c
index 548f700..e4982d7 100644
--- a/plugins/pychrysalide/glibext/comparable.c
+++ b/plugins/pychrysalide/glibext/comparable.c
@@ -1,8 +1,8 @@
/* Chrysalide - Outil d'analyse de fichiers binaires
- * comparison.c - équivalent Python du fichier "glibext/comparison.h"
+ * comparable.c - équivalent Python du fichier "glibext/comparable.c"
*
- * Copyright (C) 2018-2019 Cyrille Bagard
+ * Copyright (C) 2025 Cyrille Bagard
*
* This file is part of Chrysalide.
*
@@ -22,38 +22,40 @@
*/
-#include "comparison.h"
+#include "comparable.h"
+#include <assert.h>
#include <pygobject.h>
-#include <glibext/comparison-int.h>
+#include <glibext/comparable-int.h>
-#include "constants.h"
#include "../access.h"
#include "../helpers.h"
-#include "../analysis/content.h"
/* ------------------------ GLUE POUR CREATION DEPUIS PYTHON ------------------------ */
-/* Procède à l'initialisation de l'interface de comparaison. */
-static void py_comparable_item_interface_init(GComparableItemIface *, gpointer *);
+/* Procède à l'initialisation de l'interface de détermination. */
+static void py_comparable_object_interface_init(GComparableObjectInterface *, gpointer *);
-/* Réalise une comparaison entre objets selon un critère précis. */
-static bool py_comparable_item_compare_rich(const GComparableItem *, const GComparableItem *, RichCmpOperation, bool *);
+/* Réalise une comparaison étendue entre objets. */
+static int py_comparable_object_compare_wrapper(const GComparableObject *, const GComparableObject *);
/* ------------------------- CONNEXION AVEC L'API DE PYTHON ------------------------- */
-/* Effectue une comparaison avec un objet 'ComparableItem'. */
-static PyObject *py_comparable_item_richcompare(PyObject *, PyObject *, int);
+/* Transmet le statut d'une comparaison effectuée par le parent. */
+static PyObject *py_comparable_object_parent_compare(PyObject *, PyObject *);
+
+/* Effectue une comparaison avec un objet 'ComparableObject'. */
+static PyObject *py_comparable_object_richcompare(PyObject *, PyObject *, int);
@@ -67,7 +69,7 @@ static PyObject *py_comparable_item_richcompare(PyObject *, PyObject *, int);
* Paramètres : iface = interface GLib à initialiser. *
* unused = adresse non utilisée ici. *
* *
-* Description : Procède à l'initialisation de l'interface de comparaison. *
+* Description : Procède à l'initialisation de l'interface de détermination. *
* *
* Retour : - *
* *
@@ -75,72 +77,88 @@ static PyObject *py_comparable_item_richcompare(PyObject *, PyObject *, int);
* *
******************************************************************************/
-static void py_comparable_item_interface_init(GComparableItemIface *iface, gpointer *unused)
+static void py_comparable_object_interface_init(GComparableObjectInterface *iface, gpointer *unused)
{
-
-#define COMPARABLE_ITEM_DOC \
- "ComparableItem provides an interface to compare objects.\n" \
+#define COMPARABLE_OBJECT_DOC \
+ "The ComparableObject class provides an interface to compare" \
+ " objects.\n" \
"\n" \
"A typical class declaration for a new implementation looks like:\n" \
"\n" \
- " class NewImplem(GObject.Object, ComparableItem):\n" \
+ " class NewImplem(GObject.Object, ComparableObject):\n" \
" ...\n" \
- "\n"
+ "\n" \
+ "The following method has to be defined for new implementations:\n" \
+ "* pychrysalide.glibext.ComparableObject._compare().\n"
- iface->cmp_rich = py_comparable_item_compare_rich;
+ iface->compare = py_comparable_object_compare_wrapper;
}
/******************************************************************************
* *
-* Paramètres : item = premier objet à cnsulter pour une comparaison. *
-* other = second objet à cnsulter pour une comparaison. *
-* op = opération de comparaison à réaliser. *
-* status = bilan des opérations de comparaison. [OUT] *
+* Paramètres : object = premier objet à consulter pour une comparaison. *
+* other = second objet à consulter pour une comparaison. *
* *
-* Description : Réalise une comparaison entre objets selon un critère précis.*
+* Description : Réalise une comparaison étendue entre objets. *
* *
-* Retour : true si la comparaison a pu être effectuée, false sinon. *
+* Retour : Bilan de la comparaison. *
* *
* Remarques : - *
* *
******************************************************************************/
-static bool py_comparable_item_compare_rich(const GComparableItem *item, const GComparableItem *other, RichCmpOperation op, bool *status)
+static int py_comparable_object_compare_wrapper(const GComparableObject *object, const GComparableObject *other)
{
- bool result; /* Etat à retourner */
+ int result; /* Bilan à retourner */
PyGILState_STATE gstate; /* Sauvegarde d'environnement */
- PyObject *pyitem; /* Objet Python concerné #1 */
- PyObject *pyother; /* Objet Python concerné #2 */
+ PyObject *pyobj; /* Objet Python concerné */
+ PyObject *args; /* Arguments pour l'appel */
PyObject *pyret; /* Bilan de consultation */
- int ret; /* Bilan d'une conversion */
- result = false;
+#define COMPARABLE_OBJECT_COMPARE_WRAPPER PYTHON_WRAPPER_DEF \
+( \
+ _compare, "$self, other", \
+ METH_VARARGS, \
+ "Abstract method allowing to compare two objects implementing" \
+ " the interface. This method is used to handle rich comparisons"\
+ " automatically.\n" \
+ "\n" \
+ "The result has to be an integer lesser than, equal to, or" \
+ " greater than zero if *self* is found, respectively, to be" \
+ " lesser than, to match, or to be greater than *other*.\n" \
+ "\n" \
+ "A *TypeError* exception is raised if the return value is not" \
+ " an integer." \
+)
+
+ result = 0;
gstate = PyGILState_Ensure();
- pyitem = pygobject_new(G_OBJECT(item));
- pyother = pygobject_new(G_OBJECT(other));
+ pyobj = pygobject_new(G_OBJECT(object));
- pyret = PyObject_RichCompare(pyitem, pyother, op);
+ args = PyTuple_New(1);
+ PyTuple_SetItem(args, 0, pygobject_new(G_OBJECT(other)));
+
+ pyret = run_python_method(pyobj, "_compare", args);
if (pyret != NULL)
{
- ret = PyBool_Check(pyret);
-
- if (ret)
- {
- *status = (pyret == Py_True);
- result = true;
- }
+ if (PyLong_Check(pyret))
+ result = PyLong_AsLong(pyret);
- Py_DECREF(pyret);
+ else
+ PyErr_SetString(PyExc_TypeError, _("comparison status has to be a signed integer"));
}
- Py_DECREF(pyother);
- Py_DECREF(pyitem);
+ Py_XDECREF(pyret);
+
+ Py_DECREF(args);
+
+ Py_DECREF(pyobj);
PyGILState_Release(gstate);
@@ -157,11 +175,87 @@ static bool py_comparable_item_compare_rich(const GComparableItem *item, const G
/******************************************************************************
* *
+* Paramètres : self = objet dont l'instance se veut unique. *
+* args = adresse non utilisée ici. *
+* *
+* Description : Transmet le statut d'une comparaison effectuée par le parent.*
+* *
+* Retour : Bilan de la comparaison. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static PyObject *py_comparable_object_parent_compare(PyObject *self, PyObject *args)
+{
+ PyObject *result; /* Valeur à retourner */
+ GComparableObject *other; /* Second objet à comparer */
+ int ret; /* Bilan de lecture des args. */
+ GComparableObject *object; /* Mécanismes natifs */
+ GComparableObjectInterface *iface; /* Interface utilisée */
+ GComparableObjectInterface *parent_iface; /* Interface parente */
+ int status; /* Bilan d'une comparaison */
+
+#define COMPARABLE_OBJECT_PARENT_COMPARE_METHOD PYTHON_METHOD_DEF \
+( \
+ parent_compare, "$sel, otherf", \
+ METH_VARARGS, py_comparable_object, \
+ "Provide the comparison status defined by the interface" \
+ " implementation from the object native parent.\n" \
+ "\n" \
+ "The result is a signed integer.\n" \
+ "\n" \
+ "A *TypeError* exception is raised if the object parent does" \
+ " not implement the pychrysalide.glibext.ComparableObject" \
+ " interface.\n" \
+ "\n" \
+ "A *RuntimeError* exception is raised if the direct parent type"\
+ " of the object has not a native implementation. For Python" \
+ " implementations, the super()._compare() function has to be" \
+ " used instead." \
+)
+
+ if (!check_for_native_parent(self))
+ return NULL;
+
+ ret = PyArg_ParseTuple(args, "O&", convert_to_comparable_object, &other);
+ if (!ret) return NULL;
+
+ object = G_COMPARABLE_OBJECT(pygobject_get(self));
+
+ iface = G_COMPARABLE_OBJECT_GET_IFACE(object);
+
+ parent_iface = g_type_interface_peek_parent(iface);
+
+ if (parent_iface == NULL)
+ {
+ PyErr_SetString(PyExc_TypeError, _("object parent does not implement the ComparableObject interface"));
+
+ result = NULL;
+
+ }
+ else
+ {
+ status = parent_iface->compare(object, other);
+
+ result = PyLong_FromLong(status);
+
+ CLEAN_RESULT_IF_RAISED_EXCEPTION(result);
+
+ }
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
* Paramètres : a = premier object Python à consulter. *
* b = second object Python à consulter. *
* op = type de comparaison menée. *
* *
-* Description : Effectue une comparaison avec un objet 'ComparableItem'. *
+* Description : Effectue une comparaison avec un objet 'ComparableObject'. *
* *
* Retour : Bilan de l'opération. *
* *
@@ -169,41 +263,71 @@ static bool py_comparable_item_compare_rich(const GComparableItem *item, const G
* *
******************************************************************************/
-static PyObject *py_comparable_item_richcompare(PyObject *a, PyObject *b, int op)
+static PyObject *py_comparable_object_richcompare(PyObject *a, PyObject *b, int op)
{
PyObject *result; /* Bilan à retourner */
int ret; /* Bilan de lecture des args. */
- GComparableItem *item_a; /* Instance à manipuler #1 */
- GComparableItem *item_b; /* Instance à manipuler #2 */
- bool valid; /* Indication de validité */
- bool status; /* Résultat d'une comparaison */
+ GComparableObject *obj_a; /* Instance à manipuler #1 */
+ GComparableObject *obj_b; /* Instance à manipuler #2 */
+ int status; /* Bilan d'une comparaison */
- ret = PyObject_IsInstance(b, (PyObject *)get_python_comparable_item_type());
+ ret = PyObject_IsInstance(b, (PyObject *)get_python_comparable_object_type());
if (!ret)
{
result = Py_NotImplemented;
goto cmp_done;
}
- item_a = G_COMPARABLE_ITEM(pygobject_get(a));
- item_b = G_COMPARABLE_ITEM(pygobject_get(b));
+ obj_a = G_COMPARABLE_OBJECT(pygobject_get(a));
+ obj_b = G_COMPARABLE_OBJECT(pygobject_get(b));
- valid = g_comparable_item_compare_rich(item_a, item_b, op, &status);
+ status = g_comparable_object_compare(obj_a, obj_b);
- if (valid)
- result = status ? Py_True : Py_False;
- else
- result = Py_NotImplemented;
+ switch (op)
+ {
+ case Py_LT:
+ result = (status < 0 ? Py_True : Py_False);
+ break;
+
+ case Py_LE:
+ result = (status <= 0 ? Py_True : Py_False);
+ break;
+
+ case Py_EQ:
+ result = (status == 0 ? Py_True : Py_False);
+ break;
+
+ case Py_NE:
+ result = (status != 0 ? Py_True : Py_False);
+ break;
+
+ case Py_GT:
+ result = (status > 0 ? Py_True : Py_False);
+ break;
+
+ case Py_GE:
+ result = (status >= 0 ? Py_True : Py_False);
+ break;
+
+ default:
+ assert(false);
+ result = Py_NotImplemented;
+ break;
+
+ }
cmp_done:
Py_INCREF(result);
+ CLEAN_RESULT_IF_RAISED_EXCEPTION(result);
+
return result;
}
+
/******************************************************************************
* *
* Paramètres : - *
@@ -216,44 +340,64 @@ static PyObject *py_comparable_item_richcompare(PyObject *a, PyObject *b, int op
* *
******************************************************************************/
-PyTypeObject *get_python_comparable_item_type(void)
+PyTypeObject *get_python_comparable_object_type(void)
{
- static PyMethodDef py_comparable_item_methods[] = {
+ static PyMethodDef py_comparable_object_methods[] = {
+ COMPARABLE_OBJECT_COMPARE_WRAPPER,
+ COMPARABLE_OBJECT_PARENT_COMPARE_METHOD,
{ NULL }
};
- static PyGetSetDef py_comparable_item_getseters[] = {
+ static PyGetSetDef py_comparable_object_getseters[] = {
{ NULL }
};
- static PyTypeObject py_comparable_item_type = {
+ static PyTypeObject py_comparable_object_type = {
PyVarObject_HEAD_INIT(NULL, 0)
- .tp_name = "pychrysalide.glibext.ComparableItem",
+ .tp_name = "pychrysalide.glibext.ComparableObject",
.tp_basicsize = sizeof(PyObject),
+ /**
+ * Une valeur de .tp_richcompare non nulle écarte la définition du
+ * champ .tp_hash à la valeur par défaut du type PyBaseObject_Type
+ * dans les préparatifs de la fonction Python inherit_slots().
+ *
+ * Ces préparatifs se poursuivent avec type_ready_set_hash(),
+ * qui initialise .tp_hash avec PyObject_HashNotImplemented(),
+ * qui n'est donc pas un comportement par défaut.
+ *
+ * Côté PyGObject, la fonction pygobject_inherit_slots() y voit
+ * une implémentation de .tp_hash personnalisée, ce qui bloque
+ * la défintion d'autres personnalisations, comme celle de
+ * l'interface HashableObject.
+ *
+ * La valeur nominale nulle est ainsi écartée au préalable ici.
+ */
+ .tp_hash = (hashfunc)_Py_HashPointer,
+
.tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
- .tp_doc = COMPARABLE_ITEM_DOC,
+ .tp_doc = COMPARABLE_OBJECT_DOC,
- .tp_richcompare = py_comparable_item_richcompare,
+ .tp_richcompare = py_comparable_object_richcompare,
- .tp_methods = py_comparable_item_methods,
- .tp_getset = py_comparable_item_getseters,
+ .tp_methods = py_comparable_object_methods,
+ .tp_getset = py_comparable_object_getseters
};
- return &py_comparable_item_type;
+ return &py_comparable_object_type;
}
/******************************************************************************
* *
-* Paramètres : module = module dont la définition est à compléter. *
+* Paramètres : - *
* *
-* Description : Prend en charge l'objet 'pychrysalide.....ComparableItem'. *
+* Description : Prend en charge l'objet 'pychrysalide.....ComparableObject'. *
* *
* Retour : Bilan de l'opération. *
* *
@@ -261,21 +405,21 @@ PyTypeObject *get_python_comparable_item_type(void)
* *
******************************************************************************/
-bool ensure_python_comparable_item_is_registered(void)
+bool ensure_python_comparable_object_is_registered(void)
{
- PyTypeObject *type; /* Type Python 'ComparableItem' */
+ PyTypeObject *type; /* Type 'ComparableObject' */
PyObject *module; /* Module à recompléter */
PyObject *dict; /* Dictionnaire du module */
static GInterfaceInfo info = { /* Paramètres d'inscription */
- .interface_init = (GInterfaceInitFunc)py_comparable_item_interface_init,
+ .interface_init = (GInterfaceInitFunc)py_comparable_object_interface_init,
.interface_finalize = NULL,
.interface_data = NULL,
};
- type = get_python_comparable_item_type();
+ type = get_python_comparable_object_type();
if (!PyType_HasFeature(type, Py_TPFLAGS_READY))
{
@@ -283,10 +427,7 @@ bool ensure_python_comparable_item_is_registered(void)
dict = PyModule_GetDict(module);
- if (!register_interface_for_pygobject(dict, G_TYPE_COMPARABLE_ITEM, type, &info))
- return false;
-
- if (!define_comparable_item_constants(type))
+ if (!register_interface_for_pygobject(dict, G_TYPE_COMPARABLE_OBJECT, type, &info))
return false;
}
@@ -301,7 +442,7 @@ bool ensure_python_comparable_item_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 élément comparable. *
+* Description : Tente de convertir en interface d'objet comparable. *
* *
* Retour : Bilan de l'opération, voire indications supplémentaires. *
* *
@@ -309,11 +450,11 @@ bool ensure_python_comparable_item_is_registered(void)
* *
******************************************************************************/
-int convert_to_comparable_item(PyObject *arg, void *dst)
+int convert_to_comparable_object(PyObject *arg, void *dst)
{
int result; /* Bilan à retourner */
- result = PyObject_IsInstance(arg, (PyObject *)get_python_comparable_item_type());
+ result = PyObject_IsInstance(arg, (PyObject *)get_python_comparable_object_type());
switch (result)
{
@@ -323,11 +464,11 @@ int convert_to_comparable_item(PyObject *arg, void *dst)
break;
case 0:
- PyErr_SetString(PyExc_TypeError, "unable to convert the provided argument to comparable item");
+ PyErr_SetString(PyExc_TypeError, "unable to convert the provided argument to comparable object");
break;
case 1:
- *((GComparableItem **)dst) = G_COMPARABLE_ITEM(pygobject_get(arg));
+ *((GComparableObject **)dst) = G_COMPARABLE_OBJECT(pygobject_get(arg));
break;
default: