From f3e136eab9fd6adcb51988c9f70ca7f35552abc4 Mon Sep 17 00:00:00 2001
From: Cyrille Bagard <nocbos@gmail.com>
Date: Sun, 17 May 2020 10:48:02 +0200
Subject: Introduced a new object of string constant sets.

---
 plugins/pychrysalide/Makefile.am          |   1 +
 plugins/pychrysalide/glibext/binportion.c |  35 ----
 plugins/pychrysalide/glibext/constants.c  |  13 ++
 plugins/pychrysalide/helpers.c            |  69 ++++++++
 plugins/pychrysalide/helpers.h            |  27 +++
 plugins/pychrysalide/pychrysa.c           |   2 +
 plugins/pychrysalide/strenum.c            | 262 ++++++++++++++++++++++++++++++
 plugins/pychrysalide/strenum.h            |  42 +++++
 plugins/pychrysalide/struct.c             |   2 +-
 9 files changed, 417 insertions(+), 36 deletions(-)
 create mode 100644 plugins/pychrysalide/strenum.c
 create mode 100644 plugins/pychrysalide/strenum.h

diff --git a/plugins/pychrysalide/Makefile.am b/plugins/pychrysalide/Makefile.am
index b85f417..6bcaef4 100644
--- a/plugins/pychrysalide/Makefile.am
+++ b/plugins/pychrysalide/Makefile.am
@@ -11,6 +11,7 @@ pychrysalide_la_SOURCES =				\
 	plugin.h plugin.c					\
 	pychrysa.h pychrysa.c				\
 	star.h star.c						\
+	strenum.h strenum.c					\
 	struct.h struct.c					\
 	weak.h weak.c
 
diff --git a/plugins/pychrysalide/glibext/binportion.c b/plugins/pychrysalide/glibext/binportion.c
index 14df461..3065755 100644
--- a/plugins/pychrysalide/glibext/binportion.c
+++ b/plugins/pychrysalide/glibext/binportion.c
@@ -73,9 +73,6 @@ static PyObject *py_binary_portion_get_rights(PyObject *, void *);
 /* Définit les droits associés à une partie de code. */
 static int py_binary_portion_set_rights(PyObject *, PyObject *, void *);
 
-/* Définit les constantes pour les portions de binaire. */
-static bool py_binary_portion_define_constants(PyTypeObject *);
-
 
 
 /******************************************************************************
@@ -608,35 +605,6 @@ static int py_binary_portion_set_rights(PyObject *self, PyObject *value, void *c
 
 /******************************************************************************
 *                                                                             *
-*  Paramètres  : obj_type = type dont le dictionnaire est à compléter.        *
-*                                                                             *
-*  Description : Définit les constantes pour les portions de binaire.         *
-*                                                                             *
-*  Retour      : true en cas de succès de l'opération, false sinon.           *
-*                                                                             *
-*  Remarques   : -                                                            *
-*                                                                             *
-******************************************************************************/
-
-static bool py_binary_portion_define_constants(PyTypeObject *obj_type)
-{
-    bool result;                            /* Bilan à retourner           */
-
-    result = true;
-
-    if (result) result = PyDict_AddStringMacro(obj_type, BPC_RAW);
-    if (result) result = PyDict_AddStringMacro(obj_type, BPC_CODE);
-    if (result) result = PyDict_AddStringMacro(obj_type, BPC_DATA);
-    if (result) result = PyDict_AddStringMacro(obj_type, BPC_DATA_RO);
-    if (result) result = PyDict_AddStringMacro(obj_type, BPC_DISASS_ERROR);
-
-    return result;
-
-}
-
-
-/******************************************************************************
-*                                                                             *
 *  Paramètres  : -                                                            *
 *                                                                             *
 *  Description : Fournit un accès à une définition de type à diffuser.        *
@@ -718,9 +686,6 @@ bool ensure_python_binary_portion_is_registered(void)
         if (!register_class_for_pygobject(dict, G_TYPE_BIN_PORTION, type, &PyGObject_Type))
             return false;
 
-        if (!py_binary_portion_define_constants(type))
-            return false;
-
         if (!define_binary_portion_constants(type))
             return false;
 
diff --git a/plugins/pychrysalide/glibext/constants.c b/plugins/pychrysalide/glibext/constants.c
index 680feaf..e24a6e0 100644
--- a/plugins/pychrysalide/glibext/constants.c
+++ b/plugins/pychrysalide/glibext/constants.c
@@ -49,8 +49,21 @@
 bool define_binary_portion_constants(PyTypeObject *type)
 {
     bool result;                            /* Bilan à retourner           */
+    PyObject *strdict;                      /* Groupe de chaînes constantes*/
     PyObject *values;                       /* Groupe de valeurs à établir */
 
+    result = create_string_constants_group_to_type(type, "BinaryPortionCode",
+                                                   "Selector names for the CSS rendering.", &strdict);
+
+    if (result) result = extend_string_constants_group(strdict, "RAW", BPC_RAW);
+    if (result) result = extend_string_constants_group(strdict, "CODE", BPC_CODE);
+    if (result) result = extend_string_constants_group(strdict, "DATA", BPC_DATA);
+    if (result) result = extend_string_constants_group(strdict, "DATA_RO", BPC_DATA_RO);
+    if (result) result = extend_string_constants_group(strdict, "DISASS_ERROR", BPC_DISASS_ERROR);
+
+    if (!result)
+        goto exit;
+
     values = PyDict_New();
 
     result = add_const_to_group(values, "NONE", PAC_NONE);
diff --git a/plugins/pychrysalide/helpers.c b/plugins/pychrysalide/helpers.c
index 5e911ea..73fb4a7 100644
--- a/plugins/pychrysalide/helpers.c
+++ b/plugins/pychrysalide/helpers.c
@@ -40,6 +40,7 @@
 
 #include "access.h"
 #include "constval.h"
+#include "strenum.h"
 
 
 
@@ -1324,3 +1325,71 @@ PyObject *_cast_with_constants_group(const char *owner, const char *name, unsign
     return result;
 
 }
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : dict = dictionnaire dont le contenu est à compléter.         *
+*                name = désignation humaine du groupe à constituer.           *
+*                doc  = documentation à associer au groupe.                   *
+*                out  = dictionnaire à compléter. [OUT]                       *
+*                                                                             *
+*  Description : Officialise un groupe de constantes de chaînes de caractères.*
+*                                                                             *
+*  Retour      : true en cas de succès de l'opération, false sinon.           *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+bool _create_string_constants_group(PyObject *dict, const char *name, const char *doc, PyObject **out)
+{
+    bool result;                            /* Bilan à retourner           */
+    PyObject *class;                        /* Classe "Enum*"              */
+    PyObject *args;                         /* Argument de construction    */
+    int ret;                                /* Bilan d'une insertion       */
+    PyObject *features;                     /* Module à recompléter        */
+    PyObject *features_dict;                /* Dictionnaire à compléter    */
+
+    result = false;
+
+    /* Recherche et instanciation de la classe Python */
+
+    class = (PyObject *)get_python_string_enum_type();
+
+    args = Py_BuildValue("(s)", doc);
+
+    *out = PyObject_CallObject(class, args);
+
+    Py_DECREF(args);
+
+    if (*out == NULL)
+        goto exit;
+
+    /* Constitution de l'énumération et enregistrement */
+
+    ret = PyDict_SetItemString(dict, name, *out);
+    if (ret != 0) goto register_0_error;
+
+    features = get_access_to_python_module("pychrysalide.features");
+
+    features_dict = PyModule_GetDict(features);
+
+    ret = PyDict_SetItemString(features_dict, name, *out);
+    if (ret != 0) goto register_1_error;
+
+    result = true;
+
+    /* Sortie propre */
+
+ register_1_error:
+ register_0_error:
+
+    if (!result)
+        Py_DECREF(*out);
+
+ exit:
+
+    return result;
+
+}
diff --git a/plugins/pychrysalide/helpers.h b/plugins/pychrysalide/helpers.h
index dbc9272..5f28c57 100644
--- a/plugins/pychrysalide/helpers.h
+++ b/plugins/pychrysalide/helpers.h
@@ -225,6 +225,33 @@ PyObject *_cast_with_constants_group(const char *, const char *, unsigned long);
 #define cast_with_constants_group_from_module(owner, name, value) \
     _cast_with_constants_group(owner, name, value)
 
+/* Officialise un groupe de constantes de chaînes de caractères. */
+bool _create_string_constants_group(PyObject *, const char *, const char *, PyObject **);
+
+#define create_string_constants_group_to_type(type, name, doc, out) \
+    _create_string_constants_group(type->tp_dict, name, doc, out)
+
+#define create_string_constants_group_to_module(mod, name, doc, out)        \
+    ({                                                                      \
+        bool __result;                                                      \
+        PyObject *__dict;                                                   \
+        __dict = PyModule_GetDict(mod);                                     \
+        __result = _create_string_constants_group(__dict, name, doc, out);  \
+        __result;                                                           \
+    })
+
+#define extend_string_constants_group(dict, key, str)           \
+    ({                                                          \
+        bool __result;                                          \
+        PyObject *__str_obj;                                    \
+        int __ret;                                              \
+        __str_obj = PyUnicode_FromString(str);                  \
+        __ret = PyDict_SetItemString(dict, key, __str_obj);     \
+        Py_DECREF(__str_obj);                                   \
+        __result = (__ret == 0);                                \
+        __result;                                               \
+    })
+
 
 
 #endif  /* _PLUGINS_PYCHRYSALIDE_HELPERS_H */
diff --git a/plugins/pychrysalide/pychrysa.c b/plugins/pychrysalide/pychrysa.c
index 683e41e..333544a 100644
--- a/plugins/pychrysalide/pychrysa.c
+++ b/plugins/pychrysalide/pychrysa.c
@@ -51,6 +51,7 @@
 #include "helpers.h"
 #include "plugin.h"
 #include "star.h"
+#include "strenum.h"
 #include "struct.h"
 #include "analysis/module.h"
 #include "arch/module.h"
@@ -527,6 +528,7 @@ PyMODINIT_FUNC PyInit_pychrysalide(void)
 
     if (status) status = ensure_python_plugin_module_is_registered();
     if (status) status = ensure_python_py_constval_is_registered();
+    if (status) status = ensure_python_string_enum_is_registered();
     if (status) status = ensure_python_py_struct_is_registered();
 
     if (status) status = populate_analysis_module();
diff --git a/plugins/pychrysalide/strenum.c b/plugins/pychrysalide/strenum.c
new file mode 100644
index 0000000..52ee383
--- /dev/null
+++ b/plugins/pychrysalide/strenum.c
@@ -0,0 +1,262 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * strenum.c - mise à disposition de constantes pointant des chaînes de caractères
+ *
+ * Copyright (C) 2020 Cyrille Bagard
+ *
+ *  This file is part of Chrysalide.
+ *
+ *  Chrysalide is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  Chrysalide is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+
+#include "strenum.h"
+
+
+#include <stddef.h>
+#include <string.h>
+#include <structmember.h>
+
+
+#include "access.h"
+#include "helpers.h"
+
+
+
+/* Objet à vocation abstraite */
+typedef struct _PyStringEnum
+{
+    PyDictObject base;                      /* A laisser en premier        */
+
+    char *grp_doc;                          /* Documentation d'instance    */
+
+    int val;
+
+} PyStringEnum;
+
+
+/* Initialise un objet Python de type 'StringEnum'. */
+static int py_string_enum_init(PyStringEnum *, PyObject *, PyObject *);
+
+/* Accompagne la suppression complète d'un objet 'StringEnum'. */
+static void py_string_enum_finalize(PyStringEnum *);
+
+/* Assure l'encadrement des accès aux champs d'une structure. */
+static PyObject *py_string_enum_getattr(PyObject *, char *);
+
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : self = instance d'objet à initialiser.                       *
+*                args = arguments passés pour l'appel.                        *
+*                kwds = mots clefs éventuellement fournis en complément.      *
+*                                                                             *
+*  Description : Initialise un objet Python de type 'StringEnum'.             *
+*                                                                             *
+*  Retour      : Bilan de l'opération.                                        *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static int py_string_enum_init(PyStringEnum *self, PyObject *args, PyObject *kwds)
+{
+    int result;                             /* Bilan à retourner           */
+    char *doc;                              /* Documentation de l'instance */
+    int ret;                                /* Bilan de lecture des args.  */
+
+#define STRING_ENUM_DOC                                             \
+    "StringEnum provides dictionaries collecting string constants." \
+    "\n"                                                            \
+    "Such constants are mainly used as keywords for accessing"      \
+    " configuration parameters."
+
+    result = -1;
+
+    doc = NULL;
+
+    ret = PyArg_ParseTuple(args, "|s", &doc);
+    if (!ret) goto exit;
+
+    if (doc != NULL)
+        self->grp_doc = strdup(doc);
+
+    result = 0;
+
+ exit:
+
+    return result;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : self = instance d'objet à traiter.                           *
+*                                                                             *
+*  Description : Accompagne la suppression complète d'un objet 'StringEnum'.  *
+*                                                                             *
+*  Retour      : -                                                            *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static void py_string_enum_finalize(PyStringEnum *self)
+{
+    if (self->grp_doc != NULL)
+        free(self->grp_doc);
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : self = structure C convertie en Python.                      *
+*                name = nom du champ auquel un accès est demandé.             *
+*                                                                             *
+*  Description : Assure l'encadrement des accès aux champs d'une structure.   *
+*                                                                             *
+*  Retour      : Valeur du champ demandé.                                     *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static PyObject *py_string_enum_getattr(PyObject *self, char *name)
+{
+    PyObject *result;                       /* Elément à retourner         */
+    PyObject *w;                            /* Conversion du nom de champ  */
+    PyTypeObject *tp;                       /* Type de l'objet manipulé    */
+
+    result = PyDict_GetItemString(self, name);
+
+    if (result != NULL)
+        Py_INCREF(result);
+
+    else
+    {
+        w = PyUnicode_InternFromString(name);
+        if (w == NULL) return NULL;
+
+        tp = Py_TYPE(self);
+
+        if (tp->tp_base->tp_getattro != NULL)
+            result = tp->tp_base->tp_getattro(self, w);
+
+        Py_DECREF(w);
+
+    }
+
+    return result;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : -                                                            *
+*                                                                             *
+*  Description : Fournit un accès à une définition de type à diffuser.        *
+*                                                                             *
+*  Retour      : Définition d'objet pour Python.                              *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+PyTypeObject *get_python_string_enum_type(void)
+{
+    static PyMethodDef py_string_enum_methods[] = {
+        { NULL }
+    };
+
+    static PyMemberDef py_string_enum_members[] = {
+        {
+            "__grp_doc__", T_STRING, offsetof(PyStringEnum, grp_doc), READONLY,
+            "Specialized documentation for an instance of the object."
+        },
+        { NULL }
+    };
+
+    static PyGetSetDef py_string_enum_getseters[] = {
+        { NULL }
+    };
+
+    static PyTypeObject py_string_enum_type = {
+
+        PyVarObject_HEAD_INIT(NULL, 0)
+
+        .tp_name        = "pychrysalide.StringEnum",
+        .tp_basicsize   = sizeof(PyStringEnum),
+
+        .tp_getattr     = py_string_enum_getattr,
+
+        .tp_flags       = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE \
+                          | Py_TPFLAGS_DICT_SUBCLASS | Py_TPFLAGS_HAVE_FINALIZE,
+
+        .tp_doc         = STRING_ENUM_DOC,
+
+        .tp_methods     = py_string_enum_methods,
+        .tp_members     = py_string_enum_members,
+        .tp_getset      = py_string_enum_getseters,
+        .tp_base        = &PyDict_Type,
+
+        .tp_init        = (initproc)py_string_enum_init,
+
+        .tp_finalize    = (destructor)py_string_enum_finalize,
+
+    };
+
+    return &py_string_enum_type;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : -                                                            *
+*                                                                             *
+*  Description : Prend en charge l'objet 'pychrysalide.PyStringEnum'.         *
+*                                                                             *
+*  Retour      : Bilan de l'opération.                                        *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+bool ensure_python_string_enum_is_registered(void)
+{
+    PyTypeObject *type;                     /* Type Python 'StringEnum'    */
+    PyObject *module;                       /* Module à recompléter        */
+
+    type = get_python_string_enum_type();
+
+    if (!PyType_HasFeature(type, Py_TPFLAGS_READY))
+    {
+        module = get_access_to_python_module("pychrysalide");
+
+        if (PyType_Ready(type) != 0)
+            return false;
+
+        if (!register_python_module_object(module, type))
+            return false;
+
+    }
+
+    return true;
+
+}
diff --git a/plugins/pychrysalide/strenum.h b/plugins/pychrysalide/strenum.h
new file mode 100644
index 0000000..04b841c
--- /dev/null
+++ b/plugins/pychrysalide/strenum.h
@@ -0,0 +1,42 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * strenum.h - prototypes pour la mise à disposition de constantes pointant des chaînes de caractères
+ *
+ * Copyright (C) 2020 Cyrille Bagard
+ *
+ *  This file is part of Chrysalide.
+ *
+ *  Chrysalide is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  Chrysalide is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+
+#ifndef _PLUGINS_PYCHRYSALIDE_STRENUM_H
+#define _PLUGINS_PYCHRYSALIDE_STRENUM_H
+
+
+#include <Python.h>
+#include <stdbool.h>
+
+
+
+/* Fournit un accès à une définition de type à diffuser. */
+PyTypeObject *get_python_string_enum_type(void);
+
+/* Prend en charge l'objet 'pychrysalide.StringEnum'. */
+bool ensure_python_string_enum_is_registered(void);
+
+
+
+#endif  /* _PLUGINS_PYCHRYSALIDE_STRENUM_H */
diff --git a/plugins/pychrysalide/struct.c b/plugins/pychrysalide/struct.c
index f34a9f3..2569fa2 100644
--- a/plugins/pychrysalide/struct.c
+++ b/plugins/pychrysalide/struct.c
@@ -1,6 +1,6 @@
 
 /* Chrysalide - Outil d'analyse de fichiers binaires
- * struct.c - prototypes pour la conversion de structures C en équivalent Python
+ * struct.c - conversion de structures C en équivalent Python
  *
  * Copyright (C) 2018-2019 Cyrille Bagard
  *
-- 
cgit v0.11.2-87-g4458