[PATCH 2/3] Parse meta information from Seaber log

Miika Turkia miika.turkia at gmail.com
Tue Oct 28 02:14:00 PDT 2014


This will parse date information from Seabear log file and skips the
"header" data to allow parsing of the CSV content.

Signed-off-by: Miika Turkia <miika.turkia at gmail.com>
---
 dive.h                        |   1 +
 file.c                        | 154 ++++++++++++++++++++++++++++++++++--------
 qt-ui/divelogimportdialog.cpp |  46 ++++++-------
 3 files changed, 149 insertions(+), 52 deletions(-)

diff --git a/dive.h b/dive.h
index ef5ff0f..1c30a72 100644
--- a/dive.h
+++ b/dive.h
@@ -603,6 +603,7 @@ extern int parse_shearwater_buffer(sqlite3 *handle, const char *url, const char
 
 extern int parse_file(const char *filename);
 extern int parse_csv_file(const char *filename, int time, int depth, int temp, int po2f, int cnsf, int ndlf, int ttsf, int stopdepthf, int pressuref, int sepidx, const char *csvtemplate, int units);
+extern int parse_seabear_csv_file(const char *filename, int time, int depth, int temp, int po2f, int cnsf, int ndlf, int ttsf, int stopdepthf, int pressuref, int sepidx, const char *csvtemplate, int units);
 extern int parse_txt_file(const char *filename, const char *csv);
 extern int parse_manual_file(const char *filename, int separator_index, int units, int number, int date, int time, int duration, int location, int gps, int maxdepth, int meandepth, int buddy, int notes, int weight, int tags);
 
diff --git a/file.c b/file.c
index 6ada903..7ffe8a6 100644
--- a/file.c
+++ b/file.c
@@ -105,7 +105,7 @@ static int try_to_xslt_open_csv(const char *filename, struct memblock *mem, cons
 {
 	char *buf;
 
-	if (readfile(filename, mem) < 0)
+	if (mem->size == 0 && readfile(filename, mem) < 0)
 		return report_error(translate("gettextFromC", "Failed to read '%s'"), filename);
 
 	/* Surround the CSV file content with XML tags to enable XSLT
@@ -589,29 +589,11 @@ int parse_txt_file(const char *filename, const char *csv)
 
 #define MAXCOLDIGITS 3
 #define MAXCOLS 100
-int parse_csv_file(const char *filename, int timef, int depthf, int tempf, int po2f, int cnsf, int ndlf, int ttsf, int stopdepthf, int pressuref, int sepidx, const char *csvtemplate, int unitidx)
+#define DATESTR 9
+#define TIMESTR 6
+void init_csv_file_parsing(char **params, char *timebuf, char *depthbuf, char *tempbuf, char *po2buf, char *cnsbuf, char *ndlbuf, char *ttsbuf, char *stopdepthbuf, char *pressurebuf, char *unitbuf, char *separator_index, time_t *now, struct tm *timep, char *curdate, char *curtime, int timef, int depthf, int tempf, int po2f, int cnsf, int ndlf, int ttsf, int stopdepthf, int pressuref, int sepidx, const char *csvtemplate, int unitidx)
 {
-	struct memblock mem;
 	int pnr = 0;
-	char *params[27];
-	char timebuf[MAXCOLDIGITS];
-	char depthbuf[MAXCOLDIGITS];
-	char tempbuf[MAXCOLDIGITS];
-	char po2buf[MAXCOLDIGITS];
-	char cnsbuf[MAXCOLDIGITS];
-	char ndlbuf[MAXCOLDIGITS];
-	char ttsbuf[MAXCOLDIGITS];
-	char stopdepthbuf[MAXCOLDIGITS];
-	char pressurebuf[MAXCOLDIGITS];
-	char unitbuf[MAXCOLDIGITS];
-	char separator_index[MAXCOLDIGITS];
-	time_t now;
-	struct tm *timep;
-	char curdate[9];
-	char curtime[6];
-
-	if (timef >= MAXCOLS || depthf >= MAXCOLS || tempf >= MAXCOLS || po2f >= MAXCOLS || cnsf >= MAXCOLS || ndlf >= MAXCOLS || cnsf >= MAXCOLS || stopdepthf >= MAXCOLS || pressuref >= MAXCOLS)
-		return report_error(translate("gettextFromC", "Maximum number of supported columns on CSV import is %d"), MAXCOLS);
 
 	snprintf(timebuf, MAXCOLDIGITS, "%d", timef);
 	snprintf(depthbuf, MAXCOLDIGITS, "%d", depthf);
@@ -624,13 +606,13 @@ int parse_csv_file(const char *filename, int timef, int depthf, int tempf, int p
 	snprintf(pressurebuf, MAXCOLDIGITS, "%d", pressuref);
 	snprintf(separator_index, MAXCOLDIGITS, "%d", sepidx);
 	snprintf(unitbuf, MAXCOLDIGITS, "%d", unitidx);
-	time(&now);
-	timep = localtime(&now);
-	strftime(curdate, sizeof(curdate), "%Y%m%d", timep);
+	time(now);
+	timep = localtime(now);
+	strftime(curdate, DATESTR, "%Y%m%d", timep);
 
 	/* As the parameter is numeric, we need to ensure that the leading zero
 	* is not discarded during the transform, thus prepend time with 1 */
-	strftime(curtime, sizeof(curtime), "1%H%M", timep);
+	strftime(curtime, TIMESTR, "1%H%M", timep);
 
 	params[pnr++] = "timeField";
 	params[pnr++] = timebuf;
@@ -659,10 +641,125 @@ int parse_csv_file(const char *filename, int timef, int depthf, int tempf, int p
 	params[pnr++] = "separatorIndex";
 	params[pnr++] = separator_index;
 	params[pnr++] = NULL;
+}
+
+int parse_csv_file(const char *filename, int timef, int depthf, int tempf, int po2f, int cnsf, int ndlf, int ttsf, int stopdepthf, int pressuref, int sepidx, const char *csvtemplate, int unitidx)
+{
+	struct memblock mem;
+	char *params[27];
+	char timebuf[MAXCOLDIGITS];
+	char depthbuf[MAXCOLDIGITS];
+	char tempbuf[MAXCOLDIGITS];
+	char po2buf[MAXCOLDIGITS];
+	char cnsbuf[MAXCOLDIGITS];
+	char ndlbuf[MAXCOLDIGITS];
+	char ttsbuf[MAXCOLDIGITS];
+	char stopdepthbuf[MAXCOLDIGITS];
+	char pressurebuf[MAXCOLDIGITS];
+	char unitbuf[MAXCOLDIGITS];
+	char separator_index[MAXCOLDIGITS];
+	time_t now;
+	struct tm *timep;
+	char curdate[DATESTR];
+	char curtime[TIMESTR];
+
+	if (timef >= MAXCOLS || depthf >= MAXCOLS || tempf >= MAXCOLS || po2f >= MAXCOLS || cnsf >= MAXCOLS || ndlf >= MAXCOLS || cnsf >= MAXCOLS || stopdepthf >= MAXCOLS || pressuref >= MAXCOLS)
+		return report_error(translate("gettextFromC", "Maximum number of supported columns on CSV import is %d"), MAXCOLS);
+
+	init_csv_file_parsing(params, timebuf, depthbuf, tempbuf, po2buf, cnsbuf,ndlbuf, ttsbuf, stopdepthbuf, pressurebuf, unitbuf, separator_index, &now, timep, curdate, curtime, timef, depthf, tempf, po2f, cnsf, ndlf, ttsf, stopdepthf, pressuref, sepidx, csvtemplate, unitidx);
+
+	if (filename == NULL)
+		return report_error("No CSV filename");
+
+	mem.size = 0;
+	if (try_to_xslt_open_csv(filename, &mem, csvtemplate))
+		return -1;
+
+	parse_xml_buffer(filename, mem.buffer, mem.size, &dive_table, (const char **)params);
+	free(mem.buffer);
+	return 0;
+}
+
+int parse_seabear_csv_file(const char *filename, int timef, int depthf, int tempf, int po2f, int cnsf, int ndlf, int ttsf, int stopdepthf, int pressuref, int sepidx, const char *csvtemplate, int unitidx)
+{
+	struct memblock mem, mem_data;
+	char *params[27];
+	char timebuf[MAXCOLDIGITS];
+	char depthbuf[MAXCOLDIGITS];
+	char tempbuf[MAXCOLDIGITS];
+	char po2buf[MAXCOLDIGITS];
+	char cnsbuf[MAXCOLDIGITS];
+	char ndlbuf[MAXCOLDIGITS];
+	char ttsbuf[MAXCOLDIGITS];
+	char stopdepthbuf[MAXCOLDIGITS];
+	char pressurebuf[MAXCOLDIGITS];
+	char unitbuf[MAXCOLDIGITS];
+	char separator_index[MAXCOLDIGITS];
+	time_t now;
+	struct tm *timep;
+	char curdate[DATESTR];
+	char curtime[TIMESTR];
+	char *ptr, *ptr_old = NULL;
+	char *NL;
+
+	if (timef >= MAXCOLS || depthf >= MAXCOLS || tempf >= MAXCOLS || po2f >= MAXCOLS || cnsf >= MAXCOLS || ndlf >= MAXCOLS || cnsf >= MAXCOLS || stopdepthf >= MAXCOLS || pressuref >= MAXCOLS)
+		return report_error(translate("gettextFromC", "Maximum number of supported columns on CSV import is %d"), MAXCOLS);
+
+	init_csv_file_parsing(params, timebuf, depthbuf, tempbuf, po2buf, cnsbuf,ndlbuf, ttsbuf, stopdepthbuf, pressurebuf, unitbuf, separator_index, &now, timep, curdate, curtime, timef, depthf, tempf, po2f, cnsf, ndlf, ttsf, stopdepthf, pressuref, sepidx, csvtemplate, unitidx);
 
 	if (filename == NULL)
 		return report_error("No CSV filename");
 
+	if (readfile(filename, &mem) < 0)
+		return report_error(translate("gettextFromC", "Failed to read '%s'"), filename);
+
+	/* Determine NL (new line) character and the start of CSV data */
+	ptr = mem.buffer;
+	while (ptr = strstr(ptr, "\r\n\r\n")) {
+		ptr_old = ptr;
+		ptr += 1;
+		NL = "\r\n";
+	}
+
+	if (!ptr_old) {
+		while (ptr = strstr(ptr, "\n\n")) {
+			ptr_old = ptr;
+			ptr += 1;
+		}
+		ptr_old += 2;
+		NL = "\n";
+	} else
+		ptr_old += 4;
+
+	/*
+	 * On my current sample of Seabear DC log file, the date is
+	 * without any identifier. Thus we must search for the previous
+	 * line and step through from there.
+	 */
+	ptr = strstr(mem.buffer, "Serial number:");
+	if (ptr)
+		ptr = strstr(ptr, NL);
+
+	/* Write date and time values to params array */
+	if (ptr) {
+		ptr += strlen(NL) + 2;
+		memcpy(params[19], ptr, 4);
+		memcpy(params[19] + 4, ptr + 5, 2);
+		memcpy(params[19] + 6, ptr + 8, 2);
+		params[19][8] = 0;
+
+		params[21][0] = '1';
+		memcpy(params[21] + 1, ptr + 11, 2);
+		memcpy(params[21] + 3, ptr + 14, 2);
+		params[21][5] = 0;
+	}
+
+	/* Move the CSV data to the start of mem buffer */
+	mem_data.size = (int)mem.size - (ptr_old - (char*)mem.buffer);
+	mem_data.buffer = ptr_old;
+	memmove(mem.buffer, ptr_old, mem.size - (ptr_old - (char*)mem.buffer));
+	mem.size = (int)mem.size - (ptr_old - (char*)mem.buffer);
+
 	if (try_to_xslt_open_csv(filename, &mem, csvtemplate))
 		return -1;
 
@@ -714,11 +811,11 @@ int parse_manual_file(const char *filename, int sepidx, int units, int numberf,
 	snprintf(unit, MAXCOLDIGITS, "%d", units);
 	time(&now);
 	timep = localtime(&now);
-	strftime(curdate, sizeof(curdate), "%Y%m%d", timep);
+	strftime(curdate, DATESTR, "%Y%m%d", timep);
 
 	/* As the parameter is numeric, we need to ensure that the leading zero
 	* is not discarded during the transform, thus prepend time with 1 */
-	strftime(curtime, sizeof(curtime), "1%H%M", timep);
+	strftime(curtime, TIMESTR, "1%H%M", timep);
 
 	params[pnr++] = "numberField";
 	params[pnr++] = numberbuf;
@@ -757,6 +854,7 @@ int parse_manual_file(const char *filename, int sepidx, int units, int numberf,
 	if (filename == NULL)
 		return report_error("No manual CSV filename");
 
+	mem.size = 0;
 	if (try_to_xslt_open_csv(filename, &mem, "manualCSV"))
 		return -1;
 
diff --git a/qt-ui/divelogimportdialog.cpp b/qt-ui/divelogimportdialog.cpp
index 51112c4..91c1d73 100644
--- a/qt-ui/divelogimportdialog.cpp
+++ b/qt-ui/divelogimportdialog.cpp
@@ -69,7 +69,8 @@ void DiveLogImportDialog::on_buttonBox_accepted()
 {
 	if (ui->tabWidget->currentIndex() == 0) {
 		for (int i = 0; i < fileNames.size(); ++i) {
-			parse_csv_file(fileNames[i].toUtf8().data(), ui->CSVTime->value() - 1,
+			if (ui->knownImports->currentText() == QString("Seabear CSV")) {
+				parse_seabear_csv_file(fileNames[i].toUtf8().data(), ui->CSVTime->value() - 1,
 				       ui->CSVDepth->value() - 1, VALUE_IF_CHECKED(CSVTemperature),
 				       VALUE_IF_CHECKED(CSVpo2),
 				       VALUE_IF_CHECKED(CSVcns),
@@ -80,6 +81,26 @@ void DiveLogImportDialog::on_buttonBox_accepted()
 				       ui->CSVSeparator->currentIndex(),
 				       specialCSV.contains(ui->knownImports->currentIndex()) ? CSVApps[ui->knownImports->currentIndex()].name.toUtf8().data() : "csv",
 				       ui->CSVUnits->currentIndex());
+
+				/* Seabear CSV stores NDL and TTS in Minutes, not seconds */
+				struct dive *dive = dive_table.dives[dive_table.nr - 1];
+				for(int s_nr = 0 ; s_nr <= dive->dc.samples ; s_nr++) {
+					struct sample *sample = dive->dc.sample + s_nr;
+					sample->ndl.seconds *= 60;
+					sample->tts.seconds *= 60;
+				}
+			} else
+				parse_csv_file(fileNames[i].toUtf8().data(), ui->CSVTime->value() - 1,
+						ui->CSVDepth->value() - 1, VALUE_IF_CHECKED(CSVTemperature),
+						VALUE_IF_CHECKED(CSVpo2),
+						VALUE_IF_CHECKED(CSVcns),
+						VALUE_IF_CHECKED(CSVndl),
+						VALUE_IF_CHECKED(CSVtts),
+						VALUE_IF_CHECKED(CSVstopdepth),
+						VALUE_IF_CHECKED(CSVpressure),
+						ui->CSVSeparator->currentIndex(),
+						specialCSV.contains(ui->knownImports->currentIndex()) ? CSVApps[ui->knownImports->currentIndex()].name.toUtf8().data() : "csv",
+						ui->CSVUnits->currentIndex());
 		}
 	} else {
 		for (int i = 0; i < fileNames.size(); ++i) {
@@ -95,29 +116,6 @@ void DiveLogImportDialog::on_buttonBox_accepted()
 					  VALUE_IF_CHECKED(Tags));
 		}
 	}
-	if (ui->knownImports->currentText() == QString("Seabear CSV")) {
-		/* Seabear CSV stores NDL and TTS in Minutes, not seconds */
-		struct dive *dive = dive_table.dives[dive_table.nr - 1];
-		for(int s_nr = 0 ; s_nr <= dive->dc.samples ; s_nr++) {
-			struct sample *sample = dive->dc.sample + s_nr;
-			sample->ndl.seconds *= 60;
-			sample->tts.seconds *= 60;
-		}
-
-		/* And the two first samples are "settings" from there software */
-		memmove(dive->dc.sample, dive->dc.sample + 2, sizeof(dive->dc.sample) * dive->dc.samples - 2);
-		dive->dc.samples -= 2;
-		memset(dive->dc.sample + dive->dc.samples, 0, sizeof(dive->dc.sample) * 2);
-
-		/* And fix dammanged temperature from the initial samples */
-		dive->mintemp.mkelvin = 0;
-		dive->maxtemp.mkelvin = 0;
-		dive->watertemp.mkelvin = 0;
-		dive->dc.watertemp.mkelvin = 0;
-		dive->cylinder[0].start.mbar = 0;
-		dive->cylinder[0].sample_start.mbar = 0;
-		fixup_dive(dive);
-	}
 
 	process_dives(true, false);
 
-- 
1.9.1



More information about the subsurface mailing list