From 49fcaf9ea6dc34382ac69b3eaf803c0617b652e0 Mon Sep 17 00:00:00 2001
From: Cyrille Bagard <nocbos@gmail.com>
Date: Tue, 29 Jan 2019 23:54:42 +0100
Subject: Introduced binary portion support for Python bindings.

---
 plugins/pychrysalide/glibext/Makefile.am  |   1 +
 plugins/pychrysalide/glibext/binportion.c | 737 ++++++++++++++++++++++++++++++
 plugins/pychrysalide/glibext/binportion.h |  45 ++
 plugins/pychrysalide/glibext/module.c     |   2 +
 src/glibext/Makefile.am                   |   1 +
 src/glibext/gbinportion-int.h             |  64 +++
 src/glibext/gbinportion.c                 |  47 +-
 src/glibext/gbinportion.h                 |   3 +
 tests/glibext/__init__.py                 |   0
 tests/glibext/binportion.py               |  60 +++
 10 files changed, 926 insertions(+), 34 deletions(-)
 create mode 100644 plugins/pychrysalide/glibext/binportion.c
 create mode 100644 plugins/pychrysalide/glibext/binportion.h
 create mode 100644 src/glibext/gbinportion-int.h
 create mode 100644 tests/glibext/__init__.py
 create mode 100644 tests/glibext/binportion.py

diff --git a/plugins/pychrysalide/glibext/Makefile.am b/plugins/pychrysalide/glibext/Makefile.am
index 086ca28..8a6de46 100644
--- a/plugins/pychrysalide/glibext/Makefile.am
+++ b/plugins/pychrysalide/glibext/Makefile.am
@@ -2,6 +2,7 @@
 noinst_LTLIBRARIES = libpychrysaglibext.la
 
 libpychrysaglibext_la_SOURCES =			\
+	binportion.h binportion.c			\
 	buffercache.h buffercache.c			\
 	bufferline.h bufferline.c			\
 	bufferview.h bufferview.c			\
diff --git a/plugins/pychrysalide/glibext/binportion.c b/plugins/pychrysalide/glibext/binportion.c
new file mode 100644
index 0000000..9f719cb
--- /dev/null
+++ b/plugins/pychrysalide/glibext/binportion.c
@@ -0,0 +1,737 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * binportion.c - équivalent Python du fichier "glibext/gbinportion.c"
+ *
+ * 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
+ */
+
+
+#include "binportion.h"
+
+
+#include <pygobject.h>
+
+
+#include <i18n.h>
+#include <glibext/gbinportion-int.h>
+#include <plugins/dt.h>
+
+
+#include "../access.h"
+#include "../helpers.h"
+#include "../arch/vmpa.h"
+
+
+
+/* Accompagne la création d'une instance dérivée en Python. */
+static PyObject *py_bin_portion_new(PyTypeObject *, PyObject *, PyObject *);
+
+/* Initialise une instance sur la base du dérivé de GObject. */
+static int py_bin_portion_init(PyObject *, PyObject *, PyObject *);
+
+/* Effectue une comparaison avec un objet Python 'BinPortion'. */
+static PyObject *py_binary_portion_richcompare(PyObject *, PyObject *, int);
+
+/* Assure qu'une portion ne dépasse pas une position donnée. */
+static PyObject *py_binary_portion_limit_range(PyObject *, PyObject *);
+
+
+
+/* Fournit la description attribuée à une partie de code. */
+static PyObject *py_binary_portion_get_desc(PyObject *, void *);
+
+/* Attribue une description humaine à une partie de code. */
+static int py_binary_portion_set_desc(PyObject *, PyObject *, void *);
+
+/* Fournit l'emplacement d'une partie de code binaire. */
+static PyObject *py_binary_portion_get_range(PyObject *, void *);
+
+/* Indique la nature de la portion en terme d'originalité. */
+static PyObject *py_binary_portion_get_continuation(PyObject *, void *);
+
+/* Définit la nature de la portion en terme d'originalité. */
+static int py_binary_portion_set_continuation(PyObject *, PyObject *, void *);
+
+/* Fournit les droits associés à une partie de code. */
+static PyObject *py_binary_portion_get_rights(PyObject *, void *);
+
+/* Définit les droits associés à une partie de code. */
+static int py_binary_portion_set_rights(PyObject *, PyObject *, void *);
+
+/* Définit les constantes pour les portions de binaire. */
+static bool py_binary_portion_define_constants(PyTypeObject *);
+
+
+
+/******************************************************************************
+*                                                                             *
+*  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_bin_portion_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_binary_portion_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_BIN_PORTION, type->tp_name, NULL, NULL, NULL);
+
+    if (first_time)
+    {
+        status = register_class_for_dynamic_pygobject(gtype, type, base);
+
+        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_bin_portion_init(PyObject *self, PyObject *args, PyObject *kwds)
+{
+    const char *code;                       /* Identifiant de couleur      */
+    vmpa2t addr;                            /* Emplacement de portion      */
+    unsigned long long size;                /* Taille de la portion        */
+    PyObject *new_args;                     /* Nouveaux arguments épurés   */
+    int ret;                                /* Bilan de lecture des args.  */
+    PyObject *new_kwds;                     /* Nouveau dictionnaire épuré  */
+    GBinPortion *portion;                   /* Portion à manipuler         */
+
+    static char *kwlist[] = { "code", "addr", "size", NULL };
+
+    /* Récupération des paramètres */
+
+    ret = PyArg_ParseTupleAndKeywords(args, kwds, "sO&K", kwlist,
+                                      &code, convert_any_to_vmpa, &addr, &size);
+    if (!ret) return -1;
+
+    /* Initialisation d'un objet GLib */
+
+    new_args = PyTuple_New(0);
+    new_kwds = PyDict_New();
+
+    ret = PyGObject_Type.tp_init(self, new_args, new_kwds);
+
+    Py_DECREF(new_kwds);
+    Py_DECREF(new_args);
+
+    if (ret == -1) return -1;
+
+    /* Eléments de base */
+
+    portion = G_BIN_PORTION(pygobject_get(self));
+
+    portion->code = strdup(code);
+
+    init_mrange(&portion->range, &addr, size);
+
+    return 0;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  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 Python 'BinPortion'.  *
+*                                                                             *
+*  Retour      : Bilan de l'opération.                                        *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static PyObject *py_binary_portion_richcompare(PyObject *a, PyObject *b, int op)
+{
+    PyObject *result;                       /* Bilan à retourner           */
+    int ret;                                /* Bilan de lecture des args.  */
+    const GBinPortion *portion_a;           /* Premier élément à traiter   */
+    const GBinPortion *portion_b;           /* Second élément à traiter    */
+    int status;                             /* Résultat d'une comparaison  */
+
+    ret = PyObject_IsInstance(b, (PyObject *)get_python_binary_portion_type());
+    if (!ret)
+    {
+        result = Py_NotImplemented;
+        goto cmp_done;
+    }
+
+    portion_a = G_BIN_PORTION(pygobject_get(a));
+    portion_b = G_BIN_PORTION(pygobject_get(b));
+
+    status = g_binary_portion_compare(&portion_a, &portion_b);
+
+    result = status_to_rich_cmp_state(status, op);
+
+ cmp_done:
+
+    Py_INCREF(result);
+
+    return result;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : self = classe représentant une portion de binaire.           *
+*                args = arguments fournis à l'appel.                          *
+*                                                                             *
+*  Description : Assure qu'une portion ne dépasse pas une position donnée.    *
+*                                                                             *
+*  Retour      : True si la portion a été modifiée, False sinon.              *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static PyObject *py_binary_portion_limit_range(PyObject *self, PyObject *args)
+{
+    PyObject *result;                       /* Trouvailles à retourner     */
+    unsigned long long max;                 /* Taille maximale à accorder  */
+    int ret;                                /* Bilan de lecture des args.  */
+    GBinPortion *portion;                   /* Version GLib du type        */
+    bool status;                            /* Bilan de la modification    */
+
+    ret = PyArg_ParseTuple(args, "K", &max);
+    if (!ret) return NULL;
+
+    portion = G_BIN_PORTION(pygobject_get(self));
+
+    status = g_binary_portion_limit_range(portion, max);
+
+    result = status ? Py_True : Py_False;
+    Py_INCREF(result);
+
+    return result;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : self = classe représentant une portion de binaire.           *
+*                args = arguments fournis à l'appel.                          *
+*                                                                             *
+*  Description : Procède à l'inclusion d'une portion dans une autre.          *
+*                                                                             *
+*  Retour      : -                                                            *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static PyObject *py_binary_portion_include(PyObject *self, PyObject *args)
+{
+    GBinPortion *sub;                       /* Sous-portion à inclure      */
+    int ret;                                /* Bilan de lecture des args.  */
+    GBinPortion *portion;                   /* Version GLib du type        */
+
+    ret = PyArg_ParseTuple(args, "O&", convert_to_binary_portion, &sub);
+    if (!ret) return NULL;
+
+    portion = G_BIN_PORTION(pygobject_get(self));
+
+    g_object_ref(G_OBJECT(sub));
+    g_binary_portion_include(portion, sub);
+
+    Py_RETURN_NONE;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : self    = objet Python concerné par l'appel.                 *
+*                closure = non utilisé ici.                                   *
+*                                                                             *
+*  Description : Fournit la description attribuée à une partie de code.       *
+*                                                                             *
+*  Retour      : Nom donné à la partie.                                       *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static PyObject *py_binary_portion_get_desc(PyObject *self, void *closure)
+{
+    PyObject *result;                       /* Résultat à retourner        */
+    GBinPortion *portion;                   /* Version GLib du type        */
+    const char *desc;                       /* Description récupérée       */
+
+    portion = G_BIN_PORTION(pygobject_get(self));
+
+    desc = g_binary_portion_get_desc(portion);
+
+    result = PyUnicode_FromString(desc);
+
+    return result;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : self    = objet Python concerné par l'appel.                 *
+*                value   = valeur fournie à intégrer ou prendre en compte.    *
+*                closure = non utilisé ici.                                   *
+*                                                                             *
+*  Description : Attribue une description humaine à une partie de code.       *
+*                                                                             *
+*  Retour      : 0.                                                           *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static int py_binary_portion_set_desc(PyObject *self, PyObject *value, void *closure)
+{
+    GBinPortion *portion;                   /* Version GLib du type        */
+    const char *desc;                       /* Description à définir       */
+
+    if (!PyUnicode_Check(value))
+    {
+        PyErr_SetString(PyExc_TypeError, _("The attribute value must be a string."));
+        return -1;
+    }
+
+    portion = G_BIN_PORTION(pygobject_get(self));
+
+    desc = PyUnicode_DATA(value);
+
+    g_binary_portion_set_desc(portion, desc);
+
+    return 0;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : self    = objet Python concerné par l'appel.                 *
+*                closure = non utilisé ici.                                   *
+*                                                                             *
+*  Description : Fournit l'emplacement d'une partie de code binaire.          *
+*                                                                             *
+*  Retour      : Espace de couverture associé à la portion.                   *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static PyObject *py_binary_portion_get_range(PyObject *self, void *closure)
+{
+    PyObject *result;                       /* Résultat à retourner        */
+    GBinPortion *portion;                   /* Version GLib du type        */
+    const mrange_t *range;                  /* Espace de couverture        */
+
+    portion = G_BIN_PORTION(pygobject_get(self));
+
+    range = g_binary_portion_get_range(portion);
+
+    result = build_from_internal_mrange(range);
+
+    return result;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : self    = objet Python concerné par l'appel.                 *
+*                closure = non utilisé ici.                                   *
+*                                                                             *
+*  Description : Indique la nature de la portion en terme d'originalité.      *
+*                                                                             *
+*  Retour      : True si la portion est la suite d'une portion découpée.      *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static PyObject *py_binary_portion_get_continuation(PyObject *self, void *closure)
+{
+    PyObject *result;                       /* Résultat à retourner        */
+    GBinPortion *portion;                   /* Version GLib du type        */
+    bool status;                            /* Bilan d'une consultation    */
+
+    portion = G_BIN_PORTION(pygobject_get(self));
+
+    status = g_binary_portion_is_continuation(portion);
+
+    result = status ? Py_True : Py_False;
+    Py_INCREF(result);
+
+    return result;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : self    = objet Python concerné par l'appel.                 *
+*                value   = valeur fournie à intégrer ou prendre en compte.    *
+*                closure = non utilisé ici.                                   *
+*                                                                             *
+*  Description : Définit la nature de la portion en terme d'originalité.      *
+*                                                                             *
+*  Retour      : 0.                                                           *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static int py_binary_portion_set_continuation(PyObject *self, PyObject *value, void *closure)
+{
+    GBinPortion *portion;                   /* Version GLib du type        */
+    bool status;                            /* Valeur à manipuler          */
+
+    if (!PyBool_Check(value))
+    {
+        PyErr_SetString(PyExc_TypeError, _("The attribute value must be a boolean."));
+        return -1;
+    }
+
+    portion = G_BIN_PORTION(pygobject_get(self));
+
+    status = (value == Py_True);
+
+    g_binary_portion_mark_as_continued(portion, status);
+
+    return 0;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : self    = objet Python concerné par l'appel.                 *
+*                closure = non utilisé ici.                                   *
+*                                                                             *
+*  Description : Fournit les droits associés à une partie de code.            *
+*                                                                             *
+*  Retour      : Droits d'accès de la partie.                                 *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static PyObject *py_binary_portion_get_rights(PyObject *self, void *closure)
+{
+    PyObject *result;                       /* Résultat à retourner        */
+    GBinPortion *portion;                   /* Version GLib du type        */
+    PortionAccessRights rights;             /* Bilan d'une consultation    */
+
+    portion = G_BIN_PORTION(pygobject_get(self));
+
+    rights = g_binary_portion_get_rights(portion);
+
+    result = PyLong_FromUnsignedLong(rights);
+
+    return result;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : self    = objet Python concerné par l'appel.                 *
+*                value   = valeur fournie à intégrer ou prendre en compte.    *
+*                closure = non utilisé ici.                                   *
+*                                                                             *
+*  Description : Définit les droits associés à une partie de code.            *
+*                                                                             *
+*  Retour      : 0.                                                           *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static int py_binary_portion_set_rights(PyObject *self, PyObject *value, void *closure)
+{
+    GBinPortion *portion;                   /* Version GLib du type        */
+    unsigned long rights;                   /* Valeur à manipuler          */
+
+    if (!PyLong_Check(value))
+    {
+        PyErr_SetString(PyExc_TypeError, _("The attribute value must be an integer value (PAC_*)."));
+        return -1;
+    }
+
+    rights = PyLong_AsUnsignedLong(value);
+
+    if ((rights & ~PAC_ALL) != 0)
+    {
+        PyErr_SetString(PyExc_TypeError, _("Invalid attribute value."));
+        return -1;
+    }
+
+    portion = G_BIN_PORTION(pygobject_get(self));
+
+    g_binary_portion_set_rights(portion, rights);
+
+    return 0;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : obj_type = type dont le dictionnaire est à compléter.        *
+*                                                                             *
+*  Description : Définit les constantes pour les portions de binaire.         *
+*                                                                             *
+*  Retour      : true en cas de succès de l'opération, false sinon.           *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static bool py_binary_portion_define_constants(PyTypeObject *obj_type)
+{
+    bool result;                            /* Bilan à retourner           */
+
+    result = true;
+
+    if (result) result = PyDict_AddStringMacro(obj_type, BPC_RAW);
+    if (result) result = PyDict_AddStringMacro(obj_type, BPC_CODE);
+    if (result) result = PyDict_AddStringMacro(obj_type, BPC_DATA);
+    if (result) result = PyDict_AddStringMacro(obj_type, BPC_DATA_RO);
+    if (result) result = PyDict_AddStringMacro(obj_type, BPC_DISASS_ERROR);
+
+    if (result) result = PyDict_AddULongMacro(obj_type, PAC_NONE);
+    if (result) result = PyDict_AddULongMacro(obj_type, PAC_READ);
+    if (result) result = PyDict_AddULongMacro(obj_type, PAC_WRITE);
+    if (result) result = PyDict_AddULongMacro(obj_type, PAC_EXEC);
+    if (result) result = PyDict_AddULongMacro(obj_type, PAC_ALL);
+
+    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_binary_portion_type(void)
+{
+    static PyMethodDef py_binary_portion_methods[] = {
+        {
+            "limit_range", py_binary_portion_limit_range,
+            METH_VARARGS,
+            "limit_range($self, maxsz, /)\n--\n\nEnsure the portion range does not cross a boundary size."
+        },
+        {
+            "include", py_binary_portion_include,
+            METH_VARARGS,
+            "include($self, other, /)\n--\n\nInclude another binary portion as a child item."
+        },
+        { NULL }
+    };
+
+    static PyGetSetDef py_binary_portion_getseters[] = {
+        {
+            "desc", py_binary_portion_get_desc, py_binary_portion_set_desc,
+            "Human description for the binary portion.", NULL
+        },
+        {
+            "range", py_binary_portion_get_range, NULL,
+            "Area registered for the binary portion.", NULL
+        },
+        {
+            "continuation", py_binary_portion_get_continuation, py_binary_portion_set_continuation,
+            "Tell if the current portion is a continuation of another one.", NULL
+        },
+        {
+            "rights", py_binary_portion_get_rights, py_binary_portion_set_rights,
+            "Access rights declared for the binary portion.", NULL
+        },
+        { NULL }
+    };
+
+    static PyTypeObject py_binary_portion_type = {
+
+        PyVarObject_HEAD_INIT(NULL, 0)
+
+        .tp_name        = "pychrysalide.glibext.BinPortion",
+        .tp_basicsize   = sizeof(PyGObject),
+
+        .tp_flags       = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
+
+        .tp_doc         = "PyChrysalide binary portion",
+
+        .tp_richcompare = py_binary_portion_richcompare,
+
+        .tp_methods     = py_binary_portion_methods,
+        .tp_getset      = py_binary_portion_getseters,
+
+        .tp_init        = py_bin_portion_init,
+        .tp_new         = py_bin_portion_new,
+
+    };
+
+    return &py_binary_portion_type;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : module = module dont la définition est à compléter.          *
+*                                                                             *
+*  Description : Prend en charge l'objet 'pychrysalide.glibext.BinPortion'.   *
+*                                                                             *
+*  Retour      : Bilan de l'opération.                                        *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+bool ensure_python_binary_portion_is_registered(void)
+{
+    PyTypeObject *type;                     /* Type Python 'BinPortion'    */
+    PyObject *module;                       /* Module à recompléter        */
+    PyObject *dict;                         /* Dictionnaire du module      */
+
+    type = get_python_binary_portion_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_BIN_PORTION, type, &PyGObject_Type))
+            return false;
+
+        if (!py_binary_portion_define_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 portion de binaire.                    *
+*                                                                             *
+*  Retour      : Bilan de l'opération, voire indications supplémentaires.     *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+int convert_to_binary_portion(PyObject *arg, void *dst)
+{
+    int result;                             /* Bilan à retourner           */
+
+    result = PyObject_IsInstance(arg, (PyObject *)get_python_binary_portion_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 binary portion");
+            break;
+
+        case 1:
+            *((GBinPortion **)dst) = G_BIN_PORTION(pygobject_get(arg));
+            break;
+
+        default:
+            assert(false);
+            break;
+
+    }
+
+    return result;
+
+}
diff --git a/plugins/pychrysalide/glibext/binportion.h b/plugins/pychrysalide/glibext/binportion.h
new file mode 100644
index 0000000..0160686
--- /dev/null
+++ b/plugins/pychrysalide/glibext/binportion.h
@@ -0,0 +1,45 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * binportion.h - prototypes pour l'équivalent Python du fichier "glibext/gbinportion.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_BINPORTION_H
+#define _PLUGINS_PYCHRYSALIDE_GLIBEXT_BINPORTION_H
+
+
+#include <Python.h>
+#include <stdbool.h>
+
+
+
+/* Fournit un accès à une définition de type à diffuser. */
+PyTypeObject *get_python_binary_portion_type(void);
+
+/* Prend en charge l'objet 'pychrysalide.glibext.BinPortion'. */
+bool ensure_python_binary_portion_is_registered(void);
+
+/* Tente de convertir en portion de binaire. */
+int convert_to_binary_portion(PyObject *, void *);
+
+
+
+#endif  /* _PLUGINS_PYCHRYSALIDE_GLIBEXT_BINPORTION_H */
diff --git a/plugins/pychrysalide/glibext/module.c b/plugins/pychrysalide/glibext/module.c
index f1c0bbb..a30d200 100644
--- a/plugins/pychrysalide/glibext/module.c
+++ b/plugins/pychrysalide/glibext/module.c
@@ -28,6 +28,7 @@
 #include <assert.h>
 
 
+#include "binportion.h"
 #include "buffercache.h"
 #include "bufferline.h"
 #include "bufferview.h"
@@ -94,6 +95,7 @@ bool populate_glibext_module(void)
 
     result = true;
 
+    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();
     if (result) result = ensure_python_buffer_view_is_registered();
diff --git a/src/glibext/Makefile.am b/src/glibext/Makefile.am
index 11d2baf..127f60c 100644
--- a/src/glibext/Makefile.am
+++ b/src/glibext/Makefile.am
@@ -9,6 +9,7 @@ libglibext_la_SOURCES =					\
 	delayed-int.h						\
 	delayed.h delayed.c					\
 	gbinarycursor.h gbinarycursor.c		\
+	gbinportion-int.h					\
 	gbinportion.h gbinportion.c			\
 	gbuffercache.h gbuffercache.c		\
 	gbufferline.h gbufferline.c			\
diff --git a/src/glibext/gbinportion-int.h b/src/glibext/gbinportion-int.h
new file mode 100644
index 0000000..b5c70c8
--- /dev/null
+++ b/src/glibext/gbinportion-int.h
@@ -0,0 +1,64 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * binportion.h - prototypes pour la définition interne des portions de binaire
+ *
+ * Copyright (C) 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 Chrysalide.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#ifndef _GLIBEXT_BINPORTION_INT_H
+#define _GLIBEXT_BINPORTION_INT_H
+
+
+#include "gbinportion.h"
+
+
+
+/* Portion de données binaires quelconques (instance) */
+struct _GBinPortion
+{
+    GObject parent;                         /* A laisser en premier        */
+
+    char *code;                             /* Code de la couleur de fond  */
+
+    cairo_surface_t *icon;                  /* Image de représentation     */
+
+    char *desc;                             /* Désignation humaine         */
+    char **text;                            /* Lignes brutes à représenter */
+    size_t lcount;                          /* Quantité de ces lignes      */
+
+    mrange_t range;                         /* Emplacement dans le code    */
+    bool continued;                         /* Suite d'une découpe ?       */
+
+    PortionAccessRights rights;             /* Droits d'accès              */
+
+    GBinPortion **subs;                     /* Portions incluses           */
+    size_t count;                           /* Quantité d'inclusions       */
+
+};
+
+/* Portion de données binaires quelconques (classe) */
+struct _GBinPortionClass
+{
+    GObjectClass parent;                    /* A laisser en premier        */
+
+};
+
+
+
+#endif  /* _GLIBEXT_BINPORTION_INT_H */
diff --git a/src/glibext/gbinportion.c b/src/glibext/gbinportion.c
index 8826bd3..e020506 100644
--- a/src/glibext/gbinportion.c
+++ b/src/glibext/gbinportion.c
@@ -34,6 +34,7 @@
 #include <i18n.h>
 
 
+#include "gbinportion-int.h"
 #include "../analysis/human/asm/lang.h"
 #include "../common/extstr.h"
 #include "../common/sort.h"
@@ -45,37 +46,6 @@
 /* ------------------------------- PORTION DE BINAIRE ------------------------------- */
 
 
-/* Portion de données binaires quelconques (instance) */
-struct _GBinPortion
-{
-    GObject parent;                         /* A laisser en premier        */
-
-    char *code;                             /* Code de la couleur de fond  */
-
-    cairo_surface_t *icon;                  /* Image de représentation     */
-
-    char *desc;                             /* Désignation humaine         */
-    char **text;                            /* Lignes brutes à représenter */
-    size_t lcount;                          /* Quantité de ces lignes      */
-
-    mrange_t range;                         /* Emplacement dans le code    */
-    bool continued;                         /* Suite d'une découpe ?       */
-
-    PortionAccessRights rights;             /* Droits d'accès              */
-
-    GBinPortion **subs;                     /* Portions incluses           */
-    size_t count;                           /* Quantité d'inclusions       */
-
-};
-
-/* Portion de données binaires quelconques (classe) */
-struct _GBinPortionClass
-{
-    GObjectClass parent;                    /* A laisser en premier        */
-
-};
-
-
 /* Initialise la classe des portions de données binaires. */
 static void g_binary_portion_class_init(GBinPortionClass *);
 
@@ -179,10 +149,17 @@ static void g_binary_portion_class_init(GBinPortionClass *klass)
 
 static void g_binary_portion_init(GBinPortion *portion)
 {
+    vmpa2t dummy;                           /* Coquille presque vide       */
+
+    portion->code = NULL;
+
     portion->desc = NULL;
     portion->text = NULL;
     portion->lcount = 0;
 
+    init_vmpa(&dummy, VMPA_NO_PHYSICAL, VMPA_NO_VIRTUAL);
+    init_mrange(&portion->range, &dummy, VMPA_NO_VIRTUAL);
+
     portion->continued = false;
 
 }
@@ -246,7 +223,8 @@ static void g_binary_portion_finalize(GBinPortion *portion)
 {
     size_t i;                               /* Boucle de parcours          */
 
-    free(portion->code);
+    if (portion->code != NULL)
+        free(portion->code);
 
     if (portion->icon != NULL)
         cairo_surface_destroy(portion->icon);
@@ -480,7 +458,7 @@ const char *g_binary_portion_get_desc(const GBinPortion *portion)
 *                                                                             *
 *  Description : Fournit l'emplacement d'une partie de code binaire.          *
 *                                                                             *
-*  Retour      : -                                                            *
+*  Retour      : Espace de couverture associé à la portion.                   *
 *                                                                             *
 *  Remarques   : -                                                            *
 *                                                                             *
@@ -748,7 +726,8 @@ void g_binary_portion_draw(const GBinPortion *portion, GtkStyleContext *context,
 
     gtk_style_context_save(context);
 
-    gtk_style_context_add_class(context, portion->code);
+    if (portion->code != NULL)
+        gtk_style_context_add_class(context, portion->code);
 
     gtk_render_background(context, cr, area->x, area->y, area->width, area->height);
 
diff --git a/src/glibext/gbinportion.h b/src/glibext/gbinportion.h
index 5c8c363..e20e159 100644
--- a/src/glibext/gbinportion.h
+++ b/src/glibext/gbinportion.h
@@ -75,6 +75,9 @@ typedef enum _PortionAccessRights
 } PortionAccessRights;
 
 
+#define PAC_ALL ((PortionAccessRights)(PAC_READ | PAC_WRITE | PAC_EXEC))
+
+
 /* Indique le type défini par la GLib pour les portions de données binaires. */
 GType g_binary_portion_get_type(void);
 
diff --git a/tests/glibext/__init__.py b/tests/glibext/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/tests/glibext/binportion.py b/tests/glibext/binportion.py
new file mode 100644
index 0000000..a95352e
--- /dev/null
+++ b/tests/glibext/binportion.py
@@ -0,0 +1,60 @@
+#!/usr/bin/python3-dbg
+# -*- coding: utf-8 -*-
+
+
+from chrysacase import ChrysalideTestCase
+from pychrysalide.arch import vmpa
+from pychrysalide.glibext import BinPortion
+
+
+class TestPathNames(ChrysalideTestCase):
+    """TestCase for glibext.BinPortion*"""
+
+
+    def testPortionProperties(self):
+        """Validate various binary portion properties."""
+
+        p = BinPortion(BinPortion.BPC_RAW, 0x102, 10)
+
+        p.desc = 'ABC'
+        self.assertEqual(p.desc, 'ABC')
+
+        self.assertEqual(p.range.addr.phys, None)
+        self.assertEqual(p.range.addr.virt, 0x102)
+        self.assertEqual(p.range.length, 10)
+
+        p.continuation = True
+        self.assertTrue(p.continuation)
+
+        p.continuation = False
+        self.assertFalse(p.continuation)
+
+        p.rights = BinPortion.PAC_ALL
+        self.assertEqual(p.rights, BinPortion.PAC_READ | BinPortion.PAC_WRITE | BinPortion.PAC_EXEC)
+
+
+    def testPortionMethods(self):
+        """Validate some binary portion methods."""
+
+        p = BinPortion(BinPortion.BPC_RAW, 0x102, 10)
+
+        self.assertEqual(p.range.length, 10)
+
+        p.limit_range(10)
+
+        self.assertEqual(p.range.length, 10)
+
+        p.limit_range(6)
+
+        self.assertEqual(p.range.length, 6)
+
+
+    def testPortionComparison(self):
+        """Compare different binary portions."""
+
+        p0 = BinPortion(BinPortion.BPC_CODE, 0x102, 10)
+
+        addr = vmpa(vmpa.VMPA_NO_PHYSICAL, 0x102)
+        p1 = BinPortion(BinPortion.BPC_CODE, addr, 10)
+
+        self.assertEqual(p0, p1)
-- 
cgit v0.11.2-87-g4458