From 041056d04032d41a5c092c62cbfd67b199094991 Mon Sep 17 00:00:00 2001
From: Cyrille Bagard <nocbos@gmail.com>
Date: Mon, 18 May 2020 23:50:26 +0200
Subject: Updated the Python API for string symbols.

---
 plugins/dex/pool.c                      |   2 +-
 plugins/elf/strings.c                   |   2 +-
 plugins/pychrysalide/format/constants.c | 100 ++++++++++++
 plugins/pychrysalide/format/constants.h |   6 +
 plugins/pychrysalide/format/strsym.c    | 274 +++++++++++++++++++++++++-------
 plugins/pychrysalide/format/symbol.c    |   2 +-
 plugins/readelf/strtab.c                |   2 +-
 src/format/strsym.c                     |  92 ++++++++---
 src/format/strsym.h                     |  10 +-
 tests/format/strsym.py                  |  33 ++++
 10 files changed, 440 insertions(+), 83 deletions(-)
 create mode 100644 tests/format/strsym.py

diff --git a/plugins/dex/pool.c b/plugins/dex/pool.c
index cf7b794..dc9031b 100644
--- a/plugins/dex/pool.c
+++ b/plugins/dex/pool.c
@@ -387,7 +387,7 @@ GBinSymbol *g_dex_pool_get_string_symbol(GDexPool *pool, uint32_t index)
 
         base = G_BIN_FORMAT(pool->format);
 
-        new = g_string_symbol_new_read_only(base, &range, SET_MUTF_8);
+        new = g_string_symbol_new_read_only(SET_MUTF_8, base, &range);
 
         if (new != NULL)
             g_string_symbol_build_label(G_STR_SYMBOL(new), base);
diff --git a/plugins/elf/strings.c b/plugins/elf/strings.c
index 7a2b34a..9b14753 100644
--- a/plugins/elf/strings.c
+++ b/plugins/elf/strings.c
@@ -359,7 +359,7 @@ static bool do_elf_string_loading(GElfLoading *loading, GElfFormat *format, phys
         {
             range = g_arch_instruction_get_range(instr);
 
-            symbol = g_string_symbol_new_read_only(base, range, SET_GUESS);
+            symbol = g_string_symbol_new_read_only(SET_GUESS, base, range);
 
             g_object_ref(G_OBJECT(symbol));
 
diff --git a/plugins/pychrysalide/format/constants.c b/plugins/pychrysalide/format/constants.c
index 0df7bd4..9669b46 100644
--- a/plugins/pychrysalide/format/constants.c
+++ b/plugins/pychrysalide/format/constants.c
@@ -26,6 +26,7 @@
 
 
 #include <format/format.h>
+#include <format/strsym.h>
 #include <format/symbol.h>
 
 
@@ -159,3 +160,102 @@ bool define_binary_symbol_constants(PyTypeObject *type)
     return result;
 
 }
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : type = type dont le dictionnaire est à compléter.            *
+*                                                                             *
+*  Description : Définit les constantes pour les symboles liés à des chaînes. *
+*                                                                             *
+*  Retour      : true en cas de succès de l'opération, false sinon.           *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+bool define_string_symbol_constants(PyTypeObject *type)
+{
+    bool result;                            /* Bilan à retourner           */
+    PyObject *values;                       /* Groupe de valeurs à établir */
+
+    result = true;
+
+    values = PyDict_New();
+
+    if (result) result = add_const_to_group(values, "NONE", SET_NONE);
+    if (result) result = add_const_to_group(values, "ASCII", SET_ASCII);
+    if (result) result = add_const_to_group(values, "UTF_8", SET_UTF_8);
+    if (result) result = add_const_to_group(values, "MUTF_8", SET_MUTF_8);
+    if (result) result = add_const_to_group(values, "GUESS", SET_GUESS);
+
+    if (!result)
+    {
+        Py_DECREF(values);
+        goto exit;
+    }
+
+    result = attach_constants_group_to_type(type, false, "StringEncodingType", values,
+                                            "Kinds of encoding for strings.");
+
+ 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 StringEncodingType.          *
+*                                                                             *
+*  Retour      : Bilan de l'opération, voire indications supplémentaires.     *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+int convert_to_string_encoding_type(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 StringEncodingType");
+            break;
+
+        case 1:
+            value = PyLong_AsUnsignedLong(arg);
+
+            if (value > SET_GUESS)
+            {
+                PyErr_SetString(PyExc_TypeError, "invalid value for StringEncodingType");
+                result = 0;
+            }
+
+            else
+                *((StringEncodingType *)dst) = value;
+
+            break;
+
+        default:
+            assert(false);
+            break;
+
+    }
+
+    return result;
+
+}
diff --git a/plugins/pychrysalide/format/constants.h b/plugins/pychrysalide/format/constants.h
index ad7b9a5..bbed6ae 100644
--- a/plugins/pychrysalide/format/constants.h
+++ b/plugins/pychrysalide/format/constants.h
@@ -37,6 +37,12 @@ bool define_binary_format_constants(PyTypeObject *);
 /* Définit les constantes pour les symboles binaires. */
 bool define_binary_symbol_constants(PyTypeObject *);
 
+/* Définit les constantes pour les symboles liés à des chaînes. */
+bool define_string_symbol_constants(PyTypeObject *);
+
+/* Tente de convertir en constante StringEncodingType. */
+int convert_to_string_encoding_type(PyObject *, void *);
+
 
 
 #endif  /* _PLUGINS_PYCHRYSALIDE_FORMAT_CONSTANTS_H */
diff --git a/plugins/pychrysalide/format/strsym.c b/plugins/pychrysalide/format/strsym.c
index e465002..2824677 100644
--- a/plugins/pychrysalide/format/strsym.c
+++ b/plugins/pychrysalide/format/strsym.c
@@ -33,15 +33,33 @@
 
 
 #include <format/strsym.h>
+#include <plugins/dt.h>
 
 
+#include "constants.h"
+#include "format.h"
 #include "symbol.h"
 #include "../access.h"
 #include "../helpers.h"
 #include "../arch/feeder.h"
+#include "../arch/vmpa.h"
 
 
 
+/* ------------------------ GLUE POUR CREATION DEPUIS PYTHON ------------------------ */
+
+
+/* Accompagne la création d'une instance dérivée en Python. */
+static PyObject *py_string_symbol_new(PyTypeObject *, PyObject *, PyObject *);
+
+/* Initialise une instance sur la base du dérivé de GObject. */
+static int py_string_symbol_init(PyObject *, PyObject *, PyObject *);
+
+
+
+/* ----------------------- VITRINE POUR CHAINES DE CARACTERES ----------------------- */
+
+
 /* Indique si une chaîne de caractères est liée au format. */
 static PyObject *py_string_symbol_get_structural(PyObject *, void *);
 
@@ -57,10 +75,173 @@ static PyObject *py_string_symbol_get_raw(PyObject *, void *);
 /* Fournit la chaîne de caractères du symbole. */
 static PyObject *py_string_symbol_get_utf8(PyObject *, void *);
 
-/* Définit les constantes pour les chaînes de caractères. */
-static bool py_string_symbol_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_string_symbol_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_string_symbol_type();
+
+    if (type == base)
+        goto simple_way;
+
+    /* Mise en place d'un type dédié */
+
+    first_time = (g_type_from_name(type->tp_name) == 0);
+
+    gtype = build_dynamic_type(G_TYPE_STR_SYMBOL, type->tp_name, NULL, NULL, NULL);
+
+    if (first_time)
+    {
+        status = register_class_for_dynamic_pygobject(gtype, type, base);
+
+        if (!status)
+        {
+            result = NULL;
+            goto exit;
+        }
+
+    }
+
+    /* On crée, et on laisse ensuite la main à PyGObject_Type.tp_init() */
+
+ simple_way:
+
+    result = PyType_GenericNew(type, args, kwds);
+
+ exit:
+
+    return result;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : self = objet à initialiser (théoriquement).                  *
+*                args = arguments fournis à l'appel.                          *
+*                kwds = arguments de type key=val fournis.                    *
+*                                                                             *
+*  Description : Initialise une instance sur la base du dérivé de GObject.    *
+*                                                                             *
+*  Retour      : 0.                                                           *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static int py_string_symbol_init(PyObject *self, PyObject *args, PyObject *kwds)
+{
+    StringEncodingType encoding;            /* Encodage spécifié           */
+    GBinFormat *format;                     /* Format au contenu à relire  */
+    mrange_t range;                         /* Version native d'un espace  */
+    const char *string;                     /* Chaîne de caractères soumise*/
+    vmpa2t *addr;                           /* Emplacement de chaîne       */
+    int ret;                                /* Bilan de lecture des args.  */
+    GStrSymbol *symbol;                     /* Version GLib du symbole     */
+
+    static char *kwlist[] = { "encoding", "format", "range", "string", "addr", NULL };
+
+#define STRING_SYMBOL_DOC                                                       \
+    "StrSymbol is a special symbol object dedicated to strings.\n"              \
+    "\n"                                                                        \
+    "Instances can be created using one of the following constructors:\n"       \
+    "\n"                                                                        \
+    "    StrSymbol(encoding, format=pychrysalide.format.BinFormat,"             \
+    " range=pychrysalide.arch.mrange)"                                          \
+    "\n"                                                                        \
+    "    StrSymbol(encoding, string=string, addr=pychrysalide.arch.vmpa)"       \
+    "\n"                                                                        \
+    "The first constructor is aimed to be used for read-only strings available" \
+    " from the raw data of the analyzed binary. The format provides the raw"    \
+    " content, and the memory range specifies the location of the string.\n"    \
+    "\n"                                                                        \
+    "The second constructor is useful for strings which can not be extracted"   \
+    " directly from the original content, such as obfuscted strings. A dynamic" \
+    " string is then provided here, and the start point of this string has to"  \
+    " be provided.\n"                                                           \
+    "\n"                                                                        \
+    "In both cases, the encoding remains the first argument, as a"              \
+    " pychrysalide.format.StrSymbol.StringEncodingType value."
+
+    /* Récupération des paramètres */
+
+    format = NULL;
+    string = NULL;
+    addr = NULL;
+
+    ret = PyArg_ParseTupleAndKeywords(args, kwds, "O&|O&O&sO&", kwlist,
+                                      convert_to_string_encoding_type, &encoding,
+                                      convert_to_binary_format, &format,
+                                      convert_any_to_mrange, &range,
+                                      &string, convert_any_to_vmpa, &addr);
+    if (!ret) return -1;
+
+    /* Initialisation d'un objet GLib */
+
+    ret = forward_pygobjet_init(self);
+    if (ret == -1) return -1;
+
+    /* Eléments de base */
+
+    symbol = G_STR_SYMBOL(pygobject_get(self));
+
+    if (format != NULL)
+        g_string_symbol_init_read_only(symbol, encoding, format, &range);
+
+    else if (string != NULL && addr != NULL)
+    {
+        g_string_symbol_init_dynamic(symbol, encoding, string, addr);
+        clean_vmpa_arg(addr);
+    }
+
+    else
+    {
+        PyErr_SetString(PyExc_ValueError, _("Invalid argument combination."));
+
+        if (addr != NULL)
+            clean_vmpa_arg(addr);
+
+        return -1;
+
+    }
+
+    return 0;
+
+}
+
+
+
+/* ---------------------------------------------------------------------------------- */
+/*                         VITRINE POUR CHAINES DE CARACTERES                         */
+/* ---------------------------------------------------------------------------------- */
+
 
 /******************************************************************************
 *                                                                             *
@@ -149,10 +330,17 @@ static PyObject *py_string_symbol_get_encoding(PyObject *self, void *closure)
     GStrSymbol *symbol;                     /* Elément à consulter         */
     StringEncodingType encoding;            /* Encodage associé à la chaîne*/
 
+#define STRING_SYMBOL_ENCODING_ATTRIB PYTHON_GET_DEF_FULL       \
+(                                                               \
+    encoding, py_string_symbol,                                 \
+    "Encoding of the string, provided as a"                     \
+    " pychrysalide.format.StrSymbol.StringEncodingType value."  \
+)
+
     symbol = G_STR_SYMBOL(pygobject_get(self));
     encoding = g_string_symbol_get_encoding(symbol);
 
-    result = PyLong_FromLong(encoding);
+    result = cast_with_constants_group_from_type(get_python_string_symbol_type(), "StringEncodingType", encoding);
 
     return result;
 
@@ -179,6 +367,12 @@ static PyObject *py_string_symbol_get_raw(PyObject *self, void *closure)
     size_t len;                             /* Taille de la chaîne         */
     const char *data;                       /* Données à manipuler         */
 
+#define STRING_SYMBOL_RAW_ATTRIB PYTHON_GET_DEF_FULL    \
+(                                                       \
+    raw, py_string_symbol,                              \
+    "Raw data of the string, provided as bytes."        \
+)
+
     symbol = G_STR_SYMBOL(pygobject_get(self));
     data = g_string_symbol_get_raw(symbol, &len);
 
@@ -209,6 +403,12 @@ static PyObject *py_string_symbol_get_utf8(PyObject *self, void *closure)
     size_t len;                             /* Taille de la chaîne         */
     const char *data;                       /* Données à manipuler         */
 
+#define STRING_SYMBOL_UTF8_ATTRIB PYTHON_GET_DEF_FULL   \
+(                                                       \
+    utf8, py_string_symbol,                             \
+    "String content as UTF-8 data."                     \
+)
+
     symbol = G_STR_SYMBOL(pygobject_get(self));
     data = g_string_symbol_get_utf8(symbol, &len);
 
@@ -221,37 +421,6 @@ static PyObject *py_string_symbol_get_utf8(PyObject *self, void *closure)
 
 /******************************************************************************
 *                                                                             *
-*  Paramètres  : obj_type = type dont le dictionnaire est à compléter.        *
-*                                                                             *
-*  Description : Définit les constantes pour les chaînes de caractères.       *
-*                                                                             *
-*  Retour      : true en cas de succès de l'opération, false sinon.           *
-*                                                                             *
-*  Remarques   : -                                                            *
-*                                                                             *
-******************************************************************************/
-
-static bool py_string_symbol_define_constants(PyTypeObject *obj_type)
-{
-    bool result;                            /* Bilan à retourner           */
-
-    result = true;
-
-    result &= PyDict_AddULongMacro(obj_type, SET_NONE);
-
-    result &= PyDict_AddULongMacro(obj_type, SET_ASCII);
-    result &= PyDict_AddULongMacro(obj_type, SET_UTF_8);
-    result &= PyDict_AddULongMacro(obj_type, SET_MUTF_8);
-
-    result &= PyDict_AddULongMacro(obj_type, SET_GUESS);
-
-    return result;
-
-}
-
-
-/******************************************************************************
-*                                                                             *
 *  Paramètres  : -                                                            *
 *                                                                             *
 *  Description : Fournit un accès à une définition de type à diffuser.        *
@@ -264,28 +433,19 @@ static bool py_string_symbol_define_constants(PyTypeObject *obj_type)
 
 PyTypeObject *get_python_string_symbol_type(void)
 {
-    static PyMethodDef py_str_symbol_methods[] = {
+    static PyMethodDef py_string_symbol_methods[] = {
         { NULL }
     };
 
-    static PyGetSetDef py_str_symbol_getseters[] = {
+    static PyGetSetDef py_string_symbol_getseters[] = {
         STRING_SYMBOL_STRUCTURAL_ATTRIB,
-        {
-            "encoding", py_string_symbol_get_encoding, NULL,
-            "Encoding of the string.", NULL
-        },
-        {
-            "raw", py_string_symbol_get_raw, NULL,
-            "String content as raw data.", NULL
-        },
-        {
-            "utf8", py_string_symbol_get_utf8, NULL,
-            "String content as UTF-8 data.", NULL
-        },
+        STRING_SYMBOL_ENCODING_ATTRIB,
+        STRING_SYMBOL_RAW_ATTRIB,
+        STRING_SYMBOL_UTF8_ATTRIB,
         { NULL }
     };
 
-    static PyTypeObject py_str_symbol_type = {
+    static PyTypeObject py_string_symbol_type = {
 
         PyVarObject_HEAD_INIT(NULL, 0)
 
@@ -294,14 +454,17 @@ PyTypeObject *get_python_string_symbol_type(void)
 
         .tp_flags       = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
 
-        .tp_doc         = "PyChrysalide string symbol",
+        .tp_doc         = STRING_SYMBOL_DOC,
 
-        .tp_methods     = py_str_symbol_methods,
-        .tp_getset      = py_str_symbol_getseters
+        .tp_methods     = py_string_symbol_methods,
+        .tp_getset      = py_string_symbol_getseters,
+
+        .tp_init        = py_string_symbol_init,
+        .tp_new         = py_string_symbol_new
 
     };
 
-    return &py_str_symbol_type;
+    return &py_string_symbol_type;
 
 }
 
@@ -335,10 +498,13 @@ bool ensure_python_string_symbol_is_registered(void)
         if (!ensure_python_proxy_feeder_is_registered())
             return false;
 
+        if (!ensure_python_binary_symbol_is_registered())
+            return false;
+
         if (!register_class_for_pygobject(dict, G_TYPE_STR_SYMBOL, type, get_python_binary_symbol_type()))
             return false;
 
-        if (!py_string_symbol_define_constants(type))
+        if (!define_string_symbol_constants(type))
             return false;
 
     }
diff --git a/plugins/pychrysalide/format/symbol.c b/plugins/pychrysalide/format/symbol.c
index 7ecc576..d6d6402 100644
--- a/plugins/pychrysalide/format/symbol.c
+++ b/plugins/pychrysalide/format/symbol.c
@@ -270,7 +270,7 @@ static int py_binary_symbol_init(PyObject *self, PyObject *args, PyObject *kwds)
     mrange_t range;                         /* Version native d'un espace  */
     unsigned long stype;                    /* Type prévu pour le  symbole */
     int ret;                                /* Bilan de lecture des args.  */
-    GBinSymbol *symbol;                     /* Version GLib du symble      */
+    GBinSymbol *symbol;                     /* Version GLib du symbole     */
 
 #define BINARY_SYMBOL_DOC                                                       \
     "BinSymbol represents all kinds of symbols, such as strings, routines or"   \
diff --git a/plugins/readelf/strtab.c b/plugins/readelf/strtab.c
index 2420da6..19b44bf 100644
--- a/plugins/readelf/strtab.c
+++ b/plugins/readelf/strtab.c
@@ -118,7 +118,7 @@ static void parse_elf_string_table(GElfFormat *format, GPreloadInfo *info, const
             {
                 irange = g_arch_instruction_get_range(instr);
 
-                symbol = g_string_symbol_new_read_only(base, irange, SET_GUESS);
+                symbol = g_string_symbol_new_read_only(SET_GUESS, base, irange);
 
                 g_object_ref(G_OBJECT(symbol));
 
diff --git a/src/format/strsym.c b/src/format/strsym.c
index b078fe1..91232f4 100644
--- a/src/format/strsym.c
+++ b/src/format/strsym.c
@@ -233,9 +233,9 @@ static void g_string_symbol_finalize(GStrSymbol *symbol)
 
 /******************************************************************************
 *                                                                             *
-*  Paramètres  : format   = format binaire reconnu.                           *
+*  Paramètres  : encoding = encodage de la chaîne de caractères à représenter.*
+*                format   = format binaire reconnu.                           *
 *                range    = espace couvert par le nouveau symbole.            *
-*                encoding = encodage de la chaîne de caractères à représenter.*
 *                                                                             *
 *  Description : Crée un nouveau symbole pour chaîne de caractères.           *
 *                                                                             *
@@ -245,35 +245,58 @@ static void g_string_symbol_finalize(GStrSymbol *symbol)
 *                                                                             *
 ******************************************************************************/
 
-GBinSymbol *g_string_symbol_new_read_only(GBinFormat *format, const mrange_t *range, StringEncodingType encoding)
+GBinSymbol *g_string_symbol_new_read_only(StringEncodingType encoding, GBinFormat *format, const mrange_t *range)
 {
     GStrSymbol *result;                     /* Nouveau symbole à renvoyer  */
-    GBinSymbol *parent;                     /* Type d'instance parent      */
 
     result = g_object_new(G_TYPE_STR_SYMBOL, NULL);
 
-    parent = G_BIN_SYMBOL(result);
+    g_string_symbol_init_read_only(result, encoding, format, range);
+
+    return G_BIN_SYMBOL(result);
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : symbole  = symbole dont la définition est à initialiser.     *
+*                encoding = encodage de la chaîne de caractères à représenter.*
+*                format   = format binaire reconnu.                           *
+*                range    = espace couvert par le nouveau symbole.            *
+*                                                                             *
+*  Description : Réalise la complète initialisation d'unsymbole pour chaîne.  *
+*                                                                             *
+*  Retour      : -                                                            *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+void g_string_symbol_init_read_only(GStrSymbol *symbol, StringEncodingType encoding, GBinFormat *format, const mrange_t *range)
+{
+    GBinSymbol *parent;                     /* Type d'instance parent      */
+
+    parent = G_BIN_SYMBOL(symbol);
 
     g_binary_symbol_set_range(parent, range);
     g_binary_symbol_set_stype(parent, STP_RO_STRING);
 
-    result->encoding = encoding;
-
-    result->content = g_binary_format_get_content(format);
-    result->has_content = true;
+    symbol->encoding = encoding;
 
-    g_string_symbol_check_encoding(result);
+    symbol->content = g_binary_format_get_content(format);
+    symbol->has_content = true;
 
-    return G_BIN_SYMBOL(result);
+    g_string_symbol_check_encoding(symbol);
 
 }
 
 
 /******************************************************************************
 *                                                                             *
-*  Paramètres  : string   = contenu de la chaîne de caractères.               *
+*  Paramètres  : encoding = encodage de la chaîne de caractères à représenter.*
+*                string   = contenu de la chaîne de caractères.               *
 *                addr     = emplacement de cette chaîne virtuelle.            *
-*                encoding = encodage de la chaîne de caractères à représenter.*
 *                                                                             *
 *  Description : Crée un nouveau symbole pour chaîne de caractères.           *
 *                                                                             *
@@ -283,29 +306,52 @@ GBinSymbol *g_string_symbol_new_read_only(GBinFormat *format, const mrange_t *ra
 *                                                                             *
 ******************************************************************************/
 
-GBinSymbol *g_string_symbol_new_dynamic(const char *string, const vmpa2t *addr, StringEncodingType encoding)
+GBinSymbol *g_string_symbol_new_dynamic(StringEncodingType encoding, const char *string, const vmpa2t *addr)
 {
     GStrSymbol *result;                     /* Nouveau symbole à renvoyer  */
-    GBinSymbol *parent;                     /* Type d'instance parent      */
-    mrange_t range;                         /* Emplacement à constituer    */
 
     result = g_object_new(G_TYPE_STR_SYMBOL, NULL);
 
-    parent = G_BIN_SYMBOL(result);
+    g_string_symbol_init_dynamic(result, encoding, string, addr);
+
+    return G_BIN_SYMBOL(result);
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : symbole  = symbole dont la définition est à initialiser.     *
+*                encoding = encodage de la chaîne de caractères à représenter.*
+*                string   = contenu de la chaîne de caractères.               *
+*                addr     = emplacement de cette chaîne virtuelle.            *
+*                                                                             *
+*  Description : Réalise la complète initialisation d'unsymbole pour chaîne.  *
+*                                                                             *
+*  Retour      : -                                                            *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+void g_string_symbol_init_dynamic(GStrSymbol *symbol, StringEncodingType encoding, const char *string, const vmpa2t *addr)
+{
+    GBinSymbol *parent;                     /* Type d'instance parent      */
+    mrange_t range;                         /* Emplacement à constituer    */
+
+    parent = G_BIN_SYMBOL(symbol);
 
     init_mrange(&range, addr, strlen(string));
 
     g_binary_symbol_set_range(parent, &range);
     g_binary_symbol_set_stype(parent, STP_DYN_STRING);
 
-    result->encoding = encoding;
+    symbol->encoding = encoding;
 
-    result->string = strdup(string);
-    result->has_content = false;
-
-    g_string_symbol_check_encoding(result);
+    symbol->string = strdup(string);
+    symbol->has_content = false;
 
-    return G_BIN_SYMBOL(result);
+    g_string_symbol_check_encoding(symbol);
 
 }
 
diff --git a/src/format/strsym.h b/src/format/strsym.h
index 2400e59..6900251 100644
--- a/src/format/strsym.h
+++ b/src/format/strsym.h
@@ -69,10 +69,16 @@ typedef struct _GStrSymbolClass GStrSymbolClass;
 GType g_string_symbol_get_type(void);
 
 /* Crée un nouveau symbole pour chaîne de caractères. */
-GBinSymbol *g_string_symbol_new_read_only(GBinFormat *, const mrange_t *, StringEncodingType);
+GBinSymbol *g_string_symbol_new_read_only(StringEncodingType, GBinFormat *, const mrange_t *);
+
+/* Réalise la complète initialisation d'unsymbole pour chaîne. */
+void g_string_symbol_init_read_only(GStrSymbol *, StringEncodingType, GBinFormat *, const mrange_t *);
 
 /* Crée un nouveau symbole pour chaîne de caractères. */
-GBinSymbol *g_string_symbol_new_dynamic(const char *, const vmpa2t *, StringEncodingType);
+GBinSymbol *g_string_symbol_new_dynamic(StringEncodingType, const char *, const vmpa2t *);
+
+/* Réalise la complète initialisation d'unsymbole pour chaîne. */
+void g_string_symbol_init_dynamic(GStrSymbol *, StringEncodingType, const char *, const vmpa2t *);
 
 /* Définit si une chaîne de caractères est liée au format. */
 void g_string_symbol_set_structural(GStrSymbol *, bool);
diff --git a/tests/format/strsym.py b/tests/format/strsym.py
new file mode 100644
index 0000000..ba1d92f
--- /dev/null
+++ b/tests/format/strsym.py
@@ -0,0 +1,33 @@
+
+from chrysacase import ChrysalideTestCase
+from pychrysalide.analysis import BinContent
+from pychrysalide.analysis.contents import MemoryContent
+from pychrysalide.arch import vmpa, mrange
+from pychrysalide.format import FlatFormat, StrSymbol
+
+
+class TestBinarySymbols(ChrysalideTestCase):
+    """TestCase for format.StrSymbol."""
+
+    def testStringSymbolConstructors(self):
+        """Build string symbols."""
+
+        data = b'ABCD1234'
+
+        cnt = MemoryContent(data)
+        fmt = FlatFormat(cnt, 'xxx', BinContent.SourceEndian.LITTLE)
+
+        saddr = vmpa(0x0, vmpa.VmpaSpecialValue.NO_VIRTUAL)
+        srange = mrange(saddr, 0x5)
+
+        symbol = StrSymbol(StrSymbol.StringEncodingType.GUESS, fmt, srange)
+
+        self.assertEqual(symbol.raw, b'ABCD1')
+        self.assertEqual(symbol.utf8, 'ABCD1')
+        self.assertEqual(symbol.encoding, StrSymbol.StringEncodingType.ASCII)
+
+        symbol = StrSymbol(StrSymbol.StringEncodingType.GUESS, string='abcdef', addr=saddr)
+
+        self.assertEqual(symbol.raw, b'abcdef')
+        self.assertEqual(symbol.utf8, 'abcdef')
+        self.assertEqual(symbol.encoding, StrSymbol.StringEncodingType.ASCII)
-- 
cgit v0.11.2-87-g4458