From c1bcf3e7bd0a256005bd15832117b78cee5fdfab Mon Sep 17 00:00:00 2001
From: Cyrille Bagard <nocbos@gmail.com>
Date: Tue, 22 Jan 2019 19:28:36 +0100
Subject: Allowed to initialize instances of created dynamic types if needed.

---
 plugins/pychrysalide/arch/operands/register.c |   4 +-
 plugins/pychrysalide/arch/processor.c         | 105 +++++++++++++++++++++++++-
 plugins/pychrysalide/arch/register.c          |   4 +-
 plugins/pychrysalide/gui/panels/panel.c       |   4 +-
 plugins/pychrysalide/plugin.c                 |   4 +-
 src/plugins/dt.c                              |  98 +++++++++++++++++++++---
 src/plugins/dt.h                              |   8 +-
 src/plugins/plugin.c                          |   4 +-
 tests/arch/errors.py                          |  13 +++-
 tests/arch/processor.py                       |  13 +++-
 10 files changed, 229 insertions(+), 28 deletions(-)

diff --git a/plugins/pychrysalide/arch/operands/register.c b/plugins/pychrysalide/arch/operands/register.c
index 74b6a4f..8144af0 100644
--- a/plugins/pychrysalide/arch/operands/register.c
+++ b/plugins/pychrysalide/arch/operands/register.c
@@ -100,8 +100,8 @@ static PyObject *py_register_operand_new(PyTypeObject *type, PyObject *args, PyO
 
     first_time = (g_type_from_name(type->tp_name) == 0);
 
-    gtype = built_dynamic_type(G_TYPE_REGISTER_OPERAND, type->tp_name,
-                               (GClassInitFunc)py_register_operand_init_gclass, NULL);
+    gtype = build_dynamic_type(G_TYPE_REGISTER_OPERAND, type->tp_name,
+                               (GClassInitFunc)py_register_operand_init_gclass, NULL, NULL);
 
     if (first_time)
     {
diff --git a/plugins/pychrysalide/arch/processor.c b/plugins/pychrysalide/arch/processor.c
index 8fc2598..b59e59b 100644
--- a/plugins/pychrysalide/arch/processor.c
+++ b/plugins/pychrysalide/arch/processor.c
@@ -54,6 +54,12 @@ static PyObject *py_arch_processor_new(PyTypeObject *, PyObject *, PyObject *);
 /* Initialise la classe des descriptions de fichier binaire. */
 static void py_arch_processor_init_gclass(GArchProcessorClass *, gpointer);
 
+/* Initialise une instance de processeur d'architecture. */
+static void py_arch_processor_init_ginstance(GArchProcessor *, GArchProcessor *);
+
+/* Initialise une instance sur la base du dérivé de GObject. */
+static int py_arch_processor_init(PyObject *, PyObject *, PyObject *);
+
 /* Fournit un contexte propre au processeur d'une architecture. */
 static GProcContext *py_arch_processor_get_context_wrapper(const GArchProcessor *);
 
@@ -160,8 +166,9 @@ static PyObject *py_arch_processor_new(PyTypeObject *type, PyObject *args, PyObj
 
     first_time = (g_type_from_name(type->tp_name) == 0);
 
-    gtype = built_dynamic_type(G_TYPE_ARCH_PROCESSOR, type->tp_name,
-                               (GClassInitFunc)py_arch_processor_init_gclass, NULL);
+    gtype = build_dynamic_type(G_TYPE_ARCH_PROCESSOR, type->tp_name,
+                               (GClassInitFunc)py_arch_processor_init_gclass, NULL,
+                               (GInstanceInitFunc)py_arch_processor_init_ginstance);
 
     if (first_time)
     {
@@ -191,7 +198,7 @@ static PyObject *py_arch_processor_new(PyTypeObject *type, PyObject *args, PyObj
 *  Paramètres  : class  = classe à initialiser.                               *
 *                unused = données non utilisées ici.                          *
 *                                                                             *
-*  Description : Initialise la classe des descriptions de fichier binaire.    *
+*  Description : Initialise la classe générique des processeurs.              *
 *                                                                             *
 *  Retour      : -                                                            *
 *                                                                             *
@@ -210,6 +217,97 @@ static void py_arch_processor_init_gclass(GArchProcessorClass *class, gpointer u
 
 /******************************************************************************
 *                                                                             *
+*  Paramètres  : proc  = instance à initialiser.                              *
+*                class = classe du type correspondant.                        *
+*                                                                             *
+*  Description : Initialise une instance de processeur d'architecture.        *
+*                                                                             *
+*  Retour      : -                                                            *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static void py_arch_processor_init_ginstance(GArchProcessor *proc, GArchProcessor *class)
+{
+    GType type;                             /* Type d'instances concerné   */
+    GArchProcessor *pattern;                /* Patron de données à copier  */
+
+    type = G_TYPE_FROM_INSTANCE(proc);
+
+    pattern = get_dynamic_type_pattern(type);
+
+    if (pattern != NULL)
+    {
+        proc->endianness = pattern->endianness;
+        proc->memsize = pattern->memsize;
+        proc->inssize = pattern->inssize;
+        proc->virt_space = pattern->virt_space;
+    }
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  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_arch_processor_init(PyObject *self, PyObject *args, PyObject *kwds)
+{
+    unsigned long endianness;               /* Boutisme du processeur      */
+    unsigned long mem_size;                 /* Taille d'adressage          */
+    unsigned long ins_min_size;             /* Taille minimale d'instruct° */
+    int vspace;                             /* Support d'un espace virtuel */
+    int ret;                                /* Bilan de lecture des args.  */
+    PyObject *new_kwds;                     /* Nouveau dictionnaire épuré  */
+    GArchProcessor *proc;                   /* Processeur à manipuler      */
+
+    static char *kwlist[] = { "endianness", "mem_size", "ins_min_size", "vspace", NULL };
+
+    /* Récupération des paramètres */
+
+    ret = PyArg_ParseTupleAndKeywords(args, kwds, "kkkp", kwlist,
+                                      &endianness, &mem_size, &ins_min_size, &vspace);
+    if (!ret) return -1;
+
+    /* Initialisation d'un objet GLib */
+
+    new_kwds = PyDict_New();
+
+    ret = PyGObject_Type.tp_init(self, args, new_kwds);
+
+    Py_DECREF(new_kwds);
+
+    if (ret == -1) return -1;
+
+    /* Eléments de base */
+
+    proc = G_ARCH_PROCESSOR(pygobject_get(self));
+
+    proc->endianness = endianness;
+    proc->memsize = mem_size;
+    proc->inssize = ins_min_size;
+    proc->virt_space = vspace;
+
+    register_dynamic_type_pattern(G_OBJECT(proc));
+
+    return 0;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
 *  Paramètres  : proc = architecture visée par la procédure.                  *
 *                                                                             *
 *  Description : Fournit un contexte propre au processeur d'une architecture. *
@@ -930,6 +1028,7 @@ PyTypeObject *get_python_arch_processor_type(void)
         .tp_methods     = py_arch_processor_methods,
         .tp_getset      = py_arch_processor_getseters,
 
+        .tp_init        = py_arch_processor_init,
         .tp_new         = py_arch_processor_new,
 
     };
diff --git a/plugins/pychrysalide/arch/register.c b/plugins/pychrysalide/arch/register.c
index 0299fa6..c55cd2b 100644
--- a/plugins/pychrysalide/arch/register.c
+++ b/plugins/pychrysalide/arch/register.c
@@ -103,8 +103,8 @@ static PyObject *py_arch_register_new(PyTypeObject *type, PyObject *args, PyObje
 
     first_time = (g_type_from_name(type->tp_name) == 0);
 
-    gtype = built_dynamic_type(G_TYPE_ARCH_REGISTER, type->tp_name,
-                               (GClassInitFunc)py_arch_register_init_gclass, NULL);
+    gtype = build_dynamic_type(G_TYPE_ARCH_REGISTER, type->tp_name,
+                               (GClassInitFunc)py_arch_register_init_gclass, NULL, NULL);
 
     if (first_time)
     {
diff --git a/plugins/pychrysalide/gui/panels/panel.c b/plugins/pychrysalide/gui/panels/panel.c
index 0db1df8..2d0b562 100644
--- a/plugins/pychrysalide/gui/panels/panel.c
+++ b/plugins/pychrysalide/gui/panels/panel.c
@@ -109,8 +109,8 @@ static PyObject *py_panel_item_new(PyTypeObject *type, PyObject *args, PyObject
 
     first_time = (g_type_from_name(type->tp_name) == 0);
 
-    gtype = built_dynamic_type(G_TYPE_PANEL_ITEM, type->tp_name,
-                               (GClassInitFunc)py_panel_item_init_gclass, NULL);
+    gtype = build_dynamic_type(G_TYPE_PANEL_ITEM, type->tp_name,
+                               (GClassInitFunc)py_panel_item_init_gclass, NULL, NULL);
 
     if (first_time)
     {
diff --git a/plugins/pychrysalide/plugin.c b/plugins/pychrysalide/plugin.c
index 7667af7..51da910 100644
--- a/plugins/pychrysalide/plugin.c
+++ b/plugins/pychrysalide/plugin.c
@@ -175,8 +175,8 @@ static PyObject *py_plugin_module_new(PyTypeObject *type, PyObject *args, PyObje
 
     first_time = (g_type_from_name(type->tp_name) == 0);
 
-    gtype = built_dynamic_type(G_TYPE_PYTHON_PLUGIN, type->tp_name,
-                               (GClassInitFunc)py_plugin_module_init_gclass, NULL);
+    gtype = build_dynamic_type(G_TYPE_PYTHON_PLUGIN, type->tp_name,
+                               (GClassInitFunc)py_plugin_module_init_gclass, NULL, NULL);
 
     if (first_time)
     {
diff --git a/src/plugins/dt.c b/src/plugins/dt.c
index afdba21..14b03f0 100644
--- a/src/plugins/dt.c
+++ b/src/plugins/dt.c
@@ -26,6 +26,7 @@
 
 #include <assert.h>
 #include <malloc.h>
+#include <string.h>
 
 
 
@@ -44,9 +45,14 @@
 typedef struct _type_dyn_info_t
 {
     GType type;                             /* Identifiant unique obtenu   */
-    GClassInitFunc init;                    /* Définition des méthodes     */
+
+    GClassInitFunc cinit;                   /* Phase d'initialisation #1   */
     gconstpointer data;                     /* Eventuelles données utiles  */
 
+    GInstanceInitFunc init;                 /* Phase d'initialisation #2   */
+
+    void *pattern;                          /* Modèle de données d'instance*/
+
 } type_dyn_info_t;
 
 /* Description de fichier binaire (instance) */
@@ -98,10 +104,10 @@ static void g_dynamic_types_unuse(GDynamicTypes *);
 static void g_dynamic_types_complete_type(GDynamicTypes *, GType, GTypeInfo *, GTypeValueTable *);
 
 /* Retrouve les informations concernant un type dynamique. */
-static const type_dyn_info_t *g_dynamic_types_find(const GDynamicTypes *, GType);
+static type_dyn_info_t *g_dynamic_types_find(const GDynamicTypes *, GType);
 
 /* Fournit un identifiant GLib pour un nouveau type. */
-static GType g_dynamic_types_register_type(GDynamicTypes *, GType, const char *, GClassInitFunc, gconstpointer);
+static GType g_dynamic_types_register_type(GDynamicTypes *, GType, const char *, GClassInitFunc, gconstpointer, GInstanceInitFunc);
 
 
 
@@ -297,7 +303,7 @@ static void g_dynamic_types_unuse(GDynamicTypes *types)
 
 static void g_dynamic_types_complete_type(GDynamicTypes *types, GType type, GTypeInfo *info, GTypeValueTable *table)
 {
-    const type_dyn_info_t *nfo;             /* Source d'inspiration        */
+    type_dyn_info_t *nfo;                   /* Source d'inspiration        */
     GType parent;                           /* Type parent du type         */
     GTypeQuery query;                       /* Informations complémentaires*/
 
@@ -312,10 +318,11 @@ static void g_dynamic_types_complete_type(GDynamicTypes *types, GType type, GTyp
     /* Définition */
 
     info->class_size = query.class_size;
-    info->class_init = nfo->init;
+    info->class_init = nfo->cinit;
     info->class_data = nfo->data;
 
     info->instance_size = query.instance_size;
+    info->instance_init = nfo->init;
 
 }
 
@@ -333,7 +340,7 @@ static void g_dynamic_types_complete_type(GDynamicTypes *types, GType type, GTyp
 *                                                                             *
 ******************************************************************************/
 
-static const type_dyn_info_t *g_dynamic_types_find(const GDynamicTypes *types, GType target)
+static type_dyn_info_t *g_dynamic_types_find(const GDynamicTypes *types, GType target)
 {
     type_dyn_info_t *result;                /* Informations à retourner    */
     size_t i;                               /* Boucle de parcours          */
@@ -353,8 +360,9 @@ static const type_dyn_info_t *g_dynamic_types_find(const GDynamicTypes *types, G
 *                                                                             *
 *  Paramètres  : parent = type GLib parent.                                   *
 *                name   = désignation du nouveau type.                        *
-*                init   = procédure d'initialisation de la classe associée.   *
+*                cinit  = procédure d'initialisation de la classe associée.   *
 *                data   = éventuelles données à associer à la future classe.  *
+*                init   = procédure d'initialisation pour chaque instance.    *
 *                                                                             *
 *  Description : Fournit un identifiant GLib pour un nouveau type.            *
 *                                                                             *
@@ -364,7 +372,7 @@ static const type_dyn_info_t *g_dynamic_types_find(const GDynamicTypes *types, G
 *                                                                             *
 ******************************************************************************/
 
-static GType g_dynamic_types_register_type(GDynamicTypes *types, GType parent, const char *name, GClassInitFunc init, gconstpointer data)
+static GType g_dynamic_types_register_type(GDynamicTypes *types, GType parent, const char *name, GClassInitFunc cinit, gconstpointer data, GInstanceInitFunc init)
 {
     GType result;                           /* Identifiant à retourner     */
     type_dyn_info_t *new;                   /* Mémorisation de paramètres  */
@@ -379,9 +387,14 @@ static GType g_dynamic_types_register_type(GDynamicTypes *types, GType parent, c
     new = malloc(sizeof(type_dyn_info_t));
 
     new->type = result;
-    new->init = init;
+
+    new->cinit = cinit;
     new->data = data;
 
+    new->init = init;
+
+    new->pattern = NULL;
+
     /* Inscription définitive */
 
     types->info = realloc(types->info, ++types->count * sizeof(type_dyn_info_t *));
@@ -449,8 +462,9 @@ void exit_chrysalide_dynamic_types(void)
 *                                                                             *
 *  Paramètres  : parent = type GLib parent.                                   *
 *                name   = désignation du nouveau type.                        *
-*                init   = procédure d'initialisation de la classe associée.   *
+*                cinit  = procédure d'initialisation de la classe associée.   *
 *                data   = éventuelles données à associer à la future classe.  *
+*                init   = procédure d'initialisation pour chaque instance.    *
 *                                                                             *
 *  Description : Fournit un identifiant GLib pour un nouveau type.            *
 *                                                                             *
@@ -460,14 +474,74 @@ void exit_chrysalide_dynamic_types(void)
 *                                                                             *
 ******************************************************************************/
 
-GType built_dynamic_type(GType parent, const char *name, GClassInitFunc init, gconstpointer data)
+GType build_dynamic_type(GType parent, const char *name, GClassInitFunc cinit, gconstpointer data, GInstanceInitFunc init)
 {
     GType result;                           /* Identifiant à retourner     */
 
     result = g_type_from_name(name);
 
     if (result == 0)
-        result = g_dynamic_types_register_type(_chrysalide_dtypes, parent, name, init, data);
+        result = g_dynamic_types_register_type(_chrysalide_dtypes, parent, name, cinit, data, init);
+
+    return result;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : instance = instance portant les données à conserver.         *
+*                                                                             *
+*  Description : Enregistre les données correspondant à une instance.         *
+*                                                                             *
+*  Retour      : -                                                            *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+void register_dynamic_type_pattern(GObject *instance)
+{
+    GType type;                             /* Type d'instances concerné   */
+    type_dyn_info_t *nfo;                   /* Source d'inspiration        */
+    GTypeQuery query;                       /* Informations complémentaires*/
+
+    type = G_TYPE_FROM_INSTANCE(instance);
+
+    nfo = g_dynamic_types_find(_chrysalide_dtypes, type);
+    assert(nfo != NULL);
+
+    g_type_query(type, &query);
+
+    if (nfo->pattern == NULL)
+        nfo->pattern = malloc(query.instance_size);
+
+    memcpy(nfo->pattern, instance, query.instance_size);
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : type = type d'une instance créée sans initialisation.        *
+*                                                                             *
+*  Description : Fournit les données correspondant à une instance initiale.   *
+*                                                                             *
+*  Retour      : Données issues de la première instance d'un type ou NULL.    *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+void *get_dynamic_type_pattern(GType type)
+{
+    void *result;                           /* Modèle éventuel à retourner */
+    type_dyn_info_t *nfo;                   /* Source d'inspiration        */
+
+    nfo = g_dynamic_types_find(_chrysalide_dtypes, type);
+    assert(nfo != NULL);
+
+    result = nfo->pattern;
 
     return result;
 
diff --git a/src/plugins/dt.h b/src/plugins/dt.h
index b9d4656..c25f4fd 100644
--- a/src/plugins/dt.h
+++ b/src/plugins/dt.h
@@ -40,7 +40,13 @@ bool init_chrysalide_dynamic_types(void);
 void exit_chrysalide_dynamic_types(void);
 
 /* Fournit un identifiant GLib pour un nouveau type. */
-GType built_dynamic_type(GType, const char *, GClassInitFunc, gconstpointer);
+GType build_dynamic_type(GType, const char *, GClassInitFunc, gconstpointer, GInstanceInitFunc);
+
+/* Enregistre les données correspondant à une instance. */
+void register_dynamic_type_pattern(GObject *);
+
+/* Fournit les données correspondant à une instance initiale. */
+void *get_dynamic_type_pattern(GType);
 
 
 
diff --git a/src/plugins/plugin.c b/src/plugins/plugin.c
index ff3db31..1bdcf04 100644
--- a/src/plugins/plugin.c
+++ b/src/plugins/plugin.c
@@ -450,8 +450,8 @@ GPluginModule *g_plugin_module_new(const gchar *filename)
     if (!valid)
         goto bad_plugin;
 
-    gtype = built_dynamic_type(G_TYPE_PLUGIN_MODULE, interface->gtp_name,
-                               (GClassInitFunc)g_plugin_module_init_gclass, module);
+    gtype = build_dynamic_type(G_TYPE_PLUGIN_MODULE, interface->gtp_name,
+                               (GClassInitFunc)g_plugin_module_init_gclass, module, NULL);
 
     if (gtype == G_TYPE_INVALID)
         goto bad_plugin;
diff --git a/tests/arch/errors.py b/tests/arch/errors.py
index 8affb77..e57b94b 100644
--- a/tests/arch/errors.py
+++ b/tests/arch/errors.py
@@ -6,6 +6,7 @@
 
 
 from chrysacase import ChrysalideTestCase
+from pychrysalide import arch
 from pychrysalide.arch import vmpa
 from pychrysalide.arch import ArchProcessor
 
@@ -28,7 +29,17 @@ class TestArchErrors(ChrysalideTestCase):
 
 
         class NewProc(ArchProcessor):
-            pass
+
+            def __init__(self):
+
+                props = {
+                    'endianness':   arch.SRE_LITTLE,
+                    'mem_size':     arch.MDS_32_BITS_UNSIGNED,
+                    'ins_min_size': arch.MDS_32_BITS_UNSIGNED,
+                    'vspace':       False
+                }
+
+                super(NewProc, self).__init__(**props)
 
 
         proc = NewProc()
diff --git a/tests/arch/processor.py b/tests/arch/processor.py
index 97a713d..bf17b98 100644
--- a/tests/arch/processor.py
+++ b/tests/arch/processor.py
@@ -5,13 +5,13 @@
 import pychrysalide
 from chrysacase import ChrysalideTestCase
 from pychrysalide.analysis.contents import MemoryContent
+from pychrysalide import arch
 from pychrysalide.arch import ArchProcessor
 from pychrysalide.arch import ProcContext
 from pychrysalide.arch import vmpa
 from pychrysalide.format import FlatFormat
 
 
-
 class TestProcessor(ChrysalideTestCase):
     """TestCase for arch.ArchProcessor."""
 
@@ -28,6 +28,17 @@ class TestProcessor(ChrysalideTestCase):
 
         class NewProcWithCtx(ArchProcessor):
 
+            def __init__(self):
+
+                props = {
+                    'endianness':   arch.SRE_LITTLE,
+                    'mem_size':     arch.MDS_32_BITS_UNSIGNED,
+                    'ins_min_size': arch.MDS_32_BITS_UNSIGNED,
+                    'vspace':       False
+                }
+
+                super(NewProcWithCtx, self).__init__(**props)
+
             def _get_context(self):
                 return NewContext()
 
-- 
cgit v0.11.2-87-g4458