summaryrefslogtreecommitdiff
path: root/plugins/pychrysalide/glibext
diff options
context:
space:
mode:
Diffstat (limited to 'plugins/pychrysalide/glibext')
-rw-r--r--plugins/pychrysalide/glibext/Makefile.am41
-rw-r--r--plugins/pychrysalide/glibext/binarycursor.c2
-rw-r--r--plugins/pychrysalide/glibext/binportion.c4
-rw-r--r--plugins/pychrysalide/glibext/buffercache.c16
-rw-r--r--plugins/pychrysalide/glibext/bufferline.c4
-rw-r--r--plugins/pychrysalide/glibext/bufferview.c2
-rw-r--r--plugins/pychrysalide/glibext/comparison.c341
-rw-r--r--plugins/pychrysalide/glibext/comparison.h45
-rw-r--r--plugins/pychrysalide/glibext/configuration.c8
-rw-r--r--plugins/pychrysalide/glibext/constants.c53
-rw-r--r--plugins/pychrysalide/glibext/constants.h7
-rw-r--r--plugins/pychrysalide/glibext/linecursor.c2
-rw-r--r--plugins/pychrysalide/glibext/module.c10
-rw-r--r--plugins/pychrysalide/glibext/singleton.c1165
-rw-r--r--plugins/pychrysalide/glibext/singleton.h62
15 files changed, 1729 insertions, 33 deletions
diff --git a/plugins/pychrysalide/glibext/Makefile.am b/plugins/pychrysalide/glibext/Makefile.am
index 179a991..2ed2aa5 100644
--- a/plugins/pychrysalide/glibext/Makefile.am
+++ b/plugins/pychrysalide/glibext/Makefile.am
@@ -1,29 +1,32 @@
noinst_LTLIBRARIES = libpychrysaglibext.la
-libpychrysaglibext_la_SOURCES = \
- constants.h constants.c \
- binarycursor.h binarycursor.c \
- binportion.h binportion.c \
- buffercache.h buffercache.c \
- bufferline.h bufferline.c \
- bufferview.h bufferview.c \
- configuration.h configuration.c \
- linecursor.h linecursor.c \
- linegen.h linegen.c \
- loadedpanel.h loadedpanel.c \
- module.h module.c \
+libpychrysaglibext_la_SOURCES = \
+ constants.h constants.c \
+ binarycursor.h binarycursor.c \
+ binportion.h binportion.c \
+ buffercache.h buffercache.c \
+ bufferline.h bufferline.c \
+ comparison.h comparison.c \
+ configuration.h configuration.c \
+ linecursor.h linecursor.c \
+ linegen.h linegen.c \
+ module.h module.c \
+ singleton.h singleton.c
+
+if BUILD_GTK_SUPPORT
+
+libpychrysaglibext_la_SOURCES += \
+ bufferview.h bufferview.c \
+ loadedpanel.h loadedpanel.c \
named.h named.c
-libpychrysaglibext_la_LDFLAGS =
+endif
+
+libpychrysaglibext_la_CFLAGS = $(TOOLKIT_CFLAGS) $(LIBXML_CFLAGS) $(LIBPYTHON_INTERPRETER_CFLAGS) $(LIBPYGOBJECT_CFLAGS) \
+ -I$(top_srcdir)/src -DNO_IMPORT_PYGOBJECT
devdir = $(includedir)/chrysalide/$(subdir)
dev_HEADERS = $(libpychrysaglibext_la_SOURCES:%c=)
-
-
-AM_CPPFLAGS = $(LIBGTK_CFLAGS) $(LIBXML_CFLAGS) $(LIBPYTHON_CFLAGS) $(LIBPYGOBJECT_CFLAGS) \
- -I$(top_srcdir)/src
-
-AM_CFLAGS = $(DEBUG_CFLAGS) $(WARNING_FLAGS) $(COMPLIANCE_FLAGS)
diff --git a/plugins/pychrysalide/glibext/binarycursor.c b/plugins/pychrysalide/glibext/binarycursor.c
index 4da040a..91dce3e 100644
--- a/plugins/pychrysalide/glibext/binarycursor.c
+++ b/plugins/pychrysalide/glibext/binarycursor.c
@@ -321,7 +321,7 @@ bool ensure_python_binary_cursor_is_registered(void)
if (!ensure_python_line_cursor_is_registered())
return false;
- if (!register_class_for_pygobject(dict, G_TYPE_BINARY_CURSOR, type, get_python_line_cursor_type()))
+ if (!register_class_for_pygobject(dict, G_TYPE_BINARY_CURSOR, type))
return false;
}
diff --git a/plugins/pychrysalide/glibext/binportion.c b/plugins/pychrysalide/glibext/binportion.c
index 060f001..70eb314 100644
--- a/plugins/pychrysalide/glibext/binportion.c
+++ b/plugins/pychrysalide/glibext/binportion.c
@@ -112,7 +112,7 @@ static PyObject *py_bin_portion_new(PyTypeObject *type, PyObject *args, PyObject
if (first_time)
{
- status = register_class_for_dynamic_pygobject(gtype, type, base);
+ status = register_class_for_dynamic_pygobject(gtype, type);
if (!status)
{
@@ -674,7 +674,7 @@ bool ensure_python_binary_portion_is_registered(void)
dict = PyModule_GetDict(module);
- if (!register_class_for_pygobject(dict, G_TYPE_BIN_PORTION, type, &PyGObject_Type))
+ if (!register_class_for_pygobject(dict, G_TYPE_BIN_PORTION, type))
return false;
if (!define_binary_portion_constants(type))
diff --git a/plugins/pychrysalide/glibext/buffercache.c b/plugins/pychrysalide/glibext/buffercache.c
index 0cf3342..03301d6 100644
--- a/plugins/pychrysalide/glibext/buffercache.c
+++ b/plugins/pychrysalide/glibext/buffercache.c
@@ -88,9 +88,13 @@ static PyObject *py_buffer_cache_get_line_flags(PyObject *, PyObject *);
/* Retire une propriété particulière attachée à une ligne. */
static PyObject *py_buffer_cache_remove_line_flag(PyObject *, PyObject *);
+#ifdef INCLUDE_GTK_SUPPORT
+
/* Retrouve une ligne au sein d'un tampon avec un indice. */
static PyObject *py_buffer_cache_find_line_by_index(PyObject *, PyObject *);
+#endif
+
/* Avance autant que possible vers une ligne idéale. */
static PyObject *py_buffer_cache_look_for_flag(PyObject *, PyObject *);
@@ -153,7 +157,7 @@ static PyObject *py_buffer_cache_new(PyTypeObject *type, PyObject *args, PyObjec
if (first_time)
{
- status = register_class_for_dynamic_pygobject(gtype, type, base);
+ status = register_class_for_dynamic_pygobject(gtype, type);
if (!status)
{
@@ -825,6 +829,9 @@ static PyObject *py_buffer_cache_remove_line_flag(PyObject *self, PyObject *args
}
+#ifdef INCLUDE_GTK_SUPPORT
+
+
/******************************************************************************
* *
* Paramètres : self = classe représentant un tampon de code. *
@@ -883,6 +890,9 @@ static PyObject *py_buffer_cache_find_line_by_index(PyObject *self, PyObject *ar
}
+#endif
+
+
/******************************************************************************
* *
* Paramètres : self = classe représentant un tampon de code. *
@@ -1157,7 +1167,9 @@ PyTypeObject *get_python_buffer_cache_type(void)
BUFFER_CACHE_ADD_LINE_FLAG_METHOD,
BUFFER_CACHE_GET_LINE_FLAGS_METHOD,
BUFFER_CACHE_REMOVE_LINE_FLAG_METHOD,
+#ifdef INCLUDE_GTK_SUPPORT
BUFFER_CACHE_FIND_LINE_BY_INDEX_METHOD,
+#endif
BUFFER_CACHE_LOOK_FOR_FLAG_METHOD,
{ NULL }
};
@@ -1221,7 +1233,7 @@ bool ensure_python_buffer_cache_is_registered(void)
dict = PyModule_GetDict(module);
- if (!register_class_for_pygobject(dict, G_TYPE_BUFFER_CACHE, type, &PyGObject_Type))
+ if (!register_class_for_pygobject(dict, G_TYPE_BUFFER_CACHE, type))
return false;
}
diff --git a/plugins/pychrysalide/glibext/bufferline.c b/plugins/pychrysalide/glibext/bufferline.c
index c88fe7f..09404bc 100644
--- a/plugins/pychrysalide/glibext/bufferline.c
+++ b/plugins/pychrysalide/glibext/bufferline.c
@@ -106,7 +106,7 @@ static PyObject *py_buffer_line_new(PyTypeObject *type, PyObject *args, PyObject
if (first_time)
{
- status = register_class_for_dynamic_pygobject(gtype, type, base);
+ status = register_class_for_dynamic_pygobject(gtype, type);
if (!status)
{
@@ -339,7 +339,7 @@ bool ensure_python_buffer_line_is_registered(void)
dict = PyModule_GetDict(module);
- if (!register_class_for_pygobject(dict, G_TYPE_BUFFER_LINE, type, &PyGObject_Type))
+ if (!register_class_for_pygobject(dict, G_TYPE_BUFFER_LINE, type))
return false;
if (!define_line_segment_constants(type))
diff --git a/plugins/pychrysalide/glibext/bufferview.c b/plugins/pychrysalide/glibext/bufferview.c
index 98cc10a..d4cbdc2 100644
--- a/plugins/pychrysalide/glibext/bufferview.c
+++ b/plugins/pychrysalide/glibext/bufferview.c
@@ -146,7 +146,7 @@ bool ensure_python_buffer_view_is_registered(void)
dict = PyModule_GetDict(module);
- if (!register_class_for_pygobject(dict, G_TYPE_BUFFER_VIEW, type, &PyGObject_Type))
+ if (!register_class_for_pygobject(dict, G_TYPE_BUFFER_VIEW, type))
return false;
}
diff --git a/plugins/pychrysalide/glibext/comparison.c b/plugins/pychrysalide/glibext/comparison.c
new file mode 100644
index 0000000..548f700
--- /dev/null
+++ b/plugins/pychrysalide/glibext/comparison.c
@@ -0,0 +1,341 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * comparison.c - équivalent Python du fichier "glibext/comparison.h"
+ *
+ * Copyright (C) 2018-2019 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 "comparison.h"
+
+
+#include <pygobject.h>
+
+
+#include <glibext/comparison-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 *);
+
+/* 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 *);
+
+
+
+/* ------------------------- CONNEXION AVEC L'API DE PYTHON ------------------------- */
+
+
+/* Effectue une comparaison avec un objet 'ComparableItem'. */
+static PyObject *py_comparable_item_richcompare(PyObject *, PyObject *, int);
+
+
+
+/* ---------------------------------------------------------------------------------- */
+/* GLUE POUR CREATION DEPUIS PYTHON */
+/* ---------------------------------------------------------------------------------- */
+
+
+/******************************************************************************
+* *
+* Paramètres : iface = interface GLib à initialiser. *
+* unused = adresse non utilisée ici. *
+* *
+* Description : Procède à l'initialisation de l'interface de comparaison. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void py_comparable_item_interface_init(GComparableItemIface *iface, gpointer *unused)
+{
+
+#define COMPARABLE_ITEM_DOC \
+ "ComparableItem 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" \
+ " ...\n" \
+ "\n"
+
+ iface->cmp_rich = py_comparable_item_compare_rich;
+
+}
+
+
+/******************************************************************************
+* *
+* 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] *
+* *
+* Description : Réalise une comparaison entre objets selon un critère précis.*
+* *
+* Retour : true si la comparaison a pu être effectuée, false sinon. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static bool py_comparable_item_compare_rich(const GComparableItem *item, const GComparableItem *other, RichCmpOperation op, bool *status)
+{
+ bool result; /* Etat à retourner */
+ PyGILState_STATE gstate; /* Sauvegarde d'environnement */
+ PyObject *pyitem; /* Objet Python concerné #1 */
+ PyObject *pyother; /* Objet Python concerné #2 */
+ PyObject *pyret; /* Bilan de consultation */
+ int ret; /* Bilan d'une conversion */
+
+ result = false;
+
+ gstate = PyGILState_Ensure();
+
+ pyitem = pygobject_new(G_OBJECT(item));
+ pyother = pygobject_new(G_OBJECT(other));
+
+ pyret = PyObject_RichCompare(pyitem, pyother, op);
+
+ if (pyret != NULL)
+ {
+ ret = PyBool_Check(pyret);
+
+ if (ret)
+ {
+ *status = (pyret == Py_True);
+ result = true;
+ }
+
+ Py_DECREF(pyret);
+
+ }
+
+ Py_DECREF(pyother);
+ Py_DECREF(pyitem);
+
+ PyGILState_Release(gstate);
+
+ return result;
+
+}
+
+
+
+/* ---------------------------------------------------------------------------------- */
+/* CONNEXION AVEC L'API DE PYTHON */
+/* ---------------------------------------------------------------------------------- */
+
+
+/******************************************************************************
+* *
+* 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'. *
+* *
+* Retour : Bilan de l'opération. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static PyObject *py_comparable_item_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 */
+
+ ret = PyObject_IsInstance(b, (PyObject *)get_python_comparable_item_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));
+
+ valid = g_comparable_item_compare_rich(item_a, item_b, op, &status);
+
+ if (valid)
+ result = status ? Py_True : Py_False;
+ else
+ result = Py_NotImplemented;
+
+ cmp_done:
+
+ 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_comparable_item_type(void)
+{
+ static PyMethodDef py_comparable_item_methods[] = {
+ { NULL }
+ };
+
+ static PyGetSetDef py_comparable_item_getseters[] = {
+ { NULL }
+ };
+
+ static PyTypeObject py_comparable_item_type = {
+
+ PyVarObject_HEAD_INIT(NULL, 0)
+
+ .tp_name = "pychrysalide.glibext.ComparableItem",
+ .tp_basicsize = sizeof(PyObject),
+
+ .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
+
+ .tp_doc = COMPARABLE_ITEM_DOC,
+
+ .tp_richcompare = py_comparable_item_richcompare,
+
+ .tp_methods = py_comparable_item_methods,
+ .tp_getset = py_comparable_item_getseters,
+
+ };
+
+ return &py_comparable_item_type;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : module = module dont la définition est à compléter. *
+* *
+* Description : Prend en charge l'objet 'pychrysalide.....ComparableItem'. *
+* *
+* Retour : Bilan de l'opération. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool ensure_python_comparable_item_is_registered(void)
+{
+ PyTypeObject *type; /* Type Python 'ComparableItem' */
+ 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_finalize = NULL,
+ .interface_data = NULL,
+
+ };
+
+ type = get_python_comparable_item_type();
+
+ if (!PyType_HasFeature(type, Py_TPFLAGS_READY))
+ {
+ module = get_access_to_python_module("pychrysalide.glibext");
+
+ dict = PyModule_GetDict(module);
+
+ if (!register_interface_for_pygobject(dict, G_TYPE_COMPARABLE_ITEM, type, &info))
+ return false;
+
+ if (!define_comparable_item_constants(type))
+ return false;
+
+ }
+
+ return true;
+
+}
+
+
+/******************************************************************************
+* *
+* 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. *
+* *
+* Retour : Bilan de l'opération, voire indications supplémentaires. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+int convert_to_comparable_item(PyObject *arg, void *dst)
+{
+ int result; /* Bilan à retourner */
+
+ result = PyObject_IsInstance(arg, (PyObject *)get_python_comparable_item_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 comparable item");
+ break;
+
+ case 1:
+ *((GComparableItem **)dst) = G_COMPARABLE_ITEM(pygobject_get(arg));
+ break;
+
+ default:
+ assert(false);
+ break;
+
+ }
+
+ return result;
+
+}
diff --git a/plugins/pychrysalide/glibext/comparison.h b/plugins/pychrysalide/glibext/comparison.h
new file mode 100644
index 0000000..79f7092
--- /dev/null
+++ b/plugins/pychrysalide/glibext/comparison.h
@@ -0,0 +1,45 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * comparison.h - prototypes pour l'équivalent Python du fichier "glibext/comparison.h"
+ *
+ * Copyright (C) 2018 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_GLIBEXT_COMPARISON_H
+#define _PLUGINS_PYCHRYSALIDE_GLIBEXT_COMPARISON_H
+
+
+#include <Python.h>
+#include <stdbool.h>
+
+
+
+/* Fournit un accès à une définition de type à diffuser. */
+PyTypeObject *get_python_comparable_item_type(void);
+
+/* Prend en charge l'objet 'pychrysalide.glibext.ComparableItem'. */
+bool ensure_python_comparable_item_is_registered(void);
+
+/* Tente de convertir en élément comparable. */
+int convert_to_comparable_item(PyObject *, void *);
+
+
+
+#endif /* _PLUGINS_PYCHRYSALIDE_GLIBEXT_COMPARISON_H */
diff --git a/plugins/pychrysalide/glibext/configuration.c b/plugins/pychrysalide/glibext/configuration.c
index b0586af..c630331 100644
--- a/plugins/pychrysalide/glibext/configuration.c
+++ b/plugins/pychrysalide/glibext/configuration.c
@@ -174,7 +174,7 @@ static PyObject *py_config_param_new(PyTypeObject *type, PyObject *args, PyObjec
if (first_time)
{
- status = register_class_for_dynamic_pygobject(gtype, type, base);
+ status = register_class_for_dynamic_pygobject(gtype, type);
if (!status)
{
@@ -733,7 +733,7 @@ bool ensure_python_config_param_is_registered(void)
dict = PyModule_GetDict(module);
- if (!register_class_for_pygobject(dict, G_TYPE_CFG_PARAM, type, &PyGObject_Type))
+ if (!register_class_for_pygobject(dict, G_TYPE_CFG_PARAM, type))
return false;
if (!define_config_param_constants(type))
@@ -1036,7 +1036,7 @@ static PyObject *py_generic_config_new(PyTypeObject *type, PyObject *args, PyObj
if (first_time)
{
- status = register_class_for_dynamic_pygobject(gtype, type, base);
+ status = register_class_for_dynamic_pygobject(gtype, type);
if (!status)
{
@@ -1580,7 +1580,7 @@ bool ensure_python_generic_config_is_registered(void)
dict = PyModule_GetDict(module);
- if (!register_class_for_pygobject(dict, G_TYPE_GEN_CONFIG, type, &PyGObject_Type))
+ if (!register_class_for_pygobject(dict, G_TYPE_GEN_CONFIG, type))
return false;
}
diff --git a/plugins/pychrysalide/glibext/constants.c b/plugins/pychrysalide/glibext/constants.c
index 373d1bf..169ffa2 100644
--- a/plugins/pychrysalide/glibext/constants.c
+++ b/plugins/pychrysalide/glibext/constants.c
@@ -27,10 +27,13 @@
#include <i18n.h>
#include <glibext/bufferline.h>
+#include <glibext/comparison.h>
#include <glibext/configuration.h>
#include <glibext/linesegment.h>
#include <glibext/gbinportion.h>
-#include <glibext/gloadedpanel.h>
+#ifdef INCLUDE_GTK_SUPPORT
+# include <glibext/gloadedpanel.h>
+#endif
#include "../helpers.h"
@@ -250,6 +253,48 @@ int convert_to_buffer_line_flags(PyObject *arg, void *dst)
* *
* Paramètres : type = type dont le dictionnaire est à compléter. *
* *
+* Description : Définit les constantes relatives aux modes de comparaison. *
+* *
+* Retour : true en cas de succès de l'opération, false sinon. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool define_comparable_item_constants(PyTypeObject *type)
+{
+ bool result; /* Bilan à retourner */
+ PyObject *values; /* Groupe de valeurs à établir */
+
+ values = PyDict_New();
+
+ result = add_const_to_group(values, "LT", RCO_LT);
+ if (result) result = add_const_to_group(values, "LE", RCO_LE);
+ if (result) result = add_const_to_group(values, "EQ", RCO_EQ);
+ if (result) result = add_const_to_group(values, "NE", RCO_NE);
+ if (result) result = add_const_to_group(values, "GT", RCO_GT);
+ if (result) result = add_const_to_group(values, "GE", RCO_GE);
+
+ if (!result)
+ {
+ Py_DECREF(values);
+ goto exit;
+ }
+
+ result = attach_constants_group_to_type(type, true, "RichCmpOperation", values,
+ "Modes for objects comparison.");
+
+ exit:
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : type = type dont le dictionnaire est à compléter. *
+* *
* Description : Définit les constantes relatives aux paramètres de config. *
* *
* Retour : true en cas de succès de l'opération, false sinon. *
@@ -471,6 +516,9 @@ int convert_to_rendering_tag_type(PyObject *arg, void *dst)
}
+#ifdef INCLUDE_GTK_SUPPORT
+
+
/******************************************************************************
* *
* Paramètres : type = type dont le dictionnaire est à compléter. *
@@ -566,3 +614,6 @@ int convert_to_scroll_position_tweak(PyObject *arg, void *dst)
return result;
}
+
+
+#endif
diff --git a/plugins/pychrysalide/glibext/constants.h b/plugins/pychrysalide/glibext/constants.h
index 342b7ad..4a4f6da 100644
--- a/plugins/pychrysalide/glibext/constants.h
+++ b/plugins/pychrysalide/glibext/constants.h
@@ -43,6 +43,9 @@ bool define_buffer_line_constants(PyTypeObject *);
/* Tente de convertir en constante BufferLineFlags. */
int convert_to_buffer_line_flags(PyObject *, void *);
+/* Définit les constantes relatives aux modes de comparaison. */
+bool define_comparable_item_constants(PyTypeObject *);
+
/* Définit les constantes relatives aux paramètres de configuration. */
bool define_config_param_constants(PyTypeObject *);
@@ -55,12 +58,16 @@ bool define_line_segment_constants(PyTypeObject *);
/* Tente de convertir en constante RenderingTagType. */
int convert_to_rendering_tag_type(PyObject *, void *);
+#ifdef INCLUDE_GTK_SUPPORT
+
/* Définit les constantes relatives aux panneaux de chargement. */
bool define_loaded_panel_constants(PyTypeObject *);
/* Tente de convertir en constante ScrollPositionTweak. */
int convert_to_scroll_position_tweak(PyObject *, void *);
+#endif
+
#endif /* _PLUGINS_PYCHRYSALIDE_GLIBEXT_CONSTANTS_H */
diff --git a/plugins/pychrysalide/glibext/linecursor.c b/plugins/pychrysalide/glibext/linecursor.c
index 217234a..4ac7f85 100644
--- a/plugins/pychrysalide/glibext/linecursor.c
+++ b/plugins/pychrysalide/glibext/linecursor.c
@@ -184,7 +184,7 @@ bool ensure_python_line_cursor_is_registered(void)
dict = PyModule_GetDict(module);
- if (!register_class_for_pygobject(dict, G_TYPE_LINE_CURSOR, type, &PyGObject_Type))
+ if (!register_class_for_pygobject(dict, G_TYPE_LINE_CURSOR, type))
return false;
}
diff --git a/plugins/pychrysalide/glibext/module.c b/plugins/pychrysalide/glibext/module.c
index 176d815..3e4307a 100644
--- a/plugins/pychrysalide/glibext/module.c
+++ b/plugins/pychrysalide/glibext/module.c
@@ -33,11 +33,13 @@
#include "buffercache.h"
#include "bufferline.h"
#include "bufferview.h"
+#include "comparison.h"
#include "configuration.h"
#include "linecursor.h"
#include "linegen.h"
#include "loadedpanel.h"
#include "named.h"
+#include "singleton.h"
#include "../helpers.h"
@@ -104,18 +106,26 @@ bool populate_glibext_module(void)
result = true;
+ if (result) result = ensure_python_singleton_candidate_is_registered();
+
if (result) result = ensure_python_binary_cursor_is_registered();
if (result) result = ensure_python_binary_portion_is_registered();
if (result) result = ensure_python_buffer_cache_is_registered();
if (result) result = ensure_python_buffer_line_is_registered();
+#ifdef INCLUDE_GTK_SUPPORT
if (result) result = ensure_python_buffer_view_is_registered();
+#endif
+ if (result) result = ensure_python_comparable_item_is_registered();
if (result) result = ensure_python_config_param_is_registered();
if (result) result = ensure_python_config_param_iterator_is_registered();
if (result) result = ensure_python_generic_config_is_registered();
if (result) result = ensure_python_line_cursor_is_registered();
if (result) result = ensure_python_line_generator_is_registered();
+#ifdef INCLUDE_GTK_SUPPORT
if (result) result = ensure_python_loaded_panel_is_registered();
if (result) result = ensure_python_named_widget_is_registered();
+#endif
+ if (result) result = ensure_python_singleton_factory_is_registered();
assert(result);
diff --git a/plugins/pychrysalide/glibext/singleton.c b/plugins/pychrysalide/glibext/singleton.c
new file mode 100644
index 0000000..8491473
--- /dev/null
+++ b/plugins/pychrysalide/glibext/singleton.c
@@ -0,0 +1,1165 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * singleton.c - équivalent Python du fichier "glibext/singleton.c"
+ *
+ * Copyright (C) 2021 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 "singleton.h"
+
+
+#include <assert.h>
+#include <pygobject.h>
+
+
+#include <glibext/singleton-int.h>
+#include <plugins/dt.h>
+
+
+#include "../access.h"
+#include "../helpers.h"
+
+
+
+/* ------------------ INTERFACE POUR CANDIDAT A UNE CENTRALISATION ------------------ */
+
+
+/* Procède à l'initialisation de l'interface de candidature. */
+static void py_singleton_candidate_interface_init(GSingletonCandidateIface *, gpointer *);
+
+/* Fournit une liste de candidats embarqués par un candidat. */
+static GSingletonCandidate **py_singleton_candidate_list_inner_instances_wrapper(const GSingletonCandidate *, size_t *);
+
+/* Met à jour une liste de candidats embarqués par un candidat. */
+static void py_singleton_candidate_update_inner_instances_wrapper(GSingletonCandidate *, GSingletonCandidate **, size_t);
+
+/* Fournit l'empreinte d'un candidat à une centralisation. */
+static guint py_singleton_candidate___hash__wrapper(const GSingletonCandidate *);
+
+/* Détermine si deux candidats à l'unicité sont identiques. */
+static gboolean py_singleton_candidate___eq__wrapper(const GSingletonCandidate *, const GSingletonCandidate *);
+
+/* Marque un candidat comme figé. */
+static void py_singleton_candidate_set_ro_wrapper(GSingletonCandidate *);
+
+/* Indique si le candidat est figé. */
+static bool py_singleton_candidate_is_ro_wrapper(const GSingletonCandidate *);
+
+/* Fournit l'empreinte d'un candidat à une centralisation. */
+static PyObject *py_singleton_candidate_hash(PyObject *, PyObject *);
+
+/* Fournit une liste de candidats embarqués par un candidat. */
+static PyObject *py_singleton_candidate_get_inner_instances(PyObject *, void *);
+
+/* Indique si le candidat est figé. */
+static PyObject *py_singleton_candidate_get_read_only(PyObject *, void *);
+
+/* Effectue une comparaison avec un objet 'SingletonCandidate'. */
+static PyObject *py_singleton_candidate_richcompare(PyObject *, PyObject *, int);
+
+
+
+/* ------------------------- COLLECTION D'INSTANCES UNIQUES ------------------------- */
+
+
+/* Accompagne la création d'une instance dérivée en Python. */
+static PyObject *py_singleton_factory_new(PyTypeObject *, PyObject *, PyObject *);
+
+/* Initialise une instance sur la base du dérivé de GObject. */
+static int py_singleton_factory_init(PyObject *, PyObject *, PyObject *);
+
+/* Fournit l'instance unique correspondant à un objet. */
+static PyObject *py_singleton_factory_get_instance(PyObject *, PyObject *);
+
+
+
+/* ---------------------------------------------------------------------------------- */
+/* INTERFACE POUR CANDIDAT A UNE CENTRALISATION */
+/* ---------------------------------------------------------------------------------- */
+
+
+/******************************************************************************
+* *
+* Paramètres : iface = interface GLib à initialiser. *
+* unused = adresse non utilisée ici. *
+* *
+* Description : Procède à l'initialisation de l'interface de candidature. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void py_singleton_candidate_interface_init(GSingletonCandidateIface *iface, gpointer *unused)
+{
+#define SINGLETON_CANDIDATE_DOC \
+ "The SingletonCandidate class is a required interface for objects" \
+ " aiming at becoming singleton instances. All shared singletons are" \
+ " registered within a pychrysalide.glibext.SingletonFactory object.\n" \
+ "\n" \
+ "The main implemantations come with types derived from" \
+ " pychrysalide.analysis.DataType.\n" \
+ "\n" \
+ "A typical class declaration for a new implementation looks like:\n" \
+ "\n" \
+ " class NewImplem(GObject.Object, SingletonCandidate):\n" \
+ " ...\n" \
+ "\n" \
+ "The following methods have to be defined for new implementations:\n" \
+ "* pychrysalide.glibext.SingletonCandidate._list_inner_instances();\n" \
+ "* pychrysalide.glibext.SingletonCandidate._update_inner_instances();\n"\
+ "* pychrysalide.glibext.SingletonCandidate.__hash__();\n" \
+ "* pychrysalide.glibext.SingletonCandidate.__eq__();\n" \
+ "* pychrysalide.glibext.SingletonCandidate._set_read_only();\n" \
+ "* pychrysalide.glibext.SingletonCandidate._is_read_only().\n"
+
+ iface->update_inner = py_singleton_candidate_update_inner_instances_wrapper;
+ iface->list_inner = py_singleton_candidate_list_inner_instances_wrapper;
+
+ iface->hash = py_singleton_candidate___hash__wrapper;
+ iface->is_equal = py_singleton_candidate___eq__wrapper;
+
+ iface->set_ro = py_singleton_candidate_set_ro_wrapper;
+ iface->is_ro = py_singleton_candidate_is_ro_wrapper;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : candidate = objet dont l'instance se veut unique. *
+* count = quantité d'instances à l'unicité internes. *
+* *
+* Description : Fournit une liste de candidats embarqués par un candidat. *
+* *
+* Retour : Liste de candidats internes ou NULL si aucun. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static GSingletonCandidate **py_singleton_candidate_list_inner_instances_wrapper(const GSingletonCandidate *candidate, size_t *count)
+{
+ GSingletonCandidate **result; /* Instances à retourner */
+ PyGILState_STATE gstate; /* Sauvegarde d'environnement */
+ PyObject *pyobj; /* Objet Python concerné */
+ PyObject *pyinstances; /* Liste en version Python */
+ int ret; /* Bilan d'un appel */
+ Py_ssize_t size; /* Taille de la liste */
+ Py_ssize_t i; /* Boucle de parcours #1 */
+ PyObject *pyinstance; /* Instance interne */
+ Py_ssize_t k; /* Boucle de parcours #2 */
+
+#define SINGLETON_CANDIDATE_LIST_INNER_INSTANCES_WRAPPER PYTHON_WRAPPER_DEF \
+( \
+ _list_inner_instances, "$self, /", \
+ METH_NOARGS, \
+ "Provide an internal access to the list of optional internal singleton" \
+ " candidate instances.\n" \
+ "\n" \
+ "The result has to be a tuple containing zero or more" \
+ " pychrysalide.glibext.SingletonCandidate instances." \
+)
+
+ result = NULL;
+ *count = 0;
+
+ gstate = PyGILState_Ensure();
+
+ pyobj = pygobject_new(G_OBJECT(candidate));
+
+ if (has_python_method(pyobj, "_list_inner_instances"))
+ {
+ pyinstances = run_python_method(pyobj, "_list_inner_instances", NULL);
+
+ if (pyinstances != NULL)
+ {
+ ret = PyTuple_Check(pyinstances);
+ if (!ret)
+ {
+ PyErr_SetString(PyExc_TypeError, "the _inner_instances attribute must be a tuple");
+ goto done;
+ }
+
+ size = PyTuple_GET_SIZE(pyinstances);
+
+ result = calloc(size, sizeof(GSingletonCandidate *));
+
+ for (i = 0; i < size; i++)
+ {
+ pyinstance = PyTuple_GET_ITEM(pyinstances, i);
+
+ ret = PyObject_IsInstance(pyinstance, (PyObject *)get_python_singleton_candidate_type());
+ if (ret != 1)
+ {
+ PyErr_SetString(PyExc_TypeError, "the _inner_instances attribute must only contain pychrysalide.glibext.SingletonCandidate instances");
+
+ for (k = 0; k < i; k++)
+ g_object_unref(G_OBJECT(result[k]));
+
+ free(result);
+ result = NULL;
+
+ goto done;
+
+ }
+
+ result[i] = G_SINGLETON_CANDIDATE(pygobject_get(pyinstance));
+ assert(result[i] != NULL);
+
+ g_object_ref(G_OBJECT(result[i]));
+
+ }
+
+ *count = size;
+
+ done:
+
+ Py_DECREF(pyinstances);
+
+ }
+
+ }
+
+ Py_DECREF(pyobj);
+
+ PyGILState_Release(gstate);
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : candidate = objet dont l'instance se veut unique. *
+* instances = liste de candidats internes devenus singletons. *
+* count = quantité d'instances à l'unicité internes. *
+* *
+* Description : Met à jour une liste de candidats embarqués par un candidat. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void py_singleton_candidate_update_inner_instances_wrapper(GSingletonCandidate *candidate, GSingletonCandidate **instances, size_t count)
+{
+ PyGILState_STATE gstate; /* Sauvegarde d'environnement */
+ PyObject *pyobj; /* Objet Python concerné */
+ PyObject *args; /* Arguments pour l'appel */
+ PyObject *pyinstances; /* Liste d'instances converties*/
+ size_t i; /* Boucle de parcours */
+ PyObject *pyret; /* Bilan de consultation */
+
+#define SINGLETON_CANDIDATE_UPDATE_INNER_INSTANCES_WRAPPER PYTHON_WRAPPER_DEF \
+( \
+ _update_inner_instances, "$self, instances, /", \
+ METH_VARARGS, \
+ "Update the list of internal singleton candidate instances.\n" \
+ "\n" \
+ "The provided *instances* are a tuple of pychrysalide.glibext.SingletonCandidate" \
+ " objets promoted as singletons." \
+)
+
+ gstate = PyGILState_Ensure();
+
+ pyobj = pygobject_new(G_OBJECT(candidate));
+
+ if (has_python_method(pyobj, "_update_inner_instances"))
+ {
+ args = PyTuple_New(1);
+
+ pyinstances = PyTuple_New(count);
+ PyTuple_SetItem(args, 0, pyinstances);
+
+ for (i = 0; i < count; i++)
+ PyTuple_SetItem(pyinstances, i, pygobject_new(G_OBJECT(instances[i])));
+
+ pyret = run_python_method(pyobj, "_update_inner_instances", args);
+
+ Py_XDECREF(pyret);
+ Py_DECREF(args);
+
+ }
+
+ Py_DECREF(pyobj);
+
+ PyGILState_Release(gstate);
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : candidate = objet dont l'instance se veut unique. *
+* *
+* Description : Fournit l'empreinte d'un candidat à une centralisation. *
+* *
+* Retour : Empreinte de l'élément représenté. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static guint py_singleton_candidate___hash__wrapper(const GSingletonCandidate *candidate)
+{
+ guint result; /* Empreinte à retourner */
+ PyGILState_STATE gstate; /* Sauvegarde d'environnement */
+ PyObject *pyobj; /* Objet Python concerné */
+ PyObject *pyret; /* Bilan de consultation */
+
+#define SINGLETON_CANDIDATE_HASH_WRAPPER PYTHON_WRAPPER_DEF \
+( \
+ __hash__, "$self, /", \
+ METH_NOARGS, \
+ "Abstract method used to produce a hash of the object.\n" \
+ "\n" \
+ "The result must be an integer value up to 64 bits." \
+ "\n" \
+ "Inner instances which are listed through the" \
+ " pychrysalide.glibext.SingletonCandidate._list_inner_instances()" \
+ " method do not need to get processed here as they are handled" \
+ " automatically by the interface core." \
+)
+
+ result = 0;
+
+ gstate = PyGILState_Ensure();
+
+ pyobj = pygobject_new(G_OBJECT(candidate));
+
+ if (has_python_method(pyobj, "__hash__"))
+ {
+ pyret = run_python_method(pyobj, "__hash__", NULL);
+
+ if (pyret != NULL)
+ {
+ if (PyLong_Check(pyret))
+ result = PyLong_AsUnsignedLongMask(pyret);
+
+ Py_DECREF(pyret);
+
+ }
+
+ }
+
+ Py_DECREF(pyobj);
+
+ PyGILState_Release(gstate);
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : candidate = objet dont l'instance se veut unique. *
+* other = second élément à analyser. *
+* *
+* Description : Détermine si deux candidats à l'unicité sont identiques. *
+* *
+* Retour : Bilan de la comparaison. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static gboolean py_singleton_candidate___eq__wrapper(const GSingletonCandidate *candidate, const GSingletonCandidate *other)
+{
+ guint result; /* Empreinte à retourner */
+ PyGILState_STATE gstate; /* Sauvegarde d'environnement */
+ PyObject *pyobj; /* Objet Python concerné */
+ PyObject *args; /* Arguments pour l'appel */
+ PyObject *pyret; /* Bilan de consultation */
+
+#define SINGLETON_CANDIDATE_EQ_WRAPPER PYTHON_WRAPPER_DEF \
+( \
+ __eq__, "$self, other, /", \
+ METH_NOARGS, \
+ "Abstract method used to provide the *__eq__* method for" \
+ " rich comparison.\n" \
+ "\n" \
+ "The expected result is a boolean value." \
+)
+
+ result = 0;
+
+ gstate = PyGILState_Ensure();
+
+ pyobj = pygobject_new(G_OBJECT(candidate));
+
+ if (has_python_method(pyobj, "__eq__"))
+ {
+ args = PyTuple_New(1);
+ PyTuple_SetItem(args, 0, pygobject_new(G_OBJECT(other)));
+
+ pyret = run_python_method(pyobj, "__eq__", args);
+
+ if (pyret != NULL)
+ {
+ if (PyLong_Check(pyret))
+ result = PyLong_AsUnsignedLong(pyret);
+
+ Py_DECREF(pyret);
+
+ }
+
+ Py_DECREF(args);
+
+ }
+
+ Py_DECREF(pyobj);
+
+ PyGILState_Release(gstate);
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : candidate = objet dont l'instance se veut unique. *
+* *
+* Description : Marque un candidat comme figé. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void py_singleton_candidate_set_ro_wrapper(GSingletonCandidate *candidate)
+{
+ PyGILState_STATE gstate; /* Sauvegarde d'environnement */
+ PyObject *pyobj; /* Objet Python concerné */
+ PyObject *pyret; /* Bilan de consultation */
+
+#define SINGLETON_CANDIDATE_SET_RO_WRAPPER PYTHON_WRAPPER_DEF \
+( \
+ _set_read_only, "$self, /", \
+ METH_NOARGS, \
+ "Abstract method used to mark the content of a singleton" \
+ " candidate as read-only.\n" \
+ "\n" \
+ "The read-only state is mandatory once the candidate is" \
+ " registered inside a pychrysalide.glibext.SingletonFactory"\
+ " instance as official singleton." \
+)
+
+ gstate = PyGILState_Ensure();
+
+ pyobj = pygobject_new(G_OBJECT(candidate));
+
+ if (has_python_method(pyobj, "_set_read_only"))
+ {
+ pyret = run_python_method(pyobj, "_set_read_only", NULL);
+
+ Py_XDECREF(pyret);
+
+ }
+
+ Py_DECREF(pyobj);
+
+ PyGILState_Release(gstate);
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : candidate = objet dont l'instance se veut unique. *
+* *
+* Description : Indique si le candidat est figé. *
+* *
+* Retour : true si le contenu du candidat ne peut plus être modifié. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static bool py_singleton_candidate_is_ro_wrapper(const GSingletonCandidate *candidate)
+{
+ bool result; /* Etat à retourner */
+ PyGILState_STATE gstate; /* Sauvegarde d'environnement */
+ PyObject *pyobj; /* Objet Python concerné */
+ PyObject *pyret; /* Bilan de consultation */
+
+#define SINGLETON_CANDIDATE_IS_RO_WRAPPER PYTHON_WRAPPER_DEF \
+( \
+ _is_read_only, "$self, /", \
+ METH_NOARGS, \
+ "Abstract method used to retrieve the status of the data" \
+ " contained by a singleton candidate.\n" \
+ "\n" \
+ "The retured value is *True* if the candidate is" \
+ " registered inside a pychrysalide.glibext.SingletonFactory"\
+ " instance as official singleton, *False* otherwise." \
+)
+
+ result = false;
+
+ gstate = PyGILState_Ensure();
+
+ pyobj = pygobject_new(G_OBJECT(candidate));
+
+ if (has_python_method(pyobj, "_is_read_only"))
+ {
+ pyret = run_python_method(pyobj, "_is_read_only", NULL);
+
+ result = (pyret == Py_True);
+
+ Py_XDECREF(pyret);
+
+ }
+
+ Py_DECREF(pyobj);
+
+ PyGILState_Release(gstate);
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : self = objet dont l'instance se veut unique. *
+* args = adresse non utilisée ici. *
+* *
+* Description : Fournit l'empreinte d'un candidat à une centralisation. *
+* *
+* Retour : Empreinte de l'élément représenté. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static PyObject *py_singleton_candidate_hash(PyObject *self, PyObject *args)
+{
+ PyObject *result; /* Emplacement à retourner */
+ GSingletonCandidate *candidate; /* Mécanismes natifs */
+ guint hash; /* Valeur d'empreitne */
+
+#define SINGLETON_CANDIDATE_HASH_METHOD PYTHON_METHOD_DEF \
+( \
+ hash, "$self", \
+ METH_NOARGS, py_singleton_candidate, \
+ "Compute the hash value of the singleton candidate.\n" \
+ "\n" \
+ "The method relies on the interface core to include in the" \
+ " process the optional embedded instances which may become" \
+ " singletons.\n" \
+ "\n" \
+ "The result is an integer value.\n" \
+ "\n" \
+ "Even if the Python *hash()* method, relying on the" \
+ " pychrysalide.glibext.SingletonCandidate.__hash__()" \
+ " implementation, provides values up to 64 bits, the final" \
+ " hashes processed by the native GLib hash methods are" \
+ " limited to 32 bits values." \
+)
+
+ candidate = G_SINGLETON_CANDIDATE(pygobject_get(self));
+
+ hash = g_singleton_candidate_hash(candidate);
+
+ result = PyLong_FromUnsignedLong(hash);
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : self = objet Python concerné par l'appel. *
+* closure = non utilisé ici. *
+* *
+* Description : Fournit une liste de candidats embarqués par un candidat. *
+* *
+* Retour : Liste de candidats internes, vide si aucun. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static PyObject *py_singleton_candidate_get_inner_instances(PyObject *self, void *closure)
+{
+ PyObject *result; /* Valeur à retourner */
+ GSingletonCandidate *candidate; /* Mécanismes natifs */
+ size_t count; /* Quantité d'objets internes */
+ GSingletonCandidate **instances; /* Liste des embarqués */
+ size_t i; /* Boucle de parcours */
+
+#define SINGLETON_CANDIDATE_INNER_INSTANCES_ATTRIB PYTHON_GET_DEF_FULL \
+( \
+ inner_instances, py_singleton_candidate, \
+ "List of optional internal singleton candidate instances.\n" \
+ "\n" \
+ "The result has to be a tuple containing zero or more" \
+ " pychrysalide.glibext.SingletonCandidate instances." \
+)
+
+ candidate = G_SINGLETON_CANDIDATE(pygobject_get(self));
+
+ instances = g_singleton_candidate_list_inner_instances(candidate, &count);
+
+ result = PyTuple_New(count);
+
+ for (i = 0; i < count; i++)
+ {
+ PyTuple_SetItem(result, i, pygobject_new(G_OBJECT(instances[i])));
+ g_object_unref(G_OBJECT(instances[i]));
+ }
+
+ if (instances != NULL)
+ free(instances);
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : self = objet Python concerné par l'appel. *
+* closure = non utilisé ici. *
+* *
+* Description : Indique si le candidat est figé. *
+* *
+* Retour : true si le contenu du candidat ne peut plus être modifié. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static PyObject *py_singleton_candidate_get_read_only(PyObject *self, void *closure)
+{
+ PyObject *result; /* Valeur à retourner */
+ GSingletonCandidate *candidate; /* Mécanismes natifs */
+ bool status; /* Etat de l'élément consulté */
+
+#define SINGLETON_CANDIDATE_READ_ONLY_ATTRIB PYTHON_GET_DEF_FULL \
+( \
+ read_only, py_singleton_candidate, \
+ "State of the singleton candidate content.\n" \
+ "\n" \
+ "The result is a boolean: *True* if the object is registered" \
+ " as singleton, *False* otherwise.\n" \
+ "\n" \
+ "Once a singleton, the object must not change its content as" \
+ " it is a shared instance." \
+)
+
+ candidate = G_SINGLETON_CANDIDATE(pygobject_get(self));
+
+ status = g_singleton_candidate_is_read_only(candidate);
+
+ result = status ? Py_True : Py_False;
+ Py_INCREF(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 'SingletonCandidate'. *
+* *
+* Retour : Bilan de l'opération. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static PyObject *py_singleton_candidate_richcompare(PyObject *a, PyObject *b, int op)
+{
+ PyObject *result; /* Bilan à retourner */
+ int ret; /* Bilan de lecture des args. */
+ GSingletonCandidate *cand_a; /* Premier élément à traiter */
+ GSingletonCandidate *cand_b; /* Second élément à traiter */
+ gboolean status; /* Résultat d'une comparaison */
+
+ if (op != Py_EQ)
+ {
+ result = Py_NotImplemented;
+ goto cmp_done;
+ }
+
+ ret = PyObject_IsInstance(b, (PyObject *)get_python_singleton_candidate_type());
+ if (!ret)
+ {
+ result = Py_NotImplemented;
+ goto cmp_done;
+ }
+
+ cand_a = G_SINGLETON_CANDIDATE(pygobject_get(a));
+ cand_b = G_SINGLETON_CANDIDATE(pygobject_get(b));
+
+ status = g_singleton_candidate_is_equal(cand_a, cand_b);
+
+ result = (status ? Py_True : Py_False);
+
+ cmp_done:
+
+ 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_singleton_candidate_type(void)
+{
+ static PyMethodDef py_singleton_candidate_methods[] = {
+ SINGLETON_CANDIDATE_LIST_INNER_INSTANCES_WRAPPER,
+ SINGLETON_CANDIDATE_UPDATE_INNER_INSTANCES_WRAPPER,
+ SINGLETON_CANDIDATE_HASH_WRAPPER,
+ SINGLETON_CANDIDATE_EQ_WRAPPER,
+ SINGLETON_CANDIDATE_SET_RO_WRAPPER,
+ SINGLETON_CANDIDATE_IS_RO_WRAPPER,
+ SINGLETON_CANDIDATE_HASH_METHOD,
+ { NULL }
+ };
+
+ static PyGetSetDef py_singleton_candidate_getseters[] = {
+ SINGLETON_CANDIDATE_INNER_INSTANCES_ATTRIB,
+ SINGLETON_CANDIDATE_READ_ONLY_ATTRIB,
+ { NULL }
+ };
+
+ static PyTypeObject py_singleton_candidate_type = {
+
+ PyVarObject_HEAD_INIT(NULL, 0)
+
+ .tp_name = "pychrysalide.glibext.SingletonCandidate",
+ .tp_basicsize = sizeof(PyObject),
+
+ .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
+
+ .tp_doc = SINGLETON_CANDIDATE_DOC,
+
+ .tp_richcompare = py_singleton_candidate_richcompare,
+
+ .tp_methods = py_singleton_candidate_methods,
+ .tp_getset = py_singleton_candidate_getseters
+
+ };
+
+ return &py_singleton_candidate_type;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : - *
+* *
+* Description : Prend en charge l'objet 'pychrysalide....SingletonCandidate'.*
+* *
+* Retour : Bilan de l'opération. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool ensure_python_singleton_candidate_is_registered(void)
+{
+ PyTypeObject *type; /* Type Python 'BinContent' */
+ PyObject *module; /* Module à recompléter */
+ PyObject *dict; /* Dictionnaire du module */
+
+ static GInterfaceInfo info = { /* Paramètres d'inscription */
+
+ .interface_init = (GInterfaceInitFunc)py_singleton_candidate_interface_init,
+ .interface_finalize = NULL,
+ .interface_data = NULL,
+
+ };
+
+ type = get_python_singleton_candidate_type();
+
+ if (!PyType_HasFeature(type, Py_TPFLAGS_READY))
+ {
+ module = get_access_to_python_module("pychrysalide.glibext");
+
+ dict = PyModule_GetDict(module);
+
+ if (!register_interface_for_pygobject(dict, G_TYPE_SINGLETON_CANDIDATE, type, &info))
+ return false;
+
+ }
+
+ return true;
+
+}
+
+
+/******************************************************************************
+* *
+* 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 candidat à une centralisation. *
+* *
+* Retour : Bilan de l'opération, voire indications supplémentaires. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+int convert_to_singleton_candidate(PyObject *arg, void *dst)
+{
+ int result; /* Bilan à retourner */
+
+ result = PyObject_IsInstance(arg, (PyObject *)get_python_singleton_candidate_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 singleton candidate");
+ break;
+
+ case 1:
+ *((GSingletonCandidate **)dst) = G_SINGLETON_CANDIDATE(pygobject_get(arg));
+ break;
+
+ default:
+ assert(false);
+ break;
+
+ }
+
+ return result;
+
+}
+
+
+
+/* ---------------------------------------------------------------------------------- */
+/* COLLECTION D'INSTANCES UNIQUES */
+/* ---------------------------------------------------------------------------------- */
+
+
+/******************************************************************************
+* *
+* 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_singleton_factory_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_singleton_factory_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_SINGLETON_FACTORY, 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. *
+* *
+* Description : Initialise une instance sur la base du dérivé de GObject. *
+* *
+* Retour : 0. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static int py_singleton_factory_init(PyObject *self, PyObject *args, PyObject *kwds)
+{
+ int ret; /* Bilan de lecture des args. */
+
+#define SINGLETON_FACTORY_DOC \
+ "The SingletonFactory class reduces the memory footprint by compacting" \
+ " the quantity of running instances of a given GLib type.\n" \
+ "\n" \
+ "Instances can be created using the following constructor:\n" \
+ "\n" \
+ " SingletonFactory()" \
+ "\n" \
+ "The first processed instance defines the type handled by the factory."
+
+ /* Récupération des paramètres */
+
+ ret = PyArg_ParseTuple(args, "");
+ if (!ret) return -1;
+
+ /* Initialisation d'un objet GLib */
+
+ ret = forward_pygobjet_init(self);
+ if (ret == -1) return -1;
+
+ /* Eléments de base */
+
+ return 0;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : self = gestionnaire d'instances uniques à consulter. *
+* args = arguments fournis à l'appel. *
+* *
+* Description : Fournit l'instance unique correspondant à un objet. *
+* *
+* Retour : Instance unique à utiliser. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static PyObject *py_singleton_factory_get_instance(PyObject *self, PyObject *args)
+{
+ PyObject *result; /* Emplacement à retourner */
+ GSingletonCandidate *candidate; /* Candidat à traiter */
+ int ret; /* Bilan de lecture des args. */
+ GSingletonFactory *factory; /* Gestionnaire à manipuler */
+ GSingletonCandidate *instance; /* Instance unique à retourner */
+
+#define SINGLETON_FACTORY_GET_INSTANCE_METHOD PYTHON_METHOD_DEF \
+( \
+ get_instance, "$self, candidate, /", \
+ METH_VARARGS, py_singleton_factory, \
+ "Provide the unique instance for a given singleton *candidate*.\n" \
+ "\n" \
+ "The *candidate* object and the result of the function belong to" \
+ " the same type: pychrysalide.glibext.SingletonCandidate." \
+)
+
+ ret = PyArg_ParseTuple(args, "O&", convert_to_singleton_candidate, &candidate);
+ if (!ret) return NULL;
+
+ factory = G_SINGLETON_FACTORY(pygobject_get(self));
+
+ instance = g_singleton_factory_get_instance(factory, candidate);
+
+ result = pygobject_new(G_OBJECT(instance));
+
+ g_object_unref(G_OBJECT(instance));
+
+ 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_singleton_factory_type(void)
+{
+ static PyMethodDef py_singleton_factory_methods[] = {
+ SINGLETON_FACTORY_GET_INSTANCE_METHOD,
+ { NULL }
+ };
+
+ static PyGetSetDef py_singleton_factory_getseters[] = {
+ { NULL }
+ };
+
+ static PyTypeObject py_singleton_factory_type = {
+
+ PyVarObject_HEAD_INIT(NULL, 0)
+
+ .tp_name = "pychrysalide.glibext.SingletonFactory",
+ .tp_basicsize = sizeof(PyGObject),
+
+ .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
+
+ .tp_doc = SINGLETON_FACTORY_DOC,
+
+ .tp_methods = py_singleton_factory_methods,
+ .tp_getset = py_singleton_factory_getseters,
+
+ .tp_init = py_singleton_factory_init,
+ .tp_new = py_singleton_factory_new
+
+ };
+
+ return &py_singleton_factory_type;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : module = module dont la définition est à compléter. *
+* *
+* Description : Prend en charge l'objet 'pychrysalide....SingletonFactory'. *
+* *
+* Retour : Bilan de l'opération. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool ensure_python_singleton_factory_is_registered(void)
+{
+ PyTypeObject *type; /* Type 'SingletonFactory' */
+ PyObject *module; /* Module à recompléter */
+ PyObject *dict; /* Dictionnaire du module */
+
+ type = get_python_singleton_factory_type();
+
+ if (!PyType_HasFeature(type, Py_TPFLAGS_READY))
+ {
+ module = get_access_to_python_module("pychrysalide.glibext");
+
+ dict = PyModule_GetDict(module);
+
+ if (!register_class_for_pygobject(dict, G_TYPE_SINGLETON_FACTORY, type))
+ return false;
+
+ }
+
+ return true;
+
+}
+
+
+/******************************************************************************
+* *
+* 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 compacteur d'instances. *
+* *
+* Retour : Bilan de l'opération, voire indications supplémentaires. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+int convert_to_singleton_factory(PyObject *arg, void *dst)
+{
+ int result; /* Bilan à retourner */
+
+ result = PyObject_IsInstance(arg, (PyObject *)get_python_singleton_factory_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 singleton factory");
+ break;
+
+ case 1:
+ *((GSingletonFactory **)dst) = G_SINGLETON_FACTORY(pygobject_get(arg));
+ break;
+
+ default:
+ assert(false);
+ break;
+
+ }
+
+ return result;
+
+}
diff --git a/plugins/pychrysalide/glibext/singleton.h b/plugins/pychrysalide/glibext/singleton.h
new file mode 100644
index 0000000..6479219
--- /dev/null
+++ b/plugins/pychrysalide/glibext/singleton.h
@@ -0,0 +1,62 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * singleton.h - prototypes pour l'équivalent Python du fichier "glibext/singleton.h"
+ *
+ * Copyright (C) 2021 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_GLIBEXT_SINGLETON_H
+#define _PLUGINS_PYCHRYSALIDE_GLIBEXT_SINGLETON_H
+
+
+#include <Python.h>
+#include <stdbool.h>
+
+
+
+/* ------------------ INTERFACE POUR CANDIDAT A UNE CENTRALISATION ------------------ */
+
+
+/* Fournit un accès à une définition de type à diffuser. */
+PyTypeObject *get_python_singleton_candidate_type(void);
+
+/* Prend en charge l'objet 'pychrysalide.glibext.SingletonCandidate'. */
+bool ensure_python_singleton_candidate_is_registered(void);
+
+/* Tente de convertir en candidat à une centralisation. */
+int convert_to_singleton_candidate(PyObject *, void *);
+
+
+
+/* ------------------------- COLLECTION D'INSTANCES UNIQUES ------------------------- */
+
+
+/* Fournit un accès à une définition de type à diffuser. */
+PyTypeObject *get_python_singleton_factory_type(void);
+
+/* Prend en charge l'objet 'pychrysalide.glibext.SingletonFactory'. */
+bool ensure_python_singleton_factory_is_registered(void);
+
+/* Tente de convertir en compacteur d'instances. */
+int convert_to_singleton_factory(PyObject *, void *);
+
+
+
+#endif /* _PLUGINS_PYCHRYSALIDE_GLIBEXT_SINGLETON_H */