From eb9b7fd76451db5c9f07a800c0394480e4b88c9c Mon Sep 17 00:00:00 2001
From: Cyrille Bagard <nocbos@gmail.com>
Date: Tue, 16 Jan 2018 19:42:29 +0100
Subject: Improved the removal of format symbols.

---
 ChangeLog                        |  16 ++++++
 plugins/pychrysa/format/format.c | 104 +++++++++++++++++++++++++++++++++++++--
 plugins/pychrysa/format/symbol.c |   2 +-
 src/format/format.c              |  15 +++---
 tests/format/format.py           |  66 +++++++++++++++++++++++++
 5 files changed, 192 insertions(+), 11 deletions(-)
 create mode 100644 tests/format/format.py

diff --git a/ChangeLog b/ChangeLog
index 416027c..bd8482a 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,18 @@
+18-01-16  Cyrille Bagard <nocbos@gmail.com>
+
+	* plugins/pychrysa/format/format.c:
+	Add and remove symbols from the Python API.
+
+	* plugins/pychrysa/format/symbol.c:
+	Typo.
+
+	* src/format/format.c:
+	Improve the removal of format symbols.
+
+	* tests/format/format.py:
+	New entry: create a test suite entry for checking the addition / removal
+	of symbols.
+
 18-01-13  Cyrille Bagard <nocbos@gmail.com>
 
 	* plugins/pychrysa/format/Makefile.am:
@@ -17,6 +32,7 @@
 	* src/analysis/disass/output.c:
 	* src/analysis/disass/routines.c:
 	* src/analysis/disass/routines.h:
+	Update code.
 
 	* src/arch/processor.c:
 	Fix a compilation bug when NDEBUG is defined.
diff --git a/plugins/pychrysa/format/format.c b/plugins/pychrysa/format/format.c
index 5920b27..3bfc705 100644
--- a/plugins/pychrysa/format/format.c
+++ b/plugins/pychrysa/format/format.c
@@ -31,6 +31,7 @@
 #include <format/format.h>
 
 
+#include "symbol.h"
 #include "symiter.h"
 #include "../helpers.h"
 #include "../arch/vmpa.h"
@@ -40,6 +41,13 @@
 /* ---------------------------- FORMAT BINAIRE GENERIQUE ---------------------------- */
 
 
+
+/* Ajoute un symbole à la collection du format binaire. */
+static PyObject *py_binary_format_add_symbol(PyObject *, PyObject *);
+
+/* Retire un symbole de la collection du format binaire. */
+static PyObject *py_binary_format_remove_symbol(PyObject *, PyObject *);
+
 /* Recherche le symbole correspondant à une étiquette. */
 static PyObject *py_binary_format_find_symbol_by_label(PyObject *, PyObject *);
 
@@ -84,6 +92,84 @@ static bool define_python_binary_format_constants(PyTypeObject *);
 /* ---------------------------------------------------------------------------------- */
 
 
+
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : self = classe représentant un format.                        *
+*                args = arguments fournis à l'appel.                          *
+*                                                                             *
+*  Description : Ajoute un symbole à la collection du format binaire.         *
+*                                                                             *
+*  Retour      : True si le symbole était bien localisé et a été inséré.      *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static PyObject *py_binary_format_add_symbol(PyObject *self, PyObject *args)
+{
+    PyObject *result;                       /* Valeur à retourner          */
+    PyObject *symbol_obj;                   /* Version Python d'un symbole */
+    int ret;                                /* Bilan de lecture des args.  */
+    GBinFormat *format;                     /* Format de binaire manipulé  */
+    GBinSymbol *symbol;                     /* Enventuel symbole trouvé    */
+    bool added;                             /* Bilan de l'appel interne    */
+
+    ret = PyArg_ParseTuple(args, "O!", get_python_binary_symbol_type(), &symbol_obj);
+    if (!ret) return NULL;
+
+    format = G_BIN_FORMAT(pygobject_get(self));
+    symbol = G_BIN_SYMBOL(pygobject_get(symbol_obj));
+
+    added = g_binary_format_add_symbol(format, symbol);
+
+    result = added ? Py_True : Py_False;
+    Py_INCREF(result);
+
+    return result;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : self = classe représentant un format.                        *
+*                args = arguments fournis à l'appel.                          *
+*                                                                             *
+*  Description : Retire un symbole de la collection du format binaire.        *
+*                                                                             *
+*  Retour      : -                                                            *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static PyObject *py_binary_format_remove_symbol(PyObject *self, PyObject *args)
+{
+    PyObject *result;                       /* Valeur à retourner          */
+    PyObject *symbol_obj;                   /* Version Python d'un symbole */
+    int ret;                                /* Bilan de lecture des args.  */
+    GBinFormat *format;                     /* Format de binaire manipulé  */
+    GBinSymbol *symbol;                     /* Enventuel symbole trouvé    */
+
+    ret = PyArg_ParseTuple(args, "O!", get_python_binary_symbol_type(), &symbol_obj);
+    if (!ret) return NULL;
+
+    format = G_BIN_FORMAT(pygobject_get(self));
+    symbol = G_BIN_SYMBOL(pygobject_get(symbol_obj));
+
+    g_binary_format_remove_symbol(format, symbol);
+
+    result = Py_None;
+    Py_INCREF(result);
+
+    return result;
+
+}
+
+
 /******************************************************************************
 *                                                                             *
 *  Paramètres  : self = classe représentant un binaire.                       *
@@ -104,7 +190,7 @@ static PyObject *py_binary_format_find_symbol_by_label(PyObject *self, PyObject
     int ret;                                /* Bilan de lecture des args.  */
     GBinFormat *format;                     /* Format de binaire manipulé  */
     GBinSymbol *symbol;                     /* Enventuel symbole trouvé    */
-    bool found;                             
+    bool found;                             /* Bilan de la recherche       */
 
     ret = PyArg_ParseTuple(args, "O", &label);
     if (!ret) return NULL;
@@ -149,7 +235,7 @@ static PyObject *py_binary_format_find_symbol_at(PyObject *self, PyObject *args)
     int ret;                                /* Bilan de lecture des args.  */
     GBinFormat *format;                     /* Format de binaire manipulé  */
     GBinSymbol *symbol;                     /* Enventuel symbole trouvé    */
-    bool found;                             
+    bool found;                             /* Bilan de la recherche       */
 
     ret = PyArg_ParseTuple(args, "O", &py_vmpa);
     if (!ret) return NULL;
@@ -197,7 +283,7 @@ static PyObject *py_binary_format_find_next_symbol_at(PyObject *self, PyObject *
     int ret;                                /* Bilan de lecture des args.  */
     GBinFormat *format;                     /* Format de binaire manipulé  */
     GBinSymbol *symbol;                     /* Enventuel symbole trouvé    */
-    bool found;                             
+    bool found;                             /* Bilan de la recherche       */
 
     ret = PyArg_ParseTuple(args, "O", &py_vmpa);
     if (!ret) return NULL;
@@ -247,7 +333,7 @@ static PyObject *py_binary_format_resolve_symbol(PyObject *self, PyObject *args)
     GBinFormat *format;                     /* Format de binaire manipulé  */
     GBinSymbol *symbol;                     /* Enventuel symbole trouvé    */
     phys_t diff;                            /* Décallage éventuel mesuré   */
-    bool found;                             
+    bool found;                             /* Bilan de la recherche       */
 
     ret = PyArg_ParseTuple(args, "Op", &py_vmpa, &strict);
     if (!ret) return NULL;
@@ -486,6 +572,16 @@ PyTypeObject *get_python_binary_format_type(void)
 {
     static PyMethodDef py_bin_format_methods[] = {
         {
+            "add_symbol", py_binary_format_add_symbol,
+            METH_VARARGS,
+            "add_symbol($self, symbol, /)\n--\n\nRegister a new symbol for the format."
+        },
+        {
+            "remove_symbol", py_binary_format_remove_symbol,
+            METH_VARARGS,
+            "remove_symbol($self, symbol, /)\n--\n\nUnregister a symbol from the format."
+        },
+        {
             "find_symbol_by_label", py_binary_format_find_symbol_by_label,
             METH_VARARGS,
             "find_symbol_by_label($self, label, /)\n--\n\nFind a symbol by its label."
diff --git a/plugins/pychrysa/format/symbol.c b/plugins/pychrysa/format/symbol.c
index 736a8d2..5ddaca2 100644
--- a/plugins/pychrysa/format/symbol.c
+++ b/plugins/pychrysa/format/symbol.c
@@ -138,7 +138,7 @@ static PyObject *py_binary_symbol_new(PyTypeObject *type, PyObject *args, PyObje
 
     if (stype >= STP_COUNT)
     {
-        PyErr_SetString(PyExc_ValueError, _("Invalid type of message"));
+        PyErr_SetString(PyExc_ValueError, _("Invalid type of symbol."));
         return NULL;
     }
 
diff --git a/src/format/format.c b/src/format/format.c
index a188204..b975a7c 100644
--- a/src/format/format.c
+++ b/src/format/format.c
@@ -654,15 +654,18 @@ static void _g_binary_format_remove_symbol(GBinFormat *format, size_t index)
 
 void g_binary_format_remove_symbol(GBinFormat *format, GBinSymbol *symbol)
 {
-    size_t i;                               /* Boucle de parcours          */
+    bool found;                             /* Jeton de présence           */
+    size_t index;                           /* Indice du point de retrait  */
+
+    g_binary_format_lock_unlock_symbols_wr(format, true);
 
-    // FIXME : dicho
+    found = bsearch_index(&symbol, format->symbols, format->sym_count,
+                          sizeof(GBinSymbol *), (__compar_fn_t)g_binary_symbol_cmp, &index);
 
-    for (i = 0; i < format->sym_count; i++)
-        if (format->symbols[i] == symbol)
-            break;
+    if (found)
+        _g_binary_format_remove_symbol(format, index);
 
-    _g_binary_format_remove_symbol(format, i);
+    g_binary_format_lock_unlock_symbols_wr(format, false);
 
 }
 
diff --git a/tests/format/format.py b/tests/format/format.py
new file mode 100644
index 0000000..b6aad8f
--- /dev/null
+++ b/tests/format/format.py
@@ -0,0 +1,66 @@
+#!/usr/bin/python3-dbg
+# -*- coding: utf-8 -*-
+
+
+# Tests minimalistes pour valider la gestion des erreurs relevées.
+
+
+from chrysacase import ChrysalideTestCase
+from pychrysalide.arch import vmpa, mrange
+from pychrysalide.format import BinFormat
+from pychrysalide.format import BinSymbol
+import os
+import sys
+
+
+class SimpleFormat(BinFormat):
+    pass
+
+
+class TestFormatErrors(ChrysalideTestCase):
+    """TestCase for format.BinFormat."""
+
+
+    def create_fake_symbol(self, index):
+        saddr = vmpa(index * 0x10, vmpa.VMPA_NO_VIRTUAL)
+        srange = mrange(saddr, 0x3)
+        symbol = BinSymbol(BinSymbol.STP_ENTRY_POINT, srange)
+        return symbol
+
+
+    def testBasicSymbolOperations(self):
+        """Deal with the basic operations related to symbols in a binary format."""
+
+        sf = SimpleFormat()
+
+        self.assertTrue(len(list(sf.symbols)) == 0)
+
+        symbols = [ self.create_fake_symbol(i) for i in range(4) ]
+        s0, s1, s2, s3 = symbols
+
+        for s in symbols:
+            sf.add_symbol(s)
+
+        self.assertTrue(len(list(sf.symbols)) == len(symbols))
+
+        sf.remove_symbol(s2)
+
+        self.assertTrue(list(sf.symbols) == [s0, s1, s3])
+
+
+    def testBadParamsForAdding(self):
+        """Check if bad parameters fail for adding a new symbol."""
+
+        sf = SimpleFormat()
+
+        with self.assertRaises(TypeError):
+            sf.add_symbol('s')
+
+
+    def testWrongRemoval(self):
+        """Try to remove a wrong symbol from a format."""
+
+        sf = SimpleFormat()
+
+        s23 = self.create_fake_symbol(23)
+        sf.remove_symbol(s23)
-- 
cgit v0.11.2-87-g4458