From 1e30e2c3822f55848e2306e59a2e66d7285f6b78 Mon Sep 17 00:00:00 2001
From: Cyrille Bagard <nocbos@gmail.com>
Date: Mon, 24 Jun 2024 23:55:03 +0200
Subject: Create functions suitable for [un]setting only one bit.

---
 plugins/pychrysalide/Makefile.am        |  3 +-
 plugins/pychrysalide/common/Makefile.am | 20 ++++----
 plugins/pychrysalide/common/bits.c      | 32 +++++++++----
 plugins/pychrysalide/common/module.c    | 18 ++++----
 plugins/pychrysalide/core.c             |  6 +--
 src/common/Makefile.am                  |  1 -
 src/common/bits.c                       | 82 +++++++++++++++++++++++++++++++--
 src/common/bits.h                       | 10 +++-
 src/plugins/plugin.c                    |  2 +-
 tests/common/bitfield.py                | 22 ++++-----
 10 files changed, 147 insertions(+), 49 deletions(-)

diff --git a/plugins/pychrysalide/Makefile.am b/plugins/pychrysalide/Makefile.am
index a6abf7f..8408c96 100644
--- a/plugins/pychrysalide/Makefile.am
+++ b/plugins/pychrysalide/Makefile.am
@@ -57,6 +57,7 @@ AM_CFLAGS = $(LIBPYTHON_INTERPRETER_CFLAGS) $(LIBPYGOBJECT_CFLAGS) $(TOOLKIT_CFL
 pychrysalide_la_LIBADD =					\
 	analysis/libpychrysaanalysis4.la		\
 	arch/libpychrysaarch4.la				\
+	common/libpychrysacommon.la				\
 	core/libpychrysacore.la					\
 	glibext/libpychrysaglibext.la			\
 	plugins/libpychrysaplugins.la
@@ -76,4 +77,4 @@ dev_HEADERS = $(pychrysalide_la_SOURCES:%c=)
 
 
 #SUBDIRS = analysis arch common core debug format glibext $(GTKEXT_SUBDIR) $(GUI_SUBDIR) mangling plugins
-SUBDIRS = analysis arch core glibext plugins
+SUBDIRS = analysis arch common core glibext plugins
diff --git a/plugins/pychrysalide/common/Makefile.am b/plugins/pychrysalide/common/Makefile.am
index b5249b9..199ef43 100644
--- a/plugins/pychrysalide/common/Makefile.am
+++ b/plugins/pychrysalide/common/Makefile.am
@@ -1,16 +1,20 @@
 
 noinst_LTLIBRARIES = libpychrysacommon.la
 
+# libpychrysacommon_la_SOURCES =				\
+# 	bits.h bits.c							\
+# 	fnv1a.h fnv1a.c							\
+# 	hex.h hex.c								\
+# 	itoa.h itoa.c							\
+# 	leb128.h leb128.c						\
+# 	module.h module.c						\
+# 	packed.h packed.c						\
+# 	pathname.h pathname.c					\
+# 	pearson.h pearson.c
+
 libpychrysacommon_la_SOURCES =				\
 	bits.h bits.c							\
-	fnv1a.h fnv1a.c							\
-	hex.h hex.c								\
-	itoa.h itoa.c							\
-	leb128.h leb128.c						\
-	module.h module.c						\
-	packed.h packed.c						\
-	pathname.h pathname.c					\
-	pearson.h pearson.c
+	module.h module.c
 
 libpychrysacommon_la_CFLAGS = $(TOOLKIT_CFLAGS) $(LIBXML_CFLAGS) $(LIBPYTHON_INTERPRETER_CFLAGS) $(LIBPYGOBJECT_CFLAGS) \
 	-I$(top_srcdir)/src -DNO_IMPORT_PYGOBJECT
diff --git a/plugins/pychrysalide/common/bits.c b/plugins/pychrysalide/common/bits.c
index a127251..35d6ea4 100644
--- a/plugins/pychrysalide/common/bits.c
+++ b/plugins/pychrysalide/common/bits.c
@@ -534,27 +534,33 @@ static PyObject *py_bitfield_set_all(PyObject *self, PyObject *args)
 
 static PyObject *py_bitfield_reset(PyObject *self, PyObject *args)
 {
-    unsigned long first;                    /* Indice du premier bit testé */
     unsigned long count;                    /* Nombre de bits à analyser   */
+    unsigned long first;                    /* Indice du premier bit testé */
     int ret;                                /* Bilan de lecture des args.  */
     py_bitfield_t *bf;                      /* Instance à manipuler        */
 
 #define BITFIELD_RESET_METHOD PYTHON_METHOD_DEF             \
 (                                                           \
-    reset, "$self, first, count, /",                        \
+    reset, "$self, first, /, count=1",                      \
     METH_VARARGS, py_bitfield,                              \
     "Switch to 0 a part of bits in a bitfield.\n"           \
     "\n"                                                    \
     "The area to process starts at bit *first* and has a"   \
-    " size of *count* bits."                                \
+    " size of *count* bits (only one bit is processed if"   \
+    " no *size* is provided)."                              \
 )
 
-    ret = PyArg_ParseTuple(args, "kk", &first, &count);
+    count = 1;
+
+    ret = PyArg_ParseTuple(args, "k|k", &first, &count);
     if (!ret) return NULL;
 
     bf = (py_bitfield_t *)self;
 
-    reset_in_bit_field(bf->native, first, count);
+    if (count == 1)
+        reset_in_bit_field(bf->native, first);
+    else
+        reset_multi_in_bit_field(bf->native, first, count);
 
     Py_RETURN_NONE;
 
@@ -576,27 +582,33 @@ static PyObject *py_bitfield_reset(PyObject *self, PyObject *args)
 
 static PyObject *py_bitfield_set(PyObject *self, PyObject *args)
 {
-    unsigned long first;                    /* Indice du premier bit testé */
     unsigned long count;                    /* Nombre de bits à analyser   */
+    unsigned long first;                    /* Indice du premier bit testé */
     int ret;                                /* Bilan de lecture des args.  */
     py_bitfield_t *bf;                      /* Instance à manipuler        */
 
 #define BITFIELD_SET_METHOD PYTHON_METHOD_DEF               \
 (                                                           \
-    set, "$self, first, count, /",                          \
+    set, "$self, first, /, count=1",                        \
     METH_VARARGS, py_bitfield,                              \
     "Switch to 1 a part of bits in a bitfield.\n"           \
     "\n"                                                    \
     "The area to process starts at bit *first* and has a"   \
-    " size of *count* bits."                                \
+    " size of *count* bits (only one bit is processed if"   \
+    " no *size* is provided)."                              \
 )
 
-    ret = PyArg_ParseTuple(args, "kk", &first, &count);
+    count = 1;
+
+    ret = PyArg_ParseTuple(args, "k|k", &first, &count);
     if (!ret) return NULL;
 
     bf = (py_bitfield_t *)self;
 
-    set_in_bit_field(bf->native, first, count);
+    if (count == 1)
+        set_in_bit_field(bf->native, first);
+    else
+        set_multi_in_bit_field(bf->native, first, count);
 
     Py_RETURN_NONE;
 
diff --git a/plugins/pychrysalide/common/module.c b/plugins/pychrysalide/common/module.c
index a0042ee..5fc1135 100644
--- a/plugins/pychrysalide/common/module.c
+++ b/plugins/pychrysalide/common/module.c
@@ -26,13 +26,13 @@
 
 
 #include "bits.h"
-#include "fnv1a.h"
-#include "hex.h"
-#include "itoa.h"
-#include "leb128.h"
-#include "packed.h"
-#include "pathname.h"
-#include "pearson.h"
+//#include "fnv1a.h"
+//#include "hex.h"
+//#include "itoa.h"
+//#include "leb128.h"
+//#include "packed.h"
+//#include "pathname.h"
+//#include "pearson.h"
 #include "../helpers.h"
 
 
@@ -98,15 +98,17 @@ bool populate_common_module(void)
 
     result = true;
 
+    /*
     if (result) result = populate_common_module_with_fnv1a();
     if (result) result = populate_common_module_with_hex();
     if (result) result = populate_common_module_with_itoa();
     if (result) result = populate_common_module_with_leb128();
     if (result) result = populate_common_module_with_pathname();
     if (result) result = populate_common_module_with_pearson();
+    */
 
     if (result) result = ensure_python_bitfield_is_registered();
-    if (result) result = ensure_python_packed_buffer_is_registered();
+    //if (result) result = ensure_python_packed_buffer_is_registered();
 
     assert(result);
 
diff --git a/plugins/pychrysalide/core.c b/plugins/pychrysalide/core.c
index 4d744c7..8510d78 100644
--- a/plugins/pychrysalide/core.c
+++ b/plugins/pychrysalide/core.c
@@ -60,8 +60,8 @@
 #include "struct.h"
 #include "analysis/module.h"
 #include "arch/module.h"
+#include "common/module.h"
 #include "glibext/module.h"
-/* #include "common/module.h" */
 /* #include "core/module.h" */
 /* #include "debug/module.h" */
 /* #include "format/module.h" */
@@ -645,9 +645,9 @@ PyMODINIT_FUNC PyInit_pychrysalide(void)
 
     if (status) status = add_analysis_module(result);
     if (status) status = add_arch_module(result);
+    if (status) status = add_common_module(result);
     if (status) status = add_glibext_module(result);
     /*
-    if (status) status = add_common_module(result);
     if (status) status = add_core_module(result);
     if (status) status = add_debug_module(result);
     if (status) status = add_format_module(result);
@@ -669,8 +669,8 @@ PyMODINIT_FUNC PyInit_pychrysalide(void)
     if (status) status = populate_analysis_module();
     if (status) status = populate_arch_module();
     if (status) status = populate_glibext_module();
-    /*
     if (status) status = populate_common_module();
+    /*
     if (status) status = populate_core_module();
     if (status) status = populate_debug_module();
     if (status) status = populate_format_module();
diff --git a/src/common/Makefile.am b/src/common/Makefile.am
index 27ead1d..0a7475f 100644
--- a/src/common/Makefile.am
+++ b/src/common/Makefile.am
@@ -6,7 +6,6 @@ libcommon_la_SOURCES =					\
 	array.h array.c						\
 	asm.h asm.c							\
 	bconst.h							\
-	bits.h bits.c						\
 	compression.h compression.c			\
 	cpp.h								\
 	cpu.h cpu.c							\
diff --git a/src/common/bits.c b/src/common/bits.c
index 37e3141..91872e1 100644
--- a/src/common/bits.c
+++ b/src/common/bits.c
@@ -442,6 +442,34 @@ void set_all_in_bit_field(bitfield_t *field)
 *                                                                             *
 *  Paramètres  : field = champ de bits à modifier.                            *
 *                first = indice du premier bit à traiter.                     *
+*                                                                             *
+*  Description : Bascule à 0 une partie d'un champ de bits.                   *
+*                                                                             *
+*  Retour      : -                                                            *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+void reset_in_bit_field(bitfield_t *field, size_t first)
+{
+    size_t index;                           /* Cellule de tableau visée    */
+    size_t remaining;                       /* Nombre de bits restants     */
+
+    assert(first < field->length);
+
+    index = first / (sizeof(unsigned long) * 8);
+    remaining = first % (sizeof(unsigned long) * 8);
+
+    field->bits[index] &= ~(1ul << remaining);
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : field = champ de bits à modifier.                            *
+*                first = indice du premier bit à traiter.                     *
 *                count = nombre de bits à marquer.                            *
 *                                                                             *
 *  Description : Bascule à 0 une partie d'un champ de bits.                   *
@@ -452,7 +480,7 @@ void set_all_in_bit_field(bitfield_t *field)
 *                                                                             *
 ******************************************************************************/
 
-void reset_in_bit_field(bitfield_t *field, size_t first, size_t count)
+void reset_multi_in_bit_field(bitfield_t *field, size_t first, size_t count)
 {
     size_t last;                            /* Point d'arrêt de la boucle  */
     size_t i;                               /* Boucle de parcours          */
@@ -479,6 +507,34 @@ void reset_in_bit_field(bitfield_t *field, size_t first, size_t count)
 *                                                                             *
 *  Paramètres  : field = champ de bits à modifier.                            *
 *                first = indice du premier bit à traiter.                     *
+*                                                                             *
+*  Description : Bascule à 1 une partie d'un champ de bits.                   *
+*                                                                             *
+*  Retour      : -                                                            *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+void set_in_bit_field(bitfield_t *field, size_t first)
+{
+    size_t index;                           /* Cellule de tableau visée    */
+    size_t remaining;                       /* Nombre de bits restants     */
+
+    assert(first < field->length);
+
+    index = first / (sizeof(unsigned long) * 8);
+    remaining = first % (sizeof(unsigned long) * 8);
+
+    field->bits[index] |= (1ul << remaining);
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : field = champ de bits à modifier.                            *
+*                first = indice du premier bit à traiter.                     *
 *                count = nombre de bits à marquer.                            *
 *                                                                             *
 *  Description : Bascule à 1 une partie d'un champ de bits.                   *
@@ -489,7 +545,7 @@ void reset_in_bit_field(bitfield_t *field, size_t first, size_t count)
 *                                                                             *
 ******************************************************************************/
 
-void set_in_bit_field(bitfield_t *field, size_t first, size_t count)
+void set_multi_in_bit_field(bitfield_t *field, size_t first, size_t count)
 {
     size_t last;                            /* Point d'arrêt de la boucle  */
     size_t i;                               /* Boucle de parcours          */
@@ -805,9 +861,25 @@ static bool test_state_within_bit_field(const bitfield_t *field, size_t first, c
     unsigned long bitmask;                  /* Masque à appliquer          */
     unsigned long test;                     /* Valeur résultante du test   */
 
-    result = true;
+    /**
+     * Si un masque est à appliquer avec débordement, les bits débordés sont considérés
+     * comme initialisés à la valeur par défaut.
+     */
+
+    if ((first + mask->length) > field->length)
+    {
+        assert(mask->length > 0);
+
+        result = (state == field->default_state);
+        if (!result) goto done;
 
-    assert((first + mask->length) <= field->length);
+        if (first >= field->length)
+            goto done;
+
+    }
+
+    else
+        result = true;
 
     start = first / (sizeof(unsigned long) * 8);
     offset = first % (sizeof(unsigned long) * 8);
@@ -849,6 +921,8 @@ static bool test_state_within_bit_field(const bitfield_t *field, size_t first, c
 
     }
 
+ done:
+
     return result;
 
 }
diff --git a/src/common/bits.h b/src/common/bits.h
index a66c6f0..3898c73 100644
--- a/src/common/bits.h
+++ b/src/common/bits.h
@@ -65,10 +65,16 @@ void reset_all_in_bit_field(bitfield_t *);
 void set_all_in_bit_field(bitfield_t *);
 
 /* Bascule à 0 une partie d'un champ de bits. */
-void reset_in_bit_field(bitfield_t *, size_t, size_t);
+void reset_in_bit_field(bitfield_t *, size_t);
+
+/* Bascule à 0 une partie d'un champ de bits. */
+void reset_multi_in_bit_field(bitfield_t *, size_t, size_t);
+
+/* Bascule à 1 une partie d'un champ de bits. */
+void set_in_bit_field(bitfield_t *, size_t);
 
 /* Bascule à 1 une partie d'un champ de bits. */
-void set_in_bit_field(bitfield_t *, size_t, size_t);
+void set_multi_in_bit_field(bitfield_t *, size_t, size_t);
 
 /* Réalise une opération ET logique entre deux champs de bits. */
 void and_bit_field(bitfield_t *, const bitfield_t *);
diff --git a/src/plugins/plugin.c b/src/plugins/plugin.c
index 5b3e475..1dc20e8 100644
--- a/src/plugins/plugin.c
+++ b/src/plugins/plugin.c
@@ -1015,7 +1015,7 @@ bool g_plugin_module_resolve_dependencies(GPluginModule *plugin, GPluginModule *
                 if (dependency->dependencies == NULL)
                     dependency->dependencies = create_bit_field(count, false);
 
-                set_in_bit_field(new, index, 1);
+                set_in_bit_field(new, index);
                 or_bit_field(new, dependency->dependencies);
 
                 /**
diff --git a/tests/common/bitfield.py b/tests/common/bitfield.py
index 75dfb6e..5d535fd 100644
--- a/tests/common/bitfield.py
+++ b/tests/common/bitfield.py
@@ -93,7 +93,7 @@ class TestBitFields(ChrysalideTestCase):
         bf_a = BitField(75, 0)
 
         bf_b = BitField(4, 1)
-        bf_b.reset(2, 1)
+        bf_b.reset(2)
 
         bf_a.or_at(bf_b, 63)
 
@@ -130,14 +130,14 @@ class TestBitFields(ChrysalideTestCase):
         bf_t = BitField(75, 0)
 
         for i in range(75):
-            bf_t.set(i, 1)
+            bf_t.set(i)
 
         self.assertEqual(bf_t, bf_1)
 
         self.assertEqual(bf_t.popcount, bf_1.popcount)
 
         for i in range(75):
-            bf_t.reset(i, 1)
+            bf_t.reset(i)
 
         self.assertEqual(bf_t, bf_0)
 
@@ -223,8 +223,8 @@ class TestBitFields(ChrysalideTestCase):
         """Check bitfield comparison."""
 
         bf_a = BitField(9, 0)
-        bf_a.set(0, 1)
-        bf_a.set(5, 1)
+        bf_a.set(0)
+        bf_a.set(5)
 
         bf_b = BitField(9, 1)
 
@@ -240,7 +240,7 @@ class TestBitFields(ChrysalideTestCase):
         bits = [ 0, 1, 50, 63, 64, 65, 111 ]
 
         for b in bits:
-            bf.set(b, 1)
+            bf.set(b)
 
         prev = None
         found = []
@@ -261,17 +261,17 @@ class TestBitFields(ChrysalideTestCase):
 
 
     def testRealCase00(self):
-        """Test bits in bitfields against other bitfields in a real case (#02)."""
+        """Test bits in bitfields against other bitfields in a real case (#00)."""
 
         bf = BitField(128, 0)
 
         for b in [ 0, 50, 54, 58, 66, 70, 98 ]:
-            bf.set(b, 1)
+            bf.set(b)
 
         mask = BitField(128, 0)
 
         for b in [ 0, 51 ]:
-            mask.set(b, 1)
+            mask.set(b)
 
         self.assertFalse(bf.test_zeros_with(0, mask))
 
@@ -284,7 +284,7 @@ class TestBitFields(ChrysalideTestCase):
         self.assertTrue(bf.test_zeros_with(0, mask))
 
         for b in [ 0, 8, 9, 10 ]:
-            mask.set(b, 1)
+            mask.set(b)
 
         self.assertTrue(bf.test_zeros_with(0, mask))
 
@@ -305,7 +305,7 @@ class TestBitFields(ChrysalideTestCase):
         bits = [ 0, 50, 54, 58, 66, 70, 98 ]
 
         for b in bits:
-            mask.set(b, 1)
+            mask.set(b)
 
         bf.or_at(mask, 0)
 
-- 
cgit v0.11.2-87-g4458