From 0b0f69bd1278b8f5d95c6ea8fb56915148992a77 Mon Sep 17 00:00:00 2001
From: Cyrille Bagard <nocbos@gmail.com>
Date: Sat, 10 Oct 2020 14:01:40 +0200
Subject: Updated the basic types definition and its Python bindings.

---
 plugins/pychrysalide/analysis/constants.c |  98 +++++
 plugins/pychrysalide/analysis/constants.h |   6 +
 plugins/pychrysalide/analysis/type.c      | 707 +++++++++++++++++++++++++++---
 plugins/pychrysalide/analysis/type.h      |   3 +
 plugins/pychrysalide/helpers.c            |  50 +++
 plugins/pychrysalide/helpers.h            |  22 +
 src/analysis/type-int.h                   |   6 +-
 src/analysis/type.c                       |  33 +-
 src/analysis/type.h                       |   3 +
 src/analysis/types/proto.c                |  30 +-
 tests/analysis/type.py                    |  92 ++++
 11 files changed, 973 insertions(+), 77 deletions(-)
 create mode 100644 tests/analysis/type.py

diff --git a/plugins/pychrysalide/analysis/constants.c b/plugins/pychrysalide/analysis/constants.c
index dc507dc..8d68edc 100644
--- a/plugins/pychrysalide/analysis/constants.c
+++ b/plugins/pychrysalide/analysis/constants.c
@@ -25,6 +25,7 @@
 #include "constants.h"
 
 
+#include <analysis/type.h>
 #include <common/endianness.h>
 
 
@@ -212,3 +213,100 @@ int convert_to_memory_data_size(PyObject *arg, void *dst)
     return result;
 
 }
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : type = type dont le dictionnaire est à compléter.            *
+*                                                                             *
+*  Description : Définit les constantes pour les types de données.            *
+*                                                                             *
+*  Retour      : true en cas de succès de l'opération, false sinon.           *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+bool define_analysis_data_type_constants(PyTypeObject *type)
+{
+    bool result;                            /* Bilan à retourner           */
+    PyObject *values;                       /* Groupe de valeurs à établir */
+
+    values = PyDict_New();
+
+    result = add_const_to_group(values, "NONE", TQF_NONE);
+    if (result) result = add_const_to_group(values, "RESTRICT", TQF_RESTRICT);
+    if (result) result = add_const_to_group(values, "VOLATILE", TQF_VOLATILE);
+    if (result) result = add_const_to_group(values, "CONST", TQF_CONST);
+    if (result) result = add_const_to_group(values, "ALL", TQF_ALL);
+
+    if (!result)
+    {
+        Py_DECREF(values);
+        goto exit;
+    }
+
+    result = attach_constants_group_to_type(type, false, "TypeQualifier", values,
+                                            "Qualifier for a data type.");
+
+ 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 TypeQualifier.               *
+*                                                                             *
+*  Retour      : Bilan de l'opération, voire indications supplémentaires.     *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+int convert_to_data_type_qualifier(PyObject *arg, void *dst)
+{
+    int result;                             /* Bilan à retourner           */
+    unsigned long value;                    /* Valeur transcrite           */
+
+    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 TypeQualifier");
+            break;
+
+        case 1:
+            value = PyLong_AsUnsignedLong(arg);
+
+            if ((value & ~TQF_ALL) != 0)
+            {
+                PyErr_SetString(PyExc_TypeError, "invalid value for TypeQualifier");
+                result = 0;
+            }
+
+            else
+                *((TypeQualifier *)dst) = value;
+
+            break;
+
+        default:
+            assert(false);
+            break;
+
+    }
+
+    return result;
+
+}
diff --git a/plugins/pychrysalide/analysis/constants.h b/plugins/pychrysalide/analysis/constants.h
index 45982bb..fb96e99 100644
--- a/plugins/pychrysalide/analysis/constants.h
+++ b/plugins/pychrysalide/analysis/constants.h
@@ -39,6 +39,12 @@ int convert_to_source_endian(PyObject *, void *);
 /* Tente de convertir en constante MemoryDataSize. */
 int convert_to_memory_data_size(PyObject *, void *);
 
+/* Définit les constantes pour les types de données. */
+bool define_analysis_data_type_constants(PyTypeObject *);
+
+/* Tente de convertir en constante TypeQualifier. */
+int convert_to_data_type_qualifier(PyObject *, void *);
+
 
 
 #endif  /* _PLUGINS_PYCHRYSALIDE_ANALYSIS_CONSTANTS_H */
diff --git a/plugins/pychrysalide/analysis/type.c b/plugins/pychrysalide/analysis/type.c
index 6043042..cd849e4 100644
--- a/plugins/pychrysalide/analysis/type.c
+++ b/plugins/pychrysalide/analysis/type.c
@@ -33,17 +33,54 @@
 #include <i18n.h>
 
 
-#include <analysis/type.h>
+#include <analysis/type-int.h>
+#include <plugins/dt.h>
 
 
+#include "constants.h"
 #include "../access.h"
 #include "../helpers.h"
 
 
 
+/* ------------------------ GLUE POUR CREATION DEPUIS PYTHON ------------------------ */
+
+
+/* Accompagne la création d'une instance dérivée en Python. */
+static PyObject *py_data_type_new(PyTypeObject *, PyObject *, PyObject *);
+
+/* Initialise la classe des types quelconques. */
+static void py_data_type_init_gclass(GDataTypeClass *, gpointer);
+
+/* Crée un copie d'un type existant. */
+static GDataType *py_data_type_dup_wrapper(const GDataType *);
+
+/* Décrit le type fourni sous forme de caractères. */
+static char *py_data_type_to_string_wrapper(const GDataType *, bool);
+
+/* Indique si le type assure une gestion des espaces de noms. */
+static bool py_data_type_handle_namespaces_wrapper(const GDataType *);
+
+/* Indique si le type est un pointeur. */
+static bool py_data_type_is_pointer_wrapper(const GDataType *);
+
+/* Indique si le type est une référence. */
+static bool py_data_type_is_reference_wrapper(const GDataType *);
+
+/* Initialise une instance sur la base du dérivé de GObject. */
+static int py_data_type_init(PyObject *, PyObject *, PyObject *);
+
+
+
+/* ----------------- FONCTIONNALITES BASIQUES POUR TYPES DE DONNEES ----------------- */
+
+
 /* Décrit le type fourni sous forme de caractères. */
 static PyObject *py_data_type_to_str(PyObject *);
 
+/* Crée un copie d'un type existant. */
+static PyObject *py_data_type_dup(PyObject *, PyObject *);
+
 /* Fournit le groupe d'appartenance d'un type donné. */
 static PyObject *py_data_type_get_namespace(PyObject *, void *);
 
@@ -56,16 +93,432 @@ static PyObject *py_data_type_get_qualifiers(PyObject *, void *);
 /* Définit l'ensemble des qualificatifs d'une instance de type. */
 static int py_data_type_set_qualifiers(PyObject *, PyObject *, void *);
 
+/* Indique si le type assure une gestion des espaces de noms. */
+static PyObject *py_data_type_handle_namespaces(PyObject *, void *);
+
 /* Indique si le type est un pointeur. */
 static PyObject *py_data_type_is_pointer(PyObject *, void *);
 
 /* Indique si le type est une référence. */
 static PyObject *py_data_type_is_reference(PyObject *, void *);
 
-/* Définit les constantes pour les types de données. */
-static bool py_data_type_define_constants(PyTypeObject *);
 
 
+/* ---------------------------------------------------------------------------------- */
+/*                          GLUE POUR CREATION DEPUIS PYTHON                          */
+/* ---------------------------------------------------------------------------------- */
+
+
+/******************************************************************************
+*                                                                             *
+*  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_data_type_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_data_type_type();
+
+    if (type == base)
+    {
+        result = NULL;
+        PyErr_Format(PyExc_RuntimeError, _("%s is an abstract class"), type->tp_name);
+        goto exit;
+    }
+
+    /* Mise en place d'un type dédié */
+
+    first_time = (g_type_from_name(type->tp_name) == 0);
+
+    gtype = build_dynamic_type(G_TYPE_DATA_TYPE, type->tp_name,
+                               (GClassInitFunc)py_data_type_init_gclass, 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() */
+
+    result = PyType_GenericNew(type, args, kwds);
+
+ exit:
+
+    return result;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : class  = classe à initialiser.                               *
+*                unused = données non utilisées ici.                          *
+*                                                                             *
+*  Description : Initialise la classe des types quelconques.                  *
+*                                                                             *
+*  Retour      : -                                                            *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static void py_data_type_init_gclass(GDataTypeClass *class, gpointer unused)
+{
+    class->dup = py_data_type_dup_wrapper;
+    class->to_string = py_data_type_to_string_wrapper;
+
+    class->handle_ns = py_data_type_handle_namespaces_wrapper;
+    class->is_pointer = py_data_type_is_pointer_wrapper;
+    class->is_reference = py_data_type_is_reference_wrapper;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : type = type à dupliquer.                                     *
+*                                                                             *
+*  Description : Crée un copie d'un type existant.                            *
+*                                                                             *
+*  Retour      : Nouvelle instance de type identique à celle fournie.         *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static GDataType *py_data_type_dup_wrapper(const GDataType *type)
+{
+    GDataType *result;                      /* Copie à retourner           */
+    PyObject *pyobj;                        /* Objet Python concerné       */
+    PyObject *pyret;                        /* Bilan de consultation       */
+
+#define DATA_TYPE_DUP_WRAPPER PYTHON_WRAPPER_DEF                \
+(                                                               \
+    _dup, "$self, /",                                           \
+    METH_NOARGS,                                                \
+    "Abstract method used to create a copy of a data type.\n"   \
+    "\n"                                                        \
+    "The returned value has to be a new instance of the"        \
+    " pychrysalide.analysis.DataType class."                    \
+)
+
+    result = NULL;
+
+    pyobj = pygobject_new(G_OBJECT(type));
+
+    if (has_python_method(pyobj, "_dup"))
+    {
+        pyret = run_python_method(pyobj, "_dup", NULL);
+
+        if (pyret != NULL)
+        {
+            if (PyObject_TypeCheck(pyret, get_python_data_type_type()))
+            {
+                result = G_DATA_TYPE(pygobject_get(pyret));
+                g_object_ref(G_OBJECT(result));
+            }
+        }
+
+        Py_XDECREF(pyret);
+
+    }
+
+    Py_DECREF(pyobj);
+
+    return result;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : type    = type à convertir.                                  *
+*                include = doit-on inclure les espaces de noms ?              *
+*                                                                             *
+*  Description : Décrit le type fourni sous forme de caractères.              *
+*                                                                             *
+*  Retour      : Chaîne à libérer de la mémoire après usage.                  *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static char *py_data_type_to_string_wrapper(const GDataType *type, bool include)
+{
+    char *result;                           /* Etiquette à retourner       */
+    PyObject *pyobj;                        /* Objet Python concerné       */
+    PyObject *arg;                          /* Version Python de l'argument*/
+    PyObject *args;                         /* Arguments pour l'appel      */
+    PyObject *pyret;                        /* Bilan de consultation       */
+
+#define DATA_TYPE_TO_STRING_WRAPPER PYTHON_WRAPPER_DEF              \
+(                                                                   \
+    _to_string, "$self, include, /",                                \
+    METH_VARARGS,                                                   \
+    "Abstract method used to provide the string represention of"    \
+    " a data type.\n"                                               \
+    "\n"                                                            \
+    "The *include* argument defines if the type namespace has to"   \
+    " get prepended, if it exists.\n"                               \
+    "\n"                                                            \
+    "The returned value has to be a string."                        \
+)
+
+    result = NULL;
+
+    pyobj = pygobject_new(G_OBJECT(type));
+
+    if (has_python_method(pyobj, "_to_string"))
+    {
+        arg = include ? Py_True : Py_False;
+        Py_INCREF(arg);
+
+        args = PyTuple_New(1);
+        PyTuple_SetItem(args, 0, arg);
+
+        pyret = run_python_method(pyobj, "_to_string", args);
+
+        if (pyret != NULL)
+        {
+            if (PyUnicode_Check(pyret))
+                result = strdup(PyUnicode_DATA(pyret));
+        }
+
+        Py_XDECREF(pyret);
+
+        Py_DECREF(args);
+
+    }
+
+    Py_DECREF(pyobj);
+
+    return result;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : type = type à consulter.                                     *
+*                                                                             *
+*  Description : Indique si le type assure une gestion des espaces de noms.   *
+*                                                                             *
+*  Retour      : Bilan de la consultation.                                    *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static bool py_data_type_handle_namespaces_wrapper(const GDataType *type)
+{
+    bool result;                            /* Bilan à retourner           */
+    PyObject *pyobj;                        /* Objet Python concerné       */
+    PyObject *pyret;                        /* Bilan de consultation       */
+
+#define DATA_TYPE_HANDLE_NAMESPACES_WRAPPER PYTHON_TRUE_WRAPPER_DEF     \
+(                                                                       \
+    _handle_namespaces, "$self, /",                                     \
+    METH_NOARGS,                                                        \
+    "Abstract method used to state if the type handles namespaces"      \
+    " or not.\n"                                                        \
+    "\n"                                                                \
+    "The return is a boolean value. If this method does not"            \
+    " exist, the True value is assumed."                                \
+)
+
+    result = true;
+
+    pyobj = pygobject_new(G_OBJECT(type));
+
+    if (has_python_method(pyobj, "_handle_namespaces"))
+    {
+        pyret = run_python_method(pyobj, "_handle_namespaces", NULL);
+
+        result = (pyret == Py_True);
+
+        Py_XDECREF(pyret);
+
+    }
+
+    Py_DECREF(pyobj);
+
+    return result;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : type = type à consulter.                                     *
+*                                                                             *
+*  Description : Indique si le type est un pointeur.                          *
+*                                                                             *
+*  Retour      : Bilan de la consultation.                                    *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static bool py_data_type_is_pointer_wrapper(const GDataType *type)
+{
+    bool result;                            /* Bilan à retourner           */
+    PyObject *pyobj;                        /* Objet Python concerné       */
+    PyObject *pyret;                        /* Bilan de consultation       */
+
+#define DATA_TYPE_IS_POINTER_WRAPPER PYTHON_FALSE_WRAPPER_DEF   \
+(                                                               \
+    _is_pointer, "$self, /",                                    \
+    METH_NOARGS,                                                \
+    "Abstract method used to state if the type points to"       \
+    " another type or not.\n"                                   \
+    "\n"                                                        \
+    "The return is a boolean value. If this method does not"    \
+    " exist, the False value is assumed."                       \
+)
+
+    result = false;
+
+    pyobj = pygobject_new(G_OBJECT(type));
+
+    if (has_python_method(pyobj, "_is_pointer"))
+    {
+        pyret = run_python_method(pyobj, "_is_pointer", NULL);
+
+        result = (pyret == Py_True);
+
+        Py_XDECREF(pyret);
+
+    }
+
+    Py_DECREF(pyobj);
+
+    return result;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : type = type à consulter.                                     *
+*                                                                             *
+*  Description : Indique si le type est une référence.                        *
+*                                                                             *
+*  Retour      : Bilan de la consultation.                                    *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static bool py_data_type_is_reference_wrapper(const GDataType *type)
+{
+    bool result;                            /* Bilan à retourner           */
+    PyObject *pyobj;                        /* Objet Python concerné       */
+    PyObject *pyret;                        /* Bilan de consultation       */
+
+#define DATA_TYPE_IS_REFERENCE_WRAPPER PYTHON_FALSE_WRAPPER_DEF \
+(                                                               \
+    _is_reference, "$self, /",                                  \
+    METH_NOARGS,                                                \
+    "Abstract method used to state if the type refers to"       \
+    " another type or not.\n"                                   \
+    "\n"                                                        \
+    "The return is a boolean value. If this method does not"    \
+    " exist, the False value is assumed."                       \
+)
+
+    result = false;
+
+    pyobj = pygobject_new(G_OBJECT(type));
+
+    if (has_python_method(pyobj, "_is_reference"))
+    {
+        pyret = run_python_method(pyobj, "_is_reference", NULL);
+
+        result = (pyret == Py_True);
+
+        Py_XDECREF(pyret);
+
+    }
+
+    Py_DECREF(pyobj);
+
+    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_data_type_init(PyObject *self, PyObject *args, PyObject *kwds)
+{
+    int ret;                                /* Bilan de lecture des args.  */
+
+#define DATA_TYPE_DOC                                                   \
+    "The DataType object is the base class for all data types.\n"       \
+    "\n"                                                                \
+    "Instances can be created using the following constructor:\n"       \
+    "\n"                                                                \
+    "    DataType()"                                                    \
+    "\n"                                                                \
+    "The following methods have to be defined for new classes:\n"       \
+    "* pychrysalide.analysis.DataType._dup();\n"                        \
+    "* pychrysalide.analysis.DataType._to_string()."                    \
+    "\n"                                                                \
+    "Some extra method definitions are optional for new classes:\n"     \
+    "* pychrysalide.analysis.DataType._handle_namespaces();\n"          \
+    "* pychrysalide.analysis.DataType._is_pointer();\n"                 \
+    "* pychrysalide.analysis.DataType._is_reference();"                 \
+
+    /* Initialisation d'un objet GLib */
+
+    ret = forward_pygobjet_init(self);
+    if (ret == -1) return -1;
+
+    return 0;
+
+}
+
+
+
+/* ---------------------------------------------------------------------------------- */
+/*                   FONCTIONNALITES BASIQUES POUR TYPES DE DONNEES                   */
+/* ---------------------------------------------------------------------------------- */
+
 
 /******************************************************************************
 *                                                                             *
@@ -100,6 +553,56 @@ static PyObject *py_data_type_to_str(PyObject *self)
 
 /******************************************************************************
 *                                                                             *
+*  Paramètres  : self = serveur à manipuler.                                  *
+*                args = arguments d'appel non utilisés ici.                   *
+*                                                                             *
+*  Description : Crée un copie d'un type existant.                            *
+*                                                                             *
+*  Retour      : Nouvelle instance de type identique à celle fournie.         *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static PyObject *py_data_type_dup(PyObject *self, PyObject *args)
+{
+    PyObject *result;                       /* Bilan à retourner           */
+    GDataType *type;                        /* Version native de l'objet   */
+    GDataType *copy;                        /* Copie du type obtenue       */
+
+#define DATA_TYPE_DUP_METHOD PYTHON_METHOD_DEF              \
+(                                                           \
+    dup, "$self, /",                                        \
+    METH_NOARGS, py_data_type,                              \
+    "Create a copy of a data type.\n"                       \
+    "\n"                                                    \
+    "The returned value has to be a new instance of the"    \
+    " pychrysalide.analysis.DataType class."                \
+)
+
+    type = G_DATA_TYPE(pygobject_get(self));
+
+    copy = g_data_type_dup(type);
+
+    if (copy != NULL)
+    {
+        result = pygobject_new(G_OBJECT(copy));
+        g_object_unref(G_OBJECT(copy));
+    }
+
+    else
+    {
+        result = Py_None;
+        Py_INCREF(result);
+    }
+
+    return result;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
 *  Paramètres  : self    = objet Python concerné par l'appel.                 *
 *                closure = non utilisé ici.                                   *
 *                                                                             *
@@ -116,14 +619,33 @@ static PyObject *py_data_type_get_namespace(PyObject *self, void *closure)
     PyObject *result;                       /* Valeur à retourner          */
     GDataType *type;                        /* Elément à consulter         */
     GDataType *ns;                          /* Espace de noms              */
+    const char *sep;                        /* Séparateur d'espace         */
+
+#define DATA_TYPE_NAMESPACE_ATTRIB PYTHON_GETSET_DEF_FULL               \
+(                                                                       \
+    namespace, py_data_type,                                            \
+    "Namespace for the type, None if any.\n"                            \
+    "\n"                                                                \
+    "This property carries a tuple of two values:\n"                    \
+    "* a namespace, as a pychrysalide.analysis.DataType.TypeQualifier"  \
+    " instance;\n"                                                      \
+    "* a namespace separator, as a string."                             \
+)
 
     type = G_DATA_TYPE(pygobject_get(self));
+
     ns = g_data_type_get_namespace(type);
+    sep = g_data_type_get_namespace_separator(type);
 
-    if (ns != NULL)
+    if (ns != NULL && sep != NULL)
     {
-        result = pygobject_new(G_OBJECT(ns));
+        result = PyTuple_New(2);
+
+        PyTuple_SetItem(result, 0, pygobject_new(G_OBJECT(ns)));
         g_object_unref(G_OBJECT(ns));
+
+        PyTuple_SetItem(result, 1, PyUnicode_FromString(sep));
+
     }
 
     else
@@ -184,7 +706,7 @@ static int py_data_type_set_namespace(PyObject *self, PyObject *value, void *clo
         }
 
         ns = G_DATA_TYPE(pygobject_get(PyTuple_GetItem(value, 0)));
-        sep = strdup(PyUnicode_DATA(pygobject_get(PyTuple_GetItem(value, 1))));
+        sep = strdup(PyUnicode_DATA(PyTuple_GetItem(value, 1)));
 
         g_object_ref(G_OBJECT(ns));
         g_data_type_set_namespace(type, ns, sep);
@@ -215,10 +737,18 @@ static PyObject *py_data_type_get_qualifiers(PyObject *self, void *closure)
     GDataType *type;                        /* Elément à consulter         */
     TypeQualifier qualifiers;               /* Qualificatifs en place      */
 
+#define DATA_TYPE_QUALIFIERS_ATTRIB PYTHON_GETSET_DEF_FULL                          \
+(                                                                                   \
+    qualifiers, py_data_type,                                                       \
+    "Qualifier for the data type, *TypeQualifier.NONE* if any.\n"                   \
+    "\n"                                                                            \
+    "This property carries a pychrysalide.analysis.DataType.TypeQualifier value."   \
+)
+
     type = G_DATA_TYPE(pygobject_get(self));
     qualifiers = g_data_type_get_qualifiers(type);
 
-    result = PyLong_FromUnsignedLong(qualifiers);
+    result = cast_with_constants_group_from_type(get_python_data_type_type(), "TypeQualifier", qualifiers);
 
     return result;
 
@@ -242,21 +772,11 @@ static PyObject *py_data_type_get_qualifiers(PyObject *self, void *closure)
 static int py_data_type_set_qualifiers(PyObject *self, PyObject *value, void *closure)
 {
     GDataType *type;                        /* Elément à traiter           */
-    unsigned long qualifiers;               /* Qualificatifs à intégrer    */
-
-    if (!PyLong_Check(value))
-    {
-        PyErr_SetString(PyExc_TypeError, _("The attribute value must be a integer mask."));
-        return -1;
-    }
-
-    qualifiers = PyLong_AsUnsignedLong(value);
+    TypeQualifier qualifiers;               /* Qualificatifs à intégrer    */
+    int ret;                                /* Bilan d'une conversion      */
 
-    if (qualifiers > TQF_ALL)
-    {
-        PyErr_SetString(PyExc_TypeError, _("Invalid value for type qualifiers."));
-        return -1;
-    }
+    ret = convert_to_data_type_qualifier(value, &qualifiers);
+    if (ret != 1) return -1;
 
     type = G_DATA_TYPE(pygobject_get(self));
 
@@ -272,6 +792,43 @@ static int py_data_type_set_qualifiers(PyObject *self, PyObject *value, void *cl
 *  Paramètres  : self    = objet Python concerné par l'appel.                 *
 *                closure = non utilisé ici.                                   *
 *                                                                             *
+*  Description : Indique si le type assure une gestion des espaces de noms.   *
+*                                                                             *
+*  Retour      : Bilan de la consultation.                                    *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static PyObject *py_data_type_handle_namespaces(PyObject *self, void *closure)
+{
+    PyObject *result;                       /* Valeur à retourner          */
+    GDataType *type;                        /* Elément à consulter         */
+    bool status;                            /* Etat à faire suivre         */
+
+#define DATA_TYPE_NAMESPACES_ATTRIB PYTHON_RAWGET_DEF_FULL      \
+(                                                               \
+    handle_namespaces, py_data_type,                            \
+    "True if the type handles namespaces, False otherwise."     \
+)
+
+    type = G_DATA_TYPE(pygobject_get(self));
+
+    status = g_data_type_handle_namespaces(type);
+
+    result = status ? Py_True : Py_False;
+    Py_INCREF(result);
+
+    return result;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : self    = objet Python concerné par l'appel.                 *
+*                closure = non utilisé ici.                                   *
+*                                                                             *
 *  Description : Indique si le type est un pointeur.                          *
 *                                                                             *
 *  Retour      : Bilan de la consultation.                                    *
@@ -286,6 +843,12 @@ static PyObject *py_data_type_is_pointer(PyObject *self, void *closure)
     GDataType *type;                        /* Elément à consulter         */
     bool status;                            /* Etat à faire suivre         */
 
+#define DATA_TYPE_POINTER_ATTRIB PYTHON_IS_DEF_FULL     \
+(                                                       \
+    pointer, py_data_type,                              \
+    "True if the type is a pointer, False otherwise."   \
+)
+
     type = G_DATA_TYPE(pygobject_get(self));
 
     status = g_data_type_is_pointer(type);
@@ -317,6 +880,12 @@ static PyObject *py_data_type_is_reference(PyObject *self, void *closure)
     GDataType *type;                        /* Elément à consulter         */
     bool status;                            /* Etat à faire suivre         */
 
+#define DATA_TYPE_REFERENCE_ATTRIB PYTHON_IS_DEF_FULL   \
+(                                                       \
+    reference, py_data_type,                            \
+    "True if the type is a reference, False otherwise." \
+)
+
     type = G_DATA_TYPE(pygobject_get(self));
 
     status = g_data_type_is_reference(type);
@@ -344,26 +913,20 @@ static PyObject *py_data_type_is_reference(PyObject *self, void *closure)
 PyTypeObject *get_python_data_type_type(void)
 {
     static PyMethodDef py_data_type_methods[] = {
+        DATA_TYPE_DUP_WRAPPER,
+        DATA_TYPE_TO_STRING_WRAPPER,
+        DATA_TYPE_HANDLE_NAMESPACES_WRAPPER,
+        DATA_TYPE_IS_POINTER_WRAPPER,
+        DATA_TYPE_DUP_METHOD,
         { NULL }
     };
 
     static PyGetSetDef py_data_type_getseters[] = {
-        {
-            "namespace", py_data_type_get_namespace, py_data_type_set_namespace,
-            "Namespace for the type, None if any.", NULL
-        },
-        {
-            "qualifiers", py_data_type_get_qualifiers, py_data_type_set_qualifiers,
-            "Qualifiers linked to the type, TQF_NONE if any.", NULL
-        },
-        {
-            "is_pointer", py_data_type_is_pointer, NULL,
-            "True if the type is a pointer.", NULL
-        },
-        {
-            "is_reference", py_data_type_is_reference, NULL,
-            "True if the type is a reference.", NULL
-        },
+        DATA_TYPE_NAMESPACE_ATTRIB,
+        DATA_TYPE_QUALIFIERS_ATTRIB,
+        DATA_TYPE_NAMESPACES_ATTRIB,
+        DATA_TYPE_POINTER_ATTRIB,
+        DATA_TYPE_REFERENCE_ATTRIB,
         { NULL }
     };
 
@@ -377,10 +940,13 @@ PyTypeObject *get_python_data_type_type(void)
 
         .tp_flags       = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
 
-        .tp_doc         = "PyChrysalide data type",
+        .tp_doc         = DATA_TYPE_DOC,
 
         .tp_methods     = py_data_type_methods,
-        .tp_getset      = py_data_type_getseters
+        .tp_getset      = py_data_type_getseters,
+
+        .tp_init        = py_data_type_init,
+        .tp_new         = py_data_type_new
 
     };
 
@@ -391,36 +957,6 @@ PyTypeObject *get_python_data_type_type(void)
 
 /******************************************************************************
 *                                                                             *
-*  Paramètres  : obj_type = type dont le dictionnaire est à compléter.        *
-*                                                                             *
-*  Description : Définit les constantes pour les types de données.            *
-*                                                                             *
-*  Retour      : -                                                            *
-*                                                                             *
-*  Remarques   : -                                                            *
-*                                                                             *
-******************************************************************************/
-
-static bool py_data_type_define_constants(PyTypeObject *obj_type)
-{
-    bool result;                            /* Bilan à retourner           */
-
-    result = true;
-
-    result &= PyDict_AddULongMacro(obj_type, TQF_NONE);
-    result &= PyDict_AddULongMacro(obj_type, TQF_RESTRICT);
-    result &= PyDict_AddULongMacro(obj_type, TQF_VOLATILE);
-    result &= PyDict_AddULongMacro(obj_type, TQF_CONST);
-
-    result &= PyDict_AddULongMacro(obj_type, TQF_ALL);
-
-    return result;
-
-}
-
-
-/******************************************************************************
-*                                                                             *
 *  Paramètres  : -                                                            *
 *                                                                             *
 *  Description : Prend en charge l'objet 'pychrysalide.analysis.DataType'.    *
@@ -448,7 +984,7 @@ bool ensure_python_data_type_is_registered(void)
         if (!register_class_for_pygobject(dict, G_TYPE_DATA_TYPE, type, &PyGObject_Type))
             return false;
 
-        if (!py_data_type_define_constants(type))
+        if (!define_analysis_data_type_constants(type))
             return false;
 
     }
@@ -501,3 +1037,34 @@ int convert_to_data_type(PyObject *arg, void *dst)
     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 type de donnée ou NULL.                *
+*                                                                             *
+*  Retour      : Bilan de l'opération, voire indications supplémentaires.     *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+int convert_to_data_type_or_none(PyObject *arg, void *dst)
+{
+    int result;                             /* Bilan à retourner           */
+
+    if (arg == Py_None)
+    {
+        *((GDataType **)dst) = NULL;
+        result = 1;
+    }
+
+    else
+        result = convert_to_data_type(arg, dst);
+
+    return result;
+
+}
diff --git a/plugins/pychrysalide/analysis/type.h b/plugins/pychrysalide/analysis/type.h
index 8ea1096..9997a83 100644
--- a/plugins/pychrysalide/analysis/type.h
+++ b/plugins/pychrysalide/analysis/type.h
@@ -40,6 +40,9 @@ bool ensure_python_data_type_is_registered(void);
 /* Tente de convertir en type de donnée. */
 int convert_to_data_type(PyObject *, void *);
 
+/* Tente de convertir en type de donnée ou NULL. */
+int convert_to_data_type_or_none(PyObject *, void *);
+
 
 
 #endif  /* _PLUGINS_PYCHRYSALIDE_ANALYSIS_TYPE_H */
diff --git a/plugins/pychrysalide/helpers.c b/plugins/pychrysalide/helpers.c
index 25ce772..870035d 100644
--- a/plugins/pychrysalide/helpers.c
+++ b/plugins/pychrysalide/helpers.c
@@ -648,6 +648,56 @@ PyObject *py_return_none(PyObject *self, PyObject *args)
 
 /******************************************************************************
 *                                                                             *
+*  Paramètres  : self = objet quelconque.                                     *
+*                args = arguments fournis à l'appel.                          *
+*                                                                             *
+*  Description : Retourne toujours faux.                                      *
+*                                                                             *
+*  Retour      : False.                                                       *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+PyObject *py_return_false(PyObject *self, PyObject *args)
+{
+    PyObject *result;                       /* Bilan à retourner           */
+
+    result = Py_False;
+    Py_INCREF(result);
+
+    return result;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : self = objet quelconque.                                     *
+*                args = arguments fournis à l'appel.                          *
+*                                                                             *
+*  Description : Retourne toujours vrai.                                      *
+*                                                                             *
+*  Retour      : False.                                                       *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+PyObject *py_return_true(PyObject *self, PyObject *args)
+{
+    PyObject *result;                       /* Bilan à retourner           */
+
+    result = Py_True;
+    Py_INCREF(result);
+
+    return result;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
 *  Paramètres  : self    = objet quelconque dont le code Python hérite.       *
 *                closure = non utilisé ici.                                   *
 *                                                                             *
diff --git a/plugins/pychrysalide/helpers.h b/plugins/pychrysalide/helpers.h
index f5b5781..45b3083 100644
--- a/plugins/pychrysalide/helpers.h
+++ b/plugins/pychrysalide/helpers.h
@@ -104,6 +104,19 @@ bool register_python_module_object(PyObject *, PyTypeObject *);
         #name "(" args ")\n--\n\n" doc                  \
     }
 
+#define PYTHON_FALSE_WRAPPER_DEF(name, args, flags, doc)\
+    {                                                   \
+        #name, (PyCFunction)py_return_false,            \
+        flags,                                          \
+        #name "(" args ")\n--\n\n" doc                  \
+    }
+
+#define PYTHON_TRUE_WRAPPER_DEF(name, args, flags, doc)\
+    {                                                   \
+        #name, (PyCFunction)py_return_true,             \
+        flags,                                          \
+        #name "(" args ")\n--\n\n" doc                  \
+    }
 
 #define PYTHON_GETSET_DEF(name, get, set, doc, closure) \
     {                                                   \
@@ -118,6 +131,9 @@ bool register_python_module_object(PyObject *, PyTypeObject *);
 #define PYTHON_HAS_DEF_FULL(name, base, doc)            \
     PYTHON_GETSET_DEF(#name, base ## _has_ ## name, NULL, doc, NULL)
 
+#define PYTHON_RAWGET_DEF_FULL(name, base, doc)         \
+    PYTHON_GETSET_DEF(#name, base ## _ ## name, NULL, doc, NULL)
+
 #define PYTHON_GET_DEF_FULL(name, base, doc)            \
     PYTHON_GETSET_DEF(#name, base ## _get_ ## name, NULL, doc, NULL)
 
@@ -151,6 +167,12 @@ PyObject *not_yet_implemented_method(PyObject *, PyObject *);
 /* Retourne toujours rien. */
 PyObject *py_return_none(PyObject *, PyObject *);
 
+/* Retourne toujours faux. */
+PyObject *py_return_false(PyObject *, PyObject *);
+
+/* Retourne toujours vrai. */
+PyObject *py_return_true(PyObject *, PyObject *);
+
 /* Marque l'absence d'implémentation pour un attribut donné. */
 PyObject *not_yet_implemented_getter(PyObject *, void *);
 
diff --git a/src/analysis/type-int.h b/src/analysis/type-int.h
index f6d931b..f553bf3 100644
--- a/src/analysis/type-int.h
+++ b/src/analysis/type-int.h
@@ -35,6 +35,9 @@ typedef GDataType * (* type_dup_fc) (const GDataType *);
 /* Décrit le type fourni sous forme de caractères. */
 typedef char * (* type_to_string_fc) (const GDataType *, bool);
 
+/* Indique si le type assure une gestion des espaces de noms. */
+typedef bool (* type_handle_ns_fc) (const GDataType *);
+
 /* Indique si le type est un pointeur. */
 typedef bool (* type_is_pointer_fc) (const GDataType *);
 
@@ -60,11 +63,10 @@ struct _GDataTypeClass
 {
     GObjectClass parent;                    /* A laisser en premier        */
 
-    bool handle_ns;                         /* Gestion au niveau de base ? */
-
     type_dup_fc dup;                        /* Copie d'instance existante  */
     type_to_string_fc to_string;            /* Conversion au format texte  */
 
+    type_handle_ns_fc handle_ns;            /* Gestion des espaces de noms?*/
     type_is_pointer_fc is_pointer;          /* Représentation de pointeur ?*/
     type_is_reference_fc is_reference;      /* Représentation de référence?*/
 
diff --git a/src/analysis/type.c b/src/analysis/type.c
index 5bcb0e2..f19d846 100644
--- a/src/analysis/type.c
+++ b/src/analysis/type.c
@@ -72,8 +72,6 @@ static void g_data_type_class_init(GDataTypeClass *klass)
     object->dispose = (GObjectFinalizeFunc/* ! */)g_data_type_dispose;
     object->finalize = (GObjectFinalizeFunc)g_data_type_finalize;
 
-    klass->handle_ns = true;
-
 }
 
 
@@ -200,7 +198,7 @@ char *g_data_type_to_string(const GDataType *type, bool include)
 
     result = class->to_string(type, include);
 
-    if (include && type->namespace != NULL && class->handle_ns)
+    if (include && type->namespace != NULL && g_data_type_handle_namespaces(type))
     {
         namespace = g_data_type_to_string(type->namespace, true);
 
@@ -369,6 +367,35 @@ TypeQualifier g_data_type_get_qualifiers(const GDataType *type)
 *                                                                             *
 *  Paramètres  : type = type à consulter.                                     *
 *                                                                             *
+*  Description : Indique si le type assure une gestion des espaces de noms.   *
+*                                                                             *
+*  Retour      : Bilan de la consultation.                                    *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+bool g_data_type_handle_namespaces(const GDataType *type)
+{
+    bool result;                            /* Bilan à retourner           */
+    GDataTypeClass *class;                  /* Classe du type              */
+
+    class = G_DATA_TYPE_GET_CLASS(type);
+
+    if (class->handle_ns != NULL)
+        result = class->handle_ns(type);
+    else
+        result = true;
+
+    return result;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : type = type à consulter.                                     *
+*                                                                             *
 *  Description : Indique si le type est un pointeur.                          *
 *                                                                             *
 *  Retour      : Bilan de la consultation.                                    *
diff --git a/src/analysis/type.h b/src/analysis/type.h
index 431c080..000c557 100644
--- a/src/analysis/type.h
+++ b/src/analysis/type.h
@@ -87,6 +87,9 @@ void g_data_type_add_qualifier(GDataType *, TypeQualifier);
 /* Fournit les qualificatifs associés à une instance de type. */
 TypeQualifier g_data_type_get_qualifiers(const GDataType *);
 
+/* Indique si le type assure une gestion des espaces de noms. */
+bool g_data_type_handle_namespaces(const GDataType *);
+
 /* Indique si le type est un pointeur. */
 bool g_data_type_is_pointer(const GDataType *);
 
diff --git a/src/analysis/types/proto.c b/src/analysis/types/proto.c
index 362bd88..17f0262 100644
--- a/src/analysis/types/proto.c
+++ b/src/analysis/types/proto.c
@@ -72,6 +72,9 @@ static GDataType *g_proto_type_dup(const GProtoType *);
 /* Décrit le type fourni sous forme de caractères. */
 static char *g_proto_type_to_string(const GProtoType *, bool);
 
+/* Indique si le type assure une gestion des espaces de noms. */
+static bool g_proto_type_handle_namespaces(GProtoType *);
+
 
 
 /* Indique le type défini pour un prototype. */
@@ -102,11 +105,11 @@ static void g_proto_type_class_init(GProtoTypeClass *klass)
 
     type = G_DATA_TYPE_CLASS(klass);
 
-    type->handle_ns = false;
-
     type->dup = (type_dup_fc)g_proto_type_dup;
     type->to_string = (type_to_string_fc)g_proto_type_to_string;
 
+    type->handle_ns = (type_handle_ns_fc)g_proto_type_handle_namespaces;
+
 }
 
 
@@ -321,6 +324,29 @@ static char *g_proto_type_to_string(const GProtoType *type, bool include)
 
 /******************************************************************************
 *                                                                             *
+*  Paramètres  : type = type à consulter.                                     *
+*                                                                             *
+*  Description : Indique si le type assure une gestion des espaces de noms.   *
+*                                                                             *
+*  Retour      : Bilan de la consultation.                                    *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static bool g_proto_type_handle_namespaces(GProtoType *type)
+{
+    bool result;                            /* Bilan à retourner           */
+
+    result = false;
+
+    return result;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
 *  Paramètres  : type = type à mettre à jour.                                 *
 *                ret  = indication sur le type de retour.                     *
 *                                                                             *
diff --git a/tests/analysis/type.py b/tests/analysis/type.py
new file mode 100644
index 0000000..5106cbc
--- /dev/null
+++ b/tests/analysis/type.py
@@ -0,0 +1,92 @@
+#!/usr/bin/python3-dbg
+# -*- coding: utf-8 -*-
+
+
+from chrysacase import ChrysalideTestCase
+from pychrysalide.analysis import DataType
+
+
+class TestDataType(ChrysalideTestCase):
+    """TestCase for analysis.DataType."""
+
+
+    def testTypeSubclassing(self):
+        """Verify the data type subclassing is working."""
+
+        class MyType(DataType):
+
+            def __init__(self, num):
+                super(MyType, self).__init__()
+                self._num = num
+
+            def _to_string(self, include):
+                return '%x' % self._num
+
+            def _dup(self):
+                return MyType(self._num)
+
+        tp = MyType(0x123)
+
+        self.assertEqual(str(tp), '123')
+
+        tp2 = tp.dup()
+
+        self.assertEqual(str(tp), str(tp2))
+
+
+    def testTypeDefaultProperties(self):
+        """Check for default values of some type properties."""
+
+        class MyPropType(DataType):
+            pass
+
+        tp = MyPropType()
+
+        self.assertTrue(tp.handle_namespaces)
+
+        self.assertFalse(tp.is_pointer)
+
+        self.assertFalse(tp.is_reference)
+
+        class MyPropType2(DataType):
+
+            def _handle_namespaces(self):
+                return True
+
+            def _is_pointer(self):
+                return 123 < 1234
+
+            def _is_reference(self):
+                return False
+
+        tp2 = MyPropType2()
+
+        self.assertTrue(tp.handle_namespaces)
+
+        self.assertTrue(tp2.is_pointer)
+
+        self.assertFalse(tp2.is_reference)
+
+
+    def testTypeNamespaces(self):
+        """Test the type namespace property."""
+
+        class MyNSType(DataType):
+
+            def __init__(self, name):
+                super(MyNSType, self).__init__()
+                self._name = name
+
+            def _to_string(self, include):
+                return self._name
+
+        tp = MyNSType('TP')
+        ns = MyNSType('NS')
+
+        self.assertIsNone(tp.namespace)
+
+        tp.namespace = (ns, '.')
+
+        self.assertEqual(str(tp), 'NS.TP')
+
+        self.assertEqual(tp.namespace, (ns, '.'))
-- 
cgit v0.11.2-87-g4458