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