From 90d1fa65a1d13128a66117095a44224e8c9de656 Mon Sep 17 00:00:00 2001
From: Cyrille Bagard <nocbos@gmail.com>
Date: Tue, 12 May 2020 23:15:45 +0200
Subject: Described the Python API for binary portions.

---
 plugins/pychrysalide/format/symbol.c      |   4 +-
 plugins/pychrysalide/glibext/binportion.c | 131 +++++++++++++++++++-----------
 plugins/pychrysalide/glibext/constants.c  |  97 ++++++++++++++++++++++
 plugins/pychrysalide/glibext/constants.h  |   6 ++
 plugins/pychrysalide/glibext/module.c     |   9 +-
 plugins/pychrysalide/gui/module.c         |   2 +-
 6 files changed, 197 insertions(+), 52 deletions(-)

diff --git a/plugins/pychrysalide/format/symbol.c b/plugins/pychrysalide/format/symbol.c
index 71832cb..c86b453 100644
--- a/plugins/pychrysalide/format/symbol.c
+++ b/plugins/pychrysalide/format/symbol.c
@@ -525,7 +525,9 @@ static PyObject *py_binary_symbol_get_range(PyObject *self, void *closure)
 #define BINARY_SYMBOL_RANGE_ATTRIB PYTHON_GETSET_DEF_FULL   \
 (                                                           \
     range, py_binary_symbol,                                \
-    "Memory range covered by the symbol."                   \
+    "Memory range covered by the symbol.\n"                 \
+    "\n"                                                    \
+    "This property is a pychrysalide.arch.mrange instance." \
 )
 
     symbol = G_BIN_SYMBOL(pygobject_get(self));
diff --git a/plugins/pychrysalide/glibext/binportion.c b/plugins/pychrysalide/glibext/binportion.c
index 1119293..14df461 100644
--- a/plugins/pychrysalide/glibext/binportion.c
+++ b/plugins/pychrysalide/glibext/binportion.c
@@ -33,6 +33,7 @@
 #include <plugins/dt.h>
 
 
+#include "constants.h"
 #include "../access.h"
 #include "../helpers.h"
 #include "../arch/vmpa.h"
@@ -51,8 +52,6 @@ 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 *);
 
@@ -165,6 +164,19 @@ static int py_bin_portion_init(PyObject *self, PyObject *args, PyObject *kwds)
 
     static char *kwlist[] = { "code", "addr", "size", NULL };
 
+#define BINARY_PORTION_DOC                                                      \
+    "The BinPortion object handles parts of binaries usually formally"          \
+    " identified in binary formats, like program segments or sections for ELF"  \
+    " files for example.\n"                                                     \
+    "\n"                                                                        \
+    "Instances can be created using the following constructor:\n"               \
+    "\n"                                                                        \
+    "    BinPortion(code, addr, size)"                                          \
+    "\n"                                                                        \
+    "Where code is the CSS class style for the rendering color to use, addr is" \
+    " the starting point of the portion in memory, as a pychrysalide.arch.vmpa" \
+    " value, and size is the size of the portion."                              \
+
     /* Récupération des paramètres */
 
     ret = PyArg_ParseTupleAndKeywords(args, kwds, "sO&K", kwlist,
@@ -268,6 +280,19 @@ static PyObject *py_binary_portion_limit_range(PyObject *self, PyObject *args)
     GBinPortion *portion;                   /* Version GLib du type        */
     bool status;                            /* Bilan de la modification    */
 
+#define BINARY_SYMBOL_LIMIT_RANGE_METHOD PYTHON_METHOD_DEF          \
+(                                                                   \
+    limit_range, "$self, max, /",                                   \
+    METH_VARARGS, py_binary_portion,                                \
+    "Ensure the portion range does not cross a boundary size.\n"    \
+    "\n"                                                            \
+    "An integer value is expected as the maximum size of the"       \
+    " portion.\n"                                                   \
+    "\n"                                                            \
+    "A boolean value indicating the success of the operation is"    \
+    " returned."                                                    \
+)
+
     ret = PyArg_ParseTuple(args, "K", &max);
     if (!ret) return NULL;
 
@@ -302,6 +327,16 @@ static PyObject *py_binary_portion_include(PyObject *self, PyObject *args)
     int ret;                                /* Bilan de lecture des args.  */
     GBinPortion *portion;                   /* Version GLib du type        */
 
+#define BINARY_SYMBOL_INCLUDE_METHOD PYTHON_METHOD_DEF              \
+(                                                                   \
+    include, "$self, sub, /",                                       \
+    METH_VARARGS, py_binary_portion,                                \
+    "Include another binary portion as a child item.\n"             \
+    "\n"                                                            \
+    "The sub portion has to be a pychrysalide.glibext.BinPortion"   \
+    " instance."                                                    \
+)
+
     ret = PyArg_ParseTuple(args, "O&", convert_to_binary_portion, &sub);
     if (!ret) return NULL;
 
@@ -334,6 +369,13 @@ static PyObject *py_binary_portion_get_desc(PyObject *self, void *closure)
     GBinPortion *portion;                   /* Version GLib du type        */
     const char *desc;                       /* Description récupérée       */
 
+#define BINARY_PORTION_DESC_ATTRIB PYTHON_GETSET_DEF_FULL   \
+(                                                           \
+    desc, py_binary_portion,                                \
+    "Human description for the binary portion, as a"        \
+    " simple string."                                       \
+)
+
     portion = G_BIN_PORTION(pygobject_get(self));
 
     desc = g_binary_portion_get_desc(portion);
@@ -400,6 +442,14 @@ static PyObject *py_binary_portion_get_range(PyObject *self, void *closure)
     GBinPortion *portion;                   /* Version GLib du type        */
     const mrange_t *range;                  /* Espace de couverture        */
 
+#define BINARY_PORTION_RANGE_ATTRIB PYTHON_GET_DEF_FULL     \
+(                                                           \
+    range, py_binary_portion,                               \
+    "Area covered by the binary portion.\n"                 \
+    "\n"                                                    \
+    "This property is a pychrysalide.arch.mrange instance." \
+)
+
     portion = G_BIN_PORTION(pygobject_get(self));
 
     range = g_binary_portion_get_range(portion);
@@ -430,6 +480,16 @@ static PyObject *py_binary_portion_get_continuation(PyObject *self, void *closur
     GBinPortion *portion;                   /* Version GLib du type        */
     bool status;                            /* Bilan d'une consultation    */
 
+#define BINARY_PORTION_CONTINUATION_ATTRIB PYTHON_GETSET_DEF_FULL   \
+(                                                                   \
+    continuation, py_binary_portion,                                \
+    "Tell if the current portion is a continuation of another"      \
+    " one.\n"                                                       \
+    "\n"                                                            \
+    "If a section belongs to several parents, it is cut into"       \
+    " several parts when included in the portion tree."             \
+)
+
     portion = G_BIN_PORTION(pygobject_get(self));
 
     status = g_binary_portion_is_continuation(portion);
@@ -497,11 +557,18 @@ static PyObject *py_binary_portion_get_rights(PyObject *self, void *closure)
     GBinPortion *portion;                   /* Version GLib du type        */
     PortionAccessRights rights;             /* Bilan d'une consultation    */
 
+#define BINARY_PORTION_RIGHTS_ATTRIB PYTHON_GETSET_DEF_FULL         \
+(                                                                   \
+    rights, py_binary_portion,                                      \
+    "Access rights declared for the binary portion, as a"           \
+    " pychrysalide.glibext.BinPortion.PortionAccessRights value."   \
+)
+
     portion = G_BIN_PORTION(pygobject_get(self));
 
     rights = g_binary_portion_get_rights(portion);
 
-    result = PyLong_FromUnsignedLong(rights);
+    result = cast_with_constants_group_from_type(get_python_binary_portion_type(), "PortionAccessRights", rights);
 
     return result;
 
@@ -525,21 +592,10 @@ static PyObject *py_binary_portion_get_rights(PyObject *self, void *closure)
 static int py_binary_portion_set_rights(PyObject *self, PyObject *value, void *closure)
 {
     GBinPortion *portion;                   /* Version GLib du type        */
-    unsigned long rights;                   /* Valeur à manipuler          */
+    PortionAccessRights rights;             /* Valeur à manipuler          */
 
-    if (!PyLong_Check(value))
-    {
-        PyErr_SetString(PyExc_TypeError, _("The attribute value must be an integer value (PAC_*)."));
+    if (convert_to_portion_access_rights(value, &rights) != 1)
         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));
 
@@ -574,12 +630,6 @@ static bool py_binary_portion_define_constants(PyTypeObject *obj_type)
     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;
 
 }
@@ -600,36 +650,16 @@ static bool py_binary_portion_define_constants(PyTypeObject *obj_type)
 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."
-        },
+        BINARY_SYMBOL_LIMIT_RANGE_METHOD,
+        BINARY_SYMBOL_INCLUDE_METHOD,
         { 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
-        },
+        BINARY_PORTION_DESC_ATTRIB,
+        BINARY_PORTION_RANGE_ATTRIB,
+        BINARY_PORTION_CONTINUATION_ATTRIB,
+        BINARY_PORTION_RIGHTS_ATTRIB,
         { NULL }
     };
 
@@ -642,7 +672,7 @@ PyTypeObject *get_python_binary_portion_type(void)
 
         .tp_flags       = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
 
-        .tp_doc         = "PyChrysalide binary portion",
+        .tp_doc         = BINARY_PORTION_DOC,
 
         .tp_richcompare = py_binary_portion_richcompare,
 
@@ -691,6 +721,9 @@ bool ensure_python_binary_portion_is_registered(void)
         if (!py_binary_portion_define_constants(type))
             return false;
 
+        if (!define_binary_portion_constants(type))
+            return false;
+
     }
 
     return true;
diff --git a/plugins/pychrysalide/glibext/constants.c b/plugins/pychrysalide/glibext/constants.c
index 823465a..680feaf 100644
--- a/plugins/pychrysalide/glibext/constants.c
+++ b/plugins/pychrysalide/glibext/constants.c
@@ -26,6 +26,7 @@
 
 
 #include <glibext/linesegment.h>
+#include <glibext/gbinportion.h>
 #include <glibext/gbufferline.h>
 
 
@@ -37,6 +38,102 @@
 *                                                                             *
 *  Paramètres  : type = type dont le dictionnaire est à compléter.            *
 *                                                                             *
+*  Description : Définit les constantes relatives aux portions de binaires.   *
+*                                                                             *
+*  Retour      : true en cas de succès de l'opération, false sinon.           *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+bool define_binary_portion_constants(PyTypeObject *type)
+{
+    bool result;                            /* Bilan à retourner           */
+    PyObject *values;                       /* Groupe de valeurs à établir */
+
+    values = PyDict_New();
+
+    result = add_const_to_group(values, "NONE", PAC_NONE);
+    if (result) result = add_const_to_group(values, "READ", PAC_READ);
+    if (result) result = add_const_to_group(values, "WRITE", PAC_WRITE);
+    if (result) result = add_const_to_group(values, "EXEC", PAC_EXEC);
+
+    if (!result)
+    {
+        Py_DECREF(values);
+        goto exit;
+    }
+
+    result = attach_constants_group_to_type(type, false, "PortionAccessRights", values,
+                                            "Access rights for binary portions.");
+
+ exit:
+
+    return result;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : arg = argument quelconque à tenter de convertir.             *
+*                dst = destination des valeurs récupérées en cas de succès.   *
+*                                                                             *
+*  Description : Tente de convertir en constante PortionAccessRights.         *
+*                                                                             *
+*  Retour      : Bilan de l'opération, voire indications supplémentaires.     *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+int convert_to_portion_access_rights(PyObject *arg, void *dst)
+{
+    int result;                             /* Bilan à retourner           */
+    unsigned long value;                    /* Valeur récupérée            */
+
+    result = PyObject_IsInstance(arg, (PyObject *)&PyLong_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 PortionAccessRights");
+            break;
+
+        case 1:
+            value = PyLong_AsUnsignedLong(arg);
+
+            if ((value & ~PAC_ALL) != 0)
+            {
+                PyErr_SetString(PyExc_TypeError, "unable to convert the provided argument to PortionAccessRights");
+                result = 0;
+            }
+
+            else
+                *((PortionAccessRights *)dst) = value;
+
+            break;
+
+        default:
+            assert(false);
+            break;
+
+    }
+
+    return result;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : type = type dont le dictionnaire est à compléter.            *
+*                                                                             *
 *  Description : Définit les constantes relatives aux segments de ligne.      *
 *                                                                             *
 *  Retour      : true en cas de succès de l'opération, false sinon.           *
diff --git a/plugins/pychrysalide/glibext/constants.h b/plugins/pychrysalide/glibext/constants.h
index a1c56af..b815586 100644
--- a/plugins/pychrysalide/glibext/constants.h
+++ b/plugins/pychrysalide/glibext/constants.h
@@ -31,6 +31,12 @@
 
 
 
+/* Définit les constantes relatives aux portions de binaires. */
+bool define_binary_portion_constants(PyTypeObject *);
+
+/* Tente de convertir en constante PortionAccessRights. */
+int convert_to_portion_access_rights(PyObject *, void *);
+
 /* Définit les constantes relatives aux segments de ligne. */
 bool define_line_segment_constants(PyTypeObject *);
 
diff --git a/plugins/pychrysalide/glibext/module.c b/plugins/pychrysalide/glibext/module.c
index ff0a1bd..b45da4d 100644
--- a/plugins/pychrysalide/glibext/module.c
+++ b/plugins/pychrysalide/glibext/module.c
@@ -58,12 +58,19 @@ bool add_glibext_module(PyObject *super)
     bool result;                            /* Bilan à retourner           */
     PyObject *module;                       /* Sous-module mis en place    */
 
+#define PYCHRYSALIDE_GLIBEXT_DOC                                        \
+    "This module contains the definition of some objects derived from"  \
+    " the GObject structure.\n"                                         \
+    "\n"                                                                \
+    "These common objects are used in several places inside Chrysalide" \
+    " and could be seen as extensions to the GLib API."
+
     static PyModuleDef py_chrysalide_glibext_module = {
 
         .m_base = PyModuleDef_HEAD_INIT,
 
         .m_name = "pychrysalide.glibext",
-        .m_doc = "Python module for Chrysalide.glibext",
+        .m_doc  = PYCHRYSALIDE_GLIBEXT_DOC,
 
         .m_size = -1,
 
diff --git a/plugins/pychrysalide/gui/module.c b/plugins/pychrysalide/gui/module.c
index a2699b4..9c06940 100644
--- a/plugins/pychrysalide/gui/module.c
+++ b/plugins/pychrysalide/gui/module.c
@@ -62,7 +62,7 @@ bool add_gui_module(PyObject *super)
         .m_base = PyModuleDef_HEAD_INIT,
 
         .m_name = "pychrysalide.gui",
-        .m_doc = PYCHRYSALIDE_GUI_DOC,
+        .m_doc  = PYCHRYSALIDE_GUI_DOC,
 
         .m_size = -1,
 
-- 
cgit v0.11.2-87-g4458