[PATCH 2/3] Import Shearwater Desktop divelog database

Miika Turkia miika.turkia at gmail.com
Fri Feb 14 22:36:50 UTC 2014


Sqlite database from Shearwater Desktop log software is imported. Just
the basic information like location, buddy, notes and dive profile
(depth and temperature).

This is tested with a DB in Imperial units, thus metric input might
contain errors.

Signed-off-by: Miika Turkia <miika.turkia at gmail.com>
---
 dive.h      |   3 +-
 file.c      |  25 ++++++++++++++-
 parse-xml.c | 104 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
 3 files changed, 129 insertions(+), 3 deletions(-)

diff --git a/dive.h b/dive.h
index 953c08e..fcb0727 100644
--- a/dive.h
+++ b/dive.h
@@ -644,7 +644,8 @@ extern void parse_xml_buffer(const char *url, const char *buf, int size, struct
 extern void parse_xml_exit(void);
 extern void set_filename(const char *filename, bool force);
 
-extern int parse_dm4_buffer(const sqlite3 *handle, const char *url, const char *buf, int size, struct dive_table *table, char **error);
+extern int parse_dm4_buffer(sqlite3 *handle, const char *url, const char *buf, int size, struct dive_table *table, char **error);
+extern int parse_shearwater_buffer(sqlite3 *handle, const char *url, const char *buf, int size, struct dive_table *table, char **error);
 
 extern void parse_file(const char *filename, char **error);
 extern void parse_csv_file(const char *filename, int time, int depth, int temp, int po2f, int cnsf, int stopdepthf, int sepidx, const char *csvtemplate, int units, char **error);
diff --git a/file.c b/file.c
index b5bdede..01c519e 100644
--- a/file.c
+++ b/file.c
@@ -151,9 +151,17 @@ static int try_to_xslt_open_csv(const char *filename, struct memblock *mem, char
 	return 0;
 }
 
+int db_test_func(void *param, int columns, char **data, char **column)
+{
+	return *data[0] == '0';
+}
+
+
 static int try_to_open_db(const char *filename, struct memblock *mem, char **error)
 {
 	sqlite3 *handle;
+	char dm4_test[] = "select count(*) from sqlite_master where type='table' and name='Dive' and sql like '%ProfileBlob%'";
+	char shearwater_test[] = "select count(*) from sqlite_master where type='table' and name='system' and sql like '%dbVersion%'";
 	int retval;
 
 	retval = sqlite3_open(filename, &handle);
@@ -163,7 +171,22 @@ static int try_to_open_db(const char *filename, struct memblock *mem, char **err
 		return 1;
 	}
 
-	retval = parse_dm4_buffer(handle, filename, mem->buffer, mem->size, &dive_table, error);
+	/* Testing if DB schema resembles Suunto DM4 database format */
+	retval = sqlite3_exec(handle, dm4_test, &db_test_func, 0, NULL);
+	if (!retval) {
+		retval = parse_dm4_buffer(handle, filename, mem->buffer, mem->size, &dive_table, error);
+		sqlite3_close(handle);
+		return retval;
+	}
+
+	/* Testing if DB schema resembles Shearwater database format */
+	retval = sqlite3_exec(handle, shearwater_test, &db_test_func, 0, NULL);
+	if (!retval) {
+		retval = parse_shearwater_buffer(handle, filename, mem->buffer, mem->size, &dive_table, error);
+		sqlite3_close(handle);
+		return retval;
+	}
+
 	sqlite3_close(handle);
 
 	return retval;
diff --git a/parse-xml.c b/parse-xml.c
index 60a13c3..b93906f 100644
--- a/parse-xml.c
+++ b/parse-xml.c
@@ -18,6 +18,7 @@
 #include "device.h"
 
 int verbose, quit;
+int metric = 1;
 
 static xmlDoc *test_xslt_transforms(xmlDoc *doc, const char **params, char **error);
 
@@ -1861,7 +1862,7 @@ extern int dm4_dive(void *param, int columns, char **data, char **column)
 	return SQLITE_OK;
 }
 
-int parse_dm4_buffer(const sqlite3 *handle, const char *url, const char *buffer, int size,
+int parse_dm4_buffer(sqlite3 *handle, const char *url, const char *buffer, int size,
 			struct dive_table *table, char **error)
 {
 	int retval;
@@ -1882,6 +1883,107 @@ int parse_dm4_buffer(const sqlite3 *handle, const char *url, const char *buffer,
 	return 0;
 }
 
+extern int shearwater_profile_sample(void *handle, int columns, char **data, char **column)
+{
+	sample_start();
+	if (data[0])
+		cur_sample->time.seconds = atoi(data[0]);
+	if (data[1])
+		cur_sample->depth.mm = metric ? atof(data[1]) * 1000 : feet_to_mm(atof(data[1]));
+	if (data[2])
+		cur_sample->temperature.mkelvin = metric ? C_to_mkelvin(atof(data[2])) : F_to_mkelvin(atof(data[2]));
+
+	/* We don't actually have data[3], but it should appear in the
+	 * SQL query at some point.
+	if (data[3])
+		cur_sample->cylinderpressure.mbar = metric ? atoi(data[3]) * 1000 : psi_to_mbar(atoi(data[3]));
+	 */
+	sample_end();
+
+	return 0;
+}
+
+extern int shearwater_dive(void *param, int columns, char **data, char **column)
+{
+	int i, interval, retval = 0;
+	sqlite3 *handle = (sqlite3 *)param;
+	float *profileBlob;
+	unsigned char *tempBlob;
+	char *err = NULL;
+	char *location, *site;
+	char get_profile_template[] = "select currentTime,currentDepth,waterTemp from dive_log_records where diveLogId = %d";
+	char get_tags_template[] = "select Text from DiveTag where DiveId = %d";
+	char get_profile_sample[128];
+
+	dive_start();
+	cur_dive->number = atoi(data[0]);
+
+	cur_dive->when = (time_t)(atol(data[1]));
+
+	if (data[2])
+		utf8_string(data[2], &cur_dive->location);
+	if (data[3])
+		utf8_string(data[3], &cur_dive->buddy);
+	if (data[4])
+		utf8_string(data[4], &cur_dive->notes);
+
+	metric = atoi(data[5]) == 1 ? 0 : 1;
+
+	/* TODO: verify that metric calculation is correct */
+	if (data[6])
+		cur_dive->dc.maxdepth.mm = metric ? atof(data[6]) * 1000 : feet_to_mm(atof(data[6]));
+
+	if (data[7])
+		cur_dive->dc.duration.seconds = atoi(data[7]) * 60;
+
+	if (data[8])
+		cur_dive->dc.surface_pressure.mbar = atoi(data[8]);
+	/*
+	 * TODO: the deviceid hash should be calculated here.
+	 */
+	settings_start();
+	dc_settings_start();
+	if (data[9])
+		utf8_string(data[9], &cur_settings.dc.serial_nr);
+	if (data[10])
+		utf8_string(data[10], &cur_settings.dc.model);
+
+	cur_settings.dc.deviceid = 0xffffffff;
+	dc_settings_end();
+	settings_end();
+
+	snprintf(get_profile_sample, sizeof(get_profile_sample) - 1, get_profile_template, cur_dive->number);
+	retval = sqlite3_exec(handle, get_profile_sample, &shearwater_profile_sample, 0, &err);
+	if (retval != SQLITE_OK) {
+		fprintf(stderr, "%s", translate("gettextFromC","Database query get_profile_sample failed.\n"));
+		return 1;
+	}
+
+	dive_end();
+
+	return SQLITE_OK;
+}
+
+
+int parse_shearwater_buffer(sqlite3 *handle, const char *url, const char *buffer, int size,
+			struct dive_table *table, char **error)
+{
+	int retval;
+	char *err = NULL;
+	target_table = table;
+
+	char get_dives[] = "select i.diveId,timestamp,location||' / '||site,buddy,notes,imperialUnits,maxDepth,maxTime,startSurfacePressure,computerSerial,computerModel FROM dive_info AS i JOIN dive_logs AS l ON i.diveId=l.diveId";
+
+	retval = sqlite3_exec(handle, get_dives, &shearwater_dive, handle, &err);
+
+	if (retval != SQLITE_OK) {
+		fprintf(stderr, translate("gettextFromC","Database query failed '%s'.\n"), url);
+		return 1;
+	}
+
+	return 0;
+}
+
 void parse_xml_init(void)
 {
 	LIBXML_TEST_VERSION
-- 
1.8.3.2



More information about the subsurface mailing list