From 9dca3fdb21e3086363038926d4f49e1300b4130d Mon Sep 17 00:00:00 2001
From: Cyrille Bagard <nocbos@gmail.com>
Date: Sat, 22 Aug 2020 20:03:30 +0200
Subject: Restored the operand display switch feature.

---
 plugins/pychrysalide/analysis/db/items/Makefile.am |   3 +-
 plugins/pychrysalide/analysis/db/items/module.c    |   3 +
 plugins/pychrysalide/analysis/db/items/switcher.c  | 658 +++++++++++++++++++++
 plugins/pychrysalide/analysis/db/items/switcher.h  |  62 ++
 plugins/pychrysalide/arch/operands/constants.c     |  59 ++
 plugins/pychrysalide/arch/operands/constants.h     |   3 +
 src/analysis/db/items/switcher.c                   | 373 ++++++++----
 src/analysis/db/items/switcher.h                   |  20 +-
 src/core/collections.c                             |   4 +-
 src/gui/menus/edition.c                            |   3 +-
 10 files changed, 1050 insertions(+), 138 deletions(-)
 create mode 100644 plugins/pychrysalide/analysis/db/items/switcher.c
 create mode 100644 plugins/pychrysalide/analysis/db/items/switcher.h

diff --git a/plugins/pychrysalide/analysis/db/items/Makefile.am b/plugins/pychrysalide/analysis/db/items/Makefile.am
index bea86de..07593f8 100644
--- a/plugins/pychrysalide/analysis/db/items/Makefile.am
+++ b/plugins/pychrysalide/analysis/db/items/Makefile.am
@@ -4,7 +4,8 @@ noinst_LTLIBRARIES = libpychrysaanalysisdbitems.la
 libpychrysaanalysisdbitems_la_SOURCES =	\
 	bookmark.h bookmark.c				\
 	comment.h comment.c					\
-	module.h module.c
+	module.h module.c					\
+	switcher.h switcher.c
 
 libpychrysaanalysisdbitems_la_LDFLAGS = 
 
diff --git a/plugins/pychrysalide/analysis/db/items/module.c b/plugins/pychrysalide/analysis/db/items/module.c
index 0ab63fa..c963354 100644
--- a/plugins/pychrysalide/analysis/db/items/module.c
+++ b/plugins/pychrysalide/analysis/db/items/module.c
@@ -30,6 +30,7 @@
 
 #include "bookmark.h"
 #include "comment.h"
+#include "switcher.h"
 #include "../../../helpers.h"
 
 
@@ -90,8 +91,10 @@ bool populate_analysis_db_items_module(void)
     result = true;
 
     if (result) result = ensure_python_bookmark_collection_is_registered();
+    if (result) result = ensure_python_switcher_collection_is_registered();
     if (result) result = ensure_python_db_bookmark_is_registered();
     if (result) result = ensure_python_db_comment_is_registered();
+    if (result) result = ensure_python_db_switcher_is_registered();
 
     assert(result);
 
diff --git a/plugins/pychrysalide/analysis/db/items/switcher.c b/plugins/pychrysalide/analysis/db/items/switcher.c
new file mode 100644
index 0000000..07aa038
--- /dev/null
+++ b/plugins/pychrysalide/analysis/db/items/switcher.c
@@ -0,0 +1,658 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * switcher.c - équivalent Python du fichier "analysis/db/items/switcher.c"
+ *
+ * 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 "switcher.h"
+
+
+#include <malloc.h>
+#include <pygobject.h>
+
+
+#include <analysis/db/items/switcher.h>
+#include <plugins/dt.h>
+
+
+#include "../collection.h"
+#include "../item.h"
+#include "../../../access.h"
+#include "../../../helpers.h"
+#include "../../../arch/instruction.h"
+#include "../../../arch/vmpa.h"
+#include "../../../arch/operands/constants.h"
+#include "../../../arch/operands/immediate.h"
+
+
+
+/* --------------------- ELABORATION D'UN ELEMENT DE COLLECTION --------------------- */
+
+
+/* Crée un nouvel objet Python de type 'DbSwitcher'. */
+static PyObject *py_db_switcher_new(PyTypeObject *, PyObject *, PyObject *);
+
+/* Initialise une instance sur la base du dérivé de GObject. */
+static int py_db_switcher_init(PyObject *, PyObject *, PyObject *);
+
+/* Fournit l'adresse associée à une bascule. */
+static PyObject *py_db_switcher_get_address(PyObject *, void *);
+
+/* Fournit le chemin menant vers l'opérande basculé. */
+static PyObject *py_db_switcher_get_path(PyObject *, void *);
+
+/*  Indique l'affichage vers lequel un opérande a basculé. */
+static PyObject *py_db_switcher_get_display(PyObject *, void *);
+
+
+
+/* ---------------------- DEFINITION DE LA COLLECTION ASSOCIEE ---------------------- */
+
+
+/* Crée un nouvel objet Python de type 'SwitcherCollection'. */
+static PyObject *py_switcher_collection_new(PyTypeObject *, PyObject *, PyObject *);
+
+
+
+/* ---------------------------------------------------------------------------------- */
+/*                       ELABORATION D'UN ELEMENT DE COLLECTION                       */
+/* ---------------------------------------------------------------------------------- */
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : type = type de l'objet à instancier.                         *
+*                args = arguments fournis à l'appel.                          *
+*                kwds = arguments de type key=val fournis.                    *
+*                                                                             *
+*  Description : Crée un nouvel objet Python de type 'DbSwitcher'.            *
+*                                                                             *
+*  Retour      : Instance Python mise en place.                               *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static PyObject *py_db_switcher_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_db_switcher_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_DB_SWITCHER, 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 en cas de succès, -1 sinon.                                *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static int py_db_switcher_init(PyObject *self, PyObject *args, PyObject *kwds)
+{
+    int result;                             /* Bilan à renvoyer            */
+    GArchInstruction *instr;                /* Instruction propriétaire    */
+    GImmOperand *imm;                       /* Opérande concerné           */
+    ImmOperandDisplay display;              /* Type d'affichage forcé      */
+    int ret;                                /* Bilan de lecture des args.  */
+    GDbSwitcher *switcher;                  /* Version GLib de la bascule  */
+    bool status;                            /* Bilan de l'initialisation   */
+
+#define DB_SWITCHER_DOC                                                         \
+    "DbSwitcher allows to switch display for immediate operands.\n"             \
+    "\n"                                                                        \
+    "Instances can be created using the following constructor:\n"               \
+    "\n"                                                                        \
+    "    DbSwitcher(instr, imm, display)\n"                                     \
+    "\n"                                                                        \
+    "Where *instr* is an pychrysalide.arch.ArchInstruction instance containing" \
+    " the target *imm* operand, which must be an pychrysalide.arch.ImmOperand"  \
+    " object. The *display* argument defines the kind of display to apply, as"  \
+    " a pychrysalide.arch.operands.ImmOperand.ImmOperandDisplay value."         \
+    "\n"                                                                        \
+    "ImmOperandDisplay.COUNT can be used to reset the display to its default"   \
+    " state."
+
+    result = -1;
+
+    /* Récupération des paramètres */
+
+    ret = PyArg_ParseTuple(args, "O&O&O&",
+                           convert_to_arch_instruction, &instr,
+                           convert_to_imm_operand, &imm,
+                           convert_to_imm_operand_display, &display);
+    if (!ret) goto exit;
+
+    /* Initialisation d'un objet GLib */
+
+    ret = forward_pygobjet_init(self);
+    if (ret == -1) goto exit;
+
+    /* Eléments de base */
+
+    switcher = G_DB_SWITCHER(pygobject_get(self));
+
+    status = g_db_switcher_fill(switcher, instr, imm, display);
+    if (!status) goto exit;
+
+    result = 0;
+
+ exit:
+
+    return result;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : self    = objet Python concerné par l'appel.                 *
+*                closure = non utilisé ici.                                   *
+*                                                                             *
+*  Description : Fournit l'adresse associée à une bascule.                    *
+*                                                                             *
+*  Retour      : Adresse mémoire.                                             *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static PyObject *py_db_switcher_get_address(PyObject *self, void *closure)
+{
+    PyObject *result;                       /* Résultat à retourner        */
+    GDbSwitcher *switcher;                  /* Bascule à consulter         */
+    const vmpa2t *addr;                     /* Localisation de la bascule  */
+
+#define DB_SWITCHER_ADDRESS_ATTRIB PYTHON_GET_DEF_FULL              \
+(                                                                   \
+    address, py_db_switcher,                                        \
+    "Location of the instruction containing the switched operand,"  \
+    " as a pychrysalide.arch.vmpa instance."                        \
+)
+
+    switcher = G_DB_SWITCHER(pygobject_get(self));
+
+    addr = g_db_switcher_get_address(switcher);
+
+    result = build_from_internal_vmpa(addr);
+
+    return result;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : self    = objet Python concerné par l'appel.                 *
+*                closure = non utilisé ici.                                   *
+*                                                                             *
+*  Description : Fournit le chemin menant vers l'opérande basculé.            *
+*                                                                             *
+*  Retour      : Chemin de type "n[:n:n:n]".                                  *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static PyObject *py_db_switcher_get_path(PyObject *self, void *closure)
+{
+    PyObject *result;                       /* Résultat à retourner        */
+    GDbSwitcher *switcher;                  /* Bascule à consulter         */
+    const char *path;                       /* Chemin d'accès associé      */
+
+#define DB_SWITCHER_PATH_ATTRIB PYTHON_GET_DEF_FULL                 \
+(                                                                   \
+    path, py_db_switcher,                                           \
+    "Path used to retrieved internally the operand to switch.\n"    \
+    "\n"                                                            \
+    "This path is a string of the form 'n[:n:n:n]', where n is"     \
+    " an internal index."                                           \
+)
+
+    switcher = G_DB_SWITCHER(pygobject_get(self));
+
+    path = g_db_switcher_get_path(switcher);
+
+    result = PyUnicode_FromString(path);
+
+    return result;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : self    = objet Python concerné par l'appel.                 *
+*                closure = non utilisé ici.                                   *
+*                                                                             *
+*  Description : Indique l'affichage vers lequel un opérande a basculé.       *
+*                                                                             *
+*  Retour      : Type d'affichage forcé pour un opérande.                     *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static PyObject *py_db_switcher_get_display(PyObject *self, void *closure)
+{
+    PyObject *result;                       /* Résultat à retourner        */
+    GDbSwitcher *switcher;                  /* Bascule à consulter         */
+    ImmOperandDisplay display;              /* Type d'affichage associé    */
+
+#define DB_SWITCHER_DISPLAY_ATTRIB PYTHON_GET_DEF_FULL                  \
+(                                                                       \
+    display, py_db_switcher,                                            \
+    "Kind of display forced for the target operand, as an"              \
+    " pychrysalide.arch.operands.ImmOperand.ImmOperandDisplay value."   \
+)
+
+    switcher = G_DB_SWITCHER(pygobject_get(self));
+
+    display = g_db_switcher_get_display(switcher);
+
+    result = cast_with_constants_group_from_type(get_python_imm_operand_type(), "ImmOperandDisplay", display);
+
+    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_db_switcher_type(void)
+{
+    static PyMethodDef py_db_switcher_methods[] = {
+        { NULL }
+    };
+
+    static PyGetSetDef py_db_switcher_getseters[] = {
+        DB_SWITCHER_ADDRESS_ATTRIB,
+        DB_SWITCHER_PATH_ATTRIB,
+        DB_SWITCHER_DISPLAY_ATTRIB,
+        { NULL }
+    };
+
+    static PyTypeObject py_db_switcher_type = {
+
+        PyVarObject_HEAD_INIT(NULL, 0)
+
+        .tp_name        = "pychrysalide.analysis.db.items.DbSwitcher",
+        .tp_basicsize   = sizeof(PyGObject),
+
+        .tp_flags       = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
+
+        .tp_doc         = DB_SWITCHER_DOC,
+
+        .tp_methods     = py_db_switcher_methods,
+        .tp_getset      = py_db_switcher_getseters,
+
+        .tp_init        = py_db_switcher_init,
+        .tp_new         = py_db_switcher_new,
+
+    };
+
+    return &py_db_switcher_type;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : module = module dont la définition est à compléter.          *
+*                                                                             *
+*  Description : Prend en charge l'objet 'pychrysalide...db.items.DbSwitcher'.*
+*                                                                             *
+*  Retour      : Bilan de l'opération.                                        *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+bool ensure_python_db_switcher_is_registered(void)
+{
+    PyTypeObject *type;                     /* Type Python 'DbSwitcher'    */
+    PyObject *module;                       /* Module à recompléter        */
+    PyObject *dict;                         /* Dictionnaire du module      */
+
+    type = get_python_db_switcher_type();
+
+    if (!PyType_HasFeature(type, Py_TPFLAGS_READY))
+    {
+        module = get_access_to_python_module("pychrysalide.analysis.db.items");
+
+        dict = PyModule_GetDict(module);
+
+        if (!ensure_python_db_item_is_registered())
+            return false;
+
+        if (!register_class_for_pygobject(dict, G_TYPE_DB_SWITCHER, type, get_python_db_item_type()))
+            return false;
+
+    }
+
+    return true;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  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 bascule d'affichage de collection.     *
+*                                                                             *
+*  Retour      : Bilan de l'opération, voire indications supplémentaires.     *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+int convert_to_db_switcher(PyObject *arg, void *dst)
+{
+    int result;                             /* Bilan à retourner           */
+
+    result = PyObject_IsInstance(arg, (PyObject *)get_python_db_switcher_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 collection switcher");
+            break;
+
+        case 1:
+            *((GDbSwitcher **)dst) = G_DB_SWITCHER(pygobject_get(arg));
+            break;
+
+        default:
+            assert(false);
+            break;
+
+    }
+
+    return result;
+
+}
+
+
+
+/* ---------------------------------------------------------------------------------- */
+/*                        DEFINITION DE LA COLLECTION ASSOCIEE                        */
+/* ---------------------------------------------------------------------------------- */
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : type = type de l'objet à instancier.                         *
+*                args = arguments fournis à l'appel.                          *
+*                kwds = arguments de type key=val fournis.                    *
+*                                                                             *
+*  Description : Crée un nouvel objet Python de type 'SwitcherCollection'.    *
+*                                                                             *
+*  Retour      : Instance Python mise en place.                               *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static PyObject *py_switcher_collection_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   */
+
+#define SWITCHER_COLLECTION_DOC                                         \
+    "SwitcherCollection remembers all switch definitions for immediate" \
+    " operand display.\n"                                               \
+    "\n"                                                                \
+    "Instances can be created using the following constructor:\n"       \
+    "\n"                                                                \
+    "    SwitcherCollection()\n"                                        \
+    "\n"                                                                \
+    "There should be no need for creating such instances manually."
+
+    /* Validations diverses */
+
+    base = get_python_db_switcher_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_DB_SWITCHER, 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  : -                                                            *
+*                                                                             *
+*  Description : Fournit un accès à une définition de type à diffuser.        *
+*                                                                             *
+*  Retour      : Définition d'objet pour Python.                              *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+PyTypeObject *get_python_switcher_collection_type(void)
+{
+    static PyMethodDef py_switcher_collection_methods[] = {
+        { NULL }
+    };
+
+    static PyGetSetDef py_switcher_collection_getseters[] = {
+        { NULL }
+    };
+
+    static PyTypeObject py_switcher_collection_type = {
+
+        PyVarObject_HEAD_INIT(NULL, 0)
+
+        .tp_name        = "pychrysalide.analysis.db.items.SwitcherCollection",
+        .tp_basicsize   = sizeof(PyGObject),
+
+        .tp_flags       = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
+
+        .tp_doc         = SWITCHER_COLLECTION_DOC,
+
+        .tp_methods     = py_switcher_collection_methods,
+        .tp_getset      = py_switcher_collection_getseters,
+
+        .tp_new         = py_switcher_collection_new,
+
+    };
+
+    return &py_switcher_collection_type;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : module = module dont la définition est à compléter.          *
+*                                                                             *
+*  Description : Prend en charge l'objet 'pychrysalide....SwitcherCollection'.*
+*                                                                             *
+*  Retour      : Bilan de l'opération.                                        *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+bool ensure_python_switcher_collection_is_registered(void)
+{
+    PyTypeObject *type;                     /* Type Python 'DbSwitcher'    */
+    PyObject *module;                       /* Module à recompléter        */
+    PyObject *dict;                         /* Dictionnaire du module      */
+
+    type = get_python_switcher_collection_type();
+
+    if (!PyType_HasFeature(type, Py_TPFLAGS_READY))
+    {
+        module = get_access_to_python_module("pychrysalide.analysis.db.items");
+
+        dict = PyModule_GetDict(module);
+
+        if (!ensure_python_db_item_is_registered())
+            return false;
+
+        if (!register_class_for_pygobject(dict, G_TYPE_SWITCHER_COLLECTION, type, get_python_db_collection_type()))
+            return false;
+
+    }
+
+    return true;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  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 collection de bascules.                *
+*                                                                             *
+*  Retour      : Bilan de l'opération, voire indications supplémentaires.     *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+int convert_to_switcher_collection(PyObject *arg, void *dst)
+{
+    int result;                             /* Bilan à retourner           */
+
+    result = PyObject_IsInstance(arg, (PyObject *)get_python_switcher_collection_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 switcher collection");
+            break;
+
+        case 1:
+            *((GSwitcherCollection **)dst) = G_SWITCHER_COLLECTION(pygobject_get(arg));
+            break;
+
+        default:
+            assert(false);
+            break;
+
+    }
+
+    return result;
+
+}
diff --git a/plugins/pychrysalide/analysis/db/items/switcher.h b/plugins/pychrysalide/analysis/db/items/switcher.h
new file mode 100644
index 0000000..48ea142
--- /dev/null
+++ b/plugins/pychrysalide/analysis/db/items/switcher.h
@@ -0,0 +1,62 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * switcher.h - prototypes pour l'équivalent Python du fichier "analysis/db/items/switcher.h"
+ *
+ * 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_ANALYSIS_DB_ITEMS_SWITCHER_H
+#define _PLUGINS_PYCHRYSALIDE_ANALYSIS_DB_ITEMS_SWITCHER_H
+
+
+#include <Python.h>
+#include <stdbool.h>
+
+
+
+/* --------------------- ELABORATION D'UN ELEMENT DE COLLECTION --------------------- */
+
+
+/* Fournit un accès à une définition de type à diffuser. */
+PyTypeObject *get_python_db_switcher_type(void);
+
+/* Prend en charge l'objet 'pychrysalide.analysis.db.items.DbSwitcher'. */
+bool ensure_python_db_switcher_is_registered(void);
+
+/* Tente de convertir en bascule d'affichage de collection. */
+int convert_to_db_switcher(PyObject *, void *);
+
+
+
+/* ---------------------- DEFINITION DE LA COLLECTION ASSOCIEE ---------------------- */
+
+
+/* Fournit un accès à une définition de type à diffuser. */
+PyTypeObject *get_python_switcher_collection_type(void);
+
+/* Prend en charge l'objet 'pychrysalide.analysis.db.items.SwitcherCollection'. */
+bool ensure_python_switcher_collection_is_registered(void);
+
+/* Tente de convertir en collection de bascules. */
+int convert_to_switcher_collection(PyObject *, void *);
+
+
+
+#endif  /* _PLUGINS_PYCHRYSALIDE_ANALYSIS_DB_ITEMS_SWITCHER_H */
diff --git a/plugins/pychrysalide/arch/operands/constants.c b/plugins/pychrysalide/arch/operands/constants.c
index 464f70d..b9d80e4 100644
--- a/plugins/pychrysalide/arch/operands/constants.c
+++ b/plugins/pychrysalide/arch/operands/constants.c
@@ -25,6 +25,9 @@
 #include "constants.h"
 
 
+#include <assert.h>
+
+
 #include <arch/operands/immediate.h>
 
 
@@ -73,3 +76,59 @@ bool define_imm_operand_constants(PyTypeObject *type)
     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 ImmOperandDisplay.           *
+*                                                                             *
+*  Retour      : Bilan de l'opération, voire indications supplémentaires.     *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+int convert_to_imm_operand_display(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 ImmOperandDisplay");
+            break;
+
+        case 1:
+            value = PyLong_AsUnsignedLong(arg);
+
+            if (value > IOD_COUNT)
+            {
+                PyErr_SetString(PyExc_TypeError, "invalid value for ImmOperandDisplay");
+                result = 0;
+            }
+
+            else
+                *((ImmOperandDisplay *)dst) = value;
+
+            break;
+
+        default:
+            assert(false);
+            break;
+
+    }
+
+    return result;
+
+}
diff --git a/plugins/pychrysalide/arch/operands/constants.h b/plugins/pychrysalide/arch/operands/constants.h
index b7910c3..71a26cc 100644
--- a/plugins/pychrysalide/arch/operands/constants.h
+++ b/plugins/pychrysalide/arch/operands/constants.h
@@ -34,6 +34,9 @@
 /* Définit les constantes relatives aux opérandes d'immédiats. */
 bool define_imm_operand_constants(PyTypeObject *);
 
+/* Tente de convertir en constante ImmOperandDisplay. */
+int convert_to_imm_operand_display(PyObject *, void *);
+
 
 
 #endif  /* _PLUGINS_PYCHRYSALIDE_ARCH_OPERANDS_CONSTANTS_H */
diff --git a/src/analysis/db/items/switcher.c b/src/analysis/db/items/switcher.c
index 9c6a2a3..3ae9358 100644
--- a/src/analysis/db/items/switcher.c
+++ b/src/analysis/db/items/switcher.c
@@ -34,6 +34,7 @@
 
 #include "../collection-int.h"
 #include "../item-int.h"
+#include "../../../glibext/gbinarycursor.h"
 
 
 
@@ -46,10 +47,9 @@ struct _GDbSwitcher
     GDbItem parent;                         /* A laisser en premier        */
 
     vmpa2t addr;                            /* Adresse de l'instruction    */
-    size_t index;                           /* Indice de l'opérande visé   */
+    rle_string path;                        /* Chemin vers l'opérande visé */
 
     ImmOperandDisplay display;              /* Type de bascule             */
-    ImmOperandDisplay old;                  /* Type de bascule précédente  */
 
 };
 
@@ -74,6 +74,12 @@ static void g_db_switcher_dispose(GDbSwitcher *);
 /* Procède à la libération totale de la mémoire. */
 static void g_db_switcher_finalize(GDbSwitcher *);
 
+/* Calcule le condensat associé à l'élément vu comme clef. */
+static guint g_db_switcher_hash_key(const GDbSwitcher *);
+
+/* Compare deux éléments en tant que clefs. */
+static gboolean g_db_switcher_cmp_key(const GDbSwitcher *, const GDbSwitcher *);
+
 /* Effectue la comparaison entre deux signets de collection. */
 static gint g_db_switcher_cmp(const GDbSwitcher *, const GDbSwitcher *);
 
@@ -87,7 +93,7 @@ static bool g_db_switcher_pack(const GDbSwitcher *, packed_buffer *);
 static char *g_db_switcher_build_label(GDbSwitcher *);
 
 /* Exécute une bascule d'affichage d'opérande sur un binaire. */
-static bool g_db_switcher_run(GDbSwitcher *, GLoadedBinary *, ImmOperandDisplay *, ImmOperandDisplay);
+static bool g_db_switcher_run(GDbSwitcher *, GLoadedBinary *, ImmOperandDisplay);
 
 /* Applique une bascule d'affichage d'opérande sur un binaire. */
 static bool g_db_switcher_apply(GDbSwitcher *, GLoadedBinary *);
@@ -173,6 +179,8 @@ static void g_db_switcher_class_init(GDbSwitcherClass *klass)
 
     item->feature = DBF_DISPLAY_SWITCHERS;
 
+    item->hash_key = (hash_db_item_key_fc)g_db_switcher_hash_key;
+    item->cmp_key = (cmp_db_item_key_fc)g_db_switcher_cmp_key;
     item->cmp = (cmp_db_item_fc)g_db_switcher_cmp;
 
     item->unpack = (unpack_db_item_fc)g_db_switcher_unpack;
@@ -202,6 +210,11 @@ static void g_db_switcher_class_init(GDbSwitcherClass *klass)
 
 static void g_db_switcher_init(GDbSwitcher *switcher)
 {
+    init_vmpa(&switcher->addr, VMPA_NO_PHYSICAL, VMPA_NO_VIRTUAL);
+
+    setup_empty_rle_string(&switcher->path);
+
+    switcher->display = IOD_COUNT;
 
 }
 
@@ -239,6 +252,8 @@ static void g_db_switcher_dispose(GDbSwitcher *switcher)
 
 static void g_db_switcher_finalize(GDbSwitcher *switcher)
 {
+    exit_rle_string(&switcher->path);
+
     G_OBJECT_CLASS(g_db_switcher_parent_class)->finalize(G_OBJECT(switcher));
 
 }
@@ -246,12 +261,13 @@ static void g_db_switcher_finalize(GDbSwitcher *switcher)
 
 /******************************************************************************
 *                                                                             *
-*  Paramètres  : addr    = adresse inamovible localisant une position donnée. *
-*                comment = commentaire construit ou NULL.                     *
+*  Paramètres  : instr   = instruction contenant l'opérande à traiter.        *
+*                imm     = opérande de valeur immédiate concernée.            *
+*                display = forme d'affichage à établir pour l'opérande.       *
 *                                                                             *
-*  Description : Crée une définition d'un signet dans une zone de texte.      *
+*  Description : Crée une définition de bascule d'affichage pour un immédiat. *
 *                                                                             *
-*  Retour      : Signet mis en place ou NULL en cas d'erreur.                 *
+*  Retour      : Bascule mise en place ou NULL en cas d'erreur.               *
 *                                                                             *
 *  Remarques   : -                                                            *
 *                                                                             *
@@ -260,53 +276,122 @@ static void g_db_switcher_finalize(GDbSwitcher *switcher)
 GDbSwitcher *g_db_switcher_new(GArchInstruction *instr, const GImmOperand *imm, ImmOperandDisplay display)
 {
     GDbSwitcher *result;                    /* Instance à retourner        */
-    size_t count;                           /* Nombre d'opérandes à visiter*/
-    size_t i;                               /* Boucle de parcours          */
-    GArchOperand *op;                       /* Opérande manipulé           */
+    bool status;                            /* Bilan de l'initialisation   */
+
+    result = g_object_new(G_TYPE_DB_SWITCHER, NULL);
+
+    status = g_db_switcher_fill(result, instr, imm, display);
+    if (!status) goto error;
+
+    return result;
+
+ error:
+
+    g_object_unref(G_OBJECT(result));
+
+    return NULL;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : switcher = bascule à initialiser.                            *
+*                instr    = instruction contenant l'opérande à traiter.       *
+*                imm      = opérande de valeur immédiate concerné.            *
+*                display  = forme d'affichage à établir pour l'opérande.      *
+*                                                                             *
+*  Description : Initialise la définition de bascule d'affichage.             *
+*                                                                             *
+*  Retour      : Bilan de l'opération.                                        *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+bool g_db_switcher_fill(GDbSwitcher *switcher, GArchInstruction *instr, const GImmOperand *imm, ImmOperandDisplay display)
+{
+    bool result;                            /* Bilan à retourner           */
+    char *path;                             /* Chemin vers l'opérande visé */
     const mrange_t *range;                  /* Localisation de l'instruct° */
 
+    /**
+     * Cette fonction est principalement destinée aux initialisations
+     * depuis l'extension Python.
+     */
+
+    result = false;
+
     /* Recherche de la position de l'opérande */
 
-    g_arch_instruction_lock_operands(instr);
+    path = g_arch_instruction_find_operand_path(instr, G_ARCH_OPERAND(imm));
 
-    count = _g_arch_instruction_count_operands(instr);
+    if (path == NULL)
+        goto failure;
 
-    for (i = 0; i < count; i++)
-    {
-        op = _g_arch_instruction_get_operand(instr, i);
+    /* Sauvegarde des propriétés */
 
-        if (G_ARCH_OPERAND(imm) == op)
-        {
-            g_object_unref(G_OBJECT(op));
-            break;
-        }
+    range = g_arch_instruction_get_range(instr);
+    copy_vmpa(&switcher->addr, get_mrange_addr(range));
 
-        else
-            g_object_unref(G_OBJECT(op));
+    dup_into_rle_string(&switcher->path, path);
+    free(path);
 
-    }
+    switcher->display = display;
 
-    g_arch_instruction_unlock_operands(instr);
+    result = true;
 
-    if (i == count)
-        return NULL;
+ failure:
 
-    /* Sauvegarde des propriétés */
+    return result;
 
-    result = g_object_new(G_TYPE_DB_SWITCHER, NULL);
+}
 
-    range = g_arch_instruction_get_range(instr);
-    copy_vmpa(&result->addr, get_mrange_addr(range));
 
-    result->index = i;
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : switcher = élément de collection à consulter.                *
+*                                                                             *
+*  Description : Calcule le condensat associé à l'élément vu comme clef.      *
+*                                                                             *
+*  Retour      : Condensat associé à l'élément.                               *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static guint g_db_switcher_hash_key(const GDbSwitcher *switcher)
+{
+    guint result;                           /* Valeur "unique" à renvoyer  */
+
+    result = hash_vmpa(&switcher->addr);
+
+    return result;
 
-    result->display = display;
+}
 
-    /* Création d'un intitulé adapté */
 
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : a = premier élément de collection à consulter.               *
+*                b = second élément de collection à consulter.                *
+*                                                                             *
+*  Description : Compare deux éléments en tant que clefs.                     *
+*                                                                             *
+*  Retour      : Bilan de la comparaison.                                     *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
 
+static gboolean g_db_switcher_cmp_key(const GDbSwitcher *a, const GDbSwitcher *b)
+{
+    gboolean result;                        /* Bilan à retourner           */
+    int ret;                                /* Bilan intermédiaire         */
 
-    //g_db_switcher_set_comment(result, comment);
+    ret = cmp_vmpa(&a->addr, &b->addr);
+
+    result = (ret == 0);
 
     return result;
 
@@ -333,14 +418,7 @@ static gint g_db_switcher_cmp(const GDbSwitcher *a, const GDbSwitcher *b)
     result = cmp_vmpa(&a->addr, &b->addr);
 
     if (result == 0)
-    {
-        if (a->index < b->index)
-            result = -1;
-
-        else if (a->index > b->index)
-            result = 1;
-
-    }
+        result = cmp_rle_string(&a->path, &b->path);
 
     if (result == 0)
     {
@@ -381,10 +459,7 @@ static bool g_db_switcher_unpack(GDbSwitcher *switcher, packed_buffer *pbuf)
         result = unpack_vmpa(&switcher->addr, pbuf);
 
     if (result)
-    {
-        result = extract_packed_buffer(pbuf, &tmp32, sizeof(uint32_t), true);
-        switcher->index = tmp32;
-    }
+        result = unpack_rle_string(&switcher->path, pbuf);
 
     if (result)
     {
@@ -424,7 +499,7 @@ static bool g_db_switcher_pack(const GDbSwitcher *switcher, packed_buffer *pbuf)
         result = pack_vmpa(&switcher->addr, pbuf);
 
     if (result)
-        result = extend_packed_buffer(pbuf, (uint32_t []) { switcher->index }, sizeof(uint32_t), true);
+        result = pack_rle_string(&switcher->path, pbuf);
 
     if (result)
         result = extend_packed_buffer(pbuf, (uint32_t []) { switcher->display }, sizeof(uint32_t), true);
@@ -448,7 +523,7 @@ static bool g_db_switcher_pack(const GDbSwitcher *switcher, packed_buffer *pbuf)
 
 static char *g_db_switcher_build_label(GDbSwitcher *switcher)
 {
-#if 0
+    char *result;                           /* Description à retourner     */
     VMPA_BUFFER(loc);                       /* Indication de position      */
 
     vmpa2_to_string(&switcher->addr, MDS_UNDEFINED, loc, NULL);
@@ -456,26 +531,27 @@ static char *g_db_switcher_build_label(GDbSwitcher *switcher)
     switch (switcher->display)
     {
         case IOD_BIN:
-            asprintf(&G_DB_ITEM(switcher)->label, _("Switch to binary display at %s"), loc);
+            asprintf(&result, _("Switch to binary display at %s"), loc);
             break;
         case IOD_OCT:
-            asprintf(&G_DB_ITEM(switcher)->label, _("Switch to octal display at %s"), loc);
+            asprintf(&result, _("Switch to octal display at %s"), loc);
             break;
         case IOD_DEC:
-            asprintf(&G_DB_ITEM(switcher)->label, _("Switch to octal display at %s"), loc);
+            asprintf(&result, _("Switch to octal display at %s"), loc);
             break;
         case IOD_HEX:
-            asprintf(&G_DB_ITEM(switcher)->label, _("Switch to octal display at %s"), loc);
+            asprintf(&result, _("Switch to octal display at %s"), loc);
             break;
         case IOD_COUNT:
-            asprintf(&G_DB_ITEM(switcher)->label, _("Reset to default display at %s"), loc);
+            asprintf(&result, _("Reset to default display at %s"), loc);
             break;
         default:
             assert(false);
+            result = NULL;
             break;
     }
-#endif
-    return NULL;
+
+    return result;
 
 }
 
@@ -484,7 +560,6 @@ static char *g_db_switcher_build_label(GDbSwitcher *switcher)
 *                                                                             *
 *  Paramètres  : switcher = bascule d'affichage à manipuler.                  *
 *                binary   = binaire chargé en mémoire à modifier.             *
-*                old      = état précédent à conserver. [OUT]                 *
 *                new      = nouvel état à appliquer.                          *
 *                                                                             *
 *  Description : Exécute une bascule d'affichage d'opérande sur un binaire.   *
@@ -495,73 +570,69 @@ static char *g_db_switcher_build_label(GDbSwitcher *switcher)
 *                                                                             *
 ******************************************************************************/
 
-static bool g_db_switcher_run(GDbSwitcher *switcher, GLoadedBinary *binary, ImmOperandDisplay *old, ImmOperandDisplay new)
+static bool g_db_switcher_run(GDbSwitcher *switcher, GLoadedBinary *binary, ImmOperandDisplay new)
 {
-    return false;
-
-#if 0
     bool result;                            /* Bilan à faire remonter      */
     GArchProcessor *proc;                   /* Propriétaire d'instructions */
     GArchInstruction *instr;                /* Instruction à traiter       */
     GArchOperand *op;                       /* Opérande à modifier         */
-    GCodeBuffer *buffer;                    /* Tampon de lignes à traiter  */
-    GBufferLine *line;                      /* Ligne de tampon à marquer   */
     GImmOperand *operand;                   /* Opérande de valeur immédiate*/
-    char value[IMM_MAX_SIZE];               /* Chaîne à imprimer           */
-    size_t len;                             /* Taille de l'élément inséré  */
+    GBufferCache *cache;                    /* Tampon de lignes à traiter  */
+    GLineCursor *cursor;                    /* Emplacement dans un tampon  */
+    size_t index;                           /* Indice de ligne à traiter   */
 
-    result = true;
+    result = false;
 
     /* Traitement au niveau des instructions */
 
     proc = g_loaded_binary_get_processor(binary);
 
     instr = g_arch_processor_find_instr_by_address(proc, &switcher->addr);
-    if (instr == NULL)
-    {
-        result = false;
-        goto exit_instr;
-    }
+    if (instr == NULL) goto exit_instr;
 
-    op = g_arch_instruction_get_operand(instr, switcher->index);
-    if (op == NULL)
-    {
-        result = false;
-        goto exit_without_operand;
-    }
+    op = g_arch_instruction_get_operand_from_path(instr, get_rle_string(&switcher->path));
+    if (op == NULL) goto exit_without_operand;
 
     result = G_IS_IMM_OPERAND(op);
     if (!result) goto exit_operand;
 
+    operand = G_IMM_OPERAND(op);
+
+    if (new == IOD_COUNT)
+        new = g_imm_operand_get_default_display(operand);
+
+    g_imm_operand_set_display(operand, new);
+
     /* Traitement au niveau du rendu graphique */
 
-    buffer = g_loaded_binary_get_disassembled_buffer(binary);
+    cache = g_loaded_binary_get_disassembly_cache(binary);
+    if (cache == NULL) goto exit_operand;
 
-    line = g_code_buffer_find_line_by_addr(buffer, &switcher->addr, BLF_HAS_CODE, NULL);
-    if (line == NULL)
-    {
-        result = false;
-        goto exit_gui;
-    }
+    cursor = g_binary_cursor_new();
+    g_binary_cursor_update(G_BINARY_CURSOR(cursor), &switcher->addr);
 
-    operand = G_IMM_OPERAND(op);
+    g_buffer_cache_lock(cache);
 
-    *old = g_imm_operand_get_display(operand);
+    index = g_buffer_cache_find_index_by_cursor(cache, cursor, true);
 
-    if (new == IOD_COUNT)
-        new = g_imm_operand_get_default_display(operand);
+    g_object_unref(G_OBJECT(cursor));
+
+    index = g_buffer_cache_look_for_flag(cache, index, BLF_HAS_CODE);
 
-    g_imm_operand_set_display(&operand, new, G_SHARE_CONTAINER(instr));
+    if (index == g_buffer_cache_count_lines(cache))
+        goto exit_gui;
 
-    len = g_imm_operand_to_string(operand, value);
+    g_buffer_cache_refresh_line(cache, index);
 
-    result = g_buffer_line_replace_text(line, G_OBJECT(op), value, len);
+    result = true;
 
-    g_object_unref(G_OBJECT(line));
+    /* Phase de sortie propre */
 
  exit_gui:
 
-    /* TODO g_object_unref(G_OBJECT(buffer));*/
+    g_buffer_cache_unlock(cache);
+
+    g_object_unref(G_OBJECT(cache));
 
  exit_operand:
 
@@ -576,7 +647,7 @@ static bool g_db_switcher_run(GDbSwitcher *switcher, GLoadedBinary *binary, ImmO
     g_object_unref(G_OBJECT(proc));
 
     return result;
-#endif
+
 }
 
 
@@ -597,7 +668,7 @@ static bool g_db_switcher_apply(GDbSwitcher *switcher, GLoadedBinary *binary)
 {
     bool result;                            /* Bilan à faire remonter      */
 
-    result = g_db_switcher_run(switcher, binary, &switcher->old, switcher->display);
+    result = g_db_switcher_run(switcher, binary, switcher->display);
 
     return result;
 
@@ -621,7 +692,7 @@ static bool g_db_switcher_cancel(GDbSwitcher *switcher, GLoadedBinary *binary)
 {
     bool result;                            /* Bilan à faire remonter      */
 
-    result = g_db_switcher_run(switcher, binary, (ImmOperandDisplay []) { 0 }, switcher->old);
+    result = g_db_switcher_run(switcher, binary, IOD_COUNT);
 
     return result;
 
@@ -649,17 +720,9 @@ static bool g_db_switcher_load(GDbSwitcher *switcher, const bound_value *values,
 
     result = G_DB_ITEM_CLASS(g_db_switcher_parent_class)->load(G_DB_ITEM(switcher), values, count);
 
-    result &= load_vmpa(&switcher->addr, NULL, values, count);
+    if (result) result = load_vmpa(&switcher->addr, NULL, values, count);
 
-    if (result)
-    {
-        value = find_bound_value(values, count, "op_index");
-        result = (value != NULL && value->type == SQLITE_INTEGER);
-
-        if (result)
-            switcher->index = value->integer;
-
-    }
+    if (result) result = load_rle_string(&switcher->path, "path", values, count);
 
     if (result)
     {
@@ -709,22 +772,13 @@ static bool g_db_switcher_store(const GDbSwitcher *switcher, bound_value **value
 
     if (!status) return false;
 
-    *count += 2;
-    *values = realloc(*values, *count * sizeof(bound_value));
-
-    value = &(*values)[*count - 2];
-
-    value->cname = "op_index";
-    value->built_name = false;
-    value->type = SQLITE_INTEGER;
-
-    value->has_value = (switcher != NULL);
+    if (switcher == NULL)
+        status &= store_rle_string(NULL, "path", values, count);
+    else
+        status &= store_rle_string(&switcher->path, "path", values, count);
 
-    if (value->has_value)
-    {
-        value->integer = switcher->index;
-        value->delete = NULL;
-    }
+    *count += 1;
+    *values = realloc(*values, *count * sizeof(bound_value));
 
     value = &(*values)[*count - 1];
 
@@ -745,6 +799,75 @@ static bool g_db_switcher_store(const GDbSwitcher *switcher, bound_value **value
 }
 
 
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : switcher = informations à consulter.                         *
+*                                                                             *
+*  Description : Fournit l'adresse associée à une bascule.                    *
+*                                                                             *
+*  Retour      : Adresse mémoire.                                             *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+const vmpa2t *g_db_switcher_get_address(const GDbSwitcher *switcher)
+{
+    const vmpa2t *result;                   /* Localisation à retourner    */
+
+    result = &switcher->addr;
+
+    return result;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : switcher = informations à consulter.                         *
+*                                                                             *
+*  Description : Fournit le chemin menant vers l'opérande basculé.            *
+*                                                                             *
+*  Retour      : Chemin de type "n[:n:n:n]".                                  *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+const char *g_db_switcher_get_path(const GDbSwitcher *switcher)
+{
+    const char *result;                     /* Chemin à renvoyer           */
+
+    result = get_rle_string(&switcher->path);
+
+    return result;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : switcher = informations à consulter.                         *
+*                                                                             *
+*  Description : Indique l'affichage vers lequel un opérande a basculé.       *
+*                                                                             *
+*  Retour      : Type d'affichage forcé pour un opérande.                     *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+ImmOperandDisplay g_db_switcher_get_display(const GDbSwitcher *switcher)
+{
+    ImmOperandDisplay result;               /* Type d'affichage à retourner*/
+
+    result = switcher->display;
+
+    return result;
+
+}
+
+
 
 /* ---------------------------------------------------------------------------------- */
 /*                        DEFINITION DE LA COLLECTION ASSOCIEE                        */
@@ -887,11 +1010,11 @@ static bool g_switcher_collection_create_db_table(const GSwitcherCollection *col
     char *msg;                              /* Message d'erreur            */
     int ret;                                /* Bilan de la création        */
 
-    sql = "CREATE TABLE Switchers ("        \
-             SQLITE_DB_ITEM_CREATE ", "     \
-             "%s, "                         \
-             "op_index INTEGER, "           \
-             "type INTEGER"                 \
+    sql = "CREATE TABLE Switchers ("            \
+             SQLITE_DB_ITEM_CREATE ", "         \
+             "%s, "                             \
+             SQLITE_RLESTR_CREATE("path") ","   \
+             "type INTEGER"                     \
           ");";
 
     addr_fields = create_vmpa_db_table(NULL);
diff --git a/src/analysis/db/items/switcher.h b/src/analysis/db/items/switcher.h
index ecc6fd4..daf6154 100644
--- a/src/analysis/db/items/switcher.h
+++ b/src/analysis/db/items/switcher.h
@@ -54,19 +54,21 @@ typedef struct _GDbSwitcherClass GDbSwitcherClass;
 /* Indique le type défini pour un signet à l'intérieur d'une zone de texte. */
 GType g_db_switcher_get_type(void);
 
-/* Crée une définition d'un signet dans une zone de texte. */
+/* Crée une définition de bascule d'affichage pour un immédiat. */
 GDbSwitcher *g_db_switcher_new(GArchInstruction *, const GImmOperand *, ImmOperandDisplay);
 
-#if 0
-/* Fournit l'adresse associée à un signet. */
-const vmpa2t *g_db_switcher_get_address(GDbSwitcher *);
+/* Initialise la définition de bascule d'affichage. */
+bool g_db_switcher_fill(GDbSwitcher *, GArchInstruction *, const GImmOperand *, ImmOperandDisplay);
 
-/* Fournit le commentaire associé à un signet. */
-const char *g_db_switcher_get_comment(const GDbSwitcher *);
+/* Fournit l'adresse associée à une bascule. */
+const vmpa2t *g_db_switcher_get_address(const GDbSwitcher *);
+
+/* Fournit le chemin menant vers l'opérande basculé. */
+const char *g_db_switcher_get_path(const GDbSwitcher *);
+
+/* Indique l'affichage vers lequel un opérande a basculé. */
+ImmOperandDisplay g_db_switcher_get_display(const GDbSwitcher *);
 
-/* Définit le commentaire associé à un signet. */
-void g_db_switcher_set_comment(GDbSwitcher *, const char *);
-#endif
 
 
 /* ---------------------- DEFINITION DE LA COLLECTION ASSOCIEE ---------------------- */
diff --git a/src/core/collections.c b/src/core/collections.c
index 3419b2e..f5bccd7 100644
--- a/src/core/collections.c
+++ b/src/core/collections.c
@@ -103,7 +103,7 @@ bool load_hard_coded_collection_definitions(void)
      * afin de garder la correspondance entre les identifiants.
      */
 
-#ifndef NDEBUG
+#if 0 //ndef NDEBUG
 #   define REGISTER_COLLECTION(tp, exp)     \
     id = register_collection_type(tp);      \
     assert(id == exp);
@@ -118,7 +118,7 @@ bool load_hard_coded_collection_definitions(void)
 
     //REGISTER_COLLECTION(G_TYPE_MOVE_COLLECTION, DBF_MOVES);
 
-    //REGISTER_COLLECTION(G_TYPE_SWITCHER_COLLECTION, DBF_DISPLAY_SWITCHERS);
+    REGISTER_COLLECTION(G_TYPE_SWITCHER_COLLECTION, DBF_DISPLAY_SWITCHERS);
 
     return true;
 
diff --git a/src/gui/menus/edition.c b/src/gui/menus/edition.c
index b78c084..c9fe991 100644
--- a/src/gui/menus/edition.c
+++ b/src/gui/menus/edition.c
@@ -231,7 +231,8 @@ static void mcb_edition_switch_numeric_operand(GtkMenuItem *menuitem, gpointer u
 
     g_object_unref(G_OBJECT(instr));
 
-    g_loaded_binary_add_to_collection(binary, G_DB_ITEM(switcher));
+    if (switcher != NULL)
+        g_loaded_binary_add_to_collection(binary, G_DB_ITEM(switcher));
 
     g_object_unref(G_OBJECT(proc));
     g_object_unref(G_OBJECT(binary));
-- 
cgit v0.11.2-87-g4458