From cf11fcf862b98ef57935bcfccd6f2f6ae3f925f6 Mon Sep 17 00:00:00 2001
From: Cyrille Bagard <nocbos@gmail.com>
Date: Fri, 8 Dec 2017 21:47:09 +0100
Subject: Improved the way vmpa_t types are compared.

---
 ChangeLog                    | 14 ++++++++++++
 plugins/pychrysa/arch/vmpa.c | 31 ++++++++++++++++++++++++--
 src/arch/vmpa.c              | 52 +++++++++++++++++++++++++++++++++-----------
 src/arch/vmpa.h              |  3 ---
 tests/arch/vmpa.py           | 26 ++++++++++++++++++++++
 5 files changed, 108 insertions(+), 18 deletions(-)

diff --git a/ChangeLog b/ChangeLog
index 47c0570..7cc6a93 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,17 @@
+17-12-08  Cyrille Bagard <nocbos@gmail.com>
+
+	* plugins/pychrysa/arch/vmpa.c:
+	Update the comparison features for the Python bindings.
+
+	* src/arch/vmpa.c:
+	Improve the way vmpa_t types are compared.
+
+	* src/arch/vmpa.h:
+	Remove an useless macro.
+
+	* tests/arch/vmpa.py:
+	Populate the test suite.
+
 17-12-07  Cyrille Bagard <nocbos@gmail.com>
 
 	* plugins/pychrysa/analysis/routine.c:
diff --git a/plugins/pychrysa/arch/vmpa.c b/plugins/pychrysa/arch/vmpa.c
index af1557d..aaaede8 100644
--- a/plugins/pychrysa/arch/vmpa.c
+++ b/plugins/pychrysa/arch/vmpa.c
@@ -25,9 +25,13 @@
 #include "vmpa.h"
 
 
+#include <assert.h>
 #include <string.h>
 
 
+#include <i18n.h>
+
+
 #include "../helpers.h"
 
 
@@ -208,23 +212,43 @@ static PyObject *py_vmpa_richcompare(PyObject *a, PyObject *b, int op)
     PyObject *result;                       /* Bilan à retourner           */
     vmpa2t *addr_a;                         /* Première adresse à traiter  */
     vmpa2t addr_b;                          /* Seconde adresse à traiter   */
+    int comp;                               /* Résultat d'une comparaison  */
 
     addr_a = &((py_vmpa_t *)a)->addr;
 
     if (!convert_pyobj_to_vmpa(b, &addr_b))
         return NULL;
 
+    comp = cmp_vmpa(addr_a, &addr_b);
+
     switch (op)
     {
+        case Py_LT:
+            result = comp < 0 ? Py_True : Py_False;
+            break;
+
+        case Py_LE:
+            result = comp <= 0 ? Py_True : Py_False;
+            break;
+
         case Py_EQ:
-            result = are_equal(addr_a, &addr_b) ? Py_True : Py_False;
+            result = comp == 0 ? Py_True : Py_False;
             break;
 
         case Py_NE:
-            result = are_equal(addr_a, &addr_b) ? Py_False : Py_True;
+            result = comp != 0 ? Py_True : Py_False;
+            break;
+
+        case Py_GT:
+            result = comp > 0 ? Py_True : Py_False;
+            break;
+
+        case Py_GE:
+            result = comp >= 0 ? Py_True : Py_False;
             break;
 
         default:
+            assert(false);
             result = Py_NotImplemented;
             break;
 
@@ -436,7 +460,10 @@ static bool convert_pyobj_to_vmpa(PyObject *obj, vmpa2t *addr)
         value = PyLong_AsLongLongAndOverflow(obj, &overflow);
 
         if (value == -1 && (overflow == 1 || PyErr_Occurred()))
+        {
             PyErr_Clear();
+            PyErr_SetString(PyExc_TypeError, _("Unable to cast object as VMPA."));
+        }
 
         else
         {
diff --git a/src/arch/vmpa.c b/src/arch/vmpa.c
index 6db62cc..f90ab22 100644
--- a/src/arch/vmpa.c
+++ b/src/arch/vmpa.c
@@ -193,8 +193,8 @@ int cmp_vmpa_by_phy(const vmpa2t *a, const vmpa2t *b)
     else
     {
         if (a->physical == VMPA_NO_PHYSICAL && b->physical == VMPA_NO_PHYSICAL) result = 0;
-        else if (a->physical == VMPA_NO_PHYSICAL) result = -1;
-        else result = 1;
+        else if (a->physical == VMPA_NO_PHYSICAL) result = 1;
+        else result = -1;
     }
 
     return result;
@@ -228,8 +228,8 @@ int cmp_vmpa_by_virt(const vmpa2t *a, const vmpa2t *b)
     else
     {
         if (a->virtual == VMPA_NO_VIRTUAL && b->virtual == VMPA_NO_VIRTUAL) result = 0;
-        else if (a->virtual == VMPA_NO_VIRTUAL) result = -1;
-        else result = 1;
+        else if (a->virtual == VMPA_NO_VIRTUAL) result = 1;
+        else result = -1;
     }
 
     return result;
@@ -253,22 +253,48 @@ int cmp_vmpa_by_virt(const vmpa2t *a, const vmpa2t *b)
 int cmp_vmpa(const vmpa2t *a, const vmpa2t *b)
 {
     int result;                             /* Bilan à retourner           */
-    bool half;                              /* Comparaison débutée         */
+    bool compared;                          /* Comparaison effectuée       */
 
-    result = -1;
+    if (a->physical == VMPA_NO_PHYSICAL && a->virtual == VMPA_NO_VIRTUAL
+        && b->physical == VMPA_NO_PHYSICAL && b->virtual == VMPA_NO_VIRTUAL)
+    {
+        result = 0;
 
-    half = false;
+    }
 
-    if (a->physical != VMPA_NO_PHYSICAL && b->physical != VMPA_NO_PHYSICAL)
+    else if (a->physical == VMPA_NO_PHYSICAL && a->virtual == VMPA_NO_VIRTUAL)
     {
-        result = cmp_vmpa_by_phy(a, b);
-        half = true;
+        result = 1;
+
     }
 
-    if (a->virtual != VMPA_NO_VIRTUAL && b->virtual != VMPA_NO_VIRTUAL
-        && (!half || (half && result == 0)))
+    else if (b->physical == VMPA_NO_PHYSICAL && b->virtual == VMPA_NO_VIRTUAL)
+    {
+        result = -1;
+
+    }
+
+    else
     {
-        result = cmp_vmpa_by_virt(a, b);
+        compared = false;
+
+        if (a->physical != VMPA_NO_PHYSICAL && b->physical != VMPA_NO_PHYSICAL)
+        {
+            result = cmp_vmpa_by_phy(a, b);
+            compared = true;
+        }
+
+        if (a->virtual != VMPA_NO_VIRTUAL && b->virtual != VMPA_NO_VIRTUAL
+            && (!compared || (compared && result == 0)))
+        {
+            result = cmp_vmpa_by_virt(a, b);
+            compared = true;
+        }
+
+        /* Cas particulier : les deux éléments n'ont aucun champ défini en commun ! */
+        if (!compared)
+            result = cmp_vmpa_by_phy(a, b);
+
     }
 
     return result;
diff --git a/src/arch/vmpa.h b/src/arch/vmpa.h
index 871e282..6ed7605 100644
--- a/src/arch/vmpa.h
+++ b/src/arch/vmpa.h
@@ -99,9 +99,6 @@ int cmp_vmpa_by_virt(const vmpa2t *, const vmpa2t *);
 /* Compare deux localisations selon leurs parties définies. */
 int cmp_vmpa(const vmpa2t *, const vmpa2t *);
 
-#define are_equal(a, b) \
-    (cmp_vmpa_by_phy(a, b) == 0 && cmp_vmpa_by_virt(a, b) == 0)
-
 #define get_phy_addr(a) (a)->physical
 #define get_virt_addr(a) (a)->virtual
 
diff --git a/tests/arch/vmpa.py b/tests/arch/vmpa.py
index def61ea..09c3d9d 100755
--- a/tests/arch/vmpa.py
+++ b/tests/arch/vmpa.py
@@ -33,3 +33,29 @@ class TestVmpa(ChrysalideTestCase):
 
         self.assertEqual(a, b)
         self.assertEqual(a, c)
+
+
+    def testCompareWrong(self):
+        """Verify unhandled comparisons with VMPA."""
+
+        a = vmpa()
+
+        with self.assertRaisesRegex(Exception, 'Unable to cast object as VMPA.'):
+
+            self.assertLess(a, 'b')
+
+
+    def testCompareFair(self):
+        """Verify right VMPA comparisons."""
+
+        a = vmpa(0)
+        b = vmpa()
+
+        self.assertLess(a, b)
+
+        self.assertGreater(b, a)
+
+        a = vmpa()
+        b = vmpa()
+
+        self.assertEqual(a, b)
-- 
cgit v0.11.2-87-g4458