From b4d78e7c0fcdb6c0ecea31e775d0f72a45f3b7cb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= Date: Thu, 9 Jul 2026 17:10:34 +0200 Subject: [PATCH] fpi-print: Add function to check if two prints match While for raw prints this is just an equality check, for NBIS prints they match if at least one of the minutiae match --- libfprint/fpi-print.c | 65 +++++++++++++++ libfprint/fpi-print.h | 4 + tests/test-fpi-device.c | 176 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 245 insertions(+) diff --git a/libfprint/fpi-print.c b/libfprint/fpi-print.c index b0f5eab4..7d1ead2a 100644 --- a/libfprint/fpi-print.c +++ b/libfprint/fpi-print.c @@ -363,3 +363,68 @@ fpi_print_fill_from_user_id (FpPrint *print, const char *user_id) return FALSE; } + +/** + * fpi_print_match: + * @self: First #FpPrint + * @other: Second #FpPrint + * + * Tests whether the prints are matching. + * This is like fp_print_equal() for %FPI_PRINT_RAW prints, + * while for %FPI_PRINT_NBIS prints ensures that at least one + * sub-print minutiae matches. + * + * Returns: %TRUE if the prints are matching + */ +gboolean +fpi_print_match (FpPrint *self, FpPrint *other) +{ + g_return_val_if_fail (FP_IS_PRINT (self), FALSE); + g_return_val_if_fail (FP_IS_PRINT (other), FALSE); + g_return_val_if_fail (self->type != FPI_PRINT_UNDEFINED, FALSE); + g_return_val_if_fail (other->type != FPI_PRINT_UNDEFINED, FALSE); + + if (self == other) + return TRUE; + + switch (self->type) + { + case FPI_PRINT_RAW: + return fp_print_equal (self, other); + + case FPI_PRINT_NBIS: + { + if (other->type != FPI_PRINT_NBIS) + return FALSE; + + if (g_strcmp0 (self->driver, other->driver) != 0) + return FALSE; + + if (g_strcmp0 (self->device_id, other->device_id) != 0) + return FALSE; + + if (self->prints->len == 0 || other->prints->len == 0) + return self->prints->len == other->prints->len; + + for (guint i = 0; i < self->prints->len; i++) + { + struct xyt_struct *a = g_ptr_array_index (self->prints, i); + + for (guint j = 0; j < other->prints->len; j++) + { + struct xyt_struct *b = g_ptr_array_index (other->prints, j); + + if (memcmp (a, b, sizeof (struct xyt_struct)) == 0) + return TRUE; + } + } + + return FALSE; + } + + case FPI_PRINT_UNDEFINED: + g_assert_not_reached (); + } + + g_return_val_if_reached (FALSE); +} diff --git a/libfprint/fpi-print.h b/libfprint/fpi-print.h index 2b4b6b39..192f0a91 100644 --- a/libfprint/fpi-print.h +++ b/libfprint/fpi-print.h @@ -35,6 +35,10 @@ void fpi_print_add_print (FpPrint *print, void fpi_print_set_type (FpPrint *print, FpiPrintType type); + +gboolean fpi_print_match (FpPrint *self, + FpPrint *other); + void fpi_print_set_device_stored (FpPrint *print, gboolean device_stored); diff --git a/tests/test-fpi-device.c b/tests/test-fpi-device.c index deee5c26..df258502 100644 --- a/tests/test-fpi-device.c +++ b/tests/test-fpi-device.c @@ -3907,6 +3907,170 @@ test_fp_print_equal_different_types (void) g_assert_false (fp_print_equal (print_b, print_a)); } +static void +test_fpi_print_match_same (void) +{ + g_autoptr(FpDevice) device = g_object_new (FPI_TYPE_DEVICE_FAKE, NULL); + g_autoptr(FpPrint) print_a = NULL; + g_autoptr(FpPrint) print_b = NULL; + + print_a = make_fake_print (device, g_variant_new_string ("test")); + print_b = make_fake_print (device, g_variant_new_string ("test")); + + g_assert_true (fpi_print_match (print_a, print_b)); + g_assert_true (fpi_print_match (print_a, print_a)); + g_assert_true (fpi_print_match (print_b, print_b)); +} + +static void +test_fpi_print_match_different (void) +{ + g_autoptr(FpDevice) device = g_object_new (FPI_TYPE_DEVICE_FAKE, NULL); + g_autoptr(FpPrint) print_a = NULL; + g_autoptr(FpPrint) print_b = NULL; + + print_a = make_fake_print (device, g_variant_new_string ("test")); + print_b = make_fake_print (device, g_variant_new_string ("other")); + + g_assert_false (fpi_print_match (print_a, print_b)); +} + +static void +test_fpi_print_match_nbis_empty (void) +{ + g_autoptr(FpDevice) device = g_object_new (FPI_TYPE_DEVICE_FAKE, NULL); + g_autoptr(FpPrint) print_a = NULL; + g_autoptr(FpPrint) print_b = NULL; + + print_a = make_fake_nbis_print (device); + print_b = make_fake_nbis_print (device); + + g_assert_true (fpi_print_match (print_a, print_b)); + g_assert_true (fpi_print_match (print_a, print_a)); + g_assert_true (fpi_print_match (print_b, print_b)); +} + +static void +test_fpi_print_match_nbis_one_empty (void) +{ + g_autoptr(FpDevice) device = g_object_new (FPI_TYPE_DEVICE_FAKE, NULL); + g_autoptr(FpPrint) print_a = NULL; + g_autoptr(FpPrint) print_b = NULL; + gint xvals[] = { 10, 20 }; + gint yvals[] = { 30, 40 }; + gint tvals[] = { 50, 60 }; + + print_a = make_fake_nbis_print_filled (device, xvals, yvals, tvals, 2, 1); + print_b = make_fake_nbis_print (device); + + g_assert_false (fpi_print_match (print_a, print_b)); + g_assert_false (fpi_print_match (print_b, print_a)); +} + +static void +test_fpi_print_match_nbis_equal (void) +{ + g_autoptr(FpDevice) device = g_object_new (FPI_TYPE_DEVICE_FAKE, NULL); + g_autoptr(FpPrint) print_a = NULL; + g_autoptr(FpPrint) print_b = NULL; + gint xvals[] = { 10, 20 }; + gint yvals[] = { 30, 40 }; + gint tvals[] = { 50, 60 }; + + print_a = make_fake_nbis_print_filled (device, xvals, yvals, tvals, 2, 1); + print_b = make_fake_nbis_print_filled (device, xvals, yvals, tvals, 2, 1); + + g_assert_true (fpi_print_match (print_a, print_b)); +} + +static void +test_fpi_print_match_nbis_different (void) +{ + g_autoptr(FpDevice) device = g_object_new (FPI_TYPE_DEVICE_FAKE, NULL); + g_autoptr(FpPrint) print_a = NULL; + g_autoptr(FpPrint) print_b = NULL; + gint xvals_a[] = { 10, 20 }; + gint yvals_a[] = { 30, 40 }; + gint tvals_a[] = { 50, 60 }; + gint xvals_b[] = { 99, 88 }; + gint yvals_b[] = { 77, 66 }; + gint tvals_b[] = { 55, 44 }; + + print_a = make_fake_nbis_print_filled (device, xvals_a, yvals_a, tvals_a, 2, 1); + print_b = make_fake_nbis_print_filled (device, xvals_b, yvals_b, tvals_b, 2, 1); + + g_assert_false (fpi_print_match (print_a, print_b)); +} + +static void +test_fpi_print_match_nbis_template_scanned (void) +{ + g_autoptr(FpDevice) device = g_object_new (FPI_TYPE_DEVICE_FAKE, NULL); + gint xvals[] = { 10, 20 }; + gint yvals[] = { 30, 40 }; + gint tvals[] = { 50, 60 }; + g_autoptr(FpPrint) template = NULL; + g_autoptr(FpPrint) scanned = NULL; + + template = make_fake_nbis_print_filled (device, xvals, yvals, tvals, 2, 5); + scanned = make_fake_nbis_print_filled (device, xvals, yvals, tvals, 2, 1); + + g_assert_true (fpi_print_match (template, scanned)); + g_assert_true (fpi_print_match (scanned, template)); +} + +static void +test_fpi_print_match_nbis_template_scanned_no_match (void) +{ + g_autoptr(FpDevice) device = g_object_new (FPI_TYPE_DEVICE_FAKE, NULL); + gint xvals_t[] = { 10, 20 }; + gint yvals_t[] = { 30, 40 }; + gint tvals_t[] = { 50, 60 }; + gint xvals_s[] = { 99, 88 }; + gint yvals_s[] = { 77, 66 }; + gint tvals_s[] = { 55, 44 }; + g_autoptr(FpPrint) template = NULL; + g_autoptr(FpPrint) scanned = NULL; + + template = make_fake_nbis_print_filled (device, xvals_t, yvals_t, tvals_t, 2, 5); + scanned = make_fake_nbis_print_filled (device, xvals_s, yvals_s, tvals_s, 2, 1); + + g_assert_false (fpi_print_match (template, scanned)); + g_assert_false (fpi_print_match (scanned, template)); +} + +static void +test_fpi_print_match_nbis_match_any_position (void) +{ + g_autoptr(FpDevice) device = g_object_new (FPI_TYPE_DEVICE_FAKE, NULL); + g_autoptr(FpPrint) print_a = NULL; + g_autoptr(FpPrint) print_b = NULL; + gint xvals_a[] = { 10, 20 }; + gint yvals_a[] = { 30, 40 }; + gint tvals_a[] = { 50, 60 }; + gint xvals_b[] = { 99, 88 }; + gint yvals_b[] = { 77, 66 }; + gint tvals_b[] = { 55, 44 }; + gint xvals_match[] = { 10, 20 }; + gint yvals_match[] = { 30, 40 }; + gint tvals_match[] = { 50, 60 }; + struct xyt_struct *xyt_match = g_new0 (struct xyt_struct, 1); + + print_a = make_fake_nbis_print_filled (device, xvals_a, yvals_a, tvals_a, 2, 1); + print_b = make_fake_nbis_print_filled (device, xvals_b, yvals_b, tvals_b, 2, 1); + + xyt_match->nrows = 2; + xyt_match->xcol[0] = xvals_match[0]; + xyt_match->ycol[0] = yvals_match[0]; + xyt_match->thetacol[0] = tvals_match[0]; + xyt_match->xcol[1] = xvals_match[1]; + xyt_match->ycol[1] = yvals_match[1]; + xyt_match->thetacol[1] = tvals_match[1]; + g_ptr_array_add (print_b->prints, xyt_match); + + g_assert_true (fpi_print_match (print_a, print_b)); +} + int main (int argc, char *argv[]) { @@ -4041,5 +4205,17 @@ main (int argc, char *argv[]) g_test_add_func ("/print/equal/different_types", test_fp_print_equal_different_types); + g_test_add_func ("/print/match/same", test_fpi_print_match_same); + g_test_add_func ("/print/match/different", test_fpi_print_match_different); + g_test_add_func ("/print/match/nbis_empty", test_fpi_print_match_nbis_empty); + g_test_add_func ("/print/match/nbis_one_empty", test_fpi_print_match_nbis_one_empty); + g_test_add_func ("/print/match/nbis_equal", test_fpi_print_match_nbis_equal); + g_test_add_func ("/print/match/nbis_different", test_fpi_print_match_nbis_different); + g_test_add_func ("/print/match/nbis_template_scanned", test_fpi_print_match_nbis_template_scanned); + g_test_add_func ("/print/match/nbis_template_scanned_no_match", + test_fpi_print_match_nbis_template_scanned_no_match); + g_test_add_func ("/print/match/nbis_match_any_position", + test_fpi_print_match_nbis_match_any_position); + return g_test_run (); }