[PATCH] Clean up Divesoft Freedome time parsing

Linus Torvalds torvalds at linux-foundation.org
Sat Oct 3 07:36:11 PDT 2015


From: Linus Torvalds <torvalds at linux-foundation.org>
Date: Sat, 3 Oct 2015 10:29:40 -0400
Subject: [PATCH] Clean up Divesoft Freedome time parsing

So Anton Lundin says that the 32-bit timestamp for the Divesoft Freedom
is indeed a signed offset from Jan 1, 2000.

This does that, but also extracts the whole thing into a helper function
and makes sure that there are no overflows at any point by using
"timestamp_t" in the whole series, and all the operations are "obviously
safe" in their types (ie no "unsigned char gets widened to 'int' and
then we shift it left by 24 bits").

Signed-off-by: Linus Torvalds <torvalds at linux-fundation.org>
---

This is a bigger patch than required (it could have just changed the 
"uint32_t" into "int32_t"), but I think the code ends up being easier to 
read, and it should be as efficient (although because we compile with 
debugging and no optimizations, splitting things up like this ends up 
making the compiler split things up too - but that's our debug thing, 
not anything fundamental).

Also note that I didn't actually *test* this. Obviously. I don't  have a 
Divesoft divecomputer, much less anything that hass odd date offsets.

 parse-xml.c | 25 +++++++++++++++++++------
 1 file changed, 19 insertions(+), 6 deletions(-)

diff --git a/parse-xml.c b/parse-xml.c
index 1aaeb42fe33e..b2bc76f0c159 100644
--- a/parse-xml.c
+++ b/parse-xml.c
@@ -3246,6 +3246,24 @@ int parse_divinglog_buffer(sqlite3 *handle, const char *url, const char *buffer,
 	return 0;
 }
 
+/*
+ * Parse a signed 32-bit integer in little-endian mode,
+ * that is seconds since Jan 1, 2000.
+ */
+static timestamp_t parse_dlf_timestamp(unsigned char *buffer)
+{
+	timestamp_t offset;
+
+	offset = (signed char) buffer[3];
+	offset = (offset << 8) + buffer[2];
+	offset = (offset << 8) + buffer[1];
+	offset = (offset << 8) + buffer[0];
+
+	// Jan 1, 2000 is 946684800 seconds after Jan 1, 1970, which is
+	// the Unix epoch date that "timestamp_t" uses.
+	return offset + 946684800;
+}
+
 int parse_dlf_buffer(unsigned char *buffer, size_t size)
 {
 	unsigned char *ptr = buffer;
@@ -3268,12 +3286,7 @@ int parse_dlf_buffer(unsigned char *buffer, size_t size)
 	// (ptr[7] << 8) + ptr[6] Is "Serial"
 	snprintf(serial, sizeof(serial), "%d", (ptr[7] << 8) + ptr[6]);
 	cur_dc->serial = strdup(serial);
-	// Dive start time in seconds since 2000-01-01 00:00
-	// let's avoid implicit sign extensions
-	// ("unsigned char" is expanded to "int" in C arithmetic, so
-	// (ptr[11] << 24) can be a signed integer)
-	uint32_t offset = (ptr[11] << 24) + (ptr[10] << 16) + (ptr[9] << 8) + ptr[8];
-	cur_dc->when = (timestamp_t) offset + 946684800;
+	cur_dc->when = parse_dlf_timestamp(ptr + 8);
 	cur_dive->when = cur_dc->when;
 
 	cur_dc->duration.seconds = ((ptr[14] & 0xFE) << 16) + (ptr[13] << 8) + ptr[12];
-- 
2.6.0



More information about the subsurface mailing list