garmin: ignore FIT files that aren't dives

Dives are identified by a sub_sport range of 53-57 in the SPORT message.

This means that we need to parse the files before we actually offer them to the
application, which means we parse them three times all together, but I don't
see a way around that. Thankfully parsing a memory buffer is reasonably fast.

Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
This commit is contained in:
Dirk Hohndel 2018-09-03 14:32:58 -07:00 committed by Linus Torvalds
parent 41303bbc70
commit ac25976258
3 changed files with 38 additions and 1 deletions

View File

@ -194,6 +194,7 @@ garmin_device_foreach (dc_device_t *abstract, dc_dive_callback_t callback, void
{
dc_status_t status = DC_STATUS_SUCCESS;
garmin_device_t *device = (garmin_device_t *) abstract;
dc_parser_t *parser;
char pathname[PATH_MAX];
size_t pathlen;
struct file_list files = { 0, 0, NULL };
@ -268,6 +269,11 @@ garmin_device_foreach (dc_device_t *abstract, dc_dive_callback_t callback, void
free(files.array);
return DC_STATUS_NOMEMORY;
}
if ((rc = garmin_parser_create(&parser, abstract->context) != DC_STATUS_SUCCESS)) {
ERROR (abstract->context, "Failed to create parser for dive verification.");
free(files.array);
return rc;
}
for (int i = 0; i < files.nr; i++) {
const char *name = files.array[i].name;
@ -290,6 +296,11 @@ garmin_device_foreach (dc_device_t *abstract, dc_dive_callback_t callback, void
data = dc_buffer_get_data(file);
size = dc_buffer_get_size(file);
if (!garmin_parser_is_dive(parser, data, size)) {
DEBUG (abstract->context, "decided %s isn't a dive.", name);
continue;
}
if (callback && !callback(data, size, name, FIT_NAME_SIZE, userdata))
break;
@ -298,5 +309,6 @@ garmin_device_foreach (dc_device_t *abstract, dc_dive_callback_t callback, void
}
free(files.array);
dc_parser_destroy(parser);
return status;
}

View File

@ -37,6 +37,11 @@ garmin_device_open (dc_device_t **device, dc_context_t *context, dc_iostream_t *
dc_status_t
garmin_parser_create (dc_parser_t **parser, dc_context_t *context);
// we need to be able to call into the parser to check if the
// files that we find are actual dives
int
garmin_parser_is_dive (dc_parser_t *abstract, const unsigned char *data, unsigned int size);
// The dive names are of the form "2018-08-20-10-23-30.fit"
// With the terminating zero, that's 24 bytes.
//

View File

@ -90,6 +90,7 @@ typedef struct garmin_parser_t {
// Field cache
struct {
unsigned int initialized;
unsigned int sub_sport;
unsigned int protocol;
unsigned int profile;
unsigned int time;
@ -488,6 +489,9 @@ DECLARE_FIELD(RECORD, n2_load, UINT16) { } // percent
DECLARE_FIELD(DEVICE_SETTINGS, utc_offset, UINT32) { garmin->cache.utc_offset = (SINT32) data; } // wrong type in FIT
DECLARE_FIELD(DEVICE_SETTINGS, time_offset, UINT32) { garmin->cache.time_offset = (SINT32) data; } // wrong type in FIT
// SPORT
DECLARE_FIELD(SPORT, sub_sport, ENUM) { garmin->cache.sub_sport = (ENUM) data; }
// DIVE_GAS - uses msg index
DECLARE_FIELD(DIVE_GAS, helium, UINT8)
{
@ -574,7 +578,13 @@ DECLARE_MESG(DEVICE_SETTINGS) = {
};
DECLARE_MESG(USER_PROFILE) = { };
DECLARE_MESG(ZONES_TARGET) = { };
DECLARE_MESG(SPORT) = { };
DECLARE_MESG(SPORT) = {
.maxfield = 2,
.field = {
SET_FIELD(SPORT, 1, sub_sport, ENUM), // 53 - 57 are dive activities
}
};
DECLARE_MESG(SESSION) = {
.maxfield = 40,
@ -1079,6 +1089,16 @@ static void add_gps_string(garmin_parser_t *garmin, const char *desc, struct pos
}
}
int
garmin_parser_is_dive (dc_parser_t *abstract, const unsigned char *data, unsigned int size)
{
// set up the parser and extract data
dc_parser_set_data(abstract, data, size);
garmin_parser_t *garmin = (garmin_parser_t *) abstract;
return garmin->cache.sub_sport >= 53 && garmin->cache.sub_sport <= 57;
}
static dc_status_t
garmin_parser_set_data (dc_parser_t *abstract, const unsigned char *data, unsigned int size)
{