From fa250906c9ce2b60a9678b2ddf4bedfd402f2da5 Mon Sep 17 00:00:00 2001 From: Dirk Hohndel Date: Sat, 30 Oct 2021 09:54:18 -0700 Subject: [PATCH] core: add structures for handling fingerprints This just adds the basic structures and the accessor functions needed to manage a table of fingerprint data. The table is indexed by the hash of the model name and binary serial number as created by libdivcecomputer. This way the data is accessible when libdivecomputer fist accesses a dive computer (which is the point in time when we need to use the fingerprint. The table also contains the corresponding device id and dive id so we can verify that the current dive table still contains that dive. Signed-off-by: Dirk Hohndel --- core/device.cpp | 55 +++++++++++++++++++++++++++++++++++++++++++++++++ core/device.h | 22 ++++++++++++++++++++ 2 files changed, 77 insertions(+) diff --git a/core/device.cpp b/core/device.cpp index a01893f60..4b7eb9213 100644 --- a/core/device.cpp +++ b/core/device.cpp @@ -1,6 +1,7 @@ // SPDX-License-Identifier: GPL-2.0 #include "ssrf.h" #include "dive.h" +#include "divelist.h" #include "subsurface-string.h" #include "device.h" #include "errorhelper.h" // for verbose flag @@ -9,6 +10,7 @@ #include // for QString::number struct device_table device_table; +struct fingerprint_table fingerprint_table; bool device::operator==(const device &a) const { @@ -197,3 +199,56 @@ extern "C" void free_device_table(struct device_table *devices) { delete devices; } + +// managing fingerprint data +bool fingerprint_record::operator<(const fingerprint_record &a) const +{ + if (model == a.model) + return serial < a.serial; + return model < a.model; +} + +// annoyingly, the Cressi Edy doesn't support a serial number (it's always 0), but still uses fingerprints +// so we can't bail on the serial number being 0 +extern "C" unsigned int get_fingerprint_data(const struct fingerprint_table *table, uint32_t model, uint32_t serial, const unsigned char **fp_out) +{ + if (model == 0 || fp_out == nullptr) + return 0; + struct fingerprint_record fpr = { model, serial }; + auto it = std::lower_bound(table->fingerprints.begin(), table->fingerprints.end(), fpr); + if (it != table->fingerprints.end() && it->model == model && it->serial == serial) { + // std::lower_bound gets us the first element that isn't smaller than what we are looking + // for - so if one is found, we still need to check for equality + if (has_dive(it->fdeviceid, it->fdiveid)) { + *fp_out = it->raw_data; + return it->fsize; + } + } + return 0; +} + +extern "C" void create_fingerprint_node(struct fingerprint_table *table, uint32_t model, uint32_t serial, + const unsigned char *raw_data_in, unsigned int fsize, uint32_t fdeviceid, uint32_t fdiveid) +{ + // since raw data can contain \0 we copy this manually, not as string + unsigned char *raw_data = (unsigned char *)malloc(fsize); + if (!raw_data) + return; + memcpy(raw_data, raw_data_in, fsize); + + struct fingerprint_record fpr = { model, serial, raw_data, fsize, fdeviceid, fdiveid }; + auto it = std::lower_bound(table->fingerprints.begin(), table->fingerprints.end(), fpr); + if (it != table->fingerprints.end() && it->model == model && it->serial == serial) { + // std::lower_bound gets us the first element that isn't smaller than what we are looking + // for - so if one is found, we still need to check for equality - and then we + // can update the existing entry; first we free the memory for the stored raw data + free(it->raw_data); + it->fdeviceid = fdeviceid; + it->fdiveid = fdiveid; + it->raw_data = raw_data; + it->fsize = fsize; + } else { + // insert a new one + table->fingerprints.insert(it, fpr); + } +} diff --git a/core/device.h b/core/device.h index 9e0a90ac9..95c1f7694 100644 --- a/core/device.h +++ b/core/device.h @@ -15,6 +15,7 @@ struct dive_table; // global device table extern struct device_table device_table; +extern struct fingerprint_table fingerprint_table; extern int create_device_node(struct device_table *table, const char *model, const char *serial, const char *nickname); extern int nr_devices(const struct device_table *table); @@ -40,6 +41,12 @@ const char *device_get_nickname(const struct device *dev); extern struct device_table *alloc_device_table(); extern void free_device_table(struct device_table *devices); +// create fingerprint entry - raw data remains owned by caller +extern void create_fingerprint_node(struct fingerprint_table *table, uint32_t model, uint32_t serial, + const unsigned char *raw_data, unsigned int fsize, uint32_t fdeviceid, uint32_t fdiveid); +// look up the fingerprint for model/serial - returns the number of bytes in the fingerprint; memory owned by the table +extern unsigned int get_fingerprint_data(const struct fingerprint_table *table, uint32_t model, uint32_t serial, const unsigned char **fp_out); + #ifdef __cplusplus } #endif @@ -59,11 +66,26 @@ struct device { uint32_t deviceId; // Always the string hash of the serialNumber }; +struct fingerprint_record { + bool operator<(const fingerprint_record &a) const; + uint32_t model; // model and libdivecomputer serial number to + uint32_t serial; // look up the fingerprint + unsigned char *raw_data; // fingerprint data as provided by libdivecomputer + unsigned int fsize; // size of raw fingerprint data + unsigned int fdeviceid; // corresponding deviceid + unsigned int fdiveid; // corresponding diveid +}; + struct device_table { // Keep the dive computers in a vector sorted by (model, serial) std::vector devices; }; +struct fingerprint_table { + // Keep the fingerprint records in a vector sorted by (model, serial) - these are uint32_t here + std::vector fingerprints; +}; + #endif #endif // DEVICE_H