Back in October/November, some users asked for support to import logs from
OSTCTools software, both in this mailing list and in the user forum.

The logs I've seen (those provided by a user in the the forum and my own
dives) happen to be very simple, just a few data heavily zero padded and
then the full raw data (header+samples) as downloaded from DC,  one file
each dive.

This patch serie builds support for this import and tries to provide some
kind of groundwork to pass binary DC downloaded data buffers to
libdivecomputer for parsing.

Downloading dives from DC had worked for me after applying 0002 patch, but
would need some testing with different devices which also make use of
do_libdivecomputer_import().

All OSTCTools  .dive files I could achieve are OSTC-2N/C series. It would
be great to have some testing for logs from OSTC3, FROG or SPORT devices.
Anton, Could you provide some .dive file from your OSTC3?

Regards.

Salva.
From 9af00c35b0d07073e2acad9827290900584c6f0f Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Salvador=20Cu=C3=B1at?= <salvador.cu...@gmail.com>
Date: Sun, 29 Mar 2015 12:06:00 +0200
Subject: [PATCH 1/4] Add dc_descriptor_t structure as defined in
 libdivecomputer
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
To: subsurface@subsurface-divelog.org
Cc: d...@hohndel.org

While downloading from DC the user sets the vendor and model. In
imports, this is not possible. Parser has to figure somehow, at least,
the DC model used in a dive basis, as it can even change over time, and
a log file can include several different models.

Will use this structure in import tasks to ensure that data passed to
libdc are consistent with what it expects to find.

Signed-off-by: Salvador Cuñat <salvador.cu...@gmail.com>
---
 libdivecomputer.h | 7 +++++++
 1 file changed, 7 insertions(+)

diff --git a/libdivecomputer.h b/libdivecomputer.h
index 91548ba..eaaa998 100644
--- a/libdivecomputer.h
+++ b/libdivecomputer.h
@@ -13,6 +13,13 @@
 extern "C" {
 #endif
 
+struct dc_descriptor_t {
+	const char *vendor;
+	const char *product;
+	dc_family_t type;
+	unsigned int model;
+};
+
 /* don't forget to include the UI toolkit specific display-XXX.h first
    to get the definition of progressbar_t */
 typedef struct device_data_t
-- 
2.1.4

From 686d24da47aa36692d905ed84d9f3aec2abd21ea Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Salvador=20Cu=C3=B1at?= <salvador.cu...@gmail.com>
Date: Sun, 29 Mar 2015 12:10:42 +0200
Subject: [PATCH 2/4] Split dive_cb() callback in two
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
To: subsurface@subsurface-divelog.org
Cc: d...@hohndel.org

Actually dive_cb() needs a defined device to work as its built for DC
download tasks.
Move part of the functionality of dive_cb() to a new function
libdc_header_parser() which can be used to parse headers from raw data
buffers with no device set.
Obviously dive_cb() will call the new funtion for header parsing too.

Signed-off-by: Salvador Cuñat <salvador.cu...@gmail.com>
---
 libdivecomputer.c | 131 +++++++++++++++++++++++++++++++++---------------------
 1 file changed, 80 insertions(+), 51 deletions(-)

diff --git a/libdivecomputer.c b/libdivecomputer.c
index 950b9da..8b461ac 100644
--- a/libdivecomputer.c
+++ b/libdivecomputer.c
@@ -400,72 +400,50 @@ static void parse_string_field(struct dive *dive, dc_field_string_t *str)
 }
 #endif
 
-/* returns true if we want libdivecomputer's dc_device_foreach() to continue,
- *  false otherwise */
-static int dive_cb(const unsigned char *data, unsigned int size,
-		   const unsigned char *fingerprint, unsigned int fsize,
-		   void *userdata)
+static dc_status_t libdc_header_parser(dc_parser_t *parser, struct device_data_t *devdata, struct dive *dive)
 {
-	int rc;
-	dc_parser_t *parser = NULL;
-	device_data_t *devdata = userdata;
-	dc_datetime_t dt = { 0 };
+	dc_status_t rc = 0;
+	dc_datetime_t datetime = { 0 };
 	struct tm tm;
-	struct dive *dive = NULL;
-
-	/* reset the deco / ndl data */
-	ndl = stoptime = stopdepth = 0;
-	in_deco = false;
-
-	rc = create_parser(devdata, &parser);
-	if (rc != DC_STATUS_SUCCESS) {
-		dev_info(devdata, translate("gettextFromC", "Unable to create parser for %s %s"), devdata->vendor, devdata->product);
-		return false;
-	}
-
-	rc = dc_parser_set_data(parser, data, size);
-	if (rc != DC_STATUS_SUCCESS) {
-		dev_info(devdata, translate("gettextFromC", "Error registering the data"));
-		goto error_exit;
-	}
 
-	import_dive_number++;
-	dive = alloc_dive();
-	rc = dc_parser_get_datetime(parser, &dt);
+	rc = dc_parser_get_datetime(parser, &datetime);
 	if (rc != DC_STATUS_SUCCESS && rc != DC_STATUS_UNSUPPORTED) {
 		dev_info(devdata, translate("gettextFromC", "Error parsing the datetime"));
-		goto error_exit;
+		fprintf(stderr, "Error parsing the datetime");
+		return rc;
 	}
-	dive->dc.model = strdup(devdata->model);
+
 	dive->dc.deviceid = devdata->deviceid;
-	dive->dc.diveid = calculate_diveid(fingerprint, fsize);
 
 	if (rc == DC_STATUS_SUCCESS) {
-		tm.tm_year = dt.year;
-		tm.tm_mon = dt.month - 1;
-		tm.tm_mday = dt.day;
-		tm.tm_hour = dt.hour;
-		tm.tm_min = dt.minute;
-		tm.tm_sec = dt.second;
+		tm.tm_year = datetime.year;
+		tm.tm_mon = datetime.month - 1;
+		tm.tm_mday = datetime.day;
+		tm.tm_hour = datetime.hour;
+		tm.tm_min = datetime.minute;
+		tm.tm_sec = datetime.second;
 		dive->when = dive->dc.when = utc_mktime(&tm);
 	}
+
 	// Parse the divetime.
 	dev_info(devdata, translate("gettextFromC", "Dive %d: %s"), import_dive_number, get_dive_date_c_string(dive->when));
 	unsigned int divetime = 0;
 	rc = dc_parser_get_field(parser, DC_FIELD_DIVETIME, 0, &divetime);
 	if (rc != DC_STATUS_SUCCESS && rc != DC_STATUS_UNSUPPORTED) {
 		dev_info(devdata, translate("gettextFromC", "Error parsing the divetime"));
-		goto error_exit;
+		fprintf(stderr, "Error parsing the divetime\n");
+		return rc;
 	}
 	if (rc == DC_STATUS_SUCCESS)
-		dive->dc.duration.seconds = divetime;
+		dive->duration.seconds = dive->dc.duration.seconds = divetime;
 
 	// Parse the maxdepth.
 	double maxdepth = 0.0;
 	rc = dc_parser_get_field(parser, DC_FIELD_MAXDEPTH, 0, &maxdepth);
 	if (rc != DC_STATUS_SUCCESS && rc != DC_STATUS_UNSUPPORTED) {
 		dev_info(devdata, translate("gettextFromC", "Error parsing the maxdepth"));
-		goto error_exit;
+		fprintf(stderr, "Error parsing the maxdepth\n");
+		return rc;
 	}
 	if (rc == DC_STATUS_SUCCESS)
 		dive->dc.maxdepth.mm = rint(maxdepth * 1000);
@@ -484,7 +462,8 @@ static int dive_cb(const unsigned char *data, unsigned int size,
 		rc = dc_parser_get_field(parser, temp_fields[i], 0, &temperature);
 		if (rc != DC_STATUS_SUCCESS && rc != DC_STATUS_UNSUPPORTED) {
 			dev_info(devdata, translate("gettextFromC", "Error parsing temperature"));
-			goto error_exit;
+			fprintf(stderr, "Error parsing temperature\n");
+			return rc;
 		}
 		if (rc == DC_STATUS_SUCCESS)
 			switch(i) {
@@ -504,7 +483,8 @@ static int dive_cb(const unsigned char *data, unsigned int size,
 	rc = dc_parser_get_field(parser, DC_FIELD_GASMIX_COUNT, 0, &ngases);
 	if (rc != DC_STATUS_SUCCESS && rc != DC_STATUS_UNSUPPORTED) {
 		dev_info(devdata, translate("gettextFromC", "Error parsing the gas mix count"));
-		goto error_exit;
+		fprintf(stderr, "Error parsing the gas mix count\n");
+		return rc;
 	}
 
 #if DC_VERSION_CHECK(0, 3, 0)
@@ -516,7 +496,8 @@ static int dive_cb(const unsigned char *data, unsigned int size,
 	rc = dc_parser_get_field(parser, DC_FIELD_SALINITY, 0, &salinity);
 	if (rc != DC_STATUS_SUCCESS && rc != DC_STATUS_UNSUPPORTED) {
 		dev_info(devdata, translate("gettextFromC", "Error obtaining water salinity"));
-		goto error_exit;
+		fprintf(stderr, "Error obtaining water salinity\n");
+		return rc;
 	}
 	if (rc == DC_STATUS_SUCCESS)
 		dive->dc.salinity = rint(salinity.density * 10.0);
@@ -525,7 +506,8 @@ static int dive_cb(const unsigned char *data, unsigned int size,
 	rc = dc_parser_get_field(parser, DC_FIELD_ATMOSPHERIC, 0, &surface_pressure);
 	if (rc != DC_STATUS_SUCCESS && rc != DC_STATUS_UNSUPPORTED) {
 		dev_info(devdata, translate("gettextFromC", "Error obtaining surface pressure"));
-		goto error_exit;
+		fprintf(stderr, "Error obtaining surface pressure\n");
+		return rc;
 	}
 	if (rc == DC_STATUS_SUCCESS)
 		dive->dc.surface_pressure.mbar = rint(surface_pressure * 1000.0);
@@ -537,7 +519,7 @@ static int dive_cb(const unsigned char *data, unsigned int size,
 	for (idx = 0; idx < 100; idx++) {
 		dc_field_string_t str = { NULL };
 		rc = dc_parser_get_field(parser, DC_FIELD_STRING, idx, &str);
-		if (rc != DC_STATUS_SUCCESS)
+		if (rc != DC_STATUS_SUCCESS && rc != DC_STATUS_UNSUPPORTED)
 			break;
 		if (!str.desc || !str.value)
 			break;
@@ -550,7 +532,8 @@ static int dive_cb(const unsigned char *data, unsigned int size,
 	rc = dc_parser_get_field(parser, DC_FIELD_DIVEMODE, 0, &divemode);
 	if (rc != DC_STATUS_SUCCESS && rc != DC_STATUS_UNSUPPORTED) {
 		dev_info(devdata, translate("gettextFromC", "Error obtaining divemode"));
-		goto error_exit;
+		fprintf(stderr, "Error obtaining divemode\n");
+		return rc;
 	}
 	if (rc == DC_STATUS_SUCCESS)
 		switch(divemode) {
@@ -558,21 +541,67 @@ static int dive_cb(const unsigned char *data, unsigned int size,
 			dive->dc.divemode = FREEDIVE;
 			break;
 		case DC_DIVEMODE_GAUGE:
-		case DC_DIVEMODE_OC: /* Open circuit */
+		case DC_DIVEMODE_OC:
 			dive->dc.divemode = OC;
 			break;
-		case DC_DIVEMODE_CC:  /* Closed circuit */
+		case DC_DIVEMODE_CC:
 			dive->dc.divemode = CCR;
 			break;
 		}
 #endif
 
-	rc = parse_gasmixes(devdata, dive, parser, ngases, data);
-	if (rc != DC_STATUS_SUCCESS) {
+	rc = parse_gasmixes(devdata, dive, parser, ngases, NULL);
+	if (rc != DC_STATUS_SUCCESS && rc != DC_STATUS_UNSUPPORTED) {
 		dev_info(devdata, translate("gettextFromC", "Error parsing the gas mix"));
+		fprintf(stderr, "Error parsing the gas mix\n");
+		return rc;
+	}
+
+	return DC_STATUS_SUCCESS;
+}
+
+/* returns true if we want libdivecomputer's dc_device_foreach() to continue,
+ *  false otherwise */
+static int dive_cb(const unsigned char *data, unsigned int size,
+		   const unsigned char *fingerprint, unsigned int fsize,
+		   void *userdata)
+{
+	int rc;
+	dc_parser_t *parser = NULL;
+	device_data_t *devdata = userdata;
+	dc_datetime_t dt = { 0 };
+	struct tm tm;
+	struct dive *dive = NULL;
+
+	/* reset the deco / ndl data */
+	ndl = stoptime = stopdepth = 0;
+	in_deco = false;
+
+	rc = create_parser(devdata, &parser);
+	if (rc != DC_STATUS_SUCCESS) {
+		dev_info(devdata, translate("gettextFromC", "Unable to create parser for %s %s"), devdata->vendor, devdata->product);
+		return false;
+	}
+
+	rc = dc_parser_set_data(parser, data, size);
+	if (rc != DC_STATUS_SUCCESS) {
+		dev_info(devdata, translate("gettextFromC", "Error registering the data"));
 		goto error_exit;
 	}
 
+	import_dive_number++;
+	dive = alloc_dive();
+
+	// Parse the dive's header data
+	rc = libdc_header_parser (parser, devdata, dive);
+	if (rc != DC_STATUS_SUCCESS) {
+		dev_info(devdata, translate("getextFromC", "Error parsing the header"));
+		goto error_exit;
+	}
+
+	dive->dc.model = strdup(devdata->model);
+	dive->dc.diveid = calculate_diveid(fingerprint, fsize);
+
 	// Initialize the sample data.
 	rc = parse_samples(devdata, &dive->dc, parser);
 	if (rc != DC_STATUS_SUCCESS) {
-- 
2.1.4

From de2039fb864042c443723340320efa310d7e52d4 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Salvador=20Cu=C3=B1at?= <salvador.cu...@gmail.com>
Date: Sun, 29 Mar 2015 12:25:39 +0200
Subject: [PATCH 3/4] Add support for raw data buffer parse using libdc
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
To: subsurface@subsurface-divelog.org
Cc: d...@hohndel.org

Add function libdc_buffer_parser() intended to parse raw data buffers
prepared for libdivecomputer. We have to commit elsewhere the
necesary assembly tasks to achieve consistent data.

Actually only OSTCTools import makes use of this feature. Uwatec families
have been included as I expect to make use of this function for sample
parsing in datatrak import (and, may be in a far future, smartrak).

Adds errmsg() function taken as is from libdivecomputer's
exaples/common.c to improve error management on libdc return codes.

Signed-off-by: Salvador Cuñat <salvador.cu...@gmail.com>
---
 libdivecomputer.c | 97 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
 libdivecomputer.h |  2 ++
 2 files changed, 99 insertions(+)

diff --git a/libdivecomputer.c b/libdivecomputer.c
index 8b461ac..6a418c5 100644
--- a/libdivecomputer.c
+++ b/libdivecomputer.c
@@ -9,6 +9,9 @@
 #include "display.h"
 
 #include "libdivecomputer.h"
+#include <libdivecomputer/uwatec.h>
+#include <libdivecomputer/hw.h>
+
 
 /* Christ. Libdivecomputer has the worst configuration system ever. */
 #ifdef HW_FROG_H
@@ -26,6 +29,40 @@ double progress_bar_fraction = 0.0;
 static int stoptime, stopdepth, ndl, po2, cns;
 static bool in_deco, first_temp_is_air;
 
+/*
+ * Directly taken from libdivecomputer's examples/common.c to improve
+ * the error messages resulting from libdc's return codes
+ */
+const char *errmsg (dc_status_t rc)
+{
+	switch (rc) {
+	case DC_STATUS_SUCCESS:
+		return "Success";
+	case DC_STATUS_UNSUPPORTED:
+		return "Unsupported operation";
+	case DC_STATUS_INVALIDARGS:
+		return "Invalid arguments";
+	case DC_STATUS_NOMEMORY:
+		return "Out of memory";
+	case DC_STATUS_NODEVICE:
+		return "No device found";
+	case DC_STATUS_NOACCESS:
+		return "Access denied";
+	case DC_STATUS_IO:
+		return "Input/output error";
+	case DC_STATUS_TIMEOUT:
+		return "Timeout";
+	case DC_STATUS_PROTOCOL:
+		return "Protocol error";
+	case DC_STATUS_DATAFORMAT:
+		return "Data format error";
+	case DC_STATUS_CANCELLED:
+		return "Cancelled";
+	default:
+		return "Unknown error";
+	}
+}
+
 static dc_status_t create_parser(device_data_t *devdata, dc_parser_t **parser)
 {
 	return dc_parser_new(parser, devdata->device);
@@ -905,3 +942,63 @@ const char *do_libdivecomputer_import(device_data_t *data)
 
 	return err;
 }
+
+/*
+ * Parse data buffers instead of dc devices downloaded data.
+ * Intended to be used to parse profile data from binary files during import tasks.
+ * Actually included Uwatec families because of smartrak import and H&W families
+ * for future use in "OSTC TOOLS" .dive files import.
+ * For others, simply include them in the switch  (check parameters).
+ * Note that dc_descriptor_t in data  *must* have been filled using dc_descriptor_iterator()
+ * calls.
+ */
+dc_status_t libdc_buffer_parser(struct dive *dive, device_data_t *data, unsigned char *buffer, int size)
+{
+	dc_status_t rc;
+	dc_parser_t *parser = NULL;
+
+	switch (data->descriptor->type) {
+	case DC_FAMILY_UWATEC_ALADIN:
+	case DC_FAMILY_UWATEC_MEMOMOUSE:
+		rc = uwatec_memomouse_parser_create(&parser, data->context, 0, 0);
+		break;
+	case DC_FAMILY_UWATEC_SMART:
+	case DC_FAMILY_UWATEC_MERIDIAN:
+		rc = uwatec_smart_parser_create (&parser, data->context, data->descriptor->model, 0, 0);
+		break;
+	case DC_FAMILY_HW_OSTC:
+		rc = hw_ostc_parser_create (&parser, data->context, data->deviceid, 0);
+		break;
+	case DC_FAMILY_HW_FROG:
+	case DC_FAMILY_HW_OSTC3:
+		rc = hw_ostc_parser_create (&parser, data->context, data->deviceid, 1);
+		break;
+	}
+	if  (rc != DC_STATUS_SUCCESS) {
+		fprintf(stderr, "Error creating parser.\n");
+		dc_parser_destroy (parser);
+		return rc;
+	}
+	rc = dc_parser_set_data(parser, buffer, size);
+	if (rc != DC_STATUS_SUCCESS) {
+		fprintf(stderr, "Error registering the data.\n");
+		dc_parser_destroy (parser);
+		return rc;
+	}
+	// Do not parse Aladin/Memomouse headers as they are fakes
+	// Do not return on error, we can still parse the samples
+	if (data->descriptor->type != DC_FAMILY_UWATEC_ALADIN && data->descriptor->type != DC_FAMILY_UWATEC_MEMOMOUSE) {
+		rc = libdc_header_parser (parser, data, dive);
+		if (rc != DC_STATUS_SUCCESS) {
+			fprintf(stderr, "Error parsing the dive header data. Dive # %d\n", dive->number);
+		}
+	}
+	rc = dc_parser_samples_foreach (parser, sample_cb, &dive->dc);
+	if (rc != DC_STATUS_SUCCESS) {
+		fprintf(stderr, "Error parsing the sample data. Dive # %d\nStatus = %s\n", dive->number, errmsg(rc));
+		dc_parser_destroy (parser);
+		return rc;
+	}
+	dc_parser_destroy(parser);
+	return(DC_STATUS_SUCCESS);
+}
diff --git a/libdivecomputer.h b/libdivecomputer.h
index eaaa998..2e4fb9a 100644
--- a/libdivecomputer.h
+++ b/libdivecomputer.h
@@ -41,8 +41,10 @@ typedef struct device_data_t
 	struct dive_table *download_table;
 } device_data_t;
 
+const char *errmsg (dc_status_t rc);
 const char *do_libdivecomputer_import(device_data_t *data);
 const char *do_uemis_import(device_data_t *data);
+dc_status_t libdc_buffer_parser(struct dive *dive, device_data_t *data, unsigned char *buffer, int size);
 
 extern int import_thread_cancelled;
 extern const char *progress_bar_text;
-- 
2.1.4

From 5d5973b7fa9ddb53262e3f52e650487645e33cee Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Salvador=20Cu=C3=B1at?= <salvador.cu...@gmail.com>
Date: Sun, 29 Mar 2015 12:42:39 +0200
Subject: [PATCH 4/4] OSTCTools-Add support to import .dive files
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
To: subsurface@subsurface-divelog.org
Cc: d...@hohndel.org

OSTCTools is a windows based software by Robert Angeymar which performs
configuration upgrade, memory analysis and download tasks for H&W OSTC
devices.

Downloaded dives are stored in files (one archive each) with the raw
binary data heavily padded at the begining of the file, and some other
data not included in H&W dive header protocol as the device's serial
number.

The import function, simply, takes the raw data part of the file and
lets libdivecomputer do the parse.

Then adds some additional info as OSTC reported dive number and serial
device number.

Please note that OSTCTools is *not* a real logging software, it simply
gets the DC raw data, so there aren't infos about dive site, equipment
and so.

BTW, patch moves external funtion declarations to file.h

Signed-off-by: Salvador Cuñat <salvador.cu...@gmail.com>
---
 file.c               |   8 ++-
 file.h               |   2 +
 ostctools.c          | 156 +++++++++++++++++++++++++++++++++++++++++++++++++++
 qt-ui/mainwindow.cpp |   1 +
 subsurface.pro       |   3 +-
 5 files changed, 167 insertions(+), 3 deletions(-)
 create mode 100644 ostctools.c

diff --git a/file.c b/file.c
index bf62a95..69f9541 100644
--- a/file.c
+++ b/file.c
@@ -22,8 +22,6 @@
 #define O_BINARY 0
 #endif
 
-extern void datatrak_import(const char *file, struct dive_table *table);
-
 int readfile(const char *filename, struct memblock *mem)
 {
 	int ret, fd;
@@ -462,6 +460,12 @@ int parse_file(const char *filename)
 		return 0;
 	}
 
+	/* OSTCtools */
+	if (fmt && (!strcasecmp(fmt + 1, "DIVE"))) {
+		ostctools_import(filename, &dive_table);
+		return 0;
+	}
+
 	ret = parse_file_buffer(filename, &mem);
 	free(mem.buffer);
 	return ret;
diff --git a/file.h b/file.h
index d4c52fd..baeb8e1 100644
--- a/file.h
+++ b/file.h
@@ -8,6 +8,8 @@ struct memblock {
 
 extern int try_to_open_cochran(const char *filename, struct memblock *mem);
 extern int try_to_open_liquivision(const char *filename, struct memblock *mem);
+extern void datatrak_import(const char *file, struct dive_table *table);
+extern void ostctools_import(const char *file, struct dive_table *table);
 
 #ifdef __cplusplus
 extern "C" {
diff --git a/ostctools.c b/ostctools.c
new file mode 100644
index 0000000..e626977
--- /dev/null
+++ b/ostctools.c
@@ -0,0 +1,156 @@
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "dive.h"
+#include "gettext.h"
+#include "divelist.h"
+#include "libdivecomputer.h"
+
+/*
+ * Returns a dc_descriptor_t structure based on dc  model's number and family.
+ */
+
+static dc_descriptor_t *ostc_get_data_descriptor(int data_model, dc_family_t data_fam)
+{
+	dc_descriptor_t *descriptor = NULL, *current = NULL;;
+	dc_iterator_t *iterator = NULL;
+	dc_status_t rc;
+
+	rc = dc_descriptor_iterator(&iterator);
+	if (rc != DC_STATUS_SUCCESS) {
+		fprintf(stderr,"Error creating the device descriptor iterator.\n");
+		return current;
+	}
+	while ((dc_iterator_next(iterator, &descriptor)) == DC_STATUS_SUCCESS) {
+		int desc_model = dc_descriptor_get_model(descriptor);
+		dc_family_t desc_fam = dc_descriptor_get_type(descriptor);
+		if (data_model == desc_model && data_fam == desc_fam) {
+			current = descriptor;
+			break;
+		}
+		dc_descriptor_free(descriptor);
+	}
+	dc_iterator_free(iterator);
+	return current;
+}
+
+/*
+ * Fills a device_data_t structure with known dc data and a descriptor.
+ */
+static void ostc_prepare_data(int data_model, dc_family_t dc_fam, device_data_t *dev_data)
+{
+	device_data_t *ldc_dat = calloc(1, sizeof(device_data_t));
+	dc_descriptor_t *data_descriptor;
+
+	*ldc_dat = *dev_data;
+	ldc_dat->device = NULL;
+	ldc_dat->context = NULL;
+
+	data_descriptor = ostc_get_data_descriptor(data_model, dc_fam);
+	if (data_descriptor) {
+		ldc_dat->descriptor = data_descriptor;
+		ldc_dat->vendor = copy_string(data_descriptor->vendor);
+		ldc_dat->model = copy_string(data_descriptor->product);
+		*dev_data = *ldc_dat;
+	}
+	free(ldc_dat);
+}
+
+/*
+ * OSTCTools stores the raw dive data in heavily padded files, one dive
+ * each file. So it's not necesary to iterate once and again on a parsing
+ * function. Actually there's only one kind of archive for every DC model.
+ */
+void ostctools_import(const char *file, struct dive_table *divetable)
+{
+	FILE *archive;
+	device_data_t *devdata = calloc(1, sizeof(device_data_t));
+	dc_family_t dc_fam;
+	unsigned char *buffer = calloc(65536, 1),
+		      *tmp;
+	struct dive *ostcdive = alloc_dive();
+	dc_status_t rc = 0;
+	int model = 0, i = 0;
+	unsigned int serial;
+	struct extra_data *ptr;
+
+	// Open the archive
+	if ((archive = subsurface_fopen(file, "rb")) == NULL) {
+		report_error(translate("gettextFromC", "Error: couldn't open the file"));
+		return;
+	}
+
+	// Read dive number from the log
+	tmp =  calloc(2,1);
+	fseek(archive, 258, 0);
+	fread(tmp, 1, 2, archive);
+	ostcdive->number = tmp[0] + (tmp[1] << 8);
+	free(tmp);
+
+	// Read device's serial number
+	tmp = calloc(2, 1);
+	fseek(archive, 265, 0);
+	fread(tmp, 1, 2, archive);
+	serial = tmp[0] + (tmp[1] << 8);
+	free(tmp);
+
+	// Read dive's raw data, header + profile
+	fseek(archive, 456, 0);
+	while (!feof(archive)) {
+		fread(buffer+i, 1, 1, archive);
+		if (buffer[i] == 0xFD && buffer[i-1] == 0xFD)
+			break;
+		i++;
+	}
+
+	// Try to determine the dc family based on the header type
+	switch (buffer[2]) {
+		case 0x20:
+		case 0x21:
+			dc_fam = DC_FAMILY_HW_OSTC;
+			break;
+		case 0x22:
+			dc_fam = DC_FAMILY_HW_FROG;
+			break;
+		case 0x23:
+			dc_fam = DC_FAMILY_HW_OSTC3;
+			break;
+	}
+
+	// Prepare data to pass to libdivecomputer. OSTC protocol doesn't include
+	// a model number so will use 0.
+	ostc_prepare_data(model, dc_fam, devdata);
+	tmp = calloc(strlen(devdata->vendor)+strlen(devdata->model)+28,1);
+	sprintf(tmp,"%s %s (Imported from OSTCTools)", devdata->vendor, devdata->model);
+	ostcdive->dc.model =  copy_string(tmp);
+	free(tmp);
+
+	// Parse de dive data
+	rc = libdc_buffer_parser(ostcdive, devdata, buffer, i+1);
+	if (rc != DC_STATUS_SUCCESS)
+		report_error("Libdc returned error -%s- for dive %d", errmsg(rc), ostcdive->number);
+
+	// Serial number is not part of the header nor the profile, so libdc won't
+	// catch it. If Serial is part of the extra_data, and set to zero, remove
+	// it from the list and add again.
+	tmp = calloc(12,1);
+	sprintf(tmp, "%d", serial);
+	ostcdive->dc.serial = copy_string(tmp);
+	free(tmp);
+
+	ptr = ostcdive->dc.extra_data;
+	while (strcmp(ptr->key, "Serial"))
+		ptr = ptr->next;
+	if (!strcmp(ptr->value, "0")) {
+		add_extra_data(&ostcdive->dc, "Serial", ostcdive->dc.serial);
+		*ptr = *(ptr)->next;
+	}
+
+	free(devdata);
+	free(buffer);
+	record_dive_to_table(ostcdive, divetable);
+	mark_divelist_changed(true);
+	sort_table(divetable);
+	fclose(archive);
+}
diff --git a/qt-ui/mainwindow.cpp b/qt-ui/mainwindow.cpp
index 2c17648..65c1aee 100644
--- a/qt-ui/mainwindow.cpp
+++ b/qt-ui/mainwindow.cpp
@@ -1437,6 +1437,7 @@ void MainWindow::on_actionImportDiveLog_triggered()
 			"XML files (*.xml *.XML);;"
 			"APD log viewer (*.apd *.APD);;"
 			"Datatrak/WLog Files (*.log *.LOG);;"
+			"OSTCtools Files (*.dive *.DIVE);;"
 			"All files (*)"));
 
 	if (fileNames.isEmpty())
diff --git a/subsurface.pro b/subsurface.pro
index cedc926..bec7d65 100644
--- a/subsurface.pro
+++ b/subsurface.pro
@@ -213,7 +213,8 @@ SOURCES =  \
 	qt-ui/diveshareexportdialog.cpp \
 	qt-ui/filtermodels.cpp \
 	qt-ui/undocommands.cpp \
-	qt-ui/notificationwidget.cpp
+	qt-ui/notificationwidget.cpp \
+	ostctools.c
 
 android: SOURCES += android.cpp
 else: win32: SOURCES += windows.c
-- 
2.1.4

_______________________________________________
subsurface mailing list
subsurface@subsurface-divelog.org
http://lists.subsurface-divelog.org/cgi-bin/mailman/listinfo/subsurface

Reply via email to