From 4f2d71ce4996943affb272b3f559a47cd0ff2aee Mon Sep 17 00:00:00 2001 From: Jef Driesen Date: Tue, 12 Aug 2014 22:00:43 +0200 Subject: [PATCH 1/3] Cache the parser data internally. The code to find the offset to the footer and parse the gas mix data is duplicated in multiple places. Move this code to a single place, and cache the data in the parser instead. --- src/mares_iconhd_parser.c | 168 +++++++++++++++++++++----------------- 1 file changed, 95 insertions(+), 73 deletions(-) diff --git a/src/mares_iconhd_parser.c b/src/mares_iconhd_parser.c index 078d14f..eae33a9 100644 --- a/src/mares_iconhd_parser.c +++ b/src/mares_iconhd_parser.c @@ -32,11 +32,19 @@ #define ICONHD 0x14 #define ICONHDNET 0x15 +#define NGASMIXES 3 + typedef struct mares_iconhd_parser_t mares_iconhd_parser_t; struct mares_iconhd_parser_t { dc_parser_t base; unsigned int model; + // Cached fields. + unsigned int cached; + unsigned int footer; + unsigned int samplesize; + unsigned int ngasmixes; + unsigned int oxygen[NGASMIXES]; }; static dc_status_t mares_iconhd_parser_set_data (dc_parser_t *abstract, const unsigned char *data, unsigned int size); @@ -54,25 +62,63 @@ static const dc_parser_vtable_t mares_iconhd_parser_vtable = { mares_iconhd_parser_destroy /* destroy */ }; - -/* Find how many gas mixes are in use */ -static unsigned int -mares_iconhd_parser_count_active_gas_mixes (const unsigned char *p, unsigned int air) +static dc_status_t +mares_iconhd_parser_cache (mares_iconhd_parser_t *parser) { + const unsigned char *data = parser->base.data; + unsigned int size = parser->base.size; + + if (parser->cached) { + return DC_STATUS_SUCCESS; + } + + unsigned int footersize = 0x5C; + unsigned int samplesize = 8; + if (parser->model == ICONHDNET) { + footersize = 0x80; + samplesize = 12; + } + + if (size < 4) + return DC_STATUS_DATAFORMAT; + + unsigned int length = array_uint32_le (data); + + if (size < length || length < footersize + 4) + return DC_STATUS_DATAFORMAT; + + const unsigned char *p = data + length - footersize; + + // Gas mixes + unsigned int ngasmixes = 0; + unsigned int oxygen[NGASMIXES] = {0}; + unsigned int air = (p[0] & 0x02) == 0; if (air) { - return 1; + oxygen[0] = 21; + ngasmixes = 1; } else { // Count the number of active gas mixes. The active gas // mixes are always first, so we stop counting as soon // as the first gas marked as disabled is found. - unsigned int i = 0; - while (i < 3) { - if (p[0x14 + i * 4 + 1] & 0x80) + ngasmixes = 0; + while (ngasmixes < NGASMIXES) { + if (p[0x14 + ngasmixes * 4 + 1] & 0x80) break; - i++; + oxygen[ngasmixes] = p[0x14 + ngasmixes * 4]; + ngasmixes++; } - return i; } + + // Cache the data for later use. + parser->footer = length - footersize; + parser->samplesize = samplesize; + parser->ngasmixes = ngasmixes; + for (unsigned int i = 0; i < ngasmixes; ++i) { + parser->oxygen[i] = oxygen[i]; + } + parser->cached = 1; + + return DC_STATUS_SUCCESS; } @@ -94,6 +140,13 @@ mares_iconhd_parser_create (dc_parser_t **out, dc_context_t *context, unsigned i // Set the default values. parser->model = model; + parser->cached = 0; + parser->footer = 0; + parser->samplesize = 0; + parser->ngasmixes = 0; + for (unsigned int i = 0; i < NGASMIXES; ++i) { + parser->oxygen[i] = 0; + } *out = (dc_parser_t*) parser; @@ -114,6 +167,17 @@ mares_iconhd_parser_destroy (dc_parser_t *abstract) static dc_status_t mares_iconhd_parser_set_data (dc_parser_t *abstract, const unsigned char *data, unsigned int size) { + mares_iconhd_parser_t *parser = (mares_iconhd_parser_t *) abstract; + + // Reset the cache. + parser->cached = 0; + parser->footer = 0; + parser->samplesize = 0; + parser->ngasmixes = 0; + for (unsigned int i = 0; i < NGASMIXES; ++i) { + parser->oxygen[i] = 0; + } + return DC_STATUS_SUCCESS; } @@ -123,20 +187,12 @@ mares_iconhd_parser_get_datetime (dc_parser_t *abstract, dc_datetime_t *datetime { mares_iconhd_parser_t *parser = (mares_iconhd_parser_t *) abstract; - unsigned int header = 0x5C; - if (parser->model == ICONHDNET) { - header = 0x80; - } + // Cache the parser data. + dc_status_t rc = mares_iconhd_parser_cache (parser); + if (rc != DC_STATUS_SUCCESS) + return rc; - if (abstract->size < 4) - return DC_STATUS_DATAFORMAT; - - unsigned int length = array_uint32_le (abstract->data); - - if (abstract->size < length || length < header + 4) - return DC_STATUS_DATAFORMAT; - - const unsigned char *p = abstract->data + length - header + 6; + const unsigned char *p = abstract->data + parser->footer + 6; if (datetime) { datetime->hour = array_uint16_le (p + 0); @@ -156,25 +212,15 @@ mares_iconhd_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, unsi { mares_iconhd_parser_t *parser = (mares_iconhd_parser_t *) abstract; - unsigned int header = 0x5C; - if (parser->model == ICONHDNET) { - header = 0x80; - } + // Cache the parser data. + dc_status_t rc = mares_iconhd_parser_cache (parser); + if (rc != DC_STATUS_SUCCESS) + return rc; - if (abstract->size < 4) - return DC_STATUS_DATAFORMAT; - - unsigned int length = array_uint32_le (abstract->data); - - if (abstract->size < length || length < header + 4) - return DC_STATUS_DATAFORMAT; - - const unsigned char *p = abstract->data + length - header; + const unsigned char *p = abstract->data + parser->footer; dc_gasmix_t *gasmix = (dc_gasmix_t *) value; - unsigned int air = (p[0] & 0x02) == 0; - if (value) { switch (type) { case DC_FIELD_DIVETIME: @@ -184,13 +230,10 @@ mares_iconhd_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, unsi *((double *) value) = array_uint16_le (p + 0x04) / 10.0; break; case DC_FIELD_GASMIX_COUNT: - *((unsigned int *) value) = mares_iconhd_parser_count_active_gas_mixes (p, air); + *((unsigned int *) value) = parser->ngasmixes; break; case DC_FIELD_GASMIX: - if (air) - gasmix->oxygen = 0.21; - else - gasmix->oxygen = p[0x14 + flags * 4] / 100.0; + gasmix->oxygen = parser->oxygen[flags] / 100.0; gasmix->helium = 0.0; gasmix->nitrogen = 1.0 - gasmix->oxygen - gasmix->helium; break; @@ -212,27 +255,12 @@ mares_iconhd_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t { mares_iconhd_parser_t *parser = (mares_iconhd_parser_t *) abstract; - unsigned int header = 0x5C; - unsigned int samplesize = 8; - if (parser->model == ICONHDNET) { - header = 0x80; - samplesize = 12; - } - - if (abstract->size < 4) - return DC_STATUS_DATAFORMAT; - - unsigned int length = array_uint32_le (abstract->data); - - if (abstract->size < length || length < header + 4) - return DC_STATUS_DATAFORMAT; - - const unsigned char *p = abstract->data + length - header; - - unsigned int air = (p[0] & 0x02) == 0; + // Cache the parser data. + dc_status_t rc = mares_iconhd_parser_cache (parser); + if (rc != DC_STATUS_SUCCESS) + return rc; const unsigned char *data = abstract->data; - unsigned int size = length - header; unsigned int time = 0; unsigned int interval = 5; @@ -242,9 +270,8 @@ mares_iconhd_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t // Previous gas mix - initialize with impossible value unsigned int gasmix_previous = 0xFFFFFFFF; - unsigned int ngasmixes = mares_iconhd_parser_count_active_gas_mixes (p, air); - while (offset + samplesize <= size) { + while (offset + parser->samplesize <= parser->footer) { dc_sample_value_t sample = {0}; // Time (seconds). @@ -264,28 +291,23 @@ mares_iconhd_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t // Current gas mix unsigned int gasmix = (data[offset + 3] & 0xF0) >> 4; - if (gasmix >= ngasmixes) { + if (gasmix >= parser->ngasmixes) { return DC_STATUS_DATAFORMAT; } if (gasmix != gasmix_previous) { - unsigned int o2 = 0; - if (air) - o2 = 21; - else - o2 = p[0x14 + gasmix * 4]; sample.event.type = SAMPLE_EVENT_GASCHANGE; sample.event.time = 0; - sample.event.value = o2; + sample.event.value = parser->oxygen[gasmix]; if (callback) callback (DC_SAMPLE_EVENT, sample, userdata); gasmix_previous = gasmix; } - offset += samplesize; + offset += parser->samplesize; nsamples++; // Some extra data. if (parser->model == ICONHDNET && (nsamples % 4) == 0) { - if (offset + 8 > size) + if (offset + 8 > parser->footer) return DC_STATUS_DATAFORMAT; // Pressure (1/100 bar). From b0874ea4d9045142c8e8db4bcfc6556caf2c07a1 Mon Sep 17 00:00:00 2001 From: Jef Driesen Date: Tue, 12 Aug 2014 22:15:58 +0200 Subject: [PATCH 2/3] Disable gas mixes and events in gauge mode. For a dive in gauge mode, the gas mixes defined in the header should be ignored, and no gas change event should be emitted. This is done by hardcoding the number of gas mixes to zero. --- src/mares_iconhd_parser.c | 32 ++++++++++++++++++++------------ 1 file changed, 20 insertions(+), 12 deletions(-) diff --git a/src/mares_iconhd_parser.c b/src/mares_iconhd_parser.c index eae33a9..fc1530c 100644 --- a/src/mares_iconhd_parser.c +++ b/src/mares_iconhd_parser.c @@ -34,6 +34,10 @@ #define NGASMIXES 3 +#define AIR 0 +#define GAUGE 1 +#define NITROX 2 + typedef struct mares_iconhd_parser_t mares_iconhd_parser_t; struct mares_iconhd_parser_t { @@ -92,8 +96,10 @@ mares_iconhd_parser_cache (mares_iconhd_parser_t *parser) // Gas mixes unsigned int ngasmixes = 0; unsigned int oxygen[NGASMIXES] = {0}; - unsigned int air = (p[0] & 0x02) == 0; - if (air) { + unsigned int mode = p[0] & 0x03; + if (mode == GAUGE) { + ngasmixes = 0; + } else if (mode == AIR) { oxygen[0] = 21; ngasmixes = 1; } else { @@ -290,16 +296,18 @@ mares_iconhd_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t if (callback) callback (DC_SAMPLE_TEMPERATURE, sample, userdata); // Current gas mix - unsigned int gasmix = (data[offset + 3] & 0xF0) >> 4; - if (gasmix >= parser->ngasmixes) { - return DC_STATUS_DATAFORMAT; - } - if (gasmix != gasmix_previous) { - sample.event.type = SAMPLE_EVENT_GASCHANGE; - sample.event.time = 0; - sample.event.value = parser->oxygen[gasmix]; - if (callback) callback (DC_SAMPLE_EVENT, sample, userdata); - gasmix_previous = gasmix; + if (parser->ngasmixes > 0) { + unsigned int gasmix = (data[offset + 3] & 0xF0) >> 4; + if (gasmix >= parser->ngasmixes) { + return DC_STATUS_DATAFORMAT; + } + if (gasmix != gasmix_previous) { + sample.event.type = SAMPLE_EVENT_GASCHANGE; + sample.event.time = 0; + sample.event.value = parser->oxygen[gasmix]; + if (callback) callback (DC_SAMPLE_EVENT, sample, userdata); + gasmix_previous = gasmix; + } } offset += parser->samplesize; From 7a851ccb1b9ed9b8906721cb1872b96b35185883 Mon Sep 17 00:00:00 2001 From: Jef Driesen Date: Thu, 14 Aug 2014 10:20:23 +0200 Subject: [PATCH 3/3] Add some extra error messages. --- src/mares_iconhd_parser.c | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/src/mares_iconhd_parser.c b/src/mares_iconhd_parser.c index fc1530c..6546453 100644 --- a/src/mares_iconhd_parser.c +++ b/src/mares_iconhd_parser.c @@ -83,13 +83,17 @@ mares_iconhd_parser_cache (mares_iconhd_parser_t *parser) samplesize = 12; } - if (size < 4) + if (size < 4) { + ERROR (abstract->context, "Buffer overflow detected!"); return DC_STATUS_DATAFORMAT; + } unsigned int length = array_uint32_le (data); - if (size < length || length < footersize + 4) + if (size < length || length < footersize + 4) { + ERROR (abstract->context, "Buffer overflow detected!"); return DC_STATUS_DATAFORMAT; + } const unsigned char *p = data + length - footersize; @@ -299,6 +303,7 @@ mares_iconhd_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t if (parser->ngasmixes > 0) { unsigned int gasmix = (data[offset + 3] & 0xF0) >> 4; if (gasmix >= parser->ngasmixes) { + ERROR (abstract->context, "Invalid gas mix index."); return DC_STATUS_DATAFORMAT; } if (gasmix != gasmix_previous) { @@ -315,8 +320,10 @@ mares_iconhd_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t // Some extra data. if (parser->model == ICONHDNET && (nsamples % 4) == 0) { - if (offset + 8 > parser->footer) + if (offset + 8 > parser->footer) { + ERROR (abstract->context, "Buffer overflow detected!"); return DC_STATUS_DATAFORMAT; + } // Pressure (1/100 bar). unsigned int pressure = array_uint16_le(data + offset);